chainlesschain 0.162.179 → 0.162.181
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/package.json +6 -3
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BF13YdB-.js → AIOps-cq0dwbnf.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-B9y67AjF.js → ActionButton-CvcgGl3w.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-FcdDHoSC.js → Analytics-hM2-jFqg.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CRm_zwSp.js → AppLayout-B9_Gsd_g.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Cbo7-usf.js → Artifacts-B7bu52Og.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-vMaLpkHC.js → Audit-DThfDgqB.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-FiUY692t.js → BackgroundAgents-DjlFiD4v.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BK80j_GQ.js → Backup-CK9xJKnG.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-ChNMuYR1.js → BaseInput-DEiSU8K8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-928UREpm.js → Chat-CpT96czj.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-dFW-zDbe.js → Checkbox-C1GfDnO0.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BCcNJUj2.js → Codegen-3DAKgiLx.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DcEkLv70.js → Col-74cOwZU1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DihBRRqg.js → Community-tn9Kkz9j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DGYxwWET.js → Compact-BcoXH7m4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-OnYe1vS4.js → Compliance-DIPGUBgi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CmWB54c2.js → Cowork-doD5_91c.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BrANb2uw.js → Cron-C-IDvubz.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-2HgWzSxg.js → Crosschain-CdcCoBdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DdDwNI6K.js → DID-DdH5aMMA.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D6PnE78-.js → Dashboard-DHLA4mm0.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-ClzvSN4O.js → Dropdown-dEeCt7Md.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BUk9B727.js → EmailListRenderer-BMaecFv9.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C8hi3v7i.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B5SP8xkg.js → Federation-CMBE0_rp.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DWzJ8AU5.js → FormItemContext-PG-JDbXq.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-3E3Q3rjG.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
- package/src/assets/web-panel/assets/{Git-z8IdCMId.js → Git-Bgv15myB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CgqCF9lX.js → Governance-DB8YTArI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-zgS-AuH9.js → Inference-BQMwCWaS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BdbgmESJ.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BHpknnjy.js → Logs-DovEEnt_.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-D201OL4T.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Di9sAR7j.js → Marketplace-BlCXSpyB.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DtnR9Z_A.js → McpTools-CsCR09Wj.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BaX9uuXD.js → Memory-CBVRLKno.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-xelyKWTY.js → MobileBridge-C9OIafgA.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BiFTOGBN.js → MobileProjects-D_zoJ8Xs.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-bV3OzTiO.js → Mtc-vE-HdvLj.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BkwvFTdZ.js → MtcAudit-CPLaekCd.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-_6HQQ-oC.js → Multisig-C_UP9C2o.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BBYhmWQZ.js → NLProgramming-2nODJcU1.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cq-6dQnU.js → Notes-BhE-SJGu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-ILZ9zkX6.js → NotificationSettings-D21q7BNU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DgmTBEvk.js → OrderTableRenderer-0b62GYOD.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CkLnWwCk.js → Organization-CEqmw_sb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CWVHZbhf.js → Overflow-MW-gMDO_.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BXbqETkr.js → P2P-CY0hjI_G.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser--0JR-0ex.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Cz9_tfSy.js → Permissions-ChqEA_4Q.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dq7OWYtx.js → PersonalDataHub-B3YrbYfD.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DHPUNcc-.js → Pipeline-B8WBhhlW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CEAbrDkS.js → Privacy-Cmb0PXNx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CJYfclXE.js → ProjectInit-hF6zW3Nz.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-oCTgPCgp.js → ProjectSettings-BFSVfpW0.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-BLTZtzTG.js → Providers-B8yux8Dx.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C0b0TQB3.js → QrScannerModal-N76cQluO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-tOl6N_gM.js → QuickAsk-ClvZ0KYR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DPzKr8yr.js → Recommend-B-GfgBpT.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-Cji1Vl79.js → Reputation-DJIZzQeG.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D-NERWf2.js → Row-COzxu_bb.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DzlgmAlB.js → RssFeed-CoYsJQuE.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cs0SWSa4.js → Search-DC77Mq9S.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DL7EzcUO.js → Security-Loy2EdMO.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CT-PzgTd.js → Services-GUD07Eu0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-tByJWdJg.js → Skeleton-DWzkptYU.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Dnr_6TTl.js → Skills-CEDn1r-Z.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-4O-yq0LY.js → Sla-ub_k4pXh.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BYBVg1oR.js → SpeechSettings-D7HLX9CA.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CpOYPbE5.js → SyncSettings-DbwOvl6m.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CGVhOVh6.js → Tasks-CBQzoAu5.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BuHFxR4X.js → Templates-BNVeIhud.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DxDxHzgf.js → Tenant-PS9AzhXU.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B9g_nISg.js → Terminal-Cgb4eLB_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DlrBC_4A.js → TimelineRenderer-CrmXMOkg.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DvBlYZ6i.js → Tokens-DD-VDHw1.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dg8G9bhF.js → Trigger-BsoN_n-n.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-COICx4E-.js → Trust-n8LmN4ZV.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B4pOBv7T.js → UkeySign-C9_7MImA.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Qt4NMA8Q.js → VideoEditing-DyBteNgn.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-X1EkQc2Z.js → Wallet-BS5ixeXI.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CyeEFBE5.js → WebAuthn-spc4UImU.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-nwzbMiVQ.js → WorkflowEditor-D7iVvaBO.js} +1 -1
- package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
- package/src/assets/web-panel/assets/{colors-5Isz5lhJ.js → colors-BGoCLkxI.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DsFQS3Oy.js → compact-item-fYZBetMO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-OcEXp2uz.js → createContext-BeM-1UVj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CZvC4p09.js → hasIn-CE7ZuEnV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF1sab0Q.js → index--lap6cf7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7yeL3rf.js → index-ATcSr_2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-VkFXA9N-.js → index-B2U-ObMq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSmGGg5h.js → index-B3CDgvNW.js} +1 -1
- package/src/assets/web-panel/assets/{index-jrNIrpq4.js → index-B4wiTEOM.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8ibl7bc.js → index-B8BsdNV_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOLozRk8.js → index-BEVm0lCS.js} +10 -10
- package/src/assets/web-panel/assets/{index-BPgc_bdR.js → index-BNZDILcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTZZzlMO.js → index-BU_2qiDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Vubi6Tf5.js → index-BV551878.js} +1 -1
- package/src/assets/web-panel/assets/{index-nXrnztXp.js → index-BfPL-m46.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN8lPVpQ.js → index-BowH1eLQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgE2BZl2.js → index-BsMfoaeo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd5b2JHB.js → index-BunaQCa0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQlGw0nQ.js → index-C0v6YKKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Do6FJK32.js → index-C4SJVjs4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqvo1f9T.js → index-C9Y3k0HI.js} +1 -1
- package/src/assets/web-panel/assets/{index-LUdgPZg9.js → index-CIpVrf5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpD2O7_p.js → index-CRLjEP1H.js} +1 -1
- package/src/assets/web-panel/assets/{index-r_9NG6P7.js → index-CRnUE8Cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-FIgMAfBh.js → index-Cip8emOQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-RsQ1lFDV.js → index-CpIGIB85.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGJupV0S.js → index-D1r9tT3J.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpglwPWl.js → index-DT3zPSVX.js} +1 -1
- package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
- package/src/assets/web-panel/assets/{index-CG3B2wCF.js → index-De0quFDw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxA2PDK1.js → index-DoXk5KJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaGKOVvQ.js → index-DsvfrESp.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7CtJYXq.js → index-Dw1PyYPm.js} +1 -1
- package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
- package/src/assets/web-panel/assets/{index-Bu9NXvIa.js → index-MtOuq2i6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsZkTaa3.js → index-Puq6Luf1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPE4zHXF.js → index-QIpnpZgz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bsb-iylv.js → index-RMZ8a7Yt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMtGRQqw.js → index-WUrJ6S1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3lWvhk4.js → index-YjcumOZ4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmVbCGx_.js → index-lJBjB1QX.js} +1 -1
- package/src/assets/web-panel/assets/{index-A5SHQW_M.js → index-ukg99D1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFJgt6qM.js → index-zb7rVOhV.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cdgep9YT.js → initDefaultProps-CYHMs1ag.js} +1 -1
- package/src/assets/web-panel/assets/{motion-7yn1ACEm.js → motion-DDB2Ffk5.js} +1 -1
- package/src/assets/web-panel/assets/{move-D8o133Xc.js → move-Bg3cD-dX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CClHIG9V.js → mtc-parser-B5nedjTS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CLnrPE2d.js → omit-BHyuUILu.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-1CTWoZWl.js → pickAttrs-C9YQnEN9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-xNNtS4Sp.js → placementArrow-DBUFYUe7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ypzAofs7.js → responsiveObserve-nBs2Obnk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QsrY9UwD.js → slide-DkCEaXNU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DSdThzOB.js → statusUtils-aqE1Wi6U.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B_kKM8Ob.js → styleChecker-CN5bhfHB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CcdTBNV9.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BuAH2XFU.js → useFs-rCuXHeme.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-B3zWiG4A.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-B45Rc-CQ.js → vnode-ConCYQlX.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DaYZDU5f.js → zoom-CUdDxG5M.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +4 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/commands/hub.js +30 -24
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/background-agent-protocol.js +38 -0
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/remote-session-protocol.js +65 -6
- package/src/gateways/ws/ws-server.js +8 -1
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-team/team-runner.js +22 -0
- package/src/lib/artifact-store.js +35 -0
- package/src/lib/async-hook-supervisor.cjs +13 -2
- package/src/lib/audit-mtc.js +3 -2
- package/src/lib/background-agent-supervisor.js +104 -3
- package/src/lib/background-interaction-journal.js +407 -0
- package/src/lib/background-interaction-resolver.js +23 -34
- package/src/lib/background-session-transport.js +12 -2
- package/src/lib/capability-manifest.js +41 -3
- package/src/lib/capability-negotiation.js +1 -1
- package/src/lib/channels/channel-manager.js +33 -0
- package/src/lib/channels/telegram-channel.js +23 -5
- package/src/lib/channels/webhook-channel.js +38 -15
- package/src/lib/chrome-connector.js +169 -23
- package/src/lib/config-manager.js +23 -9
- package/src/lib/context-breakdown.js +31 -0
- package/src/lib/cowork-cron.js +274 -32
- package/src/lib/cross-chain-mtc.js +3 -2
- package/src/lib/durable-security-store.js +124 -0
- package/src/lib/event-runtime-host.js +67 -6
- package/src/lib/event-runtime-store.js +163 -0
- package/src/lib/goal-store.js +32 -12
- package/src/lib/headless-manifest.js +2 -1
- package/src/lib/hook-environment.cjs +58 -0
- package/src/lib/hook-manager.js +12 -5
- package/src/lib/hook-runner.cjs +122 -28
- package/src/lib/hook-runner.js +1 -0
- package/src/lib/hooks-v2-producers.js +36 -0
- package/src/lib/hooks-v2-runtime.js +329 -52
- package/src/lib/interaction-adapter.js +60 -19
- package/src/lib/interaction-binding.js +64 -0
- package/src/lib/json-schema-output.js +439 -14
- package/src/lib/json-schema-validate.js +514 -883
- package/src/lib/lan-pairing-tokens.js +115 -57
- package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
- package/src/lib/lsp/lsp-client.js +4 -0
- package/src/lib/lsp/lsp-manager.js +3 -0
- package/src/lib/lsp/lsp-server-registry.js +18 -0
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-oauth.js +35 -21
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/capabilities.js +50 -0
- package/src/lib/plugin-runtime/capability-consent.js +42 -35
- package/src/lib/plugin-runtime/hooks.js +36 -9
- package/src/lib/plugin-runtime/install.js +23 -7
- package/src/lib/plugin-runtime/lsp.js +4 -0
- package/src/lib/plugin-runtime/manifest.js +50 -2
- package/src/lib/plugin-runtime/mcp.js +30 -5
- package/src/lib/plugin-runtime/monitors.js +11 -0
- package/src/lib/plugin-runtime/plugin-options.js +94 -38
- package/src/lib/plugin-runtime/policy.js +29 -2
- package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
- package/src/lib/plugin-runtime/scopes.js +7 -3
- package/src/lib/plugin-runtime/trust.js +36 -31
- package/src/lib/process-execution-broker/credential-agent.js +114 -16
- package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
- package/src/lib/process-execution-broker/credential-transport.js +378 -0
- package/src/lib/process-execution-broker/index.js +408 -19
- package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
- package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +113 -28
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +331 -26
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +101 -4
- package/src/runtime/headless-stream.js +209 -23
- package/src/runtime/mcp-config.js +29 -17
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/workers/background-agent-worker.js +128 -13
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DvySUzxJ.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-DkxCweb1.js +0 -1
- package/src/assets/web-panel/assets/Projects-ClomCrN0.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-pRgaWsUK.js +0 -4
- package/src/assets/web-panel/assets/chat-Bvl-ojg2.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CSVgo71Z.js +0 -1
- package/src/assets/web-panel/assets/index-DMIWh9fu.js +0 -1
- package/src/assets/web-panel/assets/index-ssTvV1l6.js +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Hooks v2 System —
|
|
2
|
+
* Hooks v2 System — 40-event schema + 5 public executor types
|
|
3
|
+
* (plus trusted programmatic `js` compatibility handlers).
|
|
3
4
|
* 对应文档 §2.3
|
|
4
5
|
*
|
|
5
6
|
* 支持的18种生命周期事件:
|
|
@@ -24,9 +25,14 @@ import crypto from "node:crypto";
|
|
|
24
25
|
import fs from "node:fs/promises";
|
|
25
26
|
import path from "node:path";
|
|
26
27
|
import broker from "./process-execution-broker/index.js";
|
|
28
|
+
import hookEnvironment from "./hook-environment.cjs";
|
|
29
|
+
import permissionRules from "./permission-rules.cjs";
|
|
27
30
|
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
28
31
|
import { getDefaultEventRuntimeHost } from "./event-runtime-host.js";
|
|
29
32
|
|
|
33
|
+
const { globToRegExp } = permissionRules;
|
|
34
|
+
const { buildManagedHookEnvironment } = hookEnvironment;
|
|
35
|
+
|
|
30
36
|
const VALID_HOOK_EVENTS = new Set([
|
|
31
37
|
"Setup",
|
|
32
38
|
// Session
|
|
@@ -106,20 +112,6 @@ export const HOOK_EVENT_CONTRACTS = Object.freeze(
|
|
|
106
112
|
),
|
|
107
113
|
);
|
|
108
114
|
|
|
109
|
-
const SAFE_ENV_KEYS = Object.freeze([
|
|
110
|
-
"PATH",
|
|
111
|
-
"PATHEXT",
|
|
112
|
-
"SystemRoot",
|
|
113
|
-
"WINDIR",
|
|
114
|
-
"COMSPEC",
|
|
115
|
-
"TMP",
|
|
116
|
-
"TEMP",
|
|
117
|
-
"TMPDIR",
|
|
118
|
-
"LANG",
|
|
119
|
-
"LC_ALL",
|
|
120
|
-
"HOME",
|
|
121
|
-
"USERPROFILE",
|
|
122
|
-
]);
|
|
123
115
|
const DECISION_RANK = Object.freeze({
|
|
124
116
|
continue: 0,
|
|
125
117
|
allow: 1,
|
|
@@ -154,26 +146,209 @@ function hostnameMatches(hostname, pattern) {
|
|
|
154
146
|
return host === rule;
|
|
155
147
|
}
|
|
156
148
|
|
|
157
|
-
function
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
149
|
+
function managedListAllows(value, configured) {
|
|
150
|
+
if (!Array.isArray(configured)) return true;
|
|
151
|
+
const candidate = String(value || "");
|
|
152
|
+
return configured.some((entry) => {
|
|
153
|
+
const pattern = String(entry || "").trim();
|
|
154
|
+
if (!pattern) return false;
|
|
155
|
+
if (pattern === "*") return true;
|
|
156
|
+
const expression = globToRegExp(
|
|
157
|
+
process.platform === "win32" ? pattern.toLowerCase() : pattern,
|
|
158
|
+
);
|
|
159
|
+
return expression.test(
|
|
160
|
+
process.platform === "win32" ? candidate.toLowerCase() : candidate,
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function isInsideManagedRoot(candidate, roots) {
|
|
166
|
+
if (!Array.isArray(roots)) return true;
|
|
167
|
+
const resolved = path.resolve(candidate);
|
|
168
|
+
return roots.some((root) => {
|
|
169
|
+
const managedRoot = path.resolve(String(root));
|
|
170
|
+
const relative = path.relative(managedRoot, resolved);
|
|
171
|
+
return (
|
|
172
|
+
relative === "" ||
|
|
173
|
+
(!relative.startsWith("..") && !path.isAbsolute(relative))
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function managedPolicyError(message) {
|
|
179
|
+
const error = new Error(message);
|
|
180
|
+
error.code = "CC_HOOK_MANAGED_POLICY_DENIED";
|
|
181
|
+
return error;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Merge the administrator policy with a hook's own requested sandbox. Managed
|
|
186
|
+
* settings may strengthen a hook but a hook cannot remove managed boundaries.
|
|
187
|
+
* Boundary identifiers are intentionally left for ProcessExecutionBroker to
|
|
188
|
+
* validate so every external-process caller gets the same stable contract.
|
|
189
|
+
*/
|
|
190
|
+
export function resolveHookSandboxPolicy(hook = {}, managedPolicy = {}) {
|
|
191
|
+
const hookPolicy = hook.sandboxPolicy;
|
|
192
|
+
const administratorPolicy = managedPolicy.sandboxPolicy;
|
|
193
|
+
for (const [label, value] of [
|
|
194
|
+
["hook sandboxPolicy", hookPolicy],
|
|
195
|
+
["managed hook sandboxPolicy", administratorPolicy],
|
|
196
|
+
]) {
|
|
197
|
+
if (
|
|
198
|
+
value !== undefined &&
|
|
199
|
+
(value === null || typeof value !== "object" || Array.isArray(value))
|
|
200
|
+
) {
|
|
201
|
+
throw managedPolicyError(`${label} must be an object`);
|
|
202
|
+
}
|
|
161
203
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
204
|
+
|
|
205
|
+
const requiredBoundaries = [];
|
|
206
|
+
for (const [label, value] of [
|
|
207
|
+
["managed requiredBoundaries", managedPolicy.requiredBoundaries],
|
|
208
|
+
[
|
|
209
|
+
"managed sandboxPolicy.requiredBoundaries",
|
|
210
|
+
administratorPolicy?.requiredBoundaries,
|
|
211
|
+
],
|
|
212
|
+
["hook requiredBoundaries", hook.requiredBoundaries],
|
|
213
|
+
["hook sandboxPolicy.requiredBoundaries", hookPolicy?.requiredBoundaries],
|
|
214
|
+
]) {
|
|
215
|
+
if (value === undefined) continue;
|
|
216
|
+
if (!Array.isArray(value)) {
|
|
217
|
+
throw managedPolicyError(`${label} must be an array`);
|
|
218
|
+
}
|
|
219
|
+
for (const boundary of value) {
|
|
220
|
+
if (!requiredBoundaries.includes(boundary)) {
|
|
221
|
+
requiredBoundaries.push(boundary);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const configured =
|
|
227
|
+
hookPolicy !== undefined ||
|
|
228
|
+
administratorPolicy !== undefined ||
|
|
229
|
+
hook.requiredBoundaries !== undefined ||
|
|
230
|
+
managedPolicy.requiredBoundaries !== undefined;
|
|
231
|
+
if (!configured) return null;
|
|
232
|
+
const resolved = {
|
|
233
|
+
...(hookPolicy || {}),
|
|
234
|
+
...(administratorPolicy || {}),
|
|
235
|
+
};
|
|
236
|
+
delete resolved.requiredBoundaries;
|
|
237
|
+
if (requiredBoundaries.length > 0) {
|
|
238
|
+
resolved.requiredBoundaries = requiredBoundaries;
|
|
239
|
+
}
|
|
240
|
+
return resolved;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function assertManagedHookPolicy(
|
|
244
|
+
hook,
|
|
245
|
+
context = {},
|
|
246
|
+
policy = {},
|
|
247
|
+
configDir = null,
|
|
248
|
+
) {
|
|
249
|
+
if (!managedListAllows(hook.type, policy.allowedExecutors)) {
|
|
250
|
+
throw managedPolicyError(
|
|
251
|
+
`Hook executor is outside the managed allowlist: ${hook.type}`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (hook.type === "command") {
|
|
256
|
+
if (hook.shell === true && policy.allowShell !== true) {
|
|
257
|
+
throw managedPolicyError(
|
|
258
|
+
"Shell-mode command hooks are disabled by managed policy",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const executable = String(hook.command || "");
|
|
262
|
+
const commandCandidates = new Set([
|
|
263
|
+
executable,
|
|
264
|
+
path.basename(executable),
|
|
265
|
+
]);
|
|
266
|
+
if (
|
|
267
|
+
Array.isArray(policy.commandAllowlist) &&
|
|
268
|
+
![...commandCandidates].some((value) =>
|
|
269
|
+
managedListAllows(value, policy.commandAllowlist),
|
|
270
|
+
)
|
|
271
|
+
) {
|
|
272
|
+
throw managedPolicyError(
|
|
273
|
+
`Hook command is outside the managed allowlist: ${executable}`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
const cwd = hook.cwd || context.cwd || configDir || process.cwd();
|
|
277
|
+
if (!isInsideManagedRoot(cwd, policy.workspaceRoots)) {
|
|
278
|
+
throw managedPolicyError(
|
|
279
|
+
`Hook working directory is outside managed workspace roots: ${cwd}`,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (hook.type === "mcp_tool") {
|
|
285
|
+
const target = `${hook.server || ""}/${hook.tool || ""}`;
|
|
286
|
+
if (!managedListAllows(target, policy.mcpToolAllowlist)) {
|
|
287
|
+
throw managedPolicyError(
|
|
288
|
+
`MCP hook target is outside the managed allowlist: ${target}`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (
|
|
294
|
+
hook.type === "agent" &&
|
|
295
|
+
hook.agentName &&
|
|
296
|
+
!managedListAllows(hook.agentName, policy.agentAllowlist)
|
|
297
|
+
) {
|
|
298
|
+
throw managedPolicyError(
|
|
299
|
+
`Hook agent is outside the managed allowlist: ${hook.agentName}`,
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
if (
|
|
303
|
+
hook.type === "agent" &&
|
|
304
|
+
hook.skillName &&
|
|
305
|
+
!managedListAllows(hook.skillName, policy.skillAllowlist)
|
|
306
|
+
) {
|
|
307
|
+
throw managedPolicyError(
|
|
308
|
+
`Hook skill is outside the managed allowlist: ${hook.skillName}`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function fileChangedHookMatches(hook, context = {}) {
|
|
314
|
+
const configured =
|
|
315
|
+
hook?.globs ?? hook?.paths ?? hook?.glob ?? hook?.if ?? null;
|
|
316
|
+
if (configured == null) return true;
|
|
317
|
+
const patterns = (Array.isArray(configured) ? configured : [configured])
|
|
318
|
+
.map((value) => String(value || "").trim().replace(/\\/g, "/"))
|
|
319
|
+
.filter(Boolean);
|
|
320
|
+
if (patterns.length === 0) return true;
|
|
321
|
+
|
|
322
|
+
const rawPath = String(context.path || "").replace(/\\/g, "/");
|
|
323
|
+
if (!rawPath) return false;
|
|
324
|
+
const candidates = new Set([rawPath.replace(/^\.\//, "")]);
|
|
325
|
+
if (path.isAbsolute(rawPath)) {
|
|
326
|
+
const relative = path
|
|
327
|
+
.relative(context.cwd || process.cwd(), rawPath)
|
|
328
|
+
.replace(/\\/g, "/");
|
|
329
|
+
if (relative && !relative.startsWith("../")) candidates.add(relative);
|
|
173
330
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
331
|
+
const caseInsensitive = process.platform === "win32";
|
|
332
|
+
return patterns.some((pattern) => {
|
|
333
|
+
const normalizedPattern = pattern.replace(/^\.\//, "");
|
|
334
|
+
const expression = globToRegExp(
|
|
335
|
+
caseInsensitive ? normalizedPattern.toLowerCase() : normalizedPattern,
|
|
336
|
+
);
|
|
337
|
+
return [...candidates].some((candidate) =>
|
|
338
|
+
expression.test(caseInsensitive ? candidate.toLowerCase() : candidate),
|
|
339
|
+
);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function buildHookEnvironment(hook, policy) {
|
|
344
|
+
return buildManagedHookEnvironment({
|
|
345
|
+
managedAllowlist: policy.environmentAllowlist,
|
|
346
|
+
requestedAllowlist: hook.environmentAllowlist || hook.envAllowlist,
|
|
347
|
+
values: {
|
|
348
|
+
CC_HOOK_EVENT: hook.event,
|
|
349
|
+
CC_HOOK_SCHEMA_VERSION: HOOK_EVENT_SCHEMA_VERSION,
|
|
350
|
+
},
|
|
351
|
+
});
|
|
177
352
|
}
|
|
178
353
|
|
|
179
354
|
function hookBudget(hook) {
|
|
@@ -190,6 +365,29 @@ function hookBudget(hook) {
|
|
|
190
365
|
});
|
|
191
366
|
}
|
|
192
367
|
|
|
368
|
+
async function executeWithHookTimeout(label, budget, executor) {
|
|
369
|
+
const controller = new AbortController();
|
|
370
|
+
let timer;
|
|
371
|
+
const timeout = new Promise((_, reject) => {
|
|
372
|
+
timer = setTimeout(() => {
|
|
373
|
+
controller.abort();
|
|
374
|
+
const error = new Error(
|
|
375
|
+
`${label} hook exceeded its ${budget.timeoutMs}ms budget`,
|
|
376
|
+
);
|
|
377
|
+
error.code = "CC_HOOK_BUDGET_EXCEEDED";
|
|
378
|
+
reject(error);
|
|
379
|
+
}, budget.timeoutMs);
|
|
380
|
+
});
|
|
381
|
+
try {
|
|
382
|
+
return await Promise.race([
|
|
383
|
+
Promise.resolve().then(() => executor(controller.signal)),
|
|
384
|
+
timeout,
|
|
385
|
+
]);
|
|
386
|
+
} finally {
|
|
387
|
+
clearTimeout(timer);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
193
391
|
class HooksV2Runtime extends EventEmitter {
|
|
194
392
|
constructor(configDir, options = {}) {
|
|
195
393
|
super();
|
|
@@ -210,9 +408,15 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
210
408
|
...(options.promptExecutor ? { prompt: options.promptExecutor } : {}),
|
|
211
409
|
...(options.agentExecutor ? { agent: options.agentExecutor } : {}),
|
|
212
410
|
};
|
|
411
|
+
this.mcpAuthorizer =
|
|
412
|
+
typeof options.mcpAuthorizer === "function"
|
|
413
|
+
? options.mcpAuthorizer
|
|
414
|
+
: null;
|
|
213
415
|
this.managedPolicy = {
|
|
214
416
|
httpAllowlist: [],
|
|
215
417
|
environmentAllowlist: [],
|
|
418
|
+
allowShell: false,
|
|
419
|
+
requireMcpAuthorization: true,
|
|
216
420
|
...(options.managedPolicy || {}),
|
|
217
421
|
};
|
|
218
422
|
this.hooks = new Map(); // eventName -> HookDefinition[]
|
|
@@ -243,6 +447,8 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
243
447
|
* @property {boolean} [blocking] - default false
|
|
244
448
|
* @property {string[]} [if] - conditional matchers
|
|
245
449
|
* @property {string} [description]
|
|
450
|
+
* @property {{profile?:string, requiredBoundaries?:string[]}} [sandboxPolicy]
|
|
451
|
+
* @property {string[]} [requiredBoundaries]
|
|
246
452
|
*/
|
|
247
453
|
|
|
248
454
|
async loadHooks(hooksPath) {
|
|
@@ -315,7 +521,10 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
315
521
|
throw new Error(`Invalid hook event: ${eventName}`);
|
|
316
522
|
}
|
|
317
523
|
|
|
318
|
-
const hooks = this.hooks.get(eventName) || []
|
|
524
|
+
const hooks = (this.hooks.get(eventName) || []).filter(
|
|
525
|
+
(hook) =>
|
|
526
|
+
eventName !== "FileChanged" || fileChangedHookMatches(hook, context),
|
|
527
|
+
);
|
|
319
528
|
// Reserve the durable record for the inline producer before executing any
|
|
320
529
|
// hook. A process-level EventRuntimeHost may observe the same store, but it
|
|
321
530
|
// cannot reclaim this record until the longest declared hook timeout plus
|
|
@@ -371,6 +580,12 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
371
580
|
const record = { execId, hookId: hook.id, event: eventName, type: hook.type, startedAt: new Date() };
|
|
372
581
|
|
|
373
582
|
try {
|
|
583
|
+
assertManagedHookPolicy(
|
|
584
|
+
hook,
|
|
585
|
+
context,
|
|
586
|
+
this.managedPolicy,
|
|
587
|
+
this.configDir,
|
|
588
|
+
);
|
|
374
589
|
let result;
|
|
375
590
|
switch (hook.type) {
|
|
376
591
|
case "command":
|
|
@@ -474,6 +689,10 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
474
689
|
throw new Error("command hook requires a command");
|
|
475
690
|
}
|
|
476
691
|
const budget = hookBudget(hook);
|
|
692
|
+
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
693
|
+
hook,
|
|
694
|
+
this.managedPolicy,
|
|
695
|
+
);
|
|
477
696
|
const child = await this.executionBroker.spawn(
|
|
478
697
|
hook.command,
|
|
479
698
|
hook.args || [],
|
|
@@ -487,6 +706,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
487
706
|
scope: "hook",
|
|
488
707
|
policy: "allow",
|
|
489
708
|
hookName: hook.id,
|
|
709
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
490
710
|
},
|
|
491
711
|
);
|
|
492
712
|
const payload = JSON.stringify({
|
|
@@ -561,12 +781,22 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
561
781
|
if (typeof executor !== "function") {
|
|
562
782
|
throw new Error("prompt hook executor is not configured");
|
|
563
783
|
}
|
|
564
|
-
|
|
784
|
+
const budget = hookBudget(hook);
|
|
785
|
+
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
565
786
|
hook,
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
787
|
+
this.managedPolicy,
|
|
788
|
+
);
|
|
789
|
+
return executeWithHookTimeout("prompt", budget, (signal) =>
|
|
790
|
+
executor({
|
|
791
|
+
hook,
|
|
792
|
+
prompt: expanded,
|
|
793
|
+
context,
|
|
794
|
+
budget,
|
|
795
|
+
signal,
|
|
796
|
+
managedPolicy: this.managedPolicy,
|
|
797
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
798
|
+
}),
|
|
799
|
+
);
|
|
570
800
|
}
|
|
571
801
|
|
|
572
802
|
async _execAgent(hook, context) {
|
|
@@ -574,13 +804,23 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
574
804
|
if (typeof executor !== "function") {
|
|
575
805
|
throw new Error("agent hook executor is not configured");
|
|
576
806
|
}
|
|
577
|
-
|
|
807
|
+
const budget = hookBudget(hook);
|
|
808
|
+
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
578
809
|
hook,
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
810
|
+
this.managedPolicy,
|
|
811
|
+
);
|
|
812
|
+
return executeWithHookTimeout("agent", budget, (signal) =>
|
|
813
|
+
executor({
|
|
814
|
+
hook,
|
|
815
|
+
agentName: hook.agentName || null,
|
|
816
|
+
skillName: hook.skillName || null,
|
|
817
|
+
context,
|
|
818
|
+
budget,
|
|
819
|
+
signal,
|
|
820
|
+
managedPolicy: this.managedPolicy,
|
|
821
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
822
|
+
}),
|
|
823
|
+
);
|
|
584
824
|
}
|
|
585
825
|
|
|
586
826
|
async _execMcpTool(hook, context) {
|
|
@@ -591,14 +831,51 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
591
831
|
if (!hook.server || !hook.tool) {
|
|
592
832
|
throw new Error("mcp_tool hook requires server and tool");
|
|
593
833
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
834
|
+
let permission = null;
|
|
835
|
+
if (this.managedPolicy.requireMcpAuthorization !== false) {
|
|
836
|
+
if (!this.mcpAuthorizer) {
|
|
837
|
+
throw managedPolicyError(
|
|
838
|
+
"MCP hook requires the shared MCP permission authorizer",
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
permission = await this.mcpAuthorizer({
|
|
842
|
+
server: hook.server,
|
|
843
|
+
tool: hook.tool,
|
|
844
|
+
arguments: hook.arguments || context,
|
|
845
|
+
context,
|
|
846
|
+
hook,
|
|
847
|
+
});
|
|
848
|
+
const decision = String(permission?.decision || "").toLowerCase();
|
|
849
|
+
if (
|
|
850
|
+
permission !== true &&
|
|
851
|
+
permission?.allowed !== true &&
|
|
852
|
+
decision !== "allow" &&
|
|
853
|
+
decision !== "approve"
|
|
854
|
+
) {
|
|
855
|
+
throw managedPolicyError(
|
|
856
|
+
`MCP hook permission denied: ${hook.server}/${hook.tool}`,
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
const budget = hookBudget(hook);
|
|
861
|
+
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
599
862
|
hook,
|
|
600
|
-
|
|
601
|
-
|
|
863
|
+
this.managedPolicy,
|
|
864
|
+
);
|
|
865
|
+
return executeWithHookTimeout("mcp_tool", budget, (signal) =>
|
|
866
|
+
executor({
|
|
867
|
+
server: hook.server,
|
|
868
|
+
tool: hook.tool,
|
|
869
|
+
arguments: hook.arguments || context,
|
|
870
|
+
context,
|
|
871
|
+
hook,
|
|
872
|
+
budget,
|
|
873
|
+
signal,
|
|
874
|
+
permission,
|
|
875
|
+
managedPolicy: this.managedPolicy,
|
|
876
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
877
|
+
}),
|
|
878
|
+
);
|
|
602
879
|
}
|
|
603
880
|
|
|
604
881
|
async _execJs(hook, context) {
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
import { createAbortError } from "./abort-utils.js";
|
|
17
17
|
import { emitHooksV2Event } from "./hooks-v2-producers.js";
|
|
18
18
|
import { verifyApprovalBinding } from "./agent-authority.js";
|
|
19
|
+
import {
|
|
20
|
+
normalizeInteractionBinding,
|
|
21
|
+
sameInteractionBinding,
|
|
22
|
+
} from "./interaction-binding.js";
|
|
19
23
|
import { createEnvelope } from "@chainlesschain/session-core";
|
|
20
24
|
|
|
21
25
|
// Phase 5: parallel service-envelope emission. Map WS agent-handler event
|
|
@@ -128,6 +132,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
128
132
|
// this WS session instead of leaking across sessions via the process-
|
|
129
133
|
// global default tracker.
|
|
130
134
|
this._sequenceTracker = new CodingAgentSequenceTracker();
|
|
135
|
+
this._questionSequence = 0;
|
|
131
136
|
// Phase 5: parallel service-envelope emission. Opt-in (default off) so
|
|
132
137
|
// legacy callers that count ws.send invocations stay green.
|
|
133
138
|
this.enablePhase5Envelopes = options.enablePhase5Envelopes === true;
|
|
@@ -175,6 +180,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
175
180
|
// routed / argument-tampered verdict and is rejected in _resolvePending.
|
|
176
181
|
// null (the default for plain questions) → no binding check, unchanged.
|
|
177
182
|
binding: options.binding || null,
|
|
183
|
+
bindingType: options.bindingType || null,
|
|
178
184
|
});
|
|
179
185
|
|
|
180
186
|
this._sendWs({
|
|
@@ -274,6 +280,12 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
274
280
|
}
|
|
275
281
|
: {}),
|
|
276
282
|
};
|
|
283
|
+
const binding = normalizeInteractionBinding({
|
|
284
|
+
sessionId: this.sessionId,
|
|
285
|
+
turnId: normalizedTurnId,
|
|
286
|
+
toolUseId: normalizedToolUseId,
|
|
287
|
+
sequence: ++this._questionSequence,
|
|
288
|
+
});
|
|
277
289
|
|
|
278
290
|
return this._request(
|
|
279
291
|
{
|
|
@@ -295,10 +307,13 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
295
307
|
tool_use_id: normalizedToolUseId,
|
|
296
308
|
}
|
|
297
309
|
: {}),
|
|
310
|
+
binding,
|
|
298
311
|
metadata: questionMetadata,
|
|
299
312
|
},
|
|
300
313
|
{
|
|
301
314
|
kind: "question",
|
|
315
|
+
binding,
|
|
316
|
+
bindingType: "interaction",
|
|
302
317
|
...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
|
|
303
318
|
},
|
|
304
319
|
);
|
|
@@ -324,30 +339,48 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
324
339
|
requestedSchema = null,
|
|
325
340
|
timeoutMs,
|
|
326
341
|
} = {}) {
|
|
327
|
-
|
|
342
|
+
const hookContext = {
|
|
343
|
+
schema_version: 1,
|
|
328
344
|
server: server || null,
|
|
329
345
|
request_id: mcpRequestId ?? null,
|
|
330
346
|
message: String(message),
|
|
331
347
|
requested_schema: requestedSchema || null,
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
348
|
+
session_id: this.sessionId || null,
|
|
349
|
+
};
|
|
350
|
+
emitHooksV2Event("MCPElicitation", hookContext);
|
|
351
|
+
emitHooksV2Event("Elicitation", hookContext);
|
|
352
|
+
try {
|
|
353
|
+
const answer = await this._request(
|
|
354
|
+
{
|
|
355
|
+
type: "question",
|
|
356
|
+
questionType: "elicitation",
|
|
357
|
+
question: String(message),
|
|
358
|
+
...(requestedSchema ? { requestedSchema } : {}),
|
|
359
|
+
metadata: {
|
|
360
|
+
kind: "mcp_elicitation",
|
|
361
|
+
server: server || null,
|
|
362
|
+
requestId: mcpRequestId ?? null,
|
|
363
|
+
requestedSchema: requestedSchema || null,
|
|
364
|
+
},
|
|
344
365
|
},
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
366
|
+
{
|
|
367
|
+
kind: "question",
|
|
368
|
+
...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
|
|
369
|
+
},
|
|
370
|
+
);
|
|
371
|
+
emitHooksV2Event("ElicitationResult", {
|
|
372
|
+
...hookContext,
|
|
373
|
+
action: answer == null ? "cancel" : "accept",
|
|
374
|
+
});
|
|
375
|
+
return answer;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
emitHooksV2Event("ElicitationResult", {
|
|
378
|
+
...hookContext,
|
|
379
|
+
action: "cancel",
|
|
380
|
+
reason: error?.code || error?.message || "interaction_failed",
|
|
381
|
+
});
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
351
384
|
}
|
|
352
385
|
|
|
353
386
|
async requestHostTool(toolName, args = {}, extra = {}) {
|
|
@@ -484,8 +517,16 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
484
517
|
// (fail closed) instead of the approve it claims to be, mirroring the local
|
|
485
518
|
// headless approval gate. Backward-compatible: no request binding, or an
|
|
486
519
|
// answer with no echoed binding, resolves exactly as before.
|
|
520
|
+
if (
|
|
521
|
+
pending.bindingType === "interaction" &&
|
|
522
|
+
!sameInteractionBinding(pending.binding, incomingBinding)
|
|
523
|
+
) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
487
527
|
let effective = payload;
|
|
488
528
|
if (
|
|
529
|
+
pending.bindingType !== "interaction" &&
|
|
489
530
|
pending.binding &&
|
|
490
531
|
incomingBinding &&
|
|
491
532
|
!verifyApprovalBinding(pending.binding, incomingBinding)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-neutral binding for a human interaction response.
|
|
3
|
+
*
|
|
4
|
+
* The binding is intentionally plain JSON so CLI attach, WebSocket, Desktop,
|
|
5
|
+
* VS Code, JetBrains, SDK and Remote Control can echo the same value without
|
|
6
|
+
* reinterpreting it. The runtime that created the request remains authoritative
|
|
7
|
+
* and compares every field before accepting a response.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
function asNullableString(value) {
|
|
11
|
+
if (value === undefined || value === null || value === "") return null;
|
|
12
|
+
return String(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function normalizeInteractionBinding(binding = {}) {
|
|
16
|
+
const source =
|
|
17
|
+
binding && typeof binding === "object" && !Array.isArray(binding)
|
|
18
|
+
? binding
|
|
19
|
+
: {};
|
|
20
|
+
return {
|
|
21
|
+
backgroundAgentId: asNullableString(
|
|
22
|
+
source.backgroundAgentId ?? source.background_agent_id,
|
|
23
|
+
),
|
|
24
|
+
sessionId: asNullableString(source.sessionId ?? source.session_id),
|
|
25
|
+
turnId: asNullableString(source.turnId ?? source.turn_id),
|
|
26
|
+
toolUseId: asNullableString(
|
|
27
|
+
source.toolUseId ??
|
|
28
|
+
source.tool_use_id ??
|
|
29
|
+
source.toolCallId ??
|
|
30
|
+
source.tool_call_id,
|
|
31
|
+
),
|
|
32
|
+
sequence:
|
|
33
|
+
Number.isSafeInteger(source.sequence) && source.sequence > 0
|
|
34
|
+
? source.sequence
|
|
35
|
+
: null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function sameInteractionBinding(left, right) {
|
|
40
|
+
const a = normalizeInteractionBinding(left);
|
|
41
|
+
const b = normalizeInteractionBinding(right);
|
|
42
|
+
return (
|
|
43
|
+
a.backgroundAgentId === b.backgroundAgentId &&
|
|
44
|
+
a.sessionId === b.sessionId &&
|
|
45
|
+
a.turnId === b.turnId &&
|
|
46
|
+
a.toolUseId === b.toolUseId &&
|
|
47
|
+
a.sequence === b.sequence
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function hasCompleteInteractionBinding(binding) {
|
|
52
|
+
if (!binding || typeof binding !== "object" || Array.isArray(binding)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const hasAny = (...keys) =>
|
|
56
|
+
keys.some((key) => Object.prototype.hasOwnProperty.call(binding, key));
|
|
57
|
+
return (
|
|
58
|
+
hasAny("backgroundAgentId", "background_agent_id") &&
|
|
59
|
+
hasAny("sessionId", "session_id") &&
|
|
60
|
+
hasAny("turnId", "turn_id") &&
|
|
61
|
+
hasAny("toolUseId", "tool_use_id", "toolCallId", "tool_call_id") &&
|
|
62
|
+
normalizeInteractionBinding(binding).sequence !== null
|
|
63
|
+
);
|
|
64
|
+
}
|