chainlesschain 0.162.175 → 0.162.177
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-DT-VPWuN.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CDGfqt2Y.js → ActionButton-DyOreOVN.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BYhkzdgD.js → Analytics-DslNsKux.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-cEKk1cpb.js → AppLayout-BNJJAYME.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-_aXR3WWc.js → Artifacts-DoaAtEcY.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CYAf-gY7.js → Audit-DPG3WdJ9.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D4Q20phR.js → BackgroundAgents-C_JO6R5G.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cq0Tyk58.js → Backup-Cv3BooyX.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CPj_CdAv.js → BaseInput-D2uQXWu-.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BQ-Qq0es.js → Chat-B4Vczyf3.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DE6reP99.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-rke6l3yg.js → Checkbox-qTgk4VeP.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DiacrIPq.js → Codegen-DlLWcIzj.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cx3BY-Up.js → Col-DNO73qp7.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DfmWiQy8.js → Community-vRDNpc4j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DdQnpxy5.js → Compact-CEWtIXni.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-lzliOH_r.js → Compliance-KgYC9Fxi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CYx4Un5k.js → Cowork-zj5wvkpT.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BGDcPFlo.js → Cron-BLDoCozU.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-0_X5g2ri.js → Crosschain-BYnff4VY.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C0PEf3Eu.js → DID-C75VFsVm.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DULQjQ58.js → Dashboard-C4Gutni2.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DGRHRbW6.js → Dropdown-B5dbO4Kx.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-ChX8XPwB.js → EmailListRenderer-BDipZtHJ.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dyq6IBNu.js → FamilyGuardDashboard-DmIzt8jj.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DH1NfAL2.js → Federation-D9QOS-uW.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BN1I_uNi.js → FormItemContext-B47HRwAm.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Dq_2UYpe.js → GenericCardRenderer-3R4mXmgV.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BAy1yvI2.js → Git-DrNXZf1C.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Db6Q2iSy.js → Governance-BGd7JR98.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-0ub6yHcr.js → Inference-D-2he1ed.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DtLetM36.js → KnowledgeGraph-C0sHIbK5.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Bcoy7CUd.js → Logs-DiBQO-jL.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BfEMFAXf.js → MarkdownRenderer-DL_5eV2D.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tt2rzwRR.js → Marketplace-VR59OdrC.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BhOgX-MU.js → McpTools-DrPzwSd3.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-BJUxeWBL.js → Memory-CBgKALwQ.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BwUY2G9w.js → MobileBridge-pQ9Tn-Mn.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BLRfHhqi.js → MobileProjects-mASB6jyj.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-B2WMboOm.js → Mtc-DTMgE7HC.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-8pNEXO63.js → MtcAudit-CwTnCtiL.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-C1wm5a_1.js → Multisig-ngm6WU8f.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-C1QpKF7g.js → NLProgramming-4YO4Qww9.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CiQUcxFu.js → Notes-DP1k45mF.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BblDPJ_x.js → NotificationSettings-r2H8yPKb.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DRjYcPtb.js → OrderTableRenderer-CoM_Zw0J.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Dp3VKB0X.js → Organization-DrO7jRWS.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Czx161m9.js → Overflow-Cnwu4i4t.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-ClFi6wOs.js → P2P-zi-cDwA_.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CRweW0lz.js → PdhVaultBrowser-DBEryDv7.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BzcRoqTn.js → Permissions-lqXK2C3x.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-ChGTpNMd.js → PersonalDataHub-b63T3HJM.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BMOOpKWA.js → Pipeline-Kep5KAGW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D0AZHObH.js → Privacy-CHdvOAh1.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-yYFlZ6Ja.js → ProjectInit-BhKfdwe9.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DJNVuMQs.js → ProjectSettings-Yavk9K8A.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Br0rBWH1.js → Projects-CN8E_5Mq.js} +1 -1
- package/src/assets/web-panel/assets/Providers-Bfym6SQn.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-81NZOitV.js → QrScannerModal-CLSQcrlR.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Dic2lCbJ.js → QuickAsk-VPa2WKQN.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Dh9iwViE.js → Recommend-CGXR8jVU.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Bq9VYEFy.js → RemoteSession-C_20YfMB.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CxFZ-NbJ.js → Reputation-awZh68UV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BVSLcaX2.js → Row-Ctb4oiYN.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BbC-5DOH.js → RssFeed-D3sdjvUV.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BfjZ1GCr.js → Search-C-zfA4kT.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CVjhOV5r.js → Security-D9XlmHA3.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D45u-Aqe.js → Services-C3UKnr41.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-WkGoK4he.js → Skeleton-BQxagZfF.js} +1 -1
- package/src/assets/web-panel/assets/Skills-q6eb6KPZ.js +1 -0
- package/src/assets/web-panel/assets/{Sla-Bf4QTF3E.js → Sla-DveENvek.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DVpZdbMN.js → SpeechSettings-BFjXLNgF.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DEEojoMS.js → SyncSettings-BpHgbaP9.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-DvepRb8-.js +1 -0
- package/src/assets/web-panel/assets/{Templates-Bzl-9wY5.js → Templates-DEiaoyve.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-0khxUOB8.js → Tenant-ITg774nY.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DWGYhAYU.js → Terminal-D3ZBcvnb.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-B0Y4LONc.js → TimelineRenderer-BsLU6JjU.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DEE07SFh.js → Tokens-Cb5Pquc9.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BM7xvA5z.js → Trigger-Dwfy-m9N.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Dv3ijvvZ.js → Trust-CnlSRGG0.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B1-enmMt.js → UkeySign-Y4TlvKVo.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DYiIPByd.js → VideoEditing-BpKLtTTO.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D-y374BQ.js → Wallet-LLBzIq8x.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-HBDjcUhi.js → WebAuthn-BeSRiusP.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-sKn4qTID.js → WorkflowEditor-BK_l1tXO.js} +1 -1
- package/src/assets/web-panel/assets/{chat-TVYhaBXj.js → chat-DYd-X7Wg.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DMADxY9v.js → colors-C9uip71j.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-OftcHpO_.js → compact-item-JBrfjUP6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DW1zVUSN.js → createContext-D03fbuiq.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B8LQ8leS.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CaUathNp.js → hasIn-DLQOR6l-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cmdv6Dev.js → index-5YN7F5bO.js} +1 -1
- package/src/assets/web-panel/assets/{index-iDmgT2Dg.js → index-6GuLRpBQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-77kgkUgY.js → index-B0X76LjX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CM8W07sc.js → index-B46YcgsV.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9JoaYSs.js → index-BNCdRmWf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpDtN0dl.js → index-BYv-LWdy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZXYI5LU.js → index-Ba-Ps_AJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWVZ3T0t.js → index-BcBZwlnG.js} +1 -1
- package/src/assets/web-panel/assets/{index--5UvwqH_.js → index-BdH9l8wl.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBNg08cD.js → index-BfOs_bmg.js} +3 -3
- package/src/assets/web-panel/assets/index-Bh8BPtqR.js +1 -0
- package/src/assets/web-panel/assets/{index-s-EnkUCn.js → index-BnQgRjsm.js} +1 -1
- package/src/assets/web-panel/assets/{index-Lr0MO-GU.js → index-BpYKLrUT.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-19mFhn.js → index-BuNFCZCx.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeCIYYG7.js → index-ByHO3SqZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-hXq7QRA_.js → index-C2zmOsyD.js} +1 -1
- package/src/assets/web-panel/assets/{index-8YelceUU.js → index-CChQBM1d.js} +1 -1
- package/src/assets/web-panel/assets/{index-B52Ztt8Q.js → index-CChaISMb.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKjqFpYa.js → index-CILVyK3b.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAfT3EMd.js → index-CL0ixCxk.js} +1 -1
- package/src/assets/web-panel/assets/{index-sm1sGIxW.js → index-CS63r8h3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHi634g9.js → index-CVZWiUE_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEzLLVYd.js → index-Ce0Bf1YF.js} +1 -1
- package/src/assets/web-panel/assets/index-CeVrHLzZ.js +1 -0
- package/src/assets/web-panel/assets/{index-pSVCBsG4.js → index-Ck17i0OD.js} +1 -1
- package/src/assets/web-panel/assets/{index-GUKz4Pv9.js → index-Cpn19c9k.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKNdnJRo.js → index-CqWk1FLG.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bg-7FpaL.js → index-CwoDpKzW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYwwUKDg.js → index-D-1SqEpQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZdT8nio.js → index-D4UY5Z60.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvRw4Fna.js → index-D8KvuDz0.js} +1 -1
- package/src/assets/web-panel/assets/{index-kdMl_0zL.js → index-DNMAAUVk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK-p7Hji.js → index-DYLZY4uh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXcqvWBp.js → index-DaokIHt3.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFVbDpqg.js → index-Q7mmL6w4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJ1PjRY3.js → index-SO6lgMg0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSp1Ofvx.js → index-iahNhZwm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BupSWDcl.js → index-l08afIbV.js} +1 -1
- package/src/assets/web-panel/assets/{index-D63QVAiJ.js → index-rIxxfdTN.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DdcKTlQR.js → initDefaultProps-CG9z1c6w.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CL-hTBQj.js → motion-B1Ky7Zff.js} +1 -1
- package/src/assets/web-panel/assets/{move-qYSAkxNG.js → move-DME8X2P1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-ZwRSZtRP.js → mtc-parser-cuJYSWB7.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Bld-8ftI.js → omit-UI_EE0uZ.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DGHs-a9Z.js → pickAttrs-BIoE_Z_V.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DRQPMyI5.js → placementArrow-B48-9HKN.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C5MJG_Yo.js → responsiveObserve-D7x_GDgD.js} +1 -1
- package/src/assets/web-panel/assets/{slide-VZ-fpZCD.js → slide-DjzC5_7m.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-9ocfCyHk.js → statusUtils-C6BIymhh.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B6QAwAN5.js → styleChecker-B4dGrdD9.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Bq1twor3.js → useFlexGapSupport-Bken4aNE.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DKZq96tz.js → useFs-BMlqECqv.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D0RmRVXf.js → usePersonalDataHub-DLdrfmMa.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D6kEj_tt.js → vnode-CKJQmxa0.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-2yfasoQf.js → zoom-CaZunuau.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 +83 -5
- package/src/commands/agent.js +42 -4
- package/src/commands/background-session.js +11 -4
- package/src/commands/batch.js +79 -27
- package/src/commands/changelog.js +15 -4
- package/src/commands/config.js +70 -5
- package/src/commands/context.js +36 -2
- package/src/commands/eval.js +21 -6
- package/src/commands/hook.js +2 -2
- package/src/commands/hub.js +19 -1
- package/src/commands/loop.js +9 -2
- 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/skill.js +2 -0
- package/src/commands/statusline.js +3 -3
- package/src/commands/team.js +20 -7
- package/src/commands/update.js +65 -10
- package/src/data/changelog.json +293 -51
- 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/background-task-manager.js +18 -6
- package/src/harness/background-task-worker.js +11 -18
- package/src/harness/jsonl-session-store.js +13 -6
- package/src/harness/mcp-client.js +195 -2
- package/src/harness/worktree-isolator.js +18 -21
- 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-core.js +5 -0
- package/src/lib/agent-ipc-bus.js +44 -5
- package/src/lib/agent-sandbox.js +16 -2
- package/src/lib/agent-schedule-store.js +55 -0
- package/src/lib/agent-team/team-worktree.js +28 -6
- package/src/lib/agent-tool-admission.js +104 -0
- package/src/lib/agent-worktree.js +20 -19
- package/src/lib/api-key-helper.js +10 -2
- package/src/lib/async-hook-supervisor.cjs +135 -15
- package/src/lib/async-hook-supervisor.js +47 -0
- package/src/lib/background-agent-supervisor.js +35 -12
- package/src/lib/background-task-manager.js +5 -1
- package/src/lib/changelog.js +76 -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/chrome-connector.js +6 -2
- package/src/lib/claude-code-bridge.js +24 -8
- package/src/lib/cli-anything-bridge.js +82 -25
- 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/doctor-checkup.js +18 -6
- package/src/lib/downloader.js +17 -3
- package/src/lib/ensure-utf8.js +11 -3
- package/src/lib/eval/tasks.js +25 -31
- 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 +88 -8
- package/src/lib/hook-runner.js +55 -0
- 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 +129 -24
- 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__/benchmark.test.js +61 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +6 -1
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
- package/src/lib/lsp/benchmark.js +20 -4
- package/src/lib/lsp/lsp-client.js +22 -3
- package/src/lib/lsp/lsp-manager.js +4 -0
- package/src/lib/lsp/lsp-server-registry.js +11 -2
- package/src/lib/mcp-oauth.js +8 -2
- package/src/lib/npm-invocation.js +29 -0
- package/src/lib/orchestrator.js +8 -2
- package/src/lib/packer/pack-update-applier.js +14 -2
- package/src/lib/packer/pkg-runner.js +13 -2
- package/src/lib/packer/precheck.js +33 -16
- package/src/lib/packer/smoke-runner.js +18 -5
- package/src/lib/packer/web-panel-builder.js +16 -2
- package/src/lib/paths.js +1 -1
- 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 +48 -6
- 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 +11 -3
- 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/repl-bang-memorize.js +10 -2
- package/src/lib/repl-goal.js +19 -2
- package/src/lib/secret-store.js +159 -0
- package/src/lib/service-manager.js +64 -29
- package/src/lib/settings-hook-events.cjs +74 -9
- package/src/lib/settings-hook-events.js +20 -0
- package/src/lib/settings-hooks.cjs +4 -0
- package/src/lib/side-effect-ledger.js +22 -0
- package/src/lib/skill-packs/generator.js +18 -9
- package/src/lib/skill-process-broker.js +71 -0
- package/src/lib/slash-commands.js +10 -2
- package/src/lib/status-line.cjs +28 -7
- package/src/lib/status-line.js +33 -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 +60 -23
- package/src/repl/clipboard-copy.js +8 -2
- package/src/repl/pr-comments.js +30 -7
- package/src/runtime/agent-core.js +554 -118
- 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 +88 -10
- package/src/runtime/headless-stream.js +343 -21
- package/src/runtime/mcp-config.js +16 -1
- package/src/runtime/session-slash-commands.js +506 -0
- package/src/skills/video-editing/extractors/audio-extractor.js +13 -5
- package/src/skills/video-editing/extractors/video-extractor.js +13 -3
- package/src/skills/video-editing/media-process.js +20 -0
- package/src/skills/video-editing/render/audio-mix.js +13 -3
- package/src/skills/video-editing/render/ffmpeg-concat.js +7 -2
- package/src/skills/video-editing/render/ffmpeg-extract.js +7 -2
- package/src/workers/background-agent-worker.js +6 -2
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Ci97vNTs.js +0 -1
- package/src/assets/web-panel/assets/Providers-zZRhNtSu.js +0 -1
- package/src/assets/web-panel/assets/Skills-D_jvQZcj.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DFwxpLIk.js +0 -1
- 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
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
|
|
17
17
|
import fs from "fs";
|
|
18
18
|
import path from "path";
|
|
19
|
-
import
|
|
19
|
+
import broker from "../lib/process-execution-broker/index.js";
|
|
20
20
|
import os from "os";
|
|
21
21
|
import sharedCodingAgentPolicy from "./coding-agent-policy.cjs";
|
|
22
22
|
import sharedShellPolicy from "./coding-agent-shell-policy.cjs";
|
|
23
23
|
import sharedPermissionRules from "../lib/permission-rules.cjs";
|
|
24
24
|
import sharedSettingsHooks from "../lib/settings-hooks.cjs";
|
|
25
|
-
import sharedHookRunner from "../lib/hook-runner.
|
|
26
|
-
import sharedHookEvents from "../lib/settings-hook-events.
|
|
25
|
+
import sharedHookRunner from "../lib/hook-runner.js";
|
|
26
|
+
import sharedHookEvents from "../lib/settings-hook-events.js";
|
|
27
27
|
import { mergeProviderOptions } from "../lib/provider-options.js";
|
|
28
28
|
import { applyCredentialProxy } from "../lib/credential-proxy.js";
|
|
29
29
|
import { describeBackgroundCommand } from "../lib/terminal-context.js";
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
import {
|
|
48
48
|
getCodingAgentFunctionToolDefinitions,
|
|
49
49
|
listCodingAgentToolNames,
|
|
50
|
+
getCodingAgentToolPolicy,
|
|
50
51
|
} from "./coding-agent-contract.js";
|
|
51
52
|
import { createToolContext } from "../tools/tool-context.js";
|
|
52
53
|
import { createToolTelemetryRecord } from "../tools/tool-telemetry.js";
|
|
@@ -78,6 +79,12 @@ import {
|
|
|
78
79
|
imageUrlBlockToAnthropic,
|
|
79
80
|
} from "../lib/image-input.js";
|
|
80
81
|
import { executeToolSearch, gateDeferredMcpCall } from "./mcp-tool-search.js";
|
|
82
|
+
import { emitHooksV2Event } from "../lib/hooks-v2-producers.js";
|
|
83
|
+
import {
|
|
84
|
+
admitTool,
|
|
85
|
+
buildToolAttribution,
|
|
86
|
+
} from "../lib/agent-tool-admission.js";
|
|
87
|
+
import { evaluateUnattendedShellAction } from "../lib/unattended-action-policy.js";
|
|
81
88
|
|
|
82
89
|
/**
|
|
83
90
|
* Names of MCP servers currently mounted by an in-flight run_skill call.
|
|
@@ -105,6 +112,33 @@ const {
|
|
|
105
112
|
withDeliveryId,
|
|
106
113
|
} = sharedHookEvents;
|
|
107
114
|
|
|
115
|
+
const searchProcessRunner = broker.execSync.bind(broker);
|
|
116
|
+
const runCodeProcessRunner = broker.execFileSync.bind(broker);
|
|
117
|
+
|
|
118
|
+
export const _agentToolProcessDeps = {
|
|
119
|
+
runSearch: searchProcessRunner,
|
|
120
|
+
runCode: runCodeProcessRunner,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
function runSearchProcess(command, options = {}) {
|
|
124
|
+
return _agentToolProcessDeps.runSearch(command, {
|
|
125
|
+
...options,
|
|
126
|
+
origin: "agent-core:search-files",
|
|
127
|
+
policy: "allow",
|
|
128
|
+
scope: "agent-core",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function runCodeProcess(file, args, options = {}, origin = "run-code") {
|
|
133
|
+
return _agentToolProcessDeps.runCode(file, args, {
|
|
134
|
+
...options,
|
|
135
|
+
origin: `agent-core:${origin}`,
|
|
136
|
+
policy: "allow",
|
|
137
|
+
scope: "agent-core",
|
|
138
|
+
shell: false,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
108
142
|
// ─── Background shell tasks ────────────────────────────────────────────────
|
|
109
143
|
//
|
|
110
144
|
// run_shell is synchronous (execSync) and capped at a foreground timeout, which
|
|
@@ -223,25 +257,54 @@ function _releaseBgChildHandles(task) {
|
|
|
223
257
|
}
|
|
224
258
|
}
|
|
225
259
|
|
|
260
|
+
const backgroundTaskRunner = broker.spawn.bind(broker);
|
|
261
|
+
const backgroundTaskSyncRunner = broker.spawnSync.bind(broker);
|
|
262
|
+
|
|
263
|
+
export const _backgroundProcessDeps = {
|
|
264
|
+
run: backgroundTaskRunner,
|
|
265
|
+
runSync: backgroundTaskSyncRunner,
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export function _runBackgroundTaskkill(pid, { sync = false } = {}) {
|
|
269
|
+
const args = ["/pid", String(pid), "/T", "/F"];
|
|
270
|
+
const options = {
|
|
271
|
+
windowsHide: true,
|
|
272
|
+
origin: "agent-core:background-taskkill",
|
|
273
|
+
policy: "allow",
|
|
274
|
+
scope: "agent-core",
|
|
275
|
+
};
|
|
276
|
+
return sync
|
|
277
|
+
? _backgroundProcessDeps.runSync("taskkill", args, options)
|
|
278
|
+
: _backgroundProcessDeps.run("taskkill", args, options);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const gitProcessRunner = broker.spawnSync.bind(broker);
|
|
282
|
+
|
|
283
|
+
export const _gitProcessDeps = {
|
|
284
|
+
run: gitProcessRunner,
|
|
285
|
+
};
|
|
286
|
+
|
|
226
287
|
function _killTask(task) {
|
|
227
288
|
const child = task?.child;
|
|
228
289
|
if (!child || child.killed || task?.status !== "running") return false;
|
|
229
290
|
try {
|
|
230
291
|
if (process.platform === "win32") {
|
|
231
292
|
if (child.pid) {
|
|
232
|
-
const tk =
|
|
233
|
-
|
|
234
|
-
});
|
|
235
|
-
// A spawn that fails to launch emits an async 'error' event — with no
|
|
236
|
-
// listener Node rethrows it as an UNCAUGHT exception (the try/catch
|
|
237
|
-
// here can't catch the async emit), crashing the CLI. Handle it and
|
|
238
|
-
// fall back to a direct kill.
|
|
239
|
-
tk.on("error", () => {
|
|
293
|
+
const tk = _runBackgroundTaskkill(child.pid);
|
|
294
|
+
const fallbackDirectKill = () => {
|
|
240
295
|
try {
|
|
241
|
-
child.kill();
|
|
296
|
+
if (!child.killed) child.kill("SIGKILL");
|
|
242
297
|
} catch {
|
|
243
298
|
/* already dead */
|
|
244
299
|
}
|
|
300
|
+
};
|
|
301
|
+
// A launch failure emits 'error'; a permissions/policy failure instead
|
|
302
|
+
// launches taskkill successfully and exits non-zero. Both must fall
|
|
303
|
+
// back or the background command remains alive while teardown reports
|
|
304
|
+
// success.
|
|
305
|
+
tk.once("error", fallbackDirectKill);
|
|
306
|
+
tk.once("close", (code) => {
|
|
307
|
+
if (code !== 0) fallbackDirectKill();
|
|
245
308
|
});
|
|
246
309
|
} else {
|
|
247
310
|
child.kill();
|
|
@@ -302,9 +365,13 @@ function _killTaskSync(task) {
|
|
|
302
365
|
try {
|
|
303
366
|
if (process.platform === "win32") {
|
|
304
367
|
if (child.pid) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
368
|
+
const killed = _runBackgroundTaskkill(child.pid, { sync: true });
|
|
369
|
+
if (killed.error || killed.status !== 0) {
|
|
370
|
+
// Restricted runners can execute taskkill but receive a non-zero
|
|
371
|
+
// access/policy result. Direct termination is the synchronous
|
|
372
|
+
// last-resort for the child handle we own.
|
|
373
|
+
child.kill("SIGKILL");
|
|
374
|
+
}
|
|
308
375
|
} else {
|
|
309
376
|
child.kill();
|
|
310
377
|
}
|
|
@@ -470,8 +537,9 @@ async function runSettingsPreToolUseHooks(name, args, context, cwd) {
|
|
|
470
537
|
? await runCommandHooksParallel(matched, payload, {
|
|
471
538
|
cwd,
|
|
472
539
|
event: "PreToolUse",
|
|
540
|
+
broker,
|
|
473
541
|
})
|
|
474
|
-
: runCommandHooks(matched, payload, { cwd, event: "PreToolUse" });
|
|
542
|
+
: runCommandHooks(matched, payload, { cwd, event: "PreToolUse", broker });
|
|
475
543
|
if (outcome.decision === "block") {
|
|
476
544
|
return { blocked: true, reason: outcome.reason, hook: outcome.hook };
|
|
477
545
|
}
|
|
@@ -552,6 +620,7 @@ function runSettingsPermissionRequestHooks(name, args, context, cwd, reason) {
|
|
|
552
620
|
cwd,
|
|
553
621
|
event: "PermissionRequest",
|
|
554
622
|
mergeStrict: _hookStrictMergeEnabled(),
|
|
623
|
+
broker,
|
|
555
624
|
});
|
|
556
625
|
// Precedence: deny > ask > allow > defer. The runner normalizes deny/block →
|
|
557
626
|
// "block" and short-circuits block/ask, but it COLLAPSES an "allow" into the
|
|
@@ -683,6 +752,21 @@ export function reloadSkills() {
|
|
|
683
752
|
let _cachedPython = null;
|
|
684
753
|
let _cachedEnvInfo = null;
|
|
685
754
|
|
|
755
|
+
const environmentProbeRunner = broker.execFileSync.bind(broker);
|
|
756
|
+
|
|
757
|
+
export const _environmentProcessDeps = {
|
|
758
|
+
run: environmentProbeRunner,
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
function runEnvironmentProbe(file, args, options = {}) {
|
|
762
|
+
return _environmentProcessDeps.run(file, args, {
|
|
763
|
+
...options,
|
|
764
|
+
origin: "agent-core:environment-probe",
|
|
765
|
+
policy: "allow",
|
|
766
|
+
scope: "agent-core",
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
|
|
686
770
|
/**
|
|
687
771
|
* Get cached Python interpreter info (reuses cli-anything-bridge detection).
|
|
688
772
|
* @returns {{ found: boolean, command?: string, version?: string }}
|
|
@@ -706,7 +790,7 @@ export function getEnvironmentInfo() {
|
|
|
706
790
|
let pipAvailable = false;
|
|
707
791
|
if (py.found) {
|
|
708
792
|
try {
|
|
709
|
-
|
|
793
|
+
runEnvironmentProbe(py.command, ["-m", "pip", "--version"], {
|
|
710
794
|
encoding: "utf-8",
|
|
711
795
|
timeout: 10000,
|
|
712
796
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -719,7 +803,7 @@ export function getEnvironmentInfo() {
|
|
|
719
803
|
|
|
720
804
|
let nodeVersion = null;
|
|
721
805
|
try {
|
|
722
|
-
nodeVersion =
|
|
806
|
+
nodeVersion = runEnvironmentProbe(process.execPath, ["--version"], {
|
|
723
807
|
encoding: "utf-8",
|
|
724
808
|
timeout: 5000,
|
|
725
809
|
}).trim();
|
|
@@ -729,7 +813,7 @@ export function getEnvironmentInfo() {
|
|
|
729
813
|
|
|
730
814
|
let gitAvailable = false;
|
|
731
815
|
try {
|
|
732
|
-
|
|
816
|
+
runEnvironmentProbe("git", ["--version"], {
|
|
733
817
|
encoding: "utf-8",
|
|
734
818
|
timeout: 5000,
|
|
735
819
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -770,6 +854,7 @@ You have access to tools that let you read files, write files, edit files, run s
|
|
|
770
854
|
Key behaviors:
|
|
771
855
|
- When asked to modify code, read the file first, then edit it
|
|
772
856
|
- When asked to create something, use write_file to create it
|
|
857
|
+
- When asked to remove or rename a file, use delete_file or move_file so the filesystem intent is explicit and reviewable
|
|
773
858
|
- When asked to run/test something, use run_shell to execute it
|
|
774
859
|
- For long-running commands (builds, full test suites, dev servers) set run_shell { run_in_background: true } to get a task_id back immediately, then poll output and completion with check_shell { task_id }. Kill a backgrounded server with check_shell { task_id, kill: true } when finished
|
|
775
860
|
- When asked about git status, diff, log, or other repository operations, use the git tool instead of run_shell
|
|
@@ -926,6 +1011,9 @@ export function buildSystemPrompt(cwd, opts = {}) {
|
|
|
926
1011
|
const personaSkills = allSkills.filter(
|
|
927
1012
|
(s) => s.category === "persona" && s.activation === "auto",
|
|
928
1013
|
);
|
|
1014
|
+
if (typeof opts.onSkillsLoaded === "function") {
|
|
1015
|
+
opts.onSkillsLoaded(personaSkills);
|
|
1016
|
+
}
|
|
929
1017
|
for (const p of personaSkills) {
|
|
930
1018
|
if (p.body?.trim()) {
|
|
931
1019
|
prompt += `\n\n## Persona: ${p.displayName}\n${p.body}`;
|
|
@@ -1016,8 +1104,21 @@ const IDE_DIFF_EDIT_TOOLS = new Set([
|
|
|
1016
1104
|
"write_file",
|
|
1017
1105
|
"edit_file",
|
|
1018
1106
|
"edit_file_hashed",
|
|
1107
|
+
"delete_file",
|
|
1108
|
+
"move_file",
|
|
1109
|
+
]);
|
|
1110
|
+
const GUARDED_FILE_MUTATION_TOOLS = new Set([
|
|
1111
|
+
...IDE_DIFF_EDIT_TOOLS,
|
|
1112
|
+
"notebook_edit",
|
|
1019
1113
|
]);
|
|
1020
1114
|
|
|
1115
|
+
function fileMutationPaths(name, args = {}) {
|
|
1116
|
+
return [
|
|
1117
|
+
args.path,
|
|
1118
|
+
...(name === "move_file" ? [args.target_path] : []),
|
|
1119
|
+
].filter(Boolean);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1021
1122
|
/**
|
|
1022
1123
|
* Quote-aware shell tokenizer (mirrors gateways/ws `tokenizeCommand`). The `git`
|
|
1023
1124
|
* tool runs the model-supplied command via argv (spawnSync, NO shell), so a
|
|
@@ -1086,12 +1187,11 @@ function applyLiteralEdit(content, oldStr, newStr, replaceAll) {
|
|
|
1086
1187
|
/**
|
|
1087
1188
|
* Compute the content an edit tool WOULD write, without writing it — the
|
|
1088
1189
|
* left/right sides for an IDE diff review. Mirrors the corresponding
|
|
1089
|
-
* executeToolInner cases exactly (
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
* own diagnostics.
|
|
1190
|
+
* executeToolInner cases exactly (write/edit/delete/move; hashed edits use the
|
|
1191
|
+
* same pure replaceByHash). Returns an explicit operation plus the left/right
|
|
1192
|
+
* text and optional rename destination, or null when the proposal cannot be
|
|
1193
|
+
* computed — the caller then falls back to normal confirmation so the tool can
|
|
1194
|
+
* produce its own diagnostics.
|
|
1095
1195
|
*/
|
|
1096
1196
|
export function computeProposedEdit(name, args = {}, cwd = process.cwd()) {
|
|
1097
1197
|
try {
|
|
@@ -1099,10 +1199,49 @@ export function computeProposedEdit(name, args = {}, cwd = process.cwd()) {
|
|
|
1099
1199
|
const filePath = path.resolve(cwd, args.path);
|
|
1100
1200
|
if (name === "write_file") {
|
|
1101
1201
|
if (typeof args.content !== "string") return null;
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1202
|
+
const exists = fs.existsSync(filePath);
|
|
1203
|
+
const originalText = exists ? fs.readFileSync(filePath, "utf8") : "";
|
|
1204
|
+
return {
|
|
1205
|
+
filePath,
|
|
1206
|
+
newContent: args.content,
|
|
1207
|
+
originalText,
|
|
1208
|
+
operation: exists ? "modify" : "create",
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
if (name === "delete_file") {
|
|
1212
|
+
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
1213
|
+
return null;
|
|
1214
|
+
}
|
|
1215
|
+
const originalText = fs.readFileSync(filePath, "utf8");
|
|
1216
|
+
return {
|
|
1217
|
+
filePath,
|
|
1218
|
+
newContent: "",
|
|
1219
|
+
originalText,
|
|
1220
|
+
operation: "delete",
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
if (name === "move_file") {
|
|
1224
|
+
if (
|
|
1225
|
+
!args.target_path ||
|
|
1226
|
+
!fs.existsSync(filePath) ||
|
|
1227
|
+
fs.statSync(filePath).isDirectory()
|
|
1228
|
+
) {
|
|
1229
|
+
return null;
|
|
1230
|
+
}
|
|
1231
|
+
const targetPath = path.resolve(cwd, args.target_path);
|
|
1232
|
+
if (targetPath === filePath || fs.existsSync(targetPath)) return null;
|
|
1233
|
+
const targetDir = path.dirname(targetPath);
|
|
1234
|
+
if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
1237
|
+
const originalText = fs.readFileSync(filePath, "utf8");
|
|
1238
|
+
return {
|
|
1239
|
+
filePath,
|
|
1240
|
+
targetPath,
|
|
1241
|
+
newContent: originalText,
|
|
1242
|
+
originalText,
|
|
1243
|
+
operation: "rename",
|
|
1244
|
+
};
|
|
1106
1245
|
}
|
|
1107
1246
|
if (name === "edit_file") {
|
|
1108
1247
|
if (!fs.existsSync(filePath)) return null;
|
|
@@ -1124,7 +1263,12 @@ export function computeProposedEdit(name, args = {}, cwd = process.cwd()) {
|
|
|
1124
1263
|
// No match, or a non-unique match without replace_all → the edit will be
|
|
1125
1264
|
// rejected, so show no (misleading) diff and let the tool report it.
|
|
1126
1265
|
if (count === 0 || (count > 1 && !replaceAll)) return null;
|
|
1127
|
-
return {
|
|
1266
|
+
return {
|
|
1267
|
+
filePath,
|
|
1268
|
+
newContent,
|
|
1269
|
+
originalText: content,
|
|
1270
|
+
operation: "modify",
|
|
1271
|
+
};
|
|
1128
1272
|
}
|
|
1129
1273
|
if (name === "edit_file_hashed") {
|
|
1130
1274
|
if (!fs.existsSync(filePath)) return null;
|
|
@@ -1136,7 +1280,12 @@ export function computeProposedEdit(name, args = {}, cwd = process.cwd()) {
|
|
|
1136
1280
|
newLine: args.new_line,
|
|
1137
1281
|
});
|
|
1138
1282
|
if (!result.success) return null;
|
|
1139
|
-
return {
|
|
1283
|
+
return {
|
|
1284
|
+
filePath,
|
|
1285
|
+
newContent: result.content,
|
|
1286
|
+
originalText: original,
|
|
1287
|
+
operation: "modify",
|
|
1288
|
+
};
|
|
1140
1289
|
}
|
|
1141
1290
|
} catch {
|
|
1142
1291
|
// unreadable file etc. → no proposal, normal path handles it
|
|
@@ -1184,6 +1333,11 @@ async function tryIdeDiffApprovalForEdit(
|
|
|
1184
1333
|
modifiedText: proposal.newContent,
|
|
1185
1334
|
originalText: proposal.originalText,
|
|
1186
1335
|
title: `cc agent: ${name} ${path.basename(proposal.filePath)}`,
|
|
1336
|
+
operation: proposal.operation,
|
|
1337
|
+
targetPath: proposal.targetPath,
|
|
1338
|
+
sessionId: context.sessionId || null,
|
|
1339
|
+
turnId: context.turnId || null,
|
|
1340
|
+
toolUseId: context.toolCallId || null,
|
|
1187
1341
|
});
|
|
1188
1342
|
if (verdict?.outcome === "accepted") {
|
|
1189
1343
|
// When the reviewer amended the proposal in the diff before accepting,
|
|
@@ -1196,24 +1350,32 @@ async function tryIdeDiffApprovalForEdit(
|
|
|
1196
1350
|
: null;
|
|
1197
1351
|
return {
|
|
1198
1352
|
outcome: "accepted",
|
|
1199
|
-
result:
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
? {
|
|
1205
|
-
:
|
|
1206
|
-
|
|
1207
|
-
|
|
1353
|
+
result: attachDiffReviewAudit(
|
|
1354
|
+
{
|
|
1355
|
+
success: true,
|
|
1356
|
+
path: proposal.filePath,
|
|
1357
|
+
operation: proposal.operation,
|
|
1358
|
+
...(proposal.targetPath ? { targetPath: proposal.targetPath } : {}),
|
|
1359
|
+
appliedVia: "ide-diff",
|
|
1360
|
+
...(amendments
|
|
1361
|
+
? { userEdited: true, userAmendments: amendments }
|
|
1362
|
+
: {}),
|
|
1363
|
+
policy: { decision: "allow", rule, via: "ide-diff" },
|
|
1364
|
+
},
|
|
1365
|
+
verdict.audit,
|
|
1366
|
+
),
|
|
1208
1367
|
};
|
|
1209
1368
|
}
|
|
1210
1369
|
if (verdict?.outcome === "rejected") {
|
|
1211
1370
|
return {
|
|
1212
1371
|
outcome: "rejected",
|
|
1213
|
-
result:
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1372
|
+
result: attachDiffReviewAudit(
|
|
1373
|
+
{
|
|
1374
|
+
error: `[Permission] "${name}" was rejected in the IDE diff review (${source}: ${rule}).`,
|
|
1375
|
+
policy: { decision: "deny", rule, via: "ide-diff" },
|
|
1376
|
+
},
|
|
1377
|
+
verdict.audit,
|
|
1378
|
+
),
|
|
1217
1379
|
};
|
|
1218
1380
|
}
|
|
1219
1381
|
if (verdict?.outcome === "changes-requested") {
|
|
@@ -1225,14 +1387,17 @@ async function tryIdeDiffApprovalForEdit(
|
|
|
1225
1387
|
"The user requested changes in the IDE diff review (no specific notes).";
|
|
1226
1388
|
return {
|
|
1227
1389
|
outcome: "changes-requested",
|
|
1228
|
-
result:
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1390
|
+
result: attachDiffReviewAudit(
|
|
1391
|
+
{
|
|
1392
|
+
error:
|
|
1393
|
+
`[IDE review] "${name}" was NOT applied — the user requested changes:\n` +
|
|
1394
|
+
`${feedback}\n` +
|
|
1395
|
+
"Revise the edit to address this feedback, then propose it again.",
|
|
1396
|
+
policy: { decision: "deny", rule, via: "ide-diff-review" },
|
|
1397
|
+
reviewComments: verdict.comments,
|
|
1398
|
+
},
|
|
1399
|
+
verdict.audit,
|
|
1400
|
+
),
|
|
1236
1401
|
};
|
|
1237
1402
|
}
|
|
1238
1403
|
} catch (_err) {
|
|
@@ -1241,6 +1406,20 @@ async function tryIdeDiffApprovalForEdit(
|
|
|
1241
1406
|
return null;
|
|
1242
1407
|
}
|
|
1243
1408
|
|
|
1409
|
+
/**
|
|
1410
|
+
* Keep the audit available to stream/WS ledger consumers without serializing
|
|
1411
|
+
* it into the model-facing tool result (which would waste context tokens).
|
|
1412
|
+
*/
|
|
1413
|
+
function attachDiffReviewAudit(result, audit) {
|
|
1414
|
+
if (!result || typeof result !== "object" || !audit) return result;
|
|
1415
|
+
Object.defineProperty(result, "_diffReviewAudit", {
|
|
1416
|
+
value: audit,
|
|
1417
|
+
enumerable: false,
|
|
1418
|
+
configurable: true,
|
|
1419
|
+
});
|
|
1420
|
+
return result;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1244
1423
|
/**
|
|
1245
1424
|
* Execute a single tool call with plan-mode filtering and hook pipeline.
|
|
1246
1425
|
*
|
|
@@ -1264,6 +1443,56 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1264
1443
|
: null;
|
|
1265
1444
|
const runtimeDescriptor =
|
|
1266
1445
|
getRuntimeToolDescriptor(name) || localToolDescriptor;
|
|
1446
|
+
const admission = context.toolAdmission;
|
|
1447
|
+
if (admission?.enforce === true) {
|
|
1448
|
+
const override =
|
|
1449
|
+
admission.tools && typeof admission.tools === "object"
|
|
1450
|
+
? admission.tools[name] || {}
|
|
1451
|
+
: {};
|
|
1452
|
+
const tier =
|
|
1453
|
+
override.tier ||
|
|
1454
|
+
runtimeDescriptor?.tier ||
|
|
1455
|
+
getCodingAgentToolPolicy(name)?.tier ||
|
|
1456
|
+
(localToolDescriptor ? "extension" : "mvp");
|
|
1457
|
+
const decision = admitTool({
|
|
1458
|
+
tool: name,
|
|
1459
|
+
tier,
|
|
1460
|
+
capabilityGranted:
|
|
1461
|
+
override.capabilityGranted ?? admission.capabilityGranted,
|
|
1462
|
+
policyAllowed:
|
|
1463
|
+
override.policyAllowed ??
|
|
1464
|
+
(context.hostManagedToolPolicy
|
|
1465
|
+
? (context.hostManagedToolPolicy?.tools ||
|
|
1466
|
+
context.hostManagedToolPolicy?.toolPolicies ||
|
|
1467
|
+
{})[name]?.allowed !== false
|
|
1468
|
+
: admission.policyAllowed),
|
|
1469
|
+
permissionGranted:
|
|
1470
|
+
override.permissionGranted ?? admission.permissionGranted,
|
|
1471
|
+
budgetOk: override.budgetOk ?? admission.budgetOk,
|
|
1472
|
+
uiSupported: override.uiSupported ?? admission.uiSupported,
|
|
1473
|
+
});
|
|
1474
|
+
const attribution = buildToolAttribution({
|
|
1475
|
+
tool: name,
|
|
1476
|
+
source:
|
|
1477
|
+
override.source ||
|
|
1478
|
+
runtimeDescriptor?.source ||
|
|
1479
|
+
localToolDescriptor?.source ||
|
|
1480
|
+
admission.source ||
|
|
1481
|
+
null,
|
|
1482
|
+
version: override.version || runtimeDescriptor?.version || null,
|
|
1483
|
+
scope: override.scope || localToolDescriptor?.scope || null,
|
|
1484
|
+
callId: context.toolCallId || null,
|
|
1485
|
+
decision,
|
|
1486
|
+
});
|
|
1487
|
+
if (!decision.admitted) {
|
|
1488
|
+
return {
|
|
1489
|
+
error: `[Tool Admission] Tool "${name}" was not admitted: ${decision.unmet.join(", ")}.`,
|
|
1490
|
+
toolAttribution: attribution,
|
|
1491
|
+
policy: { decision: "blocked", via: "tool-admission" },
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
context = { ...context, toolAttribution: attribution };
|
|
1495
|
+
}
|
|
1267
1496
|
const toolContext = createToolContext({
|
|
1268
1497
|
toolName: runtimeDescriptor?.name || name,
|
|
1269
1498
|
cwd,
|
|
@@ -1397,26 +1626,29 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1397
1626
|
// An explicit settings `allow` rule is the only bypass (exact user
|
|
1398
1627
|
// pre-authorization); headless without a confirmer fails closed.
|
|
1399
1628
|
if (
|
|
1400
|
-
(name
|
|
1401
|
-
|
|
1402
|
-
name === "notebook_edit") &&
|
|
1403
|
-
settingsVerdict.decision !== "allow" &&
|
|
1404
|
-
args?.path
|
|
1629
|
+
GUARDED_FILE_MUTATION_TOOLS.has(name) &&
|
|
1630
|
+
settingsVerdict.decision !== "allow"
|
|
1405
1631
|
) {
|
|
1406
1632
|
const { sensitiveFileReason, autoExecConfigReason } =
|
|
1407
1633
|
await import("../lib/sensitive-file-guard.js");
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1410
|
-
|
|
1634
|
+
const guarded = fileMutationPaths(name, args)
|
|
1635
|
+
.map((candidatePath) => ({
|
|
1636
|
+
path: candidatePath,
|
|
1637
|
+
reason:
|
|
1638
|
+
sensitiveFileReason(candidatePath) ||
|
|
1639
|
+
autoExecConfigReason(candidatePath),
|
|
1640
|
+
}))
|
|
1641
|
+
.find((candidate) => candidate.reason);
|
|
1642
|
+
if (guarded) {
|
|
1411
1643
|
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
1412
1644
|
tool: name,
|
|
1413
1645
|
args,
|
|
1414
1646
|
rule: null,
|
|
1415
|
-
reason: `sensitive file: ${
|
|
1647
|
+
reason: `sensitive file: ${guarded.reason}`,
|
|
1416
1648
|
});
|
|
1417
1649
|
if (!ok) {
|
|
1418
1650
|
return {
|
|
1419
|
-
error: `[Sensitive File]
|
|
1651
|
+
error: `[Sensitive File] Mutating "${guarded.path}" requires confirmation (${guarded.reason}) — denied. Add a settings allow rule to pre-authorize.`,
|
|
1420
1652
|
policy: { decision: "ask", via: "sensitive-file" },
|
|
1421
1653
|
};
|
|
1422
1654
|
}
|
|
@@ -1430,25 +1662,27 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1430
1662
|
// sensitive-file guard: confirm-first, an explicit settings `allow` rule is
|
|
1431
1663
|
// the only bypass, headless without a confirmer fails closed.
|
|
1432
1664
|
if (
|
|
1433
|
-
(name
|
|
1434
|
-
|
|
1435
|
-
name === "notebook_edit") &&
|
|
1436
|
-
settingsVerdict.decision !== "allow" &&
|
|
1437
|
-
args?.path
|
|
1665
|
+
GUARDED_FILE_MUTATION_TOOLS.has(name) &&
|
|
1666
|
+
settingsVerdict.decision !== "allow"
|
|
1438
1667
|
) {
|
|
1439
1668
|
const { sessionStorePathReason } =
|
|
1440
1669
|
await import("../lib/session-store-guard.js");
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1670
|
+
const guarded = fileMutationPaths(name, args)
|
|
1671
|
+
.map((candidatePath) => ({
|
|
1672
|
+
path: candidatePath,
|
|
1673
|
+
reason: sessionStorePathReason(candidatePath, { cwd }),
|
|
1674
|
+
}))
|
|
1675
|
+
.find((candidate) => candidate.reason);
|
|
1676
|
+
if (guarded) {
|
|
1443
1677
|
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
1444
1678
|
tool: name,
|
|
1445
1679
|
args,
|
|
1446
1680
|
rule: null,
|
|
1447
|
-
reason: `session store: ${
|
|
1681
|
+
reason: `session store: ${guarded.reason}`,
|
|
1448
1682
|
});
|
|
1449
1683
|
if (!ok) {
|
|
1450
1684
|
return {
|
|
1451
|
-
error: `[Session Store]
|
|
1685
|
+
error: `[Session Store] Mutating "${guarded.path}" would modify a session transcript (${guarded.reason}) — denied. Add a settings allow rule to pre-authorize.`,
|
|
1452
1686
|
policy: { decision: "ask", via: "session-store-guard" },
|
|
1453
1687
|
};
|
|
1454
1688
|
}
|
|
@@ -1532,31 +1766,42 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1532
1766
|
}
|
|
1533
1767
|
}
|
|
1534
1768
|
|
|
1535
|
-
// Plan mode:
|
|
1769
|
+
// Plan mode: settings/host allow rules may help exploration, but they cannot
|
|
1770
|
+
// widen the immutable tool set issued when the user approved the plan.
|
|
1771
|
+
const executionLockActive = planManager.executionLock != null;
|
|
1536
1772
|
if (
|
|
1537
1773
|
planManager.isActive() &&
|
|
1538
|
-
!ruleAllowed &&
|
|
1774
|
+
(!ruleAllowed || executionLockActive) &&
|
|
1539
1775
|
!(name === "git" && isReadOnlyGitCommand(args.command)) &&
|
|
1540
1776
|
!planManager.isToolAllowed(name) &&
|
|
1541
|
-
!(
|
|
1542
|
-
|
|
1777
|
+
!(
|
|
1778
|
+
!executionLockActive &&
|
|
1779
|
+
isExternalHostTool &&
|
|
1780
|
+
hostToolPolicy?.allowed === true
|
|
1781
|
+
) &&
|
|
1782
|
+
!(!executionLockActive && localReadOnlyAllowedInPlanMode)
|
|
1543
1783
|
) {
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1784
|
+
if (!executionLockActive) {
|
|
1785
|
+
planManager.addPlanItem({
|
|
1786
|
+
title: `${name}: ${formatToolArgs(name, args)}`,
|
|
1787
|
+
tool: name,
|
|
1788
|
+
params: args,
|
|
1789
|
+
estimatedImpact:
|
|
1790
|
+
name === "run_shell" ||
|
|
1791
|
+
name === "run_code" ||
|
|
1792
|
+
name === "git" ||
|
|
1793
|
+
localToolDescriptor?.riskLevel === "high"
|
|
1794
|
+
? "high"
|
|
1795
|
+
: GUARDED_FILE_MUTATION_TOOLS.has(name) ||
|
|
1796
|
+
localToolDescriptor?.riskLevel === "medium"
|
|
1797
|
+
? "medium"
|
|
1798
|
+
: "low",
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1558
1801
|
return {
|
|
1559
|
-
error:
|
|
1802
|
+
error: executionLockActive
|
|
1803
|
+
? `[Plan Execution Lock] Tool "${name}" was not in the approved tool set. Request a plan revision before using it.`
|
|
1804
|
+
: `[Plan Mode] Tool "${name}" is blocked during planning. It has been added to the plan. Use /plan approve to execute.`,
|
|
1560
1805
|
};
|
|
1561
1806
|
}
|
|
1562
1807
|
|
|
@@ -1636,6 +1881,8 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1636
1881
|
settingsHooks: context.settingsHooks || null,
|
|
1637
1882
|
signal: context.signal || null,
|
|
1638
1883
|
backgroundSubAgents: context.backgroundSubAgents || null,
|
|
1884
|
+
toolAdmission: context.toolAdmission || null,
|
|
1885
|
+
unattendedActionPolicy: context.unattendedActionPolicy || null,
|
|
1639
1886
|
});
|
|
1640
1887
|
} catch (err) {
|
|
1641
1888
|
if (hookDb) {
|
|
@@ -1663,6 +1910,9 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1663
1910
|
});
|
|
1664
1911
|
if (toolResult && typeof toolResult === "object") {
|
|
1665
1912
|
toolResult.toolTelemetryRecord = telemetryRecord;
|
|
1913
|
+
if (context.toolAttribution) {
|
|
1914
|
+
toolResult.toolAttribution = context.toolAttribution;
|
|
1915
|
+
}
|
|
1666
1916
|
}
|
|
1667
1917
|
|
|
1668
1918
|
// PostToolUse hook
|
|
@@ -1717,6 +1967,7 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1717
1967
|
const outcome = runCommandHooks(sync, payload, {
|
|
1718
1968
|
cwd,
|
|
1719
1969
|
event: "PostToolUse",
|
|
1970
|
+
broker,
|
|
1720
1971
|
});
|
|
1721
1972
|
if (outcome.decision === "block" && outcome.reason) {
|
|
1722
1973
|
toolResult.hookFeedback = outcome.reason;
|
|
@@ -1725,7 +1976,7 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1725
1976
|
// Fire-and-forget the async hooks onto the REPL-owned supervisor when
|
|
1726
1977
|
// one is wired; results/rewakes drain into the next turn's context.
|
|
1727
1978
|
if (asyncHooks.length > 0 && context.hookSupervisor) {
|
|
1728
|
-
context.hookSupervisor.dispatch(asyncHooks, payload, { cwd });
|
|
1979
|
+
context.hookSupervisor.dispatch(asyncHooks, payload, { cwd, broker });
|
|
1729
1980
|
}
|
|
1730
1981
|
}
|
|
1731
1982
|
} catch (_err) {
|
|
@@ -2433,6 +2684,8 @@ async function executeToolInner(
|
|
|
2433
2684
|
signal = null,
|
|
2434
2685
|
backgroundSubAgents = null,
|
|
2435
2686
|
subAgentUsageSink = null,
|
|
2687
|
+
toolAdmission = null,
|
|
2688
|
+
unattendedActionPolicy = null,
|
|
2436
2689
|
// Hook-envelope tracing: this run's trace id, threaded into child loops
|
|
2437
2690
|
// (spawn_sub_agent / isolated run_skill) as their parent_id.
|
|
2438
2691
|
hookTraceId = null,
|
|
@@ -2599,6 +2852,86 @@ async function executeToolInner(
|
|
|
2599
2852
|
);
|
|
2600
2853
|
}
|
|
2601
2854
|
|
|
2855
|
+
case "delete_file": {
|
|
2856
|
+
if (!args.path) {
|
|
2857
|
+
return attachDescriptor({ error: "path is required" });
|
|
2858
|
+
}
|
|
2859
|
+
const filePath = path.resolve(cwd, args.path);
|
|
2860
|
+
if (!fs.existsSync(filePath)) {
|
|
2861
|
+
return attachDescriptor({ error: `File not found: ${filePath}` });
|
|
2862
|
+
}
|
|
2863
|
+
if (fs.lstatSync(filePath).isDirectory()) {
|
|
2864
|
+
return attachDescriptor({
|
|
2865
|
+
error: `Refusing to delete a directory: ${filePath}`,
|
|
2866
|
+
});
|
|
2867
|
+
}
|
|
2868
|
+
const stale = _checkFileFreshness(filePath);
|
|
2869
|
+
if (stale) return attachDescriptor({ error: stale });
|
|
2870
|
+
fs.unlinkSync(filePath);
|
|
2871
|
+
_fileObservedMtimes.delete(filePath);
|
|
2872
|
+
return attachDescriptor({
|
|
2873
|
+
success: true,
|
|
2874
|
+
path: filePath,
|
|
2875
|
+
operation: "delete",
|
|
2876
|
+
});
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
case "move_file": {
|
|
2880
|
+
if (!args.path || !args.target_path) {
|
|
2881
|
+
return attachDescriptor({
|
|
2882
|
+
error: "path and target_path are required",
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2885
|
+
const filePath = path.resolve(cwd, args.path);
|
|
2886
|
+
const targetPath = path.resolve(cwd, args.target_path);
|
|
2887
|
+
if (filePath === targetPath) {
|
|
2888
|
+
return attachDescriptor({
|
|
2889
|
+
error: "Source and target paths are the same",
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
if (!fs.existsSync(filePath)) {
|
|
2893
|
+
return attachDescriptor({ error: `File not found: ${filePath}` });
|
|
2894
|
+
}
|
|
2895
|
+
if (fs.lstatSync(filePath).isDirectory()) {
|
|
2896
|
+
return attachDescriptor({
|
|
2897
|
+
error: `Refusing to move a directory: ${filePath}`,
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
if (fs.existsSync(targetPath)) {
|
|
2901
|
+
return attachDescriptor({
|
|
2902
|
+
error: `Move target already exists: ${targetPath}`,
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
const targetDir = path.dirname(targetPath);
|
|
2906
|
+
if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
|
|
2907
|
+
return attachDescriptor({
|
|
2908
|
+
error: `Move target directory not found: ${targetDir}`,
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
const stale = _checkFileFreshness(filePath);
|
|
2912
|
+
if (stale) return attachDescriptor({ error: stale });
|
|
2913
|
+
fs.renameSync(filePath, targetPath);
|
|
2914
|
+
_fileObservedMtimes.delete(filePath);
|
|
2915
|
+
_recordFileObservation(targetPath);
|
|
2916
|
+
return attachDescriptor(
|
|
2917
|
+
await _withSubtreeInstructions(
|
|
2918
|
+
await _withPostEditDiagnostics(
|
|
2919
|
+
{
|
|
2920
|
+
success: true,
|
|
2921
|
+
path: filePath,
|
|
2922
|
+
targetPath,
|
|
2923
|
+
operation: "rename",
|
|
2924
|
+
},
|
|
2925
|
+
targetPath,
|
|
2926
|
+
cwd,
|
|
2927
|
+
additionalDirectories,
|
|
2928
|
+
),
|
|
2929
|
+
targetPath,
|
|
2930
|
+
cwd,
|
|
2931
|
+
),
|
|
2932
|
+
);
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2602
2935
|
case "notebook_edit": {
|
|
2603
2936
|
const filePath = path.resolve(cwd, args.path);
|
|
2604
2937
|
if (!fs.existsSync(filePath)) {
|
|
@@ -2763,6 +3096,23 @@ async function executeToolInner(
|
|
|
2763
3096
|
}
|
|
2764
3097
|
|
|
2765
3098
|
case "run_shell": {
|
|
3099
|
+
if (unattendedActionPolicy?.unattended === true) {
|
|
3100
|
+
const unattendedVerdict = evaluateUnattendedShellAction(args.command, {
|
|
3101
|
+
...unattendedActionPolicy,
|
|
3102
|
+
attended: false,
|
|
3103
|
+
});
|
|
3104
|
+
if (!unattendedVerdict.allow) {
|
|
3105
|
+
return attachDescriptor({
|
|
3106
|
+
error: `[Unattended Action] ${unattendedVerdict.reason}; shell command was not run.`,
|
|
3107
|
+
unattendedAction: {
|
|
3108
|
+
actionClass: unattendedVerdict.actionClass || null,
|
|
3109
|
+
...unattendedVerdict,
|
|
3110
|
+
},
|
|
3111
|
+
policy: { decision: "deny", via: "unattended-action-policy" },
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
|
|
2766
3116
|
const shellPolicyOpts = {
|
|
2767
3117
|
...(shellPolicyOverrides
|
|
2768
3118
|
? { overrideRuleIds: shellPolicyOverrides }
|
|
@@ -2877,6 +3227,28 @@ async function executeToolInner(
|
|
|
2877
3227
|
: {}
|
|
2878
3228
|
: { shell: shellInv.kind };
|
|
2879
3229
|
|
|
3230
|
+
// PATH-based plugin binaries need explicit provenance at the Broker
|
|
3231
|
+
// boundary; otherwise a trusted plugin executable is indistinguishable
|
|
3232
|
+
// from an ambient system command in the process audit log.
|
|
3233
|
+
let pluginBinProvenance = null;
|
|
3234
|
+
try {
|
|
3235
|
+
const { resolvePluginBinCommand } =
|
|
3236
|
+
await import("../lib/plugin-runtime/bin.js");
|
|
3237
|
+
pluginBinProvenance = resolvePluginBinCommand(args.command, { cwd });
|
|
3238
|
+
} catch {
|
|
3239
|
+
pluginBinProvenance = null;
|
|
3240
|
+
}
|
|
3241
|
+
const processOrigin = pluginBinProvenance
|
|
3242
|
+
? "plugin:bin"
|
|
3243
|
+
: "tool:run_shell";
|
|
3244
|
+
const processProvenance = pluginBinProvenance
|
|
3245
|
+
? {
|
|
3246
|
+
pluginId: pluginBinProvenance.pluginId,
|
|
3247
|
+
pluginVersion: pluginBinProvenance.pluginVersion,
|
|
3248
|
+
pluginSource: pluginBinProvenance.pluginSource,
|
|
3249
|
+
}
|
|
3250
|
+
: {};
|
|
3251
|
+
|
|
2880
3252
|
// Background: spawn, register, return a task_id immediately. The agent
|
|
2881
3253
|
// polls output + completion via check_shell. No timeout — that's the whole
|
|
2882
3254
|
// point of backgrounding (builds, test suites, dev servers).
|
|
@@ -2936,9 +3308,16 @@ async function executeToolInner(
|
|
|
2936
3308
|
};
|
|
2937
3309
|
// PowerShell route: explicit argv (shell:false above); default route
|
|
2938
3310
|
// is the historical spawn(command, {shell:true}) byte-for-byte.
|
|
3311
|
+
const brokerOpts = {
|
|
3312
|
+
...bgSpawnOpts,
|
|
3313
|
+
origin: processOrigin,
|
|
3314
|
+
policy: "allow",
|
|
3315
|
+
scope: "agent",
|
|
3316
|
+
...processProvenance,
|
|
3317
|
+
};
|
|
2939
3318
|
const child = shellInv.useDefaultShell
|
|
2940
|
-
? spawn(args.command,
|
|
2941
|
-
: spawn(shellInv.file, shellInv.argv,
|
|
3319
|
+
? broker.spawn(args.command, [], brokerOpts)
|
|
3320
|
+
: broker.spawn(shellInv.file, shellInv.argv, brokerOpts);
|
|
2942
3321
|
task.child = child;
|
|
2943
3322
|
if (child.stdout) {
|
|
2944
3323
|
child.stdout.setEncoding("utf8");
|
|
@@ -3111,15 +3490,22 @@ async function executeToolInner(
|
|
|
3111
3490
|
}).env,
|
|
3112
3491
|
};
|
|
3113
3492
|
let output;
|
|
3493
|
+
const brokerExecOpts = {
|
|
3494
|
+
...fgExecOpts,
|
|
3495
|
+
origin: processOrigin,
|
|
3496
|
+
policy: "allow",
|
|
3497
|
+
scope: "agent",
|
|
3498
|
+
...processProvenance,
|
|
3499
|
+
};
|
|
3114
3500
|
if (shellInv.useDefaultShell) {
|
|
3115
|
-
output = execSync(args.command,
|
|
3501
|
+
output = broker.execSync(args.command, brokerExecOpts);
|
|
3116
3502
|
} else {
|
|
3117
3503
|
// PowerShell route: explicit argv, no intermediate default shell.
|
|
3118
3504
|
// Reproduce execSync's contract so the shared catch shapes errors
|
|
3119
3505
|
// identically: throw on spawn error; throw an Error carrying
|
|
3120
3506
|
// status/stdout/stderr on non-zero exit.
|
|
3121
|
-
const res = spawnSync(shellInv.file, shellInv.argv, {
|
|
3122
|
-
...
|
|
3507
|
+
const res = broker.spawnSync(shellInv.file, shellInv.argv, {
|
|
3508
|
+
...brokerExecOpts,
|
|
3123
3509
|
windowsHide: true,
|
|
3124
3510
|
});
|
|
3125
3511
|
if (res.error) throw res.error;
|
|
@@ -3238,12 +3624,15 @@ async function executeToolInner(
|
|
|
3238
3624
|
// command-execution bypass for a prompt-injected agent. Quoted args (a
|
|
3239
3625
|
// commit message) keep their content via the quote-aware tokenizer.
|
|
3240
3626
|
const gitArgs = tokenizeShellWords(normalizedCommand);
|
|
3241
|
-
const res =
|
|
3627
|
+
const res = _gitProcessDeps.run("git", gitArgs, {
|
|
3242
3628
|
cwd: args.cwd || cwd,
|
|
3243
3629
|
encoding: "utf8",
|
|
3244
3630
|
timeout: 60000,
|
|
3245
3631
|
maxBuffer: 1024 * 1024,
|
|
3246
3632
|
windowsHide: true,
|
|
3633
|
+
origin: "agent-core:git-command",
|
|
3634
|
+
policy: "allow",
|
|
3635
|
+
scope: "agent-core",
|
|
3247
3636
|
});
|
|
3248
3637
|
const readOnly = isReadOnlyGitCommand(normalizedCommand);
|
|
3249
3638
|
if (res.error) {
|
|
@@ -3351,6 +3740,7 @@ async function executeToolInner(
|
|
|
3351
3740
|
signal,
|
|
3352
3741
|
backgroundSubAgents,
|
|
3353
3742
|
subAgentUsageSink,
|
|
3743
|
+
toolAdmission,
|
|
3354
3744
|
}),
|
|
3355
3745
|
);
|
|
3356
3746
|
}
|
|
@@ -3843,7 +4233,7 @@ async function executeToolInner(
|
|
|
3843
4233
|
};
|
|
3844
4234
|
try {
|
|
3845
4235
|
if (!fs.existsSync(root)) continue;
|
|
3846
|
-
const output =
|
|
4236
|
+
const output = runSearchProcess(cmd, {
|
|
3847
4237
|
cwd: root,
|
|
3848
4238
|
encoding: "utf8",
|
|
3849
4239
|
timeout: 10000,
|
|
@@ -4057,6 +4447,7 @@ async function executeToolInner(
|
|
|
4057
4447
|
task: `Execute the "${args.skill_name}" skill with input: ${(args.input || "").substring(0, 200)}`,
|
|
4058
4448
|
allowedTools: ["read_file", "search_files", "list_dir"],
|
|
4059
4449
|
hookParentTraceId: hookTraceId || null,
|
|
4450
|
+
toolAdmission,
|
|
4060
4451
|
cwd,
|
|
4061
4452
|
onUsage: skillUsageSink
|
|
4062
4453
|
? (u) => {
|
|
@@ -4113,7 +4504,7 @@ async function executeToolInner(
|
|
|
4113
4504
|
onWarn: (msg) => {
|
|
4114
4505
|
// Non-fatal — logged as warning, skipped servers captured
|
|
4115
4506
|
// in mountResult.skipped.
|
|
4116
|
-
|
|
4507
|
+
|
|
4117
4508
|
console.warn(msg);
|
|
4118
4509
|
},
|
|
4119
4510
|
});
|
|
@@ -4448,7 +4839,7 @@ async function _executeRunCode(args, cwd) {
|
|
|
4448
4839
|
const start = Date.now();
|
|
4449
4840
|
let output;
|
|
4450
4841
|
try {
|
|
4451
|
-
output =
|
|
4842
|
+
output = runCodeProcess(interpreter, [scriptPath], {
|
|
4452
4843
|
cwd,
|
|
4453
4844
|
encoding: "utf8",
|
|
4454
4845
|
timeout: timeoutSec * 1000,
|
|
@@ -4548,12 +4939,18 @@ async function _executeRunCode(args, cwd) {
|
|
|
4548
4939
|
|
|
4549
4940
|
// Attempt pip install
|
|
4550
4941
|
try {
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4942
|
+
runCodeProcess(
|
|
4943
|
+
interpreter,
|
|
4944
|
+
["-m", "pip", "install", packageName],
|
|
4945
|
+
{
|
|
4946
|
+
cwd,
|
|
4947
|
+
encoding: "utf-8",
|
|
4948
|
+
timeout: 120000,
|
|
4949
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
4950
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
4951
|
+
},
|
|
4952
|
+
"run-code-install",
|
|
4953
|
+
);
|
|
4557
4954
|
recordInstallAudit({
|
|
4558
4955
|
package: packageName,
|
|
4559
4956
|
interpreter,
|
|
@@ -4564,12 +4961,17 @@ async function _executeRunCode(args, cwd) {
|
|
|
4564
4961
|
|
|
4565
4962
|
// Retry execution
|
|
4566
4963
|
const retryStart = Date.now();
|
|
4567
|
-
const retryOutput =
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4964
|
+
const retryOutput = runCodeProcess(
|
|
4965
|
+
interpreter,
|
|
4966
|
+
[scriptPath],
|
|
4967
|
+
{
|
|
4968
|
+
cwd,
|
|
4969
|
+
encoding: "utf8",
|
|
4970
|
+
timeout: timeoutSec * 1000,
|
|
4971
|
+
maxBuffer: 5 * 1024 * 1024,
|
|
4972
|
+
},
|
|
4973
|
+
"run-code-retry",
|
|
4974
|
+
);
|
|
4573
4975
|
const retryDuration = Date.now() - retryStart;
|
|
4574
4976
|
|
|
4575
4977
|
return {
|
|
@@ -5290,10 +5692,29 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
5290
5692
|
// seeded with the mode's tier gates the child's run_shell / browser_act;
|
|
5291
5693
|
// absent (ungated) for a plain default spawn = byte-identical.
|
|
5292
5694
|
...(childApprovalGate ? { approvalGate: childApprovalGate } : {}),
|
|
5695
|
+
...(ctx.toolAdmission ? { toolAdmission: ctx.toolAdmission } : {}),
|
|
5293
5696
|
});
|
|
5294
5697
|
subCtxRef = subCtx;
|
|
5295
5698
|
|
|
5296
5699
|
const emit = (type, payload) => {
|
|
5700
|
+
if (type === "sub-agent.started") {
|
|
5701
|
+
emitHooksV2Event("TaskCreated", {
|
|
5702
|
+
task_id: subCtx.id,
|
|
5703
|
+
session_id: parentSessionId,
|
|
5704
|
+
role: subCtx.role,
|
|
5705
|
+
task: subCtx.task,
|
|
5706
|
+
background: payload?.background === true,
|
|
5707
|
+
});
|
|
5708
|
+
} else if (type === "sub-agent.completed" || type === "sub-agent.failed") {
|
|
5709
|
+
emitHooksV2Event("TaskCompleted", {
|
|
5710
|
+
task_id: subCtx.id,
|
|
5711
|
+
session_id: parentSessionId,
|
|
5712
|
+
role: subCtx.role,
|
|
5713
|
+
status: type === "sub-agent.failed" ? "failed" : "completed",
|
|
5714
|
+
error: payload?.error || null,
|
|
5715
|
+
completed_at: payload?.completedAt || null,
|
|
5716
|
+
});
|
|
5717
|
+
}
|
|
5297
5718
|
if (!interaction || typeof interaction.emit !== "function") return;
|
|
5298
5719
|
try {
|
|
5299
5720
|
interaction.emit(type, {
|
|
@@ -6915,6 +7336,12 @@ export async function* agentLoop(messages, options) {
|
|
|
6915
7336
|
hostManagedToolPolicy: options.hostManagedToolPolicy || null,
|
|
6916
7337
|
externalToolDescriptors: options.externalToolDescriptors || null,
|
|
6917
7338
|
externalToolExecutors: options.externalToolExecutors || null,
|
|
7339
|
+
// Optional session-level Extension Tier gate. Hosts that can provide
|
|
7340
|
+
// capability/policy/permission/budget/UI signals opt in with
|
|
7341
|
+
// { enforce: true }; omitting it preserves the CLI's existing per-call
|
|
7342
|
+
// permission pipeline for backwards compatibility.
|
|
7343
|
+
toolAdmission: options.toolAdmission || null,
|
|
7344
|
+
unattendedActionPolicy: options.unattendedActionPolicy || null,
|
|
6918
7345
|
// MCP tool DEFINITIONS the LLM sees (mcp__server__tool). Threaded here so a
|
|
6919
7346
|
// spawn can inherit the parent's MCP tools into the child (filtered by the
|
|
6920
7347
|
// contract's mcpServers allow-list). Otherwise consumed only at agentLoop.
|
|
@@ -7607,11 +8034,11 @@ export async function* agentLoop(messages, options) {
|
|
|
7607
8034
|
} catch {
|
|
7608
8035
|
toolArgs = {};
|
|
7609
8036
|
}
|
|
7610
|
-
const promise = executeTool(
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
).then(
|
|
8037
|
+
const promise = executeTool(call.function.name, toolArgs, {
|
|
8038
|
+
...toolContext,
|
|
8039
|
+
toolCallId: call.id,
|
|
8040
|
+
turnId: `${runId}:t${budget.consumed}`,
|
|
8041
|
+
}).then(
|
|
7615
8042
|
(result) => ({ result, error: null }),
|
|
7616
8043
|
(err) => ({ result: { error: err.message }, error: err.message }),
|
|
7617
8044
|
);
|
|
@@ -7724,7 +8151,12 @@ export async function* agentLoop(messages, options) {
|
|
|
7724
8151
|
recorder,
|
|
7725
8152
|
"agent.tool",
|
|
7726
8153
|
{ "tool.name": toolName, ...(toolIdAttrs || {}) },
|
|
7727
|
-
() =>
|
|
8154
|
+
() =>
|
|
8155
|
+
executeTool(toolName, toolArgs, {
|
|
8156
|
+
...toolContext,
|
|
8157
|
+
toolCallId: call.id,
|
|
8158
|
+
turnId: `${runId}:t${budget.consumed}`,
|
|
8159
|
+
}),
|
|
7728
8160
|
(span, r) => {
|
|
7729
8161
|
span.setAttribute(
|
|
7730
8162
|
"tool.is_error",
|
|
@@ -7819,6 +8251,10 @@ export function formatToolArgs(name, args) {
|
|
|
7819
8251
|
return args.path;
|
|
7820
8252
|
case "edit_file_hashed":
|
|
7821
8253
|
return `${args.path} @${args.anchor_hash}`;
|
|
8254
|
+
case "delete_file":
|
|
8255
|
+
return args.path;
|
|
8256
|
+
case "move_file":
|
|
8257
|
+
return `${args.path} → ${args.target_path}`;
|
|
7822
8258
|
case "run_shell":
|
|
7823
8259
|
return args.run_in_background
|
|
7824
8260
|
? `${args.command} (background)`
|