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
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",
|
|
@@ -251,7 +251,7 @@ class AsyncHookSupervisor {
|
|
|
251
251
|
|
|
252
252
|
let child;
|
|
253
253
|
try {
|
|
254
|
-
|
|
254
|
+
const spawnOptions = {
|
|
255
255
|
cwd: opts.cwd || process.cwd(),
|
|
256
256
|
shell: true,
|
|
257
257
|
// POSIX: own process group so a timeout / stopAll can signal the whole
|
|
@@ -262,7 +262,17 @@ class AsyncHookSupervisor {
|
|
|
262
262
|
...process.env,
|
|
263
263
|
CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
|
|
264
264
|
},
|
|
265
|
-
}
|
|
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);
|
|
266
276
|
} catch (err) {
|
|
267
277
|
this._record(hook, {
|
|
268
278
|
ok: false,
|
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",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const POLL_TIMEOUT_S = 25;
|
|
15
15
|
const ERROR_BACKOFF_MS = 5000;
|
|
16
|
+
import { EventRuntimeProducer } from "../event-runtime-producer.js";
|
|
16
17
|
|
|
17
18
|
export async function startTelegramChannel(options = {}) {
|
|
18
19
|
const {
|
|
@@ -27,7 +28,11 @@ export async function startTelegramChannel(options = {}) {
|
|
|
27
28
|
// failures) can never turn the loop into a microtask chain that starves
|
|
28
29
|
// the event loop (timers, stop()) entirely.
|
|
29
30
|
pollPauseMs = 50,
|
|
31
|
+
eventRuntimeStore = null,
|
|
30
32
|
} = options;
|
|
33
|
+
const runtimeProducer = eventRuntimeStore
|
|
34
|
+
? new EventRuntimeProducer({ store: eventRuntimeStore })
|
|
35
|
+
: null;
|
|
31
36
|
|
|
32
37
|
if (!botToken) {
|
|
33
38
|
throw new Error(
|
|
@@ -65,12 +70,17 @@ export async function startTelegramChannel(options = {}) {
|
|
|
65
70
|
if (!chatId || !text) continue;
|
|
66
71
|
if (!allowed.has(String(chatId))) continue; // fail closed
|
|
67
72
|
try {
|
|
68
|
-
|
|
73
|
+
const event = {
|
|
69
74
|
channel: "telegram",
|
|
70
75
|
sender: String(chatId),
|
|
71
76
|
text,
|
|
72
77
|
meta: { updateId: update.update_id },
|
|
78
|
+
};
|
|
79
|
+
runtimeProducer?.publish(event, {
|
|
80
|
+
origin: "telegram",
|
|
81
|
+
id: `telegram:${update.update_id}`,
|
|
73
82
|
});
|
|
83
|
+
onEvent?.(event);
|
|
74
84
|
} catch {
|
|
75
85
|
/* downstream owns its failures */
|
|
76
86
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { createServer } from "node:http";
|
|
19
19
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
20
|
+
import { EventRuntimeProducer } from "../event-runtime-producer.js";
|
|
20
21
|
|
|
21
22
|
const MAX_BODY_BYTES = 64 * 1024;
|
|
22
23
|
|
|
@@ -34,7 +35,11 @@ export async function startWebhookChannel(options = {}) {
|
|
|
34
35
|
allowlist,
|
|
35
36
|
onEvent,
|
|
36
37
|
log = () => {},
|
|
38
|
+
eventRuntimeStore = null,
|
|
37
39
|
} = options;
|
|
40
|
+
const runtimeProducer = eventRuntimeStore
|
|
41
|
+
? new EventRuntimeProducer({ store: eventRuntimeStore })
|
|
42
|
+
: null;
|
|
38
43
|
|
|
39
44
|
const isLoopback =
|
|
40
45
|
host === "127.0.0.1" || host === "::1" || host === "localhost";
|
|
@@ -92,8 +97,7 @@ export async function startWebhookChannel(options = {}) {
|
|
|
92
97
|
return respond(403, { error: "sender not in allowlist" });
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
|
-
|
|
96
|
-
onEvent?.({
|
|
100
|
+
const event = {
|
|
97
101
|
channel: "webhook",
|
|
98
102
|
sender,
|
|
99
103
|
text,
|
|
@@ -101,9 +105,17 @@ export async function startWebhookChannel(options = {}) {
|
|
|
101
105
|
payload.meta && typeof payload.meta === "object"
|
|
102
106
|
? payload.meta
|
|
103
107
|
: undefined,
|
|
108
|
+
};
|
|
109
|
+
try {
|
|
110
|
+
runtimeProducer?.publish(event, {
|
|
111
|
+
origin: "webhook",
|
|
112
|
+
id: payload.event_id || payload.eventId || null,
|
|
104
113
|
});
|
|
114
|
+
onEvent?.(event);
|
|
105
115
|
} catch {
|
|
106
|
-
|
|
116
|
+
// A configured durable runtime is the recovery boundary. Refuse the
|
|
117
|
+
// request rather than acknowledging an event that was not persisted.
|
|
118
|
+
if (runtimeProducer) return respond(503, { error: "event persistence unavailable" });
|
|
107
119
|
}
|
|
108
120
|
respond(202, { ok: true });
|
|
109
121
|
});
|
|
@@ -18,9 +18,13 @@
|
|
|
18
18
|
* is. When it is not, callers should fall back / report unavailable.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { spawnSync } from "node:child_process";
|
|
22
21
|
import { rmSync } from "node:fs";
|
|
23
22
|
import path from "node:path";
|
|
23
|
+
import executionBroker from "./process-execution-broker/index.js";
|
|
24
|
+
|
|
25
|
+
export const _deps = {
|
|
26
|
+
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
27
|
+
};
|
|
24
28
|
|
|
25
29
|
const REF_NS = "refs/cc-checkpoints";
|
|
26
30
|
// Deterministic identity for shadow commits so `git commit-tree` never trips on
|
|
@@ -41,7 +45,11 @@ const CHECKPOINT_IDENTITY = Object.freeze({
|
|
|
41
45
|
* @throws {Error} with git's stderr when the command fails
|
|
42
46
|
*/
|
|
43
47
|
function git(args, { cwd, env, input } = {}) {
|
|
44
|
-
const res = spawnSync("git", args, {
|
|
48
|
+
const res = _deps.spawnSync("git", args, {
|
|
49
|
+
origin: "checkpoint:git",
|
|
50
|
+
scope: "checkpoint",
|
|
51
|
+
policy: "allow",
|
|
52
|
+
shell: false,
|
|
45
53
|
cwd,
|
|
46
54
|
input,
|
|
47
55
|
encoding: "utf-8",
|
package/src/lib/cloud/bundle.js
CHANGED
|
@@ -7,13 +7,23 @@
|
|
|
7
7
|
* a repo.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { execFileSync } from "node:child_process";
|
|
11
10
|
import { writeFileSync, mkdtempSync } from "node:fs";
|
|
12
11
|
import { readFileSync, rmSync } from "node:fs";
|
|
13
12
|
import { join } from "node:path";
|
|
14
13
|
import { tmpdir } from "node:os";
|
|
14
|
+
import { executionBroker } from "../process-execution-broker/index.js";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
function brokerExecFileSync(file, args, options) {
|
|
17
|
+
return executionBroker.execFileSync(file, args, {
|
|
18
|
+
...options,
|
|
19
|
+
origin: "cloud:git",
|
|
20
|
+
policy: "allow",
|
|
21
|
+
scope: "cloud",
|
|
22
|
+
shell: false,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const _deps = { execFileSync: brokerExecFileSync };
|
|
17
27
|
|
|
18
28
|
function git(args, cwd, deps = _deps) {
|
|
19
29
|
return deps
|
package/src/lib/code-review.js
CHANGED
|
@@ -4,8 +4,37 @@
|
|
|
4
4
|
* @module lib/code-review
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { execSync } from "child_process";
|
|
8
7
|
import { logger } from "./logger.js";
|
|
8
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
9
|
+
|
|
10
|
+
export const _deps = {
|
|
11
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function buildGitDiffArgs(
|
|
15
|
+
target = "--staged",
|
|
16
|
+
{ nameOnly = false } = {},
|
|
17
|
+
) {
|
|
18
|
+
const args = ["diff"];
|
|
19
|
+
if (nameOnly) args.push("--name-only");
|
|
20
|
+
if (target === "--staged" || target === "--cached") {
|
|
21
|
+
args.push(target);
|
|
22
|
+
} else {
|
|
23
|
+
args.push("--end-of-options", String(target), "--");
|
|
24
|
+
}
|
|
25
|
+
return args;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function gitDiff(target, options = {}) {
|
|
29
|
+
return _deps.execFileSync("git", buildGitDiffArgs(target, options), {
|
|
30
|
+
encoding: "utf8",
|
|
31
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
32
|
+
origin: "review:git-diff",
|
|
33
|
+
policy: "allow",
|
|
34
|
+
scope: "review",
|
|
35
|
+
shell: false,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
9
38
|
|
|
10
39
|
/**
|
|
11
40
|
* Get git diff for review
|
|
@@ -14,10 +43,7 @@ import { logger } from "./logger.js";
|
|
|
14
43
|
*/
|
|
15
44
|
export function getGitDiff(target = "--staged") {
|
|
16
45
|
try {
|
|
17
|
-
return
|
|
18
|
-
encoding: "utf8",
|
|
19
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
20
|
-
});
|
|
46
|
+
return gitDiff(target);
|
|
21
47
|
} catch (err) {
|
|
22
48
|
logger.error(`Failed to get git diff: ${err.message}`);
|
|
23
49
|
return "";
|
|
@@ -31,9 +57,7 @@ export function getGitDiff(target = "--staged") {
|
|
|
31
57
|
*/
|
|
32
58
|
export function getChangedFiles(target = "--staged") {
|
|
33
59
|
try {
|
|
34
|
-
const output =
|
|
35
|
-
encoding: "utf8",
|
|
36
|
-
});
|
|
60
|
+
const output = gitDiff(target, { nameOnly: true });
|
|
37
61
|
return output.trim().split("\n").filter(Boolean);
|
|
38
62
|
} catch (err) {
|
|
39
63
|
logger.error(`Failed to get changed files: ${err.message}`);
|