shadow-claw 1.59.7 → 1.60.0

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 (253) hide show
  1. package/.well-known/mcp/server-card.json +4 -12
  2. package/.well-known/mcp.json +4 -12
  3. package/README.md +6 -2
  4. package/dist/cli/build/build.js +1 -1
  5. package/dist/cli/{chunk-DDvuLVfW.js → chunk-3C5izdQW.js} +1 -1
  6. package/dist/cli/chunk-B-75h9gX.js +1 -0
  7. package/dist/cli/{chunk-hVf839t7.js → chunk-B7Kn-otm.js} +1 -1
  8. package/dist/cli/{chunk-YX32FcN7.js → chunk-BBczgswQ.js} +1 -1
  9. package/dist/cli/{chunk-DcNxjqH6.js → chunk-BE-lYWcn.js} +1 -1
  10. package/dist/cli/{chunk-CQaCgswD.js → chunk-BECr0WxI.js} +11 -11
  11. package/dist/cli/chunk-BEz1PD1_.js +1 -0
  12. package/dist/cli/chunk-BLzI1Fp2.js +1 -0
  13. package/dist/cli/{chunk-B3TrWbca.js → chunk-BVSC1MNQ.js} +11 -11
  14. package/dist/cli/{chunk-D_te8ufL.js → chunk-BdWcep6o.js} +1 -1
  15. package/dist/cli/{chunk-SRBRVorc.js → chunk-BfTpnSS4.js} +1 -1
  16. package/dist/cli/{chunk-D2_eAO83.js → chunk-BgvqTf7w.js} +1 -1
  17. package/dist/cli/chunk-BwsJfUT3.js +1 -0
  18. package/dist/cli/{chunk--PFY91kE.js → chunk-C9b4b7c_.js} +1 -1
  19. package/dist/cli/{chunk-SxK79JmB.js → chunk-CAw9XYFe.js} +1 -1
  20. package/dist/cli/chunk-CFCcbFs2.js +396 -0
  21. package/dist/cli/{chunk-Cnjb8Usu.js → chunk-CTarF4FC.js} +1 -1
  22. package/dist/cli/{chunk-3vNYrs_L.js → chunk-Cbq5hpjb.js} +4 -4
  23. package/dist/cli/chunk-CjTjKy_v.js +310 -0
  24. package/dist/cli/chunk-Cjyu4cr_.js +36 -0
  25. package/dist/cli/{chunk-DUGZPka_.js → chunk-ClMKygjZ.js} +1 -1
  26. package/dist/cli/chunk-Cppnq1KF.js +1 -0
  27. package/dist/cli/{chunk-DvemF16v.js → chunk-D9QCNFMO.js} +1 -1
  28. package/dist/cli/{chunk-iB8OoMmW.js → chunk-DB21BMqt.js} +1 -1
  29. package/dist/cli/{chunk-_Vo-o_e3.js → chunk-DHoIWvCc.js} +1 -1
  30. package/dist/cli/chunk-DZEN9T5y.js +1 -0
  31. package/dist/cli/{chunk-5rLO4DWS.js → chunk-Dl14OyYO.js} +9 -9
  32. package/dist/cli/chunk-Dl_vv0dI.js +1 -0
  33. package/dist/cli/chunk-Dpmfhlyl.js +1 -0
  34. package/dist/cli/{chunk-BrR1DOBS.js → chunk-Du7Xtucq.js} +1 -1
  35. package/dist/cli/{chunk-B88Z8T_9.js → chunk-DxcDFUi_.js} +1 -1
  36. package/dist/cli/{chunk-Dt7-hzJU.js → chunk-DyyEWbV7.js} +1 -1
  37. package/dist/cli/chunk-N0x3mXU0.js +1 -0
  38. package/dist/cli/{chunk-CGoE4llV.js → chunk-V-w0Bata.js} +1 -1
  39. package/dist/cli/{chunk-CncW6_WL.js → chunk-ZxDxSSn-.js} +1 -1
  40. package/dist/cli/{chunk-CZdCRqNe.js → chunk-lPvFUkd5.js} +1 -1
  41. package/dist/cli/{chunk-66BvqAV0.js → chunk-n5s-sCdU.js} +1 -1
  42. package/dist/cli/{chunk-CAAeGOdy.js → chunk-nD9VPVMq.js} +1 -1
  43. package/dist/cli/{chunk-DMs7kREC.js → chunk-rFuy8aS_.js} +1 -1
  44. package/dist/cli/{chunk-B0qusANw.js → chunk-wjM6JXWa.js} +1 -1
  45. package/dist/cli/{chunk-DhOU6GYX.js → chunk-zcES9rut.js} +1 -1
  46. package/dist/cli/cli.js +3 -3
  47. package/dist/headless-agent.js +1 -1
  48. package/dist/lib/{channel-mmdGzPkT.js → channel-DB77spML.js} +2 -2
  49. package/dist/lib/{channel-mmdGzPkT.js.map → channel-DB77spML.js.map} +1 -1
  50. package/dist/lib/{compact-context-CY9BBlUQ.js → compact-context-Q9t9aL1e.js} +7 -7
  51. package/dist/lib/{compact-context-CY9BBlUQ.js.map → compact-context-Q9t9aL1e.js.map} +1 -1
  52. package/dist/lib/components/index.js +21 -21
  53. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  54. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  55. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  56. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  57. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  58. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  59. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  60. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  61. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  62. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  63. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  64. package/dist/lib/components/shadow-claw-channels.js +1 -1
  65. package/dist/lib/components/shadow-claw-chat.js +1 -1
  66. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  67. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  68. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  69. package/dist/lib/components/shadow-claw-files.js +1 -1
  70. package/dist/lib/components/shadow-claw-git.js +1 -1
  71. package/dist/lib/components/shadow-claw-llm.js +1 -1
  72. package/dist/lib/components/shadow-claw-networking.js +1 -1
  73. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  74. package/dist/lib/components/shadow-claw-pages.js +1 -1
  75. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  76. package/dist/lib/components/shadow-claw-settings.js +1 -1
  77. package/dist/lib/components/shadow-claw-storage.js +1 -1
  78. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  79. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  80. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  81. package/dist/lib/components/shadow-claw-tools.js +1 -1
  82. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  83. package/dist/lib/components/shadow-claw.js +1 -1
  84. package/dist/lib/{configure-peer-js-ccNvax2N.js → configure-peer-js-CgFiwoxY.js} +2 -2
  85. package/dist/lib/{configure-peer-js-ccNvax2N.js.map → configure-peer-js-CgFiwoxY.js.map} +1 -1
  86. package/dist/lib/content/build-attachment-content-blocks.d.ts +2 -0
  87. package/dist/lib/{discover-skills-OwlQ2sXA.js → discover-skills-CXyaWHKi.js} +5 -5
  88. package/dist/lib/{discover-skills-OwlQ2sXA.js.map → discover-skills-CXyaWHKi.js.map} +1 -1
  89. package/dist/lib/{git-D2J_j9X9.js → git-CogDRlEz.js} +2 -2
  90. package/dist/lib/{git-D2J_j9X9.js.map → git-CogDRlEz.js.map} +1 -1
  91. package/dist/lib/index.js +21 -21
  92. package/dist/lib/{init-control-plane-B7blDVIE.js → init-control-plane-CEGdzgWX.js} +7 -7
  93. package/dist/lib/{init-control-plane-B7blDVIE.js.map → init-control-plane-CEGdzgWX.js.map} +1 -1
  94. package/dist/lib/{invoke-agent-SxvudiDT.js → invoke-agent-cac3gCsj.js} +6 -6
  95. package/dist/lib/{invoke-agent-SxvudiDT.js.map → invoke-agent-cac3gCsj.js.map} +1 -1
  96. package/dist/lib/{move-group-entry-DDpjxa10.js → move-group-entry-D8dptMg0.js} +2 -2
  97. package/dist/lib/{move-group-entry-DDpjxa10.js.map → move-group-entry-D8dptMg0.js.map} +1 -1
  98. package/dist/lib/{orchestrator-C7fkh7T7.js → orchestrator-BBAwy9Nm.js} +12 -12
  99. package/dist/lib/{orchestrator-C7fkh7T7.js.map → orchestrator-BBAwy9Nm.js.map} +1 -1
  100. package/dist/lib/{orchestrator-CCARkxQC.js → orchestrator-cRBe3lhq.js} +2 -2
  101. package/dist/lib/{orchestrator-CCARkxQC.js.map → orchestrator-cRBe3lhq.js.map} +1 -1
  102. package/dist/lib/{peerjs-Bfw_FWLB.js → peerjs-BLg8aGUj.js} +3 -3
  103. package/dist/lib/{peerjs-Bfw_FWLB.js.map → peerjs-BLg8aGUj.js.map} +1 -1
  104. package/dist/lib/{process-peer-query-param-BxYiZNdf.js → process-peer-query-param-BnsVnxzH.js} +5 -5
  105. package/dist/lib/{process-peer-query-param-BxYiZNdf.js.map → process-peer-query-param-BnsVnxzH.js.map} +1 -1
  106. package/dist/lib/{process-pending-shared-payloads-DPIbwRb3.js → process-pending-shared-payloads-DBZfZOOa.js} +2 -2
  107. package/dist/lib/{process-pending-shared-payloads-DPIbwRb3.js.map → process-pending-shared-payloads-DBZfZOOa.js.map} +1 -1
  108. package/dist/lib/{process-room-query-param-B2_d50nE.js → process-room-query-param-B8EYg_-r.js} +4 -4
  109. package/dist/lib/{process-room-query-param-B2_d50nE.js.map → process-room-query-param-B8EYg_-r.js.map} +1 -1
  110. package/dist/lib/{push-client-rrjTdc-U.js → push-client-CAm6UMvE.js} +3 -3
  111. package/dist/lib/{push-client-rrjTdc-U.js.map → push-client-CAm6UMvE.js.map} +1 -1
  112. package/dist/lib/{rooms-bwGoYb1q.js → rooms-Dzphx3rK.js} +2 -2
  113. package/dist/lib/{rooms-bwGoYb1q.js.map → rooms-Dzphx3rK.js.map} +1 -1
  114. package/dist/lib/{shadow-claw-CypGVlVO.js → shadow-claw-CGl8tXtG.js} +6 -6
  115. package/dist/lib/{shadow-claw-CypGVlVO.js.map → shadow-claw-CGl8tXtG.js.map} +1 -1
  116. package/dist/lib/{shadow-claw-channel-config-DJpDovkF.js → shadow-claw-channel-config-BNIWCdsL.js} +4 -4
  117. package/dist/lib/{shadow-claw-channel-config-DJpDovkF.js.map → shadow-claw-channel-config-BNIWCdsL.js.map} +1 -1
  118. package/dist/lib/{shadow-claw-channels-DJLwRovH.js → shadow-claw-channels-C2QSn4Ew.js} +2 -2
  119. package/dist/lib/{shadow-claw-channels-DJLwRovH.js.map → shadow-claw-channels-C2QSn4Ew.js.map} +1 -1
  120. package/dist/lib/{shadow-claw-chat-B92cPaft.js → shadow-claw-chat-Wx3y9y6c.js} +3 -3
  121. package/dist/lib/{shadow-claw-chat-B92cPaft.js.map → shadow-claw-chat-Wx3y9y6c.js.map} +1 -1
  122. package/dist/lib/{shadow-claw-control-plane-fvn-qyHj.js → shadow-claw-control-plane-D5E4cFGu.js} +6 -6
  123. package/dist/lib/{shadow-claw-control-plane-fvn-qyHj.js.map → shadow-claw-control-plane-D5E4cFGu.js.map} +1 -1
  124. package/dist/lib/{shadow-claw-conversations-CsVyDOny.js → shadow-claw-conversations-BtDv7GRW.js} +2 -2
  125. package/dist/lib/{shadow-claw-conversations-CsVyDOny.js.map → shadow-claw-conversations-BtDv7GRW.js.map} +1 -1
  126. package/dist/lib/{shadow-claw-file-viewer-DFfyP7s5.js → shadow-claw-file-viewer-CG40kwWV.js} +2 -2
  127. package/dist/lib/{shadow-claw-file-viewer-DFfyP7s5.js.map → shadow-claw-file-viewer-CG40kwWV.js.map} +1 -1
  128. package/dist/lib/{shadow-claw-files-cT6HL7ye.js → shadow-claw-files-BOUULrlX.js} +3 -3
  129. package/dist/lib/{shadow-claw-files-cT6HL7ye.js.map → shadow-claw-files-BOUULrlX.js.map} +1 -1
  130. package/dist/lib/{shadow-claw-git-Cv9mQgTx.js → shadow-claw-git-BeHV73_9.js} +3 -3
  131. package/dist/lib/{shadow-claw-git-Cv9mQgTx.js.map → shadow-claw-git-BeHV73_9.js.map} +1 -1
  132. package/dist/lib/{shadow-claw-llm-CKOYzPDp.js → shadow-claw-llm-KONyWKZM.js} +2 -2
  133. package/dist/lib/{shadow-claw-llm-CKOYzPDp.js.map → shadow-claw-llm-KONyWKZM.js.map} +1 -1
  134. package/dist/lib/{shadow-claw-networking-DYfiUQaH.js → shadow-claw-networking-Diy3JJkc.js} +2 -2
  135. package/dist/lib/{shadow-claw-networking-DYfiUQaH.js.map → shadow-claw-networking-Diy3JJkc.js.map} +1 -1
  136. package/dist/lib/{shadow-claw-notifications-JJlzriuX.js → shadow-claw-notifications-C-upPa-4.js} +2 -2
  137. package/dist/lib/{shadow-claw-notifications-JJlzriuX.js.map → shadow-claw-notifications-C-upPa-4.js.map} +1 -1
  138. package/dist/lib/{shadow-claw-pages-BCo3ihZI.js → shadow-claw-pages-CfAjUKgd.js} +2 -2
  139. package/dist/lib/{shadow-claw-pages-BCo3ihZI.js.map → shadow-claw-pages-CfAjUKgd.js.map} +1 -1
  140. package/dist/lib/{shadow-claw-peerjs-CFNjfrY5.js → shadow-claw-peerjs-t4YibS9s.js} +5 -5
  141. package/dist/lib/{shadow-claw-peerjs-CFNjfrY5.js.map → shadow-claw-peerjs-t4YibS9s.js.map} +1 -1
  142. package/dist/lib/{shadow-claw-settings-BMwne0bh.js → shadow-claw-settings-Cg5V0e9g.js} +2 -2
  143. package/dist/lib/{shadow-claw-settings-BMwne0bh.js.map → shadow-claw-settings-Cg5V0e9g.js.map} +1 -1
  144. package/dist/lib/{shadow-claw-storage-DUY8B9m-.js → shadow-claw-storage-C7tCnsSG.js} +2 -2
  145. package/dist/lib/{shadow-claw-storage-DUY8B9m-.js.map → shadow-claw-storage-C7tCnsSG.js.map} +1 -1
  146. package/dist/lib/{shadow-claw-task-server-yWeoA3eL.js → shadow-claw-task-server-BObsRdf8.js} +2 -2
  147. package/dist/lib/{shadow-claw-task-server-yWeoA3eL.js.map → shadow-claw-task-server-BObsRdf8.js.map} +1 -1
  148. package/dist/lib/{shadow-claw-tasks-Bg0uM15I.js → shadow-claw-tasks-B2EEqrcY.js} +3 -3
  149. package/dist/lib/{shadow-claw-tasks-Bg0uM15I.js.map → shadow-claw-tasks-B2EEqrcY.js.map} +1 -1
  150. package/dist/lib/{shadow-claw-terminal-fyJPppY_.js → shadow-claw-terminal-DSHfO2b9.js} +2 -2
  151. package/dist/lib/{shadow-claw-terminal-fyJPppY_.js.map → shadow-claw-terminal-DSHfO2b9.js.map} +1 -1
  152. package/dist/lib/{shadow-claw-tools-D0T8m3go.js → shadow-claw-tools-DwPBADua.js} +3 -3
  153. package/dist/lib/{shadow-claw-tools-D0T8m3go.js.map → shadow-claw-tools-DwPBADua.js.map} +1 -1
  154. package/dist/lib/{shadow-claw-webvm-CQvzJwKI.js → shadow-claw-webvm-CY4qGaMB.js} +2 -2
  155. package/dist/lib/{shadow-claw-webvm-CQvzJwKI.js.map → shadow-claw-webvm-CY4qGaMB.js.map} +1 -1
  156. package/dist/lib/{sync-web-mcp-registration-BFtG_4kx.js → sync-web-mcp-registration-BiOZvW-R.js} +3 -3
  157. package/dist/lib/{sync-web-mcp-registration-BFtG_4kx.js.map → sync-web-mcp-registration-BiOZvW-R.js.map} +1 -1
  158. package/dist/lib/{system-prompt-bhGRLoL2.js → system-prompt-CxJ3Nx4c.js} +4 -3
  159. package/dist/lib/system-prompt-CxJ3Nx4c.js.map +1 -0
  160. package/dist/public/.well-known/mcp/server-card.json +4 -12
  161. package/dist/public/.well-known/mcp.json +4 -12
  162. package/dist/public/AGENTS.md +3 -1
  163. package/dist/public/README.md +6 -2
  164. package/dist/public/agent.worker.js +1 -1
  165. package/dist/public/{channel-Dk7wl-Av.js → channel-DIpDQekL.js} +1 -1
  166. package/dist/public/{chat-template-BwAnTFKf.js → chat-template-CXKs8lFR.js} +1 -1
  167. package/dist/public/compact-context-BQ2ZXoAc.js +5 -0
  168. package/dist/public/{compact-context-fOTqwKF6.js → compact-context-dHitmPsV.js} +2 -2
  169. package/dist/public/{configure-peer-js-BOV0tR6G.js → configure-peer-js-DV1rqvFX.js} +1 -1
  170. package/dist/public/{create-model-cache-fetch-DSAFjOwc.js → create-model-cache-fetch-B0mSCEk6.js} +1 -1
  171. package/dist/public/{discover-skills-D1sNTy2r.js → discover-skills-BWJB8HUA.js} +1 -1
  172. package/dist/public/docs/architecture/overview.md +1 -1
  173. package/dist/public/docs/example/article/index.html +21 -21
  174. package/dist/public/docs/example/article.html +21 -21
  175. package/dist/public/docs/publishing/index.html +21 -21
  176. package/dist/public/docs/publishing.html +21 -21
  177. package/dist/public/docs/skill-creator/index.html +21 -21
  178. package/dist/public/docs/skill-creator.html +21 -21
  179. package/dist/public/docs/subsystems/attachment-capabilities.md +14 -1
  180. package/dist/public/docs/subsystems/cli.md +95 -51
  181. package/dist/public/docs/subsystems/pages.md +5 -0
  182. package/dist/public/e2e/README.md +1 -1
  183. package/dist/public/{e2e-bridge-Cz95DLlb.js → e2e-bridge-lP2qqiv3.js} +1 -1
  184. package/dist/public/{git-BmMlwIMP.js → git-DjmQ16rm.js} +1 -1
  185. package/dist/public/{iframe-bridge-scripts-Cibg0m6A.js → iframe-bridge-scripts-CO0izGjW.js} +1 -1
  186. package/dist/public/index.html +21 -21
  187. package/dist/public/index.js +1 -1
  188. package/dist/public/{init-control-plane-Cb31yLTY.js → init-control-plane-Ctz7FI8M.js} +1 -1
  189. package/dist/public/{invoke-agent-CN7mSV0Z.js → invoke-agent-C_geruwq.js} +1 -1
  190. package/dist/public/llms.txt +1 -1
  191. package/dist/public/main/index.html +21 -21
  192. package/dist/public/main/memory/index.html +21 -21
  193. package/dist/public/main/memory.html +21 -21
  194. package/dist/public/main.html +21 -21
  195. package/dist/public/{move-group-entry-CXneuNVa.js → move-group-entry-QQ9Hkk54.js} +1 -1
  196. package/dist/public/{orchestrator-Dyylc8IU.js → orchestrator-C1kaTltu.js} +2 -2
  197. package/dist/public/{orchestrator-DBO4NZqd.js → orchestrator-Li1UAsv7.js} +1 -1
  198. package/dist/public/{peerjs-l0jiBoh6.js → peerjs-DbBryE-9.js} +1 -1
  199. package/dist/public/{process-peer-query-param-s-aSP1Rq.js → process-peer-query-param-DQIgr3KL.js} +1 -1
  200. package/dist/public/{process-pending-shared-payloads-BN3GigPT.js → process-pending-shared-payloads-Ctb-TFqB.js} +1 -1
  201. package/dist/public/{process-room-query-param-B2Qe0F0M.js → process-room-query-param-F-XnIVoZ.js} +1 -1
  202. package/dist/public/{push-client-B2LC8Qp9.js → push-client-DRx9Eggz.js} +1 -1
  203. package/dist/public/{rooms-ChCEOvkw.js → rooms-BurBI7is.js} +1 -1
  204. package/dist/public/service-worker/init.js +1 -1
  205. package/dist/public/service-worker.js +1 -1
  206. package/dist/public/{shadow-claw-Br8mWDUx.js → shadow-claw-Bg9AQ5x_.js} +2 -2
  207. package/dist/public/{shadow-claw-accounts-Dm6G7KMP.js → shadow-claw-accounts-B3mjYI0M.js} +1 -1
  208. package/dist/public/{shadow-claw-card-CggS8uSa.js → shadow-claw-card-tcXRS1GF.js} +1 -1
  209. package/dist/public/{shadow-claw-channels-088vhuWO.js → shadow-claw-channels-BiSfLvWv.js} +1 -1
  210. package/dist/public/{shadow-claw-chat-BRwRlq-n.js → shadow-claw-chat-N5jMsXZZ.js} +1 -1
  211. package/dist/public/{shadow-claw-control-plane-rhKACK85.js → shadow-claw-control-plane-DFVe_Xdq.js} +2 -2
  212. package/dist/public/{shadow-claw-conversations-CF_yUfKl.js → shadow-claw-conversations-wAR06_ya.js} +1 -1
  213. package/dist/public/{shadow-claw-empty-state-CkpOSXCS.js → shadow-claw-empty-state-CnPm3NVM.js} +1 -1
  214. package/dist/public/{shadow-claw-file-viewer-DWCejuY3.js → shadow-claw-file-viewer-sZN_FCDW.js} +2 -2
  215. package/dist/public/{shadow-claw-files-L6_ioyzh.js → shadow-claw-files-CnvkCbd4.js} +2 -2
  216. package/dist/public/{shadow-claw-git-DsdkwLqQ.js → shadow-claw-git-BBHfClGk.js} +2 -2
  217. package/dist/public/{shadow-claw-integrations-CSbRTOm3.js → shadow-claw-integrations-DvdBqzRJ.js} +1 -1
  218. package/dist/public/{shadow-claw-llm-BitaeAVc.js → shadow-claw-llm-YfohG519.js} +1 -1
  219. package/dist/public/{shadow-claw-mcp-remote-gSbV5riy.js → shadow-claw-mcp-remote-BAVbf5pi.js} +1 -1
  220. package/dist/public/{shadow-claw-networking-Dn_y6Cl9.js → shadow-claw-networking-CZ4LWPW7.js} +1 -1
  221. package/dist/public/{shadow-claw-notifications-Cj4Lqx8U.js → shadow-claw-notifications-BHwyREkG.js} +1 -1
  222. package/dist/public/{shadow-claw-page-header-DR4OZFt2.js → shadow-claw-page-header-De6Qf6eY.js} +1 -1
  223. package/dist/public/{shadow-claw-page-header-action-button-BnCV_2Kb.js → shadow-claw-page-header-action-button-FSOhTc9z.js} +1 -1
  224. package/dist/public/{shadow-claw-pages-mpDOtNYj.js → shadow-claw-pages-D_oPyDca.js} +1 -1
  225. package/dist/public/{shadow-claw-pdf-viewer-DZ_84qJH.js → shadow-claw-pdf-viewer-CrU4wqRq.js} +1 -1
  226. package/dist/public/{shadow-claw-settings-CfFTYTEy.js → shadow-claw-settings-DkUhvxVr.js} +2 -2
  227. package/dist/public/{shadow-claw-storage-DLmiT4bG.js → shadow-claw-storage-D0o56Tjw.js} +1 -1
  228. package/dist/public/{shadow-claw-task-server-BoMBCsiS.js → shadow-claw-task-server-4rkroO9K.js} +1 -1
  229. package/dist/public/{shadow-claw-tasks-ChEp1j7x.js → shadow-claw-tasks-BdP7lmvu.js} +1 -1
  230. package/dist/public/{shadow-claw-terminal-BaoVbOda.js → shadow-claw-terminal-DVHX7Fsu.js} +1 -1
  231. package/dist/public/{shadow-claw-toast-e8oz7z6Z.js → shadow-claw-toast-B9Y9tSkW.js} +1 -1
  232. package/dist/public/{shadow-claw-tools-BYjUBiJz.js → shadow-claw-tools-BwwY53Lr.js} +1 -1
  233. package/dist/public/{shadow-claw-webvm-xGb13TME.js → shadow-claw-webvm-CXGdkCNM.js} +1 -1
  234. package/dist/public/{sync-web-mcp-registration-CQluj-Kz.js → sync-web-mcp-registration-DVK_IhXZ.js} +1 -1
  235. package/dist/public/{system-prompt-CTJn0tK-.js → system-prompt-BmswoQwF.js} +2 -2
  236. package/dist/public/{workbox-92eae37e.js → workbox-e4022e15.js} +1 -1
  237. package/dist/public/{zip-reader-DN7FB-Q0.js → zip-reader-JHoTbATw.js} +1 -1
  238. package/dist/server.js +5 -5
  239. package/package.json +1 -1
  240. package/dist/cli/chunk-2gZFafgY.js +0 -1
  241. package/dist/cli/chunk-BCjL0JXf.js +0 -1
  242. package/dist/cli/chunk-BNcu1oiT.js +0 -1
  243. package/dist/cli/chunk-BUNoeMKY.js +0 -36
  244. package/dist/cli/chunk-C5ypckWC.js +0 -225
  245. package/dist/cli/chunk-CFxww5Yz.js +0 -1
  246. package/dist/cli/chunk-CGIgtL6R.js +0 -1
  247. package/dist/cli/chunk-CafdvLx-.js +0 -1
  248. package/dist/cli/chunk-Dhap1VwA.js +0 -1
  249. package/dist/cli/chunk-Ds5-K-9o.js +0 -1
  250. package/dist/cli/chunk-DwvavohW.js +0 -1
  251. package/dist/cli/chunk-_a0CkUNS.js +0 -139
  252. package/dist/lib/system-prompt-bhGRLoL2.js.map +0 -1
  253. package/dist/public/compact-context-CX4H8V57.js +0 -5
@@ -1,9 +1,9 @@
1
- import { t as orchestratorStore } from "./orchestrator-CCARkxQC.js";
1
+ import { t as orchestratorStore } from "./orchestrator-cRBe3lhq.js";
2
2
  import { ulid } from "./utils/ulid.js";
3
3
  import { a as showSuccess, r as showError } from "./toast-Ck7OIKDf.js";
4
- import { a as showPage } from "./shadow-claw-CypGVlVO.js";
5
- import { c as getPeerJsConfig, d as setChannelEnabled } from "./channel-mmdGzPkT.js";
6
- import { t as configurePeerJs } from "./configure-peer-js-ccNvax2N.js";
4
+ import { a as showPage } from "./shadow-claw-CGl8tXtG.js";
5
+ import { c as getPeerJsConfig, d as setChannelEnabled } from "./channel-DB77spML.js";
6
+ import { t as configurePeerJs } from "./configure-peer-js-CgFiwoxY.js";
7
7
 
8
8
  //#region src/components/shadow-claw/utils/process-peer-query-param.ts
9
9
  async function processPeerQueryParam(shadow, shadowClaw, db, orchestrator) {
@@ -36,4 +36,4 @@ async function processPeerQueryParam(shadow, shadowClaw, db, orchestrator) {
36
36
 
37
37
  //#endregion
38
38
  export { processPeerQueryParam };
39
- //# sourceMappingURL=process-peer-query-param-BxYiZNdf.js.map
39
+ //# sourceMappingURL=process-peer-query-param-BnsVnxzH.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-peer-query-param-BxYiZNdf.js","names":[],"sources":["../../src/components/shadow-claw/utils/process-peer-query-param.ts"],"sourcesContent":["import { configurePeerJs } from \"../../../core/orchestrator/utils/configure-peer-js.js\";\n\nimport {\n getPeerJsConfig,\n setChannelEnabled,\n} from \"../../../core/orchestrator/utils/operations/channel.js\";\n\nimport { orchestratorStore } from \"../../../stores/orchestrator.js\";\nimport { showError, showSuccess } from \"../../../ui/toast.js\";\nimport { ulid } from \"../../../utils/ulid.js\";\nimport { showPage } from \"../utils/show-page.js\";\n\nimport type { Orchestrator } from \"../../../core/orchestrator/orchestrator.js\";\nimport type { ShadowClawDatabase } from \"../../../db/db.js\";\nimport type { ShadowClaw } from \"../shadow-claw.js\";\n\nexport async function processPeerQueryParam(\n shadow: ShadowRoot,\n shadowClaw: ShadowClaw,\n db: ShadowClawDatabase | null,\n orchestrator: Orchestrator,\n): Promise<void> {\n if (!db) {\n return;\n }\n\n const currentUrl = new URL(window.location?.href || \"http://localhost/\");\n const peerParam = currentUrl.searchParams.get(\"peer\");\n if (!peerParam) {\n return;\n }\n\n const remotePeerId = peerParam.trim();\n if (!remotePeerId) {\n return;\n }\n\n try {\n // 1. Ensure PeerJS channel is enabled and configured\n const cfg = getPeerJsConfig(orchestrator);\n let myPeerId = cfg.myPeerId;\n if (!myPeerId) {\n myPeerId = ulid().toLowerCase();\n }\n\n // Automatically trust the remote peer we are connecting to\n const trusted = new Set(cfg.trustedPeerIds);\n trusted.add(remotePeerId);\n\n // Save/configure\n await configurePeerJs(\n orchestrator,\n db,\n myPeerId,\n Array.from(trusted),\n cfg.serverHost,\n cfg.serverPort,\n cfg.serverPath,\n cfg.serverSecure,\n );\n\n if (!cfg.enabled) {\n await setChannelEnabled(orchestrator, db, \"peerjs\", true);\n }\n\n // 2. Ensure peer conversation exists in the list\n const targetGroupId = await orchestratorStore.ensurePeerConversation(\n db,\n remotePeerId,\n );\n\n // 3. Switch conversation and navigate to chat\n await orchestratorStore.switchConversation(db, targetGroupId);\n showPage(shadow, shadowClaw, db, orchestratorStore, \"chat\");\n\n // 4. Remove 'peer' from URL params to prevent re-triggering\n currentUrl.searchParams.delete(\"peer\");\n const cleaned = `${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`;\n window.history.replaceState({}, \"\", cleaned || \"/\");\n\n showSuccess(`Connected to Peer: ${remotePeerId.substring(0, 8)}`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to process peer parameter: ${message}`, 6000);\n }\n}\n"],"mappings":";;;;;;;;AAgBA,eAAsB,sBACpB,QACA,YACA,IACA,cACe;CACf,IAAI,CAAC,IACH;CAGF,MAAM,aAAa,IAAI,IAAI,OAAO,UAAU,QAAQ,mBAAmB;CACvE,MAAM,YAAY,WAAW,aAAa,IAAI,MAAM;CACpD,IAAI,CAAC,WACH;CAGF,MAAM,eAAe,UAAU,KAAK;CACpC,IAAI,CAAC,cACH;CAGF,IAAI;EAEF,MAAM,MAAM,gBAAgB,YAAY;EACxC,IAAI,WAAW,IAAI;EACnB,IAAI,CAAC,UACH,WAAW,KAAK,CAAC,CAAC,YAAY;EAIhC,MAAM,UAAU,IAAI,IAAI,IAAI,cAAc;EAC1C,QAAQ,IAAI,YAAY;EAGxB,MAAM,gBACJ,cACA,IACA,UACA,MAAM,KAAK,OAAO,GAClB,IAAI,YACJ,IAAI,YACJ,IAAI,YACJ,IAAI,YACN;EAEA,IAAI,CAAC,IAAI,SACP,MAAM,kBAAkB,cAAc,IAAI,UAAU,IAAI;EAI1D,MAAM,gBAAgB,MAAM,kBAAkB,uBAC5C,IACA,YACF;EAGA,MAAM,kBAAkB,mBAAmB,IAAI,aAAa;EAC5D,SAAS,QAAQ,YAAY,IAAI,mBAAmB,MAAM;EAG1D,WAAW,aAAa,OAAO,MAAM;EACrC,MAAM,UAAU,GAAG,WAAW,WAAW,WAAW,SAAS,WAAW;EACxE,OAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,WAAW,GAAG;EAElD,YAAY,sBAAsB,aAAa,UAAU,GAAG,CAAC,GAAG;CAClE,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,UAAU,qCAAqC,WAAW,GAAI;CAChE;AACF"}
1
+ {"version":3,"file":"process-peer-query-param-BnsVnxzH.js","names":[],"sources":["../../src/components/shadow-claw/utils/process-peer-query-param.ts"],"sourcesContent":["import { configurePeerJs } from \"../../../core/orchestrator/utils/configure-peer-js.js\";\n\nimport {\n getPeerJsConfig,\n setChannelEnabled,\n} from \"../../../core/orchestrator/utils/operations/channel.js\";\n\nimport { orchestratorStore } from \"../../../stores/orchestrator.js\";\nimport { showError, showSuccess } from \"../../../ui/toast.js\";\nimport { ulid } from \"../../../utils/ulid.js\";\nimport { showPage } from \"../utils/show-page.js\";\n\nimport type { Orchestrator } from \"../../../core/orchestrator/orchestrator.js\";\nimport type { ShadowClawDatabase } from \"../../../db/db.js\";\nimport type { ShadowClaw } from \"../shadow-claw.js\";\n\nexport async function processPeerQueryParam(\n shadow: ShadowRoot,\n shadowClaw: ShadowClaw,\n db: ShadowClawDatabase | null,\n orchestrator: Orchestrator,\n): Promise<void> {\n if (!db) {\n return;\n }\n\n const currentUrl = new URL(window.location?.href || \"http://localhost/\");\n const peerParam = currentUrl.searchParams.get(\"peer\");\n if (!peerParam) {\n return;\n }\n\n const remotePeerId = peerParam.trim();\n if (!remotePeerId) {\n return;\n }\n\n try {\n // 1. Ensure PeerJS channel is enabled and configured\n const cfg = getPeerJsConfig(orchestrator);\n let myPeerId = cfg.myPeerId;\n if (!myPeerId) {\n myPeerId = ulid().toLowerCase();\n }\n\n // Automatically trust the remote peer we are connecting to\n const trusted = new Set(cfg.trustedPeerIds);\n trusted.add(remotePeerId);\n\n // Save/configure\n await configurePeerJs(\n orchestrator,\n db,\n myPeerId,\n Array.from(trusted),\n cfg.serverHost,\n cfg.serverPort,\n cfg.serverPath,\n cfg.serverSecure,\n );\n\n if (!cfg.enabled) {\n await setChannelEnabled(orchestrator, db, \"peerjs\", true);\n }\n\n // 2. Ensure peer conversation exists in the list\n const targetGroupId = await orchestratorStore.ensurePeerConversation(\n db,\n remotePeerId,\n );\n\n // 3. Switch conversation and navigate to chat\n await orchestratorStore.switchConversation(db, targetGroupId);\n showPage(shadow, shadowClaw, db, orchestratorStore, \"chat\");\n\n // 4. Remove 'peer' from URL params to prevent re-triggering\n currentUrl.searchParams.delete(\"peer\");\n const cleaned = `${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`;\n window.history.replaceState({}, \"\", cleaned || \"/\");\n\n showSuccess(`Connected to Peer: ${remotePeerId.substring(0, 8)}`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to process peer parameter: ${message}`, 6000);\n }\n}\n"],"mappings":";;;;;;;;AAgBA,eAAsB,sBACpB,QACA,YACA,IACA,cACe;CACf,IAAI,CAAC,IACH;CAGF,MAAM,aAAa,IAAI,IAAI,OAAO,UAAU,QAAQ,mBAAmB;CACvE,MAAM,YAAY,WAAW,aAAa,IAAI,MAAM;CACpD,IAAI,CAAC,WACH;CAGF,MAAM,eAAe,UAAU,KAAK;CACpC,IAAI,CAAC,cACH;CAGF,IAAI;EAEF,MAAM,MAAM,gBAAgB,YAAY;EACxC,IAAI,WAAW,IAAI;EACnB,IAAI,CAAC,UACH,WAAW,KAAK,CAAC,CAAC,YAAY;EAIhC,MAAM,UAAU,IAAI,IAAI,IAAI,cAAc;EAC1C,QAAQ,IAAI,YAAY;EAGxB,MAAM,gBACJ,cACA,IACA,UACA,MAAM,KAAK,OAAO,GAClB,IAAI,YACJ,IAAI,YACJ,IAAI,YACJ,IAAI,YACN;EAEA,IAAI,CAAC,IAAI,SACP,MAAM,kBAAkB,cAAc,IAAI,UAAU,IAAI;EAI1D,MAAM,gBAAgB,MAAM,kBAAkB,uBAC5C,IACA,YACF;EAGA,MAAM,kBAAkB,mBAAmB,IAAI,aAAa;EAC5D,SAAS,QAAQ,YAAY,IAAI,mBAAmB,MAAM;EAG1D,WAAW,aAAa,OAAO,MAAM;EACrC,MAAM,UAAU,GAAG,WAAW,WAAW,WAAW,SAAS,WAAW;EACxE,OAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,WAAW,GAAG;EAElD,YAAY,sBAAsB,aAAa,UAAU,GAAG,CAAC,GAAG;CAClE,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,UAAU,qCAAqC,WAAW,GAAI;CAChE;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { o as writeGroupFile } from "./tools-B8OJ4sMF.js";
2
2
  import { a as showSuccess, r as showError } from "./toast-Ck7OIKDf.js";
3
- import { a as showPage } from "./shadow-claw-CypGVlVO.js";
3
+ import { a as showPage } from "./shadow-claw-CGl8tXtG.js";
4
4
  import { t as writeGroupFileBytes } from "./write-group-file-bytes-CNT7DqOZ.js";
5
5
 
6
6
  //#region src/share-target/pending-shares.ts
@@ -128,4 +128,4 @@ async function processPendingSharedPayloads(win, shadow, shadowClaw, oStore, fSt
128
128
 
129
129
  //#endregion
130
130
  export { processPendingSharedPayloads };
131
- //# sourceMappingURL=process-pending-shared-payloads-DPIbwRb3.js.map
131
+ //# sourceMappingURL=process-pending-shared-payloads-DBZfZOOa.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-pending-shared-payloads-DPIbwRb3.js","names":[],"sources":["../../src/share-target/pending-shares.ts","../../src/components/shadow-claw/utils/build-shared-text-payload.ts","../../src/components/shadow-claw/utils/resolve-shared-files-conversation-id.ts","../../src/components/shadow-claw/utils/sanitize-shared-file-name.ts","../../src/components/shadow-claw/utils/process-pending-shared-payloads.ts"],"sourcesContent":["import type { ShadowClawDatabase } from \"../db/types.js\";\n\nconst PENDING_SHARES_STORE = \"pendingShares\";\n\nexport interface PendingShareRecord {\n id: string;\n createdAt: number;\n title: string;\n text: string;\n url: string;\n fileName: string;\n fileType: string;\n fileBytes: ArrayBuffer | null;\n}\n\nfunction normalizeRecord(raw: any): PendingShareRecord {\n return {\n id: typeof raw?.id === \"string\" ? raw.id : \"\",\n createdAt: typeof raw?.createdAt === \"number\" ? raw.createdAt : 0,\n title: typeof raw?.title === \"string\" ? raw.title : \"\",\n text: typeof raw?.text === \"string\" ? raw.text : \"\",\n url: typeof raw?.url === \"string\" ? raw.url : \"\",\n fileName: typeof raw?.fileName === \"string\" ? raw.fileName : \"\",\n fileType: typeof raw?.fileType === \"string\" ? raw.fileType : \"\",\n fileBytes: raw?.fileBytes instanceof ArrayBuffer ? raw.fileBytes : null,\n };\n}\n\n/**\n * Read and clear pending Web Share Target payloads in FIFO order.\n */\nexport async function consumePendingShares(\n db: ShadowClawDatabase,\n): Promise<PendingShareRecord[]> {\n if (!db || typeof (db as any).transaction !== \"function\") {\n return [];\n }\n\n return new Promise((resolve, reject) => {\n let tx: IDBTransaction;\n\n try {\n tx = (db as IDBDatabase).transaction(PENDING_SHARES_STORE, \"readwrite\");\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n resolve([]);\n\n return;\n }\n\n reject(error);\n\n return;\n }\n\n const store = tx.objectStore(PENDING_SHARES_STORE);\n const getAllRequest = store.getAll();\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error || new Error(\"Failed to read pending shares\"));\n };\n\n getAllRequest.onsuccess = () => {\n const rows = Array.isArray(getAllRequest.result)\n ? getAllRequest.result\n .map(normalizeRecord)\n .filter(\n (record) => typeof record.id === \"string\" && record.id.length > 0,\n )\n .sort((a, b) => a.createdAt - b.createdAt)\n : [];\n\n const clearRequest = store.clear();\n clearRequest.onerror = () => {\n reject(\n clearRequest.error || new Error(\"Failed to clear pending shares\"),\n );\n };\n\n clearRequest.onsuccess = () => {\n resolve(rows);\n };\n };\n\n tx.onabort = () => {\n reject(tx.error || new Error(\"Pending share transaction aborted\"));\n };\n });\n}\n","export function buildSharedTextPayload(share: {\n title: string;\n text: string;\n url: string;\n}): string {\n const lines: string[] = [\"# Shared Content\", \"\"];\n\n if (share.title) {\n lines.push(`Title: ${share.title}`);\n }\n\n if (share.url) {\n lines.push(`URL: ${share.url}`);\n }\n\n if (share.text) {\n lines.push(\"\", share.text);\n }\n\n return lines.join(\"\\n\").trim() + \"\\n\";\n}\n","import type { ShadowClawDatabase } from \"../../../db/db.js\";\nimport type { OrchestratorStore } from \"../../../stores/orchestrator.js\";\n\nexport async function resolveSharedFilesConversationId(\n db: ShadowClawDatabase,\n oStore: OrchestratorStore,\n): Promise<string> {\n const now = new Date();\n const year = String(now.getFullYear());\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const isoDate = `${year}-${month}-${day}`;\n const conversationName = `Shared Files ${isoDate}`;\n const existing = oStore.groups.find(\n (group) => group.name === conversationName,\n );\n\n if (existing) {\n await oStore.switchConversation(db, existing.groupId);\n\n return existing.groupId;\n }\n\n const group = await oStore.createConversation(db, conversationName);\n\n return group.groupId;\n}\n","export function sanitizeSharedFileName(\n name: string,\n fallbackBase: string,\n): string {\n const normalized =\n name.replace(/\\\\/g, \"/\").split(\"/\").filter(Boolean).pop() || \"\";\n\n const collapsed = normalized\n .replace(/\\s+/g, \"-\")\n .replace(/[^A-Za-z0-9._-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n\n if (collapsed) {\n return collapsed;\n }\n\n return `${fallbackBase}.txt`;\n}\n","import { consumePendingShares } from \"../../../share-target/pending-shares.js\";\nimport { writeGroupFile } from \"../../../storage/write-group-file.js\";\nimport { writeGroupFileBytes } from \"../../../storage/write-group-file-bytes.js\";\nimport { showError, showSuccess } from \"../../../ui/toast.js\";\nimport { buildSharedTextPayload } from \"./build-shared-text-payload.js\";\nimport { resolveSharedFilesConversationId } from \"./resolve-shared-files-conversation-id.js\";\nimport { sanitizeSharedFileName } from \"./sanitize-shared-file-name.js\";\nimport { showPage } from \"./show-page.js\";\n\nimport type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport type { FileViewerStore } from \"../../../stores/file-viewer.js\";\nimport type { OrchestratorStore } from \"../../../stores/orchestrator.js\";\nimport type { ShadowClaw } from \"../shadow-claw.js\";\n\nexport async function processPendingSharedPayloads(\n win: Window,\n shadow: ShadowRoot | null,\n shadowClaw: ShadowClaw,\n oStore: OrchestratorStore,\n fStore: FileViewerStore,\n db: ShadowClawDatabase,\n url: URL,\n): Promise<void> {\n if (!db) {\n return;\n }\n\n const pendingShares = await consumePendingShares(db);\n if (pendingShares.length === 0) {\n return;\n }\n\n try {\n const targetGroupId = await resolveSharedFilesConversationId(db, oStore);\n const savedPaths: string[] = [];\n\n for (let i = 0; i < pendingShares.length; i++) {\n const share = pendingShares[i];\n const baseName = `shared-${Date.now()}-${i + 1}`;\n\n if (share.fileBytes instanceof ArrayBuffer) {\n const preferredName =\n share.fileName ||\n (share.fileType === \"application/pdf\"\n ? `${baseName}.pdf`\n : `${baseName}.bin`);\n const fileName = sanitizeSharedFileName(preferredName, baseName);\n\n await writeGroupFileBytes(\n db,\n targetGroupId,\n fileName,\n new Uint8Array(share.fileBytes),\n );\n savedPaths.push(fileName);\n\n continue;\n }\n\n const textFileName = sanitizeSharedFileName(\n share.fileName || `${baseName}.md`,\n baseName,\n );\n const textPayload = buildSharedTextPayload(share);\n await writeGroupFile(db, targetGroupId, textFileName, textPayload);\n savedPaths.push(textFileName);\n }\n\n await oStore.loadFiles(db);\n showPage(shadow, shadowClaw, db, oStore, \"files\");\n\n if (savedPaths.length > 0) {\n await fStore.openFile(db, savedPaths[0], targetGroupId);\n }\n\n showSuccess(\n `Imported ${savedPaths.length} shared item${savedPaths.length === 1 ? \"\" : \"s\"}.`,\n );\n\n const currentUrl = url;\n if (currentUrl.searchParams.has(\"share-target\")) {\n currentUrl.searchParams.delete(\"share-target\");\n const cleaned = `${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`;\n win.history.replaceState({}, \"\", cleaned || \"/\");\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to import shared content: ${message}`, 6000);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"process-pending-shared-payloads-DBZfZOOa.js","names":[],"sources":["../../src/share-target/pending-shares.ts","../../src/components/shadow-claw/utils/build-shared-text-payload.ts","../../src/components/shadow-claw/utils/resolve-shared-files-conversation-id.ts","../../src/components/shadow-claw/utils/sanitize-shared-file-name.ts","../../src/components/shadow-claw/utils/process-pending-shared-payloads.ts"],"sourcesContent":["import type { ShadowClawDatabase } from \"../db/types.js\";\n\nconst PENDING_SHARES_STORE = \"pendingShares\";\n\nexport interface PendingShareRecord {\n id: string;\n createdAt: number;\n title: string;\n text: string;\n url: string;\n fileName: string;\n fileType: string;\n fileBytes: ArrayBuffer | null;\n}\n\nfunction normalizeRecord(raw: any): PendingShareRecord {\n return {\n id: typeof raw?.id === \"string\" ? raw.id : \"\",\n createdAt: typeof raw?.createdAt === \"number\" ? raw.createdAt : 0,\n title: typeof raw?.title === \"string\" ? raw.title : \"\",\n text: typeof raw?.text === \"string\" ? raw.text : \"\",\n url: typeof raw?.url === \"string\" ? raw.url : \"\",\n fileName: typeof raw?.fileName === \"string\" ? raw.fileName : \"\",\n fileType: typeof raw?.fileType === \"string\" ? raw.fileType : \"\",\n fileBytes: raw?.fileBytes instanceof ArrayBuffer ? raw.fileBytes : null,\n };\n}\n\n/**\n * Read and clear pending Web Share Target payloads in FIFO order.\n */\nexport async function consumePendingShares(\n db: ShadowClawDatabase,\n): Promise<PendingShareRecord[]> {\n if (!db || typeof (db as any).transaction !== \"function\") {\n return [];\n }\n\n return new Promise((resolve, reject) => {\n let tx: IDBTransaction;\n\n try {\n tx = (db as IDBDatabase).transaction(PENDING_SHARES_STORE, \"readwrite\");\n } catch (error) {\n if (error instanceof DOMException && error.name === \"NotFoundError\") {\n resolve([]);\n\n return;\n }\n\n reject(error);\n\n return;\n }\n\n const store = tx.objectStore(PENDING_SHARES_STORE);\n const getAllRequest = store.getAll();\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error || new Error(\"Failed to read pending shares\"));\n };\n\n getAllRequest.onsuccess = () => {\n const rows = Array.isArray(getAllRequest.result)\n ? getAllRequest.result\n .map(normalizeRecord)\n .filter(\n (record) => typeof record.id === \"string\" && record.id.length > 0,\n )\n .sort((a, b) => a.createdAt - b.createdAt)\n : [];\n\n const clearRequest = store.clear();\n clearRequest.onerror = () => {\n reject(\n clearRequest.error || new Error(\"Failed to clear pending shares\"),\n );\n };\n\n clearRequest.onsuccess = () => {\n resolve(rows);\n };\n };\n\n tx.onabort = () => {\n reject(tx.error || new Error(\"Pending share transaction aborted\"));\n };\n });\n}\n","export function buildSharedTextPayload(share: {\n title: string;\n text: string;\n url: string;\n}): string {\n const lines: string[] = [\"# Shared Content\", \"\"];\n\n if (share.title) {\n lines.push(`Title: ${share.title}`);\n }\n\n if (share.url) {\n lines.push(`URL: ${share.url}`);\n }\n\n if (share.text) {\n lines.push(\"\", share.text);\n }\n\n return lines.join(\"\\n\").trim() + \"\\n\";\n}\n","import type { ShadowClawDatabase } from \"../../../db/db.js\";\nimport type { OrchestratorStore } from \"../../../stores/orchestrator.js\";\n\nexport async function resolveSharedFilesConversationId(\n db: ShadowClawDatabase,\n oStore: OrchestratorStore,\n): Promise<string> {\n const now = new Date();\n const year = String(now.getFullYear());\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const isoDate = `${year}-${month}-${day}`;\n const conversationName = `Shared Files ${isoDate}`;\n const existing = oStore.groups.find(\n (group) => group.name === conversationName,\n );\n\n if (existing) {\n await oStore.switchConversation(db, existing.groupId);\n\n return existing.groupId;\n }\n\n const group = await oStore.createConversation(db, conversationName);\n\n return group.groupId;\n}\n","export function sanitizeSharedFileName(\n name: string,\n fallbackBase: string,\n): string {\n const normalized =\n name.replace(/\\\\/g, \"/\").split(\"/\").filter(Boolean).pop() || \"\";\n\n const collapsed = normalized\n .replace(/\\s+/g, \"-\")\n .replace(/[^A-Za-z0-9._-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n\n if (collapsed) {\n return collapsed;\n }\n\n return `${fallbackBase}.txt`;\n}\n","import { consumePendingShares } from \"../../../share-target/pending-shares.js\";\nimport { writeGroupFile } from \"../../../storage/write-group-file.js\";\nimport { writeGroupFileBytes } from \"../../../storage/write-group-file-bytes.js\";\nimport { showError, showSuccess } from \"../../../ui/toast.js\";\nimport { buildSharedTextPayload } from \"./build-shared-text-payload.js\";\nimport { resolveSharedFilesConversationId } from \"./resolve-shared-files-conversation-id.js\";\nimport { sanitizeSharedFileName } from \"./sanitize-shared-file-name.js\";\nimport { showPage } from \"./show-page.js\";\n\nimport type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport type { FileViewerStore } from \"../../../stores/file-viewer.js\";\nimport type { OrchestratorStore } from \"../../../stores/orchestrator.js\";\nimport type { ShadowClaw } from \"../shadow-claw.js\";\n\nexport async function processPendingSharedPayloads(\n win: Window,\n shadow: ShadowRoot | null,\n shadowClaw: ShadowClaw,\n oStore: OrchestratorStore,\n fStore: FileViewerStore,\n db: ShadowClawDatabase,\n url: URL,\n): Promise<void> {\n if (!db) {\n return;\n }\n\n const pendingShares = await consumePendingShares(db);\n if (pendingShares.length === 0) {\n return;\n }\n\n try {\n const targetGroupId = await resolveSharedFilesConversationId(db, oStore);\n const savedPaths: string[] = [];\n\n for (let i = 0; i < pendingShares.length; i++) {\n const share = pendingShares[i];\n const baseName = `shared-${Date.now()}-${i + 1}`;\n\n if (share.fileBytes instanceof ArrayBuffer) {\n const preferredName =\n share.fileName ||\n (share.fileType === \"application/pdf\"\n ? `${baseName}.pdf`\n : `${baseName}.bin`);\n const fileName = sanitizeSharedFileName(preferredName, baseName);\n\n await writeGroupFileBytes(\n db,\n targetGroupId,\n fileName,\n new Uint8Array(share.fileBytes),\n );\n savedPaths.push(fileName);\n\n continue;\n }\n\n const textFileName = sanitizeSharedFileName(\n share.fileName || `${baseName}.md`,\n baseName,\n );\n const textPayload = buildSharedTextPayload(share);\n await writeGroupFile(db, targetGroupId, textFileName, textPayload);\n savedPaths.push(textFileName);\n }\n\n await oStore.loadFiles(db);\n showPage(shadow, shadowClaw, db, oStore, \"files\");\n\n if (savedPaths.length > 0) {\n await fStore.openFile(db, savedPaths[0], targetGroupId);\n }\n\n showSuccess(\n `Imported ${savedPaths.length} shared item${savedPaths.length === 1 ? \"\" : \"s\"}.`,\n );\n\n const currentUrl = url;\n if (currentUrl.searchParams.has(\"share-target\")) {\n currentUrl.searchParams.delete(\"share-target\");\n const cleaned = `${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`;\n win.history.replaceState({}, \"\", cleaned || \"/\");\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to import shared content: ${message}`, 6000);\n }\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { ulid } from "./utils/ulid.js";
2
2
  import { a as showSuccess, r as showError } from "./toast-Ck7OIKDf.js";
3
- import { a as showPage } from "./shadow-claw-CypGVlVO.js";
3
+ import { a as showPage } from "./shadow-claw-CGl8tXtG.js";
4
4
  import { i as joinRoomViaLink } from "./room-QujMjoxG.js";
5
- import { c as getPeerJsConfig, d as setChannelEnabled } from "./channel-mmdGzPkT.js";
6
- import { t as configurePeerJs } from "./configure-peer-js-ccNvax2N.js";
5
+ import { c as getPeerJsConfig, d as setChannelEnabled } from "./channel-DB77spML.js";
6
+ import { t as configurePeerJs } from "./configure-peer-js-CgFiwoxY.js";
7
7
 
8
8
  //#region src/components/shadow-claw/utils/process-room-query-param.ts
9
9
  async function processRoomQueryParam(win, shadow, shadowClaw, db, orchestrator, oStore) {
@@ -38,4 +38,4 @@ async function processRoomQueryParam(win, shadow, shadowClaw, db, orchestrator,
38
38
 
39
39
  //#endregion
40
40
  export { processRoomQueryParam };
41
- //# sourceMappingURL=process-room-query-param-B2_d50nE.js.map
41
+ //# sourceMappingURL=process-room-query-param-B8EYg_-r.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-room-query-param-B2_d50nE.js","names":[],"sources":["../../src/components/shadow-claw/utils/process-room-query-param.ts"],"sourcesContent":["import { configurePeerJs } from \"../../../core/orchestrator/utils/configure-peer-js.js\";\nimport {\n getPeerJsConfig,\n setChannelEnabled,\n} from \"../../../core/orchestrator/utils/operations/channel.js\";\nimport { joinRoomViaLink } from \"../../../core/orchestrator/utils/operations/room.js\";\nimport { showError, showSuccess } from \"../../../ui/toast.js\";\nimport { ulid } from \"../../../utils/ulid.js\";\nimport { showPage } from \"./show-page.js\";\n\nimport type { Orchestrator } from \"../../../core/orchestrator/orchestrator.js\";\nimport type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport type { OrchestratorStore } from \"../../../stores/orchestrator.js\";\nimport type { ShadowClaw } from \"../shadow-claw.js\";\n\nexport async function processRoomQueryParam(\n win: Window,\n shadow: ShadowRoot | null,\n shadowClaw: ShadowClaw,\n db: ShadowClawDatabase,\n orchestrator: Orchestrator,\n oStore: OrchestratorStore,\n): Promise<void> {\n if (!db) {\n return;\n }\n\n const currentUrl = new URL(window.location?.href || \"http://localhost/\");\n const roomId = (currentUrl.searchParams.get(\"room\") || \"\").trim();\n const hostPeerId = (currentUrl.searchParams.get(\"host\") || \"\").trim();\n const roomName = (currentUrl.searchParams.get(\"name\") || \"\").trim() || \"Room\";\n\n if (!roomId || !hostPeerId) {\n return;\n }\n\n try {\n // 1. Ensure PeerJS channel is enabled and the host is trusted\n const cfg = getPeerJsConfig(orchestrator);\n let myPeerId = cfg.myPeerId;\n if (!myPeerId) {\n myPeerId = ulid().toLowerCase();\n }\n\n const trusted = new Set(cfg.trustedPeerIds);\n trusted.add(hostPeerId);\n\n await configurePeerJs(\n orchestrator,\n db,\n myPeerId,\n Array.from(trusted),\n cfg.serverHost,\n cfg.serverPort,\n cfg.serverPath,\n cfg.serverSecure,\n );\n\n if (!cfg.enabled) {\n await setChannelEnabled(orchestrator, db, \"peerjs\", true);\n }\n\n // 2. Join the room (connects to host + announces membership)\n joinRoomViaLink(orchestrator, roomId, hostPeerId, roomName);\n\n // 3. Navigate to the room conversation\n await oStore.switchConversation(db, `room:${roomId}`);\n showPage(shadow, shadowClaw, db, oStore, \"chat\");\n\n // 4. Clean the URL to prevent re-triggering\n currentUrl.searchParams.delete(\"room\");\n currentUrl.searchParams.delete(\"host\");\n currentUrl.searchParams.delete(\"name\");\n const cleaned = `${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`;\n win.history.replaceState({}, \"\", cleaned || \"/\");\n\n showSuccess(`Joined room \"${roomName}\"`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to join room: ${message}`, 6000);\n }\n}\n"],"mappings":";;;;;;;;AAeA,eAAsB,sBACpB,KACA,QACA,YACA,IACA,cACA,QACe;CACf,IAAI,CAAC,IACH;CAGF,MAAM,aAAa,IAAI,IAAI,OAAO,UAAU,QAAQ,mBAAmB;CACvE,MAAM,UAAU,WAAW,aAAa,IAAI,MAAM,KAAK,GAAE,CAAE,KAAK;CAChE,MAAM,cAAc,WAAW,aAAa,IAAI,MAAM,KAAK,GAAE,CAAE,KAAK;CACpE,MAAM,YAAY,WAAW,aAAa,IAAI,MAAM,KAAK,GAAE,CAAE,KAAK,KAAK;CAEvE,IAAI,CAAC,UAAU,CAAC,YACd;CAGF,IAAI;EAEF,MAAM,MAAM,gBAAgB,YAAY;EACxC,IAAI,WAAW,IAAI;EACnB,IAAI,CAAC,UACH,WAAW,KAAK,CAAC,CAAC,YAAY;EAGhC,MAAM,UAAU,IAAI,IAAI,IAAI,cAAc;EAC1C,QAAQ,IAAI,UAAU;EAEtB,MAAM,gBACJ,cACA,IACA,UACA,MAAM,KAAK,OAAO,GAClB,IAAI,YACJ,IAAI,YACJ,IAAI,YACJ,IAAI,YACN;EAEA,IAAI,CAAC,IAAI,SACP,MAAM,kBAAkB,cAAc,IAAI,UAAU,IAAI;EAI1D,gBAAgB,cAAc,QAAQ,YAAY,QAAQ;EAG1D,MAAM,OAAO,mBAAmB,IAAI,QAAQ,QAAQ;EACpD,SAAS,QAAQ,YAAY,IAAI,QAAQ,MAAM;EAG/C,WAAW,aAAa,OAAO,MAAM;EACrC,WAAW,aAAa,OAAO,MAAM;EACrC,WAAW,aAAa,OAAO,MAAM;EACrC,MAAM,UAAU,GAAG,WAAW,WAAW,WAAW,SAAS,WAAW;EACxE,IAAI,QAAQ,aAAa,CAAC,GAAG,IAAI,WAAW,GAAG;EAE/C,YAAY,gBAAgB,SAAS,EAAE;CACzC,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,UAAU,wBAAwB,WAAW,GAAI;CACnD;AACF"}
1
+ {"version":3,"file":"process-room-query-param-B8EYg_-r.js","names":[],"sources":["../../src/components/shadow-claw/utils/process-room-query-param.ts"],"sourcesContent":["import { configurePeerJs } from \"../../../core/orchestrator/utils/configure-peer-js.js\";\nimport {\n getPeerJsConfig,\n setChannelEnabled,\n} from \"../../../core/orchestrator/utils/operations/channel.js\";\nimport { joinRoomViaLink } from \"../../../core/orchestrator/utils/operations/room.js\";\nimport { showError, showSuccess } from \"../../../ui/toast.js\";\nimport { ulid } from \"../../../utils/ulid.js\";\nimport { showPage } from \"./show-page.js\";\n\nimport type { Orchestrator } from \"../../../core/orchestrator/orchestrator.js\";\nimport type { ShadowClawDatabase } from \"../../../db/types.js\";\nimport type { OrchestratorStore } from \"../../../stores/orchestrator.js\";\nimport type { ShadowClaw } from \"../shadow-claw.js\";\n\nexport async function processRoomQueryParam(\n win: Window,\n shadow: ShadowRoot | null,\n shadowClaw: ShadowClaw,\n db: ShadowClawDatabase,\n orchestrator: Orchestrator,\n oStore: OrchestratorStore,\n): Promise<void> {\n if (!db) {\n return;\n }\n\n const currentUrl = new URL(window.location?.href || \"http://localhost/\");\n const roomId = (currentUrl.searchParams.get(\"room\") || \"\").trim();\n const hostPeerId = (currentUrl.searchParams.get(\"host\") || \"\").trim();\n const roomName = (currentUrl.searchParams.get(\"name\") || \"\").trim() || \"Room\";\n\n if (!roomId || !hostPeerId) {\n return;\n }\n\n try {\n // 1. Ensure PeerJS channel is enabled and the host is trusted\n const cfg = getPeerJsConfig(orchestrator);\n let myPeerId = cfg.myPeerId;\n if (!myPeerId) {\n myPeerId = ulid().toLowerCase();\n }\n\n const trusted = new Set(cfg.trustedPeerIds);\n trusted.add(hostPeerId);\n\n await configurePeerJs(\n orchestrator,\n db,\n myPeerId,\n Array.from(trusted),\n cfg.serverHost,\n cfg.serverPort,\n cfg.serverPath,\n cfg.serverSecure,\n );\n\n if (!cfg.enabled) {\n await setChannelEnabled(orchestrator, db, \"peerjs\", true);\n }\n\n // 2. Join the room (connects to host + announces membership)\n joinRoomViaLink(orchestrator, roomId, hostPeerId, roomName);\n\n // 3. Navigate to the room conversation\n await oStore.switchConversation(db, `room:${roomId}`);\n showPage(shadow, shadowClaw, db, oStore, \"chat\");\n\n // 4. Clean the URL to prevent re-triggering\n currentUrl.searchParams.delete(\"room\");\n currentUrl.searchParams.delete(\"host\");\n currentUrl.searchParams.delete(\"name\");\n const cleaned = `${currentUrl.pathname}${currentUrl.search}${currentUrl.hash}`;\n win.history.replaceState({}, \"\", cleaned || \"/\");\n\n showSuccess(`Joined room \"${roomName}\"`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n showError(`Failed to join room: ${message}`, 6000);\n }\n}\n"],"mappings":";;;;;;;;AAeA,eAAsB,sBACpB,KACA,QACA,YACA,IACA,cACA,QACe;CACf,IAAI,CAAC,IACH;CAGF,MAAM,aAAa,IAAI,IAAI,OAAO,UAAU,QAAQ,mBAAmB;CACvE,MAAM,UAAU,WAAW,aAAa,IAAI,MAAM,KAAK,GAAE,CAAE,KAAK;CAChE,MAAM,cAAc,WAAW,aAAa,IAAI,MAAM,KAAK,GAAE,CAAE,KAAK;CACpE,MAAM,YAAY,WAAW,aAAa,IAAI,MAAM,KAAK,GAAE,CAAE,KAAK,KAAK;CAEvE,IAAI,CAAC,UAAU,CAAC,YACd;CAGF,IAAI;EAEF,MAAM,MAAM,gBAAgB,YAAY;EACxC,IAAI,WAAW,IAAI;EACnB,IAAI,CAAC,UACH,WAAW,KAAK,CAAC,CAAC,YAAY;EAGhC,MAAM,UAAU,IAAI,IAAI,IAAI,cAAc;EAC1C,QAAQ,IAAI,UAAU;EAEtB,MAAM,gBACJ,cACA,IACA,UACA,MAAM,KAAK,OAAO,GAClB,IAAI,YACJ,IAAI,YACJ,IAAI,YACJ,IAAI,YACN;EAEA,IAAI,CAAC,IAAI,SACP,MAAM,kBAAkB,cAAc,IAAI,UAAU,IAAI;EAI1D,gBAAgB,cAAc,QAAQ,YAAY,QAAQ;EAG1D,MAAM,OAAO,mBAAmB,IAAI,QAAQ,QAAQ;EACpD,SAAS,QAAQ,YAAY,IAAI,QAAQ,MAAM;EAG/C,WAAW,aAAa,OAAO,MAAM;EACrC,WAAW,aAAa,OAAO,MAAM;EACrC,WAAW,aAAa,OAAO,MAAM;EACrC,MAAM,UAAU,GAAG,WAAW,WAAW,WAAW,SAAS,WAAW;EACxE,IAAI,QAAQ,aAAa,CAAC,GAAG,IAAI,WAAW,GAAG;EAE/C,YAAY,gBAAgB,SAAS,EAAE;CACzC,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,UAAU,wBAAwB,WAAW,GAAI;CACnD;AACF"}
@@ -61,7 +61,7 @@ async function subscribeToPush(clientId, deviceLabel, subscriberId) {
61
61
  let resolvedDeviceLabel = deviceLabel;
62
62
  let resolvedSubscriberId = subscriberId;
63
63
  if (!resolvedClientId || !resolvedDeviceLabel) try {
64
- const initCp = await import("./init-control-plane-B7blDVIE.js");
64
+ const initCp = await import("./init-control-plane-CEGdzgWX.js");
65
65
  if (!resolvedClientId && typeof initCp.getOrCreateControlPlaneClientId === "function") resolvedClientId = initCp.getOrCreateControlPlaneClientId();
66
66
  if (!resolvedDeviceLabel && typeof initCp.detectDeviceLabel === "function") resolvedDeviceLabel = initCp.detectDeviceLabel();
67
67
  } catch (_) {}
@@ -97,7 +97,7 @@ async function syncExistingPushSubscription(subscriberId) {
97
97
  let resolvedSubscriberId = subscriberId;
98
98
  if (typeof localStorage !== "undefined") resolvedClientId = localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID) || void 0;
99
99
  try {
100
- const initCp = await import("./init-control-plane-B7blDVIE.js");
100
+ const initCp = await import("./init-control-plane-CEGdzgWX.js");
101
101
  if (!resolvedClientId && typeof initCp.getOrCreateControlPlaneClientId === "function") resolvedClientId = initCp.getOrCreateControlPlaneClientId();
102
102
  if (typeof initCp.detectDeviceLabel === "function") resolvedDeviceLabel = initCp.detectDeviceLabel();
103
103
  } catch (_) {}
@@ -144,4 +144,4 @@ async function getCurrentSubscription() {
144
144
 
145
145
  //#endregion
146
146
  export { syncExistingPushSubscription as a, subscribeToPush as i, getPushFetchOptions as n, unsubscribeFromPush as o, getPushUrl as r, getCurrentSubscription as t };
147
- //# sourceMappingURL=push-client-rrjTdc-U.js.map
147
+ //# sourceMappingURL=push-client-CAm6UMvE.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"push-client-rrjTdc-U.js","names":[],"sources":["../../src/subsystems/notifications/push-client.ts"],"sourcesContent":["/**\n * Client-side Web Push subscription management.\n * Runs in the browser — communicates with the server's push routes.\n */\n\nimport { CONFIG_KEYS } from \"../../config/config.js\";\nimport { getDb } from \"../../db/db.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { getOrCreateSubscriberId } from \"../../db/get-or-create-subscriber-id.js\";\n\n/**\n * Resolve a push route URL, optionally using a configured proxy.\n */\nexport async function getPushUrl(path: string): Promise<string> {\n const db = await getDb();\n let proxyUrl = await getConfig(db, CONFIG_KEYS.PUSH_PROXY_URL);\n\n if (!proxyUrl && typeof localStorage !== \"undefined\") {\n try {\n proxyUrl = localStorage.getItem(CONFIG_KEYS.PUSH_PROXY_URL) || undefined;\n } catch (_) {}\n }\n\n if (!proxyUrl) {\n return path;\n }\n\n // Ensure path starts with /\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n // Ensure proxyUrl doesn't end with /\n const normalizedProxy = proxyUrl.endsWith(\"/\")\n ? proxyUrl.slice(0, -1)\n : proxyUrl;\n\n return `${normalizedProxy}${normalizedPath}`;\n}\n\nexport function getPushFetchOptions(\n url: string,\n baseOptions: RequestInit = {},\n): RequestInit {\n const opts: any = { ...baseOptions };\n try {\n const locOrigin =\n typeof location !== \"undefined\"\n ? location.origin\n : \"http://127.0.0.1:8888\";\n const u = new URL(url, locOrigin);\n const host = u.hostname.toLowerCase();\n if (\n host === \"localhost\" ||\n host === \"127.0.0.1\" ||\n host === \"::1\" ||\n host === \"[::1]\"\n ) {\n opts.targetAddressSpace = \"loopback\";\n } else if (\n /^(10\\.|172\\.(1[6-9]|2\\d|3[01])\\.|192\\.168\\.)/.test(host) ||\n !host.includes(\".\") ||\n host.endsWith(\".local\") ||\n host.endsWith(\".lan\") ||\n host.endsWith(\".home\") ||\n host.endsWith(\".internal\")\n ) {\n opts.targetAddressSpace = \"private\";\n }\n } catch (_) {}\n return opts;\n}\n\n/**\n * Convert a URL-safe base64 string to a Uint8Array.\n * Required for PushManager.subscribe() applicationServerKey.\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData = atob(base64);\n\n return Uint8Array.from([...rawData].map((c) => c.charCodeAt(0)));\n}\n\n/**\n * Fetch the VAPID public key from the server.\n */\nexport async function getVapidPublicKey(): Promise<string> {\n const url = await getPushUrl(\"/push/vapid-public-key\");\n const res = await fetch(url, getPushFetchOptions(url));\n const data = await res.json();\n\n return data.publicKey;\n}\n\n/**\n * Subscribe to push notifications.\n * Requests permission, creates a push subscription, and sends it to the server.\n */\nexport async function subscribeToPush(\n clientId?: string,\n deviceLabel?: string,\n subscriberId?: string,\n): Promise<PushSubscription> {\n const registration = await navigator.serviceWorker.ready;\n const publicKey = await getVapidPublicKey();\n\n const subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: urlBase64ToUint8Array(publicKey) as any,\n });\n\n let resolvedClientId =\n clientId ||\n (typeof localStorage !== \"undefined\"\n ? localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID) || undefined\n : undefined);\n\n let resolvedDeviceLabel = deviceLabel;\n let resolvedSubscriberId = subscriberId;\n\n if (!resolvedClientId || !resolvedDeviceLabel) {\n try {\n const initCp = await import(\"../../core/utils/init-control-plane.js\");\n if (\n !resolvedClientId &&\n typeof initCp.getOrCreateControlPlaneClientId === \"function\"\n ) {\n resolvedClientId = initCp.getOrCreateControlPlaneClientId();\n }\n if (\n !resolvedDeviceLabel &&\n typeof initCp.detectDeviceLabel === \"function\"\n ) {\n resolvedDeviceLabel = initCp.detectDeviceLabel();\n }\n } catch (_) {}\n }\n\n if (!resolvedSubscriberId) {\n try {\n const db = await Promise.race([\n getDb(),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 500)),\n ]);\n if (db) {\n resolvedSubscriberId = await getOrCreateSubscriberId(db);\n }\n } catch (_) {}\n }\n\n const subJson =\n typeof subscription.toJSON === \"function\"\n ? subscription.toJSON()\n : JSON.parse(JSON.stringify(subscription));\n\n const url = await getPushUrl(\"/push/subscribe\");\n await fetch(\n url,\n getPushFetchOptions(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...subJson,\n ...(resolvedClientId ? { clientId: resolvedClientId } : {}),\n ...(resolvedDeviceLabel ? { deviceLabel: resolvedDeviceLabel } : {}),\n ...(resolvedSubscriberId ? { subscriberId: resolvedSubscriberId } : {}),\n }),\n }),\n );\n\n return subscription;\n}\n\n/**\n * Re-register an existing push subscription with the server if one exists,\n * ensuring clientId, deviceLabel, and subscriberId are up-to-date.\n */\nexport async function syncExistingPushSubscription(\n subscriberId?: string,\n): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) {\n return;\n }\n try {\n const reg = await navigator.serviceWorker.ready;\n const sub = await reg.pushManager.getSubscription();\n if (!sub) {\n return;\n }\n\n let resolvedClientId: string | undefined;\n let resolvedDeviceLabel: string | undefined;\n let resolvedSubscriberId = subscriberId;\n\n if (typeof localStorage !== \"undefined\") {\n resolvedClientId =\n localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID) || undefined;\n }\n\n try {\n const initCp = await import(\"../../core/utils/init-control-plane.js\");\n if (\n !resolvedClientId &&\n typeof initCp.getOrCreateControlPlaneClientId === \"function\"\n ) {\n resolvedClientId = initCp.getOrCreateControlPlaneClientId();\n }\n if (typeof initCp.detectDeviceLabel === \"function\") {\n resolvedDeviceLabel = initCp.detectDeviceLabel();\n }\n } catch (_) {}\n\n if (!resolvedSubscriberId) {\n try {\n const db = await Promise.race([\n getDb(),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 500)),\n ]);\n if (db) {\n resolvedSubscriberId = await getOrCreateSubscriberId(db);\n }\n } catch (_) {}\n }\n\n const subJson =\n typeof sub.toJSON === \"function\"\n ? sub.toJSON()\n : JSON.parse(JSON.stringify(sub));\n\n const url = await getPushUrl(\"/push/subscribe\");\n await fetch(\n url,\n getPushFetchOptions(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...subJson,\n ...(resolvedClientId ? { clientId: resolvedClientId } : {}),\n ...(resolvedDeviceLabel ? { deviceLabel: resolvedDeviceLabel } : {}),\n ...(resolvedSubscriberId\n ? { subscriberId: resolvedSubscriberId }\n : {}),\n }),\n }),\n );\n } catch (_) {\n // Non-fatal if server is unreachable\n }\n}\n\n/**\n * Unsubscribe from push notifications.\n * Removes the push subscription locally and notifies the server.\n */\nexport async function unsubscribeFromPush(): Promise<void> {\n const registration = await navigator.serviceWorker.ready;\n const subscription = await registration.pushManager.getSubscription();\n\n if (!subscription) {\n return;\n }\n\n const { endpoint } = subscription;\n await subscription.unsubscribe();\n\n const url = await getPushUrl(\"/push/subscribe\");\n await fetch(\n url,\n getPushFetchOptions(url, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoint }),\n }),\n );\n}\n\n/**\n * Get the current push subscription (or null if not subscribed).\n */\nexport async function getCurrentSubscription(): Promise<PushSubscription | null> {\n const registration = await navigator.serviceWorker.ready;\n\n return registration.pushManager.getSubscription();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"push-client-CAm6UMvE.js","names":[],"sources":["../../src/subsystems/notifications/push-client.ts"],"sourcesContent":["/**\n * Client-side Web Push subscription management.\n * Runs in the browser — communicates with the server's push routes.\n */\n\nimport { CONFIG_KEYS } from \"../../config/config.js\";\nimport { getDb } from \"../../db/db.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { getOrCreateSubscriberId } from \"../../db/get-or-create-subscriber-id.js\";\n\n/**\n * Resolve a push route URL, optionally using a configured proxy.\n */\nexport async function getPushUrl(path: string): Promise<string> {\n const db = await getDb();\n let proxyUrl = await getConfig(db, CONFIG_KEYS.PUSH_PROXY_URL);\n\n if (!proxyUrl && typeof localStorage !== \"undefined\") {\n try {\n proxyUrl = localStorage.getItem(CONFIG_KEYS.PUSH_PROXY_URL) || undefined;\n } catch (_) {}\n }\n\n if (!proxyUrl) {\n return path;\n }\n\n // Ensure path starts with /\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n // Ensure proxyUrl doesn't end with /\n const normalizedProxy = proxyUrl.endsWith(\"/\")\n ? proxyUrl.slice(0, -1)\n : proxyUrl;\n\n return `${normalizedProxy}${normalizedPath}`;\n}\n\nexport function getPushFetchOptions(\n url: string,\n baseOptions: RequestInit = {},\n): RequestInit {\n const opts: any = { ...baseOptions };\n try {\n const locOrigin =\n typeof location !== \"undefined\"\n ? location.origin\n : \"http://127.0.0.1:8888\";\n const u = new URL(url, locOrigin);\n const host = u.hostname.toLowerCase();\n if (\n host === \"localhost\" ||\n host === \"127.0.0.1\" ||\n host === \"::1\" ||\n host === \"[::1]\"\n ) {\n opts.targetAddressSpace = \"loopback\";\n } else if (\n /^(10\\.|172\\.(1[6-9]|2\\d|3[01])\\.|192\\.168\\.)/.test(host) ||\n !host.includes(\".\") ||\n host.endsWith(\".local\") ||\n host.endsWith(\".lan\") ||\n host.endsWith(\".home\") ||\n host.endsWith(\".internal\")\n ) {\n opts.targetAddressSpace = \"private\";\n }\n } catch (_) {}\n return opts;\n}\n\n/**\n * Convert a URL-safe base64 string to a Uint8Array.\n * Required for PushManager.subscribe() applicationServerKey.\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = \"=\".repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, \"+\").replace(/_/g, \"/\");\n const rawData = atob(base64);\n\n return Uint8Array.from([...rawData].map((c) => c.charCodeAt(0)));\n}\n\n/**\n * Fetch the VAPID public key from the server.\n */\nexport async function getVapidPublicKey(): Promise<string> {\n const url = await getPushUrl(\"/push/vapid-public-key\");\n const res = await fetch(url, getPushFetchOptions(url));\n const data = await res.json();\n\n return data.publicKey;\n}\n\n/**\n * Subscribe to push notifications.\n * Requests permission, creates a push subscription, and sends it to the server.\n */\nexport async function subscribeToPush(\n clientId?: string,\n deviceLabel?: string,\n subscriberId?: string,\n): Promise<PushSubscription> {\n const registration = await navigator.serviceWorker.ready;\n const publicKey = await getVapidPublicKey();\n\n const subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: urlBase64ToUint8Array(publicKey) as any,\n });\n\n let resolvedClientId =\n clientId ||\n (typeof localStorage !== \"undefined\"\n ? localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID) || undefined\n : undefined);\n\n let resolvedDeviceLabel = deviceLabel;\n let resolvedSubscriberId = subscriberId;\n\n if (!resolvedClientId || !resolvedDeviceLabel) {\n try {\n const initCp = await import(\"../../core/utils/init-control-plane.js\");\n if (\n !resolvedClientId &&\n typeof initCp.getOrCreateControlPlaneClientId === \"function\"\n ) {\n resolvedClientId = initCp.getOrCreateControlPlaneClientId();\n }\n if (\n !resolvedDeviceLabel &&\n typeof initCp.detectDeviceLabel === \"function\"\n ) {\n resolvedDeviceLabel = initCp.detectDeviceLabel();\n }\n } catch (_) {}\n }\n\n if (!resolvedSubscriberId) {\n try {\n const db = await Promise.race([\n getDb(),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 500)),\n ]);\n if (db) {\n resolvedSubscriberId = await getOrCreateSubscriberId(db);\n }\n } catch (_) {}\n }\n\n const subJson =\n typeof subscription.toJSON === \"function\"\n ? subscription.toJSON()\n : JSON.parse(JSON.stringify(subscription));\n\n const url = await getPushUrl(\"/push/subscribe\");\n await fetch(\n url,\n getPushFetchOptions(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...subJson,\n ...(resolvedClientId ? { clientId: resolvedClientId } : {}),\n ...(resolvedDeviceLabel ? { deviceLabel: resolvedDeviceLabel } : {}),\n ...(resolvedSubscriberId ? { subscriberId: resolvedSubscriberId } : {}),\n }),\n }),\n );\n\n return subscription;\n}\n\n/**\n * Re-register an existing push subscription with the server if one exists,\n * ensuring clientId, deviceLabel, and subscriberId are up-to-date.\n */\nexport async function syncExistingPushSubscription(\n subscriberId?: string,\n): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) {\n return;\n }\n try {\n const reg = await navigator.serviceWorker.ready;\n const sub = await reg.pushManager.getSubscription();\n if (!sub) {\n return;\n }\n\n let resolvedClientId: string | undefined;\n let resolvedDeviceLabel: string | undefined;\n let resolvedSubscriberId = subscriberId;\n\n if (typeof localStorage !== \"undefined\") {\n resolvedClientId =\n localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID) || undefined;\n }\n\n try {\n const initCp = await import(\"../../core/utils/init-control-plane.js\");\n if (\n !resolvedClientId &&\n typeof initCp.getOrCreateControlPlaneClientId === \"function\"\n ) {\n resolvedClientId = initCp.getOrCreateControlPlaneClientId();\n }\n if (typeof initCp.detectDeviceLabel === \"function\") {\n resolvedDeviceLabel = initCp.detectDeviceLabel();\n }\n } catch (_) {}\n\n if (!resolvedSubscriberId) {\n try {\n const db = await Promise.race([\n getDb(),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 500)),\n ]);\n if (db) {\n resolvedSubscriberId = await getOrCreateSubscriberId(db);\n }\n } catch (_) {}\n }\n\n const subJson =\n typeof sub.toJSON === \"function\"\n ? sub.toJSON()\n : JSON.parse(JSON.stringify(sub));\n\n const url = await getPushUrl(\"/push/subscribe\");\n await fetch(\n url,\n getPushFetchOptions(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...subJson,\n ...(resolvedClientId ? { clientId: resolvedClientId } : {}),\n ...(resolvedDeviceLabel ? { deviceLabel: resolvedDeviceLabel } : {}),\n ...(resolvedSubscriberId\n ? { subscriberId: resolvedSubscriberId }\n : {}),\n }),\n }),\n );\n } catch (_) {\n // Non-fatal if server is unreachable\n }\n}\n\n/**\n * Unsubscribe from push notifications.\n * Removes the push subscription locally and notifies the server.\n */\nexport async function unsubscribeFromPush(): Promise<void> {\n const registration = await navigator.serviceWorker.ready;\n const subscription = await registration.pushManager.getSubscription();\n\n if (!subscription) {\n return;\n }\n\n const { endpoint } = subscription;\n await subscription.unsubscribe();\n\n const url = await getPushUrl(\"/push/subscribe\");\n await fetch(\n url,\n getPushFetchOptions(url, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoint }),\n }),\n );\n}\n\n/**\n * Get the current push subscription (or null if not subscribed).\n */\nexport async function getCurrentSubscription(): Promise<PushSubscription | null> {\n const registration = await navigator.serviceWorker.ready;\n\n return registration.pushManager.getSubscription();\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { t as getConfig } from "./get-config-BWhs5HFF.js";
2
2
  import { t as setConfig } from "./set-config-CUadvYZ1.js";
3
- import { _ as createGroup, v as getGroupMetadata } from "./orchestrator-CCARkxQC.js";
3
+ import { _ as createGroup, v as getGroupMetadata } from "./orchestrator-cRBe3lhq.js";
4
4
 
5
5
  //#region src/db/rooms.ts
6
6
  /**
@@ -66,4 +66,4 @@ async function deleteRoom(db, roomId) {
66
66
 
67
67
  //#endregion
68
68
  export { roomIdFromGroupId as a, roomGroupId as i, deleteRoom as n, upsertRoom as o, getRoomMetadata as r, ROOM_PREFIX as t };
69
- //# sourceMappingURL=rooms-bwGoYb1q.js.map
69
+ //# sourceMappingURL=rooms-Dzphx3rK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rooms-bwGoYb1q.js","names":[],"sources":["../../src/db/rooms.ts"],"sourcesContent":["/**\n * ShadowClaw — Room (multi-party conversation) metadata management\n *\n * A room is layered on top of a {@link GroupMeta} whose groupId is\n * `room:<roomId>` (so existing message storage, OPFS workspace, unread state,\n * and the conversation list work unchanged). This module persists the room\n * roster / host separately under a dedicated config key.\n */\n\nimport { getConfig } from \"./get-config.js\";\nimport { setConfig } from \"./set-config.js\";\nimport { createGroup, getGroupMetadata } from \"./groups.js\";\nimport { ulid } from \"../utils/ulid.js\";\nimport type { ShadowClawDatabase } from \"./types.js\";\nimport type { RoomMember, RoomMeta } from \"../subsystems/channels/types.js\";\n\nconst CONFIG_KEY = \"room_metadata\";\n\n/** The groupId prefix used for room conversations. */\nexport const ROOM_PREFIX = \"room:\";\n\n/** Build the conversation groupId for a bare room id. */\nexport function roomGroupId(roomId: string): string {\n return `${ROOM_PREFIX}${roomId}`;\n}\n\n/** Extract the bare room id from a `room:<id>` groupId. */\nexport function roomIdFromGroupId(groupId: string): string {\n return groupId.startsWith(ROOM_PREFIX)\n ? groupId.slice(ROOM_PREFIX.length)\n : groupId;\n}\n\n/** Get all room metadata from config. */\nexport async function getRoomMetadata(\n db: ShadowClawDatabase,\n): Promise<RoomMeta[]> {\n const raw = await getConfig(db, CONFIG_KEY);\n if (!raw) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(raw);\n\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\n/** Save all room metadata to config. */\nexport async function saveRoomMetadata(\n db: ShadowClawDatabase,\n metadata: RoomMeta[],\n): Promise<void> {\n await setConfig(db, CONFIG_KEY, JSON.stringify(metadata));\n}\n\n/** Get a single room by its bare room id. */\nexport async function getRoom(\n db: ShadowClawDatabase,\n roomId: string,\n): Promise<RoomMeta | null> {\n const rooms = await getRoomMetadata(db);\n\n return rooms.find((r) => r.roomId === roomId) ?? null;\n}\n\n/**\n * Persist (insert or replace) a single room record and ensure a matching\n * conversation group exists.\n */\nexport async function upsertRoom(\n db: ShadowClawDatabase,\n room: RoomMeta,\n): Promise<void> {\n const rooms = await getRoomMetadata(db);\n const index = rooms.findIndex((r) => r.roomId === room.roomId);\n if (index >= 0) {\n rooms[index] = room;\n } else {\n rooms.push(room);\n }\n\n await saveRoomMetadata(db, rooms);\n await ensureRoomGroup(db, room);\n}\n\n/**\n * Ensure a `room:<roomId>` GroupMeta exists for the given room so the\n * conversation, message history and workspace are available.\n */\nasync function ensureRoomGroup(\n db: ShadowClawDatabase,\n room: RoomMeta,\n): Promise<void> {\n const groups = await getGroupMetadata(db);\n const groupId = roomGroupId(room.roomId);\n if (groups.some((g) => g.groupId === groupId)) {\n return;\n }\n\n await createGroup(db, room.name, ROOM_PREFIX, room.roomId);\n}\n\n/**\n * Create a new room (as host) and persist it along with its conversation group.\n */\nexport async function createRoom(\n db: ShadowClawDatabase,\n name: string,\n hostPeerId: string,\n hostMember: RoomMember,\n): Promise<RoomMeta> {\n const room: RoomMeta = {\n roomId: ulid(),\n name,\n hostPeerId,\n members: [hostMember],\n createdAt: Date.now(),\n };\n\n await upsertRoom(db, room);\n\n return room;\n}\n\n/** Add or update a member in a room's roster. Returns the updated room. */\nexport async function addRoomMember(\n db: ShadowClawDatabase,\n roomId: string,\n member: RoomMember,\n): Promise<RoomMeta | null> {\n const rooms = await getRoomMetadata(db);\n const room = rooms.find((r) => r.roomId === roomId);\n if (!room) {\n return null;\n }\n\n const index = room.members.findIndex((m) => m.peerId === member.peerId);\n if (index >= 0) {\n room.members[index] = member;\n } else {\n room.members.push(member);\n }\n\n await saveRoomMetadata(db, rooms);\n\n return room;\n}\n\n/** Remove a member from a room's roster. Returns the updated room. */\nexport async function removeRoomMember(\n db: ShadowClawDatabase,\n roomId: string,\n peerId: string,\n): Promise<RoomMeta | null> {\n const rooms = await getRoomMetadata(db);\n const room = rooms.find((r) => r.roomId === roomId);\n if (!room) {\n return null;\n }\n\n room.members = room.members.filter((m) => m.peerId !== peerId);\n await saveRoomMetadata(db, rooms);\n\n return room;\n}\n\n/** Delete a room record (does not delete its conversation group/messages). */\nexport async function deleteRoom(\n db: ShadowClawDatabase,\n roomId: string,\n): Promise<void> {\n const rooms = await getRoomMetadata(db);\n await saveRoomMetadata(\n db,\n rooms.filter((r) => r.roomId !== roomId),\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAM,aAAa;;AAGnB,MAAa,cAAc;;AAG3B,SAAgB,YAAY,QAAwB;CAClD,OAAO,GAAG,cAAc;AAC1B;;AAGA,SAAgB,kBAAkB,SAAyB;CACzD,OAAO,QAAQ,kBAAsB,IACjC,QAAQ,MAAM,CAAkB,IAChC;AACN;;AAGA,eAAsB,gBACpB,IACqB;CACrB,MAAM,MAAM,MAAM,UAAU,IAAI,UAAU;CAC1C,IAAI,CAAC,KACH,OAAO,CAAC;CAGV,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;CAC3C,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;AAGA,eAAsB,iBACpB,IACA,UACe;CACf,MAAM,UAAU,IAAI,YAAY,KAAK,UAAU,QAAQ,CAAC;AAC1D;;;;;AAgBA,eAAsB,WACpB,IACA,MACe;CACf,MAAM,QAAQ,MAAM,gBAAgB,EAAE;CACtC,MAAM,QAAQ,MAAM,WAAW,MAAM,EAAE,WAAW,KAAK,MAAM;CAC7D,IAAI,SAAS,GACX,MAAM,SAAS;MAEf,MAAM,KAAK,IAAI;CAGjB,MAAM,iBAAiB,IAAI,KAAK;CAChC,MAAM,gBAAgB,IAAI,IAAI;AAChC;;;;;AAMA,eAAe,gBACb,IACA,MACe;CACf,MAAM,SAAS,MAAM,iBAAiB,EAAE;CACxC,MAAM,UAAU,YAAY,KAAK,MAAM;CACvC,IAAI,OAAO,MAAM,MAAM,EAAE,YAAY,OAAO,GAC1C;CAGF,MAAM,YAAY,IAAI,KAAK,MAAM,aAAa,KAAK,MAAM;AAC3D;;AAmEA,eAAsB,WACpB,IACA,QACe;CAEf,MAAM,iBACJ,KACA,MAHkB,gBAAgB,EAAE,EAG/B,CAAC,QAAQ,MAAM,EAAE,WAAW,MAAM,CACzC;AACF"}
1
+ {"version":3,"file":"rooms-Dzphx3rK.js","names":[],"sources":["../../src/db/rooms.ts"],"sourcesContent":["/**\n * ShadowClaw — Room (multi-party conversation) metadata management\n *\n * A room is layered on top of a {@link GroupMeta} whose groupId is\n * `room:<roomId>` (so existing message storage, OPFS workspace, unread state,\n * and the conversation list work unchanged). This module persists the room\n * roster / host separately under a dedicated config key.\n */\n\nimport { getConfig } from \"./get-config.js\";\nimport { setConfig } from \"./set-config.js\";\nimport { createGroup, getGroupMetadata } from \"./groups.js\";\nimport { ulid } from \"../utils/ulid.js\";\nimport type { ShadowClawDatabase } from \"./types.js\";\nimport type { RoomMember, RoomMeta } from \"../subsystems/channels/types.js\";\n\nconst CONFIG_KEY = \"room_metadata\";\n\n/** The groupId prefix used for room conversations. */\nexport const ROOM_PREFIX = \"room:\";\n\n/** Build the conversation groupId for a bare room id. */\nexport function roomGroupId(roomId: string): string {\n return `${ROOM_PREFIX}${roomId}`;\n}\n\n/** Extract the bare room id from a `room:<id>` groupId. */\nexport function roomIdFromGroupId(groupId: string): string {\n return groupId.startsWith(ROOM_PREFIX)\n ? groupId.slice(ROOM_PREFIX.length)\n : groupId;\n}\n\n/** Get all room metadata from config. */\nexport async function getRoomMetadata(\n db: ShadowClawDatabase,\n): Promise<RoomMeta[]> {\n const raw = await getConfig(db, CONFIG_KEY);\n if (!raw) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(raw);\n\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\n/** Save all room metadata to config. */\nexport async function saveRoomMetadata(\n db: ShadowClawDatabase,\n metadata: RoomMeta[],\n): Promise<void> {\n await setConfig(db, CONFIG_KEY, JSON.stringify(metadata));\n}\n\n/** Get a single room by its bare room id. */\nexport async function getRoom(\n db: ShadowClawDatabase,\n roomId: string,\n): Promise<RoomMeta | null> {\n const rooms = await getRoomMetadata(db);\n\n return rooms.find((r) => r.roomId === roomId) ?? null;\n}\n\n/**\n * Persist (insert or replace) a single room record and ensure a matching\n * conversation group exists.\n */\nexport async function upsertRoom(\n db: ShadowClawDatabase,\n room: RoomMeta,\n): Promise<void> {\n const rooms = await getRoomMetadata(db);\n const index = rooms.findIndex((r) => r.roomId === room.roomId);\n if (index >= 0) {\n rooms[index] = room;\n } else {\n rooms.push(room);\n }\n\n await saveRoomMetadata(db, rooms);\n await ensureRoomGroup(db, room);\n}\n\n/**\n * Ensure a `room:<roomId>` GroupMeta exists for the given room so the\n * conversation, message history and workspace are available.\n */\nasync function ensureRoomGroup(\n db: ShadowClawDatabase,\n room: RoomMeta,\n): Promise<void> {\n const groups = await getGroupMetadata(db);\n const groupId = roomGroupId(room.roomId);\n if (groups.some((g) => g.groupId === groupId)) {\n return;\n }\n\n await createGroup(db, room.name, ROOM_PREFIX, room.roomId);\n}\n\n/**\n * Create a new room (as host) and persist it along with its conversation group.\n */\nexport async function createRoom(\n db: ShadowClawDatabase,\n name: string,\n hostPeerId: string,\n hostMember: RoomMember,\n): Promise<RoomMeta> {\n const room: RoomMeta = {\n roomId: ulid(),\n name,\n hostPeerId,\n members: [hostMember],\n createdAt: Date.now(),\n };\n\n await upsertRoom(db, room);\n\n return room;\n}\n\n/** Add or update a member in a room's roster. Returns the updated room. */\nexport async function addRoomMember(\n db: ShadowClawDatabase,\n roomId: string,\n member: RoomMember,\n): Promise<RoomMeta | null> {\n const rooms = await getRoomMetadata(db);\n const room = rooms.find((r) => r.roomId === roomId);\n if (!room) {\n return null;\n }\n\n const index = room.members.findIndex((m) => m.peerId === member.peerId);\n if (index >= 0) {\n room.members[index] = member;\n } else {\n room.members.push(member);\n }\n\n await saveRoomMetadata(db, rooms);\n\n return room;\n}\n\n/** Remove a member from a room's roster. Returns the updated room. */\nexport async function removeRoomMember(\n db: ShadowClawDatabase,\n roomId: string,\n peerId: string,\n): Promise<RoomMeta | null> {\n const rooms = await getRoomMetadata(db);\n const room = rooms.find((r) => r.roomId === roomId);\n if (!room) {\n return null;\n }\n\n room.members = room.members.filter((m) => m.peerId !== peerId);\n await saveRoomMetadata(db, rooms);\n\n return room;\n}\n\n/** Delete a room record (does not delete its conversation group/messages). */\nexport async function deleteRoom(\n db: ShadowClawDatabase,\n roomId: string,\n): Promise<void> {\n const rooms = await getRoomMetadata(db);\n await saveRoomMetadata(\n db,\n rooms.filter((r) => r.roomId !== roomId),\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAM,aAAa;;AAGnB,MAAa,cAAc;;AAG3B,SAAgB,YAAY,QAAwB;CAClD,OAAO,GAAG,cAAc;AAC1B;;AAGA,SAAgB,kBAAkB,SAAyB;CACzD,OAAO,QAAQ,kBAAsB,IACjC,QAAQ,MAAM,CAAkB,IAChC;AACN;;AAGA,eAAsB,gBACpB,IACqB;CACrB,MAAM,MAAM,MAAM,UAAU,IAAI,UAAU;CAC1C,IAAI,CAAC,KACH,OAAO,CAAC;CAGV,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;CAC3C,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;AAGA,eAAsB,iBACpB,IACA,UACe;CACf,MAAM,UAAU,IAAI,YAAY,KAAK,UAAU,QAAQ,CAAC;AAC1D;;;;;AAgBA,eAAsB,WACpB,IACA,MACe;CACf,MAAM,QAAQ,MAAM,gBAAgB,EAAE;CACtC,MAAM,QAAQ,MAAM,WAAW,MAAM,EAAE,WAAW,KAAK,MAAM;CAC7D,IAAI,SAAS,GACX,MAAM,SAAS;MAEf,MAAM,KAAK,IAAI;CAGjB,MAAM,iBAAiB,IAAI,KAAK;CAChC,MAAM,gBAAgB,IAAI,IAAI;AAChC;;;;;AAMA,eAAe,gBACb,IACA,MACe;CACf,MAAM,SAAS,MAAM,iBAAiB,EAAE;CACxC,MAAM,UAAU,YAAY,KAAK,MAAM;CACvC,IAAI,OAAO,MAAM,MAAM,EAAE,YAAY,OAAO,GAC1C;CAGF,MAAM,YAAY,IAAI,KAAK,MAAM,aAAa,KAAK,MAAM;AAC3D;;AAmEA,eAAsB,WACpB,IACA,QACe;CAEf,MAAM,iBACJ,KACA,MAHkB,gBAAgB,EAAE,EAG/B,CAAC,QAAQ,MAAM,EAAE,WAAW,MAAM,CACzC;AACF"}
@@ -6,7 +6,7 @@ import { c as isFeedRoute, d as parseRouteFromUrlAsync, h as resolveRouteToPrett
6
6
  import { t as fileViewerStore } from "./file-viewer-DOfvX6yy.js";
7
7
  import { yieldToMain } from "./utils/delay.js";
8
8
  import { t as setConfig } from "./set-config-CUadvYZ1.js";
9
- import { I as answerUserPrompt, r as getSiteConfigDefaultPinnedPage, t as orchestratorStore } from "./orchestrator-CCARkxQC.js";
9
+ import { I as answerUserPrompt, r as getSiteConfigDefaultPinnedPage, t as orchestratorStore } from "./orchestrator-cRBe3lhq.js";
10
10
  import { getNamespacedItem, getNamespacedStorageKey, setNamespacedItem } from "./utils/namespaced-storage.js";
11
11
  import { a as showSuccess, r as showError } from "./toast-Ck7OIKDf.js";
12
12
  import { isTruthyConfigValue } from "./utils/parse-boolean-config.js";
@@ -2797,7 +2797,7 @@ var ShadowClaw = class extends ShadowClawElement {
2797
2797
  const initialLocationUrl = typeof window !== "undefined" && window.location?.href ? new URL(window.location.href) : null;
2798
2798
  await yieldToMain();
2799
2799
  try {
2800
- const { Orchestrator } = await import("./orchestrator-C7fkh7T7.js");
2800
+ const { Orchestrator } = await import("./orchestrator-BBAwy9Nm.js");
2801
2801
  await yieldToMain();
2802
2802
  const loadDeferredComponents = () => {
2803
2803
  Promise.all([import("./components/shadow-claw-dialog.js"), import("./components/shadow-claw-toast.js")]).catch(console.error);
@@ -2821,16 +2821,16 @@ var ShadowClaw = class extends ShadowClawElement {
2821
2821
  await applyRouteFromCurrentLocation(this.shadowRoot, this, this.db, fileViewerStore, orchestratorStore, initialLocationUrl || new URL(window.location.href));
2822
2822
  const currentUrl = initialLocationUrl || (typeof window !== "undefined" && window.location?.href ? new URL(window.location.href) : null);
2823
2823
  if (currentUrl?.searchParams?.has("peer")) {
2824
- const { processPeerQueryParam } = await import("./process-peer-query-param-BxYiZNdf.js");
2824
+ const { processPeerQueryParam } = await import("./process-peer-query-param-BnsVnxzH.js");
2825
2825
  await processPeerQueryParam(this.shadowRoot, this, this.db, this.orchestrator);
2826
2826
  }
2827
2827
  if (currentUrl?.searchParams?.has("room") || currentUrl?.searchParams?.has("host")) {
2828
- const { processRoomQueryParam } = await import("./process-room-query-param-B2_d50nE.js");
2828
+ const { processRoomQueryParam } = await import("./process-room-query-param-B8EYg_-r.js");
2829
2829
  await processRoomQueryParam(window, this.shadowRoot, this, this.db, this.orchestrator, orchestratorStore);
2830
2830
  }
2831
2831
  const runDeferredShares = async () => {
2832
2832
  if (!this.db) return;
2833
- const { processPendingSharedPayloads } = await import("./process-pending-shared-payloads-DPIbwRb3.js");
2833
+ const { processPendingSharedPayloads } = await import("./process-pending-shared-payloads-DBZfZOOa.js");
2834
2834
  await processPendingSharedPayloads(window, this.shadowRoot, this, orchestratorStore, fileViewerStore, this.db, currentUrl || new URL(window.location.href));
2835
2835
  };
2836
2836
  if (currentUrl?.searchParams?.has("share-target") || globalThis.__SHADOWCLAW_E2E_ENABLE__ === true) await runDeferredShares();
@@ -2966,4 +2966,4 @@ if (!customElements.get(elementName)) customElements.define(elementName, ShadowC
2966
2966
 
2967
2967
  //#endregion
2968
2968
  export { showPage as a, MIN_SIDEBAR_WIDTH_PX as i, DEFAULT_SIDEBAR_WIDTH_PX as n, MAX_SIDEBAR_WIDTH_PX as r, ShadowClaw as t };
2969
- //# sourceMappingURL=shadow-claw-CypGVlVO.js.map
2969
+ //# sourceMappingURL=shadow-claw-CGl8tXtG.js.map