@ic-reactor/mcp 0.0.0-stage → 0.0.0
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/.github/ISSUE_TEMPLATE/bug_report.yml +108 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
- package/.github/actions/setup-rust-wasm/action.yml +25 -0
- package/.github/dependabot.yml +107 -0
- package/.github/workflows/auth-latest.yml +67 -0
- package/.github/workflows/b3pay-site.yml +49 -0
- package/.github/workflows/ci.yml +430 -0
- package/.github/workflows/codeql.yml +41 -0
- package/.github/workflows/dependency-review.yml +68 -0
- package/.github/workflows/docs-check.yml +98 -0
- package/.github/workflows/docs.yml +265 -0
- package/.github/workflows/e2e.yml +90 -0
- package/.github/workflows/examples-published.yml +97 -0
- package/.github/workflows/release.yml +326 -0
- package/.husky/pre-commit +12 -0
- package/.prettierignore +109 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +103 -0
- package/CHANGELOG.md +3268 -0
- package/CLAUDE.md +93 -0
- package/CNAME +1 -0
- package/CODE_OF_CONDUCT.md +7 -0
- package/CONTRIBUTING.md +433 -0
- package/LICENSE +21 -0
- package/README.md +2 -2
- package/SECURITY.md +74 -0
- package/b3pay-module.json +194 -0
- package/docs/.remarkrc.json +10 -0
- package/docs/README.md +64 -0
- package/docs/astro.config.mjs +205 -0
- package/docs/favicon.svg +15 -0
- package/docs/package.json +39 -0
- package/docs/public/favicon.svg +15 -0
- package/docs/public/ic-reactor-social-card.png +0 -0
- package/docs/scripts/b3pay-static.mjs +22 -0
- package/docs/scripts/check-example-docs.mjs +214 -0
- package/docs/scripts/check-links.mjs +212 -0
- package/docs/scripts/fix-dist-links.js +125 -0
- package/docs/scripts/fix-frontmatter.js +71 -0
- package/docs/scripts/remove-redundant-h1.cjs +48 -0
- package/docs/scripts/rewrite-typedoc-links.js +110 -0
- package/docs/scripts/split-index.js +69 -0
- package/docs/src/assets/ic-reactor-hero-dark.svg +23 -0
- package/docs/src/assets/ic-reactor-hero-light.svg +23 -0
- package/docs/src/assets/ic-reactor-lockup-dark.svg +15 -0
- package/docs/src/assets/ic-reactor-lockup-light.svg +15 -0
- package/docs/src/assets/ic-reactor-mark-dark.svg +14 -0
- package/docs/src/assets/ic-reactor-mark-light.svg +14 -0
- package/docs/src/assets/layers/candid-core-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/candid-core-layer-icon-light.svg +4 -0
- package/docs/src/assets/layers/candid-profile-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/candid-profile-layer-icon-light.svg +4 -0
- package/docs/src/assets/layers/ic-reactor-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/ic-reactor-layer-icon-light.svg +4 -0
- package/docs/src/components/LibraryCards.astro +172 -0
- package/docs/src/components/LibraryIcon.astro +28 -0
- package/docs/src/components/SiteTitle.astro +241 -0
- package/docs/src/content/docs/404.mdx +19 -0
- package/docs/src/content/docs/build/agent-tools.mdx +593 -0
- package/docs/src/content/docs/build/icrc1-wallet.mdx +619 -0
- package/docs/src/content/docs/build/ssr-per-user.mdx +552 -0
- package/docs/src/content/docs/examples/canister-studio.mdx +95 -0
- package/docs/src/content/docs/examples/icrc-ledger.mdx +45 -0
- package/docs/src/content/docs/examples/index.mdx +38 -0
- package/docs/src/content/docs/examples/next-ssr.mdx +73 -0
- package/docs/src/content/docs/examples/node-agent-tool.mdx +80 -0
- package/docs/src/content/docs/examples/vite-wallet.mdx +71 -0
- package/docs/src/content/docs/guides/auth.mdx +1181 -0
- package/docs/src/content/docs/guides/client.mdx +551 -0
- package/docs/src/content/docs/guides/deploy.mdx +180 -0
- package/docs/src/content/docs/guides/errors.mdx +475 -0
- package/docs/src/content/docs/guides/getting-started.mdx +620 -0
- package/docs/src/content/docs/guides/reads.mdx +586 -0
- package/docs/src/content/docs/guides/ssr.mdx +529 -0
- package/docs/src/content/docs/guides/testing.mdx +401 -0
- package/docs/src/content/docs/guides/values.mdx +261 -0
- package/docs/src/content/docs/guides/vite-plugin.mdx +690 -0
- package/docs/src/content/docs/guides/writes.mdx +572 -0
- package/docs/src/content/docs/ic-reactor/index.mdx +167 -0
- package/docs/src/content/docs/index.mdx +65 -0
- package/docs/src/content/docs/migrating-from-3.mdx +535 -0
- package/docs/src/content/docs/packages/core.mdx +186 -0
- package/docs/src/content/docs/packages/mcp.mdx +163 -0
- package/docs/src/content/docs/packages/react.mdx +207 -0
- package/docs/src/content/docs/packages/vite-plugin.mdx +73 -0
- package/docs/src/content/docs/versioning.mdx +104 -0
- package/docs/src/content.config.ts +7 -0
- package/docs/src/styles/custom.css +189 -0
- package/docs/tsconfig.typedoc.json +26 -0
- package/docs/typedoc-entry.ts +17 -0
- package/docs/typedoc.json +37 -0
- package/e2e/Cargo.lock +646 -0
- package/e2e/Cargo.toml +3 -0
- package/e2e/README.md +101 -0
- package/e2e/frontends/build.mjs +94 -0
- package/e2e/frontends/index.html +10 -0
- package/e2e/global-setup.ts +65 -0
- package/e2e/icp.yaml +38 -0
- package/e2e/package.json +40 -0
- package/e2e/setup.ts +6 -0
- package/e2e/src/actor/Cargo.toml +14 -0
- package/e2e/src/actor/hello_actor.did +10 -0
- package/e2e/src/actor/src/lib.rs +73 -0
- package/e2e/src/calls.test.ts +132 -0
- package/e2e/src/declarations/hello_actor.envelope.json +175 -0
- package/e2e/src/declarations/hello_actor.ts +15 -0
- package/e2e/src/errors.test.ts +107 -0
- package/e2e/src/frontend-headers.test.ts +253 -0
- package/e2e/src/identity.test.ts +61 -0
- package/e2e/src/react.test.tsx +59 -0
- package/e2e/src/replica.ts +70 -0
- package/e2e/src/vite-env.test.ts +108 -0
- package/e2e/test.sh +47 -0
- package/e2e/tsconfig.json +20 -0
- package/e2e/tsconfig.typecheck.json +9 -0
- package/e2e/vitest.config.ts +22 -0
- package/eslint.config.mjs +100 -0
- package/evals/PREREGISTRATION.md +1346 -0
- package/evals/README.md +756 -0
- package/evals/conditions/thin/condition.json +8 -0
- package/evals/conditions/thin/docs/candid-core-cli.README.md +90 -0
- package/evals/conditions/thin/docs/candid-core-schema.README.md +339 -0
- package/evals/conditions/thin/package.json +25 -0
- package/evals/conditions/thin/starter/src/generated/icrc1.ts +57 -0
- package/evals/conditions/thin-guide/condition.json +10 -0
- package/evals/conditions/thin-guide/docs/llms.txt +292 -0
- package/evals/conditions/v3/condition.json +9 -0
- package/evals/conditions/v3/docs/ic-reactor-core.llms.txt +232 -0
- package/evals/conditions/v3/docs/ic-reactor-react.llms.txt +280 -0
- package/evals/conditions/v3/docs/llms-full.txt +1053 -0
- package/evals/conditions/v3/package.json +26 -0
- package/evals/conditions/v3/starter/src/declarations/icrc1.did.d.ts +95 -0
- package/evals/conditions/v3/starter/src/declarations/icrc1.did.js +140 -0
- package/evals/conditions/v4/PORTING.md +384 -0
- package/evals/conditions/v4/README.md +106 -0
- package/evals/conditions/v4/condition.json +5 -0
- package/evals/conditions/v4/docs/llms.txt +323 -0
- package/evals/conditions/v4/package.json +27 -0
- package/evals/conditions/v4/starter/src/generated/icrc1.ts +78 -0
- package/evals/conditions/v4-proto/condition.json +6 -0
- package/evals/conditions/v4-proto/docs/llms.txt +291 -0
- package/evals/conditions/v4-proto/lib/SHIM-NOTES.md +20 -0
- package/evals/conditions/v4-proto/lib/package.json +27 -0
- package/evals/conditions/v4-proto/lib/src/client.ts +471 -0
- package/evals/conditions/v4-proto/lib/src/errors.ts +214 -0
- package/evals/conditions/v4-proto/lib/src/index.ts +36 -0
- package/evals/conditions/v4-proto/lib/src/principal.ts +175 -0
- package/evals/conditions/v4-proto/lib/src/service.ts +69 -0
- package/evals/conditions/v4-proto/lib/src/types.ts +174 -0
- package/evals/conditions/v4-proto/lib/test/runtime.test.ts +170 -0
- package/evals/conditions/v4-proto/lib/test/tsconfig.json +10 -0
- package/evals/conditions/v4-proto/lib/test/types.test-d.ts +145 -0
- package/evals/conditions/v4-proto/lib/test/vitest.config.mjs +8 -0
- package/evals/conditions/v4-proto/lib/tsconfig.json +17 -0
- package/evals/conditions/v4-proto/package.json +26 -0
- package/evals/conditions/v4-proto/starter/src/generated/icrc1.service.ts +19 -0
- package/evals/conditions/v4-proto/starter/src/generated/icrc1.ts +57 -0
- package/evals/drive.mjs +1221 -0
- package/evals/gate.mjs +161 -0
- package/evals/harness/aggregate.mjs +534 -0
- package/evals/harness/aggregate.test.mjs +344 -0
- package/evals/harness/assemble.mjs +216 -0
- package/evals/harness/assemble.test.mjs +143 -0
- package/evals/harness/auth.mjs +91 -0
- package/evals/harness/check-docs.mjs +157 -0
- package/evals/harness/declarations/icrc1.did.d.ts +95 -0
- package/evals/harness/declarations/icrc1.did.js +140 -0
- package/evals/harness/drive-auth.test.mjs +584 -0
- package/evals/harness/drive.test.mjs +509 -0
- package/evals/harness/fake-auth.ts +67 -0
- package/evals/harness/fake-ledger.ts +178 -0
- package/evals/harness/gate-plan.mjs +104 -0
- package/evals/harness/gate-plan.test.mjs +243 -0
- package/evals/harness/icrc1.did +88 -0
- package/evals/harness/judge.mjs +63 -0
- package/evals/harness/judge.test.mjs +81 -0
- package/evals/harness/leak-scan.mjs +1373 -0
- package/evals/harness/leak-scan.test.mjs +1300 -0
- package/evals/harness/probes/amounts.ts +14 -0
- package/evals/harness/probes/node-tool.probe.ts +48 -0
- package/evals/harness/probes/probe.mjs +149 -0
- package/evals/harness/probes/react-wallet.probe.ts +96 -0
- package/evals/harness/public/support/auth.ts +38 -0
- package/evals/harness/public/support/fake-replica.d.ts +28 -0
- package/evals/harness/public/support/fake-replica.js +434 -0
- package/evals/harness/public/support/ledger.idl.d.ts +95 -0
- package/evals/harness/public/support/ledger.idl.js +140 -0
- package/evals/harness/public/support/world.ts +179 -0
- package/evals/harness/runs.mjs +139 -0
- package/evals/harness/sandbox.mjs +88 -0
- package/evals/harness/sandbox.test.mjs +134 -0
- package/evals/harness/ship.mjs +264 -0
- package/evals/harness/ship.test.mjs +552 -0
- package/evals/harness/world.ts +291 -0
- package/evals/package.json +26 -0
- package/evals/pnpm-lock.yaml +1537 -0
- package/evals/pnpm-workspace.yaml +12 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.json +384 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.json +404 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.rescored.json +404 -0
- package/evals/results/2026-09-30T14-22-05-924Z/plan.json +240 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.json +1800 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.json +1843 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.rescored.json +2100 -0
- package/evals/results/2026-09-30T15-48-23-343Z/pilot.json +404 -0
- package/evals/results/2026-09-30T15-48-23-343Z/pilot.rescored.json +404 -0
- package/evals/results/2026-09-30T15-48-23-343Z/plan.json +242 -0
- package/evals/results/2026-09-30T15-48-23-343Z/summary.json +1843 -0
- package/evals/results/2026-09-30T15-48-23-343Z/summary.rescored.json +2195 -0
- package/evals/results/2026-10-03-beta1-gate/pilot.json +162 -0
- package/evals/results/2026-10-03-beta1-gate/plan.json +141 -0
- package/evals/results/2026-10-03-beta1-gate/summary.json +983 -0
- package/evals/results/2026-10-05-ga-gate/contaminated-run.json +55 -0
- package/evals/results/2026-10-05-ga-gate/pilot.json +162 -0
- package/evals/results/2026-10-05-ga-gate/plan.json +457 -0
- package/evals/results/2026-10-05-ga-gate/summary.json +1037 -0
- package/evals/results/2026-10-05-ga-gate/summary.rescanned.json +1037 -0
- package/evals/results/README.md +31 -0
- package/evals/runs-pilot.log +150 -0
- package/evals/runs-pilot2.log +150 -0
- package/evals/score.mjs +256 -0
- package/evals/setup.mjs +547 -0
- package/evals/tasks/node-tool/faulty/thin-accepts-exponent/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-accepts-exponent/src/index.ts +121 -0
- package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/src/index.ts +116 -0
- package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-ignores-root-key/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-ignores-root-key/src/index.ts +117 -0
- package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/src/index.ts +119 -0
- package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-number-amount/meta.json +10 -0
- package/evals/tasks/node-tool/faulty/thin-number-amount/src/index.ts +117 -0
- package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/src/index.ts +120 -0
- package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/v3-retry-call-errors/meta.json +11 -0
- package/evals/tasks/node-tool/faulty/v3-retry-call-errors/src/index.ts +149 -0
- package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/src/index.ts +71 -0
- package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/src/index.ts +84 -0
- package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/src/index.ts +72 -0
- package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/src/index.ts +72 -0
- package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/src/index.ts +84 -0
- package/evals/tasks/node-tool/hidden/node-tool.test.ts +312 -0
- package/evals/tasks/node-tool/prompt.md +55 -0
- package/evals/tasks/node-tool/prompt.minimal.md +30 -0
- package/evals/tasks/node-tool/solutions/thin/reference/src/index.ts +118 -0
- package/evals/tasks/node-tool/solutions/thin/reference-module-scope/src/index.ts +145 -0
- package/evals/tasks/node-tool/solutions/thin-guide/reference/src/index.ts +118 -0
- package/evals/tasks/node-tool/solutions/thin-guide/reference-module-scope/src/index.ts +145 -0
- package/evals/tasks/node-tool/solutions/v3/reference/src/index.ts +140 -0
- package/evals/tasks/node-tool/solutions/v3/reference-module-scope/src/index.ts +153 -0
- package/evals/tasks/node-tool/solutions/v4/reference/src/index.ts +84 -0
- package/evals/tasks/node-tool/solutions/v4/reference-module-scope/src/index.ts +105 -0
- package/evals/tasks/node-tool/solutions/v4-proto/reference/src/index.ts +72 -0
- package/evals/tasks/node-tool/solutions/v4-proto/reference-module-scope/src/index.ts +87 -0
- package/evals/tasks/node-tool/starter/src/contract.ts +31 -0
- package/evals/tasks/node-tool/starter/src/index.ts +7 -0
- package/evals/tasks/node-tool/starter/test/smoke.test.ts +22 -0
- package/evals/tasks/node-tool/starter/tsconfig.json +17 -0
- package/evals/tasks/node-tool/task.json +63 -0
- package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/src/Wallet.tsx +216 -0
- package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/src/Wallet.tsx +212 -0
- package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/src/Wallet.tsx +210 -0
- package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/meta.json +8 -0
- package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/meta.json +9 -0
- package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-number-balance/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-number-balance/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/src/Wallet.tsx +254 -0
- package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/src/Wallet.tsx +215 -0
- package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/src/Wallet.tsx +214 -0
- package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/src/Wallet.tsx +224 -0
- package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/src/Wallet.tsx +225 -0
- package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/meta.json +11 -0
- package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/src/Wallet.tsx +182 -0
- package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/src/Wallet.tsx +160 -0
- package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/src/Wallet.tsx +166 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/src/Wallet.tsx +162 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-retry-spread/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v4-retry-spread/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-status-not-idle/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-status-not-idle/src/Wallet.tsx +162 -0
- package/evals/tasks/react-wallet/hidden/react-wallet.test.ts +536 -0
- package/evals/tasks/react-wallet/prompt.md +88 -0
- package/evals/tasks/react-wallet/prompt.minimal.md +51 -0
- package/evals/tasks/react-wallet/solutions/thin/reference/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/solutions/thin/reference-module-scope/src/Wallet.tsx +227 -0
- package/evals/tasks/react-wallet/solutions/thin-guide/reference/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/solutions/thin-guide/reference-module-scope/src/Wallet.tsx +227 -0
- package/evals/tasks/react-wallet/solutions/v3/reference/src/Wallet.tsx +224 -0
- package/evals/tasks/react-wallet/solutions/v3/reference-module-scope/src/Wallet.tsx +230 -0
- package/evals/tasks/react-wallet/solutions/v4/reference/src/Wallet.tsx +160 -0
- package/evals/tasks/react-wallet/solutions/v4/reference-module-scope/src/Wallet.tsx +178 -0
- package/evals/tasks/react-wallet/solutions/v4-proto/reference/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/solutions/v4-proto/reference-module-scope/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/starter/src/Wallet.tsx +12 -0
- package/evals/tasks/react-wallet/starter/src/auth.ts +16 -0
- package/evals/tasks/react-wallet/starter/src/config.ts +14 -0
- package/evals/tasks/react-wallet/starter/src/ii-auth.ts +43 -0
- package/evals/tasks/react-wallet/starter/src/main.tsx +15 -0
- package/evals/tasks/react-wallet/starter/test/smoke.test.ts +34 -0
- package/evals/tasks/react-wallet/starter/tsconfig.json +18 -0
- package/evals/tasks/react-wallet/task.json +84 -0
- package/examples/canister-studio/.stackblitzrc +4 -0
- package/examples/canister-studio/README.md +183 -0
- package/examples/canister-studio/did/ckbtc_minter.did +806 -0
- package/examples/canister-studio/did/icp_ledger.did +586 -0
- package/examples/canister-studio/did/icrc1.did +88 -0
- package/examples/canister-studio/package.json +45 -0
- package/examples/canister-studio/scripts/smoke.ts +188 -0
- package/examples/canister-studio/src/calls/CacheKeyPanel.tsx +104 -0
- package/examples/canister-studio/src/calls/ConfirmWrite.tsx +265 -0
- package/examples/canister-studio/src/calls/ErrorPanel.test.tsx +113 -0
- package/examples/canister-studio/src/calls/ErrorPanel.tsx +214 -0
- package/examples/canister-studio/src/calls/MethodRunner.test.tsx +354 -0
- package/examples/canister-studio/src/calls/MethodRunner.tsx +57 -0
- package/examples/canister-studio/src/calls/ReadRunner.tsx +244 -0
- package/examples/canister-studio/src/calls/ResendPanel.tsx +165 -0
- package/examples/canister-studio/src/calls/ShareLink.tsx +59 -0
- package/examples/canister-studio/src/calls/WriteRunner.test.tsx +678 -0
- package/examples/canister-studio/src/calls/WriteRunner.tsx +670 -0
- package/examples/canister-studio/src/calls/dedupe.ts +189 -0
- package/examples/canister-studio/src/calls/error-info.ts +168 -0
- package/examples/canister-studio/src/calls/history.test.ts +284 -0
- package/examples/canister-studio/src/calls/history.ts +287 -0
- package/examples/canister-studio/src/calls/kinds.ts +68 -0
- package/examples/canister-studio/src/calls/prepare.ts +32 -0
- package/examples/canister-studio/src/calls/query-options.ts +30 -0
- package/examples/canister-studio/src/calls/read.ts +47 -0
- package/examples/canister-studio/src/calls/readback.ts +100 -0
- package/examples/canister-studio/src/calls/record.ts +123 -0
- package/examples/canister-studio/src/calls/safe-calls.test.ts +299 -0
- package/examples/canister-studio/src/calls/share.ts +46 -0
- package/examples/canister-studio/src/calls/testing/doubles.tsx +108 -0
- package/examples/canister-studio/src/calls/testing/fixtures.ts +185 -0
- package/examples/canister-studio/src/calls/useCanisterHandle.ts +35 -0
- package/examples/canister-studio/src/canisters/ckbtc_minter.envelope.json +4228 -0
- package/examples/canister-studio/src/canisters/ckbtc_minter.ts +868 -0
- package/examples/canister-studio/src/canisters/icp_ledger.envelope.json +3454 -0
- package/examples/canister-studio/src/canisters/icp_ledger.ts +584 -0
- package/examples/canister-studio/src/canisters/icrc1.envelope.json +840 -0
- package/examples/canister-studio/src/canisters/icrc1.ts +78 -0
- package/examples/canister-studio/src/components/ActionButton.tsx +32 -0
- package/examples/canister-studio/src/components/AppHeader.tsx +83 -0
- package/examples/canister-studio/src/components/AppShell.tsx +29 -0
- package/examples/canister-studio/src/components/AuthButton.tsx +79 -0
- package/examples/canister-studio/src/components/Badge.tsx +79 -0
- package/examples/canister-studio/src/components/CanisterHeader.tsx +200 -0
- package/examples/canister-studio/src/components/CanisterJump.tsx +130 -0
- package/examples/canister-studio/src/components/Card.tsx +64 -0
- package/examples/canister-studio/src/components/Code.tsx +101 -0
- package/examples/canister-studio/src/components/CopyButton.tsx +126 -0
- package/examples/canister-studio/src/components/Disclosure.tsx +34 -0
- package/examples/canister-studio/src/components/EmptyState.tsx +34 -0
- package/examples/canister-studio/src/components/MethodList.test.tsx +137 -0
- package/examples/canister-studio/src/components/MethodList.tsx +244 -0
- package/examples/canister-studio/src/components/Notice.tsx +36 -0
- package/examples/canister-studio/src/components/ProvenanceBadge.tsx +44 -0
- package/examples/canister-studio/src/components/RouteError.tsx +42 -0
- package/examples/canister-studio/src/components/SectionBoundary.tsx +76 -0
- package/examples/canister-studio/src/components/Spinner.tsx +33 -0
- package/examples/canister-studio/src/components/Tabs.tsx +96 -0
- package/examples/canister-studio/src/components/canister/CanisterLoadFailure.test.tsx +56 -0
- package/examples/canister-studio/src/components/canister/CanisterLoadFailure.tsx +165 -0
- package/examples/canister-studio/src/components/canister/CanisterNotFound.tsx +59 -0
- package/examples/canister-studio/src/components/canister/CanisterPending.tsx +33 -0
- package/examples/canister-studio/src/components/canister/MethodOverview.tsx +93 -0
- package/examples/canister-studio/src/components/canister/MethodWorkspace.test.tsx +201 -0
- package/examples/canister-studio/src/components/canister/MethodWorkspace.tsx +187 -0
- package/examples/canister-studio/src/components/canister/shared-call.test.ts +186 -0
- package/examples/canister-studio/src/components/canister/shared-call.ts +133 -0
- package/examples/canister-studio/src/components/canister/shared-link-loader.test.ts +116 -0
- package/examples/canister-studio/src/components/canister/use-canister-page.ts +44 -0
- package/examples/canister-studio/src/components/canister/workspace-key.test.ts +27 -0
- package/examples/canister-studio/src/components/canister/workspace-key.ts +36 -0
- package/examples/canister-studio/src/components/canister-id-input.ts +69 -0
- package/examples/canister-studio/src/components/canister-names.ts +11 -0
- package/examples/canister-studio/src/components/download.ts +34 -0
- package/examples/canister-studio/src/components/fallbacks.tsx +33 -0
- package/examples/canister-studio/src/components/helpers.test.ts +107 -0
- package/examples/canister-studio/src/components/history/HistoryList.tsx +284 -0
- package/examples/canister-studio/src/components/home/FeaturedLedger.tsx +149 -0
- package/examples/canister-studio/src/components/home/OpenCanister.tsx +99 -0
- package/examples/canister-studio/src/components/home/featured.test.tsx +92 -0
- package/examples/canister-studio/src/components/home/featured.ts +64 -0
- package/examples/canister-studio/src/components/interface/CandidTab.tsx +38 -0
- package/examples/canister-studio/src/components/interface/CompatReport.tsx +92 -0
- package/examples/canister-studio/src/components/interface/CompatibilityTab.tsx +190 -0
- package/examples/canister-studio/src/components/interface/ProjectTab.tsx +196 -0
- package/examples/canister-studio/src/components/interface/TypeScriptTab.tsx +114 -0
- package/examples/canister-studio/src/components/interface/tools.test.tsx +169 -0
- package/examples/canister-studio/src/components/modes.ts +31 -0
- package/examples/canister-studio/src/components/playground/MethodPicker.tsx +67 -0
- package/examples/canister-studio/src/components/playground/PlaygroundForms.tsx +112 -0
- package/examples/canister-studio/src/components/playground/PlaygroundTools.tsx +219 -0
- package/examples/canister-studio/src/components/playground/sample.ts +43 -0
- package/examples/canister-studio/src/components/playground/target.test.tsx +86 -0
- package/examples/canister-studio/src/components/primitives.test.tsx +121 -0
- package/examples/canister-studio/src/components/provenance.ts +38 -0
- package/examples/canister-studio/src/components/route-render.test.tsx +71 -0
- package/examples/canister-studio/src/components/use-task.ts +56 -0
- package/examples/canister-studio/src/components/wallet/BalancePanel.tsx +110 -0
- package/examples/canister-studio/src/components/wallet/LedgerSummary.tsx +63 -0
- package/examples/canister-studio/src/components/wallet/MinterPanel.tsx +255 -0
- package/examples/canister-studio/src/components/wallet/SendPanel.test.tsx +297 -0
- package/examples/canister-studio/src/components/wallet/SendPanel.tsx +446 -0
- package/examples/canister-studio/src/components/wallet/ledgers.test.ts +36 -0
- package/examples/canister-studio/src/components/wallet/ledgers.ts +111 -0
- package/examples/canister-studio/src/forms/JsonPanel.tsx +157 -0
- package/examples/canister-studio/src/forms/MethodForm.test.tsx +369 -0
- package/examples/canister-studio/src/forms/MethodForm.tsx +368 -0
- package/examples/canister-studio/src/forms/TypedForm.tsx +55 -0
- package/examples/canister-studio/src/forms/context.ts +62 -0
- package/examples/canister-studio/src/forms/convert.ts +131 -0
- package/examples/canister-studio/src/forms/edge.test.ts +252 -0
- package/examples/canister-studio/src/forms/engine.test.ts +358 -0
- package/examples/canister-studio/src/forms/engine.ts +1492 -0
- package/examples/canister-studio/src/forms/fields/BytesField.tsx +210 -0
- package/examples/canister-studio/src/forms/fields/Field.tsx +106 -0
- package/examples/canister-studio/src/forms/fields/FieldShell.tsx +101 -0
- package/examples/canister-studio/src/forms/fields/Group.tsx +74 -0
- package/examples/canister-studio/src/forms/fields/ListField.tsx +256 -0
- package/examples/canister-studio/src/forms/fields/Segmented.tsx +78 -0
- package/examples/canister-studio/src/forms/fields/TimestampField.tsx +108 -0
- package/examples/canister-studio/src/forms/fields/UnitsField.tsx +119 -0
- package/examples/canister-studio/src/forms/fields/composites.tsx +389 -0
- package/examples/canister-studio/src/forms/fields/leaves.tsx +350 -0
- package/examples/canister-studio/src/forms/fields.test.tsx +396 -0
- package/examples/canister-studio/src/forms/helpers.test.ts +225 -0
- package/examples/canister-studio/src/forms/hints.ts +128 -0
- package/examples/canister-studio/src/forms/json.ts +119 -0
- package/examples/canister-studio/src/forms/parsing.test.ts +217 -0
- package/examples/canister-studio/src/forms/useMethodForm.ts +251 -0
- package/examples/canister-studio/src/interface/browser.test.ts +23 -0
- package/examples/canister-studio/src/interface/browser.ts +153 -0
- package/examples/canister-studio/src/interface/cache.ts +68 -0
- package/examples/canister-studio/src/interface/cli-cache.test.ts +155 -0
- package/examples/canister-studio/src/interface/cli-cache.ts +125 -0
- package/examples/canister-studio/src/interface/compile.server.test.ts +198 -0
- package/examples/canister-studio/src/interface/compile.server.ts +262 -0
- package/examples/canister-studio/src/interface/compile.test.ts +108 -0
- package/examples/canister-studio/src/interface/compile.ts +305 -0
- package/examples/canister-studio/src/interface/docs.test.ts +75 -0
- package/examples/canister-studio/src/interface/docs.ts +100 -0
- package/examples/canister-studio/src/interface/functions.test.ts +42 -0
- package/examples/canister-studio/src/interface/functions.ts +200 -0
- package/examples/canister-studio/src/interface/live-candid.server.ts +91 -0
- package/examples/canister-studio/src/interface/live-loader.test.ts +515 -0
- package/examples/canister-studio/src/interface/live-loader.ts +364 -0
- package/examples/canister-studio/src/interface/load.test.ts +328 -0
- package/examples/canister-studio/src/interface/load.ts +249 -0
- package/examples/canister-studio/src/interface/read-candid.test.ts +185 -0
- package/examples/canister-studio/src/interface/read-candid.ts +233 -0
- package/examples/canister-studio/src/interface/server-result.ts +42 -0
- package/examples/canister-studio/src/interface/typed.ts +68 -0
- package/examples/canister-studio/src/interface/types.ts +121 -0
- package/examples/canister-studio/src/lib/format.test.ts +107 -0
- package/examples/canister-studio/src/lib/format.ts +139 -0
- package/examples/canister-studio/src/lib/hex.test.ts +43 -0
- package/examples/canister-studio/src/lib/hex.ts +33 -0
- package/examples/canister-studio/src/lib/ids.test.ts +70 -0
- package/examples/canister-studio/src/lib/ids.ts +93 -0
- package/examples/canister-studio/src/lib/reactor.test.ts +55 -0
- package/examples/canister-studio/src/lib/reactor.ts +55 -0
- package/examples/canister-studio/src/lib/registry.test.ts +74 -0
- package/examples/canister-studio/src/lib/registry.ts +238 -0
- package/examples/canister-studio/src/lib/schema.ts +148 -0
- package/examples/canister-studio/src/routeTree.gen.ts +227 -0
- package/examples/canister-studio/src/router.test.ts +290 -0
- package/examples/canister-studio/src/router.tsx +127 -0
- package/examples/canister-studio/src/routes/__root.tsx +58 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.index.tsx +172 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.interface.tsx +98 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.tsx +91 -0
- package/examples/canister-studio/src/routes/history.tsx +55 -0
- package/examples/canister-studio/src/routes/index.tsx +169 -0
- package/examples/canister-studio/src/routes/playground.tsx +286 -0
- package/examples/canister-studio/src/routes/safety.tsx +57 -0
- package/examples/canister-studio/src/routes/wallet.tsx +213 -0
- package/examples/canister-studio/src/safety/LabTransferForm.tsx +84 -0
- package/examples/canister-studio/src/safety/RequestLog.tsx +79 -0
- package/examples/canister-studio/src/safety/SafetyLab.test.tsx +89 -0
- package/examples/canister-studio/src/safety/SafetyLab.tsx +140 -0
- package/examples/canister-studio/src/safety/ScenarioCard.tsx +262 -0
- package/examples/canister-studio/src/safety/lab-run.ts +283 -0
- package/examples/canister-studio/src/safety/mock-ledger.test.ts +99 -0
- package/examples/canister-studio/src/safety/mock-ledger.ts +263 -0
- package/examples/canister-studio/src/safety/scenarios.test.ts +157 -0
- package/examples/canister-studio/src/safety/scenarios.ts +924 -0
- package/examples/canister-studio/src/styles.css +3453 -0
- package/examples/canister-studio/src/styles.test.ts +46 -0
- package/examples/canister-studio/src/values/CallPreview.test.tsx +86 -0
- package/examples/canister-studio/src/values/CallPreview.tsx +148 -0
- package/examples/canister-studio/src/values/ErrValueView.tsx +66 -0
- package/examples/canister-studio/src/values/Inspector.tsx +133 -0
- package/examples/canister-studio/src/values/ReplyView.test.tsx +341 -0
- package/examples/canister-studio/src/values/ReplyView.tsx +164 -0
- package/examples/canister-studio/src/values/candid-text.test.ts +516 -0
- package/examples/canister-studio/src/values/candid-text.ts +479 -0
- package/examples/canister-studio/src/values/hints.ts +58 -0
- package/examples/canister-studio/src/values/json.test.ts +66 -0
- package/examples/canister-studio/src/values/json.ts +31 -0
- package/examples/canister-studio/src/values/leaves.tsx +309 -0
- package/examples/canister-studio/src/values/schema.test.ts +123 -0
- package/examples/canister-studio/src/values/schema.ts +78 -0
- package/examples/canister-studio/src/values/test-router.tsx +21 -0
- package/examples/canister-studio/src/values/tree.tsx +670 -0
- package/examples/canister-studio/src/values/use-sha256.ts +29 -0
- package/examples/canister-studio/tsconfig.json +20 -0
- package/examples/canister-studio/vite.config.ts +50 -0
- package/examples/canister-studio/vitest.config.ts +20 -0
- package/examples/icrc-ledger/.stackblitzrc +4 -0
- package/examples/icrc-ledger/README.md +100 -0
- package/examples/icrc-ledger/ckbtc_minter.did +12 -0
- package/examples/icrc-ledger/icp_ledger.did +147 -0
- package/examples/icrc-ledger/icrc1.did +88 -0
- package/examples/icrc-ledger/index.html +13 -0
- package/examples/icrc-ledger/package.json +40 -0
- package/examples/icrc-ledger/scripts/smoke.ts +151 -0
- package/examples/icrc-ledger/src/App.tsx +71 -0
- package/examples/icrc-ledger/src/ErrorPanel.tsx +105 -0
- package/examples/icrc-ledger/src/MainnetTab.tsx +450 -0
- package/examples/icrc-ledger/src/SandboxTab.test.tsx +379 -0
- package/examples/icrc-ledger/src/SandboxTab.tsx +761 -0
- package/examples/icrc-ledger/src/blocks.test.ts +247 -0
- package/examples/icrc-ledger/src/blocks.ts +140 -0
- package/examples/icrc-ledger/src/canisters/ckbtc_minter.envelope.json +96 -0
- package/examples/icrc-ledger/src/canisters/ckbtc_minter.ts +16 -0
- package/examples/icrc-ledger/src/canisters/icp_ledger.envelope.json +690 -0
- package/examples/icrc-ledger/src/canisters/icp_ledger.ts +223 -0
- package/examples/icrc-ledger/src/canisters/icrc1.envelope.json +840 -0
- package/examples/icrc-ledger/src/canisters/icrc1.ts +78 -0
- package/examples/icrc-ledger/src/format.test.ts +41 -0
- package/examples/icrc-ledger/src/format.ts +68 -0
- package/examples/icrc-ledger/src/ledger.ts +15 -0
- package/examples/icrc-ledger/src/main.tsx +10 -0
- package/examples/icrc-ledger/src/minter.ts +16 -0
- package/examples/icrc-ledger/src/sandbox.test.ts +464 -0
- package/examples/icrc-ledger/src/sandbox.ts +281 -0
- package/examples/icrc-ledger/src/styles.css +391 -0
- package/examples/icrc-ledger/src/transfer-form.test.ts +62 -0
- package/examples/icrc-ledger/src/transfer-form.ts +97 -0
- package/examples/icrc-ledger/tsconfig.json +19 -0
- package/examples/icrc-ledger/vite.config.ts +44 -0
- package/examples/icrc-ledger/vitest.config.ts +12 -0
- package/examples/next-ssr/.stackblitzrc +4 -0
- package/examples/next-ssr/README.md +112 -0
- package/examples/next-ssr/icrc1.did +88 -0
- package/examples/next-ssr/next.config.ts +10 -0
- package/examples/next-ssr/package.json +41 -0
- package/examples/next-ssr/scripts/smoke.ts +169 -0
- package/examples/next-ssr/src/app/account/CertifiedBalances.tsx +58 -0
- package/examples/next-ssr/src/app/account/account.test.tsx +165 -0
- package/examples/next-ssr/src/app/account/page.tsx +82 -0
- package/examples/next-ssr/src/app/api/balance/[ledger]/[principal]/route.ts +10 -0
- package/examples/next-ssr/src/app/globals.css +278 -0
- package/examples/next-ssr/src/app/layout.tsx +34 -0
- package/examples/next-ssr/src/app/page.tsx +46 -0
- package/examples/next-ssr/src/app/providers.browser.test.tsx +127 -0
- package/examples/next-ssr/src/app/providers.test.tsx +73 -0
- package/examples/next-ssr/src/app/providers.tsx +60 -0
- package/examples/next-ssr/src/canisters/icrc1.envelope.json +840 -0
- package/examples/next-ssr/src/canisters/icrc1.ts +78 -0
- package/examples/next-ssr/src/components/BalanceTable.tsx +43 -0
- package/examples/next-ssr/src/components/LedgerCard.test.tsx +96 -0
- package/examples/next-ssr/src/components/LedgerCard.tsx +230 -0
- package/examples/next-ssr/src/components/LedgerError.tsx +32 -0
- package/examples/next-ssr/src/components/LedgerSections.tsx +22 -0
- package/examples/next-ssr/src/components/MyBalances.test.tsx +253 -0
- package/examples/next-ssr/src/components/MyBalances.tsx +129 -0
- package/examples/next-ssr/src/components/SessionBadge.tsx +18 -0
- package/examples/next-ssr/src/components/hydration.test.tsx +259 -0
- package/examples/next-ssr/src/components/server-data.ts +10 -0
- package/examples/next-ssr/src/format.ts +46 -0
- package/examples/next-ssr/src/ledgers.ts +38 -0
- package/examples/next-ssr/src/server/balance-route.test.ts +151 -0
- package/examples/next-ssr/src/server/balance-route.ts +157 -0
- package/examples/next-ssr/src/server/error-summary.test.ts +34 -0
- package/examples/next-ssr/src/server/error-summary.ts +37 -0
- package/examples/next-ssr/src/server/parse-owner.test.ts +39 -0
- package/examples/next-ssr/src/server/parse-owner.ts +34 -0
- package/examples/next-ssr/src/server/prefetch-ledgers.test.ts +137 -0
- package/examples/next-ssr/src/server/prefetch-ledgers.ts +70 -0
- package/examples/next-ssr/src/server/read-balances.test.ts +103 -0
- package/examples/next-ssr/src/server/read-balances.ts +78 -0
- package/examples/next-ssr/src/server/request-client.rsc.test.tsx +110 -0
- package/examples/next-ssr/src/server/request-client.ts +24 -0
- package/examples/next-ssr/src/testing/mock-ledgers.ts +115 -0
- package/examples/next-ssr/src/testing/react-server-dom-turbopack.d.ts +15 -0
- package/examples/next-ssr/src/testing/setup.ts +10 -0
- package/examples/next-ssr/tsconfig.json +31 -0
- package/examples/next-ssr/vitest.config.ts +59 -0
- package/examples/node-agent-tool/.stackblitzrc +4 -0
- package/examples/node-agent-tool/README.md +165 -0
- package/examples/node-agent-tool/icp.yaml +11 -0
- package/examples/node-agent-tool/icrc1.did +88 -0
- package/examples/node-agent-tool/package.json +32 -0
- package/examples/node-agent-tool/src/canisters/icrc1.envelope.json +840 -0
- package/examples/node-agent-tool/src/canisters/icrc1.ts +78 -0
- package/examples/node-agent-tool/src/cli.test.ts +64 -0
- package/examples/node-agent-tool/src/cli.ts +23 -0
- package/examples/node-agent-tool/src/command-line.ts +159 -0
- package/examples/node-agent-tool/src/commands/balance.ts +73 -0
- package/examples/node-agent-tool/src/commands/demo.test.ts +51 -0
- package/examples/node-agent-tool/src/commands/demo.ts +359 -0
- package/examples/node-agent-tool/src/commands/info.ts +69 -0
- package/examples/node-agent-tool/src/commands/reads.test.ts +133 -0
- package/examples/node-agent-tool/src/commands/resend.test.ts +363 -0
- package/examples/node-agent-tool/src/commands/transfer.test.ts +313 -0
- package/examples/node-agent-tool/src/commands/transfer.ts +415 -0
- package/examples/node-agent-tool/src/commands/watch.test.ts +159 -0
- package/examples/node-agent-tool/src/commands/watch.ts +135 -0
- package/examples/node-agent-tool/src/commands/whoami.ts +36 -0
- package/examples/node-agent-tool/src/context.ts +20 -0
- package/examples/node-agent-tool/src/dispatch.ts +70 -0
- package/examples/node-agent-tool/src/failure.test.ts +59 -0
- package/examples/node-agent-tool/src/failure.ts +176 -0
- package/examples/node-agent-tool/src/identity.test.ts +242 -0
- package/examples/node-agent-tool/src/identity.ts +228 -0
- package/examples/node-agent-tool/src/input.ts +110 -0
- package/examples/node-agent-tool/src/ledgers.test.ts +74 -0
- package/examples/node-agent-tool/src/ledgers.ts +62 -0
- package/examples/node-agent-tool/src/mock-ledger.ts +211 -0
- package/examples/node-agent-tool/src/network.test.ts +128 -0
- package/examples/node-agent-tool/src/network.ts +101 -0
- package/examples/node-agent-tool/src/output.test.ts +208 -0
- package/examples/node-agent-tool/src/output.ts +163 -0
- package/examples/node-agent-tool/src/run.ts +73 -0
- package/examples/node-agent-tool/src/test-kit.ts +167 -0
- package/examples/node-agent-tool/tsconfig.json +18 -0
- package/examples/node-agent-tool/vitest.config.ts +8 -0
- package/examples/vite-wallet/.stackblitzrc +4 -0
- package/examples/vite-wallet/Cargo.lock +646 -0
- package/examples/vite-wallet/Cargo.toml +5 -0
- package/examples/vite-wallet/README.md +107 -0
- package/examples/vite-wallet/backend/Cargo.toml +12 -0
- package/examples/vite-wallet/backend/backend.did +37 -0
- package/examples/vite-wallet/backend/src/lib.rs +133 -0
- package/examples/vite-wallet/icp.yaml +44 -0
- package/examples/vite-wallet/index.html +13 -0
- package/examples/vite-wallet/ledger.did +54 -0
- package/examples/vite-wallet/package.json +46 -0
- package/examples/vite-wallet/public/.ic-assets.json5 +26 -0
- package/examples/vite-wallet/scripts/faucet-args.test.ts +30 -0
- package/examples/vite-wallet/scripts/faucet-args.ts +41 -0
- package/examples/vite-wallet/scripts/faucet.ts +41 -0
- package/examples/vite-wallet/src/AddressBook.test.tsx +191 -0
- package/examples/vite-wallet/src/AddressBook.tsx +147 -0
- package/examples/vite-wallet/src/App.tsx +53 -0
- package/examples/vite-wallet/src/Balance.test.tsx +57 -0
- package/examples/vite-wallet/src/Balance.tsx +58 -0
- package/examples/vite-wallet/src/EnvironmentPanel.test.tsx +83 -0
- package/examples/vite-wallet/src/EnvironmentPanel.tsx +103 -0
- package/examples/vite-wallet/src/ErrorNote.tsx +70 -0
- package/examples/vite-wallet/src/Profile.test.tsx +145 -0
- package/examples/vite-wallet/src/Profile.tsx +92 -0
- package/examples/vite-wallet/src/SendIcp.test.tsx +231 -0
- package/examples/vite-wallet/src/SendIcp.tsx +244 -0
- package/examples/vite-wallet/src/SendToContact.test.tsx +113 -0
- package/examples/vite-wallet/src/SendToContact.tsx +102 -0
- package/examples/vite-wallet/src/SignIn.test.tsx +106 -0
- package/examples/vite-wallet/src/SignIn.tsx +120 -0
- package/examples/vite-wallet/src/Wallet.test.tsx +89 -0
- package/examples/vite-wallet/src/account-switch.test.tsx +108 -0
- package/examples/vite-wallet/src/auth/dev-accounts.test.ts +113 -0
- package/examples/vite-wallet/src/auth/dev-accounts.ts +216 -0
- package/examples/vite-wallet/src/auth/local-page.test.ts +28 -0
- package/examples/vite-wallet/src/auth/local-page.ts +20 -0
- package/examples/vite-wallet/src/auth/wallet-auth.test.ts +159 -0
- package/examples/vite-wallet/src/auth/wallet-auth.ts +131 -0
- package/examples/vite-wallet/src/canisters/backend.envelope.json +275 -0
- package/examples/vite-wallet/src/canisters/backend.ts +58 -0
- package/examples/vite-wallet/src/canisters/ledger.envelope.json +451 -0
- package/examples/vite-wallet/src/canisters/ledger.ts +56 -0
- package/examples/vite-wallet/src/client.ts +45 -0
- package/examples/vite-wallet/src/main.tsx +18 -0
- package/examples/vite-wallet/src/optimistic-contacts.ts +113 -0
- package/examples/vite-wallet/src/refusal.ts +17 -0
- package/examples/vite-wallet/src/styles.css +282 -0
- package/examples/vite-wallet/src/test/test-wallet.tsx +322 -0
- package/examples/vite-wallet/src/token.ts +50 -0
- package/examples/vite-wallet/src/transfer.test.ts +178 -0
- package/examples/vite-wallet/src/transfer.ts +110 -0
- package/examples/vite-wallet/src/use-canisters.ts +49 -0
- package/examples/vite-wallet/tsconfig.json +19 -0
- package/examples/vite-wallet/vite.config.ts +47 -0
- package/examples/vite-wallet/vitest.config.ts +17 -0
- package/package.json +9 -4
- package/packages/core/.size-limit.js +47 -0
- package/packages/core/LICENSE +21 -0
- package/packages/core/README.md +84 -0
- package/packages/core/llms.txt +610 -0
- package/packages/core/package.json +89 -0
- package/packages/core/src/call.ts +961 -0
- package/packages/core/src/canister.ts +259 -0
- package/packages/core/src/client.ts +2061 -0
- package/packages/core/src/errors.ts +1079 -0
- package/packages/core/src/hydration.ts +239 -0
- package/packages/core/src/index.ts +23 -0
- package/packages/core/src/keys.ts +108 -0
- package/packages/core/src/management.ts +138 -0
- package/packages/core/src/network.ts +1020 -0
- package/packages/core/src/options.ts +1000 -0
- package/packages/core/src/runtime.ts +50 -0
- package/packages/core/src/testing/fake-replica.ts +1166 -0
- package/packages/core/src/testing/index.ts +16 -0
- package/packages/core/src/testing/test-auth.ts +340 -0
- package/packages/core/src/testing/test-client.ts +559 -0
- package/packages/core/src/types.ts +541 -0
- package/packages/core/src/units.ts +299 -0
- package/packages/core/src/version.ts +4 -0
- package/packages/core/tests/canister-helpers.ts +187 -0
- package/packages/core/tests/canister-id.test.ts +158 -0
- package/packages/core/tests/canister-unwrap.test.ts +94 -0
- package/packages/core/tests/canister.test-d.ts +406 -0
- package/packages/core/tests/canister.test.ts +1921 -0
- package/packages/core/tests/client-account-change.test.ts +131 -0
- package/packages/core/tests/client-agents.test.ts +402 -0
- package/packages/core/tests/client-auth-network.test.ts +719 -0
- package/packages/core/tests/client-disposed.test.ts +403 -0
- package/packages/core/tests/client-helpers.ts +136 -0
- package/packages/core/tests/client-hydration.test.ts +166 -0
- package/packages/core/tests/client-pinned.test.ts +626 -0
- package/packages/core/tests/client-session.test.ts +348 -0
- package/packages/core/tests/client.test-d.ts +181 -0
- package/packages/core/tests/client.test.ts +1162 -0
- package/packages/core/tests/encode.test.ts +171 -0
- package/packages/core/tests/env-canister-id.test.ts +666 -0
- package/packages/core/tests/env-cookie-copies.test.ts +182 -0
- package/packages/core/tests/error-guard.test.ts +222 -0
- package/packages/core/tests/errors.test-d.ts +280 -0
- package/packages/core/tests/errors.test.ts +1359 -0
- package/packages/core/tests/fixtures/README.md +28 -0
- package/packages/core/tests/fixtures/accounts.did +21 -0
- package/packages/core/tests/fixtures/accounts.envelope.json +367 -0
- package/packages/core/tests/fixtures/accounts.ts +26 -0
- package/packages/core/tests/fixtures/archive.did +31 -0
- package/packages/core/tests/fixtures/archive.envelope.json +259 -0
- package/packages/core/tests/fixtures/archive.ts +55 -0
- package/packages/core/tests/fixtures/icrc1.did +88 -0
- package/packages/core/tests/fixtures/icrc1.envelope.json +840 -0
- package/packages/core/tests/fixtures/icrc1.ts +78 -0
- package/packages/core/tests/fixtures/management.did +724 -0
- package/packages/core/tests/fixtures/management.envelope.json +4455 -0
- package/packages/core/tests/fixtures/management.ts +486 -0
- package/packages/core/tests/fixtures/shapes.did +33 -0
- package/packages/core/tests/fixtures/shapes.envelope.json +440 -0
- package/packages/core/tests/fixtures/shapes.ts +56 -0
- package/packages/core/tests/fixtures/skippable.did +15 -0
- package/packages/core/tests/fixtures/skippable.envelope.json +182 -0
- package/packages/core/tests/fixtures/skippable.ts +33 -0
- package/packages/core/tests/func.test.ts +154 -0
- package/packages/core/tests/identity-attributes.test.ts +214 -0
- package/packages/core/tests/keys.test.ts +289 -0
- package/packages/core/tests/management.test.ts +206 -0
- package/packages/core/tests/network-helpers.ts +121 -0
- package/packages/core/tests/network.test-d.ts +78 -0
- package/packages/core/tests/network.test.ts +1051 -0
- package/packages/core/tests/options.test.ts +1594 -0
- package/packages/core/tests/redirect-sign-in.test.ts +393 -0
- package/packages/core/tests/resend.test-d.ts +81 -0
- package/packages/core/tests/resend.test.ts +723 -0
- package/packages/core/tests/skip.test-d.ts +125 -0
- package/packages/core/tests/testing-entry.test.ts +73 -0
- package/packages/core/tests/testing-fake-replica.test.ts +1242 -0
- package/packages/core/tests/testing-test-auth.test-d.ts +84 -0
- package/packages/core/tests/testing-test-auth.test.ts +483 -0
- package/packages/core/tests/testing-test-client.test-d.ts +184 -0
- package/packages/core/tests/testing-test-client.test.ts +1272 -0
- package/packages/core/tests/time-realm.test.ts +63 -0
- package/packages/core/tests/time.test.ts +238 -0
- package/packages/core/tests/traps/README.md +39 -0
- package/packages/core/tests/traps/anonymous-write.test.ts +145 -0
- package/packages/core/tests/traps/classification-table.test.ts +256 -0
- package/packages/core/tests/traps/err-arm.test.ts +144 -0
- package/packages/core/tests/traps/fetch-spy.ts +39 -0
- package/packages/core/tests/traps/invalidation-after-write.test.ts +178 -0
- package/packages/core/tests/traps/ledger.ts +248 -0
- package/packages/core/tests/traps/root-key-off-local.test.ts +130 -0
- package/packages/core/tests/traps/stale-data-across-users.test.ts +173 -0
- package/packages/core/tests/traps/unresolved-name.test.ts +155 -0
- package/packages/core/tests/traps/update-as-query.test.ts +244 -0
- package/packages/core/tests/traps/update-not-resent.test.ts +126 -0
- package/packages/core/tests/traps/update-resent-when-never-delivered.test.ts +159 -0
- package/packages/core/tests/traps.test-d.ts +476 -0
- package/packages/core/tests/units.test-d.ts +118 -0
- package/packages/core/tests/units.test.ts +634 -0
- package/packages/core/tsconfig.json +19 -0
- package/packages/core/tsconfig.typecheck.json +16 -0
- package/packages/core/vitest.config.ts +13 -0
- package/packages/mcp/LICENSE +21 -0
- package/packages/mcp/README.md +189 -0
- package/packages/mcp/package.json +62 -0
- package/packages/mcp/src/candid/candid-text.test.ts +455 -0
- package/packages/mcp/src/candid/candid-text.ts +501 -0
- package/packages/mcp/src/candid/contract.test.ts +398 -0
- package/packages/mcp/src/candid/formats.ts +155 -0
- package/packages/mcp/src/candid/hex.ts +29 -0
- package/packages/mcp/src/candid/json-schema.test.ts +758 -0
- package/packages/mcp/src/candid/json-schema.ts +454 -0
- package/packages/mcp/src/candid/json.test.ts +1207 -0
- package/packages/mcp/src/candid/json.ts +1053 -0
- package/packages/mcp/src/candid/schema-walk.ts +189 -0
- package/packages/mcp/src/candid/type-text.test.ts +179 -0
- package/packages/mcp/src/candid/type-text.ts +238 -0
- package/packages/mcp/src/cli.ts +134 -0
- package/packages/mcp/src/identity.ts +188 -0
- package/packages/mcp/src/interface/cache.test.ts +48 -0
- package/packages/mcp/src/interface/cache.ts +68 -0
- package/packages/mcp/src/interface/cli-cache.test.ts +150 -0
- package/packages/mcp/src/interface/cli-cache.ts +122 -0
- package/packages/mcp/src/interface/compile-worker.test.ts +246 -0
- package/packages/mcp/src/interface/compile-worker.ts +290 -0
- package/packages/mcp/src/interface/compile.test.ts +155 -0
- package/packages/mcp/src/interface/compile.ts +281 -0
- package/packages/mcp/src/interface/docs.test.ts +105 -0
- package/packages/mcp/src/interface/docs.ts +86 -0
- package/packages/mcp/src/interface/fixtures/icrc1.did +88 -0
- package/packages/mcp/src/interface/hex.ts +8 -0
- package/packages/mcp/src/interface/ids.test.ts +71 -0
- package/packages/mcp/src/interface/ids.ts +87 -0
- package/packages/mcp/src/interface/loader.test.ts +804 -0
- package/packages/mcp/src/interface/loader.ts +519 -0
- package/packages/mcp/src/interface/read-candid.test.ts +300 -0
- package/packages/mcp/src/interface/read-candid.ts +259 -0
- package/packages/mcp/src/interface/types.ts +113 -0
- package/packages/mcp/src/network.ts +122 -0
- package/packages/mcp/src/options.ts +149 -0
- package/packages/mcp/src/server/approval.ts +159 -0
- package/packages/mcp/src/server/naming.ts +43 -0
- package/packages/mcp/src/server/results.ts +102 -0
- package/packages/mcp/src/server/server.ts +797 -0
- package/packages/mcp/src/server/tools.ts +116 -0
- package/packages/mcp/src/usage.ts +40 -0
- package/packages/mcp/tests/approval.test.ts +60 -0
- package/packages/mcp/tests/identity.test.ts +234 -0
- package/packages/mcp/tests/naming.test.ts +62 -0
- package/packages/mcp/tests/options.test.ts +140 -0
- package/packages/mcp/tests/server.test.ts +997 -0
- package/packages/mcp/tsconfig.json +19 -0
- package/packages/mcp/tsconfig.typecheck.json +10 -0
- package/packages/mcp/vitest.config.ts +10 -0
- package/packages/react/LICENSE +21 -0
- package/packages/react/README.md +328 -0
- package/packages/react/llms.txt +95 -0
- package/packages/react/package.json +95 -0
- package/packages/react/src/index.tsx +678 -0
- package/packages/react/tests/abandoned-render.test.tsx +816 -0
- package/packages/react/tests/auth.test.tsx +315 -0
- package/packages/react/tests/caller-keys.test.tsx +2334 -0
- package/packages/react/tests/client-time.test.ts +40 -0
- package/packages/react/tests/entry.test.ts +52 -0
- package/packages/react/tests/helpers.tsx +291 -0
- package/packages/react/tests/hydration.test.tsx +262 -0
- package/packages/react/tests/ownership.test.tsx +260 -0
- package/packages/react/tests/provider.server.test.tsx +169 -0
- package/packages/react/tests/query-client.test.tsx +107 -0
- package/packages/react/tests/strict-mode.test.tsx +288 -0
- package/packages/react/tests/suspense.test-d.tsx +357 -0
- package/packages/react/tests/two-query-cores.test.tsx +135 -0
- package/packages/react/tests/types.test-d.tsx +63 -0
- package/packages/react/tsconfig.json +23 -0
- package/packages/react/tsconfig.test.json +8 -0
- package/packages/react/tsconfig.typecheck.json +16 -0
- package/packages/react/vitest.config.ts +39 -0
- package/packages/vite-plugin/LICENSE +21 -0
- package/packages/vite-plugin/README.md +532 -0
- package/packages/vite-plugin/package.json +76 -0
- package/packages/vite-plugin/src/describe-value.test.ts +43 -0
- package/packages/vite-plugin/src/describe-value.ts +167 -0
- package/packages/vite-plugin/src/dev-environment.test.ts +747 -0
- package/packages/vite-plugin/src/dev-environment.ts +510 -0
- package/packages/vite-plugin/src/env.ts +431 -0
- package/packages/vite-plugin/src/fetch.ts +348 -0
- package/packages/vite-plugin/src/file-identity.ts +106 -0
- package/packages/vite-plugin/src/generate.ts +691 -0
- package/packages/vite-plugin/src/index.test.ts +1243 -0
- package/packages/vite-plugin/src/index.ts +2565 -0
- package/packages/vite-plugin/src/interface.ts +339 -0
- package/packages/vite-plugin/src/local-host.ts +34 -0
- package/packages/vite-plugin/src/options.ts +641 -0
- package/packages/vite-plugin/src/principal-text.test.ts +87 -0
- package/packages/vite-plugin/src/principal-text.ts +98 -0
- package/packages/vite-plugin/tests/close.test.ts +141 -0
- package/packages/vite-plugin/tests/environment-mode.test.ts +136 -0
- package/packages/vite-plugin/tests/fake-ic.ts +214 -0
- package/packages/vite-plugin/tests/fetch-sdk.test.ts +27 -0
- package/packages/vite-plugin/tests/fetch.test.ts +1196 -0
- package/packages/vite-plugin/tests/fixtures/fake-cli/bin.js +90 -0
- package/packages/vite-plugin/tests/fixtures/fake-cli/package.json +8 -0
- package/packages/vite-plugin/tests/fixtures/icrc1.did +88 -0
- package/packages/vite-plugin/tests/generation.test.ts +1036 -0
- package/packages/vite-plugin/tests/icp-command.test.ts +194 -0
- package/packages/vite-plugin/tests/icp-timeout.test.ts +83 -0
- package/packages/vite-plugin/tests/no-process-exit.test.ts +83 -0
- package/packages/vite-plugin/tests/on-generated.test.ts +323 -0
- package/packages/vite-plugin/tests/output-collision.test.ts +329 -0
- package/packages/vite-plugin/tests/package.test.ts +62 -0
- package/packages/vite-plugin/tests/project.test.ts +2993 -0
- package/packages/vite-plugin/tests/support.ts +339 -0
- package/packages/vite-plugin/tests/timeout.test.ts +107 -0
- package/packages/vite-plugin/tsconfig.json +23 -0
- package/packages/vite-plugin/tsconfig.typecheck.json +16 -0
- package/packages/vite-plugin/vitest.config.ts +9 -0
- package/pnpm-workspace.yaml +23 -0
- package/scripts/ai-context-files.js +72 -0
- package/scripts/assemble-docs-site.mjs +485 -0
- package/scripts/assemble-docs-site.test.mjs +568 -0
- package/scripts/build-examples.js +58 -0
- package/scripts/check-ai-context.js +963 -0
- package/scripts/check-ai-context.test.mjs +811 -0
- package/scripts/check-exports.mjs +767 -0
- package/scripts/check-exports.test.mjs +1136 -0
- package/scripts/check-snippets/ambient.d.ts +428 -0
- package/scripts/check-snippets/app/generated/backend.did +7 -0
- package/scripts/check-snippets/app/generated/backend.ts +15 -0
- package/scripts/check-snippets/app/generated/icrc1.did +88 -0
- package/scripts/check-snippets/app/generated/icrc1.ts +78 -0
- package/scripts/check-snippets/app/globals.ts +26 -0
- package/scripts/check-snippets/docs/guides/App.tsx +21 -0
- package/scripts/check-snippets/docs/guides/app/providers.tsx +23 -0
- package/scripts/check-snippets/docs/guides/auth-client.ts +47 -0
- package/scripts/check-snippets/docs/guides/canisters/backend.ts +3 -0
- package/scripts/check-snippets/docs/guides/canisters/icrc1.ts +3 -0
- package/scripts/check-snippets/docs/guides/components/LedgerCard.tsx +26 -0
- package/scripts/check-snippets/docs/guides/components/shell.tsx +11 -0
- package/scripts/check-snippets/docs/guides/components/sign-in-page.tsx +29 -0
- package/scripts/check-snippets/docs/guides/components/slow-section.tsx +5 -0
- package/scripts/check-snippets/docs/guides/generated/accounts.ts +95 -0
- package/scripts/check-snippets/docs/guides/generated/ckbtc_minter.ts +40 -0
- package/scripts/check-snippets/docs/guides/generated/icp_ledger.ts +267 -0
- package/scripts/check-snippets/docs/guides/ledger.ts +10 -0
- package/scripts/check-snippets/docs/guides/server/request-client.ts +8 -0
- package/scripts/check-snippets.mjs +993 -0
- package/scripts/check-snippets.test.mjs +338 -0
- package/scripts/check-stack.mjs +501 -0
- package/scripts/check-stack.test.mjs +800 -0
- package/scripts/clean-node-modules.js +67 -0
- package/scripts/example-projects.js +58 -0
- package/scripts/export-budget.mjs +145 -0
- package/scripts/faults.json +6749 -0
- package/scripts/lib/fault-workspace.mjs +210 -0
- package/scripts/lib/io.mjs +29 -0
- package/scripts/lib/io.test.mjs +38 -0
- package/scripts/lib/markdown-fences.mjs +56 -0
- package/scripts/lib/markdown-fences.test.mjs +84 -0
- package/scripts/lib/package-exports.mjs +54 -0
- package/scripts/lib/package-exports.test.mjs +66 -0
- package/scripts/lib/release-pr-steps.mjs +47 -0
- package/scripts/release-tag.mjs +95 -0
- package/scripts/release-tag.test.mjs +278 -0
- package/scripts/release-workflow.test.mjs +98 -0
- package/scripts/release.js +167 -0
- package/scripts/release.test.mjs +347 -0
- package/scripts/removed-v3-names.js +125 -0
- package/scripts/size-app/.size-limit.js +90 -0
- package/scripts/size-app/core.js +3 -0
- package/scripts/size-app/package.json +24 -0
- package/scripts/size-app/react.js +4 -0
- package/scripts/size-app.test.mjs +73 -0
- package/scripts/sync-ai-context-versions.js +102 -0
- package/scripts/sync-example-versions.js +151 -0
- package/scripts/test-examples-published.mjs +1585 -0
- package/scripts/test-examples-published.test.mjs +1586 -0
- package/scripts/traps/any-method-vars-not-a-list.json +5 -0
- package/scripts/traps/canister-method-unknown.json +5 -0
- package/scripts/traps/client-says-who-calls-once.json +5 -0
- package/scripts/traps/client-says-who-calls.json +5 -0
- package/scripts/traps/err-only-on-canister-err.json +14 -0
- package/scripts/traps/format-units-refuses-missing-value.json +5 -0
- package/scripts/traps/format-units-refuses-number.json +5 -0
- package/scripts/traps/format-units-unknown-option.json +5 -0
- package/scripts/traps/guard-err-is-the-methods.json +5 -0
- package/scripts/traps/guard-false-keeps-every-kind.json +5 -0
- package/scripts/traps/internals-not-exported.json +9 -0
- package/scripts/traps/network-refuses-unknown-name.json +5 -0
- package/scripts/traps/never-err-has-no-type.json +5 -0
- package/scripts/traps/options-method-unknown.json +5 -0
- package/scripts/traps/options-vars-wrong-type.json +5 -0
- package/scripts/traps/parse-units-refuses-number.json +5 -0
- package/scripts/traps/parse-units-unknown-option.json +5 -0
- package/scripts/traps/principal-is-not-plain-text.json +14 -0
- package/scripts/traps/query-options-refuses-oneway.json +5 -0
- package/scripts/traps/query-options-refuses-update.json +5 -0
- package/scripts/traps/refuse-next-unknown-option.json +5 -0
- package/scripts/traps/resend-key-reads-the-methods-arg.json +5 -0
- package/scripts/traps/resend-states-its-dedupe-key.json +5 -0
- package/scripts/traps/suspense-refuses-argument-skip.json +5 -0
- package/scripts/traps/suspense-refuses-skippable-read.json +5 -0
- package/scripts/traps/suspense-refuses-vars-skip-fits.json +5 -0
- package/scripts/traps/test-handler-method-unknown.json +5 -0
- package/scripts/traps/test-handler-nat-is-bigint.json +5 -0
- package/scripts/traps/test-handler-takes-the-domain-value.json +5 -0
- package/scripts/traps/vars-of-two-arguments-are-the-tuple.json +5 -0
- package/scripts/typecheck-examples.js +122 -0
- package/scripts/verify-faults.mjs +375 -0
- package/scripts/verify-faults.test.mjs +402 -0
- package/scripts/verify-package-artifacts.mjs +590 -0
- package/scripts/verify-peer-floors.js +399 -0
- package/scripts/verify-peer-floors.test.mjs +422 -0
- package/scripts/verify-test-fails-rules.mjs +104 -0
- package/scripts/verify-test-fails-rules.test.mjs +215 -0
- package/scripts/verify-test-fails.js +371 -0
- package/scripts/verify-traps.mjs +505 -0
- package/scripts/verify-traps.test.mjs +521 -0
- package/scripts/verify-typescript-floor.js +239 -0
- package/skill-packages/ic-reactor/SKILL.md +103 -0
- package/stack.json +8 -0
- package/tsconfig.base.json +23 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
// The MCP server: tools/list and tools/call over the interface loader and an
|
|
2
|
+
// ic-reactor client.
|
|
3
|
+
//
|
|
4
|
+
// Reads go out at once. A write (an update or a oneway) goes out only when
|
|
5
|
+
// all of these hold, and each refusal says which did not:
|
|
6
|
+
//
|
|
7
|
+
// - the server has an identity (`--identity`); the anonymous client refuses
|
|
8
|
+
// writes before sending them in any case;
|
|
9
|
+
// - the canister is listed with `--canister`, so the person chose it;
|
|
10
|
+
// - its interface is certified metadata or a .did the person gave, never the
|
|
11
|
+
// uncertified tmp hack: a call built from a replica's unproven answer could
|
|
12
|
+
// encode something other than what the person reads;
|
|
13
|
+
// - the client can show a form (MCP form elicitation), and the person ticks
|
|
14
|
+
// "Send this call" and accepts the call shown in full: canister, method,
|
|
15
|
+
// caller, network, the arguments as Candid text, and the sha256 of the
|
|
16
|
+
// bytes that are sent.
|
|
17
|
+
//
|
|
18
|
+
// A certified read goes out as the anonymous principal, never with the key.
|
|
19
|
+
// It is a replicated call, which the IC runs as whatever the canister's
|
|
20
|
+
// module exports under that name: the interface's `query` is the canister's
|
|
21
|
+
// own claim (or, for the tmp hack, one replica's), so a method it calls a
|
|
22
|
+
// query could be an update that would otherwise act as the caller unasked.
|
|
23
|
+
//
|
|
24
|
+
// One approval is asked at a time, and the call it approves holds the turn
|
|
25
|
+
// until it settles, so two writes never race each other.
|
|
26
|
+
import { createHash } from "node:crypto"
|
|
27
|
+
import type { Canister, Client } from "@ic-reactor/core"
|
|
28
|
+
import {
|
|
29
|
+
Server,
|
|
30
|
+
type CallToolResult,
|
|
31
|
+
type ServerContext,
|
|
32
|
+
type Tool,
|
|
33
|
+
} from "@modelcontextprotocol/server"
|
|
34
|
+
import { candidArgsText, candidName } from "../candid/candid-text.ts"
|
|
35
|
+
import {
|
|
36
|
+
DEFAULT_MAX_CHARS,
|
|
37
|
+
argsFromInput,
|
|
38
|
+
inputShape,
|
|
39
|
+
methodInput,
|
|
40
|
+
resultArms,
|
|
41
|
+
signatureText,
|
|
42
|
+
type InputIssue,
|
|
43
|
+
} from "../candid/json.ts"
|
|
44
|
+
import { checkCanisterId } from "../interface/ids.ts"
|
|
45
|
+
import type {
|
|
46
|
+
CanisterInterface,
|
|
47
|
+
InterfaceLoader,
|
|
48
|
+
LoadOptions,
|
|
49
|
+
LoadResult,
|
|
50
|
+
MethodInfo,
|
|
51
|
+
} from "../interface/types.ts"
|
|
52
|
+
import type { ListedCanister } from "../options.ts"
|
|
53
|
+
import {
|
|
54
|
+
APPROVAL_TIMEOUT_MS,
|
|
55
|
+
MAX_APPROVAL_ARGS_CHARS,
|
|
56
|
+
MAX_APPROVAL_METHOD_CHARS,
|
|
57
|
+
approvalMessage,
|
|
58
|
+
askApproval,
|
|
59
|
+
provenanceText,
|
|
60
|
+
} from "./approval.ts"
|
|
61
|
+
import { toolNames } from "./naming.ts"
|
|
62
|
+
import {
|
|
63
|
+
errorResult,
|
|
64
|
+
failureText,
|
|
65
|
+
jsonText,
|
|
66
|
+
replyJson,
|
|
67
|
+
textResult,
|
|
68
|
+
} from "./results.ts"
|
|
69
|
+
import {
|
|
70
|
+
CALL,
|
|
71
|
+
DESCRIBE_METHOD,
|
|
72
|
+
GENERIC_NAMES,
|
|
73
|
+
INSTRUCTIONS,
|
|
74
|
+
LIST_METHODS,
|
|
75
|
+
QUERY,
|
|
76
|
+
WHOAMI,
|
|
77
|
+
} from "./tools.ts"
|
|
78
|
+
|
|
79
|
+
export interface ServerDeps {
|
|
80
|
+
/** The client calls go through: `createClient`, or `createTestClient` in tests. */
|
|
81
|
+
readonly client: Client
|
|
82
|
+
/**
|
|
83
|
+
* An anonymous client (`identity: "anonymous"`), for certified reads only:
|
|
84
|
+
* a replicated call made with the key could run an update the interface
|
|
85
|
+
* calls a query, as the caller and without approval.
|
|
86
|
+
*/
|
|
87
|
+
readonly anonymousClient: Client
|
|
88
|
+
readonly loader: InterfaceLoader
|
|
89
|
+
/** The canisters named with `--canister`. */
|
|
90
|
+
readonly canisters: readonly ListedCanister[]
|
|
91
|
+
/** Where the caller's key came from, for a person to read. */
|
|
92
|
+
readonly callerSource: string
|
|
93
|
+
/** The network, for a person to read. */
|
|
94
|
+
readonly networkLabel: string
|
|
95
|
+
readonly version: string
|
|
96
|
+
readonly approvalTimeoutMs?: number
|
|
97
|
+
/** How long a read waits for its answer (default `READ_TIMEOUT_MS`). */
|
|
98
|
+
readonly readTimeoutMs?: number
|
|
99
|
+
/** How long an approved write waits for its answer (default `WRITE_TIMEOUT_MS`). */
|
|
100
|
+
readonly writeTimeoutMs?: number
|
|
101
|
+
/** A line for the person's log (stderr): never the protocol's stdout. */
|
|
102
|
+
readonly log?: (line: string) => void
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** How long a read (a query, or a certified read) waits for its answer. */
|
|
106
|
+
export const READ_TIMEOUT_MS = 60_000
|
|
107
|
+
/**
|
|
108
|
+
* How long an approved write waits for its answer: past the 5 minutes an
|
|
109
|
+
* ingress message may wait to be run, after which its outcome is unknown.
|
|
110
|
+
*/
|
|
111
|
+
export const WRITE_TIMEOUT_MS = 6 * 60_000
|
|
112
|
+
|
|
113
|
+
/** The longest signature one line of list_methods or a tool description shows. */
|
|
114
|
+
const MAX_SIGNATURE_CHARS = 600
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The most characters of typed tools one tools/list carries. Past it the
|
|
118
|
+
* remaining methods get no tool of their own; query and call still reach
|
|
119
|
+
* them. Mainnet's largest interfaces come to far less: Internet Identity's
|
|
120
|
+
* 127 methods to 139,447 characters of input schemas, the NNS governance
|
|
121
|
+
* canister's 33 to 116,108.
|
|
122
|
+
*/
|
|
123
|
+
const MAX_TYPED_TOOLS_CHARS = 1_000_000
|
|
124
|
+
/** What is left of `MAX_TYPED_TOOLS_CHARS` below which no more typed tools are listed. */
|
|
125
|
+
const MIN_TYPED_TOOL_CHARS = 4_000
|
|
126
|
+
|
|
127
|
+
type Method = (...args: unknown[]) => Promise<unknown>
|
|
128
|
+
/** A canister whose methods are known only at run time. */
|
|
129
|
+
type Actor = Record<string, Method>
|
|
130
|
+
|
|
131
|
+
const isWrite = (mode: MethodInfo["mode"]): mode is "update" | "oneway" =>
|
|
132
|
+
mode === "update" || mode === "oneway"
|
|
133
|
+
|
|
134
|
+
/** A canister to call: its id, and its `--canister` entry when it has one. */
|
|
135
|
+
interface Target {
|
|
136
|
+
readonly id: string
|
|
137
|
+
readonly listed: ListedCanister | undefined
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function createMcpServer(deps: ServerDeps): Server {
|
|
141
|
+
const log = deps.log ?? (() => {})
|
|
142
|
+
const server = new Server(
|
|
143
|
+
{ name: "ic-reactor-mcp", version: deps.version },
|
|
144
|
+
{
|
|
145
|
+
capabilities: { tools: { listChanged: true } },
|
|
146
|
+
instructions: INSTRUCTIONS,
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
/** The typed tools of the last tools/list: name to canister and method. */
|
|
151
|
+
let typed = new Map<string, { canister: ListedCanister; method: string }>()
|
|
152
|
+
/** A listed canister's interface id when its tools were last listed; null when it did not load. */
|
|
153
|
+
const listedFrom = new Map<string, string | null>()
|
|
154
|
+
let approving = false
|
|
155
|
+
|
|
156
|
+
const anonymous = (): boolean =>
|
|
157
|
+
deps.client.authState().status === "anonymous"
|
|
158
|
+
const canApprove = (): boolean =>
|
|
159
|
+
server.getClientCapabilities()?.elicitation?.form !== undefined
|
|
160
|
+
|
|
161
|
+
/** Why a write to this canister is not sent, or `undefined` when it can be. */
|
|
162
|
+
function writesOff(
|
|
163
|
+
listed: ListedCanister | undefined,
|
|
164
|
+
iface: CanisterInterface
|
|
165
|
+
): string | undefined {
|
|
166
|
+
if (anonymous()) {
|
|
167
|
+
return "this server calls as the anonymous principal; start it with --identity <pem file> to send updates"
|
|
168
|
+
}
|
|
169
|
+
if (listed === undefined) {
|
|
170
|
+
return `updates go only to canisters named with --canister, and ${iface.canisterId} is not one`
|
|
171
|
+
}
|
|
172
|
+
if (iface.provenance.kind === "tmp_hack") {
|
|
173
|
+
return `its interface came from ${provenanceText(iface.provenance)}, so no update is built from it; give its .did with --did ${listed.name}=<path>`
|
|
174
|
+
}
|
|
175
|
+
if (!canApprove()) {
|
|
176
|
+
return "this MCP client cannot show an approval form (MCP form elicitation), so no update can be approved"
|
|
177
|
+
}
|
|
178
|
+
return undefined
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Tells the client to list tools again when a listed canister's interface changed. */
|
|
182
|
+
function noteInterface(target: Target, result: LoadResult): void {
|
|
183
|
+
if (target.listed === undefined || !listedFrom.has(target.id)) return
|
|
184
|
+
const now = result.ok ? result.iface.interfaceId : null
|
|
185
|
+
if (listedFrom.get(target.id) === now) return
|
|
186
|
+
listedFrom.set(target.id, now)
|
|
187
|
+
server.sendToolListChanged().catch(() => {})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function listTools(): Promise<Tool[]> {
|
|
191
|
+
const loads = await Promise.all(
|
|
192
|
+
deps.canisters.map((canister) => deps.loader.load(canister.id))
|
|
193
|
+
)
|
|
194
|
+
const entries: { canister: ListedCanister; method: MethodInfo }[] = []
|
|
195
|
+
deps.canisters.forEach((canister, i) => {
|
|
196
|
+
const result = loads[i]
|
|
197
|
+
listedFrom.set(canister.id, result.ok ? result.iface.interfaceId : null)
|
|
198
|
+
if (!result.ok) {
|
|
199
|
+
log(`${canister.name} (${canister.id}): ${result.message}`)
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
const writable = writesOff(canister, result.iface) === undefined
|
|
203
|
+
for (const method of result.iface.methods.values()) {
|
|
204
|
+
if (isWrite(method.mode) && !writable) continue
|
|
205
|
+
// A name too long to show the person gets no tool of its own.
|
|
206
|
+
if (candidName(method.name).length > MAX_APPROVAL_METHOD_CHARS) continue
|
|
207
|
+
entries.push({ canister, method })
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
const names = toolNames(
|
|
211
|
+
entries.map(({ canister, method }) => ({
|
|
212
|
+
canister: canister.name,
|
|
213
|
+
method: method.name,
|
|
214
|
+
})),
|
|
215
|
+
GENERIC_NAMES
|
|
216
|
+
)
|
|
217
|
+
const next = new Map<string, { canister: ListedCanister; method: string }>()
|
|
218
|
+
const tools = [WHOAMI, LIST_METHODS, DESCRIBE_METHOD, QUERY]
|
|
219
|
+
if (!anonymous() && canApprove() && deps.canisters.length > 0) {
|
|
220
|
+
tools.push(CALL)
|
|
221
|
+
}
|
|
222
|
+
let left = MAX_TYPED_TOOLS_CHARS
|
|
223
|
+
let leftOut = 0
|
|
224
|
+
entries.forEach(({ canister, method }, i) => {
|
|
225
|
+
if (left < MIN_TYPED_TOOL_CHARS) {
|
|
226
|
+
leftOut++
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
const tool = typedTool(names[i], canister, method, left)
|
|
230
|
+
left -= JSON.stringify(tool).length
|
|
231
|
+
next.set(names[i], { canister, method: method.name })
|
|
232
|
+
tools.push(tool)
|
|
233
|
+
})
|
|
234
|
+
if (leftOut > 0) {
|
|
235
|
+
log(
|
|
236
|
+
`${leftOut} methods got no tool of their own: the tools of the listed canisters reached ${MAX_TYPED_TOOLS_CHARS.toLocaleString("en-US")} characters. query and call still reach them.`
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
typed = next
|
|
240
|
+
return tools
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function callTool(
|
|
244
|
+
name: string,
|
|
245
|
+
input: Record<string, unknown>,
|
|
246
|
+
ctx: ServerContext
|
|
247
|
+
): Promise<CallToolResult> {
|
|
248
|
+
switch (name) {
|
|
249
|
+
case WHOAMI.name:
|
|
250
|
+
return whoami()
|
|
251
|
+
case LIST_METHODS.name: {
|
|
252
|
+
const read = readInput(input, { canister: "string" })
|
|
253
|
+
if (!read.ok) return errorResult(read.message)
|
|
254
|
+
return listMethods(read.values.canister as string)
|
|
255
|
+
}
|
|
256
|
+
case DESCRIBE_METHOD.name: {
|
|
257
|
+
const read = readInput(input, { canister: "string", method: "string" })
|
|
258
|
+
if (!read.ok) return errorResult(read.message)
|
|
259
|
+
return describeMethod(
|
|
260
|
+
read.values.canister as string,
|
|
261
|
+
read.values.method as string
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
case QUERY.name:
|
|
265
|
+
case CALL.name: {
|
|
266
|
+
const read = readInput(
|
|
267
|
+
input,
|
|
268
|
+
name === QUERY.name
|
|
269
|
+
? {
|
|
270
|
+
canister: "string",
|
|
271
|
+
method: "string",
|
|
272
|
+
args: "object?",
|
|
273
|
+
certified: "boolean?",
|
|
274
|
+
}
|
|
275
|
+
: { canister: "string", method: "string", args: "object?" }
|
|
276
|
+
)
|
|
277
|
+
if (!read.ok) return errorResult(read.message)
|
|
278
|
+
const target = targetOf(read.values.canister as string)
|
|
279
|
+
if (typeof target === "string") return errorResult(target)
|
|
280
|
+
return run(
|
|
281
|
+
target,
|
|
282
|
+
read.values.method as string,
|
|
283
|
+
read.values.args ?? {},
|
|
284
|
+
{
|
|
285
|
+
tool: name === QUERY.name ? "query" : "call",
|
|
286
|
+
certified: read.values.certified === true,
|
|
287
|
+
},
|
|
288
|
+
ctx
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (!typed.has(name)) await listTools()
|
|
293
|
+
const entry = typed.get(name)
|
|
294
|
+
if (entry === undefined) {
|
|
295
|
+
return errorResult(
|
|
296
|
+
`There is no tool ${name}. list_methods shows a canister's methods, and query and call run them.`
|
|
297
|
+
)
|
|
298
|
+
}
|
|
299
|
+
return run(
|
|
300
|
+
{ id: entry.canister.id, listed: entry.canister },
|
|
301
|
+
entry.method,
|
|
302
|
+
input,
|
|
303
|
+
{ tool: "typed", certified: false },
|
|
304
|
+
ctx
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** A listed name or a canister id; a string is the reason it is neither. */
|
|
309
|
+
function targetOf(text: string): Target | string {
|
|
310
|
+
const trimmed = text.trim()
|
|
311
|
+
const byName = deps.canisters.find((canister) => canister.name === trimmed)
|
|
312
|
+
if (byName !== undefined) return { id: byName.id, listed: byName }
|
|
313
|
+
// Principal text is lower case; its checksum still decides.
|
|
314
|
+
const checked = checkCanisterId(trimmed.toLowerCase())
|
|
315
|
+
if (!checked.ok) return checked.message
|
|
316
|
+
return {
|
|
317
|
+
id: checked.id,
|
|
318
|
+
listed: deps.canisters.find((canister) => canister.id === checked.id),
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function load(
|
|
323
|
+
target: Target,
|
|
324
|
+
options?: LoadOptions
|
|
325
|
+
): Promise<
|
|
326
|
+
{ ok: true; iface: CanisterInterface } | { ok: false; text: string }
|
|
327
|
+
> {
|
|
328
|
+
const result = await deps.loader.load(target.id, options)
|
|
329
|
+
noteInterface(target, result)
|
|
330
|
+
if (result.ok) return result
|
|
331
|
+
const lines = [
|
|
332
|
+
`Could not read the interface of ${target.id}: ${result.message}`,
|
|
333
|
+
]
|
|
334
|
+
for (const diagnostic of result.diagnostics ?? []) {
|
|
335
|
+
lines.push(`- ${diagnostic.code}: ${diagnostic.message}`)
|
|
336
|
+
}
|
|
337
|
+
return { ok: false, text: lines.join("\n") }
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function run(
|
|
341
|
+
target: Target,
|
|
342
|
+
methodName: string,
|
|
343
|
+
argsInput: unknown,
|
|
344
|
+
how: {
|
|
345
|
+
readonly tool: "query" | "call" | "typed"
|
|
346
|
+
readonly certified: boolean
|
|
347
|
+
},
|
|
348
|
+
ctx: ServerContext
|
|
349
|
+
): Promise<CallToolResult> {
|
|
350
|
+
const loaded = await load(target)
|
|
351
|
+
if (!loaded.ok) return errorResult(loaded.text)
|
|
352
|
+
let { iface } = loaded
|
|
353
|
+
let method = iface.methods.get(methodName)
|
|
354
|
+
if (method === undefined)
|
|
355
|
+
return errorResult(noMethodText(iface, methodName))
|
|
356
|
+
const write = isWrite(method.mode)
|
|
357
|
+
if (write && how.tool !== "query") {
|
|
358
|
+
// A write is built from the interface of the module installed now, not
|
|
359
|
+
// from a cache that may predate an upgrade.
|
|
360
|
+
const confirmed = await load(target, { fresh: true })
|
|
361
|
+
if (!confirmed.ok) return errorResult(`Not sent. ${confirmed.text}`)
|
|
362
|
+
iface = confirmed.iface
|
|
363
|
+
method = iface.methods.get(methodName)
|
|
364
|
+
if (method === undefined || !isWrite(method.mode)) {
|
|
365
|
+
return errorResult(
|
|
366
|
+
`Not sent: the canister was upgraded, and ${candidName(methodName)} is no longer the update it was. list_methods shows its methods now.`
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (write && how.tool === "query") {
|
|
371
|
+
return errorResult(
|
|
372
|
+
`${candidName(methodName)} is ${method.mode === "oneway" ? "a oneway method" : "an update"}: the query tool runs only queries. Use call, which asks the person to approve it.`
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
if (how.certified && method.mode === "composite_query") {
|
|
376
|
+
return errorResult(
|
|
377
|
+
`${candidName(methodName)} is a composite query, which has no certified path: run it with certified: false.`
|
|
378
|
+
)
|
|
379
|
+
}
|
|
380
|
+
if (how.certified) {
|
|
381
|
+
// A certified reply is read with the interface of the module installed
|
|
382
|
+
// now, and never with one a replica answered unproven.
|
|
383
|
+
const confirmed = await load(target, { fresh: true })
|
|
384
|
+
if (!confirmed.ok) return errorResult(confirmed.text)
|
|
385
|
+
iface = confirmed.iface
|
|
386
|
+
method = iface.methods.get(methodName)
|
|
387
|
+
if (method === undefined || method.mode !== "query") {
|
|
388
|
+
return errorResult(
|
|
389
|
+
`The canister was upgraded, and ${candidName(methodName)} is no longer the query it was. list_methods shows its methods now.`
|
|
390
|
+
)
|
|
391
|
+
}
|
|
392
|
+
if (iface.provenance.kind === "tmp_hack") {
|
|
393
|
+
return errorResult(
|
|
394
|
+
`A certified read needs an interface that is certified too, and this canister's came from ${provenanceText(iface.provenance)}. Run it with certified: false${target.listed === undefined ? "" : `, or give its .did with --did ${target.listed.name}=<path>`}.`
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const off = write ? writesOff(target.listed, iface) : undefined
|
|
400
|
+
if (off !== undefined) return errorResult(`Not sent: ${off}.`)
|
|
401
|
+
|
|
402
|
+
const shape = inputShape(method.args)
|
|
403
|
+
const converted = argsFromInput(method.args, shape, argsInput)
|
|
404
|
+
if (!converted.ok)
|
|
405
|
+
return errorResult(issuesText(methodName, converted.issues))
|
|
406
|
+
const { values } = converted
|
|
407
|
+
|
|
408
|
+
// A certified read is a replicated call: made as the anonymous principal,
|
|
409
|
+
// whatever the method turns out to be, it cannot act as the caller.
|
|
410
|
+
const through = !write && how.certified ? deps.anonymousClient : deps.client
|
|
411
|
+
const canister = through.canister<Actor>(iface.actor, {
|
|
412
|
+
id: iface.canisterId,
|
|
413
|
+
certified: how.certified,
|
|
414
|
+
timeoutMs: write
|
|
415
|
+
? (deps.writeTimeoutMs ?? WRITE_TIMEOUT_MS)
|
|
416
|
+
: (deps.readTimeoutMs ?? READ_TIMEOUT_MS),
|
|
417
|
+
})
|
|
418
|
+
const arms = resultArms(method.results)
|
|
419
|
+
if (!write) {
|
|
420
|
+
try {
|
|
421
|
+
const reply = await methodOf(canister, method.name)(...values)
|
|
422
|
+
const json = jsonText(replyJson(method.results, arms?.ok, reply))
|
|
423
|
+
return textResult(
|
|
424
|
+
arms === undefined ? json : `The canister answered Ok:\n${json}`
|
|
425
|
+
)
|
|
426
|
+
} catch (error) {
|
|
427
|
+
return errorResult(failureText(error, false, arms?.err))
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (approving) {
|
|
432
|
+
return errorResult(
|
|
433
|
+
"Not sent: another update is waiting for the person's approval or still running. Wait for its answer, then try again."
|
|
434
|
+
)
|
|
435
|
+
}
|
|
436
|
+
approving = true
|
|
437
|
+
try {
|
|
438
|
+
return await sendWrite({ target, iface, method, values, canister, ctx })
|
|
439
|
+
} finally {
|
|
440
|
+
approving = false
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async function sendWrite({
|
|
445
|
+
target,
|
|
446
|
+
iface,
|
|
447
|
+
method,
|
|
448
|
+
values,
|
|
449
|
+
canister,
|
|
450
|
+
ctx,
|
|
451
|
+
}: {
|
|
452
|
+
readonly target: Target
|
|
453
|
+
readonly iface: CanisterInterface
|
|
454
|
+
readonly method: MethodInfo
|
|
455
|
+
readonly values: unknown[]
|
|
456
|
+
readonly canister: Canister<Actor>
|
|
457
|
+
readonly ctx: ServerContext
|
|
458
|
+
}): Promise<CallToolResult> {
|
|
459
|
+
const arms = resultArms(method.results)
|
|
460
|
+
// The bytes the call path itself encodes: the value for one argument,
|
|
461
|
+
// the tuple for several, nothing for none.
|
|
462
|
+
const vars =
|
|
463
|
+
values.length === 0 ? undefined : values.length === 1 ? values[0] : values
|
|
464
|
+
let bytes: Uint8Array
|
|
465
|
+
try {
|
|
466
|
+
bytes = deps.client.encode(canister, method.name, vars as never)
|
|
467
|
+
} catch (error) {
|
|
468
|
+
return errorResult(failureText(error, false, undefined))
|
|
469
|
+
}
|
|
470
|
+
const shownName = candidName(method.name)
|
|
471
|
+
if (shownName.length > MAX_APPROVAL_METHOD_CHARS) {
|
|
472
|
+
return errorResult(
|
|
473
|
+
`Not sent: the method's name is ${shownName.length} characters long as Candid, too long to show the person for approval (at most ${MAX_APPROVAL_METHOD_CHARS}).`
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
const argsText = candidArgsText(method.args, values, { width: 72 })
|
|
477
|
+
if (argsText.length > MAX_APPROVAL_ARGS_CHARS) {
|
|
478
|
+
return errorResult(
|
|
479
|
+
`Not sent: the arguments are ${argsText.length} characters of Candid, too long to show the person for approval (at most ${MAX_APPROVAL_ARGS_CHARS}).`
|
|
480
|
+
)
|
|
481
|
+
}
|
|
482
|
+
const sha256 = createHash("sha256").update(bytes).digest("hex")
|
|
483
|
+
const oneway = method.mode === "oneway"
|
|
484
|
+
const message = approvalMessage({
|
|
485
|
+
canisterId: iface.canisterId,
|
|
486
|
+
canisterName: target.listed?.name,
|
|
487
|
+
method: method.name,
|
|
488
|
+
mode: oneway ? "oneway" : "update",
|
|
489
|
+
caller: deps.client.caller(),
|
|
490
|
+
callerSource: deps.callerSource,
|
|
491
|
+
network: deps.networkLabel,
|
|
492
|
+
argsText,
|
|
493
|
+
argBytes: bytes.length,
|
|
494
|
+
argSha256: sha256,
|
|
495
|
+
provenance: iface.provenance,
|
|
496
|
+
})
|
|
497
|
+
const what = `${candidName(method.name)} on ${iface.canisterId} (arguments sha256 ${sha256})`
|
|
498
|
+
log(`asking the person to approve ${what}`)
|
|
499
|
+
const outcome = await askApproval(
|
|
500
|
+
ctx,
|
|
501
|
+
message,
|
|
502
|
+
deps.approvalTimeoutMs ?? APPROVAL_TIMEOUT_MS
|
|
503
|
+
)
|
|
504
|
+
if (!outcome.approved) {
|
|
505
|
+
log(`not sent: ${what}: ${outcome.reason}`)
|
|
506
|
+
return errorResult(
|
|
507
|
+
`Not sent: ${outcome.reason}. Do not send it again unless the person asks you to.`
|
|
508
|
+
)
|
|
509
|
+
}
|
|
510
|
+
// The form named the module (or .did file) the call was built for. The
|
|
511
|
+
// person may have taken minutes: confirm it is still the one installed,
|
|
512
|
+
// as an upgrade in between could read the same bytes differently.
|
|
513
|
+
const now = await load(target, { fresh: true })
|
|
514
|
+
if (!now.ok) {
|
|
515
|
+
log(`not sent: ${what}: the interface could not be confirmed again`)
|
|
516
|
+
return errorResult(
|
|
517
|
+
`Not sent: the person approved it, but the canister's interface could not be confirmed again before sending. ${now.text}`
|
|
518
|
+
)
|
|
519
|
+
}
|
|
520
|
+
if (!sameInterface(iface, now.iface)) {
|
|
521
|
+
log(`not sent: ${what}: the canister changed while the person decided`)
|
|
522
|
+
return errorResult(
|
|
523
|
+
"Not sent: the canister was upgraded (or its .did file changed) while the person was deciding, so the call they approved was built for an interface that is no longer the one in use. Ask them before you try again."
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
if (ctx.mcpReq.signal.aborted) {
|
|
527
|
+
log(`not sent: ${what}: the tool call was cancelled`)
|
|
528
|
+
return errorResult("Not sent: the tool call was cancelled.")
|
|
529
|
+
}
|
|
530
|
+
log(`approved; sending ${what}`)
|
|
531
|
+
try {
|
|
532
|
+
const reply = await methodOf(canister, method.name)(...values)
|
|
533
|
+
log(`sent ${what}`)
|
|
534
|
+
if (oneway) {
|
|
535
|
+
return textResult(
|
|
536
|
+
"Approved and sent. A oneway method sends no reply, so whether it ran is not known."
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
return textResult(
|
|
540
|
+
`Approved and sent. The canister answered${arms === undefined ? "" : " Ok"}:\n${jsonText(replyJson(method.results, arms?.ok, reply))}`
|
|
541
|
+
)
|
|
542
|
+
} catch (error) {
|
|
543
|
+
log(`failed: ${what}`)
|
|
544
|
+
return errorResult(failureText(error, true, arms?.err))
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function whoami(): CallToolResult {
|
|
549
|
+
const lines = [
|
|
550
|
+
`Caller: ${deps.client.caller()}, ${deps.callerSource}`,
|
|
551
|
+
...(anonymous()
|
|
552
|
+
? []
|
|
553
|
+
: [
|
|
554
|
+
"Certified reads (query with certified: true) go out as the anonymous principal, never with the key.",
|
|
555
|
+
]),
|
|
556
|
+
`Network: ${deps.networkLabel}`,
|
|
557
|
+
canApprove()
|
|
558
|
+
? "Approvals: this client can show the approval form, so an update can be sent once the person approves it."
|
|
559
|
+
: "Approvals: this client cannot show an approval form (MCP form elicitation), so no update can be sent.",
|
|
560
|
+
]
|
|
561
|
+
if (deps.canisters.length === 0) {
|
|
562
|
+
lines.push(
|
|
563
|
+
"Listed canisters: none. Queries work on any canister; updates need one named with --canister <name>=<id>."
|
|
564
|
+
)
|
|
565
|
+
} else {
|
|
566
|
+
lines.push(
|
|
567
|
+
"Listed canisters (their methods have tools, and they take updates):"
|
|
568
|
+
)
|
|
569
|
+
for (const canister of deps.canisters) {
|
|
570
|
+
lines.push(`- ${canister.name}: ${canister.id}`)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return textResult(lines.join("\n"))
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
async function listMethods(canisterText: string): Promise<CallToolResult> {
|
|
577
|
+
const target = targetOf(canisterText)
|
|
578
|
+
if (typeof target === "string") return errorResult(target)
|
|
579
|
+
const loaded = await load(target)
|
|
580
|
+
if (!loaded.ok) return errorResult(loaded.text)
|
|
581
|
+
const { iface } = loaded
|
|
582
|
+
const off = writesOff(target.listed, iface)
|
|
583
|
+
const lines = [
|
|
584
|
+
`Canister ${iface.canisterId}${target.listed === undefined ? "" : ` (${target.listed.name})`}`,
|
|
585
|
+
`Interface: ${provenanceText(iface.provenance)}`,
|
|
586
|
+
`Interface id: ${iface.interfaceId}`,
|
|
587
|
+
off === undefined
|
|
588
|
+
? "Updates: each is sent once the person approves it."
|
|
589
|
+
: `Updates: not sent, as ${off}.`,
|
|
590
|
+
"",
|
|
591
|
+
`${iface.methods.size} methods, in Candid (a method not marked query or composite_query is an update):`,
|
|
592
|
+
]
|
|
593
|
+
for (const method of iface.methods.values()) {
|
|
594
|
+
lines.push(
|
|
595
|
+
`- ${candidName(method.name)} : ${signatureText(method, { maxChars: MAX_SIGNATURE_CHARS })}`
|
|
596
|
+
)
|
|
597
|
+
}
|
|
598
|
+
if (iface.omitted.length > 0) {
|
|
599
|
+
lines.push("", "Left out, as the schema loader cannot use them:")
|
|
600
|
+
for (const omitted of iface.omitted) {
|
|
601
|
+
lines.push(`- ${omitted.kind} ${omitted.name}: ${omitted.reason}`)
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return textResult(lines.join("\n"))
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
async function describeMethod(
|
|
608
|
+
canisterText: string,
|
|
609
|
+
methodName: string
|
|
610
|
+
): Promise<CallToolResult> {
|
|
611
|
+
const target = targetOf(canisterText)
|
|
612
|
+
if (typeof target === "string") return errorResult(target)
|
|
613
|
+
const loaded = await load(target)
|
|
614
|
+
if (!loaded.ok) return errorResult(loaded.text)
|
|
615
|
+
const { iface } = loaded
|
|
616
|
+
const method = iface.methods.get(methodName)
|
|
617
|
+
if (method === undefined)
|
|
618
|
+
return errorResult(noMethodText(iface, methodName))
|
|
619
|
+
const input = methodInput(method.args)
|
|
620
|
+
const did = await deps.loader.methodDid(iface, method.name)
|
|
621
|
+
const lines = [
|
|
622
|
+
`${candidName(method.name)}: ${method.mode} method of ${iface.canisterId}${target.listed === undefined ? "" : ` (${target.listed.name})`}`,
|
|
623
|
+
]
|
|
624
|
+
if (isWrite(method.mode)) {
|
|
625
|
+
const off = writesOff(target.listed, iface)
|
|
626
|
+
lines.push(
|
|
627
|
+
off === undefined
|
|
628
|
+
? "Sent with call once the person approves it."
|
|
629
|
+
: `Not sent, as ${off}.`
|
|
630
|
+
)
|
|
631
|
+
}
|
|
632
|
+
if (method.doc !== undefined) {
|
|
633
|
+
lines.push(
|
|
634
|
+
"",
|
|
635
|
+
"Its doc comment, written by the canister's authors:",
|
|
636
|
+
method.doc
|
|
637
|
+
)
|
|
638
|
+
}
|
|
639
|
+
lines.push(
|
|
640
|
+
"",
|
|
641
|
+
"Candid (the method and every type it uses):",
|
|
642
|
+
did.ok ? did.did : `(not available: ${did.message})`,
|
|
643
|
+
"",
|
|
644
|
+
`The args object (${shapeText(input.shape)}), as JSON Schema${input.complete ? "" : ", shortened where it was too large; the Candid above is complete"}:`,
|
|
645
|
+
JSON.stringify(input.schema, null, 2)
|
|
646
|
+
)
|
|
647
|
+
return textResult(lines.join("\n"))
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function typedTool(
|
|
651
|
+
name: string,
|
|
652
|
+
canister: ListedCanister,
|
|
653
|
+
method: MethodInfo,
|
|
654
|
+
maxChars: number
|
|
655
|
+
): Tool {
|
|
656
|
+
const input = methodInput(method.args, {
|
|
657
|
+
maxChars: Math.min(DEFAULT_MAX_CHARS, maxChars),
|
|
658
|
+
})
|
|
659
|
+
const write = isWrite(method.mode)
|
|
660
|
+
const lines = [
|
|
661
|
+
write
|
|
662
|
+
? `Update ${candidName(method.name)} of canister ${canister.name} (${canister.id}). It is sent only after the person approves this exact call in the client; if they decline, nothing is sent.`
|
|
663
|
+
: `Query ${candidName(method.name)} of canister ${canister.name} (${canister.id}). It runs at once and changes nothing.`,
|
|
664
|
+
`Candid: ${signatureText(method, { maxChars: MAX_SIGNATURE_CHARS })}`,
|
|
665
|
+
]
|
|
666
|
+
if (!input.complete) {
|
|
667
|
+
lines.push(
|
|
668
|
+
"The input schema is shortened; describe_method shows the method's whole Candid."
|
|
669
|
+
)
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
name,
|
|
673
|
+
title: `${canister.name}: ${candidName(method.name)}`,
|
|
674
|
+
description: lines.join("\n"),
|
|
675
|
+
inputSchema: input.schema as Tool["inputSchema"],
|
|
676
|
+
annotations: write
|
|
677
|
+
? {
|
|
678
|
+
readOnlyHint: false,
|
|
679
|
+
destructiveHint: true,
|
|
680
|
+
idempotentHint: false,
|
|
681
|
+
openWorldHint: true,
|
|
682
|
+
}
|
|
683
|
+
: { readOnlyHint: true, openWorldHint: true },
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
server.setRequestHandler("tools/list", async () => ({
|
|
688
|
+
tools: await listTools(),
|
|
689
|
+
}))
|
|
690
|
+
server.setRequestHandler("tools/call", async (request, ctx) => {
|
|
691
|
+
const { name, arguments: input } = request.params
|
|
692
|
+
try {
|
|
693
|
+
return await callTool(name, input ?? {}, ctx)
|
|
694
|
+
} catch (error) {
|
|
695
|
+
log(
|
|
696
|
+
`tool ${name} failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`
|
|
697
|
+
)
|
|
698
|
+
return errorResult(
|
|
699
|
+
`The server failed to run ${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
700
|
+
)
|
|
701
|
+
}
|
|
702
|
+
})
|
|
703
|
+
return server
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/** A canister method as an own property, never one of Object.prototype's. */
|
|
707
|
+
function methodOf(canister: object, name: string): Method {
|
|
708
|
+
const descriptor = Object.getOwnPropertyDescriptor(canister, name)
|
|
709
|
+
if (typeof descriptor?.value !== "function") {
|
|
710
|
+
throw new Error(`the client has no method ${name} for this canister`)
|
|
711
|
+
}
|
|
712
|
+
return descriptor.value as Method
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function noMethodText(iface: CanisterInterface, name: string): string {
|
|
716
|
+
const omitted = iface.omitted.find(
|
|
717
|
+
(entry) => entry.kind === "method" && entry.name === name
|
|
718
|
+
)
|
|
719
|
+
if (omitted !== undefined) {
|
|
720
|
+
return `${name} cannot be called here: ${omitted.reason}.`
|
|
721
|
+
}
|
|
722
|
+
const names = [...iface.methods.keys()]
|
|
723
|
+
const shown = names.slice(0, 40).join(", ")
|
|
724
|
+
return `${iface.canisterId} has no method ${name}. Its ${names.length} methods: ${shown}${names.length > 40 ? ", …" : ""}.`
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function issuesText(method: string, issues: readonly InputIssue[]): string {
|
|
728
|
+
const shown = issues
|
|
729
|
+
.slice(0, 20)
|
|
730
|
+
.map((issue) => `- ${issue.path}: ${issue.message}`)
|
|
731
|
+
if (issues.length > 20) shown.push(`- … and ${issues.length - 20} more`)
|
|
732
|
+
return `Not sent: the arguments of ${method} do not fit its Candid types:\n${shown.join("\n")}\ndescribe_method shows what each one takes.`
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/** The same interface, read from the same module or file, as when the person was asked. */
|
|
736
|
+
function sameInterface(
|
|
737
|
+
before: CanisterInterface,
|
|
738
|
+
after: CanisterInterface
|
|
739
|
+
): boolean {
|
|
740
|
+
return (
|
|
741
|
+
before.interfaceId === after.interfaceId &&
|
|
742
|
+
before.provenance.kind === after.provenance.kind &&
|
|
743
|
+
moduleHashOf(before) === moduleHashOf(after)
|
|
744
|
+
)
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function moduleHashOf(iface: CanisterInterface): string | null {
|
|
748
|
+
return iface.provenance.kind === "file" ? null : iface.provenance.moduleHash
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
function shapeText(shape: ReturnType<typeof methodInput>["shape"]): string {
|
|
752
|
+
switch (shape.kind) {
|
|
753
|
+
case "none":
|
|
754
|
+
return "the method takes no arguments: {}"
|
|
755
|
+
case "fields":
|
|
756
|
+
return "the fields of its one record argument"
|
|
757
|
+
case "positional":
|
|
758
|
+
return shape.count === 1
|
|
759
|
+
? "its one argument as arg0"
|
|
760
|
+
: `its ${shape.count} arguments as arg0 to arg${shape.count - 1}`
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
type Expect = "string" | "object?" | "boolean?"
|
|
765
|
+
|
|
766
|
+
/** The generic tools' own inputs, checked before anything is read. */
|
|
767
|
+
function readInput(
|
|
768
|
+
input: Record<string, unknown>,
|
|
769
|
+
spec: Record<string, Expect>
|
|
770
|
+
):
|
|
771
|
+
| { ok: true; values: Record<string, unknown> }
|
|
772
|
+
| { ok: false; message: string } {
|
|
773
|
+
for (const key of Object.keys(input)) {
|
|
774
|
+
if (!Object.hasOwn(spec, key)) {
|
|
775
|
+
return {
|
|
776
|
+
ok: false,
|
|
777
|
+
message: `Unknown input ${JSON.stringify(key)}: this tool takes ${Object.keys(spec).join(", ")}. A method's own arguments go in args.`,
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
const values: Record<string, unknown> = {}
|
|
782
|
+
for (const [key, expect] of Object.entries(spec)) {
|
|
783
|
+
const value = Object.hasOwn(input, key) ? input[key] : undefined
|
|
784
|
+
const optional = expect.endsWith("?")
|
|
785
|
+
if (value === undefined || value === null) {
|
|
786
|
+
if (!optional) return { ok: false, message: `${key} is required.` }
|
|
787
|
+
continue
|
|
788
|
+
}
|
|
789
|
+
const type = expect.replace("?", "")
|
|
790
|
+
const actual = Array.isArray(value) ? "array" : typeof value
|
|
791
|
+
if (actual !== type) {
|
|
792
|
+
return { ok: false, message: `${key} is a ${type}, got ${actual}.` }
|
|
793
|
+
}
|
|
794
|
+
values[key] = value
|
|
795
|
+
}
|
|
796
|
+
return { ok: true, values }
|
|
797
|
+
}
|