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

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 (502) hide show
  1. package/README.md +64 -89
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +238 -1
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +238 -1
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/client/dispatch.d.ts +25 -19
  7. package/dist/bridge/client/dispatch.d.ts.map +1 -1
  8. package/dist/bridge/client/dispatch.js +41 -48
  9. package/dist/bridge/client/dispatch.js.map +1 -1
  10. package/dist/bridge/client/tool-family-factories.d.ts +26 -0
  11. package/dist/bridge/client/tool-family-factories.d.ts.map +1 -0
  12. package/dist/bridge/client/tool-family-factories.js +10 -0
  13. package/dist/bridge/client/tool-family-factories.js.map +1 -0
  14. package/dist/bridge/server/mcp-contract.d.ts +7 -6
  15. package/dist/bridge/server/mcp-contract.d.ts.map +1 -1
  16. package/dist/bridge/server/mcp-contract.js +9 -48
  17. package/dist/bridge/server/mcp-contract.js.map +1 -1
  18. package/dist/bridge/server/peer.d.ts +11 -1
  19. package/dist/bridge/server/peer.d.ts.map +1 -1
  20. package/dist/bridge/server/peer.js +22 -1
  21. package/dist/bridge/server/peer.js.map +1 -1
  22. package/dist/bridge/server/tool-family-factories.d.ts +30 -0
  23. package/dist/bridge/server/tool-family-factories.d.ts.map +1 -0
  24. package/dist/bridge/server/tool-family-factories.js +22 -0
  25. package/dist/bridge/server/tool-family-factories.js.map +1 -0
  26. package/dist/bridge/server/tool-metadata.d.ts +17 -18
  27. package/dist/bridge/server/tool-metadata.d.ts.map +1 -1
  28. package/dist/bridge/server/tool-metadata.js +24 -59
  29. package/dist/bridge/server/tool-metadata.js.map +1 -1
  30. package/dist/bridge/tool-families.d.ts +48 -0
  31. package/dist/bridge/tool-families.d.ts.map +1 -0
  32. package/dist/bridge/tool-families.generated.d.ts +32 -0
  33. package/dist/bridge/tool-families.generated.d.ts.map +1 -0
  34. package/dist/bridge/tool-families.generated.js +15 -0
  35. package/dist/bridge/tool-families.generated.js.map +1 -0
  36. package/dist/bridge/tool-families.js +51 -0
  37. package/dist/bridge/tool-families.js.map +1 -0
  38. package/dist/bridge/tool-family-records/conformance.d.ts +7 -0
  39. package/dist/bridge/tool-family-records/conformance.d.ts.map +1 -0
  40. package/dist/bridge/tool-family-records/conformance.js +6 -0
  41. package/dist/bridge/tool-family-records/conformance.js.map +1 -0
  42. package/dist/bridge/tool-family-records/firestore-data.d.ts +7 -0
  43. package/dist/bridge/tool-family-records/firestore-data.d.ts.map +1 -0
  44. package/dist/bridge/tool-family-records/firestore-data.js +15 -0
  45. package/dist/bridge/tool-family-records/firestore-data.js.map +1 -0
  46. package/dist/bridge/tool-family-records/firestore-inspect.d.ts +7 -0
  47. package/dist/bridge/tool-family-records/firestore-inspect.d.ts.map +1 -0
  48. package/dist/bridge/tool-family-records/firestore-inspect.js +6 -0
  49. package/dist/bridge/tool-family-records/firestore-inspect.js.map +1 -0
  50. package/dist/bridge/tool-family-records/firestore-rules.d.ts +7 -0
  51. package/dist/bridge/tool-family-records/firestore-rules.d.ts.map +1 -0
  52. package/dist/bridge/tool-family-records/firestore-rules.js +15 -0
  53. package/dist/bridge/tool-family-records/firestore-rules.js.map +1 -0
  54. package/dist/bridge/tool-family-records/firestore-simulator.d.ts +7 -0
  55. package/dist/bridge/tool-family-records/firestore-simulator.d.ts.map +1 -0
  56. package/dist/bridge/tool-family-records/firestore-simulator.js +16 -0
  57. package/dist/bridge/tool-family-records/firestore-simulator.js.map +1 -0
  58. package/dist/bridge/tool-family-records/rtdb-inspection.d.ts +7 -0
  59. package/dist/bridge/tool-family-records/rtdb-inspection.d.ts.map +1 -0
  60. package/dist/bridge/tool-family-records/rtdb-inspection.js +6 -0
  61. package/dist/bridge/tool-family-records/rtdb-inspection.js.map +1 -0
  62. package/dist/bundler/externals.d.ts +37 -0
  63. package/dist/bundler/externals.d.ts.map +1 -0
  64. package/dist/bundler/externals.js +52 -0
  65. package/dist/bundler/externals.js.map +1 -0
  66. package/dist/bundler/index.d.ts +17 -0
  67. package/dist/bundler/index.d.ts.map +1 -0
  68. package/dist/bundler/index.js +17 -0
  69. package/dist/bundler/index.js.map +1 -0
  70. package/dist/cli/inlined-sdk-scanner.d.ts +6 -0
  71. package/dist/cli/inlined-sdk-scanner.d.ts.map +1 -0
  72. package/dist/cli/inlined-sdk-scanner.js +82 -0
  73. package/dist/cli/inlined-sdk-scanner.js.map +1 -0
  74. package/dist/cli/sandbox-interlock.d.ts +97 -0
  75. package/dist/cli/sandbox-interlock.d.ts.map +1 -0
  76. package/dist/cli/sandbox-interlock.js +112 -0
  77. package/dist/cli/sandbox-interlock.js.map +1 -0
  78. package/dist/cli/sandbox-runner.d.ts +20 -12
  79. package/dist/cli/sandbox-runner.d.ts.map +1 -1
  80. package/dist/cli/sandbox-runner.js +24 -21
  81. package/dist/cli/sandbox-runner.js.map +1 -1
  82. package/dist/cli/serve.d.ts +6 -10
  83. package/dist/cli/serve.d.ts.map +1 -1
  84. package/dist/cli/serve.js +57 -77
  85. package/dist/cli/serve.js.map +1 -1
  86. package/dist/cli/unsupported-runtime.d.ts +27 -0
  87. package/dist/cli/unsupported-runtime.d.ts.map +1 -0
  88. package/dist/cli/unsupported-runtime.js +63 -0
  89. package/dist/cli/unsupported-runtime.js.map +1 -0
  90. package/dist/conformance/.generated/can-i-use-browser.d.ts +1 -1
  91. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  92. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  93. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  94. package/dist/conformance/.generated/can-i-use.d.ts +1 -1
  95. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  96. package/dist/conformance/.generated/can-i-use.js +1 -1
  97. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  98. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
  99. package/dist/conformance/.generated/conformance-docs.js +1 -1
  100. package/dist/conformance/.generated/conformance-docs.js.map +1 -1
  101. package/dist/functions-rtdb/child.d.ts +37 -0
  102. package/dist/functions-rtdb/child.d.ts.map +1 -1
  103. package/dist/functions-rtdb/child.js +90 -21
  104. package/dist/functions-rtdb/child.js.map +1 -1
  105. package/dist/functions-rtdb/development-runtime.d.ts +3 -0
  106. package/dist/functions-rtdb/development-runtime.d.ts.map +1 -1
  107. package/dist/functions-rtdb/development-runtime.js +1 -0
  108. package/dist/functions-rtdb/development-runtime.js.map +1 -1
  109. package/dist/google-endpoints.d.ts +67 -0
  110. package/dist/google-endpoints.d.ts.map +1 -0
  111. package/dist/google-endpoints.js +119 -0
  112. package/dist/google-endpoints.js.map +1 -0
  113. package/dist/next/runtime-env.d.ts.map +1 -1
  114. package/dist/next/runtime-env.js +5 -0
  115. package/dist/next/runtime-env.js.map +1 -1
  116. package/dist/next/with-pyric.d.ts +1 -1
  117. package/dist/next/with-pyric.js +1 -1
  118. package/dist/register/beacon.d.ts +69 -0
  119. package/dist/register/beacon.d.ts.map +1 -0
  120. package/dist/register/beacon.js +199 -0
  121. package/dist/register/beacon.js.map +1 -0
  122. package/dist/register/index.d.ts.map +1 -1
  123. package/dist/register/index.js +65 -6
  124. package/dist/register/index.js.map +1 -1
  125. package/dist/register/net-guard.d.ts +110 -0
  126. package/dist/register/net-guard.d.ts.map +1 -0
  127. package/dist/register/net-guard.js +462 -0
  128. package/dist/register/net-guard.js.map +1 -0
  129. package/dist/serve/ai-diagnostics-relay.d.ts +63 -0
  130. package/dist/serve/ai-diagnostics-relay.d.ts.map +1 -0
  131. package/dist/serve/ai-diagnostics-relay.js +125 -0
  132. package/dist/serve/ai-diagnostics-relay.js.map +1 -0
  133. package/dist/serve/ai-proxy.d.ts +92 -0
  134. package/dist/serve/ai-proxy.d.ts.map +1 -0
  135. package/dist/serve/ai-proxy.js +269 -0
  136. package/dist/serve/ai-proxy.js.map +1 -0
  137. package/dist/serve/ai-status.d.ts +44 -0
  138. package/dist/serve/ai-status.d.ts.map +1 -0
  139. package/dist/serve/ai-status.js +77 -0
  140. package/dist/serve/ai-status.js.map +1 -0
  141. package/dist/serve/ai-terminal-blocks.d.ts +97 -0
  142. package/dist/serve/ai-terminal-blocks.d.ts.map +1 -0
  143. package/dist/serve/ai-terminal-blocks.js +128 -0
  144. package/dist/serve/ai-terminal-blocks.js.map +1 -0
  145. package/dist/serve/ai-terminal-text.d.ts +36 -0
  146. package/dist/serve/ai-terminal-text.d.ts.map +1 -0
  147. package/dist/serve/ai-terminal-text.js +48 -0
  148. package/dist/serve/ai-terminal-text.js.map +1 -0
  149. package/dist/serve/beacon-route.d.ts +53 -0
  150. package/dist/serve/beacon-route.d.ts.map +1 -0
  151. package/dist/serve/beacon-route.js +101 -0
  152. package/dist/serve/beacon-route.js.map +1 -0
  153. package/dist/serve/entries/active-auth-registry.d.ts +16 -0
  154. package/dist/serve/entries/active-auth-registry.d.ts.map +1 -0
  155. package/dist/serve/entries/active-auth-registry.js +48 -0
  156. package/dist/serve/entries/active-auth-registry.js.map +1 -0
  157. package/dist/serve/entries/active-auth.d.ts +18 -0
  158. package/dist/serve/entries/active-auth.d.ts.map +1 -0
  159. package/dist/serve/entries/active-auth.js +84 -0
  160. package/dist/serve/entries/active-auth.js.map +1 -0
  161. package/dist/serve/entries/auth-helper-core.d.ts +1 -0
  162. package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
  163. package/dist/serve/entries/auth-helper-core.js +4 -0
  164. package/dist/serve/entries/auth-helper-core.js.map +1 -1
  165. package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -1
  166. package/dist/serve/entries/auth-helper-dom.js +28 -2
  167. package/dist/serve/entries/auth-helper-dom.js.map +1 -1
  168. package/dist/serve/entries/auth.d.ts.map +1 -1
  169. package/dist/serve/entries/auth.js +8 -0
  170. package/dist/serve/entries/auth.js.map +1 -1
  171. package/dist/serve/entries/bridge-url.d.ts +1 -1
  172. package/dist/serve/entries/bridge-url.js +1 -1
  173. package/dist/serve/entries/init.d.ts.map +1 -1
  174. package/dist/serve/entries/init.js +70 -4
  175. package/dist/serve/entries/init.js.map +1 -1
  176. package/dist/serve/entries/runtime.d.ts.map +1 -1
  177. package/dist/serve/entries/runtime.js +9 -0
  178. package/dist/serve/entries/runtime.js.map +1 -1
  179. package/dist/serve/namespace.d.ts +14 -5
  180. package/dist/serve/namespace.d.ts.map +1 -1
  181. package/dist/serve/namespace.js +57 -124
  182. package/dist/serve/namespace.js.map +1 -1
  183. package/dist/serve/runtime/chip-config.d.ts.map +1 -1
  184. package/dist/serve/runtime/chip-config.js +16 -2
  185. package/dist/serve/runtime/chip-config.js.map +1 -1
  186. package/dist/serve/runtime/chip-dialog.d.ts +18 -0
  187. package/dist/serve/runtime/chip-dialog.d.ts.map +1 -0
  188. package/dist/serve/runtime/chip-dialog.js +315 -0
  189. package/dist/serve/runtime/chip-dialog.js.map +1 -0
  190. package/dist/serve/runtime/chip-install.d.ts +2 -0
  191. package/dist/serve/runtime/chip-install.d.ts.map +1 -1
  192. package/dist/serve/runtime/chip-install.js +9 -4
  193. package/dist/serve/runtime/chip-install.js.map +1 -1
  194. package/dist/serve/runtime/chip-user-search.d.ts +16 -0
  195. package/dist/serve/runtime/chip-user-search.d.ts.map +1 -0
  196. package/dist/serve/runtime/chip-user-search.js +354 -0
  197. package/dist/serve/runtime/chip-user-search.js.map +1 -0
  198. package/dist/serve/runtime/chip.d.ts +10 -0
  199. package/dist/serve/runtime/chip.d.ts.map +1 -1
  200. package/dist/serve/runtime/chip.js +118 -15
  201. package/dist/serve/runtime/chip.js.map +1 -1
  202. package/dist/serve/runtime/identity.d.ts +17 -0
  203. package/dist/serve/runtime/identity.d.ts.map +1 -0
  204. package/dist/serve/runtime/identity.js +10 -0
  205. package/dist/serve/runtime/identity.js.map +1 -0
  206. package/dist/serve/sandbox-session.d.ts +7 -0
  207. package/dist/serve/sandbox-session.d.ts.map +1 -1
  208. package/dist/serve/sandbox-session.js +2 -0
  209. package/dist/serve/sandbox-session.js.map +1 -1
  210. package/dist/serve/site-ui/_astro/{RulesCodeEditor.XtDmHOlN.js → RulesCodeEditor.DsTAsKIa.js} +1 -1
  211. package/dist/serve/site-ui/_astro/app.CMmTxyhL.js +1 -0
  212. package/dist/serve/site-ui/_astro/app.DhALsVii.js +115 -0
  213. package/dist/serve/site-ui/_astro/{chess-showcase.B72XYeoh.js → chess-showcase.Bn_pP6UJ.js} +2 -2
  214. package/dist/serve/site-ui/_astro/{example-runtime.C25_lx6Z.js → example-runtime.CXopTGv7.js} +1 -1
  215. package/dist/serve/site-ui/_astro/sandbox-controls.rOuZTOUG.js +510 -0
  216. package/dist/serve/site-ui/_astro/{seed.Co0yUJY5.js → seed.lywYbXZ0.js} +2 -2
  217. package/dist/serve/site-ui/_astro/writes.BsPBG3dp.js +653 -0
  218. package/dist/serve/site-ui/auth/index.html +1 -1
  219. package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
  220. package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +1 -1
  221. package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
  222. package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
  223. package/dist/serve/site-ui/docs/ai-compat/index.html +1 -1
  224. package/dist/serve/site-ui/docs/api-reference/index.html +8 -1
  225. package/dist/serve/site-ui/docs/api-reference.md +7 -0
  226. package/dist/serve/site-ui/docs/app-compat/index.html +1 -1
  227. package/dist/serve/site-ui/docs/auth-compat/index.html +3 -3
  228. package/dist/serve/site-ui/docs/auth-compat.md +2 -2
  229. package/dist/serve/site-ui/docs/build/ai-logic/index.html +6 -1
  230. package/dist/serve/site-ui/docs/build/ai-logic.md +6 -0
  231. package/dist/serve/site-ui/docs/build/authentication/index.html +2 -2
  232. package/dist/serve/site-ui/docs/build/authentication.md +1 -1
  233. package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +4 -2
  234. package/dist/serve/site-ui/docs/build/cloud-firestore.md +4 -0
  235. package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
  236. package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
  237. package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
  238. package/dist/serve/site-ui/docs/conformance-scores/index.html +14 -2
  239. package/dist/serve/site-ui/docs/conformance-scores.md +13 -1
  240. package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +1 -1
  241. package/dist/serve/site-ui/docs/database-compat/index.html +44 -44
  242. package/dist/serve/site-ui/docs/database-compat.md +43 -43
  243. package/dist/serve/site-ui/docs/examples/chess/index.html +1 -1
  244. package/dist/serve/site-ui/docs/examples/index.html +1 -1
  245. package/dist/serve/site-ui/docs/firestore-compat/index.html +4 -4
  246. package/dist/serve/site-ui/docs/firestore-compat.md +3 -3
  247. package/dist/serve/site-ui/docs/firestore-flutter-compat/index.html +319 -0
  248. package/dist/serve/site-ui/docs/firestore-flutter-compat.md +344 -0
  249. package/dist/serve/site-ui/docs/firestore-kotlin-compat/index.html +319 -0
  250. package/dist/serve/site-ui/docs/firestore-kotlin-compat.md +344 -0
  251. package/dist/serve/site-ui/docs/firestore-swift-compat/index.html +490 -0
  252. package/dist/serve/site-ui/docs/firestore-swift-compat.md +517 -0
  253. package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +1 -1
  254. package/dist/serve/site-ui/docs/get-started/backend-bundlers/index.html +105 -0
  255. package/dist/serve/site-ui/docs/get-started/backend-bundlers.md +165 -0
  256. package/dist/serve/site-ui/docs/get-started/flutter/index.html +98 -0
  257. package/dist/serve/site-ui/docs/get-started/flutter.md +105 -0
  258. package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
  259. package/dist/serve/site-ui/docs/get-started/nextjs/index.html +1 -1
  260. package/dist/serve/site-ui/docs/get-started/start-building/index.html +1 -1
  261. package/dist/serve/site-ui/docs/get-started/vite/index.html +1 -1
  262. package/dist/serve/site-ui/docs/index.json +3211 -1471
  263. package/dist/serve/site-ui/docs/messaging-compat/index.html +1 -1
  264. package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +4 -3
  265. package/dist/serve/site-ui/docs/observe/resolve-runtime-status.md +3 -1
  266. package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
  267. package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
  268. package/dist/serve/site-ui/docs/observe/switch-and-impersonate-identities/index.html +110 -0
  269. package/dist/serve/site-ui/docs/observe/switch-and-impersonate-identities.md +134 -0
  270. package/dist/serve/site-ui/docs/overview/index.html +1 -1
  271. package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  272. package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  273. package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  274. package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  275. package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
  276. package/dist/serve/site-ui/docs/pyric-admin-reference-api/index.html +1 -1
  277. package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  278. package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
  279. package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  280. package/dist/serve/site-ui/docs/pyric-analytics-reference-api/index.html +124 -0
  281. package/dist/serve/site-ui/docs/pyric-analytics-reference-api.md +287 -0
  282. package/dist/serve/site-ui/docs/pyric-app-check-reference-api/index.html +87 -0
  283. package/dist/serve/site-ui/docs/pyric-app-check-reference-api.md +199 -0
  284. package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
  285. package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +6 -2
  286. package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +2 -1
  287. package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  288. package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  289. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +2 -2
  290. package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api.md +1 -1
  291. package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  292. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api/index.html +56 -0
  293. package/dist/serve/site-ui/docs/pyric-cli-bundler-reference-api.md +72 -0
  294. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +4 -1
  295. package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api.md +3 -0
  296. package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  297. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +4 -1
  298. package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api.md +3 -0
  299. package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  300. package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  301. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +2 -2
  302. package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +1 -1
  303. package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +1 -1
  304. package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  305. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +34 -9
  306. package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api.md +16 -8
  307. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +133 -93
  308. package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +61 -1
  309. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +2 -2
  310. package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api.md +1 -1
  311. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +2 -2
  312. package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api.md +2 -2
  313. package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +2 -2
  314. package/dist/serve/site-ui/docs/pyric-database-reference-api.md +1 -1
  315. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api/index.html +559 -0
  316. package/dist/serve/site-ui/docs/pyric-firestore-lite-reference-api.md +1240 -0
  317. package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +40 -11
  318. package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +18 -8
  319. package/dist/serve/site-ui/docs/pyric-functions-reference-api/index.html +67 -0
  320. package/dist/serve/site-ui/docs/pyric-functions-reference-api.md +149 -0
  321. package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  322. package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  323. package/dist/serve/site-ui/docs/pyric-performance-reference-api/index.html +35 -0
  324. package/dist/serve/site-ui/docs/pyric-performance-reference-api.md +69 -0
  325. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api/index.html +132 -0
  326. package/dist/serve/site-ui/docs/pyric-remote-config-reference-api.md +307 -0
  327. package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +1 -1
  328. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +52 -17
  329. package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +48 -9
  330. package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  331. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +239 -49
  332. package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +148 -31
  333. package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +22 -4
  334. package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +25 -3
  335. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +26 -96
  336. package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api.md +20 -51
  337. package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  338. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +2 -2
  339. package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api.md +1 -1
  340. package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  341. package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  342. package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  343. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +2 -2
  344. package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api.md +1 -1
  345. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +124 -26
  346. package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api.md +58 -5
  347. package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  348. package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  349. package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  350. package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  351. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +4 -5
  352. package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +3 -4
  353. package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  354. package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  355. package/dist/serve/site-ui/docs/reference/cli/index.html +6 -3
  356. package/dist/serve/site-ui/docs/reference/cli.md +8 -2
  357. package/dist/serve/site-ui/docs/rules-compat/index.html +10 -2
  358. package/dist/serve/site-ui/docs/rules-compat.md +9 -1
  359. package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
  360. package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  361. package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
  362. package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  363. package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
  364. package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  365. package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
  366. package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  367. package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
  368. package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
  369. package/dist/serve/site-ui/docs/storage-compat/index.html +13 -13
  370. package/dist/serve/site-ui/docs/storage-compat.md +12 -12
  371. package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  372. package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
  373. package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  374. package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
  375. package/dist/serve/site-ui/examples/chess/index.html +1 -1
  376. package/dist/serve/site-ui/firestore/index.html +1 -1
  377. package/dist/serve/site-ui/llms.txt +13 -0
  378. package/dist/serve/site-ui/rtdb/index.html +1 -1
  379. package/dist/serve/site-ui/settings/index.html +1 -1
  380. package/dist/serve/site-ui/storage/index.html +1 -1
  381. package/dist/serve/site-ui/studio/index.html +1 -1
  382. package/dist/serve/site-ui/traffic/index.html +1 -1
  383. package/dist/serve/studio/disk-workspace.d.ts.map +1 -1
  384. package/dist/serve/studio/disk-workspace.js +64 -2
  385. package/dist/serve/studio/disk-workspace.js.map +1 -1
  386. package/dist/serve/vite-plugin.d.ts +7 -7
  387. package/dist/serve/vite-plugin.js +1 -1
  388. package/dist/serve/vite-plugin.js.map +1 -1
  389. package/dist/serve/vite-sandbox-generation.d.ts.map +1 -1
  390. package/dist/serve/vite-sandbox-generation.js +12 -0
  391. package/dist/serve/vite-sandbox-generation.js.map +1 -1
  392. package/dist/serve/worker/client/auth.js +1 -2
  393. package/dist/serve/worker/client/auth.js.map +1 -1
  394. package/dist/serve/worker/client/core.d.ts +21 -1
  395. package/dist/serve/worker/client/core.d.ts.map +1 -1
  396. package/dist/serve/worker/client/core.js +79 -3
  397. package/dist/serve/worker/client/core.js.map +1 -1
  398. package/dist/serve/worker/client.d.ts +1 -1
  399. package/dist/serve/worker/client.d.ts.map +1 -1
  400. package/dist/serve/worker/client.js +1 -1
  401. package/dist/serve/worker/client.js.map +1 -1
  402. package/dist/serve/worker/context-resolver.d.ts +30 -0
  403. package/dist/serve/worker/context-resolver.d.ts.map +1 -0
  404. package/dist/serve/worker/context-resolver.js +44 -0
  405. package/dist/serve/worker/context-resolver.js.map +1 -0
  406. package/dist/serve/worker/entry.js +23 -19
  407. package/dist/serve/worker/entry.js.map +1 -1
  408. package/dist/serve/worker/host/core.d.ts +1 -0
  409. package/dist/serve/worker/host/core.d.ts.map +1 -1
  410. package/dist/serve/worker/host/core.js +12 -6
  411. package/dist/serve/worker/host/core.js.map +1 -1
  412. package/dist/serve/worker/host/storage.js +2 -2
  413. package/dist/serve/worker/host-auth.js +1 -2
  414. package/dist/serve/worker/host-auth.js.map +1 -1
  415. package/dist/serve/worker/index.d.ts +1 -1
  416. package/dist/serve/worker/index.d.ts.map +1 -1
  417. package/dist/serve/worker/index.js +2 -2
  418. package/dist/serve/worker/index.js.map +1 -1
  419. package/dist/serve/worker/port-lifecycle.d.ts +18 -0
  420. package/dist/serve/worker/port-lifecycle.d.ts.map +1 -0
  421. package/dist/serve/worker/port-lifecycle.js +28 -0
  422. package/dist/serve/worker/port-lifecycle.js.map +1 -0
  423. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  424. package/dist/serve/worker/serve-init.js +8 -2
  425. package/dist/serve/worker/serve-init.js.map +1 -1
  426. package/dist/verify/fixture.d.ts +1 -1
  427. package/package.json +16 -5
  428. package/src/assurance/.generated/conformance-verdicts.ts +238 -1
  429. package/src/bridge/client/dispatch.ts +52 -56
  430. package/src/bridge/client/tool-family-factories.ts +34 -0
  431. package/src/bridge/server/mcp-contract.ts +15 -59
  432. package/src/bridge/server/peer.ts +24 -1
  433. package/src/bridge/server/tool-family-factories.ts +40 -0
  434. package/src/bridge/server/tool-metadata.ts +29 -61
  435. package/src/bridge/tool-families.generated.ts +17 -0
  436. package/src/bridge/tool-families.ts +87 -0
  437. package/src/bridge/tool-family-records/conformance.ts +6 -0
  438. package/src/bridge/tool-family-records/firestore-data.ts +15 -0
  439. package/src/bridge/tool-family-records/firestore-inspect.ts +6 -0
  440. package/src/bridge/tool-family-records/firestore-rules.ts +15 -0
  441. package/src/bridge/tool-family-records/firestore-simulator.ts +16 -0
  442. package/src/bridge/tool-family-records/rtdb-inspection.ts +6 -0
  443. package/src/bundler/externals.ts +55 -0
  444. package/src/bundler/index.ts +21 -0
  445. package/src/cli/cli.test.ts +0 -44
  446. package/src/cli/inlined-sdk-scanner.ts +77 -0
  447. package/src/cli/sandbox-interlock.ts +167 -0
  448. package/src/cli/sandbox-runner.ts +37 -26
  449. package/src/cli/serve.ts +68 -69
  450. package/src/cli/unsupported-runtime.ts +68 -0
  451. package/src/conformance/.generated/can-i-use-browser.ts +2 -2
  452. package/src/conformance/.generated/can-i-use.ts +2 -2
  453. package/src/conformance/.generated/conformance-docs.ts +1 -1
  454. package/src/functions-rtdb/child.ts +115 -21
  455. package/src/functions-rtdb/development-runtime.ts +4 -0
  456. package/src/google-endpoints.ts +155 -0
  457. package/src/next/runtime-env.ts +5 -0
  458. package/src/next/with-pyric.ts +1 -1
  459. package/src/register/beacon.ts +232 -0
  460. package/src/register/index.ts +68 -6
  461. package/src/register/net-guard.ts +567 -0
  462. package/src/serve/ai-diagnostics-relay.ts +243 -0
  463. package/src/serve/ai-proxy.ts +327 -0
  464. package/src/serve/ai-status.ts +109 -0
  465. package/src/serve/ai-terminal-blocks.ts +210 -0
  466. package/src/serve/ai-terminal-text.ts +52 -0
  467. package/src/serve/beacon-route.ts +141 -0
  468. package/src/serve/entries/active-auth-registry.ts +56 -0
  469. package/src/serve/entries/active-auth.ts +100 -0
  470. package/src/serve/entries/auth-helper-core.ts +5 -0
  471. package/src/serve/entries/auth-helper-dom.ts +26 -2
  472. package/src/serve/entries/auth.ts +8 -0
  473. package/src/serve/entries/bridge-url.ts +1 -1
  474. package/src/serve/entries/init.ts +78 -3
  475. package/src/serve/entries/runtime.ts +10 -0
  476. package/src/serve/namespace.ts +73 -140
  477. package/src/serve/runtime/chip-config.ts +16 -2
  478. package/src/serve/runtime/chip-dialog.ts +366 -0
  479. package/src/serve/runtime/chip-install.ts +10 -4
  480. package/src/serve/runtime/chip-user-search.ts +391 -0
  481. package/src/serve/runtime/chip.ts +140 -15
  482. package/src/serve/runtime/identity.ts +26 -0
  483. package/src/serve/sandbox-session.ts +9 -0
  484. package/src/serve/studio/disk-workspace.ts +76 -2
  485. package/src/serve/vite-plugin.ts +8 -8
  486. package/src/serve/vite-sandbox-generation.ts +15 -0
  487. package/src/serve/worker/client/auth.ts +1 -1
  488. package/src/serve/worker/client/core.ts +80 -3
  489. package/src/serve/worker/client.ts +1 -1
  490. package/src/serve/worker/context-resolver.ts +60 -0
  491. package/src/serve/worker/entry.ts +22 -18
  492. package/src/serve/worker/host/core.ts +9 -7
  493. package/src/serve/worker/host/storage.ts +2 -2
  494. package/src/serve/worker/host-auth.ts +1 -1
  495. package/src/serve/worker/index.ts +4 -1
  496. package/src/serve/worker/port-lifecycle.ts +45 -0
  497. package/src/serve/worker/serve-init.ts +9 -2
  498. package/src/verify/fixture.ts +1 -1
  499. package/dist/serve/site-ui/_astro/app.B52xr-DK.js +0 -1
  500. package/dist/serve/site-ui/_astro/app.DWBraPUw.js +0 -12
  501. package/dist/serve/site-ui/_astro/sandbox-controls.DEpnKg-O.js +0 -1169
  502. package/dist/serve/site-ui/_astro/writes.rpjrFzmu.js +0 -102
@@ -0,0 +1,167 @@
1
+ /**
2
+ * The interlock: the launcher's statement about interception in the child it
3
+ * is about to start, plus the warn-only watchdog for the child's answer.
4
+ *
5
+ * The status line is knowable synchronously from the env `pyric sandbox` just
6
+ * assembled: guard mode, whether NODE_OPTIONS really carries the register
7
+ * import, and where the child's handshake beacon will land. The watchdog is
8
+ * the other half: a child still alive well after launch that never posted a
9
+ * beacon is probably not intercepted.
10
+ */
11
+ import { beaconEndpoint } from '../register/beacon.js';
12
+ import { parseGuardMode, type GuardMode } from '../register/net-guard.js';
13
+ import { detectUnsupportedRuntime, formatUnsupportedRuntimeWarning } from './unsupported-runtime.js';
14
+
15
+ /**
16
+ * What `pyric sandbox` can say about the interception it is about to hand the
17
+ * child, entirely from the env it just assembled: no waiting, no round trip.
18
+ */
19
+ export interface InterlockStatus {
20
+ /** Net-guard mode the child will run under (`PYRIC_GUARD`, default warn). */
21
+ readonly guard: GuardMode;
22
+ /** Whether `NODE_OPTIONS` actually carries the register `--import`. */
23
+ readonly registerImported: boolean;
24
+ /** Where the child's handshake beacon will land, or null when the
25
+ * activator carries no bridge URL. */
26
+ readonly beacon: string | null;
27
+ }
28
+
29
+ /**
30
+ * Read the interlock off the child env. Everything here is synchronous by
31
+ * construction: it is a statement about the launch, printed before anything at
32
+ * runtime has had a chance to go wrong.
33
+ */
34
+ export function describeInterlock(
35
+ childEnv: NodeJS.ProcessEnv,
36
+ registerUrl: string,
37
+ ): InterlockStatus {
38
+ return {
39
+ guard: parseGuardMode(childEnv.PYRIC_GUARD),
40
+ registerImported: (childEnv.NODE_OPTIONS ?? '').includes(`--import ${registerUrl}`),
41
+ beacon: beaconEndpoint(childEnv.PYRIC_SANDBOX),
42
+ };
43
+ }
44
+
45
+ /**
46
+ * The startup status line, alongside the other `✔ <service>` checks.
47
+ *
48
+ * The healthy line is deliberately short: one fact per field and nothing the
49
+ * reader has to skim past. The degraded line is long because it reports a
50
+ * broken launch, which is worth every word.
51
+ */
52
+ export function formatInterlockLine(status: InterlockStatus): string {
53
+ if (!status.registerImported) {
54
+ return (
55
+ `⚠ interlock guard=${status.guard}, register is NOT in the child's NODE_OPTIONS. ` +
56
+ `Its firebase-admin/firebase imports will NOT be rewritten and would reach LIVE Firebase.\n`
57
+ );
58
+ }
59
+ return `✔ interlock guard=${status.guard}, register loaded via NODE_OPTIONS\n`;
60
+ }
61
+
62
+ export interface LaunchCheckOptions {
63
+ /** The environment the child is about to receive. */
64
+ readonly childEnv: NodeJS.ProcessEnv;
65
+ /** Absolute `file:` URL of the register module, to look for in NODE_OPTIONS. */
66
+ readonly registerUrl: string;
67
+ /** The child's argv, for the unsupported-runtime check. */
68
+ readonly argv: readonly string[];
69
+ readonly write: (line: string) => void;
70
+ }
71
+
72
+ /**
73
+ * Every statement the launcher makes about the child, printed in one block
74
+ * before the spawn, and the interlock status it derived on the way.
75
+ *
76
+ * Two checks: the interlock status line, from the env alone, and the
77
+ * unsupported-runtime warning for the other way interception can be absent, a
78
+ * child runtime that never evaluates Node loader hooks at all.
79
+ */
80
+ export function reportLaunchChecks(opts: LaunchCheckOptions): InterlockStatus {
81
+ const interlock = describeInterlock(opts.childEnv, opts.registerUrl);
82
+ opts.write(formatInterlockLine(interlock));
83
+ const unsupportedRuntime = detectUnsupportedRuntime(opts.argv);
84
+ if (unsupportedRuntime !== null) opts.write(formatUnsupportedRuntimeWarning(unsupportedRuntime));
85
+ return interlock;
86
+ }
87
+
88
+ /** How long a child may live without its beacon before we say something. */
89
+ const BEACON_GRACE_MS = 15_000;
90
+
91
+ export interface BeaconWatchdogOptions {
92
+ /** The child command, for attribution in the warning. */
93
+ readonly label: string;
94
+ /** The endpoint the child would post to. Null means nothing to watch. */
95
+ readonly beacon: string | null;
96
+ /** Whether a beacon from this child has been recorded. */
97
+ readonly sawBeacon: () => boolean;
98
+ /** Whether the child is still running. */
99
+ readonly isAlive: () => boolean;
100
+ readonly warn: (line: string) => void;
101
+ readonly graceMs?: number;
102
+ }
103
+
104
+ export interface BeaconWatchdog {
105
+ /** Cancel a pending check. Idempotent. */
106
+ stop(): void;
107
+ }
108
+
109
+ /** The warning itself: one paragraph naming what the silence means and what
110
+ * to check. Kept separate so its exact wording is testable. */
111
+ export function formatMissingBeaconWarning(opts: {
112
+ label: string;
113
+ graceMs: number;
114
+ beacon: string;
115
+ }): string {
116
+ const seconds = Math.round(opts.graceMs / 1000);
117
+ return (
118
+ ` ⚠ interlock: \`${opts.label}\` has been running ${seconds}s without posting a register ` +
119
+ `beacon to ${opts.beacon}. Its firebase-admin/firebase imports are probably NOT routed to ` +
120
+ `the pyric sandbox, which means they would reach LIVE Firebase. Check that the command starts ` +
121
+ `a Node process (bun and deno do not evaluate Node loader hooks), that it does not overwrite ` +
122
+ `NODE_OPTIONS, and that NODE_ENV is not production. Warning only: nothing was blocked, and ` +
123
+ `this is reported once per child.`
124
+ );
125
+ }
126
+
127
+ /**
128
+ * The warn-only interlock watchdog.
129
+ *
130
+ * It never kills the child and never blocks a request. The reason is the
131
+ * signal's own honesty: beacon delivery is best-effort (see
132
+ * `register/beacon.ts`), and a plausible silent child is not the same thing as
133
+ * a broken one. A short-lived script that exits before its POST lands, a child
134
+ * that reaches the sandbox only through a grandchild, a dev server slow to
135
+ * boot: each would be killed by a fail-closed version of this check, and each
136
+ * is fine.
137
+ *
138
+ * So the heuristic is the simple, attributable one: the child is still alive
139
+ * `graceMs` after launch and no beacon has arrived. Both halves matter. An
140
+ * exited child was never expected to say anything, and a child whose beacon
141
+ * landed has already proved the point. One warning per child, guaranteed by
142
+ * the one-shot timer; the timer is unref'd so a watchdog can never be the
143
+ * reason a process stays up.
144
+ *
145
+ * `sawBeacon` is a count delta rather than a pid match, deliberately. The
146
+ * process that loads register is often a grandchild (`npm run dev` starts
147
+ * node, `next dev` starts its worker), so the spawned child's own pid is
148
+ * frequently not the pid in the beacon, and matching on it would warn about
149
+ * perfectly healthy launches. The delta's known imprecision runs the other
150
+ * way: a sibling runtime's beacon that lands inside the grace window can mask
151
+ * a real miss. Erring toward silence is the right bias for a warn-only check.
152
+ */
153
+ export function startBeaconWatchdog(opts: BeaconWatchdogOptions): BeaconWatchdog {
154
+ const beacon = opts.beacon;
155
+ if (beacon === null) return { stop: () => {} };
156
+ const graceMs = opts.graceMs ?? BEACON_GRACE_MS;
157
+ const timer = setTimeout(() => {
158
+ if (opts.sawBeacon() || !opts.isAlive()) return;
159
+ opts.warn(formatMissingBeaconWarning({ label: opts.label, graceMs, beacon }));
160
+ }, graceMs);
161
+ timer.unref?.();
162
+ return {
163
+ stop(): void {
164
+ clearTimeout(timer);
165
+ },
166
+ };
167
+ }
@@ -16,6 +16,7 @@
16
16
  * only `spawnDevChild` touches the process table.
17
17
  */
18
18
  import { spawn, type ChildProcess } from 'node:child_process';
19
+ import { SHELL_OPERATORS } from './unsupported-runtime.js';
19
20
 
20
21
  // ─── First-run race guard ───────────────────────────────────────────────────
21
22
 
@@ -152,41 +153,60 @@ export function registerModuleUrl(): string {
152
153
  return new URL('../register/index.js', import.meta.url).href;
153
154
  }
154
155
 
156
+ /** What the launcher has to put in a child's environment for interception. */
157
+ export interface ChildActivation {
158
+ /** The serve host the child's sandbox calls reach. */
159
+ readonly serveUrl: string;
160
+ /** Absolute `file:` URL of the register module. */
161
+ readonly registerUrl: string;
162
+ /** The per-launch secret the child's handshake beacon must present.
163
+ * Absent when the launcher runs no beacon receiver, as the Vite plugin's
164
+ * Functions runtime does; the child then reports on stderr only. */
165
+ readonly beaconToken?: string | undefined;
166
+ }
167
+
155
168
  /**
156
- * Child env: sets the activator and APPENDS the loader to NODE_OPTIONS —
157
- * never replaces it (the user's own --inspect / --max-old-space-size etc.
158
- * must survive). `file:` URLs are percent-encoded, so no quoting is needed
159
- * even for paths with spaces.
169
+ * Child env: sets the activator and the beacon secret, and APPENDS the loader
170
+ * to NODE_OPTIONS rather than replacing it (the user's own --inspect /
171
+ * --max-old-space-size and so on must survive). `file:` URLs are
172
+ * percent-encoded, so no quoting is needed even for paths with spaces.
160
173
  */
161
174
  export function buildChildEnv(
162
175
  base: NodeJS.ProcessEnv,
163
- opts: { serveUrl: string; registerUrl: string },
176
+ opts: ChildActivation,
164
177
  ): NodeJS.ProcessEnv {
165
178
  const importFlag = `--import ${opts.registerUrl}`;
166
- return {
179
+ const env: NodeJS.ProcessEnv = {
167
180
  ...base,
168
181
  PYRIC_SANDBOX: `remote:${opts.serveUrl}`,
169
182
  NODE_OPTIONS: base.NODE_OPTIONS ? `${base.NODE_OPTIONS} ${importFlag}` : importFlag,
170
183
  };
184
+ if (opts.beaconToken !== undefined) env.PYRIC_BEACON_TOKEN = opts.beaconToken;
185
+ return env;
171
186
  }
172
187
 
173
188
  /**
174
189
  * Format copy-pasteable POSIX export statements for host-only startup.
175
190
  * Grouped in a cleanly formatted console block for easy selection and copying
176
191
  * into a separate terminal (for example, when running Next.js independently).
192
+ *
193
+ * The beacon secret is part of the block: without it a process started this
194
+ * way still intercepts, but the dev server cannot confirm that it did.
177
195
  */
178
- export function formatStartupEnvExport(opts: { serveUrl: string; registerUrl: string }): string {
179
- const pyricSandbox = `remote:${opts.serveUrl}`;
180
- const nodeOptions = `--import ${opts.registerUrl}`;
181
- const line1 = `export PYRIC_SANDBOX="${pyricSandbox}"`;
182
- const line2 = `export NODE_OPTIONS="${nodeOptions}"`;
183
- const divider = '─'.repeat(Math.max(line1.length, line2.length) + 4);
196
+ export function formatStartupEnvExport(opts: ChildActivation): string {
197
+ const lines = [`export PYRIC_SANDBOX="remote:${opts.serveUrl}"`];
198
+ if (opts.beaconToken !== undefined) {
199
+ lines.push(`export PYRIC_BEACON_TOKEN="${opts.beaconToken}"`);
200
+ }
201
+ lines.push(`export NODE_OPTIONS="--import ${opts.registerUrl}"`);
202
+ const width = Math.max(...lines.map((line) => line.length));
203
+ const divider = '─'.repeat(width + 4);
204
+ const body = lines.map((line) => ` ${line}\n`).join('');
184
205
  return (
185
206
  '\n' +
186
207
  ' To run external commands against this sandbox, paste in another terminal:\n' +
187
208
  ` ${divider}\n` +
188
- ` ${line1}\n` +
189
- ` ${line2}\n` +
209
+ body +
190
210
  ` ${divider}\n`
191
211
  );
192
212
  }
@@ -225,8 +245,6 @@ export function createLinePrefixer(
225
245
  /** How long a signalled child may linger before SIGKILL. */
226
246
  const FORCE_KILL_AFTER_MS = 2_000;
227
247
 
228
- const SHELL_OPERATORS = new Set(['&&', '||', '|', ';', '&']);
229
-
230
248
  export interface SandboxChildHandle {
231
249
  exited: Promise<number>;
232
250
  signal(sig: NodeJS.Signals): void;
@@ -259,16 +277,9 @@ export function spawnSandboxChild(
259
277
  // 2. Check for discrete shell operators (&&, ||, |, ;) among top-level tokens
260
278
  const hasShellOperators = parts.some((token) => SHELL_OPERATORS.has(token));
261
279
 
262
- // 3. Warn if runtime is bun or deno
263
- if (parts.length > 0 && (parts[0] === 'bun' || parts[0] === 'deno')) {
264
- const runner = parts[0];
265
- const target = opts.json ? process.stderr : process.stdout;
266
- target.write(
267
- ` ⚠ ${runner} detected: pyric intercepts Firebase imports via Node.js module loader hooks (NODE_OPTIONS="--import ..."). ` +
268
- `${runner} does not evaluate Node loader hooks — SDK calls in this process will not reach the pyric sandbox. ` +
269
- `Use \`node\` (or \`npx tsx\`) to run with the sandbox swap.\n`,
270
- );
271
- }
280
+ // The bun/deno warning is emitted by the launch seam in serve.ts, alongside
281
+ // the interlock line, so every pre-spawn statement about the child prints in
282
+ // one block and in order.
272
283
 
273
284
  const [command, ...args] = parts;
274
285
  let child: ChildProcess;
package/src/cli/serve.ts CHANGED
@@ -10,8 +10,9 @@
10
10
  * rules load (fail fast on broken rules) → SDK bundle (cached per pyric
11
11
  * version) → static server with the `/__pyric/` namespace + HTML injection.
12
12
  */
13
+ import { randomBytes } from 'node:crypto';
13
14
  import { join, relative, resolve } from 'node:path';
14
- import { existsSync, readdirSync, readFileSync, statSync, watch as watchFile } from 'node:fs';
15
+ import { existsSync, watch as watchFile } from 'node:fs';
15
16
  import type { ParsedArgs } from './parse-args.js';
16
17
  import { readFirebaseJson, readFirebaseRc, type FirebaseJson } from './firebase-json.js';
17
18
  import { bundleSdk, bundleWorker, defaultSdkEntries, resolveSiteUiDir } from '../serve/bundler.js';
@@ -22,7 +23,9 @@ import {
22
23
  embeddedWorkerVersion,
23
24
  } from '../serve/standalone-assets.js';
24
25
  import { hasSandboxBuildMarker } from '../serve/sandbox-marker.js';
26
+ import { formatBeaconReceipt } from '../serve/beacon-route.js';
25
27
  import type { InitPayload } from '../serve/namespace.js';
28
+ import { formatAiStatusLine } from '../serve/ai-status.js';
26
29
  import { injectServeTags } from '../serve/html-injection.js';
27
30
  import { formatActivityWarning } from '../serve/activity-warning.js';
28
31
  import { consoleServeLogger, startStaticServer, stderrServeLogger, type ServeHandle } from '../serve/server.js';
@@ -38,6 +41,12 @@ import {
38
41
  waitForSandboxPeer,
39
42
  type SandboxChildHandle,
40
43
  } from './sandbox-runner.js';
44
+ import {
45
+ reportLaunchChecks,
46
+ startBeaconWatchdog,
47
+ type BeaconWatchdog,
48
+ } from './sandbox-interlock.js';
49
+ import { scanForInlinedFirebase } from './inlined-sdk-scanner.js';
41
50
  import {
42
51
  createFunctionsDevelopmentRuntime,
43
52
  createHttpFunctionsPeerReadiness,
@@ -88,6 +97,12 @@ export interface ServeRuntime {
88
97
  uiUrl: string | null;
89
98
  /** Persistence summary (null when `--persist` is off). */
90
99
  persist: { restoredDocs: number; restoredUsers: number } | null;
100
+ /** Handshake beacons posted to `/__pyric/beacon` so far, the interlock
101
+ * watchdog's only input. */
102
+ beaconCount: () => number;
103
+ /** The per-launch secret a beacon must present, placed in every child's
104
+ * `PYRIC_BEACON_TOKEN`. */
105
+ beaconToken: string;
91
106
  }
92
107
 
93
108
  /** The `--json` stdout contract — one line, keep stable; agents parse this.
@@ -152,6 +167,12 @@ export async function startServe(opts: {
152
167
  }): Promise<ServeRuntime> {
153
168
  const logger = opts.logger ?? consoleServeLogger();
154
169
 
170
+ // Handshake beacons from pyric-launched children, plus the per-launch secret
171
+ // that authorizes one. Both live here because the route does.
172
+ let beaconsSeen = 0;
173
+ const beaconCount = (): number => beaconsSeen;
174
+ const beaconToken = randomBytes(24).toString('base64url');
175
+
155
176
  // --fresh only means anything against the state.json file `--persist`
156
177
  // maintains — without `--persist` there is no file to discard, so
157
178
  // `--fresh` alone was a silent no-op (nothing happened, nothing said so).
@@ -212,12 +233,12 @@ export async function startServe(opts: {
212
233
 
213
234
  // The import map can only remap BARE `firebase/*` specifiers. A plain bundler
214
235
  // build (`vite build`) inlines the real SDK into the app chunk, leaving
215
- // nothing to intercept the page would then talk to REAL Firebase endpoints
236
+ // nothing to intercept: the page would then talk to REAL Firebase endpoints
216
237
  // with the sandbox's fake credentials while the injected banner claims
217
238
  // otherwise. That hole is structural, so `pyric sandbox` refuses such a dist
218
239
  // rather than serving it. A pyric SANDBOX build (`vite build --mode
219
240
  // development`) carries the marker and bundles pyric's in-page adapters, so it
220
- // is trusted and the scan is skipped (marker present no real SDK to find).
241
+ // is trusted and the scan is skipped (marker present, no real SDK to find).
221
242
  if (!hasSandboxBuildMarker(publicDir)) {
222
243
  const inlined = scanForInlinedFirebase(publicDir);
223
244
  if (inlined.length > 0) {
@@ -306,6 +327,11 @@ export async function startServe(opts: {
306
327
  studio: opts.ui ? { siteUiDir } : false,
307
328
  bridgeUrl: () => mount && origin.port > 0 ? mount.wsUrl(origin) : null,
308
329
  activity: (incident) => logger.note(formatActivityWarning(incident)),
330
+ beaconToken,
331
+ beacon: (report) => {
332
+ beaconsSeen += 1;
333
+ logger.note(formatBeaconReceipt(report));
334
+ },
309
335
  permissive: opts.permissive,
310
336
  logger,
311
337
  });
@@ -494,7 +520,7 @@ export async function startServe(opts: {
494
520
  session.payload().storageRules
495
521
  ? `✔ rules ${session.summary.rules.storage.sourcePath} → deployed to the storage sandbox (hash ${session.summary.rules.storage.hash}; ` +
496
522
  `edits require a restart — storage rules do not hot-reload)`
497
- : `• rules no storage.rules — storage sandbox runs open (no rules configured)`,
523
+ : `• rules no storage.rules — storage sandbox denies client operations by default`,
498
524
  );
499
525
  if (uiUrl) {
500
526
  logger.info(`✔ studio Pyric Studio: ${uiUrl}`);
@@ -505,6 +531,13 @@ export async function startServe(opts: {
505
531
  if (mount) {
506
532
  logger.info(`✔ bridge MCP endpoint: ${mount.mcpUrl(origin)} (sandbox peers over ws at /__pyric/sandbox)`);
507
533
  }
534
+ // AI is a mounted service like the bridge: `/__pyric/ai-proxy` answers from
535
+ // the first request on, whether or not anything is configured. `pyric
536
+ // sandbox` has no AI flag, so the ENGINE is always the page's own `getAI()`
537
+ // choice (resolved lazily in the browser, since nothing here instantiates a
538
+ // broker to find out); what this server does decide is where the proxy
539
+ // forwards, and that is what the line reports.
540
+ logger.info(formatAiStatusLine({}));
508
541
  let persistSummary: ServeRuntime['persist'] = null;
509
542
  const persistence = session.summary.persistence;
510
543
  if (persistence) {
@@ -553,7 +586,8 @@ export async function startServe(opts: {
553
586
  logger.note('');
554
587
  logger.note(' ⚠ the pyric sandbox runs IN the served page — keep the browser tab open.');
555
588
  logger.note(' Firestore/auth data and persistence stop when no page is open.');
556
- return { handle, publicDir, payload, uiUrl, mcpUrl: mount ? mount.mcpUrl(origin) : null, persist: persistSummary };
589
+ const mcpUrl = mount ? mount.mcpUrl(origin) : null;
590
+ return { handle, publicDir, payload, uiUrl, mcpUrl, persist: persistSummary, beaconCount, beaconToken };
557
591
  }
558
592
 
559
593
  /**
@@ -779,6 +813,7 @@ export async function runServe(parsed: ParsedArgs): Promise<number> {
779
813
  }
780
814
 
781
815
  let devChild: SandboxChildHandle | null = null;
816
+ let beaconWatchdog: BeaconWatchdog | null = null;
782
817
  let functionsRuntime: FunctionsDevelopmentRuntime | null = null;
783
818
  let resolveFunctionsExit!: (code: number) => void;
784
819
  const functionsExited = new Promise<number>((resolve) => { resolveFunctionsExit = resolve; });
@@ -801,6 +836,7 @@ export async function runServe(parsed: ParsedArgs): Promise<number> {
801
836
  ]);
802
837
  const stopAfterSignal = async (): Promise<number> => {
803
838
  (json ? process.stderr : process.stdout).write('\nShutting down...\n');
839
+ beaconWatchdog?.stop();
804
840
  if (devChild && devChild.child.exitCode === null) devChild.signal(await signal);
805
841
  await functionsRuntime?.close().catch(() => undefined);
806
842
  await runtime.handle.stop().catch(() => undefined);
@@ -845,6 +881,7 @@ export async function runServe(parsed: ParsedArgs): Promise<number> {
845
881
  baseEnv: process.env,
846
882
  serveUrl: runtime.handle.url,
847
883
  registerUrl: registerModuleUrl(),
884
+ beaconToken: runtime.beaconToken,
848
885
  instance: `${functionsProjectId}-default-rtdb`,
849
886
  location: process.env.PYRIC_FUNCTIONS_RTDB_REGION ?? 'us-central1',
850
887
  projectId: functionsProjectId ?? 'demo-project',
@@ -910,19 +947,37 @@ export async function runServe(parsed: ParsedArgs): Promise<number> {
910
947
  info.write(
911
948
  `✔ run \`${plan.label}\` — firebase-admin/firebase imports are routed to the sandbox at ${runtime.handle.url}\n`,
912
949
  );
913
- devChild = spawnSandboxChild(plan, {
914
- cwd,
915
- json,
916
- env: buildChildEnv(process.env, {
917
- serveUrl: runtime.handle.url,
918
- registerUrl: registerModuleUrl(),
919
- }),
950
+ const childEnv = buildChildEnv(process.env, {
951
+ serveUrl: runtime.handle.url,
952
+ registerUrl: registerModuleUrl(),
953
+ beaconToken: runtime.beaconToken,
954
+ });
955
+ // What we are handing the child, stated before it starts: the interlock
956
+ // line and the unsupported-runtime check.
957
+ const interlock = reportLaunchChecks({
958
+ childEnv,
959
+ registerUrl: registerModuleUrl(),
960
+ argv: plan.argv,
961
+ write: (line) => info.write(line),
962
+ });
963
+
964
+ devChild = spawnSandboxChild(plan, { cwd, json, env: childEnv });
965
+ // A child still alive well after launch that never posted a beacon is very
966
+ // likely not intercepted. `startBeaconWatchdog` says why this only warns.
967
+ const beaconsAtSpawn = runtime.beaconCount();
968
+ beaconWatchdog = startBeaconWatchdog({
969
+ label: plan.label,
970
+ beacon: interlock.beacon,
971
+ sawBeacon: () => runtime.beaconCount() > beaconsAtSpawn,
972
+ isAlive: () => devChild !== null && devChild.child.exitCode === null,
973
+ warn: (line) => void process.stderr.write(`${line}\n`),
920
974
  });
921
975
  } else if (!json) {
922
976
  process.stdout.write(
923
977
  formatStartupEnvExport({
924
978
  serveUrl: runtime.handle.url,
925
979
  registerUrl: registerModuleUrl(),
980
+ beaconToken: runtime.beaconToken,
926
981
  }),
927
982
  );
928
983
  }
@@ -934,6 +989,7 @@ export async function runServe(parsed: ParsedArgs): Promise<number> {
934
989
  if (settled) return;
935
990
  settled = true;
936
991
  void (async () => {
992
+ beaconWatchdog?.stop();
937
993
  await functionsRuntime?.close().catch(() => undefined);
938
994
  if (devChild && devChild.child.exitCode === null) {
939
995
  devChild.signal('SIGTERM');
@@ -971,60 +1027,3 @@ export async function runServe(parsed: ParsedArgs): Promise<number> {
971
1027
  void signal.then(shutdown);
972
1028
  });
973
1029
  }
974
-
975
- /**
976
- * Detect a bundler build that INLINED the real firebase SDK into its served
977
- * assets (`vite build` output). The served import map remaps only bare
978
- * `firebase/*` specifiers, so such a build cannot be sandboxed — its calls
979
- * reach real Google endpoints. Fingerprints are real-SDK-only endpoint hosts
980
- * that never appear in a sandbox-clean app (whose calls all route to
981
- * `/__pyric/*`). Bounded: depth ≤ 4, ≤ 200 script files, first hit per file.
982
- * Returns publicDir-relative paths of offending assets.
983
- */
984
- export function scanForInlinedFirebase(dir: string): string[] {
985
- const FINGERPRINTS = [
986
- 'identitytoolkit.googleapis.com',
987
- 'firestore.googleapis.com',
988
- 'securetoken.googleapis.com',
989
- 'firebasedatabase.app',
990
- ];
991
- const hits: string[] = [];
992
- let scanned = 0;
993
- const walk = (d: string, rel: string, depth: number): void => {
994
- if (depth > 4 || scanned >= 200) return;
995
- let names: string[];
996
- try {
997
- names = readdirSync(d);
998
- } catch {
999
- return;
1000
- }
1001
- for (const name of names) {
1002
- if (scanned >= 200) return;
1003
- const p = join(d, name);
1004
- const r = rel ? `${rel}/${name}` : name;
1005
- let st;
1006
- try {
1007
- st = statSync(p);
1008
- } catch {
1009
- continue;
1010
- }
1011
- if (st.isDirectory()) {
1012
- // The pyric namespace itself never lands in hosting.public, but a
1013
- // node_modules inside a served dir would be a scan-cost trap.
1014
- // Dot-directories (.next, .git, .pyric) are internal caches and must be ignored.
1015
- if (name === 'node_modules' || name.startsWith('.')) continue;
1016
- walk(p, r, depth + 1);
1017
- } else if (/\.(js|mjs)$/.test(name)) {
1018
- scanned++;
1019
- try {
1020
- const text = readFileSync(p, 'utf8');
1021
- if (FINGERPRINTS.some((f) => text.includes(f))) hits.push(r);
1022
- } catch {
1023
- // unreadable asset: skip
1024
- }
1025
- }
1026
- }
1027
- };
1028
- walk(dir, '', 0);
1029
- return hits;
1030
- }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Child runtimes that cannot evaluate Node loader hooks, and the one warning
3
+ * that says what is lost when a command starts one.
4
+ */
5
+
6
+ /** Tokens that end one command and begin the next inside a shell string. */
7
+ export const SHELL_OPERATORS = new Set(['&&', '||', '|', ';', '&']);
8
+
9
+ /** Command basenames that cannot evaluate Node loader hooks, to the runtime. */
10
+ const UNSUPPORTED_RUNTIME_BINARIES = new Map<string, string>([
11
+ ['bun', 'bun'],
12
+ ['bunx', 'bun'],
13
+ ['deno', 'deno'],
14
+ ]);
15
+
16
+ /** Leading `KEY=VAL` environment assignments in a shell command. */
17
+ const ENV_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
18
+
19
+ /** Strip directory and a Windows `.exe` suffix from a command token. */
20
+ function commandBasename(token: string): string {
21
+ const base = token.split(/[\\/]/).pop() ?? token;
22
+ return base.toLowerCase().replace(/\.exe$/, '');
23
+ }
24
+
25
+ /**
26
+ * Decide whether the child command starts a runtime that cannot intercept.
27
+ *
28
+ * Detection is by command name: argv[0], and any token that begins a new
29
+ * command after a shell operator, with leading `KEY=VAL` assignments skipped
30
+ * and the path and `.exe` decoration stripped. That is the honest 90%.
31
+ * `npm run dev` whose package script shells out to bun is undetectable from
32
+ * here, and guessing would cost false positives on names that merely start
33
+ * with the same letters (`bundle exec`).
34
+ *
35
+ * Returns the canonical runtime name (`bun` for `bunx` too) or null.
36
+ */
37
+ export function detectUnsupportedRuntime(argv: readonly string[]): string | null {
38
+ let atCommandStart = true;
39
+ for (const token of argv) {
40
+ if (atCommandStart && ENV_ASSIGNMENT.test(token)) continue;
41
+ if (SHELL_OPERATORS.has(token)) {
42
+ atCommandStart = true;
43
+ continue;
44
+ }
45
+ if (atCommandStart) {
46
+ const runtime = UNSUPPORTED_RUNTIME_BINARIES.get(commandBasename(token));
47
+ if (runtime !== undefined) return runtime;
48
+ atCommandStart = false;
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+
54
+ /**
55
+ * The one warning. It has to say both halves of what is lost: the loader swap
56
+ * (interception itself) and the net guard (the socket backstop that would
57
+ * otherwise catch the egress), because the guard is installed by the same
58
+ * `--import`ed register module and is therefore just as absent.
59
+ */
60
+ export function formatUnsupportedRuntimeWarning(runtime: string): string {
61
+ return (
62
+ ` ⚠ runtime: pyric interception is not supported under \`${runtime}\`. It does not evaluate ` +
63
+ `Node loader hooks, so the child's firebase/firebase-admin imports will NOT be rewritten and ` +
64
+ `may reach LIVE Firebase. The net-guard socket backstop also only applies under Node, so it ` +
65
+ `will not catch that egress either. Run the command under \`node\` (or \`npx tsx\`) for the ` +
66
+ `sandbox swap. Warning only: nothing was blocked.\n`
67
+ );
68
+ }