@pyric/cli 0.1.0-alpha.19 → 0.1.0-alpha.20

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 (317) hide show
  1. package/README.md +9 -9
  2. package/dist/cli/index.d.ts +2 -2
  3. package/dist/cli/index.d.ts.map +1 -1
  4. package/dist/cli/index.js +48 -42
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/mcp-proxy.js +3 -3
  7. package/dist/cli/mcp-proxy.js.map +1 -1
  8. package/dist/cli/parse-args.d.ts +1 -1
  9. package/dist/cli/parse-args.d.ts.map +1 -1
  10. package/dist/cli/parse-args.js +51 -15
  11. package/dist/cli/parse-args.js.map +1 -1
  12. package/dist/cli/pyric-config.d.ts +24 -0
  13. package/dist/cli/pyric-config.d.ts.map +1 -0
  14. package/dist/cli/pyric-config.js +28 -0
  15. package/dist/cli/pyric-config.js.map +1 -0
  16. package/dist/cli/{dev-runner.d.ts → sandbox-runner.d.ts} +33 -36
  17. package/dist/cli/sandbox-runner.d.ts.map +1 -0
  18. package/dist/cli/{dev-runner.js → sandbox-runner.js} +90 -55
  19. package/dist/cli/sandbox-runner.js.map +1 -0
  20. package/dist/cli/serve.d.ts +6 -4
  21. package/dist/cli/serve.d.ts.map +1 -1
  22. package/dist/cli/serve.js +99 -40
  23. package/dist/cli/serve.js.map +1 -1
  24. package/dist/cli/snapshot.js +5 -5
  25. package/dist/cli/snapshot.js.map +1 -1
  26. package/dist/cli/verify.js +1 -1
  27. package/dist/cli/verify.js.map +1 -1
  28. package/dist/functions-rtdb/development-runtime.js +1 -1
  29. package/dist/functions-rtdb/development-runtime.js.map +1 -1
  30. package/dist/functions-rtdb/project.js +8 -8
  31. package/dist/functions-rtdb/project.js.map +1 -1
  32. package/dist/next/guard.js +1 -1
  33. package/dist/next/guard.js.map +1 -1
  34. package/dist/remote/index.d.ts +1 -1
  35. package/dist/remote/index.js +9 -9
  36. package/dist/remote/index.js.map +1 -1
  37. package/dist/serve/bundler.js +10 -10
  38. package/dist/serve/bundler.js.map +1 -1
  39. package/dist/serve/entries/ai.d.ts.map +1 -1
  40. package/dist/serve/entries/ai.js +27 -1
  41. package/dist/serve/entries/ai.js.map +1 -1
  42. package/dist/serve/entries/auth-helper-dom.js +1 -1
  43. package/dist/serve/entries/auth-helper-dom.js.map +1 -1
  44. package/dist/serve/entries/auth-helper-runtime.js +1 -1
  45. package/dist/serve/entries/auth-helper-runtime.js.map +1 -1
  46. package/dist/serve/entries/firestore.js +3 -3
  47. package/dist/serve/entries/firestore.js.map +1 -1
  48. package/dist/serve/entries/keepalive.js +1 -1
  49. package/dist/serve/entries/keepalive.js.map +1 -1
  50. package/dist/serve/entries/runtime.js +21 -14
  51. package/dist/serve/entries/runtime.js.map +1 -1
  52. package/dist/serve/entries/storage.js +1 -1
  53. package/dist/serve/entries/storage.js.map +1 -1
  54. package/dist/serve/entries/worker-runtime.js +1 -1
  55. package/dist/serve/entries/worker-runtime.js.map +1 -1
  56. package/dist/serve/init-payload.d.ts +4 -0
  57. package/dist/serve/init-payload.d.ts.map +1 -1
  58. package/dist/serve/namespace.d.ts +6 -0
  59. package/dist/serve/namespace.d.ts.map +1 -1
  60. package/dist/serve/namespace.js +36 -5
  61. package/dist/serve/namespace.js.map +1 -1
  62. package/dist/serve/rules.d.ts.map +1 -1
  63. package/dist/serve/rules.js +44 -21
  64. package/dist/serve/rules.js.map +1 -1
  65. package/dist/serve/runtime/chip.d.ts.map +1 -1
  66. package/dist/serve/runtime/chip.js +32 -1
  67. package/dist/serve/runtime/chip.js.map +1 -1
  68. package/dist/serve/runtime/manifest.d.ts +1 -1
  69. package/dist/serve/runtime/manifest.d.ts.map +1 -1
  70. package/dist/serve/runtime/manifest.js +1 -1
  71. package/dist/serve/runtime/manifest.js.map +1 -1
  72. package/dist/serve/runtime/status.d.ts.map +1 -1
  73. package/dist/serve/runtime/status.js +23 -0
  74. package/dist/serve/runtime/status.js.map +1 -1
  75. package/dist/serve/sandbox-session.d.ts +1 -0
  76. package/dist/serve/sandbox-session.d.ts.map +1 -1
  77. package/dist/serve/sandbox-session.js +10 -4
  78. package/dist/serve/sandbox-session.js.map +1 -1
  79. package/dist/serve/server.d.ts +7 -0
  80. package/dist/serve/server.d.ts.map +1 -1
  81. package/dist/serve/server.js +15 -1
  82. package/dist/serve/server.js.map +1 -1
  83. package/dist/serve/site-ui/404.html +1 -1
  84. package/dist/serve/site-ui/_astro/{RulesCodeEditor.Bl-XMkhD.js → RulesCodeEditor.XtDmHOlN.js} +1 -1
  85. package/dist/serve/site-ui/_astro/_slug_.Da5VLhW1.css +1 -0
  86. package/dist/serve/site-ui/_astro/_studio_.BnfYCKoI.css +1 -0
  87. package/dist/serve/site-ui/_astro/app.B52xr-DK.js +1 -0
  88. package/dist/serve/site-ui/_astro/app.DWBraPUw.js +12 -0
  89. package/dist/serve/site-ui/_astro/app.pMSnN6Qw.css +1 -0
  90. package/dist/serve/site-ui/_astro/{chess-showcase.Dh5D8kqe.js → chess-showcase.B72XYeoh.js} +1 -1
  91. package/dist/serve/site-ui/_astro/{example-runtime.CuyAjjiG.js → example-runtime.C25_lx6Z.js} +1 -1
  92. package/dist/serve/site-ui/_astro/index.Tb-31efc.css +1 -0
  93. package/dist/serve/site-ui/_astro/index.UkCBr-_0.css +1 -0
  94. package/dist/serve/site-ui/_astro/{sandbox-controls.BP4M5f1M.js → sandbox-controls.DEpnKg-O.js} +11 -11
  95. package/dist/serve/site-ui/_astro/{seed.CSUkloMi.js → seed.Co0yUJY5.js} +1 -1
  96. package/dist/serve/site-ui/_astro/{writes.C57paAj2.js → writes.rpjrFzmu.js} +7 -4
  97. package/dist/serve/site-ui/auth/index.html +5 -3
  98. package/dist/serve/site-ui/david-east.jpg +0 -0
  99. package/dist/serve/site-ui/docs/_rhythm/index.html +6 -3
  100. package/dist/serve/site-ui/docs/_rhythm.md +1 -1
  101. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +18 -15
  102. package/dist/serve/site-ui/docs/agent/set-up-your-agent.md +16 -16
  103. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +6 -5
  104. package/dist/serve/site-ui/docs/agent/watch-and-review.md +1 -5
  105. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +8 -5
  106. package/dist/serve/site-ui/docs/agent/work-with-an-agent.md +4 -4
  107. package/dist/serve/site-ui/docs/ai-compat/index.html +5 -2
  108. package/dist/serve/site-ui/docs/api-reference/index.html +6 -2
  109. package/dist/serve/site-ui/docs/api-reference.md +1 -0
  110. package/dist/serve/site-ui/docs/app-compat/index.html +5 -2
  111. package/dist/serve/site-ui/docs/auth-compat/index.html +5 -2
  112. package/dist/serve/site-ui/docs/build/ai-logic/index.html +5 -2
  113. package/dist/serve/site-ui/docs/build/authentication/index.html +7 -4
  114. package/dist/serve/site-ui/docs/build/authentication.md +2 -2
  115. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +5 -2
  116. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +5 -2
  117. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +6 -3
  118. package/dist/serve/site-ui/docs/build/cloud-storage.md +1 -1
  119. package/dist/serve/site-ui/docs/build/realtime-database/index.html +9 -6
  120. package/dist/serve/site-ui/docs/build/realtime-database.md +4 -4
  121. package/dist/serve/site-ui/docs/conformance-scores/index.html +5 -2
  122. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +6 -3
  123. package/dist/serve/site-ui/docs/create-pyric-reference-api.md +1 -1
  124. package/dist/serve/site-ui/docs/database-compat/index.html +5 -2
  125. package/dist/serve/site-ui/docs/examples/chess/index.html +5 -2
  126. package/dist/serve/site-ui/docs/examples/index.html +5 -2
  127. package/dist/serve/site-ui/docs/firestore-compat/index.html +5 -2
  128. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +5 -2
  129. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +9 -6
  130. package/dist/serve/site-ui/docs/get-started/how-the-swap-works.md +5 -5
  131. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +9 -6
  132. package/dist/serve/site-ui/docs/get-started/nextjs.md +4 -4
  133. package/dist/serve/site-ui/docs/get-started/start-building/index.html +14 -9
  134. package/dist/serve/site-ui/docs/get-started/start-building.md +16 -10
  135. package/dist/serve/site-ui/docs/get-started/vite/index.html +6 -3
  136. package/dist/serve/site-ui/docs/get-started/vite.md +1 -1
  137. package/dist/serve/site-ui/docs/index.json +180 -150
  138. package/dist/serve/site-ui/docs/messaging-compat/index.html +5 -2
  139. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +5 -2
  140. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +6 -4
  141. package/dist/serve/site-ui/docs/observe/see-whats-happening.md +2 -4
  142. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +9 -6
  143. package/dist/serve/site-ui/docs/observe/shape-your-data.md +4 -4
  144. package/dist/serve/site-ui/docs/overview/index.html +16 -10
  145. package/dist/serve/site-ui/docs/overview.md +19 -11
  146. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +5 -2
  147. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +5 -2
  148. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +5 -2
  149. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +8 -5
  150. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api.md +3 -3
  151. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +5 -2
  152. package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +501 -0
  153. package/dist/serve/site-ui/docs/pyric-admin-reference-api.md +587 -0
  154. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +5 -2
  155. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +5 -2
  156. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +5 -2
  157. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +5 -2
  158. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +5 -2
  159. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +5 -2
  160. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +5 -2
  161. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +5 -2
  162. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +5 -2
  163. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +5 -2
  164. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +5 -2
  165. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +5 -2
  166. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +5 -2
  167. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +5 -2
  168. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +5 -2
  169. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +5 -2
  170. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +5 -2
  171. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +6 -3
  172. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api.md +1 -1
  173. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +5 -2
  174. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +5 -2
  175. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +5 -2
  176. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +166 -95
  177. package/dist/serve/site-ui/docs/pyric-database-reference-api.md +107 -1
  178. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +5 -2
  179. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +10 -4
  180. package/dist/serve/site-ui/docs/pyric-messaging-reference-api.md +5 -2
  181. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +10 -4
  182. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api.md +5 -2
  183. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +5 -2
  184. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +5 -2
  185. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +6 -3
  186. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api.md +2 -2
  187. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +5 -2
  188. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +5 -2
  189. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +5 -2
  190. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +5 -2
  191. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +5 -2
  192. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +5 -2
  193. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +5 -2
  194. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +5 -2
  195. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +5 -2
  196. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +5 -2
  197. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +5 -2
  198. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +5 -2
  199. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +5 -2
  200. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +5 -2
  201. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +5 -2
  202. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +5 -2
  203. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +5 -2
  204. package/dist/serve/site-ui/docs/reference/cli/index.html +153 -0
  205. package/dist/serve/site-ui/docs/reference/cli.md +114 -0
  206. package/dist/serve/site-ui/docs/rules-compat/index.html +5 -2
  207. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +5 -2
  208. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +5 -2
  209. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +6 -3
  210. package/dist/serve/site-ui/docs/secure/read-a-denial.md +1 -1
  211. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +5 -2
  212. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +5 -2
  213. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +5 -2
  214. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +5 -2
  215. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +5 -2
  216. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +7 -4
  217. package/dist/serve/site-ui/docs/ship/ship-to-production.md +2 -2
  218. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +9 -6
  219. package/dist/serve/site-ui/docs/ship/test-in-node.md +4 -4
  220. package/dist/serve/site-ui/docs/storage-compat/index.html +5 -2
  221. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +5 -2
  222. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +5 -2
  223. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +5 -2
  224. package/dist/serve/site-ui/docs/tutorial/index.html +10 -7
  225. package/dist/serve/site-ui/docs/tutorial.md +4 -4
  226. package/dist/serve/site-ui/examples/chess/index.html +4 -2
  227. package/dist/serve/site-ui/firestore/index.html +5 -3
  228. package/dist/serve/site-ui/hero-charcoal.jpg +0 -0
  229. package/dist/serve/site-ui/index.html +9 -7
  230. package/dist/serve/site-ui/llms.txt +4 -3
  231. package/dist/serve/site-ui/pyric-campfire-full.png +0 -0
  232. package/dist/serve/site-ui/pyric-campfire.png +0 -0
  233. package/dist/serve/site-ui/rtdb/index.html +5 -3
  234. package/dist/serve/site-ui/settings/index.html +5 -3
  235. package/dist/serve/site-ui/storage/index.html +5 -3
  236. package/dist/serve/site-ui/studio/index.html +13 -0
  237. package/dist/serve/site-ui/studio-routes.json +1 -1
  238. package/dist/serve/site-ui/traffic/index.html +5 -3
  239. package/dist/serve/studio/routes.d.ts +9 -0
  240. package/dist/serve/studio/routes.d.ts.map +1 -1
  241. package/dist/serve/studio/routes.js +47 -7
  242. package/dist/serve/studio/routes.js.map +1 -1
  243. package/dist/serve/vite-ai-config.d.ts.map +1 -1
  244. package/dist/serve/vite-ai-config.js +38 -8
  245. package/dist/serve/vite-ai-config.js.map +1 -1
  246. package/dist/serve/vite-module-swap.d.ts.map +1 -1
  247. package/dist/serve/vite-module-swap.js +0 -28
  248. package/dist/serve/vite-module-swap.js.map +1 -1
  249. package/dist/serve/vite-sandbox-generation.d.ts +1 -1
  250. package/dist/serve/vite-sandbox-generation.d.ts.map +1 -1
  251. package/dist/serve/vite-sandbox-generation.js +1 -1
  252. package/dist/serve/vite-sandbox-generation.js.map +1 -1
  253. package/dist/serve/worker/client/disconnect.js +1 -1
  254. package/dist/serve/worker/client/disconnect.js.map +1 -1
  255. package/dist/serve/worker/client/presence.d.ts.map +1 -1
  256. package/dist/serve/worker/client/presence.js +18 -5
  257. package/dist/serve/worker/client/presence.js.map +1 -1
  258. package/dist/serve/worker/host-ai.d.ts.map +1 -1
  259. package/dist/serve/worker/host-ai.js +15 -0
  260. package/dist/serve/worker/host-ai.js.map +1 -1
  261. package/dist/serve/worker/protocol.d.ts +4 -0
  262. package/dist/serve/worker/protocol.d.ts.map +1 -1
  263. package/dist/serve/worker/protocol.js.map +1 -1
  264. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  265. package/dist/serve/worker/serve-init.js +7 -1
  266. package/dist/serve/worker/serve-init.js.map +1 -1
  267. package/package.json +5 -5
  268. package/src/cli/cli.test.ts +2 -2
  269. package/src/cli/index.ts +48 -42
  270. package/src/cli/mcp-proxy.ts +4 -4
  271. package/src/cli/parse-args.ts +61 -15
  272. package/src/cli/pyric-config.ts +45 -0
  273. package/src/cli/{dev-runner.ts → sandbox-runner.ts} +117 -72
  274. package/src/cli/serve.ts +115 -47
  275. package/src/cli/snapshot.ts +5 -5
  276. package/src/cli/verify.ts +1 -1
  277. package/src/functions-rtdb/development-runtime.ts +1 -1
  278. package/src/functions-rtdb/project.ts +8 -8
  279. package/src/next/guard.ts +1 -1
  280. package/src/remote/index.ts +9 -9
  281. package/src/serve/bundler.ts +10 -10
  282. package/src/serve/entries/ai.ts +27 -1
  283. package/src/serve/entries/auth-helper-dom.ts +1 -1
  284. package/src/serve/entries/auth-helper-runtime.ts +1 -1
  285. package/src/serve/entries/firestore.ts +3 -3
  286. package/src/serve/entries/keepalive.ts +1 -1
  287. package/src/serve/entries/runtime.ts +19 -14
  288. package/src/serve/entries/storage.ts +1 -1
  289. package/src/serve/entries/worker-runtime.ts +1 -1
  290. package/src/serve/init-payload.ts +4 -0
  291. package/src/serve/namespace.ts +44 -5
  292. package/src/serve/rules.ts +47 -22
  293. package/src/serve/runtime/chip.ts +38 -1
  294. package/src/serve/runtime/manifest.ts +1 -1
  295. package/src/serve/runtime/status.ts +24 -0
  296. package/src/serve/sandbox-session.ts +10 -4
  297. package/src/serve/server.ts +18 -1
  298. package/src/serve/studio/routes.ts +63 -7
  299. package/src/serve/vite-ai-config.ts +37 -7
  300. package/src/serve/vite-module-swap.ts +0 -28
  301. package/src/serve/vite-sandbox-generation.ts +1 -1
  302. package/src/serve/worker/client/disconnect.ts +1 -1
  303. package/src/serve/worker/client/presence.ts +25 -5
  304. package/src/serve/worker/host-ai.ts +15 -0
  305. package/src/serve/worker/protocol.ts +2 -1
  306. package/src/serve/worker/serve-init.ts +5 -1
  307. package/README.md.orig +0 -145
  308. package/dist/cli/dev-runner.d.ts.map +0 -1
  309. package/dist/cli/dev-runner.js.map +0 -1
  310. package/dist/serve/site-ui/_astro/_slug_.CXh9yTP1.css +0 -1
  311. package/dist/serve/site-ui/_astro/_slug_.CupVK4TM.css +0 -1
  312. package/dist/serve/site-ui/_astro/_studio_.CfxiQWkk.css +0 -1
  313. package/dist/serve/site-ui/_astro/app.BsFsMjn0.css +0 -1
  314. package/dist/serve/site-ui/_astro/app.Ce3MTLQm.js +0 -1
  315. package/dist/serve/site-ui/_astro/app.taqzyjD0.js +0 -11
  316. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +0 -582
  317. package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research.md +0 -448
@@ -1,7 +1,7 @@
1
1
  /** Stable routes and identity used by the served runtime and its UI. */
2
2
  export const PYRIC_WORKER_URL = '/__pyric/sdk/worker.js';
3
3
  export const PYRIC_WORKER_NAME = 'pyric-shared-worker';
4
- export const PYRIC_STUDIO_URL = '/__pyric/ui/';
4
+ export const PYRIC_STUDIO_URL = '/__pyric/ui/studio';
5
5
 
6
6
  export interface PyricRuntimeManifest {
7
7
  studioUrl: string;
@@ -108,6 +108,13 @@ function isListenerPhaseErroredEvent(event: SandboxEvent): boolean {
108
108
  return isListenerKind && isErroredPhase && hasErrorPayload;
109
109
  }
110
110
 
111
+ function isAiRejectedEvent(event: SandboxEvent): boolean {
112
+ const isServiceMutationKind = event.kind === 'service_mutation';
113
+ const isAiService = event.service === 'ai';
114
+ const isRejectedOp = 'op' in event && event.op === 'request_rejected';
115
+ return isServiceMutationKind && isAiService && isRejectedOp;
116
+ }
117
+
111
118
  function sandboxError(event: SandboxEvent): PyricRuntimeError | null {
112
119
  if (isRuntimeErrorEvent(event)) {
113
120
  const hasPathProperty = 'path' in event && typeof event.path === 'string';
@@ -127,6 +134,23 @@ function sandboxError(event: SandboxEvent): PyricRuntimeError | null {
127
134
  message: errorPayload?.message ? errorPayload.message : 'Sandbox runtime error',
128
135
  };
129
136
  }
137
+ if (isAiRejectedEvent(event)) {
138
+ const detail = 'detail' in event ? (event.detail as Record<string, unknown> | undefined) : undefined;
139
+ const code = typeof detail?.code === 'string' ? detail.code : 'AI_ERROR';
140
+ const message = typeof detail?.message === 'string' ? detail.message : 'AI request rejected';
141
+ const hasPathProperty = 'path' in event && typeof event.path === 'string';
142
+ const targetPath = hasPathProperty ? event.path : '(ai)';
143
+ return {
144
+ id: event.id,
145
+ source: 'sandbox',
146
+ at: event.at,
147
+ service: 'ai',
148
+ method: 'generateContent',
149
+ path: targetPath,
150
+ code,
151
+ message: `AI_ERROR: ${message}`,
152
+ };
153
+ }
130
154
  if (isListenerErroredEvent(event)) {
131
155
  const errorPayload = (event as { error: { code?: string; message: string } }).error;
132
156
  return {
@@ -35,6 +35,7 @@ export interface SandboxSessionOptions {
35
35
  bridgeUrl?: () => string | null;
36
36
  ai?: InitPayload['ai'];
37
37
  aiProxyUpstream?: string;
38
+ permissive?: boolean;
38
39
  logger?: ServeLogger;
39
40
  activity?: (incident: ActivityIncident) => void;
40
41
  }
@@ -97,6 +98,13 @@ export async function createSandboxSession(
97
98
  databaseRules: database.rules,
98
99
  databaseRulesHash: database.rulesHash,
99
100
  };
101
+ if (!database.sourcePath) {
102
+ if (options.permissive) {
103
+ options.logger?.note(' ⓘ RTDB permissive mode active — client reads/writes are open by default.');
104
+ } else {
105
+ options.logger?.note(' ⚠ no database.rules.json found — client RTDB reads/writes default to DENY (matching production Firebase). Use --permissive for open prototyping.');
106
+ }
107
+ }
100
108
  const events = createEventHub();
101
109
  const capture: CaptureStore | undefined = (options.capture ?? true)
102
110
  ? createCaptureStore(options.projectDir)
@@ -164,6 +172,7 @@ export async function createSandboxSession(
164
172
  : seedUsers,
165
173
  messaging: true,
166
174
  ai: options.ai ?? null,
175
+ permissive: Boolean(options.permissive),
167
176
  });
168
177
 
169
178
  const summary: SandboxSessionSummary = {
@@ -221,16 +230,13 @@ export async function createSandboxSession(
221
230
  }
222
231
  };
223
232
  const reloadDatabaseRules = async (): Promise<RulesReloadResult> => {
224
- const isMissingDatabaseRules = database.sourcePath === null;
225
- if (isMissingDatabaseRules) {
226
- return { kind: 'not-configured' };
227
- }
228
233
  try {
229
234
  const updated = await loadProjectDatabaseRules(options.projectDir, options.firebaseConfig);
230
235
  const isMissingUpdatedRules = updated.rules === null || updated.rulesHash === null;
231
236
  if (isMissingUpdatedRules) {
232
237
  return { kind: 'not-configured' };
233
238
  }
239
+ database.sourcePath = updated.sourcePath;
234
240
  live.databaseRules = updated.rules;
235
241
  live.databaseRulesHash = updated.rulesHash;
236
242
  events.broadcast('rtdb-rules-update', { rules: updated.rules, rulesHash: updated.rulesHash });
@@ -134,6 +134,23 @@ export function isAllowedUpgrade(
134
134
  );
135
135
  }
136
136
 
137
+ /**
138
+ * Extract a header value case-insensitively from either Node's IncomingMessage headers
139
+ * or Fetch API Headers object.
140
+ */
141
+ export function getHeader(
142
+ req: { headers?: Record<string, string | string[] | undefined> | Headers },
143
+ name: string,
144
+ ): string | undefined {
145
+ const headers = req?.headers;
146
+ if (!headers) return undefined;
147
+ if (typeof (headers as Headers).get === 'function') {
148
+ return (headers as Headers).get(name) ?? undefined;
149
+ }
150
+ const val = (headers as Record<string, string | string[] | undefined>)[name.toLowerCase()];
151
+ return Array.isArray(val) ? val.join(', ') : val;
152
+ }
153
+
137
154
  export interface ServeHandle {
138
155
  port: number;
139
156
  host: string;
@@ -249,7 +266,7 @@ async function handleRequest(
249
266
  if (!isAllowedHost(req.headers.host, opts.host ?? 'localhost', opts.allowedHosts)) {
250
267
  logger.note(` ✖ 403 blocked Host '${req.headers.host}' (DNS-rebinding guard)`);
251
268
  res.writeHead(403, { 'content-type': 'text/plain' }).end(
252
- `pyric dev: refused request for Host '${req.headers.host ?? ''}'. ` +
269
+ `pyric sandbox: refused request for Host '${req.headers.host ?? ''}'. ` +
253
270
  'Only localhost is allowed; use --allowed-host to add one.',
254
271
  );
255
272
  return;
@@ -33,12 +33,22 @@ import type {
33
33
  WorkspaceChange,
34
34
  WorkspaceStore,
35
35
  } from './store-types.js';
36
+ import { isAllowedHost, isAllowedOrigin, getHeader } from '../server.js';
37
+ import type { WriterLock } from '../writer-lock.js';
36
38
 
37
39
  export interface StudioRouteOptions {
38
40
  /** The single-project file tree served at `/__pyric/workspace`. */
39
41
  workspace?: WorkspaceStore;
40
42
  /** The project list served at `/__pyric/projects`. */
41
43
  projects?: ProjectStore;
44
+ /** Per-boot session capability token required on workspace & project endpoints. */
45
+ sessionToken?: string;
46
+ /** Single-writer lock validator for file mutation & deletion endpoints. */
47
+ writerLock?: WriterLock;
48
+ /** Bound host for DNS rebinding guard. */
49
+ boundHost?: string;
50
+ /** Extra hostnames allowed for DNS rebinding/origin guard. */
51
+ allowedHosts?: string[];
42
52
  }
43
53
 
44
54
  /** Collect the raw request body as a UTF-8 string. */
@@ -207,6 +217,10 @@ async function handleProjects(
207
217
  .end('method not allowed');
208
218
  }
209
219
 
220
+ function isWorkspaceMutation(method?: string): boolean {
221
+ return method === 'PUT' || method === 'POST' || method === 'PATCH' || method === 'DELETE';
222
+ }
223
+
210
224
  /**
211
225
  * Build a namespace fragment for the Studio storage routes. Returns a handler
212
226
  * shaped like the other `/__pyric/*` fragments: it resolves `true` when it
@@ -219,13 +233,55 @@ export function createStudioRoutes(opts: StudioRouteOptions) {
219
233
  url: URL,
220
234
  ): Promise<boolean> => {
221
235
  try {
222
- if (opts.workspace && url.pathname.startsWith('/__pyric/workspace')) {
223
- await handleWorkspace(opts.workspace, req, res, url);
224
- return true;
225
- }
226
- if (opts.projects && url.pathname.startsWith('/__pyric/projects')) {
227
- await handleProjects(opts.projects, req, res, url);
228
- return true;
236
+ const isWorkspaceRoute = opts.workspace && url.pathname.startsWith('/__pyric/workspace');
237
+ const isProjectsRoute = opts.projects && url.pathname.startsWith('/__pyric/projects');
238
+
239
+ if (isWorkspaceRoute || isProjectsRoute) {
240
+ const hostHeader = getHeader(req, 'host');
241
+ const originHeader = getHeader(req, 'origin');
242
+
243
+ // 1. Host and Origin guard (Requirement 1)
244
+ if (!isAllowedHost(hostHeader, opts.boundHost ?? 'localhost', opts.allowedHosts)) {
245
+ res.writeHead(403, { 'content-type': 'text/plain' }).end('Forbidden: host not allowed');
246
+ return true;
247
+ }
248
+ if (originHeader && !isAllowedOrigin(originHeader, opts.boundHost ?? 'localhost', opts.allowedHosts)) {
249
+ res.writeHead(403, { 'content-type': 'text/plain' }).end('Forbidden: origin mismatch');
250
+ return true;
251
+ }
252
+
253
+ // 2. Per-boot session capability token guard (Requirement 2)
254
+ if (opts.sessionToken) {
255
+ const reqToken =
256
+ getHeader(req, 'x-pyric-session-token') ??
257
+ url.searchParams.get('token');
258
+ if (!reqToken || reqToken !== opts.sessionToken) {
259
+ res.writeHead(401, { 'content-type': 'text/plain' }).end('Unauthorized: invalid session capability token');
260
+ return true;
261
+ }
262
+ }
263
+
264
+ // 3. Single-writer lock guard for mutation endpoints (Requirement 4)
265
+ if (opts.writerLock && isWorkspaceMutation(req.method)) {
266
+ const writerId = getHeader(req, 'x-pyric-writer');
267
+ if (!writerId) {
268
+ res.writeHead(423, { 'content-type': 'text/plain' }).end('Locked: missing active writer lock header');
269
+ return true;
270
+ }
271
+ if (!opts.writerLock.claim(writerId, Date.now())) {
272
+ res.writeHead(423, { 'content-type': 'text/plain' }).end('Locked: another tab holds the writer lock');
273
+ return true;
274
+ }
275
+ }
276
+
277
+ if (isWorkspaceRoute) {
278
+ await handleWorkspace(opts.workspace!, req, res, url);
279
+ return true;
280
+ }
281
+ if (isProjectsRoute) {
282
+ await handleProjects(opts.projects!, req, res, url);
283
+ return true;
284
+ }
229
285
  }
230
286
  } catch (e) {
231
287
  if (!res.headersSent) sendError(res, e);
@@ -44,7 +44,18 @@ export function loadViteAiEnv(
44
44
  const resolvedEnvDir = envDir === undefined
45
45
  ? resolvedRoot
46
46
  : path.resolve(resolvedRoot, envDir);
47
- return loadEnv(mode, resolvedEnvDir, '');
47
+ const loaded = loadEnv(mode, resolvedEnvDir, '');
48
+ for (const [key, val] of Object.entries(loaded)) {
49
+ const isAuthKey =
50
+ key === 'GEMINI_API_KEY' ||
51
+ key === 'GOOGLE_GENAI_API_KEY' ||
52
+ key === 'VITE_GEMINI_API_KEY' ||
53
+ key === 'PYRIC_API_KEY';
54
+ if (isAuthKey && process.env[key] === undefined) {
55
+ process.env[key] = val;
56
+ }
57
+ }
58
+ return loaded;
48
59
  }
49
60
 
50
61
  /** Convert a public declarative engine into the JSON-safe worker wire shape. */
@@ -65,6 +76,21 @@ export function engineConfigToWire(engine: PyricAiEngineConfig): AiEngineConfigW
65
76
  }
66
77
  return result as AiEngineConfigWire;
67
78
  }
79
+ const isGeminiEngine = engine.kind === 'gemini';
80
+ if (isGeminiEngine) {
81
+ const result: Record<string, unknown> = {
82
+ kind: 'gemini',
83
+ };
84
+ const hasBaseUrl = engine.baseUrl !== undefined;
85
+ if (hasBaseUrl) {
86
+ result.baseUrl = engine.baseUrl;
87
+ }
88
+ const hasApiKey = engine.apiKey !== undefined;
89
+ if (hasApiKey) {
90
+ result.apiKey = engine.apiKey;
91
+ }
92
+ return result as AiEngineConfigWire;
93
+ }
68
94
  const result: Record<string, unknown> = {
69
95
  kind: 'scripted',
70
96
  };
@@ -123,12 +149,16 @@ export function resolveViteAiConfig(
123
149
  }
124
150
 
125
151
  let engineWire: AiEngineConfigWire | undefined = undefined;
126
- if (!isProductionMode) {
127
- if (explicitEngine !== undefined) {
128
- engineWire = engineConfigToWire(explicitEngine);
129
- } else if (model !== undefined) {
130
- engineWire = engineConfigToWire({ kind: 'openai', baseUrl: AI_PROXY_PATH, model });
131
- }
152
+ if (isProductionMode) {
153
+ const apiKey = env.GEMINI_API_KEY ?? env.GOOGLE_GENAI_API_KEY ?? env.VITE_GEMINI_API_KEY;
154
+ engineWire = {
155
+ kind: 'gemini',
156
+ ...(apiKey !== undefined && apiKey.trim() !== '' ? { apiKey: apiKey.trim() } : {}),
157
+ };
158
+ } else if (explicitEngine !== undefined) {
159
+ engineWire = engineConfigToWire(explicitEngine);
160
+ } else if (model !== undefined) {
161
+ engineWire = engineConfigToWire({ kind: 'openai', baseUrl: AI_PROXY_PATH, model });
132
162
  }
133
163
 
134
164
  let proxyUpstream: string | undefined = undefined;
@@ -86,20 +86,6 @@ export function createViteModuleSwap(
86
86
 
87
87
  const match = FIREBASE_SPECIFIER.exec(args.path);
88
88
  const subpath = match !== null && match[1] !== undefined ? match[1] : '';
89
- const isProductionAiMode = aiMode() === 'production';
90
- if (isProductionAiMode) {
91
- const isAiSubpath = subpath === 'ai';
92
- if (isAiSubpath) {
93
- return null;
94
- }
95
- const isAppSubpath = subpath === 'app';
96
- const passthroughEntry = entries['app-ai-passthrough'];
97
- const hasPassthroughEntry = passthroughEntry !== undefined;
98
- const shouldUsePassthroughBridge = isAppSubpath && hasPassthroughEntry;
99
- if (shouldUsePassthroughBridge) {
100
- return { path: passthroughEntry };
101
- }
102
- }
103
89
 
104
90
  const isServedSubpath = SERVED_FIREBASE_SUBPATHS.has(subpath);
105
91
  if (isServedSubpath) {
@@ -173,20 +159,6 @@ export function createViteModuleSwap(
173
159
  const isFirebaseSpecifier = firebaseMatch !== null;
174
160
  if (isFirebaseSpecifier) {
175
161
  const subpath = firebaseMatch[1] !== undefined ? firebaseMatch[1] : '';
176
- const isProductionAiMode = aiMode() === 'production';
177
- if (isProductionAiMode) {
178
- const isAiSubpath = subpath === 'ai';
179
- if (isAiSubpath) {
180
- return null;
181
- }
182
- const isAppSubpath = subpath === 'app';
183
- const passthroughEntry = entries['app-ai-passthrough'];
184
- const hasPassthroughEntry = passthroughEntry !== undefined;
185
- const shouldUsePassthroughBridge = isAppSubpath && hasPassthroughEntry;
186
- if (shouldUsePassthroughBridge) {
187
- return passthroughEntry;
188
- }
189
- }
190
162
  const isServedSubpath = SERVED_FIREBASE_SUBPATHS.has(subpath);
191
163
  if (isServedSubpath) {
192
164
  const key = entryKey(subpath);
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import type { ViteDevServer } from 'vite';
3
3
  import { readFirebaseJson, readFirebaseRc, type FirebaseJson } from '../cli/firebase-json.js';
4
- import { registerModuleUrl } from '../cli/dev-runner.js';
4
+ import { registerModuleUrl } from '../cli/sandbox-runner.js';
5
5
  import {
6
6
  discoverFunctionsRtdbProject,
7
7
  type FunctionsRtdbProject,
@@ -15,7 +15,7 @@ function deleteTimeoutError(): Error & { code: string } {
15
15
  return Object.assign(
16
16
  new Error(
17
17
  'Timed out waiting for SharedWorker app cleanup acknowledgment. ' +
18
- 'Close all tabs using this pyric dev origin so the worker can restart.',
18
+ 'Close all tabs using this pyric sandbox origin so the worker can restart.',
19
19
  ),
20
20
  { code: 'app/delete-timeout' },
21
21
  );
@@ -25,9 +25,29 @@ import type { ClientDb, Unsubscribe } from './handles.js';
25
25
  export type { PresenceClientKind, PresenceSnapshot, PresenceVisibility };
26
26
  export { PRESENCE_HEARTBEAT_INTERVAL_MS, PRESENCE_STALE_MS };
27
27
 
28
+ function supportsRandomUUID(): boolean {
29
+ return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function';
30
+ }
31
+
32
+ function supportsDocumentEventListeners(): boolean {
33
+ return (
34
+ typeof document !== 'undefined' &&
35
+ typeof document.addEventListener === 'function' &&
36
+ typeof document.removeEventListener === 'function'
37
+ );
38
+ }
39
+
40
+ function supportsWindowEventListeners(): boolean {
41
+ return (
42
+ typeof window !== 'undefined' &&
43
+ typeof window.addEventListener === 'function' &&
44
+ typeof window.removeEventListener === 'function'
45
+ );
46
+ }
47
+
28
48
  /** Mint a random client id (page-lifetime). */
29
49
  export function mintPresenceClientId(): string {
30
- if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
50
+ if (supportsRandomUUID()) {
31
51
  return crypto.randomUUID();
32
52
  }
33
53
  return `page-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
@@ -114,10 +134,10 @@ export function startPresence(opts: StartPresenceOptions): PresenceSession {
114
134
 
115
135
  register();
116
136
 
117
- if (typeof document !== 'undefined') {
137
+ if (supportsDocumentEventListeners()) {
118
138
  document.addEventListener('visibilitychange', update);
119
139
  }
120
- if (typeof window !== 'undefined') {
140
+ if (supportsWindowEventListeners()) {
121
141
  window.addEventListener('popstate', update);
122
142
  window.addEventListener('hashchange', update);
123
143
  // Best-effort clean disconnect; lease expiry covers unclean shutdown.
@@ -139,10 +159,10 @@ export function startPresence(opts: StartPresenceOptions): PresenceSession {
139
159
  clearInterval(timer);
140
160
  timer = null;
141
161
  }
142
- if (typeof document !== 'undefined') {
162
+ if (supportsDocumentEventListeners()) {
143
163
  document.removeEventListener('visibilitychange', update);
144
164
  }
145
- if (typeof window !== 'undefined') {
165
+ if (supportsWindowEventListeners()) {
146
166
  window.removeEventListener('popstate', update);
147
167
  window.removeEventListener('hashchange', update);
148
168
  window.removeEventListener('pagehide', onPageHide);
@@ -57,6 +57,21 @@ function resolveEngineConfig(wire: AiEngineConfigWire): NonNullable<AIOptions['e
57
57
  ...(wire.modelMap !== undefined ? { modelMap: wire.modelMap } : {}),
58
58
  };
59
59
  }
60
+ const isGeminiWire = wire.kind === 'gemini';
61
+ if (isGeminiWire) {
62
+ const result: Record<string, unknown> = {
63
+ kind: 'gemini',
64
+ };
65
+ const hasBaseUrl = wire.baseUrl !== undefined;
66
+ if (hasBaseUrl) {
67
+ result.baseUrl = wire.baseUrl;
68
+ }
69
+ const hasApiKey = wire.apiKey !== undefined;
70
+ if (hasApiKey) {
71
+ result.apiKey = wire.apiKey;
72
+ }
73
+ return result as unknown as NonNullable<AIOptions['engine']>;
74
+ }
60
75
  return {
61
76
  kind: 'scripted',
62
77
  ...(wire.script !== undefined
@@ -203,7 +203,8 @@ export type AiEngineConfigWire =
203
203
  model?: string;
204
204
  /** Explicit Gemini-model-id → upstream-model mapping. */
205
205
  modelMap?: Record<string, string>;
206
- };
206
+ }
207
+ | { kind: 'gemini'; baseUrl?: string; apiKey?: string };
207
208
 
208
209
  /**
209
210
  * Wire form of the Gemini error envelope an `AiBrokerError` carries
@@ -221,8 +221,8 @@ export function applyServeInit(
221
221
  };
222
222
  }
223
223
  }
224
+ const rtdb = ctx.rtdb ??= getDatabase(ctx.sandbox);
224
225
  if (payload.databaseRules) {
225
- const rtdb = ctx.rtdb ??= getDatabase(ctx.sandbox);
226
226
  rtdbSandbox.setRules(rtdb, payload.databaseRules);
227
227
  ctx.activeRules ??= {};
228
228
  ctx.activeRules.database = {
@@ -231,6 +231,10 @@ export function applyServeInit(
231
231
  status: 'active',
232
232
  messages: [],
233
233
  };
234
+ } else if (payload.permissive) {
235
+ rtdbSandbox.setDefaultPolicy(rtdb, 'allow');
236
+ } else {
237
+ rtdbSandbox.setDefaultPolicy(rtdb, 'deny');
234
238
  }
235
239
 
236
240
  // 1b. Storage rules — deployed ONCE, here, before any storage op can run.
package/README.md.orig DELETED
@@ -1,145 +0,0 @@
1
- # `@pyric/cli`
2
-
3
- The Pyric CLI and programmatic helpers for local sandbox development,
4
- verification, artifact generation, and agent bridges.
5
-
6
- > **Alpha.** This package is an early alpha. Non-mirrored exports (e.g.
7
- > `@pyric/cli/serve/worker`, `@pyric/cli/verify`, `@pyric/cli/credentials/node`)
8
- > are experimental public-alpha surfaces that may change without notice. The
9
- > MCP tool surface (tool names and shapes) will consolidate during early
10
- > alpha — do not treat tool names as stable.
11
-
12
- Production project administration (deploy, Identity Toolkit configuration,
13
- hosted discovery) is **not** part of this package. Use
14
- [`firebase-tools`](https://firebase.google.com/docs/cli) or the Firebase
15
- Console to ship rules, indexes, hosting, and functions to a real project.
16
-
17
- ## CLI subcommands
18
-
19
- | Command | What it does |
20
- |---|---|
21
- | `pyric init [dir]` | Scaffold a pyric project — never prompts, idempotent, safe to rerun. `--template web` (default) creates a Vite app with canonical `firebase/*` imports; `--template static` creates a no-bundler app; `--template node` creates a script-style project. Run any template through `pyric dev` for sandbox resolution; inactive production tooling loads Firebase directly. Also `--name`, `--force` (overwrite scaffold-owned files), and `--json` (machine result on stdout). |
22
- | `pyric bridge` | Stand up an HTTP+WebSocket bridge an MCP client (Claude Code, Cursor) connects to (sandbox mode only) |
23
- | `pyric dev` | Local dev server with the pyric sandbox standing in for Firebase: serves `hosting.public`, resolves unmodified `firebase/*` imports to a pyric sandbox via a served import map, deploys + hot-reloads `firestore.rules` (SSE), opens an emulator-style sign-in helper for `signInWithPopup`/`signInWithRedirect`. The sandbox runs in a **SharedWorker by default** — one backend shared by every tab of the origin (live cross-tab sync), kept in the browser's IndexedDB so **your sandbox data — Firestore docs, auth users, RTDB, storage objects, and the traffic history — survives a refresh/restart by default** (see the persistence guide's coverage matrix for the exact tiers); a per-tab in-page sandbox is the fallback when SharedWorker is unavailable. Flags + exit codes: [CLI reference](docs/reference/cli.md#pyric-dev); persistence, ephemeral runs, clearing data, and SharedWorker tips: [persistence & multi-tab](docs/how-to/serve-persistence-and-multi-tab.md) |
24
- | `pyric snapshot` | Promote lived sandbox state (live `dev --persist`, else `.pyric/state/state.json`) to a committable fixture; `pyric dev --seed <fixture>` re-serves it (docs + users). `--out`, `--port`, `--force`, `--json` |
25
- | `pyric verify` | Replay a captured sandbox session against candidate rules (`--engine sandbox\|rules-test-api\|both`). Hosted Rules Test API needs SA/ADC via `FIREBASE_SA_BASE64` / `GOOGLE_APPLICATION_CREDENTIALS` |
26
- | `pyric can-i-use <feature>` | Query the canonical conformance model for availability, behaviour fidelity, assurance eligibility, caveats, and evidence. Only an exact canonical feature name exits 0; ambiguous names, spelling suggestions, and missing features exit 1. Accepts `--json`. |
27
- | `pyric mcp` | Start the stdio MCP server; attach to `pyric dev --bridge` when available or host a headless sandbox |
28
- | `pyric firestore rules lint <path>` | Lint a Firestore rules file |
29
- | `pyric firestore rules validate <path>` | Validate Firestore rules structure |
30
- | `pyric firestore rules simulate` | Run the local Firestore rules simulator |
31
- | `pyric firestore rules resolve <path>` | Resolve `2+modules` imports into a Firebase rules artifact |
32
- | `pyric firestore indexes generate <path...>` | Derive composite-index definitions from application source |
33
- | `pyric storage rules lint <path>` / `simulate` | Run local Storage rules lint or simulation |
34
- | `pyric storage rules resolve <path> --out storage.rules` | Resolve `storage.modules.rules` into a deployable Storage rules artifact |
35
- | `pyric database rules lint <path>` | Lint a Realtime Database rules JSON file |
36
- | `pyric database rules validate <path>` | Validate Realtime Database rules expressions |
37
- | `pyric database rules simulate` | Run the local Realtime Database rules simulator |
38
- | `pyric database rules generate` | Compile a constraints module to local `database.rules.json` without contacting production |
39
-
40
- Every command's full flags, defaults, exit codes, and environment variables are
41
- in the **[CLI reference](docs/reference/cli.md)**. Task guides and the rest of
42
- the docs are indexed in **[docs/](docs/README.md)**.
43
-
44
- ### Persistence caveats (documented limits)
45
-
46
- - **Anonymous users don't persist** (no round-trip key) — but their *documents
47
- do*. An app that calls `signInAnonymously` on load mints a new uid every
48
- reload under `--persist`, so docs owned by prior anonymous uids accumulate
49
- unreachably. Use the sign-in helper (or seeded users) for owner-based data
50
- you want durable.
51
- - **The state file is not a point-in-time snapshot** — firestore and auth
52
- sections flush on independent debounces; a crash between them can persist
53
- docs whose owner user hasn't flushed yet (or vice versa).
54
- - **One writer tab at a time (in-page fallback only)** — when several per-tab
55
- in-page sandboxes share one `.pyric/state` file, the first tab to flush holds
56
- the writer lock; others run read-only (console warning + `persistReadOnly`
57
- diagnostic) so they can't erase the writer's data. On the default SharedWorker
58
- path this can't happen — the single worker is the sole writer.
59
- - **Loss window** — the final unsaved change can be lost if the tab CLOSES
60
- within the flush debounce while the state exceeds ~60KB (keepalive cap);
61
- smaller states flush on unload, and reloads are always safe. A reset (or
62
- any delete-all) that empties a non-empty state first preserves the prior
63
- file at `.pyric/state/state.json.bak`.
64
-
65
- ### Agent onboarding (init → dev → MCP)
66
-
67
- Three parseable steps, no flags to discover:
68
-
69
- ```bash
70
- pyric init myapp --json # → {..., "nextSteps": [...]}
71
- cd myapp && bun install
72
- bun run dev:agent # pyric dev --bridge --seed seed.json
73
- ```
74
-
75
- Readiness probe: `GET <url>/__pyric/init.json` → 200 once serving (body
76
- carries the live rules hash). MCP endpoint: `<url>/__pyric/mcp`. With
77
- `pyric dev --json`, stdout's single line carries `{url, port, mcpUrl,
78
- rulesHash}`.
79
-
80
- ## Programmatic subpaths
81
-
82
- | Subpath | Surface |
83
- |---|---|
84
- | `@pyric/cli/credentials/node` | `fromServiceAccount`, `fromAdc` — build a `ProjectScope` for the Rules Test API (`pyric verify --engine rules-test-api\|both`) |
85
- | `@pyric/cli/verify` | Captured-session replay for Firestore and RTDB rules |
86
- | `@pyric/cli/conformance` | Node query surface: `canIUse` returns full claims and evidence; `canIUseImport` resolves a published import to its canonical compatibility page. |
87
- | `@pyric/cli/conformance/browser` | Compact browser query surface: `canIUse` returns availability, fidelity, assurance, summary, caveats, and the evidence slug without the full claim graph. |
88
- | `@pyric/cli/assurance` | Assurance campaign types and tools |
89
- | `@pyric/cli/assurance/browser` | Browser attachment for assurance campaigns |
90
- | `@pyric/cli/bridge` | `createBridge`, `startServer` (Node) / `connectBridge` (browser via conditional export). Vite integration is `pyric({ bridge })` in `@pyric/cli/vite`. |
91
- | `@pyric/cli/bridge/client` | Browser bridge client helpers |
92
- | `@pyric/cli/vite` | `pyric(opts)`, the dev-only firebase→sandbox swap plugin. Opts: `rules`, `persist`/`fresh`, `seed`, `capture`, `bridge` (MCP), `ui` (Pyric Studio at `/__pyric/ui/`, parity with `dev --ui`). |
93
- | `@pyric/cli/discover` | Credential-free crawl helpers for sandbox discovery (`crawl`, `findCollectionGroup`, `createFirestoreDiscoverTools`). Not registered on the default MCP bridge. |
94
- | `@pyric/cli/serve/worker` | SharedWorker serve runtime |
95
- | `@pyric/cli/remote` | Remote / headless helpers |
96
- | `@pyric/cli/register` | Registration helpers |
97
-
98
- ## MCP tool surface (`pyric bridge`)
99
-
100
- The bridge composes its toolsets from the same factories used by its browser
101
- dispatcher so advertised and executable tools cannot drift. The canonical,
102
- always-current list is the
103
- [agent tool inventory](../../docs/agent-tools.md).
104
-
105
- **Sandbox-routed** — dispatched against the connected browser sandbox
106
- (`createFirestoreDataTools` + `createFirestoreSimulatorTools` +
107
- `createFirestoreInspectTools` + local RTDB inspection):
108
-
109
- - data: `firestore_get_document` / `_list_documents` / `_create_document` / `_add_document` / `_update_document` / `_delete_document` / `_batch_write` / `_query_where` / `firestore_create_with_auto_id`
110
- - stateful simulator session: `firestore_simulator_create` / `_execute` / `_read` / `_batch` / `_undo` / `_redo` / `_events` / `_transaction`
111
- - diagnostics: `sandbox_inspect` — single-call sandbox state/rules snapshot
112
- - RTDB authorization: `rtdb_simulate_access` — evaluates one operation against
113
- the rules and data currently installed in the connected sandbox
114
- - RTDB structure: `rtdb_crawl_structure` — returns a bounded structural view of
115
- current sandbox data without leaf values
116
-
117
- Assurance campaign tools remain available programmatically from
118
- `@pyric/cli/assurance`, but are not registered on the default MCP bridge.
119
-
120
- **In-process** — run on the bridge process itself (`createFirestoreRulesTools`
121
- without a live `ProjectScope`, so no Rules Test API tool):
122
-
123
- - `firestore_simulate_rules`
124
- - `rules_stdlib_list` / `_get` (Firestore or Storage), with
125
- `firestore_rules_stdlib_list` / `_get` retained as compatibility aliases
126
- - `rules_resolve_modules` (Firestore or Storage), with
127
- `firestore_resolve_modules` retained as a compatibility alias
128
- - `firestore_lint_rules`
129
- - `firestore_resolve_modules`
130
-
131
- ### Gaps from the playground tool surface
132
-
133
- The `packages/playground/` app ships richer diagnostic tools that
134
- the `pyric bridge` does NOT register out of the box today. They're
135
- playground-specific orchestrators built on top of `useRuntimeStore`
136
- and other browser-only state:
137
-
138
- - `inspect_firestore_traffic` — structured dump of the sandbox traffic log
139
- - `seed_firestore_data_as_admin` — admin-bypass bulk writes for fixture setup
140
- - `generate_fixture_from_session` — snapshot `sandbox.history()` as a replay fixture
141
- - `try_rules_edit` — replay events under a proposed rules edit
142
- - `debug_firestore_rules` — orchestrator over simulate + lint + history + state
143
-
144
- The underlying primitives (`sandbox.history()`, `pyric/sandbox/replay`, and the
145
- rules simulator) remain available for custom compositions.
@@ -1 +0,0 @@
1
- {"version":3,"file":"dev-runner.d.ts","sourceRoot":"","sources":["../../src/cli/dev-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAM9D;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC,GACL,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAID,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAKhE;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUxD;AAED,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;CAChC,GAAG,YAAY,GAAG,IAAI,CAWtB;AAID;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAQ1C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,CAAC,UAAU,EACvB,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9C,MAAM,CAAC,UAAU,CAOnB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAc9F;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC5B;IAAE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,IAAI,IAAI,CAAA;CAAE,CAkB9C;AAID,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB;0EACsE;IACtE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAClC,KAAK,EAAE,YAAY,CAAC;CACrB;AAKD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC3D,cAAc,CAiEhB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dev-runner.js","sourceRoot":"","sources":["../../src/cli/dev-runner.ts"],"names":[],"mappings":"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"}