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

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 (304) hide show
  1. package/README.md.orig +2 -2
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +16 -0
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +16 -0
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/server/peer.d.ts +1 -1
  7. package/dist/bridge/server.d.ts +1 -1
  8. package/dist/bridge/server.js +1 -1
  9. package/dist/cli/index.d.ts +11 -0
  10. package/dist/cli/index.d.ts.map +1 -1
  11. package/dist/cli/index.js +13 -1
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/init.d.ts +3 -3
  14. package/dist/cli/init.d.ts.map +1 -1
  15. package/dist/cli/init.js +5 -5
  16. package/dist/cli/init.js.map +1 -1
  17. package/dist/cli/serve.d.ts.map +1 -1
  18. package/dist/cli/serve.js +8 -2
  19. package/dist/cli/serve.js.map +1 -1
  20. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  21. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  22. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  23. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  24. package/dist/conformance/.generated/can-i-use.js +1 -1
  25. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  26. package/dist/conformance/.generated/conformance-docs.d.ts +12 -0
  27. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -0
  28. package/dist/conformance/.generated/conformance-docs.js +2 -0
  29. package/dist/conformance/.generated/conformance-docs.js.map +1 -0
  30. package/dist/conformance/docs.d.ts +6 -0
  31. package/dist/conformance/docs.d.ts.map +1 -0
  32. package/dist/conformance/docs.js +6 -0
  33. package/dist/conformance/docs.js.map +1 -0
  34. package/dist/remote/index.d.ts.map +1 -1
  35. package/dist/remote/index.js +1 -0
  36. package/dist/remote/index.js.map +1 -1
  37. package/dist/serve/activity-guard.d.ts +4 -0
  38. package/dist/serve/activity-guard.d.ts.map +1 -0
  39. package/dist/serve/activity-guard.js +22 -0
  40. package/dist/serve/activity-guard.js.map +1 -0
  41. package/dist/serve/activity-route.d.ts +4 -0
  42. package/dist/serve/activity-route.d.ts.map +1 -0
  43. package/dist/serve/activity-route.js +157 -0
  44. package/dist/serve/activity-route.js.map +1 -0
  45. package/dist/serve/activity-warning.d.ts +4 -0
  46. package/dist/serve/activity-warning.d.ts.map +1 -0
  47. package/dist/serve/activity-warning.js +21 -0
  48. package/dist/serve/activity-warning.js.map +1 -0
  49. package/dist/serve/bridge-mount.d.ts +5 -0
  50. package/dist/serve/bridge-mount.d.ts.map +1 -1
  51. package/dist/serve/bridge-mount.js +1 -0
  52. package/dist/serve/bridge-mount.js.map +1 -1
  53. package/dist/serve/docs-ui/404.html +3 -0
  54. package/dist/serve/docs-ui/_astro/{_slug_.DPUwShm2.css → _slug_.CXh9yTP1.css} +1 -1
  55. package/dist/serve/docs-ui/_astro/_slug_.DUci-duz.css +1 -0
  56. package/dist/serve/docs-ui/docs/_rhythm/index.html +2 -1
  57. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +3 -2
  58. package/dist/serve/docs-ui/docs/agent/set-up-your-agent.md +1 -1
  59. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +2 -1
  60. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +2 -1
  61. package/dist/serve/docs-ui/docs/ai-compat/index.html +2 -1
  62. package/dist/serve/docs-ui/docs/api-reference/index.html +51 -49
  63. package/dist/serve/docs-ui/docs/api-reference.md +2 -2
  64. package/dist/serve/docs-ui/docs/app-compat/index.html +2 -1
  65. package/dist/serve/docs-ui/docs/auth-compat/index.html +2 -1
  66. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +18 -3
  67. package/dist/serve/docs-ui/docs/build/ai-logic.md +30 -2
  68. package/dist/serve/docs-ui/docs/build/authentication/index.html +2 -1
  69. package/dist/serve/docs-ui/docs/build/authentication.md +1 -1
  70. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +2 -1
  71. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +46 -2
  72. package/dist/serve/docs-ui/docs/build/cloud-messaging.md +56 -1
  73. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +2 -1
  74. package/dist/serve/docs-ui/docs/build/cloud-storage.md +1 -1
  75. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +21 -3
  76. package/dist/serve/docs-ui/docs/build/realtime-database.md +25 -1
  77. package/dist/serve/docs-ui/docs/conformance-scores/index.html +2 -1
  78. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +61 -28
  79. package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +65 -20
  80. package/dist/serve/docs-ui/docs/database-compat/index.html +2 -1
  81. package/dist/serve/docs-ui/docs/firestore-compat/index.html +6 -5
  82. package/dist/serve/docs-ui/docs/firestore-compat.md +4 -4
  83. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +2 -1
  84. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
  85. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +4 -3
  86. package/dist/serve/docs-ui/docs/get-started/start-building.md +2 -2
  87. package/dist/serve/docs-ui/docs/index.json +800 -575
  88. package/dist/serve/docs-ui/docs/messaging-compat/index.html +2 -1
  89. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +2 -1
  90. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +2 -1
  91. package/dist/serve/docs-ui/docs/overview/index.html +2 -1
  92. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +5 -4
  93. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +3 -4
  94. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +5 -4
  95. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +3 -4
  96. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +5 -4
  97. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +3 -4
  98. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +2503 -12
  99. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +2219 -8
  100. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +4 -3
  101. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +2 -3
  102. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +16 -11
  103. package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +14 -13
  104. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +4 -3
  105. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +2 -3
  106. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +7 -2
  107. package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +5 -2
  108. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +23 -12
  109. package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +15 -12
  110. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +10 -48
  111. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +11 -24
  112. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +87 -97
  113. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +53 -65
  114. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +14 -15
  115. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +19 -28
  116. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +4 -3
  117. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +2 -3
  118. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +3 -2
  119. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api.md +1 -2
  120. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +51 -0
  121. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api.md +36 -0
  122. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +3 -2
  123. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api.md +1 -2
  124. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +3 -2
  125. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +1 -2
  126. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +3 -2
  127. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +1 -2
  128. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +3 -2
  129. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +1 -2
  130. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1067 -83
  131. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +1291 -160
  132. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +123 -92
  133. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +49 -20
  134. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +72 -7
  135. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +22 -7
  136. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +33 -12
  137. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +15 -12
  138. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +18 -17
  139. package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +19 -22
  140. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1512 -545
  141. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +1311 -316
  142. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +3 -2
  143. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +1 -2
  144. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +5 -4
  145. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +3 -4
  146. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +69 -369
  147. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +103 -216
  148. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +10 -9
  149. package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +9 -10
  150. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +8 -7
  151. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +6 -7
  152. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +10 -9
  153. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +9 -10
  154. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +374 -910
  155. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +377 -911
  156. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +25 -17
  157. package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +21 -19
  158. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +3 -2
  159. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +1 -2
  160. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +63 -776
  161. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +69 -510
  162. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +22 -21
  163. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +29 -30
  164. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +15 -168
  165. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +17 -87
  166. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +6 -5
  167. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +5 -6
  168. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +82 -970
  169. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +104 -479
  170. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +30 -29
  171. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +54 -55
  172. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +3 -2
  173. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +1 -2
  174. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +5 -4
  175. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +3 -4
  176. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +9 -124
  177. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +7 -58
  178. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +24 -23
  179. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +31 -34
  180. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +104 -1385
  181. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +133 -817
  182. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +34 -33
  183. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +37 -38
  184. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +116 -1169
  185. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +142 -590
  186. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +4 -3
  187. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +3 -4
  188. package/dist/serve/docs-ui/docs/rules-compat/index.html +34 -1
  189. package/dist/serve/docs-ui/docs/rules-compat.md +32 -0
  190. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +19 -2
  191. package/dist/serve/docs-ui/docs/secure/audit-your-rules.md +32 -0
  192. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +2 -1
  193. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +2 -1
  194. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +2 -1
  195. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript.md +1 -1
  196. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +2 -1
  197. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +2 -1
  198. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +2 -1
  199. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +2 -1
  200. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +2 -1
  201. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +2 -1
  202. package/dist/serve/docs-ui/docs/storage-compat/index.html +2 -1
  203. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +2 -1
  204. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +2 -1
  205. package/dist/serve/docs-ui/llms.txt +1 -0
  206. package/dist/serve/entries/ai.d.ts.map +1 -1
  207. package/dist/serve/entries/ai.js +39 -1
  208. package/dist/serve/entries/ai.js.map +1 -1
  209. package/dist/serve/entries/messaging-sw.d.ts.map +1 -1
  210. package/dist/serve/entries/messaging-sw.js +5 -1
  211. package/dist/serve/entries/messaging-sw.js.map +1 -1
  212. package/dist/serve/entries/messaging.d.ts.map +1 -1
  213. package/dist/serve/entries/messaging.js +7 -1
  214. package/dist/serve/entries/messaging.js.map +1 -1
  215. package/dist/serve/entries/runtime.d.ts.map +1 -1
  216. package/dist/serve/entries/runtime.js +20 -1
  217. package/dist/serve/entries/runtime.js.map +1 -1
  218. package/dist/serve/init-payload.d.ts +25 -0
  219. package/dist/serve/init-payload.d.ts.map +1 -1
  220. package/dist/serve/namespace.d.ts +39 -0
  221. package/dist/serve/namespace.d.ts.map +1 -1
  222. package/dist/serve/namespace.js +80 -1
  223. package/dist/serve/namespace.js.map +1 -1
  224. package/dist/serve/standalone-assets.d.ts +11 -9
  225. package/dist/serve/standalone-assets.d.ts.map +1 -1
  226. package/dist/serve/standalone-assets.js +6 -5
  227. package/dist/serve/standalone-assets.js.map +1 -1
  228. package/dist/serve/studio-ui/assets/{RulesCodeEditor-CXdSLKhO.js → RulesCodeEditor-CxVYcZXw.js} +1 -1
  229. package/dist/serve/studio-ui/assets/index-cpSfgQ7H.js +1218 -0
  230. package/dist/serve/studio-ui/assets/seed-DeuFKi4J.js +20 -0
  231. package/dist/serve/studio-ui/index.html +1 -1
  232. package/dist/serve/vite-plugin.d.ts +92 -15
  233. package/dist/serve/vite-plugin.d.ts.map +1 -1
  234. package/dist/serve/vite-plugin.js +281 -11
  235. package/dist/serve/vite-plugin.js.map +1 -1
  236. package/dist/serve/worker/activity-bootstrap.d.ts +8 -0
  237. package/dist/serve/worker/activity-bootstrap.d.ts.map +1 -0
  238. package/dist/serve/worker/activity-bootstrap.js +11 -0
  239. package/dist/serve/worker/activity-bootstrap.js.map +1 -0
  240. package/dist/serve/worker/client/connection.d.ts.map +1 -1
  241. package/dist/serve/worker/client/connection.js +17 -5
  242. package/dist/serve/worker/client/connection.js.map +1 -1
  243. package/dist/serve/worker/client/core.d.ts +2 -2
  244. package/dist/serve/worker/client/core.d.ts.map +1 -1
  245. package/dist/serve/worker/client/core.js +33 -5
  246. package/dist/serve/worker/client/core.js.map +1 -1
  247. package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -1
  248. package/dist/serve/worker/client/firestore-writes.js +1 -0
  249. package/dist/serve/worker/client/firestore-writes.js.map +1 -1
  250. package/dist/serve/worker/client/messaging.d.ts +9 -1
  251. package/dist/serve/worker/client/messaging.d.ts.map +1 -1
  252. package/dist/serve/worker/client/messaging.js +15 -0
  253. package/dist/serve/worker/client/messaging.js.map +1 -1
  254. package/dist/serve/worker/client/studio.d.ts +10 -0
  255. package/dist/serve/worker/client/studio.d.ts.map +1 -1
  256. package/dist/serve/worker/client/studio.js +11 -0
  257. package/dist/serve/worker/client/studio.js.map +1 -1
  258. package/dist/serve/worker/durable-persistence.d.ts +12 -0
  259. package/dist/serve/worker/durable-persistence.d.ts.map +1 -0
  260. package/dist/serve/worker/durable-persistence.js +118 -0
  261. package/dist/serve/worker/durable-persistence.js.map +1 -0
  262. package/dist/serve/worker/entry.d.ts +7 -3
  263. package/dist/serve/worker/entry.d.ts.map +1 -1
  264. package/dist/serve/worker/entry.js +7 -3
  265. package/dist/serve/worker/entry.js.map +1 -1
  266. package/dist/serve/worker/host/core.d.ts +9 -5
  267. package/dist/serve/worker/host/core.d.ts.map +1 -1
  268. package/dist/serve/worker/host/core.js +33 -8
  269. package/dist/serve/worker/host/core.js.map +1 -1
  270. package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
  271. package/dist/serve/worker/host/dispatch.js +9 -2
  272. package/dist/serve/worker/host/dispatch.js.map +1 -1
  273. package/dist/serve/worker/host/studio.d.ts +1 -1
  274. package/dist/serve/worker/host/studio.d.ts.map +1 -1
  275. package/dist/serve/worker/host/studio.js +36 -1
  276. package/dist/serve/worker/host/studio.js.map +1 -1
  277. package/dist/serve/worker/host/subscriptions.d.ts.map +1 -1
  278. package/dist/serve/worker/host/subscriptions.js +27 -7
  279. package/dist/serve/worker/host/subscriptions.js.map +1 -1
  280. package/dist/serve/worker/host-context.d.ts +15 -0
  281. package/dist/serve/worker/host-context.d.ts.map +1 -1
  282. package/dist/serve/worker/host-context.js +10 -0
  283. package/dist/serve/worker/host-context.js.map +1 -1
  284. package/dist/serve/worker/host-messaging.d.ts.map +1 -1
  285. package/dist/serve/worker/host-messaging.js +9 -2
  286. package/dist/serve/worker/host-messaging.js.map +1 -1
  287. package/dist/serve/worker/index.d.ts +1 -1
  288. package/dist/serve/worker/index.d.ts.map +1 -1
  289. package/dist/serve/worker/index.js +2 -0
  290. package/dist/serve/worker/index.js.map +1 -1
  291. package/dist/serve/worker/protocol.d.ts +25 -3
  292. package/dist/serve/worker/protocol.d.ts.map +1 -1
  293. package/dist/serve/worker/protocol.js.map +1 -1
  294. package/dist/serve/worker/serve-init.d.ts +23 -37
  295. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  296. package/dist/serve/worker/serve-init.js +95 -172
  297. package/dist/serve/worker/serve-init.js.map +1 -1
  298. package/dist/vite.d.ts +4 -4
  299. package/dist/vite.d.ts.map +1 -1
  300. package/dist/vite.js +3 -3
  301. package/dist/vite.js.map +1 -1
  302. package/package.json +8 -4
  303. package/dist/serve/studio-ui/assets/index-BvtQIpGn.js +0 -1211
  304. package/dist/serve/studio-ui/assets/seed-3DMedLL3.js +0 -2
@@ -0,0 +1,20 @@
1
+ import{s as f,a as o,b as d,d as s,G as h,c as n,e as w,f as A,u as m,r as p,T as g}from"./index-cpSfgQ7H.js";async function y(a){n.createUser(a,{uid:"alice",email:"alice@gmail.com",displayName:"Alice Nguyen",emailVerified:!0,photoUrl:"https://lh3.googleusercontent.com/a/alice",providerUserInfo:[{providerId:"google.com"}],customClaims:{plan:"pro"}}),n.createUser(a,{uid:"bob",email:"bob@example.com",password:"pyric-demo",displayName:"Bob Carter",emailVerified:!0,customClaims:{role:"editor"}}),n.createUser(a,{uid:"carol",email:"carol@example.com",displayName:"Carol Diaz",emailVerified:!1}),await w(a),await A(a)}const b=new h(37.7749,-122.4194);async function C(a){const r=Date.now(),i=e=>g.fromMillis(r-e*6e4),l=[{id:"alice",name:"Alice Nguyen",email:"alice@gmail.com",plan:"pro"},{id:"bob",name:"Bob Carter",email:"bob@example.com",plan:"free"},{id:"carol",name:"Carol Diaz",email:"carol@example.com",plan:"free"}];for(const e of l)await o(s(a,"users",e.id),{name:e.name,email:e.email,plan:e.plan,createdAt:d()});const t=["alice","bob","carol"],c=["Ship the redesign","Reply to carol","Buy milk","Draft the launch post","Review the rules","Plan offsite","Renew the domain","Read the spec","Fix the flaky test","Call the bank","Water the plants","Book the flights"];for(let e=0;e<c.length;e++){const u=t[e%t.length];await o(s(a,"notes",`note-${String(e+1).padStart(2,"0")}`),{title:c[e],done:e%3===0,pinned:e===0,priority:e%3+1,ownerId:u,ownerRef:`users/${u}`,tags:e%2===0?["work","urgent"]:["personal"],meta:{source:e%2===0?"app":"import",revision:e+1,flags:{starred:e%4===0,archived:!1}},location:e%3===0?b:null,createdAt:i(120-e*7),updatedAt:d()})}await o(s(a,"posts","post-hello"),{title:"Hello world",body:"First post from the seeded sandbox.",authorRef:"users/alice",published:!0,publishedAt:i(8)}),await o(s(a,"posts","post-draft"),{title:"Draft: roadmap",body:"Unpublished draft.",authorRef:"users/bob",published:!1})}async function R(a){const r=new TextEncoder,l=Uint8Array.from(atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="),t=>t.charCodeAt(0));await m(p(a,"avatars/alice.png"),l,{contentType:"image/png"}),await m(p(a,"notes/note-01/attachment.txt"),r.encode(`Attachment for the redesign note.
2
+ `),{contentType:"text/plain"})}const x=`rules_version = '2';
3
+ service cloud.firestore {
4
+ match /databases/{database}/documents {
5
+ match /users/{userId} {
6
+ allow read: if request.auth != null;
7
+ allow write: if request.auth != null && request.auth.uid == userId;
8
+ }
9
+ match /notes/{noteId} {
10
+ allow read: if request.auth != null;
11
+ allow create: if request.auth != null && request.resource.data.ownerId == request.auth.uid;
12
+ allow update, delete: if request.auth != null && resource.data.ownerId == request.auth.uid;
13
+ }
14
+ match /posts/{postId} {
15
+ allow read: if true;
16
+ allow write: if request.auth != null;
17
+ }
18
+ }
19
+ }
20
+ `;function U(a){f(a,x)}async function q(a){await C(a.adminFirestore),await y(a.auth),await R(a.storage)}export{q as applySeed,U as deploySeedRules,y as seedAuth};
@@ -23,7 +23,7 @@
23
23
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
24
24
  rel="stylesheet"
25
25
  />
26
- <script type="module" crossorigin src="/__pyric/ui/assets/index-BvtQIpGn.js"></script>
26
+ <script type="module" crossorigin src="/__pyric/ui/assets/index-cpSfgQ7H.js"></script>
27
27
  <link rel="stylesheet" crossorigin href="/__pyric/ui/assets/index-BlSGru_r.css">
28
28
  </head>
29
29
  <body>
@@ -1,5 +1,25 @@
1
1
  import type { Plugin } from 'vite';
2
- export interface PyricSandboxOptions {
2
+ import type { AiEngineConfigWire } from './worker/protocol.js';
3
+ import type { AIOptions } from 'pyric/ai';
4
+ /**
5
+ * The plugin-level engine config surface = `pyric/ai`'s `EngineConfig` (what an
6
+ * app passes to `getAI`), minus the custom `AnswerEngine` object variant — a
7
+ * live object cannot cross to the SharedWorker host or serialize into the page,
8
+ * so the plugin's declarative surface is the JSON-able `scripted` / `openai`
9
+ * configs only (the same restriction the worker path already enforces).
10
+ */
11
+ export type PyricAiEngineConfig = Extract<NonNullable<AIOptions['engine']>, {
12
+ kind: string;
13
+ }>;
14
+ /**
15
+ * Node-side `EngineConfig` → JSON-safe {@link AiEngineConfigWire}. Mirrors the
16
+ * browser `toEngineWire` (entries/ai.ts): an openai config with no `baseUrl`
17
+ * targets the same-origin proxy; scripted `script` entries pass through (plain
18
+ * authoring shapes — function/RegExp matchers can't survive JSON and are not a
19
+ * plugin-config use case).
20
+ */
21
+ export declare function engineConfigToWire(engine: PyricAiEngineConfig): AiEngineConfigWire;
22
+ export interface PyricOptions {
3
23
  /** firestore.rules path (relative to `root`). Default: `firebase.json`'s
4
24
  * `firestore.rules`, else `firestore.rules` in the project root. */
5
25
  rules?: string;
@@ -21,10 +41,10 @@ export interface PyricSandboxOptions {
21
41
  * + `GET /__pyric/health` + `WS /__pyric/sandbox`, all on Vite's port.
22
42
  * `true` is shorthand for `{}`. The agent and the page share ONE sandbox.
23
43
  *
24
- * **Forces the in-page sandbox (single-tab).** The bridge peer is the
25
- * in-page sandbox, never the SharedWorker, so enabling `bridge` disables the
26
- * default multi-tab SharedWorker path otherwise the agent would drive an
27
- * empty in-page sandbox while the app's data lived in the worker. */
44
+ * Does NOT change the sandbox topology: on the default SharedWorker path the
45
+ * page dials the bridge WS and relays agent tool-calls THROUGH the worker
46
+ * (`connectBridgePeer`), so multi-tab stays on. The in-page fallback engages
47
+ * only when the worker bundle itself fails, bridge or not. */
28
48
  bridge?: boolean | {
29
49
  project?: string;
30
50
  disableAuditLog?: boolean;
@@ -32,26 +52,83 @@ export interface PyricSandboxOptions {
32
52
  /** Serve the **Pyric Studio** app at `/__pyric/ui/` on Vite's dev origin (the
33
53
  * `pyric dev --ui` equivalent). Mounts the disk-backed workspace/project
34
54
  * routes Studio's `local` mode talks to AND serves the built Studio assets
35
- * (vendored in this package at `dist/serve/studio-ui`). **On by default**;
36
- * pass `ui: false` to disable.
37
- *
38
- * Not compatible with `bridge`: bridge forces the app in-page, but Studio's
39
- * live plane reads the SharedWorker, so Studio would observe nothing. Under
40
- * `bridge` ui therefore defaults OFF (an explicit `ui: true` still works but
41
- * warns). Use `ui` without `bridge`, or `pyric dev --ui`. */
55
+ * (vendored in this package at `dist/serve/studio-ui`). **On by default**,
56
+ * including under `bridge` (the bridge peer routes through the SharedWorker,
57
+ * so app, Studio, and agent all observe the one sandbox); pass `ui: false`
58
+ * to disable. */
42
59
  ui?: boolean;
60
+ /** RTDB-triggered Cloud Functions under this dev server (the `pyric dev`
61
+ * parity fold). By default a `functions` block in `firebase.json` is
62
+ * discovered automatically: its `onValueCreated` triggers run in an isolated
63
+ * node child against the shared sandbox (other trigger kinds warn and are
64
+ * skipped), and the discovered codebase turns the MCP bridge mount on (the
65
+ * child dials the sandbox over the bridge WS — the page's sandbox topology
66
+ * is unchanged, see `bridge`). `functions: false` is the off switch: no
67
+ * discovery, no child, no functions-forced bridge mount.
68
+ *
69
+ * Field precedence: explicit option > env var > firebase files > default.
70
+ * - `region`: the trigger location. Beats `PYRIC_FUNCTIONS_RTDB_REGION`;
71
+ * default `us-central1`.
72
+ * - `instance`: the RTDB instance name. Default `<projectId>-default-rtdb`,
73
+ * where projectId is `PYRIC_PROJECT`, else `.firebaserc`'s default
74
+ * project, else `demo-project`.
75
+ * - `watch`: hot-reload the functions source (default `true`, matching
76
+ * rules). A save under the functions source dir stops the child and
77
+ * respawns it — redeploy semantics: in-flight executions in the old child
78
+ * may drop, and writes landing during the swap gap are consumed as the new
79
+ * child's baseline (they do not fire). Unlike rules, a broken save cannot
80
+ * keep last-good live — the old child is already gone — so functions stay
81
+ * down until the next good save. */
82
+ functions?: false | {
83
+ region?: string;
84
+ instance?: string;
85
+ watch?: boolean;
86
+ };
43
87
  /** Force whether `vite build` runs the firebase→pyric swap, overriding the
44
88
  * mode default. Unset (default): swap for any NON-production mode, keep real
45
89
  * firebase for mode `production`. `true` = always produce a sandbox build;
46
90
  * `false` = never swap in build (real firebase regardless of mode). `vite
47
91
  * dev` is unaffected — the swap is always on there. */
48
92
  swapInBuild?: boolean;
93
+ /**
94
+ * Dev-server-level AI configuration for `pyric/ai` (the sanctioned
95
+ * replacement for threading `engine` through every app `getAI(...)` call,
96
+ * which is first-call-wins and easy to get wrong).
97
+ *
98
+ * pyric({
99
+ * ai: {
100
+ * engine: { kind: 'openai', model: 'llama3.2', baseUrl: '/__pyric/ai-proxy' },
101
+ * proxyUpstream: 'http://localhost:11434/v1', // your Ollama
102
+ * },
103
+ * })
104
+ *
105
+ * - `engine` is `pyric/ai`'s `EngineConfig` (scripted | openai), applied on
106
+ * both the SharedWorker and in-page paths. An openai `baseUrl` of
107
+ * `/__pyric/ai-proxy` (or omitted) routes through the same-origin proxy so a
108
+ * localhost upstream needs zero CORS setup.
109
+ * - `proxyUpstream` sets what `/__pyric/ai-proxy` forwards to (beats the
110
+ * `PYRIC_AI_PROXY_UPSTREAM` env var; default `http://localhost:11434/v1`).
111
+ *
112
+ * Precedence: a plugin-level `engine`, when set, always wins over an engine an
113
+ * app's own `getAI()` passes (host-side via `ctx.aiEngine` on the worker path,
114
+ * page-side via an injected global on the in-page fallback); with no plugin
115
+ * engine the first `getAI()` call's engine is honored (first-call-wins), and
116
+ * with neither the zero-config scripted default applies.
117
+ */
118
+ ai?: {
119
+ /** Engine config (scripted | openai). Custom `AnswerEngine` objects are not
120
+ * supported at the plugin level — they can't cross to the worker/page. */
121
+ engine?: PyricAiEngineConfig;
122
+ /** OpenAI-compatible upstream `/__pyric/ai-proxy` forwards to. Beats
123
+ * `PYRIC_AI_PROXY_UPSTREAM`; default `http://localhost:11434/v1`. */
124
+ proxyUpstream?: string;
125
+ };
49
126
  }
50
127
  /**
51
128
  * The dev-only Vite plugin. Add to `vite.config`:
52
129
  *
53
- * import { pyricSandbox } from '@pyric/cli/vite';
54
- * export default defineConfig({ plugins: [pyricSandbox()] });
130
+ * import { pyric } from '@pyric/cli/vite';
131
+ * export default defineConfig({ plugins: [pyric()] });
55
132
  */
56
- export declare function pyricSandbox(options?: PyricSandboxOptions): Plugin;
133
+ export declare function pyric(options?: PyricOptions): Plugin;
57
134
  //# sourceMappingURL=vite-plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../../src/serve/vite-plugin.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,MAAM,EAAyB,MAAM,MAAM,CAAC;AA0D1D,MAAM,WAAW,mBAAmB;IAClC;yEACqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;gEAC4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;iFAC6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;0EAQsE;IACtE,MAAM,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnE;;;;;;;;;kEAS8D;IAC9D,EAAE,CAAC,EAAE,OAAO,CAAC;IACb;;;;4DAIwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA6kBtE"}
1
+ {"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../../src/serve/vite-plugin.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,MAAM,EAAyB,MAAM,MAAM,CAAC;AAkB1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiD1C;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9F;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,kBAAkB,CAelF;AAeD,MAAM,WAAW,YAAY;IAC3B;yEACqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;gEAC4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;qEACiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;iFAC6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;mEAQ+D;IAC/D,MAAM,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnE;;;;;;sBAMkB;IAClB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb;;;;;;;;;;;;;;;;;;;;;2CAqBuC;IACvC,SAAS,CAAC,EAAE,KAAK,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5E;;;;4DAIwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,EAAE,CAAC,EAAE;QACH;mFAC2E;QAC3E,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B;8EACsE;QACtE,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,MAAM,CAo0BxD"}
@@ -14,7 +14,7 @@
14
14
  * mode) produces a SANDBOX build that bundles pyric's in-page adapters instead
15
15
  * of the real SDK: self-contained, meant to be previewed under `pyric dev`, and
16
16
  * stamped with the sandbox-build marker so it can never be deployed (`pyric
17
- * deploy hosting` refuses it). `pyricSandbox({ swapInBuild })` forces the build
17
+ * deploy hosting` refuses it). `pyric({ swapInBuild })` forces the build
18
18
  * behavior on/off regardless of mode. See `sandbox-marker.ts`.
19
19
  *
20
20
  * This is a thin adapter over serve's proven machinery. It REUSES, not reimplements:
@@ -30,8 +30,9 @@
30
30
  * Scope = M1 (swap + rules) + M2 (SharedWorker multi-tab + persist/capture/seed)
31
31
  * + M3 (the MCP bridge fold — `{ bridge }`). M3 reuses `createBridgeMount` (the
32
32
  * proven serve-flavored bridge behind `pyric dev --bridge`), composing it into
33
- * the same `/__pyric` middleware; bridge mode forces the in-page sandbox path so
34
- * the agent and the app share one backend.
33
+ * the same `/__pyric` middleware; on the worker path the bridge peer routes
34
+ * agent tool-calls THROUGH the SharedWorker (`connectBridgePeer`), so the agent
35
+ * and the app share one backend without forcing the page in-page.
35
36
  *
36
37
  * Serving `worker.js` flips `runtime.ts` to the worker path (one backend across
37
38
  * tabs, IndexedDB-durable); on that path the WORKER owns persist/capture/seed via
@@ -43,7 +44,8 @@ import { existsSync, readFileSync, rmSync, writeFileSync, mkdirSync } from 'node
43
44
  import { homedir } from 'node:os';
44
45
  import path from 'node:path';
45
46
  import { SDK_MODULES, defaultSdkEntries, resolveStudioUiDir, pyricPackageRoot, bundleWorker, workerSourceHash, NODE_BUILTIN_RE, NODE_BUILTIN_SHIMS, } from './bundler.js';
46
- import { createEventHub, createPyricNamespace } from './namespace.js';
47
+ import { createEventHub, createPyricNamespace, } from './namespace.js';
48
+ import { formatActivityWarning } from './activity-warning.js';
47
49
  import { diskWorkspace, diskProjectStore } from './studio/index.js';
48
50
  import { createBridgeMount } from './bridge-mount.js';
49
51
  import { loadProjectDatabaseRules, loadProjectRules, loadProjectStorageRules, prepareRulesSource, rulesHashOf, } from './rules.js';
@@ -51,7 +53,10 @@ import { createStateStore, STATE_FILE_VERSION } from './state-store.js';
51
53
  import { createCaptureStore } from './capture-store.js';
52
54
  import { isAllowedHost } from './server.js';
53
55
  import { SANDBOX_BUILD_META } from './sandbox-marker.js';
54
- import { readFirebaseJson } from '../cli/firebase-json.js';
56
+ import { readFirebaseJson, readFirebaseRc } from '../cli/firebase-json.js';
57
+ import { discoverFunctionsRtdbProject, } from '../functions-rtdb/project.js';
58
+ import { spawnFunctionsRtdbChild, } from '../functions-rtdb/child.js';
59
+ import { buildChildEnv, createLinePrefixer, registerModuleUrl, } from '../cli/dev-runner.js';
55
60
  /**
56
61
  * Whether a `vite build` should run the firebase→pyric swap (produce a SANDBOX
57
62
  * build). MODE-based with a plugin-config override:
@@ -68,6 +73,31 @@ function swapsInBuild(env, swapInBuild) {
68
73
  }
69
74
  /** Any `firebase/<sub>` specifier. */
70
75
  const FB_ANY = /^firebase\/([a-z-]+(?:\/[a-z-]+)*)$/;
76
+ /** The serve proxy route the browser openai engine defaults to (#98.2). */
77
+ const AI_PROXY_PATH = '/__pyric/ai-proxy';
78
+ /**
79
+ * Node-side `EngineConfig` → JSON-safe {@link AiEngineConfigWire}. Mirrors the
80
+ * browser `toEngineWire` (entries/ai.ts): an openai config with no `baseUrl`
81
+ * targets the same-origin proxy; scripted `script` entries pass through (plain
82
+ * authoring shapes — function/RegExp matchers can't survive JSON and are not a
83
+ * plugin-config use case).
84
+ */
85
+ export function engineConfigToWire(engine) {
86
+ if (engine.kind === 'openai') {
87
+ return {
88
+ kind: 'openai',
89
+ baseUrl: engine.baseUrl ?? AI_PROXY_PATH,
90
+ ...(engine.model !== undefined ? { model: engine.model } : {}),
91
+ ...(engine.modelMap !== undefined ? { modelMap: engine.modelMap } : {}),
92
+ };
93
+ }
94
+ return {
95
+ kind: 'scripted',
96
+ ...(engine.script !== undefined
97
+ ? { script: engine.script }
98
+ : {}),
99
+ };
100
+ }
71
101
  /** The firebase subpaths with swap entries. */
72
102
  const SERVED = new Set(SDK_MODULES.map((specifier) => specifier.slice('firebase/'.length)));
73
103
  const entryKey = (subpath) => subpath.replaceAll('/', '-');
@@ -83,10 +113,10 @@ function packageRootOf(file) {
83
113
  /**
84
114
  * The dev-only Vite plugin. Add to `vite.config`:
85
115
  *
86
- * import { pyricSandbox } from '@pyric/cli/vite';
87
- * export default defineConfig({ plugins: [pyricSandbox()] });
116
+ * import { pyric } from '@pyric/cli/vite';
117
+ * export default defineConfig({ plugins: [pyric()] });
88
118
  */
89
- export function pyricSandbox(options = {}) {
119
+ export function pyric(options = {}) {
90
120
  // Resolved once. `defaultSdkEntries()` prefers compiled dist `.js` and falls
91
121
  // back to source `.ts` in the workspace.
92
122
  const entries = defaultSdkEntries(); // { app, auth, firestore, init } → abs paths
@@ -177,6 +207,11 @@ export function pyricSandbox(options = {}) {
177
207
  // sandbox path — the bridge peer is the in-page sandbox, never the SharedWorker,
178
208
  // so multi-tab is disabled under bridge to keep agent + app on one backend.
179
209
  const bridgeOpts = options.bridge === true ? {} : options.bridge || null;
210
+ // Plugin-level AI engine, normalized once to the JSON-safe wire shape. Travels
211
+ // to the worker host via the init payload (→ ctx.aiEngine) AND to the in-page
212
+ // fallback via an injected synchronous global (see transformIndexHtml). Undefined
213
+ // when the `ai.engine` option is unset.
214
+ const aiEngineWire = options.ai?.engine ? engineConfigToWire(options.ai.engine) : undefined;
180
215
  return {
181
216
  name: 'pyric:sandbox',
182
217
  // Active for `vite dev` ALWAYS, and for `vite build` only when it is a
@@ -352,6 +387,30 @@ export function pyricSandbox(options = {}) {
352
387
  catch (e) {
353
388
  server.config.logger.warn(` ⚠ [pyric] SharedWorker bundle failed — using the in-page sandbox (single-tab, ephemeral): ${e instanceof Error ? e.message : String(e)}`);
354
389
  }
390
+ // ── Functions (RTDB triggers) — the `pyric dev` parity fold ───────────
391
+ // Discover the one supported Functions codebase from the same resolved
392
+ // firebase.json the rules used (project.ts reads it itself). Reuses the
393
+ // exact serve module, so absent `functions` → null (silently off) and a
394
+ // malformed config throws serve's own error text — which, thrown from an
395
+ // async configureServer, fails the dev start the same way serve's
396
+ // `return 2` aborts. The Functions child connects to the sandbox over the
397
+ // bridge WS, so a discovered codebase forces the bridge mount on (mirrors
398
+ // serve's `bridgeEnabledFor(..., functionsProject)`). `functions: false`
399
+ // is the off switch: discovery never runs, so neither does the mount.
400
+ const functionsOpts = typeof options.functions === 'object' ? options.functions : {};
401
+ let functionsProject = null;
402
+ if (options.functions !== false) {
403
+ try {
404
+ functionsProject = discoverFunctionsRtdbProject(cwd);
405
+ }
406
+ catch (error) {
407
+ // Malformed functions config: fail the start with serve's exact message.
408
+ throw error instanceof Error ? error : new Error(String(error));
409
+ }
410
+ }
411
+ const functionsProjectId = functionsProject
412
+ ? (process.env.PYRIC_PROJECT ?? (await readFirebaseRc(cwd))?.projects?.default ?? 'demo-project')
413
+ : null;
355
414
  // ── M3 MCP bridge (mirrors serve.ts:221–274) ─────────────────────────
356
415
  // The mount is long-lived (one bridge per dev session); its MCP transport
357
416
  // is rebuilt per request (stateless). Composed into the /__pyric middleware
@@ -360,9 +419,12 @@ export function pyricSandbox(options = {}) {
360
419
  // Guard the WS upgrade with the SAME allow rule Vite's own host check
361
420
  // uses (host + allowedHosts, where `true` = opted into all hosts). Vite's
362
421
  // upgrade path bypasses connect middleware, so this is the only guard on it.
363
- const mount = bridgeOpts
422
+ const mount = bridgeOpts || functionsProject
364
423
  ? createBridgeMount({
365
- ...bridgeOpts,
424
+ ...(bridgeOpts ?? {}),
425
+ // A functions-only session still needs a labeled bridge; prefer an
426
+ // explicit bridge project, else the resolved functions project id.
427
+ project: bridgeOpts?.project ?? functionsProjectId ?? undefined,
366
428
  upgradeGuard: {
367
429
  boundHost: typeof server.config.server.host === 'string' ? server.config.server.host : 'localhost',
368
430
  allowedHosts: server.config.server.allowedHosts === true
@@ -384,6 +446,9 @@ export function pyricSandbox(options = {}) {
384
446
  databaseUrl: live.databaseUrl,
385
447
  storageRules: live.storageRules,
386
448
  storageRulesHash: live.storageRulesHash,
449
+ // Project identity: scopes the storage IDB name per served project
450
+ // (issue #359). Local-only — a dev path never leaves the machine.
451
+ projectKey: cwd,
387
452
  // The bound port is known only after `listen`; initPayload runs per
388
453
  // request (after listen), so resolve it lazily here. Absolute ws://host:port
389
454
  // mirrors serve (the browser reads this as the bridge peer URL).
@@ -406,6 +471,9 @@ export function pyricSandbox(options = {}) {
406
471
  : seedUsers,
407
472
  // Messaging is part of the canonical firebase/* sandbox swap.
408
473
  messaging: true,
474
+ // Plugin-level engine → the worker host's ctx.aiEngine (host-ai.ts),
475
+ // which wins over any op-carried engine. Null when unset.
476
+ ai: aiEngineWire ? { engine: aiEngineWire } : null,
409
477
  });
410
478
  // Pyric Studio: mount the disk-backed workspace/project routes that
411
479
  // Studio's `local` mode talks to + serve the built Studio app at
@@ -435,10 +503,22 @@ export function pyricSandbox(options = {}) {
435
503
  sdkDir,
436
504
  initPayload,
437
505
  events,
506
+ activity: (incident) => server.config.logger.warn(formatActivityWarning(incident)),
438
507
  state,
439
508
  capture,
440
509
  studio,
441
510
  studioUiDir,
511
+ // `ai.proxyUpstream`: what `/__pyric/ai-proxy` forwards to (beats the
512
+ // PYRIC_AI_PROXY_UPSTREAM env var; falls back to the default when unset).
513
+ aiProxyUpstream: options.ai?.proxyUpstream,
514
+ // Adapt Vite's logger to the plain info/note shape the namespace's
515
+ // diagnostics (denial relay, future hot-reload lines) expect —
516
+ // matches the `↻`/`⚠ [pyric]` lines already logged elsewhere in this
517
+ // plugin via `server.config.logger` directly.
518
+ logger: {
519
+ info: (m) => server.config.logger.info(m),
520
+ note: (m) => server.config.logger.warn(m),
521
+ },
442
522
  });
443
523
  // DNS-rebinding guard for the /__pyric/* surface. Vite has its own host
444
524
  // check, but a `configureServer` hook that doesn't return a function mounts
@@ -565,6 +645,187 @@ export function pyricSandbox(options = {}) {
565
645
  }
566
646
  });
567
647
  }
648
+ // ── Functions child lifecycle (mirrors serve's runServe) ─────────────
649
+ // The Functions runtime executes in an isolated node child (child.ts),
650
+ // exactly as `pyric dev` runs it: the child loads the user's unchanged
651
+ // functions module, and `--import @pyric/cli/register` + `PYRIC_SANDBOX=
652
+ // remote:<serveUrl>` route its `firebase-admin/app` to a RemoteSandbox that
653
+ // dials the bridge WS (`/__pyric/sandbox`). onValueCreated triggers observe
654
+ // RTDB writes and write their effects back through that one shared sandbox.
655
+ // Started once a sandbox peer (a browser tab / SharedWorker relay) has
656
+ // connected — the trigger's baseline needs a live backend — and stopped on
657
+ // server close. Vite restarts re-run configureServer, so the child respawns
658
+ // with the new server. Unlike `pyric dev` (which does not watch functions
659
+ // source), the plugin hot-reloads it via Vite's own watcher — see the
660
+ // watch block below; `functions: { watch: false }` restores dev's
661
+ // restart-to-reload behavior.
662
+ if (functionsProject && functionsProjectId && mount && server.httpServer) {
663
+ const httpServer = server.httpServer;
664
+ const project = functionsProject;
665
+ const projectId = functionsProjectId;
666
+ const bridgeMount = mount;
667
+ const host = (typeof server.config.server.host === 'string' && server.config.server.host) || 'localhost';
668
+ // Prefer the compiled child (node cannot execute the .ts source when the
669
+ // plugin runs from source in tests); fall back to spawnFunctionsRtdbChild's
670
+ // own default (correct when the plugin runs from dist in production).
671
+ const builtChild = path.join(cliRoot, 'dist/functions-rtdb/child.js');
672
+ const childModuleUrl = existsSync(builtChild) ? builtChild : undefined;
673
+ let functionsChild = null;
674
+ let disposed = false;
675
+ const start = async (mode = 'initial') => {
676
+ const addr = httpServer.address();
677
+ const port = addr && typeof addr === 'object' ? addr.port : 0;
678
+ if (!port || disposed)
679
+ return;
680
+ const serveUrl = `http://${host}:${port}`;
681
+ // Wait (bounded) for a sandbox peer — the SharedWorker relay / browser
682
+ // tab that holds the backend. Poll the mount directly (no self-fetch).
683
+ // On a hot reload the peer is usually still connected (the loop exits
684
+ // immediately); when it dropped mid-session, wait briefly rather than
685
+ // the full initial 30s.
686
+ const deadline = Date.now() + (mode === 'reload' ? 5_000 : 30_000);
687
+ while (!disposed && !bridgeMount.sandboxConnected()) {
688
+ if (Date.now() >= deadline)
689
+ break;
690
+ await new Promise((r) => setTimeout(r, 250));
691
+ }
692
+ if (disposed)
693
+ return;
694
+ if (!bridgeMount.sandboxConnected()) {
695
+ server.config.logger.warn(mode === 'reload'
696
+ ? ` ✖ [pyric] functions not restarted — no sandbox peer connected. ` +
697
+ `Functions stay down until the next save with ${serveUrl} open.`
698
+ : ` ⚠ [pyric] functions not started — no browser tab connected after 30s. ` +
699
+ `Open ${serveUrl} and restart the dev server.`);
700
+ return;
701
+ }
702
+ functionsChild = spawnFunctionsRtdbChild({
703
+ cwd: project.sourceDir,
704
+ entry: project.entry,
705
+ env: buildChildEnv(process.env, { serveUrl, registerUrl: registerModuleUrl() }),
706
+ // Precedence (per field): plugin option > env var > firebase files
707
+ // > default. projectId already folds PYRIC_PROJECT > .firebaserc >
708
+ // demo-project.
709
+ instance: functionsOpts.instance ?? `${projectId}-default-rtdb`,
710
+ location: functionsOpts.region ?? process.env.PYRIC_FUNCTIONS_RTDB_REGION ?? 'us-central1',
711
+ ...(childModuleUrl ? { childModuleUrl } : {}),
712
+ onEvent(event) {
713
+ if (event.type === 'execution') {
714
+ const params = Object.entries(event.params)
715
+ .map(([name, value]) => `${name}=${value}`)
716
+ .join(', ');
717
+ const suffix = params ? ` (${params})` : '';
718
+ if (event.status === 'fulfilled') {
719
+ server.config.logger.info(` ✔ [pyric] function ${event.exportName} ← /${event.ref}${suffix}`);
720
+ }
721
+ else {
722
+ server.config.logger.error(` ✖ [pyric] function ${event.exportName} ← /${event.ref}${suffix}: ${event.error.message}`);
723
+ }
724
+ }
725
+ else {
726
+ server.config.logger.error(` ✖ [pyric] functions delivery for ${event.exportName}: ${event.error.message}`);
727
+ }
728
+ },
729
+ });
730
+ const out = createLinePrefixer('[functions] ', (line) => server.config.logger.info(line.replace(/\n$/, '')));
731
+ const err = createLinePrefixer('[functions] ', (line) => server.config.logger.warn(line.replace(/\n$/, '')));
732
+ functionsChild.child.stdout?.setEncoding('utf8');
733
+ functionsChild.child.stderr?.setEncoding('utf8');
734
+ functionsChild.child.stdout?.on('data', (chunk) => out.push(chunk));
735
+ functionsChild.child.stderr?.on('data', (chunk) => err.push(chunk));
736
+ functionsChild.child.stdout?.once('end', () => out.flush());
737
+ functionsChild.child.stderr?.once('end', () => err.flush());
738
+ try {
739
+ const ready = await functionsChild.ready;
740
+ server.config.logger.info(mode === 'reload'
741
+ ? ` ↻ [pyric] functions reloaded (${ready.triggerCount} trigger${ready.triggerCount === 1 ? '' : 's'})`
742
+ : ` ✔ [pyric] functions ${ready.triggerCount} onValueCreated ` +
743
+ `trigger${ready.triggerCount === 1 ? '' : 's'} from ${path.relative(cwd, project.entry)}`);
744
+ for (const unsupported of ready.unsupportedTriggers) {
745
+ server.config.logger.warn(` ⚠ [pyric] functions export ${unsupported.exportName} uses unsupported trigger ` +
746
+ `${unsupported.eventType}; it will not run.`);
747
+ }
748
+ }
749
+ catch (error) {
750
+ const message = error instanceof Error ? error.message : String(error);
751
+ server.config.logger.error(mode === 'reload'
752
+ ? // Unlike rules, last-good cannot stay live — the old child is
753
+ // already stopped — so a broken save takes functions down.
754
+ ` ✖ [pyric] functions failed to reload: ${message}\n` +
755
+ ` ✖ [pyric] functions are down until the next good save.`
756
+ : ` ✖ [pyric] functions failed to start: ${message}`);
757
+ await functionsChild.stop().catch(() => undefined);
758
+ functionsChild = null;
759
+ }
760
+ };
761
+ let reloadDebounce = null;
762
+ httpServer.once('close', () => {
763
+ disposed = true;
764
+ if (reloadDebounce)
765
+ clearTimeout(reloadDebounce);
766
+ void functionsChild?.stop().catch(() => undefined);
767
+ });
768
+ if (httpServer.listening)
769
+ void start();
770
+ else
771
+ httpServer.once('listening', () => void start());
772
+ // Functions hot-reload from Vite's OWN watcher (mirrors the rules block
773
+ // below). Restart = redeploy: stop the old child, respawn via the same
774
+ // start path — there is no in-place swap, so in-flight executions in the
775
+ // old child may drop and writes landing in the swap gap become the new
776
+ // child's baseline (execution.ts consumes each trigger's first observed
777
+ // value as baseline; they do not fire). Debounced 300ms — a save fans
778
+ // out several fs events and a child respawn is far heavier than a rules
779
+ // re-parse. Restarts are serialized: a save landing mid-restart queues
780
+ // exactly one follow-up run.
781
+ if (functionsOpts.watch !== false) {
782
+ const sourceDir = project.sourceDir;
783
+ // Usually redundant (Vite watches its root, which contains the
784
+ // functions dir in the common layout) but load-bearing when the
785
+ // functions source lives outside Vite's root. node_modules stays
786
+ // ignored: Vite's watcher ignores `**/node_modules/**` globally, and
787
+ // the handler below filters it again for explicitly-added trees.
788
+ server.watcher.add(sourceDir);
789
+ let restarting = false;
790
+ let queued = false;
791
+ const restart = async () => {
792
+ if (restarting) {
793
+ queued = true;
794
+ return;
795
+ }
796
+ restarting = true;
797
+ try {
798
+ do {
799
+ queued = false;
800
+ if (disposed)
801
+ return;
802
+ const old = functionsChild;
803
+ functionsChild = null;
804
+ if (old)
805
+ await old.stop().catch(() => undefined);
806
+ await start('reload');
807
+ } while (queued && !disposed);
808
+ }
809
+ finally {
810
+ restarting = false;
811
+ }
812
+ };
813
+ const onFunctionsFsEvent = (file) => {
814
+ const resolved = path.resolve(file);
815
+ const rel = path.relative(sourceDir, resolved);
816
+ if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel))
817
+ return;
818
+ if (rel.split(path.sep).includes('node_modules'))
819
+ return;
820
+ if (reloadDebounce)
821
+ clearTimeout(reloadDebounce);
822
+ reloadDebounce = setTimeout(() => void restart(), 300);
823
+ };
824
+ server.watcher.on('change', onFunctionsFsEvent);
825
+ server.watcher.on('add', onFunctionsFsEvent);
826
+ server.watcher.on('unlink', onFunctionsFsEvent);
827
+ }
828
+ }
568
829
  // Rules hot-reload from Vite's OWN watcher (no second fs watcher). Reuse
569
830
  // prepareRulesSource (resolve + lint); last-good stays live on a broken save.
570
831
  // Debounced (editors emit several change events per save) — matches
@@ -653,10 +914,19 @@ export function pyricSandbox(options = {}) {
653
914
  const head = workerReady
654
915
  ? `<meta name="pyric-worker-v" content="${workerVersion}" ${MARKER}>`
655
916
  : `<script ${MARKER}>globalThis.__PYRIC_FORCE_INPAGE__=true;</script>`;
917
+ // Plugin-level engine for the IN-PAGE path: a classic inline script runs
918
+ // before the deferred init module AND before app code's `getAI`, so the
919
+ // served `getAI` (entries/ai.ts) reads it synchronously — init.json can't
920
+ // be awaited there. Harmless on the worker path (that branch ignores the
921
+ // global; the worker reads ctx.aiEngine from init.json). `<` is escaped so
922
+ // an engine value can never break out of the script tag.
923
+ const aiEngineTag = aiEngineWire
924
+ ? `<script ${MARKER}>globalThis.__PYRIC_AI_ENGINE__=${JSON.stringify(aiEngineWire).replace(/</g, '\\u003c')};</script>`
925
+ : '';
656
926
  // Boot the sandbox by loading the real init entry as a module (Vite
657
927
  // serves + transforms it). The init module's top-level await deploys rules
658
928
  // before app code runs. Mirrors serve's injectServeTags.
659
- const tag = head + `<script type="module" src="/@fs/${entries.init}" ${MARKER}></script>`;
929
+ const tag = head + aiEngineTag + `<script type="module" src="/@fs/${entries.init}" ${MARKER}></script>`;
660
930
  return html.includes('</head>') ? html.replace('</head>', `${tag}</head>`) : tag + html;
661
931
  },
662
932
  };