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
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small OS-backed secret store used by plugin options and other user-scoped
|
|
3
|
+
* credentials. Secrets never fall back to plaintext JSON:
|
|
4
|
+
* - Windows: DPAPI (CurrentUser) encrypted blobs in the user data dir
|
|
5
|
+
* - macOS: Keychain via `security`
|
|
6
|
+
* - Linux: Secret Service via `secret-tool`
|
|
7
|
+
*
|
|
8
|
+
* The command runner is injectable so the protocol is deterministic in unit
|
|
9
|
+
* tests and so callers can route it through ProcessExecutionBroker.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import crypto from "node:crypto";
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { getElectronUserDataDir } from "./paths.js";
|
|
17
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
18
|
+
|
|
19
|
+
const DPAPI_SCRIPT = [
|
|
20
|
+
"$ErrorActionPreference='Stop'",
|
|
21
|
+
"Add-Type -AssemblyName System.Security",
|
|
22
|
+
"$raw=[Console]::In.ReadToEnd()",
|
|
23
|
+
"$b=[Convert]::FromBase64String($raw)",
|
|
24
|
+
"$p=[Security.Cryptography.ProtectedData]::Protect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser)",
|
|
25
|
+
"[Console]::Write([Convert]::ToBase64String($p))",
|
|
26
|
+
].join("; ");
|
|
27
|
+
|
|
28
|
+
const DPAPI_UNPROTECT_SCRIPT = [
|
|
29
|
+
"$ErrorActionPreference='Stop'",
|
|
30
|
+
"Add-Type -AssemblyName System.Security",
|
|
31
|
+
"$raw=[Console]::In.ReadToEnd()",
|
|
32
|
+
"$b=[Convert]::FromBase64String($raw)",
|
|
33
|
+
"$p=[Security.Cryptography.ProtectedData]::Unprotect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser)",
|
|
34
|
+
"[Console]::Write([Convert]::ToBase64String($p))",
|
|
35
|
+
].join("; ");
|
|
36
|
+
|
|
37
|
+
function defaultRunner(file, args, input = undefined) {
|
|
38
|
+
const result = executionBroker.spawnSync(file, args, {
|
|
39
|
+
origin: "secret-store",
|
|
40
|
+
policy: "allow",
|
|
41
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
windowsHide: true,
|
|
44
|
+
...(input !== undefined ? { input } : {}),
|
|
45
|
+
});
|
|
46
|
+
if (result.status !== 0) {
|
|
47
|
+
throw new Error(String(result.stderr || "secret store command failed").trim());
|
|
48
|
+
}
|
|
49
|
+
return String(result.stdout || "").trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function safeToken(value) {
|
|
53
|
+
return crypto
|
|
54
|
+
.createHash("sha256")
|
|
55
|
+
.update(String(value || ""))
|
|
56
|
+
.digest("hex")
|
|
57
|
+
.slice(0, 32);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function chooseBackend(platform = process.platform) {
|
|
61
|
+
if (platform === "win32") return "dpapi";
|
|
62
|
+
if (platform === "darwin") return "keychain";
|
|
63
|
+
if (platform === "linux" || platform === "freebsd") return "secret-service";
|
|
64
|
+
return "unavailable";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function readJson(file, readFile = fs.readFileSync) {
|
|
68
|
+
try {
|
|
69
|
+
const value = JSON.parse(readFile(file, "utf8"));
|
|
70
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
71
|
+
? value
|
|
72
|
+
: {};
|
|
73
|
+
} catch {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function writeJson(file, value, deps = {}) {
|
|
79
|
+
const mkdirSync = deps.mkdirSync || fs.mkdirSync;
|
|
80
|
+
const writeFileSync = deps.writeFileSync || fs.writeFileSync;
|
|
81
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
82
|
+
writeFileSync(file, JSON.stringify(value, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
83
|
+
try { fs.chmodSync(file, 0o600); } catch {}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function createDpapiBackend({ file, runner, readFile, writeFile, mkdirSync } = {}) {
|
|
87
|
+
const storeFile = file || path.join(getElectronUserDataDir(), "plugin-secrets.dpapi.json");
|
|
88
|
+
const load = () => readJson(storeFile, readFile);
|
|
89
|
+
const save = (v) => writeJson(storeFile, v, { writeFileSync: writeFile, mkdirSync });
|
|
90
|
+
return {
|
|
91
|
+
name: "dpapi",
|
|
92
|
+
set(key, value) {
|
|
93
|
+
const payload = Buffer.from(String(value), "utf8").toString("base64");
|
|
94
|
+
const encoded = runner("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", DPAPI_SCRIPT], payload);
|
|
95
|
+
const data = load(); data[key] = encoded; save(data);
|
|
96
|
+
},
|
|
97
|
+
get(key) {
|
|
98
|
+
const encoded = load()[key];
|
|
99
|
+
if (!encoded) return null;
|
|
100
|
+
const plain = runner("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", DPAPI_UNPROTECT_SCRIPT], encoded);
|
|
101
|
+
return Buffer.from(plain, "base64").toString("utf8");
|
|
102
|
+
},
|
|
103
|
+
delete(key) {
|
|
104
|
+
const data = load();
|
|
105
|
+
if (!Object.prototype.hasOwnProperty.call(data, key)) return false;
|
|
106
|
+
delete data[key]; save(data); return true;
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function createKeychainBackend({ service, runner } = {}) {
|
|
112
|
+
const name = service || "com.chainlesschain.plugin";
|
|
113
|
+
return {
|
|
114
|
+
name: "keychain",
|
|
115
|
+
set(key, value) {
|
|
116
|
+
runner("security", ["add-generic-password", "-a", key, "-s", name, "-w", String(value), "-U"]);
|
|
117
|
+
},
|
|
118
|
+
get(key) {
|
|
119
|
+
try { return runner("security", ["find-generic-password", "-a", key, "-s", name, "-w"]) || null; } catch { return null; }
|
|
120
|
+
},
|
|
121
|
+
delete(key) {
|
|
122
|
+
try { runner("security", ["delete-generic-password", "-a", key, "-s", name]); return true; } catch { return false; }
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function createSecretServiceBackend({ service, runner } = {}) {
|
|
128
|
+
const name = service || "chainlesschain-plugin";
|
|
129
|
+
return {
|
|
130
|
+
name: "secret-service",
|
|
131
|
+
set(key, value) {
|
|
132
|
+
runner("secret-tool", ["store", "--label", `${name}:${key}`, "service", name, "account", key], String(value));
|
|
133
|
+
},
|
|
134
|
+
get(key) {
|
|
135
|
+
try { return runner("secret-tool", ["lookup", "service", name, "account", key]) || null; } catch { return null; }
|
|
136
|
+
},
|
|
137
|
+
delete(key) {
|
|
138
|
+
try { runner("secret-tool", ["clear", "service", name, "account", key]); return true; } catch { return false; }
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Create a fail-closed secret store. `memory` is intended for tests only. */
|
|
144
|
+
export function createSecretStore(options = {}) {
|
|
145
|
+
const backend = options.backend || chooseBackend(options.platform);
|
|
146
|
+
const runner = options.runner || defaultRunner;
|
|
147
|
+
if (backend === "memory") {
|
|
148
|
+
const values = options.values || new Map();
|
|
149
|
+
return { name: "memory", set: (k, v) => values.set(k, String(v)), get: (k) => values.get(k) ?? null, delete: (k) => values.delete(k) };
|
|
150
|
+
}
|
|
151
|
+
if (backend === "dpapi") return createDpapiBackend({ ...options, runner });
|
|
152
|
+
if (backend === "keychain") return createKeychainBackend({ ...options, runner });
|
|
153
|
+
if (backend === "secret-service") return createSecretServiceBackend({ ...options, runner });
|
|
154
|
+
throw new Error(`No OS secret store available for platform ${options.platform || process.platform}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function secretRef(key) { return { __cc_secret_ref: String(key) }; }
|
|
158
|
+
export function isSecretRef(value) { return Boolean(value && typeof value === "object" && value.__cc_secret_ref); }
|
|
159
|
+
export { chooseBackend };
|
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
import { execSync, spawn } from "node:child_process";
|
|
2
1
|
import { existsSync } from "node:fs";
|
|
3
2
|
import { join } from "node:path";
|
|
4
3
|
import logger from "./logger.js";
|
|
4
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
5
|
+
|
|
6
|
+
export const _deps = {
|
|
7
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
8
|
+
spawn: (...args) => executionBroker.spawn(...args),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function syncDocker(command, args, options = {}, origin = "service:docker") {
|
|
12
|
+
return _deps.execFileSync(command, args, {
|
|
13
|
+
...options,
|
|
14
|
+
origin,
|
|
15
|
+
policy: "allow",
|
|
16
|
+
scope: "service",
|
|
17
|
+
shell: false,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
5
20
|
|
|
6
21
|
export function isDockerAvailable() {
|
|
7
22
|
try {
|
|
8
|
-
|
|
23
|
+
syncDocker("docker", ["--version"], { stdio: "ignore" });
|
|
9
24
|
return true;
|
|
10
25
|
} catch {
|
|
11
26
|
return false;
|
|
@@ -14,11 +29,11 @@ export function isDockerAvailable() {
|
|
|
14
29
|
|
|
15
30
|
export function isDockerComposeAvailable() {
|
|
16
31
|
try {
|
|
17
|
-
|
|
32
|
+
syncDocker("docker", ["compose", "version"], { stdio: "ignore" });
|
|
18
33
|
return true;
|
|
19
34
|
} catch {
|
|
20
35
|
try {
|
|
21
|
-
|
|
36
|
+
syncDocker("docker-compose", ["--version"], { stdio: "ignore" });
|
|
22
37
|
return true;
|
|
23
38
|
} catch {
|
|
24
39
|
return false;
|
|
@@ -26,12 +41,12 @@ export function isDockerComposeAvailable() {
|
|
|
26
41
|
}
|
|
27
42
|
}
|
|
28
43
|
|
|
29
|
-
function
|
|
44
|
+
export function getComposeInvocation() {
|
|
30
45
|
try {
|
|
31
|
-
|
|
32
|
-
return "docker compose";
|
|
46
|
+
syncDocker("docker", ["compose", "version"], { stdio: "ignore" });
|
|
47
|
+
return { command: "docker", prefixArgs: ["compose"] };
|
|
33
48
|
} catch {
|
|
34
|
-
return "docker-compose";
|
|
49
|
+
return { command: "docker-compose", prefixArgs: [] };
|
|
35
50
|
}
|
|
36
51
|
}
|
|
37
52
|
|
|
@@ -54,30 +69,37 @@ export function findComposeFile(searchPaths) {
|
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
export function servicesUp(composePath, options = {}) {
|
|
57
|
-
const
|
|
72
|
+
const invocation = getComposeInvocation();
|
|
58
73
|
const args = ["-f", composePath, "up", "-d"];
|
|
59
74
|
if (options.services) {
|
|
60
75
|
args.push(...options.services);
|
|
61
76
|
}
|
|
62
|
-
return runCompose(
|
|
77
|
+
return runCompose(invocation, args);
|
|
63
78
|
}
|
|
64
79
|
|
|
65
80
|
export function servicesDown(composePath) {
|
|
66
|
-
const
|
|
67
|
-
return runCompose(
|
|
81
|
+
const invocation = getComposeInvocation();
|
|
82
|
+
return runCompose(invocation, ["-f", composePath, "down"]);
|
|
68
83
|
}
|
|
69
84
|
|
|
70
85
|
export function servicesLogs(composePath, options = {}) {
|
|
71
|
-
const
|
|
86
|
+
const invocation = getComposeInvocation();
|
|
72
87
|
const args = ["-f", composePath, "logs"];
|
|
73
88
|
if (options.follow) args.push("-f");
|
|
74
89
|
if (options.tail) args.push("--tail", String(options.tail));
|
|
75
90
|
if (options.services) args.push(...options.services);
|
|
76
91
|
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
92
|
+
const child = _deps.spawn(
|
|
93
|
+
invocation.command,
|
|
94
|
+
[...invocation.prefixArgs, ...args],
|
|
95
|
+
{
|
|
96
|
+
stdio: "inherit",
|
|
97
|
+
origin: "service:compose-logs",
|
|
98
|
+
policy: "allow",
|
|
99
|
+
scope: "service",
|
|
100
|
+
shell: false,
|
|
101
|
+
},
|
|
102
|
+
);
|
|
81
103
|
|
|
82
104
|
return new Promise((resolve, reject) => {
|
|
83
105
|
child.on("close", (code) => {
|
|
@@ -89,17 +111,22 @@ export function servicesLogs(composePath, options = {}) {
|
|
|
89
111
|
}
|
|
90
112
|
|
|
91
113
|
export function servicesPull(composePath) {
|
|
92
|
-
const
|
|
93
|
-
return runCompose(
|
|
114
|
+
const invocation = getComposeInvocation();
|
|
115
|
+
return runCompose(invocation, ["-f", composePath, "pull"]);
|
|
94
116
|
}
|
|
95
117
|
|
|
96
118
|
export function getServiceStatus(composePath) {
|
|
97
|
-
const
|
|
119
|
+
const invocation = getComposeInvocation();
|
|
98
120
|
try {
|
|
99
|
-
const output =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
121
|
+
const output = syncDocker(
|
|
122
|
+
invocation.command,
|
|
123
|
+
[...invocation.prefixArgs, "-f", composePath, "ps", "--format", "json"],
|
|
124
|
+
{
|
|
125
|
+
encoding: "utf-8",
|
|
126
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
127
|
+
},
|
|
128
|
+
"service:compose-status",
|
|
129
|
+
);
|
|
103
130
|
try {
|
|
104
131
|
return JSON.parse(`[${output.trim().split("\n").join(",")}]`);
|
|
105
132
|
} catch {
|
|
@@ -110,14 +137,22 @@ export function getServiceStatus(composePath) {
|
|
|
110
137
|
}
|
|
111
138
|
}
|
|
112
139
|
|
|
113
|
-
function runCompose(
|
|
114
|
-
const
|
|
115
|
-
|
|
140
|
+
function runCompose(invocation, args) {
|
|
141
|
+
const fullArgs = [...invocation.prefixArgs, ...args];
|
|
142
|
+
const display = [invocation.command, ...fullArgs]
|
|
143
|
+
.map((part) => JSON.stringify(String(part)))
|
|
144
|
+
.join(" ");
|
|
145
|
+
logger.verbose(`Running: ${display}`);
|
|
116
146
|
try {
|
|
117
|
-
|
|
147
|
+
syncDocker(
|
|
148
|
+
invocation.command,
|
|
149
|
+
fullArgs,
|
|
150
|
+
{ stdio: "inherit" },
|
|
151
|
+
"service:compose",
|
|
152
|
+
);
|
|
118
153
|
return true;
|
|
119
154
|
} catch (err) {
|
|
120
|
-
logger.error(`Command failed: ${
|
|
155
|
+
logger.error(`Command failed: ${display}`);
|
|
121
156
|
throw err;
|
|
122
157
|
}
|
|
123
158
|
}
|
|
@@ -21,6 +21,26 @@ const { runHooks } = require("./hook-runner.cjs");
|
|
|
21
21
|
const { buildHookEnvelope } = require("./hook-event-bus.cjs");
|
|
22
22
|
const hookEventLog = require("./hook-event-log.cjs");
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Publish lifecycle events to Hooks v2 without making the legacy settings hook
|
|
26
|
+
* path depend on the ESM runtime. Payloads are deliberately reduced before
|
|
27
|
+
* publication: prompt text and file contents must never become durable hook
|
|
28
|
+
* context merely because a lifecycle producer fired.
|
|
29
|
+
*/
|
|
30
|
+
function publishHooksV2Event(event, payload = {}) {
|
|
31
|
+
const safe = { ...payload };
|
|
32
|
+
delete safe.prompt;
|
|
33
|
+
delete safe.content;
|
|
34
|
+
delete safe.files;
|
|
35
|
+
void import("./hooks-v2-producers.js")
|
|
36
|
+
.then(({ emitHooksV2Event }) => {
|
|
37
|
+
emitHooksV2Event(event, safe);
|
|
38
|
+
})
|
|
39
|
+
.catch(() => {
|
|
40
|
+
// Optional producer bridge; legacy settings hooks remain authoritative.
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
24
44
|
/**
|
|
25
45
|
* Stamp a unified-bus delivery id (event_id) onto a hook payload (P2 event bus).
|
|
26
46
|
* Additive — a hook that ignores it is unaffected; a hook that reads it gets a
|
|
@@ -104,6 +124,10 @@ function runUserPromptSubmitHooks(
|
|
|
104
124
|
settingsHooks,
|
|
105
125
|
{ prompt, cwd, sessionId } = {},
|
|
106
126
|
) {
|
|
127
|
+
publishHooksV2Event("UserPromptSubmit", {
|
|
128
|
+
cwd: cwd || null,
|
|
129
|
+
session_id: sessionId || null,
|
|
130
|
+
});
|
|
107
131
|
if (!settingsHooks) return { blocked: false, additionalContext: null };
|
|
108
132
|
const matched = collectHooks(settingsHooks, "UserPromptSubmit", "");
|
|
109
133
|
if (matched.length === 0) return { blocked: false, additionalContext: null };
|
|
@@ -159,7 +183,7 @@ function dispatchAsyncHooks(settingsHooks, event, payload = {}, opts = {}) {
|
|
|
159
183
|
return supervisor.dispatch(
|
|
160
184
|
asyncHooks,
|
|
161
185
|
{ hook_event_name: event, cwd: opts.cwd, ...payload },
|
|
162
|
-
{ cwd: opts.cwd },
|
|
186
|
+
{ cwd: opts.cwd, broker: opts.broker },
|
|
163
187
|
);
|
|
164
188
|
}
|
|
165
189
|
|
|
@@ -169,6 +193,11 @@ function dispatchAsyncHooks(settingsHooks, event, payload = {}, opts = {}) {
|
|
|
169
193
|
* @returns {{ additionalContext:string|null }}
|
|
170
194
|
*/
|
|
171
195
|
function runSessionStartHooks(settingsHooks, { source, cwd, sessionId } = {}) {
|
|
196
|
+
publishHooksV2Event("SessionStart", {
|
|
197
|
+
source: source || "startup",
|
|
198
|
+
cwd: cwd || null,
|
|
199
|
+
session_id: sessionId || null,
|
|
200
|
+
});
|
|
172
201
|
if (!settingsHooks) return { additionalContext: null };
|
|
173
202
|
const matched = collectHooks(settingsHooks, "SessionStart", source || "");
|
|
174
203
|
if (matched.length === 0) return { additionalContext: null };
|
|
@@ -199,6 +228,11 @@ function runCwdChangedHooks(
|
|
|
199
228
|
settingsHooks,
|
|
200
229
|
{ oldCwd, newCwd, cwd, sessionId } = {},
|
|
201
230
|
) {
|
|
231
|
+
publishHooksV2Event("CwdChanged", {
|
|
232
|
+
old_cwd: oldCwd || null,
|
|
233
|
+
cwd: newCwd || cwd || null,
|
|
234
|
+
session_id: sessionId || null,
|
|
235
|
+
});
|
|
202
236
|
if (!settingsHooks) return { additionalContext: null };
|
|
203
237
|
const matched = collectHooks(settingsHooks, "CwdChanged", newCwd || "");
|
|
204
238
|
const { sync } = partitionAsyncHooks(matched);
|
|
@@ -234,6 +268,13 @@ function runWorktreeCreateHooks(
|
|
|
234
268
|
settingsHooks,
|
|
235
269
|
{ worktreePath, branch, baseSha, cwd, sessionId } = {},
|
|
236
270
|
) {
|
|
271
|
+
publishHooksV2Event("WorktreeCreate", {
|
|
272
|
+
worktree_path: worktreePath || null,
|
|
273
|
+
branch: branch || null,
|
|
274
|
+
base_sha: baseSha || null,
|
|
275
|
+
cwd: cwd || worktreePath || null,
|
|
276
|
+
session_id: sessionId || null,
|
|
277
|
+
});
|
|
237
278
|
if (!settingsHooks) return { additionalContext: null };
|
|
238
279
|
const matched = collectHooks(settingsHooks, "WorktreeCreate", branch || "");
|
|
239
280
|
const { sync } = partitionAsyncHooks(matched);
|
|
@@ -271,6 +312,14 @@ function runWorktreeRemoveHooks(
|
|
|
271
312
|
settingsHooks,
|
|
272
313
|
{ worktreePath, branch, removed, reason, cwd, sessionId } = {},
|
|
273
314
|
) {
|
|
315
|
+
publishHooksV2Event("WorktreeRemove", {
|
|
316
|
+
worktree_path: worktreePath || null,
|
|
317
|
+
branch: branch || null,
|
|
318
|
+
removed: removed === true,
|
|
319
|
+
reason: reason || null,
|
|
320
|
+
cwd: cwd || worktreePath || null,
|
|
321
|
+
session_id: sessionId || null,
|
|
322
|
+
});
|
|
274
323
|
if (!settingsHooks) return { additionalContext: null };
|
|
275
324
|
const matched = collectHooks(settingsHooks, "WorktreeRemove", branch || "");
|
|
276
325
|
const { sync } = partitionAsyncHooks(matched);
|
|
@@ -312,6 +361,11 @@ function runInstructionsLoadedHooks(
|
|
|
312
361
|
settingsHooks,
|
|
313
362
|
{ files, cwd, sessionId } = {},
|
|
314
363
|
) {
|
|
364
|
+
publishHooksV2Event("InstructionsLoaded", {
|
|
365
|
+
count: Array.isArray(files) ? files.length : 0,
|
|
366
|
+
cwd: cwd || null,
|
|
367
|
+
session_id: sessionId || null,
|
|
368
|
+
});
|
|
315
369
|
if (!settingsHooks) return { additionalContext: null };
|
|
316
370
|
const matched = collectHooks(settingsHooks, "InstructionsLoaded", "");
|
|
317
371
|
const { sync } = partitionAsyncHooks(matched);
|
|
@@ -353,6 +407,12 @@ function runObserveHooks(
|
|
|
353
407
|
payload = {},
|
|
354
408
|
{ cwd, matchTarget, traceId, parentId } = {},
|
|
355
409
|
) {
|
|
410
|
+
publishHooksV2Event(event, {
|
|
411
|
+
...payload,
|
|
412
|
+
cwd: cwd || payload.cwd || null,
|
|
413
|
+
trace_id: traceId || payload.trace_id || null,
|
|
414
|
+
parent_id: parentId || payload.parent_id || null,
|
|
415
|
+
});
|
|
356
416
|
if (!settingsHooks) return { decision: "continue", results: [] };
|
|
357
417
|
const matched = collectHooks(settingsHooks, event, matchTarget || "");
|
|
358
418
|
const { sync } = partitionAsyncHooks(matched);
|
|
@@ -252,6 +252,10 @@ function collectHooks(hooksBlock, event, toolName) {
|
|
|
252
252
|
event,
|
|
253
253
|
async: h.async === true,
|
|
254
254
|
asyncRewake: h.asyncRewake === true,
|
|
255
|
+
origin: h.origin || "hook",
|
|
256
|
+
pluginId: h.pluginId || null,
|
|
257
|
+
pluginVersion: h.pluginVersion || null,
|
|
258
|
+
pluginSource: h.pluginSource || null,
|
|
255
259
|
});
|
|
256
260
|
}
|
|
257
261
|
}
|
|
@@ -56,6 +56,8 @@ const KIND_IDEMPOTENT = new Map([
|
|
|
56
56
|
["network-mutation", false],
|
|
57
57
|
["payment", false],
|
|
58
58
|
["file-write", false],
|
|
59
|
+
["file-delete", false],
|
|
60
|
+
["file-move", false],
|
|
59
61
|
["file-write-checkpointed", true],
|
|
60
62
|
["read", true],
|
|
61
63
|
["compute", true],
|
|
@@ -99,6 +101,18 @@ export function classifyToolSideEffect(toolName, args = {}) {
|
|
|
99
101
|
kind: "file-write",
|
|
100
102
|
key: shortKey(a.path || a.file || a.notebook_path),
|
|
101
103
|
};
|
|
104
|
+
case "delete_file":
|
|
105
|
+
return {
|
|
106
|
+
kind: "file-delete",
|
|
107
|
+
key: shortKey(a.path || a.file),
|
|
108
|
+
};
|
|
109
|
+
case "move_file":
|
|
110
|
+
return {
|
|
111
|
+
kind: "file-move",
|
|
112
|
+
key: shortKey(
|
|
113
|
+
`${a.path || a.file || ""} -> ${a.target_path || a.targetPath || ""}`,
|
|
114
|
+
),
|
|
115
|
+
};
|
|
102
116
|
case "edit_file_hashed":
|
|
103
117
|
// Hash-guarded: re-applying over an already-changed tree fails safely, so
|
|
104
118
|
// a replay cannot silently double-apply — idempotent-by-construction.
|
|
@@ -201,6 +215,14 @@ export class SideEffectLedger {
|
|
|
201
215
|
]);
|
|
202
216
|
}
|
|
203
217
|
|
|
218
|
+
/** Merge bounded correlation metadata discovered after an effect started. */
|
|
219
|
+
annotate(opId, metadata = {}) {
|
|
220
|
+
const rec = this._rec(opId);
|
|
221
|
+
if (!rec || !metadata || typeof metadata !== "object") return this;
|
|
222
|
+
rec.meta = { ...rec.meta, ...metadata };
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
204
226
|
/** Confirm the effect applied. Only from `started`. */
|
|
205
227
|
commit(opId) {
|
|
206
228
|
return this._advance(
|
|
@@ -83,6 +83,10 @@ export class SubAgentContext {
|
|
|
83
83
|
// nested spawns (threaded into the loop options so a nested spawn_sub_agent
|
|
84
84
|
// reads it as ctx.subAgentContract).
|
|
85
85
|
this.subAgentContract = options.subAgentContract || null;
|
|
86
|
+
// Optional session-level Extension Tier admission policy. Keep it as an
|
|
87
|
+
// explicit inherited capability so child loops cannot silently bypass the
|
|
88
|
+
// parent's admission decision.
|
|
89
|
+
this.toolAdmission = options.toolAdmission || null;
|
|
86
90
|
// Skill capability INTERSECT: null = unrestricted; a list (possibly empty)
|
|
87
91
|
// restricts run_skill/list_skills in this context's loop to those skills.
|
|
88
92
|
this.skillAllowlist =
|
|
@@ -335,6 +339,7 @@ export class SubAgentContext {
|
|
|
335
339
|
subAgentBudget: this.subAgentBudget,
|
|
336
340
|
// This context's effective contract = the ceiling for its nested spawns.
|
|
337
341
|
subAgentContract: this.subAgentContract,
|
|
342
|
+
toolAdmission: this.toolAdmission,
|
|
338
343
|
// Skill allow-list restricting run_skill/list_skills in this loop.
|
|
339
344
|
skillAllowlist: this.skillAllowlist,
|
|
340
345
|
// Parent trace for hook envelopes (absent → key omitted, no parent_id).
|
|
@@ -30,6 +30,8 @@ const FULL_TOOLS = Object.freeze([
|
|
|
30
30
|
"write_file",
|
|
31
31
|
"edit_file",
|
|
32
32
|
"edit_file_hashed",
|
|
33
|
+
"delete_file",
|
|
34
|
+
"move_file",
|
|
33
35
|
"list_dir",
|
|
34
36
|
"search_files",
|
|
35
37
|
"search_sessions",
|
|
@@ -49,6 +51,8 @@ const DESIGN_TOOLS = Object.freeze([
|
|
|
49
51
|
"write_file",
|
|
50
52
|
"edit_file",
|
|
51
53
|
"edit_file_hashed",
|
|
54
|
+
"delete_file",
|
|
55
|
+
"move_file",
|
|
52
56
|
"list_dir",
|
|
53
57
|
"search_files",
|
|
54
58
|
"web_fetch",
|
package/src/lib/turn-context.js
CHANGED
|
@@ -11,21 +11,23 @@
|
|
|
11
11
|
* @module turn-context
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { execSync } from "child_process";
|
|
15
14
|
import path from "path";
|
|
15
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
16
16
|
|
|
17
|
-
const _deps = {
|
|
17
|
+
const _deps = {
|
|
18
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
19
|
+
};
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* Run a git command with stdio pipe and return stdout or null.
|
|
21
|
-
* @param {string}
|
|
23
|
+
* @param {string[]} args
|
|
22
24
|
* @param {string} cwd
|
|
23
25
|
* @returns {string|null}
|
|
24
26
|
*/
|
|
25
|
-
function _git(
|
|
27
|
+
function _git(args, cwd) {
|
|
26
28
|
try {
|
|
27
29
|
return _deps
|
|
28
|
-
.
|
|
30
|
+
.execFileSync("git", args, {
|
|
29
31
|
cwd,
|
|
30
32
|
encoding: "utf-8",
|
|
31
33
|
stdio: ["ignore", "pipe", "ignore"],
|
|
@@ -33,6 +35,10 @@ function _git(cmd, cwd) {
|
|
|
33
35
|
// `status --porcelain` on a dirty repo with many files can exceed the
|
|
34
36
|
// 1 MB execSync default → ENOBUFS → null → "(clean)" misreport below.
|
|
35
37
|
maxBuffer: 16 * 1024 * 1024,
|
|
38
|
+
origin: "context:git",
|
|
39
|
+
policy: "allow",
|
|
40
|
+
scope: "context",
|
|
41
|
+
shell: false,
|
|
36
42
|
})
|
|
37
43
|
.trim();
|
|
38
44
|
} catch (_e) {
|
|
@@ -60,10 +66,10 @@ export function buildTurnContext({
|
|
|
60
66
|
lines.push(`## Turn context (iteration ${iteration})`);
|
|
61
67
|
lines.push(`- cwd: ${path.resolve(cwd)}`);
|
|
62
68
|
|
|
63
|
-
const branch = _git("rev-parse --abbrev-ref HEAD", cwd);
|
|
69
|
+
const branch = _git(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
|
|
64
70
|
if (branch) {
|
|
65
|
-
const head = _git("rev-parse --short HEAD", cwd);
|
|
66
|
-
const status = _git("status --porcelain", cwd);
|
|
71
|
+
const head = _git(["rev-parse", "--short", "HEAD"], cwd);
|
|
72
|
+
const status = _git(["status", "--porcelain"], cwd);
|
|
67
73
|
// Distinguish "command failed" (null — timeout / huge output) from "" (truly
|
|
68
74
|
// clean): the old `status && …` reported a repo as "(clean)" whenever status
|
|
69
75
|
// couldn't be determined, which is a wrong signal to the model.
|
|
@@ -121,6 +121,89 @@ export function classifyActionRisk(actionClass) {
|
|
|
121
121
|
return "conditional"; // push — depends on branch protection
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Classify a shell command before it reaches the process broker. This is a
|
|
126
|
+
* deliberately conservative, token-free classifier: compound commands use
|
|
127
|
+
* the highest-risk segment and unknown commands remain unknown so an
|
|
128
|
+
* unattended caller can fail closed.
|
|
129
|
+
*/
|
|
130
|
+
export function classifyShellAction(command) {
|
|
131
|
+
if (typeof command !== "string" || !command.trim()) return null;
|
|
132
|
+
const segments = command
|
|
133
|
+
.split(/&&|\|\||[;\n]|\|/)
|
|
134
|
+
.map((part) =>
|
|
135
|
+
part
|
|
136
|
+
.trim()
|
|
137
|
+
.replace(/^(?:env\s+)?(?:sudo\s+)?(?:command\s+)?/i, "")
|
|
138
|
+
.toLowerCase(),
|
|
139
|
+
)
|
|
140
|
+
.filter(Boolean);
|
|
141
|
+
const classifySegment = (segment) => {
|
|
142
|
+
if (/^git\s+push\b/.test(segment)) return ACTION_CLASS.PUSH;
|
|
143
|
+
if (/^git\s+(?:merge|rebase|cherry-pick)\b/.test(segment)) {
|
|
144
|
+
return ACTION_CLASS.MERGE;
|
|
145
|
+
}
|
|
146
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+publish\b/.test(segment)) {
|
|
147
|
+
return ACTION_CLASS.PUBLISH;
|
|
148
|
+
}
|
|
149
|
+
if (
|
|
150
|
+
/^(?:terraform\s+(?:apply|destroy)|pulumi\s+up|kubectl\s+(?:apply|delete|rollout)|helm\s+(?:install|upgrade)|docker\s+push)\b/.test(
|
|
151
|
+
segment,
|
|
152
|
+
)
|
|
153
|
+
) {
|
|
154
|
+
return segment.startsWith("docker push")
|
|
155
|
+
? ACTION_CLASS.DEPLOY
|
|
156
|
+
: ACTION_CLASS.INFRA_MUTATION;
|
|
157
|
+
}
|
|
158
|
+
if (/\b(?:deploy|rollout)\b/.test(segment)) return ACTION_CLASS.DEPLOY;
|
|
159
|
+
if (/^(?:git\s+(?:status|diff|log|show|branch)|ls\b|dir\b|pwd\b|cat\b|type\b|rg\b|grep\b|find\b|where\b)/.test(segment)) {
|
|
160
|
+
return ACTION_CLASS.READ;
|
|
161
|
+
}
|
|
162
|
+
if (/^(?:npm|pnpm|yarn|bun)\s+(?:test|run\s+(?:test|lint|build)|install\b)/.test(segment) || /^(?:pytest|vitest|jest|cargo\s+test|go\s+test)\b/.test(segment)) {
|
|
163
|
+
return ACTION_CLASS.LOCAL_WRITE;
|
|
164
|
+
}
|
|
165
|
+
if (/^echo\b/.test(segment) && />/.test(segment)) {
|
|
166
|
+
return ACTION_CLASS.LOCAL_WRITE;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
};
|
|
170
|
+
const rank = [
|
|
171
|
+
ACTION_CLASS.READ,
|
|
172
|
+
ACTION_CLASS.LOCAL_WRITE,
|
|
173
|
+
ACTION_CLASS.COMMIT,
|
|
174
|
+
ACTION_CLASS.PUSH,
|
|
175
|
+
ACTION_CLASS.PUBLISH,
|
|
176
|
+
ACTION_CLASS.MERGE,
|
|
177
|
+
ACTION_CLASS.DEPLOY,
|
|
178
|
+
ACTION_CLASS.INFRA_MUTATION,
|
|
179
|
+
ACTION_CLASS.EXTERNAL_MESSAGE,
|
|
180
|
+
];
|
|
181
|
+
const classified = segments.map(classifySegment);
|
|
182
|
+
return classified.reduce((highest, current) => {
|
|
183
|
+
if (!current) return null;
|
|
184
|
+
if (!highest) return current;
|
|
185
|
+
return rank.indexOf(current) > rank.indexOf(highest) ? current : highest;
|
|
186
|
+
}, null);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Apply the unattended policy to a shell command, including protected push targets. */
|
|
190
|
+
export function evaluateUnattendedShellAction(command, params = {}) {
|
|
191
|
+
const actionClass = classifyShellAction(command);
|
|
192
|
+
const protectedBranch =
|
|
193
|
+
params.protectedBranch === true ||
|
|
194
|
+
/\bgit\s+push\b[^\n]*(?:^|\s)(?:main|master|develop|production)(?:\s|$)/i.test(
|
|
195
|
+
command || "",
|
|
196
|
+
);
|
|
197
|
+
return {
|
|
198
|
+
actionClass,
|
|
199
|
+
...evaluateUnattendedAction({
|
|
200
|
+
...params,
|
|
201
|
+
actionClass,
|
|
202
|
+
protectedBranch,
|
|
203
|
+
}),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
124
207
|
/**
|
|
125
208
|
* Decide whether a fired task may perform one action. Fail-closed.
|
|
126
209
|
*
|