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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (424) hide show
  1. package/dist/cli/serve.js +4 -4
  2. package/dist/cli/serve.js.map +1 -1
  3. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  4. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  5. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  6. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  7. package/dist/conformance/.generated/can-i-use.js +2 -2
  8. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  9. package/dist/serve/bundler.d.ts +13 -8
  10. package/dist/serve/bundler.d.ts.map +1 -1
  11. package/dist/serve/bundler.js +31 -36
  12. package/dist/serve/bundler.js.map +1 -1
  13. package/dist/serve/docs-ui/docs/_rhythm/index.html +1 -1
  14. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +1 -1
  15. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +1 -1
  16. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +1 -1
  17. package/dist/serve/docs-ui/docs/ai-compat/index.html +1 -1
  18. package/dist/serve/docs-ui/docs/api-reference/index.html +2 -2
  19. package/dist/serve/docs-ui/docs/api-reference.md +1 -1
  20. package/dist/serve/docs-ui/docs/app-compat/index.html +1 -1
  21. package/dist/serve/docs-ui/docs/auth-compat/index.html +1 -1
  22. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +44 -22
  23. package/dist/serve/docs-ui/docs/build/ai-logic.md +69 -21
  24. package/dist/serve/docs-ui/docs/build/authentication/index.html +1 -1
  25. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +1 -1
  26. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +1 -1
  27. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +1 -1
  28. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +1 -1
  29. package/dist/serve/docs-ui/docs/conformance-scores/index.html +1 -1
  30. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +1 -1
  31. package/dist/serve/docs-ui/docs/database-compat/index.html +1 -1
  32. package/dist/serve/docs-ui/docs/firestore-compat/index.html +1 -1
  33. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +1 -1
  34. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
  35. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works.md +2 -0
  36. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +3 -2
  37. package/dist/serve/docs-ui/docs/get-started/start-building.md +3 -1
  38. package/dist/serve/docs-ui/docs/index.json +349 -29
  39. package/dist/serve/docs-ui/docs/messaging-compat/index.html +1 -1
  40. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status/index.html +28 -0
  41. package/dist/serve/docs-ui/docs/observe/resolve-runtime-status.md +47 -0
  42. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +1 -1
  43. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +1 -1
  44. package/dist/serve/docs-ui/docs/overview/index.html +1 -1
  45. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +1 -1
  46. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
  47. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +1 -1
  48. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +1 -1
  49. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
  50. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
  51. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +1 -1
  52. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +1 -1
  53. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
  54. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +1 -1
  55. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +1 -1
  56. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
  57. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
  58. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
  59. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
  60. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
  61. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
  62. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
  63. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
  64. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
  65. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
  66. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
  67. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +168 -76
  68. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +156 -73
  69. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
  70. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +11 -8
  71. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +17 -4
  72. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1 -1
  73. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1 -1
  74. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +1 -1
  75. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
  76. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +1 -1
  77. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +1 -1
  78. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
  79. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +37 -14
  80. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +28 -8
  81. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +1 -1
  82. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
  83. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
  84. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
  85. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
  86. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
  87. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
  88. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
  89. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
  90. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
  91. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
  92. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
  93. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
  94. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +1 -1
  95. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
  96. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
  97. package/dist/serve/docs-ui/docs/rules-compat/index.html +1 -1
  98. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +1 -1
  99. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +1 -1
  100. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +1 -1
  101. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
  102. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +1 -1
  103. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +1 -1
  104. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +1 -1
  105. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
  106. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +1 -1
  107. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +1 -1
  108. package/dist/serve/docs-ui/docs/storage-compat/index.html +1 -1
  109. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
  110. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
  111. package/dist/serve/docs-ui/docs/tutorial/index.html +429 -0
  112. package/dist/serve/docs-ui/docs/tutorial.md +701 -0
  113. package/dist/serve/docs-ui/llms.txt +3 -1
  114. package/dist/serve/entries/init.d.ts.map +1 -1
  115. package/dist/serve/entries/init.js +3 -0
  116. package/dist/serve/entries/init.js.map +1 -1
  117. package/dist/serve/entries/runtime.d.ts.map +1 -1
  118. package/dist/serve/entries/runtime.js +20 -5
  119. package/dist/serve/entries/runtime.js.map +1 -1
  120. package/dist/serve/entries/worker-runtime.d.ts +2 -2
  121. package/dist/serve/entries/worker-runtime.d.ts.map +1 -1
  122. package/dist/serve/entries/worker-runtime.js +45 -10
  123. package/dist/serve/entries/worker-runtime.js.map +1 -1
  124. package/dist/serve/runtime/chip-config.d.ts +19 -0
  125. package/dist/serve/runtime/chip-config.d.ts.map +1 -0
  126. package/dist/serve/runtime/chip-config.js +19 -0
  127. package/dist/serve/runtime/chip-config.js.map +1 -0
  128. package/dist/serve/runtime/chip-install.d.ts +10 -0
  129. package/dist/serve/runtime/chip-install.d.ts.map +1 -0
  130. package/dist/serve/runtime/chip-install.js +15 -0
  131. package/dist/serve/runtime/chip-install.js.map +1 -0
  132. package/dist/serve/runtime/chip.d.ts +17 -0
  133. package/dist/serve/runtime/chip.d.ts.map +1 -0
  134. package/dist/serve/runtime/chip.js +257 -0
  135. package/dist/serve/runtime/chip.js.map +1 -0
  136. package/dist/serve/runtime/manifest.d.ts +22 -0
  137. package/dist/serve/runtime/manifest.d.ts.map +1 -0
  138. package/dist/serve/runtime/manifest.js +20 -0
  139. package/dist/serve/runtime/manifest.js.map +1 -0
  140. package/dist/serve/runtime/status.d.ts +49 -0
  141. package/dist/serve/runtime/status.d.ts.map +1 -0
  142. package/dist/serve/runtime/status.js +164 -0
  143. package/dist/serve/runtime/status.js.map +1 -0
  144. package/dist/serve/runtime/worker-connection.d.ts +4 -0
  145. package/dist/serve/runtime/worker-connection.d.ts.map +1 -0
  146. package/dist/serve/runtime/worker-connection.js +11 -0
  147. package/dist/serve/runtime/worker-connection.js.map +1 -0
  148. package/dist/serve/runtime/worker-generation.d.ts +14 -0
  149. package/dist/serve/runtime/worker-generation.d.ts.map +1 -0
  150. package/dist/serve/runtime/worker-generation.js +56 -0
  151. package/dist/serve/runtime/worker-generation.js.map +1 -0
  152. package/dist/serve/runtime/worker-replacement.d.ts +18 -0
  153. package/dist/serve/runtime/worker-replacement.d.ts.map +1 -0
  154. package/dist/serve/runtime/worker-replacement.js +29 -0
  155. package/dist/serve/runtime/worker-replacement.js.map +1 -0
  156. package/dist/serve/standalone-assets.d.ts +2 -2
  157. package/dist/serve/standalone-assets.d.ts.map +1 -1
  158. package/dist/serve/standalone-assets.js +1 -1
  159. package/dist/serve/standalone-assets.js.map +1 -1
  160. package/dist/serve/studio-ui/assets/{RulesCodeEditor-CxVYcZXw.js → RulesCodeEditor-BDlH-5lp.js} +1 -1
  161. package/dist/serve/studio-ui/assets/{index-cpSfgQ7H.js → index-Bf9SSE8L.js} +5 -5
  162. package/dist/serve/studio-ui/assets/{seed-DeuFKi4J.js → seed-D_UjxfOU.js} +1 -1
  163. package/dist/serve/studio-ui/index.html +1 -1
  164. package/dist/serve/vite-ai-config.d.ts +25 -0
  165. package/dist/serve/vite-ai-config.d.ts.map +1 -0
  166. package/dist/serve/vite-ai-config.js +45 -0
  167. package/dist/serve/vite-ai-config.js.map +1 -0
  168. package/dist/serve/vite-plugin.d.ts +17 -36
  169. package/dist/serve/vite-plugin.d.ts.map +1 -1
  170. package/dist/serve/vite-plugin.js +38 -57
  171. package/dist/serve/vite-plugin.js.map +1 -1
  172. package/dist/serve/vite-rules-source.d.ts +8 -0
  173. package/dist/serve/vite-rules-source.d.ts.map +1 -0
  174. package/dist/serve/vite-rules-source.js +23 -0
  175. package/dist/serve/vite-rules-source.js.map +1 -0
  176. package/dist/serve/vite-worker-runtime.d.ts +20 -0
  177. package/dist/serve/vite-worker-runtime.d.ts.map +1 -0
  178. package/dist/serve/vite-worker-runtime.js +25 -0
  179. package/dist/serve/vite-worker-runtime.js.map +1 -0
  180. package/dist/serve/worker/client/connection.d.ts +7 -2
  181. package/dist/serve/worker/client/connection.d.ts.map +1 -1
  182. package/dist/serve/worker/client/connection.js +13 -16
  183. package/dist/serve/worker/client/connection.js.map +1 -1
  184. package/dist/serve/worker/client/core.d.ts +7 -0
  185. package/dist/serve/worker/client/core.d.ts.map +1 -1
  186. package/dist/serve/worker/client/core.js +28 -0
  187. package/dist/serve/worker/client/core.js.map +1 -1
  188. package/dist/serve/worker/client/runtime-control.d.ts +8 -0
  189. package/dist/serve/worker/client/runtime-control.d.ts.map +1 -0
  190. package/dist/serve/worker/client/runtime-control.js +11 -0
  191. package/dist/serve/worker/client/runtime-control.js.map +1 -0
  192. package/dist/serve/worker/entry.js +44 -2
  193. package/dist/serve/worker/entry.js.map +1 -1
  194. package/dist/serve/worker/host/core.js +1 -1
  195. package/dist/serve/worker/host/core.js.map +1 -1
  196. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
  197. package/dist/serve/worker/host/firestore-writes.js +3 -2
  198. package/dist/serve/worker/host/firestore-writes.js.map +1 -1
  199. package/dist/serve/worker/host/studio.js +1 -1
  200. package/dist/serve/worker/host/studio.js.map +1 -1
  201. package/dist/serve/worker/host-context.d.ts +1 -1
  202. package/dist/serve/worker/host-context.d.ts.map +1 -1
  203. package/dist/serve/worker/index.d.ts +2 -1
  204. package/dist/serve/worker/index.d.ts.map +1 -1
  205. package/dist/serve/worker/index.js +2 -1
  206. package/dist/serve/worker/index.js.map +1 -1
  207. package/dist/serve/worker/protocol.d.ts +15 -1
  208. package/dist/serve/worker/protocol.d.ts.map +1 -1
  209. package/dist/serve/worker/protocol.js +2 -2
  210. package/dist/serve/worker/protocol.js.map +1 -1
  211. package/dist/serve/worker/retirement.d.ts +21 -0
  212. package/dist/serve/worker/retirement.d.ts.map +1 -0
  213. package/dist/serve/worker/retirement.js +97 -0
  214. package/dist/serve/worker/retirement.js.map +1 -0
  215. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  216. package/dist/serve/worker/serve-init.js +5 -6
  217. package/dist/serve/worker/serve-init.js.map +1 -1
  218. package/dist/vite.d.ts +1 -0
  219. package/dist/vite.d.ts.map +1 -1
  220. package/dist/vite.js.map +1 -1
  221. package/package.json +6 -4
  222. package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
  223. package/src/assurance/attachment.ts +211 -0
  224. package/src/assurance/browser.ts +80 -0
  225. package/src/assurance/campaign.ts +496 -0
  226. package/src/assurance/capabilities.ts +446 -0
  227. package/src/assurance/cases.ts +43 -0
  228. package/src/assurance/index.ts +75 -0
  229. package/src/assurance/runner.ts +885 -0
  230. package/src/assurance/tool-names.ts +15 -0
  231. package/src/assurance/tools.ts +830 -0
  232. package/src/assurance/types.ts +352 -0
  233. package/src/assurance/validation.ts +434 -0
  234. package/src/bridge/client/bridge.ts +550 -0
  235. package/src/bridge/client/dispatch.ts +137 -0
  236. package/src/bridge/client.ts +45 -0
  237. package/src/bridge/protocol.ts +351 -0
  238. package/src/bridge/server/audit.ts +53 -0
  239. package/src/bridge/server/bridge.ts +597 -0
  240. package/src/bridge/server/headless.ts +160 -0
  241. package/src/bridge/server/json-schema-to-zod.ts +108 -0
  242. package/src/bridge/server/local-bridge.ts +66 -0
  243. package/src/bridge/server/logger.ts +50 -0
  244. package/src/bridge/server/mcp-contract.ts +93 -0
  245. package/src/bridge/server/mcp.ts +129 -0
  246. package/src/bridge/server/peer.ts +232 -0
  247. package/src/bridge/server/standalone.ts +347 -0
  248. package/src/bridge/server/tool-metadata.ts +99 -0
  249. package/src/bridge/server.ts +28 -0
  250. package/src/cli/can-i-use.ts +50 -0
  251. package/src/cli/cli.test.ts +493 -0
  252. package/src/cli/database-rules.ts +329 -0
  253. package/src/cli/dev-runner.ts +282 -0
  254. package/src/cli/firebase-json.ts +100 -0
  255. package/src/cli/firestore-indexes.ts +70 -0
  256. package/src/cli/index.ts +425 -0
  257. package/src/cli/init.ts +260 -0
  258. package/src/cli/mcp-proxy.ts +196 -0
  259. package/src/cli/parse-args.ts +80 -0
  260. package/src/cli/rules.ts +259 -0
  261. package/src/cli/scope.ts +67 -0
  262. package/src/cli/serve.ts +996 -0
  263. package/src/cli/service-commands.ts +73 -0
  264. package/src/cli/snapshot.ts +164 -0
  265. package/src/cli/storage-rules.ts +172 -0
  266. package/src/cli/verify.ts +416 -0
  267. package/src/conformance/.generated/can-i-use-browser.ts +113 -0
  268. package/src/conformance/.generated/can-i-use.ts +117 -0
  269. package/src/conformance/.generated/conformance-docs.ts +14 -0
  270. package/src/conformance/browser.ts +24 -0
  271. package/src/conformance/can-i-use-tool.ts +51 -0
  272. package/src/conformance/can-i-use.ts +18 -0
  273. package/src/conformance/docs.ts +8 -0
  274. package/src/conformance/index.ts +20 -0
  275. package/src/conformance/tools.ts +16 -0
  276. package/src/credentials/core/memoize-ttl.ts +142 -0
  277. package/src/credentials/core/types.ts +10 -0
  278. package/src/credentials/node/from-adc.ts +96 -0
  279. package/src/credentials/node/from-service-account.ts +133 -0
  280. package/src/credentials/node/index.ts +6 -0
  281. package/src/discover/concurrency.ts +127 -0
  282. package/src/discover/crawler-adapter.ts +142 -0
  283. package/src/discover/crawler.ts +1127 -0
  284. package/src/discover/credential-free.ts +27 -0
  285. package/src/discover/findCollectionGroup.ts +131 -0
  286. package/src/discover/firestore-source.ts +59 -0
  287. package/src/discover/index.ts +5 -0
  288. package/src/discover/merge.ts +523 -0
  289. package/src/discover/session.ts +402 -0
  290. package/src/discover/tools.ts +201 -0
  291. package/src/discover/types.ts +187 -0
  292. package/src/discover/wire.ts +324 -0
  293. package/src/functions-rtdb/child.ts +382 -0
  294. package/src/functions-rtdb/delivery.ts +7 -0
  295. package/src/functions-rtdb/discovery.ts +136 -0
  296. package/src/functions-rtdb/event.ts +64 -0
  297. package/src/functions-rtdb/execution.ts +111 -0
  298. package/src/functions-rtdb/in-memory-delivery.ts +40 -0
  299. package/src/functions-rtdb/project.ts +74 -0
  300. package/src/functions-rtdb/projection.ts +104 -0
  301. package/src/functions-rtdb/reference-pattern.ts +20 -0
  302. package/src/functions-rtdb/remote-delivery.ts +23 -0
  303. package/src/pkg-version.ts +49 -0
  304. package/src/register/esm-exports.ts +63 -0
  305. package/src/register/hooks.ts +30 -0
  306. package/src/register/index.ts +150 -0
  307. package/src/register/mapping.ts +33 -0
  308. package/src/remote/index.ts +1050 -0
  309. package/src/rtdb/crawl-snapshot.ts +118 -0
  310. package/src/rtdb/inspection.ts +137 -0
  311. package/src/rtdb/load-rules-document.ts +56 -0
  312. package/src/rtdb/rules-generation-tool.ts +38 -0
  313. package/src/rtdb/rules-json.ts +29 -0
  314. package/src/serve/activity-guard.ts +29 -0
  315. package/src/serve/activity-route.ts +164 -0
  316. package/src/serve/activity-warning.ts +26 -0
  317. package/src/serve/bridge-mount.ts +200 -0
  318. package/src/serve/bundler.ts +519 -0
  319. package/src/serve/capture-store.ts +65 -0
  320. package/src/serve/discovery.ts +199 -0
  321. package/src/serve/entries/ai.ts +292 -0
  322. package/src/serve/entries/app-backend.ts +4 -0
  323. package/src/serve/entries/app-client.ts +26 -0
  324. package/src/serve/entries/app-session-store.ts +47 -0
  325. package/src/serve/entries/app.ts +11 -0
  326. package/src/serve/entries/auth-helper-core.ts +181 -0
  327. package/src/serve/entries/auth-helper-dom.ts +134 -0
  328. package/src/serve/entries/auth-helper-runtime.ts +20 -0
  329. package/src/serve/entries/auth.ts +255 -0
  330. package/src/serve/entries/bridge-url.ts +31 -0
  331. package/src/serve/entries/database.ts +129 -0
  332. package/src/serve/entries/firestore.ts +232 -0
  333. package/src/serve/entries/init.ts +49 -0
  334. package/src/serve/entries/keepalive.ts +46 -0
  335. package/src/serve/entries/messaging-sw.ts +75 -0
  336. package/src/serve/entries/messaging.ts +96 -0
  337. package/src/serve/entries/runtime.ts +556 -0
  338. package/src/serve/entries/session-store.ts +97 -0
  339. package/src/serve/entries/storage.ts +92 -0
  340. package/src/serve/entries/tab-sync-wiring.ts +274 -0
  341. package/src/serve/entries/worker-runtime.ts +135 -0
  342. package/src/serve/init-payload.ts +42 -0
  343. package/src/serve/namespace.ts +675 -0
  344. package/src/serve/open-browser.ts +68 -0
  345. package/src/serve/rules.ts +272 -0
  346. package/src/serve/runtime/chip-config.ts +30 -0
  347. package/src/serve/runtime/chip-install.ts +27 -0
  348. package/src/serve/runtime/chip.ts +282 -0
  349. package/src/serve/runtime/manifest.ts +37 -0
  350. package/src/serve/runtime/status.ts +216 -0
  351. package/src/serve/runtime/worker-connection.ts +14 -0
  352. package/src/serve/runtime/worker-generation.ts +75 -0
  353. package/src/serve/runtime/worker-replacement.ts +42 -0
  354. package/src/serve/sandbox-marker.ts +31 -0
  355. package/src/serve/server.ts +428 -0
  356. package/src/serve/standalone-assets.ts +180 -0
  357. package/src/serve/state-store.ts +166 -0
  358. package/src/serve/studio/disk-project-store.ts +185 -0
  359. package/src/serve/studio/disk-workspace.ts +162 -0
  360. package/src/serve/studio/index.ts +20 -0
  361. package/src/serve/studio/routes.ts +237 -0
  362. package/src/serve/studio/store-types.ts +48 -0
  363. package/src/serve/studio/studio-storage.test.ts +289 -0
  364. package/src/serve/vite-ai-config.ts +77 -0
  365. package/src/serve/vite-plugin.ts +1075 -0
  366. package/src/serve/vite-rules-source.ts +28 -0
  367. package/src/serve/vite-worker-runtime.ts +51 -0
  368. package/src/serve/worker/activity-bootstrap.ts +24 -0
  369. package/src/serve/worker/client/admin-firestore.ts +38 -0
  370. package/src/serve/worker/client/ai.ts +124 -0
  371. package/src/serve/worker/client/auth.ts +489 -0
  372. package/src/serve/worker/client/connection.ts +227 -0
  373. package/src/serve/worker/client/core.ts +384 -0
  374. package/src/serve/worker/client/disconnect.ts +45 -0
  375. package/src/serve/worker/client/firestore-reads.ts +181 -0
  376. package/src/serve/worker/client/firestore-refs.ts +226 -0
  377. package/src/serve/worker/client/firestore-writes.ts +232 -0
  378. package/src/serve/worker/client/handles.ts +91 -0
  379. package/src/serve/worker/client/messaging.ts +119 -0
  380. package/src/serve/worker/client/presence.ts +174 -0
  381. package/src/serve/worker/client/rtdb.ts +311 -0
  382. package/src/serve/worker/client/rules.ts +63 -0
  383. package/src/serve/worker/client/runtime-control.ts +22 -0
  384. package/src/serve/worker/client/service-worker-connection.ts +59 -0
  385. package/src/serve/worker/client/snapshots.ts +86 -0
  386. package/src/serve/worker/client/storage.ts +195 -0
  387. package/src/serve/worker/client/studio.ts +88 -0
  388. package/src/serve/worker/client.ts +57 -0
  389. package/src/serve/worker/durable-persistence.ts +137 -0
  390. package/src/serve/worker/entry.ts +223 -0
  391. package/src/serve/worker/host/admin-firestore.ts +88 -0
  392. package/src/serve/worker/host/connection.ts +179 -0
  393. package/src/serve/worker/host/core.ts +387 -0
  394. package/src/serve/worker/host/dispatch.ts +316 -0
  395. package/src/serve/worker/host/firestore-reads.ts +117 -0
  396. package/src/serve/worker/host/firestore-writes.ts +456 -0
  397. package/src/serve/worker/host/presence.ts +312 -0
  398. package/src/serve/worker/host/rtdb.ts +136 -0
  399. package/src/serve/worker/host/rules.ts +128 -0
  400. package/src/serve/worker/host/storage.ts +312 -0
  401. package/src/serve/worker/host/studio.ts +75 -0
  402. package/src/serve/worker/host/subscriptions.ts +238 -0
  403. package/src/serve/worker/host-ai.ts +165 -0
  404. package/src/serve/worker/host-auth.ts +469 -0
  405. package/src/serve/worker/host-context.ts +273 -0
  406. package/src/serve/worker/host-events.ts +94 -0
  407. package/src/serve/worker/host-messaging.ts +240 -0
  408. package/src/serve/worker/host.ts +47 -0
  409. package/src/serve/worker/index.ts +196 -0
  410. package/src/serve/worker/presence-timing.ts +15 -0
  411. package/src/serve/worker/protocol.ts +1124 -0
  412. package/src/serve/worker/retirement.ts +125 -0
  413. package/src/serve/worker/serve-init.ts +605 -0
  414. package/src/serve/worker/service-worker-channel.ts +33 -0
  415. package/src/serve/worker/service-worker-relay.ts +86 -0
  416. package/src/serve/writer-lock.ts +53 -0
  417. package/src/verify/cases.ts +233 -0
  418. package/src/verify/fixture.ts +258 -0
  419. package/src/verify/index.ts +519 -0
  420. package/src/verify/tools.ts +108 -0
  421. package/src/version/compat-target.ts +17 -0
  422. package/src/vite.ts +18 -0
  423. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -31
  424. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -29
@@ -0,0 +1,70 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { dirname, resolve as resolvePath } from 'node:path';
3
+ import {
4
+ ExtractFirestoreIndexesHandler,
5
+ type ExtractIndexesOptions,
6
+ } from 'pyric/rules/internal/extract';
7
+ import type { ParsedArgs } from './parse-args.js';
8
+ import { readFirebaseJson, type FirebaseJson } from './firebase-json.js';
9
+
10
+ type ExtractResult = ReturnType<ExtractFirestoreIndexesHandler['execute']>;
11
+
12
+ export interface FirestoreIndexesDeps {
13
+ extract?: (options: ExtractIndexesOptions) => ExtractResult;
14
+ readFirebaseJson?: (cwd: string) => Promise<FirebaseJson>;
15
+ writeFile?: typeof writeFile;
16
+ mkdir?: typeof mkdir;
17
+ cwd?: string;
18
+ stdout?: { write(s: string): void };
19
+ stderr?: { write(s: string): void };
20
+ }
21
+
22
+ export async function runFirestoreIndexesGenerate(
23
+ parsed: ParsedArgs,
24
+ deps: FirestoreIndexesDeps = {},
25
+ ): Promise<number> {
26
+ const out = deps.stdout ?? process.stdout;
27
+ const err = deps.stderr ?? process.stderr;
28
+ const cwd = deps.cwd ?? process.cwd();
29
+ if (parsed.positional.length === 0) {
30
+ err.write(
31
+ 'pyric firestore indexes generate: missing source path. Usage: pyric firestore indexes generate <path...> [--out <path>]\n',
32
+ );
33
+ return 1;
34
+ }
35
+
36
+ const extract =
37
+ deps.extract ??
38
+ ((options: ExtractIndexesOptions) => new ExtractFirestoreIndexesHandler().execute(options));
39
+ const result = extract({ paths: parsed.positional.map((path) => resolvePath(cwd, path)) });
40
+ if (!result.success) {
41
+ err.write(`pyric firestore indexes generate: ${result.error.message}\n`);
42
+ return 2;
43
+ }
44
+
45
+ const outFlag = parsed.flags.get('out');
46
+ let configuredPath: string | undefined;
47
+ if (typeof outFlag !== 'string') {
48
+ try {
49
+ configuredPath = (await (deps.readFirebaseJson ?? readFirebaseJson)(cwd)).firestore?.indexes;
50
+ } catch {
51
+ configuredPath = undefined;
52
+ }
53
+ }
54
+ const outputPath = resolvePath(
55
+ cwd,
56
+ typeof outFlag === 'string' ? outFlag : configuredPath ?? 'firestore.indexes.json',
57
+ );
58
+ await (deps.mkdir ?? mkdir)(dirname(outputPath), { recursive: true });
59
+ await (deps.writeFile ?? writeFile)(
60
+ outputPath,
61
+ `${JSON.stringify(result.data.config, null, 2)}\n`,
62
+ 'utf-8',
63
+ );
64
+
65
+ out.write(`pyric firestore indexes generate: wrote ${outputPath}\n`);
66
+ for (const warning of result.data.warnings) {
67
+ err.write(`pyric firestore indexes generate: warning: ${warning.file}: ${warning.message}\n`);
68
+ }
69
+ return 0;
70
+ }
@@ -0,0 +1,425 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `pyric` CLI — front door to the bridge + project tooling.
4
+ *
5
+ * Subcommands:
6
+ * pyric bridge [--port N] [--project ID]
7
+ * pyric dev [--port N] [--host H] [--no-cache] [--bridge] [--ui] [--seed FILE] [--no-watch] [--no-open] [--no-capture] [--no-run] [--json] [--persist] [--fresh] [-- <cmd>]
8
+ * pyric init [dir] [--template web|node] [--name N] [--force] [--json]
9
+ * pyric vendor [dir] [--json]
10
+ * pyric snapshot [--out FILE] [--port N] [--force] [--json] [--include-passwords]
11
+ * pyric mcp
12
+ * pyric firestore rules lint <path>
13
+ * pyric firestore rules validate <path>
14
+ * pyric firestore rules simulate [--stdin]
15
+ * pyric firestore rules resolve <path> [--out <path>]
16
+ * pyric firestore indexes generate <path...> [--out <path>]
17
+ * pyric storage rules lint <path>
18
+ * pyric storage rules simulate [--stdin]
19
+ * pyric database rules lint <path>
20
+ * pyric database rules validate <path>
21
+ * pyric database rules simulate [--stdin]
22
+ * pyric database rules generate [--config <path>] [--out <path>]
23
+ * pyric --help
24
+ * pyric --version
25
+ *
26
+ * Env vars:
27
+ * PYRIC_PORT — bridge port (default 5174)
28
+ * PYRIC_PROJECT — project label for bridge health and audit output
29
+ * PYRIC_VERBOSE — set to 1 for per-tool-call logging
30
+ * FIREBASE_SA_BASE64 — base64-encoded service-account JSON (Rules Test API verify)
31
+ * GOOGLE_APPLICATION_CREDENTIALS — path to service-account JSON (Rules Test API verify)
32
+ *
33
+ * Exit codes:
34
+ * 0 success
35
+ * 1 usage error
36
+ * 2 runtime error
37
+ */
38
+
39
+ import { realpathSync } from 'node:fs';
40
+ import { fileURLToPath } from 'node:url';
41
+ import { parseArgs, type ParsedArgs } from './parse-args.js';
42
+ import { runInit, runVendor } from './init.js';
43
+ import { runSnapshot } from './snapshot.js';
44
+ import { runVerify } from './verify.js';
45
+ import { runMcpProxy } from './mcp-proxy.js';
46
+ import { pyricVersion } from '../serve/standalone-assets.js';
47
+ import { cliVersion } from '../pkg-version.js';
48
+ import { FIREBASE_TESTED_AGAINST } from '../version/compat-target.js';
49
+ import { dispatchServiceCommand } from './service-commands.js';
50
+
51
+ // The standalone binary bakes the real `pyric` version onto the embedded-assets
52
+ // global; the npm bin has no such global and falls back to '0.0.0'.
53
+ const VERSION = pyricVersion();
54
+
55
+ function printUsage(): void {
56
+ process.stdout.write(`pyric ${VERSION}
57
+ Firebase for agents — bridge an in-browser pyric sandbox to external MCP
58
+ clients (Claude Code, Cursor, ...).
59
+
60
+ USAGE
61
+ pyric bridge [flags]
62
+ pyric dev [flags] [-- <cmd>]
63
+ pyric init [dir] [--template=web|node]
64
+ pyric snapshot [--out=FILE]
65
+ pyric verify [fixture|dir] [--engine sandbox|rules-test-api|both]
66
+ pyric can-i-use <feature> [--json]
67
+ pyric verify cases [fixture] [--service firestore] [--out FILE]
68
+ pyric firestore rules lint <path>
69
+ pyric firestore rules validate <path>
70
+ pyric firestore rules simulate [--stdin]
71
+ pyric firestore rules resolve <path> [--out <path>]
72
+ pyric firestore indexes generate <path...> [--out <path>]
73
+ pyric storage rules lint <path>
74
+ pyric storage rules simulate [--stdin]
75
+ pyric database rules lint <path>
76
+ pyric database rules validate <path>
77
+ pyric database rules simulate [--stdin]
78
+ pyric database rules generate [--config <path>] [--out <path>]
79
+ pyric --help
80
+ pyric --version
81
+
82
+ COMMANDS
83
+ bridge Start the HTTP+WebSocket bridge external MCP clients point at.
84
+ dev Serve the app locally with the pyric sandbox standing in for
85
+ Firebase — unmodified firebase/* imports hit an in-page sandbox
86
+ with your firestore.rules deployed. Also runs your own dev
87
+ command (\`-- <cmd>\`, else the package.json \`dev\` script) with
88
+ unchanged firebase-admin/firebase imports routed to the
89
+ sandbox (PYRIC_SANDBOX + \`--import @pyric/cli/register\`). A
90
+ firebase.json Functions source is discovered automatically;
91
+ supported RTDB onValueCreated exports run in isolated Node.
92
+ init [dir] Scaffold a pyric project. --template=web (default; Vite app
93
+ on \`@pyric/cli/vite\`), static (\`pyric dev\`), or node.
94
+ --name=NAME --force (overwrite scaffold files) --json (machine
95
+ output on stdout). Never prompts; rerunning is safe.
96
+ Greenfield shortcut: \`npm create pyric [dir]\`.
97
+ vendor [dir] Retrofit: vendor pyric + @pyric/cli into an existing
98
+ project (lay file: tarballs into vendor/ + merge their
99
+ deps into package.json). Scaffolds nothing. Then run
100
+ bun install. Standalone binary only.
101
+ mcp Stdio MCP server for editors (Cursor / Claude /
102
+ Antigravity). Hosts a headless in-process sandbox,
103
+ or attaches to a running \`pyric dev --bridge\`
104
+ (found via .pyric/serve.json) for shared-live Studio.
105
+ snapshot [--out=FILE] Promote lived sandbox state (live dev --persist, else
106
+ .pyric/state/state.json) to a committable fixture that
107
+ \`pyric dev --seed FILE\` re-serves. Passwords are redacted
108
+ by default (--include-passwords keeps them). --port, --force, --json.
109
+ verify [fixture|dir] Replay a captured sandbox session against candidate rules
110
+ for the Firestore/RTDB services present in the fixture.
111
+ No arg replays the latest \`pyric dev\` capture
112
+ (.pyric/last-session.json). --service filters services.
113
+ --engine sandbox (default), rules-test-api, or both.
114
+ Hosted Rules Test API verification is Firestore-only
115
+ and uses --project plus the configured Google credentials.
116
+ --rules service=path overrides firebase.json resolution
117
+ (repeat for mixed captures). --json. Exit 1 on divergence.
118
+ can-i-use <feature> Report Pyric availability, behavior fidelity, and assurance
119
+ eligibility from the canonical conformance model. A surface
120
+ prefix such as firestore-rules/getAfter disambiguates names.
121
+ Exact and fuzzy queries use the same model as MCP. --json.
122
+ verify cases [fixture] Derive Firestore Rules Test API cases from a captured
123
+ fixture and print JSON, or write with --out FILE.
124
+ firestore rules lint Run the Firestore rules linter against a file.
125
+ firestore rules validate Validate Firestore rules structure against a file.
126
+ firestore rules simulate Run the local Firestore rules simulator.
127
+ firestore rules resolve Resolve Firestore 2+modules imports to one ruleset.
128
+ firestore indexes generate Generate firestore.indexes.json from application source.
129
+ storage rules lint Check Storage rules syntax locally.
130
+ storage rules simulate Run the local Storage rules evaluator.
131
+ database rules lint Run the Realtime Database rules expression linter.
132
+ database rules validate Validate Realtime Database rules expressions.
133
+ database rules simulate Run the local Realtime Database rules simulator.
134
+ database rules generate Compile a constraints module to database.rules.json.
135
+ CORE FLAGS (dev)
136
+ --port Port to serve on. Default 3473 — "FIRE" on a phone keypad (scans forward when taken;
137
+ macOS AirPlay squats 5000).
138
+ --host Host to bind. Default localhost.
139
+ --no-cache Rebuild the served pyric SDK bundles (skip ~/.pyric/serve-cache).
140
+ --only hosting Accepted for firebase-serve parity (hosting is all v1 serves).
141
+ --bridge Also mount the MCP bridge on the serve origin — agents point
142
+ at http://<host>:<port>/__pyric/mcp and drive the sandbox
143
+ living in the served page. --project labels health/audit.
144
+ --ui Also serve the Pyric Studio app at <url>/__pyric/ui/ (and
145
+ mount its disk-backed workspace + project data routes).
146
+ Auto-opens Studio instead of the served page. Needs a full
147
+ build so the app assets are present.
148
+ --seed FILE JSON map of "collection/doc" → fields, loaded admin-style.
149
+ Also accepts a pyric state file (from \`pyric snapshot\`,
150
+ detected by its version key) — seeds docs + auth users.
151
+ into the page sandbox before app code runs.
152
+ --no-watch Disable firestore.rules hot-reload (on by default).
153
+ --no-open Don't auto-open the browser. dev opens the served page
154
+ by default (the sandbox is browser-resident); auto-open
155
+ is already suppressed under --json, no TTY, and CI.
156
+ --no-capture Don't write the session capture. dev writes
157
+ .pyric/last-session.json by default so \`pyric verify\`
158
+ can replay your session; --no-capture disables it.
159
+ --allowed-host H Allow an extra Host header past the DNS-rebinding guard
160
+ (comma-separated; localhost/127.0.0.1 always allowed).
161
+ --persist Persist sandbox state (docs + auth users) to
162
+ .pyric/state/state.json — survives reloads and dev
163
+ restarts. Once a state file exists it wins; --seed
164
+ applies only on the first (state-less) run. Ephemeral
165
+ is the default.
166
+ --fresh Requires --persist: discard the existing state file and
167
+ re-seed from scratch (escape hatch when you've edited
168
+ seed.json). Without --persist, --fresh errors — there is
169
+ no state file to discard. Half-reset warning: a browser
170
+ tab that already has sandbox data in IndexedDB keeps it
171
+ and writes it back to the new file; also clear the
172
+ browser store (Studio → Settings → Reset, or an
173
+ incognito window) for a full reset.
174
+ -- <cmd> Run <cmd> once the host is up, with PYRIC_SANDBOX set and
175
+ NODE_OPTIONS extended with --import @pyric/cli/register
176
+ so firebase-admin/firebase resolve to the sandbox. When
177
+ omitted, the package.json \`dev\` script runs (via the
178
+ detected package manager); no script → host-only.
179
+ --no-run Don't run the project's dev command (for users with their
180
+ own process manager). A declared Functions source still
181
+ runs. --json skips the dev command unless a \`-- <cmd>\`
182
+ is given explicitly.
183
+ --json One machine-readable line on stdout ({url, port, mcpUrl,
184
+ rulesHash, persist, restoredDocs, restoredUsers}); the
185
+ banner moves to stderr. Readiness probe:
186
+ GET <url>/__pyric/init.json → 200 (live rules hash).
187
+
188
+ CORE FLAGS (bridge)
189
+ --port Port to bind on 127.0.0.1. Default 5174. Env: PYRIC_PORT.
190
+ --project Project label surfaced in /health + audit output.
191
+ Env: PYRIC_PROJECT.
192
+
193
+ CREDENTIALS
194
+ Rules Test API verification resolves existing Google credentials:
195
+ 1. FIREBASE_SA_BASE64 base64-encoded service-account JSON (CI)
196
+ 2. GOOGLE_APPLICATION_CREDENTIALS path to a service-account JSON file
197
+ 3. ADC \`gcloud auth application-default login\` (ambient)
198
+ PYRIC_PROJECT / --project Firebase project id for Rules Test API verification
199
+ `);
200
+ }
201
+
202
+ function printVersion(): void {
203
+ process.stdout.write(
204
+ `@pyric/cli ${cliVersion()}\n` +
205
+ `Firebase ${FIREBASE_TESTED_AGAINST} (conformance-tested against this release)\n`,
206
+ );
207
+ }
208
+
209
+ async function runBridge(parsed: ParsedArgs): Promise<number> {
210
+ const removedFlags = [
211
+ 'mode',
212
+ 'auto-approve',
213
+ 'require-confirm',
214
+ 'require-confirm-all',
215
+ 'confirm-timeout',
216
+ 'non-interactive',
217
+ ];
218
+ for (const flag of removedFlags) {
219
+ if (parsed.flags.has(flag)) {
220
+ process.stderr.write(`pyric: unknown option '--${flag}' for pyric bridge.\n`);
221
+ return 1;
222
+ }
223
+ }
224
+
225
+ const flagPort = parsed.flags.get('port');
226
+ const port =
227
+ typeof flagPort === 'string'
228
+ ? Number(flagPort)
229
+ : process.env.PYRIC_PORT
230
+ ? Number(process.env.PYRIC_PORT)
231
+ : undefined;
232
+ if (port !== undefined && (!Number.isFinite(port) || port < 1 || port > 65535)) {
233
+ process.stderr.write(`pyric: invalid --port '${flagPort ?? process.env.PYRIC_PORT}'.\n`);
234
+ return 1;
235
+ }
236
+
237
+ const flagProject = parsed.flags.get('project');
238
+ const project =
239
+ typeof flagProject === 'string' ? flagProject : process.env.PYRIC_PROJECT ?? undefined;
240
+
241
+ let handle;
242
+ try {
243
+ const { startServer } = await import('@pyric/cli/bridge');
244
+ handle = await startServer({
245
+ port,
246
+ project,
247
+ });
248
+ } catch (err) {
249
+ process.stderr.write(
250
+ `pyric: failed to start bridge: ${err instanceof Error ? err.message : String(err)}\n`,
251
+ );
252
+ return 2;
253
+ }
254
+
255
+ // Graceful shutdown. Idempotent because:
256
+ // 1. npx forwards SIGINT to its child AND the terminal sends SIGINT
257
+ // to the process group, so one Ctrl-C delivers SIGINT TWICE to
258
+ // this process — without a guard, the handler ran twice and
259
+ // printed everything twice.
260
+ // 2. An impatient user mashing Ctrl-C expects "now I mean it" to
261
+ // force-exit, not enqueue more clean-shutdowns.
262
+ let shuttingDown = false;
263
+ const stop = async (signal: NodeJS.Signals) => {
264
+ if (shuttingDown) {
265
+ process.stderr.write('pyric: force-exiting\n');
266
+ process.exit(130);
267
+ }
268
+ shuttingDown = true;
269
+ process.stdout.write(`\npyric: received ${signal}, stopping bridge...\n`);
270
+ // Hard safety net: clean shutdown is ~instant once sockets are
271
+ // forcibly closed (see handle.stop in standalone.ts). If something
272
+ // hangs anyway — peer pre-handshake, MCP transport in mid-write —
273
+ // don't make the user wait forever.
274
+ const forceExitTimer = setTimeout(() => {
275
+ process.stderr.write('pyric: shutdown taking longer than expected, force-exiting\n');
276
+ process.exit(130);
277
+ }, 2000);
278
+ forceExitTimer.unref();
279
+ try {
280
+ await handle.stop();
281
+ } catch (err) {
282
+ process.stderr.write(
283
+ `pyric: error during shutdown: ${err instanceof Error ? err.message : String(err)}\n`,
284
+ );
285
+ }
286
+ clearTimeout(forceExitTimer);
287
+ process.exit(signal === 'SIGINT' ? 130 : 0);
288
+ };
289
+ process.on('SIGINT', () => void stop('SIGINT'));
290
+ process.on('SIGTERM', () => void stop('SIGTERM'));
291
+
292
+ process.stdout.write(
293
+ `\npyric bridge ${VERSION} ready\n` +
294
+ ` target: sandbox\n` +
295
+ ` project: ${handle.bridge.project}\n` +
296
+ ` health: ${handle.url}/health\n` +
297
+ ` mcp: ${handle.url}/mcp\n` +
298
+ ` sandbox: ${handle.url.replace('http://', 'ws://')}/sandbox\n` +
299
+ (handle.auditLogPath ? ` audit: ${handle.auditLogPath}\n` : '') +
300
+ `\nRegister with Claude Code:\n` +
301
+ ` claude mcp add --transport http pyric ${handle.url}/mcp --scope project\n` +
302
+ `\nBridge will log peer connect/disconnect to stderr. Set PYRIC_VERBOSE=1 for per-tool-call logs.\n` +
303
+ `Press Ctrl-C to stop.\n`,
304
+ );
305
+
306
+ // Keep the event loop alive.
307
+ return await new Promise<number>(() => {});
308
+ }
309
+
310
+ /**
311
+ * Dispatch a parsed CLI invocation to its subcommand handler.
312
+ * Exported so the test suite can drive the dispatcher directly
313
+ * without spawning a child process. `process.exit` is not called
314
+ * here — the caller (the top-level `main()` below) does that.
315
+ */
316
+ export async function dispatch(parsed: ParsedArgs): Promise<number> {
317
+ if (parsed.flags.get('help') || parsed.flags.get('h')) {
318
+ printUsage();
319
+ return 0;
320
+ }
321
+ if (parsed.flags.get('version') || parsed.flags.get('v')) {
322
+ printVersion();
323
+ return 0;
324
+ }
325
+
326
+ const serviceCommand = await dispatchServiceCommand(parsed);
327
+ if (serviceCommand !== null) return serviceCommand;
328
+
329
+ switch (parsed.subcommand) {
330
+ case null:
331
+ case undefined:
332
+ printUsage();
333
+ return parsed.subcommand === null ? 0 : 1;
334
+ case 'bridge':
335
+ return await runBridge(parsed);
336
+ case 'dev':
337
+ const { runServe } = await import('./serve.js');
338
+ return runServe(parsed);
339
+ case 'snapshot':
340
+ return await runSnapshot(parsed);
341
+ case 'verify':
342
+ return await runVerify(parsed);
343
+ case 'can-i-use':
344
+ const { runCanIUse } = await import('./can-i-use.js');
345
+ return runCanIUse(parsed);
346
+ case 'mcp':
347
+ return await runMcpProxy(parsed);
348
+ case 'init':
349
+ return await runInit(parsed);
350
+ case 'vendor':
351
+ return await runVendor(parsed);
352
+ default:
353
+ process.stderr.write(`pyric: unknown command '${parsed.subcommand}'.\n\n`);
354
+ printUsage();
355
+ return 1;
356
+ }
357
+ }
358
+
359
+ async function main(): Promise<number> {
360
+ const parsed = parseArgs(process.argv.slice(2));
361
+ return dispatch(parsed);
362
+ }
363
+
364
+ // Re-export parseArgs so the bin script + tests can share the parser.
365
+ export { parseArgs } from './parse-args.js';
366
+
367
+ /**
368
+ * True when this module is the executable entry rather than an import.
369
+ *
370
+ * Bun identifies source and compiled entry points with `import.meta.main`.
371
+ * Node does not, so compare real paths there: resolving both sides preserves
372
+ * npm's `node_modules/.bin/pyric` symlink behavior that a textual path check
373
+ * previously broke.
374
+ */
375
+ export function isDirectRun(): boolean {
376
+ if (import.meta.main) return true;
377
+ const argvEntry = process.argv[1];
378
+ if (!argvEntry) return false;
379
+ try {
380
+ return realpathSync(argvEntry) === realpathSync(fileURLToPath(import.meta.url));
381
+ } catch {
382
+ return false;
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Explicit executable entry: parse argv, dispatch, flush, exit.
388
+ *
389
+ * The compiled standalone binary calls this from its generated entry
390
+ * (scripts/compile.ts) instead of relying on {@link isDirectRun}: inside a
391
+ * `bun build --compile` binary this module is an import (import.meta.main is
392
+ * false) and `process.argv[1]` is the user's first argument, not a path — so
393
+ * direct-run detection is structurally false there and the binary would
394
+ * otherwise exit 0 silently.
395
+ */
396
+ export function runDirect(): void {
397
+ main().then(
398
+ (code) => exitAfterFlush(code),
399
+ (err) => {
400
+ process.stderr.write(
401
+ `pyric: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`,
402
+ );
403
+ exitAfterFlush(2);
404
+ },
405
+ );
406
+ }
407
+
408
+ if (isDirectRun()) runDirect();
409
+
410
+ /**
411
+ * Drain stdout + stderr before exiting. `process.exit()` does NOT wait
412
+ * for pipe-buffered output to flush — `process.stdout.write(text)`
413
+ * against a pipe (which `bash -c '$(pyric --help)'` creates) queues
414
+ * the data, and a bare `process.exit(0)` discards it on Linux Node 20.
415
+ * Symptom: `pyric --help | cat` prints nothing in CI but works in a
416
+ * TTY. The zero-byte write + callback pattern below queues behind any
417
+ * pending writes and only exits once they've been flushed to the
418
+ * underlying fd. See nodejs/node #6379.
419
+ */
420
+ function exitAfterFlush(code: number): void {
421
+ let pending = 2;
422
+ const done = () => { if (--pending === 0) process.exit(code); };
423
+ process.stdout.write('', done);
424
+ process.stderr.write('', done);
425
+ }