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
|
@@ -26,35 +26,79 @@ import fs from "node:fs/promises";
|
|
|
26
26
|
import path from "node:path";
|
|
27
27
|
import broker from "./process-execution-broker/index.js";
|
|
28
28
|
import hookEnvironment from "./hook-environment.cjs";
|
|
29
|
+
import hookShellCommand from "./hook-shell-command.cjs";
|
|
29
30
|
import permissionRules from "./permission-rules.cjs";
|
|
30
31
|
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
31
32
|
import { getDefaultEventRuntimeHost } from "./event-runtime-host.js";
|
|
33
|
+
import {
|
|
34
|
+
currentHostHooksV2WorkspaceBinding,
|
|
35
|
+
currentHostHooksV2WorkspaceRoot,
|
|
36
|
+
registerHostHooksV2Workspace,
|
|
37
|
+
resolveRegisteredHostHooksV2Workspace,
|
|
38
|
+
runWithHostHooksV2Workspace,
|
|
39
|
+
} from "./hooks-v2-workspace-context.js";
|
|
32
40
|
|
|
33
41
|
const { globToRegExp } = permissionRules;
|
|
34
42
|
const { buildManagedHookEnvironment } = hookEnvironment;
|
|
43
|
+
const {
|
|
44
|
+
buildExplicitHookShellInvocation,
|
|
45
|
+
issueTrustedHookSandboxContract,
|
|
46
|
+
isPathInside,
|
|
47
|
+
requireTrustedHookRoot,
|
|
48
|
+
requiresExplicitHookShell,
|
|
49
|
+
sandboxBoundaryError,
|
|
50
|
+
} = hookShellCommand;
|
|
35
51
|
|
|
36
52
|
const VALID_HOOK_EVENTS = new Set([
|
|
37
53
|
"Setup",
|
|
38
54
|
// Session
|
|
39
|
-
"PreToolUse",
|
|
40
|
-
"
|
|
55
|
+
"PreToolUse",
|
|
56
|
+
"PostToolUse",
|
|
57
|
+
"Notification",
|
|
58
|
+
"Stop",
|
|
59
|
+
"SubagentStart",
|
|
60
|
+
"SubagentStop",
|
|
61
|
+
"SessionResume",
|
|
62
|
+
"SessionPause",
|
|
63
|
+
"PostCompact",
|
|
64
|
+
"StopFailure",
|
|
41
65
|
// Auth
|
|
42
|
-
"PreCommit",
|
|
66
|
+
"PreCommit",
|
|
67
|
+
"PostCommit",
|
|
43
68
|
// Skill
|
|
44
|
-
"UserPromptSubmit",
|
|
69
|
+
"UserPromptSubmit",
|
|
70
|
+
"UserPromptExpansion",
|
|
71
|
+
"SessionStart",
|
|
72
|
+
"SessionEnd",
|
|
45
73
|
// Model
|
|
46
|
-
"PreCompact",
|
|
74
|
+
"PreCompact",
|
|
75
|
+
"ModelSelection",
|
|
47
76
|
// Config
|
|
48
|
-
"ConfigChange",
|
|
77
|
+
"ConfigChange",
|
|
78
|
+
"PermissionAllow",
|
|
79
|
+
"PermissionDeny",
|
|
80
|
+
"PermissionRequest",
|
|
81
|
+
"PermissionDenied",
|
|
49
82
|
// Timeline
|
|
50
83
|
"TimelineEntry",
|
|
51
84
|
// MCP
|
|
52
|
-
"McpRequest",
|
|
85
|
+
"McpRequest",
|
|
86
|
+
"McpResponse",
|
|
87
|
+
"MCPElicitation",
|
|
88
|
+
"Elicitation",
|
|
89
|
+
"ElicitationResult",
|
|
53
90
|
// Task / workspace lifecycle
|
|
54
|
-
"TaskCreated",
|
|
55
|
-
"
|
|
91
|
+
"TaskCreated",
|
|
92
|
+
"TaskCompleted",
|
|
93
|
+
"InstructionsLoaded",
|
|
94
|
+
"CwdChanged",
|
|
95
|
+
"WorktreeCreate",
|
|
96
|
+
"WorktreeRemove",
|
|
97
|
+
"TeammateIdle",
|
|
56
98
|
// Tool aggregate / failure / filesystem lifecycle
|
|
57
|
-
"PostToolUseFailure",
|
|
99
|
+
"PostToolUseFailure",
|
|
100
|
+
"PostToolBatch",
|
|
101
|
+
"FileChanged",
|
|
58
102
|
]);
|
|
59
103
|
|
|
60
104
|
const VALID_EXECUTOR_TYPES = new Set([
|
|
@@ -137,7 +181,9 @@ function strictestDecision(results) {
|
|
|
137
181
|
|
|
138
182
|
function hostnameMatches(hostname, pattern) {
|
|
139
183
|
const host = String(hostname || "").toLowerCase();
|
|
140
|
-
const rule = String(pattern || "")
|
|
184
|
+
const rule = String(pattern || "")
|
|
185
|
+
.trim()
|
|
186
|
+
.toLowerCase();
|
|
141
187
|
if (!host || !rule) return false;
|
|
142
188
|
if (rule.startsWith("*.")) {
|
|
143
189
|
const suffix = rule.slice(1);
|
|
@@ -240,12 +286,31 @@ export function resolveHookSandboxPolicy(hook = {}, managedPolicy = {}) {
|
|
|
240
286
|
return resolved;
|
|
241
287
|
}
|
|
242
288
|
|
|
289
|
+
function hooksRequireWorkspaceBinding(hooks, managedPolicy) {
|
|
290
|
+
return hooks.some((hook) => {
|
|
291
|
+
if (hook.type !== "command") return false;
|
|
292
|
+
try {
|
|
293
|
+
return requiresExplicitHookShell(
|
|
294
|
+
resolveHookSandboxPolicy(hook, managedPolicy),
|
|
295
|
+
);
|
|
296
|
+
} catch {
|
|
297
|
+
// Invalid policy is fail-closed during execution and must remain so after
|
|
298
|
+
// a crash instead of recovering without workspace authority.
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
243
304
|
export function assertManagedHookPolicy(
|
|
244
305
|
hook,
|
|
245
306
|
context = {},
|
|
246
307
|
policy = {},
|
|
247
308
|
configDir = null,
|
|
309
|
+
workspaceRoot = null,
|
|
248
310
|
) {
|
|
311
|
+
// Retained for API compatibility and non-command policy growth, but never
|
|
312
|
+
// consulted as filesystem authority.
|
|
313
|
+
void context;
|
|
249
314
|
if (!managedListAllows(hook.type, policy.allowedExecutors)) {
|
|
250
315
|
throw managedPolicyError(
|
|
251
316
|
`Hook executor is outside the managed allowlist: ${hook.type}`,
|
|
@@ -259,10 +324,7 @@ export function assertManagedHookPolicy(
|
|
|
259
324
|
);
|
|
260
325
|
}
|
|
261
326
|
const executable = String(hook.command || "");
|
|
262
|
-
const commandCandidates = new Set([
|
|
263
|
-
executable,
|
|
264
|
-
path.basename(executable),
|
|
265
|
-
]);
|
|
327
|
+
const commandCandidates = new Set([executable, path.basename(executable)]);
|
|
266
328
|
if (
|
|
267
329
|
Array.isArray(policy.commandAllowlist) &&
|
|
268
330
|
![...commandCandidates].some((value) =>
|
|
@@ -273,7 +335,11 @@ export function assertManagedHookPolicy(
|
|
|
273
335
|
`Hook command is outside the managed allowlist: ${executable}`,
|
|
274
336
|
);
|
|
275
337
|
}
|
|
276
|
-
|
|
338
|
+
// The event context is payload, not workspace authority. Keep this
|
|
339
|
+
// selection identical to _execCommand so a forged context.cwd cannot make
|
|
340
|
+
// the managed-root check approve a different directory than the one the
|
|
341
|
+
// Broker will actually execute in.
|
|
342
|
+
const cwd = hook.cwd || configDir || workspaceRoot || process.cwd();
|
|
277
343
|
if (!isInsideManagedRoot(cwd, policy.workspaceRoots)) {
|
|
278
344
|
throw managedPolicyError(
|
|
279
345
|
`Hook working directory is outside managed workspace roots: ${cwd}`,
|
|
@@ -315,7 +381,11 @@ export function fileChangedHookMatches(hook, context = {}) {
|
|
|
315
381
|
hook?.globs ?? hook?.paths ?? hook?.glob ?? hook?.if ?? null;
|
|
316
382
|
if (configured == null) return true;
|
|
317
383
|
const patterns = (Array.isArray(configured) ? configured : [configured])
|
|
318
|
-
.map((value) =>
|
|
384
|
+
.map((value) =>
|
|
385
|
+
String(value || "")
|
|
386
|
+
.trim()
|
|
387
|
+
.replace(/\\/g, "/"),
|
|
388
|
+
)
|
|
319
389
|
.filter(Boolean);
|
|
320
390
|
if (patterns.length === 0) return true;
|
|
321
391
|
|
|
@@ -392,6 +462,17 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
392
462
|
constructor(configDir, options = {}) {
|
|
393
463
|
super();
|
|
394
464
|
this.configDir = configDir;
|
|
465
|
+
// Both values are host constructor inputs. Hook definitions may select a
|
|
466
|
+
// cwd inside this root, but can never replace the writable root used to
|
|
467
|
+
// issue a Linux one-shot execution contract.
|
|
468
|
+
const configuredWorkspaceRoot = options.workspaceRoot || configDir || null;
|
|
469
|
+
this.workspaceBinding =
|
|
470
|
+
typeof configuredWorkspaceRoot === "string" &&
|
|
471
|
+
path.isAbsolute(configuredWorkspaceRoot)
|
|
472
|
+
? registerHostHooksV2Workspace(configuredWorkspaceRoot)
|
|
473
|
+
: null;
|
|
474
|
+
this.workspaceRoot =
|
|
475
|
+
this.workspaceBinding?.workspaceRoot || configuredWorkspaceRoot;
|
|
395
476
|
this.durableStore = options.durableStore || null;
|
|
396
477
|
this.durableOwner =
|
|
397
478
|
options.durableOwner ||
|
|
@@ -457,14 +538,18 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
457
538
|
const config = JSON.parse(content);
|
|
458
539
|
this.hooks.clear();
|
|
459
540
|
|
|
460
|
-
const hookDefs = Array.isArray(config) ? config :
|
|
541
|
+
const hookDefs = Array.isArray(config) ? config : config.hooks || [];
|
|
461
542
|
for (const def of hookDefs) {
|
|
462
543
|
if (!VALID_HOOK_EVENTS.has(def.event)) {
|
|
463
|
-
process.emitWarning(
|
|
544
|
+
process.emitWarning(
|
|
545
|
+
`[hooks-v2] Unknown event type: ${def.event}, skipping`,
|
|
546
|
+
);
|
|
464
547
|
continue;
|
|
465
548
|
}
|
|
466
549
|
if (!VALID_EXECUTOR_TYPES.has(def.type)) {
|
|
467
|
-
process.emitWarning(
|
|
550
|
+
process.emitWarning(
|
|
551
|
+
`[hooks-v2] Unknown executor type: ${def.type} for ${def.event}, skipping`,
|
|
552
|
+
);
|
|
468
553
|
continue;
|
|
469
554
|
}
|
|
470
555
|
const id = def.id || crypto.randomUUID();
|
|
@@ -472,7 +557,10 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
472
557
|
this.hooks.get(def.event).push({ id, ...def });
|
|
473
558
|
}
|
|
474
559
|
this._loaded = true;
|
|
475
|
-
this.emit("loaded", {
|
|
560
|
+
this.emit("loaded", {
|
|
561
|
+
count: hookDefs.length,
|
|
562
|
+
events: Array.from(this.hooks.keys()),
|
|
563
|
+
});
|
|
476
564
|
} catch (e) {
|
|
477
565
|
if (e.code !== "ENOENT") {
|
|
478
566
|
this.emit("load:error", e);
|
|
@@ -484,8 +572,10 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
484
572
|
* Register a hook programmatically
|
|
485
573
|
*/
|
|
486
574
|
registerHook(def) {
|
|
487
|
-
if (!VALID_HOOK_EVENTS.has(def.event))
|
|
488
|
-
|
|
575
|
+
if (!VALID_HOOK_EVENTS.has(def.event))
|
|
576
|
+
throw new Error(`Invalid event: ${def.event}`);
|
|
577
|
+
if (!VALID_EXECUTOR_TYPES.has(def.type))
|
|
578
|
+
throw new Error(`Invalid executor type: ${def.type}`);
|
|
489
579
|
const contract = HOOK_EVENT_CONTRACTS[def.event];
|
|
490
580
|
if (!contract.allowedExecutors.includes(def.type)) {
|
|
491
581
|
throw new Error(
|
|
@@ -501,7 +591,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
501
591
|
|
|
502
592
|
unregisterHook(id) {
|
|
503
593
|
for (const [event, hooks] of this.hooks.entries()) {
|
|
504
|
-
const idx = hooks.findIndex(h => h.id === id);
|
|
594
|
+
const idx = hooks.findIndex((h) => h.id === id);
|
|
505
595
|
if (idx >= 0) {
|
|
506
596
|
hooks.splice(idx, 1);
|
|
507
597
|
return true;
|
|
@@ -534,22 +624,34 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
534
624
|
(max, hook) => Math.max(max, Number(hook?.timeoutMs) || 30000),
|
|
535
625
|
0,
|
|
536
626
|
);
|
|
627
|
+
const durableWorkspaceBinding =
|
|
628
|
+
this.workspaceBinding || currentHostHooksV2WorkspaceBinding();
|
|
629
|
+
const durableWorkspaceBindingRequired = hooksRequireWorkspaceBinding(
|
|
630
|
+
hooks,
|
|
631
|
+
this.managedPolicy,
|
|
632
|
+
);
|
|
537
633
|
const durableRecord =
|
|
538
634
|
this.durableStore && options.skipDurable !== true
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
635
|
+
? this.durableStore.enqueueInbox(
|
|
636
|
+
{
|
|
637
|
+
runtime_type: "hooks.v2",
|
|
638
|
+
requiresHandler: true,
|
|
639
|
+
event: eventName,
|
|
640
|
+
context,
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
id: context.event_id || context.eventId || null,
|
|
644
|
+
metadata: {
|
|
645
|
+
hooksV2WorkspaceBindingId:
|
|
646
|
+
durableWorkspaceBinding?.bindingId || null,
|
|
647
|
+
hooksV2WorkspaceBindingRequired:
|
|
648
|
+
durableWorkspaceBindingRequired,
|
|
649
|
+
},
|
|
650
|
+
claimOwner: this.durableOwner,
|
|
651
|
+
leaseMs: longestHookTimeout + this.durableRecoveryBufferMs,
|
|
652
|
+
},
|
|
653
|
+
)
|
|
654
|
+
: null;
|
|
553
655
|
if (durableRecord?.duplicate) {
|
|
554
656
|
if (durableRecord.status === "done" && durableRecord.result) {
|
|
555
657
|
return { ...durableRecord.result, duplicate: true };
|
|
@@ -577,7 +679,13 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
577
679
|
const runOne = async (hook) => {
|
|
578
680
|
const execId = crypto.randomUUID();
|
|
579
681
|
const start = Date.now();
|
|
580
|
-
const record = {
|
|
682
|
+
const record = {
|
|
683
|
+
execId,
|
|
684
|
+
hookId: hook.id,
|
|
685
|
+
event: eventName,
|
|
686
|
+
type: hook.type,
|
|
687
|
+
startedAt: new Date(),
|
|
688
|
+
};
|
|
581
689
|
|
|
582
690
|
try {
|
|
583
691
|
assertManagedHookPolicy(
|
|
@@ -585,6 +693,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
585
693
|
context,
|
|
586
694
|
this.managedPolicy,
|
|
587
695
|
this.configDir,
|
|
696
|
+
this.workspaceRoot || currentHostHooksV2WorkspaceRoot(),
|
|
588
697
|
);
|
|
589
698
|
let result;
|
|
590
699
|
switch (hook.type) {
|
|
@@ -629,9 +738,10 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
629
738
|
this.executionLog.push(record);
|
|
630
739
|
return record;
|
|
631
740
|
};
|
|
632
|
-
const results =
|
|
633
|
-
|
|
634
|
-
|
|
741
|
+
const results =
|
|
742
|
+
options.parallel === false
|
|
743
|
+
? []
|
|
744
|
+
: await Promise.all(uniqueHooks.map(runOne));
|
|
635
745
|
if (options.parallel === false) {
|
|
636
746
|
for (const hook of uniqueHooks) results.push(await runOne(hook));
|
|
637
747
|
}
|
|
@@ -643,8 +753,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
643
753
|
const blocked = decision === "block";
|
|
644
754
|
const blockingResult = blocking[0]?.result || null;
|
|
645
755
|
const outcome = {
|
|
646
|
-
success:
|
|
647
|
-
!blocked && results.every((record) => record.status !== "error"),
|
|
756
|
+
success: !blocked && results.every((record) => record.status !== "error"),
|
|
648
757
|
results,
|
|
649
758
|
blocked,
|
|
650
759
|
requiresApproval: decision === "ask",
|
|
@@ -689,24 +798,74 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
689
798
|
throw new Error("command hook requires a command");
|
|
690
799
|
}
|
|
691
800
|
const budget = hookBudget(hook);
|
|
692
|
-
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
801
|
+
const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
|
|
802
|
+
const requiresContract = requiresExplicitHookShell(sandboxPolicy);
|
|
803
|
+
const trustedRootSource =
|
|
804
|
+
this.workspaceRoot || currentHostHooksV2WorkspaceRoot();
|
|
805
|
+
const trustedRoot = requiresContract
|
|
806
|
+
? requireTrustedHookRoot(
|
|
807
|
+
trustedRootSource,
|
|
808
|
+
"Hooks v2 trusted workspace root",
|
|
809
|
+
)
|
|
810
|
+
: null;
|
|
811
|
+
const commandCwd =
|
|
812
|
+
hook.cwd || this.configDir || trustedRoot || process.cwd();
|
|
813
|
+
if (requiresContract) {
|
|
814
|
+
requireTrustedHookRoot(commandCwd, "Hooks v2 hook working directory");
|
|
815
|
+
if (!isPathInside(trustedRoot, commandCwd)) {
|
|
816
|
+
throw sandboxBoundaryError(
|
|
817
|
+
"Hooks v2 hook working directory escapes the trusted workspace root",
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
const invocation =
|
|
822
|
+
requiresContract && hook.shell === true
|
|
823
|
+
? buildExplicitHookShellInvocation(hook.command, {
|
|
824
|
+
args: hook.args || [],
|
|
825
|
+
})
|
|
826
|
+
: {
|
|
827
|
+
file: hook.command,
|
|
828
|
+
argv: hook.args || [],
|
|
829
|
+
};
|
|
830
|
+
const commandOptions = {
|
|
831
|
+
cwd: commandCwd,
|
|
832
|
+
env: buildHookEnvironment(hook, this.managedPolicy),
|
|
833
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
834
|
+
timeout: budget.timeoutMs,
|
|
835
|
+
shell: requiresContract ? false : hook.shell === true,
|
|
836
|
+
origin: "hook",
|
|
837
|
+
scope: "hook",
|
|
838
|
+
policy: "allow",
|
|
839
|
+
hookName: hook.id,
|
|
840
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
841
|
+
};
|
|
842
|
+
const sandboxExecutionContract = requiresContract
|
|
843
|
+
? issueTrustedHookSandboxContract({
|
|
844
|
+
issuer:
|
|
845
|
+
this.executionBroker.issueLinuxWorkspaceSandboxExecutionContract,
|
|
846
|
+
receiver: this.executionBroker,
|
|
847
|
+
file: invocation.file,
|
|
848
|
+
args: invocation.argv,
|
|
849
|
+
options: commandOptions,
|
|
850
|
+
trustedRoot,
|
|
851
|
+
label: "trusted Hooks v2 sandbox contract issuance failed",
|
|
852
|
+
})
|
|
853
|
+
: null;
|
|
854
|
+
if (
|
|
855
|
+
process.platform === "linux" &&
|
|
856
|
+
requiresContract &&
|
|
857
|
+
!sandboxExecutionContract
|
|
858
|
+
) {
|
|
859
|
+
throw sandboxBoundaryError(
|
|
860
|
+
"trusted Linux Hooks v2 sandbox contract could not be issued",
|
|
861
|
+
);
|
|
862
|
+
}
|
|
696
863
|
const child = await this.executionBroker.spawn(
|
|
697
|
-
|
|
698
|
-
|
|
864
|
+
invocation.file,
|
|
865
|
+
invocation.argv,
|
|
699
866
|
{
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
703
|
-
timeout: budget.timeoutMs,
|
|
704
|
-
shell: hook.shell === true,
|
|
705
|
-
origin: "hook",
|
|
706
|
-
scope: "hook",
|
|
707
|
-
policy: "allow",
|
|
708
|
-
hookName: hook.id,
|
|
709
|
-
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
867
|
+
...commandOptions,
|
|
868
|
+
...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
|
|
710
869
|
},
|
|
711
870
|
);
|
|
712
871
|
const payload = JSON.stringify({
|
|
@@ -716,14 +875,19 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
716
875
|
});
|
|
717
876
|
child.stdin?.end(payload);
|
|
718
877
|
return new Promise((resolve, reject) => {
|
|
719
|
-
let stdout = "",
|
|
720
|
-
|
|
721
|
-
child.
|
|
878
|
+
let stdout = "",
|
|
879
|
+
stderr = "";
|
|
880
|
+
child.stdout?.on("data", (d) => (stdout += d));
|
|
881
|
+
child.stderr?.on("data", (d) => (stderr += d));
|
|
722
882
|
child.on("error", reject);
|
|
723
883
|
child.on("exit", (code) => {
|
|
724
884
|
if (code === 0) {
|
|
725
885
|
let parsed = {};
|
|
726
|
-
try {
|
|
886
|
+
try {
|
|
887
|
+
parsed = JSON.parse(stdout);
|
|
888
|
+
} catch {
|
|
889
|
+
parsed = { raw: stdout };
|
|
890
|
+
}
|
|
727
891
|
resolve({ ...parsed, exitCode: code, stderr });
|
|
728
892
|
} else {
|
|
729
893
|
reject(new Error(`Hook command failed with exit ${code}: ${stderr}`));
|
|
@@ -763,7 +927,10 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
763
927
|
const res = await this.fetchImpl(target, {
|
|
764
928
|
method,
|
|
765
929
|
headers,
|
|
766
|
-
body:
|
|
930
|
+
body:
|
|
931
|
+
method !== "GET"
|
|
932
|
+
? JSON.stringify({ event: hook.event, context })
|
|
933
|
+
: undefined,
|
|
767
934
|
signal: controller.signal,
|
|
768
935
|
});
|
|
769
936
|
clearTimeout(timer);
|
|
@@ -782,10 +949,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
782
949
|
throw new Error("prompt hook executor is not configured");
|
|
783
950
|
}
|
|
784
951
|
const budget = hookBudget(hook);
|
|
785
|
-
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
786
|
-
hook,
|
|
787
|
-
this.managedPolicy,
|
|
788
|
-
);
|
|
952
|
+
const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
|
|
789
953
|
return executeWithHookTimeout("prompt", budget, (signal) =>
|
|
790
954
|
executor({
|
|
791
955
|
hook,
|
|
@@ -805,10 +969,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
805
969
|
throw new Error("agent hook executor is not configured");
|
|
806
970
|
}
|
|
807
971
|
const budget = hookBudget(hook);
|
|
808
|
-
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
809
|
-
hook,
|
|
810
|
-
this.managedPolicy,
|
|
811
|
-
);
|
|
972
|
+
const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
|
|
812
973
|
return executeWithHookTimeout("agent", budget, (signal) =>
|
|
813
974
|
executor({
|
|
814
975
|
hook,
|
|
@@ -858,10 +1019,7 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
858
1019
|
}
|
|
859
1020
|
}
|
|
860
1021
|
const budget = hookBudget(hook);
|
|
861
|
-
const sandboxPolicy = resolveHookSandboxPolicy(
|
|
862
|
-
hook,
|
|
863
|
-
this.managedPolicy,
|
|
864
|
-
);
|
|
1022
|
+
const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
|
|
865
1023
|
return executeWithHookTimeout("mcp_tool", budget, (signal) =>
|
|
866
1024
|
executor({
|
|
867
1025
|
server: hook.server,
|
|
@@ -889,7 +1047,12 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
889
1047
|
getHookRegistry() {
|
|
890
1048
|
const registry = {};
|
|
891
1049
|
for (const [event, hooks] of this.hooks.entries()) {
|
|
892
|
-
registry[event] = hooks.map(h => ({
|
|
1050
|
+
registry[event] = hooks.map((h) => ({
|
|
1051
|
+
id: h.id,
|
|
1052
|
+
type: h.type,
|
|
1053
|
+
description: h.description,
|
|
1054
|
+
blocking: h.blocking,
|
|
1055
|
+
}));
|
|
893
1056
|
}
|
|
894
1057
|
return registry;
|
|
895
1058
|
}
|
|
@@ -912,12 +1075,48 @@ const hooksRuntime = new HooksV2Runtime(undefined, {
|
|
|
912
1075
|
? new EventRuntimeStore()
|
|
913
1076
|
: null),
|
|
914
1077
|
});
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1078
|
+
broker._setHooksEventSink(hooksRuntime);
|
|
1079
|
+
|
|
1080
|
+
export async function executeRecoveredHooksV2Event(
|
|
1081
|
+
runtime,
|
|
1082
|
+
event,
|
|
1083
|
+
record = {},
|
|
1084
|
+
) {
|
|
1085
|
+
const bindingId = record?.metadata?.hooksV2WorkspaceBindingId || null;
|
|
1086
|
+
const bindingRequired =
|
|
1087
|
+
record?.metadata?.hooksV2WorkspaceBindingRequired === true ||
|
|
1088
|
+
hooksRequireWorkspaceBinding(
|
|
1089
|
+
runtime?.hooks?.get?.(event?.event) || [],
|
|
1090
|
+
runtime?.managedPolicy || {},
|
|
1091
|
+
);
|
|
1092
|
+
if (!bindingId) {
|
|
1093
|
+
if (bindingRequired) {
|
|
1094
|
+
throw sandboxBoundaryError(
|
|
1095
|
+
"durable Hooks v2 recovery requires a trusted host workspace binding",
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
return runtime.executeHooks(event.event, event.context || {}, {
|
|
1099
|
+
skipDurable: true,
|
|
1100
|
+
recovered: true,
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const binding = resolveRegisteredHostHooksV2Workspace(bindingId);
|
|
1105
|
+
if (!binding) {
|
|
1106
|
+
throw sandboxBoundaryError(
|
|
1107
|
+
"durable Hooks v2 workspace binding is not registered by this host",
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
return runWithHostHooksV2Workspace(binding.workspaceRoot, () =>
|
|
1111
|
+
runtime.executeHooks(event.event, event.context || {}, {
|
|
918
1112
|
skipDurable: true,
|
|
919
1113
|
recovered: true,
|
|
920
1114
|
}),
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
defaultEventRuntimeHost?.registerHandler(
|
|
1119
|
+
(event, record) => executeRecoveredHooksV2Event(hooksRuntime, event, record),
|
|
921
1120
|
{ queue: "inbox", type: "hooks.v2" },
|
|
922
1121
|
);
|
|
923
1122
|
export default hooksRuntime;
|