chainlesschain 0.162.180 → 0.162.182
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 +7 -3
- package/scripts/build-windows-sandbox-helper.ps1 +163 -0
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-DzZ5_xoj.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-DeLXddIg.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-rvDCmet1.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-Yt6QVDnp.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-BS112K5L.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-0wJuQrNu.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-B90PMgbn.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-TkgMglQQ.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-CQVS9p1l.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-YTjQHoC7.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-5bwaOabq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-BFmNQ_Xe.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-BT_u4Dzp.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-CJP52u5b.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BpzhJE9i.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-Cg7rfslp.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-JisxL6Yy.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-Bu7Ug_MC.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CvuqoLdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-C2u9G8Pu.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-BFt5Yv3d.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-DIaT9Wxq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-D_A601Y4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard--IyQ8I8w.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-BihWHxuY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-BB8dOXc_.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-DQYhj1HH.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-B-2QZxGf.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-CusSb-nG.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BAjmvPPL.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-DoNYWKYq.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-B8fKWD-n.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-BlJm1J7E.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-CyOscbSL.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-Ex6Om5da.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CDcD8l8r.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-xfBqoFDg.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-BwObMMA2.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-CIWd36OV.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPX0ouuA.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-BDJsIUuW.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-DEkbuD3N.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-DJpHRhH1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-C1UZ-Qd5.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-GlJtqLjT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-Bbhj0fac.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-1H04x3kx.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CDpPe3et.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-MUX0Bpvw.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-A07-0Ci1.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-DhhDWxAZ.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-CyfbJfe-.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-CNFps3ED.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit--T-u3Dr5.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-DJmrK2fC.js} +2 -2
- package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-DLzzbOZd.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-CexOomKS.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-QklGi19_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-Bb9kwSw8.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-DZuVNNN5.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-Dr5cLP0N.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-oCQHYv5t.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-IFDEykIR.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-CspVIxDc.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Bm66o_DH.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-DvanNqXl.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-CHjEe9_O.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-Cb8jWjMX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-DxZm1491.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-DWxEEclC.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-FIvOFw5p.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +1 -0
- package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-CaNjzV_t.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-DjlP6TmH.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-DoZ8y7y8.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-390cg2TC.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-CLrtCj5_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-DpESfSPn.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-CN6279O0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DPtAUlSe.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-nKOMV_1n.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-HuXlSOc4.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-CUfFjARi.js} +1 -1
- package/src/assets/web-panel/assets/chat-6Eq0PcZJ.js +1 -0
- package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BP_Sf6Iy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-BufMKIh5.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BBMXxWSW.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-fUK_tRO2.js} +1 -1
- package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-2A5ph8b2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-3FuwBewR.js} +1 -1
- package/src/assets/web-panel/assets/{index-53z1YUxX.js → index-6GmBa4Kg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-B2vS66eI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-B7Etk0Te.js} +1 -1
- package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-B9WYSn4m.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-BHy6yNiF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-BMLHv389.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-BWKoBU8R.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-Bkg4ZePE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-C44atv4k.js} +1 -1
- package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-CE2DdTP2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-CGjmILDm.js} +1 -1
- package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-CW_G-MXw.js} +1 -1
- package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-CZ6Yt17L.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-CeASi4fr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-CgiECHu2.js} +1 -1
- package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Cp8vhyZy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-CwSf5pnf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-D4_MuGkd.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-D9vU25ij.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-DASluSqY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-DLpIs_P_.js} +1 -1
- package/src/assets/web-panel/assets/index-DOZTSoS7.js +1 -0
- package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DPdUNk1i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-DVsqvI4M.js} +1 -1
- package/src/assets/web-panel/assets/index-DhpvjpqI.js +1 -0
- package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-DmkMXwnR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-DocdRcbd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-Dyngbd29.js} +20 -20
- package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-GwdRUZ-x.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-LvCBfTLo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhXay17G.js → index-cpEli44X.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-fzaMtSJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-pum7HYBA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-t8N1tSeX.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5IytTND.js → index-uCbEN7cY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-wKTLbKyc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-wV6iGdpY.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-V5Fo95FM.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-BYWU0hUT.js} +1 -1
- package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Cr1M-J2h.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-BysQKi2N.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-D1zHU8GC.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-CUArxtfi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-ChoYEys0.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-BQRs3Mo7.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-B8zbsCkg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-C2U8Gs6h.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-Dd8MgL_V.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-hknqY5NH.js} +1 -1
- package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-CLTAmcfw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-ByegHbiB.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-DqlAy5DP.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-DiXiztQn.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +115 -3
- package/src/commands/agent.js +10 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -4
- package/src/gateways/ws/background-agent-protocol.js +38 -0
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/remote-session-protocol.js +65 -6
- package/src/gateways/ws/ws-server.js +18 -2
- package/src/harness/background-task-manager.js +70 -2
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/harness/worktree-isolator.js +14 -3
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +3 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-schedule-store.js +45 -22
- package/src/lib/agent-team/team-runner.js +22 -0
- package/src/lib/artifact-store.js +35 -0
- package/src/lib/async-hook-supervisor.cjs +13 -2
- package/src/lib/audit-mtc.js +3 -2
- package/src/lib/background-agent-supervisor.js +104 -3
- package/src/lib/background-interaction-journal.js +407 -0
- package/src/lib/background-interaction-resolver.js +23 -34
- package/src/lib/background-session-transport.js +12 -2
- package/src/lib/capability-manifest.js +41 -3
- package/src/lib/capability-negotiation.js +1 -1
- package/src/lib/channels/channel-manager.js +33 -0
- package/src/lib/channels/telegram-channel.js +23 -5
- package/src/lib/channels/webhook-channel.js +38 -15
- package/src/lib/chrome-connector.js +169 -23
- package/src/lib/config-manager.js +23 -9
- package/src/lib/context-breakdown.js +31 -0
- package/src/lib/cowork-cron.js +274 -32
- package/src/lib/cross-chain-mtc.js +3 -2
- package/src/lib/durable-security-store.js +124 -0
- package/src/lib/event-runtime-host.js +67 -6
- package/src/lib/event-runtime-store.js +163 -0
- package/src/lib/goal-store.js +32 -12
- package/src/lib/headless-manifest.js +2 -1
- package/src/lib/hook-environment.cjs +58 -0
- package/src/lib/hook-manager.js +12 -5
- package/src/lib/hook-runner.cjs +122 -28
- package/src/lib/hook-runner.js +7 -2
- package/src/lib/hooks-v2-producers.js +36 -0
- package/src/lib/hooks-v2-runtime.js +329 -52
- package/src/lib/interaction-adapter.js +60 -19
- package/src/lib/interaction-binding.js +64 -0
- package/src/lib/json-schema-output.js +439 -14
- package/src/lib/json-schema-validate.js +514 -883
- package/src/lib/lan-pairing-tokens.js +115 -57
- package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
- package/src/lib/lsp/lsp-client.js +4 -0
- package/src/lib/lsp/lsp-manager.js +3 -0
- package/src/lib/lsp/lsp-server-registry.js +18 -0
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-oauth.js +35 -21
- package/src/lib/packer/pkg-config-generator.js +3 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/bin.js +1148 -70
- package/src/lib/plugin-runtime/capabilities.js +50 -0
- package/src/lib/plugin-runtime/capability-consent.js +42 -35
- package/src/lib/plugin-runtime/hooks.js +36 -9
- package/src/lib/plugin-runtime/install.js +23 -7
- package/src/lib/plugin-runtime/lsp.js +4 -0
- package/src/lib/plugin-runtime/manifest.js +112 -8
- package/src/lib/plugin-runtime/mcp.js +30 -5
- package/src/lib/plugin-runtime/monitors.js +11 -0
- package/src/lib/plugin-runtime/plugin-options.js +94 -38
- package/src/lib/plugin-runtime/policy.js +29 -2
- package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
- package/src/lib/plugin-runtime/scopes.js +27 -13
- package/src/lib/plugin-runtime/trust.js +36 -31
- package/src/lib/process-execution-broker/credential-agent.js +114 -16
- package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
- package/src/lib/process-execution-broker/credential-transport.js +378 -0
- package/src/lib/process-execution-broker/index.js +765 -49
- package/src/lib/process-execution-broker/platform-sandbox.js +4233 -138
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/repl-bang-memorize.js +67 -10
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/slash-commands.js +27 -4
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +117 -31
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +699 -70
- package/src/runtime/agent-runtime.js +13 -1
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +105 -7
- package/src/runtime/headless-stream.js +209 -23
- package/src/runtime/mcp-config.js +29 -17
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/workers/background-agent-worker.js +128 -13
- package/src/assets/web-panel/assets/ChatBubbleRenderer-C7bofJuA.js +0 -1
- package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
- package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
- package/src/assets/web-panel/assets/Terminal-CsMLKIoV.js +0 -3
- package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
- package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
- package/src/assets/web-panel/assets/index-UYAJ6iNM.js +0 -1
|
@@ -93,6 +93,8 @@ import {
|
|
|
93
93
|
formatProviderHttpError,
|
|
94
94
|
formatProviderResponseError,
|
|
95
95
|
} from "../lib/provider-http-error.js";
|
|
96
|
+
import { buildPermissionDecision } from "../lib/permission-decision.js";
|
|
97
|
+
import { resolveSandboxPolicyPath } from "../lib/agent-sandbox.js";
|
|
96
98
|
|
|
97
99
|
export { formatProviderHttpError };
|
|
98
100
|
|
|
@@ -149,6 +151,56 @@ function runCodeProcess(file, args, options = {}, origin = "run-code") {
|
|
|
149
151
|
});
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
function collectWorkspacePluginBinSandboxPolicy(
|
|
155
|
+
pluginBin,
|
|
156
|
+
workspaceCwd,
|
|
157
|
+
executionCwd = workspaceCwd,
|
|
158
|
+
) {
|
|
159
|
+
const resolvedWorkspaceCwd = path.resolve(workspaceCwd);
|
|
160
|
+
const pluginPolicyBoundaries = new Set();
|
|
161
|
+
for (const policyCwd of new Set([
|
|
162
|
+
resolvedWorkspaceCwd,
|
|
163
|
+
path.resolve(executionCwd),
|
|
164
|
+
])) {
|
|
165
|
+
const observedPolicy = pluginBin.collectPluginBinSandboxPolicy({
|
|
166
|
+
cwd: policyCwd,
|
|
167
|
+
});
|
|
168
|
+
for (const boundary of observedPolicy?.requiredBoundaries || []) {
|
|
169
|
+
pluginPolicyBoundaries.add(boundary);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return pluginBin.pinPluginBinSandboxPolicy(
|
|
173
|
+
{ requiredBoundaries: [...pluginPolicyBoundaries] },
|
|
174
|
+
{ cwd: resolvedWorkspaceCwd },
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function rethrowRunCodeSandboxFailure(error) {
|
|
179
|
+
if (
|
|
180
|
+
error?.sandboxFailClosed === true ||
|
|
181
|
+
(typeof error?.code === "string" &&
|
|
182
|
+
error.code.startsWith("ERR_PROCESS_SANDBOX"))
|
|
183
|
+
) {
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function createPythonInterpreterProbeSandboxFailure(sandboxPolicy) {
|
|
189
|
+
const requiredBoundaries = [...(sandboxPolicy?.requiredBoundaries || [])];
|
|
190
|
+
const error = new Error(
|
|
191
|
+
`Python interpreter discovery cannot run without its required sandbox boundaries: ${requiredBoundaries.join(", ")}`,
|
|
192
|
+
);
|
|
193
|
+
error.code = "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
|
|
194
|
+
error.sandboxReason = "python_interpreter_probe_requires_sandbox";
|
|
195
|
+
error.sandboxFailClosed = true;
|
|
196
|
+
error.requiredBoundaries = requiredBoundaries;
|
|
197
|
+
error.actualGuarantees = [];
|
|
198
|
+
error.missingBoundaries = [...requiredBoundaries];
|
|
199
|
+
error.sandboxBackend = null;
|
|
200
|
+
error.sandboxCandidateBackend = null;
|
|
201
|
+
return error;
|
|
202
|
+
}
|
|
203
|
+
|
|
152
204
|
// ─── Background shell tasks ────────────────────────────────────────────────
|
|
153
205
|
//
|
|
154
206
|
// run_shell is synchronous (execSync) and capped at a foreground timeout, which
|
|
@@ -837,6 +889,10 @@ export function getCachedPython() {
|
|
|
837
889
|
return _cachedPython;
|
|
838
890
|
}
|
|
839
891
|
|
|
892
|
+
export function _resetCachedPythonForTests() {
|
|
893
|
+
_cachedPython = null;
|
|
894
|
+
}
|
|
895
|
+
|
|
840
896
|
/**
|
|
841
897
|
* Gather environment info (cached once per process).
|
|
842
898
|
* @returns {{ os: string, arch: string, python: string|null, pip: boolean, node: string|null, git: boolean }}
|
|
@@ -1172,6 +1228,89 @@ const GUARDED_FILE_MUTATION_TOOLS = new Set([
|
|
|
1172
1228
|
"notebook_edit",
|
|
1173
1229
|
]);
|
|
1174
1230
|
|
|
1231
|
+
function agentFileToolPathRequests(name, args = {}, workspaceRoots = []) {
|
|
1232
|
+
const one = (argument, access) =>
|
|
1233
|
+
typeof args[argument] === "string" && args[argument].length > 0
|
|
1234
|
+
? [{ argument, path: args[argument], access }]
|
|
1235
|
+
: [];
|
|
1236
|
+
switch (name) {
|
|
1237
|
+
case "read_file":
|
|
1238
|
+
return one("path", "read");
|
|
1239
|
+
case "write_file":
|
|
1240
|
+
case "edit_file":
|
|
1241
|
+
case "edit_file_hashed":
|
|
1242
|
+
case "delete_file":
|
|
1243
|
+
case "notebook_edit":
|
|
1244
|
+
return one("path", "write");
|
|
1245
|
+
case "move_file":
|
|
1246
|
+
return [...one("path", "write"), ...one("target_path", "write")];
|
|
1247
|
+
case "list_dir":
|
|
1248
|
+
return [
|
|
1249
|
+
{
|
|
1250
|
+
argument: "path",
|
|
1251
|
+
path:
|
|
1252
|
+
typeof args.path === "string" && args.path.length > 0
|
|
1253
|
+
? args.path
|
|
1254
|
+
: ".",
|
|
1255
|
+
access: "read",
|
|
1256
|
+
},
|
|
1257
|
+
];
|
|
1258
|
+
case "search_files":
|
|
1259
|
+
return typeof args.directory === "string" && args.directory.length > 0
|
|
1260
|
+
? [
|
|
1261
|
+
{
|
|
1262
|
+
argument: "directory",
|
|
1263
|
+
path: args.directory,
|
|
1264
|
+
access: "read",
|
|
1265
|
+
},
|
|
1266
|
+
]
|
|
1267
|
+
: workspaceRoots.map((root) => ({
|
|
1268
|
+
argument: "directory",
|
|
1269
|
+
path: root,
|
|
1270
|
+
access: "read",
|
|
1271
|
+
}));
|
|
1272
|
+
case "code_intelligence":
|
|
1273
|
+
return args.action === "workspace_symbols"
|
|
1274
|
+
? workspaceRoots.map((root) => ({
|
|
1275
|
+
argument: "file",
|
|
1276
|
+
path: root,
|
|
1277
|
+
access: "read",
|
|
1278
|
+
}))
|
|
1279
|
+
: one("file", "read");
|
|
1280
|
+
case "publish_artifact":
|
|
1281
|
+
return one("path", "read");
|
|
1282
|
+
default:
|
|
1283
|
+
return [];
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
function guardAgentFileToolPaths(name, args, context, cwd) {
|
|
1288
|
+
const workspaceRoots = workspaceRootsFor(cwd, context.additionalDirectories);
|
|
1289
|
+
const requests = agentFileToolPathRequests(name, args || {}, workspaceRoots);
|
|
1290
|
+
for (const request of requests) {
|
|
1291
|
+
const verdict = resolveSandboxPolicyPath(request.path, {
|
|
1292
|
+
access: request.access,
|
|
1293
|
+
cwd,
|
|
1294
|
+
workspaceRoots,
|
|
1295
|
+
sandbox: context.sandbox || null,
|
|
1296
|
+
});
|
|
1297
|
+
if (!verdict.ok) {
|
|
1298
|
+
return {
|
|
1299
|
+
error:
|
|
1300
|
+
`[Workspace Path Guard] ${name}.${request.argument} ` +
|
|
1301
|
+
`"${request.path}" was blocked: ${verdict.error}.`,
|
|
1302
|
+
policy: {
|
|
1303
|
+
decision: "deny",
|
|
1304
|
+
via: "workspace-path-guard",
|
|
1305
|
+
reason: verdict.reason,
|
|
1306
|
+
access: request.access,
|
|
1307
|
+
},
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
return null;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1175
1314
|
function fileMutationPaths(name, args = {}) {
|
|
1176
1315
|
return [
|
|
1177
1316
|
args.path,
|
|
@@ -1553,6 +1692,16 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1553
1692
|
}
|
|
1554
1693
|
context = { ...context, toolAttribution: attribution };
|
|
1555
1694
|
}
|
|
1695
|
+
|
|
1696
|
+
// Built-in file tools are confined to the declared workspace roots even
|
|
1697
|
+
// when no process sandbox is enabled. Resolve existing targets (and the
|
|
1698
|
+
// nearest existing parent for creates) through symlinks/junctions before any
|
|
1699
|
+
// permission hook, IDE preview, credential check, or filesystem operation
|
|
1700
|
+
// can touch them. Explicit --add-dir roots and sandbox allowRead/allowWrite
|
|
1701
|
+
// paths are the only supported expansions beyond cwd; deny paths still win.
|
|
1702
|
+
const workspacePathDenial = guardAgentFileToolPaths(name, args, context, cwd);
|
|
1703
|
+
if (workspacePathDenial) return workspacePathDenial;
|
|
1704
|
+
|
|
1556
1705
|
const toolContext = createToolContext({
|
|
1557
1706
|
toolName: runtimeDescriptor?.name || name,
|
|
1558
1707
|
cwd,
|
|
@@ -2758,6 +2907,39 @@ async function filterSkillsByCwd(skills, cwd) {
|
|
|
2758
2907
|
}
|
|
2759
2908
|
}
|
|
2760
2909
|
|
|
2910
|
+
async function promoteBrowserScreenshot(
|
|
2911
|
+
filePath,
|
|
2912
|
+
{ sessionId = null, title = "Browser screenshot" } = {},
|
|
2913
|
+
) {
|
|
2914
|
+
if (!filePath) return { artifact: null, error: null };
|
|
2915
|
+
try {
|
|
2916
|
+
const { ArtifactStore, publicArtifactMetadata } =
|
|
2917
|
+
await import("../lib/artifact-store.js");
|
|
2918
|
+
const entry = new ArtifactStore().publish({
|
|
2919
|
+
filePath,
|
|
2920
|
+
title,
|
|
2921
|
+
kind: "screenshot",
|
|
2922
|
+
sessionId: sessionId ? String(sessionId) : null,
|
|
2923
|
+
});
|
|
2924
|
+
return { artifact: publicArtifactMetadata(entry), error: null };
|
|
2925
|
+
} catch (err) {
|
|
2926
|
+
const code =
|
|
2927
|
+
typeof err?.code === "string"
|
|
2928
|
+
? err.code.replace(/[^A-Z0-9_-]/gi, "").slice(0, 40)
|
|
2929
|
+
: "";
|
|
2930
|
+
return {
|
|
2931
|
+
artifact: null,
|
|
2932
|
+
error: `browser screenshot artifact publication failed${code ? ` (${code})` : ""}`,
|
|
2933
|
+
};
|
|
2934
|
+
} finally {
|
|
2935
|
+
try {
|
|
2936
|
+
fs.rmSync(filePath, { force: true });
|
|
2937
|
+
} catch {
|
|
2938
|
+
/* best-effort cleanup */
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2761
2943
|
async function executeToolInner(
|
|
2762
2944
|
name,
|
|
2763
2945
|
args,
|
|
@@ -3337,25 +3519,117 @@ async function executeToolInner(
|
|
|
3337
3519
|
: {}
|
|
3338
3520
|
: { shell: shellInv.kind };
|
|
3339
3521
|
|
|
3340
|
-
//
|
|
3341
|
-
//
|
|
3342
|
-
//
|
|
3343
|
-
|
|
3522
|
+
// Policy-bearing plugin bins never enter PATH. Their declared alias is
|
|
3523
|
+
// accepted only as one direct command: resolve it to literal argv, attest
|
|
3524
|
+
// the exact target, then give Broker an absolute command with shell:false.
|
|
3525
|
+
// Resolver failures for a matching strict alias are terminal — falling
|
|
3526
|
+
// back to a shell would bypass target identity and manifest requirements.
|
|
3527
|
+
let pluginBinInvocation = null;
|
|
3528
|
+
let reattestPluginBinInvocation = null;
|
|
3529
|
+
let pluginBinSandboxPolicy = null;
|
|
3530
|
+
let pluginBinSandboxExecutionContract = null;
|
|
3344
3531
|
try {
|
|
3345
|
-
const
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3532
|
+
const pluginBin = await import("../lib/plugin-runtime/bin.js");
|
|
3533
|
+
reattestPluginBinInvocation = pluginBin.reattestPluginBinInvocation;
|
|
3534
|
+
pluginBinSandboxPolicy = collectWorkspacePluginBinSandboxPolicy(
|
|
3535
|
+
pluginBin,
|
|
3536
|
+
cwd,
|
|
3537
|
+
args.cwd || cwd,
|
|
3538
|
+
);
|
|
3539
|
+
pluginBinInvocation = pluginBin.resolvePluginBinInvocation(
|
|
3540
|
+
args.command,
|
|
3541
|
+
{
|
|
3542
|
+
cwd,
|
|
3543
|
+
commandCwd: args.cwd || cwd,
|
|
3544
|
+
},
|
|
3545
|
+
);
|
|
3546
|
+
if (pluginBinInvocation?.sandboxPolicy) {
|
|
3547
|
+
pluginBinSandboxPolicy = pluginBin.pinPluginBinSandboxPolicy(
|
|
3548
|
+
{
|
|
3549
|
+
requiredBoundaries: [
|
|
3550
|
+
...(pluginBinSandboxPolicy?.requiredBoundaries || []),
|
|
3551
|
+
...(pluginBinInvocation.sandboxPolicy.requiredBoundaries || []),
|
|
3552
|
+
],
|
|
3553
|
+
},
|
|
3554
|
+
{ cwd },
|
|
3555
|
+
);
|
|
3556
|
+
if (
|
|
3557
|
+
process.platform === "linux" ||
|
|
3558
|
+
(process.platform === "win32" &&
|
|
3559
|
+
pluginBinInvocation.runtime === "node")
|
|
3560
|
+
) {
|
|
3561
|
+
try {
|
|
3562
|
+
pluginBinSandboxExecutionContract =
|
|
3563
|
+
pluginBin.createPluginSandboxExecutionContract(
|
|
3564
|
+
pluginBinInvocation,
|
|
3565
|
+
);
|
|
3566
|
+
} catch (error) {
|
|
3567
|
+
if (error?.pluginBinFailClosed) throw error;
|
|
3568
|
+
const contractError = new Error(
|
|
3569
|
+
`plugin sandbox execution contract could not be created: ${error.message}`,
|
|
3570
|
+
);
|
|
3571
|
+
contractError.code = "ERR_PLUGIN_SANDBOX_CONTRACT_UNATTESTED";
|
|
3572
|
+
contractError.pluginBinFailClosed = true;
|
|
3573
|
+
throw contractError;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
} catch (err) {
|
|
3578
|
+
if (err?.pluginBinFailClosed) {
|
|
3579
|
+
const policyVia =
|
|
3580
|
+
err.code === "ERR_PLUGIN_BIN_DISCOVERY_FAILED"
|
|
3581
|
+
? "plugin-bin-pinned-sandbox-policy"
|
|
3582
|
+
: "plugin-bin-direct-invocation";
|
|
3583
|
+
return attachDescriptor(
|
|
3584
|
+
{
|
|
3585
|
+
error: `[Plugin bin] ${err.message}`,
|
|
3586
|
+
policy: {
|
|
3587
|
+
decision: "deny",
|
|
3588
|
+
via: policyVia,
|
|
3589
|
+
reason: err.code || "plugin_bin_resolution_failed",
|
|
3590
|
+
},
|
|
3591
|
+
shellCommandPolicy: shellPolicy,
|
|
3592
|
+
approval: approvalOutcome,
|
|
3593
|
+
},
|
|
3594
|
+
override || runtimeDescriptor,
|
|
3595
|
+
);
|
|
3596
|
+
}
|
|
3597
|
+
pluginBinInvocation = null;
|
|
3350
3598
|
}
|
|
3351
|
-
const processOrigin =
|
|
3599
|
+
const processOrigin = pluginBinInvocation
|
|
3352
3600
|
? "plugin:bin"
|
|
3353
3601
|
: "tool:run_shell";
|
|
3354
|
-
const processProvenance =
|
|
3602
|
+
const processProvenance = {
|
|
3603
|
+
...(pluginBinInvocation
|
|
3604
|
+
? {
|
|
3605
|
+
pluginId: pluginBinInvocation.pluginId,
|
|
3606
|
+
pluginVersion: pluginBinInvocation.pluginVersion,
|
|
3607
|
+
pluginSource: pluginBinInvocation.pluginSource,
|
|
3608
|
+
pluginExecutableIdentity: pluginBinInvocation.executableIdentity,
|
|
3609
|
+
}
|
|
3610
|
+
: {}),
|
|
3611
|
+
...(pluginBinSandboxPolicy
|
|
3612
|
+
? { sandboxPolicy: pluginBinSandboxPolicy }
|
|
3613
|
+
: {}),
|
|
3614
|
+
...(pluginBinSandboxExecutionContract
|
|
3615
|
+
? {
|
|
3616
|
+
sandboxExecutionContract: pluginBinSandboxExecutionContract,
|
|
3617
|
+
}
|
|
3618
|
+
: {}),
|
|
3619
|
+
};
|
|
3620
|
+
const pluginBinResult = pluginBinInvocation
|
|
3355
3621
|
? {
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3622
|
+
plugin_bin: {
|
|
3623
|
+
plugin: pluginBinInvocation.pluginId,
|
|
3624
|
+
version: pluginBinInvocation.pluginVersion,
|
|
3625
|
+
name: pluginBinInvocation.binName,
|
|
3626
|
+
target: pluginBinInvocation.binPath,
|
|
3627
|
+
runtime: pluginBinInvocation.runtime,
|
|
3628
|
+
sha256: pluginBinInvocation.executableIdentity.sha256,
|
|
3629
|
+
identity_attested: true,
|
|
3630
|
+
launch_identity_reattested: false,
|
|
3631
|
+
direct_argv: true,
|
|
3632
|
+
},
|
|
3359
3633
|
}
|
|
3360
3634
|
: {};
|
|
3361
3635
|
|
|
@@ -3370,6 +3644,23 @@ async function executeToolInner(
|
|
|
3370
3644
|
policy: { decision: "deny", via: "sandbox" },
|
|
3371
3645
|
});
|
|
3372
3646
|
}
|
|
3647
|
+
if (
|
|
3648
|
+
(process.platform === "linux" || process.platform === "win32") &&
|
|
3649
|
+
pluginBinSandboxPolicy?.requiredBoundaries?.length > 0
|
|
3650
|
+
) {
|
|
3651
|
+
return attachDescriptor({
|
|
3652
|
+
error:
|
|
3653
|
+
"[Plugin bin] The current strong plugin boundary supports foreground execution only; background execution is fail-closed until Broker-owned process-tree teardown is available.",
|
|
3654
|
+
policy: {
|
|
3655
|
+
decision: "deny",
|
|
3656
|
+
via: "plugin-bin-pinned-sandbox-policy",
|
|
3657
|
+
reason: "background_execution_unsupported",
|
|
3658
|
+
},
|
|
3659
|
+
...pluginBinResult,
|
|
3660
|
+
shellCommandPolicy: shellPolicy,
|
|
3661
|
+
approval: approvalOutcome,
|
|
3662
|
+
});
|
|
3663
|
+
}
|
|
3373
3664
|
// Free memory from idle background tasks before adding another, so a
|
|
3374
3665
|
// long agent run can't accumulate forgotten dev servers (no-op unless
|
|
3375
3666
|
// the machine is actually under memory pressure).
|
|
@@ -3425,9 +3716,29 @@ async function executeToolInner(
|
|
|
3425
3716
|
scope: "agent",
|
|
3426
3717
|
...processProvenance,
|
|
3427
3718
|
};
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3719
|
+
let child;
|
|
3720
|
+
if (pluginBinInvocation) {
|
|
3721
|
+
reattestPluginBinInvocation(pluginBinInvocation);
|
|
3722
|
+
pluginBinResult.plugin_bin.launch_identity_reattested = true;
|
|
3723
|
+
child = broker.spawn(
|
|
3724
|
+
pluginBinSandboxExecutionContract?.kind ===
|
|
3725
|
+
"strict-plugin-node-bin"
|
|
3726
|
+
? pluginBinSandboxExecutionContract.runtimePath
|
|
3727
|
+
: pluginBinInvocation.command,
|
|
3728
|
+
pluginBinInvocation.args,
|
|
3729
|
+
{
|
|
3730
|
+
...brokerOpts,
|
|
3731
|
+
cwd:
|
|
3732
|
+
pluginBinSandboxExecutionContract?.workingDirectory ||
|
|
3733
|
+
brokerOpts.cwd,
|
|
3734
|
+
shell: false,
|
|
3735
|
+
},
|
|
3736
|
+
);
|
|
3737
|
+
} else {
|
|
3738
|
+
child = shellInv.useDefaultShell
|
|
3739
|
+
? broker.spawn(args.command, [], brokerOpts)
|
|
3740
|
+
: broker.spawn(shellInv.file, shellInv.argv, brokerOpts);
|
|
3741
|
+
}
|
|
3431
3742
|
task.child = child;
|
|
3432
3743
|
if (child.stdout) {
|
|
3433
3744
|
child.stdout.setEncoding("utf8");
|
|
@@ -3478,6 +3789,7 @@ async function executeToolInner(
|
|
|
3478
3789
|
status: task.status,
|
|
3479
3790
|
command: task.command,
|
|
3480
3791
|
...shellMeta,
|
|
3792
|
+
...pluginBinResult,
|
|
3481
3793
|
hint: "Poll output and completion with the check_shell tool using this task_id. Kill long-lived servers with check_shell { task_id, kill: true } when done.",
|
|
3482
3794
|
shellCommandPolicy: shellPolicy,
|
|
3483
3795
|
approval: approvalOutcome,
|
|
@@ -3487,6 +3799,23 @@ async function executeToolInner(
|
|
|
3487
3799
|
}
|
|
3488
3800
|
|
|
3489
3801
|
if (sandbox) {
|
|
3802
|
+
if (pluginBinSandboxPolicy) {
|
|
3803
|
+
return attachDescriptor(
|
|
3804
|
+
{
|
|
3805
|
+
error:
|
|
3806
|
+
"[Plugin bin] A strict plugin bin policy cannot be combined with the legacy ephemeral shell sandbox. Run without that sandbox so the ProcessExecutionBroker can enforce the pinned plugin boundary union.",
|
|
3807
|
+
policy: {
|
|
3808
|
+
decision: "deny",
|
|
3809
|
+
via: "plugin-bin-pinned-sandbox-policy",
|
|
3810
|
+
reason: "conflicting_sandbox_routes",
|
|
3811
|
+
},
|
|
3812
|
+
...pluginBinResult,
|
|
3813
|
+
shellCommandPolicy: shellPolicy,
|
|
3814
|
+
approval: approvalOutcome,
|
|
3815
|
+
},
|
|
3816
|
+
override || runtimeDescriptor,
|
|
3817
|
+
);
|
|
3818
|
+
}
|
|
3490
3819
|
const { executeSandboxedShell, sandboxSummary } =
|
|
3491
3820
|
await import("../lib/agent-sandbox.js");
|
|
3492
3821
|
// Domain-restricted networking is ENFORCED by routing the sandboxed
|
|
@@ -3607,7 +3936,35 @@ async function executeToolInner(
|
|
|
3607
3936
|
scope: "agent",
|
|
3608
3937
|
...processProvenance,
|
|
3609
3938
|
};
|
|
3610
|
-
if (
|
|
3939
|
+
if (pluginBinInvocation) {
|
|
3940
|
+
reattestPluginBinInvocation(pluginBinInvocation);
|
|
3941
|
+
pluginBinResult.plugin_bin.launch_identity_reattested = true;
|
|
3942
|
+
const res = broker.spawnSync(
|
|
3943
|
+
pluginBinSandboxExecutionContract?.kind === "strict-plugin-node-bin"
|
|
3944
|
+
? pluginBinSandboxExecutionContract.runtimePath
|
|
3945
|
+
: pluginBinInvocation.command,
|
|
3946
|
+
pluginBinInvocation.args,
|
|
3947
|
+
{
|
|
3948
|
+
...brokerExecOpts,
|
|
3949
|
+
cwd:
|
|
3950
|
+
pluginBinSandboxExecutionContract?.workingDirectory ||
|
|
3951
|
+
brokerExecOpts.cwd,
|
|
3952
|
+
shell: false,
|
|
3953
|
+
windowsHide: true,
|
|
3954
|
+
},
|
|
3955
|
+
);
|
|
3956
|
+
if (res.error) throw res.error;
|
|
3957
|
+
if (res.status !== 0) {
|
|
3958
|
+
const e = new Error(
|
|
3959
|
+
`Plugin bin failed (exit ${res.status}): ${pluginBinInvocation.binName}`,
|
|
3960
|
+
);
|
|
3961
|
+
e.status = res.status;
|
|
3962
|
+
e.stdout = res.stdout;
|
|
3963
|
+
e.stderr = res.stderr;
|
|
3964
|
+
throw e;
|
|
3965
|
+
}
|
|
3966
|
+
output = res.stdout ?? "";
|
|
3967
|
+
} else if (shellInv.useDefaultShell) {
|
|
3611
3968
|
output = broker.execSync(args.command, brokerExecOpts);
|
|
3612
3969
|
} else {
|
|
3613
3970
|
// PowerShell route: explicit argv, no intermediate default shell.
|
|
@@ -3649,6 +4006,7 @@ async function executeToolInner(
|
|
|
3649
4006
|
{
|
|
3650
4007
|
stdout: output.substring(0, 30000),
|
|
3651
4008
|
...shellMeta,
|
|
4009
|
+
...pluginBinResult,
|
|
3652
4010
|
shellCommandPolicy: shellPolicy,
|
|
3653
4011
|
approval: approvalOutcome,
|
|
3654
4012
|
},
|
|
@@ -3669,6 +4027,7 @@ async function executeToolInner(
|
|
|
3669
4027
|
stderr: (err.stderr || "").substring(0, 2000),
|
|
3670
4028
|
exitCode: err.status,
|
|
3671
4029
|
...shellMeta,
|
|
4030
|
+
...pluginBinResult,
|
|
3672
4031
|
shellCommandPolicy: shellPolicy,
|
|
3673
4032
|
approval: approvalOutcome,
|
|
3674
4033
|
},
|
|
@@ -4181,6 +4540,9 @@ async function executeToolInner(
|
|
|
4181
4540
|
: 60000;
|
|
4182
4541
|
const entry = store.createMonitor({
|
|
4183
4542
|
command: args.command,
|
|
4543
|
+
// Bind the persisted command to the host/session workspace. This
|
|
4544
|
+
// value comes from executeTool's trusted context, never model args.
|
|
4545
|
+
workspaceCwd: path.resolve(cwd),
|
|
4184
4546
|
intervalMs,
|
|
4185
4547
|
stopWhen: args.stop_when || null,
|
|
4186
4548
|
notify: args.notify_title ? { title: args.notify_title } : null,
|
|
@@ -4219,7 +4581,8 @@ async function executeToolInner(
|
|
|
4219
4581
|
// Only METADATA returns to the conversation (the transcript never
|
|
4220
4582
|
// carries the file body); `cc artifacts` lists/inspects/cleans.
|
|
4221
4583
|
try {
|
|
4222
|
-
const { ArtifactStore } =
|
|
4584
|
+
const { ArtifactStore, publicArtifactMetadata } =
|
|
4585
|
+
await import("../lib/artifact-store.js");
|
|
4223
4586
|
const store = new ArtifactStore();
|
|
4224
4587
|
const entry = store.publish({
|
|
4225
4588
|
filePath: path.resolve(cwd, String(args.path || "")),
|
|
@@ -4229,7 +4592,7 @@ async function executeToolInner(
|
|
|
4229
4592
|
sessionId: sessionId ? String(sessionId) : null,
|
|
4230
4593
|
});
|
|
4231
4594
|
return attachDescriptor({
|
|
4232
|
-
published: entry,
|
|
4595
|
+
published: publicArtifactMetadata(entry),
|
|
4233
4596
|
hint: "The user can browse this with `cc artifacts list` / `cc artifacts show <id>`.",
|
|
4234
4597
|
});
|
|
4235
4598
|
} catch (err) {
|
|
@@ -4265,7 +4628,25 @@ async function executeToolInner(
|
|
|
4265
4628
|
error: `browser_state failed: ${state.error}`,
|
|
4266
4629
|
});
|
|
4267
4630
|
}
|
|
4268
|
-
|
|
4631
|
+
const safeState = { ...state };
|
|
4632
|
+
if (state.screenshotPath) {
|
|
4633
|
+
const promoted = await promoteBrowserScreenshot(
|
|
4634
|
+
state.screenshotPath,
|
|
4635
|
+
{
|
|
4636
|
+
sessionId,
|
|
4637
|
+
title: `Browser state — ${state.title || "page"}`,
|
|
4638
|
+
},
|
|
4639
|
+
);
|
|
4640
|
+
delete safeState.screenshotPath;
|
|
4641
|
+
delete safeState.screenshotRef;
|
|
4642
|
+
if (promoted.artifact) {
|
|
4643
|
+
safeState.screenshotArtifact = promoted.artifact;
|
|
4644
|
+
safeState.screenshotRef = promoted.artifact.id;
|
|
4645
|
+
} else {
|
|
4646
|
+
safeState.screenshotArtifactError = promoted.error;
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
return attachDescriptor(safeState);
|
|
4269
4650
|
} catch (err) {
|
|
4270
4651
|
return attachDescriptor({
|
|
4271
4652
|
error: `browser_state failed: ${err.message}`,
|
|
@@ -4336,7 +4717,32 @@ async function executeToolInner(
|
|
|
4336
4717
|
error: `browser_act failed: ${result.error}`,
|
|
4337
4718
|
});
|
|
4338
4719
|
}
|
|
4339
|
-
|
|
4720
|
+
const safeResult = { ...result, steps: [] };
|
|
4721
|
+
for (let i = 0; i < (result.steps || []).length; i += 1) {
|
|
4722
|
+
const originalStep = result.steps[i];
|
|
4723
|
+
const step = { ...originalStep };
|
|
4724
|
+
if (originalStep.screenshotPath) {
|
|
4725
|
+
const promoted = await promoteBrowserScreenshot(
|
|
4726
|
+
originalStep.screenshotPath,
|
|
4727
|
+
{
|
|
4728
|
+
sessionId,
|
|
4729
|
+
title: `Browser action screenshot ${i + 1}`,
|
|
4730
|
+
},
|
|
4731
|
+
);
|
|
4732
|
+
delete step.screenshotPath;
|
|
4733
|
+
delete step.screenshotRef;
|
|
4734
|
+
if (promoted.artifact) {
|
|
4735
|
+
step.screenshotArtifact = promoted.artifact;
|
|
4736
|
+
step.screenshotRef = promoted.artifact.id;
|
|
4737
|
+
step.detail = `screenshot artifact: ${promoted.artifact.id}`;
|
|
4738
|
+
} else {
|
|
4739
|
+
step.screenshotArtifactError = promoted.error;
|
|
4740
|
+
step.detail = promoted.error;
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
safeResult.steps.push(step);
|
|
4744
|
+
}
|
|
4745
|
+
return attachDescriptor(safeResult);
|
|
4340
4746
|
} catch (err) {
|
|
4341
4747
|
return attachDescriptor({
|
|
4342
4748
|
error: `browser_act failed: ${err.message}`,
|
|
@@ -4982,6 +5388,54 @@ async function _executeRunCode(args, cwd) {
|
|
|
4982
5388
|
};
|
|
4983
5389
|
}
|
|
4984
5390
|
|
|
5391
|
+
// Every agent-generated interpreter process inherits the tighten-only union
|
|
5392
|
+
// of strict Plugin bin boundaries visible from this workspace. Discover and
|
|
5393
|
+
// pin it before creating a persistent directory, writing a temporary script,
|
|
5394
|
+
// or probing an interpreter so discovery failure cannot fall through to an
|
|
5395
|
+
// unbounded native spawn.
|
|
5396
|
+
let pluginBinSandboxPolicy = null;
|
|
5397
|
+
try {
|
|
5398
|
+
const pluginBin = await import("../lib/plugin-runtime/bin.js");
|
|
5399
|
+
pluginBinSandboxPolicy = collectWorkspacePluginBinSandboxPolicy(
|
|
5400
|
+
pluginBin,
|
|
5401
|
+
cwd,
|
|
5402
|
+
);
|
|
5403
|
+
} catch (error) {
|
|
5404
|
+
return {
|
|
5405
|
+
error: `[Plugin bin] ${error.message}`,
|
|
5406
|
+
policy: {
|
|
5407
|
+
decision: "deny",
|
|
5408
|
+
via: "plugin-bin-pinned-sandbox-policy",
|
|
5409
|
+
reason: error.code || "ERR_PLUGIN_BIN_SANDBOX_POLICY_DISCOVERY_FAILED",
|
|
5410
|
+
},
|
|
5411
|
+
};
|
|
5412
|
+
}
|
|
5413
|
+
const pluginBinSandboxOptions = pluginBinSandboxPolicy
|
|
5414
|
+
? { sandboxPolicy: pluginBinSandboxPolicy }
|
|
5415
|
+
: {};
|
|
5416
|
+
|
|
5417
|
+
// cli-anything's Python discovery probes candidate executables through its
|
|
5418
|
+
// own Broker call. That probe cannot inherit this run_code invocation's
|
|
5419
|
+
// pinned Plugin sandbox policy, so never launch it when strict boundaries
|
|
5420
|
+
// are required. A previously cached interpreter is safe to execute here
|
|
5421
|
+
// because the real script (and any pip/retry process) still goes through
|
|
5422
|
+
// runCodeProcess with the exact pinned policy below.
|
|
5423
|
+
let cachedPythonInterpreter = null;
|
|
5424
|
+
if (
|
|
5425
|
+
lang === "python" &&
|
|
5426
|
+
pluginBinSandboxPolicy?.requiredBoundaries?.length > 0
|
|
5427
|
+
) {
|
|
5428
|
+
if (
|
|
5429
|
+
_cachedPython?.found === true &&
|
|
5430
|
+
typeof _cachedPython.command === "string" &&
|
|
5431
|
+
_cachedPython.command.trim()
|
|
5432
|
+
) {
|
|
5433
|
+
cachedPythonInterpreter = _cachedPython.command;
|
|
5434
|
+
} else {
|
|
5435
|
+
throw createPythonInterpreterProbeSandboxFailure(pluginBinSandboxPolicy);
|
|
5436
|
+
}
|
|
5437
|
+
}
|
|
5438
|
+
|
|
4985
5439
|
// Determine script path
|
|
4986
5440
|
let scriptPath;
|
|
4987
5441
|
if (persist) {
|
|
@@ -5004,8 +5458,12 @@ async function _executeRunCode(args, cwd) {
|
|
|
5004
5458
|
// Determine interpreter
|
|
5005
5459
|
let interpreter;
|
|
5006
5460
|
if (lang === "python") {
|
|
5007
|
-
|
|
5008
|
-
|
|
5461
|
+
if (cachedPythonInterpreter) {
|
|
5462
|
+
interpreter = cachedPythonInterpreter;
|
|
5463
|
+
} else {
|
|
5464
|
+
const py = getCachedPython();
|
|
5465
|
+
interpreter = py.found ? py.command : "python";
|
|
5466
|
+
}
|
|
5009
5467
|
} else if (lang === "node") {
|
|
5010
5468
|
interpreter = "node";
|
|
5011
5469
|
} else {
|
|
@@ -5020,8 +5478,13 @@ async function _executeRunCode(args, cwd) {
|
|
|
5020
5478
|
encoding: "utf8",
|
|
5021
5479
|
timeout: timeoutSec * 1000,
|
|
5022
5480
|
maxBuffer: 5 * 1024 * 1024,
|
|
5481
|
+
...pluginBinSandboxOptions,
|
|
5023
5482
|
});
|
|
5024
5483
|
} catch (err) {
|
|
5484
|
+
// Broker boundary errors carry the required/actual/missing guarantees and
|
|
5485
|
+
// backend attestation. Preserve that exact structured error for callers
|
|
5486
|
+
// instead of flattening it into run_code's generic runtime classifier.
|
|
5487
|
+
rethrowRunCodeSandboxFailure(err);
|
|
5025
5488
|
const stderr = (err.stderr || "").toString();
|
|
5026
5489
|
const message = err.message || "";
|
|
5027
5490
|
const classified = classifyError(stderr, message, err.status, lang);
|
|
@@ -5113,6 +5576,36 @@ async function _executeRunCode(args, cwd) {
|
|
|
5113
5576
|
/* unified audit must never affect the install itself */
|
|
5114
5577
|
}
|
|
5115
5578
|
|
|
5579
|
+
const autoInstallFailure = (installError) => {
|
|
5580
|
+
recordInstallAudit({
|
|
5581
|
+
package: packageName,
|
|
5582
|
+
interpreter,
|
|
5583
|
+
cwd,
|
|
5584
|
+
outcome: "failed",
|
|
5585
|
+
detail: (
|
|
5586
|
+
installError.stderr ||
|
|
5587
|
+
installError.message ||
|
|
5588
|
+
""
|
|
5589
|
+
).substring(0, 200),
|
|
5590
|
+
});
|
|
5591
|
+
auditUnifiedInstall(
|
|
5592
|
+
"failed",
|
|
5593
|
+
(installError.stderr || installError.message || "").substring(
|
|
5594
|
+
0,
|
|
5595
|
+
200,
|
|
5596
|
+
),
|
|
5597
|
+
);
|
|
5598
|
+
return {
|
|
5599
|
+
error: (stderr || message).substring(0, 5000),
|
|
5600
|
+
stderr: stderr.substring(0, 5000),
|
|
5601
|
+
exitCode: err.status,
|
|
5602
|
+
language: lang,
|
|
5603
|
+
...classified,
|
|
5604
|
+
hint: `Failed to auto-install "${packageName}". ${(installError.stderr || installError.message || "").substring(0, 500)}`,
|
|
5605
|
+
scriptPath: persist ? scriptPath : undefined,
|
|
5606
|
+
};
|
|
5607
|
+
};
|
|
5608
|
+
|
|
5116
5609
|
// Attempt pip install
|
|
5117
5610
|
try {
|
|
5118
5611
|
runCodeProcess(
|
|
@@ -5124,18 +5617,27 @@ async function _executeRunCode(args, cwd) {
|
|
|
5124
5617
|
timeout: 120000,
|
|
5125
5618
|
maxBuffer: 2 * 1024 * 1024,
|
|
5126
5619
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5620
|
+
...pluginBinSandboxOptions,
|
|
5127
5621
|
},
|
|
5128
5622
|
"run-code-install",
|
|
5129
5623
|
);
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5624
|
+
} catch (pipErr) {
|
|
5625
|
+
const failure = autoInstallFailure(pipErr);
|
|
5626
|
+
rethrowRunCodeSandboxFailure(pipErr);
|
|
5627
|
+
return failure;
|
|
5628
|
+
}
|
|
5629
|
+
recordInstallAudit({
|
|
5630
|
+
package: packageName,
|
|
5631
|
+
interpreter,
|
|
5632
|
+
cwd,
|
|
5633
|
+
outcome: "installed",
|
|
5634
|
+
});
|
|
5635
|
+
auditUnifiedInstall("installed");
|
|
5137
5636
|
|
|
5138
|
-
|
|
5637
|
+
// Keep retry separate from the install catch: either Broker call can
|
|
5638
|
+
// carry an independently attested fail-closed boundary error, and
|
|
5639
|
+
// neither may be flattened into the legacy auto-install result.
|
|
5640
|
+
try {
|
|
5139
5641
|
const retryStart = Date.now();
|
|
5140
5642
|
const retryOutput = runCodeProcess(
|
|
5141
5643
|
interpreter,
|
|
@@ -5145,6 +5647,7 @@ async function _executeRunCode(args, cwd) {
|
|
|
5145
5647
|
encoding: "utf8",
|
|
5146
5648
|
timeout: timeoutSec * 1000,
|
|
5147
5649
|
maxBuffer: 5 * 1024 * 1024,
|
|
5650
|
+
...pluginBinSandboxOptions,
|
|
5148
5651
|
},
|
|
5149
5652
|
"run-code-retry",
|
|
5150
5653
|
);
|
|
@@ -5158,25 +5661,24 @@ async function _executeRunCode(args, cwd) {
|
|
|
5158
5661
|
autoInstalled: [packageName],
|
|
5159
5662
|
scriptPath: persist ? scriptPath : undefined,
|
|
5160
5663
|
};
|
|
5161
|
-
} catch (
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
"failed",
|
|
5171
|
-
(pipErr.stderr || pipErr.message || "").substring(0, 200),
|
|
5664
|
+
} catch (retryErr) {
|
|
5665
|
+
rethrowRunCodeSandboxFailure(retryErr);
|
|
5666
|
+
const retryStderr = (retryErr.stderr || "").toString();
|
|
5667
|
+
const retryMessage = retryErr.message || "";
|
|
5668
|
+
const retryClassified = classifyError(
|
|
5669
|
+
retryStderr,
|
|
5670
|
+
retryMessage,
|
|
5671
|
+
retryErr.status,
|
|
5672
|
+
lang,
|
|
5172
5673
|
);
|
|
5173
5674
|
return {
|
|
5174
|
-
error: (
|
|
5175
|
-
stderr:
|
|
5176
|
-
exitCode:
|
|
5675
|
+
error: (retryStderr || retryMessage).substring(0, 5000),
|
|
5676
|
+
stderr: retryStderr.substring(0, 5000),
|
|
5677
|
+
exitCode: retryErr.status,
|
|
5177
5678
|
language: lang,
|
|
5178
|
-
...
|
|
5179
|
-
hint: `
|
|
5679
|
+
...retryClassified,
|
|
5680
|
+
hint: `Package "${packageName}" was installed, but the script retry failed.`,
|
|
5681
|
+
autoInstalled: [packageName],
|
|
5180
5682
|
scriptPath: persist ? scriptPath : undefined,
|
|
5181
5683
|
};
|
|
5182
5684
|
}
|
|
@@ -5297,7 +5799,7 @@ export function safeStringifyToolResult(value) {
|
|
|
5297
5799
|
}
|
|
5298
5800
|
}
|
|
5299
5801
|
|
|
5300
|
-
function emitToolHookLifecycle({
|
|
5802
|
+
export function emitToolHookLifecycle({
|
|
5301
5803
|
tool,
|
|
5302
5804
|
args,
|
|
5303
5805
|
result,
|
|
@@ -5306,6 +5808,7 @@ function emitToolHookLifecycle({
|
|
|
5306
5808
|
turnId = null,
|
|
5307
5809
|
toolUseId = null,
|
|
5308
5810
|
cwd = process.cwd(),
|
|
5811
|
+
emit = emitHooksV2Event,
|
|
5309
5812
|
}) {
|
|
5310
5813
|
const failed = Boolean(error || result?.error);
|
|
5311
5814
|
const base = {
|
|
@@ -5317,7 +5820,7 @@ function emitToolHookLifecycle({
|
|
|
5317
5820
|
duration_ms: Number(result?.toolTelemetryRecord?.durationMs || 0),
|
|
5318
5821
|
cwd,
|
|
5319
5822
|
};
|
|
5320
|
-
|
|
5823
|
+
emit(failed ? "PostToolUseFailure" : "PostToolUse", {
|
|
5321
5824
|
...base,
|
|
5322
5825
|
...(failed
|
|
5323
5826
|
? {
|
|
@@ -5337,7 +5840,7 @@ function emitToolHookLifecycle({
|
|
|
5337
5840
|
args?.targetPath ||
|
|
5338
5841
|
args?.target_path ||
|
|
5339
5842
|
null;
|
|
5340
|
-
|
|
5843
|
+
emit("FileChanged", {
|
|
5341
5844
|
...base,
|
|
5342
5845
|
path: changedPath == null ? null : String(changedPath),
|
|
5343
5846
|
operation: tool,
|
|
@@ -5346,6 +5849,32 @@ function emitToolHookLifecycle({
|
|
|
5346
5849
|
return failed;
|
|
5347
5850
|
}
|
|
5348
5851
|
|
|
5852
|
+
export function emitToolBatchHookLifecycle({
|
|
5853
|
+
records = [],
|
|
5854
|
+
sessionId = null,
|
|
5855
|
+
turnId = null,
|
|
5856
|
+
cwd = process.cwd(),
|
|
5857
|
+
parallel = false,
|
|
5858
|
+
emit = emitHooksV2Event,
|
|
5859
|
+
}) {
|
|
5860
|
+
if (!Array.isArray(records) || records.length === 0) return null;
|
|
5861
|
+
const failed = records.filter((record) => record?.failed === true).length;
|
|
5862
|
+
const payload = {
|
|
5863
|
+
schema_version: 1,
|
|
5864
|
+
session_id: sessionId,
|
|
5865
|
+
turn_id: turnId,
|
|
5866
|
+
cwd,
|
|
5867
|
+
parallel: parallel === true,
|
|
5868
|
+
total: records.length,
|
|
5869
|
+
succeeded: records.length - failed,
|
|
5870
|
+
failed,
|
|
5871
|
+
tool_names: records.map((record) => record?.tool || "(unknown)"),
|
|
5872
|
+
tool_use_ids: records.map((record) => record?.toolUseId || null),
|
|
5873
|
+
};
|
|
5874
|
+
emit("PostToolBatch", payload);
|
|
5875
|
+
return payload;
|
|
5876
|
+
}
|
|
5877
|
+
|
|
5349
5878
|
/**
|
|
5350
5879
|
* Execute a spawn_sub_agent tool call.
|
|
5351
5880
|
* Creates an isolated SubAgentContext, runs it, and returns only the summary.
|
|
@@ -7507,11 +8036,12 @@ function extractInitialPromptText(messages) {
|
|
|
7507
8036
|
* recompute it. Not exported (no shim-parity impact) — only the telemetry seam
|
|
7508
8037
|
* uses it.
|
|
7509
8038
|
*/
|
|
7510
|
-
function
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
8039
|
+
function permissionDecision(callId, tool, result) {
|
|
8040
|
+
return buildPermissionDecision({
|
|
8041
|
+
toolUseId: callId,
|
|
8042
|
+
tool,
|
|
8043
|
+
result,
|
|
8044
|
+
});
|
|
7515
8045
|
}
|
|
7516
8046
|
|
|
7517
8047
|
export async function* agentLoop(messages, options) {
|
|
@@ -7931,6 +8461,14 @@ export async function* agentLoop(messages, options) {
|
|
|
7931
8461
|
// self-persist is best-effort
|
|
7932
8462
|
}
|
|
7933
8463
|
}
|
|
8464
|
+
emitHooksV2Event("PostCompact", {
|
|
8465
|
+
schema_version: 1,
|
|
8466
|
+
trigger: "auto",
|
|
8467
|
+
session_id: options.sessionId || null,
|
|
8468
|
+
messages_after: messages.length,
|
|
8469
|
+
stats,
|
|
8470
|
+
cwd: options.cwd || process.cwd(),
|
|
8471
|
+
});
|
|
7934
8472
|
yield { type: "compaction", stats, runId };
|
|
7935
8473
|
}
|
|
7936
8474
|
}
|
|
@@ -8182,7 +8720,33 @@ export async function* agentLoop(messages, options) {
|
|
|
8182
8720
|
},
|
|
8183
8721
|
{ cwd: options.cwd || process.cwd() },
|
|
8184
8722
|
);
|
|
8185
|
-
|
|
8723
|
+
const failures = (stopOutcome?.results || []).filter(
|
|
8724
|
+
(result) =>
|
|
8725
|
+
result?.nonBlockingError === true ||
|
|
8726
|
+
result?.malformedDecision === true ||
|
|
8727
|
+
result?.breakerOpen === true,
|
|
8728
|
+
);
|
|
8729
|
+
if (failures.length > 0) {
|
|
8730
|
+
emitHooksV2Event("StopFailure", {
|
|
8731
|
+
schema_version: 1,
|
|
8732
|
+
session_id: options.sessionId || null,
|
|
8733
|
+
run_id: runId,
|
|
8734
|
+
phase: "stop-hook",
|
|
8735
|
+
failures: failures.map((failure) => ({
|
|
8736
|
+
command: failure.command || null,
|
|
8737
|
+
exit_code: failure.exitCode ?? null,
|
|
8738
|
+
reason: failure.reason || failure.error || null,
|
|
8739
|
+
})),
|
|
8740
|
+
});
|
|
8741
|
+
}
|
|
8742
|
+
} catch (error) {
|
|
8743
|
+
emitHooksV2Event("StopFailure", {
|
|
8744
|
+
schema_version: 1,
|
|
8745
|
+
session_id: options.sessionId || null,
|
|
8746
|
+
run_id: runId,
|
|
8747
|
+
phase: "stop-hook",
|
|
8748
|
+
reason: error?.message || String(error),
|
|
8749
|
+
});
|
|
8186
8750
|
stopOutcome = null; // never affect the run outcome
|
|
8187
8751
|
}
|
|
8188
8752
|
if (stopOutcome && stopOutcome.decision === "block") {
|
|
@@ -8243,6 +8807,8 @@ export async function* agentLoop(messages, options) {
|
|
|
8243
8807
|
);
|
|
8244
8808
|
if (parallelReads) {
|
|
8245
8809
|
throwIfAborted(signal);
|
|
8810
|
+
const turnId = `${runId}:t${budget.consumed}`;
|
|
8811
|
+
const toolBatchRecords = [];
|
|
8246
8812
|
// Kick every read off now; settle into {result,error} so an unawaited
|
|
8247
8813
|
// promise can never surface as an unhandled rejection if the loop aborts
|
|
8248
8814
|
// before it is consumed.
|
|
@@ -8277,6 +8843,21 @@ export async function* agentLoop(messages, options) {
|
|
|
8277
8843
|
};
|
|
8278
8844
|
const { result: toolResult, error: toolError } = await promise;
|
|
8279
8845
|
throwIfAborted(signal);
|
|
8846
|
+
const failed = emitToolHookLifecycle({
|
|
8847
|
+
tool: call.function.name,
|
|
8848
|
+
args: toolArgs,
|
|
8849
|
+
result: toolResult,
|
|
8850
|
+
error: toolError,
|
|
8851
|
+
sessionId: options.sessionId || null,
|
|
8852
|
+
turnId,
|
|
8853
|
+
toolUseId: call.id,
|
|
8854
|
+
cwd: options.cwd || process.cwd(),
|
|
8855
|
+
});
|
|
8856
|
+
toolBatchRecords.push({
|
|
8857
|
+
tool: call.function.name,
|
|
8858
|
+
toolUseId: call.id,
|
|
8859
|
+
failed,
|
|
8860
|
+
});
|
|
8280
8861
|
const warningMsg = budget.toWarningMessage();
|
|
8281
8862
|
const resultStr = capToolResultString(
|
|
8282
8863
|
safeStringifyToolResult(toolResult),
|
|
@@ -8284,6 +8865,11 @@ export async function* agentLoop(messages, options) {
|
|
|
8284
8865
|
const toolContent = warningMsg
|
|
8285
8866
|
? `${resultStr}\n\n${warningMsg}`
|
|
8286
8867
|
: resultStr;
|
|
8868
|
+
const decision = permissionDecision(
|
|
8869
|
+
call.id,
|
|
8870
|
+
call.function.name,
|
|
8871
|
+
toolResult,
|
|
8872
|
+
);
|
|
8287
8873
|
yield {
|
|
8288
8874
|
type: "tool-result",
|
|
8289
8875
|
tool: call.function.name,
|
|
@@ -8291,10 +8877,8 @@ export async function* agentLoop(messages, options) {
|
|
|
8291
8877
|
error: toolError,
|
|
8292
8878
|
tool_use_id: call.id,
|
|
8293
8879
|
turn_id: `${runId}:t${budget.consumed}`,
|
|
8294
|
-
permission_decision_id:
|
|
8295
|
-
|
|
8296
|
-
toolResult?.policy,
|
|
8297
|
-
),
|
|
8880
|
+
permission_decision_id: decision?.id || null,
|
|
8881
|
+
permission_decision: decision,
|
|
8298
8882
|
};
|
|
8299
8883
|
messages.push({
|
|
8300
8884
|
role: "tool",
|
|
@@ -8302,9 +8886,18 @@ export async function* agentLoop(messages, options) {
|
|
|
8302
8886
|
tool_call_id: call.id,
|
|
8303
8887
|
});
|
|
8304
8888
|
}
|
|
8889
|
+
emitToolBatchHookLifecycle({
|
|
8890
|
+
records: toolBatchRecords,
|
|
8891
|
+
sessionId: options.sessionId || null,
|
|
8892
|
+
turnId,
|
|
8893
|
+
cwd: options.cwd || process.cwd(),
|
|
8894
|
+
parallel: true,
|
|
8895
|
+
});
|
|
8305
8896
|
continue; // all read results in place — back to the LLM call
|
|
8306
8897
|
}
|
|
8307
8898
|
|
|
8899
|
+
const turnId = `${runId}:t${budget.consumed}`;
|
|
8900
|
+
const toolBatchRecords = [];
|
|
8308
8901
|
for (const call of toolCalls) {
|
|
8309
8902
|
throwIfAborted(signal);
|
|
8310
8903
|
const fn = call?.function;
|
|
@@ -8318,6 +8911,21 @@ export async function* agentLoop(messages, options) {
|
|
|
8318
8911
|
// malformed call.
|
|
8319
8912
|
if (typeof toolName !== "string" || !toolName) {
|
|
8320
8913
|
const reason = "malformed tool call: missing function name";
|
|
8914
|
+
emitToolHookLifecycle({
|
|
8915
|
+
tool: "(unknown)",
|
|
8916
|
+
args: null,
|
|
8917
|
+
result: { error: reason },
|
|
8918
|
+
error: reason,
|
|
8919
|
+
sessionId: options.sessionId || null,
|
|
8920
|
+
turnId,
|
|
8921
|
+
toolUseId: call?.id || null,
|
|
8922
|
+
cwd: options.cwd || process.cwd(),
|
|
8923
|
+
});
|
|
8924
|
+
toolBatchRecords.push({
|
|
8925
|
+
tool: "(unknown)",
|
|
8926
|
+
toolUseId: call?.id || null,
|
|
8927
|
+
failed: true,
|
|
8928
|
+
});
|
|
8321
8929
|
yield {
|
|
8322
8930
|
type: "tool-result",
|
|
8323
8931
|
tool: "(unknown)",
|
|
@@ -8413,14 +9021,14 @@ export async function* agentLoop(messages, options) {
|
|
|
8413
9021
|
// (derived from the call + gate, so it's recomputable from the
|
|
8414
9022
|
// tool-result's policy + tool_call_id) plus the low-cardinality
|
|
8415
9023
|
// decision, letting a blocked tool span be tied to its decision.
|
|
8416
|
-
const
|
|
9024
|
+
const decision =
|
|
8417
9025
|
r && typeof r === "object"
|
|
8418
|
-
?
|
|
9026
|
+
? permissionDecision(call.id, toolName, r)
|
|
8419
9027
|
: null;
|
|
8420
|
-
if (
|
|
9028
|
+
if (decision?.id) {
|
|
8421
9029
|
const permAttrs = buildTelemetryAttributes({
|
|
8422
|
-
decisionId:
|
|
8423
|
-
"permission.decision":
|
|
9030
|
+
decisionId: decision.id,
|
|
9031
|
+
"permission.decision": decision.decision,
|
|
8424
9032
|
});
|
|
8425
9033
|
if (permAttrs["permission.decision_id"]) {
|
|
8426
9034
|
span.setAttribute(
|
|
@@ -8458,6 +9066,7 @@ export async function* agentLoop(messages, options) {
|
|
|
8458
9066
|
? `${resultStr}\n\n${warningMsg}`
|
|
8459
9067
|
: resultStr;
|
|
8460
9068
|
|
|
9069
|
+
const decision = permissionDecision(call.id, toolName, toolResult);
|
|
8461
9070
|
yield {
|
|
8462
9071
|
type: "tool-result",
|
|
8463
9072
|
tool: toolName,
|
|
@@ -8465,10 +9074,8 @@ export async function* agentLoop(messages, options) {
|
|
|
8465
9074
|
error: toolError,
|
|
8466
9075
|
tool_use_id: call.id,
|
|
8467
9076
|
turn_id: `${runId}:t${budget.consumed}`,
|
|
8468
|
-
permission_decision_id:
|
|
8469
|
-
|
|
8470
|
-
toolResult?.policy,
|
|
8471
|
-
),
|
|
9077
|
+
permission_decision_id: decision?.id || null,
|
|
9078
|
+
permission_decision: decision,
|
|
8472
9079
|
};
|
|
8473
9080
|
|
|
8474
9081
|
messages.push({
|
|
@@ -8476,7 +9083,29 @@ export async function* agentLoop(messages, options) {
|
|
|
8476
9083
|
content: toolContent,
|
|
8477
9084
|
tool_call_id: call.id,
|
|
8478
9085
|
});
|
|
9086
|
+
const failed = emitToolHookLifecycle({
|
|
9087
|
+
tool: toolName,
|
|
9088
|
+
args: toolArgs,
|
|
9089
|
+
result: toolResult,
|
|
9090
|
+
error: toolError,
|
|
9091
|
+
sessionId: options.sessionId || null,
|
|
9092
|
+
turnId,
|
|
9093
|
+
toolUseId: call.id,
|
|
9094
|
+
cwd: options.cwd || process.cwd(),
|
|
9095
|
+
});
|
|
9096
|
+
toolBatchRecords.push({
|
|
9097
|
+
tool: toolName,
|
|
9098
|
+
toolUseId: call.id,
|
|
9099
|
+
failed,
|
|
9100
|
+
});
|
|
8479
9101
|
}
|
|
9102
|
+
emitToolBatchHookLifecycle({
|
|
9103
|
+
records: toolBatchRecords,
|
|
9104
|
+
sessionId: options.sessionId || null,
|
|
9105
|
+
turnId,
|
|
9106
|
+
cwd: options.cwd || process.cwd(),
|
|
9107
|
+
parallel: false,
|
|
9108
|
+
});
|
|
8480
9109
|
}
|
|
8481
9110
|
|
|
8482
9111
|
// Budget exhausted — flush any child usage the final iteration produced,
|