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.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-DywJ7xTv.js → AIOps-DwpCCp64.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BTlqcY-q.js → ActionButton-C9pBYocA.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-FdG1Mvwy.js → Analytics-BWAkeXxK.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CVsnbvN1.js → AppLayout-CivFGH6B.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-ITdpJ7vR.js → Audit-Cm8hRpZm.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BfXqnXo1.js → Backup-DXdFMsE8.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C09ip3_E.js → BaseInput-uAwSTeql.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-qdkhB42l.js → Chat-KU8eeJJE.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DCNfbdlx.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-j6WZCuff.js → Checkbox-C6AMDkjd.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CGZ-K3uK.js → Codegen-t2moDxcO.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CIlPOAu6.js → Col-DCcsRRhN.js} +1 -1
- package/src/assets/web-panel/assets/{Community-sY-i-hic.js → Community-DtB-8SAC.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DcoEfyL8.js → Compact-CZm8THYA.js} +1 -1
- package/src/assets/web-panel/assets/Compliance-LiQgC7g1.js +1 -0
- package/src/assets/web-panel/assets/{Cowork-DLY_fkLv.js → Cowork-CA8SAxht.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-D049pZBC.js → Cron-CtRaF1wD.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DCXdE8M9.js → Crosschain-6-br6Hub.js} +1 -1
- package/src/assets/web-panel/assets/{DID-JCvPZtjW.js → DID-Do2EccrL.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cg2xu3iE.js → Dashboard-wrXcbzGe.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DjJLjbLh.js → Dropdown-p3FsT245.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DugNcSLR.js → EmailListRenderer-D95A2L8q.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-J6Nb-E30.js → FamilyGuardDashboard-cLuJW2zo.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CQ3Ttpbl.js → Federation-Brgq_cbN.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cz0NKag4.js → FormItemContext-DWLCkNgh.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-NYcMP6iz.js → GenericCardRenderer-BBqUfQd6.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B4hYN18N.js → Git-8F090w4I.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DOQPCcC0.js → Governance-CCogEbxb.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-HtLF746W.js → Inference-CfLD7v7C.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BXrk8rMm.js → KnowledgeGraph-DDuHJewd.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DS0JnD3-.js → Logs-CE8KSEVC.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-Cqnjihrz.js → Marketplace-DmwpZmhT.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Cx3Psk-U.js → McpTools-Bf7AazU8.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BjyysPtj.js → Memory-D0QU_00S.js} +2 -2
- package/src/assets/web-panel/assets/MobileBridge-D3Arxfeg.css +1 -0
- package/src/assets/web-panel/assets/MobileBridge-yXS9xdhx.js +1 -0
- package/src/assets/web-panel/assets/{MobileProjects-Xwf-fdOQ.js → MobileProjects-BuDUoGUP.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Djkql5m5.js → Mtc-BYyHy28p.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-D2BAZlu0.js → MtcAudit-CK0aqpiZ.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-ByqP1ZzH.js → Multisig-mNimKYeb.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-C_kn0nE2.js → NLProgramming-AioAJ0YA.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-7l7eXHPq.js → Notes-CVVNCLHE.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BrCDoitw.js → NotificationSettings-C4ABj-TK.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CmtqIdwr.js → OrderTableRenderer-DIp8Xcbd.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DdoNAxsM.js → Organization-uozl_gWK.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bw7R6dE3.js → Overflow-BCZOM2hK.js} +1 -1
- package/src/assets/web-panel/assets/{OverrideContext-C2r4vyBb.js → OverrideContext-BlgL9440.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DJNtBugA.js → P2P-CArcaiaj.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Dwhd5_ue.js → PdhVaultBrowser-Sgq2Srr8.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BYoSfhPR.js → Permissions-BYrQrXnH.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-aYCYJbnH.js → PersonalDataHub-BzHStAbz.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-DJp6CprF.js → Pipeline-k7KqxX1M.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Cq9HZweR.js → Privacy-IumTUWqx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CmF0HsSt.js → ProjectInit-BRyImYTf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-P8V5Aea2.js → ProjectSettings-BFIqTBFk.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DPd5-lNS.js → Projects-Dpid9CDg.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-D589v0q2.js → Providers-CyyFnUPs.js} +1 -1
- package/src/assets/web-panel/assets/QrScannerModal-C82cRx-X.js +1 -0
- package/src/assets/web-panel/assets/{MobileBridge-zJpPuf4E.css → QrScannerModal-NwAHNfiJ.css} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-lvRV2osB.js → QuickAsk-DGxDF521.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-sb84MTpY.js → Recommend-Cns-Am1y.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-R7OqAIlg.js +4 -0
- package/src/assets/web-panel/assets/{Reputation-d9Y3vy-W.js → Reputation-D7mgPIYV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DMdhLUTp.js → Row-B3lEURyd.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-OL-SMDkz.js → RssFeed-9_UVrpBt.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BjStLKq1.js → Search-ClZeO80q.js} +1 -1
- package/src/assets/web-panel/assets/{Security-MeI411qr.js → Security-BNNJczEp.js} +3 -3
- package/src/assets/web-panel/assets/{Services-UajosuhT.js → Services-C5SjrWUj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CGpG-QJ1.js → Skeleton-Ci_obQ-g.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C6P2RPY-.js → Skills-DdebN15P.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-B_fPprgw.js → Sla-OinZP2vi.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CqxLjSlQ.js → SpeechSettings-CxzbNF51.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DixSfFOQ.js → SyncSettings-D06N_66b.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-PavzPBxc.js → Tasks-BdEdW0AZ.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BYdGRnfX.js → Templates-F1ctKmPa.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BQLgnarD.js → Tenant-CVz1Urot.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BzOHpq-B.js → Terminal-BvAK_Zel.js} +2 -2
- package/src/assets/web-panel/assets/TimelineRenderer-Doitzjmf.js +1 -0
- package/src/assets/web-panel/assets/{Tokens-DxhgszRJ.js → Tokens-BpyVRpVA.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-nQYHayuc.js → Trigger-nWhWYTbU.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CvqZDuZ4.js → Trust-DK_G-wLx.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DaR8GV2I.js → UkeySign-B5yBUojO.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C6Mpsokw.js → VideoEditing-C5D51qAe.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B57VRrWc.js → Wallet-CLbL9K7v.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BbtEEtpq.js → WebAuthn-DZUelI3V.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-C5LwvKmH.js → WorkflowEditor-8RPxt4KW.js} +1 -1
- package/src/assets/web-panel/assets/{chat-MzuPR5jh.js → chat-4N4tOA3d.js} +1 -1
- package/src/assets/web-panel/assets/{collapseMotion-mxzzcDsg.js → collapseMotion-DVfhbsdP.js} +1 -1
- package/src/assets/web-panel/assets/{colors-HyW8mi_y.js → colors-zbbGVrua.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DvUSzWAp.js → compact-item-D7iMkbnE.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-4MppZl7X.js → createContext-CBzPJv-w.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-C2Z5LRgq.js +1 -0
- package/src/assets/web-panel/assets/{echarts-jxgIOFUZ.js → echarts-CL0F2SnX.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-D9q3CJ-u.js → hasIn-bHdrQSqZ.js} +1 -1
- package/src/assets/web-panel/assets/{icons-DP3uiYxy.js → icons-BsDmGpcT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Caqtu6Et.js → index-308gCGh7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgIfXOD9.js → index-B1s0Bz9O.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcunsBIx.js → index-B7b1hGry.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDZ6fP5Z.js → index-BBNr77E1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF2JsbiX.js → index-BCr0geV9.js} +1 -1
- package/src/assets/web-panel/assets/index-BGp6Yr-Y.js +1 -0
- package/src/assets/web-panel/assets/{index-CucRo4Vz.js → index-BJ4ZGyW0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bl-E4W4q.js → index-BS4_Mwk6.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv7ffI2g.js → index-BTIjjXry.js} +1 -1
- package/src/assets/web-panel/assets/index-BXiw9dQf.js +1 -0
- package/src/assets/web-panel/assets/{index-CifKUNtV.js → index-BZb8F8YG.js} +1 -1
- package/src/assets/web-panel/assets/{index-Btz8pU68.js → index-BnBOpqv3.js} +1 -1
- package/src/assets/web-panel/assets/{index-m0b6Fj9q.js → index-Bqmx24kh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dvg5xYuP.js → index-BsKehmmS.js} +1 -1
- package/src/assets/web-panel/assets/{index-UUMCA2Sq.js → index-BtbbdLnf.js} +4 -4
- package/src/assets/web-panel/assets/{index-CvAqCAo9.js → index-CPxkoKgA.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5E4DhVc.js → index-CQ6NcfWz.js} +1 -1
- package/src/assets/web-panel/assets/{index-B994UQfE.js → index-CQfu1U78.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLAZs1Vd.js → index-CahryTX0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFGfC5RS.js → index-CdmMoYN1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcMkjb92.js → index-Ci009ijp.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNYqw0MO.js → index-CiG1IZao.js} +1 -1
- package/src/assets/web-panel/assets/{index--Bm6OqmU.js → index-CkxK86vf.js} +1 -1
- package/src/assets/web-panel/assets/{index-zLwYpvX0.js → index-CqdPyWm5.js} +1 -1
- package/src/assets/web-panel/assets/{index-Zvtru2oE.js → index-CvRMA9uT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmCo2Xdp.js → index-D1YDh7Wr.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2jrnaq3.js → index-D4XKpj6c.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7TDMMfu.js → index-DE9j5YgT.js} +1 -1
- package/src/assets/web-panel/assets/{index-ryFLxB1p.js → index-DISWAYce.js} +1 -1
- package/src/assets/web-panel/assets/{index-xvUVuFnA.js → index-DUyjUkY7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9I5MuJ0.js → index-DbE5D0WL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGQtFso0.js → index-DmqlJed-.js} +1 -1
- package/src/assets/web-panel/assets/{index-SDblbKj6.js → index-DyoNgbXl.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ci6adKh8.js → index-QFObYeo1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs-RKRUM.js → index-QNAG4JtR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFqvWeGc.js → index-S74FpAIn.js} +1 -1
- package/src/assets/web-panel/assets/{index-eOQO6KnV.js → index-kmh1TxRa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmZ6-suL.js → index-oDKNgCsP.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0DiL97c.js → index-xYCm6W2h.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CC--PMsC.js → initDefaultProps-BD55yNBt.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DdrBjRF1.js → motion-B5Bbe77U.js} +1 -1
- package/src/assets/web-panel/assets/{move-D712Gwl2.js → move-CTvIqHEH.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-39y-keKO.js → mtc-parser-BkNyPQKB.js} +1 -1
- package/src/assets/web-panel/assets/{omit-6Y51gDB9.js → omit-BaXJXgHA.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Cy6EHbq9.js → pickAttrs-Bw6-YTxH.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BYxdAm0p.js → placementArrow-BLdbkLqJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C9R6q_cr.js → responsiveObserve-IVYkzntU.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CXUJlilB.js → slide-DFMFwwtY.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DOtrOeql.js → statusUtils-CURYRtZ1.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-D5r39o92.js → styleChecker-Cfz63s1r.js} +1 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-COJL0KE3.js +1 -0
- package/src/assets/web-panel/assets/{useFs-BkrT-Zbc.js → useFs-YLLojQQf.js} +1 -1
- package/src/assets/web-panel/assets/{useMergedState-Cl2q1fes.js → useMergedState-Dc9sO2d7.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BwnnnZjU.js → usePersonalDataHub-BF_21qUC.js} +1 -1
- package/src/assets/web-panel/assets/{useRefs-DD9q4mOT.js → useRefs-CAeFRzPf.js} +1 -1
- package/src/assets/web-panel/assets/{useState-BK4hy8Ma.js → useState-LwExUYDO.js} +1 -1
- package/src/assets/web-panel/assets/{vendor-BvqAck49.js → vendor-BMxUs6UX.js} +16 -16
- package/src/assets/web-panel/assets/{vnode-SU-N4pum.js → vnode-9ZpkA7bb.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DHScfpTP.js → zoom-DhtAfhl8.js} +1 -1
- package/src/assets/web-panel/index.html +3 -3
- package/src/commands/serve.js +10 -0
- package/src/gateways/remote-session-relay.js +160 -0
- package/src/gateways/ws/message-dispatcher.js +32 -0
- package/src/gateways/ws/remote-session-protocol.js +429 -0
- package/src/gateways/ws/ws-server.js +299 -0
- package/src/harness/golden-transcript.js +65 -0
- package/src/harness/mcp-client.js +6 -2
- package/src/harness/remote-session-audit-sink.js +132 -0
- package/src/harness/remote-session-audit.js +110 -0
- package/src/harness/remote-session-crypto.js +217 -0
- package/src/harness/remote-session-push-fcm.js +254 -0
- package/src/harness/remote-session-push.js +104 -0
- package/src/harness/remote-session-registry.js +420 -0
- package/src/lib/did-manager.js +6 -4
- package/src/lib/mcp-oauth.js +23 -6
- package/src/lib/session-manager.js +7 -3
- package/src/runtime/agent-runtime.js +8 -13
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D2KfETZD.js +0 -1
- package/src/assets/web-panel/assets/Compliance-T8EtTecW.js +0 -1
- package/src/assets/web-panel/assets/MobileBridge-CYaITZ7w.js +0 -1
- package/src/assets/web-panel/assets/TimelineRenderer-Bv7uZRM7.js +0 -1
- package/src/assets/web-panel/assets/devWarning-6YJJMjSH.js +0 -1
- package/src/assets/web-panel/assets/index-D_oeGLr6.js +0 -1
- package/src/assets/web-panel/assets/index-Qa57YG19.js +0 -1
- 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-
|
|
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-
|
|
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-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="./assets/vendor-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="./assets/icons-
|
|
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>
|
package/src/commands/serve.js
CHANGED
|
@@ -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
|
+
}
|