chainlesschain 0.162.154 → 0.162.156
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/README.md +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-CIpoXyVI.js → AIOps-DjBXlypQ.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Ch_QXIPk.js → ActionButton-Cv9er9bp.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CvaBYShv.js → Analytics-CLKDjSNs.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-CfyZNzmJ.js +9 -0
- package/src/assets/web-panel/assets/{Audit-Bng8eHCW.js → Audit-CXafD178.js} +1 -1
- package/src/assets/web-panel/assets/BackgroundAgents-CP5c-GSd.js +1 -0
- package/src/assets/web-panel/assets/BackgroundAgents-Dq2340Kl.css +1 -0
- package/src/assets/web-panel/assets/{Backup-DvBs8-lm.js → Backup-BbYLQfyt.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DKwajm0g.js → BaseInput-Bqe0MwZL.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BoGpZ3uO.js → Chat-jNA_yUPH.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-mDQl_PXO.js → ChatBubbleRenderer-BOFLF01s.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BMJEmxFQ.js → Checkbox-Dlzz-zD1.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Bsoag5CV.js → Codegen-BAsDQjGf.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CDjH9-sp.js → Col-Ju0HrAuS.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Cg2QHPQ6.js → Community-DynJd43Z.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BU2BaqP-.js → Compact-CabbZVww.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-D6ZYMCqZ.js → Compliance-DW4BmAoh.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DaZ8VW-I.js → Cowork-Bk1S_7X-.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DQY1RH9v.js → Cron-By4sh_NM.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BVR28vk9.js → Crosschain-DdZdbS1C.js} +1 -1
- package/src/assets/web-panel/assets/{DID-N44KvTP-.js → DID-CkL-sQyS.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Bjhlx6wS.js → Dashboard-g_mOpumg.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CpLYxpy1.js → Dropdown-DtHyE7Ao.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-srEITSPI.js → EmailListRenderer-Kpvov5Wr.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-juOC_fX2.js → FamilyGuardDashboard-C4kZoePR.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-nRaQtaXW.js → Federation-BAwWoK2N.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DflhTj09.js → FormItemContext-DeI0i5f8.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DulI_3NI.js → GenericCardRenderer-CkcKRtos.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BxOPefXn.js → Git-kX6jjI9y.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C6G_Wnwi.js → Governance-BXJCBm6x.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BnFYa2BF.js → Inference-ujD2JSKo.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-TqQLEabm.js → KnowledgeGraph-3Dnuf1Wh.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BH4AVh7s.js → Logs-lVAZCtUB.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-DoWLTaEE.js → Marketplace-qnzNPm-A.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D6yC7OG_.js → McpTools-CqjzefRU.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-DLCeHj21.js → Memory-BFiPAxk6.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BZBE0GRl.js → MobileBridge-D0O43VwF.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DJA15G1J.js → MobileProjects-B3now48t.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CyTKJDHn.js → Mtc-DybhtaCS.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-DZKjgEVc.js → MtcAudit-D7MmY4F0.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-2rMPNhSO.js → Multisig-wZvGJnB8.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-VeMk4Fx-.js → NLProgramming-BNPpgfvn.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-jr2GHMhh.js → Notes-B6FS3KBj.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-WN9VZyFb.js → NotificationSettings-CK0yla9U.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CXfPHIpy.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DdjVHuzT.js → Organization-geqgwN1T.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-l8vBsGGq.js → Overflow-BWJYZFbC.js} +1 -1
- package/src/assets/web-panel/assets/{OverrideContext-BlgL9440.js → OverrideContext-C0w0P4A3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CVQDHHwq.js → P2P-DnU1505F.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CTsNh8qE.js → PdhVaultBrowser-BGY74KnC.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DLW87uyK.js → Permissions-CgArrWtQ.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-N8OvASTx.js → PersonalDataHub-C2vYE61a.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BPZmdlz2.js → Pipeline-CBYLI4yW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-MFZw_GNh.js → Privacy-B-PdW9aN.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-zW0pEsfU.js → ProjectInit-CuWQegbV.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CppVHr_o.js → ProjectSettings-4d32m_cS.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BTglkJO2.js → Projects-VLA7ttwd.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CPHZ6JKT.js → Providers-B_Izb_oa.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DO4klNZ2.js → QrScannerModal-C6B_ndXV.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-B37TTqUa.js → QuickAsk-C6tavL-y.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-n7KIfK7y.js → Recommend-CF-LaZ6x.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-SjVoS9mm.js → RemoteSession-DBqTTQ9_.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Dt6RTeHi.js → Reputation-B01FALUi.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Dty6jz5V.js → Row-DO0fd48A.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DDLhqw5j.js → RssFeed-BV5LDzFR.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DrYbXi-W.js → Search-CTti4_MP.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Fc9Z6fbB.js → Security-DwSrWRCw.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BAhPgjSM.js → Services-BEf1QyM4.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-8JF7EPfE.js → Skeleton-LZXTpovy.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DL39dY0t.js → Skills-SKgc0Zug.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CSvjcATc.js → Sla-C_QVOtkN.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Demx7Gnx.js → SpeechSettings-v5TW2V-X.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CKLnRWJr.js → SyncSettings-CQPjHdqU.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-DCd-uYcI.js +1 -0
- package/src/assets/web-panel/assets/{Templates-AjQI5rxD.js → Templates-62VDIjtj.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-dbtEh1yR.js → Tenant-BnFQ0pNy.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DX-9jjfk.js → Terminal-D3v0MGSj.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C11EDZRt.js → TimelineRenderer-BI1Ka-cu.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-GiA9fiZn.js → Tokens-BwX1jXYP.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BPcnclJn.js → Trigger-CSA8TqNx.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-C-DVY8nq.js → Trust-Bn3IjCx7.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DxodSwME.js → UkeySign-pUbOAqNi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D_WV0O8O.js → VideoEditing-Db2RercF.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DSeNlVSU.js → Wallet-CpR1BVAl.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Bwuuvpz1.js → WebAuthn-Yxtkn7Zp.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-8M96EU1N.js → WorkflowEditor-CYLe9a2E.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D5S6SmLm.js → chat-gsOGdak0.js} +1 -1
- package/src/assets/web-panel/assets/{collapseMotion-DVfhbsdP.js → collapseMotion-CqM1QOwM.js} +1 -1
- package/src/assets/web-panel/assets/{colors-5fbnGkAP.js → colors-D9fN299a.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DaSuuMlW.js → compact-item-vkd7s-ay.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BNOHcXAF.js → createContext-C7YkbMyy.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DEcR2h6k.js +1 -0
- package/src/assets/web-panel/assets/{echarts-CL0F2SnX.js → echarts-C61Vn3mP.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-DONwZUra.js → hasIn-ig7reRSU.js} +1 -1
- package/src/assets/web-panel/assets/{icons-BsDmGpcT.js → icons-DEmcnxBf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJp4kRjw.js → index-9TxdMYju.js} +1 -1
- package/src/assets/web-panel/assets/{index-MOgO5Yvx.js → index-B7QRpKif.js} +1 -1
- package/src/assets/web-panel/assets/index-BEibanjg.js +1 -0
- package/src/assets/web-panel/assets/{index-CAYmc5Nh.js → index-BHHN_KTS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcWMZqb4.js → index-BMw48d19.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_yDD9Lm.js → index-BYe9HRSt.js} +1 -1
- package/src/assets/web-panel/assets/{index-xo2f4DZR.js → index-BfpVcXKa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbdQBn4n.js → index-BhftELHI.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd7xwGcD.js → index-BkP17Z95.js} +1 -1
- package/src/assets/web-panel/assets/{index-RkInlwV0.js → index-BpGlLbRv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM3Ug61e.js → index-Bt-9ZhIu.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrkCFohi.js → index-BvDEukXe.js} +1 -1
- package/src/assets/web-panel/assets/{index-_6S41ikV.js → index-C7AY39sg.js} +1 -1
- package/src/assets/web-panel/assets/{index-uR5KTNZA.js → index-C8HZMygt.js} +1 -1
- package/src/assets/web-panel/assets/{index-5_fj5gVd.js → index-CAkz1f1r.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLzMuz38.js → index-CDWTycrg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEO5f7Vf.js → index-CGzGe5tv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEzd5m5a.js → index-Co2NYyew.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcqOK7Lv.js → index-CspGymmg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DP2-3A_j.js → index-D2yhtk6a.js} +1 -1
- package/src/assets/web-panel/assets/{index-LRIt-AFl.js → index-D6s_kbjt.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4L3gsNA.js → index-DFM1oNe1.js} +1 -1
- package/src/assets/web-panel/assets/{index-KwV9g_cf.js → index-DFfxF7Vt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK2N5yVW.js → index-DPguq3X7.js} +4 -4
- package/src/assets/web-panel/assets/{index-Cf2OCa8q.js → index-DQ8U7kzC.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7gs_3Ck.js → index-DZAxCnjS.js} +1 -1
- package/src/assets/web-panel/assets/{index-PsMErAB1.js → index-DhdXbsXX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTZeOnzO.js → index-DuwbKHoS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dm5A-MN5.js → index-DvCJXmrx.js} +1 -1
- package/src/assets/web-panel/assets/{index-vYtprlNs.js → index-Dy_TKZ9h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHx2lhHW.js → index-FzGr6CVk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cn5LtyIH.js → index-PkH39qsp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmUOjyL6.js → index-SDrcQXO1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CztESwB4.js → index-W52sHRdr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSfYJqXt.js → index-bVbgYBhv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrAJSu-v.js → index-gj8kxcAi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLXf-8ek.js → index-gpurplyq.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClGqO-2X.js → index-nX8YE6cj.js} +1 -1
- package/src/assets/web-panel/assets/index-z_25tU3p.js +1 -0
- package/src/assets/web-panel/assets/{initDefaultProps-CxwLynp9.js → initDefaultProps-BrgfVRg9.js} +1 -1
- package/src/assets/web-panel/assets/{motion-XbPvGJbW.js → motion-D_3xmwac.js} +1 -1
- package/src/assets/web-panel/assets/{move-D1u5pcgS.js → move-DDDJdlxw.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BDxhTBMH.js → mtc-parser-BK2uEWwn.js} +1 -1
- package/src/assets/web-panel/assets/{omit-EtIFGg5k.js → omit-BPHKbDcf.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D33sWb0l.js → pickAttrs-LNnTscuz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BwFRzaGo.js → placementArrow-CvmTZll5.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CBk2WqvQ.js → responsiveObserve-eBj7qi2J.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B52HtrKn.js → slide-D68hHkrM.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D4qxqWnH.js → statusUtils-daTlaeo0.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BxaCFlOL.js → styleChecker-DtyKMtHB.js} +1 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-ekFwFs9h.js +1 -0
- package/src/assets/web-panel/assets/{useFs-C6VAU1_6.js → useFs-jRaSEoF4.js} +1 -1
- package/src/assets/web-panel/assets/{useMergedState-Dc9sO2d7.js → useMergedState-DXbJa_zE.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-rEG6oXG8.js → usePersonalDataHub-DD5nGzjA.js} +1 -1
- package/src/assets/web-panel/assets/{useRefs-CAeFRzPf.js → useRefs-BrCfMLMc.js} +1 -1
- package/src/assets/web-panel/assets/{useState-LwExUYDO.js → useState-CnxtbLoC.js} +1 -1
- package/src/assets/web-panel/assets/{vendor-BMxUs6UX.js → vendor-Bn1JzzAn.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DOTafkEi.js → vnode-KcgLUiom.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BuwwN5K2.js → zoom-Cyk2PQ-s.js} +1 -1
- package/src/assets/web-panel/index.html +3 -3
- package/src/command-manifest.json +50 -1
- package/src/commands/agenda.js +228 -0
- package/src/commands/agent.js +23 -2
- package/src/commands/agents.js +62 -1
- package/src/commands/auto-mode.js +87 -0
- package/src/commands/background-session.js +499 -0
- package/src/commands/batch.js +345 -0
- package/src/commands/command.js +4 -1
- package/src/commands/permissions.js +49 -0
- package/src/commands/remote-control.js +407 -0
- package/src/data/changelog.json +12 -2
- package/src/gateways/ws/background-agent-protocol.js +337 -0
- package/src/gateways/ws/message-dispatcher.js +10 -0
- package/src/gateways/ws/remote-session-protocol.js +102 -1
- package/src/gateways/ws/ws-server.js +61 -0
- package/src/harness/mcp-client.js +8 -0
- package/src/index.js +22 -0
- package/src/lib/agent-batch.js +235 -0
- package/src/lib/agent-notify.js +66 -0
- package/src/lib/agent-schedule-store.js +330 -0
- package/src/lib/auto-mode-config.js +396 -0
- package/src/lib/background-agent-supervisor.js +202 -17
- package/src/lib/background-session-transport.js +315 -0
- package/src/lib/permission-denial-store.js +159 -0
- package/src/lib/remote-approval-bridge.js +360 -0
- package/src/lib/remote-control.js +270 -0
- package/src/lib/repl-denials.js +26 -0
- package/src/lib/shell-approval.js +4 -0
- package/src/lib/ws-rpc-client.js +150 -0
- package/src/repl/agent-repl.js +208 -16
- package/src/repl/permission-tier.js +31 -0
- package/src/runtime/agent-core.js +161 -0
- package/src/runtime/coding-agent-contract-shared.cjs +104 -0
- package/src/runtime/coding-agent-policy.cjs +28 -0
- package/src/runtime/headless-runner.js +126 -8
- package/src/runtime/headless-stream.js +87 -1
- package/src/runtime/mcp-config.js +11 -0
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/policies/agent-policy.js +17 -0
- package/src/workers/background-agent-worker.js +218 -37
- package/src/assets/web-panel/assets/AppLayout-B6Q6olcr.js +0 -9
- package/src/assets/web-panel/assets/OrderTableRenderer-CjNO-e9T.js +0 -1
- package/src/assets/web-panel/assets/Tasks-mhITRxjv.js +0 -1
- package/src/assets/web-panel/assets/devWarning-K_woVElh.js +0 -1
- package/src/assets/web-panel/assets/index-3ILvaBpo.js +0 -1
- package/src/assets/web-panel/assets/index-JpB-FoZq.js +0 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-B1lWlqXN.js +0 -1
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
toOllamaMessages,
|
|
65
65
|
imageUrlBlockToAnthropic,
|
|
66
66
|
} from "../lib/image-input.js";
|
|
67
|
+
import { executeToolSearch, gateDeferredMcpCall } from "./mcp-tool-search.js";
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* Names of MCP servers currently mounted by an in-flight run_skill call.
|
|
@@ -1439,6 +1440,7 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1439
1440
|
additionalDirectories: context.additionalDirectories || null,
|
|
1440
1441
|
sandbox: context.sandbox || null,
|
|
1441
1442
|
ruleAllowed,
|
|
1443
|
+
settingsVerdict,
|
|
1442
1444
|
subAgentDepth: context.subAgentDepth || 0,
|
|
1443
1445
|
subAgentBudget: context.subAgentBudget || null,
|
|
1444
1446
|
interactiveApproval: context.interactiveApproval || false,
|
|
@@ -2057,6 +2059,7 @@ async function executeToolInner(
|
|
|
2057
2059
|
additionalDirectories,
|
|
2058
2060
|
sandbox,
|
|
2059
2061
|
ruleAllowed = false,
|
|
2062
|
+
settingsVerdict = null,
|
|
2060
2063
|
subAgentDepth = 0,
|
|
2061
2064
|
subAgentBudget = null,
|
|
2062
2065
|
interactiveApproval = false,
|
|
@@ -2338,6 +2341,40 @@ async function executeToolInner(
|
|
|
2338
2341
|
: {}),
|
|
2339
2342
|
...(classifyAllShell ? { classifyAllShell: true } : {}),
|
|
2340
2343
|
};
|
|
2344
|
+
// Layer-by-layer explanation chain for a blocked command: which layers
|
|
2345
|
+
// were consulted and what each said (settings rules → shell policy →
|
|
2346
|
+
// approval gate). Attached to denial results so `/permissions denials`
|
|
2347
|
+
// and `cc permissions recent` can explain WHY, not just THAT.
|
|
2348
|
+
const buildPermissionChain = (gated) => {
|
|
2349
|
+
const chain = [
|
|
2350
|
+
{
|
|
2351
|
+
layer: "settings-rules",
|
|
2352
|
+
outcome:
|
|
2353
|
+
settingsVerdict?.decision || (ruleAllowed ? "allow" : "no-match"),
|
|
2354
|
+
rule: settingsVerdict?.rule || null,
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
layer: "shell-policy",
|
|
2358
|
+
outcome: shellPolicy?.decision || null,
|
|
2359
|
+
rule: shellPolicy?.ruleId || null,
|
|
2360
|
+
reason: shellPolicy?.reason || null,
|
|
2361
|
+
},
|
|
2362
|
+
];
|
|
2363
|
+
// A hard shell-policy deny returns before the gate is consulted
|
|
2364
|
+
// (via === "shell-policy") — no approval-gate layer to explain then.
|
|
2365
|
+
if (gated && gated.via !== "shell-policy") {
|
|
2366
|
+
chain.push({
|
|
2367
|
+
layer: "approval-gate",
|
|
2368
|
+
outcome: gated.decision,
|
|
2369
|
+
via: gated.via || null,
|
|
2370
|
+
policy: gated.policy || null,
|
|
2371
|
+
riskLevel: gated.riskLevel || null,
|
|
2372
|
+
rule: gated.gateRule || null,
|
|
2373
|
+
reason: gated.gateReason || null,
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
return chain;
|
|
2377
|
+
};
|
|
2341
2378
|
const override = getRuntimeToolDescriptorByCommand(args.command);
|
|
2342
2379
|
let shellPolicy;
|
|
2343
2380
|
let approvalOutcome = null;
|
|
@@ -2375,6 +2412,7 @@ async function executeToolInner(
|
|
|
2375
2412
|
: `[ApprovalGate] command denied by the ${tierLabel}approval policy (via ${gated.via}). Retrying the same command will not help — it needs user approval. Tell the user (they can run it themselves, approve it, or relax the policy) and continue with other work.`,
|
|
2376
2413
|
shellCommandPolicy: shellPolicy,
|
|
2377
2414
|
approval: approvalOutcome,
|
|
2415
|
+
permissionChain: buildPermissionChain(gated),
|
|
2378
2416
|
},
|
|
2379
2417
|
override || runtimeDescriptor,
|
|
2380
2418
|
);
|
|
@@ -2386,6 +2424,7 @@ async function executeToolInner(
|
|
|
2386
2424
|
{
|
|
2387
2425
|
error: `[Shell Policy] ${shellPolicy.reason} This command is blocked by policy and will not run — do not retry it; find another approach.`,
|
|
2388
2426
|
shellCommandPolicy: shellPolicy,
|
|
2427
|
+
permissionChain: buildPermissionChain(null),
|
|
2389
2428
|
},
|
|
2390
2429
|
override || runtimeDescriptor,
|
|
2391
2430
|
);
|
|
@@ -2971,6 +3010,100 @@ async function executeToolInner(
|
|
|
2971
3010
|
}
|
|
2972
3011
|
}
|
|
2973
3012
|
|
|
3013
|
+
case "notify": {
|
|
3014
|
+
try {
|
|
3015
|
+
const { sendAgentNotification } =
|
|
3016
|
+
await import("../lib/agent-notify.js");
|
|
3017
|
+
const outcome = await sendAgentNotification({
|
|
3018
|
+
title: args.title,
|
|
3019
|
+
body: args.body,
|
|
3020
|
+
level: args.level,
|
|
3021
|
+
});
|
|
3022
|
+
return attachDescriptor(outcome);
|
|
3023
|
+
} catch (err) {
|
|
3024
|
+
return attachDescriptor({ error: `notify failed: ${err.message}` });
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
case "schedule": {
|
|
3029
|
+
try {
|
|
3030
|
+
const { AgentScheduleStore } =
|
|
3031
|
+
await import("../lib/agent-schedule-store.js");
|
|
3032
|
+
const { parseDuration } = await import("../lib/loop.js");
|
|
3033
|
+
const store = new AgentScheduleStore();
|
|
3034
|
+
const action = String(args.action || "").toLowerCase();
|
|
3035
|
+
if (action === "wakeup") {
|
|
3036
|
+
if (!args.prompt) {
|
|
3037
|
+
return attachDescriptor({
|
|
3038
|
+
error: "schedule wakeup requires a prompt",
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
const delayMs = args.delay ? parseDuration(args.delay) : 0;
|
|
3042
|
+
const entry = store.scheduleWakeup({
|
|
3043
|
+
prompt: args.prompt,
|
|
3044
|
+
delayMs,
|
|
3045
|
+
label: args.label || null,
|
|
3046
|
+
});
|
|
3047
|
+
return attachDescriptor({
|
|
3048
|
+
scheduled: entry,
|
|
3049
|
+
hint: "Run `cc agenda run` (e.g. via cron or `cc loop`) to fire due entries.",
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
if (action === "cron") {
|
|
3053
|
+
if (!args.prompt || !args.cron) {
|
|
3054
|
+
return attachDescriptor({
|
|
3055
|
+
error: "schedule cron requires a prompt and a cron expression",
|
|
3056
|
+
});
|
|
3057
|
+
}
|
|
3058
|
+
const entry = store.createCron({
|
|
3059
|
+
prompt: args.prompt,
|
|
3060
|
+
cron: args.cron,
|
|
3061
|
+
label: args.label || null,
|
|
3062
|
+
});
|
|
3063
|
+
return attachDescriptor({ scheduled: entry });
|
|
3064
|
+
}
|
|
3065
|
+
if (action === "monitor") {
|
|
3066
|
+
if (!args.command) {
|
|
3067
|
+
return attachDescriptor({
|
|
3068
|
+
error: "schedule monitor requires a command",
|
|
3069
|
+
});
|
|
3070
|
+
}
|
|
3071
|
+
const intervalMs = args.interval
|
|
3072
|
+
? parseDuration(args.interval)
|
|
3073
|
+
: 60000;
|
|
3074
|
+
const entry = store.createMonitor({
|
|
3075
|
+
command: args.command,
|
|
3076
|
+
intervalMs,
|
|
3077
|
+
stopWhen: args.stop_when || null,
|
|
3078
|
+
notify: args.notify_title ? { title: args.notify_title } : null,
|
|
3079
|
+
maxChecks: args.max_checks ?? null,
|
|
3080
|
+
label: args.label || null,
|
|
3081
|
+
});
|
|
3082
|
+
return attachDescriptor({ scheduled: entry });
|
|
3083
|
+
}
|
|
3084
|
+
if (action === "list") {
|
|
3085
|
+
return attachDescriptor({ entries: store.list() });
|
|
3086
|
+
}
|
|
3087
|
+
if (action === "cancel") {
|
|
3088
|
+
if (!args.id) {
|
|
3089
|
+
return attachDescriptor({
|
|
3090
|
+
error: "schedule cancel requires an id",
|
|
3091
|
+
});
|
|
3092
|
+
}
|
|
3093
|
+
const removed = store.cancel(args.id);
|
|
3094
|
+
return attachDescriptor({
|
|
3095
|
+
cancelled: removed ? removed.id : null,
|
|
3096
|
+
found: Boolean(removed),
|
|
3097
|
+
});
|
|
3098
|
+
}
|
|
3099
|
+
return attachDescriptor({
|
|
3100
|
+
error: `unknown schedule action "${args.action}". Valid: wakeup, cron, monitor, list, cancel.`,
|
|
3101
|
+
});
|
|
3102
|
+
} catch (err) {
|
|
3103
|
+
return attachDescriptor({ error: `schedule failed: ${err.message}` });
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
|
|
2974
3107
|
case "search_files": {
|
|
2975
3108
|
// An explicit directory scopes the search to one root; otherwise span
|
|
2976
3109
|
// cwd plus any --add-dir roots so cross-package searches find matches.
|
|
@@ -3347,6 +3480,15 @@ async function executeToolInner(
|
|
|
3347
3480
|
}
|
|
3348
3481
|
}
|
|
3349
3482
|
|
|
3483
|
+
// Internal tool-search tool (MCP context scaling): resolves deferred
|
|
3484
|
+
// MCP tool schemas from the registry attached at setup time. Read-only,
|
|
3485
|
+
// local — same risk class as list_skills, so no approval gate.
|
|
3486
|
+
if (localToolExecutor?.kind === "tool-search") {
|
|
3487
|
+
return attachDescriptor(
|
|
3488
|
+
executeToolSearch(localToolExecutor.registry, args || {}),
|
|
3489
|
+
);
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3350
3492
|
if (localToolExecutor?.kind === "mcp") {
|
|
3351
3493
|
if (!mcpClient || typeof mcpClient.callTool !== "function") {
|
|
3352
3494
|
return attachDescriptor({
|
|
@@ -3354,6 +3496,15 @@ async function executeToolInner(
|
|
|
3354
3496
|
});
|
|
3355
3497
|
}
|
|
3356
3498
|
|
|
3499
|
+
// Deferred-schema gate: a direct call to a tool whose schema was never
|
|
3500
|
+
// loaded returns a self-healing error embedding the schema (and marks
|
|
3501
|
+
// it loaded), instead of forwarding likely-malformed arguments to the
|
|
3502
|
+
// server. No-op unless tool search deferred this tool.
|
|
3503
|
+
const deferredGate = gateDeferredMcpCall(name, localToolExecutor);
|
|
3504
|
+
if (deferredGate) {
|
|
3505
|
+
return attachDescriptor(deferredGate);
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3357
3508
|
try {
|
|
3358
3509
|
const result = await mcpClient.callTool(
|
|
3359
3510
|
localToolExecutor.serverName,
|
|
@@ -6285,6 +6436,16 @@ export function formatToolArgs(name, args) {
|
|
|
6285
6436
|
return `[${args.role}] ${(args.task || "").substring(0, 60)}`;
|
|
6286
6437
|
case "search_sessions":
|
|
6287
6438
|
return `"${(args.query || "").substring(0, 60)}"`;
|
|
6439
|
+
case "notify":
|
|
6440
|
+
return `${args.level || "info"}: ${(args.title || "").substring(0, 50)}`;
|
|
6441
|
+
case "schedule":
|
|
6442
|
+
return args.action === "cron"
|
|
6443
|
+
? `cron ${args.cron || ""}`.trim()
|
|
6444
|
+
: args.action === "monitor"
|
|
6445
|
+
? `monitor ${(args.command || "").substring(0, 40)}`.trim()
|
|
6446
|
+
: args.action === "wakeup"
|
|
6447
|
+
? `wakeup +${args.delay || "0s"}`
|
|
6448
|
+
: String(args.action || "");
|
|
6288
6449
|
default:
|
|
6289
6450
|
return JSON.stringify(args).substring(0, 60);
|
|
6290
6451
|
}
|
|
@@ -849,6 +849,110 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
|
|
|
849
849
|
tags: ["tool:search_sessions", "contract:coding-agent", "tier:extension"],
|
|
850
850
|
},
|
|
851
851
|
},
|
|
852
|
+
{
|
|
853
|
+
name: "notify",
|
|
854
|
+
title: "Send Notification",
|
|
855
|
+
kind: "notify",
|
|
856
|
+
tier: "extension",
|
|
857
|
+
description:
|
|
858
|
+
"Push a notification to the user's configured channels (Telegram / WeCom / DingTalk / Feishu) and/or a paired mobile device. Use for long-running tasks: report completion, flag that you need a human decision, or surface an error. Best-effort: reports which channels delivered.",
|
|
859
|
+
inputSchema: {
|
|
860
|
+
type: "object",
|
|
861
|
+
properties: {
|
|
862
|
+
title: { type: "string", description: "Short notification title" },
|
|
863
|
+
body: { type: "string", description: "Notification body text" },
|
|
864
|
+
level: {
|
|
865
|
+
type: "string",
|
|
866
|
+
enum: ["info", "success", "failure"],
|
|
867
|
+
description: "Severity (default: info)",
|
|
868
|
+
},
|
|
869
|
+
},
|
|
870
|
+
required: ["title"],
|
|
871
|
+
},
|
|
872
|
+
...TOOL_POLICY_METADATA.notify,
|
|
873
|
+
permissions: {
|
|
874
|
+
level: "standard",
|
|
875
|
+
scopes: ["network:notify"],
|
|
876
|
+
},
|
|
877
|
+
telemetry: {
|
|
878
|
+
category: "notify",
|
|
879
|
+
tags: ["tool:notify", "contract:coding-agent", "tier:extension"],
|
|
880
|
+
},
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
name: "schedule",
|
|
884
|
+
title: "Schedule / Monitor",
|
|
885
|
+
kind: "schedule",
|
|
886
|
+
tier: "extension",
|
|
887
|
+
description:
|
|
888
|
+
"Set up work that outlives this turn (persisted for `cc agenda run` to execute). Actions: `wakeup` — run a prompt once after a delay; `cron` — run a prompt on a 5-field cron schedule; `monitor` — run a shell command every interval and notify when its output matches a regex; `list` — show scheduled items; `cancel` — remove one by id.",
|
|
889
|
+
inputSchema: {
|
|
890
|
+
type: "object",
|
|
891
|
+
properties: {
|
|
892
|
+
action: {
|
|
893
|
+
type: "string",
|
|
894
|
+
enum: ["wakeup", "cron", "monitor", "list", "cancel"],
|
|
895
|
+
description: "What to do",
|
|
896
|
+
},
|
|
897
|
+
prompt: {
|
|
898
|
+
type: "string",
|
|
899
|
+
description:
|
|
900
|
+
"For wakeup/cron: the agent prompt to run (via `cc agent -p`) when it fires",
|
|
901
|
+
},
|
|
902
|
+
delay: {
|
|
903
|
+
type: "string",
|
|
904
|
+
description:
|
|
905
|
+
"For wakeup: how long from now before it fires (e.g. 30s, 5m, 1h)",
|
|
906
|
+
},
|
|
907
|
+
cron: {
|
|
908
|
+
type: "string",
|
|
909
|
+
description:
|
|
910
|
+
'For cron: a 5-field cron expression, e.g. "0 9 * * 1" (09:00 every Monday)',
|
|
911
|
+
},
|
|
912
|
+
command: {
|
|
913
|
+
type: "string",
|
|
914
|
+
description: "For monitor: the shell command to run each interval",
|
|
915
|
+
},
|
|
916
|
+
interval: {
|
|
917
|
+
type: "string",
|
|
918
|
+
description:
|
|
919
|
+
"For monitor: how often to run the command (e.g. 30s, 5m)",
|
|
920
|
+
},
|
|
921
|
+
stop_when: {
|
|
922
|
+
type: "string",
|
|
923
|
+
description:
|
|
924
|
+
"For monitor: a regex; when the command output matches, the monitor fires its notification and stops",
|
|
925
|
+
},
|
|
926
|
+
notify_title: {
|
|
927
|
+
type: "string",
|
|
928
|
+
description: "For monitor: notification title sent when it matches",
|
|
929
|
+
},
|
|
930
|
+
max_checks: {
|
|
931
|
+
type: "number",
|
|
932
|
+
description:
|
|
933
|
+
"For monitor: give up after this many checks (optional safety cap)",
|
|
934
|
+
},
|
|
935
|
+
label: {
|
|
936
|
+
type: "string",
|
|
937
|
+
description: "Optional human label for list/cancel",
|
|
938
|
+
},
|
|
939
|
+
id: {
|
|
940
|
+
type: "string",
|
|
941
|
+
description: "For cancel: the schedule entry id to remove",
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
required: ["action"],
|
|
945
|
+
},
|
|
946
|
+
...TOOL_POLICY_METADATA.schedule,
|
|
947
|
+
permissions: {
|
|
948
|
+
level: "standard",
|
|
949
|
+
scopes: ["schedule:write"],
|
|
950
|
+
},
|
|
951
|
+
telemetry: {
|
|
952
|
+
category: "schedule",
|
|
953
|
+
tags: ["tool:schedule", "contract:coding-agent", "tier:extension"],
|
|
954
|
+
},
|
|
955
|
+
},
|
|
852
956
|
]);
|
|
853
957
|
|
|
854
958
|
const CODING_AGENT_MVP_TOOL_NAMES = Object.freeze(
|
|
@@ -261,6 +261,34 @@ const TOOL_POLICY_METADATA = Object.freeze({
|
|
|
261
261
|
approvalFlow: "auto",
|
|
262
262
|
isReadOnly: true,
|
|
263
263
|
},
|
|
264
|
+
// Sends an outbound notification to the user's own channels/device. No
|
|
265
|
+
// workspace mutation and no un-gated shell; blocked in plan mode (an
|
|
266
|
+
// external side effect) but otherwise auto — it targets the user, not a
|
|
267
|
+
// third party.
|
|
268
|
+
notify: {
|
|
269
|
+
riskLevel: RISK_LEVELS.LOW,
|
|
270
|
+
category: TOOL_CATEGORIES.WRITE,
|
|
271
|
+
availableInPlanMode: false,
|
|
272
|
+
planModeBehavior: "blocked",
|
|
273
|
+
requiresPlanApproval: false,
|
|
274
|
+
requiresConfirmation: false,
|
|
275
|
+
approvalFlow: "auto",
|
|
276
|
+
isReadOnly: false,
|
|
277
|
+
},
|
|
278
|
+
// Persists a wakeup/cron/monitor entry for `cc agenda run` to execute later.
|
|
279
|
+
// Writing the schedule is itself harmless (a JSONL row under the user's
|
|
280
|
+
// config dir); the eventual `cc agent`/shell run is gated when the agenda
|
|
281
|
+
// consumer executes it. Blocked in plan mode (schedules future side effects).
|
|
282
|
+
schedule: {
|
|
283
|
+
riskLevel: RISK_LEVELS.LOW,
|
|
284
|
+
category: TOOL_CATEGORIES.WRITE,
|
|
285
|
+
availableInPlanMode: false,
|
|
286
|
+
planModeBehavior: "blocked",
|
|
287
|
+
requiresPlanApproval: false,
|
|
288
|
+
requiresConfirmation: false,
|
|
289
|
+
approvalFlow: "auto",
|
|
290
|
+
isReadOnly: false,
|
|
291
|
+
},
|
|
264
292
|
});
|
|
265
293
|
|
|
266
294
|
function normalizeGitCommand(command) {
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
* Permission model: headless cannot show an interactive approval prompt, so the
|
|
16
16
|
* default is fail-closed (deny MEDIUM/HIGH-risk shell). --permission-mode opts
|
|
17
17
|
* into a looser tier:
|
|
18
|
-
* - (default) / plan
|
|
19
|
-
*
|
|
20
|
-
* -
|
|
18
|
+
* - (default) / manual / dontAsk / plan → STRICT + deny-confirmer
|
|
19
|
+
* (plan also restricts tools)
|
|
20
|
+
* - auto / acceptEdits → TRUSTED + deny-confirmer
|
|
21
|
+
* (HIGH-risk shell still denied)
|
|
22
|
+
* - bypassPermissions → AUTOPILOT (everything allowed)
|
|
21
23
|
*/
|
|
22
24
|
|
|
23
25
|
import { bootstrap } from "./bootstrap.js";
|
|
@@ -33,6 +35,7 @@ import {
|
|
|
33
35
|
resolvePermissionPromptTool,
|
|
34
36
|
makePermissionPromptConfirmer,
|
|
35
37
|
} from "./mcp-config.js";
|
|
38
|
+
import { maybeApplyToolSearch } from "./mcp-tool-search.js";
|
|
36
39
|
import { IterationBudget } from "../lib/iteration-budget.js";
|
|
37
40
|
import {
|
|
38
41
|
startSession as jsonlStartSession,
|
|
@@ -68,6 +71,9 @@ export const READ_ONLY_TOOLS = Object.freeze([
|
|
|
68
71
|
|
|
69
72
|
const VALID_PERMISSION_MODES = Object.freeze([
|
|
70
73
|
"default",
|
|
74
|
+
"manual",
|
|
75
|
+
"auto",
|
|
76
|
+
"dontAsk",
|
|
71
77
|
"plan",
|
|
72
78
|
"acceptEdits",
|
|
73
79
|
"bypassPermissions",
|
|
@@ -81,19 +87,30 @@ export { installPipeSafety } from "./pipe-safety.js";
|
|
|
81
87
|
import { installPipeSafety } from "./pipe-safety.js";
|
|
82
88
|
|
|
83
89
|
/**
|
|
84
|
-
*
|
|
85
|
-
* non-interactive confirmer + whether to clamp tools to the read-only set.
|
|
90
|
+
* Normalize a public --permission-mode spelling to the canonical internal mode.
|
|
86
91
|
*
|
|
87
|
-
* @param {string} mode
|
|
88
|
-
* @returns {
|
|
92
|
+
* @param {string} [mode]
|
|
93
|
+
* @returns {string}
|
|
89
94
|
*/
|
|
90
|
-
export function
|
|
95
|
+
export function normalizePermissionMode(mode = "default") {
|
|
91
96
|
const m = mode || "default";
|
|
92
97
|
if (!VALID_PERMISSION_MODES.includes(m)) {
|
|
93
98
|
throw new Error(
|
|
94
99
|
`Invalid --permission-mode "${m}". Expected one of: ${VALID_PERMISSION_MODES.join(", ")}`,
|
|
95
100
|
);
|
|
96
101
|
}
|
|
102
|
+
return m;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resolve a --permission-mode string into the session-policy tier + a
|
|
107
|
+
* non-interactive confirmer + whether to clamp tools to the read-only set.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} mode
|
|
110
|
+
* @returns {{ sessionPolicy: string, confirmer: (ctx:any)=>Promise<boolean>, readOnly: boolean, allowInteractiveApprovals: boolean }}
|
|
111
|
+
*/
|
|
112
|
+
export function resolvePermissionMode(mode = "default") {
|
|
113
|
+
const m = normalizePermissionMode(mode);
|
|
97
114
|
// Headless can't ask a human — deny when a confirm would be required.
|
|
98
115
|
const denyConfirmer = async () => false;
|
|
99
116
|
const allowConfirmer = async () => true;
|
|
@@ -103,25 +120,38 @@ export function resolvePermissionMode(mode = "default") {
|
|
|
103
120
|
sessionPolicy: "autopilot",
|
|
104
121
|
confirmer: allowConfirmer,
|
|
105
122
|
readOnly: false,
|
|
123
|
+
allowInteractiveApprovals: false,
|
|
106
124
|
};
|
|
125
|
+
case "auto":
|
|
107
126
|
case "acceptEdits":
|
|
108
127
|
return {
|
|
109
128
|
sessionPolicy: "trusted",
|
|
110
129
|
confirmer: denyConfirmer,
|
|
111
130
|
readOnly: false,
|
|
131
|
+
allowInteractiveApprovals: true,
|
|
112
132
|
};
|
|
113
133
|
case "plan":
|
|
114
134
|
return {
|
|
115
135
|
sessionPolicy: "strict",
|
|
116
136
|
confirmer: denyConfirmer,
|
|
117
137
|
readOnly: true,
|
|
138
|
+
allowInteractiveApprovals: true,
|
|
139
|
+
};
|
|
140
|
+
case "dontAsk":
|
|
141
|
+
return {
|
|
142
|
+
sessionPolicy: "strict",
|
|
143
|
+
confirmer: denyConfirmer,
|
|
144
|
+
readOnly: false,
|
|
145
|
+
allowInteractiveApprovals: false,
|
|
118
146
|
};
|
|
147
|
+
case "manual":
|
|
119
148
|
case "default":
|
|
120
149
|
default:
|
|
121
150
|
return {
|
|
122
151
|
sessionPolicy: "strict",
|
|
123
152
|
confirmer: denyConfirmer,
|
|
124
153
|
readOnly: false,
|
|
154
|
+
allowInteractiveApprovals: true,
|
|
125
155
|
};
|
|
126
156
|
}
|
|
127
157
|
}
|
|
@@ -610,6 +640,28 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
610
640
|
let approvalGate = null;
|
|
611
641
|
try {
|
|
612
642
|
approvalGate = await getApprovalGate();
|
|
643
|
+
if (approvalGate && (options.permissionMode || "default") === "auto") {
|
|
644
|
+
// autoMode.decisions: user-configured riskLevel → allow/ask/deny
|
|
645
|
+
// classifier. Only wrap when settings actually customize the map so the
|
|
646
|
+
// unconfigured auto path keeps the byte-identical trusted-tier mapping.
|
|
647
|
+
try {
|
|
648
|
+
const {
|
|
649
|
+
loadAutoModeConfig,
|
|
650
|
+
resolveAutoModeDecisions,
|
|
651
|
+
createAutoModeApprovalGate,
|
|
652
|
+
} = await import("../lib/auto-mode-config.js");
|
|
653
|
+
const autoConfig = loadAutoModeConfig({
|
|
654
|
+
cwd,
|
|
655
|
+
settingsFile: options.settingsFile,
|
|
656
|
+
});
|
|
657
|
+
const resolved = resolveAutoModeDecisions(autoConfig.effective);
|
|
658
|
+
if (resolved.customized) {
|
|
659
|
+
approvalGate = createAutoModeApprovalGate(approvalGate, resolved);
|
|
660
|
+
}
|
|
661
|
+
} catch {
|
|
662
|
+
// fail to the default trusted mapping — never block the run
|
|
663
|
+
}
|
|
664
|
+
}
|
|
613
665
|
if (approvalGate) {
|
|
614
666
|
if (typeof approvalGate.setSessionPolicy === "function") {
|
|
615
667
|
approvalGate.setSessionPolicy(sessionId, perm.sessionPolicy);
|
|
@@ -800,6 +852,22 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
800
852
|
writeErr(` mcp: ${c.server} (${c.tools} tools)\n`);
|
|
801
853
|
}
|
|
802
854
|
}
|
|
855
|
+
// MCP tool search (context scaling): when the tool schemas would eat a
|
|
856
|
+
// significant share of the context window, defer them behind the
|
|
857
|
+
// internal tool_search tool. Below-threshold / disabled → no-op, the
|
|
858
|
+
// wiring object is untouched.
|
|
859
|
+
if (mcp) {
|
|
860
|
+
try {
|
|
861
|
+
(deps.maybeApplyToolSearch || maybeApplyToolSearch)(mcp, {
|
|
862
|
+
model,
|
|
863
|
+
provider,
|
|
864
|
+
cwd: options.cwd || process.cwd(),
|
|
865
|
+
writeErr: isText ? writeErr : () => {},
|
|
866
|
+
});
|
|
867
|
+
} catch {
|
|
868
|
+
// best-effort — full schemas still work without deferral
|
|
869
|
+
}
|
|
870
|
+
}
|
|
803
871
|
} catch (err) {
|
|
804
872
|
writeErr(`Error: ${err.message}\n`);
|
|
805
873
|
emitHeadlessError(err.message);
|
|
@@ -861,6 +929,35 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
861
929
|
}
|
|
862
930
|
}
|
|
863
931
|
|
|
932
|
+
// --remote-control: route CONFIRM-tier approvals to paired mobile/web
|
|
933
|
+
// devices (第四阶段 #2). Self-hosts a lightweight WS server + approval
|
|
934
|
+
// bridge for THIS run's session, prints the pairing URI/QR to stderr, and
|
|
935
|
+
// installs the remote confirmer on the gate (same override point as
|
|
936
|
+
// --permission-prompt-tool; that flag wins when both are given since it is
|
|
937
|
+
// installed above and this block skips). Fail-closed on timeout.
|
|
938
|
+
let _remoteApproval = null;
|
|
939
|
+
if (options.remoteControl && !options.permissionPromptTool) {
|
|
940
|
+
try {
|
|
941
|
+
const { startHeadlessRemoteApproval } =
|
|
942
|
+
await import("../lib/remote-approval-bridge.js");
|
|
943
|
+
_remoteApproval = await (
|
|
944
|
+
deps.startHeadlessRemoteApproval || startHeadlessRemoteApproval
|
|
945
|
+
)({
|
|
946
|
+
agentSessionId: sessionId,
|
|
947
|
+
writeErr,
|
|
948
|
+
isText,
|
|
949
|
+
});
|
|
950
|
+
if (approvalGate && typeof approvalGate.setConfirmer === "function") {
|
|
951
|
+
approvalGate.setConfirmer(_remoteApproval.confirmer);
|
|
952
|
+
}
|
|
953
|
+
} catch (err) {
|
|
954
|
+
// Remote approval could not come up → keep headless fail-closed rather
|
|
955
|
+
// than running un-gated; say why so the user can fix pairing.
|
|
956
|
+
writeErr(` remote-control: unavailable (${err.message})\n`);
|
|
957
|
+
_remoteApproval = null;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
864
961
|
// --otlp <file>: attach an OpenTelemetry recorder so the real agent loop's
|
|
865
962
|
// model/tool/retry spans are captured and exported as OTLP/JSON on exit.
|
|
866
963
|
// Off by default (zero cost) — only built when a path is requested.
|
|
@@ -1350,6 +1447,15 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1350
1447
|
} catch {
|
|
1351
1448
|
// best-effort — never mask the run's own outcome
|
|
1352
1449
|
}
|
|
1450
|
+
// Tear down the --remote-control approval bridge + its self-hosted WS
|
|
1451
|
+
// server so the run's port/socket never outlives the invocation.
|
|
1452
|
+
if (_remoteApproval) {
|
|
1453
|
+
try {
|
|
1454
|
+
await _remoteApproval.close();
|
|
1455
|
+
} catch {
|
|
1456
|
+
// best-effort — never mask the run's own outcome
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1353
1459
|
// settings.json Stop + SessionEnd hooks when the run finishes. Stop is the
|
|
1354
1460
|
// canonical async-hook trigger ("run the test suite at turn end"); fire its
|
|
1355
1461
|
// async hooks fire-and-forget, then settle so a fast background check can
|
|
@@ -1502,6 +1608,18 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1502
1608
|
} else if (isStream) {
|
|
1503
1609
|
emitStream({ type: "denials_summary", count: denials.length, denials });
|
|
1504
1610
|
}
|
|
1611
|
+
try {
|
|
1612
|
+
const { appendRecentDenials } =
|
|
1613
|
+
await import("../lib/permission-denial-store.js");
|
|
1614
|
+
appendRecentDenials(denials, {
|
|
1615
|
+
sessionId,
|
|
1616
|
+
permissionMode: options.permissionMode || "default",
|
|
1617
|
+
cwd,
|
|
1618
|
+
source: "headless",
|
|
1619
|
+
});
|
|
1620
|
+
} catch {
|
|
1621
|
+
// Persisting the review surface is best-effort; never affect the run.
|
|
1622
|
+
}
|
|
1505
1623
|
}
|
|
1506
1624
|
|
|
1507
1625
|
if (isStream) {
|