chainlesschain 0.162.175 → 0.162.176
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 +10 -10
- package/src/assets/web-panel/assets/{AIOps-DherW0Rh.js → AIOps-BDLu5Elz.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CDGfqt2Y.js → ActionButton-DH5us-CK.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BYhkzdgD.js → Analytics-BZ0u8IFG.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-cEKk1cpb.js → AppLayout-Duu8xR14.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-_aXR3WWc.js → Artifacts-Br2YBbh_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CYAf-gY7.js → Audit-C3C6a482.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D4Q20phR.js → BackgroundAgents-CzHvebcj.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cq0Tyk58.js → Backup-DZNHYDFd.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CPj_CdAv.js → BaseInput-VRiC4fIx.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BQ-Qq0es.js → Chat-Cm08WWAD.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Ci97vNTs.js → ChatBubbleRenderer-CGHYrugQ.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-rke6l3yg.js → Checkbox-DtByk7d7.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DiacrIPq.js → Codegen-CphXXOfD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cx3BY-Up.js → Col-Hz86TnLR.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DfmWiQy8.js → Community-HP03ltpD.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DdQnpxy5.js → Compact-B_N1mqQz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-lzliOH_r.js → Compliance-CVztRpi8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CYx4Un5k.js → Cowork-wUVOyZih.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-BGDcPFlo.js → Cron-DW5TLJKw.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-0_X5g2ri.js → Crosschain-CrAFGhWH.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C0PEf3Eu.js → DID-pA-oD8ke.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DULQjQ58.js → Dashboard-CXrd5gAw.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DGRHRbW6.js → Dropdown-EweJcsek.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-ChX8XPwB.js → EmailListRenderer-C9xVLPG4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dyq6IBNu.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DH1NfAL2.js → Federation-DtZda9A_.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BN1I_uNi.js → FormItemContext-CiYdcVz3.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Dq_2UYpe.js → GenericCardRenderer-DA13uwA0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BAy1yvI2.js → Git-DzRhZD1O.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Db6Q2iSy.js → Governance-D5RMgOSb.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-0ub6yHcr.js → Inference-BgrPfSNk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DtLetM36.js → KnowledgeGraph-DzjnD571.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Bcoy7CUd.js → Logs-BhWzVDtN.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BfEMFAXf.js → MarkdownRenderer-BDape9cx.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tt2rzwRR.js → Marketplace-DJtL5GV7.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BhOgX-MU.js → McpTools-CZcQygI7.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BJUxeWBL.js → Memory-DUWSDUUu.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BwUY2G9w.js → MobileBridge-BTwq2WKY.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-B2WMboOm.js → Mtc-BiGugEQm.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-8pNEXO63.js → MtcAudit-DY7a6gUe.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-C1wm5a_1.js → Multisig-BQbDu_w7.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-C1QpKF7g.js → NLProgramming-CM2wXTLv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CiQUcxFu.js → Notes-DI6gGs1v.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BblDPJ_x.js → NotificationSettings-BsZOLWAB.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DRjYcPtb.js → OrderTableRenderer-C48mu09U.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Dp3VKB0X.js → Organization-Cds0_tXr.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Czx161m9.js → Overflow-WunYMD87.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-ClFi6wOs.js → P2P-Bo6j4DDv.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CRweW0lz.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BzcRoqTn.js → Permissions-EMvMMC8N.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-ChGTpNMd.js → PersonalDataHub-AX3ypUDV.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BMOOpKWA.js → Pipeline-BOx8HOgL.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D0AZHObH.js → Privacy-tBeTVQVM.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-yYFlZ6Ja.js → ProjectInit-CVYg1W4M.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DJNVuMQs.js → ProjectSettings-Dvt5I7y1.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Br0rBWH1.js → Projects-Cc7FC9-e.js} +1 -1
- package/src/assets/web-panel/assets/Providers-Ct8xqY-E.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-81NZOitV.js → QrScannerModal-Cni8Ooja.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Dic2lCbJ.js → QuickAsk-BJVLKdxr.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Dh9iwViE.js → Recommend-DPG8Rbbm.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Bq9VYEFy.js → RemoteSession-DsdR7dCt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CxFZ-NbJ.js → Reputation-Csg1YM-b.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BVSLcaX2.js → Row-D9DoFoEf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BbC-5DOH.js → RssFeed-BsvKrXMS.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BfjZ1GCr.js → Search-DFUStfgQ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CVjhOV5r.js → Security-ILg1zxdK.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D45u-Aqe.js → Services-Dd41PCaY.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-WkGoK4he.js → Skeleton-Bzo1cN80.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-D_jvQZcj.js → Skills-BDHh17P0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Bf4QTF3E.js → Sla-jl7UTiRY.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DVpZdbMN.js → SpeechSettings-BePa-RF6.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DEEojoMS.js → SyncSettings-DiqqDKGZ.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DFwxpLIk.js → Tasks-DYQ_6lxj.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Bzl-9wY5.js → Templates-JiDeI06L.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-0khxUOB8.js → Tenant-hhgI6zwS.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-B0Y4LONc.js → TimelineRenderer-B8uB5Llk.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DEE07SFh.js → Tokens-C3b_6r2z.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BM7xvA5z.js → Trigger-tIP7HKVe.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Dv3ijvvZ.js → Trust-vjoc11vJ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B1-enmMt.js → UkeySign-DUPBnGuH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DYiIPByd.js → VideoEditing-CBvhUY5T.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D-y374BQ.js → Wallet-DUaQ0uA5.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-HBDjcUhi.js → WebAuthn-DllSivjE.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-sKn4qTID.js → WorkflowEditor-xc8D3uO6.js} +1 -1
- package/src/assets/web-panel/assets/{chat-TVYhaBXj.js → chat-BVicU7oA.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DMADxY9v.js → colors-DJzLmhLm.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-OftcHpO_.js → compact-item-BvYRfThE.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DW1zVUSN.js → createContext-DGXxCBKR.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CaUathNp.js → hasIn-SBDJB1y4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeCIYYG7.js → index-1SdDS6lR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAfT3EMd.js → index-9gdI7uUW.js} +1 -1
- package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
- package/src/assets/web-panel/assets/{index-sm1sGIxW.js → index-BJZf9DhV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBNg08cD.js → index-BO1itZaY.js} +3 -3
- package/src/assets/web-panel/assets/{index-CKNdnJRo.js → index-BTrBGBJs.js} +1 -1
- package/src/assets/web-panel/assets/{index--5UvwqH_.js → index-BYqz4Wrr.js} +1 -1
- package/src/assets/web-panel/assets/{index-8YelceUU.js → index-Bf-ctERC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Lr0MO-GU.js → index-CKyEivf8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZdT8nio.js → index-CdGY9P8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-s-EnkUCn.js → index-Cf-O_g_8.js} +1 -1
- package/src/assets/web-panel/assets/{index-pSVCBsG4.js → index-CloCgBUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-19mFhn.js → index-CoJAO1Lm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKjqFpYa.js → index-Crk5NTb0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJ1PjRY3.js → index-Cs2rmLFt.js} +1 -1
- package/src/assets/web-panel/assets/{index-77kgkUgY.js → index-CtwqO5qo.js} +1 -1
- package/src/assets/web-panel/assets/{index-D63QVAiJ.js → index-D7HimK0M.js} +1 -1
- package/src/assets/web-panel/assets/{index-B52Ztt8Q.js → index-DCdRAgjy.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHi634g9.js → index-DCqRS6da.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFVbDpqg.js → index-DHVLJ8q0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvRw4Fna.js → index-DKrvvWm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZXYI5LU.js → index-DMarmfrv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CM8W07sc.js → index-DRfiXB_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-iDmgT2Dg.js → index-Dm_77jgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-hXq7QRA_.js → index-DnjPdvR6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEzLLVYd.js → index-DonCnfMr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYwwUKDg.js → index-DvUTDYXX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXcqvWBp.js → index-FxZzRyE1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cmdv6Dev.js → index-MjC4G09d.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9JoaYSs.js → index-VMfwIH5G.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK-p7Hji.js → index-YJkzy8ZF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BupSWDcl.js → index-d5BVd-cL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bg-7FpaL.js → index-e4fXH_WO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpDtN0dl.js → index-hxTODbM1.js} +1 -1
- package/src/assets/web-panel/assets/{index-kdMl_0zL.js → index-lpaGoTH3.js} +1 -1
- package/src/assets/web-panel/assets/{index-GUKz4Pv9.js → index-wcCL-miV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWVZ3T0t.js → index-xfluRkCT.js} +1 -1
- package/src/assets/web-panel/assets/index-ycwAfC-i.js +1 -0
- package/src/assets/web-panel/assets/{index-BSp1Ofvx.js → index-z1ZylsLq.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DdcKTlQR.js → initDefaultProps-C1zO1KnY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CL-hTBQj.js → motion-CWLtEGmC.js} +1 -1
- package/src/assets/web-panel/assets/{move-qYSAkxNG.js → move-DzD_C3Vm.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-ZwRSZtRP.js → mtc-parser-D880PYJl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Bld-8ftI.js → omit-CFR_z2ov.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DGHs-a9Z.js → pickAttrs-srIhgrSC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DRQPMyI5.js → placementArrow-C1rXpibP.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C5MJG_Yo.js → responsiveObserve-C30gRcSS.js} +1 -1
- package/src/assets/web-panel/assets/{slide-VZ-fpZCD.js → slide-CvtKiMfV.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-9ocfCyHk.js → statusUtils-DNHO7ITG.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B6QAwAN5.js → styleChecker-Dt_Sl-g4.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Bq1twor3.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DKZq96tz.js → useFs-Baxglj2V.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D0RmRVXf.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D6kEj_tt.js → vnode-mIRkdT7o.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-2yfasoQf.js → zoom-HzI5DlH_.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/auth/npm-auth.js +30 -5
- package/src/commands/agenda.js +64 -2
- package/src/commands/agent.js +39 -1
- package/src/commands/config.js +70 -5
- package/src/commands/context.js +36 -2
- package/src/commands/hub.js +19 -1
- package/src/commands/memory.js +21 -6
- package/src/commands/permissions.js +57 -1
- package/src/commands/plugin.js +2 -0
- package/src/commands/review.js +23 -11
- package/src/commands/routine.js +31 -8
- package/src/commands/session.js +11 -3
- package/src/commands/team.js +20 -7
- package/src/commands/update.js +65 -10
- package/src/gateways/terminal/PtyManager.js +8 -1
- package/src/gateways/ws/message-dispatcher.js +3 -0
- package/src/gateways/ws/session-protocol.js +26 -0
- package/src/gateways/ws/ws-agent-handler.js +107 -69
- package/src/gateways/ws/ws-server.js +74 -2
- package/src/harness/jsonl-session-store.js +13 -6
- package/src/harness/mcp-client.js +200 -1
- package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
- package/src/lib/agent-coordinator.js +4 -0
- package/src/lib/agent-ipc-bus.js +32 -2
- package/src/lib/agent-sandbox.js +16 -2
- package/src/lib/agent-schedule-store.js +55 -0
- package/src/lib/agent-tool-admission.js +104 -0
- package/src/lib/api-key-helper.js +10 -2
- package/src/lib/async-hook-supervisor.cjs +12 -2
- package/src/lib/changelog.js +19 -11
- package/src/lib/channels/channel-manager.js +6 -0
- package/src/lib/channels/telegram-channel.js +11 -1
- package/src/lib/channels/webhook-channel.js +15 -3
- package/src/lib/checkpoint-store.js +10 -2
- package/src/lib/cloud/bundle.js +12 -2
- package/src/lib/code-review.js +32 -8
- package/src/lib/computer-use/control-backend.js +18 -3
- package/src/lib/context-breakdown.js +46 -0
- package/src/lib/context-source-ledger.js +43 -0
- package/src/lib/diff-review-follow-up.js +154 -0
- package/src/lib/downloader.js +17 -3
- package/src/lib/ensure-utf8.js +11 -3
- package/src/lib/event-runtime-producer.js +58 -0
- package/src/lib/event-runtime-store.js +354 -0
- package/src/lib/event-runtime-worker.js +109 -0
- package/src/lib/execution-backend.js +72 -21
- package/src/lib/git-integration.js +19 -4
- package/src/lib/hook-manager.js +6 -15
- package/src/lib/hook-runner.cjs +48 -3
- package/src/lib/hooks-v2-producers.js +15 -0
- package/src/lib/hooks-v2-runtime.js +70 -21
- package/src/lib/host-adb-bridge.js +111 -21
- package/src/lib/ide-context.js +128 -1
- package/src/lib/interaction-adapter.js +39 -0
- package/src/lib/json-schema-validate.js +190 -36
- package/src/lib/lan-pairing-preflight.js +13 -2
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
- package/src/lib/lsp/lsp-client.js +18 -1
- package/src/lib/lsp/lsp-manager.js +4 -0
- package/src/lib/lsp/lsp-server-registry.js +11 -0
- package/src/lib/mcp-oauth.js +8 -2
- package/src/lib/npm-invocation.js +29 -0
- package/src/lib/packer/pkg-runner.js +13 -2
- package/src/lib/packer/precheck.js +33 -16
- package/src/lib/packer/web-panel-builder.js +16 -2
- package/src/lib/permission-rules.cjs +5 -1
- package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
- package/src/lib/personal-data-hub-wiring.js +27 -3
- package/src/lib/plan-mode.js +204 -11
- package/src/lib/plugin-monitor-supervisor.js +39 -4
- package/src/lib/plugin-runtime/bin.js +45 -0
- package/src/lib/plugin-runtime/hooks.js +14 -1
- package/src/lib/plugin-runtime/install.js +2 -1
- package/src/lib/plugin-runtime/lsp.js +3 -0
- package/src/lib/plugin-runtime/mcp.js +8 -1
- package/src/lib/plugin-runtime/monitors.js +4 -0
- package/src/lib/plugin-runtime/plugin-options.js +74 -7
- package/src/lib/plugin-runtime/signature.js +45 -0
- package/src/lib/pr-create.js +21 -8
- package/src/lib/pr-link-ledger.js +15 -3
- package/src/lib/process-execution-broker/credential-agent.js +23 -3
- package/src/lib/process-execution-broker/index.js +315 -38
- package/src/lib/process-execution-broker/patch-child-process.js +2 -3
- package/src/lib/process-manager.js +18 -3
- package/src/lib/publish-workspace.js +14 -6
- package/src/lib/secret-store.js +159 -0
- package/src/lib/service-manager.js +64 -29
- package/src/lib/settings-hook-events.cjs +61 -1
- package/src/lib/settings-hooks.cjs +4 -0
- package/src/lib/side-effect-ledger.js +22 -0
- package/src/lib/sub-agent-context.js +5 -0
- package/src/lib/sub-agent-profiles.js +4 -0
- package/src/lib/turn-context.js +14 -8
- package/src/lib/unattended-action-policy.js +83 -0
- package/src/lib/update-notice.js +6 -2
- package/src/lib/with-file-lock.js +7 -0
- package/src/lib/ws-server.js +1 -0
- package/src/repl/agent-repl.js +32 -0
- package/src/repl/clipboard-copy.js +8 -2
- package/src/repl/pr-comments.js +30 -7
- package/src/runtime/agent-core.js +439 -87
- package/src/runtime/agent-runtime.js +1 -0
- package/src/runtime/coding-agent-contract-shared.cjs +52 -0
- package/src/runtime/coding-agent-policy.cjs +20 -0
- package/src/runtime/diagnostics.js +73 -8
- package/src/runtime/headless-runner.js +63 -0
- package/src/runtime/headless-stream.js +269 -17
- package/src/runtime/mcp-config.js +16 -1
- package/src/assets/web-panel/assets/MobileProjects-BLRfHhqi.js +0 -1
- package/src/assets/web-panel/assets/Providers-zZRhNtSu.js +0 -1
- package/src/assets/web-panel/assets/Terminal-DWGYhAYU.js +0 -3
- package/src/assets/web-panel/assets/devWarning-CLOk6rdE.js +0 -1
- package/src/assets/web-panel/assets/index-CSgUfMTM.js +0 -1
- package/src/assets/web-panel/assets/index-DliSZvAP.js +0 -1
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { agentLoop, formatToolArgs } from "../../runtime/agent-core.js";
|
|
15
15
|
import { classifyToolSideEffect } from "../../lib/side-effect-ledger.js";
|
|
16
|
+
import { DiffReviewFollowUpTracker } from "../../lib/diff-review-follow-up.js";
|
|
16
17
|
import {
|
|
17
18
|
loadSideEffectLedger,
|
|
18
19
|
persistSideEffectLedger,
|
|
@@ -88,6 +89,8 @@ export class WSAgentHandler {
|
|
|
88
89
|
const abortController = new AbortController();
|
|
89
90
|
this._abortController = abortController;
|
|
90
91
|
this._activeRequestId = requestId || null;
|
|
92
|
+
let sideEffectLedger = null;
|
|
93
|
+
let diffReviewFollowUps = null;
|
|
91
94
|
|
|
92
95
|
try {
|
|
93
96
|
const { session } = this;
|
|
@@ -159,88 +162,123 @@ export class WSAgentHandler {
|
|
|
159
162
|
// persisted BEFORE it settles) and commit/fail on its result, so a bridge
|
|
160
163
|
// worker killed mid-flight is surfaced for verification on resume (see
|
|
161
164
|
// handleSessionResume) instead of being blindly replayed.
|
|
162
|
-
|
|
165
|
+
sideEffectLedger = loadSideEffectLedger(session.id);
|
|
166
|
+
diffReviewFollowUps = new DiffReviewFollowUpTracker(sideEffectLedger);
|
|
163
167
|
let currentSideEffectOpId = null;
|
|
164
168
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
idempotencyKey: operationIdempotencyKey({
|
|
169
|
+
const runAgentTurn = async () => {
|
|
170
|
+
for await (const event of agentLoop(session.messages, loopOptions)) {
|
|
171
|
+
switch (event.type) {
|
|
172
|
+
case "slot-filling":
|
|
173
|
+
this.interaction.emit("slot-filling", {
|
|
174
|
+
requestId,
|
|
175
|
+
slot: event.slot,
|
|
176
|
+
question: event.question,
|
|
177
|
+
});
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
case "tool-executing":
|
|
181
|
+
this.interaction.emit("tool-executing", {
|
|
182
|
+
requestId,
|
|
183
|
+
tool: event.tool,
|
|
184
|
+
args: event.args,
|
|
185
|
+
display: formatToolArgs(event.tool, event.args),
|
|
186
|
+
});
|
|
187
|
+
currentSideEffectOpId = null;
|
|
188
|
+
{
|
|
189
|
+
const se = classifyToolSideEffect(event.tool, event.args);
|
|
190
|
+
if (se) {
|
|
191
|
+
const opId = `ws:${session.id}:${Date.now()}:${this._sideEffectSeq++}`;
|
|
192
|
+
currentSideEffectOpId = opId;
|
|
193
|
+
sideEffectLedger
|
|
194
|
+
.prepare(opId, {
|
|
195
|
+
kind: se.kind,
|
|
196
|
+
key: se.key,
|
|
197
|
+
meta: {
|
|
195
198
|
tool: event.tool,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
idempotencyKey: operationIdempotencyKey({
|
|
200
|
+
tool: event.tool,
|
|
201
|
+
args: event.args,
|
|
202
|
+
}),
|
|
203
|
+
},
|
|
204
|
+
})
|
|
205
|
+
.start(opId);
|
|
206
|
+
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
case "tool-result":
|
|
212
|
+
this.interaction.emit("tool-result", {
|
|
213
|
+
requestId,
|
|
214
|
+
tool: event.tool,
|
|
215
|
+
result: event.result,
|
|
216
|
+
error: event.error,
|
|
217
|
+
});
|
|
218
|
+
if (currentSideEffectOpId) {
|
|
219
|
+
const err = event.error || event.result?.error || null;
|
|
220
|
+
if (event.result?._diffReviewAudit) {
|
|
221
|
+
diffReviewFollowUps.observe(
|
|
222
|
+
sideEffectLedger,
|
|
223
|
+
currentSideEffectOpId,
|
|
224
|
+
event.result._diffReviewAudit,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (err)
|
|
228
|
+
sideEffectLedger.fail(
|
|
229
|
+
currentSideEffectOpId,
|
|
230
|
+
String(err).slice(0, 200),
|
|
231
|
+
);
|
|
232
|
+
else sideEffectLedger.commit(currentSideEffectOpId);
|
|
201
233
|
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
234
|
+
currentSideEffectOpId = null;
|
|
202
235
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const err = event.error || event.result?.error || null;
|
|
215
|
-
if (err)
|
|
216
|
-
sideEffectLedger.fail(
|
|
217
|
-
currentSideEffectOpId,
|
|
218
|
-
String(err).slice(0, 200),
|
|
219
|
-
);
|
|
220
|
-
else sideEffectLedger.commit(currentSideEffectOpId);
|
|
221
|
-
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
222
|
-
currentSideEffectOpId = null;
|
|
223
|
-
}
|
|
224
|
-
break;
|
|
225
|
-
|
|
226
|
-
case "response-complete":
|
|
227
|
-
if (event.content) {
|
|
228
|
-
session.messages.push({
|
|
229
|
-
role: "assistant",
|
|
236
|
+
break;
|
|
237
|
+
|
|
238
|
+
case "response-complete":
|
|
239
|
+
if (event.content) {
|
|
240
|
+
session.messages.push({
|
|
241
|
+
role: "assistant",
|
|
242
|
+
content: event.content,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
this.interaction.emit("response-complete", {
|
|
246
|
+
requestId,
|
|
230
247
|
content: event.content,
|
|
231
248
|
});
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
requestId,
|
|
235
|
-
content: event.content,
|
|
236
|
-
});
|
|
237
|
-
break;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
238
251
|
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (session.mcpClient?.withElicitationContext) {
|
|
255
|
+
await session.mcpClient.withElicitationContext(
|
|
256
|
+
session.id,
|
|
257
|
+
runAgentTurn,
|
|
258
|
+
);
|
|
259
|
+
} else {
|
|
260
|
+
await runAgentTurn();
|
|
261
|
+
}
|
|
262
|
+
if (
|
|
263
|
+
diffReviewFollowUps.complete(sideEffectLedger, {
|
|
264
|
+
status: "completed-without-reproposal",
|
|
265
|
+
}).length > 0
|
|
266
|
+
) {
|
|
267
|
+
persistSideEffectLedger(session.id, sideEffectLedger);
|
|
239
268
|
}
|
|
240
269
|
|
|
241
270
|
// Update last activity
|
|
242
271
|
session.lastActivity = new Date().toISOString();
|
|
243
272
|
} catch (err) {
|
|
273
|
+
if (
|
|
274
|
+
sideEffectLedger &&
|
|
275
|
+
diffReviewFollowUps?.complete(sideEffectLedger, {
|
|
276
|
+
status: "interrupted",
|
|
277
|
+
reason: isAbortError(err) ? "aborted" : err.message,
|
|
278
|
+
}).length > 0
|
|
279
|
+
) {
|
|
280
|
+
persistSideEffectLedger(this.session.id, sideEffectLedger);
|
|
281
|
+
}
|
|
244
282
|
if (isAbortError(err) || abortController.signal.aborted) {
|
|
245
283
|
return;
|
|
246
284
|
}
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { EventEmitter } from "node:events";
|
|
14
|
-
import { spawn } from "node:child_process";
|
|
15
14
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
16
15
|
import { fileURLToPath } from "node:url";
|
|
17
16
|
import { dirname, join } from "node:path";
|
|
@@ -113,6 +112,11 @@ import {
|
|
|
113
112
|
handleArtifactRemove,
|
|
114
113
|
handleArtifactShow,
|
|
115
114
|
} from "./artifact-protocol.js";
|
|
115
|
+
import { executionBroker } from "../../lib/process-execution-broker/index.js";
|
|
116
|
+
|
|
117
|
+
export const _deps = {
|
|
118
|
+
spawn: (...args) => executionBroker.spawn(...args),
|
|
119
|
+
};
|
|
116
120
|
|
|
117
121
|
const __filename = fileURLToPath(import.meta.url);
|
|
118
122
|
const __dirname = dirname(__filename);
|
|
@@ -216,6 +220,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
216
220
|
* @param {string} [options.token] - If set, clients must authenticate first
|
|
217
221
|
* @param {number} [options.maxConnections=10]
|
|
218
222
|
* @param {number} [options.timeout=30000] - Command execution timeout (ms)
|
|
223
|
+
* @param {Function} [options.spawn] - Process seam for tests
|
|
219
224
|
*/
|
|
220
225
|
constructor(options = {}) {
|
|
221
226
|
super();
|
|
@@ -240,6 +245,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
240
245
|
// grace window so it can't hold a maxConnections slot forever (see
|
|
241
246
|
// AUTH_TIMEOUT_MS). `??` so an explicit 0 (disable) is honoured.
|
|
242
247
|
this.authTimeoutMs = options.authTimeoutMs ?? AUTH_TIMEOUT_MS;
|
|
248
|
+
this._spawnProcess = options.spawn || _deps.spawn;
|
|
243
249
|
|
|
244
250
|
/** Optional Phase-5 envelope bus for fan-out to hosted HTTP SSE. */
|
|
245
251
|
this.envelopeBus = options.envelopeBus || null;
|
|
@@ -255,6 +261,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
255
261
|
|
|
256
262
|
/** Session manager for stateful agent/chat sessions */
|
|
257
263
|
this.sessionManager = options.sessionManager || null;
|
|
264
|
+
this.projectRoot = options.projectRoot || process.cwd();
|
|
258
265
|
|
|
259
266
|
/** Session handlers: sessionId → WSAgentHandler | WSChatHandler */
|
|
260
267
|
this.sessionHandlers = new Map();
|
|
@@ -530,6 +537,67 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
530
537
|
return this._dispatcher.dispatch(clientId, ws, message);
|
|
531
538
|
}
|
|
532
539
|
|
|
540
|
+
/** Read the same .claude settings rules used by the Agent Core. */
|
|
541
|
+
async _handlePermissionRulesGet(id, ws) {
|
|
542
|
+
try {
|
|
543
|
+
const { loadSettings } = await import("../../lib/settings-loader.cjs");
|
|
544
|
+
const loaded = loadSettings({ cwd: this.projectRoot });
|
|
545
|
+
this._send(ws, {
|
|
546
|
+
id,
|
|
547
|
+
type: "permission-rules",
|
|
548
|
+
rules: loaded.rules,
|
|
549
|
+
sources: loaded.sources,
|
|
550
|
+
files: loaded.files,
|
|
551
|
+
managed: loaded.managed || null,
|
|
552
|
+
});
|
|
553
|
+
} catch (error) {
|
|
554
|
+
this._send(ws, {
|
|
555
|
+
id,
|
|
556
|
+
type: "error",
|
|
557
|
+
code: "PERMISSION_RULES_READ_FAILED",
|
|
558
|
+
message: error.message,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Persist one rule through settings-loader; managed policy remains authoritative. */
|
|
564
|
+
async _handlePermissionRulesSet(id, ws, message) {
|
|
565
|
+
try {
|
|
566
|
+
const decision = String(message.decision || "").toLowerCase();
|
|
567
|
+
if (!["allow", "ask", "deny"].includes(decision)) {
|
|
568
|
+
throw new Error("decision must be allow, ask, or deny");
|
|
569
|
+
}
|
|
570
|
+
const rulesMod = await import("../../lib/permission-rules.cjs");
|
|
571
|
+
const mod = rulesMod.default || rulesMod;
|
|
572
|
+
if (!mod.parseRule(message.rule)) throw new Error("invalid permission rule");
|
|
573
|
+
const { addRule } = await import("../../lib/settings-loader.cjs");
|
|
574
|
+
const scope = ["project", "local", "user"].includes(message.scope)
|
|
575
|
+
? message.scope
|
|
576
|
+
: "project";
|
|
577
|
+
const result = addRule({
|
|
578
|
+
cwd: this.projectRoot,
|
|
579
|
+
kind: decision,
|
|
580
|
+
rule: message.rule,
|
|
581
|
+
scope,
|
|
582
|
+
});
|
|
583
|
+
this._send(ws, {
|
|
584
|
+
id,
|
|
585
|
+
type: "permission-rule-updated",
|
|
586
|
+
...result,
|
|
587
|
+
decision,
|
|
588
|
+
rule: message.rule,
|
|
589
|
+
scope,
|
|
590
|
+
});
|
|
591
|
+
} catch (error) {
|
|
592
|
+
this._send(ws, {
|
|
593
|
+
id,
|
|
594
|
+
type: "error",
|
|
595
|
+
code: "PERMISSION_RULES_WRITE_FAILED",
|
|
596
|
+
message: error.message,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
533
601
|
/**
|
|
534
602
|
* Handle an orchestrate message — runs ChainlessChain orchestration with
|
|
535
603
|
* real-time progress pushed back over this WebSocket connection.
|
|
@@ -854,7 +922,7 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
854
922
|
return;
|
|
855
923
|
}
|
|
856
924
|
|
|
857
|
-
const child =
|
|
925
|
+
const child = this._spawnProcess(process.execPath, [BIN_PATH, ...args], {
|
|
858
926
|
env: {
|
|
859
927
|
...process.env,
|
|
860
928
|
FORCE_COLOR: "0",
|
|
@@ -870,6 +938,10 @@ export class ChainlessChainWSServer extends EventEmitter {
|
|
|
870
938
|
},
|
|
871
939
|
stdio: ["pipe", "pipe", "pipe"],
|
|
872
940
|
windowsHide: true,
|
|
941
|
+
origin: "gateway:ws-command",
|
|
942
|
+
policy: "allow",
|
|
943
|
+
scope: "gateway",
|
|
944
|
+
shell: false,
|
|
873
945
|
});
|
|
874
946
|
|
|
875
947
|
this.processes.set(id, child);
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
verifyTranscriptText,
|
|
21
21
|
TRANSCRIPT_CHAIN_STATUS,
|
|
22
22
|
} from "./transcript-integrity.js";
|
|
23
|
+
import { withFileLock } from "../lib/with-file-lock.js";
|
|
23
24
|
|
|
24
25
|
function getSessionsDir() {
|
|
25
26
|
const dir = join(getHomeDir(), "sessions");
|
|
@@ -82,12 +83,18 @@ function _resolveChainTail(sessionId, filePath) {
|
|
|
82
83
|
|
|
83
84
|
export function appendEvent(sessionId, type, data) {
|
|
84
85
|
const filePath = sessionPath(sessionId);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
withFileLock(
|
|
87
|
+
filePath,
|
|
88
|
+
() => {
|
|
89
|
+
const prevHash = _resolveChainTail(sessionId, filePath);
|
|
90
|
+
const core = { type, timestamp: Date.now(), data };
|
|
91
|
+
const hash = computeEventHash(prevHash, core);
|
|
92
|
+
const line = JSON.stringify({ ...core, prevHash, hash }) + "\n";
|
|
93
|
+
appendFileSync(filePath, line, "utf-8");
|
|
94
|
+
_chainTailCache.set(sessionId, hash);
|
|
95
|
+
},
|
|
96
|
+
{ failIfUnavailable: true },
|
|
97
|
+
);
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
/**
|
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { spawn } from "child_process";
|
|
12
|
+
import { executionBroker } from "../lib/process-execution-broker/index.js";
|
|
13
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12
14
|
import { EventEmitter } from "events";
|
|
13
15
|
import { pathToFileURL } from "url";
|
|
14
16
|
import { safeJsonParse } from "../lib/safe-json.js";
|
|
17
|
+
import { EventRuntimeProducer } from "../lib/event-runtime-producer.js";
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Injectable dependencies — overridable from tests.
|
|
@@ -166,6 +169,178 @@ export class MCPClient extends EventEmitter {
|
|
|
166
169
|
options && Array.isArray(options.roots) && options.roots.length > 0
|
|
167
170
|
? options.roots.map(String)
|
|
168
171
|
: null;
|
|
172
|
+
// MCP elicitation (server -> client `elicitation/create`). The handler is
|
|
173
|
+
// intentionally injected by the host (REPL, headless, or Desktop bridge)
|
|
174
|
+
// so the transport layer never reads stdin or invents an approval policy.
|
|
175
|
+
this._elicitationHandler =
|
|
176
|
+
typeof options.elicitationHandler === "function"
|
|
177
|
+
? options.elicitationHandler
|
|
178
|
+
: null;
|
|
179
|
+
this._elicitationHandlers = new Map();
|
|
180
|
+
this._elicitationContext = new AsyncLocalStorage();
|
|
181
|
+
this._elicitationTimeoutMs =
|
|
182
|
+
Number(options.elicitationTimeoutMs) > 0
|
|
183
|
+
? Number(options.elicitationTimeoutMs)
|
|
184
|
+
: 180000;
|
|
185
|
+
this._pendingElicitations = new Map();
|
|
186
|
+
this._runtimeProducer = options.eventRuntimeStore
|
|
187
|
+
? new EventRuntimeProducer({ store: options.eventRuntimeStore, emitter: this })
|
|
188
|
+
: null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Install or clear the host-side MCP elicitation resolver. */
|
|
192
|
+
setElicitationHandler(handler, options = {}) {
|
|
193
|
+
const sessionId = options.sessionId;
|
|
194
|
+
if (sessionId != null && sessionId !== "") {
|
|
195
|
+
const key = String(sessionId);
|
|
196
|
+
if (typeof handler === "function") this._elicitationHandlers.set(key, handler);
|
|
197
|
+
else this._elicitationHandlers.delete(key);
|
|
198
|
+
} else {
|
|
199
|
+
this._elicitationHandler =
|
|
200
|
+
typeof handler === "function" ? handler : null;
|
|
201
|
+
}
|
|
202
|
+
if (Number(options.timeoutMs) > 0) {
|
|
203
|
+
this._elicitationTimeoutMs = Number(options.timeoutMs);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Run an async agent turn with a session-scoped elicitation route. */
|
|
208
|
+
withElicitationContext(sessionId, fn) {
|
|
209
|
+
if (typeof fn !== "function") return Promise.resolve(undefined);
|
|
210
|
+
return this._elicitationContext.run(
|
|
211
|
+
sessionId == null ? null : String(sessionId),
|
|
212
|
+
fn,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Remove a session route when a WS session is closed. */
|
|
217
|
+
clearElicitationHandler(sessionId) {
|
|
218
|
+
if (sessionId == null || sessionId === "") return false;
|
|
219
|
+
return this._elicitationHandlers.delete(String(sessionId));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Resolve a pending server elicitation by its server/request id pair. */
|
|
223
|
+
respondElicitation(serverName, requestId, response) {
|
|
224
|
+
const key = this._elicitationKey(serverName, requestId);
|
|
225
|
+
const pending = this._pendingElicitations.get(key);
|
|
226
|
+
if (!pending) return false;
|
|
227
|
+
pending.resolve(this._normalizeElicitationResponse(response));
|
|
228
|
+
try {
|
|
229
|
+
this._runtimeProducer?.store.acknowledgeInbox(
|
|
230
|
+
`mcp-elicitation:${this._elicitationKey(serverName, requestId)}`,
|
|
231
|
+
{ response: this._normalizeElicitationResponse(response) },
|
|
232
|
+
);
|
|
233
|
+
} catch {}
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Cancel a pending server elicitation. */
|
|
238
|
+
cancelElicitation(serverName, requestId) {
|
|
239
|
+
return this.respondElicitation(serverName, requestId, {
|
|
240
|
+
action: "cancel",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
_elicitationKey(serverName, requestId) {
|
|
245
|
+
return `${String(serverName)}:${String(requestId)}`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
_normalizeElicitationResponse(response) {
|
|
249
|
+
const action = String(response?.action || "decline").toLowerCase();
|
|
250
|
+
const safeAction = new Set(["accept", "decline", "cancel"]).has(action)
|
|
251
|
+
? action
|
|
252
|
+
: "decline";
|
|
253
|
+
const normalized = { action: safeAction };
|
|
254
|
+
if (safeAction === "accept" && response?.content !== undefined) {
|
|
255
|
+
normalized.content = response.content;
|
|
256
|
+
}
|
|
257
|
+
return normalized;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async _resolveElicitation(serverName, requestId, params = {}) {
|
|
261
|
+
const key = this._elicitationKey(serverName, requestId);
|
|
262
|
+
try {
|
|
263
|
+
this._runtimeProducer?.publish(
|
|
264
|
+
{ type: "mcp_elicitation", server: serverName, requestId, params },
|
|
265
|
+
{ origin: "mcp", id: `mcp-elicitation:${key}` },
|
|
266
|
+
);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
this.emit("elicitation-error", { server: serverName, requestId, error });
|
|
269
|
+
return { action: "cancel" };
|
|
270
|
+
}
|
|
271
|
+
const contextSessionId = this._elicitationContext.getStore();
|
|
272
|
+
const handler =
|
|
273
|
+
(contextSessionId && this._elicitationHandlers.get(contextSessionId)) ||
|
|
274
|
+
this._elicitationHandler;
|
|
275
|
+
if (handler) {
|
|
276
|
+
try {
|
|
277
|
+
const direct = await handler({
|
|
278
|
+
server: serverName,
|
|
279
|
+
requestId,
|
|
280
|
+
...params,
|
|
281
|
+
});
|
|
282
|
+
if (direct !== undefined) {
|
|
283
|
+
const response = this._normalizeElicitationResponse(direct);
|
|
284
|
+
try {
|
|
285
|
+
this._runtimeProducer?.store.acknowledgeInbox(
|
|
286
|
+
`mcp-elicitation:${key}`,
|
|
287
|
+
{ response },
|
|
288
|
+
);
|
|
289
|
+
} catch {}
|
|
290
|
+
return response;
|
|
291
|
+
}
|
|
292
|
+
} catch (error) {
|
|
293
|
+
this.emit("elicitation-error", {
|
|
294
|
+
server: serverName,
|
|
295
|
+
requestId,
|
|
296
|
+
error,
|
|
297
|
+
});
|
|
298
|
+
return { action: "cancel" };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// An event-driven host may answer later through respondElicitation().
|
|
303
|
+
// No handler/listener means fail closed with decline rather than leaving a
|
|
304
|
+
// server request hanging indefinitely.
|
|
305
|
+
if (this.listenerCount("elicitation-request") === 0) {
|
|
306
|
+
try {
|
|
307
|
+
this._runtimeProducer?.store.acknowledgeInbox(
|
|
308
|
+
`mcp-elicitation:${key}`,
|
|
309
|
+
{ response: { action: "decline" } },
|
|
310
|
+
);
|
|
311
|
+
} catch {}
|
|
312
|
+
return { action: "decline" };
|
|
313
|
+
}
|
|
314
|
+
return new Promise((resolve) => {
|
|
315
|
+
const timeout = setTimeout(() => {
|
|
316
|
+
this._pendingElicitations.delete(key);
|
|
317
|
+
this.emit("elicitation-timeout", { server: serverName, requestId });
|
|
318
|
+
try {
|
|
319
|
+
this._runtimeProducer?.store.fail(
|
|
320
|
+
"inbox",
|
|
321
|
+
`mcp-elicitation:${key}`,
|
|
322
|
+
"elicitation timeout",
|
|
323
|
+
{ retryDelayMs: 0, maxAttempts: 1 },
|
|
324
|
+
);
|
|
325
|
+
} catch {}
|
|
326
|
+
resolve({ action: "cancel" });
|
|
327
|
+
}, this._elicitationTimeoutMs);
|
|
328
|
+
timeout.unref?.();
|
|
329
|
+
this._pendingElicitations.set(key, {
|
|
330
|
+
resolve: (response) => {
|
|
331
|
+
clearTimeout(timeout);
|
|
332
|
+
this._pendingElicitations.delete(key);
|
|
333
|
+
resolve(this._normalizeElicitationResponse(response));
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
this.emit("elicitation-request", {
|
|
337
|
+
server: serverName,
|
|
338
|
+
requestId,
|
|
339
|
+
...params,
|
|
340
|
+
respond: (response) => this.respondElicitation(serverName, requestId, response),
|
|
341
|
+
cancel: () => this.cancelElicitation(serverName, requestId),
|
|
342
|
+
});
|
|
343
|
+
});
|
|
169
344
|
}
|
|
170
345
|
|
|
171
346
|
/**
|
|
@@ -311,7 +486,10 @@ export class MCPClient extends EventEmitter {
|
|
|
311
486
|
`stdio transport requires a command (server "${name}")`,
|
|
312
487
|
);
|
|
313
488
|
}
|
|
314
|
-
const
|
|
489
|
+
const spawnFn = String(config.origin || "").startsWith("plugin:")
|
|
490
|
+
? executionBroker.spawn.bind(executionBroker)
|
|
491
|
+
: _deps.spawn;
|
|
492
|
+
const proc = spawnFn(config.command, config.args || [], {
|
|
315
493
|
stdio: ["pipe", "pipe", "pipe"],
|
|
316
494
|
// process.env < agent identity (CLAUDECODE / session id) < the
|
|
317
495
|
// server's own config.env, so an explicit per-server override wins.
|
|
@@ -320,6 +498,15 @@ export class MCPClient extends EventEmitter {
|
|
|
320
498
|
...this._agentIdentityEnv(),
|
|
321
499
|
...(config.env || {}),
|
|
322
500
|
},
|
|
501
|
+
...(config.origin
|
|
502
|
+
? {
|
|
503
|
+
origin: config.origin,
|
|
504
|
+
policy: config.policy || "allow",
|
|
505
|
+
pluginId: config.pluginId,
|
|
506
|
+
pluginVersion: config.pluginVersion,
|
|
507
|
+
pluginSource: config.pluginSource,
|
|
508
|
+
}
|
|
509
|
+
: {}),
|
|
323
510
|
});
|
|
324
511
|
|
|
325
512
|
entry.process = proc;
|
|
@@ -510,6 +697,12 @@ export class MCPClient extends EventEmitter {
|
|
|
510
697
|
const entry = this.servers.get(name);
|
|
511
698
|
if (!entry) return false;
|
|
512
699
|
|
|
700
|
+
for (const [key, pending] of this._pendingElicitations) {
|
|
701
|
+
if (key.startsWith(`${String(name)}:`)) {
|
|
702
|
+
pending.resolve({ action: "cancel" });
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
513
706
|
if (entry.process) {
|
|
514
707
|
entry.process.kill();
|
|
515
708
|
}
|
|
@@ -1125,6 +1318,12 @@ export class MCPClient extends EventEmitter {
|
|
|
1125
1318
|
this._sendResponse(serverName, id, {});
|
|
1126
1319
|
return;
|
|
1127
1320
|
}
|
|
1321
|
+
if (method === "elicitation/create") {
|
|
1322
|
+
this._resolveElicitation(serverName, id, msg.params || {})
|
|
1323
|
+
.then((response) => this._sendResponse(serverName, id, response))
|
|
1324
|
+
.catch(() => this._sendResponse(serverName, id, { action: "cancel" }));
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1128
1327
|
this._sendResponse(serverName, id, undefined, {
|
|
1129
1328
|
code: -32601,
|
|
1130
1329
|
message: `method not found: ${method}`,
|
|
@@ -91,6 +91,21 @@ describe("createVendorAdapterBridge (cli)", () => {
|
|
|
91
91
|
expect(r.userId).toBe("userToken");
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
it("attaches a validated session to the registry runtime adapter", async () => {
|
|
95
|
+
const runtimeAdapter = { setSession: vi.fn() };
|
|
96
|
+
const bridge = createVendorAdapterBridge({
|
|
97
|
+
specs: [fakeSpec("deepseek", async () => ({ ok: true }))],
|
|
98
|
+
runtimeAdapter,
|
|
99
|
+
_httpClientFactory: () => ({}),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await bridge.registerVendor("deepseek", { userToken: "abc" });
|
|
103
|
+
|
|
104
|
+
expect(runtimeAdapter.setSession).toHaveBeenCalledOnce();
|
|
105
|
+
expect(runtimeAdapter.setSession.mock.calls[0][0]).toBe("deepseek");
|
|
106
|
+
expect(runtimeAdapter.setSession.mock.calls[0][1].get("userToken")).toBe("abc");
|
|
107
|
+
});
|
|
108
|
+
|
|
94
109
|
it("UNKNOWN_VENDOR for unrecognized", async () => {
|
|
95
110
|
const bridge = createVendorAdapterBridge({
|
|
96
111
|
specs: [fakeSpec("deepseek", async () => ({ ok: true }))],
|
|
@@ -281,6 +281,8 @@ export const ROLE_TOOL_WHITELIST = {
|
|
|
281
281
|
"read_file",
|
|
282
282
|
"write_file",
|
|
283
283
|
"edit_file",
|
|
284
|
+
"delete_file",
|
|
285
|
+
"move_file",
|
|
284
286
|
"run_shell",
|
|
285
287
|
"search_files",
|
|
286
288
|
"list_dir",
|
|
@@ -297,6 +299,8 @@ export const ROLE_TOOL_WHITELIST = {
|
|
|
297
299
|
"read_file",
|
|
298
300
|
"write_file",
|
|
299
301
|
"edit_file",
|
|
302
|
+
"delete_file",
|
|
303
|
+
"move_file",
|
|
300
304
|
"run_shell",
|
|
301
305
|
"search_files",
|
|
302
306
|
"list_dir",
|