@pyric/cli 0.1.0-alpha.11 → 0.1.0-alpha.13

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 (424) hide show
  1. package/dist/cli/serve.js +4 -4
  2. package/dist/cli/serve.js.map +1 -1
  3. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  4. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  5. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  6. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  7. package/dist/conformance/.generated/can-i-use.js +2 -2
  8. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  9. package/dist/serve/bundler.d.ts +13 -8
  10. package/dist/serve/bundler.d.ts.map +1 -1
  11. package/dist/serve/bundler.js +31 -36
  12. package/dist/serve/bundler.js.map +1 -1
  13. package/dist/serve/docs-ui/docs/_rhythm/index.html +1 -1
  14. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +1 -1
  15. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +1 -1
  16. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +1 -1
  17. package/dist/serve/docs-ui/docs/ai-compat/index.html +1 -1
  18. package/dist/serve/docs-ui/docs/api-reference/index.html +2 -2
  19. package/dist/serve/docs-ui/docs/api-reference.md +1 -1
  20. package/dist/serve/docs-ui/docs/app-compat/index.html +1 -1
  21. package/dist/serve/docs-ui/docs/auth-compat/index.html +1 -1
  22. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +44 -22
  23. package/dist/serve/docs-ui/docs/build/ai-logic.md +69 -21
  24. package/dist/serve/docs-ui/docs/build/authentication/index.html +1 -1
  25. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +1 -1
  26. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +1 -1
  27. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +1 -1
  28. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +1 -1
  29. package/dist/serve/docs-ui/docs/conformance-scores/index.html +1 -1
  30. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +1 -1
  31. package/dist/serve/docs-ui/docs/database-compat/index.html +1 -1
  32. package/dist/serve/docs-ui/docs/firestore-compat/index.html +1 -1
  33. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +1 -1
  34. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
  35. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works.md +2 -0
  36. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +3 -2
  37. package/dist/serve/docs-ui/docs/get-started/start-building.md +3 -1
  38. package/dist/serve/docs-ui/docs/index.json +349 -29
  39. package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
  40. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +28 -0
  41. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status.md +47 -0
  42. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +1 -1
  43. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +1 -1
  44. package/dist/serve/docs-ui/docs/overview/index.html +1 -1
  45. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  46. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  47. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  48. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  49. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
  50. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
  51. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  52. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +1 -1
  53. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  54. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +1 -1
  55. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +1 -1
  56. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  57. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  58. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  59. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  60. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  61. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  62. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  63. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  64. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  65. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  66. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  67. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +168 -76
  68. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +156 -73
  69. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  70. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +11 -8
  71. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +17 -4
  72. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1 -1
  73. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1 -1
  74. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  75. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  76. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +1 -1
  77. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
  78. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  79. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +37 -14
  80. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +28 -8
  81. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +1 -1
  82. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  83. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  84. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  85. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  86. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  87. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  88. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  89. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  90. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  91. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  92. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  93. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  94. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
  95. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  96. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  97. package/dist/serve/docs-ui/docs/rules-compat/index.html +1 -1
  98. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +1 -1
  99. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  100. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +1 -1
  101. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  102. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +1 -1
  103. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  104. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +1 -1
  105. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  106. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +1 -1
  107. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +1 -1
  108. package/dist/serve/docs-ui/docs/storage-compat/index.html +1 -1
  109. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  110. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  111. package/dist/serve/docs-ui/docs/tutorial/index.html +429 -0
  112. package/dist/serve/docs-ui/docs/tutorial.md +701 -0
  113. package/dist/serve/docs-ui/llms.txt +3 -1
  114. package/dist/serve/entries/init.d.ts.map +1 -1
  115. package/dist/serve/entries/init.js +3 -0
  116. package/dist/serve/entries/init.js.map +1 -1
  117. package/dist/serve/entries/runtime.d.ts.map +1 -1
  118. package/dist/serve/entries/runtime.js +20 -5
  119. package/dist/serve/entries/runtime.js.map +1 -1
  120. package/dist/serve/entries/worker-runtime.d.ts +2 -2
  121. package/dist/serve/entries/worker-runtime.d.ts.map +1 -1
  122. package/dist/serve/entries/worker-runtime.js +45 -10
  123. package/dist/serve/entries/worker-runtime.js.map +1 -1
  124. package/dist/serve/runtime/chip-config.d.ts +19 -0
  125. package/dist/serve/runtime/chip-config.d.ts.map +1 -0
  126. package/dist/serve/runtime/chip-config.js +19 -0
  127. package/dist/serve/runtime/chip-config.js.map +1 -0
  128. package/dist/serve/runtime/chip-install.d.ts +10 -0
  129. package/dist/serve/runtime/chip-install.d.ts.map +1 -0
  130. package/dist/serve/runtime/chip-install.js +15 -0
  131. package/dist/serve/runtime/chip-install.js.map +1 -0
  132. package/dist/serve/runtime/chip.d.ts +17 -0
  133. package/dist/serve/runtime/chip.d.ts.map +1 -0
  134. package/dist/serve/runtime/chip.js +257 -0
  135. package/dist/serve/runtime/chip.js.map +1 -0
  136. package/dist/serve/runtime/manifest.d.ts +22 -0
  137. package/dist/serve/runtime/manifest.d.ts.map +1 -0
  138. package/dist/serve/runtime/manifest.js +20 -0
  139. package/dist/serve/runtime/manifest.js.map +1 -0
  140. package/dist/serve/runtime/status.d.ts +49 -0
  141. package/dist/serve/runtime/status.d.ts.map +1 -0
  142. package/dist/serve/runtime/status.js +164 -0
  143. package/dist/serve/runtime/status.js.map +1 -0
  144. package/dist/serve/runtime/worker-connection.d.ts +4 -0
  145. package/dist/serve/runtime/worker-connection.d.ts.map +1 -0
  146. package/dist/serve/runtime/worker-connection.js +11 -0
  147. package/dist/serve/runtime/worker-connection.js.map +1 -0
  148. package/dist/serve/runtime/worker-generation.d.ts +14 -0
  149. package/dist/serve/runtime/worker-generation.d.ts.map +1 -0
  150. package/dist/serve/runtime/worker-generation.js +56 -0
  151. package/dist/serve/runtime/worker-generation.js.map +1 -0
  152. package/dist/serve/runtime/worker-replacement.d.ts +18 -0
  153. package/dist/serve/runtime/worker-replacement.d.ts.map +1 -0
  154. package/dist/serve/runtime/worker-replacement.js +29 -0
  155. package/dist/serve/runtime/worker-replacement.js.map +1 -0
  156. package/dist/serve/standalone-assets.d.ts +2 -2
  157. package/dist/serve/standalone-assets.d.ts.map +1 -1
  158. package/dist/serve/standalone-assets.js +1 -1
  159. package/dist/serve/standalone-assets.js.map +1 -1
  160. package/dist/serve/studio-ui/assets/{RulesCodeEditor-CxVYcZXw.js → RulesCodeEditor-BDlH-5lp.js} +1 -1
  161. package/dist/serve/studio-ui/assets/{index-cpSfgQ7H.js → index-Bf9SSE8L.js} +5 -5
  162. package/dist/serve/studio-ui/assets/{seed-DeuFKi4J.js → seed-D_UjxfOU.js} +1 -1
  163. package/dist/serve/studio-ui/index.html +1 -1
  164. package/dist/serve/vite-ai-config.d.ts +25 -0
  165. package/dist/serve/vite-ai-config.d.ts.map +1 -0
  166. package/dist/serve/vite-ai-config.js +45 -0
  167. package/dist/serve/vite-ai-config.js.map +1 -0
  168. package/dist/serve/vite-plugin.d.ts +17 -36
  169. package/dist/serve/vite-plugin.d.ts.map +1 -1
  170. package/dist/serve/vite-plugin.js +38 -57
  171. package/dist/serve/vite-plugin.js.map +1 -1
  172. package/dist/serve/vite-rules-source.d.ts +8 -0
  173. package/dist/serve/vite-rules-source.d.ts.map +1 -0
  174. package/dist/serve/vite-rules-source.js +23 -0
  175. package/dist/serve/vite-rules-source.js.map +1 -0
  176. package/dist/serve/vite-worker-runtime.d.ts +20 -0
  177. package/dist/serve/vite-worker-runtime.d.ts.map +1 -0
  178. package/dist/serve/vite-worker-runtime.js +25 -0
  179. package/dist/serve/vite-worker-runtime.js.map +1 -0
  180. package/dist/serve/worker/client/connection.d.ts +7 -2
  181. package/dist/serve/worker/client/connection.d.ts.map +1 -1
  182. package/dist/serve/worker/client/connection.js +13 -16
  183. package/dist/serve/worker/client/connection.js.map +1 -1
  184. package/dist/serve/worker/client/core.d.ts +7 -0
  185. package/dist/serve/worker/client/core.d.ts.map +1 -1
  186. package/dist/serve/worker/client/core.js +28 -0
  187. package/dist/serve/worker/client/core.js.map +1 -1
  188. package/dist/serve/worker/client/runtime-control.d.ts +8 -0
  189. package/dist/serve/worker/client/runtime-control.d.ts.map +1 -0
  190. package/dist/serve/worker/client/runtime-control.js +11 -0
  191. package/dist/serve/worker/client/runtime-control.js.map +1 -0
  192. package/dist/serve/worker/entry.js +44 -2
  193. package/dist/serve/worker/entry.js.map +1 -1
  194. package/dist/serve/worker/host/core.js +1 -1
  195. package/dist/serve/worker/host/core.js.map +1 -1
  196. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
  197. package/dist/serve/worker/host/firestore-writes.js +3 -2
  198. package/dist/serve/worker/host/firestore-writes.js.map +1 -1
  199. package/dist/serve/worker/host/studio.js +1 -1
  200. package/dist/serve/worker/host/studio.js.map +1 -1
  201. package/dist/serve/worker/host-context.d.ts +1 -1
  202. package/dist/serve/worker/host-context.d.ts.map +1 -1
  203. package/dist/serve/worker/index.d.ts +2 -1
  204. package/dist/serve/worker/index.d.ts.map +1 -1
  205. package/dist/serve/worker/index.js +2 -1
  206. package/dist/serve/worker/index.js.map +1 -1
  207. package/dist/serve/worker/protocol.d.ts +15 -1
  208. package/dist/serve/worker/protocol.d.ts.map +1 -1
  209. package/dist/serve/worker/protocol.js +2 -2
  210. package/dist/serve/worker/protocol.js.map +1 -1
  211. package/dist/serve/worker/retirement.d.ts +21 -0
  212. package/dist/serve/worker/retirement.d.ts.map +1 -0
  213. package/dist/serve/worker/retirement.js +97 -0
  214. package/dist/serve/worker/retirement.js.map +1 -0
  215. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  216. package/dist/serve/worker/serve-init.js +5 -6
  217. package/dist/serve/worker/serve-init.js.map +1 -1
  218. package/dist/vite.d.ts +1 -0
  219. package/dist/vite.d.ts.map +1 -1
  220. package/dist/vite.js.map +1 -1
  221. package/package.json +6 -4
  222. package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
  223. package/src/assurance/attachment.ts +211 -0
  224. package/src/assurance/browser.ts +80 -0
  225. package/src/assurance/campaign.ts +496 -0
  226. package/src/assurance/capabilities.ts +446 -0
  227. package/src/assurance/cases.ts +43 -0
  228. package/src/assurance/index.ts +75 -0
  229. package/src/assurance/runner.ts +885 -0
  230. package/src/assurance/tool-names.ts +15 -0
  231. package/src/assurance/tools.ts +830 -0
  232. package/src/assurance/types.ts +352 -0
  233. package/src/assurance/validation.ts +434 -0
  234. package/src/bridge/client/bridge.ts +550 -0
  235. package/src/bridge/client/dispatch.ts +137 -0
  236. package/src/bridge/client.ts +45 -0
  237. package/src/bridge/protocol.ts +351 -0
  238. package/src/bridge/server/audit.ts +53 -0
  239. package/src/bridge/server/bridge.ts +597 -0
  240. package/src/bridge/server/headless.ts +160 -0
  241. package/src/bridge/server/json-schema-to-zod.ts +108 -0
  242. package/src/bridge/server/local-bridge.ts +66 -0
  243. package/src/bridge/server/logger.ts +50 -0
  244. package/src/bridge/server/mcp-contract.ts +93 -0
  245. package/src/bridge/server/mcp.ts +129 -0
  246. package/src/bridge/server/peer.ts +232 -0
  247. package/src/bridge/server/standalone.ts +347 -0
  248. package/src/bridge/server/tool-metadata.ts +99 -0
  249. package/src/bridge/server.ts +28 -0
  250. package/src/cli/can-i-use.ts +50 -0
  251. package/src/cli/cli.test.ts +493 -0
  252. package/src/cli/database-rules.ts +329 -0
  253. package/src/cli/dev-runner.ts +282 -0
  254. package/src/cli/firebase-json.ts +100 -0
  255. package/src/cli/firestore-indexes.ts +70 -0
  256. package/src/cli/index.ts +425 -0
  257. package/src/cli/init.ts +260 -0
  258. package/src/cli/mcp-proxy.ts +196 -0
  259. package/src/cli/parse-args.ts +80 -0
  260. package/src/cli/rules.ts +259 -0
  261. package/src/cli/scope.ts +67 -0
  262. package/src/cli/serve.ts +996 -0
  263. package/src/cli/service-commands.ts +73 -0
  264. package/src/cli/snapshot.ts +164 -0
  265. package/src/cli/storage-rules.ts +172 -0
  266. package/src/cli/verify.ts +416 -0
  267. package/src/conformance/.generated/can-i-use-browser.ts +113 -0
  268. package/src/conformance/.generated/can-i-use.ts +117 -0
  269. package/src/conformance/.generated/conformance-docs.ts +14 -0
  270. package/src/conformance/browser.ts +24 -0
  271. package/src/conformance/can-i-use-tool.ts +51 -0
  272. package/src/conformance/can-i-use.ts +18 -0
  273. package/src/conformance/docs.ts +8 -0
  274. package/src/conformance/index.ts +20 -0
  275. package/src/conformance/tools.ts +16 -0
  276. package/src/credentials/core/memoize-ttl.ts +142 -0
  277. package/src/credentials/core/types.ts +10 -0
  278. package/src/credentials/node/from-adc.ts +96 -0
  279. package/src/credentials/node/from-service-account.ts +133 -0
  280. package/src/credentials/node/index.ts +6 -0
  281. package/src/discover/concurrency.ts +127 -0
  282. package/src/discover/crawler-adapter.ts +142 -0
  283. package/src/discover/crawler.ts +1127 -0
  284. package/src/discover/credential-free.ts +27 -0
  285. package/src/discover/findCollectionGroup.ts +131 -0
  286. package/src/discover/firestore-source.ts +59 -0
  287. package/src/discover/index.ts +5 -0
  288. package/src/discover/merge.ts +523 -0
  289. package/src/discover/session.ts +402 -0
  290. package/src/discover/tools.ts +201 -0
  291. package/src/discover/types.ts +187 -0
  292. package/src/discover/wire.ts +324 -0
  293. package/src/functions-rtdb/child.ts +382 -0
  294. package/src/functions-rtdb/delivery.ts +7 -0
  295. package/src/functions-rtdb/discovery.ts +136 -0
  296. package/src/functions-rtdb/event.ts +64 -0
  297. package/src/functions-rtdb/execution.ts +111 -0
  298. package/src/functions-rtdb/in-memory-delivery.ts +40 -0
  299. package/src/functions-rtdb/project.ts +74 -0
  300. package/src/functions-rtdb/projection.ts +104 -0
  301. package/src/functions-rtdb/reference-pattern.ts +20 -0
  302. package/src/functions-rtdb/remote-delivery.ts +23 -0
  303. package/src/pkg-version.ts +49 -0
  304. package/src/register/esm-exports.ts +63 -0
  305. package/src/register/hooks.ts +30 -0
  306. package/src/register/index.ts +150 -0
  307. package/src/register/mapping.ts +33 -0
  308. package/src/remote/index.ts +1050 -0
  309. package/src/rtdb/crawl-snapshot.ts +118 -0
  310. package/src/rtdb/inspection.ts +137 -0
  311. package/src/rtdb/load-rules-document.ts +56 -0
  312. package/src/rtdb/rules-generation-tool.ts +38 -0
  313. package/src/rtdb/rules-json.ts +29 -0
  314. package/src/serve/activity-guard.ts +29 -0
  315. package/src/serve/activity-route.ts +164 -0
  316. package/src/serve/activity-warning.ts +26 -0
  317. package/src/serve/bridge-mount.ts +200 -0
  318. package/src/serve/bundler.ts +519 -0
  319. package/src/serve/capture-store.ts +65 -0
  320. package/src/serve/discovery.ts +199 -0
  321. package/src/serve/entries/ai.ts +292 -0
  322. package/src/serve/entries/app-backend.ts +4 -0
  323. package/src/serve/entries/app-client.ts +26 -0
  324. package/src/serve/entries/app-session-store.ts +47 -0
  325. package/src/serve/entries/app.ts +11 -0
  326. package/src/serve/entries/auth-helper-core.ts +181 -0
  327. package/src/serve/entries/auth-helper-dom.ts +134 -0
  328. package/src/serve/entries/auth-helper-runtime.ts +20 -0
  329. package/src/serve/entries/auth.ts +255 -0
  330. package/src/serve/entries/bridge-url.ts +31 -0
  331. package/src/serve/entries/database.ts +129 -0
  332. package/src/serve/entries/firestore.ts +232 -0
  333. package/src/serve/entries/init.ts +49 -0
  334. package/src/serve/entries/keepalive.ts +46 -0
  335. package/src/serve/entries/messaging-sw.ts +75 -0
  336. package/src/serve/entries/messaging.ts +96 -0
  337. package/src/serve/entries/runtime.ts +556 -0
  338. package/src/serve/entries/session-store.ts +97 -0
  339. package/src/serve/entries/storage.ts +92 -0
  340. package/src/serve/entries/tab-sync-wiring.ts +274 -0
  341. package/src/serve/entries/worker-runtime.ts +135 -0
  342. package/src/serve/init-payload.ts +42 -0
  343. package/src/serve/namespace.ts +675 -0
  344. package/src/serve/open-browser.ts +68 -0
  345. package/src/serve/rules.ts +272 -0
  346. package/src/serve/runtime/chip-config.ts +30 -0
  347. package/src/serve/runtime/chip-install.ts +27 -0
  348. package/src/serve/runtime/chip.ts +282 -0
  349. package/src/serve/runtime/manifest.ts +37 -0
  350. package/src/serve/runtime/status.ts +216 -0
  351. package/src/serve/runtime/worker-connection.ts +14 -0
  352. package/src/serve/runtime/worker-generation.ts +75 -0
  353. package/src/serve/runtime/worker-replacement.ts +42 -0
  354. package/src/serve/sandbox-marker.ts +31 -0
  355. package/src/serve/server.ts +428 -0
  356. package/src/serve/standalone-assets.ts +180 -0
  357. package/src/serve/state-store.ts +166 -0
  358. package/src/serve/studio/disk-project-store.ts +185 -0
  359. package/src/serve/studio/disk-workspace.ts +162 -0
  360. package/src/serve/studio/index.ts +20 -0
  361. package/src/serve/studio/routes.ts +237 -0
  362. package/src/serve/studio/store-types.ts +48 -0
  363. package/src/serve/studio/studio-storage.test.ts +289 -0
  364. package/src/serve/vite-ai-config.ts +77 -0
  365. package/src/serve/vite-plugin.ts +1075 -0
  366. package/src/serve/vite-rules-source.ts +28 -0
  367. package/src/serve/vite-worker-runtime.ts +51 -0
  368. package/src/serve/worker/activity-bootstrap.ts +24 -0
  369. package/src/serve/worker/client/admin-firestore.ts +38 -0
  370. package/src/serve/worker/client/ai.ts +124 -0
  371. package/src/serve/worker/client/auth.ts +489 -0
  372. package/src/serve/worker/client/connection.ts +227 -0
  373. package/src/serve/worker/client/core.ts +384 -0
  374. package/src/serve/worker/client/disconnect.ts +45 -0
  375. package/src/serve/worker/client/firestore-reads.ts +181 -0
  376. package/src/serve/worker/client/firestore-refs.ts +226 -0
  377. package/src/serve/worker/client/firestore-writes.ts +232 -0
  378. package/src/serve/worker/client/handles.ts +91 -0
  379. package/src/serve/worker/client/messaging.ts +119 -0
  380. package/src/serve/worker/client/presence.ts +174 -0
  381. package/src/serve/worker/client/rtdb.ts +311 -0
  382. package/src/serve/worker/client/rules.ts +63 -0
  383. package/src/serve/worker/client/runtime-control.ts +22 -0
  384. package/src/serve/worker/client/service-worker-connection.ts +59 -0
  385. package/src/serve/worker/client/snapshots.ts +86 -0
  386. package/src/serve/worker/client/storage.ts +195 -0
  387. package/src/serve/worker/client/studio.ts +88 -0
  388. package/src/serve/worker/client.ts +57 -0
  389. package/src/serve/worker/durable-persistence.ts +137 -0
  390. package/src/serve/worker/entry.ts +223 -0
  391. package/src/serve/worker/host/admin-firestore.ts +88 -0
  392. package/src/serve/worker/host/connection.ts +179 -0
  393. package/src/serve/worker/host/core.ts +387 -0
  394. package/src/serve/worker/host/dispatch.ts +316 -0
  395. package/src/serve/worker/host/firestore-reads.ts +117 -0
  396. package/src/serve/worker/host/firestore-writes.ts +456 -0
  397. package/src/serve/worker/host/presence.ts +312 -0
  398. package/src/serve/worker/host/rtdb.ts +136 -0
  399. package/src/serve/worker/host/rules.ts +128 -0
  400. package/src/serve/worker/host/storage.ts +312 -0
  401. package/src/serve/worker/host/studio.ts +75 -0
  402. package/src/serve/worker/host/subscriptions.ts +238 -0
  403. package/src/serve/worker/host-ai.ts +165 -0
  404. package/src/serve/worker/host-auth.ts +469 -0
  405. package/src/serve/worker/host-context.ts +273 -0
  406. package/src/serve/worker/host-events.ts +94 -0
  407. package/src/serve/worker/host-messaging.ts +240 -0
  408. package/src/serve/worker/host.ts +47 -0
  409. package/src/serve/worker/index.ts +196 -0
  410. package/src/serve/worker/presence-timing.ts +15 -0
  411. package/src/serve/worker/protocol.ts +1124 -0
  412. package/src/serve/worker/retirement.ts +125 -0
  413. package/src/serve/worker/serve-init.ts +605 -0
  414. package/src/serve/worker/service-worker-channel.ts +33 -0
  415. package/src/serve/worker/service-worker-relay.ts +86 -0
  416. package/src/serve/writer-lock.ts +53 -0
  417. package/src/verify/cases.ts +233 -0
  418. package/src/verify/fixture.ts +258 -0
  419. package/src/verify/index.ts +519 -0
  420. package/src/verify/tools.ts +108 -0
  421. package/src/version/compat-target.ts +17 -0
  422. package/src/vite.ts +18 -0
  423. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
  424. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
@@ -0,0 +1,830 @@
1
+ import type { ToolHandler } from "@inbrowser/agent";
2
+ import {
3
+ AuthorizationCampaign,
4
+ createAuthorizationCampaign,
5
+ } from "./campaign.js";
6
+ import { publishAssuranceVisualization } from "./browser.js";
7
+ import type { AssuranceAttachmentProvider } from "./attachment.js";
8
+ import {
9
+ AssuranceInputError,
10
+ type AssuranceActor,
11
+ type CampaignExport,
12
+ type AssuranceObservation,
13
+ type AssuranceProbe,
14
+ type AssuranceVisualizationSnapshot,
15
+ type LocalFirebaseTarget,
16
+ type MutationCandidate,
17
+ type SecurityInvariant,
18
+ } from "./types.js";
19
+
20
+ export class AssuranceCampaignStore {
21
+ #campaigns = new Map<string, AuthorizationCampaign>();
22
+ #listeners = new Set<(campaign: AssuranceVisualizationSnapshot) => void>();
23
+
24
+ create(campaign: AuthorizationCampaign): void {
25
+ if (this.#campaigns.has(campaign.id)) {
26
+ throw new AssuranceInputError(
27
+ `campaign '${campaign.id}' already exists.`,
28
+ );
29
+ }
30
+ this.#campaigns.set(campaign.id, campaign);
31
+ }
32
+
33
+ get(id: string): AuthorizationCampaign {
34
+ const campaign = this.#campaigns.get(id);
35
+ if (!campaign) throw new AssuranceInputError(`unknown campaign '${id}'.`);
36
+ return campaign;
37
+ }
38
+
39
+ publish(campaign: AuthorizationCampaign): void {
40
+ const snapshot = campaign.visualization();
41
+ for (const listener of this.#listeners) listener(snapshot);
42
+ publishAssuranceVisualization(snapshot);
43
+ }
44
+
45
+ subscribe(
46
+ listener: (campaign: AssuranceVisualizationSnapshot) => void,
47
+ ): () => void {
48
+ this.#listeners.add(listener);
49
+ for (const campaign of this.#campaigns.values())
50
+ listener(campaign.visualization());
51
+ return () => this.#listeners.delete(listener);
52
+ }
53
+ }
54
+
55
+ export const defaultAssuranceCampaignStore = new AssuranceCampaignStore();
56
+
57
+ export interface AssuranceToolDeps {
58
+ store?: AssuranceCampaignStore;
59
+ onCampaignUpdate?: (campaign: AssuranceVisualizationSnapshot) => void;
60
+ attachmentProvider?: AssuranceAttachmentProvider;
61
+ }
62
+
63
+ let generatedCampaignId = 0;
64
+
65
+ const jsonRecordSchema = {
66
+ type: "object",
67
+ additionalProperties: true,
68
+ };
69
+
70
+ const firestoreOperationSchema = {
71
+ type: "object",
72
+ additionalProperties: false,
73
+ properties: {
74
+ service: { const: "firestore" },
75
+ method: {
76
+ enum: ["get", "list", "create", "set", "merge", "update", "delete"],
77
+ },
78
+ path: { type: "string", minLength: 1 },
79
+ data: jsonRecordSchema,
80
+ query: jsonRecordSchema,
81
+ },
82
+ required: ["service", "method", "path"],
83
+ };
84
+
85
+ const rtdbOperationSchema = {
86
+ type: "object",
87
+ additionalProperties: false,
88
+ properties: {
89
+ service: { const: "rtdb" },
90
+ method: { enum: ["get", "set", "update", "remove"] },
91
+ path: { type: "string", minLength: 1 },
92
+ data: {},
93
+ query: jsonRecordSchema,
94
+ },
95
+ required: ["service", "method", "path"],
96
+ };
97
+
98
+ const storageOperationSchema = {
99
+ type: "object",
100
+ additionalProperties: false,
101
+ properties: {
102
+ service: { const: "storage" },
103
+ method: { enum: ["get", "list", "upload", "updateMetadata", "delete"] },
104
+ path: { type: "string", minLength: 1 },
105
+ dataBase64: { type: "string" },
106
+ contentType: { type: "string" },
107
+ customMetadata: {
108
+ type: "object",
109
+ additionalProperties: { type: "string" },
110
+ },
111
+ },
112
+ required: ["service", "method", "path"],
113
+ };
114
+
115
+ const operationSchema = {
116
+ oneOf: [
117
+ firestoreOperationSchema,
118
+ rtdbOperationSchema,
119
+ storageOperationSchema,
120
+ ],
121
+ };
122
+
123
+ const actorSchema = {
124
+ type: "object",
125
+ additionalProperties: false,
126
+ properties: {
127
+ id: { type: "string", minLength: 1 },
128
+ acquisition: {
129
+ oneOf: [
130
+ {
131
+ type: "object",
132
+ additionalProperties: false,
133
+ properties: { kind: { const: "anonymous-request" } },
134
+ required: ["kind"],
135
+ },
136
+ {
137
+ type: "object",
138
+ additionalProperties: false,
139
+ properties: { kind: { const: "anonymous-account" } },
140
+ required: ["kind"],
141
+ },
142
+ {
143
+ type: "object",
144
+ additionalProperties: false,
145
+ properties: {
146
+ kind: { const: "password" },
147
+ email: { type: "string", minLength: 1 },
148
+ password: { type: "string", minLength: 1 },
149
+ },
150
+ required: ["kind", "email", "password"],
151
+ },
152
+ {
153
+ type: "object",
154
+ additionalProperties: false,
155
+ properties: {
156
+ kind: { const: "fixture-user" },
157
+ uid: { type: "string", minLength: 1 },
158
+ },
159
+ required: ["kind", "uid"],
160
+ },
161
+ {
162
+ type: "object",
163
+ additionalProperties: false,
164
+ properties: {
165
+ kind: { const: "synthetic" },
166
+ uid: { type: "string", minLength: 1 },
167
+ token: jsonRecordSchema,
168
+ },
169
+ required: ["kind", "uid"],
170
+ },
171
+ ],
172
+ },
173
+ },
174
+ required: ["id", "acquisition"],
175
+ };
176
+
177
+ const invariantSchema = {
178
+ type: "object",
179
+ additionalProperties: false,
180
+ properties: {
181
+ id: { type: "string", minLength: 1 },
182
+ statement: { type: "string", minLength: 1 },
183
+ service: { enum: ["firestore", "rtdb", "storage", "cross-service"] },
184
+ expected: { enum: ["ALLOW", "DENY"] },
185
+ source: {
186
+ enum: ["declared", "authored-test", "captured", "derived", "agent"],
187
+ },
188
+ confidence: { enum: ["authoritative", "strong", "tentative"] },
189
+ },
190
+ required: ["id", "statement", "service", "expected", "source", "confidence"],
191
+ };
192
+
193
+ const observationSchema = {
194
+ type: "object",
195
+ additionalProperties: false,
196
+ properties: {
197
+ id: { type: "string", minLength: 1 },
198
+ actorId: { type: "string", minLength: 1 },
199
+ operation: operationSchema,
200
+ result: { const: "ALLOW" },
201
+ source: { enum: ["captured", "authored", "discovered"] },
202
+ description: { type: "string" },
203
+ },
204
+ required: ["id", "actorId", "operation", "result", "source"],
205
+ };
206
+
207
+ const mutationSchema = {
208
+ type: "object",
209
+ additionalProperties: false,
210
+ properties: {
211
+ id: { type: "string", minLength: 1 },
212
+ dimension: { enum: ["path", "query", "payload", "operation"] },
213
+ description: { type: "string", minLength: 1 },
214
+ operation: operationSchema,
215
+ },
216
+ required: ["dimension", "description", "operation"],
217
+ };
218
+
219
+ const probeSchema = {
220
+ type: "object",
221
+ additionalProperties: false,
222
+ properties: {
223
+ id: { type: "string", minLength: 1 },
224
+ actorId: { type: "string", minLength: 1 },
225
+ invariantId: { type: "string", minLength: 1 },
226
+ control: operationSchema,
227
+ mutation: mutationSchema,
228
+ requires: {
229
+ type: "array",
230
+ items: {
231
+ type: "object",
232
+ additionalProperties: false,
233
+ properties: {
234
+ kind: { enum: ["construct", "registry-row"] },
235
+ id: { type: "string", minLength: 1 },
236
+ },
237
+ required: ["kind", "id"],
238
+ },
239
+ },
240
+ },
241
+ required: ["id", "actorId", "invariantId", "control", "mutation"],
242
+ };
243
+
244
+ const rulesSchema = {
245
+ type: "object",
246
+ additionalProperties: false,
247
+ properties: {
248
+ firestore: { type: "string" },
249
+ rtdb: {
250
+ type: "object",
251
+ additionalProperties: false,
252
+ properties: { rules: jsonRecordSchema },
253
+ required: ["rules"],
254
+ },
255
+ storage: { type: "string" },
256
+ },
257
+ };
258
+
259
+ const targetSchema = {
260
+ type: "object",
261
+ additionalProperties: false,
262
+ properties: {
263
+ schema: { const: "pyric.assurance.target.v1" },
264
+ network: { const: "forbid" },
265
+ rules: rulesSchema,
266
+ state: {
267
+ type: "object",
268
+ additionalProperties: false,
269
+ properties: {
270
+ firestore: jsonRecordSchema,
271
+ rtdb: {},
272
+ storage: {
273
+ type: "array",
274
+ items: {
275
+ type: "object",
276
+ additionalProperties: false,
277
+ properties: {
278
+ path: { type: "string", minLength: 1 },
279
+ dataBase64: { type: "string" },
280
+ contentType: { type: "string" },
281
+ customMetadata: {
282
+ type: "object",
283
+ additionalProperties: { type: "string" },
284
+ },
285
+ },
286
+ required: ["path", "dataBase64"],
287
+ },
288
+ },
289
+ auth: {
290
+ type: "object",
291
+ additionalProperties: false,
292
+ properties: {
293
+ users: {
294
+ type: "array",
295
+ items: {
296
+ type: "object",
297
+ additionalProperties: false,
298
+ properties: {
299
+ uid: { type: "string", minLength: 1 },
300
+ email: {
301
+ oneOf: [{ type: "string" }, { type: "null" }],
302
+ },
303
+ password: { type: "string" },
304
+ emailVerified: { type: "boolean" },
305
+ disabled: { type: "boolean" },
306
+ customClaims: jsonRecordSchema,
307
+ },
308
+ required: ["uid"],
309
+ },
310
+ },
311
+ },
312
+ required: ["users"],
313
+ },
314
+ },
315
+ },
316
+ },
317
+ required: ["schema", "network", "rules", "state"],
318
+ };
319
+
320
+ function resultError(error: unknown): {
321
+ ok: false;
322
+ summary: string;
323
+ data?: { code: string };
324
+ } {
325
+ return {
326
+ ok: false,
327
+ summary: error instanceof Error ? error.message : String(error),
328
+ ...(error instanceof AssuranceInputError
329
+ ? { data: { code: error.code } }
330
+ : {}),
331
+ };
332
+ }
333
+
334
+ function campaignParameters(
335
+ extra: Record<string, unknown> = {},
336
+ ): ToolHandler["parameters"] {
337
+ return {
338
+ type: "object",
339
+ properties: {
340
+ campaignId: { type: "string", minLength: 1 },
341
+ ...extra,
342
+ },
343
+ required: ["campaignId"],
344
+ };
345
+ }
346
+
347
+ function redactCampaignExport(bundle: CampaignExport) {
348
+ const auth = bundle.campaign.target.state.auth;
349
+ const actors = bundle.campaign.actors.map((actor) =>
350
+ actor.acquisition.kind === "password"
351
+ ? {
352
+ ...actor,
353
+ acquisition: { ...actor.acquisition, password: "[REDACTED]" },
354
+ }
355
+ : actor,
356
+ );
357
+ const target = {
358
+ ...bundle.campaign.target,
359
+ state: {
360
+ ...bundle.campaign.target.state,
361
+ ...(auth
362
+ ? {
363
+ auth: {
364
+ users: auth.users.map((user) => {
365
+ const { password: _password, ...safe } = user;
366
+ return safe;
367
+ }),
368
+ },
369
+ }
370
+ : {}),
371
+ },
372
+ };
373
+ return {
374
+ ...bundle,
375
+ campaign: { ...bundle.campaign, target, actors },
376
+ redactions: [
377
+ "campaign.target.state.auth.users[].password",
378
+ "campaign.actors[].acquisition.password",
379
+ ],
380
+ };
381
+ }
382
+
383
+ export function createAssuranceTools(
384
+ deps: AssuranceToolDeps = {},
385
+ ): ToolHandler[] {
386
+ const store = deps.store ?? defaultAssuranceCampaignStore;
387
+ if (deps.onCampaignUpdate) store.subscribe(deps.onCampaignUpdate);
388
+ return [
389
+ {
390
+ name: "firebase_assurance_attach",
391
+ description:
392
+ "Attach read-only to the same-origin Pyric sandbox behind a loopback Studio URL, clone its explicit Firestore/RTDB/Auth state, and start an isolated authorization campaign. The live sandbox is never probed or mutated.",
393
+ parameters: {
394
+ type: "object",
395
+ properties: {
396
+ url: { type: "string", format: "uri" },
397
+ campaignId: { type: "string", minLength: 1 },
398
+ maxRuns: { type: "integer", minimum: 1 },
399
+ },
400
+ required: ["url"],
401
+ },
402
+ async execute(args) {
403
+ const input = args as {
404
+ url: string;
405
+ campaignId?: string;
406
+ maxRuns?: number;
407
+ };
408
+ try {
409
+ if (!deps.attachmentProvider) {
410
+ throw new AssuranceInputError(
411
+ "localhost attachment is unavailable in this runtime. Provide an attachmentProvider or use firebase_assurance_start with an explicit target.",
412
+ );
413
+ }
414
+ const attached = await deps.attachmentProvider({ url: input.url });
415
+ const campaignId =
416
+ input.campaignId ?? `assurance-${++generatedCampaignId}`;
417
+ const campaign = createAuthorizationCampaign({
418
+ id: campaignId,
419
+ target: attached.target,
420
+ context: {
421
+ attachment: {
422
+ source: attached.source,
423
+ inventory: attached.inventory,
424
+ coverageGaps: attached.coverageGaps,
425
+ },
426
+ },
427
+ safety: {
428
+ network: "forbid",
429
+ ...(input.maxRuns !== undefined
430
+ ? { maxRuns: input.maxRuns }
431
+ : {}),
432
+ },
433
+ });
434
+ store.create(campaign);
435
+ store.publish(campaign);
436
+ const services = (["firestore", "rtdb", "storage"] as const).filter(
437
+ (service) => attached.target.rules[service] !== undefined,
438
+ );
439
+ const visualizationUrl = new URL(attached.source.studioUrl);
440
+ visualizationUrl.searchParams.set("campaign", campaignId);
441
+ return {
442
+ ok: true,
443
+ summary: `Attached read-only to '${attached.source.origin}' and cloned ${services.join(", ") || "no rules services"} into local campaign '${campaignId}'`,
444
+ data: {
445
+ campaignId,
446
+ localOnly: true,
447
+ attachment: { network: "loopback-read-only" },
448
+ execution: { network: "forbid", engine: "pyric-local-sandboxes" },
449
+ source: attached.source,
450
+ inventory: attached.inventory,
451
+ services,
452
+ coverageGaps: attached.coverageGaps,
453
+ suggestedActors: (attached.target.state.auth?.users ?? []).map(
454
+ (user) => ({
455
+ id: `candidate-${user.uid}`,
456
+ acquisition: { kind: "synthetic" as const, uid: user.uid },
457
+ reachability: "candidate-only" as const,
458
+ reason:
459
+ "Auth inventory proves this identity exists, not that an attacker can acquire it. Use fixture-user only after the app owner confirms the test account is obtainable.",
460
+ }),
461
+ ),
462
+ visualization: {
463
+ view: "assurance",
464
+ url: visualizationUrl.toString(),
465
+ },
466
+ nextActions: [
467
+ "Map reachable actors and known-good operations from the cloned state.",
468
+ "Define explicit security invariants before interpreting permissive behavior.",
469
+ ],
470
+ },
471
+ };
472
+ } catch (error) {
473
+ return resultError(error);
474
+ }
475
+ },
476
+ },
477
+ {
478
+ name: "firebase_assurance_start",
479
+ description:
480
+ "Start a defensive authorization campaign against Pyric local sandboxes only. Requires network=forbid and never contacts Firebase, an emulator, or a real database.",
481
+ parameters: {
482
+ type: "object",
483
+ properties: {
484
+ campaignId: { type: "string", minLength: 1 },
485
+ target: targetSchema,
486
+ maxRuns: { type: "integer", minimum: 1 },
487
+ },
488
+ required: ["target"],
489
+ },
490
+ async execute(args) {
491
+ const input = args as {
492
+ campaignId?: string;
493
+ target: LocalFirebaseTarget;
494
+ maxRuns?: number;
495
+ };
496
+ try {
497
+ const campaignId =
498
+ input.campaignId ?? `assurance-${++generatedCampaignId}`;
499
+ const campaign = createAuthorizationCampaign({
500
+ id: campaignId,
501
+ target: input.target,
502
+ safety: {
503
+ network: "forbid",
504
+ ...(input.maxRuns !== undefined
505
+ ? { maxRuns: input.maxRuns }
506
+ : {}),
507
+ },
508
+ });
509
+ store.create(campaign);
510
+ store.publish(campaign);
511
+ const services = (["firestore", "rtdb", "storage"] as const).filter(
512
+ (service) => input.target.rules[service] !== undefined,
513
+ );
514
+ return {
515
+ ok: true,
516
+ summary: `Started local-only campaign '${campaignId}' for ${services.join(", ") || "no configured services"}`,
517
+ data: {
518
+ campaignId,
519
+ localOnly: true,
520
+ network: "forbid",
521
+ services,
522
+ nextActions: [
523
+ "Map reachable actors and known-good operations.",
524
+ "Define explicit security invariants.",
525
+ ],
526
+ },
527
+ };
528
+ } catch (error) {
529
+ return resultError(error);
530
+ }
531
+ },
532
+ },
533
+ {
534
+ name: "firebase_assurance_map",
535
+ description:
536
+ "Add reachable actors, known-good observations, and optional authored probes to a local assurance campaign.",
537
+ parameters: campaignParameters({
538
+ actors: { type: "array", items: actorSchema },
539
+ observations: { type: "array", items: observationSchema },
540
+ probes: { type: "array", items: probeSchema },
541
+ }),
542
+ async execute(args) {
543
+ const input = args as {
544
+ campaignId: string;
545
+ actors?: AssuranceActor[];
546
+ observations?: AssuranceObservation[];
547
+ probes?: AssuranceProbe[];
548
+ };
549
+ try {
550
+ const campaign = store.get(input.campaignId);
551
+ for (const actor of input.actors ?? []) campaign.addActor(actor);
552
+ for (const observation of input.observations ?? [])
553
+ campaign.addObservation(observation);
554
+ for (const probe of input.probes ?? []) campaign.addProbe(probe);
555
+ store.publish(campaign);
556
+ const spec = campaign.spec();
557
+ return {
558
+ ok: true,
559
+ summary: `Mapped ${spec.actors.length} actor(s), ${campaign.observations.length} observation(s), and ${spec.probes.length} probe(s)`,
560
+ data: {
561
+ actors: spec.actors.length,
562
+ observations: campaign.observations.length,
563
+ probes: spec.probes.length,
564
+ nextActions: [
565
+ "Define the intended boundary for each negative probe.",
566
+ ],
567
+ },
568
+ };
569
+ } catch (error) {
570
+ return resultError(error);
571
+ }
572
+ },
573
+ },
574
+ {
575
+ name: "firebase_assurance_define",
576
+ description:
577
+ "Add explicit authorization invariants. Permissive behavior is not interpreted without one of these expectations.",
578
+ parameters: {
579
+ ...campaignParameters({
580
+ invariants: { type: "array", minItems: 1, items: invariantSchema },
581
+ }),
582
+ required: ["campaignId", "invariants"],
583
+ },
584
+ async execute(args) {
585
+ const input = args as {
586
+ campaignId: string;
587
+ invariants: SecurityInvariant[];
588
+ };
589
+ try {
590
+ const campaign = store.get(input.campaignId);
591
+ for (const invariant of input.invariants ?? [])
592
+ campaign.addInvariant(invariant);
593
+ store.publish(campaign);
594
+ const count = campaign.spec().invariants.length;
595
+ return {
596
+ ok: true,
597
+ summary: `Campaign now has ${count} explicit invariant(s)`,
598
+ data: {
599
+ invariants: count,
600
+ nextActions: [
601
+ "Propose one-dimension mutations from known-good operations.",
602
+ ],
603
+ },
604
+ };
605
+ } catch (error) {
606
+ return resultError(error);
607
+ }
608
+ },
609
+ },
610
+ {
611
+ name: "firebase_assurance_propose",
612
+ description:
613
+ "Turn a known-good observation into bounded probes by changing exactly one mechanically checked path, query, payload, or operation dimension.",
614
+ parameters: {
615
+ ...campaignParameters({
616
+ observationId: { type: "string", minLength: 1 },
617
+ invariantId: { type: "string", minLength: 1 },
618
+ mutations: { type: "array", minItems: 1, items: mutationSchema },
619
+ }),
620
+ required: ["campaignId", "observationId", "invariantId", "mutations"],
621
+ },
622
+ async execute(args) {
623
+ const input = args as {
624
+ campaignId: string;
625
+ observationId: string;
626
+ invariantId: string;
627
+ mutations: MutationCandidate[];
628
+ };
629
+ try {
630
+ const campaign = store.get(input.campaignId);
631
+ const probes = campaign.propose(input);
632
+ store.publish(campaign);
633
+ return {
634
+ ok: true,
635
+ summary: `Proposed ${probes.length} probe(s)`,
636
+ data: {
637
+ probes,
638
+ nextActions: [
639
+ "Run the control and selected mutations in isolated local sandboxes.",
640
+ ],
641
+ },
642
+ };
643
+ } catch (error) {
644
+ return resultError(error);
645
+ }
646
+ },
647
+ },
648
+ {
649
+ name: "firebase_assurance_run",
650
+ description:
651
+ "Run selected controls and mutations against fresh Pyric local sandboxes, then classify expected/observed behavior with evaluator fidelity gates.",
652
+ parameters: campaignParameters({
653
+ probeIds: { type: "array", items: { type: "string" } },
654
+ }),
655
+ async execute(args) {
656
+ const input = args as { campaignId: string; probeIds?: string[] };
657
+ try {
658
+ const campaign = store.get(input.campaignId);
659
+ const report = await campaign.run(input.probeIds);
660
+ store.publish(campaign);
661
+ return {
662
+ ok: true,
663
+ summary: `Ran ${report.summary.probes} probe(s): ${report.summary.localCounterexamples} local counterexample(s), ${report.summary.engineGaps} engine gap(s)`,
664
+ data: {
665
+ ...report,
666
+ nextActions: report.summary.localCounterexamples
667
+ ? [
668
+ "Inspect and minimize local counterexamples.",
669
+ "Test a candidate rules change with exported cases.",
670
+ ]
671
+ : [
672
+ "Inspect engine and coverage gaps before expanding mutations.",
673
+ ],
674
+ },
675
+ };
676
+ } catch (error) {
677
+ return resultError(error);
678
+ }
679
+ },
680
+ },
681
+ {
682
+ name: "firebase_assurance_inspect",
683
+ description:
684
+ "Inspect one completed probe with actor evidence, exact operations, state impact, event evidence, and engine qualification.",
685
+ parameters: {
686
+ ...campaignParameters({ probeId: { type: "string", minLength: 1 } }),
687
+ required: ["campaignId", "probeId"],
688
+ },
689
+ async execute(args) {
690
+ const input = args as { campaignId: string; probeId: string };
691
+ try {
692
+ const result = store.get(input.campaignId).inspect(input.probeId);
693
+ return {
694
+ ok: true,
695
+ summary: `${input.probeId}: ${result.classification}`,
696
+ data: {
697
+ result,
698
+ visualization: {
699
+ view: "assurance",
700
+ campaignId: input.campaignId,
701
+ probeId: input.probeId,
702
+ },
703
+ nextActions:
704
+ result.classification === "local-counterexample"
705
+ ? [
706
+ "Minimize this counterexample.",
707
+ "Open its rule decision in Studio.",
708
+ ]
709
+ : ["Review its qualification and evidence."],
710
+ },
711
+ };
712
+ } catch (error) {
713
+ return resultError(error);
714
+ }
715
+ },
716
+ },
717
+ {
718
+ name: "firebase_assurance_minimize",
719
+ description:
720
+ "Minimize a demonstrated local counterexample by removing payload fields while preserving its qualified classification.",
721
+ parameters: {
722
+ ...campaignParameters({ probeId: { type: "string", minLength: 1 } }),
723
+ required: ["campaignId", "probeId"],
724
+ },
725
+ async execute(args) {
726
+ const input = args as { campaignId: string; probeId: string };
727
+ try {
728
+ const campaign = store.get(input.campaignId);
729
+ const result = await campaign.minimize(input.probeId);
730
+ store.publish(campaign);
731
+ return {
732
+ ok: true,
733
+ summary: result.changed
734
+ ? `Minimized '${input.probeId}' by removing ${result.removedPayloadFields.length} field(s)`
735
+ : `'${input.probeId}' is already minimal for the v1 payload reducer`,
736
+ data: {
737
+ ...result,
738
+ nextActions: [
739
+ "Export this explicit expectation as a regression case.",
740
+ ],
741
+ },
742
+ };
743
+ } catch (error) {
744
+ return resultError(error);
745
+ }
746
+ },
747
+ },
748
+ {
749
+ name: "firebase_assurance_verify",
750
+ description:
751
+ "Verify candidate local rules against the campaign regression cases while retaining private actor credentials inside the campaign. Preserves known-good controls and requires negative cases to be denied in fresh Pyric sandboxes.",
752
+ parameters: {
753
+ ...campaignParameters({
754
+ rules: rulesSchema,
755
+ includeCandidates: { type: "boolean" },
756
+ verificationId: { type: "string" },
757
+ }),
758
+ required: ["campaignId", "rules"],
759
+ },
760
+ async execute(args) {
761
+ const input = args as {
762
+ campaignId: string;
763
+ rules: LocalFirebaseTarget["rules"];
764
+ includeCandidates?: boolean;
765
+ verificationId?: string;
766
+ };
767
+ try {
768
+ const campaign = store.get(input.campaignId);
769
+ const report = await campaign.verifyRules({
770
+ rules: input.rules,
771
+ ...(input.includeCandidates !== undefined
772
+ ? { includeCandidates: input.includeCandidates }
773
+ : {}),
774
+ ...(input.verificationId ? { id: input.verificationId } : {}),
775
+ });
776
+ store.publish(campaign);
777
+ const passed =
778
+ report.summary.controlsPassed === report.summary.probes &&
779
+ report.summary.noCounterexamples === report.summary.probes &&
780
+ report.summary.localCounterexamples === 0 &&
781
+ report.summary.engineGaps === 0 &&
782
+ report.summary.invalidProbes === 0;
783
+ return {
784
+ ok: true,
785
+ summary: passed
786
+ ? `Candidate rules preserved ${report.summary.controlsPassed} control(s) and denied ${report.summary.noCounterexamples} negative case(s)`
787
+ : `Candidate rules did not fully verify: ${report.summary.controlsPassed}/${report.summary.probes} controls passed and ${report.summary.noCounterexamples}/${report.summary.probes} negative cases were denied`,
788
+ data: {
789
+ ...report,
790
+ verified: passed,
791
+ visualization: {
792
+ view: "assurance",
793
+ campaignId: input.campaignId,
794
+ verificationId: report.campaignId,
795
+ },
796
+ nextActions: passed
797
+ ? ["Export the campaign and verified regression cases."]
798
+ : [
799
+ "Inspect verification results before changing or reporting the candidate rules.",
800
+ ],
801
+ },
802
+ };
803
+ } catch (error) {
804
+ return resultError(error);
805
+ }
806
+ },
807
+ },
808
+ {
809
+ name: "firebase_assurance_export",
810
+ description:
811
+ "Export the serializable local campaign, observations, qualified report, and explicit regression cases.",
812
+ parameters: campaignParameters(),
813
+ async execute(args) {
814
+ const input = args as { campaignId: string };
815
+ try {
816
+ const bundle = redactCampaignExport(
817
+ store.get(input.campaignId).export(),
818
+ );
819
+ return {
820
+ ok: true,
821
+ summary: `Exported campaign '${input.campaignId}' with ${bundle.cases.length} regression case(s)`,
822
+ data: bundle,
823
+ };
824
+ } catch (error) {
825
+ return resultError(error);
826
+ }
827
+ },
828
+ },
829
+ ];
830
+ }