chainlesschain 0.166.89 → 0.166.91
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 +91 -5
- package/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-C8AkN9R5.js → AIOps-DgV7xb8F.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BrAzSQor.js → ActionButton-CgANpkKu.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Cu56X8Oh.js → Analytics-DnvpX7RB.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BP1Riofl.js → AppLayout-C2bHccBM.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-CIW-nNAz.js → Artifacts-BIhijC9g.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CJtDabk-.js → Audit-CKRjWGdp.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DYIHeQ_P.js → BackgroundAgents-CblYtgBE.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B4CsFzj7.js → Backup-Cq35b78a.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-3eoJ5kfb.js → BaseInput-DcB7NoRz.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BBhX2L_E.js → Chat-tc3b-s7i.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-RN8cbv7w.js → ChatBubbleRenderer-fcc_Tvqu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-5UvmwHVk.js → Checkbox-BLD5bH5u.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BFy8zsBN.js → Codegen-BLOsoazN.js} +1 -1
- package/src/assets/web-panel/assets/{Col-4M6bKRRO.js → Col-Bdr7JwIx.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D6LC0j7_.js → Community-C84BsWE0.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dd48xMcv.js → Compact-Dzdwd04z.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Ba85ggmy.js → Compliance-CCG-R0EV.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-D1BXlkuK.js → Cowork-BYj72SK0.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Ca2Uy7Ia.js → Cron-B6iKAwOf.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C2bDRXZg.js → Crosschain-BJ-oDC6u.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DySZKAJf.js → DID-BnMckGLr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DDpYf-TT.js → Dashboard-Cyje-gCO.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DGjROfPv.js → Dropdown-BpNlenjK.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DxX9QYiB.js → EmailListRenderer-BhonO7Nv.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-TBCZyrSJ.js → EvolutionSettings-DVoNU-Id.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BeqwTXBa.js → FamilyGuardDashboard-tdn-KC67.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CiCpKJQ1.js → Federation--EEVrHhz.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CdTmbLkU.js → FormItemContext-Cy8zr0-4.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BwbkEY-5.js → GenericCardRenderer-BuUhpgFi.js} +1 -1
- package/src/assets/web-panel/assets/{Git-VnAga2vv.js → Git-Ctd3E5Pe.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-i-4Ebs-H.js → Governance-Ce7dV6aU.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CirjTgNw.js → Inference-CD1vExIH.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CunS7vhA.js → KnowledgeGraph-Dn64OdQ7.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DBuTF0c6.js → Logs-PmElVRrT.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-B-iE-tt_.js → MarkdownRenderer-BFiVKf5t.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BK6ZivTS.js → Marketplace-OW4jTXwx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CUnCRnd3.js → McpTools-BEq2Ib4x.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CBGGr8Gy.js → Memory-Can_P2oK.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-reB6iaWD.js → MobileBridge-DJ8R-dn3.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-o1YdVB7i.js → MobileProjects-B7kV9GOt.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-if5OE3GH.js → Mtc-BfxamolS.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BTZWpq0j.js → MtcAudit-DHtuv7av.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-8cvMAYFL.js → Multisig-DLkLpvxc.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BMvUXAWo.js → NLProgramming-u4XtJTIt.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BWWjColh.js → Notes-BwuuPJLS.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Ccr4lIhS.js → NotificationSettings-HEeu-E9v.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DhksGy6D.js → OrderTableRenderer-BtvN-Qwh.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DciXQfdY.js → Organization-Yh-czs3b.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-8DR7uMSx.js → Overflow-DmE8mYVM.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DE6euHYl.js → P2P-CWVck8WN.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-ByuWoauq.js → PdhVaultBrowser-DgFqekod.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DkjM87ac.js → Permissions-BtJBVOHV.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-2DLp0KTL.js → PersonalDataHub-6VBObXzd.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-Ci2Qlkfr.js → Pipeline-D222FmqY.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DlwDnDVA.js → Privacy-Bi9FMikp.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CmMifW39.js → ProjectInit-Bo52H47H.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DJVFIh-6.js → ProjectSettings-BPkesfOc.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-P2nWBS70.js → Projects-GynohSFX.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B2cxaGCU.js → Providers-DVdMg04n.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CpO77kcE.js → QrScannerModal-DqJCb595.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BDQl1hb0.js → QuickAsk-J7loQbXi.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DTD2f3IN.js → Recommend-BI5aURVc.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DGZAnwvs.js → RemoteSession-BN2sqGvz.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-B_R4vitb.js → Reputation-BGOND-Fi.js} +1 -1
- package/src/assets/web-panel/assets/{Row-4Jj6JyXN.js → Row-77dfwaUk.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D1t1MCZ-.js → RssFeed-FtBAxS3g.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CyOUlIn7.js → Search-BaYVLFb7.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BmknPT5Q.js → Security-LE3Vv6ab.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DkEK8mpa.js → Services-C5pP-Whz.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Bvo5bpuk.js → Skeleton-CLqKUVsF.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-AMmG8fim.js → Skills-BPjN0SX5.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Dl7-OKOV.js → Sla-14jD70kg.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DtiGKu0E.js → SpeechSettings-Dr9ij42W.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Ch7mp3ES.js → SyncSettings-BzLHP7B8.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Ck-sEgj-.js → Tasks-YqV9b0rV.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BlV22Il8.js → Templates-CxxAE4PK.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CaaAu0mX.js → Tenant-CRb3PcKJ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-lA9g3FtJ.js → Terminal-CTzPpBaP.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CG26IFC3.js → TimelineRenderer-DjFUj_hy.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-iaJUBLBm.js → Tokens-Bbb8tPvx.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DWQJtLK3.js → Trigger-CSeWGM0W.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CTjmUwqp.js → Trust-JgESMBo3.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CMnxufgD.js → UkeySign-CiObLk0T.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-diCFSWJw.js → VideoEditing-CFEZaQ2x.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ba1oND1K.js → Wallet-DR8ZGDNn.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DZDqPS-S.js → WebAuthn-DxZukvu7.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CfN8fPMe.js → WorkflowEditor-CKgSZQwn.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BiqMsO_i.js → chat-CTxEQE66.js} +1 -1
- package/src/assets/web-panel/assets/{colors-By8LkjqH.js → colors-CAjKMUu3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-B0mxvRe3.js → compact-item-BXuz49at.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Li2ub348.js → createContext-CFN_Hwr9.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DYbHPkbl.js → hasIn-BwoSBSfP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVZNYRzM.js → index-B0QbLlWn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGZzexNa.js → index-B2o_BBjg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYv3JIzl.js → index-B2tEnBPx.js} +1 -1
- package/src/assets/web-panel/assets/{index-1lVoRUrQ.js → index-B7kp-zRE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTVPeUh3.js → index-B9yR7zqr.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFhksbXp.js → index-BK4ftQ4d.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0D0HkkM.js → index-Bj4hIiLW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEp_3fKJ.js → index-BmQITjMU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIImi0cd.js → index-BmXpdcHI.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6qL3QBU.js → index-Bqv_Cray.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSk0xuXP.js → index-Bu2P6u8m.js} +1 -1
- package/src/assets/web-panel/assets/{index-zSzXsF9b.js → index-Bw9s2d3c.js} +1 -1
- package/src/assets/web-panel/assets/{index-beDji-cB.js → index-C8er4W9u.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-RE3mFh.js → index-CB3kVd9c.js} +1 -1
- package/src/assets/web-panel/assets/index-CCsRfd0k.js +1 -0
- package/src/assets/web-panel/assets/{index-CA0AOURT.js → index-CF9lWi1o.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMh3VxgO.js → index-CN53dE_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-KWt8Owo8.js → index-CSmFby3Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DB4DCzqU.js → index-CehdwJ_Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHgiSV6R.js → index-Cgk0YEiq.js} +1 -1
- package/src/assets/web-panel/assets/{index-b4O_YBVR.js → index-Cp5y7lX_.js} +1 -1
- package/src/assets/web-panel/assets/index-CsmiZIQ4.js +1 -0
- package/src/assets/web-panel/assets/{index-DAOpBv3C.js → index-DTX9CJPx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZqTG7fP.js → index-DViK2bkv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bc6bxU24.js → index-DY-gBSm8.js} +1 -1
- package/src/assets/web-panel/assets/{index-Czt7WAtA.js → index-DjF5BOZx.js} +1 -1
- package/src/assets/web-panel/assets/{index-KqfqSdAC.js → index-DmkbAADP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bd5znvCV.js → index-DpdDnZX_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5Se6Lnv.js → index-Dv7V2kg6.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cpfn4YbT.js → index-DxunxaTw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcOJEgBE.js → index-F2E5RCwz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgyrklzQ.js → index-IY9bd5az.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClsJN8sW.js → index-IahILygB.js} +3 -3
- package/src/assets/web-panel/assets/{index-hw3sCYAz.js → index-T3MTE6jB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bm2P2Kgp.js → index-Tz5dheZa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRzewWeE.js → index-_ZtCyUdz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPRgnazi.js → index-o9DpkZKf.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByqFKMWL.js → index-t2Ch_JKn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgMFnBOv.js → index-u9_DM3ZC.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-TgDL_7OY.js → initDefaultProps-BoiGJDoO.js} +1 -1
- package/src/assets/web-panel/assets/{motion-fHosyV5c.js → motion-5eL4E0pA.js} +1 -1
- package/src/assets/web-panel/assets/{move-C_QfW5qg.js → move-DjggDi_1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-u7ywDVOg.js → mtc-parser-Ce8Vo2T3.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BEJdUgE9.js → omit-D1yOBaO2.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DGkQFAJ5.js → pickAttrs-8NLceQe8.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DUyZXAjt.js → placementArrow-CsIdBRmQ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B4xDxO7Q.js → responsiveObserve-GM5NE8En.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B8WuJtst.js → slide-44yj3u49.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DLUqy7JO.js → statusUtils-B8tqtWcX.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BYOJOyqL.js → styleChecker-NhDPBbyB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-WChWQURv.js → useFlexGapSupport-C8Qz1GtN.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-vLNpm3dv.js → useFs-ClUv4kih.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DSZ8unoU.js → usePersonalDataHub-BwkOVEh6.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C4Xf7Kg1.js → vnode--gMF33R0.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BulmeAGy.js → zoom-DXg3TqOP.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +5 -5
- package/src/commands/agent-process-ownership.js +121 -0
- package/src/commands/agent.js +2 -0
- package/src/commands/automation.js +35 -8
- package/src/commands/hub.js +224 -0
- package/src/commands/project.js +162 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +54 -8
- package/src/lib/audit-logger.js +59 -46
- package/src/lib/audit-sanitizer.js +279 -0
- package/src/lib/automation-center.js +14 -4
- package/src/lib/automation-engine.js +151 -39
- package/src/lib/checkpoint-restore-saga.js +11 -1
- package/src/lib/eval/verify01-host-evidence.js +36 -3
- package/src/lib/knowledge-graph.js +27 -0
- package/src/lib/personal-data-hub-wiring.js +44 -1
- package/src/lib/process-execution-broker/index.js +91 -1
- package/src/lib/process-execution-broker/platform-sandbox.js +42 -0
- package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +757 -0
- package/src/lib/process-execution-broker/windows-native-evaluator.js +316 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +383 -11
- package/src/lib/scheduler-kernel/automation-adapter.js +15 -3
- package/src/lib/scheduler-kernel/automation-event-adapter.js +15 -3
- package/src/assets/web-panel/assets/devWarning-D90arbUg.js +0 -1
- package/src/assets/web-panel/assets/index-CeP1oROI.js +0 -1
- package/src/assets/web-panel/assets/index-Cu9gkyRc.js +0 -1
|
@@ -27,6 +27,16 @@ export const EXECUTION_STATUS = Object.freeze({
|
|
|
27
27
|
SUCCESS: "success",
|
|
28
28
|
FAILED: "failed",
|
|
29
29
|
CANCELLED: "cancelled",
|
|
30
|
+
SIMULATED: "simulated",
|
|
31
|
+
UNSUPPORTED: "unsupported",
|
|
32
|
+
UNVERIFIED: "legacy-unverified",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const AUTOMATION_EXECUTION_CAPABILITY = Object.freeze({
|
|
36
|
+
live: false,
|
|
37
|
+
simulation: true,
|
|
38
|
+
reason:
|
|
39
|
+
"Connector catalog only; live automation execution is not implemented",
|
|
30
40
|
});
|
|
31
41
|
|
|
32
42
|
export const TRIGGER_TYPE = Object.freeze({
|
|
@@ -125,12 +135,22 @@ export const CONNECTOR_CATALOG = Object.freeze([
|
|
|
125
135
|
const CONNECTOR_INDEX = new Map(CONNECTOR_CATALOG.map((c) => [c.id, c]));
|
|
126
136
|
|
|
127
137
|
export function listConnectors() {
|
|
128
|
-
return CONNECTOR_CATALOG.map((c) => ({
|
|
138
|
+
return CONNECTOR_CATALOG.map((c) => ({
|
|
139
|
+
...c,
|
|
140
|
+
actions: [...c.actions],
|
|
141
|
+
executionCapability: AUTOMATION_EXECUTION_CAPABILITY,
|
|
142
|
+
}));
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
export function getConnector(id) {
|
|
132
146
|
const c = CONNECTOR_INDEX.get(id);
|
|
133
|
-
return c
|
|
147
|
+
return c
|
|
148
|
+
? {
|
|
149
|
+
...c,
|
|
150
|
+
actions: [...c.actions],
|
|
151
|
+
executionCapability: AUTOMATION_EXECUTION_CAPABILITY,
|
|
152
|
+
}
|
|
153
|
+
: null;
|
|
134
154
|
}
|
|
135
155
|
|
|
136
156
|
/* ── Built-in flow templates ───────────────────────────────── */
|
|
@@ -462,14 +482,42 @@ function _rowToFlow(row) {
|
|
|
462
482
|
|
|
463
483
|
function _rowToExecution(row) {
|
|
464
484
|
if (!row) return null;
|
|
485
|
+
const outputData = _parseJSON(row.output_data, null);
|
|
486
|
+
const stepsLog = _parseJSON(row.steps_log, []);
|
|
487
|
+
const simulated =
|
|
488
|
+
row.test_mode === 1 ||
|
|
489
|
+
outputData?.simulated === true ||
|
|
490
|
+
stepsLog.some((step) => step.output?.simulated === true);
|
|
491
|
+
const adjudication = _parseJSON(row.error, null);
|
|
492
|
+
const confirmedApplied =
|
|
493
|
+
adjudication?.authority === "scheduler-adjudication" &&
|
|
494
|
+
adjudication?.decision === "confirmed_applied";
|
|
495
|
+
const legacyControlOnly =
|
|
496
|
+
row.status === EXECUTION_STATUS.SUCCESS &&
|
|
497
|
+
!confirmedApplied &&
|
|
498
|
+
stepsLog.every((step) => step.nodeType && step.nodeType !== "action") &&
|
|
499
|
+
(outputData == null ||
|
|
500
|
+
outputData.parallel === true ||
|
|
501
|
+
outputData.loop === true ||
|
|
502
|
+
(typeof outputData.branch === "string" && "expression" in outputData));
|
|
503
|
+
// Old releases persisted simulator results as success. Do not recover those
|
|
504
|
+
// rows as evidence that an external action was applied.
|
|
505
|
+
const status =
|
|
506
|
+
row.status === EXECUTION_STATUS.SUCCESS && simulated
|
|
507
|
+
? EXECUTION_STATUS.SIMULATED
|
|
508
|
+
: legacyControlOnly
|
|
509
|
+
? EXECUTION_STATUS.UNVERIFIED
|
|
510
|
+
: row.status;
|
|
465
511
|
return {
|
|
466
512
|
id: row.id,
|
|
467
513
|
flowId: row.flow_id,
|
|
468
514
|
triggerType: row.trigger_type,
|
|
469
515
|
inputData: _parseJSON(row.input_data, null),
|
|
470
|
-
outputData
|
|
471
|
-
status
|
|
472
|
-
|
|
516
|
+
outputData,
|
|
517
|
+
status,
|
|
518
|
+
...(status !== row.status ? { recordedStatus: row.status } : {}),
|
|
519
|
+
mode: simulated ? "simulation" : legacyControlOnly ? "unverified" : "live",
|
|
520
|
+
stepsLog,
|
|
473
521
|
durationMs: row.duration_ms || 0,
|
|
474
522
|
error: row.error || null,
|
|
475
523
|
testMode: row.test_mode === 1,
|
|
@@ -1161,13 +1209,20 @@ export function executeFlow(db, flowId, options = {}) {
|
|
|
1161
1209
|
executionAuthority = null,
|
|
1162
1210
|
assertRuntimeBoundary = null,
|
|
1163
1211
|
} = options;
|
|
1212
|
+
if (typeof testMode !== "boolean") {
|
|
1213
|
+
throw new TypeError("testMode must be a boolean");
|
|
1214
|
+
}
|
|
1164
1215
|
const execId =
|
|
1165
1216
|
executionId === undefined
|
|
1166
1217
|
? _genId("exec")
|
|
1167
1218
|
: _normalizeExecutionId(executionId);
|
|
1168
1219
|
const existing = getExecution(db, execId);
|
|
1169
1220
|
if (existing) {
|
|
1170
|
-
return _resolveExistingExecution(existing, {
|
|
1221
|
+
return _resolveExistingExecution(existing, {
|
|
1222
|
+
flowId,
|
|
1223
|
+
triggerType,
|
|
1224
|
+
testMode,
|
|
1225
|
+
});
|
|
1171
1226
|
}
|
|
1172
1227
|
// Validate every declared action boundary before creating an execution row
|
|
1173
1228
|
// or invoking the first effect. The per-node assertion below remains as the
|
|
@@ -1210,20 +1265,34 @@ export function executeFlow(db, flowId, options = {}) {
|
|
|
1210
1265
|
// the winner from durable evidence instead of running the flow twice.
|
|
1211
1266
|
const concurrent = getExecution(db, execId);
|
|
1212
1267
|
if (!concurrent) throw error;
|
|
1213
|
-
return _resolveExistingExecution(concurrent, {
|
|
1268
|
+
return _resolveExistingExecution(concurrent, {
|
|
1269
|
+
flowId,
|
|
1270
|
+
triggerType,
|
|
1271
|
+
testMode,
|
|
1272
|
+
});
|
|
1214
1273
|
}
|
|
1215
1274
|
|
|
1216
1275
|
const stepsLog = [];
|
|
1217
|
-
let finalStatus =
|
|
1276
|
+
let finalStatus = testMode
|
|
1277
|
+
? EXECUTION_STATUS.SIMULATED
|
|
1278
|
+
: EXECUTION_STATUS.UNSUPPORTED;
|
|
1218
1279
|
let finalError = null;
|
|
1219
1280
|
let outputData = null;
|
|
1220
1281
|
|
|
1221
1282
|
try {
|
|
1222
1283
|
const ordered = _topoOrder(flow.nodes, flow.edges);
|
|
1284
|
+
if (!testMode) {
|
|
1285
|
+
finalError = AUTOMATION_EXECUTION_CAPABILITY.reason;
|
|
1286
|
+
outputData = {
|
|
1287
|
+
executed: false,
|
|
1288
|
+
code: "AUTOMATION_EXECUTION_UNSUPPORTED",
|
|
1289
|
+
capability: AUTOMATION_EXECUTION_CAPABILITY,
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1223
1292
|
const stepInputs = new Map();
|
|
1224
1293
|
stepInputs.set("__initial__", inputData);
|
|
1225
1294
|
|
|
1226
|
-
for (const node of ordered) {
|
|
1295
|
+
for (const node of testMode ? ordered : []) {
|
|
1227
1296
|
const stepStart = Date.now();
|
|
1228
1297
|
const parentEdges = flow.edges.filter((e) => e.to === node.id);
|
|
1229
1298
|
let merged;
|
|
@@ -1251,7 +1320,7 @@ export function executeFlow(db, flowId, options = {}) {
|
|
|
1251
1320
|
nodeType: node.type || "action",
|
|
1252
1321
|
connector: node.connector || null,
|
|
1253
1322
|
action: node.action || null,
|
|
1254
|
-
status:
|
|
1323
|
+
status: EXECUTION_STATUS.SIMULATED,
|
|
1255
1324
|
durationMs: Date.now() - stepStart,
|
|
1256
1325
|
output,
|
|
1257
1326
|
});
|
|
@@ -1389,8 +1458,15 @@ function _normalizeExecutionId(value) {
|
|
|
1389
1458
|
return value;
|
|
1390
1459
|
}
|
|
1391
1460
|
|
|
1392
|
-
function _resolveExistingExecution(
|
|
1393
|
-
|
|
1461
|
+
function _resolveExistingExecution(
|
|
1462
|
+
existing,
|
|
1463
|
+
{ flowId, triggerType, testMode },
|
|
1464
|
+
) {
|
|
1465
|
+
if (
|
|
1466
|
+
existing.flowId !== flowId ||
|
|
1467
|
+
existing.triggerType !== triggerType ||
|
|
1468
|
+
existing.testMode !== testMode
|
|
1469
|
+
) {
|
|
1394
1470
|
const error = new Error(
|
|
1395
1471
|
`Execution id is already bound to another automation request: ${existing.id}`,
|
|
1396
1472
|
);
|
|
@@ -1407,7 +1483,7 @@ function _resolveExistingExecution(existing, { flowId, triggerType }) {
|
|
|
1407
1483
|
return existing;
|
|
1408
1484
|
}
|
|
1409
1485
|
|
|
1410
|
-
export function fireTrigger(db, triggerId, inputData = {}) {
|
|
1486
|
+
export function fireTrigger(db, triggerId, inputData = {}, options = {}) {
|
|
1411
1487
|
const trig = getTrigger(db, triggerId);
|
|
1412
1488
|
if (!trig) throw new Error(`Trigger not found: ${triggerId}`);
|
|
1413
1489
|
if (!trig.enabled) throw new Error(`Trigger disabled: ${triggerId}`);
|
|
@@ -1434,6 +1510,7 @@ export function fireTrigger(db, triggerId, inputData = {}) {
|
|
|
1434
1510
|
return executeFlow(db, trig.flowId, {
|
|
1435
1511
|
inputData,
|
|
1436
1512
|
triggerType: trig.type,
|
|
1513
|
+
testMode: options.testMode ?? false,
|
|
1437
1514
|
});
|
|
1438
1515
|
}
|
|
1439
1516
|
|
|
@@ -1445,31 +1522,64 @@ export function getExecution(db, execId) {
|
|
|
1445
1522
|
|
|
1446
1523
|
export function listExecutions(db, filters = {}) {
|
|
1447
1524
|
const { flowId, status, limit = 50 } = filters;
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1525
|
+
if (!Number.isSafeInteger(limit) || limit < 0) {
|
|
1526
|
+
throw new RangeError(
|
|
1527
|
+
"Execution history limit must be a non-negative integer",
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
if (limit === 0) return [];
|
|
1531
|
+
|
|
1532
|
+
const clauses = [];
|
|
1533
|
+
const params = [];
|
|
1534
|
+
if (flowId) {
|
|
1535
|
+
clauses.push("flow_id = ?");
|
|
1536
|
+
params.push(flowId);
|
|
1537
|
+
}
|
|
1538
|
+
const needsLegacyProjection = [
|
|
1539
|
+
EXECUTION_STATUS.SUCCESS,
|
|
1540
|
+
EXECUTION_STATUS.SIMULATED,
|
|
1541
|
+
EXECUTION_STATUS.UNVERIFIED,
|
|
1542
|
+
].includes(status);
|
|
1543
|
+
if (status) {
|
|
1544
|
+
if (needsLegacyProjection && status !== EXECUTION_STATUS.SUCCESS) {
|
|
1545
|
+
clauses.push("status IN (?, ?)");
|
|
1546
|
+
params.push(status, EXECUTION_STATUS.SUCCESS);
|
|
1547
|
+
} else {
|
|
1548
|
+
clauses.push("status = ?");
|
|
1549
|
+
params.push(status);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
const where = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
|
|
1553
|
+
if (!needsLegacyProjection) {
|
|
1554
|
+
return db
|
|
1463
1555
|
.prepare(
|
|
1464
|
-
`SELECT * FROM auto_executions
|
|
1556
|
+
`SELECT * FROM auto_executions${where} ORDER BY started_at DESC LIMIT ?`,
|
|
1465
1557
|
)
|
|
1466
|
-
.all(
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1558
|
+
.all(...params, limit)
|
|
1559
|
+
.map(_rowToExecution);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// A stored success can project to simulated/unverified. Scan only candidate
|
|
1563
|
+
// statuses in bounded pages and stop once the caller's normalized limit is
|
|
1564
|
+
// met, instead of loading all execution payloads into memory. The id tie
|
|
1565
|
+
// breaker keeps page boundaries stable when timestamps are identical.
|
|
1566
|
+
const pageSize = 128;
|
|
1567
|
+
const statement = db.prepare(
|
|
1568
|
+
`SELECT * FROM auto_executions${where} ORDER BY started_at DESC, id DESC LIMIT ? OFFSET ?`,
|
|
1569
|
+
);
|
|
1570
|
+
const executions = [];
|
|
1571
|
+
let offset = 0;
|
|
1572
|
+
while (executions.length < limit) {
|
|
1573
|
+
const rows = statement.all(...params, pageSize, offset);
|
|
1574
|
+
for (const row of rows) {
|
|
1575
|
+
const execution = _rowToExecution(row);
|
|
1576
|
+
if (execution.status === status) executions.push(execution);
|
|
1577
|
+
if (executions.length === limit) return executions;
|
|
1578
|
+
}
|
|
1579
|
+
if (rows.length < pageSize) break;
|
|
1580
|
+
offset += rows.length;
|
|
1471
1581
|
}
|
|
1472
|
-
return
|
|
1582
|
+
return executions;
|
|
1473
1583
|
}
|
|
1474
1584
|
|
|
1475
1585
|
/* ── Stats ─────────────────────────────────────────────────── */
|
|
@@ -1477,7 +1587,7 @@ export function listExecutions(db, filters = {}) {
|
|
|
1477
1587
|
export function getStats(db) {
|
|
1478
1588
|
const flowsByStatus = {};
|
|
1479
1589
|
for (const status of Object.values(FLOW_STATUS)) flowsByStatus[status] = 0;
|
|
1480
|
-
for (const row of db.
|
|
1590
|
+
for (const row of db.prepare("SELECT * FROM auto_flows").all()) {
|
|
1481
1591
|
flowsByStatus[row.status] = (flowsByStatus[row.status] || 0) + 1;
|
|
1482
1592
|
}
|
|
1483
1593
|
|
|
@@ -1486,15 +1596,16 @@ export function getStats(db) {
|
|
|
1486
1596
|
execByStatus[status] = 0;
|
|
1487
1597
|
let totalDuration = 0;
|
|
1488
1598
|
let execCount = 0;
|
|
1489
|
-
for (const row of db.
|
|
1490
|
-
|
|
1599
|
+
for (const row of db.prepare("SELECT * FROM auto_executions").all()) {
|
|
1600
|
+
const { status } = _rowToExecution(row);
|
|
1601
|
+
execByStatus[status] = (execByStatus[status] || 0) + 1;
|
|
1491
1602
|
totalDuration += row.duration_ms || 0;
|
|
1492
1603
|
execCount++;
|
|
1493
1604
|
}
|
|
1494
1605
|
|
|
1495
1606
|
const triggersByType = {};
|
|
1496
1607
|
for (const type of Object.values(TRIGGER_TYPE)) triggersByType[type] = 0;
|
|
1497
|
-
for (const row of db.
|
|
1608
|
+
for (const row of db.prepare("SELECT * FROM auto_triggers").all()) {
|
|
1498
1609
|
triggersByType[row.type] = (triggersByType[row.type] || 0) + 1;
|
|
1499
1610
|
}
|
|
1500
1611
|
|
|
@@ -1528,6 +1639,7 @@ export function getStats(db) {
|
|
|
1528
1639
|
|
|
1529
1640
|
export function getConfig() {
|
|
1530
1641
|
return {
|
|
1642
|
+
executionCapability: AUTOMATION_EXECUTION_CAPABILITY,
|
|
1531
1643
|
connectors: CONNECTOR_CATALOG.length,
|
|
1532
1644
|
templates: FLOW_TEMPLATES.length,
|
|
1533
1645
|
flowStatuses: Object.values(FLOW_STATUS),
|
|
@@ -464,6 +464,16 @@ function isMissingPathError(error) {
|
|
|
464
464
|
return error?.code === "ENOENT" || error?.cause?.code === "ENOENT";
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
+
function hasMissingLockPathCause(error) {
|
|
468
|
+
// A bounded owner read wraps secure-parent errors, which themselves wrap
|
|
469
|
+
// ENOENT when a cooperating process detaches its released lock directory.
|
|
470
|
+
// Only unlocked lock inspection uses this; losing our held owner still fails.
|
|
471
|
+
for (let depth = 0; error && depth < 8; depth++, error = error.cause) {
|
|
472
|
+
if (error.code === "ENOENT") return true;
|
|
473
|
+
}
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
|
|
467
477
|
function attachCommitState(error, details) {
|
|
468
478
|
if (!error || typeof error !== "object") return error;
|
|
469
479
|
for (const [key, value] of Object.entries(details)) {
|
|
@@ -1887,7 +1897,7 @@ export class CheckpointRestoreSagaStore {
|
|
|
1887
1897
|
// The same valid release can happen after readdir observed owner.json
|
|
1888
1898
|
// but before its lstat/read. Only tolerate absence during the unlocked
|
|
1889
1899
|
// pre/postflight inspection; losing our own owner still fails closed.
|
|
1890
|
-
if (
|
|
1900
|
+
if (hasMissingLockPathCause(cause) && !requireOwner) return null;
|
|
1891
1901
|
throw sagaError(
|
|
1892
1902
|
CHECKPOINT_RESTORE_SAGA_ERROR_CODES.LOCK_FAILED,
|
|
1893
1903
|
"Saga state lock owner is corrupt or unbounded",
|
|
@@ -149,13 +149,46 @@ export function inspectIdeProtocol(records, { prompt, comparison } = {}) {
|
|
|
149
149
|
resultRecords[0].event.session_id === sessionId,
|
|
150
150
|
"IDE terminal is missing or ambiguous",
|
|
151
151
|
);
|
|
152
|
+
const terminal = resultRecords[0].event;
|
|
153
|
+
// Persistent headless streams emit one lifecycle end after stdin closes.
|
|
154
|
+
// Accept only that exact, same-session one-turn trailer; task output after
|
|
155
|
+
// the result stays ambiguous. Keep the complete capture intact.
|
|
156
|
+
const trailing = outputs.slice(outputs.indexOf(resultRecords[0]) + 1);
|
|
157
|
+
const end = trailing[0]?.event;
|
|
158
|
+
const lifecycleFrames = outputs.filter(
|
|
159
|
+
(record) =>
|
|
160
|
+
record.event.type === "system" && record.event.subtype === "end",
|
|
161
|
+
);
|
|
162
|
+
const lifecycleEnded =
|
|
163
|
+
trailing.length === 1 &&
|
|
164
|
+
lifecycleFrames.length === 1 &&
|
|
165
|
+
end.type === "system" &&
|
|
166
|
+
end.subtype === "end" &&
|
|
167
|
+
end.session_id === sessionId &&
|
|
168
|
+
end.turns === 1 &&
|
|
169
|
+
terminal.turn === 1 &&
|
|
170
|
+
Object.keys(end).every((key) =>
|
|
171
|
+
["type", "subtype", "session_id", "turns", "trace_id", "seq"].includes(
|
|
172
|
+
key,
|
|
173
|
+
),
|
|
174
|
+
) &&
|
|
175
|
+
(end.trace_id === undefined ||
|
|
176
|
+
(typeof end.trace_id === "string" &&
|
|
177
|
+
end.trace_id === terminal.trace_id)) &&
|
|
178
|
+
(end.seq === undefined ||
|
|
179
|
+
(Number.isSafeInteger(end.seq) &&
|
|
180
|
+
Number.isSafeInteger(terminal.seq) &&
|
|
181
|
+
end.seq === terminal.seq + 1));
|
|
182
|
+
const taskOutputs = lifecycleEnded ? outputs.slice(0, -1) : outputs;
|
|
152
183
|
const parsed = verifyAgentTerminal(
|
|
153
|
-
|
|
184
|
+
taskOutputs.map((record) => JSON.stringify(record.event)).join("\n"),
|
|
154
185
|
);
|
|
155
|
-
|
|
186
|
+
if (lifecycleFrames.length > 0 && !lifecycleEnded)
|
|
187
|
+
parsed.terminalVerified = false;
|
|
156
188
|
// A complete explicit failure is an observation. It never becomes success.
|
|
157
189
|
const knownFailure =
|
|
158
|
-
|
|
190
|
+
taskOutputs.at(-1) === resultRecords[0] &&
|
|
191
|
+
(lifecycleFrames.length === 0 || lifecycleEnded) &&
|
|
159
192
|
terminal.is_error === true &&
|
|
160
193
|
typeof terminal.subtype === "string" &&
|
|
161
194
|
terminal.subtype.length > 0 &&
|
|
@@ -239,6 +239,33 @@ export function getEntity(id) {
|
|
|
239
239
|
return e ? _strip(e) : null;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/** Replace supplied entity fields while preserving identity and relationships. */
|
|
243
|
+
export function updateEntity(db, id, config = {}) {
|
|
244
|
+
const current = _entities.get(id);
|
|
245
|
+
if (!current) throw new Error(`Entity not found: ${id}`);
|
|
246
|
+
const name = String(config.name ?? current.name).trim();
|
|
247
|
+
const type = String(config.type ?? current.type).trim();
|
|
248
|
+
if (!name) throw new Error("entity name is required");
|
|
249
|
+
if (!type) throw new Error("entity type is required");
|
|
250
|
+
const entity = {
|
|
251
|
+
...current,
|
|
252
|
+
name,
|
|
253
|
+
type,
|
|
254
|
+
properties: Object.hasOwn(config, "properties")
|
|
255
|
+
? config.properties
|
|
256
|
+
: current.properties,
|
|
257
|
+
tags: Object.hasOwn(config, "tags")
|
|
258
|
+
? Array.isArray(config.tags)
|
|
259
|
+
? [...config.tags]
|
|
260
|
+
: null
|
|
261
|
+
: current.tags,
|
|
262
|
+
updatedAt: Number(config.now ?? Date.now()),
|
|
263
|
+
};
|
|
264
|
+
_persistEntity(db, entity);
|
|
265
|
+
_entities.set(id, entity);
|
|
266
|
+
return _strip(entity);
|
|
267
|
+
}
|
|
268
|
+
|
|
242
269
|
export function listEntities(opts = {}) {
|
|
243
270
|
let rows = [..._entities.values()];
|
|
244
271
|
if (opts.type) {
|
|
@@ -368,6 +368,17 @@ async function loadBm25() {
|
|
|
368
368
|
let _hub = null;
|
|
369
369
|
let _initPromise = null;
|
|
370
370
|
let _bm25 = null;
|
|
371
|
+
let _processExitHook = null;
|
|
372
|
+
|
|
373
|
+
function installProcessExitHook() {
|
|
374
|
+
if (_processExitHook) return;
|
|
375
|
+
_processExitHook = (code) => {
|
|
376
|
+
// exit callbacks are synchronous. Nonzero exits keep the generation active;
|
|
377
|
+
// exit(0) still has to pass the registry's in-flight operation guard.
|
|
378
|
+
close({ retireConsumer: code === 0 });
|
|
379
|
+
};
|
|
380
|
+
process.once("exit", _processExitHook);
|
|
381
|
+
}
|
|
371
382
|
|
|
372
383
|
// LLM override — see file header. Default cli-side hub uses a direct
|
|
373
384
|
// OllamaClient; when the desktop main process embeds this wiring via
|
|
@@ -453,6 +464,11 @@ async function initHub() {
|
|
|
453
464
|
kgSink = new CcKgSink({
|
|
454
465
|
addEntity: kgMod.addEntity,
|
|
455
466
|
addRelation: kgMod.addRelation,
|
|
467
|
+
updateEntity: kgMod.updateEntity,
|
|
468
|
+
getEntity: kgMod.getEntity,
|
|
469
|
+
removeEntity: kgMod.removeEntity,
|
|
470
|
+
listRelations: kgMod.listRelations,
|
|
471
|
+
removeRelation: kgMod.removeRelation,
|
|
456
472
|
db: null,
|
|
457
473
|
});
|
|
458
474
|
}
|
|
@@ -550,6 +566,8 @@ async function initHub() {
|
|
|
550
566
|
vault,
|
|
551
567
|
kgSink: kgSink ? kgSink.write.bind(kgSink) : null,
|
|
552
568
|
ragSink: ragSink ? ragSink.write.bind(ragSink) : null,
|
|
569
|
+
kgRemove: kgSink?.remove?.bind(kgSink) || null,
|
|
570
|
+
ragRemove: ragSink?.remove?.bind(ragSink) || null,
|
|
553
571
|
entityResolver,
|
|
554
572
|
adbReadiness: {
|
|
555
573
|
probe: adbReadinessProbe,
|
|
@@ -557,6 +575,20 @@ async function initHub() {
|
|
|
557
575
|
},
|
|
558
576
|
});
|
|
559
577
|
|
|
578
|
+
// Both projections are in memory. A fresh registry consumer must rebuild
|
|
579
|
+
// from durable desired state before serving retrieval; leave failures
|
|
580
|
+
// visible and explicitly retryable instead of blocking startup forever.
|
|
581
|
+
if (typeof registry.retryDerivations === "function") {
|
|
582
|
+
for (let page = 0; page < 100; page += 1) {
|
|
583
|
+
const result = await registry.retryDerivations({ limit: 1000 });
|
|
584
|
+
if (!result.remaining) break;
|
|
585
|
+
// A referenced KG endpoint can occur on a later page. Visit fresh
|
|
586
|
+
// work before concluding that a failed dependency is unrecoverable.
|
|
587
|
+
if (result.summary?.pending > 0) continue;
|
|
588
|
+
if (!result.succeeded || result.unsupported || result.blocked) break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
560
592
|
const engine = new AnalysisEngine({
|
|
561
593
|
vault,
|
|
562
594
|
llm,
|
|
@@ -2106,6 +2138,7 @@ export async function getHub() {
|
|
|
2106
2138
|
_initPromise = initHub()
|
|
2107
2139
|
.then((h) => {
|
|
2108
2140
|
_hub = h;
|
|
2141
|
+
installProcessExitHook();
|
|
2109
2142
|
return h;
|
|
2110
2143
|
})
|
|
2111
2144
|
.catch((err) => {
|
|
@@ -2226,6 +2259,7 @@ export async function getHubMinimal() {
|
|
|
2226
2259
|
_hubMinimalInitPromise = initHubMinimal()
|
|
2227
2260
|
.then((h) => {
|
|
2228
2261
|
_hubMinimal = h;
|
|
2262
|
+
installProcessExitHook();
|
|
2229
2263
|
return h;
|
|
2230
2264
|
})
|
|
2231
2265
|
.catch((err) => {
|
|
@@ -2236,7 +2270,11 @@ export async function getHubMinimal() {
|
|
|
2236
2270
|
return _hubMinimalInitPromise;
|
|
2237
2271
|
}
|
|
2238
2272
|
|
|
2239
|
-
export function close() {
|
|
2273
|
+
export function close({ retireConsumer = true } = {}) {
|
|
2274
|
+
if (_processExitHook) {
|
|
2275
|
+
process.removeListener("exit", _processExitHook);
|
|
2276
|
+
_processExitHook = null;
|
|
2277
|
+
}
|
|
2240
2278
|
if (_hub && _hub.aichatHealthChecker) {
|
|
2241
2279
|
try {
|
|
2242
2280
|
_hub.aichatHealthChecker.stop();
|
|
@@ -2245,6 +2283,11 @@ export function close() {
|
|
|
2245
2283
|
}
|
|
2246
2284
|
}
|
|
2247
2285
|
if (_hub && _hub.vault) {
|
|
2286
|
+
try {
|
|
2287
|
+
if (retireConsumer) _hub.registry?.retireDerivationConsumer?.();
|
|
2288
|
+
} catch {
|
|
2289
|
+
// Busy/unknown generations retain their receipts for explicit recovery.
|
|
2290
|
+
}
|
|
2248
2291
|
try {
|
|
2249
2292
|
_hub.vault.close();
|
|
2250
2293
|
} catch {
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
SANDBOX_BOUNDARIES,
|
|
47
47
|
} from "./platform-sandbox.js";
|
|
48
48
|
import { normalizeLinuxCgroupPolicy } from "./linux-cgroup-v2.js";
|
|
49
|
+
import { consumeWindowsNativeEvaluatorPolicy } from "./windows-native-evaluator.js";
|
|
49
50
|
import { acquireLinuxSubreaperHelper } from "./linux-subreaper-helper.js";
|
|
50
51
|
import { spawnLinuxSubreaperChild } from "./linux-subreaper-process.js";
|
|
51
52
|
import {
|
|
@@ -1625,7 +1626,49 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1625
1626
|
requiredBoundaries,
|
|
1626
1627
|
launch,
|
|
1627
1628
|
);
|
|
1628
|
-
|
|
1629
|
+
const wallTimeMs = rawPolicy?.limits?.wallTimeMs;
|
|
1630
|
+
if (wallTimeMs !== undefined) {
|
|
1631
|
+
if (
|
|
1632
|
+
!Number.isSafeInteger(wallTimeMs) ||
|
|
1633
|
+
wallTimeMs < 1 ||
|
|
1634
|
+
wallTimeMs > 3600000
|
|
1635
|
+
) {
|
|
1636
|
+
throw this._sandboxBoundaryError(
|
|
1637
|
+
"invalid_wall_time_limit",
|
|
1638
|
+
"Native wall-time limit must be an integer from 1 to 3600000 milliseconds",
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
if (!requiredBoundaries.includes(SANDBOX_BOUNDARIES.RESOURCE_LIMITS)) {
|
|
1642
|
+
requiredBoundaries.push(SANDBOX_BOUNDARIES.RESOURCE_LIMITS);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
const windowsNativeEvaluator =
|
|
1646
|
+
rawPolicy?.windowsNativeEvaluator === undefined
|
|
1647
|
+
? null
|
|
1648
|
+
: consumeWindowsNativeEvaluatorPolicy(
|
|
1649
|
+
rawPolicy.windowsNativeEvaluator,
|
|
1650
|
+
launch,
|
|
1651
|
+
options,
|
|
1652
|
+
);
|
|
1653
|
+
if (windowsNativeEvaluator) {
|
|
1654
|
+
for (const boundary of [
|
|
1655
|
+
SANDBOX_BOUNDARIES.FILESYSTEM,
|
|
1656
|
+
SANDBOX_BOUNDARIES.NETWORK,
|
|
1657
|
+
SANDBOX_BOUNDARIES.PROCESS_TREE,
|
|
1658
|
+
SANDBOX_BOUNDARIES.RESOURCE_LIMITS,
|
|
1659
|
+
]) {
|
|
1660
|
+
if (!requiredBoundaries.includes(boundary))
|
|
1661
|
+
requiredBoundaries.push(boundary);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
return {
|
|
1665
|
+
profile,
|
|
1666
|
+
requiredBoundaries,
|
|
1667
|
+
linuxCgroup,
|
|
1668
|
+
executionContract,
|
|
1669
|
+
...(windowsNativeEvaluator ? { windowsNativeEvaluator } : {}),
|
|
1670
|
+
...(wallTimeMs !== undefined ? { wallTimeMs } : {}),
|
|
1671
|
+
};
|
|
1629
1672
|
}
|
|
1630
1673
|
|
|
1631
1674
|
_stripSandboxControlOptions(options) {
|
|
@@ -3660,6 +3703,12 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3660
3703
|
...(sandboxPolicy.executionContract
|
|
3661
3704
|
? { executionContract: sandboxPolicy.executionContract }
|
|
3662
3705
|
: {}),
|
|
3706
|
+
...(sandboxPolicy.wallTimeMs !== undefined
|
|
3707
|
+
? { limits: Object.freeze({ wallTimeMs: sandboxPolicy.wallTimeMs }) }
|
|
3708
|
+
: {}),
|
|
3709
|
+
...(sandboxPolicy.windowsNativeEvaluator
|
|
3710
|
+
? { windowsNativeEvaluator: sandboxPolicy.windowsNativeEvaluator }
|
|
3711
|
+
: {}),
|
|
3663
3712
|
});
|
|
3664
3713
|
// Keep the legacy string profile in argument four. The built-in adapter
|
|
3665
3714
|
// reserves argument five for runtime injection, so the typed request is
|
|
@@ -3667,6 +3716,12 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3667
3716
|
const sandboxAdapter = this._sandboxAdapter;
|
|
3668
3717
|
const applySandboxAdapter = sandboxAdapter.applySandbox;
|
|
3669
3718
|
const builtInSandboxAdapter = applySandboxAdapter === _applySandbox;
|
|
3719
|
+
if (sandboxPolicy.wallTimeMs !== undefined && !builtInSandboxAdapter) {
|
|
3720
|
+
throw this._sandboxBoundaryError(
|
|
3721
|
+
"native_wall_time_adapter_unattested",
|
|
3722
|
+
"Native wall-time enforcement requires the built-in Windows supervisor",
|
|
3723
|
+
);
|
|
3724
|
+
}
|
|
3670
3725
|
// Never dispatch the built-in through a mutable Function property or a
|
|
3671
3726
|
// global reflective helper after consulting an injected adapter getter.
|
|
3672
3727
|
// The lexical import is the identity we checked and the implementation we
|
|
@@ -3690,6 +3745,41 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3690
3745
|
]);
|
|
3691
3746
|
let plan;
|
|
3692
3747
|
try {
|
|
3748
|
+
if (
|
|
3749
|
+
sandboxPolicy.wallTimeMs !== undefined &&
|
|
3750
|
+
(!rawPlan?.applied ||
|
|
3751
|
+
rawPlan.platform !== "win32" ||
|
|
3752
|
+
![
|
|
3753
|
+
"windows-job-restricted-token",
|
|
3754
|
+
"windows-appcontainer-job-restricted-token",
|
|
3755
|
+
].includes(rawPlan.backend) ||
|
|
3756
|
+
rawPlan.windowsWallTimeMs !== sandboxPolicy.wallTimeMs)
|
|
3757
|
+
) {
|
|
3758
|
+
throw this._sandboxBoundaryError(
|
|
3759
|
+
"native_wall_time_limit_unavailable",
|
|
3760
|
+
`The requested native wall-time limit was not enforced: ${rawPlan?.reason || "unattested_plan"}`,
|
|
3761
|
+
{
|
|
3762
|
+
requiredBoundaries,
|
|
3763
|
+
actualGuarantees: rawPlan?.guarantees || [],
|
|
3764
|
+
sandboxBackend: rawPlan?.backend,
|
|
3765
|
+
sandboxCandidateBackend: rawPlan?.candidateBackend,
|
|
3766
|
+
sandboxRuntimeProbe: rawPlan?.runtimeProbe,
|
|
3767
|
+
sandboxCandidateReason: rawPlan?.reason,
|
|
3768
|
+
},
|
|
3769
|
+
);
|
|
3770
|
+
}
|
|
3771
|
+
if (
|
|
3772
|
+
sandboxPolicy.windowsNativeEvaluator &&
|
|
3773
|
+
(rawPlan.backend !== "windows-appcontainer-job-restricted-token" ||
|
|
3774
|
+
rawPlan.policyAttested !== true ||
|
|
3775
|
+
rawPlan.windowsNativeEvaluatorDigest !==
|
|
3776
|
+
sandboxPolicy.windowsNativeEvaluator.manifestDigest)
|
|
3777
|
+
) {
|
|
3778
|
+
throw this._sandboxBoundaryError(
|
|
3779
|
+
"native_evaluator_plan_unattested",
|
|
3780
|
+
"The staged native evaluator policy was not enforced",
|
|
3781
|
+
);
|
|
3782
|
+
}
|
|
3693
3783
|
plan = this._validateSandboxPlan(rawPlan, {
|
|
3694
3784
|
command,
|
|
3695
3785
|
args: Object.freeze([...(args || [])]),
|