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
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
const trustedWorkspaceStorage = new AsyncLocalStorage();
|
|
7
|
+
const registeredHostWorkspaces = new Map();
|
|
8
|
+
const registeredHostWorkspaceIdentities = new Map();
|
|
9
|
+
const MAX_REGISTERED_HOST_WORKSPACES = 1024;
|
|
10
|
+
|
|
11
|
+
function validateHostWorkspaceRoot(workspaceRoot) {
|
|
12
|
+
if (
|
|
13
|
+
typeof workspaceRoot !== "string" ||
|
|
14
|
+
workspaceRoot.length === 0 ||
|
|
15
|
+
workspaceRoot.includes("\0")
|
|
16
|
+
) {
|
|
17
|
+
const error = new TypeError(
|
|
18
|
+
"Hooks v2 host workspace root must be a non-empty path",
|
|
19
|
+
);
|
|
20
|
+
error.code = "CC_HOOK_TRUSTED_WORKSPACE_INVALID";
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
return path.resolve(workspaceRoot);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function invalidWorkspaceRoot(message, cause) {
|
|
27
|
+
const error = new Error(message, cause ? { cause } : undefined);
|
|
28
|
+
error.code = "CC_HOOK_TRUSTED_WORKSPACE_INVALID";
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function workspaceGeneration(stats) {
|
|
33
|
+
// dev+ino alone is insufficient: filesystems may immediately reuse an inode
|
|
34
|
+
// after a same-path directory replacement. Prefer the stable creation
|
|
35
|
+
// timestamp and fail closed on metadata changes when a filesystem does not
|
|
36
|
+
// expose one.
|
|
37
|
+
return stats.birthtimeNs > 0n
|
|
38
|
+
? `birth:${stats.birthtimeNs.toString()}`
|
|
39
|
+
: `ctime:${stats.ctimeNs.toString()}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function captureWorkspaceIdentity(workspaceRoot) {
|
|
43
|
+
const resolvedRoot = validateHostWorkspaceRoot(workspaceRoot);
|
|
44
|
+
let canonicalRoot;
|
|
45
|
+
let stats;
|
|
46
|
+
try {
|
|
47
|
+
canonicalRoot = fs.realpathSync.native(resolvedRoot);
|
|
48
|
+
stats = fs.statSync(canonicalRoot, { bigint: true });
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw invalidWorkspaceRoot(
|
|
51
|
+
"Hooks v2 host workspace root must resolve to an existing directory",
|
|
52
|
+
error,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
if (!stats.isDirectory()) {
|
|
56
|
+
throw invalidWorkspaceRoot(
|
|
57
|
+
"Hooks v2 host workspace root must resolve to a directory",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return Object.freeze({
|
|
61
|
+
canonicalRoot,
|
|
62
|
+
device: stats.dev,
|
|
63
|
+
inode: stats.ino,
|
|
64
|
+
generation: workspaceGeneration(stats),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function workspaceIdentityKey(identity) {
|
|
69
|
+
return JSON.stringify([
|
|
70
|
+
identity.canonicalRoot,
|
|
71
|
+
identity.device.toString(),
|
|
72
|
+
identity.inode.toString(),
|
|
73
|
+
identity.generation,
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function sameWorkspaceIdentity(left, right) {
|
|
78
|
+
return (
|
|
79
|
+
left.canonicalRoot === right.canonicalRoot &&
|
|
80
|
+
left.device === right.device &&
|
|
81
|
+
left.inode === right.inode &&
|
|
82
|
+
left.generation === right.generation
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function invalidateWorkspaceRecord(record) {
|
|
87
|
+
if (registeredHostWorkspaces.get(record.binding.bindingId) === record) {
|
|
88
|
+
registeredHostWorkspaces.delete(record.binding.bindingId);
|
|
89
|
+
}
|
|
90
|
+
if (
|
|
91
|
+
registeredHostWorkspaceIdentities.get(record.identityKey) ===
|
|
92
|
+
record.binding.bindingId
|
|
93
|
+
) {
|
|
94
|
+
registeredHostWorkspaceIdentities.delete(record.identityKey);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function verifyWorkspaceRecord(record) {
|
|
99
|
+
if (!record) return null;
|
|
100
|
+
if (registeredHostWorkspaces.get(record.binding.bindingId) !== record) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
let currentIdentity;
|
|
104
|
+
try {
|
|
105
|
+
currentIdentity = captureWorkspaceIdentity(record.binding.workspaceRoot);
|
|
106
|
+
} catch {
|
|
107
|
+
invalidateWorkspaceRecord(record);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (!sameWorkspaceIdentity(record.identity, currentIdentity)) {
|
|
111
|
+
invalidateWorkspaceRecord(record);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return record.binding;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function pruneInvalidWorkspaceRecords() {
|
|
118
|
+
for (const record of Array.from(registeredHostWorkspaces.values())) {
|
|
119
|
+
verifyWorkspaceRecord(record);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function workspaceBindingId(identity) {
|
|
124
|
+
return createHash("sha256")
|
|
125
|
+
.update("chainlesschain.hooks-v2-host-workspace.v3\0")
|
|
126
|
+
.update(workspaceIdentityKey(identity), "utf8")
|
|
127
|
+
.digest("hex");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Register a root selected by trusted host bootstrap code. Durable records
|
|
132
|
+
* persist only the returned opaque stable digest; the plaintext canonical path
|
|
133
|
+
* and directory identity remain process-local.
|
|
134
|
+
*/
|
|
135
|
+
export function registerHostHooksV2Workspace(workspaceRoot) {
|
|
136
|
+
const identity = captureWorkspaceIdentity(workspaceRoot);
|
|
137
|
+
const identityKey = workspaceIdentityKey(identity);
|
|
138
|
+
const existingBindingId = registeredHostWorkspaceIdentities.get(identityKey);
|
|
139
|
+
if (existingBindingId) {
|
|
140
|
+
const existingRecord = registeredHostWorkspaces.get(existingBindingId);
|
|
141
|
+
const existingBinding = verifyWorkspaceRecord(existingRecord);
|
|
142
|
+
if (
|
|
143
|
+
existingBinding &&
|
|
144
|
+
sameWorkspaceIdentity(existingRecord.identity, identity)
|
|
145
|
+
) {
|
|
146
|
+
return existingBinding;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// A long-running host may create and remove many isolated worktrees. Sweep
|
|
151
|
+
// stale filesystem identities before enforcing the bounded registry so
|
|
152
|
+
// deleted roots cannot exhaust future trusted registrations.
|
|
153
|
+
if (registeredHostWorkspaces.size >= MAX_REGISTERED_HOST_WORKSPACES) {
|
|
154
|
+
pruneInvalidWorkspaceRecords();
|
|
155
|
+
}
|
|
156
|
+
if (registeredHostWorkspaces.size >= MAX_REGISTERED_HOST_WORKSPACES) {
|
|
157
|
+
const error = new Error(
|
|
158
|
+
"Hooks v2 host workspace registry capacity exceeded",
|
|
159
|
+
);
|
|
160
|
+
error.code = "CC_HOOK_TRUSTED_WORKSPACE_LIMIT";
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const bindingId = workspaceBindingId(identity);
|
|
165
|
+
const collidingRecord = registeredHostWorkspaces.get(bindingId);
|
|
166
|
+
if (collidingRecord) {
|
|
167
|
+
const collidingBinding = verifyWorkspaceRecord(collidingRecord);
|
|
168
|
+
if (
|
|
169
|
+
collidingBinding &&
|
|
170
|
+
sameWorkspaceIdentity(collidingRecord.identity, identity)
|
|
171
|
+
) {
|
|
172
|
+
registeredHostWorkspaceIdentities.set(identityKey, bindingId);
|
|
173
|
+
return collidingBinding;
|
|
174
|
+
}
|
|
175
|
+
if (
|
|
176
|
+
collidingBinding &&
|
|
177
|
+
collidingRecord.identity.canonicalRoot !== identity.canonicalRoot
|
|
178
|
+
) {
|
|
179
|
+
const error = new Error("Hooks v2 workspace binding digest collision");
|
|
180
|
+
error.code = "CC_HOOK_TRUSTED_WORKSPACE_COLLISION";
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
if (collidingBinding) {
|
|
184
|
+
throw invalidWorkspaceRoot(
|
|
185
|
+
"Hooks v2 host workspace identity changed during registration",
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const binding = Object.freeze({
|
|
191
|
+
bindingId,
|
|
192
|
+
workspaceRoot: identity.canonicalRoot,
|
|
193
|
+
});
|
|
194
|
+
const record = Object.freeze({
|
|
195
|
+
binding,
|
|
196
|
+
identity,
|
|
197
|
+
identityKey,
|
|
198
|
+
});
|
|
199
|
+
registeredHostWorkspaces.set(bindingId, record);
|
|
200
|
+
registeredHostWorkspaceIdentities.set(identityKey, bindingId);
|
|
201
|
+
return binding;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Run a CLI-host operation with an immutable Hooks v2 workspace authority.
|
|
206
|
+
*
|
|
207
|
+
* Only host bootstrap code may call this with a root selected before hook,
|
|
208
|
+
* plugin, model, or event payload processing. The binding is async-scoped
|
|
209
|
+
* instead of global so concurrent CLI runs cannot replace one another's
|
|
210
|
+
* writable root.
|
|
211
|
+
*/
|
|
212
|
+
export function runWithHostHooksV2Workspace(workspaceRoot, callback) {
|
|
213
|
+
if (typeof callback !== "function") {
|
|
214
|
+
throw new TypeError("Hooks v2 workspace callback must be a function");
|
|
215
|
+
}
|
|
216
|
+
const binding = registerHostHooksV2Workspace(workspaceRoot);
|
|
217
|
+
return trustedWorkspaceStorage.run(
|
|
218
|
+
registeredHostWorkspaces.get(binding.bindingId),
|
|
219
|
+
callback,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Internal consumer seam for HooksV2Runtime. Event and hook payloads never
|
|
225
|
+
* participate in selecting this value.
|
|
226
|
+
*/
|
|
227
|
+
export function currentHostHooksV2WorkspaceRoot() {
|
|
228
|
+
return currentHostHooksV2WorkspaceBinding()?.workspaceRoot || null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function currentHostHooksV2WorkspaceBinding() {
|
|
232
|
+
return verifyWorkspaceRecord(trustedWorkspaceStorage.getStore());
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Resolve an opaque durable binding only against roots registered by the
|
|
237
|
+
* current host process. No persisted or event-supplied path is accepted.
|
|
238
|
+
*/
|
|
239
|
+
export function resolveRegisteredHostHooksV2Workspace(bindingId) {
|
|
240
|
+
if (typeof bindingId !== "string" || !/^[a-f0-9]{64}$/.test(bindingId)) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return verifyWorkspaceRecord(registeredHostWorkspaces.get(bindingId));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Revoke a process-local binding owned by trusted host lifecycle code.
|
|
248
|
+
* Payloads, hooks, and durable records must never call this release seam.
|
|
249
|
+
*/
|
|
250
|
+
export function releaseRegisteredHostHooksV2Workspace(bindingId) {
|
|
251
|
+
if (typeof bindingId !== "string" || !/^[a-f0-9]{64}$/.test(bindingId)) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
const record = registeredHostWorkspaces.get(bindingId);
|
|
255
|
+
if (!record) return false;
|
|
256
|
+
invalidateWorkspaceRecord(record);
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
@@ -100,6 +100,10 @@ describe("LSPClient handshake", () => {
|
|
|
100
100
|
|
|
101
101
|
it("passes plugin sandbox requirements to ProcessExecutionBroker", async () => {
|
|
102
102
|
const child = new FakeChild();
|
|
103
|
+
const contract = Object.freeze({ kind: "test-workspace-contract" });
|
|
104
|
+
const issueAuthority = vi
|
|
105
|
+
.spyOn(executionBroker, "issueLinuxWorkspaceSandboxExecutionContract")
|
|
106
|
+
.mockReturnValue(contract);
|
|
103
107
|
const brokerSpawn = vi
|
|
104
108
|
.spyOn(executionBroker, "spawn")
|
|
105
109
|
.mockReturnValue(child);
|
|
@@ -123,8 +127,19 @@ describe("LSPClient handshake", () => {
|
|
|
123
127
|
sandboxPolicy: {
|
|
124
128
|
requiredBoundaries: ["filesystem", "network"],
|
|
125
129
|
},
|
|
130
|
+
sandboxExecutionContract: contract,
|
|
126
131
|
}),
|
|
127
132
|
);
|
|
133
|
+
expect(issueAuthority).toHaveBeenCalledWith(
|
|
134
|
+
"fake-lsp",
|
|
135
|
+
["--stdio"],
|
|
136
|
+
expect.objectContaining({
|
|
137
|
+
cwd: "/proj",
|
|
138
|
+
shell: false,
|
|
139
|
+
origin: "plugin:lsp",
|
|
140
|
+
}),
|
|
141
|
+
"/proj",
|
|
142
|
+
);
|
|
128
143
|
expect(_deps.spawn).not.toHaveBeenCalled();
|
|
129
144
|
});
|
|
130
145
|
|
|
@@ -83,7 +83,7 @@ export class LSPClient extends EventEmitter {
|
|
|
83
83
|
const spawnFn = String(this.origin || "").startsWith("plugin:")
|
|
84
84
|
? executionBroker.spawn.bind(executionBroker)
|
|
85
85
|
: _deps.spawn;
|
|
86
|
-
|
|
86
|
+
const spawnOptions = {
|
|
87
87
|
cwd: this.rootPath,
|
|
88
88
|
env: { ...process.env, ...this.env },
|
|
89
89
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -103,6 +103,17 @@ export class LSPClient extends EventEmitter {
|
|
|
103
103
|
: {}),
|
|
104
104
|
}
|
|
105
105
|
: {}),
|
|
106
|
+
};
|
|
107
|
+
const sandboxExecutionContract =
|
|
108
|
+
executionBroker.issueLinuxWorkspaceSandboxExecutionContract(
|
|
109
|
+
spawnSpec.file,
|
|
110
|
+
spawnSpec.args,
|
|
111
|
+
spawnOptions,
|
|
112
|
+
this.rootPath,
|
|
113
|
+
);
|
|
114
|
+
this._child = spawnFn(spawnSpec.file, spawnSpec.args, {
|
|
115
|
+
...spawnOptions,
|
|
116
|
+
...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
|
|
106
117
|
});
|
|
107
118
|
|
|
108
119
|
this._child.on("error", (err) => {
|
|
@@ -25,6 +25,7 @@ import { executionBroker } from "./process-execution-broker/index.js";
|
|
|
25
25
|
import { EventRuntimeProducer } from "./event-runtime-producer.js";
|
|
26
26
|
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
27
27
|
import { monitorEventId } from "./monitor-event.js";
|
|
28
|
+
import { resolvePluginWorkspaceAuthority } from "./plugin-runtime/sandbox-policy.js";
|
|
28
29
|
|
|
29
30
|
export const _deps = {
|
|
30
31
|
spawn: (...args) => executionBroker.spawn(...args),
|
|
@@ -44,7 +45,9 @@ export class PluginMonitorSupervisor {
|
|
|
44
45
|
this._pluginSpawn = opts.brokerSpawn || this._spawn;
|
|
45
46
|
const eventRuntimeStore =
|
|
46
47
|
opts.eventRuntimeStore ||
|
|
47
|
-
(process.env.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
48
|
+
(process.env.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
49
|
+
? new EventRuntimeStore()
|
|
50
|
+
: null);
|
|
48
51
|
this._runtimeProducer = eventRuntimeStore
|
|
49
52
|
? new EventRuntimeProducer({ store: eventRuntimeStore, emitter: this })
|
|
50
53
|
: null;
|
|
@@ -118,7 +121,11 @@ export class PluginMonitorSupervisor {
|
|
|
118
121
|
{ origin: "monitor", id: monitorEventId(desc.id, { stream, line }) },
|
|
119
122
|
);
|
|
120
123
|
} catch (error) {
|
|
121
|
-
this._outputs.push({
|
|
124
|
+
this._outputs.push({
|
|
125
|
+
...output,
|
|
126
|
+
stream: "error",
|
|
127
|
+
line: `durable publish failed: ${error.message}`,
|
|
128
|
+
});
|
|
122
129
|
}
|
|
123
130
|
if (this._outputs.length > OUTPUT_RING) this._outputs.shift();
|
|
124
131
|
}
|
|
@@ -211,24 +218,54 @@ export class PluginMonitorSupervisor {
|
|
|
211
218
|
|
|
212
219
|
_spawnForDescriptor(desc, options) {
|
|
213
220
|
const isPlugin = desc?.origin === "plugin:monitor";
|
|
221
|
+
const pluginWorkspaceRoot = isPlugin
|
|
222
|
+
? resolvePluginWorkspaceAuthority(desc.pluginWorkspaceAuthority, {
|
|
223
|
+
origin: desc.origin,
|
|
224
|
+
pluginId: desc.pluginId,
|
|
225
|
+
pluginVersion: desc.pluginVersion,
|
|
226
|
+
pluginSource: desc.pluginSource,
|
|
227
|
+
})
|
|
228
|
+
: null;
|
|
229
|
+
if (
|
|
230
|
+
isPlugin &&
|
|
231
|
+
desc.sandboxPolicy?.requiredBoundaries?.length > 0 &&
|
|
232
|
+
!pluginWorkspaceRoot
|
|
233
|
+
) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`plugin monitor "${desc.id || desc.name || "unknown"}" is missing its trusted workspace authority`,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
const spawnOptions = {
|
|
239
|
+
...options,
|
|
240
|
+
origin: isPlugin ? desc.origin : "plugin-monitor:process",
|
|
241
|
+
policy: "allow",
|
|
242
|
+
scope: "plugin-monitor",
|
|
243
|
+
...(isPlugin
|
|
244
|
+
? {
|
|
245
|
+
pluginId: desc.pluginId,
|
|
246
|
+
pluginVersion: desc.pluginVersion,
|
|
247
|
+
pluginSource: desc.pluginSource,
|
|
248
|
+
...(desc.sandboxPolicy
|
|
249
|
+
? { sandboxPolicy: desc.sandboxPolicy }
|
|
250
|
+
: {}),
|
|
251
|
+
}
|
|
252
|
+
: {}),
|
|
253
|
+
};
|
|
254
|
+
const sandboxExecutionContract =
|
|
255
|
+
isPlugin && pluginWorkspaceRoot
|
|
256
|
+
? executionBroker.issueLinuxWorkspaceSandboxExecutionContract(
|
|
257
|
+
desc.command,
|
|
258
|
+
desc.args,
|
|
259
|
+
spawnOptions,
|
|
260
|
+
pluginWorkspaceRoot,
|
|
261
|
+
)
|
|
262
|
+
: null;
|
|
214
263
|
return (isPlugin ? this._pluginSpawn : this._spawn)(
|
|
215
264
|
desc.command,
|
|
216
265
|
desc.args,
|
|
217
266
|
{
|
|
218
|
-
...
|
|
219
|
-
|
|
220
|
-
policy: "allow",
|
|
221
|
-
scope: "plugin-monitor",
|
|
222
|
-
...(isPlugin
|
|
223
|
-
? {
|
|
224
|
-
pluginId: desc.pluginId,
|
|
225
|
-
pluginVersion: desc.pluginVersion,
|
|
226
|
-
pluginSource: desc.pluginSource,
|
|
227
|
-
...(desc.sandboxPolicy
|
|
228
|
-
? { sandboxPolicy: desc.sandboxPolicy }
|
|
229
|
-
: {}),
|
|
230
|
-
}
|
|
231
|
-
: {}),
|
|
267
|
+
...spawnOptions,
|
|
268
|
+
...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
|
|
232
269
|
},
|
|
233
270
|
);
|
|
234
271
|
}
|
|
@@ -990,7 +990,20 @@ export function reattestPluginBinInvocation(invocation) {
|
|
|
990
990
|
* policy-bearing Plugin Node or native invocation. Object identity is the
|
|
991
991
|
* capability: callers cannot mint a usable contract by copying public fields.
|
|
992
992
|
*/
|
|
993
|
-
export function createPluginSandboxExecutionContract(invocation) {
|
|
993
|
+
export function createPluginSandboxExecutionContract(invocation, options = {}) {
|
|
994
|
+
if (
|
|
995
|
+
options === null ||
|
|
996
|
+
typeof options !== "object" ||
|
|
997
|
+
Array.isArray(options) ||
|
|
998
|
+
Object.keys(options).some((key) => key !== "sync") ||
|
|
999
|
+
(options.sync !== undefined && typeof options.sync !== "boolean")
|
|
1000
|
+
) {
|
|
1001
|
+
throw pluginBinError(
|
|
1002
|
+
"ERR_PLUGIN_SANDBOX_CONTRACT_OPTIONS_INVALID",
|
|
1003
|
+
"plugin sandbox execution contract options must contain an optional boolean sync field",
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
const sync = options.sync !== false;
|
|
994
1007
|
const issuedResolution =
|
|
995
1008
|
invocation && typeof invocation === "object"
|
|
996
1009
|
? _issuedPluginBinInvocations.get(invocation)
|
|
@@ -1118,7 +1131,7 @@ export function createPluginSandboxExecutionContract(invocation) {
|
|
|
1118
1131
|
contractVersion: 1,
|
|
1119
1132
|
kind:
|
|
1120
1133
|
runtime === "native"
|
|
1121
|
-
? "strict-plugin-native-
|
|
1134
|
+
? "strict-plugin-native-elf-bin"
|
|
1122
1135
|
: "strict-plugin-node-bin",
|
|
1123
1136
|
pluginRoot,
|
|
1124
1137
|
workingDirectory: pluginRoot,
|
|
@@ -1140,7 +1153,7 @@ export function createPluginSandboxExecutionContract(invocation) {
|
|
|
1140
1153
|
pluginSource: invocation.pluginSource,
|
|
1141
1154
|
pluginExecutableIdentity: invocation.executableIdentity,
|
|
1142
1155
|
requiredBoundaries: invocation.sandboxPolicy.requiredBoundaries,
|
|
1143
|
-
sync
|
|
1156
|
+
sync,
|
|
1144
1157
|
}),
|
|
1145
1158
|
);
|
|
1146
1159
|
return contract;
|
|
@@ -1156,14 +1169,17 @@ export function createPluginSandboxExecutionContract(invocation) {
|
|
|
1156
1169
|
/**
|
|
1157
1170
|
* Backward-compatible Node-only issuer retained for existing callers.
|
|
1158
1171
|
*/
|
|
1159
|
-
export function createPluginNodeSandboxExecutionContract(
|
|
1172
|
+
export function createPluginNodeSandboxExecutionContract(
|
|
1173
|
+
invocation,
|
|
1174
|
+
options = {},
|
|
1175
|
+
) {
|
|
1160
1176
|
if (invocation?.runtime !== "node") {
|
|
1161
1177
|
throw pluginBinError(
|
|
1162
1178
|
"ERR_PLUGIN_NODE_SANDBOX_CONTRACT_UNSUPPORTED",
|
|
1163
1179
|
"plugin Node sandbox execution contract requires one direct policy-bearing Node bin",
|
|
1164
1180
|
);
|
|
1165
1181
|
}
|
|
1166
|
-
return createPluginSandboxExecutionContract(invocation);
|
|
1182
|
+
return createPluginSandboxExecutionContract(invocation, options);
|
|
1167
1183
|
}
|
|
1168
1184
|
|
|
1169
1185
|
/**
|