@ic-reactor/mcp 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +108 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
- package/.github/actions/setup-rust-wasm/action.yml +25 -0
- package/.github/dependabot.yml +107 -0
- package/.github/workflows/auth-latest.yml +67 -0
- package/.github/workflows/b3pay-site.yml +49 -0
- package/.github/workflows/ci.yml +430 -0
- package/.github/workflows/codeql.yml +41 -0
- package/.github/workflows/dependency-review.yml +68 -0
- package/.github/workflows/docs-check.yml +98 -0
- package/.github/workflows/docs.yml +265 -0
- package/.github/workflows/e2e.yml +90 -0
- package/.github/workflows/examples-published.yml +97 -0
- package/.github/workflows/release.yml +326 -0
- package/.husky/pre-commit +12 -0
- package/.prettierignore +109 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +103 -0
- package/CHANGELOG.md +3268 -0
- package/CLAUDE.md +93 -0
- package/CNAME +1 -0
- package/CODE_OF_CONDUCT.md +7 -0
- package/CONTRIBUTING.md +433 -0
- package/LICENSE +21 -0
- package/README.md +2 -2
- package/SECURITY.md +74 -0
- package/b3pay-module.json +194 -0
- package/docs/.remarkrc.json +10 -0
- package/docs/README.md +64 -0
- package/docs/astro.config.mjs +205 -0
- package/docs/favicon.svg +15 -0
- package/docs/package.json +39 -0
- package/docs/public/favicon.svg +15 -0
- package/docs/public/ic-reactor-social-card.png +0 -0
- package/docs/scripts/b3pay-static.mjs +22 -0
- package/docs/scripts/check-example-docs.mjs +214 -0
- package/docs/scripts/check-links.mjs +212 -0
- package/docs/scripts/fix-dist-links.js +125 -0
- package/docs/scripts/fix-frontmatter.js +71 -0
- package/docs/scripts/remove-redundant-h1.cjs +48 -0
- package/docs/scripts/rewrite-typedoc-links.js +110 -0
- package/docs/scripts/split-index.js +69 -0
- package/docs/src/assets/ic-reactor-hero-dark.svg +23 -0
- package/docs/src/assets/ic-reactor-hero-light.svg +23 -0
- package/docs/src/assets/ic-reactor-lockup-dark.svg +15 -0
- package/docs/src/assets/ic-reactor-lockup-light.svg +15 -0
- package/docs/src/assets/ic-reactor-mark-dark.svg +14 -0
- package/docs/src/assets/ic-reactor-mark-light.svg +14 -0
- package/docs/src/assets/layers/candid-core-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/candid-core-layer-icon-light.svg +4 -0
- package/docs/src/assets/layers/candid-profile-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/candid-profile-layer-icon-light.svg +4 -0
- package/docs/src/assets/layers/ic-reactor-layer-icon-dark.svg +4 -0
- package/docs/src/assets/layers/ic-reactor-layer-icon-light.svg +4 -0
- package/docs/src/components/LibraryCards.astro +172 -0
- package/docs/src/components/LibraryIcon.astro +28 -0
- package/docs/src/components/SiteTitle.astro +241 -0
- package/docs/src/content/docs/404.mdx +19 -0
- package/docs/src/content/docs/build/agent-tools.mdx +593 -0
- package/docs/src/content/docs/build/icrc1-wallet.mdx +619 -0
- package/docs/src/content/docs/build/ssr-per-user.mdx +552 -0
- package/docs/src/content/docs/examples/canister-studio.mdx +95 -0
- package/docs/src/content/docs/examples/icrc-ledger.mdx +45 -0
- package/docs/src/content/docs/examples/index.mdx +38 -0
- package/docs/src/content/docs/examples/next-ssr.mdx +73 -0
- package/docs/src/content/docs/examples/node-agent-tool.mdx +80 -0
- package/docs/src/content/docs/examples/vite-wallet.mdx +71 -0
- package/docs/src/content/docs/guides/auth.mdx +1181 -0
- package/docs/src/content/docs/guides/client.mdx +551 -0
- package/docs/src/content/docs/guides/deploy.mdx +180 -0
- package/docs/src/content/docs/guides/errors.mdx +475 -0
- package/docs/src/content/docs/guides/getting-started.mdx +620 -0
- package/docs/src/content/docs/guides/reads.mdx +586 -0
- package/docs/src/content/docs/guides/ssr.mdx +529 -0
- package/docs/src/content/docs/guides/testing.mdx +401 -0
- package/docs/src/content/docs/guides/values.mdx +261 -0
- package/docs/src/content/docs/guides/vite-plugin.mdx +690 -0
- package/docs/src/content/docs/guides/writes.mdx +572 -0
- package/docs/src/content/docs/ic-reactor/index.mdx +167 -0
- package/docs/src/content/docs/index.mdx +65 -0
- package/docs/src/content/docs/migrating-from-3.mdx +535 -0
- package/docs/src/content/docs/packages/core.mdx +186 -0
- package/docs/src/content/docs/packages/mcp.mdx +163 -0
- package/docs/src/content/docs/packages/react.mdx +207 -0
- package/docs/src/content/docs/packages/vite-plugin.mdx +73 -0
- package/docs/src/content/docs/versioning.mdx +104 -0
- package/docs/src/content.config.ts +7 -0
- package/docs/src/styles/custom.css +189 -0
- package/docs/tsconfig.typedoc.json +26 -0
- package/docs/typedoc-entry.ts +17 -0
- package/docs/typedoc.json +37 -0
- package/e2e/Cargo.lock +646 -0
- package/e2e/Cargo.toml +3 -0
- package/e2e/README.md +101 -0
- package/e2e/frontends/build.mjs +94 -0
- package/e2e/frontends/index.html +10 -0
- package/e2e/global-setup.ts +65 -0
- package/e2e/icp.yaml +38 -0
- package/e2e/package.json +40 -0
- package/e2e/setup.ts +6 -0
- package/e2e/src/actor/Cargo.toml +14 -0
- package/e2e/src/actor/hello_actor.did +10 -0
- package/e2e/src/actor/src/lib.rs +73 -0
- package/e2e/src/calls.test.ts +132 -0
- package/e2e/src/declarations/hello_actor.envelope.json +175 -0
- package/e2e/src/declarations/hello_actor.ts +15 -0
- package/e2e/src/errors.test.ts +107 -0
- package/e2e/src/frontend-headers.test.ts +253 -0
- package/e2e/src/identity.test.ts +61 -0
- package/e2e/src/react.test.tsx +59 -0
- package/e2e/src/replica.ts +70 -0
- package/e2e/src/vite-env.test.ts +108 -0
- package/e2e/test.sh +47 -0
- package/e2e/tsconfig.json +20 -0
- package/e2e/tsconfig.typecheck.json +9 -0
- package/e2e/vitest.config.ts +22 -0
- package/eslint.config.mjs +100 -0
- package/evals/PREREGISTRATION.md +1346 -0
- package/evals/README.md +756 -0
- package/evals/conditions/thin/condition.json +8 -0
- package/evals/conditions/thin/docs/candid-core-cli.README.md +90 -0
- package/evals/conditions/thin/docs/candid-core-schema.README.md +339 -0
- package/evals/conditions/thin/package.json +25 -0
- package/evals/conditions/thin/starter/src/generated/icrc1.ts +57 -0
- package/evals/conditions/thin-guide/condition.json +10 -0
- package/evals/conditions/thin-guide/docs/llms.txt +292 -0
- package/evals/conditions/v3/condition.json +9 -0
- package/evals/conditions/v3/docs/ic-reactor-core.llms.txt +232 -0
- package/evals/conditions/v3/docs/ic-reactor-react.llms.txt +280 -0
- package/evals/conditions/v3/docs/llms-full.txt +1053 -0
- package/evals/conditions/v3/package.json +26 -0
- package/evals/conditions/v3/starter/src/declarations/icrc1.did.d.ts +95 -0
- package/evals/conditions/v3/starter/src/declarations/icrc1.did.js +140 -0
- package/evals/conditions/v4/PORTING.md +384 -0
- package/evals/conditions/v4/README.md +106 -0
- package/evals/conditions/v4/condition.json +5 -0
- package/evals/conditions/v4/docs/llms.txt +323 -0
- package/evals/conditions/v4/package.json +27 -0
- package/evals/conditions/v4/starter/src/generated/icrc1.ts +78 -0
- package/evals/conditions/v4-proto/condition.json +6 -0
- package/evals/conditions/v4-proto/docs/llms.txt +291 -0
- package/evals/conditions/v4-proto/lib/SHIM-NOTES.md +20 -0
- package/evals/conditions/v4-proto/lib/package.json +27 -0
- package/evals/conditions/v4-proto/lib/src/client.ts +471 -0
- package/evals/conditions/v4-proto/lib/src/errors.ts +214 -0
- package/evals/conditions/v4-proto/lib/src/index.ts +36 -0
- package/evals/conditions/v4-proto/lib/src/principal.ts +175 -0
- package/evals/conditions/v4-proto/lib/src/service.ts +69 -0
- package/evals/conditions/v4-proto/lib/src/types.ts +174 -0
- package/evals/conditions/v4-proto/lib/test/runtime.test.ts +170 -0
- package/evals/conditions/v4-proto/lib/test/tsconfig.json +10 -0
- package/evals/conditions/v4-proto/lib/test/types.test-d.ts +145 -0
- package/evals/conditions/v4-proto/lib/test/vitest.config.mjs +8 -0
- package/evals/conditions/v4-proto/lib/tsconfig.json +17 -0
- package/evals/conditions/v4-proto/package.json +26 -0
- package/evals/conditions/v4-proto/starter/src/generated/icrc1.service.ts +19 -0
- package/evals/conditions/v4-proto/starter/src/generated/icrc1.ts +57 -0
- package/evals/drive.mjs +1221 -0
- package/evals/gate.mjs +161 -0
- package/evals/harness/aggregate.mjs +534 -0
- package/evals/harness/aggregate.test.mjs +344 -0
- package/evals/harness/assemble.mjs +216 -0
- package/evals/harness/assemble.test.mjs +143 -0
- package/evals/harness/auth.mjs +91 -0
- package/evals/harness/check-docs.mjs +157 -0
- package/evals/harness/declarations/icrc1.did.d.ts +95 -0
- package/evals/harness/declarations/icrc1.did.js +140 -0
- package/evals/harness/drive-auth.test.mjs +584 -0
- package/evals/harness/drive.test.mjs +509 -0
- package/evals/harness/fake-auth.ts +67 -0
- package/evals/harness/fake-ledger.ts +178 -0
- package/evals/harness/gate-plan.mjs +104 -0
- package/evals/harness/gate-plan.test.mjs +243 -0
- package/evals/harness/icrc1.did +88 -0
- package/evals/harness/judge.mjs +63 -0
- package/evals/harness/judge.test.mjs +81 -0
- package/evals/harness/leak-scan.mjs +1373 -0
- package/evals/harness/leak-scan.test.mjs +1300 -0
- package/evals/harness/probes/amounts.ts +14 -0
- package/evals/harness/probes/node-tool.probe.ts +48 -0
- package/evals/harness/probes/probe.mjs +149 -0
- package/evals/harness/probes/react-wallet.probe.ts +96 -0
- package/evals/harness/public/support/auth.ts +38 -0
- package/evals/harness/public/support/fake-replica.d.ts +28 -0
- package/evals/harness/public/support/fake-replica.js +434 -0
- package/evals/harness/public/support/ledger.idl.d.ts +95 -0
- package/evals/harness/public/support/ledger.idl.js +140 -0
- package/evals/harness/public/support/world.ts +179 -0
- package/evals/harness/runs.mjs +139 -0
- package/evals/harness/sandbox.mjs +88 -0
- package/evals/harness/sandbox.test.mjs +134 -0
- package/evals/harness/ship.mjs +264 -0
- package/evals/harness/ship.test.mjs +552 -0
- package/evals/harness/world.ts +291 -0
- package/evals/package.json +26 -0
- package/evals/pnpm-lock.yaml +1537 -0
- package/evals/pnpm-workspace.yaml +12 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.json +384 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.json +404 -0
- package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.rescored.json +404 -0
- package/evals/results/2026-09-30T14-22-05-924Z/plan.json +240 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.json +1800 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.json +1843 -0
- package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.rescored.json +2100 -0
- package/evals/results/2026-09-30T15-48-23-343Z/pilot.json +404 -0
- package/evals/results/2026-09-30T15-48-23-343Z/pilot.rescored.json +404 -0
- package/evals/results/2026-09-30T15-48-23-343Z/plan.json +242 -0
- package/evals/results/2026-09-30T15-48-23-343Z/summary.json +1843 -0
- package/evals/results/2026-09-30T15-48-23-343Z/summary.rescored.json +2195 -0
- package/evals/results/2026-10-03-beta1-gate/pilot.json +162 -0
- package/evals/results/2026-10-03-beta1-gate/plan.json +141 -0
- package/evals/results/2026-10-03-beta1-gate/summary.json +983 -0
- package/evals/results/2026-10-05-ga-gate/contaminated-run.json +55 -0
- package/evals/results/2026-10-05-ga-gate/pilot.json +162 -0
- package/evals/results/2026-10-05-ga-gate/plan.json +457 -0
- package/evals/results/2026-10-05-ga-gate/summary.json +1037 -0
- package/evals/results/2026-10-05-ga-gate/summary.rescanned.json +1037 -0
- package/evals/results/README.md +31 -0
- package/evals/runs-pilot.log +150 -0
- package/evals/runs-pilot2.log +150 -0
- package/evals/score.mjs +256 -0
- package/evals/setup.mjs +547 -0
- package/evals/tasks/node-tool/faulty/thin-accepts-exponent/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-accepts-exponent/src/index.ts +121 -0
- package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/src/index.ts +116 -0
- package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-ignores-root-key/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-ignores-root-key/src/index.ts +117 -0
- package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/src/index.ts +119 -0
- package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/thin-number-amount/meta.json +10 -0
- package/evals/tasks/node-tool/faulty/thin-number-amount/src/index.ts +117 -0
- package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/src/index.ts +120 -0
- package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/src/index.ts +118 -0
- package/evals/tasks/node-tool/faulty/v3-retry-call-errors/meta.json +11 -0
- package/evals/tasks/node-tool/faulty/v3-retry-call-errors/src/index.ts +149 -0
- package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/src/index.ts +71 -0
- package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/src/index.ts +84 -0
- package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/meta.json +9 -0
- package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/src/index.ts +72 -0
- package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/src/index.ts +72 -0
- package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/meta.json +5 -0
- package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/src/index.ts +84 -0
- package/evals/tasks/node-tool/hidden/node-tool.test.ts +312 -0
- package/evals/tasks/node-tool/prompt.md +55 -0
- package/evals/tasks/node-tool/prompt.minimal.md +30 -0
- package/evals/tasks/node-tool/solutions/thin/reference/src/index.ts +118 -0
- package/evals/tasks/node-tool/solutions/thin/reference-module-scope/src/index.ts +145 -0
- package/evals/tasks/node-tool/solutions/thin-guide/reference/src/index.ts +118 -0
- package/evals/tasks/node-tool/solutions/thin-guide/reference-module-scope/src/index.ts +145 -0
- package/evals/tasks/node-tool/solutions/v3/reference/src/index.ts +140 -0
- package/evals/tasks/node-tool/solutions/v3/reference-module-scope/src/index.ts +153 -0
- package/evals/tasks/node-tool/solutions/v4/reference/src/index.ts +84 -0
- package/evals/tasks/node-tool/solutions/v4/reference-module-scope/src/index.ts +105 -0
- package/evals/tasks/node-tool/solutions/v4-proto/reference/src/index.ts +72 -0
- package/evals/tasks/node-tool/solutions/v4-proto/reference-module-scope/src/index.ts +87 -0
- package/evals/tasks/node-tool/starter/src/contract.ts +31 -0
- package/evals/tasks/node-tool/starter/src/index.ts +7 -0
- package/evals/tasks/node-tool/starter/test/smoke.test.ts +22 -0
- package/evals/tasks/node-tool/starter/tsconfig.json +17 -0
- package/evals/tasks/node-tool/task.json +63 -0
- package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/src/Wallet.tsx +216 -0
- package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/src/Wallet.tsx +212 -0
- package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/src/Wallet.tsx +210 -0
- package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/meta.json +8 -0
- package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/meta.json +9 -0
- package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-number-balance/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-number-balance/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/src/Wallet.tsx +254 -0
- package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/src/Wallet.tsx +215 -0
- package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/src/Wallet.tsx +214 -0
- package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/src/Wallet.tsx +224 -0
- package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/src/Wallet.tsx +225 -0
- package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/meta.json +11 -0
- package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/src/Wallet.tsx +182 -0
- package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/src/Wallet.tsx +160 -0
- package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/src/Wallet.tsx +166 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/src/Wallet.tsx +162 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-retry-spread/meta.json +12 -0
- package/evals/tasks/react-wallet/faulty/v4-retry-spread/src/Wallet.tsx +163 -0
- package/evals/tasks/react-wallet/faulty/v4-status-not-idle/meta.json +5 -0
- package/evals/tasks/react-wallet/faulty/v4-status-not-idle/src/Wallet.tsx +162 -0
- package/evals/tasks/react-wallet/hidden/react-wallet.test.ts +536 -0
- package/evals/tasks/react-wallet/prompt.md +88 -0
- package/evals/tasks/react-wallet/prompt.minimal.md +51 -0
- package/evals/tasks/react-wallet/solutions/thin/reference/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/solutions/thin/reference-module-scope/src/Wallet.tsx +227 -0
- package/evals/tasks/react-wallet/solutions/thin-guide/reference/src/Wallet.tsx +213 -0
- package/evals/tasks/react-wallet/solutions/thin-guide/reference-module-scope/src/Wallet.tsx +227 -0
- package/evals/tasks/react-wallet/solutions/v3/reference/src/Wallet.tsx +224 -0
- package/evals/tasks/react-wallet/solutions/v3/reference-module-scope/src/Wallet.tsx +230 -0
- package/evals/tasks/react-wallet/solutions/v4/reference/src/Wallet.tsx +160 -0
- package/evals/tasks/react-wallet/solutions/v4/reference-module-scope/src/Wallet.tsx +178 -0
- package/evals/tasks/react-wallet/solutions/v4-proto/reference/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/solutions/v4-proto/reference-module-scope/src/Wallet.tsx +161 -0
- package/evals/tasks/react-wallet/starter/src/Wallet.tsx +12 -0
- package/evals/tasks/react-wallet/starter/src/auth.ts +16 -0
- package/evals/tasks/react-wallet/starter/src/config.ts +14 -0
- package/evals/tasks/react-wallet/starter/src/ii-auth.ts +43 -0
- package/evals/tasks/react-wallet/starter/src/main.tsx +15 -0
- package/evals/tasks/react-wallet/starter/test/smoke.test.ts +34 -0
- package/evals/tasks/react-wallet/starter/tsconfig.json +18 -0
- package/evals/tasks/react-wallet/task.json +84 -0
- package/examples/canister-studio/.stackblitzrc +4 -0
- package/examples/canister-studio/README.md +183 -0
- package/examples/canister-studio/did/ckbtc_minter.did +806 -0
- package/examples/canister-studio/did/icp_ledger.did +586 -0
- package/examples/canister-studio/did/icrc1.did +88 -0
- package/examples/canister-studio/package.json +45 -0
- package/examples/canister-studio/scripts/smoke.ts +188 -0
- package/examples/canister-studio/src/calls/CacheKeyPanel.tsx +104 -0
- package/examples/canister-studio/src/calls/ConfirmWrite.tsx +265 -0
- package/examples/canister-studio/src/calls/ErrorPanel.test.tsx +113 -0
- package/examples/canister-studio/src/calls/ErrorPanel.tsx +214 -0
- package/examples/canister-studio/src/calls/MethodRunner.test.tsx +354 -0
- package/examples/canister-studio/src/calls/MethodRunner.tsx +57 -0
- package/examples/canister-studio/src/calls/ReadRunner.tsx +244 -0
- package/examples/canister-studio/src/calls/ResendPanel.tsx +165 -0
- package/examples/canister-studio/src/calls/ShareLink.tsx +59 -0
- package/examples/canister-studio/src/calls/WriteRunner.test.tsx +678 -0
- package/examples/canister-studio/src/calls/WriteRunner.tsx +670 -0
- package/examples/canister-studio/src/calls/dedupe.ts +189 -0
- package/examples/canister-studio/src/calls/error-info.ts +168 -0
- package/examples/canister-studio/src/calls/history.test.ts +284 -0
- package/examples/canister-studio/src/calls/history.ts +287 -0
- package/examples/canister-studio/src/calls/kinds.ts +68 -0
- package/examples/canister-studio/src/calls/prepare.ts +32 -0
- package/examples/canister-studio/src/calls/query-options.ts +30 -0
- package/examples/canister-studio/src/calls/read.ts +47 -0
- package/examples/canister-studio/src/calls/readback.ts +100 -0
- package/examples/canister-studio/src/calls/record.ts +123 -0
- package/examples/canister-studio/src/calls/safe-calls.test.ts +299 -0
- package/examples/canister-studio/src/calls/share.ts +46 -0
- package/examples/canister-studio/src/calls/testing/doubles.tsx +108 -0
- package/examples/canister-studio/src/calls/testing/fixtures.ts +185 -0
- package/examples/canister-studio/src/calls/useCanisterHandle.ts +35 -0
- package/examples/canister-studio/src/canisters/ckbtc_minter.envelope.json +4228 -0
- package/examples/canister-studio/src/canisters/ckbtc_minter.ts +868 -0
- package/examples/canister-studio/src/canisters/icp_ledger.envelope.json +3454 -0
- package/examples/canister-studio/src/canisters/icp_ledger.ts +584 -0
- package/examples/canister-studio/src/canisters/icrc1.envelope.json +840 -0
- package/examples/canister-studio/src/canisters/icrc1.ts +78 -0
- package/examples/canister-studio/src/components/ActionButton.tsx +32 -0
- package/examples/canister-studio/src/components/AppHeader.tsx +83 -0
- package/examples/canister-studio/src/components/AppShell.tsx +29 -0
- package/examples/canister-studio/src/components/AuthButton.tsx +79 -0
- package/examples/canister-studio/src/components/Badge.tsx +79 -0
- package/examples/canister-studio/src/components/CanisterHeader.tsx +200 -0
- package/examples/canister-studio/src/components/CanisterJump.tsx +130 -0
- package/examples/canister-studio/src/components/Card.tsx +64 -0
- package/examples/canister-studio/src/components/Code.tsx +101 -0
- package/examples/canister-studio/src/components/CopyButton.tsx +126 -0
- package/examples/canister-studio/src/components/Disclosure.tsx +34 -0
- package/examples/canister-studio/src/components/EmptyState.tsx +34 -0
- package/examples/canister-studio/src/components/MethodList.test.tsx +137 -0
- package/examples/canister-studio/src/components/MethodList.tsx +244 -0
- package/examples/canister-studio/src/components/Notice.tsx +36 -0
- package/examples/canister-studio/src/components/ProvenanceBadge.tsx +44 -0
- package/examples/canister-studio/src/components/RouteError.tsx +42 -0
- package/examples/canister-studio/src/components/SectionBoundary.tsx +76 -0
- package/examples/canister-studio/src/components/Spinner.tsx +33 -0
- package/examples/canister-studio/src/components/Tabs.tsx +96 -0
- package/examples/canister-studio/src/components/canister/CanisterLoadFailure.test.tsx +56 -0
- package/examples/canister-studio/src/components/canister/CanisterLoadFailure.tsx +165 -0
- package/examples/canister-studio/src/components/canister/CanisterNotFound.tsx +59 -0
- package/examples/canister-studio/src/components/canister/CanisterPending.tsx +33 -0
- package/examples/canister-studio/src/components/canister/MethodOverview.tsx +93 -0
- package/examples/canister-studio/src/components/canister/MethodWorkspace.test.tsx +201 -0
- package/examples/canister-studio/src/components/canister/MethodWorkspace.tsx +187 -0
- package/examples/canister-studio/src/components/canister/shared-call.test.ts +186 -0
- package/examples/canister-studio/src/components/canister/shared-call.ts +133 -0
- package/examples/canister-studio/src/components/canister/shared-link-loader.test.ts +116 -0
- package/examples/canister-studio/src/components/canister/use-canister-page.ts +44 -0
- package/examples/canister-studio/src/components/canister/workspace-key.test.ts +27 -0
- package/examples/canister-studio/src/components/canister/workspace-key.ts +36 -0
- package/examples/canister-studio/src/components/canister-id-input.ts +69 -0
- package/examples/canister-studio/src/components/canister-names.ts +11 -0
- package/examples/canister-studio/src/components/download.ts +34 -0
- package/examples/canister-studio/src/components/fallbacks.tsx +33 -0
- package/examples/canister-studio/src/components/helpers.test.ts +107 -0
- package/examples/canister-studio/src/components/history/HistoryList.tsx +284 -0
- package/examples/canister-studio/src/components/home/FeaturedLedger.tsx +149 -0
- package/examples/canister-studio/src/components/home/OpenCanister.tsx +99 -0
- package/examples/canister-studio/src/components/home/featured.test.tsx +92 -0
- package/examples/canister-studio/src/components/home/featured.ts +64 -0
- package/examples/canister-studio/src/components/interface/CandidTab.tsx +38 -0
- package/examples/canister-studio/src/components/interface/CompatReport.tsx +92 -0
- package/examples/canister-studio/src/components/interface/CompatibilityTab.tsx +190 -0
- package/examples/canister-studio/src/components/interface/ProjectTab.tsx +196 -0
- package/examples/canister-studio/src/components/interface/TypeScriptTab.tsx +114 -0
- package/examples/canister-studio/src/components/interface/tools.test.tsx +169 -0
- package/examples/canister-studio/src/components/modes.ts +31 -0
- package/examples/canister-studio/src/components/playground/MethodPicker.tsx +67 -0
- package/examples/canister-studio/src/components/playground/PlaygroundForms.tsx +112 -0
- package/examples/canister-studio/src/components/playground/PlaygroundTools.tsx +219 -0
- package/examples/canister-studio/src/components/playground/sample.ts +43 -0
- package/examples/canister-studio/src/components/playground/target.test.tsx +86 -0
- package/examples/canister-studio/src/components/primitives.test.tsx +121 -0
- package/examples/canister-studio/src/components/provenance.ts +38 -0
- package/examples/canister-studio/src/components/route-render.test.tsx +71 -0
- package/examples/canister-studio/src/components/use-task.ts +56 -0
- package/examples/canister-studio/src/components/wallet/BalancePanel.tsx +110 -0
- package/examples/canister-studio/src/components/wallet/LedgerSummary.tsx +63 -0
- package/examples/canister-studio/src/components/wallet/MinterPanel.tsx +255 -0
- package/examples/canister-studio/src/components/wallet/SendPanel.test.tsx +297 -0
- package/examples/canister-studio/src/components/wallet/SendPanel.tsx +446 -0
- package/examples/canister-studio/src/components/wallet/ledgers.test.ts +36 -0
- package/examples/canister-studio/src/components/wallet/ledgers.ts +111 -0
- package/examples/canister-studio/src/forms/JsonPanel.tsx +157 -0
- package/examples/canister-studio/src/forms/MethodForm.test.tsx +369 -0
- package/examples/canister-studio/src/forms/MethodForm.tsx +368 -0
- package/examples/canister-studio/src/forms/TypedForm.tsx +55 -0
- package/examples/canister-studio/src/forms/context.ts +62 -0
- package/examples/canister-studio/src/forms/convert.ts +131 -0
- package/examples/canister-studio/src/forms/edge.test.ts +252 -0
- package/examples/canister-studio/src/forms/engine.test.ts +358 -0
- package/examples/canister-studio/src/forms/engine.ts +1492 -0
- package/examples/canister-studio/src/forms/fields/BytesField.tsx +210 -0
- package/examples/canister-studio/src/forms/fields/Field.tsx +106 -0
- package/examples/canister-studio/src/forms/fields/FieldShell.tsx +101 -0
- package/examples/canister-studio/src/forms/fields/Group.tsx +74 -0
- package/examples/canister-studio/src/forms/fields/ListField.tsx +256 -0
- package/examples/canister-studio/src/forms/fields/Segmented.tsx +78 -0
- package/examples/canister-studio/src/forms/fields/TimestampField.tsx +108 -0
- package/examples/canister-studio/src/forms/fields/UnitsField.tsx +119 -0
- package/examples/canister-studio/src/forms/fields/composites.tsx +389 -0
- package/examples/canister-studio/src/forms/fields/leaves.tsx +350 -0
- package/examples/canister-studio/src/forms/fields.test.tsx +396 -0
- package/examples/canister-studio/src/forms/helpers.test.ts +225 -0
- package/examples/canister-studio/src/forms/hints.ts +128 -0
- package/examples/canister-studio/src/forms/json.ts +119 -0
- package/examples/canister-studio/src/forms/parsing.test.ts +217 -0
- package/examples/canister-studio/src/forms/useMethodForm.ts +251 -0
- package/examples/canister-studio/src/interface/browser.test.ts +23 -0
- package/examples/canister-studio/src/interface/browser.ts +153 -0
- package/examples/canister-studio/src/interface/cache.ts +68 -0
- package/examples/canister-studio/src/interface/cli-cache.test.ts +155 -0
- package/examples/canister-studio/src/interface/cli-cache.ts +125 -0
- package/examples/canister-studio/src/interface/compile.server.test.ts +198 -0
- package/examples/canister-studio/src/interface/compile.server.ts +262 -0
- package/examples/canister-studio/src/interface/compile.test.ts +108 -0
- package/examples/canister-studio/src/interface/compile.ts +305 -0
- package/examples/canister-studio/src/interface/docs.test.ts +75 -0
- package/examples/canister-studio/src/interface/docs.ts +100 -0
- package/examples/canister-studio/src/interface/functions.test.ts +42 -0
- package/examples/canister-studio/src/interface/functions.ts +200 -0
- package/examples/canister-studio/src/interface/live-candid.server.ts +91 -0
- package/examples/canister-studio/src/interface/live-loader.test.ts +515 -0
- package/examples/canister-studio/src/interface/live-loader.ts +364 -0
- package/examples/canister-studio/src/interface/load.test.ts +328 -0
- package/examples/canister-studio/src/interface/load.ts +249 -0
- package/examples/canister-studio/src/interface/read-candid.test.ts +185 -0
- package/examples/canister-studio/src/interface/read-candid.ts +233 -0
- package/examples/canister-studio/src/interface/server-result.ts +42 -0
- package/examples/canister-studio/src/interface/typed.ts +68 -0
- package/examples/canister-studio/src/interface/types.ts +121 -0
- package/examples/canister-studio/src/lib/format.test.ts +107 -0
- package/examples/canister-studio/src/lib/format.ts +139 -0
- package/examples/canister-studio/src/lib/hex.test.ts +43 -0
- package/examples/canister-studio/src/lib/hex.ts +33 -0
- package/examples/canister-studio/src/lib/ids.test.ts +70 -0
- package/examples/canister-studio/src/lib/ids.ts +93 -0
- package/examples/canister-studio/src/lib/reactor.test.ts +55 -0
- package/examples/canister-studio/src/lib/reactor.ts +55 -0
- package/examples/canister-studio/src/lib/registry.test.ts +74 -0
- package/examples/canister-studio/src/lib/registry.ts +238 -0
- package/examples/canister-studio/src/lib/schema.ts +148 -0
- package/examples/canister-studio/src/routeTree.gen.ts +227 -0
- package/examples/canister-studio/src/router.test.ts +290 -0
- package/examples/canister-studio/src/router.tsx +127 -0
- package/examples/canister-studio/src/routes/__root.tsx +58 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.index.tsx +172 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.interface.tsx +98 -0
- package/examples/canister-studio/src/routes/canister.$canisterId.tsx +91 -0
- package/examples/canister-studio/src/routes/history.tsx +55 -0
- package/examples/canister-studio/src/routes/index.tsx +169 -0
- package/examples/canister-studio/src/routes/playground.tsx +286 -0
- package/examples/canister-studio/src/routes/safety.tsx +57 -0
- package/examples/canister-studio/src/routes/wallet.tsx +213 -0
- package/examples/canister-studio/src/safety/LabTransferForm.tsx +84 -0
- package/examples/canister-studio/src/safety/RequestLog.tsx +79 -0
- package/examples/canister-studio/src/safety/SafetyLab.test.tsx +89 -0
- package/examples/canister-studio/src/safety/SafetyLab.tsx +140 -0
- package/examples/canister-studio/src/safety/ScenarioCard.tsx +262 -0
- package/examples/canister-studio/src/safety/lab-run.ts +283 -0
- package/examples/canister-studio/src/safety/mock-ledger.test.ts +99 -0
- package/examples/canister-studio/src/safety/mock-ledger.ts +263 -0
- package/examples/canister-studio/src/safety/scenarios.test.ts +157 -0
- package/examples/canister-studio/src/safety/scenarios.ts +924 -0
- package/examples/canister-studio/src/styles.css +3453 -0
- package/examples/canister-studio/src/styles.test.ts +46 -0
- package/examples/canister-studio/src/values/CallPreview.test.tsx +86 -0
- package/examples/canister-studio/src/values/CallPreview.tsx +148 -0
- package/examples/canister-studio/src/values/ErrValueView.tsx +66 -0
- package/examples/canister-studio/src/values/Inspector.tsx +133 -0
- package/examples/canister-studio/src/values/ReplyView.test.tsx +341 -0
- package/examples/canister-studio/src/values/ReplyView.tsx +164 -0
- package/examples/canister-studio/src/values/candid-text.test.ts +516 -0
- package/examples/canister-studio/src/values/candid-text.ts +479 -0
- package/examples/canister-studio/src/values/hints.ts +58 -0
- package/examples/canister-studio/src/values/json.test.ts +66 -0
- package/examples/canister-studio/src/values/json.ts +31 -0
- package/examples/canister-studio/src/values/leaves.tsx +309 -0
- package/examples/canister-studio/src/values/schema.test.ts +123 -0
- package/examples/canister-studio/src/values/schema.ts +78 -0
- package/examples/canister-studio/src/values/test-router.tsx +21 -0
- package/examples/canister-studio/src/values/tree.tsx +670 -0
- package/examples/canister-studio/src/values/use-sha256.ts +29 -0
- package/examples/canister-studio/tsconfig.json +20 -0
- package/examples/canister-studio/vite.config.ts +50 -0
- package/examples/canister-studio/vitest.config.ts +20 -0
- package/examples/icrc-ledger/.stackblitzrc +4 -0
- package/examples/icrc-ledger/README.md +100 -0
- package/examples/icrc-ledger/ckbtc_minter.did +12 -0
- package/examples/icrc-ledger/icp_ledger.did +147 -0
- package/examples/icrc-ledger/icrc1.did +88 -0
- package/examples/icrc-ledger/index.html +13 -0
- package/examples/icrc-ledger/package.json +40 -0
- package/examples/icrc-ledger/scripts/smoke.ts +151 -0
- package/examples/icrc-ledger/src/App.tsx +71 -0
- package/examples/icrc-ledger/src/ErrorPanel.tsx +105 -0
- package/examples/icrc-ledger/src/MainnetTab.tsx +450 -0
- package/examples/icrc-ledger/src/SandboxTab.test.tsx +379 -0
- package/examples/icrc-ledger/src/SandboxTab.tsx +761 -0
- package/examples/icrc-ledger/src/blocks.test.ts +247 -0
- package/examples/icrc-ledger/src/blocks.ts +140 -0
- package/examples/icrc-ledger/src/canisters/ckbtc_minter.envelope.json +96 -0
- package/examples/icrc-ledger/src/canisters/ckbtc_minter.ts +16 -0
- package/examples/icrc-ledger/src/canisters/icp_ledger.envelope.json +690 -0
- package/examples/icrc-ledger/src/canisters/icp_ledger.ts +223 -0
- package/examples/icrc-ledger/src/canisters/icrc1.envelope.json +840 -0
- package/examples/icrc-ledger/src/canisters/icrc1.ts +78 -0
- package/examples/icrc-ledger/src/format.test.ts +41 -0
- package/examples/icrc-ledger/src/format.ts +68 -0
- package/examples/icrc-ledger/src/ledger.ts +15 -0
- package/examples/icrc-ledger/src/main.tsx +10 -0
- package/examples/icrc-ledger/src/minter.ts +16 -0
- package/examples/icrc-ledger/src/sandbox.test.ts +464 -0
- package/examples/icrc-ledger/src/sandbox.ts +281 -0
- package/examples/icrc-ledger/src/styles.css +391 -0
- package/examples/icrc-ledger/src/transfer-form.test.ts +62 -0
- package/examples/icrc-ledger/src/transfer-form.ts +97 -0
- package/examples/icrc-ledger/tsconfig.json +19 -0
- package/examples/icrc-ledger/vite.config.ts +44 -0
- package/examples/icrc-ledger/vitest.config.ts +12 -0
- package/examples/next-ssr/.stackblitzrc +4 -0
- package/examples/next-ssr/README.md +112 -0
- package/examples/next-ssr/icrc1.did +88 -0
- package/examples/next-ssr/next.config.ts +10 -0
- package/examples/next-ssr/package.json +41 -0
- package/examples/next-ssr/scripts/smoke.ts +169 -0
- package/examples/next-ssr/src/app/account/CertifiedBalances.tsx +58 -0
- package/examples/next-ssr/src/app/account/account.test.tsx +165 -0
- package/examples/next-ssr/src/app/account/page.tsx +82 -0
- package/examples/next-ssr/src/app/api/balance/[ledger]/[principal]/route.ts +10 -0
- package/examples/next-ssr/src/app/globals.css +278 -0
- package/examples/next-ssr/src/app/layout.tsx +34 -0
- package/examples/next-ssr/src/app/page.tsx +46 -0
- package/examples/next-ssr/src/app/providers.browser.test.tsx +127 -0
- package/examples/next-ssr/src/app/providers.test.tsx +73 -0
- package/examples/next-ssr/src/app/providers.tsx +60 -0
- package/examples/next-ssr/src/canisters/icrc1.envelope.json +840 -0
- package/examples/next-ssr/src/canisters/icrc1.ts +78 -0
- package/examples/next-ssr/src/components/BalanceTable.tsx +43 -0
- package/examples/next-ssr/src/components/LedgerCard.test.tsx +96 -0
- package/examples/next-ssr/src/components/LedgerCard.tsx +230 -0
- package/examples/next-ssr/src/components/LedgerError.tsx +32 -0
- package/examples/next-ssr/src/components/LedgerSections.tsx +22 -0
- package/examples/next-ssr/src/components/MyBalances.test.tsx +253 -0
- package/examples/next-ssr/src/components/MyBalances.tsx +129 -0
- package/examples/next-ssr/src/components/SessionBadge.tsx +18 -0
- package/examples/next-ssr/src/components/hydration.test.tsx +259 -0
- package/examples/next-ssr/src/components/server-data.ts +10 -0
- package/examples/next-ssr/src/format.ts +46 -0
- package/examples/next-ssr/src/ledgers.ts +38 -0
- package/examples/next-ssr/src/server/balance-route.test.ts +151 -0
- package/examples/next-ssr/src/server/balance-route.ts +157 -0
- package/examples/next-ssr/src/server/error-summary.test.ts +34 -0
- package/examples/next-ssr/src/server/error-summary.ts +37 -0
- package/examples/next-ssr/src/server/parse-owner.test.ts +39 -0
- package/examples/next-ssr/src/server/parse-owner.ts +34 -0
- package/examples/next-ssr/src/server/prefetch-ledgers.test.ts +137 -0
- package/examples/next-ssr/src/server/prefetch-ledgers.ts +70 -0
- package/examples/next-ssr/src/server/read-balances.test.ts +103 -0
- package/examples/next-ssr/src/server/read-balances.ts +78 -0
- package/examples/next-ssr/src/server/request-client.rsc.test.tsx +110 -0
- package/examples/next-ssr/src/server/request-client.ts +24 -0
- package/examples/next-ssr/src/testing/mock-ledgers.ts +115 -0
- package/examples/next-ssr/src/testing/react-server-dom-turbopack.d.ts +15 -0
- package/examples/next-ssr/src/testing/setup.ts +10 -0
- package/examples/next-ssr/tsconfig.json +31 -0
- package/examples/next-ssr/vitest.config.ts +59 -0
- package/examples/node-agent-tool/.stackblitzrc +4 -0
- package/examples/node-agent-tool/README.md +165 -0
- package/examples/node-agent-tool/icp.yaml +11 -0
- package/examples/node-agent-tool/icrc1.did +88 -0
- package/examples/node-agent-tool/package.json +32 -0
- package/examples/node-agent-tool/src/canisters/icrc1.envelope.json +840 -0
- package/examples/node-agent-tool/src/canisters/icrc1.ts +78 -0
- package/examples/node-agent-tool/src/cli.test.ts +64 -0
- package/examples/node-agent-tool/src/cli.ts +23 -0
- package/examples/node-agent-tool/src/command-line.ts +159 -0
- package/examples/node-agent-tool/src/commands/balance.ts +73 -0
- package/examples/node-agent-tool/src/commands/demo.test.ts +51 -0
- package/examples/node-agent-tool/src/commands/demo.ts +359 -0
- package/examples/node-agent-tool/src/commands/info.ts +69 -0
- package/examples/node-agent-tool/src/commands/reads.test.ts +133 -0
- package/examples/node-agent-tool/src/commands/resend.test.ts +363 -0
- package/examples/node-agent-tool/src/commands/transfer.test.ts +313 -0
- package/examples/node-agent-tool/src/commands/transfer.ts +415 -0
- package/examples/node-agent-tool/src/commands/watch.test.ts +159 -0
- package/examples/node-agent-tool/src/commands/watch.ts +135 -0
- package/examples/node-agent-tool/src/commands/whoami.ts +36 -0
- package/examples/node-agent-tool/src/context.ts +20 -0
- package/examples/node-agent-tool/src/dispatch.ts +70 -0
- package/examples/node-agent-tool/src/failure.test.ts +59 -0
- package/examples/node-agent-tool/src/failure.ts +176 -0
- package/examples/node-agent-tool/src/identity.test.ts +242 -0
- package/examples/node-agent-tool/src/identity.ts +228 -0
- package/examples/node-agent-tool/src/input.ts +110 -0
- package/examples/node-agent-tool/src/ledgers.test.ts +74 -0
- package/examples/node-agent-tool/src/ledgers.ts +62 -0
- package/examples/node-agent-tool/src/mock-ledger.ts +211 -0
- package/examples/node-agent-tool/src/network.test.ts +128 -0
- package/examples/node-agent-tool/src/network.ts +101 -0
- package/examples/node-agent-tool/src/output.test.ts +208 -0
- package/examples/node-agent-tool/src/output.ts +163 -0
- package/examples/node-agent-tool/src/run.ts +73 -0
- package/examples/node-agent-tool/src/test-kit.ts +167 -0
- package/examples/node-agent-tool/tsconfig.json +18 -0
- package/examples/node-agent-tool/vitest.config.ts +8 -0
- package/examples/vite-wallet/.stackblitzrc +4 -0
- package/examples/vite-wallet/Cargo.lock +646 -0
- package/examples/vite-wallet/Cargo.toml +5 -0
- package/examples/vite-wallet/README.md +107 -0
- package/examples/vite-wallet/backend/Cargo.toml +12 -0
- package/examples/vite-wallet/backend/backend.did +37 -0
- package/examples/vite-wallet/backend/src/lib.rs +133 -0
- package/examples/vite-wallet/icp.yaml +44 -0
- package/examples/vite-wallet/index.html +13 -0
- package/examples/vite-wallet/ledger.did +54 -0
- package/examples/vite-wallet/package.json +46 -0
- package/examples/vite-wallet/public/.ic-assets.json5 +26 -0
- package/examples/vite-wallet/scripts/faucet-args.test.ts +30 -0
- package/examples/vite-wallet/scripts/faucet-args.ts +41 -0
- package/examples/vite-wallet/scripts/faucet.ts +41 -0
- package/examples/vite-wallet/src/AddressBook.test.tsx +191 -0
- package/examples/vite-wallet/src/AddressBook.tsx +147 -0
- package/examples/vite-wallet/src/App.tsx +53 -0
- package/examples/vite-wallet/src/Balance.test.tsx +57 -0
- package/examples/vite-wallet/src/Balance.tsx +58 -0
- package/examples/vite-wallet/src/EnvironmentPanel.test.tsx +83 -0
- package/examples/vite-wallet/src/EnvironmentPanel.tsx +103 -0
- package/examples/vite-wallet/src/ErrorNote.tsx +70 -0
- package/examples/vite-wallet/src/Profile.test.tsx +145 -0
- package/examples/vite-wallet/src/Profile.tsx +92 -0
- package/examples/vite-wallet/src/SendIcp.test.tsx +231 -0
- package/examples/vite-wallet/src/SendIcp.tsx +244 -0
- package/examples/vite-wallet/src/SendToContact.test.tsx +113 -0
- package/examples/vite-wallet/src/SendToContact.tsx +102 -0
- package/examples/vite-wallet/src/SignIn.test.tsx +106 -0
- package/examples/vite-wallet/src/SignIn.tsx +120 -0
- package/examples/vite-wallet/src/Wallet.test.tsx +89 -0
- package/examples/vite-wallet/src/account-switch.test.tsx +108 -0
- package/examples/vite-wallet/src/auth/dev-accounts.test.ts +113 -0
- package/examples/vite-wallet/src/auth/dev-accounts.ts +216 -0
- package/examples/vite-wallet/src/auth/local-page.test.ts +28 -0
- package/examples/vite-wallet/src/auth/local-page.ts +20 -0
- package/examples/vite-wallet/src/auth/wallet-auth.test.ts +159 -0
- package/examples/vite-wallet/src/auth/wallet-auth.ts +131 -0
- package/examples/vite-wallet/src/canisters/backend.envelope.json +275 -0
- package/examples/vite-wallet/src/canisters/backend.ts +58 -0
- package/examples/vite-wallet/src/canisters/ledger.envelope.json +451 -0
- package/examples/vite-wallet/src/canisters/ledger.ts +56 -0
- package/examples/vite-wallet/src/client.ts +45 -0
- package/examples/vite-wallet/src/main.tsx +18 -0
- package/examples/vite-wallet/src/optimistic-contacts.ts +113 -0
- package/examples/vite-wallet/src/refusal.ts +17 -0
- package/examples/vite-wallet/src/styles.css +282 -0
- package/examples/vite-wallet/src/test/test-wallet.tsx +322 -0
- package/examples/vite-wallet/src/token.ts +50 -0
- package/examples/vite-wallet/src/transfer.test.ts +178 -0
- package/examples/vite-wallet/src/transfer.ts +110 -0
- package/examples/vite-wallet/src/use-canisters.ts +49 -0
- package/examples/vite-wallet/tsconfig.json +19 -0
- package/examples/vite-wallet/vite.config.ts +47 -0
- package/examples/vite-wallet/vitest.config.ts +17 -0
- package/package.json +9 -4
- package/packages/core/.size-limit.js +47 -0
- package/packages/core/LICENSE +21 -0
- package/packages/core/README.md +84 -0
- package/packages/core/llms.txt +610 -0
- package/packages/core/package.json +89 -0
- package/packages/core/src/call.ts +961 -0
- package/packages/core/src/canister.ts +259 -0
- package/packages/core/src/client.ts +2061 -0
- package/packages/core/src/errors.ts +1079 -0
- package/packages/core/src/hydration.ts +239 -0
- package/packages/core/src/index.ts +23 -0
- package/packages/core/src/keys.ts +108 -0
- package/packages/core/src/management.ts +138 -0
- package/packages/core/src/network.ts +1020 -0
- package/packages/core/src/options.ts +1000 -0
- package/packages/core/src/runtime.ts +50 -0
- package/packages/core/src/testing/fake-replica.ts +1166 -0
- package/packages/core/src/testing/index.ts +16 -0
- package/packages/core/src/testing/test-auth.ts +340 -0
- package/packages/core/src/testing/test-client.ts +559 -0
- package/packages/core/src/types.ts +541 -0
- package/packages/core/src/units.ts +299 -0
- package/packages/core/src/version.ts +4 -0
- package/packages/core/tests/canister-helpers.ts +187 -0
- package/packages/core/tests/canister-id.test.ts +158 -0
- package/packages/core/tests/canister-unwrap.test.ts +94 -0
- package/packages/core/tests/canister.test-d.ts +406 -0
- package/packages/core/tests/canister.test.ts +1921 -0
- package/packages/core/tests/client-account-change.test.ts +131 -0
- package/packages/core/tests/client-agents.test.ts +402 -0
- package/packages/core/tests/client-auth-network.test.ts +719 -0
- package/packages/core/tests/client-disposed.test.ts +403 -0
- package/packages/core/tests/client-helpers.ts +136 -0
- package/packages/core/tests/client-hydration.test.ts +166 -0
- package/packages/core/tests/client-pinned.test.ts +626 -0
- package/packages/core/tests/client-session.test.ts +348 -0
- package/packages/core/tests/client.test-d.ts +181 -0
- package/packages/core/tests/client.test.ts +1162 -0
- package/packages/core/tests/encode.test.ts +171 -0
- package/packages/core/tests/env-canister-id.test.ts +666 -0
- package/packages/core/tests/env-cookie-copies.test.ts +182 -0
- package/packages/core/tests/error-guard.test.ts +222 -0
- package/packages/core/tests/errors.test-d.ts +280 -0
- package/packages/core/tests/errors.test.ts +1359 -0
- package/packages/core/tests/fixtures/README.md +28 -0
- package/packages/core/tests/fixtures/accounts.did +21 -0
- package/packages/core/tests/fixtures/accounts.envelope.json +367 -0
- package/packages/core/tests/fixtures/accounts.ts +26 -0
- package/packages/core/tests/fixtures/archive.did +31 -0
- package/packages/core/tests/fixtures/archive.envelope.json +259 -0
- package/packages/core/tests/fixtures/archive.ts +55 -0
- package/packages/core/tests/fixtures/icrc1.did +88 -0
- package/packages/core/tests/fixtures/icrc1.envelope.json +840 -0
- package/packages/core/tests/fixtures/icrc1.ts +78 -0
- package/packages/core/tests/fixtures/management.did +724 -0
- package/packages/core/tests/fixtures/management.envelope.json +4455 -0
- package/packages/core/tests/fixtures/management.ts +486 -0
- package/packages/core/tests/fixtures/shapes.did +33 -0
- package/packages/core/tests/fixtures/shapes.envelope.json +440 -0
- package/packages/core/tests/fixtures/shapes.ts +56 -0
- package/packages/core/tests/fixtures/skippable.did +15 -0
- package/packages/core/tests/fixtures/skippable.envelope.json +182 -0
- package/packages/core/tests/fixtures/skippable.ts +33 -0
- package/packages/core/tests/func.test.ts +154 -0
- package/packages/core/tests/identity-attributes.test.ts +214 -0
- package/packages/core/tests/keys.test.ts +289 -0
- package/packages/core/tests/management.test.ts +206 -0
- package/packages/core/tests/network-helpers.ts +121 -0
- package/packages/core/tests/network.test-d.ts +78 -0
- package/packages/core/tests/network.test.ts +1051 -0
- package/packages/core/tests/options.test.ts +1594 -0
- package/packages/core/tests/redirect-sign-in.test.ts +393 -0
- package/packages/core/tests/resend.test-d.ts +81 -0
- package/packages/core/tests/resend.test.ts +723 -0
- package/packages/core/tests/skip.test-d.ts +125 -0
- package/packages/core/tests/testing-entry.test.ts +73 -0
- package/packages/core/tests/testing-fake-replica.test.ts +1242 -0
- package/packages/core/tests/testing-test-auth.test-d.ts +84 -0
- package/packages/core/tests/testing-test-auth.test.ts +483 -0
- package/packages/core/tests/testing-test-client.test-d.ts +184 -0
- package/packages/core/tests/testing-test-client.test.ts +1272 -0
- package/packages/core/tests/time-realm.test.ts +63 -0
- package/packages/core/tests/time.test.ts +238 -0
- package/packages/core/tests/traps/README.md +39 -0
- package/packages/core/tests/traps/anonymous-write.test.ts +145 -0
- package/packages/core/tests/traps/classification-table.test.ts +256 -0
- package/packages/core/tests/traps/err-arm.test.ts +144 -0
- package/packages/core/tests/traps/fetch-spy.ts +39 -0
- package/packages/core/tests/traps/invalidation-after-write.test.ts +178 -0
- package/packages/core/tests/traps/ledger.ts +248 -0
- package/packages/core/tests/traps/root-key-off-local.test.ts +130 -0
- package/packages/core/tests/traps/stale-data-across-users.test.ts +173 -0
- package/packages/core/tests/traps/unresolved-name.test.ts +155 -0
- package/packages/core/tests/traps/update-as-query.test.ts +244 -0
- package/packages/core/tests/traps/update-not-resent.test.ts +126 -0
- package/packages/core/tests/traps/update-resent-when-never-delivered.test.ts +159 -0
- package/packages/core/tests/traps.test-d.ts +476 -0
- package/packages/core/tests/units.test-d.ts +118 -0
- package/packages/core/tests/units.test.ts +634 -0
- package/packages/core/tsconfig.json +19 -0
- package/packages/core/tsconfig.typecheck.json +16 -0
- package/packages/core/vitest.config.ts +13 -0
- package/packages/mcp/LICENSE +21 -0
- package/packages/mcp/README.md +189 -0
- package/packages/mcp/package.json +62 -0
- package/packages/mcp/src/candid/candid-text.test.ts +455 -0
- package/packages/mcp/src/candid/candid-text.ts +501 -0
- package/packages/mcp/src/candid/contract.test.ts +398 -0
- package/packages/mcp/src/candid/formats.ts +155 -0
- package/packages/mcp/src/candid/hex.ts +29 -0
- package/packages/mcp/src/candid/json-schema.test.ts +758 -0
- package/packages/mcp/src/candid/json-schema.ts +454 -0
- package/packages/mcp/src/candid/json.test.ts +1207 -0
- package/packages/mcp/src/candid/json.ts +1053 -0
- package/packages/mcp/src/candid/schema-walk.ts +189 -0
- package/packages/mcp/src/candid/type-text.test.ts +179 -0
- package/packages/mcp/src/candid/type-text.ts +238 -0
- package/packages/mcp/src/cli.ts +134 -0
- package/packages/mcp/src/identity.ts +188 -0
- package/packages/mcp/src/interface/cache.test.ts +48 -0
- package/packages/mcp/src/interface/cache.ts +68 -0
- package/packages/mcp/src/interface/cli-cache.test.ts +150 -0
- package/packages/mcp/src/interface/cli-cache.ts +122 -0
- package/packages/mcp/src/interface/compile-worker.test.ts +246 -0
- package/packages/mcp/src/interface/compile-worker.ts +290 -0
- package/packages/mcp/src/interface/compile.test.ts +155 -0
- package/packages/mcp/src/interface/compile.ts +281 -0
- package/packages/mcp/src/interface/docs.test.ts +105 -0
- package/packages/mcp/src/interface/docs.ts +86 -0
- package/packages/mcp/src/interface/fixtures/icrc1.did +88 -0
- package/packages/mcp/src/interface/hex.ts +8 -0
- package/packages/mcp/src/interface/ids.test.ts +71 -0
- package/packages/mcp/src/interface/ids.ts +87 -0
- package/packages/mcp/src/interface/loader.test.ts +804 -0
- package/packages/mcp/src/interface/loader.ts +519 -0
- package/packages/mcp/src/interface/read-candid.test.ts +300 -0
- package/packages/mcp/src/interface/read-candid.ts +259 -0
- package/packages/mcp/src/interface/types.ts +113 -0
- package/packages/mcp/src/network.ts +122 -0
- package/packages/mcp/src/options.ts +149 -0
- package/packages/mcp/src/server/approval.ts +159 -0
- package/packages/mcp/src/server/naming.ts +43 -0
- package/packages/mcp/src/server/results.ts +102 -0
- package/packages/mcp/src/server/server.ts +797 -0
- package/packages/mcp/src/server/tools.ts +116 -0
- package/packages/mcp/src/usage.ts +40 -0
- package/packages/mcp/tests/approval.test.ts +60 -0
- package/packages/mcp/tests/identity.test.ts +234 -0
- package/packages/mcp/tests/naming.test.ts +62 -0
- package/packages/mcp/tests/options.test.ts +140 -0
- package/packages/mcp/tests/server.test.ts +997 -0
- package/packages/mcp/tsconfig.json +19 -0
- package/packages/mcp/tsconfig.typecheck.json +10 -0
- package/packages/mcp/vitest.config.ts +10 -0
- package/packages/react/LICENSE +21 -0
- package/packages/react/README.md +328 -0
- package/packages/react/llms.txt +95 -0
- package/packages/react/package.json +95 -0
- package/packages/react/src/index.tsx +678 -0
- package/packages/react/tests/abandoned-render.test.tsx +816 -0
- package/packages/react/tests/auth.test.tsx +315 -0
- package/packages/react/tests/caller-keys.test.tsx +2334 -0
- package/packages/react/tests/client-time.test.ts +40 -0
- package/packages/react/tests/entry.test.ts +52 -0
- package/packages/react/tests/helpers.tsx +291 -0
- package/packages/react/tests/hydration.test.tsx +262 -0
- package/packages/react/tests/ownership.test.tsx +260 -0
- package/packages/react/tests/provider.server.test.tsx +169 -0
- package/packages/react/tests/query-client.test.tsx +107 -0
- package/packages/react/tests/strict-mode.test.tsx +288 -0
- package/packages/react/tests/suspense.test-d.tsx +357 -0
- package/packages/react/tests/two-query-cores.test.tsx +135 -0
- package/packages/react/tests/types.test-d.tsx +63 -0
- package/packages/react/tsconfig.json +23 -0
- package/packages/react/tsconfig.test.json +8 -0
- package/packages/react/tsconfig.typecheck.json +16 -0
- package/packages/react/vitest.config.ts +39 -0
- package/packages/vite-plugin/LICENSE +21 -0
- package/packages/vite-plugin/README.md +532 -0
- package/packages/vite-plugin/package.json +76 -0
- package/packages/vite-plugin/src/describe-value.test.ts +43 -0
- package/packages/vite-plugin/src/describe-value.ts +167 -0
- package/packages/vite-plugin/src/dev-environment.test.ts +747 -0
- package/packages/vite-plugin/src/dev-environment.ts +510 -0
- package/packages/vite-plugin/src/env.ts +431 -0
- package/packages/vite-plugin/src/fetch.ts +348 -0
- package/packages/vite-plugin/src/file-identity.ts +106 -0
- package/packages/vite-plugin/src/generate.ts +691 -0
- package/packages/vite-plugin/src/index.test.ts +1243 -0
- package/packages/vite-plugin/src/index.ts +2565 -0
- package/packages/vite-plugin/src/interface.ts +339 -0
- package/packages/vite-plugin/src/local-host.ts +34 -0
- package/packages/vite-plugin/src/options.ts +641 -0
- package/packages/vite-plugin/src/principal-text.test.ts +87 -0
- package/packages/vite-plugin/src/principal-text.ts +98 -0
- package/packages/vite-plugin/tests/close.test.ts +141 -0
- package/packages/vite-plugin/tests/environment-mode.test.ts +136 -0
- package/packages/vite-plugin/tests/fake-ic.ts +214 -0
- package/packages/vite-plugin/tests/fetch-sdk.test.ts +27 -0
- package/packages/vite-plugin/tests/fetch.test.ts +1196 -0
- package/packages/vite-plugin/tests/fixtures/fake-cli/bin.js +90 -0
- package/packages/vite-plugin/tests/fixtures/fake-cli/package.json +8 -0
- package/packages/vite-plugin/tests/fixtures/icrc1.did +88 -0
- package/packages/vite-plugin/tests/generation.test.ts +1036 -0
- package/packages/vite-plugin/tests/icp-command.test.ts +194 -0
- package/packages/vite-plugin/tests/icp-timeout.test.ts +83 -0
- package/packages/vite-plugin/tests/no-process-exit.test.ts +83 -0
- package/packages/vite-plugin/tests/on-generated.test.ts +323 -0
- package/packages/vite-plugin/tests/output-collision.test.ts +329 -0
- package/packages/vite-plugin/tests/package.test.ts +62 -0
- package/packages/vite-plugin/tests/project.test.ts +2993 -0
- package/packages/vite-plugin/tests/support.ts +339 -0
- package/packages/vite-plugin/tests/timeout.test.ts +107 -0
- package/packages/vite-plugin/tsconfig.json +23 -0
- package/packages/vite-plugin/tsconfig.typecheck.json +16 -0
- package/packages/vite-plugin/vitest.config.ts +9 -0
- package/pnpm-workspace.yaml +23 -0
- package/scripts/ai-context-files.js +72 -0
- package/scripts/assemble-docs-site.mjs +485 -0
- package/scripts/assemble-docs-site.test.mjs +568 -0
- package/scripts/build-examples.js +58 -0
- package/scripts/check-ai-context.js +963 -0
- package/scripts/check-ai-context.test.mjs +811 -0
- package/scripts/check-exports.mjs +767 -0
- package/scripts/check-exports.test.mjs +1136 -0
- package/scripts/check-snippets/ambient.d.ts +428 -0
- package/scripts/check-snippets/app/generated/backend.did +7 -0
- package/scripts/check-snippets/app/generated/backend.ts +15 -0
- package/scripts/check-snippets/app/generated/icrc1.did +88 -0
- package/scripts/check-snippets/app/generated/icrc1.ts +78 -0
- package/scripts/check-snippets/app/globals.ts +26 -0
- package/scripts/check-snippets/docs/guides/App.tsx +21 -0
- package/scripts/check-snippets/docs/guides/app/providers.tsx +23 -0
- package/scripts/check-snippets/docs/guides/auth-client.ts +47 -0
- package/scripts/check-snippets/docs/guides/canisters/backend.ts +3 -0
- package/scripts/check-snippets/docs/guides/canisters/icrc1.ts +3 -0
- package/scripts/check-snippets/docs/guides/components/LedgerCard.tsx +26 -0
- package/scripts/check-snippets/docs/guides/components/shell.tsx +11 -0
- package/scripts/check-snippets/docs/guides/components/sign-in-page.tsx +29 -0
- package/scripts/check-snippets/docs/guides/components/slow-section.tsx +5 -0
- package/scripts/check-snippets/docs/guides/generated/accounts.ts +95 -0
- package/scripts/check-snippets/docs/guides/generated/ckbtc_minter.ts +40 -0
- package/scripts/check-snippets/docs/guides/generated/icp_ledger.ts +267 -0
- package/scripts/check-snippets/docs/guides/ledger.ts +10 -0
- package/scripts/check-snippets/docs/guides/server/request-client.ts +8 -0
- package/scripts/check-snippets.mjs +993 -0
- package/scripts/check-snippets.test.mjs +338 -0
- package/scripts/check-stack.mjs +501 -0
- package/scripts/check-stack.test.mjs +800 -0
- package/scripts/clean-node-modules.js +67 -0
- package/scripts/example-projects.js +58 -0
- package/scripts/export-budget.mjs +145 -0
- package/scripts/faults.json +6749 -0
- package/scripts/lib/fault-workspace.mjs +210 -0
- package/scripts/lib/io.mjs +29 -0
- package/scripts/lib/io.test.mjs +38 -0
- package/scripts/lib/markdown-fences.mjs +56 -0
- package/scripts/lib/markdown-fences.test.mjs +84 -0
- package/scripts/lib/package-exports.mjs +54 -0
- package/scripts/lib/package-exports.test.mjs +66 -0
- package/scripts/lib/release-pr-steps.mjs +47 -0
- package/scripts/release-tag.mjs +95 -0
- package/scripts/release-tag.test.mjs +278 -0
- package/scripts/release-workflow.test.mjs +98 -0
- package/scripts/release.js +167 -0
- package/scripts/release.test.mjs +347 -0
- package/scripts/removed-v3-names.js +125 -0
- package/scripts/size-app/.size-limit.js +90 -0
- package/scripts/size-app/core.js +3 -0
- package/scripts/size-app/package.json +24 -0
- package/scripts/size-app/react.js +4 -0
- package/scripts/size-app.test.mjs +73 -0
- package/scripts/sync-ai-context-versions.js +102 -0
- package/scripts/sync-example-versions.js +151 -0
- package/scripts/test-examples-published.mjs +1585 -0
- package/scripts/test-examples-published.test.mjs +1586 -0
- package/scripts/traps/any-method-vars-not-a-list.json +5 -0
- package/scripts/traps/canister-method-unknown.json +5 -0
- package/scripts/traps/client-says-who-calls-once.json +5 -0
- package/scripts/traps/client-says-who-calls.json +5 -0
- package/scripts/traps/err-only-on-canister-err.json +14 -0
- package/scripts/traps/format-units-refuses-missing-value.json +5 -0
- package/scripts/traps/format-units-refuses-number.json +5 -0
- package/scripts/traps/format-units-unknown-option.json +5 -0
- package/scripts/traps/guard-err-is-the-methods.json +5 -0
- package/scripts/traps/guard-false-keeps-every-kind.json +5 -0
- package/scripts/traps/internals-not-exported.json +9 -0
- package/scripts/traps/network-refuses-unknown-name.json +5 -0
- package/scripts/traps/never-err-has-no-type.json +5 -0
- package/scripts/traps/options-method-unknown.json +5 -0
- package/scripts/traps/options-vars-wrong-type.json +5 -0
- package/scripts/traps/parse-units-refuses-number.json +5 -0
- package/scripts/traps/parse-units-unknown-option.json +5 -0
- package/scripts/traps/principal-is-not-plain-text.json +14 -0
- package/scripts/traps/query-options-refuses-oneway.json +5 -0
- package/scripts/traps/query-options-refuses-update.json +5 -0
- package/scripts/traps/refuse-next-unknown-option.json +5 -0
- package/scripts/traps/resend-key-reads-the-methods-arg.json +5 -0
- package/scripts/traps/resend-states-its-dedupe-key.json +5 -0
- package/scripts/traps/suspense-refuses-argument-skip.json +5 -0
- package/scripts/traps/suspense-refuses-skippable-read.json +5 -0
- package/scripts/traps/suspense-refuses-vars-skip-fits.json +5 -0
- package/scripts/traps/test-handler-method-unknown.json +5 -0
- package/scripts/traps/test-handler-nat-is-bigint.json +5 -0
- package/scripts/traps/test-handler-takes-the-domain-value.json +5 -0
- package/scripts/traps/vars-of-two-arguments-are-the-tuple.json +5 -0
- package/scripts/typecheck-examples.js +122 -0
- package/scripts/verify-faults.mjs +375 -0
- package/scripts/verify-faults.test.mjs +402 -0
- package/scripts/verify-package-artifacts.mjs +590 -0
- package/scripts/verify-peer-floors.js +399 -0
- package/scripts/verify-peer-floors.test.mjs +422 -0
- package/scripts/verify-test-fails-rules.mjs +104 -0
- package/scripts/verify-test-fails-rules.test.mjs +215 -0
- package/scripts/verify-test-fails.js +371 -0
- package/scripts/verify-traps.mjs +505 -0
- package/scripts/verify-traps.test.mjs +521 -0
- package/scripts/verify-typescript-floor.js +239 -0
- package/skill-packages/ic-reactor/SKILL.md +103 -0
- package/stack.json +8 -0
- package/tsconfig.base.json +23 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs"
|
|
4
|
+
import { basename, join, posix } from "node:path"
|
|
5
|
+
import {
|
|
6
|
+
AI_CONTEXT_FILES,
|
|
7
|
+
CLAUDE_MARKETPLACE,
|
|
8
|
+
RUNTIME_PLUGIN_MANIFESTS,
|
|
9
|
+
} from "./ai-context-files.js"
|
|
10
|
+
import { fencedLines } from "./lib/markdown-fences.mjs"
|
|
11
|
+
import { LANE_PACKAGES } from "./release-tag.mjs"
|
|
12
|
+
import { REMOVED_V3_NAMES } from "./removed-v3-names.js"
|
|
13
|
+
|
|
14
|
+
const rootDir = process.cwd()
|
|
15
|
+
|
|
16
|
+
// The packages of the release lane (scripts/release-tag.mjs): each one
|
|
17
|
+
// publishes, at the lane's version.
|
|
18
|
+
const versionChecks = LANE_PACKAGES.map((packageDir) => ({
|
|
19
|
+
packageName: `@ic-reactor/${packageDir}`,
|
|
20
|
+
packageDir,
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
// The one consumer guide of the 4.x line: core ships `packages/core/llms.txt`
|
|
24
|
+
// in its npm tarball, and it must open with an "Applies to
|
|
25
|
+
// `@ic-reactor/core` <version>." line. A pointer guide in another package
|
|
26
|
+
// (react's, once DX3 adds it) is stamped the same way, so a `llms.txt` that
|
|
27
|
+
// ships names the release it was written for.
|
|
28
|
+
const requiredPackageLlms = ["core"]
|
|
29
|
+
const optionalPackageLlms = versionChecks
|
|
30
|
+
.map(({ packageDir }) => packageDir)
|
|
31
|
+
.filter(
|
|
32
|
+
(packageDir) =>
|
|
33
|
+
!requiredPackageLlms.includes(packageDir) &&
|
|
34
|
+
existsSync(join(rootDir, "packages", packageDir, "llms.txt"))
|
|
35
|
+
)
|
|
36
|
+
const packageGuides = [...requiredPackageLlms, ...optionalPackageLlms]
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Files whose `https://ic-reactor.b3pay.net/...` links must resolve: the
|
|
40
|
+
* AI-context files, plus the READMEs npm shows, the changelog and the
|
|
41
|
+
* contributing guide. linkinator (`pnpm docs:check-links`) skips absolute
|
|
42
|
+
* links to the site, so without this a renamed page left these dangling.
|
|
43
|
+
*/
|
|
44
|
+
const docsLinkFiles = [
|
|
45
|
+
...AI_CONTEXT_FILES,
|
|
46
|
+
"README.md",
|
|
47
|
+
"CHANGELOG.md",
|
|
48
|
+
"CONTRIBUTING.md",
|
|
49
|
+
...versionChecks.map(({ packageDir }) => `packages/${packageDir}/README.md`),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Files whose whole purpose is to orient an AI agent. They are the "package
|
|
54
|
+
* surface" source of truth, so a stale version here steers agents (and the
|
|
55
|
+
* humans reading their output) at a release that is no longer current.
|
|
56
|
+
*
|
|
57
|
+
* Until this check covered them, only the version table in the root llms.txt was
|
|
58
|
+
* validated, so a release could bump every manifest and leave all of these
|
|
59
|
+
* claiming the previous version with the gate still green.
|
|
60
|
+
*/
|
|
61
|
+
const aiContextFiles = AI_CONTEXT_FILES
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The base the docs site in this tree is served under, read from
|
|
65
|
+
* docs/astro.config.mjs so the check follows the branch: `/v3/` on the 3.x
|
|
66
|
+
* line (v3), `/v4/` on the 4.x line (main). Links under it are resolved against
|
|
67
|
+
* this tree's pages.
|
|
68
|
+
*/
|
|
69
|
+
const DOCS_BASE = (() => {
|
|
70
|
+
const config = readFileSync(join(rootDir, "docs", "astro.config.mjs"), "utf8")
|
|
71
|
+
const base = config.match(/^\s*base:\s*["'](.+?)["']/m)?.[1]
|
|
72
|
+
if (!base) {
|
|
73
|
+
console.error(
|
|
74
|
+
"check-ai-context: could not read `base` from docs/astro.config.mjs"
|
|
75
|
+
)
|
|
76
|
+
process.exit(1)
|
|
77
|
+
}
|
|
78
|
+
return `/${base.replace(/^\/|\/$/g, "")}/`
|
|
79
|
+
})()
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Every versioned base the site publishes (.github/workflows/docs.yml): the
|
|
83
|
+
* static 2.x docs, the 3.x line built from the v3 branch and the 4.x line
|
|
84
|
+
* built from main. A link to a base outside this set 404s. A link under a base
|
|
85
|
+
* other than DOCS_BASE is served from another line's tree, so only its base
|
|
86
|
+
* is checked here.
|
|
87
|
+
*/
|
|
88
|
+
const PUBLISHED_DOCS_BASES = new Set(["/v2/", "/v3/", "/v4/"])
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Versions that legitimately appear in the AI-context files without belonging to
|
|
92
|
+
* an @ic-reactor package (a documented Node or pnpm version, for example).
|
|
93
|
+
*
|
|
94
|
+
* Deliberately starts empty: every version-like token in these files today is an
|
|
95
|
+
* @ic-reactor version, so anything else is drift until someone says otherwise.
|
|
96
|
+
* Adding an entry here is the explicit way to say "this one is not ours".
|
|
97
|
+
*/
|
|
98
|
+
const ALLOWED_EXTERNAL_VERSIONS = new Set([])
|
|
99
|
+
|
|
100
|
+
const failures = []
|
|
101
|
+
|
|
102
|
+
// ── Current package versions ─────────────────────────────────────────────────
|
|
103
|
+
const currentVersions = new Map()
|
|
104
|
+
for (const { packageName, packageDir } of versionChecks) {
|
|
105
|
+
const pkgPath = join(rootDir, "packages", packageDir, "package.json")
|
|
106
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"))
|
|
107
|
+
currentVersions.set(packageName, pkg.version)
|
|
108
|
+
}
|
|
109
|
+
const validVersions = new Set(currentVersions.values())
|
|
110
|
+
|
|
111
|
+
// ── 1. (3.x only) The version lists of the root llms.txt and llms-full.txt ───
|
|
112
|
+
// The 4.x line has no root guides in the tree: the docs deploy serves
|
|
113
|
+
// packages/core/llms.txt (checked below) as the site's /llms.txt, and
|
|
114
|
+
// /llms-full.txt is the 3.x line's, frozen on the v3 branch
|
|
115
|
+
// (.github/workflows/docs.yml, scripts/assemble-docs-site.mjs).
|
|
116
|
+
|
|
117
|
+
// ── 2. The package guide is stamped with its package's version ───────────────
|
|
118
|
+
// The stamp tells an agent reading node_modules/@ic-reactor/<dir>/llms.txt
|
|
119
|
+
// which release the guide describes. The generic version check below accepts
|
|
120
|
+
// any version some package is at, so it would not notice a stamp naming
|
|
121
|
+
// another lane's version; this compares against the package's own.
|
|
122
|
+
for (const packageDir of packageGuides) {
|
|
123
|
+
const relPath = `packages/${packageDir}/llms.txt`
|
|
124
|
+
const packageLlmsPath = join(rootDir, relPath)
|
|
125
|
+
if (!existsSync(packageLlmsPath)) {
|
|
126
|
+
failures.push(`Missing package AI guide: ${relPath}`)
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
const packageName = `@ic-reactor/${packageDir}`
|
|
130
|
+
const version = currentVersions.get(packageName)
|
|
131
|
+
const expectedStamp = `Applies to \`${packageName}\` ${version}.`
|
|
132
|
+
const stamp = readFileSync(packageLlmsPath, "utf8")
|
|
133
|
+
.split("\n")
|
|
134
|
+
.find((line) => line.startsWith(`Applies to \`${packageName}\``))
|
|
135
|
+
|
|
136
|
+
if (stamp === undefined) {
|
|
137
|
+
failures.push(
|
|
138
|
+
`${relPath} has no version stamp. Expected line: ${expectedStamp}`
|
|
139
|
+
)
|
|
140
|
+
} else if (stamp.trim() !== expectedStamp) {
|
|
141
|
+
failures.push(
|
|
142
|
+
`${relPath} is stamped "${stamp.trim()}" but ${packageName} is at ${version}. Expected line: ${expectedStamp}`
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ── 3. No stale version anywhere in the AI-context files ─────────────────────
|
|
148
|
+
// Matches every semver-shaped token regardless of how it is written: backticked,
|
|
149
|
+
// `v`-prefixed, or bare in prose. An earlier version of this check only matched
|
|
150
|
+
// the first two forms, so a stale bare "3.7.0" in a sentence passed silently --
|
|
151
|
+
// which defeats the point, since prose is exactly where these versions rot.
|
|
152
|
+
//
|
|
153
|
+
// The lookarounds keep it from matching a fragment of a longer dotted number
|
|
154
|
+
// (1.2.3.4) while still allowing a version at the end of a sentence ("v3.8.0.").
|
|
155
|
+
// A prerelease tag (4.0.0-alpha.0) is part of the version, so it is compared
|
|
156
|
+
// whole; a sentence's closing period is not taken into it.
|
|
157
|
+
const SEMVER =
|
|
158
|
+
/(?<![\d.])v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)(?![\d.]\d)/g
|
|
159
|
+
|
|
160
|
+
// Any /vN/ path segment, not just one inside markdown link syntax -- the same
|
|
161
|
+
// narrowness bug as above.
|
|
162
|
+
const VERSIONED_DOC_PATH = /\/v\d+\//g
|
|
163
|
+
|
|
164
|
+
for (const relPath of aiContextFiles) {
|
|
165
|
+
const absPath = join(rootDir, relPath)
|
|
166
|
+
if (!existsSync(absPath)) {
|
|
167
|
+
failures.push(`Missing AI-context file: ${relPath}`)
|
|
168
|
+
continue
|
|
169
|
+
}
|
|
170
|
+
const text = readFileSync(absPath, "utf8")
|
|
171
|
+
|
|
172
|
+
text.split("\n").forEach((line, i) => {
|
|
173
|
+
for (const [, version] of line.matchAll(SEMVER)) {
|
|
174
|
+
if (validVersions.has(version)) continue
|
|
175
|
+
if (ALLOWED_EXTERNAL_VERSIONS.has(version)) continue
|
|
176
|
+
|
|
177
|
+
failures.push(
|
|
178
|
+
`${relPath}:${i + 1} refers to version ${version}, which no @ic-reactor package is at. ` +
|
|
179
|
+
`Current: ${[...currentVersions].map(([n, v]) => `${n}@${v}`).join(", ")}. ` +
|
|
180
|
+
`If this version is not an @ic-reactor package, add it to ` +
|
|
181
|
+
`ALLOWED_EXTERNAL_VERSIONS in scripts/check-ai-context.js.`
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 4. Doc links must use a base the site publishes.
|
|
186
|
+
for (const seg of line.match(VERSIONED_DOC_PATH) ?? []) {
|
|
187
|
+
if (!PUBLISHED_DOCS_BASES.has(seg)) {
|
|
188
|
+
failures.push(
|
|
189
|
+
`${relPath}:${i + 1} references ${seg} but the docs site publishes only ${[...PUBLISHED_DOCS_BASES].join(", ")}`
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── 5. Links to the docs site resolve ────────────────────────────────────────
|
|
197
|
+
// The site serves each page twice under DOCS_BASE: as a route, lowercased by
|
|
198
|
+
// Starlight (`/v3/reference/clientmanager/`), and as the Markdown companion
|
|
199
|
+
// starlight-page-actions writes at the SOURCE-cased path
|
|
200
|
+
// (`/v3/reference/ClientManager.md`, and `/v3/packages/candid.md` for
|
|
201
|
+
// `packages/candid/index.mdx`). The host is case-sensitive, so each form is
|
|
202
|
+
// matched exactly. A `#fragment` must name a heading of the page.
|
|
203
|
+
const DOCS_SITE = "https://ic-reactor.b3pay.net"
|
|
204
|
+
const DOCS_CONTENT = join(rootDir, "docs", "src", "content", "docs")
|
|
205
|
+
/** Published at the site root by .github/workflows/docs.yml. */
|
|
206
|
+
const SITE_ROOT_FILES = new Set(["", "llms.txt", "llms-full.txt"])
|
|
207
|
+
|
|
208
|
+
function* docsSources(dir, rel = "") {
|
|
209
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
210
|
+
const entryRel = rel ? `${rel}/${entry.name}` : entry.name
|
|
211
|
+
// TypeDoc output, generated by docs:build and not in the repository.
|
|
212
|
+
if (entry.isDirectory() && entryRel !== "libs") {
|
|
213
|
+
yield* docsSources(join(dir, entry.name), entryRel)
|
|
214
|
+
} else if (entry.isFile() && /\.mdx?$/.test(entry.name)) {
|
|
215
|
+
yield entryRel
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const sourcePages = new Set(docsSources(DOCS_CONTENT))
|
|
221
|
+
/** Route (lowercased, no trailing slash, "" for the home page) -> source file. */
|
|
222
|
+
const sourceByRoute = new Map()
|
|
223
|
+
for (const page of sourcePages) {
|
|
224
|
+
const route = page
|
|
225
|
+
.replace(/\.mdx?$/, "")
|
|
226
|
+
.replace(/(^|\/)index$/, "")
|
|
227
|
+
.toLowerCase()
|
|
228
|
+
sourceByRoute.set(route, page)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** The source page a path under DOCS_BASE names, or undefined. */
|
|
232
|
+
function resolveDocsPath(path) {
|
|
233
|
+
if (path.endsWith(".md")) {
|
|
234
|
+
const key = path.slice(0, -".md".length)
|
|
235
|
+
// `packages/candid/index.md` is not published; `packages/candid.md` is.
|
|
236
|
+
if (key.endsWith("/index")) return undefined
|
|
237
|
+
return [
|
|
238
|
+
`${key}.mdx`,
|
|
239
|
+
`${key}.md`,
|
|
240
|
+
`${key}/index.mdx`,
|
|
241
|
+
`${key}/index.md`,
|
|
242
|
+
].find((candidate) => sourcePages.has(candidate))
|
|
243
|
+
}
|
|
244
|
+
const route = path.replace(/\/$/, "")
|
|
245
|
+
const page = sourceByRoute.get(route.toLowerCase())
|
|
246
|
+
// Starlight lowercases routes; a mixed-case route 404s on the host.
|
|
247
|
+
return page !== undefined && route === route.toLowerCase() ? page : undefined
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** github-slugger's rule, which Starlight uses for heading ids. */
|
|
251
|
+
function slugify(text) {
|
|
252
|
+
return text
|
|
253
|
+
.toLowerCase()
|
|
254
|
+
.replace(/[^\p{L}\p{M}\p{N}\p{Pc} -]/gu, "")
|
|
255
|
+
.replace(/ /g, "-")
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* A heading's text without inline HTML or JSX tags. The pattern runs until
|
|
260
|
+
* nothing changes, so a tag that one pass would leave behind (`<<b>b>`) goes
|
|
261
|
+
* too, and a lone "<" is dropped, as the slug drops it anyway.
|
|
262
|
+
*/
|
|
263
|
+
function withoutTags(text) {
|
|
264
|
+
let previous
|
|
265
|
+
let current = text
|
|
266
|
+
do {
|
|
267
|
+
previous = current
|
|
268
|
+
current = current.replace(/<[^<>]*>/g, "")
|
|
269
|
+
} while (current !== previous)
|
|
270
|
+
return current.replace(/</g, "")
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const headingIdsCache = new Map()
|
|
274
|
+
function headingIds(page) {
|
|
275
|
+
if (headingIdsCache.has(page)) return headingIdsCache.get(page)
|
|
276
|
+
const ids = new Set(["_top"])
|
|
277
|
+
const seen = new Map()
|
|
278
|
+
const fenced = fencedLines()
|
|
279
|
+
for (const line of readFileSync(join(DOCS_CONTENT, page), "utf8").split(
|
|
280
|
+
"\n"
|
|
281
|
+
)) {
|
|
282
|
+
if (fenced(line)) continue
|
|
283
|
+
// A heading may open a list item, as the steps of a <Steps> block do.
|
|
284
|
+
const heading = line.match(
|
|
285
|
+
/^\s*(?:(?:\d+\.|[-*+])\s+)?#{1,6}\s+(.+?)\s*#*\s*$/
|
|
286
|
+
)
|
|
287
|
+
if (!heading) continue
|
|
288
|
+
const text = withoutTags(
|
|
289
|
+
heading[1].replace(/\[([^\]]*)\]\([^)]*\)/g, "$1") // [text](url) -> text
|
|
290
|
+
).replace(/[`*]/g, "")
|
|
291
|
+
const base = slugify(text)
|
|
292
|
+
const count = seen.get(base) ?? 0
|
|
293
|
+
seen.set(base, count + 1)
|
|
294
|
+
ids.add(count === 0 ? base : `${base}-${count}`)
|
|
295
|
+
}
|
|
296
|
+
headingIdsCache.set(page, ids)
|
|
297
|
+
return ids
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const SITE_LINK = /https:\/\/ic-reactor\.b3pay\.net(\/[^\s)\]`>"'<]*)?/g
|
|
301
|
+
|
|
302
|
+
for (const relPath of docsLinkFiles) {
|
|
303
|
+
const absPath = join(rootDir, relPath)
|
|
304
|
+
if (!existsSync(absPath)) continue // a missing AI-context file is reported above
|
|
305
|
+
readFileSync(absPath, "utf8")
|
|
306
|
+
.split("\n")
|
|
307
|
+
.forEach((line, i) => {
|
|
308
|
+
for (const match of line.matchAll(SITE_LINK)) {
|
|
309
|
+
const url = match[0].replace(/[.,;:]+$/, "")
|
|
310
|
+
const [pathAndQuery, fragment] = url.slice(DOCS_SITE.length).split("#")
|
|
311
|
+
const path = pathAndQuery.split("?")[0].replace(/^\//, "")
|
|
312
|
+
const where = `${relPath}:${i + 1}`
|
|
313
|
+
|
|
314
|
+
if (SITE_ROOT_FILES.has(path)) continue
|
|
315
|
+
const base = DOCS_BASE.replace(/^\/|\/$/g, "") // "v4"
|
|
316
|
+
if (path !== base && !path.startsWith(`${base}/`)) {
|
|
317
|
+
// Served from another line's tree (DOCS_BASE's doc comment); a base
|
|
318
|
+
// the site does not publish is reported by check 4 above.
|
|
319
|
+
const other = path.match(/^(v\d+)(\/|$)/)?.[1]
|
|
320
|
+
if (other && PUBLISHED_DOCS_BASES.has(`/${other}/`)) continue
|
|
321
|
+
failures.push(
|
|
322
|
+
`${where} links ${url}, which is neither under ${DOCS_BASE} nor one of the files published at the site root`
|
|
323
|
+
)
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
326
|
+
const docsPath = path === base ? "" : path.slice(base.length + 1)
|
|
327
|
+
if (docsPath.startsWith("libs/")) continue // TypeDoc pages are generated
|
|
328
|
+
|
|
329
|
+
const page = resolveDocsPath(docsPath)
|
|
330
|
+
if (page === undefined) {
|
|
331
|
+
failures.push(
|
|
332
|
+
`${where} links ${url}, but no page in docs/src/content/docs serves it. ` +
|
|
333
|
+
`Use the lowercase route (${DOCS_BASE}guides/error-handling) or the source-cased ` +
|
|
334
|
+
`Markdown path (${DOCS_BASE}guides/error-handling.md).`
|
|
335
|
+
)
|
|
336
|
+
} else if (fragment && !headingIds(page).has(fragment)) {
|
|
337
|
+
failures.push(
|
|
338
|
+
`${where} links ${url}, but docs/src/content/docs/${page} has no heading with the id "${fragment}"`
|
|
339
|
+
)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ── 6. Agent skills ──────────────────────────────────────────────────────────
|
|
346
|
+
// Every `skill-packages/<name>/SKILL.md`, and every skill a plugin in the
|
|
347
|
+
// marketplace installs, must load in the tools that read the Agent Skills
|
|
348
|
+
// format (https://agentskills.io/specification): YAML frontmatter with a
|
|
349
|
+
// `name` equal to its folder and a `description` of at most 1024 characters,
|
|
350
|
+
// and no key outside the spec, which claude.ai uploads and the Skills API
|
|
351
|
+
// reject.
|
|
352
|
+
const SKILLS_DIR = "skill-packages"
|
|
353
|
+
// Absent only in a tree with no skill, such as this script's tests.
|
|
354
|
+
const skillEntries = existsSync(join(rootDir, SKILLS_DIR))
|
|
355
|
+
? readdirSync(join(rootDir, SKILLS_DIR), { withFileTypes: true })
|
|
356
|
+
: []
|
|
357
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
|
|
358
|
+
const SKILL_KEYS = new Set([
|
|
359
|
+
"name",
|
|
360
|
+
"description",
|
|
361
|
+
"license",
|
|
362
|
+
"compatibility",
|
|
363
|
+
"metadata",
|
|
364
|
+
"allowed-tools",
|
|
365
|
+
])
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* The top-level keys of a SKILL.md's YAML frontmatter, or null when it has
|
|
369
|
+
* none. Enough YAML for skill frontmatter: plain, quoted and multi-line plain
|
|
370
|
+
* scalars, `>`/`|` block scalars (folded or kept), and one level of nested
|
|
371
|
+
* mapping for `metadata`. Anything else is reported rather than guessed at.
|
|
372
|
+
*/
|
|
373
|
+
function parseFrontmatter(text) {
|
|
374
|
+
const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/)
|
|
375
|
+
if (!match) return null
|
|
376
|
+
const lines = match[1].split(/\r?\n/)
|
|
377
|
+
const fields = {}
|
|
378
|
+
let i = 0
|
|
379
|
+
while (i < lines.length) {
|
|
380
|
+
const line = lines[i]
|
|
381
|
+
if (line.trim() === "" || line.trimStart().startsWith("#")) {
|
|
382
|
+
i++
|
|
383
|
+
continue
|
|
384
|
+
}
|
|
385
|
+
const keyMatch = line.match(/^([A-Za-z][\w-]*):(?:[ \t]+(.*))?$/)
|
|
386
|
+
if (!keyMatch) throw new Error(`cannot read frontmatter line "${line}"`)
|
|
387
|
+
const key = keyMatch[1]
|
|
388
|
+
const inline = (keyMatch[2] ?? "").trim()
|
|
389
|
+
i++
|
|
390
|
+
const block = []
|
|
391
|
+
while (
|
|
392
|
+
i < lines.length &&
|
|
393
|
+
(lines[i].trim() === "" || /^\s/.test(lines[i]))
|
|
394
|
+
) {
|
|
395
|
+
block.push(lines[i])
|
|
396
|
+
i++
|
|
397
|
+
}
|
|
398
|
+
while (block.length > 0 && block[block.length - 1].trim() === "")
|
|
399
|
+
block.pop()
|
|
400
|
+
|
|
401
|
+
if (/^[>|][+-]?$/.test(inline)) {
|
|
402
|
+
const indent = Math.min(
|
|
403
|
+
...block.filter((l) => l.trim()).map((l) => l.match(/^\s*/)[0].length)
|
|
404
|
+
)
|
|
405
|
+
const body = block.map((l) => l.slice(indent))
|
|
406
|
+
fields[key] =
|
|
407
|
+
inline[0] === "|"
|
|
408
|
+
? body.join("\n")
|
|
409
|
+
: body
|
|
410
|
+
.join("\n")
|
|
411
|
+
.replace(/([^\n])\n(?=[^\n])/g, "$1 ")
|
|
412
|
+
.replace(/\n\n/g, "\n")
|
|
413
|
+
} else if (inline === "" && block.length > 0) {
|
|
414
|
+
fields[key] = Object.fromEntries(
|
|
415
|
+
block
|
|
416
|
+
.filter((l) => l.trim())
|
|
417
|
+
.map((l) => {
|
|
418
|
+
const entry = l.trim().match(/^([\w-]+):\s*(.*)$/)
|
|
419
|
+
if (!entry) throw new Error(`cannot read "${l.trim()}" in ${key}`)
|
|
420
|
+
return [entry[1], entry[2].replace(/^(["'])(.*)\1$/, "$2")]
|
|
421
|
+
})
|
|
422
|
+
)
|
|
423
|
+
} else {
|
|
424
|
+
const value = [inline, ...block.map((l) => l.trim())]
|
|
425
|
+
.filter(Boolean)
|
|
426
|
+
.join(" ")
|
|
427
|
+
fields[key] = value.replace(/^(["'])(.*)\1$/s, "$2")
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return fields
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function checkSkill(relSkillMd) {
|
|
434
|
+
const absPath = join(rootDir, relSkillMd)
|
|
435
|
+
let fields
|
|
436
|
+
try {
|
|
437
|
+
fields = parseFrontmatter(readFileSync(absPath, "utf8"))
|
|
438
|
+
} catch (error) {
|
|
439
|
+
failures.push(`${relSkillMd}: ${error.message}`)
|
|
440
|
+
return
|
|
441
|
+
}
|
|
442
|
+
if (fields === null) {
|
|
443
|
+
failures.push(
|
|
444
|
+
`${relSkillMd} has no YAML frontmatter; it must open with ---, name: and description:`
|
|
445
|
+
)
|
|
446
|
+
return
|
|
447
|
+
}
|
|
448
|
+
const folder = basename(posix.dirname(relSkillMd))
|
|
449
|
+
const { name, description } = fields
|
|
450
|
+
if (typeof name !== "string" || !SKILL_NAME.test(name) || name.length > 64) {
|
|
451
|
+
failures.push(
|
|
452
|
+
`${relSkillMd}: name must be 1-64 lowercase letters, digits and single hyphens (got ${JSON.stringify(name)})`
|
|
453
|
+
)
|
|
454
|
+
} else if (name !== folder) {
|
|
455
|
+
failures.push(
|
|
456
|
+
`${relSkillMd}: name "${name}" must match its folder "${folder}"`
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
if (typeof description !== "string" || description.trim() === "") {
|
|
460
|
+
failures.push(`${relSkillMd}: description is missing`)
|
|
461
|
+
} else if (description.length > 1024) {
|
|
462
|
+
failures.push(
|
|
463
|
+
`${relSkillMd}: description is ${description.length} characters; the limit is 1024`
|
|
464
|
+
)
|
|
465
|
+
}
|
|
466
|
+
for (const key of Object.keys(fields)) {
|
|
467
|
+
if (!SKILL_KEYS.has(key)) {
|
|
468
|
+
failures.push(
|
|
469
|
+
`${relSkillMd}: frontmatter key "${key}" is not in the Agent Skills spec (${[...SKILL_KEYS].join(", ")})`
|
|
470
|
+
)
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** Markdown files of a skill folder, relative to the repository root. */
|
|
476
|
+
function* skillMarkdown(relDir) {
|
|
477
|
+
for (const entry of readdirSync(join(rootDir, relDir), {
|
|
478
|
+
withFileTypes: true,
|
|
479
|
+
})) {
|
|
480
|
+
const rel = `${relDir}/${entry.name}`
|
|
481
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
482
|
+
yield* skillMarkdown(rel)
|
|
483
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
484
|
+
yield rel
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const checkedSkills = new Set()
|
|
490
|
+
for (const entry of skillEntries) {
|
|
491
|
+
if (!entry.isDirectory()) continue
|
|
492
|
+
const relSkillMd = `${SKILLS_DIR}/${entry.name}/SKILL.md`
|
|
493
|
+
if (!existsSync(join(rootDir, relSkillMd))) {
|
|
494
|
+
failures.push(`${SKILLS_DIR}/${entry.name}/ has no SKILL.md`)
|
|
495
|
+
continue
|
|
496
|
+
}
|
|
497
|
+
checkSkill(relSkillMd)
|
|
498
|
+
checkedSkills.add(relSkillMd)
|
|
499
|
+
// What a skill tells an agent must be version- and link-checked like the
|
|
500
|
+
// other AI files, so a new reference file cannot slip past this script.
|
|
501
|
+
for (const relMd of skillMarkdown(`${SKILLS_DIR}/${entry.name}`)) {
|
|
502
|
+
if (/\/(SKILL\.md|references\/[^/]+\.md)$/.test(relMd)) {
|
|
503
|
+
if (!AI_CONTEXT_FILES.includes(relMd)) {
|
|
504
|
+
failures.push(
|
|
505
|
+
`${relMd} is not listed in scripts/ai-context-files.js, so its versions and links go unchecked and releases do not update it`
|
|
506
|
+
)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ── 7. The Claude Code plugin marketplace ────────────────────────────────────
|
|
513
|
+
// `/plugin marketplace add B3Pay/ic-reactor` reads CLAUDE_MARKETPLACE from the
|
|
514
|
+
// default branch; each relative `source` is a plugin directory holding
|
|
515
|
+
// `.claude-plugin/plugin.json` and its skills. `claude plugin validate .`
|
|
516
|
+
// checks the same shape, but it is not installed in CI.
|
|
517
|
+
const currentReact = currentVersions.get("@ic-reactor/react")
|
|
518
|
+
/** Folders whose skills an app installs: every text an agent loads from them
|
|
519
|
+
* must stand on the published packages alone. They are the folder of every
|
|
520
|
+
* skill under SKILLS_DIR, which `npx skills add` installs from this repository
|
|
521
|
+
* whether or not a marketplace lists it (#970), and of each skill of a
|
|
522
|
+
* marketplace plugin below. So a contributor skill does not go under
|
|
523
|
+
* SKILLS_DIR. */
|
|
524
|
+
const consumerSkillDirs = [...checkedSkills].map((rel) => posix.dirname(rel))
|
|
525
|
+
|
|
526
|
+
function readJson(relPath) {
|
|
527
|
+
try {
|
|
528
|
+
return JSON.parse(readFileSync(join(rootDir, relPath), "utf8"))
|
|
529
|
+
} catch (error) {
|
|
530
|
+
failures.push(`${relPath} is not valid JSON: ${error.message}`)
|
|
531
|
+
return undefined
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const isDirectory = (relPath) =>
|
|
536
|
+
existsSync(join(rootDir, relPath)) &&
|
|
537
|
+
statSync(join(rootDir, relPath)).isDirectory()
|
|
538
|
+
|
|
539
|
+
// Optional: v4 has no marketplace (DX3 added the skill without one), so the
|
|
540
|
+
// consumer rules of section 8 do not depend on this file.
|
|
541
|
+
if (existsSync(join(rootDir, CLAUDE_MARKETPLACE))) {
|
|
542
|
+
const marketplace = readJson(CLAUDE_MARKETPLACE)
|
|
543
|
+
if (marketplace !== undefined) {
|
|
544
|
+
if (
|
|
545
|
+
typeof marketplace.name !== "string" ||
|
|
546
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(marketplace.name)
|
|
547
|
+
) {
|
|
548
|
+
failures.push(
|
|
549
|
+
`${CLAUDE_MARKETPLACE}: name must be letters, digits, ".", "_" and "-", starting with a letter or digit`
|
|
550
|
+
)
|
|
551
|
+
}
|
|
552
|
+
if (typeof marketplace.owner?.name !== "string") {
|
|
553
|
+
failures.push(`${CLAUDE_MARKETPLACE}: owner.name is required`)
|
|
554
|
+
}
|
|
555
|
+
if (
|
|
556
|
+
!Array.isArray(marketplace.plugins) ||
|
|
557
|
+
marketplace.plugins.length === 0
|
|
558
|
+
) {
|
|
559
|
+
failures.push(
|
|
560
|
+
`${CLAUDE_MARKETPLACE}: plugins must list at least one plugin`
|
|
561
|
+
)
|
|
562
|
+
}
|
|
563
|
+
for (const [i, entry] of (marketplace.plugins ?? []).entries()) {
|
|
564
|
+
const where = `${CLAUDE_MARKETPLACE} plugins[${i}]`
|
|
565
|
+
const { source } = entry
|
|
566
|
+
if (typeof entry.name !== "string" || /\s/.test(entry.name)) {
|
|
567
|
+
failures.push(`${where}: name is required and has no spaces`)
|
|
568
|
+
}
|
|
569
|
+
if (
|
|
570
|
+
typeof source !== "string" ||
|
|
571
|
+
!source.startsWith("./") ||
|
|
572
|
+
source.split("/").includes("..")
|
|
573
|
+
) {
|
|
574
|
+
failures.push(
|
|
575
|
+
`${where}: source must be a "./" path inside the repository (got ${JSON.stringify(source)})`
|
|
576
|
+
)
|
|
577
|
+
continue
|
|
578
|
+
}
|
|
579
|
+
const pluginDir = posix.normalize(source).replace(/\/$/, "")
|
|
580
|
+
if (!isDirectory(pluginDir)) {
|
|
581
|
+
failures.push(`${where}: source ${source} is not a directory`)
|
|
582
|
+
continue
|
|
583
|
+
}
|
|
584
|
+
if ("version" in entry) {
|
|
585
|
+
failures.push(
|
|
586
|
+
`${where}: set version in ${pluginDir}/.claude-plugin/plugin.json only; Claude Code ignores the entry's when both are set`
|
|
587
|
+
)
|
|
588
|
+
}
|
|
589
|
+
const manifestPath = `${pluginDir}/.claude-plugin/plugin.json`
|
|
590
|
+
if (!existsSync(join(rootDir, manifestPath))) {
|
|
591
|
+
failures.push(`${where}: ${manifestPath} is missing`)
|
|
592
|
+
continue
|
|
593
|
+
}
|
|
594
|
+
const manifest = readJson(manifestPath)
|
|
595
|
+
if (manifest === undefined) continue
|
|
596
|
+
if (manifest.name !== entry.name) {
|
|
597
|
+
failures.push(
|
|
598
|
+
`${manifestPath}: name "${manifest.name}" must equal the marketplace entry's "${entry.name}", or installing by one name fails`
|
|
599
|
+
)
|
|
600
|
+
}
|
|
601
|
+
if (typeof manifest.description !== "string") {
|
|
602
|
+
failures.push(`${manifestPath}: description is required`)
|
|
603
|
+
}
|
|
604
|
+
if (typeof manifest.author?.name !== "string") {
|
|
605
|
+
failures.push(`${manifestPath}: author.name is required`)
|
|
606
|
+
}
|
|
607
|
+
if (manifest.version !== undefined) {
|
|
608
|
+
if (!RUNTIME_PLUGIN_MANIFESTS.includes(manifestPath)) {
|
|
609
|
+
failures.push(
|
|
610
|
+
`${manifestPath} sets a version but is not in RUNTIME_PLUGIN_MANIFESTS (scripts/ai-context-files.js), so no release would update it`
|
|
611
|
+
)
|
|
612
|
+
} else if (manifest.version !== currentReact) {
|
|
613
|
+
failures.push(
|
|
614
|
+
`${manifestPath} is at version ${manifest.version} but @ic-reactor/react is at ${currentReact}; installed copies update only when it changes`
|
|
615
|
+
)
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Its skills: SKILL.md at the plugin root, or skills/<name>/SKILL.md.
|
|
620
|
+
const skillFiles = []
|
|
621
|
+
if (existsSync(join(rootDir, pluginDir, "SKILL.md"))) {
|
|
622
|
+
skillFiles.push(`${pluginDir}/SKILL.md`)
|
|
623
|
+
}
|
|
624
|
+
if (isDirectory(`${pluginDir}/skills`)) {
|
|
625
|
+
for (const dir of readdirSync(join(rootDir, pluginDir, "skills"))) {
|
|
626
|
+
const rel = `${pluginDir}/skills/${dir}/SKILL.md`
|
|
627
|
+
if (existsSync(join(rootDir, rel))) skillFiles.push(rel)
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (skillFiles.length === 0) {
|
|
631
|
+
failures.push(
|
|
632
|
+
`${where}: ${pluginDir} holds no SKILL.md at its root or under skills/<name>/`
|
|
633
|
+
)
|
|
634
|
+
}
|
|
635
|
+
for (const rel of skillFiles) {
|
|
636
|
+
if (!checkedSkills.has(rel)) checkSkill(rel)
|
|
637
|
+
const skillDir = posix.dirname(rel)
|
|
638
|
+
if (!consumerSkillDirs.includes(skillDir)) {
|
|
639
|
+
consumerSkillDirs.push(skillDir)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
for (const relPath of RUNTIME_PLUGIN_MANIFESTS) {
|
|
647
|
+
if (!existsSync(join(rootDir, relPath))) {
|
|
648
|
+
failures.push(
|
|
649
|
+
`RUNTIME_PLUGIN_MANIFESTS names ${relPath}, which does not exist`
|
|
650
|
+
)
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// ── 8. Consumer skills stand on the published packages ───────────────────────
|
|
655
|
+
// A consumer skill runs in an app's repository, where `packages/react/src` or
|
|
656
|
+
// `examples/...` do not exist; it may point only at the public API, the docs
|
|
657
|
+
// site and node_modules/@ic-reactor/*/llms.txt. It must also state the version
|
|
658
|
+
// of each package it describes, as `- \`@ic-reactor/<pkg>\`: \`<version>\``,
|
|
659
|
+
// the line shape the release scripts rewrite.
|
|
660
|
+
const REPO_PATH =
|
|
661
|
+
/(?<![\w@/.-])(?:packages|examples|skill-packages|scripts|e2e|docs\/src)\/[\w.-][\w./-]*/
|
|
662
|
+
const VERSION_LINE = /^- `(@ic-reactor\/[\w-]+)`: `([^`]+)`\s*$/
|
|
663
|
+
|
|
664
|
+
for (const skillDir of consumerSkillDirs) {
|
|
665
|
+
for (const relMd of skillMarkdown(skillDir)) {
|
|
666
|
+
// What the agent loads: SKILL.md and its references. README.md is for
|
|
667
|
+
// people browsing the repository.
|
|
668
|
+
if (!/\/(SKILL\.md|references\/[^/]+\.md)$/.test(relMd)) continue
|
|
669
|
+
readFileSync(join(rootDir, relMd), "utf8")
|
|
670
|
+
.split("\n")
|
|
671
|
+
.forEach((line, i) => {
|
|
672
|
+
const found = line.match(REPO_PATH)
|
|
673
|
+
if (found) {
|
|
674
|
+
failures.push(
|
|
675
|
+
`${relMd}:${i + 1} names the repository path "${found[0]}", which an app does not have; link the docs site or node_modules/@ic-reactor/<package>/llms.txt instead`
|
|
676
|
+
)
|
|
677
|
+
}
|
|
678
|
+
})
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const skillMd = `${skillDir}/SKILL.md`
|
|
682
|
+
const listed = readFileSync(join(rootDir, skillMd), "utf8")
|
|
683
|
+
.split("\n")
|
|
684
|
+
.map((line) => line.match(VERSION_LINE))
|
|
685
|
+
.filter(Boolean)
|
|
686
|
+
if (!listed.some(([, name]) => name === "@ic-reactor/react")) {
|
|
687
|
+
failures.push(
|
|
688
|
+
`${skillMd} must list the versions it describes, one line per package, such as: - \`@ic-reactor/react\`: \`${currentReact}\``
|
|
689
|
+
)
|
|
690
|
+
}
|
|
691
|
+
for (const [line, name, version] of listed) {
|
|
692
|
+
const current = currentVersions.get(name)
|
|
693
|
+
if (current === undefined) {
|
|
694
|
+
failures.push(`${skillMd}: "${line.trim()}" names no @ic-reactor package`)
|
|
695
|
+
} else if (version !== current) {
|
|
696
|
+
failures.push(`${skillMd}: "${line.trim()}" but ${name} is at ${current}`)
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// ── 9. No removed 3.x name outside a "Removed in 4.0" section ────────────────
|
|
702
|
+
// The guides, the contributor files and the skill are what an agent reads to
|
|
703
|
+
// learn the 4 API. A 3.x name left in one (`ClientManager` in a snippet, a
|
|
704
|
+
// `createQuery` in a sentence about caching) teaches an API that is gone,
|
|
705
|
+
// and the agent writes it. The 34 names of the migration table
|
|
706
|
+
// (scripts/removed-v3-names.js) may appear only under a heading that begins
|
|
707
|
+
// "Removed in 4.0", which is where the guide says what replaced them; the
|
|
708
|
+
// section runs to the next heading of the same or a higher level. Headings are
|
|
709
|
+
// read outside code fences only, so a `# Removed in 4.0` comment in a snippet
|
|
710
|
+
// opens nothing.
|
|
711
|
+
//
|
|
712
|
+
// What counts as a mention: the name as a whole word, in prose, a code span
|
|
713
|
+
// or a snippet alike. Two names get a narrower rule, stated in
|
|
714
|
+
// removed-v3-names.js: the product name "IC Reactor" is not `Reactor`, and
|
|
715
|
+
// `skipToken` is stale only when imported from, or named beside, an
|
|
716
|
+
// `@ic-reactor/*` package, since `@tanstack/react-query` still exports it.
|
|
717
|
+
const REMOVED_NAME = new RegExp(
|
|
718
|
+
`(?<![\\w$])(${[...REMOVED_V3_NAMES]
|
|
719
|
+
.sort((a, b) => b.name.length - a.name.length)
|
|
720
|
+
.map(({ name }) => name)
|
|
721
|
+
.join("|")})(?![\\w$])`,
|
|
722
|
+
"g"
|
|
723
|
+
)
|
|
724
|
+
const removedByName = new Map(
|
|
725
|
+
REMOVED_V3_NAMES.map((entry) => [entry.name, entry])
|
|
726
|
+
)
|
|
727
|
+
const REMOVED_HEADING = /^removed in 4\.0\b/i
|
|
728
|
+
const PRODUCT_NAME = /\bIC Reactor\b/g
|
|
729
|
+
const IC_REACTOR_IMPORT =
|
|
730
|
+
/\bimport\s+(?:type\s+)?\{[^}]*\}\s*from\s*["']@ic-reactor\/[^"']*["']/g
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Every mention of a removed name outside a "Removed in 4.0" section, or every
|
|
734
|
+
* mention at all when `exempt` is `false`.
|
|
735
|
+
*
|
|
736
|
+
* @param {string} text
|
|
737
|
+
* @param {{ exempt?: boolean }} [options] - `exempt: false` ignores the
|
|
738
|
+
* "Removed in 4.0" headings
|
|
739
|
+
* @returns {{ line: number, name: string }[]} `line` is 1-based
|
|
740
|
+
*/
|
|
741
|
+
function staleNameMentions(text, { exempt = true } = {}) {
|
|
742
|
+
const lines = text.split("\n")
|
|
743
|
+
const starts = []
|
|
744
|
+
let offset = 0
|
|
745
|
+
for (const line of lines) {
|
|
746
|
+
starts.push(offset)
|
|
747
|
+
offset += line.length + 1
|
|
748
|
+
}
|
|
749
|
+
// An import's braces may span lines, so its extent is found in the whole text.
|
|
750
|
+
const icImports = [...text.matchAll(IC_REACTOR_IMPORT)].map((m) => [
|
|
751
|
+
m.index,
|
|
752
|
+
m.index + m[0].length,
|
|
753
|
+
])
|
|
754
|
+
const found = []
|
|
755
|
+
const fenced = fencedLines()
|
|
756
|
+
let exemptLevel = null
|
|
757
|
+
lines.forEach((line, i) => {
|
|
758
|
+
if (!fenced(line)) {
|
|
759
|
+
const heading = line.match(/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/)
|
|
760
|
+
if (heading) {
|
|
761
|
+
const level = heading[1].length
|
|
762
|
+
const title = heading[2].replace(/[`*_]/g, "")
|
|
763
|
+
if (exempt && REMOVED_HEADING.test(title)) exemptLevel = level
|
|
764
|
+
else if (exemptLevel !== null && level <= exemptLevel)
|
|
765
|
+
exemptLevel = null
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
if (exemptLevel !== null) return
|
|
769
|
+
const prose = line.replace(PRODUCT_NAME, (m) => " ".repeat(m.length))
|
|
770
|
+
for (const match of prose.matchAll(REMOVED_NAME)) {
|
|
771
|
+
const { name, fromTanStack } = removedByName.get(match[1])
|
|
772
|
+
if (
|
|
773
|
+
fromTanStack &&
|
|
774
|
+
!line.includes("@ic-reactor/") &&
|
|
775
|
+
!icImports.some(
|
|
776
|
+
([from, to]) =>
|
|
777
|
+
starts[i] + match.index >= from && starts[i] + match.index < to
|
|
778
|
+
)
|
|
779
|
+
) {
|
|
780
|
+
continue
|
|
781
|
+
}
|
|
782
|
+
found.push({ line: i + 1, name })
|
|
783
|
+
}
|
|
784
|
+
})
|
|
785
|
+
return found
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
for (const relPath of aiContextFiles) {
|
|
789
|
+
const absPath = join(rootDir, relPath)
|
|
790
|
+
if (!existsSync(absPath)) continue // reported above
|
|
791
|
+
for (const { line, name } of staleNameMentions(
|
|
792
|
+
readFileSync(absPath, "utf8")
|
|
793
|
+
)) {
|
|
794
|
+
failures.push(
|
|
795
|
+
`${relPath}:${line} mentions ${name}, which 4.0 removed (use ${removedByName.get(name).use}). ` +
|
|
796
|
+
`Remove it, or move the mention under a heading that begins "Removed in 4.0".`
|
|
797
|
+
)
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// ── 10. The 4 docs pages teach no removed name and link no 3.x page ──────────
|
|
802
|
+
// The pages of docs/src/content/docs are what a person reads once they have
|
|
803
|
+
// found the site, so they follow check 9 as the AI-context files do: a removed
|
|
804
|
+
// name appears only under a heading that begins "Removed in 4.0", and only on
|
|
805
|
+
// the migration page (V3_LINK_PAGE). Another page gets no exemption for such a
|
|
806
|
+
// heading, so the table of removed names stays in one place. They are not
|
|
807
|
+
// in AI_CONTEXT_FILES, which would also apply check 3 and let the release
|
|
808
|
+
// script rewrite them: a page names versions of other packages (a peer range,
|
|
809
|
+
// a TanStack Query release) that check 3 refuses. The generated API reference
|
|
810
|
+
// (`libs/`) is not a page of the tree and is left out, as in check 5.
|
|
811
|
+
//
|
|
812
|
+
// Versions get a rule of their own. A page names no @ic-reactor version (the
|
|
813
|
+
// site follows the branch, so a release would leave one stale), and every
|
|
814
|
+
// prerelease version it names, such as the `--save-exact` install of
|
|
815
|
+
// `@meantjs/schema`, is the exact pin some packages/*/package.json has,
|
|
816
|
+
// so an install line moves with the pin. A stable version is held to the pin
|
|
817
|
+
// when the page names it with its package, as `@meantjs/schema@0.6.0`: a
|
|
818
|
+
// package that packages/*/package.json pins exactly is installed at that pin.
|
|
819
|
+
//
|
|
820
|
+
// The pages also keep out of the 3.x docs: one page, the migration guide,
|
|
821
|
+
// links `/v3/`, and every other page reaches the 3.x docs through it. A link
|
|
822
|
+
// is an absolute URL of the site's `/v3/`, or a link, `href` or reference
|
|
823
|
+
// definition that starts with `/v3` (the site's own path, which leaves the
|
|
824
|
+
// 4 docs). The whole page is read, code fences included, since a reader
|
|
825
|
+
// copies a URL from a fence as well.
|
|
826
|
+
const V3_LINK_PAGE = "migrating-from-3.mdx"
|
|
827
|
+
const V3_LINK =
|
|
828
|
+
/ic-reactor\.b3pay\.net\/v3(?![\w-])|(?:\]\(\s*<?|href=\s*["']|^\s*\[[^\]]+\]:\s*<?)\/v3(?![\w-])/g
|
|
829
|
+
|
|
830
|
+
/** Exact prerelease pins (such as `0.3.0-beta.1`) of the packages' dependencies. */
|
|
831
|
+
const exactPins = new Set()
|
|
832
|
+
/** Every exact pin of the packages' dependencies, stable ones included, by package. */
|
|
833
|
+
const exactPinsByName = new Map()
|
|
834
|
+
for (const { packageDir } of versionChecks) {
|
|
835
|
+
const pkg = JSON.parse(
|
|
836
|
+
readFileSync(join(rootDir, "packages", packageDir, "package.json"), "utf8")
|
|
837
|
+
)
|
|
838
|
+
for (const field of ["dependencies", "peerDependencies", "devDependencies"]) {
|
|
839
|
+
for (const [name, range] of Object.entries(pkg[field] ?? {})) {
|
|
840
|
+
if (/^\d+\.\d+\.\d+-[0-9A-Za-z.-]+$/.test(range)) exactPins.add(range)
|
|
841
|
+
if (/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(range)) {
|
|
842
|
+
if (!exactPinsByName.has(name)) exactPinsByName.set(name, new Set())
|
|
843
|
+
exactPinsByName.get(name).add(range)
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
const PRERELEASE =
|
|
849
|
+
/(?<![\d.])v?(\d+\.\d+\.\d+-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)(?![\d.]\d)/g
|
|
850
|
+
/** A scoped package named with a version, as an install line names it: `@scope/name@1.2.3`. */
|
|
851
|
+
const NAMED_VERSION =
|
|
852
|
+
/(?<![\w@/.-])(@[a-z0-9][\w.-]*\/[a-z0-9][\w.-]*)@(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)(?![\w.-]*\d)/g
|
|
853
|
+
|
|
854
|
+
for (const page of [...sourcePages].sort()) {
|
|
855
|
+
const relPath = `docs/src/content/docs/${page}`
|
|
856
|
+
const text = readFileSync(join(rootDir, relPath), "utf8")
|
|
857
|
+
text.split("\n").forEach((line, i) => {
|
|
858
|
+
for (const [, name, version] of line.matchAll(NAMED_VERSION)) {
|
|
859
|
+
const pins = exactPinsByName.get(name)
|
|
860
|
+
// A prerelease is held to the pins by the rule below.
|
|
861
|
+
if (!pins || version.includes("-") || pins.has(version)) continue
|
|
862
|
+
failures.push(
|
|
863
|
+
`${relPath}:${i + 1} names ${name}@${version}, which packages/*/package.json pins exactly at ` +
|
|
864
|
+
`${[...pins].join(", ")}. Name the pin.`
|
|
865
|
+
)
|
|
866
|
+
}
|
|
867
|
+
for (const [, version] of line.matchAll(PRERELEASE)) {
|
|
868
|
+
if (exactPins.has(version)) continue
|
|
869
|
+
failures.push(
|
|
870
|
+
validVersions.has(version)
|
|
871
|
+
? `${relPath}:${i + 1} names the @ic-reactor version ${version}. A docs page names none: ` +
|
|
872
|
+
`the site follows main, which can be ahead of the latest release, so install without a version instead.`
|
|
873
|
+
: `${relPath}:${i + 1} names version ${version}, which no package pins exactly ` +
|
|
874
|
+
`(pins: ${[...exactPins].join(", ") || "none"}). Name the pin of packages/*/package.json.`
|
|
875
|
+
)
|
|
876
|
+
}
|
|
877
|
+
})
|
|
878
|
+
for (const { line, name } of staleNameMentions(text, {
|
|
879
|
+
exempt: page === V3_LINK_PAGE,
|
|
880
|
+
})) {
|
|
881
|
+
failures.push(
|
|
882
|
+
`${relPath}:${line} mentions ${name}, which 4.0 removed (use ${removedByName.get(name).use}). ` +
|
|
883
|
+
`Remove it, or move it to ${V3_LINK_PAGE}, under a heading that begins "Removed in 4.0".`
|
|
884
|
+
)
|
|
885
|
+
}
|
|
886
|
+
if (page === V3_LINK_PAGE) continue
|
|
887
|
+
text.split("\n").forEach((line, i) => {
|
|
888
|
+
for (const match of line.matchAll(V3_LINK)) {
|
|
889
|
+
failures.push(
|
|
890
|
+
`${relPath}:${i + 1} links the 3.x docs (${match[0].trim()}). ` +
|
|
891
|
+
`Only ${V3_LINK_PAGE} may; link to /v4/${V3_LINK_PAGE.replace(/\.mdx$/, "")}/ instead.`
|
|
892
|
+
)
|
|
893
|
+
}
|
|
894
|
+
})
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// ── 11. Each package's homepage is its own page of the 4 docs ───────────────
|
|
898
|
+
// npm shows `homepage` as the package's link, so it names the package's page
|
|
899
|
+
// (`https://ic-reactor.b3pay.net/v4/packages/core/`), and that page must exist.
|
|
900
|
+
// Every package of the lane publishes, so a missing `homepage` fails too: npm
|
|
901
|
+
// would fall back to the repository's README.
|
|
902
|
+
for (const { packageName, packageDir } of versionChecks) {
|
|
903
|
+
const relPath = `packages/${packageDir}/package.json`
|
|
904
|
+
const { homepage } = JSON.parse(readFileSync(join(rootDir, relPath), "utf8"))
|
|
905
|
+
const expected = `${DOCS_SITE}${DOCS_BASE}packages/${packageDir}/`
|
|
906
|
+
if (homepage === undefined) {
|
|
907
|
+
failures.push(
|
|
908
|
+
`${relPath} has no homepage; ${packageName}'s is its page, ${expected}`
|
|
909
|
+
)
|
|
910
|
+
} else if (homepage !== expected) {
|
|
911
|
+
failures.push(
|
|
912
|
+
`${relPath} has homepage ${homepage}; ${packageName}'s is its page, ${expected}`
|
|
913
|
+
)
|
|
914
|
+
} else if (resolveDocsPath(`packages/${packageDir}/`) === undefined) {
|
|
915
|
+
failures.push(
|
|
916
|
+
`${relPath} has homepage ${homepage}, but docs/src/content/docs has no packages/${packageDir} page`
|
|
917
|
+
)
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// ── 12. No link to the retired v4 branch ─────────────────────────────────────
|
|
922
|
+
// ic-reactor 4 lives on `main` since the 4.0 GA flip, and the `v4` branch is
|
|
923
|
+
// deleted after a window, so a GitHub, raw or sandbox link to it would 404.
|
|
924
|
+
// A tag (`tree/v4.0.0`) is not a branch and is allowed. Checked in the files
|
|
925
|
+
// whose site links are checked, the docs pages and the docs config (its edit
|
|
926
|
+
// link).
|
|
927
|
+
const V4_BRANCH_LINK =
|
|
928
|
+
/(?:github\.com\/b3pay\/ic-reactor\/(?:tree|blob|edit|raw|commits)\/|raw\.githubusercontent\.com\/b3pay\/ic-reactor\/|stackblitz\.com\/github\/b3pay\/ic-reactor\/tree\/|codesandbox\.io\/p\/github\/b3pay\/ic-reactor\/)v4(?![\w.-])/gi
|
|
929
|
+
for (const relPath of [
|
|
930
|
+
...new Set([
|
|
931
|
+
...docsLinkFiles,
|
|
932
|
+
"docs/astro.config.mjs",
|
|
933
|
+
...[...sourcePages].sort().map((page) => `docs/src/content/docs/${page}`),
|
|
934
|
+
]),
|
|
935
|
+
]) {
|
|
936
|
+
const absPath = join(rootDir, relPath)
|
|
937
|
+
if (!existsSync(absPath)) continue
|
|
938
|
+
readFileSync(absPath, "utf8")
|
|
939
|
+
.split("\n")
|
|
940
|
+
.forEach((line, i) => {
|
|
941
|
+
for (const match of line.matchAll(V4_BRANCH_LINK)) {
|
|
942
|
+
failures.push(
|
|
943
|
+
`${relPath}:${i + 1} links the v4 branch (${match[0]}). ic-reactor 4 is on main: link main instead.`
|
|
944
|
+
)
|
|
945
|
+
}
|
|
946
|
+
})
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
if (failures.length > 0) {
|
|
950
|
+
console.error("AI context check failed:\n")
|
|
951
|
+
for (const failure of failures) {
|
|
952
|
+
console.error(`- ${failure}`)
|
|
953
|
+
}
|
|
954
|
+
// Not process.exit(): on a pipe it can cut off output still being written,
|
|
955
|
+
// and a long list of failures is the output most worth reading in full.
|
|
956
|
+
process.exitCode = 1
|
|
957
|
+
} else {
|
|
958
|
+
console.log(
|
|
959
|
+
`AI context check passed (${aiContextFiles.length} files, ${packageGuides.length} package guides, ` +
|
|
960
|
+
`${checkedSkills.size} skills, ${consumerSkillDirs.length} consumer skill(s), ` +
|
|
961
|
+
`docs links in ${docsLinkFiles.length} files, ${sourcePages.size} docs pages, versions: ${[...validVersions].join(", ")}).`
|
|
962
|
+
)
|
|
963
|
+
}
|