@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
package/evals/drive.mjs
ADDED
|
@@ -0,0 +1,1221 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Run driver for the agent matrix. NOT EXECUTED by the harness author: the
|
|
3
|
+
// matrix needs a budget decision. `--dry-run` prints the plan.
|
|
4
|
+
//
|
|
5
|
+
// node evals/drive.mjs --n 20 --model <model> [--task t]... [--condition c]...
|
|
6
|
+
// [--jobs 4] [--timeout-min 30] [--max-turns 60] [--seed 1]
|
|
7
|
+
// [--prompt explicit|minimal] [--effort <level>] [--oauth-token-file <f>]
|
|
8
|
+
// [--mode sandboxed|tsc-only] [--sandbox-allow <dir>]... [--agent-cmd <tpl>]
|
|
9
|
+
// [--retries 2] [--out <dir>] [--resume <dir>] [--pilot] [--margin 0.1] [--dry-run]
|
|
10
|
+
// node evals/drive.mjs --aggregate <results dir> [--rescan] [--rescore] [--pilot] [--margin 0.1]
|
|
11
|
+
//
|
|
12
|
+
// --rescan re-audits each stored transcript with the current leak scanner;
|
|
13
|
+
// --rescore re-scores each stored solution with the current hidden tests and
|
|
14
|
+
// task.json (no agent is launched), under the prompt variant its run used.
|
|
15
|
+
// Either writes summary.<rescanned|rescored>.json (and pilot.…json) beside
|
|
16
|
+
// the originals, which are never changed; --rescore also writes each run's
|
|
17
|
+
// score.rescored.json beside its score.json.
|
|
18
|
+
//
|
|
19
|
+
// --prompt picks the prompt variant (harness/assemble.mjs PROMPT_VARIANTS):
|
|
20
|
+
// `explicit` (default) states the safety rules; `minimal` gives only the
|
|
21
|
+
// product and its public contract. Every record carries it; variants are
|
|
22
|
+
// never pooled.
|
|
23
|
+
//
|
|
24
|
+
// Phase 1, agents. Runs are ordered round-robin — every round has one run of
|
|
25
|
+
// every task × condition cell, in a seeded shuffle — so conditions interleave
|
|
26
|
+
// in time instead of running in cell blocks. For each run it
|
|
27
|
+
// 1. builds a private run directory under a fresh 0700 batch directory in
|
|
28
|
+
// the OS temp dir (refused if inside the repository): work/ (the starter,
|
|
29
|
+
// that condition's docs only, a clean copy of the condition's shipped
|
|
30
|
+
// node_modules, git-initialised), home/ (a clean HOME and
|
|
31
|
+
// CLAUDE_CONFIG_DIR, so the host's ~/.claude — settings, memory, MCP
|
|
32
|
+
// servers, OAuth login — is not visible) and tmp/ (TMPDIR);
|
|
33
|
+
// 2. launches ONE headless agent in work/ with the rendered prompt (identical
|
|
34
|
+
// across conditions but for the library line), inside the OS sandbox
|
|
35
|
+
// (harness/sandbox.mjs: file contents outside the run and the toolchain
|
|
36
|
+
// unreadable, nothing outside the run writable), with a wall-clock
|
|
37
|
+
// timeout; the only host values passed are PATH and exactly one
|
|
38
|
+
// credential (harness/auth.mjs), which is how the agent authenticates;
|
|
39
|
+
// 3. audits the transcript (harness/leak-scan.mjs, a second line behind the
|
|
40
|
+
// sandbox, and the only one for the network, which the sandbox leaves
|
|
41
|
+
// open): a successful tool call reaching outside the run or using the
|
|
42
|
+
// network marks the run contaminated;
|
|
43
|
+
// 4. records the agent's exit (normal / max_turns / timeout / error /
|
|
44
|
+
// no_result), turns, tokens and cost from the transcript, and copies
|
|
45
|
+
// work/ (minus node_modules) to the results directory.
|
|
46
|
+
// A run that throws is recorded as a harness error and retried (--retries).
|
|
47
|
+
//
|
|
48
|
+
// Phase 2, scoring — only after every agent run has ended, so no agent is
|
|
49
|
+
// alive while hidden tests exist anywhere on disk. score.mjs works in its own
|
|
50
|
+
// 0700 directory. A scoring harness error is retried, then excluded and
|
|
51
|
+
// counted (never scored as 0).
|
|
52
|
+
//
|
|
53
|
+
// Phase 3, aggregation (harness/aggregate.mjs): per task × model × condition,
|
|
54
|
+
// never pooling models; primary metric the fraction of runs with zero safety
|
|
55
|
+
// violations (Wilson; Newcombe for differences), secondary mean requirements
|
|
56
|
+
// met; main result without contaminated runs, intent-to-treat with them.
|
|
57
|
+
// `--pilot` (5 runs per cell by default) adds variance, minutes/turns/tokens
|
|
58
|
+
// per run, ceiling/floor warnings and the runs needed for `--margin`.
|
|
59
|
+
//
|
|
60
|
+
// --resume <dir> continues a batch: runs with agent.json are not re-run, runs
|
|
61
|
+
// without score.json are scored. A run excluded as a harness error has no
|
|
62
|
+
// agent.json, so it is run again and scored. A new batch refuses an --out
|
|
63
|
+
// directory that already holds files: it would take that directory's records
|
|
64
|
+
// for its own runs.
|
|
65
|
+
//
|
|
66
|
+
// ASSUMED AGENT CLI (override with --agent-cmd): Claude Code headless,
|
|
67
|
+
// claude -p "$(cat {prompt})" --output-format stream-json --verbose
|
|
68
|
+
// --model {model} --permission-mode acceptEdits --max-turns {maxTurns}
|
|
69
|
+
// --allowedTools "{allowedTools}" --disallowedTools "WebFetch,WebSearch"
|
|
70
|
+
// --strict-mcp-config
|
|
71
|
+
// Placeholders: {prompt}, {model}, {maxTurns}, {allowedTools}, {task},
|
|
72
|
+
// {condition} (the last two are for stub agents in harness tests). The
|
|
73
|
+
// transcript must be stream-json for the audit and the exit/turn/token record.
|
|
74
|
+
import { spawn } from "node:child_process"
|
|
75
|
+
import {
|
|
76
|
+
cpSync,
|
|
77
|
+
existsSync,
|
|
78
|
+
mkdirSync,
|
|
79
|
+
readFileSync,
|
|
80
|
+
readdirSync,
|
|
81
|
+
rmSync,
|
|
82
|
+
statSync,
|
|
83
|
+
writeFileSync,
|
|
84
|
+
} from "node:fs"
|
|
85
|
+
import { join, resolve } from "node:path"
|
|
86
|
+
import { pathToFileURL } from "node:url"
|
|
87
|
+
import { isDeepStrictEqual } from "node:util"
|
|
88
|
+
import {
|
|
89
|
+
CONDITIONS,
|
|
90
|
+
DEFAULT_CONDITIONS,
|
|
91
|
+
EVALS,
|
|
92
|
+
TASKS,
|
|
93
|
+
PROMPT_VARIANTS,
|
|
94
|
+
conditionDocDirs,
|
|
95
|
+
renderPrompt,
|
|
96
|
+
taskSpec,
|
|
97
|
+
} from "./harness/assemble.mjs"
|
|
98
|
+
import {
|
|
99
|
+
aggregate,
|
|
100
|
+
pilotReport,
|
|
101
|
+
printPilot,
|
|
102
|
+
printSummary,
|
|
103
|
+
round,
|
|
104
|
+
} from "./harness/aggregate.mjs"
|
|
105
|
+
import { scanTranscript, transcriptCwd } from "./harness/leak-scan.mjs"
|
|
106
|
+
import { describeV4Source, v4Source } from "./harness/ship.mjs"
|
|
107
|
+
import {
|
|
108
|
+
agentEnv,
|
|
109
|
+
makeBatchDir,
|
|
110
|
+
prepareBareRun,
|
|
111
|
+
prepareRun,
|
|
112
|
+
REPO,
|
|
113
|
+
} from "./harness/runs.mjs"
|
|
114
|
+
import {
|
|
115
|
+
AUTH_VARS,
|
|
116
|
+
MISSING_AUTH_MESSAGE,
|
|
117
|
+
redact,
|
|
118
|
+
resolveAuth,
|
|
119
|
+
secretsOf,
|
|
120
|
+
} from "./harness/auth.mjs"
|
|
121
|
+
import {
|
|
122
|
+
cliInstallDir,
|
|
123
|
+
nodeInstallDir,
|
|
124
|
+
sandboxAvailable,
|
|
125
|
+
sandboxPrefix,
|
|
126
|
+
} from "./harness/sandbox.mjs"
|
|
127
|
+
|
|
128
|
+
export const ALLOWED_TOOLS = {
|
|
129
|
+
sandboxed:
|
|
130
|
+
"Read,Edit,Write,Glob,Grep,Bash(npx tsc:*),Bash(npx vitest:*),Bash(node:*),Bash(ls:*),Bash(cat:*)",
|
|
131
|
+
"tsc-only": "Read,Edit,Write,Glob,Grep,Bash(npx tsc:*),Bash(ls:*)",
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const DEFAULT_AGENT_CMD =
|
|
135
|
+
'claude -p "$(cat {prompt})" --output-format stream-json --verbose --model {model} {effortFlag}' +
|
|
136
|
+
"--permission-mode acceptEdits --max-turns {maxTurns} " +
|
|
137
|
+
'--allowedTools "{allowedTools}" --disallowedTools "WebFetch,WebSearch" ' +
|
|
138
|
+
"--strict-mcp-config"
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The preflight: one tiny call in the same isolated environment and sandbox
|
|
142
|
+
* as a real run, which must succeed before any agent run starts.
|
|
143
|
+
*/
|
|
144
|
+
export const PREFLIGHT_CMD =
|
|
145
|
+
"claude -p 'Reply with the single word: ok' --output-format stream-json --verbose " +
|
|
146
|
+
"--model {model} {effortFlag}--max-turns 1 " +
|
|
147
|
+
'--disallowedTools "WebFetch,WebSearch" --strict-mcp-config'
|
|
148
|
+
|
|
149
|
+
// The credential, resolved once (harness/auth.mjs). Kept out of `args`, which
|
|
150
|
+
// is written to plan.json: only its kind and source are recorded.
|
|
151
|
+
let AUTH
|
|
152
|
+
|
|
153
|
+
// ---------------------------------------------------------------- arguments
|
|
154
|
+
function parseArgs(argv) {
|
|
155
|
+
const args = {
|
|
156
|
+
tasks: [],
|
|
157
|
+
conditions: [],
|
|
158
|
+
n: 0,
|
|
159
|
+
model: undefined,
|
|
160
|
+
effort: undefined,
|
|
161
|
+
oauthTokenFile: undefined,
|
|
162
|
+
preflight: false,
|
|
163
|
+
preflightCmd: PREFLIGHT_CMD,
|
|
164
|
+
jobs: undefined,
|
|
165
|
+
timeoutMin: 30,
|
|
166
|
+
maxTurns: 60,
|
|
167
|
+
seed: 1,
|
|
168
|
+
mode: undefined,
|
|
169
|
+
prompt: "explicit",
|
|
170
|
+
sandboxAllow: [],
|
|
171
|
+
agentCmd: DEFAULT_AGENT_CMD,
|
|
172
|
+
customCmd: false,
|
|
173
|
+
retries: 2,
|
|
174
|
+
rateLimitRetries: 4,
|
|
175
|
+
rateLimitBackoffMin: 5,
|
|
176
|
+
rateLimitMaxWaitMin: 300,
|
|
177
|
+
out: undefined,
|
|
178
|
+
resume: undefined,
|
|
179
|
+
pilot: false,
|
|
180
|
+
margin: 0.1,
|
|
181
|
+
dryRun: false,
|
|
182
|
+
aggregate: undefined,
|
|
183
|
+
estMinutes: 12,
|
|
184
|
+
}
|
|
185
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
186
|
+
const flag = argv[i]
|
|
187
|
+
const value = () => {
|
|
188
|
+
const v = argv[++i]
|
|
189
|
+
if (v === undefined) throw new Error(`${flag} needs a value`)
|
|
190
|
+
return v
|
|
191
|
+
}
|
|
192
|
+
switch (flag) {
|
|
193
|
+
case "--task":
|
|
194
|
+
args.tasks.push(value())
|
|
195
|
+
break
|
|
196
|
+
case "--condition":
|
|
197
|
+
args.conditions.push(value())
|
|
198
|
+
break
|
|
199
|
+
case "--n":
|
|
200
|
+
args.n = Number(value())
|
|
201
|
+
break
|
|
202
|
+
case "--model":
|
|
203
|
+
args.model = value()
|
|
204
|
+
break
|
|
205
|
+
case "--effort":
|
|
206
|
+
args.effort = value()
|
|
207
|
+
break
|
|
208
|
+
case "--oauth-token-file":
|
|
209
|
+
args.oauthTokenFile = resolve(value())
|
|
210
|
+
break
|
|
211
|
+
case "--preflight":
|
|
212
|
+
args.preflight = true
|
|
213
|
+
break
|
|
214
|
+
case "--preflight-cmd":
|
|
215
|
+
// For harness tests: a stub in place of the real CLI call.
|
|
216
|
+
args.preflightCmd = value()
|
|
217
|
+
break
|
|
218
|
+
case "--jobs":
|
|
219
|
+
args.jobs = Number(value())
|
|
220
|
+
break
|
|
221
|
+
case "--rate-limit-retries":
|
|
222
|
+
args.rateLimitRetries = Number(value())
|
|
223
|
+
break
|
|
224
|
+
case "--rate-limit-backoff-min":
|
|
225
|
+
args.rateLimitBackoffMin = Number(value())
|
|
226
|
+
break
|
|
227
|
+
case "--rate-limit-max-wait-min":
|
|
228
|
+
args.rateLimitMaxWaitMin = Number(value())
|
|
229
|
+
break
|
|
230
|
+
case "--timeout-min":
|
|
231
|
+
args.timeoutMin = Number(value())
|
|
232
|
+
break
|
|
233
|
+
case "--max-turns":
|
|
234
|
+
args.maxTurns = Number(value())
|
|
235
|
+
break
|
|
236
|
+
case "--seed":
|
|
237
|
+
args.seed = Number(value())
|
|
238
|
+
break
|
|
239
|
+
case "--mode":
|
|
240
|
+
args.mode = value()
|
|
241
|
+
break
|
|
242
|
+
case "--prompt":
|
|
243
|
+
args.prompt = value()
|
|
244
|
+
args.promptGiven = true
|
|
245
|
+
break
|
|
246
|
+
case "--sandbox-allow":
|
|
247
|
+
args.sandboxAllow.push(value())
|
|
248
|
+
break
|
|
249
|
+
case "--agent-cmd":
|
|
250
|
+
args.agentCmd = value()
|
|
251
|
+
args.customCmd = true
|
|
252
|
+
break
|
|
253
|
+
case "--retries":
|
|
254
|
+
args.retries = Number(value())
|
|
255
|
+
break
|
|
256
|
+
case "--out":
|
|
257
|
+
args.out = value()
|
|
258
|
+
break
|
|
259
|
+
case "--resume":
|
|
260
|
+
args.resume = value()
|
|
261
|
+
break
|
|
262
|
+
case "--pilot":
|
|
263
|
+
args.pilot = true
|
|
264
|
+
break
|
|
265
|
+
case "--margin":
|
|
266
|
+
args.margin = Number(value())
|
|
267
|
+
break
|
|
268
|
+
case "--est-minutes":
|
|
269
|
+
args.estMinutes = Number(value())
|
|
270
|
+
break
|
|
271
|
+
case "--dry-run":
|
|
272
|
+
args.dryRun = true
|
|
273
|
+
break
|
|
274
|
+
case "--aggregate":
|
|
275
|
+
args.aggregate = value()
|
|
276
|
+
break
|
|
277
|
+
case "--rescan":
|
|
278
|
+
args.rescan = true
|
|
279
|
+
break
|
|
280
|
+
case "--rescore":
|
|
281
|
+
args.rescore = true
|
|
282
|
+
break
|
|
283
|
+
default:
|
|
284
|
+
throw new Error(`unknown argument ${flag}`)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (args.tasks.length === 0) args.tasks = [...TASKS]
|
|
288
|
+
if (args.conditions.length === 0) args.conditions = [...DEFAULT_CONDITIONS]
|
|
289
|
+
for (const t of args.tasks) taskSpec(t)
|
|
290
|
+
for (const c of args.conditions) {
|
|
291
|
+
if (!CONDITIONS.includes(c)) throw new Error(`unknown condition ${c}`)
|
|
292
|
+
}
|
|
293
|
+
if (!PROMPT_VARIANTS.includes(args.prompt)) {
|
|
294
|
+
throw new Error(`--prompt is one of ${PROMPT_VARIANTS.join(", ")}`)
|
|
295
|
+
}
|
|
296
|
+
if (args.pilot && args.n === 0) args.n = 5
|
|
297
|
+
args.mode ??= sandboxAvailable() ? "sandboxed" : undefined
|
|
298
|
+
if (args.effort !== undefined && !/^[a-z]+$/.test(args.effort)) {
|
|
299
|
+
throw new Error(`--effort takes a level name such as low, medium or high`)
|
|
300
|
+
}
|
|
301
|
+
if (!args.aggregate && !args.resume && !args.preflight) {
|
|
302
|
+
if (!(args.n >= 1))
|
|
303
|
+
throw new Error("--n <runs per cell> is required (or --pilot)")
|
|
304
|
+
if (!args.mode) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
"no OS sandbox is available here: agents cannot be allowed to run node/vitest. " +
|
|
307
|
+
"Pass --mode tsc-only for the documented fallback (type-check feedback only)."
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
if (!["sandboxed", "tsc-only"].includes(args.mode))
|
|
311
|
+
throw new Error("--mode is sandboxed or tsc-only")
|
|
312
|
+
if (args.mode === "sandboxed" && !sandboxAvailable()) {
|
|
313
|
+
throw new Error(
|
|
314
|
+
"--mode sandboxed needs sandbox-exec (macOS); use --mode tsc-only"
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
if (!args.dryRun && !args.model) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
"--model is required for a real run (an owner decision; see README)"
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
resolveCredential(args)
|
|
324
|
+
if (
|
|
325
|
+
(args.preflight || (!args.aggregate && !args.dryRun)) &&
|
|
326
|
+
!args.customCmd &&
|
|
327
|
+
!AUTH
|
|
328
|
+
) {
|
|
329
|
+
throw new Error(MISSING_AUTH_MESSAGE)
|
|
330
|
+
}
|
|
331
|
+
if (
|
|
332
|
+
(args.preflight || (!args.aggregate && !args.resume && !args.dryRun)) &&
|
|
333
|
+
!args.model
|
|
334
|
+
) {
|
|
335
|
+
throw new Error("--model is required (an owner decision; see README)")
|
|
336
|
+
}
|
|
337
|
+
// A subscription is rate-limited per account: fewer agents at a time.
|
|
338
|
+
args.jobs ??= args.auth === "oauth" ? 2 : 4
|
|
339
|
+
return args
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Resolves the credential once — `--oauth-token-file`, then
|
|
344
|
+
* CLAUDE_CODE_OAUTH_TOKEN, then ANTHROPIC_API_KEY — and records its kind and
|
|
345
|
+
* source (never its value) in `args`. A custom --agent-cmd (a stub agent in
|
|
346
|
+
* harness tests) may run without one.
|
|
347
|
+
*/
|
|
348
|
+
function resolveCredential(args) {
|
|
349
|
+
AUTH = resolveAuth(process.env, { tokenFile: args.oauthTokenFile })
|
|
350
|
+
args.auth = AUTH?.kind ?? "none"
|
|
351
|
+
args.authSource = AUTH
|
|
352
|
+
? AUTH.source === "file"
|
|
353
|
+
? "--oauth-token-file"
|
|
354
|
+
: AUTH.name
|
|
355
|
+
: "none"
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// ---------------------------------------------------------------- planning
|
|
359
|
+
function rng(seed) {
|
|
360
|
+
let s = seed >>> 0
|
|
361
|
+
return () => {
|
|
362
|
+
s = (s + 0x6d2b79f5) >>> 0
|
|
363
|
+
let t = s
|
|
364
|
+
t = Math.imul(t ^ (t >>> 15), t | 1)
|
|
365
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
|
|
366
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** Round-robin over cells, each round in a seeded shuffle. */
|
|
371
|
+
/**
|
|
372
|
+
* Refuses to resume a batch whose v4 packages are no longer the ones it was
|
|
373
|
+
* planned with: `saved` is plan.json's `v4Source`, `current` what
|
|
374
|
+
* `.ship/v4/source.json` holds now. A run of the batch and the scoring read
|
|
375
|
+
* `.ship/v4` and `conditions/v4/node_modules`, so after `setup.mjs` rebuilt
|
|
376
|
+
* them from another source, the runs still to come would test other
|
|
377
|
+
* packages than the plan names. A plan from before v4Source was recorded
|
|
378
|
+
* (`saved` undefined) is let through.
|
|
379
|
+
*/
|
|
380
|
+
/**
|
|
381
|
+
* Refuses a real v4 batch, new or resumed, when setup has recorded no source
|
|
382
|
+
* for the v4 packages (`.ship/v4/source.json`, from a setup run that predates
|
|
383
|
+
* it, or none): its runs would test packages nobody can identify, and
|
|
384
|
+
* Addendum 4 requires plan.json's `v4Source` to name them. A dry run only
|
|
385
|
+
* prints the gap.
|
|
386
|
+
*/
|
|
387
|
+
export function refuseMissingV4Source(source, { dryRun }) {
|
|
388
|
+
if (source || dryRun) return
|
|
389
|
+
throw new Error(
|
|
390
|
+
"no .ship/v4/source.json: the v4 packages this batch would test are not identified. " +
|
|
391
|
+
"Run `node setup.mjs --v4-from ...` first."
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function refuseChangedV4Source(saved, current) {
|
|
396
|
+
if (saved === undefined || isDeepStrictEqual(saved, current)) return
|
|
397
|
+
throw new Error(
|
|
398
|
+
`--resume: this batch was planned with the v4 packages from ${describeV4Source(saved)}, ` +
|
|
399
|
+
`but .ship/v4 now holds ${describeV4Source(current)}. ` +
|
|
400
|
+
"Rebuild the planned source with `node setup.mjs --v4-from ...` before resuming."
|
|
401
|
+
)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export function plan({ tasks, conditions, n, seed }) {
|
|
405
|
+
const random = rng(seed)
|
|
406
|
+
const cells = tasks.flatMap((task) =>
|
|
407
|
+
conditions.map((condition) => ({ task, condition }))
|
|
408
|
+
)
|
|
409
|
+
const runs = []
|
|
410
|
+
for (let i = 1; i <= n; i += 1) {
|
|
411
|
+
const round = [...cells]
|
|
412
|
+
for (let j = round.length - 1; j > 0; j -= 1) {
|
|
413
|
+
const k = Math.floor(random() * (j + 1))
|
|
414
|
+
;[round[j], round[k]] = [round[k], round[j]]
|
|
415
|
+
}
|
|
416
|
+
for (const cell of round) runs.push({ ...cell, i })
|
|
417
|
+
}
|
|
418
|
+
return runs
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const runDirOf = (outDir, run) =>
|
|
422
|
+
join(outDir, run.task, run.condition, String(run.i).padStart(3, "0"))
|
|
423
|
+
|
|
424
|
+
function agentCommand(
|
|
425
|
+
args,
|
|
426
|
+
{ promptFile, runRoot },
|
|
427
|
+
run,
|
|
428
|
+
template = args.agentCmd
|
|
429
|
+
) {
|
|
430
|
+
const shq = (s) => `'${String(s).replace(/'/g, "'\\''")}'`
|
|
431
|
+
const inner = template
|
|
432
|
+
.replaceAll("{prompt}", shq(promptFile))
|
|
433
|
+
.replaceAll("{model}", shq(args.model ?? "<model: owner decision>"))
|
|
434
|
+
.replaceAll("{maxTurns}", String(args.maxTurns))
|
|
435
|
+
.replaceAll(
|
|
436
|
+
"{effortFlag}",
|
|
437
|
+
args.effort ? `--effort ${shq(args.effort)} ` : ""
|
|
438
|
+
)
|
|
439
|
+
.replaceAll("{allowedTools}", ALLOWED_TOOLS[args.mode])
|
|
440
|
+
.replaceAll("{task}", run?.task ?? "<task>")
|
|
441
|
+
.replaceAll("{condition}", run?.condition ?? "<condition>")
|
|
442
|
+
if (!sandboxAvailable())
|
|
443
|
+
return { argv: ["sh", "-c", inner], sandboxed: false }
|
|
444
|
+
const readOnly = [
|
|
445
|
+
nodeInstallDir(),
|
|
446
|
+
cliInstallDir("claude"),
|
|
447
|
+
...args.sandboxAllow,
|
|
448
|
+
]
|
|
449
|
+
const prefix = runRoot
|
|
450
|
+
? sandboxPrefix({ runRoot, readOnly })
|
|
451
|
+
: ["sandbox-exec", "-f", "<run>/sandbox.sb"]
|
|
452
|
+
return { argv: [...prefix, "sh", "-c", inner], sandboxed: true }
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ---------------------------------------------------------------- phase 1
|
|
456
|
+
function spawnAgent(argv, { cwd, env, timeoutMs, logBase }) {
|
|
457
|
+
return new Promise((resolvePromise) => {
|
|
458
|
+
const child = spawn(argv[0], argv.slice(1), {
|
|
459
|
+
cwd,
|
|
460
|
+
env,
|
|
461
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
462
|
+
})
|
|
463
|
+
let out = ""
|
|
464
|
+
let err = ""
|
|
465
|
+
let timedOut = false
|
|
466
|
+
child.stdout.on("data", (d) => (out += d))
|
|
467
|
+
child.stderr.on("data", (d) => (err += d))
|
|
468
|
+
const timer = setTimeout(() => {
|
|
469
|
+
timedOut = true
|
|
470
|
+
child.kill("SIGKILL")
|
|
471
|
+
}, timeoutMs)
|
|
472
|
+
const onAbort = () => child.kill("SIGKILL")
|
|
473
|
+
batchAbort.signal.addEventListener("abort", onAbort, { once: true })
|
|
474
|
+
child.on("close", (code, signal) => {
|
|
475
|
+
clearTimeout(timer)
|
|
476
|
+
batchAbort.signal.removeEventListener("abort", onAbort)
|
|
477
|
+
writeFileSync(`${logBase}.stdout`, redact(out))
|
|
478
|
+
writeFileSync(`${logBase}.stderr`, redact(err))
|
|
479
|
+
resolvePromise({ code, signal, out, err, timedOut })
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// A usage or rate limit, as the CLI reports one. ASSUMED (from the CLI's
|
|
485
|
+
// documented stream-json shape and its observed error texts, not verified
|
|
486
|
+
// against 2.1.285): a subscription limit ends the run with an error `result`
|
|
487
|
+
// whose text reads like "Claude AI usage limit reached|<reset epoch>" or
|
|
488
|
+
// "... limit reached ... resets ...", and an API limit as
|
|
489
|
+
// "API Error: 429 ... rate_limit_error" or "overloaded_error". Only error
|
|
490
|
+
// results, top-level `error` fields and the CLI's stderr are inspected — the
|
|
491
|
+
// agent's own prose in this task talks about HTTP 429 all the time — and a
|
|
492
|
+
// successful result is never a rate limit.
|
|
493
|
+
// Sign-in failures, measured on CLI 2.1.285: with an isolated config
|
|
494
|
+
// directory and no credential a run returns subtype "success", is_error true,
|
|
495
|
+
// result "Not logged in · Please run /login". Also: api_error_status 401/403.
|
|
496
|
+
const SIGN_IN =
|
|
497
|
+
/not logged in|\/login\b|invalid api key|oauth token (has )?(expired|revoked)|authentication (failed|error)|unauthori[sz]ed/i
|
|
498
|
+
const SIGN_IN_STATUS = new Set([401, 403])
|
|
499
|
+
const LIMIT_STATUS = new Set([429, 529])
|
|
500
|
+
|
|
501
|
+
const RATE_LIMIT =
|
|
502
|
+
/usage limit|limit reached|rate[_ ]?limit|too many requests|\b429\b|overloaded(_error)?|\b529\b/i
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Exit reason, turns, tokens and cost from the stream-json `result` message.
|
|
506
|
+
* `rateLimitedUntil` is the reset time (ms) when the limit message names one.
|
|
507
|
+
*/
|
|
508
|
+
export function agentOutcome(stdout, { timedOut, stderr = "" }) {
|
|
509
|
+
let result
|
|
510
|
+
const errorTexts = []
|
|
511
|
+
for (const line of stdout.split("\n")) {
|
|
512
|
+
const l = line.trim()
|
|
513
|
+
if (!l.startsWith("{")) continue
|
|
514
|
+
try {
|
|
515
|
+
const msg = JSON.parse(l)
|
|
516
|
+
if (msg.type === "result") result = msg
|
|
517
|
+
if (msg.type === "error" || msg.error !== undefined) {
|
|
518
|
+
errorTexts.push(JSON.stringify(msg.error ?? msg))
|
|
519
|
+
}
|
|
520
|
+
} catch {
|
|
521
|
+
// not JSON
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const failed = result
|
|
525
|
+
? result.is_error === true || result.subtype !== "success"
|
|
526
|
+
: true
|
|
527
|
+
if (result && failed && typeof result.result === "string") {
|
|
528
|
+
errorTexts.push(result.result)
|
|
529
|
+
}
|
|
530
|
+
if (failed) errorTexts.push(stderr)
|
|
531
|
+
const status = failed ? result?.api_error_status : undefined
|
|
532
|
+
const signInText = errorTexts.find((t) => SIGN_IN.test(t))
|
|
533
|
+
const signIn =
|
|
534
|
+
!timedOut && (SIGN_IN_STATUS.has(status) || signInText !== undefined)
|
|
535
|
+
const limitText =
|
|
536
|
+
errorTexts.find((t) => RATE_LIMIT.test(t)) ??
|
|
537
|
+
(LIMIT_STATUS.has(status) ? `api_error_status ${status}` : undefined)
|
|
538
|
+
const epoch = limitText && /\|(\d{10})\b/.exec(limitText)
|
|
539
|
+
const exit = signIn
|
|
540
|
+
? "sign_in_error"
|
|
541
|
+
: !timedOut && limitText
|
|
542
|
+
? "rate_limited"
|
|
543
|
+
: timedOut
|
|
544
|
+
? "timeout"
|
|
545
|
+
: !result
|
|
546
|
+
? "no_result"
|
|
547
|
+
: result.subtype === "success" && result.is_error !== true
|
|
548
|
+
? "normal"
|
|
549
|
+
: result.subtype === "error_max_turns"
|
|
550
|
+
? "max_turns"
|
|
551
|
+
: "error"
|
|
552
|
+
const usage = result?.usage ?? {}
|
|
553
|
+
return {
|
|
554
|
+
exit,
|
|
555
|
+
turns: result?.num_turns ?? null,
|
|
556
|
+
tokens: {
|
|
557
|
+
input: usage.input_tokens ?? null,
|
|
558
|
+
output: usage.output_tokens ?? null,
|
|
559
|
+
cacheRead: usage.cache_read_input_tokens ?? null,
|
|
560
|
+
cacheCreation: usage.cache_creation_input_tokens ?? null,
|
|
561
|
+
},
|
|
562
|
+
costUsd: result?.total_cost_usd ?? null,
|
|
563
|
+
resultText:
|
|
564
|
+
typeof result?.result === "string" ? result.result.slice(0, 500) : null,
|
|
565
|
+
apiErrorStatus: result?.api_error_status ?? null,
|
|
566
|
+
...(exit === "sign_in_error"
|
|
567
|
+
? {
|
|
568
|
+
signInMessage: String(
|
|
569
|
+
signInText ?? `api_error_status ${status}`
|
|
570
|
+
).slice(0, 300),
|
|
571
|
+
}
|
|
572
|
+
: {}),
|
|
573
|
+
...(exit === "rate_limited"
|
|
574
|
+
? {
|
|
575
|
+
rateLimitedUntil: epoch ? Number(epoch[1]) * 1000 : null,
|
|
576
|
+
rateLimitMessage: String(limitText).slice(0, 300),
|
|
577
|
+
}
|
|
578
|
+
: {}),
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/** The CLI could not sign in: the whole batch stops at once. */
|
|
583
|
+
export class SignInError extends Error {}
|
|
584
|
+
|
|
585
|
+
/** Stops every agent run of the batch (a sign-in failure). */
|
|
586
|
+
const batchAbort = new AbortController()
|
|
587
|
+
|
|
588
|
+
/** A run the account's usage or rate limit stopped: a harness error, not a result. */
|
|
589
|
+
export class RateLimited extends Error {
|
|
590
|
+
constructor(message, until) {
|
|
591
|
+
super(message)
|
|
592
|
+
this.until = until
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/** Replaces credential values in every text file under `dir`. */
|
|
597
|
+
function redactTree(dir, secrets) {
|
|
598
|
+
if (secrets.length === 0) return
|
|
599
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
600
|
+
const p = join(dir, entry.name)
|
|
601
|
+
if (entry.isDirectory()) redactTree(p, secrets)
|
|
602
|
+
else if (entry.isFile()) {
|
|
603
|
+
const text = readFileSync(p, "latin1")
|
|
604
|
+
if (secrets.some((s) => text.includes(s))) {
|
|
605
|
+
writeFileSync(p, redact(text, secrets), "latin1")
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
async function agentRun(args, batchDir, outDir, run) {
|
|
612
|
+
const dir = runDirOf(outDir, run)
|
|
613
|
+
mkdirSync(dir, { recursive: true })
|
|
614
|
+
const prepared = prepareRun({
|
|
615
|
+
batchDir,
|
|
616
|
+
...run,
|
|
617
|
+
mode: args.mode,
|
|
618
|
+
prompt: args.prompt,
|
|
619
|
+
})
|
|
620
|
+
const { argv, sandboxed } = agentCommand(args, prepared, run)
|
|
621
|
+
const started = Date.now()
|
|
622
|
+
const auth = AUTH
|
|
623
|
+
const agent = await spawnAgent(argv, {
|
|
624
|
+
cwd: prepared.work,
|
|
625
|
+
env: agentEnv(prepared, auth),
|
|
626
|
+
timeoutMs: args.timeoutMin * 60_000,
|
|
627
|
+
logBase: join(dir, "agent"),
|
|
628
|
+
})
|
|
629
|
+
const minutes = (Date.now() - started) / 60_000
|
|
630
|
+
const outcome = agentOutcome(agent.out, { ...agent, stderr: agent.err })
|
|
631
|
+
if (batchAbort.signal.aborted) {
|
|
632
|
+
// Killed because another run could not sign in: not a result.
|
|
633
|
+
rmSync(prepared.runRoot, { recursive: true, force: true })
|
|
634
|
+
throw new SignInError("the batch was stopped")
|
|
635
|
+
}
|
|
636
|
+
if (outcome.exit === "sign_in_error") {
|
|
637
|
+
rmSync(prepared.runRoot, { recursive: true, force: true })
|
|
638
|
+
throw new SignInError(redact(outcome.signInMessage ?? "not signed in"))
|
|
639
|
+
}
|
|
640
|
+
if (outcome.exit === "rate_limited") {
|
|
641
|
+
// Keep the attempt's logs for the record; the run itself is retried.
|
|
642
|
+
for (const ext of ["stdout", "stderr"]) {
|
|
643
|
+
cpSync(
|
|
644
|
+
join(dir, `agent.${ext}`),
|
|
645
|
+
join(dir, `rate-limited-${Date.now()}.${ext}`)
|
|
646
|
+
)
|
|
647
|
+
}
|
|
648
|
+
rmSync(prepared.runRoot, { recursive: true, force: true })
|
|
649
|
+
throw new RateLimited(
|
|
650
|
+
redact(outcome.rateLimitMessage ?? "rate limited"),
|
|
651
|
+
outcome.rateLimitedUntil
|
|
652
|
+
)
|
|
653
|
+
}
|
|
654
|
+
const audit = scanTranscript(agent.out, { runDir: prepared.work })
|
|
655
|
+
cpSync(prepared.work, join(dir, "solution"), {
|
|
656
|
+
recursive: true,
|
|
657
|
+
filter: (src) =>
|
|
658
|
+
!src.startsWith(join(prepared.work, "node_modules")) &&
|
|
659
|
+
!src.endsWith("/.git"),
|
|
660
|
+
})
|
|
661
|
+
redactTree(join(dir, "solution"), secretsOf())
|
|
662
|
+
const meta = {
|
|
663
|
+
task: run.task,
|
|
664
|
+
condition: run.condition,
|
|
665
|
+
run: run.i,
|
|
666
|
+
model: args.model,
|
|
667
|
+
effort: args.effort ?? "default",
|
|
668
|
+
prompt: args.prompt,
|
|
669
|
+
auth: auth?.kind ?? "none",
|
|
670
|
+
seed: args.seed,
|
|
671
|
+
mode: args.mode,
|
|
672
|
+
sandboxed,
|
|
673
|
+
agent: {
|
|
674
|
+
...outcome,
|
|
675
|
+
minutes: round(minutes),
|
|
676
|
+
code: agent.code,
|
|
677
|
+
signal: agent.signal,
|
|
678
|
+
},
|
|
679
|
+
contaminated: audit.contaminated,
|
|
680
|
+
audit: {
|
|
681
|
+
auditable: audit.auditable,
|
|
682
|
+
toolCalls: audit.toolCalls,
|
|
683
|
+
attempts: audit.attempts,
|
|
684
|
+
violations: audit.violations.slice(0, 20),
|
|
685
|
+
persistedReads: audit.persistedReads.slice(0, 20),
|
|
686
|
+
},
|
|
687
|
+
}
|
|
688
|
+
writeFileSync(
|
|
689
|
+
join(dir, "agent.json"),
|
|
690
|
+
redact(JSON.stringify(meta, null, 2)) + "\n"
|
|
691
|
+
)
|
|
692
|
+
rmSync(prepared.runRoot, { recursive: true, force: true })
|
|
693
|
+
return meta
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
async function pool(items, jobs, fn) {
|
|
697
|
+
let next = 0
|
|
698
|
+
const worker = async () => {
|
|
699
|
+
while (next < items.length && !batchAbort.signal.aborted) {
|
|
700
|
+
await fn(items[next++])
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
await Promise.all(Array.from({ length: Math.max(1, jobs) }, worker))
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ---------------------------------------------------------------- phase 2
|
|
707
|
+
function scoreOnce(run, dir, prompt = "explicit") {
|
|
708
|
+
return new Promise((resolvePromise) => {
|
|
709
|
+
const child = spawn(
|
|
710
|
+
process.execPath,
|
|
711
|
+
[
|
|
712
|
+
join(EVALS, "score.mjs"),
|
|
713
|
+
"--task",
|
|
714
|
+
run.task,
|
|
715
|
+
"--condition",
|
|
716
|
+
run.condition,
|
|
717
|
+
"--solution",
|
|
718
|
+
join(dir, "solution"),
|
|
719
|
+
"--prompt",
|
|
720
|
+
prompt,
|
|
721
|
+
],
|
|
722
|
+
{ cwd: EVALS, stdio: ["ignore", "pipe", "pipe"] }
|
|
723
|
+
)
|
|
724
|
+
let out = ""
|
|
725
|
+
let err = ""
|
|
726
|
+
child.stdout.on("data", (d) => (out += d))
|
|
727
|
+
child.stderr.on("data", (d) => (err += d))
|
|
728
|
+
child.on("close", (code) => resolvePromise({ code, out, err }))
|
|
729
|
+
})
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
async function scoreRun(args, outDir, run) {
|
|
733
|
+
const dir = runDirOf(outDir, run)
|
|
734
|
+
const meta = JSON.parse(readFileSync(join(dir, "agent.json"), "utf8"))
|
|
735
|
+
let score
|
|
736
|
+
let lastError = ""
|
|
737
|
+
for (let attempt = 0; attempt <= args.retries && !score; attempt += 1) {
|
|
738
|
+
const r = await scoreOnce(run, dir, meta.prompt ?? args.prompt)
|
|
739
|
+
if (r.code === 0) score = JSON.parse(r.out)
|
|
740
|
+
else lastError = redact(`score.mjs exit ${r.code}: ${r.err.slice(-2000)}`)
|
|
741
|
+
}
|
|
742
|
+
const record = score
|
|
743
|
+
? { ...score, ...meta }
|
|
744
|
+
: { ...meta, harnessError: lastError, harnessKind: "scoring" }
|
|
745
|
+
delete record.details
|
|
746
|
+
writeFileSync(
|
|
747
|
+
join(dir, "score.json"),
|
|
748
|
+
redact(JSON.stringify(record, null, 2)) + "\n"
|
|
749
|
+
)
|
|
750
|
+
return record
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function loadRecords(dir) {
|
|
754
|
+
const records = []
|
|
755
|
+
const walk = (d) => {
|
|
756
|
+
for (const entry of readdirSync(d, { withFileTypes: true })) {
|
|
757
|
+
const p = join(d, entry.name)
|
|
758
|
+
if (entry.isDirectory() && entry.name !== "solution") walk(p)
|
|
759
|
+
else if (entry.name === "score.json")
|
|
760
|
+
records.push({ ...JSON.parse(readFileSync(p, "utf8")), _dir: d })
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
walk(dir)
|
|
764
|
+
return records
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Re-audits every run from its stored transcript with the current scanner
|
|
769
|
+
* (the run directory it names in its init message), in memory: the records
|
|
770
|
+
* on disk are not changed.
|
|
771
|
+
*/
|
|
772
|
+
function rescan(records) {
|
|
773
|
+
let changed = 0
|
|
774
|
+
const out = records.map((r) => {
|
|
775
|
+
const transcript = r._dir && join(r._dir, "agent.stdout")
|
|
776
|
+
if (!transcript || !existsSync(transcript) || r.harnessError) return r
|
|
777
|
+
const text = readFileSync(transcript, "utf8")
|
|
778
|
+
const runDir = transcriptCwd(text)
|
|
779
|
+
if (!runDir) return r
|
|
780
|
+
const audit = scanTranscript(text, { runDir })
|
|
781
|
+
if (audit.contaminated !== Boolean(r.contaminated)) changed += 1
|
|
782
|
+
return {
|
|
783
|
+
...r,
|
|
784
|
+
contaminatedAtRun: Boolean(r.contaminated),
|
|
785
|
+
contaminated: audit.contaminated,
|
|
786
|
+
audit: {
|
|
787
|
+
auditable: audit.auditable,
|
|
788
|
+
toolCalls: audit.toolCalls,
|
|
789
|
+
attempts: audit.attempts,
|
|
790
|
+
violations: audit.violations.slice(0, 20),
|
|
791
|
+
persistedReads: audit.persistedReads.slice(0, 20),
|
|
792
|
+
},
|
|
793
|
+
}
|
|
794
|
+
})
|
|
795
|
+
process.stdout.write(
|
|
796
|
+
`rescan: ${out.length} runs re-audited from their transcripts; contamination changed in ${changed}; ` +
|
|
797
|
+
`now ${out.filter((r) => r.contaminated && !r.harnessError).length} contaminated ` +
|
|
798
|
+
`(was ${records.filter((r) => r.contaminated && !r.harnessError).length})\n\n`
|
|
799
|
+
)
|
|
800
|
+
return out
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Re-scores every stored solution with the current hidden tests and
|
|
805
|
+
* task.json, under the prompt variant its run used; the run's agent record is
|
|
806
|
+
* kept. Writes score.rescored.json beside each score.json (never changed).
|
|
807
|
+
*/
|
|
808
|
+
async function rescore(args, records) {
|
|
809
|
+
let changed = 0
|
|
810
|
+
let errors = 0
|
|
811
|
+
const out = [...records]
|
|
812
|
+
await pool(
|
|
813
|
+
records.map((r, i) => [r, i]),
|
|
814
|
+
args.jobs,
|
|
815
|
+
async ([r, i]) => {
|
|
816
|
+
if (r.harnessError || !r._dir || !existsSync(join(r._dir, "solution")))
|
|
817
|
+
return
|
|
818
|
+
const agentFile = join(r._dir, "agent.json")
|
|
819
|
+
const meta = existsSync(agentFile)
|
|
820
|
+
? JSON.parse(readFileSync(agentFile, "utf8"))
|
|
821
|
+
: {}
|
|
822
|
+
let score
|
|
823
|
+
let lastError = ""
|
|
824
|
+
for (let attempt = 0; attempt <= args.retries && !score; attempt += 1) {
|
|
825
|
+
const s = await scoreOnce(r, r._dir, r.prompt ?? "explicit")
|
|
826
|
+
if (s.code === 0) score = JSON.parse(s.out)
|
|
827
|
+
else
|
|
828
|
+
lastError = redact(`score.mjs exit ${s.code}: ${s.err.slice(-2000)}`)
|
|
829
|
+
}
|
|
830
|
+
if (!score) {
|
|
831
|
+
errors += 1
|
|
832
|
+
process.stderr.write(`${r._dir}: rescoring failed: ${lastError}\n`)
|
|
833
|
+
out[i] = { ...r, harnessError: lastError, harnessKind: "rescoring" }
|
|
834
|
+
return
|
|
835
|
+
}
|
|
836
|
+
delete score.details
|
|
837
|
+
const record = {
|
|
838
|
+
...score,
|
|
839
|
+
...meta,
|
|
840
|
+
// agent.json never carries a score; keep the run's own variant and
|
|
841
|
+
// a re-audit (--rescan) if one was made.
|
|
842
|
+
prompt: r.prompt ?? "explicit",
|
|
843
|
+
contaminated: r.contaminated,
|
|
844
|
+
...(r.contaminatedAtRun !== undefined
|
|
845
|
+
? { contaminatedAtRun: r.contaminatedAtRun, audit: r.audit }
|
|
846
|
+
: {}),
|
|
847
|
+
scoredAtRun: { safe: r.safe, requirementsMet: r.requirementsMet },
|
|
848
|
+
}
|
|
849
|
+
if (
|
|
850
|
+
record.safe !== r.safe ||
|
|
851
|
+
record.requirementsMet !== r.requirementsMet
|
|
852
|
+
)
|
|
853
|
+
changed += 1
|
|
854
|
+
writeFileSync(
|
|
855
|
+
join(r._dir, "score.rescored.json"),
|
|
856
|
+
redact(JSON.stringify(record, null, 2)) + "\n"
|
|
857
|
+
)
|
|
858
|
+
out[i] = { ...record, _dir: r._dir }
|
|
859
|
+
}
|
|
860
|
+
)
|
|
861
|
+
process.stdout.write(
|
|
862
|
+
`rescore: ${records.length} runs re-scored from their stored solutions with the current hidden tests; ` +
|
|
863
|
+
`safe or requirements-met changed in ${changed}; rescoring errors ${errors}\n\n`
|
|
864
|
+
)
|
|
865
|
+
return out
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
async function report(args, records, outDir) {
|
|
869
|
+
if (args.rescan) records = rescan(records)
|
|
870
|
+
if (args.rescore) records = await rescore(args, records)
|
|
871
|
+
const suffix =
|
|
872
|
+
(args.rescan ? ".rescanned" : "") + (args.rescore ? ".rescored" : "")
|
|
873
|
+
records = records.map(({ _dir, ...r }) => r)
|
|
874
|
+
const summary = aggregate(records)
|
|
875
|
+
writeFileSync(
|
|
876
|
+
join(outDir, `summary${suffix}.json`),
|
|
877
|
+
redact(JSON.stringify(summary, null, 2)) + "\n"
|
|
878
|
+
)
|
|
879
|
+
printSummary(summary)
|
|
880
|
+
if (args.pilot) {
|
|
881
|
+
const pilot = pilotReport(records, { margin: args.margin })
|
|
882
|
+
writeFileSync(
|
|
883
|
+
join(outDir, `pilot${suffix}.json`),
|
|
884
|
+
redact(JSON.stringify(pilot, null, 2)) + "\n"
|
|
885
|
+
)
|
|
886
|
+
process.stdout.write("\n")
|
|
887
|
+
printPilot(pilot)
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
function describeAuth(args) {
|
|
892
|
+
if (args.auth === "oauth") {
|
|
893
|
+
return (
|
|
894
|
+
`Claude subscription token from ${args.authSource}` +
|
|
895
|
+
(process.env[AUTH_VARS.api_key]
|
|
896
|
+
? ` (${AUTH_VARS.api_key} is set but not passed)`
|
|
897
|
+
: "")
|
|
898
|
+
)
|
|
899
|
+
}
|
|
900
|
+
if (args.auth === "api_key") return `${AUTH_VARS.api_key} (API billing)`
|
|
901
|
+
return "none (custom agent command)"
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* One tiny call in an isolated run directory, environment and sandbox exactly
|
|
906
|
+
* like an agent run's. Succeeds when the CLI returns a successful result that
|
|
907
|
+
* is not an error; otherwise prints the CLI's result text and stops.
|
|
908
|
+
*/
|
|
909
|
+
export async function preflight(args) {
|
|
910
|
+
const batchDir = makeBatchDir()
|
|
911
|
+
try {
|
|
912
|
+
const prepared = prepareBareRun({ batchDir })
|
|
913
|
+
const { argv } = agentCommand(
|
|
914
|
+
args,
|
|
915
|
+
{ promptFile: "", runRoot: prepared.runRoot },
|
|
916
|
+
undefined,
|
|
917
|
+
args.preflightCmd
|
|
918
|
+
)
|
|
919
|
+
const logBase = join(prepared.runRoot, "preflight")
|
|
920
|
+
const r = await spawnAgent(argv, {
|
|
921
|
+
cwd: prepared.work,
|
|
922
|
+
env: agentEnv(prepared, AUTH),
|
|
923
|
+
timeoutMs: 5 * 60_000,
|
|
924
|
+
logBase,
|
|
925
|
+
})
|
|
926
|
+
const outcome = agentOutcome(r.out, { ...r, stderr: r.err })
|
|
927
|
+
if (outcome.exit !== "normal") {
|
|
928
|
+
throw new Error(
|
|
929
|
+
`preflight failed (${outcome.exit}): the CLI said: ` +
|
|
930
|
+
redact(outcome.resultText ?? r.err.slice(-500) ?? "(nothing)") +
|
|
931
|
+
(outcome.exit === "sign_in_error"
|
|
932
|
+
? " — check --oauth-token-file / CLAUDE_CODE_OAUTH_TOKEN (`claude setup-token`) or ANTHROPIC_API_KEY"
|
|
933
|
+
: "")
|
|
934
|
+
)
|
|
935
|
+
}
|
|
936
|
+
process.stdout.write(
|
|
937
|
+
`preflight ok (${describeAuth(args)}; model ${args.model}; effort ${args.effort ?? "default"})\n`
|
|
938
|
+
)
|
|
939
|
+
} finally {
|
|
940
|
+
rmSync(batchDir, { recursive: true, force: true })
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// ---------------------------------------------------------------- main
|
|
945
|
+
/**
|
|
946
|
+
* A new batch starts in a new or empty directory. In one that already holds
|
|
947
|
+
* files, plan.json would be overwritten while the run directories stayed: a
|
|
948
|
+
* run with an agent.json would count as run, one with a score.json as scored,
|
|
949
|
+
* and the summary would aggregate another batch's records with this one's.
|
|
950
|
+
* Only --resume continues a batch in place.
|
|
951
|
+
*/
|
|
952
|
+
function refuseUsedOutDir(outDir) {
|
|
953
|
+
if (!existsSync(outDir)) return
|
|
954
|
+
if (!statSync(outDir).isDirectory()) {
|
|
955
|
+
throw new Error(`--out ${outDir} exists and is not a directory`)
|
|
956
|
+
}
|
|
957
|
+
if (readdirSync(outDir).length > 0) {
|
|
958
|
+
throw new Error(
|
|
959
|
+
`--out ${outDir} already holds files: a new batch needs a new or empty directory, ` +
|
|
960
|
+
"or it would count the runs recorded there as its own. " +
|
|
961
|
+
`Continue that batch with --resume ${outDir}, or pick another --out.`
|
|
962
|
+
)
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
async function main() {
|
|
967
|
+
const args = parseArgs(process.argv.slice(2))
|
|
968
|
+
if (args.preflight && !args.dryRun) {
|
|
969
|
+
await preflight(args)
|
|
970
|
+
return
|
|
971
|
+
}
|
|
972
|
+
if (args.aggregate) {
|
|
973
|
+
await report(
|
|
974
|
+
args,
|
|
975
|
+
loadRecords(resolve(args.aggregate)),
|
|
976
|
+
resolve(args.aggregate)
|
|
977
|
+
)
|
|
978
|
+
return
|
|
979
|
+
}
|
|
980
|
+
let outDir
|
|
981
|
+
let runs
|
|
982
|
+
let savedV4Source
|
|
983
|
+
if (args.resume) {
|
|
984
|
+
outDir = resolve(args.resume)
|
|
985
|
+
const saved = JSON.parse(readFileSync(join(outDir, "plan.json"), "utf8"))
|
|
986
|
+
// A batch keeps its prompt variant (batches from before --prompt existed
|
|
987
|
+
// were explicit); asking to resume it with another one is refused.
|
|
988
|
+
const savedPrompt = saved.args.prompt ?? "explicit"
|
|
989
|
+
if (args.promptGiven && args.prompt !== savedPrompt) {
|
|
990
|
+
throw new Error(
|
|
991
|
+
`${outDir} is a --prompt ${savedPrompt} batch; it cannot be resumed with --prompt ${args.prompt}`
|
|
992
|
+
)
|
|
993
|
+
}
|
|
994
|
+
Object.assign(args, {
|
|
995
|
+
...saved.args,
|
|
996
|
+
prompt: savedPrompt,
|
|
997
|
+
resume: args.resume,
|
|
998
|
+
dryRun: args.dryRun,
|
|
999
|
+
pilot: args.pilot || saved.args.pilot,
|
|
1000
|
+
oauthTokenFile: args.oauthTokenFile ?? saved.args.oauthTokenFile,
|
|
1001
|
+
})
|
|
1002
|
+
resolveCredential(args)
|
|
1003
|
+
if (!args.customCmd && !AUTH) throw new Error(MISSING_AUTH_MESSAGE)
|
|
1004
|
+
runs = saved.runs
|
|
1005
|
+
savedV4Source = saved.v4Source
|
|
1006
|
+
} else {
|
|
1007
|
+
runs = plan(args)
|
|
1008
|
+
outDir = resolve(
|
|
1009
|
+
args.out ??
|
|
1010
|
+
join(EVALS, "runs", new Date().toISOString().replace(/[:.]/g, "-"))
|
|
1011
|
+
)
|
|
1012
|
+
refuseUsedOutDir(outDir)
|
|
1013
|
+
}
|
|
1014
|
+
const cells = args.tasks.length * args.conditions.length
|
|
1015
|
+
// Where the v4 packages under test came from (setup.mjs --v4-from): the
|
|
1016
|
+
// tarballs' integrity and the guide's size and sha256, kept in plan.json.
|
|
1017
|
+
const v4 = args.conditions.includes("v4") ? { v4Source: v4Source() } : {}
|
|
1018
|
+
if (args.conditions.includes("v4")) refuseMissingV4Source(v4.v4Source, args)
|
|
1019
|
+
if (args.resume && args.conditions.includes("v4"))
|
|
1020
|
+
refuseChangedV4Source(savedV4Source, v4.v4Source)
|
|
1021
|
+
|
|
1022
|
+
if (args.dryRun) {
|
|
1023
|
+
const example = agentCommand(args, { promptFile: "<run>/prompt.md" })
|
|
1024
|
+
process.stdout.write(
|
|
1025
|
+
[
|
|
1026
|
+
`drive.mjs --dry-run${args.pilot ? " --pilot" : ""}: nothing will be launched.`,
|
|
1027
|
+
`cells: ${cells} (tasks: ${args.tasks.join(", ")}; conditions: ${args.conditions.join(", ")})`,
|
|
1028
|
+
`runs: ${runs.length} (${args.n} per cell), round-robin in a shuffle seeded ${args.seed}; ${args.jobs} at a time; timeout ${args.timeoutMin} min; max ${args.maxTurns} turns`,
|
|
1029
|
+
`model: ${args.model ?? "<unset: an owner decision; required for a real run>"} (every record carries it; models are never pooled)`,
|
|
1030
|
+
`mode: ${args.mode} (${args.mode === "sandboxed" ? "agents may run tsc, vitest and node, inside the OS sandbox" : "type-check feedback only"})`,
|
|
1031
|
+
`sandbox: ${sandboxAvailable() ? `sandbox-exec; readable toolchain: ${[nodeInstallDir(), cliInstallDir("claude") ?? "<claude CLI not on PATH here>", ...args.sandboxAllow].join(", ")}` : "none available"}`,
|
|
1032
|
+
`run dirs: a fresh 0700 batch dir under the OS temp dir (refused if inside ${REPO}); per run work/ home/ tmp/`,
|
|
1033
|
+
`auth: ${args.auth === "none" ? `none found (--oauth-token-file, ${AUTH_VARS.oauth} — see \`claude setup-token\` — or ${AUTH_VARS.api_key}): a real run will refuse to start` : describeAuth(args)}; passed to the agent as exactly one variable; the value is never printed or recorded`,
|
|
1034
|
+
`effort: ${args.effort ?? "the CLI default"} (recorded per run; never pooled across effort levels)`,
|
|
1035
|
+
...(args.conditions.includes("v4")
|
|
1036
|
+
? [
|
|
1037
|
+
`v4 built from: ${describeV4Source(v4.v4Source)} (recorded in plan.json)`,
|
|
1038
|
+
]
|
|
1039
|
+
: []),
|
|
1040
|
+
`prompt: ${args.prompt} (${args.prompt === "explicit" ? "states the safety rules the hidden tests check" : "product and public contract only; no safety rules"}; recorded per run; never pooled across prompt variants)`,
|
|
1041
|
+
`preflight: before any run, one tiny call ("Reply with the single word: ok", max 1 turn) in the same isolated environment and sandbox must succeed; also runnable alone with --preflight`,
|
|
1042
|
+
`agent environment: PATH, HOME=<run>/home, CLAUDE_CONFIG_DIR=<run>/home/.claude, TMPDIR=<run>/tmp, and exactly one of ${AUTH_VARS.oauth} / ${AUTH_VARS.api_key} (the host's ~/.claude login is not visible)`,
|
|
1043
|
+
"rate limits: a usage/rate-limit exit is a harness error, retried with backoff (up to --rate-limit-retries), then excluded and counted — never scored as a failed solution",
|
|
1044
|
+
"leak audit: stream-json transcript scanned; a successful outside read or network use marks the run contaminated (excluded from main, kept in intent-to-treat)",
|
|
1045
|
+
"scoring: after every agent run has ended, in score.mjs's own 0700 directory; harness errors retried, then excluded and counted",
|
|
1046
|
+
`results: ${outDir}/<task>/<condition>/<nnn>/{agent.stdout,agent.stderr,agent.json,solution/,score.json}, plan.json, summary.json${args.pilot ? ", pilot.json" : ""}`,
|
|
1047
|
+
`estimated agent time: ${runs.length} runs × ~${args.estMinutes} min = ${round((runs.length * args.estMinutes) / 60)} agent-hours` +
|
|
1048
|
+
` (~${round((runs.length * args.estMinutes) / 60 / args.jobs)} h wall-clock at ${args.jobs} parallel), plus ~2 min scoring per run`,
|
|
1049
|
+
`agent command (cwd = <run>/work):\n ${example.argv.join(" ")}`,
|
|
1050
|
+
"",
|
|
1051
|
+
"per-cell plan:",
|
|
1052
|
+
...args.tasks.flatMap((task) =>
|
|
1053
|
+
args.conditions.map((condition) => {
|
|
1054
|
+
const docs =
|
|
1055
|
+
conditionDocDirs(condition)
|
|
1056
|
+
.flatMap((d) => readdirSync(d))
|
|
1057
|
+
.join(", ") || "(none)"
|
|
1058
|
+
return ` ${task} × ${condition}: ${args.n} runs; docs/: ${docs}; ${args.prompt} prompt ${renderPrompt(task, condition, args.mode, args.prompt).length} chars`
|
|
1059
|
+
})
|
|
1060
|
+
),
|
|
1061
|
+
"",
|
|
1062
|
+
"first runs, in order:",
|
|
1063
|
+
...runs
|
|
1064
|
+
.slice(0, Math.min(runs.length, 10))
|
|
1065
|
+
.map((r) => ` ${r.task}/${r.condition}#${r.i}`),
|
|
1066
|
+
runs.length > 10 ? ` ... ${runs.length - 10} more` : "",
|
|
1067
|
+
args.pilot
|
|
1068
|
+
? `\nafter the runs: pilot report (variance, minutes/turns/tokens, ceiling/floor warnings, runs per cell for margin ${args.margin})`
|
|
1069
|
+
: "",
|
|
1070
|
+
].join("\n") + "\n"
|
|
1071
|
+
)
|
|
1072
|
+
return
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
process.stdout.write(
|
|
1076
|
+
`auth: ${describeAuth(args)}; effort ${args.effort ?? "default"}; prompt ${args.prompt}; ${args.jobs} agents at a time\n`
|
|
1077
|
+
)
|
|
1078
|
+
mkdirSync(outDir, { recursive: true })
|
|
1079
|
+
if (!args.resume) {
|
|
1080
|
+
writeFileSync(
|
|
1081
|
+
join(outDir, "plan.json"),
|
|
1082
|
+
redact(JSON.stringify({ args, runs, ...v4 }, null, 2)) + "\n"
|
|
1083
|
+
)
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Preflight: one tiny call must succeed before any agent run starts.
|
|
1087
|
+
if (!args.customCmd || args.preflightCmd !== PREFLIGHT_CMD)
|
|
1088
|
+
await preflight(args)
|
|
1089
|
+
|
|
1090
|
+
// Phase 1: agents.
|
|
1091
|
+
let signInFailure
|
|
1092
|
+
const pending = runs.filter(
|
|
1093
|
+
(run) => !existsSync(join(runDirOf(outDir, run), "agent.json"))
|
|
1094
|
+
)
|
|
1095
|
+
const batchDir = makeBatchDir()
|
|
1096
|
+
try {
|
|
1097
|
+
await pool(pending, args.jobs, async (run) => {
|
|
1098
|
+
const label = `${run.task}/${run.condition}#${run.i}`
|
|
1099
|
+
const fail = (kind, message) => {
|
|
1100
|
+
const dir = runDirOf(outDir, run)
|
|
1101
|
+
mkdirSync(dir, { recursive: true })
|
|
1102
|
+
writeFileSync(
|
|
1103
|
+
join(dir, "score.json"),
|
|
1104
|
+
redact(
|
|
1105
|
+
JSON.stringify(
|
|
1106
|
+
{
|
|
1107
|
+
task: run.task,
|
|
1108
|
+
condition: run.condition,
|
|
1109
|
+
run: run.i,
|
|
1110
|
+
model: args.model,
|
|
1111
|
+
effort: args.effort ?? "default",
|
|
1112
|
+
prompt: args.prompt,
|
|
1113
|
+
auth: args.auth,
|
|
1114
|
+
seed: args.seed,
|
|
1115
|
+
mode: args.mode,
|
|
1116
|
+
harnessError: message,
|
|
1117
|
+
harnessKind: kind,
|
|
1118
|
+
},
|
|
1119
|
+
null,
|
|
1120
|
+
2
|
|
1121
|
+
)
|
|
1122
|
+
) + "\n"
|
|
1123
|
+
)
|
|
1124
|
+
}
|
|
1125
|
+
// A pending run with a score.json is a harness error recorded by an
|
|
1126
|
+
// earlier attempt (`fail` above), which --resume runs again: drop that
|
|
1127
|
+
// record so the new attempt is scored like any other run.
|
|
1128
|
+
rmSync(join(runDirOf(outDir, run), "score.json"), { force: true })
|
|
1129
|
+
let errors = 0
|
|
1130
|
+
let limits = 0
|
|
1131
|
+
for (;;) {
|
|
1132
|
+
try {
|
|
1133
|
+
const meta = await agentRun(args, batchDir, outDir, run)
|
|
1134
|
+
process.stdout.write(
|
|
1135
|
+
`${label}: agent ${meta.agent.exit}` +
|
|
1136
|
+
`${meta.contaminated ? " CONTAMINATED" : ""} (${meta.agent.minutes} min)\n`
|
|
1137
|
+
)
|
|
1138
|
+
return
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
if (error instanceof SignInError) {
|
|
1141
|
+
if (!batchAbort.signal.aborted) {
|
|
1142
|
+
signInFailure = `${label}: ${error.message}`
|
|
1143
|
+
batchAbort.abort()
|
|
1144
|
+
}
|
|
1145
|
+
return
|
|
1146
|
+
}
|
|
1147
|
+
if (error instanceof RateLimited) {
|
|
1148
|
+
limits += 1
|
|
1149
|
+
if (limits > args.rateLimitRetries) {
|
|
1150
|
+
process.stderr.write(
|
|
1151
|
+
`${label}: still rate limited; excluded as a harness error\n`
|
|
1152
|
+
)
|
|
1153
|
+
fail("rate_limited", error.message)
|
|
1154
|
+
return
|
|
1155
|
+
}
|
|
1156
|
+
const backoff =
|
|
1157
|
+
args.rateLimitBackoffMin * 60_000 * 2 ** (limits - 1)
|
|
1158
|
+
const untilReset = error.until
|
|
1159
|
+
? error.until - Date.now() + 60_000
|
|
1160
|
+
: 0
|
|
1161
|
+
const wait = Math.min(
|
|
1162
|
+
Math.max(backoff, untilReset),
|
|
1163
|
+
args.rateLimitMaxWaitMin * 60_000
|
|
1164
|
+
)
|
|
1165
|
+
process.stderr.write(
|
|
1166
|
+
`${label}: rate limited (${error.message.slice(0, 120)}); retry ${limits}/${args.rateLimitRetries} in ${round(wait / 60_000)} min\n`
|
|
1167
|
+
)
|
|
1168
|
+
await new Promise((r) => setTimeout(r, wait))
|
|
1169
|
+
continue
|
|
1170
|
+
}
|
|
1171
|
+
errors += 1
|
|
1172
|
+
const message = redact(String(error?.stack ?? error))
|
|
1173
|
+
process.stderr.write(
|
|
1174
|
+
`${label}: harness error (attempt ${errors}): ${redact(error?.message ?? error)}\n`
|
|
1175
|
+
)
|
|
1176
|
+
if (errors > args.retries) {
|
|
1177
|
+
fail("harness", message)
|
|
1178
|
+
return
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
})
|
|
1183
|
+
} finally {
|
|
1184
|
+
rmSync(batchDir, { recursive: true, force: true })
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
if (signInFailure) {
|
|
1188
|
+
throw new Error(
|
|
1189
|
+
`the CLI could not sign in, so the batch was stopped at once (${signInFailure}). ` +
|
|
1190
|
+
"Check --oauth-token-file / CLAUDE_CODE_OAUTH_TOKEN (`claude setup-token`) or " +
|
|
1191
|
+
`ANTHROPIC_API_KEY, then continue with --resume ${outDir}`
|
|
1192
|
+
)
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// Phase 2: scoring, only now that no agent is running.
|
|
1196
|
+
const toScore = runs.filter(
|
|
1197
|
+
(run) =>
|
|
1198
|
+
existsSync(join(runDirOf(outDir, run), "agent.json")) &&
|
|
1199
|
+
!existsSync(join(runDirOf(outDir, run), "score.json"))
|
|
1200
|
+
)
|
|
1201
|
+
await pool(toScore, args.jobs, async (run) => {
|
|
1202
|
+
const record = await scoreRun(args, outDir, run)
|
|
1203
|
+
process.stdout.write(
|
|
1204
|
+
`${run.task}/${run.condition}#${run.i}: ` +
|
|
1205
|
+
(record.harnessError
|
|
1206
|
+
? "SCORING HARNESS ERROR (excluded)"
|
|
1207
|
+
: `safe ${record.safe}, met ${record.requirementsMet}`) +
|
|
1208
|
+
"\n"
|
|
1209
|
+
)
|
|
1210
|
+
})
|
|
1211
|
+
|
|
1212
|
+
// Phase 3: aggregation.
|
|
1213
|
+
await report(args, loadRecords(outDir), outDir)
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
1217
|
+
main().catch((error) => {
|
|
1218
|
+
process.stderr.write(`drive.mjs: ${error?.stack ?? error}\n`)
|
|
1219
|
+
process.exit(2)
|
|
1220
|
+
})
|
|
1221
|
+
}
|