chainlesschain 0.162.183 → 0.162.185
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 +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BapS7lz4.js → AIOps-Co4ipAKx.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-BpsoDrDq.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-DMUqeBik.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-C6fD_dXr.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DW0YlQlV.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit-DXtHiiFK.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-BgmF62U-.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-D8vhVLQC.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-D7nCtY2X.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-CBZLEV2G.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CI_jT0ru.js → ChatBubbleRenderer-CtDb-2Qu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-DJLkeD4M.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-Cs6xO8Fd.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col-Dtx9wxfT.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-DiigJg4n.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-B67oMDDL.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-BBDl-Jos.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-Ba98hSsa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-DBWQZIz7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-OcrKzxAt.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-mW2eSbjM.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-BmsDPmKJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-CVzmCyRx.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-vVgqKzhh.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-CWY5t_ZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-ZGomhjxr.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-DyaknbLr.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-CmIvN1qr.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-DQOJIYkG.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CMiY-EEp.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-D6IXuucf.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-6jkTL0hV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-N0jD-349.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BL1IVXm-.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-WhYuhBxm.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-DTeO28xy.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-MSHzPSE-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-Cyqs3J3W.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-7IN2hWHg.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-MWBnezNM.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-DQu35Nu-.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-CQS_M-DP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-WD16vQvY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-DqsiSwOq.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-D3LoxO-P.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DdcsOqEz.js → OrderTableRenderer-C5jPoTd6.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-48aMBJso.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-j-a2XkhR.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-BYpBNYnh.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-CYCsrrLg.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-ZRXGXDFb.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-6OWUPHyL.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-FcjlDK9E.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-vD_6Tldp.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-B_CHOLXp.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-rEiqQ2da.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-Bg8obRAM.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-Dgtt97B4.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-DaGVylZO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DP2_2x3u.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-D29yj4ki.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-Ue2wnBLp.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CrxIHqeC.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-BgSzJPCn.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-AwhYOrP9.js} +3 -3
- package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-D2shpEcm.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-BtKzhTbT.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-BY0DsUSm.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-B3Sb0UI9.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DtT6rWOX.js → Skills-Ne5w0bDs.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-C8VkaP4T.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-BQdIEYP9.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-CwFafrUg.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-yJuKoDlR.js +1 -0
- package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-DYn9qCmx.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-DkKReHvn.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-r6bd-owt.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-Mq2juUC3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-BnMw7MRi.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-CTzKp4o9.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-BBrSZm9U.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-D9fDvEMq.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-DUi5ve-0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-C8Fi1P8_.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-s1LppYi2.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-DJL2C4lj.js} +1 -1
- package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-D3F2ndOB.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-B7739-e3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-CcJbFTF4.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CuP_DEFS.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Cj_36GHq.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-6YEXfIik.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-4h3lpWJ3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-BIID4XcP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BOHUo3aM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-BYYSLEjn.js} +1 -1
- package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-Bh4hcNWW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C327pLbw.js → index-BhIKnQAW.js} +1 -1
- package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-Bru_kpZl.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-BsdSnHQE.js} +1 -1
- package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-BxSqVMGh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-C3ZA_h1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-C3pctdCb.js} +1 -1
- package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-CRuoRapN.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-CY0zd_jc.js} +1 -1
- package/src/assets/web-panel/assets/index-CezFrAmD.js +1 -0
- package/src/assets/web-panel/assets/index-Cxgguez6.js +1 -0
- package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-CxradkS6.js} +19 -19
- package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-D0K_rFC1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-D0zdPyTD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-D3haorUt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-D6Ij_2uw.js} +1 -1
- package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-DDRlBaDt.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-DGsE7MQz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-DHvxXXNA.js} +1 -1
- package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DV11jpeO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-DXdnfDVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-D_75jYWk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-DjI9MkId.js} +1 -1
- package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-DlSvpNMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dox44j29.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-DpEKmjoa.js} +1 -1
- package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Dsy7_x4s.js} +1 -1
- package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-Gxw09e9R.js} +1 -1
- package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-LfRlSmqe.js} +1 -1
- package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-Nz-MUHD1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUU2606o.js → index-b9cuvFEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-eR6H6NR7.js} +1 -1
- package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-fWgUQZ9d.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-mfWQRSLn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-yOZYSNmG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-CJ1Bq2L3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-rYJN_vzf.js} +1 -1
- package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-DnDK2gTP.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-CKnXy7ES.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-3nRc3hWT.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Ddjj3sLu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-CbsbphQY.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-D9aZ4VDJ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-D4pvdFj0.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-C2W-vY-S.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-Cbq5150d.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-BA2B7R82.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CLrwg3xg.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-DQeAI5qs.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-8BDGy-YU.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-B2SzFprl.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +74 -1
- package/src/commands/background-session.js +11 -1
- package/src/commands/batch.js +160 -5
- package/src/commands/plugin.js +90 -27
- package/src/commands/session.js +31 -1
- package/src/commands/team.js +212 -6
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -15
- package/src/gateways/ws/ws-agent-handler.js +15 -1
- package/src/gateways/ws/ws-session-gateway.js +88 -0
- package/src/harness/background-task-command-runner.js +234 -0
- package/src/harness/background-task-manager.js +150 -20
- package/src/harness/background-task-worker.js +17 -11
- package/src/harness/jsonl-session-store.js +57 -6
- package/src/harness/mcp-client.js +65 -43
- package/src/lib/agent-batch.js +4 -1
- package/src/lib/agent-team/team-worktree.js +3 -0
- package/src/lib/async-hook-supervisor.cjs +82 -10
- package/src/lib/async-hook-supervisor.js +50 -4
- package/src/lib/background-agent-supervisor.js +46 -0
- package/src/lib/collaboration-run-store.js +362 -0
- package/src/lib/event-runtime-host.js +12 -10
- package/src/lib/hook-runner.cjs +105 -18
- package/src/lib/hook-runner.js +79 -6
- package/src/lib/hook-shell-command.cjs +148 -0
- package/src/lib/hooks-v2-runtime.js +280 -81
- package/src/lib/hooks-v2-workspace-context.js +258 -0
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +15 -0
- package/src/lib/lsp/lsp-client.js +12 -1
- package/src/lib/plugin-monitor-supervisor.js +53 -16
- package/src/lib/plugin-runtime/bin.js +21 -5
- package/src/lib/plugin-runtime/install.js +249 -57
- package/src/lib/plugin-runtime/mcp.js +21 -2
- package/src/lib/plugin-runtime/monitors.js +19 -3
- package/src/lib/plugin-runtime/sandbox-policy.js +100 -4
- package/src/lib/process-execution-broker/index.js +1151 -44
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1557 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +1378 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +586 -58
- package/src/lib/session-usage.js +202 -2
- package/src/lib/stream-retry.js +29 -0
- package/src/repl/agent-repl.js +40 -3
- package/src/runtime/agent-core.js +304 -42
- package/src/runtime/headless-runner.js +48 -1
- package/src/runtime/headless-stream.js +42 -2
- package/src/workers/background-agent-worker.js +5 -11
- package/src/assets/web-panel/assets/MarkdownRenderer-C0o4FtpD.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
- package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +0 -3
- package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +0 -1
- package/src/assets/web-panel/assets/index-5iAFwYx1.js +0 -1
- package/src/assets/web-panel/assets/index-BfnB7LPx.js +0 -1
|
@@ -201,6 +201,76 @@ function createPythonInterpreterProbeSandboxFailure(sandboxPolicy) {
|
|
|
201
201
|
return error;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
function createBackgroundShellSandboxFailure(
|
|
205
|
+
reason,
|
|
206
|
+
message,
|
|
207
|
+
sandboxPolicy,
|
|
208
|
+
cause = null,
|
|
209
|
+
) {
|
|
210
|
+
const requiredBoundaries = [...(sandboxPolicy?.requiredBoundaries || [])];
|
|
211
|
+
const error = new Error(message);
|
|
212
|
+
error.code = "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
|
|
213
|
+
error.sandboxReason = reason;
|
|
214
|
+
error.sandboxFailClosed = true;
|
|
215
|
+
error.requiredBoundaries = requiredBoundaries;
|
|
216
|
+
error.actualGuarantees = [];
|
|
217
|
+
error.missingBoundaries = [...requiredBoundaries];
|
|
218
|
+
error.sandboxBackend = null;
|
|
219
|
+
error.sandboxCandidateBackend = "linux-bwrap-workspace";
|
|
220
|
+
if (cause) error.cause = cause;
|
|
221
|
+
return error;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function resolveBackgroundShellWorkspacePaths(
|
|
225
|
+
trustedWorkspaceRoot,
|
|
226
|
+
requestedCwd,
|
|
227
|
+
sandboxPolicy,
|
|
228
|
+
) {
|
|
229
|
+
if (
|
|
230
|
+
typeof trustedWorkspaceRoot !== "string" ||
|
|
231
|
+
!trustedWorkspaceRoot ||
|
|
232
|
+
trustedWorkspaceRoot.includes("\0") ||
|
|
233
|
+
!path.isAbsolute(trustedWorkspaceRoot)
|
|
234
|
+
) {
|
|
235
|
+
throw createBackgroundShellSandboxFailure(
|
|
236
|
+
"background_workspace_root_untrusted",
|
|
237
|
+
"Background shell strong sandbox requires an absolute trusted host workspace root",
|
|
238
|
+
sandboxPolicy,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
const workspaceRoot = path.resolve(trustedWorkspaceRoot);
|
|
242
|
+
let workingDirectory = workspaceRoot;
|
|
243
|
+
if (
|
|
244
|
+
requestedCwd !== undefined &&
|
|
245
|
+
requestedCwd !== null &&
|
|
246
|
+
requestedCwd !== ""
|
|
247
|
+
) {
|
|
248
|
+
if (typeof requestedCwd !== "string" || requestedCwd.includes("\0")) {
|
|
249
|
+
throw createBackgroundShellSandboxFailure(
|
|
250
|
+
"background_working_directory_untrusted",
|
|
251
|
+
"Background shell strong sandbox cwd must be a trusted path string",
|
|
252
|
+
sandboxPolicy,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
workingDirectory = path.isAbsolute(requestedCwd)
|
|
256
|
+
? path.resolve(requestedCwd)
|
|
257
|
+
: path.resolve(workspaceRoot, requestedCwd);
|
|
258
|
+
}
|
|
259
|
+
const relative = path.relative(workspaceRoot, workingDirectory);
|
|
260
|
+
if (
|
|
261
|
+
relative === ".." ||
|
|
262
|
+
relative.startsWith(`..${path.sep}`) ||
|
|
263
|
+
path.isAbsolute(relative)
|
|
264
|
+
) {
|
|
265
|
+
throw createBackgroundShellSandboxFailure(
|
|
266
|
+
"background_working_directory_escape",
|
|
267
|
+
"Background shell strong sandbox cwd escapes the trusted host workspace root",
|
|
268
|
+
sandboxPolicy,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return { workspaceRoot, workingDirectory };
|
|
272
|
+
}
|
|
273
|
+
|
|
204
274
|
// ─── Background shell tasks ────────────────────────────────────────────────
|
|
205
275
|
//
|
|
206
276
|
// run_shell is synchronous (execSync) and capped at a foreground timeout, which
|
|
@@ -321,10 +391,16 @@ function _releaseBgChildHandles(task) {
|
|
|
321
391
|
|
|
322
392
|
const backgroundTaskRunner = broker.spawn.bind(broker);
|
|
323
393
|
const backgroundTaskSyncRunner = broker.spawnSync.bind(broker);
|
|
394
|
+
const backgroundTaskContractIssuer =
|
|
395
|
+
typeof broker.issueLinuxWorkspaceSandboxExecutionContract === "function"
|
|
396
|
+
? broker.issueLinuxWorkspaceSandboxExecutionContract.bind(broker)
|
|
397
|
+
: null;
|
|
324
398
|
|
|
325
399
|
export const _backgroundProcessDeps = {
|
|
326
400
|
run: backgroundTaskRunner,
|
|
327
401
|
runSync: backgroundTaskSyncRunner,
|
|
402
|
+
issueLinuxWorkspaceSandboxExecutionContract: backgroundTaskContractIssuer,
|
|
403
|
+
platform: () => process.platform,
|
|
328
404
|
};
|
|
329
405
|
|
|
330
406
|
export function _runBackgroundTaskkill(pid, { sync = false } = {}) {
|
|
@@ -350,7 +426,12 @@ function _killTask(task) {
|
|
|
350
426
|
const child = task?.child;
|
|
351
427
|
if (!child || child.killed || task?.status !== "running") return false;
|
|
352
428
|
try {
|
|
353
|
-
if (
|
|
429
|
+
if (task.sandboxManagedTree === true) {
|
|
430
|
+
// Linux generic launches are never detached. Bubblewrap owns the private
|
|
431
|
+
// PID namespace and runs with --die-with-parent/--new-session, so killing
|
|
432
|
+
// the Broker child reaps the complete sandbox tree.
|
|
433
|
+
child.kill("SIGTERM");
|
|
434
|
+
} else if (process.platform === "win32") {
|
|
354
435
|
if (child.pid) {
|
|
355
436
|
const tk = _runBackgroundTaskkill(child.pid);
|
|
356
437
|
const fallbackDirectKill = () => {
|
|
@@ -425,7 +506,9 @@ function _killTaskSync(task) {
|
|
|
425
506
|
const child = task?.child;
|
|
426
507
|
if (!child || child.killed || task?.status !== "running") return false;
|
|
427
508
|
try {
|
|
428
|
-
if (
|
|
509
|
+
if (task.sandboxManagedTree === true) {
|
|
510
|
+
child.kill("SIGKILL");
|
|
511
|
+
} else if (process.platform === "win32") {
|
|
429
512
|
if (child.pid) {
|
|
430
513
|
const killed = _runBackgroundTaskkill(child.pid, { sync: true });
|
|
431
514
|
if (killed.error || killed.status !== 0) {
|
|
@@ -3562,6 +3645,7 @@ async function executeToolInner(
|
|
|
3562
3645
|
pluginBinSandboxExecutionContract =
|
|
3563
3646
|
pluginBin.createPluginSandboxExecutionContract(
|
|
3564
3647
|
pluginBinInvocation,
|
|
3648
|
+
{ sync: args.run_in_background !== true },
|
|
3565
3649
|
);
|
|
3566
3650
|
} catch (error) {
|
|
3567
3651
|
if (error?.pluginBinFailClosed) throw error;
|
|
@@ -3644,9 +3728,33 @@ async function executeToolInner(
|
|
|
3644
3728
|
policy: { decision: "deny", via: "sandbox" },
|
|
3645
3729
|
});
|
|
3646
3730
|
}
|
|
3731
|
+
const backgroundPlatform =
|
|
3732
|
+
typeof _backgroundProcessDeps.platform === "function"
|
|
3733
|
+
? _backgroundProcessDeps.platform()
|
|
3734
|
+
: process.platform;
|
|
3735
|
+
const pinnedBackgroundBoundaries = [
|
|
3736
|
+
...(pluginBinSandboxPolicy?.requiredBoundaries || []),
|
|
3737
|
+
];
|
|
3738
|
+
const hasPinnedBackgroundPolicy = pinnedBackgroundBoundaries.length > 0;
|
|
3739
|
+
const linuxGenericStrongBackground =
|
|
3740
|
+
backgroundPlatform === "linux" &&
|
|
3741
|
+
!pluginBinInvocation &&
|
|
3742
|
+
pinnedBackgroundBoundaries.some(
|
|
3743
|
+
(boundary) => boundary === "filesystem" || boundary === "network",
|
|
3744
|
+
);
|
|
3745
|
+
const linuxDirectPluginStrongBackground =
|
|
3746
|
+
backgroundPlatform === "linux" &&
|
|
3747
|
+
pluginBinInvocation !== null &&
|
|
3748
|
+
pluginBinSandboxExecutionContract !== null &&
|
|
3749
|
+
pinnedBackgroundBoundaries.some(
|
|
3750
|
+
(boundary) => boundary === "filesystem" || boundary === "network",
|
|
3751
|
+
);
|
|
3647
3752
|
if (
|
|
3648
|
-
|
|
3649
|
-
|
|
3753
|
+
hasPinnedBackgroundPolicy &&
|
|
3754
|
+
(backgroundPlatform === "win32" ||
|
|
3755
|
+
(backgroundPlatform === "linux" &&
|
|
3756
|
+
!linuxGenericStrongBackground &&
|
|
3757
|
+
!linuxDirectPluginStrongBackground))
|
|
3650
3758
|
) {
|
|
3651
3759
|
return attachDescriptor({
|
|
3652
3760
|
error:
|
|
@@ -3661,6 +3769,84 @@ async function executeToolInner(
|
|
|
3661
3769
|
approval: approvalOutcome,
|
|
3662
3770
|
});
|
|
3663
3771
|
}
|
|
3772
|
+
let linuxGenericBackgroundLaunch = null;
|
|
3773
|
+
if (linuxGenericStrongBackground) {
|
|
3774
|
+
const { workspaceRoot, workingDirectory } =
|
|
3775
|
+
resolveBackgroundShellWorkspacePaths(
|
|
3776
|
+
cwd,
|
|
3777
|
+
args.cwd,
|
|
3778
|
+
pluginBinSandboxPolicy,
|
|
3779
|
+
);
|
|
3780
|
+
const file = "/bin/sh";
|
|
3781
|
+
const launchArgs = ["-c", args.command];
|
|
3782
|
+
const options = {
|
|
3783
|
+
cwd: workingDirectory,
|
|
3784
|
+
shell: false,
|
|
3785
|
+
windowsHide: true,
|
|
3786
|
+
env: applyCredentialProxy({
|
|
3787
|
+
...process.env,
|
|
3788
|
+
CLAUDECODE: "1",
|
|
3789
|
+
...(sessionId
|
|
3790
|
+
? {
|
|
3791
|
+
CC_SESSION_ID: String(sessionId),
|
|
3792
|
+
CLAUDE_CODE_SESSION_ID: String(sessionId),
|
|
3793
|
+
}
|
|
3794
|
+
: {}),
|
|
3795
|
+
}).env,
|
|
3796
|
+
detached: false,
|
|
3797
|
+
origin: "tool:run_shell",
|
|
3798
|
+
policy: "allow",
|
|
3799
|
+
scope: "agent",
|
|
3800
|
+
sandboxPolicy: pluginBinSandboxPolicy,
|
|
3801
|
+
};
|
|
3802
|
+
const issuer =
|
|
3803
|
+
_backgroundProcessDeps.issueLinuxWorkspaceSandboxExecutionContract;
|
|
3804
|
+
if (typeof issuer !== "function") {
|
|
3805
|
+
throw createBackgroundShellSandboxFailure(
|
|
3806
|
+
"background_contract_issuer_unavailable",
|
|
3807
|
+
"Linux background shell sandbox contract issuer is unavailable",
|
|
3808
|
+
pluginBinSandboxPolicy,
|
|
3809
|
+
);
|
|
3810
|
+
}
|
|
3811
|
+
let sandboxExecutionContract;
|
|
3812
|
+
try {
|
|
3813
|
+
sandboxExecutionContract = issuer(
|
|
3814
|
+
file,
|
|
3815
|
+
launchArgs,
|
|
3816
|
+
options,
|
|
3817
|
+
workspaceRoot,
|
|
3818
|
+
{ sync: false },
|
|
3819
|
+
);
|
|
3820
|
+
} catch (error) {
|
|
3821
|
+
if (
|
|
3822
|
+
error?.sandboxFailClosed === true ||
|
|
3823
|
+
error?.code === "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED"
|
|
3824
|
+
) {
|
|
3825
|
+
throw error;
|
|
3826
|
+
}
|
|
3827
|
+
throw createBackgroundShellSandboxFailure(
|
|
3828
|
+
"background_contract_issuance_failed",
|
|
3829
|
+
`Linux background shell sandbox contract could not be issued: ${error?.message || String(error)}`,
|
|
3830
|
+
pluginBinSandboxPolicy,
|
|
3831
|
+
error,
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
3834
|
+
if (!sandboxExecutionContract) {
|
|
3835
|
+
throw createBackgroundShellSandboxFailure(
|
|
3836
|
+
"background_contract_unavailable",
|
|
3837
|
+
"Linux background shell sandbox contract issuer returned no authority",
|
|
3838
|
+
pluginBinSandboxPolicy,
|
|
3839
|
+
);
|
|
3840
|
+
}
|
|
3841
|
+
linuxGenericBackgroundLaunch = {
|
|
3842
|
+
file,
|
|
3843
|
+
args: launchArgs,
|
|
3844
|
+
options: {
|
|
3845
|
+
...options,
|
|
3846
|
+
sandboxExecutionContract,
|
|
3847
|
+
},
|
|
3848
|
+
};
|
|
3849
|
+
}
|
|
3664
3850
|
// Free memory from idle background tasks before adding another, so a
|
|
3665
3851
|
// long agent run can't accumulate forgotten dev servers (no-op unless
|
|
3666
3852
|
// the machine is actually under memory pressure).
|
|
@@ -3669,7 +3855,11 @@ async function executeToolInner(
|
|
|
3669
3855
|
const task = {
|
|
3670
3856
|
id,
|
|
3671
3857
|
command: args.command,
|
|
3672
|
-
cwd:
|
|
3858
|
+
cwd:
|
|
3859
|
+
linuxGenericBackgroundLaunch?.options.cwd ||
|
|
3860
|
+
(linuxDirectPluginStrongBackground
|
|
3861
|
+
? pluginBinSandboxExecutionContract.workingDirectory
|
|
3862
|
+
: args.cwd || cwd),
|
|
3673
3863
|
status: "running",
|
|
3674
3864
|
exitCode: null,
|
|
3675
3865
|
signal: null,
|
|
@@ -3680,44 +3870,61 @@ async function executeToolInner(
|
|
|
3680
3870
|
out: _newBgStream(),
|
|
3681
3871
|
err: _newBgStream(),
|
|
3682
3872
|
child: null,
|
|
3873
|
+
sandboxManagedTree:
|
|
3874
|
+
linuxGenericBackgroundLaunch !== null ||
|
|
3875
|
+
linuxDirectPluginStrongBackground,
|
|
3683
3876
|
};
|
|
3684
3877
|
try {
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3878
|
+
// The strong route already has its exact contract-bound options.
|
|
3879
|
+
// Construct legacy options only for legacy/direct-Plugin launches.
|
|
3880
|
+
const bgSpawnOpts = linuxGenericBackgroundLaunch
|
|
3881
|
+
? null
|
|
3882
|
+
: {
|
|
3883
|
+
cwd: task.cwd,
|
|
3884
|
+
shell: shellInv.useDefaultShell,
|
|
3885
|
+
windowsHide: true,
|
|
3886
|
+
// Same agent-identity env as the foreground path: CLAUDECODE marks
|
|
3887
|
+
// "running under the agent"; the session id correlates work to the
|
|
3888
|
+
// run (CC_SESSION_ID + CLAUDE_CODE_SESSION_ID for Claude-Code parity).
|
|
3889
|
+
// Credential proxy (opt-in, CC_CREDENTIAL_PROXY): keeps the agent's
|
|
3890
|
+
// real long-lived secrets out of the spawned command's env — a
|
|
3891
|
+
// no-op (same object) when disabled. See credential-proxy.js.
|
|
3892
|
+
env: applyCredentialProxy({
|
|
3893
|
+
...process.env,
|
|
3894
|
+
CLAUDECODE: "1",
|
|
3895
|
+
...(sessionId
|
|
3896
|
+
? {
|
|
3897
|
+
CC_SESSION_ID: String(sessionId),
|
|
3898
|
+
CLAUDE_CODE_SESSION_ID: String(sessionId),
|
|
3899
|
+
}
|
|
3900
|
+
: {}),
|
|
3901
|
+
}).env,
|
|
3902
|
+
// POSIX: own process group so check_shell{kill}/teardown can signal
|
|
3903
|
+
// the whole tree (shell + its grandchild command). No-op on Windows
|
|
3904
|
+
// where the tree is killed via taskkill /T instead.
|
|
3905
|
+
detached:
|
|
3906
|
+
process.platform !== "win32" &&
|
|
3907
|
+
!linuxDirectPluginStrongBackground,
|
|
3908
|
+
};
|
|
3710
3909
|
// PowerShell route: explicit argv (shell:false above); default route
|
|
3711
3910
|
// is the historical spawn(command, {shell:true}) byte-for-byte.
|
|
3712
|
-
const brokerOpts =
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3911
|
+
const brokerOpts = bgSpawnOpts
|
|
3912
|
+
? {
|
|
3913
|
+
...bgSpawnOpts,
|
|
3914
|
+
origin: processOrigin,
|
|
3915
|
+
policy: "allow",
|
|
3916
|
+
scope: "agent",
|
|
3917
|
+
...processProvenance,
|
|
3918
|
+
}
|
|
3919
|
+
: null;
|
|
3719
3920
|
let child;
|
|
3720
|
-
if (
|
|
3921
|
+
if (linuxGenericBackgroundLaunch) {
|
|
3922
|
+
child = _backgroundProcessDeps.run(
|
|
3923
|
+
linuxGenericBackgroundLaunch.file,
|
|
3924
|
+
linuxGenericBackgroundLaunch.args,
|
|
3925
|
+
linuxGenericBackgroundLaunch.options,
|
|
3926
|
+
);
|
|
3927
|
+
} else if (pluginBinInvocation) {
|
|
3721
3928
|
reattestPluginBinInvocation(pluginBinInvocation);
|
|
3722
3929
|
pluginBinResult.plugin_bin.launch_identity_reattested = true;
|
|
3723
3930
|
child = broker.spawn(
|
|
@@ -3774,6 +3981,33 @@ async function executeToolInner(
|
|
|
3774
3981
|
_releaseBgChildHandles(task);
|
|
3775
3982
|
});
|
|
3776
3983
|
} catch (err) {
|
|
3984
|
+
if (
|
|
3985
|
+
linuxGenericBackgroundLaunch ||
|
|
3986
|
+
linuxDirectPluginStrongBackground
|
|
3987
|
+
) {
|
|
3988
|
+
if (task.child && !task.child.killed) {
|
|
3989
|
+
try {
|
|
3990
|
+
task.child.kill("SIGKILL");
|
|
3991
|
+
} catch {
|
|
3992
|
+
// Preserve the setup failure; the bwrap supervisor also has
|
|
3993
|
+
// --die-with-parent as a final process-lifetime backstop.
|
|
3994
|
+
}
|
|
3995
|
+
_releaseBgChildHandles(task);
|
|
3996
|
+
}
|
|
3997
|
+
if (
|
|
3998
|
+
err?.sandboxFailClosed === true ||
|
|
3999
|
+
(typeof err?.code === "string" &&
|
|
4000
|
+
err.code.startsWith("ERR_PROCESS_SANDBOX"))
|
|
4001
|
+
) {
|
|
4002
|
+
throw err;
|
|
4003
|
+
}
|
|
4004
|
+
throw createBackgroundShellSandboxFailure(
|
|
4005
|
+
"background_sandbox_launch_failed",
|
|
4006
|
+
`Linux background shell sandbox launch failed: ${err?.message || String(err)}`,
|
|
4007
|
+
pluginBinSandboxPolicy,
|
|
4008
|
+
err,
|
|
4009
|
+
);
|
|
4010
|
+
}
|
|
3777
4011
|
task.status = "error";
|
|
3778
4012
|
task.error = String(err?.message || err).substring(0, 2000);
|
|
3779
4013
|
task.endedAt = new Date().toISOString();
|
|
@@ -6742,7 +6976,15 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
6742
6976
|
options.streamStallMs,
|
|
6743
6977
|
options.streamStallTimeoutMs,
|
|
6744
6978
|
),
|
|
6745
|
-
{
|
|
6979
|
+
{
|
|
6980
|
+
signal,
|
|
6981
|
+
onRetry: (attempt, error, telemetry) =>
|
|
6982
|
+
options.onStreamRetry?.(attempt, error, {
|
|
6983
|
+
...telemetry,
|
|
6984
|
+
provider: "ollama",
|
|
6985
|
+
model: model || null,
|
|
6986
|
+
}),
|
|
6987
|
+
},
|
|
6746
6988
|
);
|
|
6747
6989
|
}
|
|
6748
6990
|
const response = await fetch(apiUrl, {
|
|
@@ -6868,7 +7110,15 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
6868
7110
|
options.streamStallMs,
|
|
6869
7111
|
options.streamStallTimeoutMs,
|
|
6870
7112
|
),
|
|
6871
|
-
{
|
|
7113
|
+
{
|
|
7114
|
+
signal,
|
|
7115
|
+
onRetry: (attempt, error, telemetry) =>
|
|
7116
|
+
options.onStreamRetry?.(attempt, error, {
|
|
7117
|
+
...telemetry,
|
|
7118
|
+
provider: "anthropic",
|
|
7119
|
+
model: effModel,
|
|
7120
|
+
}),
|
|
7121
|
+
},
|
|
6872
7122
|
);
|
|
6873
7123
|
}
|
|
6874
7124
|
|
|
@@ -6972,7 +7222,15 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
6972
7222
|
options.streamStallMs,
|
|
6973
7223
|
options.streamStallTimeoutMs,
|
|
6974
7224
|
),
|
|
6975
|
-
{
|
|
7225
|
+
{
|
|
7226
|
+
signal,
|
|
7227
|
+
onRetry: (attempt, error, telemetry) =>
|
|
7228
|
+
options.onStreamRetry?.(attempt, error, {
|
|
7229
|
+
...telemetry,
|
|
7230
|
+
provider,
|
|
7231
|
+
model: model || defaultModels[provider] || "gpt-4o-mini",
|
|
7232
|
+
}),
|
|
7233
|
+
},
|
|
6976
7234
|
);
|
|
6977
7235
|
}
|
|
6978
7236
|
|
|
@@ -7171,8 +7429,10 @@ export async function _retryStreamingChat(streamFn, opts = {}) {
|
|
|
7171
7429
|
const base = opts.baseDelayMs ?? STREAM_RETRY_BASE_MS;
|
|
7172
7430
|
const signal = opts.signal;
|
|
7173
7431
|
const sleep = opts.sleep || ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
7432
|
+
const now = typeof opts.now === "function" ? opts.now : Date.now;
|
|
7174
7433
|
let attempt = 0;
|
|
7175
7434
|
for (;;) {
|
|
7435
|
+
const attemptStartedAt = now();
|
|
7176
7436
|
try {
|
|
7177
7437
|
return await streamFn();
|
|
7178
7438
|
} catch (err) {
|
|
@@ -7181,7 +7441,9 @@ export async function _retryStreamingChat(streamFn, opts = {}) {
|
|
|
7181
7441
|
attempt++;
|
|
7182
7442
|
if (typeof opts.onRetry === "function") {
|
|
7183
7443
|
try {
|
|
7184
|
-
opts.onRetry(attempt, err
|
|
7444
|
+
opts.onRetry(attempt, err, {
|
|
7445
|
+
durationMs: Math.max(0, now() - attemptStartedAt),
|
|
7446
|
+
});
|
|
7185
7447
|
} catch {
|
|
7186
7448
|
/* the retry notice is best-effort; never let it mask the retry */
|
|
7187
7449
|
}
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
appendAssistantMessage as jsonlAppendAssistantMessage,
|
|
44
44
|
appendTokenUsage as jsonlAppendTokenUsage,
|
|
45
45
|
appendToolCallCompact as jsonlAppendToolCallCompact,
|
|
46
|
+
appendLlmRetryCompact as jsonlAppendLlmRetryCompact,
|
|
46
47
|
appendCompactEvent as jsonlAppendCompactEvent,
|
|
47
48
|
appendEvent as jsonlAppendEvent,
|
|
48
49
|
readEvents as jsonlReadEvents,
|
|
@@ -51,6 +52,7 @@ import {
|
|
|
51
52
|
getLastSessionId as jsonlGetLastSessionId,
|
|
52
53
|
verifySession as jsonlVerifySession,
|
|
53
54
|
} from "../harness/jsonl-session-store.js";
|
|
55
|
+
import { classifyStreamRetryReason } from "../lib/stream-retry.js";
|
|
54
56
|
import {
|
|
55
57
|
SideEffectLedger,
|
|
56
58
|
reconcileSideEffects,
|
|
@@ -66,6 +68,7 @@ import {
|
|
|
66
68
|
executeHooksV2Event,
|
|
67
69
|
resolvePromptExpansion,
|
|
68
70
|
} from "../lib/hooks-v2-producers.js";
|
|
71
|
+
import { runWithHostHooksV2Workspace } from "../lib/hooks-v2-workspace-context.js";
|
|
69
72
|
import { CLISkillLoader } from "../lib/skill-loader.js";
|
|
70
73
|
import { expandFileRefsAsync } from "./file-ref-expander.js";
|
|
71
74
|
import { composeSystemPrompt } from "./system-prompt.js";
|
|
@@ -323,7 +326,9 @@ export function applyForkSession(opts = {}, store = {}) {
|
|
|
323
326
|
* @param {string[]} [options.allowedTools]
|
|
324
327
|
* @param {string[]} [options.disallowedTools]
|
|
325
328
|
* @param {number} [options.maxTurns] Cap on agent loop iterations.
|
|
326
|
-
* @param {string} [options.cwd]
|
|
329
|
+
* @param {string} [options.cwd] Trusted CLI-host workspace
|
|
330
|
+
* input. Never populate this from
|
|
331
|
+
* model/plugin/hook/event payloads.
|
|
327
332
|
* @param {string[]} [options.additionalDirectories] Extra workspace roots
|
|
328
333
|
* (--add-dir): absolute dirs the
|
|
329
334
|
* agent may read/search/edit.
|
|
@@ -339,6 +344,13 @@ export function applyForkSession(opts = {}, store = {}) {
|
|
|
339
344
|
* @returns {Promise<{ exitCode:number, result:string, isError:boolean }>}
|
|
340
345
|
*/
|
|
341
346
|
export async function runAgentHeadless(options = {}, deps = {}) {
|
|
347
|
+
const trustedWorkspaceRoot = options.cwd || process.cwd();
|
|
348
|
+
return runWithHostHooksV2Workspace(trustedWorkspaceRoot, () =>
|
|
349
|
+
runAgentHeadlessInWorkspace(options, deps),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async function runAgentHeadlessInWorkspace(options = {}, deps = {}) {
|
|
342
354
|
const prompt = (options.prompt || "").trim();
|
|
343
355
|
if (!prompt) {
|
|
344
356
|
throw new Error(
|
|
@@ -503,6 +515,8 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
503
515
|
appendTokenUsage: deps.appendTokenUsage || jsonlAppendTokenUsage,
|
|
504
516
|
appendToolCallCompact:
|
|
505
517
|
deps.appendToolCallCompact || jsonlAppendToolCallCompact,
|
|
518
|
+
appendLlmRetryCompact:
|
|
519
|
+
deps.appendLlmRetryCompact || jsonlAppendLlmRetryCompact,
|
|
506
520
|
appendCompactEvent: deps.appendCompactEvent || jsonlAppendCompactEvent,
|
|
507
521
|
appendEvent: deps.appendEvent || jsonlAppendEvent,
|
|
508
522
|
readEvents: deps.readEvents || jsonlReadEvents,
|
|
@@ -1626,6 +1640,22 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1626
1640
|
// while a human watching a long `cc agent -p` run learns we're still waiting
|
|
1627
1641
|
// and, when a hard inactivity timeout is set, when it will auto-retry. Plain
|
|
1628
1642
|
// text (no chalk) since headless stderr is frequently piped/non-TTY.
|
|
1643
|
+
onStreamRetry: (attempt, error, telemetry = {}) => {
|
|
1644
|
+
writeErr(` ⟳ connection dropped — retrying (attempt ${attempt})…\n`);
|
|
1645
|
+
if (persist) {
|
|
1646
|
+
try {
|
|
1647
|
+
store.appendLlmRetryCompact(sessionId, {
|
|
1648
|
+
attempt,
|
|
1649
|
+
durationMs: telemetry.durationMs,
|
|
1650
|
+
provider: telemetry.provider || provider,
|
|
1651
|
+
model: telemetry.model || model,
|
|
1652
|
+
reason: classifyStreamRetryReason(error),
|
|
1653
|
+
});
|
|
1654
|
+
} catch {
|
|
1655
|
+
/* usage telemetry is best-effort */
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
},
|
|
1629
1659
|
onStall: (ms, timeoutMs) => {
|
|
1630
1660
|
const silent = Math.round(ms / 1000);
|
|
1631
1661
|
const retryIn = timeoutMs > ms ? Math.round((timeoutMs - ms) / 1000) : 0;
|
|
@@ -1678,6 +1708,11 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1678
1708
|
|
|
1679
1709
|
const startedAt = deps.now ? deps.now() : Date.now();
|
|
1680
1710
|
const toolCalls = [];
|
|
1711
|
+
// The core normally attaches a precise toolTelemetryRecord on success.
|
|
1712
|
+
// Keep an event-boundary fallback for denials/early throws that settle
|
|
1713
|
+
// before that record is produced. Tools are serial in this loop, so one
|
|
1714
|
+
// timestamp is sufficient and never leaks into the result envelope.
|
|
1715
|
+
let currentToolStartedAt = null;
|
|
1681
1716
|
// Policy denials (blocked tool calls) collected for an end-of-run summary,
|
|
1682
1717
|
// so a non-interactive run surfaces what got blocked the way the REPL's
|
|
1683
1718
|
// `/permissions denials` does (Claude-Code 2.1.193 denial reasons).
|
|
@@ -1970,6 +2005,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1970
2005
|
break;
|
|
1971
2006
|
}
|
|
1972
2007
|
case "tool-executing": {
|
|
2008
|
+
currentToolStartedAt = deps.now ? deps.now() : Date.now();
|
|
1973
2009
|
const line = ` [${event.tool}] ${formatToolArgs(event.tool, event.args)}`;
|
|
1974
2010
|
if (isText) writeErr(line + "\n");
|
|
1975
2011
|
emitStream({
|
|
@@ -2057,11 +2093,21 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
2057
2093
|
if (toolCalls.length > 0) {
|
|
2058
2094
|
const settledCall = toolCalls[toolCalls.length - 1];
|
|
2059
2095
|
settledCall.is_error = Boolean(err);
|
|
2096
|
+
settledCall.durationMs =
|
|
2097
|
+
event.result?.toolTelemetryRecord?.durationMs ??
|
|
2098
|
+
(currentToolStartedAt === null
|
|
2099
|
+
? undefined
|
|
2100
|
+
: Math.max(
|
|
2101
|
+
0,
|
|
2102
|
+
(deps.now ? deps.now() : Date.now()) -
|
|
2103
|
+
currentToolStartedAt,
|
|
2104
|
+
));
|
|
2060
2105
|
Object.assign(
|
|
2061
2106
|
settledCall,
|
|
2062
2107
|
extractPluginUsageAttribution(event.result),
|
|
2063
2108
|
);
|
|
2064
2109
|
}
|
|
2110
|
+
currentToolStartedAt = null;
|
|
2065
2111
|
// Track policy denials (not plain tool failures) for the end-of-run
|
|
2066
2112
|
// summary. The preceding tool-executing pushed the args.
|
|
2067
2113
|
if (err) {
|
|
@@ -2540,6 +2586,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
2540
2586
|
tc.tool === "run_skill" ? tc.args?.skill_name || null : undefined,
|
|
2541
2587
|
plugin: tc.plugin || undefined,
|
|
2542
2588
|
pluginVersion: tc.pluginVersion || undefined,
|
|
2589
|
+
durationMs: tc.durationMs,
|
|
2543
2590
|
});
|
|
2544
2591
|
}
|
|
2545
2592
|
// Attributed child-loop usage first (chronology: it happened during
|