chainlesschain 0.166.88 → 0.166.90
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 +101 -14
- 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-QzeGep9J.js → AIOps-CZzXRe1-.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Dfc5bx7S.js → ActionButton-_AZfbW1Q.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-tn-_ZG2E.js → Analytics-CzaUx_wv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Deg3WAK8.js → AppLayout-xHEeeD-m.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-KU05t0a6.js → Artifacts-DmTbtudE.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CkSZf54T.js → Audit-Cn4ng4fo.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-i7ivfXF0.js → BackgroundAgents-DLUY1VD2.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-QcVUKtf0.js → Backup-B2v--wB6.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B3h5ZJ0g.js → BaseInput-Bgih7yAv.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D7AVz0xi.js → Chat-1MiiA3yA.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B0-euPW7.js → ChatBubbleRenderer-CPLynmbb.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-H0p0TMlD.js → Checkbox-DsyBa_NO.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B6HOmAY3.js → Codegen-B7WCFx9H.js} +1 -1
- package/src/assets/web-panel/assets/{Col-n_64Fog2.js → Col-D2x4GBGm.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CX0JGgj0.js → Community-Rnwg9nea.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C4JWUZlx.js → Compact-BPczlrRh.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DKyTZakB.js → Compliance-Br1L_wGU.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-C0joBMci.js → Cowork-DlsWB_oS.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-D6VkYpxK.js → Cron-BWo_KGpG.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-7b6Uu8jc.js → Crosschain-Cug7N8ge.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C8YPKqzY.js → DID-CMbyOZJN.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DJsOiEry.js → Dashboard-C4dl_UaE.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CyStFY-4.js → Dropdown-CBrC7M-9.js} +1 -1
- package/src/assets/web-panel/assets/EmailListRenderer-DTq7tU4b.js +1 -0
- package/src/assets/web-panel/assets/{EvolutionSettings-DpxORusH.js → EvolutionSettings-DWP3csxS.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-5BYZdMG0.js → FamilyGuardDashboard-DZl7zuv_.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-s1kS0ekU.js → Federation-W-GSlVK5.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CmgoH9HV.js → FormItemContext-DMB7xYFV.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DSRWrvcL.js → GenericCardRenderer-DNv8GEoq.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Cz3EgnS1.js → Git-BZ0Bbzw6.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-De4atTe7.js → Governance-BNEdcOM5.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DoitBBxJ.js → Inference-C8249gIz.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CIdmJ1pH.js → KnowledgeGraph-ngzebU3e.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Coa_qNhU.js → Logs-CP15th-f.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-CW3B3JDq.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-C6kbAQoM.js → Marketplace-CaH59OsY.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C2TZn8D-.js → McpTools-C07vnJev.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DYdEKDuB.js → Memory-CqAOkVAS.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-pKLeVviZ.js → MobileBridge-qp7mZimq.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DKhbqvTw.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-IEoVRV29.js → Mtc-CRYCnWXv.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-Cov-yYTY.js → MtcAudit-Z08IrKws.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig--Jr7OCmp.js → Multisig-BWdatUnH.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D2gXnYAA.js → NLProgramming-BKWiCZ_m.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-hk8pMyve.js → Notes-Bgpzk3sm.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-D26Nc7MU.js → NotificationSettings-DvtZEktR.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DmzHMEOa.js → OrderTableRenderer-CBcy0szc.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Cn-o6mHT.js → Organization-DRRL6vW1.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DP6xpDak.js → Overflow-COmfB8Ns.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-C9WAjG-I.js → P2P-BqMq_DSa.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-BX7iNvle.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BFBN4-IL.js → Permissions-DzYkjmV_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BEDvoAiz.js → PersonalDataHub-BBTcxBbN.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-Co2Ze_rR.js → Pipeline-eRkYFSbO.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BOTn1EId.js → Privacy-Ch7IFKBh.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CObyrZYm.js → ProjectInit-Ci8EcBYg.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DVTN31rd.js → ProjectSettings-B4lYHFbI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DQSEaVjE.js → Projects-zkE5cCo_.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BRIKWIdQ.js → Providers-BKDVD3_e.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-3nxaEXxN.js → QrScannerModal-BromrHlf.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-iwZJEE9z.js → QuickAsk-CCgoY1gR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-D2_EEbvc.js → Recommend-DCPZvpq7.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-S4w2mUfq.js → RemoteSession-DPnFP8HU.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-CstUvfTC.js → Reputation-l6r8ytAs.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DEGHFpxz.js → Row-ke9Mk1cx.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DGdZtJQl.js → RssFeed-DQOEzUEn.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DhfXi99U.js → Search-BqgA0aUz.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BbzISrgX.js → Security-FeGD_jqV.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CFjP2sQ3.js → Services-4kiYYAjZ.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CFn5wbvm.js → Skeleton-BbU8Xegs.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-fVbT8RcW.js → Skills-Dl2bUMUL.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-D6OtC0MT.js → Sla-xRGALeaZ.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-D0kteBjU.js → SpeechSettings-DZfd4RDm.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BGEWCtPh.js → SyncSettings-BRtCV9Ga.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-B1xZUG4D.js → Tasks-DVRQklfG.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-COlorjqb.js → Templates-BbhE5jt5.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-yLkwfuo3.js → Tenant-qXPDNKbK.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CAmkq1wf.js → Terminal-CV48Ks7E.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CcKYq1Ue.js → TimelineRenderer-BLGfJIDr.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-9hIqn_LE.js → Tokens-7G9H6Hrt.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dsdkb74C.js → Trigger--F64N11F.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DC4GuE3C.js → Trust-Cq1r-D_y.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CSlh00wf.js → UkeySign-Dqyu4RVh.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-QEWLo3QY.js → VideoEditing-DuFmWH_B.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BkPNQgmg.js → Wallet-C3mg7EWP.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-7---jCBl.js → WebAuthn-CDK-Aj_X.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Dq6Yiu8E.js → WorkflowEditor--K7K-T1F.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTYIMpWD.js → chat-BQDcS6VP.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C8JtYlDN.js → colors-BKxJL2-T.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-spXpnsNC.js → compact-item-CFjQAMbY.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D04ewPuL.js → createContext-DbgCsdQd.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DlIv9Mbc.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DZblOKXx.js → hasIn-BhkaOBNv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdC0OsNh.js → index-3YutaXnp.js} +1 -1
- package/src/assets/web-panel/assets/{index-rVEqWa0_.js → index-3djsY75k.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSoyEHi2.js → index-3uR0ThJO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLUHbPl3.js → index-7BY44UEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7RA974g.js → index-B4LlAJqc.js} +1 -1
- package/src/assets/web-panel/assets/index-BC972Grv.js +1 -0
- package/src/assets/web-panel/assets/{index-BKfR2eSQ.js → index-BNjYPJNU.js} +1 -1
- package/src/assets/web-panel/assets/{index-KIoJ2eCK.js → index-BRqlCTrz.js} +1 -1
- package/src/assets/web-panel/assets/{index-rU6_An6N.js → index-BfGGsAU7.js} +1 -1
- package/src/assets/web-panel/assets/{index-B57W1RB6.js → index-BuWPqSGT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLv-KSGc.js → index-C0DzhUOX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHOV24VR.js → index-CB4oHynY.js} +1 -1
- package/src/assets/web-panel/assets/{index-IFEbaISP.js → index-CE506mgj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cgztj1JO.js → index-CJoXgJ2N.js} +1 -1
- package/src/assets/web-panel/assets/{index-DruABY-g.js → index-COGy6wXn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLkua5sJ.js → index-CRtUDiXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSO33_O2.js → index-CSUDlsIr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHtwoTKX.js → index-CUs7XpUO.js} +1 -1
- package/src/assets/web-panel/assets/index-CVifyQqL.js +1 -0
- package/src/assets/web-panel/assets/{index-DtSzmzFF.js → index-CoOu7sdP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-cKXztT.js → index-D-Yh3-1z.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_65aY6c.js → index-D2Zb-Kd1.js} +1 -1
- package/src/assets/web-panel/assets/{index-749P1pkM.js → index-D9sVcw6v.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw-3CtK2.js → index-DEwHywz9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dssnz_1x.js → index-DFt48Z-x.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOuUUW2U.js → index-DJ2OiRvh.js} +3 -3
- package/src/assets/web-panel/assets/{index-D_Md0Jhp.js → index-DP1NrM9J.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjMY3Y_L.js → index-DdcrixaQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-EM4_wLPi.js → index-De7daEnc.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz0gkRz_.js → index-Dhfa_BIl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZmBlh5P.js → index-DjmVlpap.js} +1 -1
- package/src/assets/web-panel/assets/{index-DwIEfKo7.js → index-DmYK9Tqt.js} +1 -1
- package/src/assets/web-panel/assets/{index-COvZnoIg.js → index-Dn2QSsuI.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bm0z1M6s.js → index-Du_SxxBY.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cfk4o9eI.js → index-DvWWFJHJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mxj-qi1G.js → index-T9ka3Xj3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE3TYhl0.js → index-aPdVzagA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcjouIsi.js → index-bMX8BBLE.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dcd-qZ68.js → index-sKfUUldY.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Dl0wiMxn.js → initDefaultProps-wrqabmui.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BFmZYrGO.js → motion-BoyB3ilP.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cjs64yWq.js → move-Cq31cSFE.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-NeQsnBuP.js → mtc-parser-BkxNt-8H.js} +1 -1
- package/src/assets/web-panel/assets/{omit-4Rs-rfs9.js → omit-DofGni53.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CUhx2rDY.js → pickAttrs-BnluLL16.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DbIM_OB2.js → placementArrow-C-yegJSP.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B_TGx9AN.js → responsiveObserve-CD3ziNhu.js} +1 -1
- package/src/assets/web-panel/assets/{slide-C46cEP5t.js → slide-ToZO4gQ1.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DqeksICX.js → statusUtils-DFVmDmVl.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-2rrypo5u.js → styleChecker-De0Y8g1O.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-RRe1Edsg.js → useFlexGapSupport-wBKIYFKX.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CB0oxU1U.js → useFs-CP9nmUMJ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-B98WdlUE.js → usePersonalDataHub-vFGrVDyp.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CY8AoD95.js → vnode-BcBIjvjH.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BnT-0MbP.js → zoom-DnXDAQxA.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +5 -5
- package/src/commands/agent-controlled-host.js +220 -0
- package/src/commands/agent.js +3 -1
- package/src/commands/automation.js +35 -8
- package/src/commands/hub.js +147 -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 +16 -29
- 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/eval/verify01-execution.js +9 -0
- package/src/lib/eval/verify01-host-capture.js +430 -0
- package/src/lib/knowledge-graph.js +27 -0
- package/src/lib/personal-data-hub-wiring.js +44 -1
- 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/EmailListRenderer-COrIx2Rg.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-CeT_RocE.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-D4bWcHA_.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-DxZb0Ux8.js +0 -7
- package/src/assets/web-panel/assets/devWarning-3-s4adfp.js +0 -1
- package/src/assets/web-panel/assets/index-ZMf_BGlO.js +0 -1
- package/src/assets/web-panel/assets/index-jvp8bJBF.js +0 -1
package/src/data/changelog.json
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "CHANGELOG.md",
|
|
3
3
|
"releases": [
|
|
4
|
+
{
|
|
5
|
+
"productVersion": null,
|
|
6
|
+
"cliVersion": "0.166.90",
|
|
7
|
+
"cliVersions": ["0.166.90"],
|
|
8
|
+
"date": null,
|
|
9
|
+
"title": "",
|
|
10
|
+
"sections": [
|
|
11
|
+
{
|
|
12
|
+
"heading": "Added - cc CLI 0.166.90: recoverable projections and project risk evidence",
|
|
13
|
+
"body": "- Publish Personal Data Hub `0.4.63` and Session Core `0.3.15` before the CLI,\n with exact dependency pins and public tarball verification. Require the full\n PDH suite with its declared native SQLCipher driver on Linux, Windows and macOS.\n- Publish Agent SDK `0.2.13` with Vitest `4.1.11` test tooling to remove the\n vulnerable Tinypool dependency, and upgrade the workspace proxy-addr to\n `2.0.8`. Require SDK build and tests on the exact Linux, Windows and macOS\n release commit before OIDC publication.\n- Persist PDH projection receipts, recover incomplete derivations and support\n bounded receipt retention. Harden RAG updates, audit redaction and capability\n reporting so unavailable sources do not appear as successful live collection.\n- Add offline project risk evaluation and version-bound task description\n previews. Session Core also supplies native SQLite action/read services and\n saved rule/source reviews for the desktop project workbench; CLI previews\n carry unverified snapshot authority and do not execute those desktop actions.\n- Pair VS Code `0.37.135` and JetBrains `0.4.153` with CLI `0.166.90` after\n exact-commit release checks and public npm readback."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"productVersion": null,
|
|
19
|
+
"cliVersion": "0.166.89",
|
|
20
|
+
"cliVersions": ["0.166.89"],
|
|
21
|
+
"date": null,
|
|
22
|
+
"title": "",
|
|
23
|
+
"sections": [
|
|
24
|
+
{
|
|
25
|
+
"heading": "Added - cc CLI 0.166.89: IDE capture journeys and controlled Linux entry",
|
|
26
|
+
"body": "- Prepare and finish frozen IDE tasks with byte-pinned baselines, complete diffs,\n a shared deadline and real protocol/UI evidence from both IDE hosts.\n- Add explicit `agent controlled-host` for pre-provisioned Linux permission domains;\n configuration checks do not claim backend execution or provision new authority.\n- Pair VS Code `0.37.134` and JetBrains `0.4.152` with CLI `0.166.89` for\n opt-in panel capture, deterministic initial/restart diagnostics and retained\n process-cleanup evidence. Add official MCP stdio interoperability checks."
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
4
30
|
{
|
|
5
31
|
"productVersion": null,
|
|
6
32
|
"cliVersion": "0.166.88",
|
|
@@ -193,7 +193,8 @@ async function withHub(fn, loadHub = getHub) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
function governedHubLoader(factory) {
|
|
196
|
-
if (typeof factory === "function")
|
|
196
|
+
if (typeof factory === "function")
|
|
197
|
+
return () => getGovernedAnalysisHub(factory);
|
|
197
198
|
const error = new Error(
|
|
198
199
|
"Personal Data Hub model egress requires an authenticated evolution composition factory",
|
|
199
200
|
);
|
|
@@ -201,16 +202,24 @@ function governedHubLoader(factory) {
|
|
|
201
202
|
throw error;
|
|
202
203
|
}
|
|
203
204
|
|
|
205
|
+
function validateEntityReference(entityType, entityId) {
|
|
206
|
+
if (
|
|
207
|
+
!["event", "person", "place", "item", "topic"].includes(entityType) ||
|
|
208
|
+
typeof entityId !== "string" ||
|
|
209
|
+
!entityId.trim() ||
|
|
210
|
+
entityId.length > 1024
|
|
211
|
+
) {
|
|
212
|
+
throw new Error("A valid entityType and entityId are required");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
204
216
|
export const PERSONAL_DATA_HUB_HANDLERS = {
|
|
205
217
|
"personal-data-hub.ask": async (msg, context = {}) => {
|
|
206
218
|
const factory = context.server?.evolutionCompositionFactory;
|
|
207
|
-
return withHub(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
},
|
|
212
|
-
governedHubLoader(factory),
|
|
213
|
-
);
|
|
219
|
+
return withHub(async (hub) => {
|
|
220
|
+
if (!hub.engine) throw new Error("Analysis engine unavailable");
|
|
221
|
+
return await hub.engine.ask(msg.question, msg.options || {});
|
|
222
|
+
}, governedHubLoader(factory));
|
|
214
223
|
},
|
|
215
224
|
|
|
216
225
|
// Path Y: prompt context only, no LLM call. Lets web-shell / mobile host
|
|
@@ -250,6 +259,43 @@ export const PERSONAL_DATA_HUB_HANDLERS = {
|
|
|
250
259
|
"personal-data-hub.list-adapters": async () =>
|
|
251
260
|
withHub((hub) => hub.registry.list()),
|
|
252
261
|
|
|
262
|
+
"personal-data-hub.derivation-status": async (msg) =>
|
|
263
|
+
withHub((hub) =>
|
|
264
|
+
hub.registry.getDerivationStatus({
|
|
265
|
+
adapter: msg.adapter,
|
|
266
|
+
scope: msg.scope,
|
|
267
|
+
}),
|
|
268
|
+
),
|
|
269
|
+
|
|
270
|
+
"personal-data-hub.derivation-state": async (msg) =>
|
|
271
|
+
withHub((hub) => {
|
|
272
|
+
validateEntityReference(msg.entityType, msg.entityId);
|
|
273
|
+
return hub.vault
|
|
274
|
+
.getDerivationStore()
|
|
275
|
+
.getState(msg.entityType, msg.entityId, {
|
|
276
|
+
consumerId: hub.registry.consumerId,
|
|
277
|
+
});
|
|
278
|
+
}),
|
|
279
|
+
|
|
280
|
+
"personal-data-hub.retry-derivations": async (msg) =>
|
|
281
|
+
withHub((hub) =>
|
|
282
|
+
hub.registry.retryDerivations({
|
|
283
|
+
adapter: msg.adapter,
|
|
284
|
+
scope: msg.scope,
|
|
285
|
+
limit: msg.limit,
|
|
286
|
+
}),
|
|
287
|
+
),
|
|
288
|
+
|
|
289
|
+
"personal-data-hub.delete-entity": async (msg) =>
|
|
290
|
+
withHub(async (hub) => {
|
|
291
|
+
if (msg.confirm !== true)
|
|
292
|
+
throw new Error("Entity deletion requires confirm: true");
|
|
293
|
+
validateEntityReference(msg.entityType, msg.entityId);
|
|
294
|
+
const deleted = hub.vault.deleteEntity(msg.entityType, msg.entityId);
|
|
295
|
+
const derivations = await hub.registry.retryDerivations({ limit: 1000 });
|
|
296
|
+
return { deleted, derivations };
|
|
297
|
+
}),
|
|
298
|
+
|
|
253
299
|
// Per-adapter readiness ("能否采集 + 不能的原因"). Probes each adapter's
|
|
254
300
|
// authenticate({ readinessOnly: true }) — see AdapterRegistry.readiness().
|
|
255
301
|
// The web-shell PersonalDataHub view renders this as a 就绪状态 column so
|
package/src/lib/audit-logger.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import crypto from "crypto";
|
|
7
7
|
import { safeJsonParse } from "./safe-json.js";
|
|
8
8
|
import { escapeLike } from "./sql-like.js";
|
|
9
|
+
import { sanitizeAuditDetails } from "./audit-sanitizer.js";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Event types for audit logging.
|
|
@@ -112,29 +113,15 @@ export function assessRisk(eventType, operation, details) {
|
|
|
112
113
|
* Sanitize sensitive data from log details.
|
|
113
114
|
*/
|
|
114
115
|
export function sanitizeDetails(details) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const sanitized = { ...details };
|
|
118
|
-
const sensitiveKeys = [
|
|
119
|
-
"password",
|
|
120
|
-
"secret",
|
|
121
|
-
"secretKey",
|
|
122
|
-
"secret_key",
|
|
123
|
-
"privateKey",
|
|
124
|
-
"private_key",
|
|
125
|
-
"token",
|
|
126
|
-
"apiKey",
|
|
127
|
-
"api_key",
|
|
128
|
-
"mnemonic",
|
|
129
|
-
];
|
|
130
|
-
|
|
131
|
-
for (const key of sensitiveKeys) {
|
|
132
|
-
if (sanitized[key]) {
|
|
133
|
-
sanitized[key] = "[REDACTED]";
|
|
134
|
-
}
|
|
135
|
-
}
|
|
116
|
+
return sanitizeAuditDetails(details);
|
|
117
|
+
}
|
|
136
118
|
|
|
137
|
-
|
|
119
|
+
function sanitizeErrorMessage(value) {
|
|
120
|
+
const sanitized = sanitizeDetails(value);
|
|
121
|
+
if (sanitized == null) return null;
|
|
122
|
+
return typeof sanitized === "object"
|
|
123
|
+
? JSON.stringify(sanitized)
|
|
124
|
+
: String(sanitized);
|
|
138
125
|
}
|
|
139
126
|
|
|
140
127
|
/**
|
|
@@ -146,8 +133,7 @@ export function logEvent(db, event) {
|
|
|
146
133
|
const id = crypto.randomUUID();
|
|
147
134
|
const sanitized = sanitizeDetails(event.details);
|
|
148
135
|
const risk =
|
|
149
|
-
event.riskLevel ||
|
|
150
|
-
assessRisk(event.eventType, event.operation, event.details);
|
|
136
|
+
event.riskLevel || assessRisk(event.eventType, event.operation, sanitized);
|
|
151
137
|
|
|
152
138
|
db.prepare(
|
|
153
139
|
`INSERT INTO audit_log (id, event_type, operation, actor, target, details, risk_level, ip_address, user_agent, success, error_message)
|
|
@@ -158,12 +144,12 @@ export function logEvent(db, event) {
|
|
|
158
144
|
event.operation || "unknown",
|
|
159
145
|
event.actor || null,
|
|
160
146
|
event.target || null,
|
|
161
|
-
sanitized ? JSON.stringify(sanitized)
|
|
147
|
+
sanitized == null ? null : JSON.stringify(sanitized),
|
|
162
148
|
risk,
|
|
163
149
|
event.ipAddress || null,
|
|
164
150
|
event.userAgent || null,
|
|
165
151
|
event.success !== false ? 1 : 0,
|
|
166
|
-
event.errorMessage
|
|
152
|
+
sanitizeErrorMessage(event.errorMessage),
|
|
167
153
|
);
|
|
168
154
|
|
|
169
155
|
return { id, riskLevel: risk, createdAt: new Date().toISOString() };
|
|
@@ -516,7 +502,8 @@ export function logEventV2(
|
|
|
516
502
|
if (_logStatesV2.has(logId)) {
|
|
517
503
|
throw new Error(`Log already registered: ${logId}`);
|
|
518
504
|
}
|
|
519
|
-
const
|
|
505
|
+
const sanitized = sanitizeDetails(details);
|
|
506
|
+
const risk = riskLevel || assessRisk(eventType, operation, sanitized);
|
|
520
507
|
if (!RISK_LEVELS_V2.includes(risk)) {
|
|
521
508
|
throw new Error(`Invalid riskLevel: ${risk}`);
|
|
522
509
|
}
|
|
@@ -527,12 +514,12 @@ export function logEventV2(
|
|
|
527
514
|
operation,
|
|
528
515
|
actor: actor || null,
|
|
529
516
|
target: target || null,
|
|
530
|
-
details:
|
|
517
|
+
details: sanitized ?? null,
|
|
531
518
|
riskLevel: risk,
|
|
532
519
|
ipAddress: ipAddress || null,
|
|
533
520
|
userAgent: userAgent || null,
|
|
534
521
|
success: success !== false,
|
|
535
|
-
errorMessage: errorMessage
|
|
522
|
+
errorMessage: sanitizeErrorMessage(errorMessage),
|
|
536
523
|
status: LOG_STATUS_V2.ACTIVE,
|
|
537
524
|
integrityStatus: INTEGRITY_STATUS_V2.UNVERIFIED,
|
|
538
525
|
prevHash: _lastChainHash,
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-safe audit details. Limits apply before string processing and while
|
|
3
|
+
* traversing; getters and user-provided toJSON methods are never invoked.
|
|
4
|
+
* This is field/credential redaction, not detection of arbitrary secrets in prose.
|
|
5
|
+
*/
|
|
6
|
+
const REDACTED = "[REDACTED]";
|
|
7
|
+
const TRUNCATED = "[Truncated]";
|
|
8
|
+
const LIMITS = Object.freeze({
|
|
9
|
+
depth: 8,
|
|
10
|
+
entries: 100,
|
|
11
|
+
nodes: 512,
|
|
12
|
+
stringLength: 4096,
|
|
13
|
+
keyLength: 256,
|
|
14
|
+
totalCharacters: 16384,
|
|
15
|
+
serializedBytes: 65536,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const SENSITIVE_KEYS = new Set([
|
|
19
|
+
"password",
|
|
20
|
+
"passwd",
|
|
21
|
+
"pwd",
|
|
22
|
+
"passphrase",
|
|
23
|
+
"secret",
|
|
24
|
+
"secretkey",
|
|
25
|
+
"privatekey",
|
|
26
|
+
"apikey",
|
|
27
|
+
"token",
|
|
28
|
+
"authorization",
|
|
29
|
+
"proxyauthorization",
|
|
30
|
+
"cookie",
|
|
31
|
+
"setcookie",
|
|
32
|
+
"mnemonic",
|
|
33
|
+
"seedphrase",
|
|
34
|
+
"credentials",
|
|
35
|
+
"credential",
|
|
36
|
+
"encryptionkey",
|
|
37
|
+
"signingkey",
|
|
38
|
+
"sessionid",
|
|
39
|
+
"auth",
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
function normalizeKey(key) {
|
|
43
|
+
return key.toLowerCase().replace(/[\s_.-]/g, "");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isSensitiveKey(key) {
|
|
47
|
+
const normalized = normalizeKey(key);
|
|
48
|
+
return (
|
|
49
|
+
SENSITIVE_KEYS.has(normalized) ||
|
|
50
|
+
/(?:password|secret|privatekey|apikey|token)$/.test(normalized)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isSensitiveQueryKey(key) {
|
|
55
|
+
return isSensitiveKey(key) || /^(?:key|code|sig|signature)$/i.test(key);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function sanitizeUrl(text) {
|
|
59
|
+
try {
|
|
60
|
+
const url = new URL(text);
|
|
61
|
+
if (url.username || url.password) {
|
|
62
|
+
url.username = REDACTED;
|
|
63
|
+
url.password = "";
|
|
64
|
+
}
|
|
65
|
+
const params = new URLSearchParams();
|
|
66
|
+
for (const [key, value] of url.searchParams) {
|
|
67
|
+
params.append(key, isSensitiveQueryKey(key) ? REDACTED : value);
|
|
68
|
+
}
|
|
69
|
+
url.search = params.toString();
|
|
70
|
+
// OAuth implicit responses put credentials in the fragment instead of query.
|
|
71
|
+
if (url.hash.includes("=")) {
|
|
72
|
+
const fragment = new URLSearchParams(url.hash.slice(1));
|
|
73
|
+
const sanitized = new URLSearchParams();
|
|
74
|
+
for (const [key, value] of fragment) {
|
|
75
|
+
sanitized.append(key, isSensitiveQueryKey(key) ? REDACTED : value);
|
|
76
|
+
}
|
|
77
|
+
url.hash = sanitized.toString();
|
|
78
|
+
}
|
|
79
|
+
return url.toString();
|
|
80
|
+
} catch {
|
|
81
|
+
return "[REDACTED URL]";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function sanitizeString(value) {
|
|
86
|
+
// Drop oversized strings whole: slicing can expose half of a credential.
|
|
87
|
+
if (value.length > LIMITS.stringLength) return TRUNCATED;
|
|
88
|
+
return value
|
|
89
|
+
.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s<>"'`]+/gi, sanitizeUrl)
|
|
90
|
+
.replace(/\b(?:Bearer|Basic)\s+[a-z0-9._~+/=-]+/gi, REDACTED)
|
|
91
|
+
.replace(
|
|
92
|
+
/\b((?:proxy[-_ ]?)?authorization|(?:set[-_ ]?)?cookie)\s*:\s*[^\r\n]+/gi,
|
|
93
|
+
"$1: [REDACTED]",
|
|
94
|
+
)
|
|
95
|
+
.replace(
|
|
96
|
+
/\b((?:[a-z0-9_.-]{0,64})?(?:password|secret|private[-_.]?key|api[-_.]?key|token)|passwd|pwd|passphrase|mnemonic|seed[-_.]?phrase|credentials?|encryption[-_.]?key|signing[-_.]?key|session[-_.]?id|auth|(?:proxy[-_.]?)?authorization|(?:set[-_.]?)?cookie)(["']?\s*[=:]\s*)("(?:\\.|[^"\\\r\n])*"|'(?:\\.|[^'\\\r\n])*'|[^\s&,;"']+)/gi,
|
|
97
|
+
(_match, key, separator, value) => {
|
|
98
|
+
const quote = value[0] === '"' || value[0] === "'" ? value[0] : "";
|
|
99
|
+
return `${key}${separator}${quote}${REDACTED}${quote}`;
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function readDataProperty(value, key) {
|
|
105
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
106
|
+
return descriptor && "value" in descriptor
|
|
107
|
+
? descriptor.value
|
|
108
|
+
: "[Accessor omitted]";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function errorName(value) {
|
|
112
|
+
let prototype = value;
|
|
113
|
+
for (let i = 0; prototype && i < LIMITS.depth; i += 1) {
|
|
114
|
+
if (Object.hasOwn(prototype, "name")) {
|
|
115
|
+
const name = readDataProperty(prototype, "name");
|
|
116
|
+
return typeof name === "string" ? name : "Error";
|
|
117
|
+
}
|
|
118
|
+
prototype = Object.getPrototypeOf(prototype);
|
|
119
|
+
}
|
|
120
|
+
return "Error";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function setDataProperty(target, key, value) {
|
|
124
|
+
// Defining __proto__ as data cannot mutate the output object's prototype.
|
|
125
|
+
Object.defineProperty(target, key, {
|
|
126
|
+
value,
|
|
127
|
+
enumerable: true,
|
|
128
|
+
configurable: true,
|
|
129
|
+
writable: true,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function sanitizeAuditDetails(details) {
|
|
134
|
+
const ancestors = new WeakSet();
|
|
135
|
+
let remainingNodes = LIMITS.nodes;
|
|
136
|
+
let remainingCharacters = LIMITS.totalCharacters;
|
|
137
|
+
|
|
138
|
+
function text(value) {
|
|
139
|
+
const sanitized = sanitizeString(value);
|
|
140
|
+
if (sanitized.length > remainingCharacters) return TRUNCATED;
|
|
141
|
+
remainingCharacters -= sanitized.length;
|
|
142
|
+
return sanitized;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function visit(value, depth = 0, context = "") {
|
|
146
|
+
if (remainingNodes-- <= 0) return TRUNCATED;
|
|
147
|
+
if (value === null || value === undefined) return value;
|
|
148
|
+
if (typeof value === "string") return text(value);
|
|
149
|
+
if (typeof value === "bigint") return text(value.toString());
|
|
150
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
151
|
+
if (typeof value === "boolean") return value;
|
|
152
|
+
if (typeof value === "function") return "[Function omitted]";
|
|
153
|
+
if (typeof value === "symbol") return "[Symbol omitted]";
|
|
154
|
+
if (depth >= LIMITS.depth) return TRUNCATED;
|
|
155
|
+
if (ancestors.has(value)) return "[Circular Reference]";
|
|
156
|
+
ancestors.add(value);
|
|
157
|
+
try {
|
|
158
|
+
if (value instanceof Date) {
|
|
159
|
+
return text(Date.prototype.toISOString.call(value));
|
|
160
|
+
}
|
|
161
|
+
if (value instanceof URL) {
|
|
162
|
+
return text(URL.prototype.toString.call(value));
|
|
163
|
+
}
|
|
164
|
+
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
165
|
+
return "[Binary omitted]";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Native fetch headers and query objects have no useful enumerable fields.
|
|
169
|
+
if (value instanceof Headers || value instanceof URLSearchParams) {
|
|
170
|
+
const result = {};
|
|
171
|
+
const iterator =
|
|
172
|
+
value instanceof Headers
|
|
173
|
+
? Headers.prototype.entries.call(value)
|
|
174
|
+
: URLSearchParams.prototype.entries.call(value);
|
|
175
|
+
let count = 0;
|
|
176
|
+
for (const [key, item] of iterator) {
|
|
177
|
+
if (count++ >= LIMITS.entries || remainingNodes <= 0) {
|
|
178
|
+
setDataProperty(result, "[Truncated]", true);
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
if (key.length > LIMITS.keyLength) continue;
|
|
182
|
+
setDataProperty(
|
|
183
|
+
result,
|
|
184
|
+
text(key),
|
|
185
|
+
isSensitiveQueryKey(key) ? REDACTED : visit(item, depth + 1),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (Array.isArray(value)) {
|
|
192
|
+
const result = [];
|
|
193
|
+
const isHeaderList = normalizeKey(context).endsWith("headers");
|
|
194
|
+
// Header tuple arrays are commonly returned by fetch/HTTP clients.
|
|
195
|
+
const first = readDataProperty(value, "0");
|
|
196
|
+
const isSensitivePair =
|
|
197
|
+
value.length === 2 &&
|
|
198
|
+
typeof first === "string" &&
|
|
199
|
+
isSensitiveKey(first);
|
|
200
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
201
|
+
if (i >= LIMITS.entries || remainingNodes <= 0) {
|
|
202
|
+
result.push(TRUNCATED);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
const previous =
|
|
206
|
+
i % 2 === 1 && isHeaderList
|
|
207
|
+
? readDataProperty(value, String(i - 1))
|
|
208
|
+
: null;
|
|
209
|
+
const redact =
|
|
210
|
+
(isSensitivePair && i === 1) ||
|
|
211
|
+
(typeof previous === "string" && isSensitiveKey(previous));
|
|
212
|
+
result.push(
|
|
213
|
+
redact
|
|
214
|
+
? REDACTED
|
|
215
|
+
: visit(readDataProperty(value, String(i)), depth + 1, context),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const result = {};
|
|
222
|
+
if (value instanceof Error) {
|
|
223
|
+
setDataProperty(result, "name", text(errorName(value)));
|
|
224
|
+
// message/stack/cause are usually non-enumerable. Do not call getters.
|
|
225
|
+
for (const key of ["name", "message", "stack", "cause"]) {
|
|
226
|
+
if (Object.hasOwn(value, key)) {
|
|
227
|
+
setDataProperty(
|
|
228
|
+
result,
|
|
229
|
+
key,
|
|
230
|
+
visit(readDataProperty(value, key), depth + 1),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
let count = 0;
|
|
236
|
+
const headerName = normalizeKey(context).endsWith("headers")
|
|
237
|
+
? readDataProperty(value, "name")
|
|
238
|
+
: null;
|
|
239
|
+
for (const key in value) {
|
|
240
|
+
if (
|
|
241
|
+
count++ >= LIMITS.entries ||
|
|
242
|
+
remainingNodes <= 0 ||
|
|
243
|
+
remainingCharacters <= 0
|
|
244
|
+
) {
|
|
245
|
+
setDataProperty(result, "[Truncated]", true);
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
249
|
+
if (key.length > LIMITS.keyLength) {
|
|
250
|
+
setDataProperty(result, "[Truncated key]", true);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
setDataProperty(
|
|
254
|
+
result,
|
|
255
|
+
text(key),
|
|
256
|
+
isSensitiveKey(key) ||
|
|
257
|
+
(key === "value" &&
|
|
258
|
+
typeof headerName === "string" &&
|
|
259
|
+
isSensitiveKey(headerName))
|
|
260
|
+
? REDACTED
|
|
261
|
+
: visit(readDataProperty(value, key), depth + 1, key),
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return result;
|
|
265
|
+
} catch {
|
|
266
|
+
// Proxies, invalid native objects, etc. must not break event persistence.
|
|
267
|
+
return "[Unserializable]";
|
|
268
|
+
} finally {
|
|
269
|
+
ancestors.delete(value);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const sanitized = visit(details);
|
|
274
|
+
const serialized = JSON.stringify(sanitized);
|
|
275
|
+
return serialized &&
|
|
276
|
+
Buffer.byteLength(serialized, "utf8") > LIMITS.serializedBytes
|
|
277
|
+
? TRUNCATED
|
|
278
|
+
: sanitized;
|
|
279
|
+
}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
buildAutomationCenterRuntimeProjection,
|
|
19
19
|
} from "./automation-center-runtime.js";
|
|
20
20
|
import {
|
|
21
|
+
AUTOMATION_EXECUTION_CAPABILITY,
|
|
21
22
|
EXECUTION_STATUS,
|
|
22
23
|
FLOW_STATUS,
|
|
23
24
|
TRIGGER_TYPE,
|
|
@@ -117,6 +118,7 @@ function projectExecution(execution) {
|
|
|
117
118
|
return {
|
|
118
119
|
id: execution.id,
|
|
119
120
|
status: execution.status,
|
|
121
|
+
mode: execution.mode,
|
|
120
122
|
triggerType: execution.triggerType || null,
|
|
121
123
|
durationMs: Number(execution.durationMs) || 0,
|
|
122
124
|
startedAt: execution.startedAt || null,
|
|
@@ -213,6 +215,7 @@ function projectFlow(db, flow, { historyLimit, now }) {
|
|
|
213
215
|
history,
|
|
214
216
|
incidents,
|
|
215
217
|
security,
|
|
218
|
+
executionCapability: AUTOMATION_EXECUTION_CAPABILITY,
|
|
216
219
|
};
|
|
217
220
|
const revision = digest(content);
|
|
218
221
|
const active = flow.status === FLOW_STATUS.ACTIVE;
|
|
@@ -225,21 +228,28 @@ function projectFlow(db, flow, { historyLimit, now }) {
|
|
|
225
228
|
actions: [
|
|
226
229
|
action(
|
|
227
230
|
"run_now",
|
|
228
|
-
active && security.ready,
|
|
231
|
+
active && security.ready && AUTOMATION_EXECUTION_CAPABILITY.live,
|
|
229
232
|
!active
|
|
230
233
|
? "flow is not active"
|
|
231
|
-
:
|
|
234
|
+
: !security.ready
|
|
235
|
+
? "permission or budget preflight denied"
|
|
236
|
+
: AUTOMATION_EXECUTION_CAPABILITY.reason,
|
|
232
237
|
flow.id,
|
|
233
238
|
revision,
|
|
234
239
|
),
|
|
235
240
|
action(
|
|
236
241
|
"retry_failed",
|
|
237
|
-
active &&
|
|
242
|
+
active &&
|
|
243
|
+
latestFailed &&
|
|
244
|
+
security.ready &&
|
|
245
|
+
AUTOMATION_EXECUTION_CAPABILITY.live,
|
|
238
246
|
!active
|
|
239
247
|
? "flow is not active"
|
|
240
248
|
: !latestFailed
|
|
241
249
|
? "latest run did not fail"
|
|
242
|
-
:
|
|
250
|
+
: !security.ready
|
|
251
|
+
? "permission or budget preflight denied"
|
|
252
|
+
: AUTOMATION_EXECUTION_CAPABILITY.reason,
|
|
243
253
|
flow.id,
|
|
244
254
|
revision,
|
|
245
255
|
),
|