chainlesschain 0.162.177 → 0.162.178
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-DT-VPWuN.js → AIOps-DRftcSue.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DyOreOVN.js → ActionButton-BFvUaMKR.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DslNsKux.js → Analytics-C0-Rru4P.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-bx-BCljj.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-DoaAtEcY.js → Artifacts-DAJ8B3Un.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DPG3WdJ9.js → Audit-hOk4L1lr.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-C_JO6R5G.js → BackgroundAgents-3pbDpM9z.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cv3BooyX.js → Backup-BtziGDn9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D2uQXWu-.js → BaseInput-kmshphJ3.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B4Vczyf3.js → Chat-d7tGSosA.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-p-_PBpX_.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-qTgk4VeP.js → Checkbox-C4Eh4Tz5.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DlLWcIzj.js → Codegen-r7gmhZyA.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DNO73qp7.js → Col-U7mDaGlL.js} +1 -1
- package/src/assets/web-panel/assets/{Community-vRDNpc4j.js → Community-Bpu8aH1T.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CEWtIXni.js → Compact-CHb2XBJe.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-KgYC9Fxi.js → Compliance-Cn_r4dey.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-zj5wvkpT.js → Cowork-CdMWfDcz.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BLDoCozU.js → Cron-BtnREHWy.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BYnff4VY.js → Crosschain-BKI9TSzr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C75VFsVm.js → DID-pkNubzzJ.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-1rrz1snN.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-B5dbO4Kx.js → Dropdown-DLyFVxDc.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BDipZtHJ.js → EmailListRenderer-CtUWfYVq.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DmIzt8jj.js → FamilyGuardDashboard-B8eX2Qe4.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D9QOS-uW.js → Federation-D8lsDGus.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B47HRwAm.js → FormItemContext-CRYt_aIw.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-3R4mXmgV.js → GenericCardRenderer-ClKzY8_N.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DrNXZf1C.js → Git-BXj5Dney.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BGd7JR98.js → Governance-Cm-I8RMz.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-D-2he1ed.js → Inference-CPvbhvgt.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C0sHIbK5.js → KnowledgeGraph-sYNDZaoi.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DiBQO-jL.js → Logs-BZY_3CRZ.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DL_5eV2D.js → MarkdownRenderer-up0BW6pv.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-VR59OdrC.js → Marketplace-C5MEJ2Qe.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DrPzwSd3.js → McpTools-ihdrn43I.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-CBgKALwQ.js → Memory-Br8bPMlh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-pQ9Tn-Mn.js → MobileBridge-BNntgrYW.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-mASB6jyj.js → MobileProjects-BdV915mw.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DTMgE7HC.js → Mtc-A3wDmlqL.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-CwTnCtiL.js → MtcAudit-CF-mBLWM.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-ngm6WU8f.js → Multisig-Iy2k_MSo.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-4YO4Qww9.js → NLProgramming-kk0W7HUb.js} +1 -1
- package/src/assets/web-panel/assets/Notes-B5u5t_4S.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-r2H8yPKb.js → NotificationSettings-BN0POf6_.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CHkSUrXB.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DrO7jRWS.js → Organization-DwWQESuN.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cnwu4i4t.js → Overflow-DG6klrcC.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-zi-cDwA_.js → P2P-BwJcKkgZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DBEryDv7.js → PdhVaultBrowser-BwOHG0in.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-lqXK2C3x.js → Permissions-CGMXe4TX.js} +4 -4
- package/src/assets/web-panel/assets/PersonalDataHub-ziYqg7-A.js +8 -0
- package/src/assets/web-panel/assets/{Pipeline-Kep5KAGW.js → Pipeline-BzJfeoGt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CHdvOAh1.js → Privacy-DLh3Bblx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BhKfdwe9.js → ProjectInit-USVWW36c.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Yavk9K8A.js → ProjectSettings-CiiOn62h.js} +2 -2
- package/src/assets/web-panel/assets/Projects-6V-PNmcA.js +1 -0
- package/src/assets/web-panel/assets/{Providers-Bfym6SQn.js → Providers-CBPWWzpu.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CLSQcrlR.js → QrScannerModal-QVwoRUq3.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-VPa2WKQN.js → QuickAsk-CXnR-2Vn.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CGXR8jVU.js → Recommend-ClaNzjmF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C_20YfMB.js → RemoteSession-C3rGw8vJ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-awZh68UV.js → Reputation-Ci-OWAoP.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Ctb4oiYN.js → Row-DRhAwXOS.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D3sdjvUV.js → RssFeed-BQLJQ2_y.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C-zfA4kT.js → Search-QQUpkfFd.js} +1 -1
- package/src/assets/web-panel/assets/{Security-D9XlmHA3.js → Security-DdXKzuKT.js} +4 -4
- package/src/assets/web-panel/assets/{Services-C3UKnr41.js → Services-x2Zh62Qd.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BQxagZfF.js → Skeleton-GdY4KwRz.js} +1 -1
- package/src/assets/web-panel/assets/Skills-Bv4tY1Fd.js +1 -0
- package/src/assets/web-panel/assets/{Sla-DveENvek.js → Sla-C3QnM-11.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BFjXLNgF.js → SpeechSettings-Bl3ytvmI.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BpHgbaP9.js → SyncSettings-Wp9IwTsP.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CF3rIrDe.js +1 -0
- package/src/assets/web-panel/assets/{Templates-DEiaoyve.js → Templates-CGfvVVM9.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-ITg774nY.js → Tenant-CVXmwQ3U.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D3ZBcvnb.js → Terminal-bvwrt03E.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BsLU6JjU.js → TimelineRenderer-D0g74KhH.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Cb5Pquc9.js → Tokens-BH4IwzlT.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dwfy-m9N.js → Trigger-DJOpM533.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CnlSRGG0.js → Trust-B43EPRLr.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Y4TlvKVo.js → UkeySign-BmBFG-em.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BpKLtTTO.js → VideoEditing-n9oJwB8k.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-LLBzIq8x.js → Wallet-D5QeivHp.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BeSRiusP.js → WebAuthn-DcNy7igO.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-BK_l1tXO.js → WorkflowEditor-BVjc7-5-.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DYd-X7Wg.js → chat-Dy5Tfj3m.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C9uip71j.js → colors-C4c2CNZU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-JBrfjUP6.js → compact-item-DPa3O5vN.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D03fbuiq.js → createContext-TLcfNA6_.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BAwdDA_5.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DLQOR6l-.js → hasIn-D41LVFkp.js} +1 -1
- package/src/assets/web-panel/assets/{index-rIxxfdTN.js → index-0oevYjfT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CChaISMb.js → index-388pLGJ1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfOs_bmg.js → index-B8nLBZbv.js} +3 -3
- package/src/assets/web-panel/assets/{index-D-1SqEpQ.js → index-BPTGAjee.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYv-LWdy.js → index-BPtrOBmW.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cpn19c9k.js → index-BQiIxHBy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpYKLrUT.js → index-BSM1cHVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CS63r8h3.js → index-BYPr9fkz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q7mmL6w4.js → index-BsQ7Ev6i.js} +1 -1
- package/src/assets/web-panel/assets/{index-SO6lgMg0.js → index-Btk9qLL2.js} +1 -1
- package/src/assets/web-panel/assets/{index-iahNhZwm.js → index-BvmziZSG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnQgRjsm.js → index-BvopLC_T.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ba-Ps_AJ.js → index-C7xhTVyP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuNFCZCx.js → index-CNk_ZooP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CL0ixCxk.js → index-CQrEHoOG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CChQBM1d.js → index-CSxex23J.js} +1 -1
- package/src/assets/web-panel/assets/{index-5YN7F5bO.js → index-CVjgm992.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwoDpKzW.js → index-CWK4zOPe.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcBZwlnG.js → index-CX0VsoP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B46YcgsV.js → index-CXl0YPNG.js} +1 -1
- package/src/assets/web-panel/assets/{index-l08afIbV.js → index-Cip7LWml.js} +1 -1
- package/src/assets/web-panel/assets/{index-6GuLRpBQ.js → index-Cq_hlWNt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYLZY4uh.js → index-CzZ49YZL.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0X76LjX.js → index-D2Nkivlm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdH9l8wl.js → index-DBUgRs4D.js} +1 -1
- package/src/assets/web-panel/assets/index-DEjVkdzq.js +1 -0
- package/src/assets/web-panel/assets/{index-D4UY5Z60.js → index-DNsBj2Ob.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ce0Bf1YF.js → index-Di4X8cfI.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByHO3SqZ.js → index-DljFsVGI.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2zmOsyD.js → index-Korc3QIe.js} +1 -1
- package/src/assets/web-panel/assets/index-LMOc5xrS.js +1 -0
- package/src/assets/web-panel/assets/{index-BNCdRmWf.js → index-MKZDje0H.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8KvuDz0.js → index-OHAfRu_3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaokIHt3.js → index-WEJr8PL5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CILVyK3b.js → index-WinCp6du.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVZWiUE_.js → index-Yjr6cqSK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqWk1FLG.js → index-iQ6gtFih.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNMAAUVk.js → index-pt3s7yvV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ck17i0OD.js → index-tQ3igERQ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CG9z1c6w.js → initDefaultProps-BFZu87WZ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-B1Ky7Zff.js → motion-DJIo7qvt.js} +1 -1
- package/src/assets/web-panel/assets/{move-DME8X2P1.js → move-Cfr5qknL.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-cuJYSWB7.js → mtc-parser-Bgc-OadH.js} +1 -1
- package/src/assets/web-panel/assets/{omit-UI_EE0uZ.js → omit-X3WI-TNp.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BIoE_Z_V.js → pickAttrs-pJhU9IxK.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B48-9HKN.js → placementArrow-BNg_Vj3T.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D7x_GDgD.js → responsiveObserve-TeSEGQ5-.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DjzC5_7m.js → slide-D_t_P0bv.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C6BIymhh.js → statusUtils-DrrIMwAT.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B4dGrdD9.js → styleChecker-BjZCuFRm.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Bken4aNE.js → useFlexGapSupport-rTFdlqdQ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BMlqECqv.js → useFs-BidCpfLX.js} +1 -1
- package/src/assets/web-panel/assets/usePersonalDataHub-C5mHttA9.js +1 -0
- package/src/assets/web-panel/assets/{vnode-CKJQmxa0.js → vnode-BrbcRiHZ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CaZunuau.js → zoom-PISX7AkR.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-wechat.test.js +45 -0
- package/src/commands/background-session.js +5 -2
- package/src/commands/context.js +33 -1
- package/src/commands/hub.js +473 -39
- package/src/commands/init.js +212 -110
- package/src/commands/llm.js +22 -6
- package/src/commands/skill.js +11 -1
- package/src/data/changelog.json +76 -270
- package/src/gateways/ws/personal-data-hub-protocol.js +22 -2
- package/src/harness/golden-transcript.js +3 -0
- package/src/index.js +18 -7
- package/src/lib/approval-authority-store.js +891 -0
- package/src/lib/background-interaction-resolver.js +399 -54
- package/src/lib/background-session-transport.js +3 -1
- package/src/lib/context-breakdown.js +82 -3
- package/src/lib/event-runtime-host.js +225 -0
- package/src/lib/event-runtime-store.js +102 -21
- package/src/lib/event-runtime-worker.js +70 -2
- package/src/lib/hooks-v2-producers.js +33 -8
- package/src/lib/hooks-v2-runtime.js +360 -40
- package/src/lib/interaction-adapter.js +66 -0
- package/src/lib/operation-fingerprint.js +107 -2
- package/src/lib/pdh-dedicated-batch-collectors.js +124 -0
- package/src/lib/personal-data-hub-wiring.js +327 -52
- package/src/lib/process-execution-broker/credential-agent.js +954 -111
- package/src/lib/process-execution-broker/index.js +369 -85
- package/src/lib/process-execution-broker/platform-sandbox.js +320 -140
- package/src/lib/provider-http-error.js +94 -0
- package/src/lib/remote-approval-bridge.js +222 -26
- package/src/lib/side-effect-ledger-store.js +65 -14
- package/src/lib/skill-loader.js +215 -12
- package/src/lib/skill-process-broker.js +15 -1
- package/src/lib/sub-agent-context.js +42 -0
- package/src/lib/turn-binding-store.js +64 -15
- package/src/lib/turn-binding.js +85 -16
- package/src/repl/agent-repl.js +40 -6
- package/src/repl/remote-approval.js +13 -13
- package/src/repl/repl-turn-binding.js +46 -16
- package/src/runtime/agent-core.js +286 -35
- package/src/runtime/coding-agent-contract-shared.cjs +16 -0
- package/src/runtime/headless-runner.js +147 -34
- package/src/runtime/headless-stream.js +147 -7
- package/src/workers/background-agent-worker.js +70 -38
- package/src/assets/web-panel/assets/AppLayout-BNJJAYME.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DE6reP99.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-C4Gutni2.js +0 -3
- package/src/assets/web-panel/assets/Notes-DP1k45mF.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-CoM_Zw0J.js +0 -1
- package/src/assets/web-panel/assets/PersonalDataHub-b63T3HJM.js +0 -9
- package/src/assets/web-panel/assets/Projects-CN8E_5Mq.js +0 -1
- package/src/assets/web-panel/assets/Skills-q6eb6KPZ.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DvepRb8-.js +0 -1
- package/src/assets/web-panel/assets/devWarning-B8LQ8leS.js +0 -1
- package/src/assets/web-panel/assets/index-Bh8BPtqR.js +0 -1
- package/src/assets/web-panel/assets/index-CeVrHLzZ.js +0 -1
- package/src/assets/web-panel/assets/usePersonalDataHub-DLdrfmMa.js +0 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-level lifecycle owner for the durable Event Runtime.
|
|
3
|
+
*
|
|
4
|
+
* Producers only append records. This host owns the single non-overlapping
|
|
5
|
+
* drain loop, dispatches records to registered handlers, and exposes a
|
|
6
|
+
* stoppable lifecycle shared by short CLI commands and resident daemons.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { EventEmitter } from "node:events";
|
|
10
|
+
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
11
|
+
import { EventRuntimeWorker } from "./event-runtime-worker.js";
|
|
12
|
+
|
|
13
|
+
function routeType(event) {
|
|
14
|
+
return String(
|
|
15
|
+
event?.runtime_type ||
|
|
16
|
+
event?.runtimeType ||
|
|
17
|
+
event?.event ||
|
|
18
|
+
event?.type ||
|
|
19
|
+
"*",
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function routeOrigin(event) {
|
|
24
|
+
return String(event?.origin || "*");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function routeKey(queue, type = "*", origin = "*") {
|
|
28
|
+
return `${queue}:${String(type || "*")}:${String(origin || "*")}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class EventRuntimeHost extends EventEmitter {
|
|
32
|
+
constructor({
|
|
33
|
+
store = new EventRuntimeStore(),
|
|
34
|
+
intervalMs = 1000,
|
|
35
|
+
worker = null,
|
|
36
|
+
setTimeoutFn = setTimeout,
|
|
37
|
+
clearTimeoutFn = clearTimeout,
|
|
38
|
+
} = {}) {
|
|
39
|
+
super();
|
|
40
|
+
this.store = store;
|
|
41
|
+
this.intervalMs = Math.max(1, Number(intervalMs) || 1000);
|
|
42
|
+
this.setTimeoutFn = setTimeoutFn;
|
|
43
|
+
this.clearTimeoutFn = clearTimeoutFn;
|
|
44
|
+
this.handlers = new Map();
|
|
45
|
+
this.running = false;
|
|
46
|
+
this.timer = null;
|
|
47
|
+
this.inFlight = null;
|
|
48
|
+
this.lastStats = null;
|
|
49
|
+
this.lastError = null;
|
|
50
|
+
this.worker =
|
|
51
|
+
worker ||
|
|
52
|
+
new EventRuntimeWorker({
|
|
53
|
+
store,
|
|
54
|
+
onInbox: (event, record) =>
|
|
55
|
+
this._dispatch("inbox", event, record),
|
|
56
|
+
onOutbox: (event, record) =>
|
|
57
|
+
this._dispatch("outbox", event, record),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
registerHandler(
|
|
62
|
+
handler,
|
|
63
|
+
{ queue = "inbox", type = "*", origin = "*" } = {},
|
|
64
|
+
) {
|
|
65
|
+
if (typeof handler !== "function") {
|
|
66
|
+
throw new TypeError("Event Runtime handler must be a function");
|
|
67
|
+
}
|
|
68
|
+
if (queue !== "inbox" && queue !== "outbox") {
|
|
69
|
+
throw new Error(`unsupported event queue: ${queue}`);
|
|
70
|
+
}
|
|
71
|
+
const key = routeKey(queue, type, origin);
|
|
72
|
+
const handlers = this.handlers.get(key) || new Set();
|
|
73
|
+
handlers.add(handler);
|
|
74
|
+
this.handlers.set(key, handlers);
|
|
75
|
+
return () => {
|
|
76
|
+
handlers.delete(handler);
|
|
77
|
+
if (handlers.size === 0) this.handlers.delete(key);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async _dispatch(queue, event, record) {
|
|
82
|
+
const type = routeType(event);
|
|
83
|
+
const origin = routeOrigin(event);
|
|
84
|
+
const candidates = [
|
|
85
|
+
routeKey(queue, type, origin),
|
|
86
|
+
routeKey(queue, type, "*"),
|
|
87
|
+
routeKey(queue, "*", origin),
|
|
88
|
+
routeKey(queue, "*", "*"),
|
|
89
|
+
];
|
|
90
|
+
const handlers = [];
|
|
91
|
+
const seen = new Set();
|
|
92
|
+
for (const key of candidates) {
|
|
93
|
+
for (const handler of this.handlers.get(key) || []) {
|
|
94
|
+
if (seen.has(handler)) continue;
|
|
95
|
+
seen.add(handler);
|
|
96
|
+
handlers.push(handler);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (handlers.length === 0 && event?.requiresHandler === true) {
|
|
100
|
+
const error = new Error(
|
|
101
|
+
`No Event Runtime handler for ${queue}:${type}:${origin}`,
|
|
102
|
+
);
|
|
103
|
+
error.code = "CC_EVENT_RUNTIME_HANDLER_UNAVAILABLE";
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
const results = await Promise.all(
|
|
107
|
+
handlers.map((handler) => handler(event, record)),
|
|
108
|
+
);
|
|
109
|
+
const delivery = {
|
|
110
|
+
queue,
|
|
111
|
+
type,
|
|
112
|
+
origin,
|
|
113
|
+
handlerCount: handlers.length,
|
|
114
|
+
results,
|
|
115
|
+
};
|
|
116
|
+
this.emit("delivered", delivery, event, record);
|
|
117
|
+
this.emit(`${queue}:${type}`, event, record, delivery);
|
|
118
|
+
return delivery;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async runOnce() {
|
|
122
|
+
if (this.inFlight) return this.inFlight;
|
|
123
|
+
this.inFlight = Promise.resolve()
|
|
124
|
+
.then(() => this.worker.runOnce())
|
|
125
|
+
.then((stats) => {
|
|
126
|
+
this.lastStats = stats;
|
|
127
|
+
this.lastError = null;
|
|
128
|
+
this.emit("tick", stats);
|
|
129
|
+
return stats;
|
|
130
|
+
})
|
|
131
|
+
.catch((error) => {
|
|
132
|
+
this.lastError = error;
|
|
133
|
+
this.emit("runtime-error", error);
|
|
134
|
+
throw error;
|
|
135
|
+
})
|
|
136
|
+
.finally(() => {
|
|
137
|
+
this.inFlight = null;
|
|
138
|
+
});
|
|
139
|
+
return this.inFlight;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_schedule() {
|
|
143
|
+
if (!this.running || this.timer != null) return;
|
|
144
|
+
this.timer = this.setTimeoutFn(async () => {
|
|
145
|
+
this.timer = null;
|
|
146
|
+
try {
|
|
147
|
+
await this.runOnce();
|
|
148
|
+
} catch {
|
|
149
|
+
// The durable records remain pending/retriable. The host keeps running
|
|
150
|
+
// so a transient lock or filesystem failure does not kill the daemon.
|
|
151
|
+
} finally {
|
|
152
|
+
this._schedule();
|
|
153
|
+
}
|
|
154
|
+
}, this.intervalMs);
|
|
155
|
+
this.timer?.unref?.();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
start({ immediate = true } = {}) {
|
|
159
|
+
if (this.running) return false;
|
|
160
|
+
this.running = true;
|
|
161
|
+
if (immediate) {
|
|
162
|
+
void this.runOnce()
|
|
163
|
+
.catch(() => {})
|
|
164
|
+
.finally(() => this._schedule());
|
|
165
|
+
} else {
|
|
166
|
+
this._schedule();
|
|
167
|
+
}
|
|
168
|
+
this.emit("started");
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async stop({ drain = true } = {}) {
|
|
173
|
+
const wasRunning = this.running;
|
|
174
|
+
this.running = false;
|
|
175
|
+
if (this.timer != null) {
|
|
176
|
+
this.clearTimeoutFn(this.timer);
|
|
177
|
+
this.timer = null;
|
|
178
|
+
}
|
|
179
|
+
if (drain && this.inFlight) {
|
|
180
|
+
try {
|
|
181
|
+
await this.inFlight;
|
|
182
|
+
} catch {
|
|
183
|
+
// Error already exposed through runtime-error/lastError.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (wasRunning) this.emit("stopped");
|
|
187
|
+
return wasRunning;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
status() {
|
|
191
|
+
return {
|
|
192
|
+
running: this.running,
|
|
193
|
+
inFlight: this.inFlight != null,
|
|
194
|
+
handlerRoutes: this.handlers.size,
|
|
195
|
+
lastStats: this.lastStats,
|
|
196
|
+
lastError: this.lastError?.message || null,
|
|
197
|
+
health: this.store.getHealthSnapshot(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let defaultHost = null;
|
|
203
|
+
|
|
204
|
+
export function getDefaultEventRuntimeHost(options = {}) {
|
|
205
|
+
if (!defaultHost) defaultHost = new EventRuntimeHost(options);
|
|
206
|
+
return defaultHost;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function startDefaultEventRuntimeHost(options = {}) {
|
|
210
|
+
if (process.env.CC_EVENT_RUNTIME_DURABLE !== "1" && options.force !== true) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
const host = getDefaultEventRuntimeHost(options);
|
|
214
|
+
host.start({ immediate: options.immediate !== false });
|
|
215
|
+
return host;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function stopDefaultEventRuntimeHost(options) {
|
|
219
|
+
return defaultHost ? defaultHost.stop(options) : false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function _resetDefaultEventRuntimeHostForTests() {
|
|
223
|
+
defaultHost = null;
|
|
224
|
+
}
|
|
225
|
+
|
|
@@ -100,7 +100,17 @@ export class EventRuntimeStore {
|
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
enqueue(
|
|
103
|
+
enqueue(
|
|
104
|
+
queue,
|
|
105
|
+
event,
|
|
106
|
+
{
|
|
107
|
+
id = null,
|
|
108
|
+
metadata = null,
|
|
109
|
+
claimOwner = null,
|
|
110
|
+
leaseMs = this.leaseMs,
|
|
111
|
+
availableAt = null,
|
|
112
|
+
} = {},
|
|
113
|
+
) {
|
|
104
114
|
const key = eventId(event, id);
|
|
105
115
|
return this._mutate(queue, (records) => {
|
|
106
116
|
const existing = records.find((record) => record.id === key);
|
|
@@ -118,15 +128,27 @@ export class EventRuntimeStore {
|
|
|
118
128
|
error.code = "CC_EVENT_RUNTIME_BACKPRESSURE";
|
|
119
129
|
throw error;
|
|
120
130
|
}
|
|
131
|
+
const createdAt = this._now();
|
|
132
|
+
const claimed = claimOwner != null && String(claimOwner);
|
|
121
133
|
const record = {
|
|
122
134
|
id: key,
|
|
123
135
|
event: clone(event || {}),
|
|
124
136
|
metadata: clone(metadata),
|
|
125
|
-
status: "pending",
|
|
126
|
-
attempts: 0,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
status: claimed ? "processing" : "pending",
|
|
138
|
+
attempts: claimed ? 1 : 0,
|
|
139
|
+
fence: claimed ? 1 : 0,
|
|
140
|
+
createdAt,
|
|
141
|
+
nextAttemptAt:
|
|
142
|
+
availableAt == null ? createdAt : Math.max(createdAt, Number(availableAt)),
|
|
143
|
+
lease: claimed
|
|
144
|
+
? {
|
|
145
|
+
owner: String(claimOwner),
|
|
146
|
+
fence: 1,
|
|
147
|
+
claimedAt: createdAt,
|
|
148
|
+
expiresAt:
|
|
149
|
+
createdAt + Math.max(1, Number(leaseMs) || this.leaseMs),
|
|
150
|
+
}
|
|
151
|
+
: null,
|
|
130
152
|
};
|
|
131
153
|
records.push(record);
|
|
132
154
|
return clone(record);
|
|
@@ -160,7 +182,13 @@ export class EventRuntimeStore {
|
|
|
160
182
|
if (Number(record.nextAttemptAt || 0) > t) continue;
|
|
161
183
|
record.status = "processing";
|
|
162
184
|
record.attempts = Number(record.attempts || 0) + 1;
|
|
163
|
-
record.
|
|
185
|
+
record.fence = Number(record.fence || 0) + 1;
|
|
186
|
+
record.lease = {
|
|
187
|
+
owner: this.owner,
|
|
188
|
+
fence: record.fence,
|
|
189
|
+
claimedAt: t,
|
|
190
|
+
expiresAt: t + ttl,
|
|
191
|
+
};
|
|
164
192
|
claimed.push(clone(record));
|
|
165
193
|
}
|
|
166
194
|
return claimed;
|
|
@@ -175,16 +203,68 @@ export class EventRuntimeStore {
|
|
|
175
203
|
return this.claim("outbox", options);
|
|
176
204
|
}
|
|
177
205
|
|
|
178
|
-
|
|
206
|
+
_leaseMatches(record, { owner = null, fence = null, now = this._now() } = {}) {
|
|
207
|
+
const expectedOwner = owner == null ? null : String(owner);
|
|
208
|
+
const expectedFence =
|
|
209
|
+
fence == null || !Number.isFinite(Number(fence)) ? null : Number(fence);
|
|
210
|
+
if (expectedOwner == null && expectedFence == null) return true;
|
|
211
|
+
if (record.status !== "processing" || !record.lease) return false;
|
|
212
|
+
if (expectedOwner != null && record.lease.owner !== expectedOwner) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
if (
|
|
216
|
+
expectedFence != null &&
|
|
217
|
+
Number(record.lease.fence) !== expectedFence
|
|
218
|
+
) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
// A holder that let its lease expire must renew before it is allowed to
|
|
222
|
+
// commit. This closes the gap where a slow worker could settle just before
|
|
223
|
+
// a recovery worker claims the same record.
|
|
224
|
+
return Number(record.lease.expiresAt) > Number(now);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
renew(
|
|
228
|
+
queue,
|
|
229
|
+
id,
|
|
230
|
+
{
|
|
231
|
+
owner = this.owner,
|
|
232
|
+
fence = null,
|
|
233
|
+
now = this._now(),
|
|
234
|
+
leaseMs = this.leaseMs,
|
|
235
|
+
} = {},
|
|
236
|
+
) {
|
|
237
|
+
const t = Number(now);
|
|
238
|
+
const ttl = Math.max(1, Number(leaseMs) || this.leaseMs);
|
|
239
|
+
return this._mutate(queue, (records) => {
|
|
240
|
+
const record = records.find((item) => item.id === String(id));
|
|
241
|
+
if (!record || !this._leaseMatches(record, { owner, fence, now: t })) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
record.lease.expiresAt = t + ttl;
|
|
245
|
+
record.lease.renewedAt = t;
|
|
246
|
+
return clone(record);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
renewInbox(id, options) {
|
|
251
|
+
return this.renew("inbox", id, options);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
renewOutbox(id, options) {
|
|
255
|
+
return this.renew("outbox", id, options);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
acknowledge(
|
|
259
|
+
queue,
|
|
260
|
+
id,
|
|
261
|
+
result = null,
|
|
262
|
+
{ owner = null, fence = null, now = this._now() } = {},
|
|
263
|
+
) {
|
|
179
264
|
return this._mutate(queue, (records) => {
|
|
180
265
|
const record = records.find((item) => item.id === String(id));
|
|
181
266
|
if (!record) return null;
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
expectedOwner &&
|
|
185
|
-
(record.status !== "processing" ||
|
|
186
|
-
record.lease?.owner !== expectedOwner)
|
|
187
|
-
) {
|
|
267
|
+
if (!this._leaseMatches(record, { owner, fence, now })) {
|
|
188
268
|
return null;
|
|
189
269
|
}
|
|
190
270
|
record.status = "done";
|
|
@@ -207,17 +287,18 @@ export class EventRuntimeStore {
|
|
|
207
287
|
queue,
|
|
208
288
|
id,
|
|
209
289
|
error,
|
|
210
|
-
{
|
|
290
|
+
{
|
|
291
|
+
retryDelayMs = 1000,
|
|
292
|
+
maxAttempts = this.maxAttempts,
|
|
293
|
+
owner = null,
|
|
294
|
+
fence = null,
|
|
295
|
+
now = this._now(),
|
|
296
|
+
} = {},
|
|
211
297
|
) {
|
|
212
298
|
return this._mutate(queue, (records) => {
|
|
213
299
|
const record = records.find((item) => item.id === String(id));
|
|
214
300
|
if (!record) return null;
|
|
215
|
-
|
|
216
|
-
if (
|
|
217
|
-
expectedOwner &&
|
|
218
|
-
(record.status !== "processing" ||
|
|
219
|
-
record.lease?.owner !== expectedOwner)
|
|
220
|
-
) {
|
|
301
|
+
if (!this._leaseMatches(record, { owner, fence, now })) {
|
|
221
302
|
return null;
|
|
222
303
|
}
|
|
223
304
|
record.error = String(error || "event delivery failed").slice(0, 1000);
|
|
@@ -16,6 +16,9 @@ export class EventRuntimeWorker {
|
|
|
16
16
|
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
17
17
|
batchSize = 50,
|
|
18
18
|
retryDelayMs = 1000,
|
|
19
|
+
leaseRenewIntervalMs = null,
|
|
20
|
+
setIntervalFn = setInterval,
|
|
21
|
+
clearIntervalFn = clearInterval,
|
|
19
22
|
} = {}) {
|
|
20
23
|
if (!store) throw new Error("EventRuntimeWorker requires a store");
|
|
21
24
|
this.store = store;
|
|
@@ -25,6 +28,60 @@ export class EventRuntimeWorker {
|
|
|
25
28
|
this.sleep = sleep;
|
|
26
29
|
this.batchSize = Math.max(1, Number(batchSize) || 50);
|
|
27
30
|
this.retryDelayMs = Math.max(0, Number(retryDelayMs) || 0);
|
|
31
|
+
const inferredRenewMs = Math.max(
|
|
32
|
+
1,
|
|
33
|
+
Math.floor(Number(store.leaseMs || 120000) / 3),
|
|
34
|
+
);
|
|
35
|
+
this.leaseRenewIntervalMs =
|
|
36
|
+
leaseRenewIntervalMs == null
|
|
37
|
+
? inferredRenewMs
|
|
38
|
+
: Math.max(0, Number(leaseRenewIntervalMs) || 0);
|
|
39
|
+
this.setIntervalFn = setIntervalFn;
|
|
40
|
+
this.clearIntervalFn = clearIntervalFn;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_settlementOptions(record) {
|
|
44
|
+
if (!record?.lease?.owner) return {};
|
|
45
|
+
return {
|
|
46
|
+
owner: record.lease.owner,
|
|
47
|
+
...(record.lease.fence == null ? {} : { fence: record.lease.fence }),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_startLeaseRenewal(queue, record) {
|
|
52
|
+
const renew =
|
|
53
|
+
queue === "inbox" ? this.store.renewInbox : this.store.renewOutbox;
|
|
54
|
+
if (
|
|
55
|
+
typeof renew !== "function" ||
|
|
56
|
+
!record?.lease?.owner ||
|
|
57
|
+
this.leaseRenewIntervalMs <= 0
|
|
58
|
+
) {
|
|
59
|
+
return { lost: false, stop() {} };
|
|
60
|
+
}
|
|
61
|
+
const options = this._settlementOptions(record);
|
|
62
|
+
const state = { lost: false, timer: null };
|
|
63
|
+
const tick = () => {
|
|
64
|
+
if (state.lost) return;
|
|
65
|
+
try {
|
|
66
|
+
const renewed = renew.call(this.store, record.id, options);
|
|
67
|
+
if (renewed == null) state.lost = true;
|
|
68
|
+
} catch {
|
|
69
|
+
// Renewal is part of the correctness boundary. A lock/storage failure
|
|
70
|
+
// means this worker can no longer prove it owns the record.
|
|
71
|
+
state.lost = true;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
state.timer = this.setIntervalFn(tick, this.leaseRenewIntervalMs);
|
|
75
|
+
state.timer?.unref?.();
|
|
76
|
+
return {
|
|
77
|
+
get lost() {
|
|
78
|
+
return state.lost;
|
|
79
|
+
},
|
|
80
|
+
stop: () => {
|
|
81
|
+
if (state.timer != null) this.clearIntervalFn(state.timer);
|
|
82
|
+
state.timer = null;
|
|
83
|
+
},
|
|
84
|
+
};
|
|
28
85
|
}
|
|
29
86
|
|
|
30
87
|
async _drain(queue, handler, stats) {
|
|
@@ -33,9 +90,15 @@ export class EventRuntimeWorker {
|
|
|
33
90
|
? this.store.claimInbox({ limit: this.batchSize, now: this.now() })
|
|
34
91
|
: this.store.claimOutbox({ limit: this.batchSize, now: this.now() });
|
|
35
92
|
for (const record of claimed) {
|
|
93
|
+
const renewal = this._startLeaseRenewal(queue, record);
|
|
36
94
|
try {
|
|
37
95
|
const result = await handler(record.event, record);
|
|
38
|
-
|
|
96
|
+
renewal.stop();
|
|
97
|
+
if (renewal.lost) {
|
|
98
|
+
stats[`${queue}LeaseLost`] += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const options = this._settlementOptions(record);
|
|
39
102
|
const settled =
|
|
40
103
|
queue === "inbox"
|
|
41
104
|
? this.store.acknowledgeInbox(record.id, result, options)
|
|
@@ -43,9 +106,14 @@ export class EventRuntimeWorker {
|
|
|
43
106
|
if (settled === null && options.owner) stats[`${queue}LeaseLost`] += 1;
|
|
44
107
|
else stats[`${queue}Acked`] += 1;
|
|
45
108
|
} catch (error) {
|
|
109
|
+
renewal.stop();
|
|
110
|
+
if (renewal.lost) {
|
|
111
|
+
stats[`${queue}LeaseLost`] += 1;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
46
114
|
const options = {
|
|
47
115
|
retryDelayMs: this.retryDelayMs,
|
|
48
|
-
|
|
116
|
+
...this._settlementOptions(record),
|
|
49
117
|
};
|
|
50
118
|
const settled = this.store.fail(
|
|
51
119
|
queue,
|
|
@@ -3,13 +3,38 @@
|
|
|
3
3
|
* Hook failures never change the surrounding agent or interaction result.
|
|
4
4
|
*/
|
|
5
5
|
export function emitHooksV2Event(eventName, context = {}, options = {}) {
|
|
6
|
-
void
|
|
7
|
-
.then(({ default: runtime }) => {
|
|
8
|
-
if (!runtime || typeof runtime.executeHooks !== "function") return;
|
|
9
|
-
return runtime.executeHooks(eventName, context, options);
|
|
10
|
-
})
|
|
11
|
-
.catch(() => {
|
|
12
|
-
// Hooks are an optional extension; producer delivery is best-effort.
|
|
13
|
-
});
|
|
6
|
+
void executeHooksV2Event(eventName, context, options);
|
|
14
7
|
}
|
|
15
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Decision-capable producer bridge. Callers at a real gate (PreToolUse,
|
|
11
|
+
* Setup, prompt expansion) await this result; observer producers can keep
|
|
12
|
+
* using emitHooksV2Event().
|
|
13
|
+
*/
|
|
14
|
+
export async function executeHooksV2Event(
|
|
15
|
+
eventName,
|
|
16
|
+
context = {},
|
|
17
|
+
options = {},
|
|
18
|
+
) {
|
|
19
|
+
try {
|
|
20
|
+
const { default: runtime } = await import("./hooks-v2-runtime.js");
|
|
21
|
+
if (!runtime || typeof runtime.executeHooks !== "function") {
|
|
22
|
+
return {
|
|
23
|
+
success: options.failClosed !== true,
|
|
24
|
+
blocked: options.failClosed === true,
|
|
25
|
+
decision: options.failClosed === true ? "block" : "continue",
|
|
26
|
+
unavailable: true,
|
|
27
|
+
results: [],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return await runtime.executeHooks(eventName, context, options);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return {
|
|
33
|
+
success: options.failClosed !== true,
|
|
34
|
+
blocked: options.failClosed === true,
|
|
35
|
+
decision: options.failClosed === true ? "block" : "continue",
|
|
36
|
+
error: error?.message || String(error),
|
|
37
|
+
results: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|