chainlesschain 0.162.174 → 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-Dcl-X1Hw.js → AIOps-BDLu5Elz.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-DH5us-CK.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BZ0u8IFG.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-Br2YBbh_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-C3C6a482.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-CzHvebcj.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-DZNHYDFd.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-VRiC4fIx.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-Cm08WWAD.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CGHYrugQ.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-DtByk7d7.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-CphXXOfD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Hz86TnLR.js} +1 -1
- package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-HP03ltpD.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-B_N1mqQz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-CVztRpi8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-wUVOyZih.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-DW5TLJKw.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-CrAFGhWH.js} +1 -1
- package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-pA-oD8ke.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-EweJcsek.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-C9xVLPG4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DtZda9A_.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-CiYdcVz3.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-DA13uwA0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-DzRhZD1O.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-D5RMgOSb.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-BgrPfSNk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DzjnD571.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-BhWzVDtN.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BDape9cx.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-DJtL5GV7.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-CZcQygI7.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-DUWSDUUu.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BTwq2WKY.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-BiGugEQm.js} +6 -6
- package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-DY7a6gUe.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-BQbDu_w7.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-CM2wXTLv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-DI6gGs1v.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BsZOLWAB.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-C48mu09U.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Cds0_tXr.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-WunYMD87.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-Bo6j4DDv.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-EMvMMC8N.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-AX3ypUDV.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BOx8HOgL.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-tBeTVQVM.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-CVYg1W4M.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-Dvt5I7y1.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Cc7FC9-e.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CbCe2eUl.js → Providers-Ct8xqY-E.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-Cni8Ooja.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-BJVLKdxr.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-DPG8Rbbm.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-DsdR7dCt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-Csg1YM-b.js} +1 -1
- package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-D9DoFoEf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BsvKrXMS.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-DFUStfgQ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-ILg1zxdK.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-Dd41PCaY.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-Bzo1cN80.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-BDHh17P0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-jl7UTiRY.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-BePa-RF6.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DiqqDKGZ.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DYQ_6lxj.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-JiDeI06L.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-hhgI6zwS.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B8uB5Llk.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-C3b_6r2z.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-tIP7HKVe.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-vjoc11vJ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-DUPBnGuH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-CBvhUY5T.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-DUaQ0uA5.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-DllSivjE.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-xc8D3uO6.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-BVicU7oA.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DJzLmhLm.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-BvYRfThE.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BJmpSlf1.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-D1q-zw7u.js → hasIn-SBDJB1y4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-1SdDS6lR.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-9gdI7uUW.js} +1 -1
- package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
- package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-BJZf9DhV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BO1itZaY.js} +3 -3
- package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-BTrBGBJs.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index-BYqz4Wrr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-Bf-ctERC.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-CKyEivf8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-CdGY9P8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-Cf-O_g_8.js} +1 -1
- package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-CloCgBUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-CoJAO1Lm.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-Crk5NTb0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-Cs2rmLFt.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-CtwqO5qo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D7HimK0M.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-DCdRAgjy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DCqRS6da.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-DHVLJ8q0.js} +1 -1
- package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-DKrvvWm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-DMarmfrv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-DRfiXB_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-Dm_77jgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-DnjPdvR6.js} +1 -1
- package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-DonCnfMr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DvUTDYXX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-FxZzRyE1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-MjC4G09d.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-VMfwIH5G.js} +1 -1
- package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-YJkzy8ZF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-d5BVd-cL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-e4fXH_WO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-hxTODbM1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-lpaGoTH3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-wcCL-miV.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZDUhX41Z.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-z8ATo2aQ.js → index-z1ZylsLq.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-C1zO1KnY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CWLtEGmC.js} +1 -1
- package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-DzD_C3Vm.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-D880PYJl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-CFR_z2ov.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-srIhgrSC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-C1rXpibP.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C30gRcSS.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-CvtKiMfV.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-DNHO7ITG.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-Dt_Sl-g4.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-Baxglj2V.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-mIRkdT7o.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-G3LMswgy.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 +45 -3
- package/src/commands/background-session.js +103 -0
- 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/esm-bridge.js +3 -0
- 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 +92 -4
- package/src/harness/jsonl-session-store.js +13 -6
- package/src/harness/mcp-client.js +200 -1
- package/src/index.js +123 -55
- package/src/lazy-dispatch.js +86 -85
- 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 +26 -4
- package/src/lib/background-interaction-resolver.js +71 -0
- package/src/lib/background-session-transport.js +59 -1
- 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/crash-reporter.js +6 -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 +34 -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/ipc-attach-protocol.js +98 -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 +295 -0
- package/src/lib/process-execution-broker/index.js +440 -14
- package/src/lib/process-execution-broker/patch-child-process.js +2 -3
- package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
- package/src/lib/process-manager.js +18 -3
- package/src/lib/provenance-api.js +6 -0
- package/src/lib/proxy-bootstrap.js +19 -0
- package/src/lib/publish-workspace.js +14 -6
- package/src/lib/repl-rewind.js +9 -4
- package/src/lib/secret-store.js +159 -0
- package/src/lib/service-manager.js +64 -29
- package/src/lib/session-hooks.js +328 -473
- package/src/lib/session-telemetry-middleware.js +6 -0
- 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/trace-api.js +6 -0
- package/src/lib/turn-context.js +14 -8
- package/src/lib/unattended-action-policy.js +83 -0
- package/src/lib/update-notice.js +9 -45
- package/src/lib/with-file-lock.js +7 -0
- package/src/lib/ws-server.js +1 -0
- package/src/repl/agent-repl.js +71 -13
- 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/workers/background-agent-worker.js +80 -1
- package/src/assets/web-panel/assets/AppLayout-7iSKDmlI.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DcbUHeGW.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-BAKYNavw.js +0 -3
- package/src/assets/web-panel/assets/MobileProjects-C4GKn1dH.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Fj7ea0In.js +0 -3
- package/src/assets/web-panel/assets/devWarning-CDI8Sbaj.js +0 -1
- package/src/assets/web-panel/assets/index-96LBR96V.js +0 -1
- package/src/assets/web-panel/assets/index-DyQkiW24.js +0 -1
|
@@ -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",
|
package/src/lib/agent-ipc-bus.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
import { EventEmitter } from "node:events";
|
|
13
13
|
import crypto from "node:crypto";
|
|
14
|
+
import { EventRuntimeProducer } from "./event-runtime-producer.js";
|
|
15
|
+
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* @typedef {Object} InteractionRequest
|
|
@@ -27,8 +29,11 @@ import crypto from "node:crypto";
|
|
|
27
29
|
*/
|
|
28
30
|
|
|
29
31
|
class AgentIPCBus extends EventEmitter {
|
|
30
|
-
constructor() {
|
|
32
|
+
constructor({ runtimeStore = null } = {}) {
|
|
31
33
|
super();
|
|
34
|
+
this._runtimeProducer = runtimeStore
|
|
35
|
+
? new EventRuntimeProducer({ store: runtimeStore, emitter: this })
|
|
36
|
+
: null;
|
|
32
37
|
/** @type {Map<string, {req: InteractionRequest, resolve: Function, reject: Function, timer?: NodeJS.Timeout}>} */
|
|
33
38
|
this._pendingRequests = new Map();
|
|
34
39
|
/** @type {Map<string, Function>} resolvers by agentId */
|
|
@@ -58,6 +63,10 @@ class AgentIPCBus extends EventEmitter {
|
|
|
58
63
|
this.emit("agent:unregistered", { agentId });
|
|
59
64
|
}
|
|
60
65
|
|
|
66
|
+
isAgentRegistered(agentId) {
|
|
67
|
+
return this._agentResolvers.has(agentId);
|
|
68
|
+
}
|
|
69
|
+
|
|
61
70
|
/**
|
|
62
71
|
* Child agent calls this to request human interaction
|
|
63
72
|
* @param {string} agentId
|
|
@@ -91,6 +100,19 @@ class AgentIPCBus extends EventEmitter {
|
|
|
91
100
|
}, fullReq.timeoutMs);
|
|
92
101
|
|
|
93
102
|
this._pendingRequests.set(requestId, { req: fullReq, resolve, reject, timer });
|
|
103
|
+
try {
|
|
104
|
+
this._runtimeProducer?.publish(
|
|
105
|
+
{ type: "interaction_request", request: fullReq },
|
|
106
|
+
{ origin: "agent-ipc", id: `interaction:${requestId}` },
|
|
107
|
+
);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
// Durable publication is fail-closed for configured runtime mode: do
|
|
110
|
+
// not leave a request that cannot be recovered after a crash.
|
|
111
|
+
this._pendingRequests.delete(requestId);
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
reject(error);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
94
116
|
this.emit("request", fullReq);
|
|
95
117
|
});
|
|
96
118
|
}
|
|
@@ -106,6 +128,10 @@ class AgentIPCBus extends EventEmitter {
|
|
|
106
128
|
if (entry.timer) clearTimeout(entry.timer);
|
|
107
129
|
this._pendingRequests.delete(requestId);
|
|
108
130
|
entry.resolve(response);
|
|
131
|
+
try {
|
|
132
|
+
const id = `interaction:${requestId}`;
|
|
133
|
+
this._runtimeProducer?.store.acknowledgeInbox(id, { response });
|
|
134
|
+
} catch {}
|
|
109
135
|
this.emit("request:resolved", { requestId, response });
|
|
110
136
|
return true;
|
|
111
137
|
}
|
|
@@ -326,6 +352,10 @@ class AgentIPCBus extends EventEmitter {
|
|
|
326
352
|
}
|
|
327
353
|
|
|
328
354
|
// Singleton
|
|
329
|
-
const ipcBus = new AgentIPCBus(
|
|
355
|
+
const ipcBus = new AgentIPCBus(
|
|
356
|
+
process.env.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
357
|
+
? { runtimeStore: new EventRuntimeStore() }
|
|
358
|
+
: {},
|
|
359
|
+
);
|
|
330
360
|
export default ipcBus;
|
|
331
361
|
export { AgentIPCBus };
|
package/src/lib/agent-sandbox.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/** OS-isolated shell execution for the coding agent. */
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { proxyEnv } from "./sandbox-egress-proxy.js";
|
|
4
|
+
import executionBroker from "./process-execution-broker/index.js";
|
|
5
5
|
|
|
6
6
|
export const DEFAULT_SANDBOX_IMAGE = "node:22-bookworm-slim";
|
|
7
|
-
export const _deps = {
|
|
7
|
+
export const _deps = {
|
|
8
|
+
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
9
|
+
};
|
|
8
10
|
|
|
9
11
|
function stringList(value) {
|
|
10
12
|
if (!Array.isArray(value)) return [];
|
|
@@ -126,6 +128,10 @@ export function executeSandboxedShell(command, sandbox, options = {}) {
|
|
|
126
128
|
}
|
|
127
129
|
args.push(sandbox.image, "sh", "-lc", String(command || ""));
|
|
128
130
|
const result = _deps.spawnSync("docker", args, {
|
|
131
|
+
origin: "agent-sandbox:docker",
|
|
132
|
+
scope: "sandbox",
|
|
133
|
+
policy: "allow",
|
|
134
|
+
shell: false,
|
|
129
135
|
encoding: "utf8",
|
|
130
136
|
timeout: options.timeout,
|
|
131
137
|
maxBuffer: options.maxBuffer,
|
|
@@ -189,6 +195,10 @@ function executeBubblewrapShell(command, sandbox, options, hostCwd, policy) {
|
|
|
189
195
|
? { ...(options.env || {}), ...proxyEnv(egress.port, "127.0.0.1") }
|
|
190
196
|
: options.env;
|
|
191
197
|
const result = _deps.spawnSync("bwrap", args, {
|
|
198
|
+
origin: "agent-sandbox:bubblewrap",
|
|
199
|
+
scope: "sandbox",
|
|
200
|
+
policy: "allow",
|
|
201
|
+
shell: false,
|
|
192
202
|
cwd: hostCwd,
|
|
193
203
|
env: bwrapEnv,
|
|
194
204
|
encoding: "utf8",
|
|
@@ -244,6 +254,10 @@ export function probeSandboxAvailability(sandbox, deps = _deps) {
|
|
|
244
254
|
? ["bwrap", ["--version"]]
|
|
245
255
|
: ["docker", ["version", "--format", "{{.Server.Version}}"]];
|
|
246
256
|
const result = deps.spawnSync(probeArgs[0], probeArgs[1], {
|
|
257
|
+
origin: "agent-sandbox:probe",
|
|
258
|
+
scope: "sandbox",
|
|
259
|
+
policy: "allow",
|
|
260
|
+
shell: false,
|
|
247
261
|
encoding: "utf8",
|
|
248
262
|
timeout: 10000,
|
|
249
263
|
windowsHide: true,
|
|
@@ -27,6 +27,7 @@ import { isEntryExpired, effectiveFireAt } from "./schedule-planner.js";
|
|
|
27
27
|
import { SUBAGENT_PERMISSION_MODES } from "./subagent-contract.js";
|
|
28
28
|
import { parseGoalCondition } from "./goal-condition-engine.js";
|
|
29
29
|
import { normalizeActionClass } from "./unattended-action-policy.js";
|
|
30
|
+
import { withFileLock } from "./with-file-lock.js";
|
|
30
31
|
|
|
31
32
|
export const SCHEDULE_KINDS = Object.freeze(["wakeup", "cron", "monitor"]);
|
|
32
33
|
|
|
@@ -155,6 +156,10 @@ function isSchedulableStatus(entry) {
|
|
|
155
156
|
: entry.status === "active";
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
function hasLiveExecutionLease(entry, now) {
|
|
160
|
+
return Number(entry.executionLease?.expiresAt) > Number(now);
|
|
161
|
+
}
|
|
162
|
+
|
|
158
163
|
/** Statuses an entry can never leave — safe to prune. */
|
|
159
164
|
export const TERMINAL_STATUSES = Object.freeze([
|
|
160
165
|
"fired",
|
|
@@ -487,6 +492,7 @@ export class AgentScheduleStore {
|
|
|
487
492
|
// (defense-in-depth: retireExpired need not have run first).
|
|
488
493
|
if (isEntryExpired(entry, now)) return false;
|
|
489
494
|
if (!isSchedulableStatus(entry)) return false;
|
|
495
|
+
if (hasLiveExecutionLease(entry, now)) return false;
|
|
490
496
|
// The effective fire time applies the entry's OWN deterministic jitter
|
|
491
497
|
// (`entry.jitterMs`, default 0 → base fire time, byte-identical to the
|
|
492
498
|
// prior `dueAt`/`nextAt` comparison). A jittered entry fires slightly
|
|
@@ -496,6 +502,52 @@ export class AgentScheduleStore {
|
|
|
496
502
|
});
|
|
497
503
|
}
|
|
498
504
|
|
|
505
|
+
/**
|
|
506
|
+
* Atomically claim due entries for one agenda runner. The lease is retained
|
|
507
|
+
* on the durable entry, so a second process cannot fire the same item while
|
|
508
|
+
* the first is working; an abandoned process becomes reclaimable after the
|
|
509
|
+
* lease expires. This is deliberately separate from `due()` for backwards
|
|
510
|
+
* compatibility with read-only callers and injected test stores.
|
|
511
|
+
*/
|
|
512
|
+
claimDue(atMs = null, leaseMs = 120000) {
|
|
513
|
+
const now = atMs != null ? Number(atMs) : this._now();
|
|
514
|
+
const ttl = Math.max(1000, Number(leaseMs) || 120000);
|
|
515
|
+
this._ensureDir();
|
|
516
|
+
return withFileLock(path.join(this.dir, ".agenda-claims"), () => {
|
|
517
|
+
const claimed = [];
|
|
518
|
+
for (const kind of SCHEDULE_KINDS) {
|
|
519
|
+
const entries = this._readAll(kind);
|
|
520
|
+
let changed = false;
|
|
521
|
+
for (const entry of entries) {
|
|
522
|
+
if (!isSchedulableStatus(entry) || isEntryExpired(entry, now)) continue;
|
|
523
|
+
if (hasLiveExecutionLease(entry, now)) continue;
|
|
524
|
+
const fireAt = effectiveFireAt(entry);
|
|
525
|
+
if (fireAt == null || fireAt > now) continue;
|
|
526
|
+
entry.executionLease = {
|
|
527
|
+
owner: `${process.pid}:${randomUUID()}`,
|
|
528
|
+
claimedAt: now,
|
|
529
|
+
expiresAt: now + ttl,
|
|
530
|
+
};
|
|
531
|
+
claimed.push({ ...entry, executionLease: { ...entry.executionLease } });
|
|
532
|
+
changed = true;
|
|
533
|
+
}
|
|
534
|
+
if (changed) this._writeAll(kind, entries);
|
|
535
|
+
}
|
|
536
|
+
return claimed;
|
|
537
|
+
}, { failIfUnavailable: true });
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/** Release a failed/aborted claim so a later runner can retry it. */
|
|
541
|
+
releaseClaim(id) {
|
|
542
|
+
for (const kind of SCHEDULE_KINDS) {
|
|
543
|
+
const updated = this._mutate(kind, id, (entry) => {
|
|
544
|
+
delete entry.executionLease;
|
|
545
|
+
});
|
|
546
|
+
if (updated) return updated;
|
|
547
|
+
}
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
|
|
499
551
|
/**
|
|
500
552
|
* Retire every schedulable entry whose `expiresAt` has passed (status →
|
|
501
553
|
* "expired", stamping `expiredAt`), across all kinds, so it never fires again.
|
|
@@ -632,6 +684,9 @@ export class AgentScheduleStore {
|
|
|
632
684
|
const entry = entries.find((e) => e.id === id);
|
|
633
685
|
if (!entry) return null;
|
|
634
686
|
fn(entry);
|
|
687
|
+
// Every lifecycle mutation settles the claim before the write becomes
|
|
688
|
+
// visible, including a recurring cron/monitor entry that remains active.
|
|
689
|
+
delete entry.executionLease;
|
|
635
690
|
this._writeAll(kind, entries);
|
|
636
691
|
return entry;
|
|
637
692
|
}
|
|
@@ -30,6 +30,110 @@ export const TOOL_TIER = Object.freeze({
|
|
|
30
30
|
EXTENSION: "extension",
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
const ADMISSION_BOOLEAN_FIELDS = Object.freeze([
|
|
34
|
+
"enforce",
|
|
35
|
+
"capabilityGranted",
|
|
36
|
+
"policyAllowed",
|
|
37
|
+
"permissionGranted",
|
|
38
|
+
"budgetOk",
|
|
39
|
+
"uiSupported",
|
|
40
|
+
]);
|
|
41
|
+
const ADMISSION_TEXT_FIELDS = Object.freeze([
|
|
42
|
+
"source",
|
|
43
|
+
"version",
|
|
44
|
+
"scope",
|
|
45
|
+
"tier",
|
|
46
|
+
]);
|
|
47
|
+
const ADMISSION_TEXT_PATTERN = /^[A-Za-z0-9@][A-Za-z0-9_.:/@+-]{0,127}$/;
|
|
48
|
+
const RESERVED_TOOL_NAMES = new Set(["__proto__", "prototype", "constructor"]);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parse the IDE-to-CLI CC_TOOL_ADMISSION envelope. Only decision/provenance
|
|
52
|
+
* fields are accepted; arguments, prompts and credentials have no place in
|
|
53
|
+
* this contract. Invalid input throws so a host that opted into enforcement
|
|
54
|
+
* cannot silently fall back to an ungoverned session.
|
|
55
|
+
*/
|
|
56
|
+
export function parseToolAdmissionConfig(input) {
|
|
57
|
+
if (input == null || input === "") return null;
|
|
58
|
+
let raw;
|
|
59
|
+
try {
|
|
60
|
+
raw = typeof input === "string" ? input : JSON.stringify(input);
|
|
61
|
+
} catch {
|
|
62
|
+
throw new Error("tool admission config is not valid JSON");
|
|
63
|
+
}
|
|
64
|
+
if (typeof raw !== "string") {
|
|
65
|
+
throw new Error("tool admission config must be an object");
|
|
66
|
+
}
|
|
67
|
+
if (Buffer.byteLength(raw, "utf8") > 32768) {
|
|
68
|
+
throw new Error("tool admission config exceeds 32 KiB");
|
|
69
|
+
}
|
|
70
|
+
let value;
|
|
71
|
+
try {
|
|
72
|
+
value = typeof input === "string" ? JSON.parse(input) : input;
|
|
73
|
+
} catch {
|
|
74
|
+
throw new Error("tool admission config is not valid JSON");
|
|
75
|
+
}
|
|
76
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
77
|
+
throw new Error("tool admission config must be an object");
|
|
78
|
+
}
|
|
79
|
+
if (value.enforce !== true) {
|
|
80
|
+
throw new Error("tool admission config must set enforce=true");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const sanitize = (entry, label) => {
|
|
84
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
85
|
+
throw new Error(`${label} must be an object`);
|
|
86
|
+
}
|
|
87
|
+
const out = {};
|
|
88
|
+
for (const field of ADMISSION_BOOLEAN_FIELDS) {
|
|
89
|
+
if (entry[field] !== undefined) {
|
|
90
|
+
if (typeof entry[field] !== "boolean") {
|
|
91
|
+
throw new Error(`${label}.${field} must be boolean`);
|
|
92
|
+
}
|
|
93
|
+
out[field] = entry[field];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (const field of ADMISSION_TEXT_FIELDS) {
|
|
97
|
+
if (entry[field] !== undefined) {
|
|
98
|
+
if (
|
|
99
|
+
typeof entry[field] !== "string" ||
|
|
100
|
+
!ADMISSION_TEXT_PATTERN.test(entry[field])
|
|
101
|
+
) {
|
|
102
|
+
throw new Error(`${label}.${field} must be a safe identifier`);
|
|
103
|
+
}
|
|
104
|
+
out[field] = entry[field];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const config = sanitize(value, "toolAdmission");
|
|
111
|
+
config.enforce = true;
|
|
112
|
+
if (value.tools !== undefined) {
|
|
113
|
+
if (
|
|
114
|
+
!value.tools ||
|
|
115
|
+
typeof value.tools !== "object" ||
|
|
116
|
+
Array.isArray(value.tools)
|
|
117
|
+
) {
|
|
118
|
+
throw new Error("toolAdmission.tools must be an object");
|
|
119
|
+
}
|
|
120
|
+
const entries = Object.entries(value.tools);
|
|
121
|
+
if (entries.length > 256)
|
|
122
|
+
throw new Error("toolAdmission.tools exceeds 256 entries");
|
|
123
|
+
config.tools = {};
|
|
124
|
+
for (const [name, entry] of entries) {
|
|
125
|
+
if (
|
|
126
|
+
!/^[A-Za-z0-9_.:-]{1,160}$/.test(name) ||
|
|
127
|
+
RESERVED_TOOL_NAMES.has(name)
|
|
128
|
+
) {
|
|
129
|
+
throw new Error(`invalid tool admission name: ${name}`);
|
|
130
|
+
}
|
|
131
|
+
config.tools[name] = sanitize(entry, `toolAdmission.tools.${name}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return config;
|
|
135
|
+
}
|
|
136
|
+
|
|
33
137
|
/** Normalize a tier label; anything unrecognized → EXTENSION (fail-closed). */
|
|
34
138
|
export function normalizeToolTier(value) {
|
|
35
139
|
const s = String(value || "")
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* rule). Cached per process (5 min) so multi-call runs don't re-spawn it.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
18
18
|
|
|
19
19
|
const TTL_MS = 5 * 60 * 1000;
|
|
20
20
|
const _cache = new Map(); // helper command → { key, at }
|
|
@@ -31,7 +31,15 @@ export function resolveApiKeyFromHelper(helperCmd, opts = {}) {
|
|
|
31
31
|
const now = opts.now || Date.now;
|
|
32
32
|
const hit = _cache.get(cmd);
|
|
33
33
|
if (hit && now() - hit.at < TTL_MS) return hit.key;
|
|
34
|
-
const exec =
|
|
34
|
+
const exec =
|
|
35
|
+
opts.exec ||
|
|
36
|
+
((command, options) =>
|
|
37
|
+
executionBroker.execSync(command, {
|
|
38
|
+
...options,
|
|
39
|
+
origin: "credential:api-key-helper",
|
|
40
|
+
policy: "allow",
|
|
41
|
+
scope: "credential",
|
|
42
|
+
}));
|
|
35
43
|
try {
|
|
36
44
|
const out = exec(cmd, {
|
|
37
45
|
encoding: "utf-8",
|
|
@@ -128,11 +128,23 @@ class AsyncHookSupervisor {
|
|
|
128
128
|
if (process.platform === "win32") {
|
|
129
129
|
const r = this._deps.spawnSync(
|
|
130
130
|
"taskkill",
|
|
131
|
-
["/
|
|
131
|
+
["/PID", String(pid), "/T", "/F"],
|
|
132
132
|
{ windowsHide: true },
|
|
133
133
|
);
|
|
134
|
+
// A shell can publish a just-created descendant between the first
|
|
135
|
+
// tree snapshot and termination. Repeat once so that race cannot
|
|
136
|
+
// leave a short-lived hook grandchild orphaned.
|
|
137
|
+
if (!r?.error && r?.status === 0) {
|
|
138
|
+
this._deps.spawnSync(
|
|
139
|
+
"taskkill",
|
|
140
|
+
["/PID", String(pid), "/T", "/F"],
|
|
141
|
+
{ windowsHide: true },
|
|
142
|
+
);
|
|
143
|
+
}
|
|
134
144
|
// If taskkill couldn't launch, fall back to a direct kill.
|
|
135
|
-
if (r && r.error
|
|
145
|
+
if (r && (r.error || (r.status != null && r.status !== 0))) {
|
|
146
|
+
child.kill(signal);
|
|
147
|
+
}
|
|
136
148
|
} else {
|
|
137
149
|
// Negative pid → the whole process group (requires the detached spawn).
|
|
138
150
|
try {
|
|
@@ -239,7 +251,7 @@ class AsyncHookSupervisor {
|
|
|
239
251
|
|
|
240
252
|
let child;
|
|
241
253
|
try {
|
|
242
|
-
|
|
254
|
+
const spawnOptions = {
|
|
243
255
|
cwd: opts.cwd || process.cwd(),
|
|
244
256
|
shell: true,
|
|
245
257
|
// POSIX: own process group so a timeout / stopAll can signal the whole
|
|
@@ -250,7 +262,17 @@ class AsyncHookSupervisor {
|
|
|
250
262
|
...process.env,
|
|
251
263
|
CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
|
|
252
264
|
},
|
|
253
|
-
}
|
|
265
|
+
};
|
|
266
|
+
child = opts.broker && hook.origin === "plugin:hook"
|
|
267
|
+
? opts.broker.spawn(hook.command, [], {
|
|
268
|
+
...spawnOptions,
|
|
269
|
+
origin: hook.origin,
|
|
270
|
+
policy: "allow",
|
|
271
|
+
pluginId: hook.pluginId || null,
|
|
272
|
+
pluginVersion: hook.pluginVersion || null,
|
|
273
|
+
pluginSource: hook.pluginSource || null,
|
|
274
|
+
})
|
|
275
|
+
: this._deps.spawn(hook.command, spawnOptions);
|
|
254
276
|
} catch (err) {
|
|
255
277
|
this._record(hook, {
|
|
256
278
|
ok: false,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* background-interaction-resolver — 监听 agent 子进程发来的交互请求,
|
|
3
|
+
* 转发给后台会话 transport 并通过 pendingInteractions 追踪回复。
|
|
4
|
+
*
|
|
5
|
+
* 当 agent 调用 onPrompt/onApprove 等需要用户交互的方法时,子进程通过 IPC
|
|
6
|
+
* 发送 { type: "interaction-request", intId, requestType, prompt, options } 消息。
|
|
7
|
+
* 本模块监听这些消息,加入本地 pending map,并广播给所有 attach 客户端。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const INTERACTION_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟超时
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 挂载交互请求监听到 agent 子进程。
|
|
14
|
+
*
|
|
15
|
+
* @param {import('node:child_process').ChildProcess} child - agent 子进程实例
|
|
16
|
+
* @param {Map<string, { resolve: Function, reject: Function, timer: NodeJS.Timeout }>} pendingInteractions - 待处理交互映射
|
|
17
|
+
* @param {Function} broadcast - 广播消息给所有 attach 客户端的函数
|
|
18
|
+
* @returns {Function} 卸载函数,调用后停止监听
|
|
19
|
+
*/
|
|
20
|
+
export function attachInteractionRequestHandler(
|
|
21
|
+
child,
|
|
22
|
+
pendingInteractions,
|
|
23
|
+
broadcast,
|
|
24
|
+
) {
|
|
25
|
+
if (!child) {
|
|
26
|
+
return () => {};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const handler = (message) => {
|
|
30
|
+
if (!message || typeof message !== "object") return;
|
|
31
|
+
if (message.type !== "interaction-request") return;
|
|
32
|
+
|
|
33
|
+
const { intId, requestType, prompt, options = {} } = message;
|
|
34
|
+
if (!intId) return;
|
|
35
|
+
|
|
36
|
+
// 加入 pending 映射,设置超时
|
|
37
|
+
const timer = setTimeout(() => {
|
|
38
|
+
const entry = pendingInteractions.get(intId);
|
|
39
|
+
if (!entry) return;
|
|
40
|
+
pendingInteractions.delete(intId);
|
|
41
|
+
// 超时返回默认值:confirm 返回 false,其他返回 null
|
|
42
|
+
const defaultAnswer = requestType === "confirm" ? false : null;
|
|
43
|
+
entry.resolve(defaultAnswer);
|
|
44
|
+
broadcast?.({
|
|
45
|
+
type: "interaction-timeout",
|
|
46
|
+
intId,
|
|
47
|
+
});
|
|
48
|
+
}, INTERACTION_TIMEOUT_MS);
|
|
49
|
+
// 不保持事件循环存活
|
|
50
|
+
timer.unref?.();
|
|
51
|
+
|
|
52
|
+
// 这里不存 resolve/reject — 调用方 (worker) 已经在 agentAskUser 中存了
|
|
53
|
+
// 我们只负责广播给 attach 客户端
|
|
54
|
+
// 但为了超时能触发 worker 的 resolve,需要把 entry 透传?不,worker 自己存 entry
|
|
55
|
+
// 只需要广播消息即可
|
|
56
|
+
broadcast?.({
|
|
57
|
+
type: "interaction_request",
|
|
58
|
+
intId,
|
|
59
|
+
requestType,
|
|
60
|
+
prompt,
|
|
61
|
+
options,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
child.on("message", handler);
|
|
66
|
+
|
|
67
|
+
// 返回卸载函数
|
|
68
|
+
return () => {
|
|
69
|
+
child.off("message", handler);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* Protocol (one JSON object per line, both directions):
|
|
17
17
|
* client → worker: {type:"hello", token} · {type:"prompt", text}
|
|
18
18
|
* · {type:"status"} · {type:"stop"} · {type:"detach"}
|
|
19
|
+
* · {type:"interaction_response", requestId, result, error?}
|
|
19
20
|
* worker → client: {type:"hello", ...status} · {type:"accepted", queued}
|
|
20
21
|
* · {type:"status", ...status} · {type:"error", message}
|
|
21
22
|
* · {type:"turn-started"|"turn-ended"|"idle", ...}
|
|
23
|
+
* · {type:"interaction_request", requestId, payload}
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
import net from "node:net";
|
|
@@ -85,13 +87,24 @@ function writeMessage(socket, message) {
|
|
|
85
87
|
* @param {(text:string)=>{queued:number}} opts.onPrompt queue a follow-up
|
|
86
88
|
* prompt; throw to reject (message is relayed to the client)
|
|
87
89
|
* @param {()=>void} [opts.onStop] kill the current agent turn
|
|
90
|
+
* @param {(requestId:string, result:any, error?:string)=>void} [opts.onInteractionResponse]
|
|
91
|
+
* handle a user's response to a pending interaction request
|
|
88
92
|
* @param {(count:number)=>void} [opts.onClientChange]
|
|
89
93
|
* @param {()=>object} [opts.getStatus] session status payload for hello/status
|
|
90
94
|
* @returns {Promise<{pipePath:string, clientCount:()=>number,
|
|
91
95
|
* broadcast:(msg:object)=>void, close:()=>Promise<void>}>}
|
|
92
96
|
*/
|
|
93
97
|
export function startBackgroundSessionServer(opts) {
|
|
94
|
-
const {
|
|
98
|
+
const {
|
|
99
|
+
id,
|
|
100
|
+
dir,
|
|
101
|
+
token,
|
|
102
|
+
onPrompt,
|
|
103
|
+
onStop,
|
|
104
|
+
onInteractionResponse,
|
|
105
|
+
onClientChange,
|
|
106
|
+
getStatus,
|
|
107
|
+
} = opts;
|
|
95
108
|
const pipePath = opts.pipePath || transportPipePath(id, dir);
|
|
96
109
|
if (process.platform !== "win32") {
|
|
97
110
|
try {
|
|
@@ -182,6 +195,36 @@ export function startBackgroundSessionServer(opts) {
|
|
|
182
195
|
socket.end();
|
|
183
196
|
return;
|
|
184
197
|
}
|
|
198
|
+
case "interaction_response": {
|
|
199
|
+
try {
|
|
200
|
+
// Support both field names: requestId (client) and intId (wire legacy)
|
|
201
|
+
const { requestId, intId, answer, result, error } = message;
|
|
202
|
+
const resolvedId = requestId || intId;
|
|
203
|
+
if (!resolvedId) {
|
|
204
|
+
writeMessage(socket, {
|
|
205
|
+
type: "error",
|
|
206
|
+
message: "interaction_response requires requestId or intId",
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Single-object callback matching worker expectation: { requestId, answer, error }
|
|
211
|
+
onInteractionResponse?.({
|
|
212
|
+
requestId: resolvedId,
|
|
213
|
+
answer: answer ?? result,
|
|
214
|
+
error,
|
|
215
|
+
});
|
|
216
|
+
writeMessage(socket, {
|
|
217
|
+
type: "received",
|
|
218
|
+
requestId: resolvedId,
|
|
219
|
+
});
|
|
220
|
+
} catch (err) {
|
|
221
|
+
writeMessage(socket, {
|
|
222
|
+
type: "error",
|
|
223
|
+
message: err?.message || String(err),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
185
228
|
default:
|
|
186
229
|
writeMessage(socket, {
|
|
187
230
|
type: "error",
|
|
@@ -218,6 +261,21 @@ export function startBackgroundSessionServer(opts) {
|
|
|
218
261
|
broadcast: (message) => {
|
|
219
262
|
for (const socket of clients) writeMessage(socket, message);
|
|
220
263
|
},
|
|
264
|
+
broadcastInteractionRequest: (intId, payload) => {
|
|
265
|
+
for (const socket of clients)
|
|
266
|
+
writeMessage(socket, {
|
|
267
|
+
type: "interaction_request",
|
|
268
|
+
intId,
|
|
269
|
+
requestId: intId,
|
|
270
|
+
question:
|
|
271
|
+
payload.question || payload.prompt || "Agent needs your input",
|
|
272
|
+
prompt: payload.question || payload.prompt || "",
|
|
273
|
+
hint: payload.hint || "",
|
|
274
|
+
options: payload.options || null,
|
|
275
|
+
multiSelect: payload.multiSelect || false,
|
|
276
|
+
defaultValue: payload.defaultValue,
|
|
277
|
+
});
|
|
278
|
+
},
|
|
221
279
|
close: () =>
|
|
222
280
|
new Promise((done) => {
|
|
223
281
|
for (const socket of clients) socket.destroy();
|
package/src/lib/changelog.js
CHANGED
|
@@ -225,24 +225,32 @@ function extractCliSections(bodyLines, header) {
|
|
|
225
225
|
*
|
|
226
226
|
* @returns {{ source: string, releases: Array }}
|
|
227
227
|
*/
|
|
228
|
-
export function loadChangelog(
|
|
228
|
+
export function loadChangelog({
|
|
229
|
+
fsApi = fs,
|
|
230
|
+
pathApi = path,
|
|
231
|
+
dirname = __dirname,
|
|
232
|
+
} = {}) {
|
|
229
233
|
const changelogCandidates = [
|
|
230
|
-
|
|
231
|
-
|
|
234
|
+
pathApi.join(dirname, "..", "..", "CHANGELOG.md"), // packages/cli/CHANGELOG.md
|
|
235
|
+
pathApi.join(dirname, "..", "..", "..", "..", "CHANGELOG.md"), // repo root
|
|
232
236
|
];
|
|
233
237
|
for (const p of changelogCandidates) {
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
238
|
+
if (fsApi.existsSync(p)) {
|
|
239
|
+
const releases = parseChangelog(fsApi.readFileSync(p, "utf-8"));
|
|
240
|
+
// A parent-level CHANGELOG can exist in a global Node.js installation
|
|
241
|
+
// (for example C:\\nvm4w\\nodejs\\CHANGELOG.md). Do not treat an
|
|
242
|
+
// unrelated, successfully-read file with zero CLI releases as the
|
|
243
|
+
// authoritative source; continue to the bundled artifact instead.
|
|
244
|
+
if (releases.length > 0) {
|
|
245
|
+
return { source: "CHANGELOG.md", releases };
|
|
246
|
+
}
|
|
239
247
|
}
|
|
240
248
|
}
|
|
241
249
|
// Installed npm package: CHANGELOG.md isn't shipped, use the bundled artifact.
|
|
242
|
-
const jsonPath =
|
|
243
|
-
if (
|
|
250
|
+
const jsonPath = pathApi.join(dirname, "..", "data", "changelog.json");
|
|
251
|
+
if (fsApi.existsSync(jsonPath)) {
|
|
244
252
|
try {
|
|
245
|
-
const data = JSON.parse(
|
|
253
|
+
const data = JSON.parse(fsApi.readFileSync(jsonPath, "utf-8"));
|
|
246
254
|
if (Array.isArray(data.releases)) return data;
|
|
247
255
|
} catch {
|
|
248
256
|
/* fall through to empty */
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
canApprove,
|
|
21
21
|
describeAuthorityChain,
|
|
22
22
|
} from "../agent-authority.js";
|
|
23
|
+
import { EventRuntimeStore } from "../event-runtime-store.js";
|
|
23
24
|
|
|
24
25
|
export const CHANNEL_KINDS = ["webhook", "telegram"];
|
|
25
26
|
|
|
@@ -120,6 +121,9 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
120
121
|
const config = opts.config || {};
|
|
121
122
|
const log = opts.log || ((msg) => logger.info(msg));
|
|
122
123
|
const deps = opts.deps || {};
|
|
124
|
+
const eventRuntimeStore =
|
|
125
|
+
opts.eventRuntimeStore ||
|
|
126
|
+
(process.env.CC_EVENT_RUNTIME_DURABLE === "1" ? new EventRuntimeStore() : null);
|
|
123
127
|
// Every inbound event is stamped with its channel authority (`steer`, never
|
|
124
128
|
// `approve`) before the caller's handler sees it — so a channel message can
|
|
125
129
|
// never be mistaken for a user approval no matter what it contains.
|
|
@@ -149,6 +153,7 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
149
153
|
port: spec.arg ? Number(spec.arg) : cfg.port,
|
|
150
154
|
onEvent,
|
|
151
155
|
log,
|
|
156
|
+
eventRuntimeStore,
|
|
152
157
|
});
|
|
153
158
|
started.push({ kind: "webhook", describe: handle.describe, ...handle });
|
|
154
159
|
} else if (spec.kind === "telegram") {
|
|
@@ -161,6 +166,7 @@ export async function startChannels(specsInput, opts = {}) {
|
|
|
161
166
|
...cfg,
|
|
162
167
|
onEvent,
|
|
163
168
|
log,
|
|
169
|
+
eventRuntimeStore,
|
|
164
170
|
});
|
|
165
171
|
started.push({
|
|
166
172
|
kind: "telegram",
|