@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,45 @@
1
+ /**
2
+ * `@pyric/cli/bridge` — browser-side entry.
3
+ *
4
+ * Resolved by the `browser` condition in `package.json`'s exports map.
5
+ * Exports `connectBridge`, which the host app calls to register its
6
+ * in-page sandbox with a running pyric bridge process. After
7
+ * registration, MCP tool calls reaching the bridge are forwarded over
8
+ * WebSocket and dispatched into the local sandbox.
9
+ *
10
+ * The Node-side server entry lives in `./server.ts`. Wire format
11
+ * shared by both lives in `./protocol.ts`.
12
+ *
13
+ * ALSO reachable as `@pyric/cli/bridge/client` — an explicit, condition-free
14
+ * subpath for browser apps whose TYPE resolution doesn't apply the `browser`
15
+ * condition (Pyric Studio's `moduleResolution: bundler` tsconfig resolves the
16
+ * `./bridge` subpath's top-level `types` to the SERVER entry). Same file,
17
+ * same surface.
18
+ */
19
+
20
+ export type {
21
+ BridgeMessage,
22
+ HelloFromClient,
23
+ HelloFromBridge,
24
+ ToolCallRequest,
25
+ ToolCallResponse,
26
+ } from './protocol.js';
27
+ export {
28
+ DEFAULT_BRIDGE_PORT,
29
+ DEFAULT_SANDBOX_PATH,
30
+ } from './protocol.js';
31
+
32
+ export { connectBridge } from './client/bridge.js';
33
+ export type {
34
+ ConnectBridgeOptions,
35
+ ConnectedBridge,
36
+ ConnectedBridgeState,
37
+ SandboxToolDispatcher,
38
+ WorkerRelay,
39
+ } from './client/bridge.js';
40
+
41
+ // Re-anchor a served bridge URL to the page's own origin. The served app page
42
+ // and Pyric Studio both do this before connecting as the bridge peer (see
43
+ // `serve/entries/bridge-url.ts` for why the baked host can be the wrong
44
+ // machine). Pure + browser-safe; exported here so Studio reuses it verbatim.
45
+ export { toPageOriginWsUrl } from '../serve/entries/bridge-url.js';
@@ -0,0 +1,351 @@
1
+ /**
2
+ * Wire protocol shared by `@pyric/cli/bridge` (Node bridge) and
3
+ * `@pyric/cli/bridge` (in-browser sandbox connector).
4
+ *
5
+ * The bridge process speaks MCP HTTP to external agents (Claude Code,
6
+ * Cursor) on `/mcp` and WebSocket to the in-browser sandbox on
7
+ * `/sandbox`. Data-plane and sandbox-management tool calls received
8
+ * over MCP are forwarded to whichever browser tab is currently
9
+ * connected; the browser dispatches them into the local
10
+ * `LocalEnvironment` and returns the result.
11
+ *
12
+ * This module has NO runtime imports — only types — so it can be
13
+ * referenced from both the `node` and `browser` builds without
14
+ * pulling Node-specific or DOM-specific modules into the wrong
15
+ * environment.
16
+ */
17
+
18
+ // TYPE-ONLY imports (erased at build) — the wire payloads for the generic
19
+ // worker relay are the SharedWorker protocol's own op/sub messages, minus
20
+ // the port-level `t`/`id`/`subId` fields the relay re-mints per hop.
21
+ import type { OpMessage, SubMessage } from '../serve/worker/protocol.js';
22
+
23
+ /** Health report returned by the bridge's `GET /health` endpoint. */
24
+ export interface HealthReport {
25
+ status: 'ok';
26
+ /** Constant provenance marker: the programmatic bridge is sandbox-only. */
27
+ mode: 'sandbox';
28
+ /** Sandbox identifier surfaced in health and audit metadata. */
29
+ project: string;
30
+ /** Whether a browser tab is currently connected over `/sandbox`. */
31
+ sandboxConnected: boolean;
32
+ /** Bridge package version. */
33
+ version: string;
34
+ /** ISO timestamp the bridge started. */
35
+ startedAt: string;
36
+ /**
37
+ * Random identity, stable for this bridge process's lifetime. The discovery
38
+ * pointer (`.pyric/serve.json`) records the same value, so a proxy can confirm
39
+ * it reached the SAME server the pointer names — two sandboxes can collide on
40
+ * one port across loopback families (IPv4 `*:P` + IPv6 `[::1]:P`), and `mode`
41
+ * alone can't tell them apart. (Not `version` — that's hardcoded.)
42
+ */
43
+ instanceId: string;
44
+ }
45
+
46
+ /** Default port the standalone bridge binds to. */
47
+ export const DEFAULT_BRIDGE_PORT = 5174;
48
+
49
+ /** Default WS path the browser connects to. */
50
+ export const DEFAULT_SANDBOX_PATH = '/sandbox';
51
+
52
+ /** Default HTTP path the MCP client connects to. */
53
+ export const DEFAULT_MCP_PATH = '/mcp';
54
+
55
+ /** Default health endpoint path. */
56
+ export const DEFAULT_HEALTH_PATH = '/health';
57
+
58
+ /**
59
+ * WS close code the transport sends a sandbox peer when a NEWER registration
60
+ * displaces it (last-connection-wins). Application-defined (4000–4999 per RFC
61
+ * 6455 §7.4.2) so it survives every WS stack verbatim. The browser client
62
+ * treats this close as "the slot is legitimately held by another tab" and
63
+ * enters STANDBY (poll the health endpoint, reconnect only when the slot is
64
+ * vacant) instead of re-helloing — two open tabs used to kick each other in a
65
+ * perpetual last-wins fight, re-firing every relayed subscription and failing
66
+ * all in-flight worker ops once per cycle. Any OTHER close (server restart,
67
+ * network drop, tab-refresh takeover) keeps the immediate-reconnect loop.
68
+ */
69
+ export const PEER_REPLACED_CLOSE_CODE = 4001;
70
+
71
+ /** Human-readable reason sent with {@link PEER_REPLACED_CLOSE_CODE}. */
72
+ export const PEER_REPLACED_CLOSE_REASON = 'replaced by a newer sandbox peer';
73
+
74
+ // ── Bridge ↔ browser WebSocket protocol ──────────────────────────────
75
+ //
76
+ // All messages are JSON. Each message has a `type` discriminator.
77
+ // Both directions share the same envelope shape so the wire can be
78
+ // audited with a single parser.
79
+
80
+ /** Browser → bridge: "I'm here and ready to receive tool calls." */
81
+ export interface HelloFromClient {
82
+ type: 'hello';
83
+ /** Protocol version. Bump if the wire format changes incompatibly. */
84
+ protocol: 1;
85
+ /** Tool names the browser can dispatch. Bridge uses this to size MCP tool surface. */
86
+ tools: string[];
87
+ /** Stable identifier for this sandbox session (for audit log). */
88
+ sandboxId: string;
89
+ /**
90
+ * Optional peer capabilities (additive). The bridge only sends `worker-*`
91
+ * frames to a peer that declared {@link WORKER_RELAY_CAPABILITY} — an old
92
+ * peer that omits it simply never receives them, and worker ops against it
93
+ * fail fast with a clear error instead of timing out.
94
+ */
95
+ capabilities?: string[];
96
+ }
97
+
98
+ /** Bridge → browser: acknowledge connection. */
99
+ export interface HelloFromBridge {
100
+ type: 'hello-ack';
101
+ protocol: 1;
102
+ /** Bridge version, for compatibility checks. */
103
+ bridgeVersion: string;
104
+ }
105
+
106
+ /** Bridge → browser: please dispatch this tool call into the sandbox. */
107
+ export interface ToolCallRequest {
108
+ type: 'tool-call';
109
+ /** Correlation id — browser must echo in `ToolCallResponse`. */
110
+ id: string;
111
+ /** Tool name (e.g. `firestore_simulator_create`). */
112
+ name: string;
113
+ /** Tool arguments (JSON-serializable). */
114
+ args: Record<string, unknown>;
115
+ }
116
+
117
+ /** Browser → bridge: tool call result. */
118
+ export interface ToolCallResponse {
119
+ type: 'tool-result';
120
+ /** Correlation id from the matching request. */
121
+ id: string;
122
+ /** When `ok===false`, `error` is populated and `result` is omitted. */
123
+ ok: boolean;
124
+ /** Tool result (matches `ToolResult` shape from `@inbrowser/agent`). */
125
+ result?: {
126
+ ok: boolean;
127
+ summary: string;
128
+ data?: unknown;
129
+ };
130
+ error?: {
131
+ code: string;
132
+ message: string;
133
+ };
134
+ }
135
+
136
+ // ── Generic worker relay (remote sandbox, slice 1) ───────────────────
137
+ //
138
+ // Beyond `tool-call`, the bridge can relay ANY SharedWorker-protocol op or
139
+ // (snap-delivering) subscription between a Node consumer and the browser
140
+ // peer. The SAME frame shapes travel both legs:
141
+ //
142
+ // Node consumer ──ws──> bridge ──ws──> browser tab ──port──> worker
143
+ //
144
+ // Correlation ids/subIds are re-minted per hop (consumer-minted on the
145
+ // consumer leg, bridge-minted UUIDs on the peer leg, page-local ids on the
146
+ // worker port) so each hop's pending/registry maps stay collision-free.
147
+
148
+ /** Peer capability flag: "I can relay worker-op / worker-sub frames". */
149
+ export const WORKER_RELAY_CAPABILITY = 'worker-relay';
150
+
151
+ /** `Omit` distributed over a union (plain `Omit` collapses union members). */
152
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
153
+ ? Omit<T, K>
154
+ : never;
155
+
156
+ /** A worker one-shot op, minus the port-level `t`/`id` the relay re-mints. */
157
+ export type WorkerOpPayload = DistributiveOmit<OpMessage, 't' | 'id'>;
158
+
159
+ /**
160
+ * A worker subscription, minus the port-level `t`/`subId`. Slice 1 relays
161
+ * snap-delivering subs (RTDB value, auth state, Firestore); the unified
162
+ * event stream (`target: 'events'`) is NOT relayable yet — it needs bounded
163
+ * backpressure first (slice 2).
164
+ */
165
+ export type WorkerSubPayload = DistributiveOmit<SubMessage, 't' | 'subId'>;
166
+
167
+ /** Node consumer → bridge: attach as a worker-relay consumer (NOT a peer —
168
+ * a consumer never replaces the browser tab in last-connection-wins). */
169
+ export interface AttachFromConsumer {
170
+ type: 'attach';
171
+ protocol: 1;
172
+ }
173
+
174
+ /** Bridge → Node consumer: attach acknowledged. */
175
+ export interface AttachAckFromBridge {
176
+ type: 'attach-ack';
177
+ protocol: 1;
178
+ bridgeVersion: string;
179
+ /** Whether a browser tab is currently registered as the sandbox peer. */
180
+ peerConnected: boolean;
181
+ /**
182
+ * The `@pyric/cli` package version the serve/bridge process runs
183
+ * (version-skew stamp). ADDITIVE + OPTIONAL: old servers omit it and
184
+ * the client stays silent. When present and different from the
185
+ * client's own version, the client warns once at attach and enriches
186
+ * op-timeout errors — a skewed old worker can accept a newer op frame
187
+ * and die mid-handling, which otherwise surfaces as a bare timeout.
188
+ */
189
+ serveVersion?: string;
190
+ }
191
+
192
+ /** Toward the worker: dispatch this one-shot op. (consumer→bridge and
193
+ * bridge→browser use the same shape; `id` is per-leg.) */
194
+ export interface WorkerOpFrame {
195
+ type: 'worker-op';
196
+ /** Correlation id — echoed back in the matching `worker-res`. */
197
+ id: string;
198
+ op: WorkerOpPayload;
199
+ }
200
+
201
+ /** Away from the worker: the relayed op result. */
202
+ export interface WorkerResFrame {
203
+ type: 'worker-res';
204
+ id: string;
205
+ /** When `ok === false`, `error` is populated and `value` omitted. */
206
+ ok: boolean;
207
+ value?: unknown;
208
+ /** `denialContext` (additive, spike gap 6): the structured "why did this
209
+ * deny" frame a `SandboxError` carries on `permission-denied` — plain
210
+ * JSON, so it rides the WS legs verbatim and the Node side re-attaches it. */
211
+ error?: { code: string; message: string; denialContext?: unknown };
212
+ }
213
+
214
+ /** Toward the worker: register a subscription. Re-issued by the bridge to a
215
+ * NEW peer on reconnect/replacement (value subs re-deliver a fresh initial
216
+ * snapshot, so replay is cursor-free and last-value-wins-safe). */
217
+ export interface WorkerSubFrame {
218
+ type: 'worker-sub';
219
+ subId: string;
220
+ sub: WorkerSubPayload;
221
+ }
222
+
223
+ /** Toward the worker: tear a subscription down. */
224
+ export interface WorkerUnsubFrame {
225
+ type: 'worker-unsub';
226
+ subId: string;
227
+ }
228
+
229
+ /** Away from the worker: one streamed snapshot for a subscription. A failed
230
+ * ESTABLISHMENT also arrives here as `value: { __error: { code, message } }`
231
+ * (the worker host's snap-error convention) — relays forward it verbatim. */
232
+ export interface WorkerSnapFrame {
233
+ type: 'worker-snap';
234
+ subId: string;
235
+ value: unknown;
236
+ }
237
+
238
+ /** Either direction: ping for keepalive / liveness detection. */
239
+ export interface Ping {
240
+ type: 'ping';
241
+ /** Echo back as `pong.id`. */
242
+ id: string;
243
+ }
244
+
245
+ /** Pong response to a Ping. */
246
+ export interface Pong {
247
+ type: 'pong';
248
+ id: string;
249
+ }
250
+
251
+ export type BridgeMessage =
252
+ | HelloFromClient
253
+ | HelloFromBridge
254
+ | AttachFromConsumer
255
+ | AttachAckFromBridge
256
+ | ToolCallRequest
257
+ | ToolCallResponse
258
+ | WorkerOpFrame
259
+ | WorkerResFrame
260
+ | WorkerSubFrame
261
+ | WorkerUnsubFrame
262
+ | WorkerSnapFrame
263
+ | Ping
264
+ | Pong;
265
+
266
+ /** Type guard for runtime parsing. */
267
+ export function isBridgeMessage(value: unknown): value is BridgeMessage {
268
+ if (value === null || typeof value !== 'object') return false;
269
+ const t = (value as { type?: unknown }).type;
270
+ return (
271
+ t === 'hello' ||
272
+ t === 'hello-ack' ||
273
+ t === 'attach' ||
274
+ t === 'attach-ack' ||
275
+ t === 'tool-call' ||
276
+ t === 'tool-result' ||
277
+ t === 'worker-op' ||
278
+ t === 'worker-res' ||
279
+ t === 'worker-sub' ||
280
+ t === 'worker-unsub' ||
281
+ t === 'worker-snap' ||
282
+ t === 'ping' ||
283
+ t === 'pong'
284
+ );
285
+ }
286
+
287
+ /** Error returned by MCP when no browser tab is currently connected. */
288
+ export const NO_SANDBOX_ERROR_MESSAGE =
289
+ 'sandbox not connected. Open your dev server in a browser and refresh the page so the bridge client can register.';
290
+
291
+ /** Error for worker ops against a peer that predates the worker relay. */
292
+ export const NO_WORKER_RELAY_ERROR_MESSAGE =
293
+ 'the connected browser tab does not support the worker relay — reload the tab (and update pyric if reloading does not help).';
294
+
295
+ // ─── Binary-payload guard (worker-op relay boundary) ────────────────────────
296
+ //
297
+ // Both WS legs of the worker relay are `JSON.stringify` — a `Blob` or
298
+ // `ArrayBuffer` in a relayed value silently becomes `{}` and a TypedArray /
299
+ // Buffer becomes an index-keyed object. Nothing errors; the far side just
300
+ // receives garbage (the live failure mode: relaying `storage.getBlob` yields
301
+ // `{}`). This guard turns that silent corruption into a loud, remediable
302
+ // rejection at the relay boundary. It is a cheap explicit TYPE check
303
+ // (Blob/ArrayBuffer/TypedArray/DataView), NOT a full JSON round-trip.
304
+
305
+ /** Human label for a non-JSON-safe binary value, or null when `value` (and
306
+ * every nested array/plain-object member) is free of binary containers. */
307
+ export function findBinaryPayload(value: unknown): string | null {
308
+ if (value === null || typeof value !== 'object') return null;
309
+ if (typeof Blob !== 'undefined' && value instanceof Blob) return 'Blob';
310
+ if (value instanceof ArrayBuffer) return 'ArrayBuffer';
311
+ if (ArrayBuffer.isView(value)) {
312
+ return (value as { constructor?: { name?: string } }).constructor?.name ?? 'TypedArray';
313
+ }
314
+ if (Array.isArray(value)) {
315
+ for (const item of value) {
316
+ const hit = findBinaryPayload(item);
317
+ if (hit) return hit;
318
+ }
319
+ return null;
320
+ }
321
+ for (const item of Object.values(value as Record<string, unknown>)) {
322
+ const hit = findBinaryPayload(item);
323
+ if (hit) return hit;
324
+ }
325
+ return null;
326
+ }
327
+
328
+ /**
329
+ * Assert a worker-op result (or subscription snap value) is safe to
330
+ * serialize onto the JSON relay. Throws (code `invalid-argument`) naming
331
+ * the offending type and the base64 storage ops to use instead — so a
332
+ * future caller relaying `storage.getBlob` gets a clear error, not `{}`.
333
+ *
334
+ * `context` is a human label for the message: `op '<method>'` for op
335
+ * results, `subscription '<subId>'` for snap values.
336
+ */
337
+ export function assertJsonSafeRelayValue(
338
+ context: string,
339
+ value: unknown,
340
+ ): void {
341
+ const kind = findBinaryPayload(value);
342
+ if (!kind) return;
343
+ const err = new Error(
344
+ `worker ${context} produced a binary payload (${kind}) that cannot cross the ` +
345
+ 'JSON bridge relay — it would be silently corrupted by JSON.stringify. Use the ' +
346
+ "base64 storage ops instead ('storage.getBytes' / 'storage.putBytes'), which carry " +
347
+ "bytes as JSON-safe 'dataB64' strings; 'storage.getBlob' is MessagePort-only.",
348
+ ) as Error & { code: string };
349
+ err.code = 'invalid-argument';
350
+ throw err;
351
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Audit log writer. Every sandbox bridge tool call appends
3
+ * one JSON line to the project's events.ndjson file.
4
+ *
5
+ * Audit events land at the project's conventional location:
6
+ * `~/.pyric/projects/<projectId>/events.ndjson`
7
+ *
8
+ * The bridge passes its `BridgeToolEvent` here through `onToolEvent`.
9
+ * Writes are best-effort — failure to log must not break tool
10
+ * dispatch.
11
+ */
12
+
13
+ import { homedir } from 'node:os';
14
+ import { join } from 'node:path';
15
+ import { mkdirSync, appendFileSync } from 'node:fs';
16
+ import type { BridgeToolEvent } from './bridge.js';
17
+
18
+ export interface AuditWriter {
19
+ write(event: BridgeToolEvent): void;
20
+ /** Filesystem path of the active log. */
21
+ readonly path: string;
22
+ }
23
+
24
+ export function createAuditWriter(project: string): AuditWriter {
25
+ const dir = join(homedir(), '.pyric', 'projects', sanitiseProjectId(project));
26
+ const path = join(dir, 'events.ndjson');
27
+ try {
28
+ mkdirSync(dir, { recursive: true });
29
+ } catch (err) {
30
+ // If we can't create the directory, fall back to silent no-op.
31
+ return {
32
+ write: () => {},
33
+ path,
34
+ };
35
+ }
36
+ return {
37
+ path,
38
+ write(event: BridgeToolEvent) {
39
+ try {
40
+ const line = JSON.stringify(event) + '\n';
41
+ appendFileSync(path, line, { encoding: 'utf8' });
42
+ } catch {
43
+ // Drop the entry; tool dispatch continues.
44
+ }
45
+ },
46
+ };
47
+ }
48
+
49
+ function sanitiseProjectId(value: string): string {
50
+ // Project ids are normally alphanumeric + dash; defend against
51
+ // path traversal just in case (someone passes `../etc` etc.).
52
+ return value.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 128) || 'unknown';
53
+ }