@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.
Files changed (1041) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +108 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
  4. package/.github/actions/setup-rust-wasm/action.yml +25 -0
  5. package/.github/dependabot.yml +107 -0
  6. package/.github/workflows/auth-latest.yml +67 -0
  7. package/.github/workflows/b3pay-site.yml +49 -0
  8. package/.github/workflows/ci.yml +430 -0
  9. package/.github/workflows/codeql.yml +41 -0
  10. package/.github/workflows/dependency-review.yml +68 -0
  11. package/.github/workflows/docs-check.yml +98 -0
  12. package/.github/workflows/docs.yml +265 -0
  13. package/.github/workflows/e2e.yml +90 -0
  14. package/.github/workflows/examples-published.yml +97 -0
  15. package/.github/workflows/release.yml +326 -0
  16. package/.husky/pre-commit +12 -0
  17. package/.prettierignore +109 -0
  18. package/.prettierrc +6 -0
  19. package/AGENTS.md +103 -0
  20. package/CHANGELOG.md +3268 -0
  21. package/CLAUDE.md +93 -0
  22. package/CNAME +1 -0
  23. package/CODE_OF_CONDUCT.md +7 -0
  24. package/CONTRIBUTING.md +433 -0
  25. package/LICENSE +21 -0
  26. package/README.md +2 -2
  27. package/SECURITY.md +74 -0
  28. package/b3pay-module.json +194 -0
  29. package/docs/.remarkrc.json +10 -0
  30. package/docs/README.md +64 -0
  31. package/docs/astro.config.mjs +205 -0
  32. package/docs/favicon.svg +15 -0
  33. package/docs/package.json +39 -0
  34. package/docs/public/favicon.svg +15 -0
  35. package/docs/public/ic-reactor-social-card.png +0 -0
  36. package/docs/scripts/b3pay-static.mjs +22 -0
  37. package/docs/scripts/check-example-docs.mjs +214 -0
  38. package/docs/scripts/check-links.mjs +212 -0
  39. package/docs/scripts/fix-dist-links.js +125 -0
  40. package/docs/scripts/fix-frontmatter.js +71 -0
  41. package/docs/scripts/remove-redundant-h1.cjs +48 -0
  42. package/docs/scripts/rewrite-typedoc-links.js +110 -0
  43. package/docs/scripts/split-index.js +69 -0
  44. package/docs/src/assets/ic-reactor-hero-dark.svg +23 -0
  45. package/docs/src/assets/ic-reactor-hero-light.svg +23 -0
  46. package/docs/src/assets/ic-reactor-lockup-dark.svg +15 -0
  47. package/docs/src/assets/ic-reactor-lockup-light.svg +15 -0
  48. package/docs/src/assets/ic-reactor-mark-dark.svg +14 -0
  49. package/docs/src/assets/ic-reactor-mark-light.svg +14 -0
  50. package/docs/src/assets/layers/candid-core-layer-icon-dark.svg +4 -0
  51. package/docs/src/assets/layers/candid-core-layer-icon-light.svg +4 -0
  52. package/docs/src/assets/layers/candid-profile-layer-icon-dark.svg +4 -0
  53. package/docs/src/assets/layers/candid-profile-layer-icon-light.svg +4 -0
  54. package/docs/src/assets/layers/ic-reactor-layer-icon-dark.svg +4 -0
  55. package/docs/src/assets/layers/ic-reactor-layer-icon-light.svg +4 -0
  56. package/docs/src/components/LibraryCards.astro +172 -0
  57. package/docs/src/components/LibraryIcon.astro +28 -0
  58. package/docs/src/components/SiteTitle.astro +241 -0
  59. package/docs/src/content/docs/404.mdx +19 -0
  60. package/docs/src/content/docs/build/agent-tools.mdx +593 -0
  61. package/docs/src/content/docs/build/icrc1-wallet.mdx +619 -0
  62. package/docs/src/content/docs/build/ssr-per-user.mdx +552 -0
  63. package/docs/src/content/docs/examples/canister-studio.mdx +95 -0
  64. package/docs/src/content/docs/examples/icrc-ledger.mdx +45 -0
  65. package/docs/src/content/docs/examples/index.mdx +38 -0
  66. package/docs/src/content/docs/examples/next-ssr.mdx +73 -0
  67. package/docs/src/content/docs/examples/node-agent-tool.mdx +80 -0
  68. package/docs/src/content/docs/examples/vite-wallet.mdx +71 -0
  69. package/docs/src/content/docs/guides/auth.mdx +1181 -0
  70. package/docs/src/content/docs/guides/client.mdx +551 -0
  71. package/docs/src/content/docs/guides/deploy.mdx +180 -0
  72. package/docs/src/content/docs/guides/errors.mdx +475 -0
  73. package/docs/src/content/docs/guides/getting-started.mdx +620 -0
  74. package/docs/src/content/docs/guides/reads.mdx +586 -0
  75. package/docs/src/content/docs/guides/ssr.mdx +529 -0
  76. package/docs/src/content/docs/guides/testing.mdx +401 -0
  77. package/docs/src/content/docs/guides/values.mdx +261 -0
  78. package/docs/src/content/docs/guides/vite-plugin.mdx +690 -0
  79. package/docs/src/content/docs/guides/writes.mdx +572 -0
  80. package/docs/src/content/docs/ic-reactor/index.mdx +167 -0
  81. package/docs/src/content/docs/index.mdx +65 -0
  82. package/docs/src/content/docs/migrating-from-3.mdx +535 -0
  83. package/docs/src/content/docs/packages/core.mdx +186 -0
  84. package/docs/src/content/docs/packages/mcp.mdx +163 -0
  85. package/docs/src/content/docs/packages/react.mdx +207 -0
  86. package/docs/src/content/docs/packages/vite-plugin.mdx +73 -0
  87. package/docs/src/content/docs/versioning.mdx +104 -0
  88. package/docs/src/content.config.ts +7 -0
  89. package/docs/src/styles/custom.css +189 -0
  90. package/docs/tsconfig.typedoc.json +26 -0
  91. package/docs/typedoc-entry.ts +17 -0
  92. package/docs/typedoc.json +37 -0
  93. package/e2e/Cargo.lock +646 -0
  94. package/e2e/Cargo.toml +3 -0
  95. package/e2e/README.md +101 -0
  96. package/e2e/frontends/build.mjs +94 -0
  97. package/e2e/frontends/index.html +10 -0
  98. package/e2e/global-setup.ts +65 -0
  99. package/e2e/icp.yaml +38 -0
  100. package/e2e/package.json +40 -0
  101. package/e2e/setup.ts +6 -0
  102. package/e2e/src/actor/Cargo.toml +14 -0
  103. package/e2e/src/actor/hello_actor.did +10 -0
  104. package/e2e/src/actor/src/lib.rs +73 -0
  105. package/e2e/src/calls.test.ts +132 -0
  106. package/e2e/src/declarations/hello_actor.envelope.json +175 -0
  107. package/e2e/src/declarations/hello_actor.ts +15 -0
  108. package/e2e/src/errors.test.ts +107 -0
  109. package/e2e/src/frontend-headers.test.ts +253 -0
  110. package/e2e/src/identity.test.ts +61 -0
  111. package/e2e/src/react.test.tsx +59 -0
  112. package/e2e/src/replica.ts +70 -0
  113. package/e2e/src/vite-env.test.ts +108 -0
  114. package/e2e/test.sh +47 -0
  115. package/e2e/tsconfig.json +20 -0
  116. package/e2e/tsconfig.typecheck.json +9 -0
  117. package/e2e/vitest.config.ts +22 -0
  118. package/eslint.config.mjs +100 -0
  119. package/evals/PREREGISTRATION.md +1346 -0
  120. package/evals/README.md +756 -0
  121. package/evals/conditions/thin/condition.json +8 -0
  122. package/evals/conditions/thin/docs/candid-core-cli.README.md +90 -0
  123. package/evals/conditions/thin/docs/candid-core-schema.README.md +339 -0
  124. package/evals/conditions/thin/package.json +25 -0
  125. package/evals/conditions/thin/starter/src/generated/icrc1.ts +57 -0
  126. package/evals/conditions/thin-guide/condition.json +10 -0
  127. package/evals/conditions/thin-guide/docs/llms.txt +292 -0
  128. package/evals/conditions/v3/condition.json +9 -0
  129. package/evals/conditions/v3/docs/ic-reactor-core.llms.txt +232 -0
  130. package/evals/conditions/v3/docs/ic-reactor-react.llms.txt +280 -0
  131. package/evals/conditions/v3/docs/llms-full.txt +1053 -0
  132. package/evals/conditions/v3/package.json +26 -0
  133. package/evals/conditions/v3/starter/src/declarations/icrc1.did.d.ts +95 -0
  134. package/evals/conditions/v3/starter/src/declarations/icrc1.did.js +140 -0
  135. package/evals/conditions/v4/PORTING.md +384 -0
  136. package/evals/conditions/v4/README.md +106 -0
  137. package/evals/conditions/v4/condition.json +5 -0
  138. package/evals/conditions/v4/docs/llms.txt +323 -0
  139. package/evals/conditions/v4/package.json +27 -0
  140. package/evals/conditions/v4/starter/src/generated/icrc1.ts +78 -0
  141. package/evals/conditions/v4-proto/condition.json +6 -0
  142. package/evals/conditions/v4-proto/docs/llms.txt +291 -0
  143. package/evals/conditions/v4-proto/lib/SHIM-NOTES.md +20 -0
  144. package/evals/conditions/v4-proto/lib/package.json +27 -0
  145. package/evals/conditions/v4-proto/lib/src/client.ts +471 -0
  146. package/evals/conditions/v4-proto/lib/src/errors.ts +214 -0
  147. package/evals/conditions/v4-proto/lib/src/index.ts +36 -0
  148. package/evals/conditions/v4-proto/lib/src/principal.ts +175 -0
  149. package/evals/conditions/v4-proto/lib/src/service.ts +69 -0
  150. package/evals/conditions/v4-proto/lib/src/types.ts +174 -0
  151. package/evals/conditions/v4-proto/lib/test/runtime.test.ts +170 -0
  152. package/evals/conditions/v4-proto/lib/test/tsconfig.json +10 -0
  153. package/evals/conditions/v4-proto/lib/test/types.test-d.ts +145 -0
  154. package/evals/conditions/v4-proto/lib/test/vitest.config.mjs +8 -0
  155. package/evals/conditions/v4-proto/lib/tsconfig.json +17 -0
  156. package/evals/conditions/v4-proto/package.json +26 -0
  157. package/evals/conditions/v4-proto/starter/src/generated/icrc1.service.ts +19 -0
  158. package/evals/conditions/v4-proto/starter/src/generated/icrc1.ts +57 -0
  159. package/evals/drive.mjs +1221 -0
  160. package/evals/gate.mjs +161 -0
  161. package/evals/harness/aggregate.mjs +534 -0
  162. package/evals/harness/aggregate.test.mjs +344 -0
  163. package/evals/harness/assemble.mjs +216 -0
  164. package/evals/harness/assemble.test.mjs +143 -0
  165. package/evals/harness/auth.mjs +91 -0
  166. package/evals/harness/check-docs.mjs +157 -0
  167. package/evals/harness/declarations/icrc1.did.d.ts +95 -0
  168. package/evals/harness/declarations/icrc1.did.js +140 -0
  169. package/evals/harness/drive-auth.test.mjs +584 -0
  170. package/evals/harness/drive.test.mjs +509 -0
  171. package/evals/harness/fake-auth.ts +67 -0
  172. package/evals/harness/fake-ledger.ts +178 -0
  173. package/evals/harness/gate-plan.mjs +104 -0
  174. package/evals/harness/gate-plan.test.mjs +243 -0
  175. package/evals/harness/icrc1.did +88 -0
  176. package/evals/harness/judge.mjs +63 -0
  177. package/evals/harness/judge.test.mjs +81 -0
  178. package/evals/harness/leak-scan.mjs +1373 -0
  179. package/evals/harness/leak-scan.test.mjs +1300 -0
  180. package/evals/harness/probes/amounts.ts +14 -0
  181. package/evals/harness/probes/node-tool.probe.ts +48 -0
  182. package/evals/harness/probes/probe.mjs +149 -0
  183. package/evals/harness/probes/react-wallet.probe.ts +96 -0
  184. package/evals/harness/public/support/auth.ts +38 -0
  185. package/evals/harness/public/support/fake-replica.d.ts +28 -0
  186. package/evals/harness/public/support/fake-replica.js +434 -0
  187. package/evals/harness/public/support/ledger.idl.d.ts +95 -0
  188. package/evals/harness/public/support/ledger.idl.js +140 -0
  189. package/evals/harness/public/support/world.ts +179 -0
  190. package/evals/harness/runs.mjs +139 -0
  191. package/evals/harness/sandbox.mjs +88 -0
  192. package/evals/harness/sandbox.test.mjs +134 -0
  193. package/evals/harness/ship.mjs +264 -0
  194. package/evals/harness/ship.test.mjs +552 -0
  195. package/evals/harness/world.ts +291 -0
  196. package/evals/package.json +26 -0
  197. package/evals/pnpm-lock.yaml +1537 -0
  198. package/evals/pnpm-workspace.yaml +12 -0
  199. package/evals/results/2026-09-30T14-22-05-924Z/pilot.json +384 -0
  200. package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.json +404 -0
  201. package/evals/results/2026-09-30T14-22-05-924Z/pilot.rescanned.rescored.json +404 -0
  202. package/evals/results/2026-09-30T14-22-05-924Z/plan.json +240 -0
  203. package/evals/results/2026-09-30T14-22-05-924Z/summary.json +1800 -0
  204. package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.json +1843 -0
  205. package/evals/results/2026-09-30T14-22-05-924Z/summary.rescanned.rescored.json +2100 -0
  206. package/evals/results/2026-09-30T15-48-23-343Z/pilot.json +404 -0
  207. package/evals/results/2026-09-30T15-48-23-343Z/pilot.rescored.json +404 -0
  208. package/evals/results/2026-09-30T15-48-23-343Z/plan.json +242 -0
  209. package/evals/results/2026-09-30T15-48-23-343Z/summary.json +1843 -0
  210. package/evals/results/2026-09-30T15-48-23-343Z/summary.rescored.json +2195 -0
  211. package/evals/results/2026-10-03-beta1-gate/pilot.json +162 -0
  212. package/evals/results/2026-10-03-beta1-gate/plan.json +141 -0
  213. package/evals/results/2026-10-03-beta1-gate/summary.json +983 -0
  214. package/evals/results/2026-10-05-ga-gate/contaminated-run.json +55 -0
  215. package/evals/results/2026-10-05-ga-gate/pilot.json +162 -0
  216. package/evals/results/2026-10-05-ga-gate/plan.json +457 -0
  217. package/evals/results/2026-10-05-ga-gate/summary.json +1037 -0
  218. package/evals/results/2026-10-05-ga-gate/summary.rescanned.json +1037 -0
  219. package/evals/results/README.md +31 -0
  220. package/evals/runs-pilot.log +150 -0
  221. package/evals/runs-pilot2.log +150 -0
  222. package/evals/score.mjs +256 -0
  223. package/evals/setup.mjs +547 -0
  224. package/evals/tasks/node-tool/faulty/thin-accepts-exponent/meta.json +5 -0
  225. package/evals/tasks/node-tool/faulty/thin-accepts-exponent/src/index.ts +121 -0
  226. package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/meta.json +5 -0
  227. package/evals/tasks/node-tool/faulty/thin-anonymous-transfer/src/index.ts +116 -0
  228. package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/meta.json +9 -0
  229. package/evals/tasks/node-tool/faulty/thin-every-reject-may-have-executed/src/index.ts +118 -0
  230. package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/meta.json +5 -0
  231. package/evals/tasks/node-tool/faulty/thin-fetches-root-key-off-local/src/index.ts +118 -0
  232. package/evals/tasks/node-tool/faulty/thin-ignores-root-key/meta.json +5 -0
  233. package/evals/tasks/node-tool/faulty/thin-ignores-root-key/src/index.ts +117 -0
  234. package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/meta.json +9 -0
  235. package/evals/tasks/node-tool/faulty/thin-misclassifies-reject-codes/src/index.ts +119 -0
  236. package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/meta.json +9 -0
  237. package/evals/tasks/node-tool/faulty/thin-no-nat64-cap/src/index.ts +118 -0
  238. package/evals/tasks/node-tool/faulty/thin-number-amount/meta.json +10 -0
  239. package/evals/tasks/node-tool/faulty/thin-number-amount/src/index.ts +117 -0
  240. package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/meta.json +5 -0
  241. package/evals/tasks/node-tool/faulty/thin-truncates-fraction-digits/src/index.ts +120 -0
  242. package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/meta.json +5 -0
  243. package/evals/tasks/node-tool/faulty/thin-unvalidated-recipient/src/index.ts +118 -0
  244. package/evals/tasks/node-tool/faulty/v3-retry-call-errors/meta.json +11 -0
  245. package/evals/tasks/node-tool/faulty/v3-retry-call-errors/src/index.ts +149 -0
  246. package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/meta.json +5 -0
  247. package/evals/tasks/node-tool/faulty/v4-anonymous-identity-sent/src/index.ts +71 -0
  248. package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/meta.json +9 -0
  249. package/evals/tasks/node-tool/faulty/v4-never-may-have-executed/src/index.ts +84 -0
  250. package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/meta.json +9 -0
  251. package/evals/tasks/node-tool/faulty/v4-proto-never-may-have-executed/src/index.ts +72 -0
  252. package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/meta.json +5 -0
  253. package/evals/tasks/node-tool/faulty/v4-proto-refuses-nat64-max/src/index.ts +72 -0
  254. package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/meta.json +5 -0
  255. package/evals/tasks/node-tool/faulty/v4-refuses-nat64-max/src/index.ts +84 -0
  256. package/evals/tasks/node-tool/hidden/node-tool.test.ts +312 -0
  257. package/evals/tasks/node-tool/prompt.md +55 -0
  258. package/evals/tasks/node-tool/prompt.minimal.md +30 -0
  259. package/evals/tasks/node-tool/solutions/thin/reference/src/index.ts +118 -0
  260. package/evals/tasks/node-tool/solutions/thin/reference-module-scope/src/index.ts +145 -0
  261. package/evals/tasks/node-tool/solutions/thin-guide/reference/src/index.ts +118 -0
  262. package/evals/tasks/node-tool/solutions/thin-guide/reference-module-scope/src/index.ts +145 -0
  263. package/evals/tasks/node-tool/solutions/v3/reference/src/index.ts +140 -0
  264. package/evals/tasks/node-tool/solutions/v3/reference-module-scope/src/index.ts +153 -0
  265. package/evals/tasks/node-tool/solutions/v4/reference/src/index.ts +84 -0
  266. package/evals/tasks/node-tool/solutions/v4/reference-module-scope/src/index.ts +105 -0
  267. package/evals/tasks/node-tool/solutions/v4-proto/reference/src/index.ts +72 -0
  268. package/evals/tasks/node-tool/solutions/v4-proto/reference-module-scope/src/index.ts +87 -0
  269. package/evals/tasks/node-tool/starter/src/contract.ts +31 -0
  270. package/evals/tasks/node-tool/starter/src/index.ts +7 -0
  271. package/evals/tasks/node-tool/starter/test/smoke.test.ts +22 -0
  272. package/evals/tasks/node-tool/starter/tsconfig.json +17 -0
  273. package/evals/tasks/node-tool/task.json +63 -0
  274. package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/meta.json +5 -0
  275. package/evals/tasks/react-wallet/faulty/thin-accepts-exponent/src/Wallet.tsx +216 -0
  276. package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/meta.json +5 -0
  277. package/evals/tasks/react-wallet/faulty/thin-anonymous-transfer/src/Wallet.tsx +212 -0
  278. package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/meta.json +5 -0
  279. package/evals/tasks/react-wallet/faulty/thin-both-auth-buttons/src/Wallet.tsx +210 -0
  280. package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/meta.json +8 -0
  281. package/evals/tasks/react-wallet/faulty/thin-constant-balance-key/src/Wallet.tsx +213 -0
  282. package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/meta.json +9 -0
  283. package/evals/tasks/react-wallet/faulty/thin-no-nat64-cap/src/Wallet.tsx +213 -0
  284. package/evals/tasks/react-wallet/faulty/thin-number-balance/meta.json +5 -0
  285. package/evals/tasks/react-wallet/faulty/thin-number-balance/src/Wallet.tsx +213 -0
  286. package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/meta.json +5 -0
  287. package/evals/tasks/react-wallet/faulty/thin-transfer-as-query/src/Wallet.tsx +254 -0
  288. package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/meta.json +5 -0
  289. package/evals/tasks/react-wallet/faulty/thin-truncates-fraction-digits/src/Wallet.tsx +215 -0
  290. package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/meta.json +5 -0
  291. package/evals/tasks/react-wallet/faulty/thin-unguarded-balance-effect/src/Wallet.tsx +214 -0
  292. package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/meta.json +5 -0
  293. package/evals/tasks/react-wallet/faulty/v3-http-4xx-unknown/src/Wallet.tsx +224 -0
  294. package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/meta.json +12 -0
  295. package/evals/tasks/react-wallet/faulty/v3-mutation-retry-3/src/Wallet.tsx +225 -0
  296. package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/meta.json +11 -0
  297. package/evals/tasks/react-wallet/faulty/v3-unknown-as-error/src/Wallet.tsx +182 -0
  298. package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/meta.json +5 -0
  299. package/evals/tasks/react-wallet/faulty/v4-every-reject-unknown/src/Wallet.tsx +160 -0
  300. package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/meta.json +5 -0
  301. package/evals/tasks/react-wallet/faulty/v4-keep-previous-data/src/Wallet.tsx +166 -0
  302. package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/meta.json +5 -0
  303. package/evals/tasks/react-wallet/faulty/v4-proto-every-reject-unknown/src/Wallet.tsx +161 -0
  304. package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/meta.json +5 -0
  305. package/evals/tasks/react-wallet/faulty/v4-proto-keep-previous-data/src/Wallet.tsx +163 -0
  306. package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/meta.json +12 -0
  307. package/evals/tasks/react-wallet/faulty/v4-proto-retry-spread/src/Wallet.tsx +162 -0
  308. package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/meta.json +5 -0
  309. package/evals/tasks/react-wallet/faulty/v4-proto-status-not-idle/src/Wallet.tsx +163 -0
  310. package/evals/tasks/react-wallet/faulty/v4-retry-spread/meta.json +12 -0
  311. package/evals/tasks/react-wallet/faulty/v4-retry-spread/src/Wallet.tsx +163 -0
  312. package/evals/tasks/react-wallet/faulty/v4-status-not-idle/meta.json +5 -0
  313. package/evals/tasks/react-wallet/faulty/v4-status-not-idle/src/Wallet.tsx +162 -0
  314. package/evals/tasks/react-wallet/hidden/react-wallet.test.ts +536 -0
  315. package/evals/tasks/react-wallet/prompt.md +88 -0
  316. package/evals/tasks/react-wallet/prompt.minimal.md +51 -0
  317. package/evals/tasks/react-wallet/solutions/thin/reference/src/Wallet.tsx +213 -0
  318. package/evals/tasks/react-wallet/solutions/thin/reference-module-scope/src/Wallet.tsx +227 -0
  319. package/evals/tasks/react-wallet/solutions/thin-guide/reference/src/Wallet.tsx +213 -0
  320. package/evals/tasks/react-wallet/solutions/thin-guide/reference-module-scope/src/Wallet.tsx +227 -0
  321. package/evals/tasks/react-wallet/solutions/v3/reference/src/Wallet.tsx +224 -0
  322. package/evals/tasks/react-wallet/solutions/v3/reference-module-scope/src/Wallet.tsx +230 -0
  323. package/evals/tasks/react-wallet/solutions/v4/reference/src/Wallet.tsx +160 -0
  324. package/evals/tasks/react-wallet/solutions/v4/reference-module-scope/src/Wallet.tsx +178 -0
  325. package/evals/tasks/react-wallet/solutions/v4-proto/reference/src/Wallet.tsx +161 -0
  326. package/evals/tasks/react-wallet/solutions/v4-proto/reference-module-scope/src/Wallet.tsx +161 -0
  327. package/evals/tasks/react-wallet/starter/src/Wallet.tsx +12 -0
  328. package/evals/tasks/react-wallet/starter/src/auth.ts +16 -0
  329. package/evals/tasks/react-wallet/starter/src/config.ts +14 -0
  330. package/evals/tasks/react-wallet/starter/src/ii-auth.ts +43 -0
  331. package/evals/tasks/react-wallet/starter/src/main.tsx +15 -0
  332. package/evals/tasks/react-wallet/starter/test/smoke.test.ts +34 -0
  333. package/evals/tasks/react-wallet/starter/tsconfig.json +18 -0
  334. package/evals/tasks/react-wallet/task.json +84 -0
  335. package/examples/canister-studio/.stackblitzrc +4 -0
  336. package/examples/canister-studio/README.md +183 -0
  337. package/examples/canister-studio/did/ckbtc_minter.did +806 -0
  338. package/examples/canister-studio/did/icp_ledger.did +586 -0
  339. package/examples/canister-studio/did/icrc1.did +88 -0
  340. package/examples/canister-studio/package.json +45 -0
  341. package/examples/canister-studio/scripts/smoke.ts +188 -0
  342. package/examples/canister-studio/src/calls/CacheKeyPanel.tsx +104 -0
  343. package/examples/canister-studio/src/calls/ConfirmWrite.tsx +265 -0
  344. package/examples/canister-studio/src/calls/ErrorPanel.test.tsx +113 -0
  345. package/examples/canister-studio/src/calls/ErrorPanel.tsx +214 -0
  346. package/examples/canister-studio/src/calls/MethodRunner.test.tsx +354 -0
  347. package/examples/canister-studio/src/calls/MethodRunner.tsx +57 -0
  348. package/examples/canister-studio/src/calls/ReadRunner.tsx +244 -0
  349. package/examples/canister-studio/src/calls/ResendPanel.tsx +165 -0
  350. package/examples/canister-studio/src/calls/ShareLink.tsx +59 -0
  351. package/examples/canister-studio/src/calls/WriteRunner.test.tsx +678 -0
  352. package/examples/canister-studio/src/calls/WriteRunner.tsx +670 -0
  353. package/examples/canister-studio/src/calls/dedupe.ts +189 -0
  354. package/examples/canister-studio/src/calls/error-info.ts +168 -0
  355. package/examples/canister-studio/src/calls/history.test.ts +284 -0
  356. package/examples/canister-studio/src/calls/history.ts +287 -0
  357. package/examples/canister-studio/src/calls/kinds.ts +68 -0
  358. package/examples/canister-studio/src/calls/prepare.ts +32 -0
  359. package/examples/canister-studio/src/calls/query-options.ts +30 -0
  360. package/examples/canister-studio/src/calls/read.ts +47 -0
  361. package/examples/canister-studio/src/calls/readback.ts +100 -0
  362. package/examples/canister-studio/src/calls/record.ts +123 -0
  363. package/examples/canister-studio/src/calls/safe-calls.test.ts +299 -0
  364. package/examples/canister-studio/src/calls/share.ts +46 -0
  365. package/examples/canister-studio/src/calls/testing/doubles.tsx +108 -0
  366. package/examples/canister-studio/src/calls/testing/fixtures.ts +185 -0
  367. package/examples/canister-studio/src/calls/useCanisterHandle.ts +35 -0
  368. package/examples/canister-studio/src/canisters/ckbtc_minter.envelope.json +4228 -0
  369. package/examples/canister-studio/src/canisters/ckbtc_minter.ts +868 -0
  370. package/examples/canister-studio/src/canisters/icp_ledger.envelope.json +3454 -0
  371. package/examples/canister-studio/src/canisters/icp_ledger.ts +584 -0
  372. package/examples/canister-studio/src/canisters/icrc1.envelope.json +840 -0
  373. package/examples/canister-studio/src/canisters/icrc1.ts +78 -0
  374. package/examples/canister-studio/src/components/ActionButton.tsx +32 -0
  375. package/examples/canister-studio/src/components/AppHeader.tsx +83 -0
  376. package/examples/canister-studio/src/components/AppShell.tsx +29 -0
  377. package/examples/canister-studio/src/components/AuthButton.tsx +79 -0
  378. package/examples/canister-studio/src/components/Badge.tsx +79 -0
  379. package/examples/canister-studio/src/components/CanisterHeader.tsx +200 -0
  380. package/examples/canister-studio/src/components/CanisterJump.tsx +130 -0
  381. package/examples/canister-studio/src/components/Card.tsx +64 -0
  382. package/examples/canister-studio/src/components/Code.tsx +101 -0
  383. package/examples/canister-studio/src/components/CopyButton.tsx +126 -0
  384. package/examples/canister-studio/src/components/Disclosure.tsx +34 -0
  385. package/examples/canister-studio/src/components/EmptyState.tsx +34 -0
  386. package/examples/canister-studio/src/components/MethodList.test.tsx +137 -0
  387. package/examples/canister-studio/src/components/MethodList.tsx +244 -0
  388. package/examples/canister-studio/src/components/Notice.tsx +36 -0
  389. package/examples/canister-studio/src/components/ProvenanceBadge.tsx +44 -0
  390. package/examples/canister-studio/src/components/RouteError.tsx +42 -0
  391. package/examples/canister-studio/src/components/SectionBoundary.tsx +76 -0
  392. package/examples/canister-studio/src/components/Spinner.tsx +33 -0
  393. package/examples/canister-studio/src/components/Tabs.tsx +96 -0
  394. package/examples/canister-studio/src/components/canister/CanisterLoadFailure.test.tsx +56 -0
  395. package/examples/canister-studio/src/components/canister/CanisterLoadFailure.tsx +165 -0
  396. package/examples/canister-studio/src/components/canister/CanisterNotFound.tsx +59 -0
  397. package/examples/canister-studio/src/components/canister/CanisterPending.tsx +33 -0
  398. package/examples/canister-studio/src/components/canister/MethodOverview.tsx +93 -0
  399. package/examples/canister-studio/src/components/canister/MethodWorkspace.test.tsx +201 -0
  400. package/examples/canister-studio/src/components/canister/MethodWorkspace.tsx +187 -0
  401. package/examples/canister-studio/src/components/canister/shared-call.test.ts +186 -0
  402. package/examples/canister-studio/src/components/canister/shared-call.ts +133 -0
  403. package/examples/canister-studio/src/components/canister/shared-link-loader.test.ts +116 -0
  404. package/examples/canister-studio/src/components/canister/use-canister-page.ts +44 -0
  405. package/examples/canister-studio/src/components/canister/workspace-key.test.ts +27 -0
  406. package/examples/canister-studio/src/components/canister/workspace-key.ts +36 -0
  407. package/examples/canister-studio/src/components/canister-id-input.ts +69 -0
  408. package/examples/canister-studio/src/components/canister-names.ts +11 -0
  409. package/examples/canister-studio/src/components/download.ts +34 -0
  410. package/examples/canister-studio/src/components/fallbacks.tsx +33 -0
  411. package/examples/canister-studio/src/components/helpers.test.ts +107 -0
  412. package/examples/canister-studio/src/components/history/HistoryList.tsx +284 -0
  413. package/examples/canister-studio/src/components/home/FeaturedLedger.tsx +149 -0
  414. package/examples/canister-studio/src/components/home/OpenCanister.tsx +99 -0
  415. package/examples/canister-studio/src/components/home/featured.test.tsx +92 -0
  416. package/examples/canister-studio/src/components/home/featured.ts +64 -0
  417. package/examples/canister-studio/src/components/interface/CandidTab.tsx +38 -0
  418. package/examples/canister-studio/src/components/interface/CompatReport.tsx +92 -0
  419. package/examples/canister-studio/src/components/interface/CompatibilityTab.tsx +190 -0
  420. package/examples/canister-studio/src/components/interface/ProjectTab.tsx +196 -0
  421. package/examples/canister-studio/src/components/interface/TypeScriptTab.tsx +114 -0
  422. package/examples/canister-studio/src/components/interface/tools.test.tsx +169 -0
  423. package/examples/canister-studio/src/components/modes.ts +31 -0
  424. package/examples/canister-studio/src/components/playground/MethodPicker.tsx +67 -0
  425. package/examples/canister-studio/src/components/playground/PlaygroundForms.tsx +112 -0
  426. package/examples/canister-studio/src/components/playground/PlaygroundTools.tsx +219 -0
  427. package/examples/canister-studio/src/components/playground/sample.ts +43 -0
  428. package/examples/canister-studio/src/components/playground/target.test.tsx +86 -0
  429. package/examples/canister-studio/src/components/primitives.test.tsx +121 -0
  430. package/examples/canister-studio/src/components/provenance.ts +38 -0
  431. package/examples/canister-studio/src/components/route-render.test.tsx +71 -0
  432. package/examples/canister-studio/src/components/use-task.ts +56 -0
  433. package/examples/canister-studio/src/components/wallet/BalancePanel.tsx +110 -0
  434. package/examples/canister-studio/src/components/wallet/LedgerSummary.tsx +63 -0
  435. package/examples/canister-studio/src/components/wallet/MinterPanel.tsx +255 -0
  436. package/examples/canister-studio/src/components/wallet/SendPanel.test.tsx +297 -0
  437. package/examples/canister-studio/src/components/wallet/SendPanel.tsx +446 -0
  438. package/examples/canister-studio/src/components/wallet/ledgers.test.ts +36 -0
  439. package/examples/canister-studio/src/components/wallet/ledgers.ts +111 -0
  440. package/examples/canister-studio/src/forms/JsonPanel.tsx +157 -0
  441. package/examples/canister-studio/src/forms/MethodForm.test.tsx +369 -0
  442. package/examples/canister-studio/src/forms/MethodForm.tsx +368 -0
  443. package/examples/canister-studio/src/forms/TypedForm.tsx +55 -0
  444. package/examples/canister-studio/src/forms/context.ts +62 -0
  445. package/examples/canister-studio/src/forms/convert.ts +131 -0
  446. package/examples/canister-studio/src/forms/edge.test.ts +252 -0
  447. package/examples/canister-studio/src/forms/engine.test.ts +358 -0
  448. package/examples/canister-studio/src/forms/engine.ts +1492 -0
  449. package/examples/canister-studio/src/forms/fields/BytesField.tsx +210 -0
  450. package/examples/canister-studio/src/forms/fields/Field.tsx +106 -0
  451. package/examples/canister-studio/src/forms/fields/FieldShell.tsx +101 -0
  452. package/examples/canister-studio/src/forms/fields/Group.tsx +74 -0
  453. package/examples/canister-studio/src/forms/fields/ListField.tsx +256 -0
  454. package/examples/canister-studio/src/forms/fields/Segmented.tsx +78 -0
  455. package/examples/canister-studio/src/forms/fields/TimestampField.tsx +108 -0
  456. package/examples/canister-studio/src/forms/fields/UnitsField.tsx +119 -0
  457. package/examples/canister-studio/src/forms/fields/composites.tsx +389 -0
  458. package/examples/canister-studio/src/forms/fields/leaves.tsx +350 -0
  459. package/examples/canister-studio/src/forms/fields.test.tsx +396 -0
  460. package/examples/canister-studio/src/forms/helpers.test.ts +225 -0
  461. package/examples/canister-studio/src/forms/hints.ts +128 -0
  462. package/examples/canister-studio/src/forms/json.ts +119 -0
  463. package/examples/canister-studio/src/forms/parsing.test.ts +217 -0
  464. package/examples/canister-studio/src/forms/useMethodForm.ts +251 -0
  465. package/examples/canister-studio/src/interface/browser.test.ts +23 -0
  466. package/examples/canister-studio/src/interface/browser.ts +153 -0
  467. package/examples/canister-studio/src/interface/cache.ts +68 -0
  468. package/examples/canister-studio/src/interface/cli-cache.test.ts +155 -0
  469. package/examples/canister-studio/src/interface/cli-cache.ts +125 -0
  470. package/examples/canister-studio/src/interface/compile.server.test.ts +198 -0
  471. package/examples/canister-studio/src/interface/compile.server.ts +262 -0
  472. package/examples/canister-studio/src/interface/compile.test.ts +108 -0
  473. package/examples/canister-studio/src/interface/compile.ts +305 -0
  474. package/examples/canister-studio/src/interface/docs.test.ts +75 -0
  475. package/examples/canister-studio/src/interface/docs.ts +100 -0
  476. package/examples/canister-studio/src/interface/functions.test.ts +42 -0
  477. package/examples/canister-studio/src/interface/functions.ts +200 -0
  478. package/examples/canister-studio/src/interface/live-candid.server.ts +91 -0
  479. package/examples/canister-studio/src/interface/live-loader.test.ts +515 -0
  480. package/examples/canister-studio/src/interface/live-loader.ts +364 -0
  481. package/examples/canister-studio/src/interface/load.test.ts +328 -0
  482. package/examples/canister-studio/src/interface/load.ts +249 -0
  483. package/examples/canister-studio/src/interface/read-candid.test.ts +185 -0
  484. package/examples/canister-studio/src/interface/read-candid.ts +233 -0
  485. package/examples/canister-studio/src/interface/server-result.ts +42 -0
  486. package/examples/canister-studio/src/interface/typed.ts +68 -0
  487. package/examples/canister-studio/src/interface/types.ts +121 -0
  488. package/examples/canister-studio/src/lib/format.test.ts +107 -0
  489. package/examples/canister-studio/src/lib/format.ts +139 -0
  490. package/examples/canister-studio/src/lib/hex.test.ts +43 -0
  491. package/examples/canister-studio/src/lib/hex.ts +33 -0
  492. package/examples/canister-studio/src/lib/ids.test.ts +70 -0
  493. package/examples/canister-studio/src/lib/ids.ts +93 -0
  494. package/examples/canister-studio/src/lib/reactor.test.ts +55 -0
  495. package/examples/canister-studio/src/lib/reactor.ts +55 -0
  496. package/examples/canister-studio/src/lib/registry.test.ts +74 -0
  497. package/examples/canister-studio/src/lib/registry.ts +238 -0
  498. package/examples/canister-studio/src/lib/schema.ts +148 -0
  499. package/examples/canister-studio/src/routeTree.gen.ts +227 -0
  500. package/examples/canister-studio/src/router.test.ts +290 -0
  501. package/examples/canister-studio/src/router.tsx +127 -0
  502. package/examples/canister-studio/src/routes/__root.tsx +58 -0
  503. package/examples/canister-studio/src/routes/canister.$canisterId.index.tsx +172 -0
  504. package/examples/canister-studio/src/routes/canister.$canisterId.interface.tsx +98 -0
  505. package/examples/canister-studio/src/routes/canister.$canisterId.tsx +91 -0
  506. package/examples/canister-studio/src/routes/history.tsx +55 -0
  507. package/examples/canister-studio/src/routes/index.tsx +169 -0
  508. package/examples/canister-studio/src/routes/playground.tsx +286 -0
  509. package/examples/canister-studio/src/routes/safety.tsx +57 -0
  510. package/examples/canister-studio/src/routes/wallet.tsx +213 -0
  511. package/examples/canister-studio/src/safety/LabTransferForm.tsx +84 -0
  512. package/examples/canister-studio/src/safety/RequestLog.tsx +79 -0
  513. package/examples/canister-studio/src/safety/SafetyLab.test.tsx +89 -0
  514. package/examples/canister-studio/src/safety/SafetyLab.tsx +140 -0
  515. package/examples/canister-studio/src/safety/ScenarioCard.tsx +262 -0
  516. package/examples/canister-studio/src/safety/lab-run.ts +283 -0
  517. package/examples/canister-studio/src/safety/mock-ledger.test.ts +99 -0
  518. package/examples/canister-studio/src/safety/mock-ledger.ts +263 -0
  519. package/examples/canister-studio/src/safety/scenarios.test.ts +157 -0
  520. package/examples/canister-studio/src/safety/scenarios.ts +924 -0
  521. package/examples/canister-studio/src/styles.css +3453 -0
  522. package/examples/canister-studio/src/styles.test.ts +46 -0
  523. package/examples/canister-studio/src/values/CallPreview.test.tsx +86 -0
  524. package/examples/canister-studio/src/values/CallPreview.tsx +148 -0
  525. package/examples/canister-studio/src/values/ErrValueView.tsx +66 -0
  526. package/examples/canister-studio/src/values/Inspector.tsx +133 -0
  527. package/examples/canister-studio/src/values/ReplyView.test.tsx +341 -0
  528. package/examples/canister-studio/src/values/ReplyView.tsx +164 -0
  529. package/examples/canister-studio/src/values/candid-text.test.ts +516 -0
  530. package/examples/canister-studio/src/values/candid-text.ts +479 -0
  531. package/examples/canister-studio/src/values/hints.ts +58 -0
  532. package/examples/canister-studio/src/values/json.test.ts +66 -0
  533. package/examples/canister-studio/src/values/json.ts +31 -0
  534. package/examples/canister-studio/src/values/leaves.tsx +309 -0
  535. package/examples/canister-studio/src/values/schema.test.ts +123 -0
  536. package/examples/canister-studio/src/values/schema.ts +78 -0
  537. package/examples/canister-studio/src/values/test-router.tsx +21 -0
  538. package/examples/canister-studio/src/values/tree.tsx +670 -0
  539. package/examples/canister-studio/src/values/use-sha256.ts +29 -0
  540. package/examples/canister-studio/tsconfig.json +20 -0
  541. package/examples/canister-studio/vite.config.ts +50 -0
  542. package/examples/canister-studio/vitest.config.ts +20 -0
  543. package/examples/icrc-ledger/.stackblitzrc +4 -0
  544. package/examples/icrc-ledger/README.md +100 -0
  545. package/examples/icrc-ledger/ckbtc_minter.did +12 -0
  546. package/examples/icrc-ledger/icp_ledger.did +147 -0
  547. package/examples/icrc-ledger/icrc1.did +88 -0
  548. package/examples/icrc-ledger/index.html +13 -0
  549. package/examples/icrc-ledger/package.json +40 -0
  550. package/examples/icrc-ledger/scripts/smoke.ts +151 -0
  551. package/examples/icrc-ledger/src/App.tsx +71 -0
  552. package/examples/icrc-ledger/src/ErrorPanel.tsx +105 -0
  553. package/examples/icrc-ledger/src/MainnetTab.tsx +450 -0
  554. package/examples/icrc-ledger/src/SandboxTab.test.tsx +379 -0
  555. package/examples/icrc-ledger/src/SandboxTab.tsx +761 -0
  556. package/examples/icrc-ledger/src/blocks.test.ts +247 -0
  557. package/examples/icrc-ledger/src/blocks.ts +140 -0
  558. package/examples/icrc-ledger/src/canisters/ckbtc_minter.envelope.json +96 -0
  559. package/examples/icrc-ledger/src/canisters/ckbtc_minter.ts +16 -0
  560. package/examples/icrc-ledger/src/canisters/icp_ledger.envelope.json +690 -0
  561. package/examples/icrc-ledger/src/canisters/icp_ledger.ts +223 -0
  562. package/examples/icrc-ledger/src/canisters/icrc1.envelope.json +840 -0
  563. package/examples/icrc-ledger/src/canisters/icrc1.ts +78 -0
  564. package/examples/icrc-ledger/src/format.test.ts +41 -0
  565. package/examples/icrc-ledger/src/format.ts +68 -0
  566. package/examples/icrc-ledger/src/ledger.ts +15 -0
  567. package/examples/icrc-ledger/src/main.tsx +10 -0
  568. package/examples/icrc-ledger/src/minter.ts +16 -0
  569. package/examples/icrc-ledger/src/sandbox.test.ts +464 -0
  570. package/examples/icrc-ledger/src/sandbox.ts +281 -0
  571. package/examples/icrc-ledger/src/styles.css +391 -0
  572. package/examples/icrc-ledger/src/transfer-form.test.ts +62 -0
  573. package/examples/icrc-ledger/src/transfer-form.ts +97 -0
  574. package/examples/icrc-ledger/tsconfig.json +19 -0
  575. package/examples/icrc-ledger/vite.config.ts +44 -0
  576. package/examples/icrc-ledger/vitest.config.ts +12 -0
  577. package/examples/next-ssr/.stackblitzrc +4 -0
  578. package/examples/next-ssr/README.md +112 -0
  579. package/examples/next-ssr/icrc1.did +88 -0
  580. package/examples/next-ssr/next.config.ts +10 -0
  581. package/examples/next-ssr/package.json +41 -0
  582. package/examples/next-ssr/scripts/smoke.ts +169 -0
  583. package/examples/next-ssr/src/app/account/CertifiedBalances.tsx +58 -0
  584. package/examples/next-ssr/src/app/account/account.test.tsx +165 -0
  585. package/examples/next-ssr/src/app/account/page.tsx +82 -0
  586. package/examples/next-ssr/src/app/api/balance/[ledger]/[principal]/route.ts +10 -0
  587. package/examples/next-ssr/src/app/globals.css +278 -0
  588. package/examples/next-ssr/src/app/layout.tsx +34 -0
  589. package/examples/next-ssr/src/app/page.tsx +46 -0
  590. package/examples/next-ssr/src/app/providers.browser.test.tsx +127 -0
  591. package/examples/next-ssr/src/app/providers.test.tsx +73 -0
  592. package/examples/next-ssr/src/app/providers.tsx +60 -0
  593. package/examples/next-ssr/src/canisters/icrc1.envelope.json +840 -0
  594. package/examples/next-ssr/src/canisters/icrc1.ts +78 -0
  595. package/examples/next-ssr/src/components/BalanceTable.tsx +43 -0
  596. package/examples/next-ssr/src/components/LedgerCard.test.tsx +96 -0
  597. package/examples/next-ssr/src/components/LedgerCard.tsx +230 -0
  598. package/examples/next-ssr/src/components/LedgerError.tsx +32 -0
  599. package/examples/next-ssr/src/components/LedgerSections.tsx +22 -0
  600. package/examples/next-ssr/src/components/MyBalances.test.tsx +253 -0
  601. package/examples/next-ssr/src/components/MyBalances.tsx +129 -0
  602. package/examples/next-ssr/src/components/SessionBadge.tsx +18 -0
  603. package/examples/next-ssr/src/components/hydration.test.tsx +259 -0
  604. package/examples/next-ssr/src/components/server-data.ts +10 -0
  605. package/examples/next-ssr/src/format.ts +46 -0
  606. package/examples/next-ssr/src/ledgers.ts +38 -0
  607. package/examples/next-ssr/src/server/balance-route.test.ts +151 -0
  608. package/examples/next-ssr/src/server/balance-route.ts +157 -0
  609. package/examples/next-ssr/src/server/error-summary.test.ts +34 -0
  610. package/examples/next-ssr/src/server/error-summary.ts +37 -0
  611. package/examples/next-ssr/src/server/parse-owner.test.ts +39 -0
  612. package/examples/next-ssr/src/server/parse-owner.ts +34 -0
  613. package/examples/next-ssr/src/server/prefetch-ledgers.test.ts +137 -0
  614. package/examples/next-ssr/src/server/prefetch-ledgers.ts +70 -0
  615. package/examples/next-ssr/src/server/read-balances.test.ts +103 -0
  616. package/examples/next-ssr/src/server/read-balances.ts +78 -0
  617. package/examples/next-ssr/src/server/request-client.rsc.test.tsx +110 -0
  618. package/examples/next-ssr/src/server/request-client.ts +24 -0
  619. package/examples/next-ssr/src/testing/mock-ledgers.ts +115 -0
  620. package/examples/next-ssr/src/testing/react-server-dom-turbopack.d.ts +15 -0
  621. package/examples/next-ssr/src/testing/setup.ts +10 -0
  622. package/examples/next-ssr/tsconfig.json +31 -0
  623. package/examples/next-ssr/vitest.config.ts +59 -0
  624. package/examples/node-agent-tool/.stackblitzrc +4 -0
  625. package/examples/node-agent-tool/README.md +165 -0
  626. package/examples/node-agent-tool/icp.yaml +11 -0
  627. package/examples/node-agent-tool/icrc1.did +88 -0
  628. package/examples/node-agent-tool/package.json +32 -0
  629. package/examples/node-agent-tool/src/canisters/icrc1.envelope.json +840 -0
  630. package/examples/node-agent-tool/src/canisters/icrc1.ts +78 -0
  631. package/examples/node-agent-tool/src/cli.test.ts +64 -0
  632. package/examples/node-agent-tool/src/cli.ts +23 -0
  633. package/examples/node-agent-tool/src/command-line.ts +159 -0
  634. package/examples/node-agent-tool/src/commands/balance.ts +73 -0
  635. package/examples/node-agent-tool/src/commands/demo.test.ts +51 -0
  636. package/examples/node-agent-tool/src/commands/demo.ts +359 -0
  637. package/examples/node-agent-tool/src/commands/info.ts +69 -0
  638. package/examples/node-agent-tool/src/commands/reads.test.ts +133 -0
  639. package/examples/node-agent-tool/src/commands/resend.test.ts +363 -0
  640. package/examples/node-agent-tool/src/commands/transfer.test.ts +313 -0
  641. package/examples/node-agent-tool/src/commands/transfer.ts +415 -0
  642. package/examples/node-agent-tool/src/commands/watch.test.ts +159 -0
  643. package/examples/node-agent-tool/src/commands/watch.ts +135 -0
  644. package/examples/node-agent-tool/src/commands/whoami.ts +36 -0
  645. package/examples/node-agent-tool/src/context.ts +20 -0
  646. package/examples/node-agent-tool/src/dispatch.ts +70 -0
  647. package/examples/node-agent-tool/src/failure.test.ts +59 -0
  648. package/examples/node-agent-tool/src/failure.ts +176 -0
  649. package/examples/node-agent-tool/src/identity.test.ts +242 -0
  650. package/examples/node-agent-tool/src/identity.ts +228 -0
  651. package/examples/node-agent-tool/src/input.ts +110 -0
  652. package/examples/node-agent-tool/src/ledgers.test.ts +74 -0
  653. package/examples/node-agent-tool/src/ledgers.ts +62 -0
  654. package/examples/node-agent-tool/src/mock-ledger.ts +211 -0
  655. package/examples/node-agent-tool/src/network.test.ts +128 -0
  656. package/examples/node-agent-tool/src/network.ts +101 -0
  657. package/examples/node-agent-tool/src/output.test.ts +208 -0
  658. package/examples/node-agent-tool/src/output.ts +163 -0
  659. package/examples/node-agent-tool/src/run.ts +73 -0
  660. package/examples/node-agent-tool/src/test-kit.ts +167 -0
  661. package/examples/node-agent-tool/tsconfig.json +18 -0
  662. package/examples/node-agent-tool/vitest.config.ts +8 -0
  663. package/examples/vite-wallet/.stackblitzrc +4 -0
  664. package/examples/vite-wallet/Cargo.lock +646 -0
  665. package/examples/vite-wallet/Cargo.toml +5 -0
  666. package/examples/vite-wallet/README.md +107 -0
  667. package/examples/vite-wallet/backend/Cargo.toml +12 -0
  668. package/examples/vite-wallet/backend/backend.did +37 -0
  669. package/examples/vite-wallet/backend/src/lib.rs +133 -0
  670. package/examples/vite-wallet/icp.yaml +44 -0
  671. package/examples/vite-wallet/index.html +13 -0
  672. package/examples/vite-wallet/ledger.did +54 -0
  673. package/examples/vite-wallet/package.json +46 -0
  674. package/examples/vite-wallet/public/.ic-assets.json5 +26 -0
  675. package/examples/vite-wallet/scripts/faucet-args.test.ts +30 -0
  676. package/examples/vite-wallet/scripts/faucet-args.ts +41 -0
  677. package/examples/vite-wallet/scripts/faucet.ts +41 -0
  678. package/examples/vite-wallet/src/AddressBook.test.tsx +191 -0
  679. package/examples/vite-wallet/src/AddressBook.tsx +147 -0
  680. package/examples/vite-wallet/src/App.tsx +53 -0
  681. package/examples/vite-wallet/src/Balance.test.tsx +57 -0
  682. package/examples/vite-wallet/src/Balance.tsx +58 -0
  683. package/examples/vite-wallet/src/EnvironmentPanel.test.tsx +83 -0
  684. package/examples/vite-wallet/src/EnvironmentPanel.tsx +103 -0
  685. package/examples/vite-wallet/src/ErrorNote.tsx +70 -0
  686. package/examples/vite-wallet/src/Profile.test.tsx +145 -0
  687. package/examples/vite-wallet/src/Profile.tsx +92 -0
  688. package/examples/vite-wallet/src/SendIcp.test.tsx +231 -0
  689. package/examples/vite-wallet/src/SendIcp.tsx +244 -0
  690. package/examples/vite-wallet/src/SendToContact.test.tsx +113 -0
  691. package/examples/vite-wallet/src/SendToContact.tsx +102 -0
  692. package/examples/vite-wallet/src/SignIn.test.tsx +106 -0
  693. package/examples/vite-wallet/src/SignIn.tsx +120 -0
  694. package/examples/vite-wallet/src/Wallet.test.tsx +89 -0
  695. package/examples/vite-wallet/src/account-switch.test.tsx +108 -0
  696. package/examples/vite-wallet/src/auth/dev-accounts.test.ts +113 -0
  697. package/examples/vite-wallet/src/auth/dev-accounts.ts +216 -0
  698. package/examples/vite-wallet/src/auth/local-page.test.ts +28 -0
  699. package/examples/vite-wallet/src/auth/local-page.ts +20 -0
  700. package/examples/vite-wallet/src/auth/wallet-auth.test.ts +159 -0
  701. package/examples/vite-wallet/src/auth/wallet-auth.ts +131 -0
  702. package/examples/vite-wallet/src/canisters/backend.envelope.json +275 -0
  703. package/examples/vite-wallet/src/canisters/backend.ts +58 -0
  704. package/examples/vite-wallet/src/canisters/ledger.envelope.json +451 -0
  705. package/examples/vite-wallet/src/canisters/ledger.ts +56 -0
  706. package/examples/vite-wallet/src/client.ts +45 -0
  707. package/examples/vite-wallet/src/main.tsx +18 -0
  708. package/examples/vite-wallet/src/optimistic-contacts.ts +113 -0
  709. package/examples/vite-wallet/src/refusal.ts +17 -0
  710. package/examples/vite-wallet/src/styles.css +282 -0
  711. package/examples/vite-wallet/src/test/test-wallet.tsx +322 -0
  712. package/examples/vite-wallet/src/token.ts +50 -0
  713. package/examples/vite-wallet/src/transfer.test.ts +178 -0
  714. package/examples/vite-wallet/src/transfer.ts +110 -0
  715. package/examples/vite-wallet/src/use-canisters.ts +49 -0
  716. package/examples/vite-wallet/tsconfig.json +19 -0
  717. package/examples/vite-wallet/vite.config.ts +47 -0
  718. package/examples/vite-wallet/vitest.config.ts +17 -0
  719. package/package.json +9 -4
  720. package/packages/core/.size-limit.js +47 -0
  721. package/packages/core/LICENSE +21 -0
  722. package/packages/core/README.md +84 -0
  723. package/packages/core/llms.txt +610 -0
  724. package/packages/core/package.json +89 -0
  725. package/packages/core/src/call.ts +961 -0
  726. package/packages/core/src/canister.ts +259 -0
  727. package/packages/core/src/client.ts +2061 -0
  728. package/packages/core/src/errors.ts +1079 -0
  729. package/packages/core/src/hydration.ts +239 -0
  730. package/packages/core/src/index.ts +23 -0
  731. package/packages/core/src/keys.ts +108 -0
  732. package/packages/core/src/management.ts +138 -0
  733. package/packages/core/src/network.ts +1020 -0
  734. package/packages/core/src/options.ts +1000 -0
  735. package/packages/core/src/runtime.ts +50 -0
  736. package/packages/core/src/testing/fake-replica.ts +1166 -0
  737. package/packages/core/src/testing/index.ts +16 -0
  738. package/packages/core/src/testing/test-auth.ts +340 -0
  739. package/packages/core/src/testing/test-client.ts +559 -0
  740. package/packages/core/src/types.ts +541 -0
  741. package/packages/core/src/units.ts +299 -0
  742. package/packages/core/src/version.ts +4 -0
  743. package/packages/core/tests/canister-helpers.ts +187 -0
  744. package/packages/core/tests/canister-id.test.ts +158 -0
  745. package/packages/core/tests/canister-unwrap.test.ts +94 -0
  746. package/packages/core/tests/canister.test-d.ts +406 -0
  747. package/packages/core/tests/canister.test.ts +1921 -0
  748. package/packages/core/tests/client-account-change.test.ts +131 -0
  749. package/packages/core/tests/client-agents.test.ts +402 -0
  750. package/packages/core/tests/client-auth-network.test.ts +719 -0
  751. package/packages/core/tests/client-disposed.test.ts +403 -0
  752. package/packages/core/tests/client-helpers.ts +136 -0
  753. package/packages/core/tests/client-hydration.test.ts +166 -0
  754. package/packages/core/tests/client-pinned.test.ts +626 -0
  755. package/packages/core/tests/client-session.test.ts +348 -0
  756. package/packages/core/tests/client.test-d.ts +181 -0
  757. package/packages/core/tests/client.test.ts +1162 -0
  758. package/packages/core/tests/encode.test.ts +171 -0
  759. package/packages/core/tests/env-canister-id.test.ts +666 -0
  760. package/packages/core/tests/env-cookie-copies.test.ts +182 -0
  761. package/packages/core/tests/error-guard.test.ts +222 -0
  762. package/packages/core/tests/errors.test-d.ts +280 -0
  763. package/packages/core/tests/errors.test.ts +1359 -0
  764. package/packages/core/tests/fixtures/README.md +28 -0
  765. package/packages/core/tests/fixtures/accounts.did +21 -0
  766. package/packages/core/tests/fixtures/accounts.envelope.json +367 -0
  767. package/packages/core/tests/fixtures/accounts.ts +26 -0
  768. package/packages/core/tests/fixtures/archive.did +31 -0
  769. package/packages/core/tests/fixtures/archive.envelope.json +259 -0
  770. package/packages/core/tests/fixtures/archive.ts +55 -0
  771. package/packages/core/tests/fixtures/icrc1.did +88 -0
  772. package/packages/core/tests/fixtures/icrc1.envelope.json +840 -0
  773. package/packages/core/tests/fixtures/icrc1.ts +78 -0
  774. package/packages/core/tests/fixtures/management.did +724 -0
  775. package/packages/core/tests/fixtures/management.envelope.json +4455 -0
  776. package/packages/core/tests/fixtures/management.ts +486 -0
  777. package/packages/core/tests/fixtures/shapes.did +33 -0
  778. package/packages/core/tests/fixtures/shapes.envelope.json +440 -0
  779. package/packages/core/tests/fixtures/shapes.ts +56 -0
  780. package/packages/core/tests/fixtures/skippable.did +15 -0
  781. package/packages/core/tests/fixtures/skippable.envelope.json +182 -0
  782. package/packages/core/tests/fixtures/skippable.ts +33 -0
  783. package/packages/core/tests/func.test.ts +154 -0
  784. package/packages/core/tests/identity-attributes.test.ts +214 -0
  785. package/packages/core/tests/keys.test.ts +289 -0
  786. package/packages/core/tests/management.test.ts +206 -0
  787. package/packages/core/tests/network-helpers.ts +121 -0
  788. package/packages/core/tests/network.test-d.ts +78 -0
  789. package/packages/core/tests/network.test.ts +1051 -0
  790. package/packages/core/tests/options.test.ts +1594 -0
  791. package/packages/core/tests/redirect-sign-in.test.ts +393 -0
  792. package/packages/core/tests/resend.test-d.ts +81 -0
  793. package/packages/core/tests/resend.test.ts +723 -0
  794. package/packages/core/tests/skip.test-d.ts +125 -0
  795. package/packages/core/tests/testing-entry.test.ts +73 -0
  796. package/packages/core/tests/testing-fake-replica.test.ts +1242 -0
  797. package/packages/core/tests/testing-test-auth.test-d.ts +84 -0
  798. package/packages/core/tests/testing-test-auth.test.ts +483 -0
  799. package/packages/core/tests/testing-test-client.test-d.ts +184 -0
  800. package/packages/core/tests/testing-test-client.test.ts +1272 -0
  801. package/packages/core/tests/time-realm.test.ts +63 -0
  802. package/packages/core/tests/time.test.ts +238 -0
  803. package/packages/core/tests/traps/README.md +39 -0
  804. package/packages/core/tests/traps/anonymous-write.test.ts +145 -0
  805. package/packages/core/tests/traps/classification-table.test.ts +256 -0
  806. package/packages/core/tests/traps/err-arm.test.ts +144 -0
  807. package/packages/core/tests/traps/fetch-spy.ts +39 -0
  808. package/packages/core/tests/traps/invalidation-after-write.test.ts +178 -0
  809. package/packages/core/tests/traps/ledger.ts +248 -0
  810. package/packages/core/tests/traps/root-key-off-local.test.ts +130 -0
  811. package/packages/core/tests/traps/stale-data-across-users.test.ts +173 -0
  812. package/packages/core/tests/traps/unresolved-name.test.ts +155 -0
  813. package/packages/core/tests/traps/update-as-query.test.ts +244 -0
  814. package/packages/core/tests/traps/update-not-resent.test.ts +126 -0
  815. package/packages/core/tests/traps/update-resent-when-never-delivered.test.ts +159 -0
  816. package/packages/core/tests/traps.test-d.ts +476 -0
  817. package/packages/core/tests/units.test-d.ts +118 -0
  818. package/packages/core/tests/units.test.ts +634 -0
  819. package/packages/core/tsconfig.json +19 -0
  820. package/packages/core/tsconfig.typecheck.json +16 -0
  821. package/packages/core/vitest.config.ts +13 -0
  822. package/packages/mcp/LICENSE +21 -0
  823. package/packages/mcp/README.md +189 -0
  824. package/packages/mcp/package.json +62 -0
  825. package/packages/mcp/src/candid/candid-text.test.ts +455 -0
  826. package/packages/mcp/src/candid/candid-text.ts +501 -0
  827. package/packages/mcp/src/candid/contract.test.ts +398 -0
  828. package/packages/mcp/src/candid/formats.ts +155 -0
  829. package/packages/mcp/src/candid/hex.ts +29 -0
  830. package/packages/mcp/src/candid/json-schema.test.ts +758 -0
  831. package/packages/mcp/src/candid/json-schema.ts +454 -0
  832. package/packages/mcp/src/candid/json.test.ts +1207 -0
  833. package/packages/mcp/src/candid/json.ts +1053 -0
  834. package/packages/mcp/src/candid/schema-walk.ts +189 -0
  835. package/packages/mcp/src/candid/type-text.test.ts +179 -0
  836. package/packages/mcp/src/candid/type-text.ts +238 -0
  837. package/packages/mcp/src/cli.ts +134 -0
  838. package/packages/mcp/src/identity.ts +188 -0
  839. package/packages/mcp/src/interface/cache.test.ts +48 -0
  840. package/packages/mcp/src/interface/cache.ts +68 -0
  841. package/packages/mcp/src/interface/cli-cache.test.ts +150 -0
  842. package/packages/mcp/src/interface/cli-cache.ts +122 -0
  843. package/packages/mcp/src/interface/compile-worker.test.ts +246 -0
  844. package/packages/mcp/src/interface/compile-worker.ts +290 -0
  845. package/packages/mcp/src/interface/compile.test.ts +155 -0
  846. package/packages/mcp/src/interface/compile.ts +281 -0
  847. package/packages/mcp/src/interface/docs.test.ts +105 -0
  848. package/packages/mcp/src/interface/docs.ts +86 -0
  849. package/packages/mcp/src/interface/fixtures/icrc1.did +88 -0
  850. package/packages/mcp/src/interface/hex.ts +8 -0
  851. package/packages/mcp/src/interface/ids.test.ts +71 -0
  852. package/packages/mcp/src/interface/ids.ts +87 -0
  853. package/packages/mcp/src/interface/loader.test.ts +804 -0
  854. package/packages/mcp/src/interface/loader.ts +519 -0
  855. package/packages/mcp/src/interface/read-candid.test.ts +300 -0
  856. package/packages/mcp/src/interface/read-candid.ts +259 -0
  857. package/packages/mcp/src/interface/types.ts +113 -0
  858. package/packages/mcp/src/network.ts +122 -0
  859. package/packages/mcp/src/options.ts +149 -0
  860. package/packages/mcp/src/server/approval.ts +159 -0
  861. package/packages/mcp/src/server/naming.ts +43 -0
  862. package/packages/mcp/src/server/results.ts +102 -0
  863. package/packages/mcp/src/server/server.ts +797 -0
  864. package/packages/mcp/src/server/tools.ts +116 -0
  865. package/packages/mcp/src/usage.ts +40 -0
  866. package/packages/mcp/tests/approval.test.ts +60 -0
  867. package/packages/mcp/tests/identity.test.ts +234 -0
  868. package/packages/mcp/tests/naming.test.ts +62 -0
  869. package/packages/mcp/tests/options.test.ts +140 -0
  870. package/packages/mcp/tests/server.test.ts +997 -0
  871. package/packages/mcp/tsconfig.json +19 -0
  872. package/packages/mcp/tsconfig.typecheck.json +10 -0
  873. package/packages/mcp/vitest.config.ts +10 -0
  874. package/packages/react/LICENSE +21 -0
  875. package/packages/react/README.md +328 -0
  876. package/packages/react/llms.txt +95 -0
  877. package/packages/react/package.json +95 -0
  878. package/packages/react/src/index.tsx +678 -0
  879. package/packages/react/tests/abandoned-render.test.tsx +816 -0
  880. package/packages/react/tests/auth.test.tsx +315 -0
  881. package/packages/react/tests/caller-keys.test.tsx +2334 -0
  882. package/packages/react/tests/client-time.test.ts +40 -0
  883. package/packages/react/tests/entry.test.ts +52 -0
  884. package/packages/react/tests/helpers.tsx +291 -0
  885. package/packages/react/tests/hydration.test.tsx +262 -0
  886. package/packages/react/tests/ownership.test.tsx +260 -0
  887. package/packages/react/tests/provider.server.test.tsx +169 -0
  888. package/packages/react/tests/query-client.test.tsx +107 -0
  889. package/packages/react/tests/strict-mode.test.tsx +288 -0
  890. package/packages/react/tests/suspense.test-d.tsx +357 -0
  891. package/packages/react/tests/two-query-cores.test.tsx +135 -0
  892. package/packages/react/tests/types.test-d.tsx +63 -0
  893. package/packages/react/tsconfig.json +23 -0
  894. package/packages/react/tsconfig.test.json +8 -0
  895. package/packages/react/tsconfig.typecheck.json +16 -0
  896. package/packages/react/vitest.config.ts +39 -0
  897. package/packages/vite-plugin/LICENSE +21 -0
  898. package/packages/vite-plugin/README.md +532 -0
  899. package/packages/vite-plugin/package.json +76 -0
  900. package/packages/vite-plugin/src/describe-value.test.ts +43 -0
  901. package/packages/vite-plugin/src/describe-value.ts +167 -0
  902. package/packages/vite-plugin/src/dev-environment.test.ts +747 -0
  903. package/packages/vite-plugin/src/dev-environment.ts +510 -0
  904. package/packages/vite-plugin/src/env.ts +431 -0
  905. package/packages/vite-plugin/src/fetch.ts +348 -0
  906. package/packages/vite-plugin/src/file-identity.ts +106 -0
  907. package/packages/vite-plugin/src/generate.ts +691 -0
  908. package/packages/vite-plugin/src/index.test.ts +1243 -0
  909. package/packages/vite-plugin/src/index.ts +2565 -0
  910. package/packages/vite-plugin/src/interface.ts +339 -0
  911. package/packages/vite-plugin/src/local-host.ts +34 -0
  912. package/packages/vite-plugin/src/options.ts +641 -0
  913. package/packages/vite-plugin/src/principal-text.test.ts +87 -0
  914. package/packages/vite-plugin/src/principal-text.ts +98 -0
  915. package/packages/vite-plugin/tests/close.test.ts +141 -0
  916. package/packages/vite-plugin/tests/environment-mode.test.ts +136 -0
  917. package/packages/vite-plugin/tests/fake-ic.ts +214 -0
  918. package/packages/vite-plugin/tests/fetch-sdk.test.ts +27 -0
  919. package/packages/vite-plugin/tests/fetch.test.ts +1196 -0
  920. package/packages/vite-plugin/tests/fixtures/fake-cli/bin.js +90 -0
  921. package/packages/vite-plugin/tests/fixtures/fake-cli/package.json +8 -0
  922. package/packages/vite-plugin/tests/fixtures/icrc1.did +88 -0
  923. package/packages/vite-plugin/tests/generation.test.ts +1036 -0
  924. package/packages/vite-plugin/tests/icp-command.test.ts +194 -0
  925. package/packages/vite-plugin/tests/icp-timeout.test.ts +83 -0
  926. package/packages/vite-plugin/tests/no-process-exit.test.ts +83 -0
  927. package/packages/vite-plugin/tests/on-generated.test.ts +323 -0
  928. package/packages/vite-plugin/tests/output-collision.test.ts +329 -0
  929. package/packages/vite-plugin/tests/package.test.ts +62 -0
  930. package/packages/vite-plugin/tests/project.test.ts +2993 -0
  931. package/packages/vite-plugin/tests/support.ts +339 -0
  932. package/packages/vite-plugin/tests/timeout.test.ts +107 -0
  933. package/packages/vite-plugin/tsconfig.json +23 -0
  934. package/packages/vite-plugin/tsconfig.typecheck.json +16 -0
  935. package/packages/vite-plugin/vitest.config.ts +9 -0
  936. package/pnpm-workspace.yaml +23 -0
  937. package/scripts/ai-context-files.js +72 -0
  938. package/scripts/assemble-docs-site.mjs +485 -0
  939. package/scripts/assemble-docs-site.test.mjs +568 -0
  940. package/scripts/build-examples.js +58 -0
  941. package/scripts/check-ai-context.js +963 -0
  942. package/scripts/check-ai-context.test.mjs +811 -0
  943. package/scripts/check-exports.mjs +767 -0
  944. package/scripts/check-exports.test.mjs +1136 -0
  945. package/scripts/check-snippets/ambient.d.ts +428 -0
  946. package/scripts/check-snippets/app/generated/backend.did +7 -0
  947. package/scripts/check-snippets/app/generated/backend.ts +15 -0
  948. package/scripts/check-snippets/app/generated/icrc1.did +88 -0
  949. package/scripts/check-snippets/app/generated/icrc1.ts +78 -0
  950. package/scripts/check-snippets/app/globals.ts +26 -0
  951. package/scripts/check-snippets/docs/guides/App.tsx +21 -0
  952. package/scripts/check-snippets/docs/guides/app/providers.tsx +23 -0
  953. package/scripts/check-snippets/docs/guides/auth-client.ts +47 -0
  954. package/scripts/check-snippets/docs/guides/canisters/backend.ts +3 -0
  955. package/scripts/check-snippets/docs/guides/canisters/icrc1.ts +3 -0
  956. package/scripts/check-snippets/docs/guides/components/LedgerCard.tsx +26 -0
  957. package/scripts/check-snippets/docs/guides/components/shell.tsx +11 -0
  958. package/scripts/check-snippets/docs/guides/components/sign-in-page.tsx +29 -0
  959. package/scripts/check-snippets/docs/guides/components/slow-section.tsx +5 -0
  960. package/scripts/check-snippets/docs/guides/generated/accounts.ts +95 -0
  961. package/scripts/check-snippets/docs/guides/generated/ckbtc_minter.ts +40 -0
  962. package/scripts/check-snippets/docs/guides/generated/icp_ledger.ts +267 -0
  963. package/scripts/check-snippets/docs/guides/ledger.ts +10 -0
  964. package/scripts/check-snippets/docs/guides/server/request-client.ts +8 -0
  965. package/scripts/check-snippets.mjs +993 -0
  966. package/scripts/check-snippets.test.mjs +338 -0
  967. package/scripts/check-stack.mjs +501 -0
  968. package/scripts/check-stack.test.mjs +800 -0
  969. package/scripts/clean-node-modules.js +67 -0
  970. package/scripts/example-projects.js +58 -0
  971. package/scripts/export-budget.mjs +145 -0
  972. package/scripts/faults.json +6749 -0
  973. package/scripts/lib/fault-workspace.mjs +210 -0
  974. package/scripts/lib/io.mjs +29 -0
  975. package/scripts/lib/io.test.mjs +38 -0
  976. package/scripts/lib/markdown-fences.mjs +56 -0
  977. package/scripts/lib/markdown-fences.test.mjs +84 -0
  978. package/scripts/lib/package-exports.mjs +54 -0
  979. package/scripts/lib/package-exports.test.mjs +66 -0
  980. package/scripts/lib/release-pr-steps.mjs +47 -0
  981. package/scripts/release-tag.mjs +95 -0
  982. package/scripts/release-tag.test.mjs +278 -0
  983. package/scripts/release-workflow.test.mjs +98 -0
  984. package/scripts/release.js +167 -0
  985. package/scripts/release.test.mjs +347 -0
  986. package/scripts/removed-v3-names.js +125 -0
  987. package/scripts/size-app/.size-limit.js +90 -0
  988. package/scripts/size-app/core.js +3 -0
  989. package/scripts/size-app/package.json +24 -0
  990. package/scripts/size-app/react.js +4 -0
  991. package/scripts/size-app.test.mjs +73 -0
  992. package/scripts/sync-ai-context-versions.js +102 -0
  993. package/scripts/sync-example-versions.js +151 -0
  994. package/scripts/test-examples-published.mjs +1585 -0
  995. package/scripts/test-examples-published.test.mjs +1586 -0
  996. package/scripts/traps/any-method-vars-not-a-list.json +5 -0
  997. package/scripts/traps/canister-method-unknown.json +5 -0
  998. package/scripts/traps/client-says-who-calls-once.json +5 -0
  999. package/scripts/traps/client-says-who-calls.json +5 -0
  1000. package/scripts/traps/err-only-on-canister-err.json +14 -0
  1001. package/scripts/traps/format-units-refuses-missing-value.json +5 -0
  1002. package/scripts/traps/format-units-refuses-number.json +5 -0
  1003. package/scripts/traps/format-units-unknown-option.json +5 -0
  1004. package/scripts/traps/guard-err-is-the-methods.json +5 -0
  1005. package/scripts/traps/guard-false-keeps-every-kind.json +5 -0
  1006. package/scripts/traps/internals-not-exported.json +9 -0
  1007. package/scripts/traps/network-refuses-unknown-name.json +5 -0
  1008. package/scripts/traps/never-err-has-no-type.json +5 -0
  1009. package/scripts/traps/options-method-unknown.json +5 -0
  1010. package/scripts/traps/options-vars-wrong-type.json +5 -0
  1011. package/scripts/traps/parse-units-refuses-number.json +5 -0
  1012. package/scripts/traps/parse-units-unknown-option.json +5 -0
  1013. package/scripts/traps/principal-is-not-plain-text.json +14 -0
  1014. package/scripts/traps/query-options-refuses-oneway.json +5 -0
  1015. package/scripts/traps/query-options-refuses-update.json +5 -0
  1016. package/scripts/traps/refuse-next-unknown-option.json +5 -0
  1017. package/scripts/traps/resend-key-reads-the-methods-arg.json +5 -0
  1018. package/scripts/traps/resend-states-its-dedupe-key.json +5 -0
  1019. package/scripts/traps/suspense-refuses-argument-skip.json +5 -0
  1020. package/scripts/traps/suspense-refuses-skippable-read.json +5 -0
  1021. package/scripts/traps/suspense-refuses-vars-skip-fits.json +5 -0
  1022. package/scripts/traps/test-handler-method-unknown.json +5 -0
  1023. package/scripts/traps/test-handler-nat-is-bigint.json +5 -0
  1024. package/scripts/traps/test-handler-takes-the-domain-value.json +5 -0
  1025. package/scripts/traps/vars-of-two-arguments-are-the-tuple.json +5 -0
  1026. package/scripts/typecheck-examples.js +122 -0
  1027. package/scripts/verify-faults.mjs +375 -0
  1028. package/scripts/verify-faults.test.mjs +402 -0
  1029. package/scripts/verify-package-artifacts.mjs +590 -0
  1030. package/scripts/verify-peer-floors.js +399 -0
  1031. package/scripts/verify-peer-floors.test.mjs +422 -0
  1032. package/scripts/verify-test-fails-rules.mjs +104 -0
  1033. package/scripts/verify-test-fails-rules.test.mjs +215 -0
  1034. package/scripts/verify-test-fails.js +371 -0
  1035. package/scripts/verify-traps.mjs +505 -0
  1036. package/scripts/verify-traps.test.mjs +521 -0
  1037. package/scripts/verify-typescript-floor.js +239 -0
  1038. package/skill-packages/ic-reactor/SKILL.md +103 -0
  1039. package/stack.json +8 -0
  1040. package/tsconfig.base.json +23 -0
  1041. 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
+ }