chainlesschain 0.166.91 → 0.166.92
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 +17 -17
- 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-DgV7xb8F.js → AIOps-C74YzqwJ.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CgANpkKu.js → ActionButton-TFef1hOE.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DnvpX7RB.js → Analytics-CYsWpkkU.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-C2bHccBM.js → AppLayout-CFf9kjwu.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-BIhijC9g.js → Artifacts-TQqa94YO.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CKRjWGdp.js → Audit-B79ayqfS.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CblYtgBE.js → BackgroundAgents-pjkHfLP9.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cq35b78a.js → Backup-CE6A-t_r.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DcB7NoRz.js → BaseInput-CwcgWMBY.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-tc3b-s7i.js → Chat-BIkDNesY.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DgaokYts.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BLD5bH5u.js → Checkbox-MbypIy5V.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BLOsoazN.js → Codegen-DiFHWDnt.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bdr7JwIx.js → Col-BNMlYMso.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C84BsWE0.js → Community-B3HVyHOX.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dzdwd04z.js → Compact-C7hlAubb.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CCG-R0EV.js → Compliance-PaXZu6sE.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BYj72SK0.js → Cowork-BGiojbm-.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B6iKAwOf.js → Cron-Bmr-1QAx.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BJ-oDC6u.js → Crosschain-BwUvWCVd.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BnMckGLr.js → DID-k_4QZocW.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cyje-gCO.js → Dashboard-_ieRo2C5.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BpNlenjK.js → Dropdown-DYHh6T27.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BhonO7Nv.js → EmailListRenderer-BNlQcWQX.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DVoNU-Id.js → EvolutionSettings-DIkZ6U2D.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-tdn-KC67.js → FamilyGuardDashboard-Dq7qSr0P.js} +1 -1
- package/src/assets/web-panel/assets/{Federation--EEVrHhz.js → Federation-C64e3Cbx.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cy8zr0-4.js → FormItemContext-D-GE2vUa.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BuUhpgFi.js → GenericCardRenderer-DO3B2gis.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Ctd3E5Pe.js → Git-0ETirIQH.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Ce7dV6aU.js → Governance-C9fnRygX.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CD1vExIH.js → Inference-CLJ9RTsK.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Dn64OdQ7.js → KnowledgeGraph-D3C_GxrN.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-PmElVRrT.js → Logs-C5ctGbkN.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Ce-eWK3j.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-OW4jTXwx.js → Marketplace-GF_t6hJ_.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BEq2Ib4x.js → McpTools-BGsGzgQs.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Can_P2oK.js → Memory-CcrY2A0j.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DJ8R-dn3.js → MobileBridge-Bi4T0RlS.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B7kV9GOt.js → MobileProjects-DvjEGyvf.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BfxamolS.js → Mtc-DL77Vf-k.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DHtuv7av.js → MtcAudit-CDy_Uswb.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DLkLpvxc.js → Multisig-DL0BAO_c.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-u4XtJTIt.js → NLProgramming-B-woh5IR.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BwuuPJLS.js → Notes-CEFVCxk7.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-HEeu-E9v.js → NotificationSettings-BqPPMuAP.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BtvN-Qwh.js → OrderTableRenderer-GUKQ1xwp.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Yh-czs3b.js → Organization-B1gX8jlr.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DmE8mYVM.js → Overflow-CeMxuUZy.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWVck8WN.js → P2P-B5aIRWwJ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DgFqekod.js → PdhVaultBrowser-6rYgejd4.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BtJBVOHV.js → Permissions-CqCp2SIl.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-6VBObXzd.js → PersonalDataHub-BsA7DJWW.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-D222FmqY.js → Pipeline-CiW6HeZh.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bi9FMikp.js → Privacy-DckUOLYq.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bo52H47H.js → ProjectInit-CZppOOYR.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BPkesfOc.js → ProjectSettings-B9QPzhDU.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-GynohSFX.js → Projects-BErjjGha.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DVdMg04n.js → Providers-DehU6Qiz.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DqJCb595.js → QrScannerModal-E1SUvv1m.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-J7loQbXi.js → QuickAsk-COWFxyH3.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BI5aURVc.js → Recommend-D26pWKxX.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BN2sqGvz.js → RemoteSession-DCOIaId3.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BGOND-Fi.js → Reputation-DT_AHGAR.js} +1 -1
- package/src/assets/web-panel/assets/{Row-77dfwaUk.js → Row-B50S-1nl.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-FtBAxS3g.js → RssFeed-BaBnHg3Q.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BaYVLFb7.js → Search-BVdnLuuS.js} +1 -1
- package/src/assets/web-panel/assets/{Security-LE3Vv6ab.js → Security-BnacH74J.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5pP-Whz.js → Services-CxM08Zch.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CLqKUVsF.js → Skeleton-DE7CIc1N.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BPjN0SX5.js → Skills-CGI0SJmf.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-14jD70kg.js → Sla-DpEzPcqc.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Dr9ij42W.js → SpeechSettings-CTmnmMHn.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BzLHP7B8.js → SyncSettings-Dxgrd9hd.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-YqV9b0rV.js → Tasks-CW4slS0A.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CxxAE4PK.js → Templates-DxvGWDgB.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CRb3PcKJ.js → Tenant-_Q0o2tNK.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CTzPpBaP.js → Terminal-BTZn8pow.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DjFUj_hy.js → TimelineRenderer-CauL0KFe.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bbb8tPvx.js → Tokens-CDoM2qeT.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CSeWGM0W.js → Trigger-B-QYGEU7.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-JgESMBo3.js → Trust-BD6XJHT-.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CiObLk0T.js → UkeySign-x4TFwCy0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CFEZaQ2x.js → VideoEditing-t3imBK_0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DR8ZGDNn.js → Wallet-BCfkWwNC.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DxZukvu7.js → WebAuthn-WH314Mdm.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CKgSZQwn.js → WorkflowEditor-jUlcjrUg.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTxEQE66.js → chat-Dg3VASTL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CAjKMUu3.js → colors-BNvmBRKE.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BXuz49at.js → compact-item-BGOfoqf4.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CFN_Hwr9.js → createContext-BNQeqKAs.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B7_ypN1G.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BwoSBSfP.js → hasIn-Bg3AjCrq.js} +1 -1
- package/src/assets/web-panel/assets/{index-u9_DM3ZC.js → index--I3UF5t1.js} +1 -1
- package/src/assets/web-panel/assets/{index-IahILygB.js → index-2D04Zltx.js} +3 -3
- package/src/assets/web-panel/assets/{index-Bqv_Cray.js → index-60AnjUTX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSmFby3Q.js → index-7QJUWemf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTX9CJPx.js → index-B--0QM0S.js} +1 -1
- package/src/assets/web-panel/assets/index-B-jSKJK6.js +1 -0
- package/src/assets/web-panel/assets/{index-C8er4W9u.js → index-B0mgngoB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DViK2bkv.js → index-BBCMulQ-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkbAADP.js → index-BSNhW95G.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2tEnBPx.js → index-B_JmInC0.js} +1 -1
- package/src/assets/web-panel/assets/{index-_ZtCyUdz.js → index-BaPvEvB4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN53dE_u.js → index-Bkz1tgFR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj4hIiLW.js → index-BmTacaQV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Tz5dheZa.js → index-CCFZN66A.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv7V2kg6.js → index-COol3xfA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu2P6u8m.js → index-CY8cRKHR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw9s2d3c.js → index-Cbp-wp-U.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9yR7zqr.js → index-Co_LnCWD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK4ftQ4d.js → index-Cx2EXRfr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxunxaTw.js → index-D-mSvCQK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7kp-zRE.js → index-D072oLjp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CB3kVd9c.js → index-D6UqK83L.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF9lWi1o.js → index-DF_FKSVH.js} +1 -1
- package/src/assets/web-panel/assets/{index-IY9bd5az.js → index-DLwEXRrb.js} +1 -1
- package/src/assets/web-panel/assets/{index-F2E5RCwz.js → index-DO0VlNtc.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2o_BBjg.js → index-DS04wRll.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY-gBSm8.js → index-DYn5DnDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0QbLlWn.js → index-D_O2ZjPk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjF5BOZx.js → index-DcCnO0RU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CehdwJ_Q.js → index-Dkp-okWa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmXpdcHI.js → index-OUFoxUgH.js} +1 -1
- package/src/assets/web-panel/assets/index-P4FXZJqI.js +1 -0
- package/src/assets/web-panel/assets/{index-t2Ch_JKn.js → index-Wo0f2iqb.js} +1 -1
- package/src/assets/web-panel/assets/{index-T3MTE6jB.js → index-ZD5Kd8tx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp5y7lX_.js → index-fOwii3LP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cgk0YEiq.js → index-hG7jXGEW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpdDnZX_.js → index-pVdQieac.js} +1 -1
- package/src/assets/web-panel/assets/{index-o9DpkZKf.js → index-uH2LnAs_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmQITjMU.js → index-xzaUx19r.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BoiGJDoO.js → initDefaultProps-B8PN9AxJ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-5eL4E0pA.js → motion-BHivfw5Q.js} +1 -1
- package/src/assets/web-panel/assets/{move-DjggDi_1.js → move-B0QU5nDd.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Ce8Vo2T3.js → mtc-parser-DRwRM3PE.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D1yOBaO2.js → omit-SHt2rV2p.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-8NLceQe8.js → pickAttrs-CcmDlEb2.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CsIdBRmQ.js → placementArrow-DYatmXDS.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-GM5NE8En.js → responsiveObserve-B7qrsXq5.js} +1 -1
- package/src/assets/web-panel/assets/{slide-44yj3u49.js → slide-BRGhlOWd.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B8tqtWcX.js → statusUtils-CT-7NXsQ.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NhDPBbyB.js → styleChecker-rZdw_Yyp.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C8Qz1GtN.js → useFlexGapSupport-D8YNIP4P.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-ClUv4kih.js → useFs-B8pt0Gu-.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BwkOVEh6.js → usePersonalDataHub-VMmYM1tt.js} +1 -1
- package/src/assets/web-panel/assets/{vnode--gMF33R0.js → vnode-UNDuoPoq.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DXg3TqOP.js → zoom-dN-u667S.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +39 -0
- package/src/lib/evolution/evolution-artifact-ports.js +26 -0
- package/src/lib/evolution/evolution-eval-cohort-enrollment.js +713 -47
- package/src/lib/evolution/evolution-eval-gate.js +146 -0
- package/src/lib/evolution/evolution-eval-launch-admission.js +168 -90
- package/src/lib/evolution/evolution-eval-ledger-capture.js +50 -0
- package/src/lib/evolution/evolution-eval-readonly-audit.js +106 -0
- package/src/lib/evolution/evolution-ledger-file-backend.js +20 -0
- package/src/lib/evolution/evolution-ledger-ports.js +59 -27
- package/src/lib/evolution/evolution-ledger-v2-journal.js +55 -18
- package/src/lib/evolution/evolution-workbench-file-resources.js +19 -1
- package/src/lib/evolution/rrsi-cohort-registration.js +275 -0
- package/src/lib/evolution/rrsi-contracts.js +742 -0
- package/src/lib/evolution/rrsi-data.js +196 -0
- package/src/lib/evolution/rrsi-evaluation-adapter.js +275 -0
- package/src/lib/evolution/rrsi-evaluation-variants.js +267 -0
- package/src/lib/evolution/rrsi-group-statistics.js +553 -0
- package/src/lib/evolution/rrsi-history-ledger-adapter.js +3261 -0
- package/src/lib/evolution/rrsi-native-batch-evidence.js +520 -0
- package/src/lib/evolution/rrsi-native-eval-row-collector.js +538 -0
- package/src/lib/evolution/rrsi-native-evaluation-batch.js +547 -0
- package/src/lib/evolution/rrsi-native-evaluation-plan.js +431 -0
- package/src/lib/evolution/rrsi-native-group-statistics-plan.js +121 -0
- package/src/lib/evolution/rrsi-native-group-statistics.js +482 -0
- package/src/lib/evolution/rrsi-native-quality-receipt-contracts.js +321 -0
- package/src/lib/evolution/rrsi-native-quality-receipt.js +256 -0
- package/src/lib/evolution/rrsi-native-statistics-protocol.js +330 -0
- package/src/lib/evolution/rrsi-parent-binding.js +290 -0
- package/src/lib/evolution/rrsi-pm-execution-bridge.js +500 -0
- package/src/lib/evolution/rrsi-pm-training-mapping.js +134 -0
- package/src/lib/evolution/rrsi-preparation-contracts.js +213 -0
- package/src/lib/evolution/rrsi-registry-history-binding.js +193 -0
- package/src/lib/evolution/rrsi-registry-store-policy.js +1191 -0
- package/src/lib/evolution/rrsi-runtime-composition.js +79 -0
- package/src/lib/evolution/rrsi-selector.js +434 -0
- package/src/lib/evolution/rrsi-statistics-simulation.js +354 -0
- package/src/lib/evolution/skill-candidate-registry.js +216 -29
- package/src/lib/evolution/skill-registry-maintenance.js +80 -0
- package/src/lib/evolution/skill-registry-writer-control.js +138 -0
- package/src/lib/evolution/skill-release-registry.js +399 -169
- package/src/lib/formal-quality-eval-runtime.js +2 -14
- package/src/lib/goal-store.js +225 -16
- package/src/lib/record-replay/skill-recorder.js +38 -3
- package/src/lib/scheduler-kernel/authority-resolver.js +12 -163
- package/src/lib/scheduler-kernel/contract.js +27 -414
- package/src/lib/scheduler-kernel/runtime.js +21 -823
- package/src/lib/scheduler-kernel/service.js +11 -328
- package/src/lib/scheduler-kernel/source-locator-path.js +7 -142
- package/src/lib/scheduler-kernel/store.js +67 -5931
- package/src/lib/secure-fs.js +16 -1314
- package/src/lib/with-file-lock.js +122 -20
- package/src/assets/web-panel/assets/ChatBubbleRenderer-fcc_Tvqu.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BFiVKf5t.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +0 -1
- package/src/assets/web-panel/assets/index-CCsRfd0k.js +0 -1
- package/src/assets/web-panel/assets/index-CsmiZIQ4.js +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isFormalQualityHermeticRuntime } from "@chainlesschain/session-core/host-storage-environment";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import os from "node:os";
|
|
@@ -23,20 +24,7 @@ export const FORMAL_QUALITY_FILE_TOOLS = Object.freeze([
|
|
|
23
24
|
* headless boundary through a launcher-only environment marker. Keep the
|
|
24
25
|
* check exact so inherited or malformed values never change normal CLI runs.
|
|
25
26
|
*/
|
|
26
|
-
export
|
|
27
|
-
if (environment?.[FORMAL_QUALITY_HERMETIC_ENV] !== "1") return false;
|
|
28
|
-
const configuredHome = String(environment?.CHAINLESSCHAIN_HOME || "").trim();
|
|
29
|
-
if (!configuredHome) return false;
|
|
30
|
-
const temporaryRoot = path.resolve(os.tmpdir());
|
|
31
|
-
const resolvedHome = path.resolve(configuredHome);
|
|
32
|
-
const relation = path.relative(temporaryRoot, resolvedHome);
|
|
33
|
-
return Boolean(
|
|
34
|
-
relation &&
|
|
35
|
-
relation !== ".." &&
|
|
36
|
-
!relation.startsWith(`..${path.sep}`) &&
|
|
37
|
-
!path.isAbsolute(relation),
|
|
38
|
-
);
|
|
39
|
-
}
|
|
27
|
+
export { isFormalQualityHermeticRuntime };
|
|
40
28
|
|
|
41
29
|
function formalQualityIsolationRoot(environment) {
|
|
42
30
|
if (!isFormalQualityHermeticRuntime(environment)) return null;
|
package/src/lib/goal-store.js
CHANGED
|
@@ -18,8 +18,15 @@
|
|
|
18
18
|
|
|
19
19
|
import fs from "node:fs";
|
|
20
20
|
import path from "node:path";
|
|
21
|
+
import { createHash } from "node:crypto";
|
|
21
22
|
import { getHomeDir } from "./paths.js";
|
|
22
23
|
import { withFileLock } from "./with-file-lock.js";
|
|
24
|
+
import {
|
|
25
|
+
createGoalRecord,
|
|
26
|
+
validateGoalRecord,
|
|
27
|
+
upgradeLegacyGoal,
|
|
28
|
+
goalError,
|
|
29
|
+
} from "@chainlesschain/session-core/goal-contract";
|
|
23
30
|
|
|
24
31
|
/** Valid goal lifecycle states. `active` goals are the ones injected. */
|
|
25
32
|
export const GOAL_STATUS = Object.freeze({
|
|
@@ -35,6 +42,25 @@ function defaultRoot() {
|
|
|
35
42
|
return path.join(getHomeDir(), "goals");
|
|
36
43
|
}
|
|
37
44
|
|
|
45
|
+
/** Store identity is path-bound metadata, not filesystem authorization. */
|
|
46
|
+
export function goalFileStoreId(root = defaultRoot()) {
|
|
47
|
+
const resolved = path.resolve(root);
|
|
48
|
+
const canonical =
|
|
49
|
+
process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
50
|
+
return `cli-goals-${createHash("sha256").update(canonical).digest("hex")}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function fileRecord(value, root) {
|
|
54
|
+
const record = upgradeLegacyGoal(value, goalFileStoreId(root));
|
|
55
|
+
if (record.storeId !== goalFileStoreId(root))
|
|
56
|
+
throw goalError("GOAL_STORE_MISMATCH");
|
|
57
|
+
// Files are the legacy standalone CLI store. Project authority lives in the
|
|
58
|
+
// host database and must not be acquired by copying a record into this dir.
|
|
59
|
+
if (record.ownerRef !== null || record.projectRef !== null)
|
|
60
|
+
throw goalError("GOAL_PROJECT_STORE_REQUIRED");
|
|
61
|
+
return record;
|
|
62
|
+
}
|
|
63
|
+
|
|
38
64
|
function ensureDir(dir) {
|
|
39
65
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
40
66
|
}
|
|
@@ -83,6 +109,7 @@ function isUnsafeGoalId(id) {
|
|
|
83
109
|
id == null ||
|
|
84
110
|
id === "" ||
|
|
85
111
|
typeof id !== "string" ||
|
|
112
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/u.test(id) ||
|
|
86
113
|
id.includes("/") ||
|
|
87
114
|
id.includes("\\") ||
|
|
88
115
|
id.includes("..")
|
|
@@ -133,17 +160,15 @@ export function createGoal(input = {}, opts = {}) {
|
|
|
133
160
|
}
|
|
134
161
|
const keyResults = (input.keyResults || []).map((kr) => normalizeKr(kr));
|
|
135
162
|
const goal = {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
163
|
+
...createGoalRecord({
|
|
164
|
+
id,
|
|
165
|
+
storeId: goalFileStoreId(root),
|
|
166
|
+
title: String(input.title || objective).trim(),
|
|
167
|
+
objective,
|
|
168
|
+
keyResults,
|
|
169
|
+
createdAt: nowIso(),
|
|
170
|
+
}),
|
|
141
171
|
progress: derivedProgress(keyResults) ?? 0,
|
|
142
|
-
linkedSessions: [],
|
|
143
|
-
notes: [],
|
|
144
|
-
drift: { lastProgressAt: null, flags: [] },
|
|
145
|
-
createdAt: nowIso(),
|
|
146
|
-
updatedAt: nowIso(),
|
|
147
172
|
};
|
|
148
173
|
ensureDir(root);
|
|
149
174
|
const file = goalFile(root, id);
|
|
@@ -186,21 +211,42 @@ export function getGoal(id, opts = {}) {
|
|
|
186
211
|
const file = goalFile(root, id);
|
|
187
212
|
if (!fs.existsSync(file)) return null;
|
|
188
213
|
try {
|
|
189
|
-
|
|
214
|
+
const value = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
215
|
+
if (value?.id !== id) return null;
|
|
216
|
+
if (Object.hasOwn(value, "schema") || Object.hasOwn(value, "schemaVersion"))
|
|
217
|
+
fileRecord(value, root);
|
|
218
|
+
return value;
|
|
190
219
|
} catch {
|
|
191
220
|
return null;
|
|
192
221
|
}
|
|
193
222
|
}
|
|
194
223
|
|
|
195
|
-
function saveGoal(goal, opts = {}) {
|
|
224
|
+
function saveGoal(goal, opts = {}, before = null) {
|
|
196
225
|
if (isUnsafeGoalId(goal && goal.id)) {
|
|
197
226
|
throw new Error(`非法 goal id: ${String(goal && goal.id).slice(0, 60)}`);
|
|
198
227
|
}
|
|
199
228
|
const root = opts.root || defaultRoot();
|
|
200
229
|
ensureDir(root);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
230
|
+
const previous = before || fileRecord(goal, root);
|
|
231
|
+
const migrated = goal.schema ? goal : { ...fileRecord(goal, root) };
|
|
232
|
+
if (previous.completion !== null && migrated.status === "done")
|
|
233
|
+
throw goalError("GOAL_TERMINAL_REVISION_DENIED");
|
|
234
|
+
const controls = ["status", "objective", "keyResults"];
|
|
235
|
+
const changedControl = controls.some(
|
|
236
|
+
(key) => JSON.stringify(previous[key]) !== JSON.stringify(migrated[key]),
|
|
237
|
+
);
|
|
238
|
+
const saved = fileRecord(
|
|
239
|
+
{
|
|
240
|
+
...migrated,
|
|
241
|
+
revision: previous.revision + 1,
|
|
242
|
+
controlGeneration: previous.controlGeneration + (changedControl ? 1 : 0),
|
|
243
|
+
completion: null,
|
|
244
|
+
updatedAt: nowIso(),
|
|
245
|
+
},
|
|
246
|
+
root,
|
|
247
|
+
);
|
|
248
|
+
atomicWriteFileSync(goalFile(root, goal.id), JSON.stringify(saved, null, 2));
|
|
249
|
+
return saved;
|
|
204
250
|
}
|
|
205
251
|
|
|
206
252
|
/** List goals, newest first. Optionally filter by status. */
|
|
@@ -233,8 +279,64 @@ function mutate(id, fn, opts = {}) {
|
|
|
233
279
|
() => {
|
|
234
280
|
const goal = getGoal(id, opts);
|
|
235
281
|
if (!goal) throw new Error(`no such goal: ${id}`);
|
|
282
|
+
let before;
|
|
283
|
+
try {
|
|
284
|
+
before = fileRecord(goal, root);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
// Older CLI records had unbounded notes/strings. Preserve their full
|
|
287
|
+
// history and existing controls if the bounded contract cannot accept
|
|
288
|
+
// them. This fallback is never available to a versioned record.
|
|
289
|
+
if (
|
|
290
|
+
Object.hasOwn(goal, "schema") ||
|
|
291
|
+
Object.hasOwn(goal, "schemaVersion") ||
|
|
292
|
+
![
|
|
293
|
+
"GOAL_INVALID_ARRAY",
|
|
294
|
+
"GOAL_INVALID_TEXT",
|
|
295
|
+
"GOAL_INVALID_JSON",
|
|
296
|
+
].includes(error.code)
|
|
297
|
+
)
|
|
298
|
+
throw error;
|
|
299
|
+
const revision = goal.revision ?? 1;
|
|
300
|
+
const generation = goal.controlGeneration ?? 0;
|
|
301
|
+
if (
|
|
302
|
+
!Number.isSafeInteger(revision) ||
|
|
303
|
+
revision < 1 ||
|
|
304
|
+
!Number.isSafeInteger(generation) ||
|
|
305
|
+
generation < 0 ||
|
|
306
|
+
!Number.isSafeInteger(revision + 1) ||
|
|
307
|
+
!Number.isSafeInteger(generation + 1)
|
|
308
|
+
)
|
|
309
|
+
throw goalError("GOAL_INVALID_REVISION");
|
|
310
|
+
if (
|
|
311
|
+
opts.expectedRevision !== undefined &&
|
|
312
|
+
opts.expectedRevision !== revision
|
|
313
|
+
)
|
|
314
|
+
throw goalError("GOAL_REVISION_CONFLICT");
|
|
315
|
+
const controls = JSON.stringify([
|
|
316
|
+
goal.status,
|
|
317
|
+
goal.objective,
|
|
318
|
+
goal.keyResults,
|
|
319
|
+
]);
|
|
320
|
+
fn(goal);
|
|
321
|
+
goal.revision = revision + 1;
|
|
322
|
+
goal.controlGeneration =
|
|
323
|
+
generation +
|
|
324
|
+
(controls !==
|
|
325
|
+
JSON.stringify([goal.status, goal.objective, goal.keyResults])
|
|
326
|
+
? 1
|
|
327
|
+
: 0);
|
|
328
|
+
goal.updatedAt = nowIso();
|
|
329
|
+
atomicWriteFileSync(goalFile(root, id), JSON.stringify(goal, null, 2));
|
|
330
|
+
return goal;
|
|
331
|
+
}
|
|
332
|
+
if (
|
|
333
|
+
opts.expectedRevision !== undefined &&
|
|
334
|
+
(!Number.isSafeInteger(opts.expectedRevision) ||
|
|
335
|
+
opts.expectedRevision !== before.revision)
|
|
336
|
+
)
|
|
337
|
+
throw goalError("GOAL_REVISION_CONFLICT");
|
|
236
338
|
fn(goal);
|
|
237
|
-
return saveGoal(goal, opts);
|
|
339
|
+
return saveGoal(goal, opts, before);
|
|
238
340
|
},
|
|
239
341
|
{ failIfUnavailable: true },
|
|
240
342
|
);
|
|
@@ -385,6 +487,15 @@ export function deleteGoal(id, opts = {}) {
|
|
|
385
487
|
file,
|
|
386
488
|
() => {
|
|
387
489
|
if (!fs.existsSync(file)) return false;
|
|
490
|
+
if (opts.expectedRevision !== undefined) {
|
|
491
|
+
const current = getGoal(id, { root });
|
|
492
|
+
if (
|
|
493
|
+
!current ||
|
|
494
|
+
!Number.isSafeInteger(opts.expectedRevision) ||
|
|
495
|
+
opts.expectedRevision !== (current.revision ?? 1)
|
|
496
|
+
)
|
|
497
|
+
throw goalError("GOAL_REVISION_CONFLICT");
|
|
498
|
+
}
|
|
388
499
|
fs.rmSync(file);
|
|
389
500
|
return true;
|
|
390
501
|
},
|
|
@@ -419,3 +530,101 @@ export function resolveActiveGoal(sel = {}, opts = {}) {
|
|
|
419
530
|
// Ambiguous (multiple active, none linked) — caller must pick explicitly.
|
|
420
531
|
return null;
|
|
421
532
|
}
|
|
533
|
+
|
|
534
|
+
/** Injectable repository adapter using the same files/strict locks as cc goal.
|
|
535
|
+
* Reading a legacy file upgrades the returned view only; it never rewrites the
|
|
536
|
+
* file, binds an owner or enables scheduling. */
|
|
537
|
+
export function createGoalFileAdapter(opts = {}) {
|
|
538
|
+
const root = opts.root || defaultRoot();
|
|
539
|
+
const storeId = goalFileStoreId(root);
|
|
540
|
+
function read(id) {
|
|
541
|
+
if (isUnsafeGoalId(id)) throw goalError("GOAL_INVALID_ID");
|
|
542
|
+
const file = goalFile(root, id);
|
|
543
|
+
if (!fs.existsSync(file)) return null;
|
|
544
|
+
let value;
|
|
545
|
+
try {
|
|
546
|
+
value = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
547
|
+
} catch {
|
|
548
|
+
throw goalError("GOAL_RECORD_CORRUPT");
|
|
549
|
+
}
|
|
550
|
+
const record = fileRecord(value, root);
|
|
551
|
+
if (record.id !== id) throw goalError("GOAL_RECORD_CORRUPT");
|
|
552
|
+
return record;
|
|
553
|
+
}
|
|
554
|
+
return Object.freeze({
|
|
555
|
+
storeId,
|
|
556
|
+
get: read,
|
|
557
|
+
create(value) {
|
|
558
|
+
const record = fileRecord(value, root);
|
|
559
|
+
if (isUnsafeGoalId(record.id)) throw goalError("GOAL_INVALID_ID");
|
|
560
|
+
if (
|
|
561
|
+
record.revision !== 1 ||
|
|
562
|
+
record.controlGeneration !== 0 ||
|
|
563
|
+
record.status !== "active"
|
|
564
|
+
)
|
|
565
|
+
throw goalError("GOAL_INVALID_INITIAL_STATE");
|
|
566
|
+
ensureDir(root);
|
|
567
|
+
return withFileLock(
|
|
568
|
+
goalFile(root, record.id),
|
|
569
|
+
() => {
|
|
570
|
+
if (fs.existsSync(goalFile(root, record.id)))
|
|
571
|
+
throw goalError("GOAL_ALREADY_EXISTS");
|
|
572
|
+
atomicWriteFileSync(
|
|
573
|
+
goalFile(root, record.id),
|
|
574
|
+
JSON.stringify(record, null, 2),
|
|
575
|
+
);
|
|
576
|
+
return record;
|
|
577
|
+
},
|
|
578
|
+
{ failIfUnavailable: true },
|
|
579
|
+
);
|
|
580
|
+
},
|
|
581
|
+
compareAndSwap(id, expectedRevision, transform) {
|
|
582
|
+
if (isUnsafeGoalId(id)) throw goalError("GOAL_INVALID_ID");
|
|
583
|
+
if (
|
|
584
|
+
!Number.isSafeInteger(expectedRevision) ||
|
|
585
|
+
expectedRevision < 1 ||
|
|
586
|
+
typeof transform !== "function"
|
|
587
|
+
)
|
|
588
|
+
throw goalError("GOAL_INVALID_REVISION");
|
|
589
|
+
if (!fs.existsSync(goalFile(root, id)))
|
|
590
|
+
throw goalError("GOAL_NOT_FOUND_OR_DENIED");
|
|
591
|
+
return withFileLock(
|
|
592
|
+
goalFile(root, id),
|
|
593
|
+
() => {
|
|
594
|
+
const current = read(id);
|
|
595
|
+
if (current === null) throw goalError("GOAL_NOT_FOUND_OR_DENIED");
|
|
596
|
+
if (current.revision !== expectedRevision)
|
|
597
|
+
throw goalError("GOAL_REVISION_CONFLICT");
|
|
598
|
+
const next = fileRecord(validateGoalRecord(transform(current)), root);
|
|
599
|
+
if (
|
|
600
|
+
next.id !== id ||
|
|
601
|
+
next.revision !== current.revision + 1 ||
|
|
602
|
+
next.controlGeneration < current.controlGeneration
|
|
603
|
+
)
|
|
604
|
+
throw goalError("GOAL_INVALID_REPLACEMENT");
|
|
605
|
+
atomicWriteFileSync(
|
|
606
|
+
goalFile(root, id),
|
|
607
|
+
JSON.stringify(next, null, 2),
|
|
608
|
+
);
|
|
609
|
+
return next;
|
|
610
|
+
},
|
|
611
|
+
{ failIfUnavailable: true },
|
|
612
|
+
);
|
|
613
|
+
},
|
|
614
|
+
list({ status } = {}) {
|
|
615
|
+
if (status !== undefined && !STATUS_VALUES.has(status))
|
|
616
|
+
throw goalError("GOAL_INVALID_STATUS");
|
|
617
|
+
if (!fs.existsSync(root)) return [];
|
|
618
|
+
return fs
|
|
619
|
+
.readdirSync(root)
|
|
620
|
+
.filter((name) => name.endsWith(".json"))
|
|
621
|
+
.map((name) => read(name.slice(0, -5)))
|
|
622
|
+
.filter(
|
|
623
|
+
(record) =>
|
|
624
|
+
record !== null &&
|
|
625
|
+
(status === undefined || record.status === status),
|
|
626
|
+
)
|
|
627
|
+
.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
}
|
|
@@ -26,6 +26,7 @@ const VOLATILE_PATTERNS = Object.freeze([
|
|
|
26
26
|
/(?:^|[\\/])(?:tmp|temp)(?:[\\/]|$)/iu,
|
|
27
27
|
]);
|
|
28
28
|
const PARAMETER_PATTERN = /^\$\{parameter\.([A-Za-z][A-Za-z0-9_]*)\}$/u;
|
|
29
|
+
const SHA256_PATTERN = /^sha256:[a-f0-9]{64}$/u;
|
|
29
30
|
const EMBEDDED_PARAMETER_PATTERN = /\$\{parameter\.([A-Za-z][A-Za-z0-9_]*)\}/gu;
|
|
30
31
|
const DRAFT_SCHEMA = "chainlesschain.recorded-skill-draft/v1";
|
|
31
32
|
const REPORT_SCHEMA = "chainlesschain.recorded-skill-replay/v1";
|
|
@@ -165,6 +166,34 @@ export function scanRecordedValue(value) {
|
|
|
165
166
|
return findings;
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
function scanRecordedContent({ environment, ...content }) {
|
|
170
|
+
const scannedEnvironment = clone(environment);
|
|
171
|
+
const omitDigest = (object, key, nullable = false) => {
|
|
172
|
+
if (!Object.hasOwn(object, key) || (nullable && object[key] === null))
|
|
173
|
+
return;
|
|
174
|
+
if (typeof object[key] !== "string" || !SHA256_PATTERN.test(object[key])) {
|
|
175
|
+
throw recorderError(
|
|
176
|
+
"CC_REPLAY_INVALID_ARGUMENT",
|
|
177
|
+
`recorded browser ${key} must be a canonical SHA-256 digest`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
delete object[key];
|
|
181
|
+
};
|
|
182
|
+
// These exact browser-binding fields contain generated hashes, whose hex
|
|
183
|
+
// digits can accidentally match a phone number. Do not exempt digest-like
|
|
184
|
+
// strings in descriptions, actions or arbitrary environment fields.
|
|
185
|
+
omitDigest(scannedEnvironment, "targetDigest");
|
|
186
|
+
omitDigest(scannedEnvironment, "storageStateDigest", true);
|
|
187
|
+
if (
|
|
188
|
+
scannedEnvironment.networkPolicy &&
|
|
189
|
+
typeof scannedEnvironment.networkPolicy === "object" &&
|
|
190
|
+
!Array.isArray(scannedEnvironment.networkPolicy)
|
|
191
|
+
) {
|
|
192
|
+
omitDigest(scannedEnvironment.networkPolicy, "digest");
|
|
193
|
+
}
|
|
194
|
+
return scanRecordedValue({ ...content, environment: scannedEnvironment });
|
|
195
|
+
}
|
|
196
|
+
|
|
168
197
|
function environmentBinding(environment) {
|
|
169
198
|
const value = canonicalValue(environment || {});
|
|
170
199
|
assertPlainObject(value, "environment");
|
|
@@ -440,8 +469,14 @@ export function validateRecordedSkillDraft(value) {
|
|
|
440
469
|
"recorded skill environment binding was modified",
|
|
441
470
|
);
|
|
442
471
|
}
|
|
443
|
-
|
|
444
|
-
|
|
472
|
+
// The binding digest was recomputed and checked above. Scan the underlying
|
|
473
|
+
// requirements, not the generated digest, just as initial capture does.
|
|
474
|
+
const findings = scanRecordedContent({
|
|
475
|
+
description,
|
|
476
|
+
actions,
|
|
477
|
+
failureConditions,
|
|
478
|
+
environment: environment.requirements,
|
|
479
|
+
});
|
|
445
480
|
if (findings.length > 0) {
|
|
446
481
|
throw recorderError(
|
|
447
482
|
"CC_REPLAY_SENSITIVE_OR_VOLATILE_DATA",
|
|
@@ -689,7 +724,7 @@ export function createRecordedSkillDraft({
|
|
|
689
724
|
clone(actions, "actions"),
|
|
690
725
|
bindings,
|
|
691
726
|
);
|
|
692
|
-
const findings =
|
|
727
|
+
const findings = scanRecordedContent({
|
|
693
728
|
description: safeDescription,
|
|
694
729
|
actions: sanitizedActions,
|
|
695
730
|
environment: safeEnvironment,
|
|
@@ -1,163 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
code,
|
|
14
|
-
message,
|
|
15
|
-
details,
|
|
16
|
-
cause ? { cause } : undefined,
|
|
17
|
-
);
|
|
18
|
-
error.retryable = false;
|
|
19
|
-
return error;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function assertAuthorityStore(store) {
|
|
23
|
-
const methods = [
|
|
24
|
-
"ensureAuthorityPolicy",
|
|
25
|
-
"getAuthorityPolicy",
|
|
26
|
-
"reserveAuthority",
|
|
27
|
-
];
|
|
28
|
-
if (!store || methods.some((method) => typeof store[method] !== "function")) {
|
|
29
|
-
throw authorityError(
|
|
30
|
-
"SCHEDULER_AUTHORITY_STORE_REQUIRED",
|
|
31
|
-
"Scheduler authority resolver requires a compatible scheduler store",
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
return store;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function normalizeUnits(value) {
|
|
38
|
-
if (!Number.isSafeInteger(value) || value < 1) {
|
|
39
|
-
throw authorityError(
|
|
40
|
-
"SCHEDULER_AUTHORITY_UNITS_INVALID",
|
|
41
|
-
"Scheduler authority units must be a positive integer",
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
return value;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function schedulerAuthorityPolicyReference(revision) {
|
|
48
|
-
if (!Number.isSafeInteger(revision) || revision < 1) {
|
|
49
|
-
throw authorityError(
|
|
50
|
-
"SCHEDULER_AUTHORITY_POLICY_INVALID",
|
|
51
|
-
"Scheduler authority policy revision must be a positive integer",
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
return `scheduler-authority:${revision}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function parseSchedulerAuthorityPolicyReference(value) {
|
|
58
|
-
const match = /^scheduler-authority:(\d+)$/u.exec(String(value || ""));
|
|
59
|
-
const revision = match ? Number(match[1]) : NaN;
|
|
60
|
-
return Number.isSafeInteger(revision) && revision > 0 ? revision : null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function bindSchedulerAuthorityPolicy(store, authority, defaults = {}) {
|
|
64
|
-
const compatibleStore = assertAuthorityStore(store);
|
|
65
|
-
const normalized = normalizeAuthorityEnvelope(authority);
|
|
66
|
-
const policy = compatibleStore.ensureAuthorityPolicy(normalized, {
|
|
67
|
-
windowMs: defaults.windowMs ?? DEFAULT_SCHEDULER_AUTHORITY_WINDOW_MS,
|
|
68
|
-
maxRuns: defaults.maxRuns ?? DEFAULT_SCHEDULER_AUTHORITY_MAX_RUNS,
|
|
69
|
-
maxUnits: defaults.maxUnits ?? DEFAULT_SCHEDULER_AUTHORITY_MAX_UNITS,
|
|
70
|
-
});
|
|
71
|
-
return {
|
|
72
|
-
...normalized,
|
|
73
|
-
authorizationRefs: {
|
|
74
|
-
...normalized.authorizationRefs,
|
|
75
|
-
schedulerPolicyRevision: schedulerAuthorityPolicyReference(
|
|
76
|
-
policy.revision,
|
|
77
|
-
),
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function createSchedulerAuthorityResolver({
|
|
83
|
-
store,
|
|
84
|
-
validate,
|
|
85
|
-
units = () => 1,
|
|
86
|
-
} = {}) {
|
|
87
|
-
const compatibleStore = assertAuthorityStore(store);
|
|
88
|
-
if (typeof validate !== "function") {
|
|
89
|
-
throw authorityError(
|
|
90
|
-
"SCHEDULER_AUTHORITY_VALIDATOR_REQUIRED",
|
|
91
|
-
"Scheduler authority resolver requires a domain validator",
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
if (typeof units !== "function") {
|
|
95
|
-
throw authorityError(
|
|
96
|
-
"SCHEDULER_AUTHORITY_UNITS_REQUIRED",
|
|
97
|
-
"Scheduler authority resolver requires a unit estimator",
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
return async (context) => {
|
|
101
|
-
const domain = await validate(context);
|
|
102
|
-
if (!domain || typeof domain !== "object" || domain.allowed !== true) {
|
|
103
|
-
return {
|
|
104
|
-
allowed: false,
|
|
105
|
-
reason:
|
|
106
|
-
typeof domain?.reason === "string"
|
|
107
|
-
? domain.reason.slice(0, 256)
|
|
108
|
-
: "domain_authority_denied",
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
const authority = normalizeAuthorityEnvelope(
|
|
112
|
-
context?.occurrence?.authority,
|
|
113
|
-
);
|
|
114
|
-
const policy = compatibleStore.getAuthorityPolicy(authority.principal);
|
|
115
|
-
if (!policy || !policy.enabled) {
|
|
116
|
-
return { allowed: false, reason: "scheduler_authority_policy_required" };
|
|
117
|
-
}
|
|
118
|
-
const reference = parseSchedulerAuthorityPolicyReference(
|
|
119
|
-
authority.authorizationRefs.schedulerPolicyRevision,
|
|
120
|
-
);
|
|
121
|
-
if (reference === null) {
|
|
122
|
-
return { allowed: false, reason: "scheduler_authority_policy_unbound" };
|
|
123
|
-
}
|
|
124
|
-
if (reference !== policy.revision) {
|
|
125
|
-
return { allowed: false, reason: "scheduler_authority_policy_stale" };
|
|
126
|
-
}
|
|
127
|
-
const occurrenceId = normalizeIdentifier(
|
|
128
|
-
context?.occurrence?.id,
|
|
129
|
-
"occurrenceId",
|
|
130
|
-
);
|
|
131
|
-
try {
|
|
132
|
-
const requestedUnits = normalizeUnits(await units(context));
|
|
133
|
-
const reservation = compatibleStore.reserveAuthority({
|
|
134
|
-
occurrenceId,
|
|
135
|
-
policyRevision: policy.revision,
|
|
136
|
-
units: requestedUnits,
|
|
137
|
-
});
|
|
138
|
-
return {
|
|
139
|
-
allowed: true,
|
|
140
|
-
reason: "scheduler_authority_reserved",
|
|
141
|
-
policyRevision: policy.revision,
|
|
142
|
-
reservation,
|
|
143
|
-
};
|
|
144
|
-
} catch (cause) {
|
|
145
|
-
if (
|
|
146
|
-
typeof cause?.code === "string" &&
|
|
147
|
-
cause.code.startsWith("SCHEDULER_AUTHORITY_")
|
|
148
|
-
) {
|
|
149
|
-
return {
|
|
150
|
-
allowed: false,
|
|
151
|
-
reason: cause.code.toLowerCase(),
|
|
152
|
-
details: cause.details,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
throw authorityError(
|
|
156
|
-
"SCHEDULER_AUTHORITY_RESOLUTION_FAILED",
|
|
157
|
-
"Scheduler permission and budget resolution failed closed",
|
|
158
|
-
undefined,
|
|
159
|
-
cause,
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
}
|
|
1
|
+
// Shared policy reservations; the CLI retains its public ESM entry.
|
|
2
|
+
import authority from "@chainlesschain/session-core/scheduler-authority-resolver";
|
|
3
|
+
export const {
|
|
4
|
+
DEFAULT_SCHEDULER_AUTHORITY_WINDOW_MS,
|
|
5
|
+
DEFAULT_SCHEDULER_AUTHORITY_MAX_RUNS,
|
|
6
|
+
DEFAULT_SCHEDULER_AUTHORITY_MAX_UNITS,
|
|
7
|
+
schedulerAuthorityPolicyReference,
|
|
8
|
+
parseSchedulerAuthorityPolicyReference,
|
|
9
|
+
bindSchedulerAuthorityPolicy,
|
|
10
|
+
checkSchedulerAuthorityPolicy,
|
|
11
|
+
createSchedulerAuthorityResolver,
|
|
12
|
+
} = authority;
|