chainlesschain 0.162.147 → 0.162.148

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 (184) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DywJ7xTv.js → AIOps-DwpCCp64.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-BTlqcY-q.js → ActionButton-C9pBYocA.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-FdG1Mvwy.js → Analytics-BWAkeXxK.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CVsnbvN1.js → AppLayout-CivFGH6B.js} +5 -5
  8. package/src/assets/web-panel/assets/{Audit-ITdpJ7vR.js → Audit-Cm8hRpZm.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BfXqnXo1.js → Backup-DXdFMsE8.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-C09ip3_E.js → BaseInput-uAwSTeql.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-qdkhB42l.js → Chat-KU8eeJJE.js} +6 -6
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-DCNfbdlx.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-j6WZCuff.js → Checkbox-C6AMDkjd.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-CGZ-K3uK.js → Codegen-t2moDxcO.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-CIlPOAu6.js → Col-DCcsRRhN.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-sY-i-hic.js → Community-DtB-8SAC.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DcoEfyL8.js → Compact-CZm8THYA.js} +1 -1
  18. package/src/assets/web-panel/assets/Compliance-LiQgC7g1.js +1 -0
  19. package/src/assets/web-panel/assets/{Cowork-DLY_fkLv.js → Cowork-CA8SAxht.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-D049pZBC.js → Cron-CtRaF1wD.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-DCXdE8M9.js → Crosschain-6-br6Hub.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-JCvPZtjW.js → DID-Do2EccrL.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-Cg2xu3iE.js → Dashboard-wrXcbzGe.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DjJLjbLh.js → Dropdown-p3FsT245.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DugNcSLR.js → EmailListRenderer-D95A2L8q.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-J6Nb-E30.js → FamilyGuardDashboard-cLuJW2zo.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-CQ3Ttpbl.js → Federation-Brgq_cbN.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-Cz0NKag4.js → FormItemContext-DWLCkNgh.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-NYcMP6iz.js → GenericCardRenderer-BBqUfQd6.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-B4hYN18N.js → Git-8F090w4I.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DOQPCcC0.js → Governance-CCogEbxb.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-HtLF746W.js → Inference-CfLD7v7C.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-BXrk8rMm.js → KnowledgeGraph-DDuHJewd.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DS0JnD3-.js → Logs-CE8KSEVC.js} +2 -2
  35. package/src/assets/web-panel/assets/{Marketplace-Cqnjihrz.js → Marketplace-DmwpZmhT.js} +1 -1
  36. package/src/assets/web-panel/assets/{McpTools-Cx3Psk-U.js → McpTools-Bf7AazU8.js} +5 -5
  37. package/src/assets/web-panel/assets/{Memory-BjyysPtj.js → Memory-D0QU_00S.js} +2 -2
  38. package/src/assets/web-panel/assets/MobileBridge-D3Arxfeg.css +1 -0
  39. package/src/assets/web-panel/assets/MobileBridge-yXS9xdhx.js +1 -0
  40. package/src/assets/web-panel/assets/{MobileProjects-Xwf-fdOQ.js → MobileProjects-BuDUoGUP.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-Djkql5m5.js → Mtc-BYyHy28p.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-D2BAZlu0.js → MtcAudit-CK0aqpiZ.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-ByqP1ZzH.js → Multisig-mNimKYeb.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-C_kn0nE2.js → NLProgramming-AioAJ0YA.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-7l7eXHPq.js → Notes-CVVNCLHE.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BrCDoitw.js → NotificationSettings-C4ABj-TK.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-CmtqIdwr.js → OrderTableRenderer-DIp8Xcbd.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-DdoNAxsM.js → Organization-uozl_gWK.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Bw7R6dE3.js → Overflow-BCZOM2hK.js} +1 -1
  50. package/src/assets/web-panel/assets/{OverrideContext-C2r4vyBb.js → OverrideContext-BlgL9440.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-DJNtBugA.js → P2P-CArcaiaj.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-Dwhd5_ue.js → PdhVaultBrowser-Sgq2Srr8.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-BYoSfhPR.js → Permissions-BYrQrXnH.js} +3 -3
  54. package/src/assets/web-panel/assets/{PersonalDataHub-aYCYJbnH.js → PersonalDataHub-BzHStAbz.js} +2 -2
  55. package/src/assets/web-panel/assets/{Pipeline-DJp6CprF.js → Pipeline-k7KqxX1M.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-Cq9HZweR.js → Privacy-IumTUWqx.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-CmF0HsSt.js → ProjectInit-BRyImYTf.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-P8V5Aea2.js → ProjectSettings-BFIqTBFk.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-DPd5-lNS.js → Projects-Dpid9CDg.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-D589v0q2.js → Providers-CyyFnUPs.js} +1 -1
  61. package/src/assets/web-panel/assets/QrScannerModal-C82cRx-X.js +1 -0
  62. package/src/assets/web-panel/assets/{MobileBridge-zJpPuf4E.css → QrScannerModal-NwAHNfiJ.css} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-lvRV2osB.js → QuickAsk-DGxDF521.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-sb84MTpY.js → Recommend-Cns-Am1y.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-R7OqAIlg.js +4 -0
  66. package/src/assets/web-panel/assets/{Reputation-d9Y3vy-W.js → Reputation-D7mgPIYV.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-DMdhLUTp.js → Row-B3lEURyd.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-OL-SMDkz.js → RssFeed-9_UVrpBt.js} +2 -2
  69. package/src/assets/web-panel/assets/{Search-BjStLKq1.js → Search-ClZeO80q.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-MeI411qr.js → Security-BNNJczEp.js} +3 -3
  71. package/src/assets/web-panel/assets/{Services-UajosuhT.js → Services-C5SjrWUj.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-CGpG-QJ1.js → Skeleton-Ci_obQ-g.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-C6P2RPY-.js → Skills-DdebN15P.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-B_fPprgw.js → Sla-OinZP2vi.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-CqxLjSlQ.js → SpeechSettings-CxzbNF51.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-DixSfFOQ.js → SyncSettings-D06N_66b.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-PavzPBxc.js → Tasks-BdEdW0AZ.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-BYdGRnfX.js → Templates-F1ctKmPa.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-BQLgnarD.js → Tenant-CVz1Urot.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-BzOHpq-B.js → Terminal-BvAK_Zel.js} +2 -2
  81. package/src/assets/web-panel/assets/TimelineRenderer-Doitzjmf.js +1 -0
  82. package/src/assets/web-panel/assets/{Tokens-DxhgszRJ.js → Tokens-BpyVRpVA.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-nQYHayuc.js → Trigger-nWhWYTbU.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-CvqZDuZ4.js → Trust-DK_G-wLx.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DaR8GV2I.js → UkeySign-B5yBUojO.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-C6Mpsokw.js → VideoEditing-C5D51qAe.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-B57VRrWc.js → Wallet-CLbL9K7v.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-BbtEEtpq.js → WebAuthn-DZUelI3V.js} +4 -4
  89. package/src/assets/web-panel/assets/{WorkflowEditor-C5LwvKmH.js → WorkflowEditor-8RPxt4KW.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-MzuPR5jh.js → chat-4N4tOA3d.js} +1 -1
  91. package/src/assets/web-panel/assets/{collapseMotion-mxzzcDsg.js → collapseMotion-DVfhbsdP.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-HyW8mi_y.js → colors-zbbGVrua.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-DvUSzWAp.js → compact-item-D7iMkbnE.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-4MppZl7X.js → createContext-CBzPJv-w.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-C2Z5LRgq.js +1 -0
  96. package/src/assets/web-panel/assets/{echarts-jxgIOFUZ.js → echarts-CL0F2SnX.js} +1 -1
  97. package/src/assets/web-panel/assets/{hasIn-D9q3CJ-u.js → hasIn-bHdrQSqZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{icons-DP3uiYxy.js → icons-BsDmGpcT.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Caqtu6Et.js → index-308gCGh7.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CgIfXOD9.js → index-B1s0Bz9O.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BcunsBIx.js → index-B7b1hGry.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DDZ6fP5Z.js → index-BBNr77E1.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BF2JsbiX.js → index-BCr0geV9.js} +1 -1
  104. package/src/assets/web-panel/assets/index-BGp6Yr-Y.js +1 -0
  105. package/src/assets/web-panel/assets/{index-CucRo4Vz.js → index-BJ4ZGyW0.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Bl-E4W4q.js → index-BS4_Mwk6.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Dv7ffI2g.js → index-BTIjjXry.js} +1 -1
  108. package/src/assets/web-panel/assets/index-BXiw9dQf.js +1 -0
  109. package/src/assets/web-panel/assets/{index-CifKUNtV.js → index-BZb8F8YG.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Btz8pU68.js → index-BnBOpqv3.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-m0b6Fj9q.js → index-Bqmx24kh.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Dvg5xYuP.js → index-BsKehmmS.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-UUMCA2Sq.js → index-BtbbdLnf.js} +4 -4
  114. package/src/assets/web-panel/assets/{index-CvAqCAo9.js → index-CPxkoKgA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B5E4DhVc.js → index-CQ6NcfWz.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B994UQfE.js → index-CQfu1U78.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CLAZs1Vd.js → index-CahryTX0.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BFGfC5RS.js → index-CdmMoYN1.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DcMkjb92.js → index-Ci009ijp.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DNYqw0MO.js → index-CiG1IZao.js} +1 -1
  121. package/src/assets/web-panel/assets/{index--Bm6OqmU.js → index-CkxK86vf.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-zLwYpvX0.js → index-CqdPyWm5.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Zvtru2oE.js → index-CvRMA9uT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BmCo2Xdp.js → index-D1YDh7Wr.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-D2jrnaq3.js → index-D4XKpj6c.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D7TDMMfu.js → index-DE9j5YgT.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-ryFLxB1p.js → index-DISWAYce.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-xvUVuFnA.js → index-DUyjUkY7.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C9I5MuJ0.js → index-DbE5D0WL.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BGQtFso0.js → index-DmqlJed-.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-SDblbKj6.js → index-DyoNgbXl.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Ci6adKh8.js → index-QFObYeo1.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Cs-RKRUM.js → index-QNAG4JtR.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-DFqvWeGc.js → index-S74FpAIn.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-eOQO6KnV.js → index-kmh1TxRa.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DmZ6-suL.js → index-oDKNgCsP.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-C0DiL97c.js → index-xYCm6W2h.js} +1 -1
  138. package/src/assets/web-panel/assets/{initDefaultProps-CC--PMsC.js → initDefaultProps-BD55yNBt.js} +1 -1
  139. package/src/assets/web-panel/assets/{motion-DdrBjRF1.js → motion-B5Bbe77U.js} +1 -1
  140. package/src/assets/web-panel/assets/{move-D712Gwl2.js → move-CTvIqHEH.js} +1 -1
  141. package/src/assets/web-panel/assets/{mtc-parser-39y-keKO.js → mtc-parser-BkNyPQKB.js} +1 -1
  142. package/src/assets/web-panel/assets/{omit-6Y51gDB9.js → omit-BaXJXgHA.js} +1 -1
  143. package/src/assets/web-panel/assets/{pickAttrs-Cy6EHbq9.js → pickAttrs-Bw6-YTxH.js} +1 -1
  144. package/src/assets/web-panel/assets/{placementArrow-BYxdAm0p.js → placementArrow-BLdbkLqJ.js} +1 -1
  145. package/src/assets/web-panel/assets/{responsiveObserve-C9R6q_cr.js → responsiveObserve-IVYkzntU.js} +1 -1
  146. package/src/assets/web-panel/assets/{slide-CXUJlilB.js → slide-DFMFwwtY.js} +1 -1
  147. package/src/assets/web-panel/assets/{statusUtils-DOtrOeql.js → statusUtils-CURYRtZ1.js} +1 -1
  148. package/src/assets/web-panel/assets/{styleChecker-D5r39o92.js → styleChecker-Cfz63s1r.js} +1 -1
  149. package/src/assets/web-panel/assets/useFlexGapSupport-COJL0KE3.js +1 -0
  150. package/src/assets/web-panel/assets/{useFs-BkrT-Zbc.js → useFs-YLLojQQf.js} +1 -1
  151. package/src/assets/web-panel/assets/{useMergedState-Cl2q1fes.js → useMergedState-Dc9sO2d7.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-BwnnnZjU.js → usePersonalDataHub-BF_21qUC.js} +1 -1
  153. package/src/assets/web-panel/assets/{useRefs-DD9q4mOT.js → useRefs-CAeFRzPf.js} +1 -1
  154. package/src/assets/web-panel/assets/{useState-BK4hy8Ma.js → useState-LwExUYDO.js} +1 -1
  155. package/src/assets/web-panel/assets/{vendor-BvqAck49.js → vendor-BMxUs6UX.js} +16 -16
  156. package/src/assets/web-panel/assets/{vnode-SU-N4pum.js → vnode-9ZpkA7bb.js} +1 -1
  157. package/src/assets/web-panel/assets/{zoom-DHScfpTP.js → zoom-DhtAfhl8.js} +1 -1
  158. package/src/assets/web-panel/index.html +3 -3
  159. package/src/commands/serve.js +10 -0
  160. package/src/gateways/remote-session-relay.js +160 -0
  161. package/src/gateways/ws/message-dispatcher.js +32 -0
  162. package/src/gateways/ws/remote-session-protocol.js +429 -0
  163. package/src/gateways/ws/ws-server.js +299 -0
  164. package/src/harness/golden-transcript.js +65 -0
  165. package/src/harness/mcp-client.js +6 -2
  166. package/src/harness/remote-session-audit-sink.js +132 -0
  167. package/src/harness/remote-session-audit.js +110 -0
  168. package/src/harness/remote-session-crypto.js +217 -0
  169. package/src/harness/remote-session-push-fcm.js +254 -0
  170. package/src/harness/remote-session-push.js +104 -0
  171. package/src/harness/remote-session-registry.js +420 -0
  172. package/src/lib/did-manager.js +6 -4
  173. package/src/lib/mcp-oauth.js +23 -6
  174. package/src/lib/session-manager.js +7 -3
  175. package/src/runtime/agent-runtime.js +8 -13
  176. package/src/runtime/policies/agent-policy.js +2 -0
  177. package/src/assets/web-panel/assets/ChatBubbleRenderer-D2KfETZD.js +0 -1
  178. package/src/assets/web-panel/assets/Compliance-T8EtTecW.js +0 -1
  179. package/src/assets/web-panel/assets/MobileBridge-CYaITZ7w.js +0 -1
  180. package/src/assets/web-panel/assets/TimelineRenderer-Bv7uZRM7.js +0 -1
  181. package/src/assets/web-panel/assets/devWarning-6YJJMjSH.js +0 -1
  182. package/src/assets/web-panel/assets/index-D_oeGLr6.js +0 -1
  183. package/src/assets/web-panel/assets/index-Qa57YG19.js +0 -1
  184. package/src/assets/web-panel/assets/useFlexGapSupport-DfAD5U4Z.js +0 -1
@@ -1 +1 @@
1
- import{N as i,h as a,w as l}from"./index-UUMCA2Sq.js";import{a7 as o,k as g,C as d,F as f,A as p}from"./vendor-BvqAck49.js";function c(e){let r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},t=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0,s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1,u=e;if(Array.isArray(e)&&(u=i(e)[0]),!u)return null;const n=o(u,r,s);return n.props=t?a(a({},n.props),r):n.props,l(typeof n.props.class!="object","class must be string"),n}function V(e){let r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},t=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0;return e.map(s=>c(s,r,t))}function v(e,r,t){p(o(e,a({},r)),t)}const m=e=>(e||[]).some(r=>g(r)?!(r.type===d||r.type===f&&!m(r.children)):!0)?e:null;function h(e,r,t,s){var u;const n=(u=e[r])===null||u===void 0?void 0:u.call(e,t);return m(n)?n:s?.()}export{h as a,V as b,c,v as t};
1
+ import{N as i,h as a,w as l}from"./index-BtbbdLnf.js";import{a8 as o,k as g,C as d,F as f,A as p}from"./vendor-BMxUs6UX.js";function c(e){let r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},t=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0,s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1,u=e;if(Array.isArray(e)&&(u=i(e)[0]),!u)return null;const n=o(u,r,s);return n.props=t?a(a({},n.props),r):n.props,l(typeof n.props.class!="object","class must be string"),n}function V(e){let r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},t=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0;return e.map(s=>c(s,r,t))}function v(e,r,t){p(o(e,a({},r)),t)}const m=e=>(e||[]).some(r=>g(r)?!(r.type===d||r.type===f&&!m(r.children)):!0)?e:null;function h(e,r,t,s){var u;const n=(u=e[r])===null||u===void 0?void 0:u.call(e,t);return m(n)?n:s?.()}export{h as a,V as b,c,v as t};
@@ -1,4 +1,4 @@
1
- import{K as o}from"./index-UUMCA2Sq.js";import{i as f}from"./motion-DdrBjRF1.js";const c=new o("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),y=new o("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),a=new o("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),s=new o("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),g=new o("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),O=new o("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),l=new o("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),u=new o("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}}),p=new o("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),z=new o("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}}),K=new o("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),w=new o("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}}),I={zoom:{inKeyframes:c,outKeyframes:y},"zoom-big":{inKeyframes:a,outKeyframes:s},"zoom-big-fast":{inKeyframes:a,outKeyframes:s},"zoom-left":{inKeyframes:l,outKeyframes:u},"zoom-right":{inKeyframes:p,outKeyframes:z},"zoom-up":{inKeyframes:g,outKeyframes:O},"zoom-down":{inKeyframes:K,outKeyframes:w}},h=(n,r)=>{const{antCls:m}=n,t=`${m}-${r}`,{inKeyframes:i,outKeyframes:e}=I[r];return[f(t,i,e,r==="zoom-big-fast"?n.motionDurationFast:n.motionDurationMid),{[`
1
+ import{K as o}from"./index-BtbbdLnf.js";import{i as f}from"./motion-B5Bbe77U.js";const c=new o("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),y=new o("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),a=new o("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),s=new o("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),g=new o("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),O=new o("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),l=new o("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),u=new o("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}}),p=new o("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),z=new o("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}}),K=new o("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),w=new o("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}}),I={zoom:{inKeyframes:c,outKeyframes:y},"zoom-big":{inKeyframes:a,outKeyframes:s},"zoom-big-fast":{inKeyframes:a,outKeyframes:s},"zoom-left":{inKeyframes:l,outKeyframes:u},"zoom-right":{inKeyframes:p,outKeyframes:z},"zoom-up":{inKeyframes:g,outKeyframes:O},"zoom-down":{inKeyframes:K,outKeyframes:w}},h=(n,r)=>{const{antCls:m}=n,t=`${m}-${r}`,{inKeyframes:i,outKeyframes:e}=I[r];return[f(t,i,e,r==="zoom-big-fast"?n.motionDurationFast:n.motionDurationMid),{[`
2
2
  ${t}-enter,
3
3
  ${t}-appear
4
4
  `]:{transform:"scale(0)",opacity:0,animationTimingFunction:n.motionEaseOutCirc,"&-prepare":{transform:"none"}},[`${t}-leave`]:{animationTimingFunction:n.motionEaseInOutCirc}}]};export{h as i,c as z};
@@ -8,9 +8,9 @@
8
8
  // Injected by web-ui-server.js at serve time
9
9
  window.__CC_CONFIG__ = __CC_CONFIG_PLACEHOLDER__;
10
10
  </script>
11
- <script type="module" crossorigin src="./assets/index-UUMCA2Sq.js"></script>
12
- <link rel="modulepreload" crossorigin href="./assets/vendor-BvqAck49.js">
13
- <link rel="modulepreload" crossorigin href="./assets/icons-DP3uiYxy.js">
11
+ <script type="module" crossorigin src="./assets/index-BtbbdLnf.js"></script>
12
+ <link rel="modulepreload" crossorigin href="./assets/vendor-BMxUs6UX.js">
13
+ <link rel="modulepreload" crossorigin href="./assets/icons-BsDmGpcT.js">
14
14
  <link rel="stylesheet" crossorigin href="./assets/index-Cq93VfoF.css">
15
15
  </head>
16
16
  <body>
@@ -27,6 +27,14 @@ export function registerServeCommand(program) {
27
27
  "Allow non-localhost connections (requires --token)",
28
28
  )
29
29
  .option("--project <path>", "Default project root for sessions")
30
+ .option(
31
+ "--remote-session-relay-url <url>",
32
+ "Signaling relay URL for Remote Session pairing",
33
+ )
34
+ .option(
35
+ "--remote-session-peer-id <id>",
36
+ "Stable relay peer ID for this local runtime",
37
+ )
30
38
  .option(
31
39
  "--http-port <port>",
32
40
  "Hosted HTTP port for Phase 5 envelope SSE (disabled if unset)",
@@ -47,6 +55,8 @@ export function registerServeCommand(program) {
47
55
  project: opts.project,
48
56
  httpPort: opts.httpPort ? parseInt(opts.httpPort, 10) : null,
49
57
  bundlePath: opts.bundle || null,
58
+ remoteSessionRelayUrl: opts.remoteSessionRelayUrl || null,
59
+ remoteSessionPeerId: opts.remoteSessionPeerId || null,
50
60
  });
51
61
  await runtime.startServer();
52
62
  } catch (err) {
@@ -0,0 +1,160 @@
1
+ import { EventEmitter } from "events";
2
+ import WebSocket from "ws";
3
+
4
+ export class RemoteSessionRelay extends EventEmitter {
5
+ constructor({
6
+ relayUrl,
7
+ peerId,
8
+ deviceType = "remote-session",
9
+ websocketFactory,
10
+ reconnectBaseMs = 500,
11
+ reconnectMaxMs = 30_000,
12
+ maxReconnectAttempts = Infinity,
13
+ queueLimit = 100,
14
+ setTimer = setTimeout,
15
+ clearTimer = clearTimeout,
16
+ } = {}) {
17
+ super();
18
+ if (!relayUrl || !peerId)
19
+ throw new Error("relayUrl and peerId are required");
20
+ this.relayUrl = relayUrl;
21
+ this.peerId = peerId;
22
+ this.deviceType = deviceType;
23
+ this.websocketFactory = websocketFactory || ((url) => new WebSocket(url));
24
+ this.ws = null;
25
+ this.reconnectBaseMs = reconnectBaseMs;
26
+ this.reconnectMaxMs = reconnectMaxMs;
27
+ this.maxReconnectAttempts = maxReconnectAttempts;
28
+ this.queueLimit = queueLimit;
29
+ this.setTimer = setTimer;
30
+ this.clearTimer = clearTimer;
31
+ this.reconnectAttempts = 0;
32
+ this.reconnectTimer = null;
33
+ this.outbox = [];
34
+ this.closedExplicitly = false;
35
+ this.connectPromise = null;
36
+ }
37
+
38
+ connect() {
39
+ if (this.ws && this.ws.readyState === this.ws.OPEN)
40
+ return Promise.resolve();
41
+ if (this.connectPromise) return this.connectPromise;
42
+ this.closedExplicitly = false;
43
+ this.connectPromise = new Promise((resolve, reject) => {
44
+ const ws = this.websocketFactory(this.relayUrl);
45
+ this.ws = ws;
46
+ const onOpen = () => {
47
+ this._send({
48
+ type: "register",
49
+ peerId: this.peerId,
50
+ deviceType: this.deviceType,
51
+ deviceInfo: { protocol: "remote-session.e2ee.v1" },
52
+ });
53
+ this.reconnectAttempts = 0;
54
+ this.connectPromise = null;
55
+ this._flushOutbox();
56
+ this.emit("connect");
57
+ resolve();
58
+ };
59
+ ws.once("open", onOpen);
60
+ ws.once("error", (error) => {
61
+ this.connectPromise = null;
62
+ reject(error);
63
+ });
64
+ ws.on("message", (raw) => this._handleMessage(raw));
65
+ ws.on("close", () => {
66
+ if (this.ws === ws) this.ws = null;
67
+ this.connectPromise = null;
68
+ this.emit("disconnect");
69
+ this._scheduleReconnect();
70
+ });
71
+ });
72
+ return this.connectPromise;
73
+ }
74
+
75
+ sendEncrypted(targetPeerId, envelope) {
76
+ const message = {
77
+ type: "message",
78
+ to: targetPeerId,
79
+ payload: { type: "remote-session.encrypted", envelope },
80
+ };
81
+ if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
82
+ if (this.outbox.length >= this.queueLimit) this.outbox.shift();
83
+ this.outbox.push(message);
84
+ this.emit("queued", { size: this.outbox.length });
85
+ return false;
86
+ }
87
+ this._send(message);
88
+ return true;
89
+ }
90
+
91
+ close() {
92
+ this.closedExplicitly = true;
93
+ if (this.reconnectTimer) {
94
+ this.clearTimer(this.reconnectTimer);
95
+ this.reconnectTimer = null;
96
+ }
97
+ this.ws?.close();
98
+ this.ws = null;
99
+ }
100
+
101
+ _scheduleReconnect() {
102
+ if (
103
+ this.closedExplicitly ||
104
+ this.reconnectTimer ||
105
+ this.reconnectAttempts >= this.maxReconnectAttempts
106
+ ) {
107
+ return;
108
+ }
109
+ const delay = Math.min(
110
+ this.reconnectBaseMs * 2 ** this.reconnectAttempts,
111
+ this.reconnectMaxMs,
112
+ );
113
+ this.reconnectAttempts += 1;
114
+ this.emit("reconnecting", { attempt: this.reconnectAttempts, delay });
115
+ this.reconnectTimer = this.setTimer(() => {
116
+ this.reconnectTimer = null;
117
+ this.connect().catch((error) => {
118
+ this.emit("reconnect-error", error);
119
+ this._scheduleReconnect();
120
+ });
121
+ }, delay);
122
+ if (typeof this.reconnectTimer?.unref === "function")
123
+ this.reconnectTimer.unref();
124
+ }
125
+
126
+ _flushOutbox() {
127
+ const pending = this.outbox.splice(0);
128
+ for (const message of pending) this._send(message);
129
+ if (pending.length) this.emit("flushed", { count: pending.length });
130
+ }
131
+
132
+ _send(message) {
133
+ if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
134
+ throw new Error("Remote Session relay is not connected");
135
+ }
136
+ this.ws.send(JSON.stringify(message));
137
+ }
138
+
139
+ _handleMessage(raw) {
140
+ let message;
141
+ try {
142
+ message = JSON.parse(raw.toString("utf8"));
143
+ } catch {
144
+ this.emit("protocol-error", new Error("Invalid signaling relay JSON"));
145
+ return;
146
+ }
147
+ if (message.type === "offline-message") message = message.originalMessage;
148
+ if (
149
+ message?.type === "message" &&
150
+ message.payload?.type === "remote-session.encrypted"
151
+ ) {
152
+ this.emit("encrypted-message", {
153
+ from: message.from,
154
+ envelope: message.payload.envelope,
155
+ });
156
+ return;
157
+ }
158
+ this.emit("relay-message", message);
159
+ }
160
+ }
@@ -7,6 +7,18 @@ import {
7
7
  PERSONAL_DATA_HUB_HANDLERS,
8
8
  PERSONAL_DATA_HUB_STREAMING_HANDLERS,
9
9
  } from "./personal-data-hub-protocol.js";
10
+ import {
11
+ handleRemoteSessionAudit,
12
+ handleRemoteSessionCreate,
13
+ handleRemoteSessionClose,
14
+ handleRemoteSessionDevices,
15
+ handleRemoteSessionJoin,
16
+ handleRemoteSessionPairingToken,
17
+ handleRemoteSessionPolicy,
18
+ handleRemoteSessionPublish,
19
+ handleRemoteSessionPushRegister,
20
+ handleRemoteSessionRevoke,
21
+ } from "./remote-session-protocol.js";
10
22
 
11
23
  export function createWsMessageDispatcher(server) {
12
24
  return {
@@ -54,6 +66,26 @@ export function createWsMessageDispatcher(server) {
54
66
  server._handleSessionInterrupt(id, ws, message),
55
67
  "slash-command": () => server._handleSlashCommand(id, ws, message),
56
68
  "session-answer": () => server._handleSessionAnswer(id, ws, message),
69
+ "remote-session-create": () =>
70
+ handleRemoteSessionCreate(server, clientId, ws, message),
71
+ "remote-session-close": () =>
72
+ handleRemoteSessionClose(server, clientId, ws, message),
73
+ "remote-session-pairing-token": () =>
74
+ handleRemoteSessionPairingToken(server, clientId, ws, message),
75
+ "remote-session-join": () =>
76
+ handleRemoteSessionJoin(server, clientId, ws, message),
77
+ "remote-session-devices": () =>
78
+ handleRemoteSessionDevices(server, clientId, ws, message),
79
+ "remote-session-audit": () =>
80
+ handleRemoteSessionAudit(server, clientId, ws, message),
81
+ "remote-session-policy": () =>
82
+ handleRemoteSessionPolicy(server, clientId, ws, message),
83
+ "remote-session-push-register": () =>
84
+ handleRemoteSessionPushRegister(server, clientId, ws, message),
85
+ "remote-session-revoke": () =>
86
+ handleRemoteSessionRevoke(server, clientId, ws, message),
87
+ "remote-session-publish": () =>
88
+ handleRemoteSessionPublish(server, clientId, ws, message),
57
89
  "host-tool-result": () => server._handleHostToolResult(id, ws, message),
58
90
  orchestrate: () => server._handleOrchestrate(id, ws, message),
59
91
  "cowork-task": () => server._handleCoworkTask(id, ws, message),
@@ -0,0 +1,429 @@
1
+ import {
2
+ handleSessionAnswer,
3
+ handleSessionInterrupt,
4
+ handleSessionMessage,
5
+ } from "./session-protocol.js";
6
+ import {
7
+ RemoteSessionCryptoContext,
8
+ createRemotePairingUri,
9
+ } from "../../harness/remote-session-crypto.js";
10
+
11
+ const CLIENT_EVENT_SCOPES = Object.freeze({
12
+ prompt: "prompt",
13
+ "approval.resolve": "approve",
14
+ interrupt: "interrupt",
15
+ });
16
+
17
+ function reply(server, ws, id, type, payload = {}) {
18
+ server._send(ws, { id, type, ...payload });
19
+ }
20
+
21
+ function audit(server, entry) {
22
+ server.remoteSessionAudit?.record(entry);
23
+ }
24
+
25
+ function attachPairingUri(server, result) {
26
+ const relayUrl = server.remoteSessionRelayUrl;
27
+ const hostPeerId = server.remoteSessionPeerId;
28
+ if (!relayUrl || !hostPeerId) return result;
29
+ server.remoteSessionPairingSecrets.set(
30
+ result.session.sessionId,
31
+ result.pairing.token,
32
+ );
33
+ let crypto = server.remoteSessionCrypto.get(result.session.sessionId);
34
+ if (!crypto) {
35
+ crypto = new RemoteSessionCryptoContext({
36
+ sessionId: result.session.sessionId,
37
+ localPeerId: hostPeerId,
38
+ });
39
+ server.remoteSessionCrypto.set(result.session.sessionId, crypto);
40
+ }
41
+ return {
42
+ ...result,
43
+ pairing: {
44
+ ...result.pairing,
45
+ hostPublicKey: crypto.publicKey,
46
+ uri: createRemotePairingUri({
47
+ relayUrl,
48
+ remoteSessionId: result.session.sessionId,
49
+ hostPeerId,
50
+ hostPublicKey: crypto.publicKey,
51
+ pairingToken: result.pairing.token,
52
+ expiresAt: result.pairing.expiresAt,
53
+ }),
54
+ },
55
+ };
56
+ }
57
+
58
+ export function handleRemoteSessionCreate(server, clientId, ws, message) {
59
+ try {
60
+ const result = server.remoteSessions.create({
61
+ hostClientId: clientId,
62
+ agentSessionId: message.sessionId,
63
+ name: message.name,
64
+ scopes: message.scopes,
65
+ });
66
+ audit(server, {
67
+ sessionId: result.session.sessionId,
68
+ actor: clientId,
69
+ action: "session.created",
70
+ detail: { agentSessionId: message.sessionId, name: message.name || null },
71
+ });
72
+ reply(
73
+ server,
74
+ ws,
75
+ message.id,
76
+ "remote-session-created",
77
+ attachPairingUri(server, result),
78
+ );
79
+ } catch (error) {
80
+ reply(server, ws, message.id, "error", {
81
+ code: "REMOTE_SESSION_CREATE_ERROR",
82
+ message: error.message,
83
+ });
84
+ }
85
+ }
86
+
87
+ export function handleRemoteSessionPairingToken(server, clientId, ws, message) {
88
+ try {
89
+ const { session } = server.remoteSessions.authorize(
90
+ message.remoteSessionId,
91
+ clientId,
92
+ "observe",
93
+ );
94
+ if (session.hostClientId !== clientId) {
95
+ throw new Error("Only the host can issue pairing tokens");
96
+ }
97
+ const pairing = server.remoteSessions.issuePairingToken(
98
+ message.remoteSessionId,
99
+ { scopes: message.scopes },
100
+ );
101
+ const result = attachPairingUri(server, {
102
+ session: {
103
+ sessionId: message.remoteSessionId,
104
+ },
105
+ pairing,
106
+ });
107
+ audit(server, {
108
+ sessionId: message.remoteSessionId,
109
+ actor: clientId,
110
+ action: "pairing-token.issued",
111
+ detail: { scopes: message.scopes || null, expiresAt: pairing.expiresAt },
112
+ });
113
+ reply(server, ws, message.id, "remote-session-pairing-token", {
114
+ pairing: result.pairing,
115
+ });
116
+ } catch (error) {
117
+ reply(server, ws, message.id, "error", {
118
+ code: "REMOTE_SESSION_PAIRING_ERROR",
119
+ message: error.message,
120
+ });
121
+ }
122
+ }
123
+
124
+ export function handleRemoteSessionJoin(server, clientId, ws, message) {
125
+ try {
126
+ const result = server.remoteSessions.join({
127
+ sessionId: message.remoteSessionId,
128
+ clientId,
129
+ token: message.token,
130
+ pushToken: message.pushToken,
131
+ pushProvider: message.pushProvider,
132
+ });
133
+ audit(server, {
134
+ sessionId: message.remoteSessionId,
135
+ actor: clientId,
136
+ action: "device.joined",
137
+ detail: {
138
+ scopes: result.member.scopes,
139
+ via: "direct",
140
+ hasPush: result.member.pushToken ? true : false,
141
+ },
142
+ });
143
+ reply(server, ws, message.id, "remote-session-joined", result);
144
+ } catch (error) {
145
+ reply(server, ws, message.id, "error", {
146
+ code: "REMOTE_SESSION_JOIN_ERROR",
147
+ message: error.message,
148
+ });
149
+ }
150
+ }
151
+
152
+ export function handleRemoteSessionPushRegister(server, clientId, ws, message) {
153
+ try {
154
+ // A device may only register its OWN token (clientId is the authenticated
155
+ // caller). Storing no push value clears it.
156
+ const result = server.remoteSessions.registerPush(
157
+ message.remoteSessionId,
158
+ clientId,
159
+ { token: message.pushToken, provider: message.pushProvider },
160
+ );
161
+ audit(server, {
162
+ sessionId: message.remoteSessionId,
163
+ actor: clientId,
164
+ action: "push.registered",
165
+ detail: { hasPush: result.hasPush, provider: result.provider },
166
+ });
167
+ reply(server, ws, message.id, "remote-session-push-registered", result);
168
+ } catch (error) {
169
+ reply(server, ws, message.id, "error", {
170
+ code: "REMOTE_SESSION_PUSH_REGISTER_ERROR",
171
+ message: error.message,
172
+ });
173
+ }
174
+ }
175
+
176
+ export function handleRemoteSessionDevices(server, clientId, ws, message) {
177
+ try {
178
+ const result = server.remoteSessions.listDevices(
179
+ message.remoteSessionId,
180
+ clientId,
181
+ );
182
+ reply(server, ws, message.id, "remote-session-devices", result);
183
+ } catch (error) {
184
+ reply(server, ws, message.id, "error", {
185
+ code: "REMOTE_SESSION_DEVICES_ERROR",
186
+ message: error.message,
187
+ });
188
+ }
189
+ }
190
+
191
+ export function handleRemoteSessionPolicy(server, clientId, ws, message) {
192
+ try {
193
+ // The active org policy is not sensitive — any authenticated client may
194
+ // read it (e.g. to pre-check allowed scopes before requesting a session).
195
+ const policy = server.remoteSessions?.policy;
196
+ reply(server, ws, message.id, "remote-session-policy", {
197
+ policy: policy ? policy.describe() : null,
198
+ });
199
+ } catch (error) {
200
+ reply(server, ws, message.id, "error", {
201
+ code: "REMOTE_SESSION_POLICY_ERROR",
202
+ message: error.message,
203
+ });
204
+ }
205
+ }
206
+
207
+ export function handleRemoteSessionAudit(server, clientId, ws, message) {
208
+ try {
209
+ // Host-only: authorize proves membership, the host check proves ownership.
210
+ const { session } = server.remoteSessions.authorize(
211
+ message.remoteSessionId,
212
+ clientId,
213
+ "observe",
214
+ );
215
+ if (session.hostClientId !== clientId) {
216
+ throw new Error("Only the host can read the audit log");
217
+ }
218
+ const auditLog = server.remoteSessionAudit;
219
+ const entries = auditLog
220
+ ? auditLog.list({
221
+ sessionId: message.remoteSessionId,
222
+ limit: message.limit || 200,
223
+ })
224
+ : [];
225
+ const stats = auditLog
226
+ ? auditLog.stats(message.remoteSessionId)
227
+ : { total: 0, byAction: {} };
228
+ reply(server, ws, message.id, "remote-session-audit", {
229
+ remoteSessionId: message.remoteSessionId,
230
+ entries,
231
+ stats,
232
+ });
233
+ } catch (error) {
234
+ reply(server, ws, message.id, "error", {
235
+ code: "REMOTE_SESSION_AUDIT_ERROR",
236
+ message: error.message,
237
+ });
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Tell a revoked device it is no longer paired. Locally connected clients get a
243
+ * plaintext `remote-session-revoked` push; relay-paired mobile devices get an
244
+ * encrypted `session.revoked` control event so they stop auto-reconnecting.
245
+ */
246
+ function notifyRevokedDevice(
247
+ server,
248
+ remoteSessionId,
249
+ agentSessionId,
250
+ clientId,
251
+ ) {
252
+ const target = server.clients.get(clientId);
253
+ if (target) {
254
+ server._send(target.ws, {
255
+ type: "remote-session-revoked",
256
+ remoteSessionId,
257
+ agentSessionId,
258
+ });
259
+ return;
260
+ }
261
+ if (!server.remoteSessionRelay) return;
262
+ const crypto = server.remoteSessionCrypto.get(remoteSessionId);
263
+ if (!crypto) return;
264
+ try {
265
+ server.remoteSessionRelay.sendEncrypted(
266
+ clientId,
267
+ crypto.encrypt(clientId, { type: "session.revoked", remoteSessionId }),
268
+ );
269
+ } catch {
270
+ // Peer key may already be gone; the registry removal is what actually
271
+ // enforces revocation, so a failed courtesy notice is non-fatal.
272
+ }
273
+ }
274
+
275
+ export function handleRemoteSessionRevoke(server, clientId, ws, message) {
276
+ try {
277
+ const targetClientId = message.clientId || message.deviceId;
278
+ const { session, member } = server.remoteSessions.revokeMember(
279
+ message.remoteSessionId,
280
+ clientId,
281
+ targetClientId,
282
+ );
283
+ notifyRevokedDevice(
284
+ server,
285
+ message.remoteSessionId,
286
+ session.agentSessionId,
287
+ member.clientId,
288
+ );
289
+ audit(server, {
290
+ sessionId: message.remoteSessionId,
291
+ actor: clientId,
292
+ action: "device.revoked",
293
+ detail: { revoked: member.clientId },
294
+ });
295
+ reply(server, ws, message.id, "remote-session-revoked", {
296
+ session,
297
+ revoked: member.clientId,
298
+ devices: server.remoteSessions.listDevices(
299
+ message.remoteSessionId,
300
+ clientId,
301
+ ).devices,
302
+ });
303
+ } catch (error) {
304
+ reply(server, ws, message.id, "error", {
305
+ code: "REMOTE_SESSION_REVOKE_ERROR",
306
+ message: error.message,
307
+ });
308
+ }
309
+ }
310
+
311
+ export function handleRemoteSessionClose(server, clientId, ws, message) {
312
+ try {
313
+ const session = server.remoteSessions.close(
314
+ message.remoteSessionId,
315
+ clientId,
316
+ );
317
+ server.remoteSessionCrypto.delete(message.remoteSessionId);
318
+ server.remoteSessionPairingSecrets.delete(message.remoteSessionId);
319
+ audit(server, {
320
+ sessionId: message.remoteSessionId,
321
+ actor: clientId,
322
+ action: "session.closed",
323
+ detail: { reason: "host-closed" },
324
+ });
325
+ reply(server, ws, message.id, "remote-session-closed", { session });
326
+ } catch (error) {
327
+ reply(server, ws, message.id, "error", {
328
+ code: "REMOTE_SESSION_CLOSE_ERROR",
329
+ message: error.message,
330
+ });
331
+ }
332
+ }
333
+
334
+ export async function handleRemoteSessionPublish(
335
+ server,
336
+ clientId,
337
+ ws,
338
+ message,
339
+ ) {
340
+ try {
341
+ if (!message.event || typeof message.event.type !== "string") {
342
+ throw new Error("event.type is required");
343
+ }
344
+ const requiredScope = CLIENT_EVENT_SCOPES[message.event.type];
345
+ const { session } = server.remoteSessions.authorize(
346
+ message.remoteSessionId,
347
+ clientId,
348
+ requiredScope || "observe",
349
+ );
350
+ // Runtime/output events are host-only. Remote clients may publish only the
351
+ // three explicitly scoped control event types above.
352
+ if (!requiredScope && session.hostClientId !== clientId) {
353
+ throw new Error("Only the host can publish runtime events");
354
+ }
355
+
356
+ if (requiredScope && session.hostClientId !== clientId) {
357
+ const controlMessage = {
358
+ id: message.id,
359
+ sessionId: session.agentSessionId,
360
+ };
361
+ if (message.event.type === "prompt") {
362
+ if (
363
+ typeof message.event.content !== "string" ||
364
+ !message.event.content.trim()
365
+ ) {
366
+ throw new Error("prompt content is required");
367
+ }
368
+ // Record the shape, not the content — the audit trail must stay useful
369
+ // without hoarding potentially sensitive session prompts.
370
+ audit(server, {
371
+ sessionId: message.remoteSessionId,
372
+ actor: clientId,
373
+ action: "control.prompt",
374
+ detail: { chars: message.event.content.length },
375
+ });
376
+ handleSessionMessage(server, message.id, ws, {
377
+ ...controlMessage,
378
+ content: message.event.content,
379
+ });
380
+ } else if (message.event.type === "approval.resolve") {
381
+ audit(server, {
382
+ sessionId: message.remoteSessionId,
383
+ actor: clientId,
384
+ action: "control.approval",
385
+ detail: {
386
+ requestId: message.event.requestId || message.event.approvalId,
387
+ approved: message.event.answer ?? message.event.approved,
388
+ },
389
+ });
390
+ await handleSessionAnswer(server, message.id, ws, {
391
+ ...controlMessage,
392
+ requestId: message.event.requestId || message.event.approvalId,
393
+ answer: message.event.answer ?? message.event.approved,
394
+ });
395
+ } else if (message.event.type === "interrupt") {
396
+ audit(server, {
397
+ sessionId: message.remoteSessionId,
398
+ actor: clientId,
399
+ action: "control.interrupt",
400
+ detail: null,
401
+ });
402
+ await handleSessionInterrupt(server, message.id, ws, controlMessage);
403
+ }
404
+ return;
405
+ }
406
+
407
+ let delivered = 0;
408
+ for (const member of server.remoteSessions.members(
409
+ message.remoteSessionId,
410
+ )) {
411
+ if (member.clientId === clientId) continue;
412
+ const target = server.clients.get(member.clientId);
413
+ if (!target) continue;
414
+ server._send(target.ws, {
415
+ type: "remote-session-event",
416
+ remoteSessionId: message.remoteSessionId,
417
+ agentSessionId: session.agentSessionId,
418
+ event: message.event,
419
+ });
420
+ delivered += 1;
421
+ }
422
+ reply(server, ws, message.id, "remote-session-published", { delivered });
423
+ } catch (error) {
424
+ reply(server, ws, message.id, "error", {
425
+ code: "REMOTE_SESSION_PUBLISH_ERROR",
426
+ message: error.message,
427
+ });
428
+ }
429
+ }