chainlesschain 0.166.18 → 0.166.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-CQSBl3hY.js → AIOps-BjMnsUci.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-IQt-vRLt.js → ActionButton-DdYFP03A.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DkHC8O7k.js → Analytics-Bb8TuuK_.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CSti2P2T.js → AppLayout-Kn3TIOtk.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-C57hxn3v.js → Artifacts-4IxpqI_b.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DByLntcf.js → Audit-BOV2caqU.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D1Bd2EOa.js → BackgroundAgents-B86k-ay4.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-VstHzHng.js → Backup-C5_ie1e3.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CLhdexIf.js → BaseInput-xpwg6QCW.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BefC_JZS.js → Chat-CVZOcZau.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DbXMvgmn.js → ChatBubbleRenderer-D8fPYhUu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CEY982vx.js → Checkbox-MKTq3zdP.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Dcm_DTvJ.js → Codegen-JUk3wzep.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C8SSu4KA.js → Col-JPvTA0kC.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BVV9vwRR.js → Community-Tqgl87NQ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-B7c5Vo18.js → Compact-BuAFYBmN.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Tq9jSZ5a.js → Compliance-CXS9WIPZ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BJUjT09Q.js → Cowork-Ds2bFHrr.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CjV9PEaS.js → Cron-C_dV_OeW.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dl7ReL8F.js → Crosschain-BsO6tIRo.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CG8PjWmM.js → DID-rNOFqBac.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CDBM6wmF.js → Dashboard-C2fcKKVY.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-8_55bXTD.js → Dropdown-Y7Ndr0X_.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-D3qOU1Cm.js → EmailListRenderer-DcP_uPmL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bv5oWMZF.js → FamilyGuardDashboard-Cwn3gDzk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-hpZ1xkKd.js → Federation-ClQuOsqb.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BN7GT191.js → FormItemContext-DfwtmlcK.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-PCRhfA7M.js → GenericCardRenderer-zNZhtbC5.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CIlP2vy7.js → Git-BZmdW-G5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-81lgm7YL.js → Governance-CqBk4lEn.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Cs24xMOV.js → Inference-Dbmt3ZXk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CrJLVCZo.js → KnowledgeGraph-hMTH6qf3.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DLyO8RKT.js → Logs-CkiYgiW2.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DBOqijrP.js → MarkdownRenderer-BL1FElXg.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-Dz7AbQZc.js → Marketplace-CbB6wfin.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BM0aFiWv.js → McpTools-BSwiFtte.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-C9SJzENX.js → Memory-B03PeHrz.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BO2HnNRk.js → MobileBridge-CRGrnd-X.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CK_jMz0l.js → MobileProjects-CE_5v2kO.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CfhrJsdO.js → Mtc-Dp11QVx1.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BE2ELxgI.js → MtcAudit-CYu-3JBu.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CgR_E3Jd.js → Multisig-CGyJ0Xl3.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Cw9445_K.js → NLProgramming-CoWi_ov1.js} +1 -1
- package/src/assets/web-panel/assets/Notes-CgU9DDo9.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-DxHVh4uT.js → NotificationSettings-DX4I2b4W.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CwHc15Zs.js +1 -0
- package/src/assets/web-panel/assets/{Organization-pPXJtWo4.js → Organization-oopLO_tk.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-YamdTJwA.js → Overflow-BFVvjMyf.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BvqP53x7.js → P2P-CBy5t-Tk.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Blz1Xn2n.js → PdhVaultBrowser--YWJNsu6.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CgFRQqFJ.js → Permissions-C2dZ8scb.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CFeo3-6O.js → PersonalDataHub-Bs3l7Hlx.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BkaRojEK.js → Pipeline-DEBWbZuD.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BNZEx2Qp.js → Privacy-CjHBb6NU.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-HUBOgEEK.js → ProjectInit-D2WipUz5.js} +2 -2
- package/src/assets/web-panel/assets/ProjectSettings-B6WfnrGB.js +2 -0
- package/src/assets/web-panel/assets/{Projects-Dc517BXp.js → Projects-FF_thRi6.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DTLf8bgj.js → Providers-CCv5M_Dv.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BBNjPszk.js → QrScannerModal-CGthxU54.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DCsHvk3G.js → QuickAsk-CnPmXPFb.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Dpr5YSop.js → Recommend-Df_tGEa9.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DmKnvqGg.js → RemoteSession-Z58N0Loe.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CSRfuurX.js → Reputation-CZTBQ2Vt.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CDj3pQ_w.js → Row-CdK3YpCQ.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DI0a_kNq.js → RssFeed-CFMVT5sb.js} +3 -3
- package/src/assets/web-panel/assets/{Search-jAy7B2nU.js → Search-DrF8RIvD.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CkHTqYhc.js → Security-Ddk2f2DM.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CP-0Nzga.js → Services-CCuK-VOo.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BkF5-p3n.js → Skeleton-DxCpHzeM.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BDu-utDE.js → Skills-t2oTDgcv.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CQvq_2Qb.js → Sla-Df63M9_R.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-T7Ap512g.js → SpeechSettings-l7ox6KuX.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bt-PLvot.js → SyncSettings-COd_tgPp.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-yLEcCogg.js → Tasks-CzDCcrik.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-ByN3fmbr.js → Templates-D-vfxTGA.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DBI7hITH.js → Tenant-BlpT_Gxc.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B77_DlGX.js → Terminal-D5rq52Hg.js} +2 -2
- package/src/assets/web-panel/assets/TimelineRenderer-DdoMndkK.js +1 -0
- package/src/assets/web-panel/assets/{Tokens-BV2N6cR8.js → Tokens-BhgBsI6g.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CjXWGH3p.js → Trigger-DwwzoikZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-uqXIq3WC.js → Trust-HkTpzXFb.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D-6qu4vY.js → UkeySign-D9nk6Ehe.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CxGmx_2e.js → VideoEditing-BKk0rfoy.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DSq7WlAg.js → Wallet-IVWIU_Lq.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CDBiD57O.js → WebAuthn-CFTCpfsG.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Z8f63TSb.js → WorkflowEditor-Dnf4Obif.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B-UZFBjy.js → chat-D2snERdj.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CFk7K-7Q.js → colors-DKEjK1N1.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-X0IVMvgi.js → compact-item-BEDLwQdt.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DWg4j2n6.js → createContext-DA9iW1a0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DyhgpXPf.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CkVCwNNF.js → hasIn-5l2xEcY9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BipwEbTA.js → index-5pW4t1iD.js} +1 -1
- package/src/assets/web-panel/assets/{index-5OcZHdzc.js → index-7P1b8HZo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cvwu_rA_.js → index-B00GeekA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbIAWbma.js → index-B4QYBliR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNKFsBlz.js → index-B7_W_rYd.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoskgPt9.js → index-BO9dQjpt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvOa-IFV.js → index-BZ5lY2zx.js} +1 -1
- package/src/assets/web-panel/assets/{index-_-9k3Tna.js → index-B_eCoZgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbihMThv.js → index-BgfImyZI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLSBks8h.js → index-Bq5P3piS.js} +1 -1
- package/src/assets/web-panel/assets/{index-LU54bChK.js → index-Bqc8tdIF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Btqk6zWb.js → index-C7sKbM5s.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8uEL8Uw.js → index-CGlotREA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLlP1E4X.js → index-CRPrHE7h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeWKPQGs.js → index-CX1x4AFn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Db_5xhrU.js → index-CbTPvp2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDfSD07S.js → index-CjWltbi_.js} +1 -1
- package/src/assets/web-panel/assets/index-Ck1jhFE0.js +1 -0
- package/src/assets/web-panel/assets/{index-BPBia4b-.js → index-CkMKuqUs.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1ZAOJRW.js → index-CmruhzFi.js} +1 -1
- package/src/assets/web-panel/assets/{index-P83LDnCz.js → index-Csfb-7hw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcDggpWR.js → index-CxEtQYdi.js} +1 -1
- package/src/assets/web-panel/assets/{index-OjnAwUJo.js → index-D7z4zB_a.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-EJNxgR.js → index-DLoalqRX.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3-B3FWD.js → index-DU2TXJu-.js} +1 -1
- package/src/assets/web-panel/assets/{index-D92g4l3n.js → index-DXet1xol.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ca0mij1n.js → index-Dbd7eEex.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCqpl_E_.js → index-Dbkghqn_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyWlOuak.js → index-Dg2a9owQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUBkvFPH.js → index-DpqtbXdE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhVHoqGL.js → index-DqwPFbOb.js} +3 -3
- package/src/assets/web-panel/assets/{index-BG-GaZri.js → index-DvV03Ayk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMCEXBRh.js → index-NJieh3T1.js} +1 -1
- package/src/assets/web-panel/assets/{index-B273IY-E.js → index-Td8ZwyoC.js} +1 -1
- package/src/assets/web-panel/assets/index-c8jJEHVs.js +1 -0
- package/src/assets/web-panel/assets/{index-BzXjYUmd.js → index-e-e40id6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCLwoATF.js → index-fccZmC_h.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN8HZlLH.js → index-fgYk0QXO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BB4KHHcv.js → index-yYEQXYaU.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CFNgY8lJ.js → initDefaultProps-CPrcB1TC.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D-5RrDzn.js → motion-BQ7mWRh_.js} +1 -1
- package/src/assets/web-panel/assets/{move-DN-L0Bd-.js → move-CzOEq99p.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-6mgLSeCK.js → mtc-parser-BlQI5jrw.js} +1 -1
- package/src/assets/web-panel/assets/{omit-ClWW8eTP.js → omit-DlW4gxmv.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Vystq3R8.js → pickAttrs-BBYms5nP.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D0H9hK4W.js → placementArrow-az2MPJ_7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B3iNRU-a.js → responsiveObserve-D1-ibEol.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CiMXe6am.js → slide-DHGqa4GA.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CGDZJ1uT.js → statusUtils-CYGDo6lD.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-D2zA6NkY.js → styleChecker-Cl2EM9K6.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C1sYU6QE.js → useFlexGapSupport-DdYhzuv1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BzUHSjg2.js → useFs-DWumPuBW.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CxB5yZCq.js → usePersonalDataHub-DxAO-Aqi.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BfUfMwtc.js → vnode-CplsQf_N.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CFYmj1TO.js → zoom-Cw5HXNSG.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agent.js +19 -1
- package/src/commands/evolution-knowledge.js +54 -0
- package/src/commands/evolution-workbench.js +83 -0
- package/src/commands/evolution.js +6 -1
- package/src/commands/serve.js +16 -0
- package/src/commands/skill.js +158 -16
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/session-protocol.js +2 -0
- package/src/gateways/ws/ws-agent-handler.js +124 -69
- package/src/gateways/ws/ws-server.js +19 -0
- package/src/generated/cc-agent-protocol.schema.json +7 -1
- package/src/harness/jsonl-session-store.js +25 -1
- package/src/index.js +1 -1
- package/src/lib/app-server/cli-agent-kernel-adapter.js +8 -0
- package/src/lib/app-server/graph-runtime.js +40 -1
- package/src/lib/app-server/server.js +181 -3
- package/src/lib/app-server/websocket-transport.js +2 -0
- package/src/lib/evolution/agent-evolution-runtime-composition-brand.js +17 -0
- package/src/lib/evolution/agent-evolution-runtime-composition.js +165 -1
- package/src/lib/evolution/controlled-skill-production-pilot.js +912 -0
- package/src/lib/evolution/evolution-artifact-ports.js +21 -0
- package/src/lib/evolution/evolution-raw-crypto-shred.js +185 -0
- package/src/lib/evolution/evolution-workbench-batch-executor.js +195 -0
- package/src/lib/evolution/evolution-workbench-cli-host.js +169 -0
- package/src/lib/evolution/evolution-workbench-metrics-ledger-adapter.js +648 -0
- package/src/lib/evolution/evolution-workbench-metrics.js +943 -0
- package/src/lib/evolution/evolution-workbench-projection.js +734 -0
- package/src/lib/evolution/evolution-workbench-version-control.js +272 -0
- package/src/lib/evolution/governed-knowledge-conflict-merge.js +352 -0
- package/src/lib/evolution/governed-knowledge-dependency-authority.js +273 -0
- package/src/lib/evolution/governed-knowledge-dependency-ledger-executor.js +646 -0
- package/src/lib/evolution/governed-knowledge-merge-ledger-executor.js +644 -0
- package/src/lib/evolution/governed-knowledge-merge-publisher-authority.js +282 -0
- package/src/lib/evolution/governed-knowledge-node-crypto-authority.js +348 -0
- package/src/lib/evolution/governed-knowledge-rbac-approval-authority.js +621 -0
- package/src/lib/evolution/governed-knowledge-review-host.js +249 -0
- package/src/lib/evolution/governed-knowledge-sync-ledger-adapter.js +643 -0
- package/src/lib/evolution/governed-knowledge-sync-merge-publisher.js +259 -0
- package/src/lib/evolution/governed-knowledge-sync.js +485 -0
- package/src/lib/evolution/governed-knowledge-trust-ledger.js +707 -0
- package/src/lib/evolution/governed-skill-marketplace.js +430 -0
- package/src/lib/evolution/governed-wiki-pruning.js +435 -0
- package/src/lib/evolution/skill-outcome-index-authority.js +268 -0
- package/src/lib/evolution/skill-outcome-source-catalog-authority.js +237 -0
- package/src/lib/public-ide-capability-manifest.js +4 -0
- package/src/lib/skill-outcome-authority.js +43 -0
- package/src/lib/skill-outcome-transcript-authority.js +252 -0
- package/src/lib/skill-retrieval-router-benchmark.js +135 -0
- package/src/lib/skill-retrieval-router.js +235 -0
- package/src/lib/skill-vector-authority.js +325 -0
- package/src/lib/skill-vector-process-authority.js +386 -0
- package/src/repl/agent-repl.js +7 -1
- package/src/runtime/agent-core.js +72 -6
- package/src/runtime/agent-runtime.js +42 -0
- package/src/runtime/headless-runner.js +32 -0
- package/src/runtime/headless-stream.js +36 -1
- package/src/runtime/runtime-factory.js +62 -4
- package/src/assets/web-panel/assets/Notes-DZimkTrb.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-Iy-pnX56.js +0 -1
- package/src/assets/web-panel/assets/ProjectSettings-CFMmhROS.js +0 -2
- package/src/assets/web-panel/assets/TimelineRenderer-CsLTB_QO.js +0 -1
- package/src/assets/web-panel/assets/devWarning-B2IW1J_J.js +0 -1
- package/src/assets/web-panel/assets/index-BCp2ir-1.js +0 -1
- package/src/assets/web-panel/assets/index-Bw4iuzRD.js +0 -1
|
@@ -71,6 +71,12 @@ export const EVOLUTION_ARTIFACT_LEDGER_RETENTION_TYPES = Object.freeze([
|
|
|
71
71
|
"skill-registry-transition-request",
|
|
72
72
|
"skill-registry-transition-settlement",
|
|
73
73
|
"evolution-run-event",
|
|
74
|
+
"evolution-workbench-metrics-receipt-retention",
|
|
75
|
+
"evolution-workbench-metrics-snapshot",
|
|
76
|
+
"governed-knowledge-sync-record",
|
|
77
|
+
"governed-knowledge-merge-operation",
|
|
78
|
+
"governed-knowledge-dependency-operation",
|
|
79
|
+
"governed-knowledge-trust-record",
|
|
74
80
|
"structured-memory-authority-receipt",
|
|
75
81
|
"structured-memory-event",
|
|
76
82
|
"structured-memory-snapshot",
|
|
@@ -100,6 +106,12 @@ export const EVOLUTION_ARTIFACT_TYPES = Object.freeze([
|
|
|
100
106
|
"evaluation",
|
|
101
107
|
"evaluation-result",
|
|
102
108
|
"evolution-run-event",
|
|
109
|
+
"evolution-workbench-metrics-receipt-retention",
|
|
110
|
+
"evolution-workbench-metrics-snapshot",
|
|
111
|
+
"governed-knowledge-sync-record",
|
|
112
|
+
"governed-knowledge-merge-operation",
|
|
113
|
+
"governed-knowledge-dependency-operation",
|
|
114
|
+
"governed-knowledge-trust-record",
|
|
103
115
|
"evidence",
|
|
104
116
|
"model-projection",
|
|
105
117
|
"policy",
|
|
@@ -307,6 +319,15 @@ const LEDGER_RETENTION_PURPOSES_BY_TYPE = new Map([
|
|
|
307
319
|
["skill-registry-transition-request", new Set(["evolution-ledger"])],
|
|
308
320
|
["skill-registry-transition-settlement", new Set(["evolution-ledger"])],
|
|
309
321
|
["evolution-run-event", new Set(["evolution-ledger"])],
|
|
322
|
+
[
|
|
323
|
+
"evolution-workbench-metrics-receipt-retention",
|
|
324
|
+
new Set(["evolution-ledger"]),
|
|
325
|
+
],
|
|
326
|
+
["evolution-workbench-metrics-snapshot", new Set(["evolution-ledger"])],
|
|
327
|
+
["governed-knowledge-sync-record", new Set(["evolution-ledger"])],
|
|
328
|
+
["governed-knowledge-merge-operation", new Set(["evolution-ledger"])],
|
|
329
|
+
["governed-knowledge-dependency-operation", new Set(["evolution-ledger"])],
|
|
330
|
+
["governed-knowledge-trust-record", new Set(["evolution-ledger"])],
|
|
310
331
|
["wiki-revision", new Set(["evolution-ledger"])],
|
|
311
332
|
["structured-memory-authority-receipt", new Set(["evolution-ledger"])],
|
|
312
333
|
["structured-memory-event", new Set(["evolution-ledger"])],
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export const EVOLUTION_RAW_CRYPTO_SHRED_SCHEMA =
|
|
4
|
+
"chainlesschain.evolution-raw-crypto-shred/v1";
|
|
5
|
+
export const EVOLUTION_RAW_DELETION_TOMBSTONE_SCHEMA =
|
|
6
|
+
"chainlesschain.evolution-raw-deletion-tombstone/v1";
|
|
7
|
+
|
|
8
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
9
|
+
|
|
10
|
+
function canonical(value) {
|
|
11
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
12
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
13
|
+
return `{${Object.keys(value)
|
|
14
|
+
.sort()
|
|
15
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
16
|
+
.join(",")}}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function hash(domain, value) {
|
|
20
|
+
return `sha256:${createHash("sha256")
|
|
21
|
+
.update(domain)
|
|
22
|
+
.update("\0")
|
|
23
|
+
.update(canonical(value))
|
|
24
|
+
.digest("hex")}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function freeze(value) {
|
|
28
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
29
|
+
Object.freeze(value);
|
|
30
|
+
for (const child of Object.values(value)) freeze(child);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function capture(ports, name) {
|
|
36
|
+
if (typeof ports?.[name] !== "function")
|
|
37
|
+
throw new TypeError(`Raw crypto-shred port ${name} is required`);
|
|
38
|
+
return ports[name].bind(ports);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function string(value, name) {
|
|
42
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
43
|
+
throw new TypeError(`${name} is required`);
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function digest(value, name) {
|
|
48
|
+
if (!DIGEST.test(value ?? "")) throw new TypeError(`${name} is invalid`);
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function verifyPruningCall(call, tenantId) {
|
|
53
|
+
const request = call?.request;
|
|
54
|
+
if (
|
|
55
|
+
request?.tenantId !== tenantId ||
|
|
56
|
+
request.operation !== "crypto-shred" ||
|
|
57
|
+
!DIGEST.test(call?.requestDigest ?? "") ||
|
|
58
|
+
call.requestDigest !==
|
|
59
|
+
hash("chainlesschain.governed-wiki-pruning-operation/v1", request)
|
|
60
|
+
)
|
|
61
|
+
throw new Error("Raw crypto-shred request is not pruning-plan-bound");
|
|
62
|
+
const payload = request.payload;
|
|
63
|
+
if (
|
|
64
|
+
typeof payload?.rawArtifactRef !== "string" ||
|
|
65
|
+
!payload.rawArtifactRef.startsWith(`artifact://${tenantId}/raw/`) ||
|
|
66
|
+
typeof payload.keyRef !== "string" ||
|
|
67
|
+
!payload.keyRef.startsWith(`kms://${tenantId}/`)
|
|
68
|
+
)
|
|
69
|
+
throw new Error("Raw crypto-shred target is cross-tenant or incomplete");
|
|
70
|
+
for (const [value, name] of [
|
|
71
|
+
[request.planDigest, "planDigest"],
|
|
72
|
+
[request.wikiStateDigest, "wikiStateDigest"],
|
|
73
|
+
[payload.sourceDigest, "sourceDigest"],
|
|
74
|
+
[payload.rawCipherDigest, "rawCipherDigest"],
|
|
75
|
+
[payload.receiptDigest, "deletionReceiptDigest"],
|
|
76
|
+
])
|
|
77
|
+
digest(value, name);
|
|
78
|
+
string(payload.evidenceRef, "evidenceRef");
|
|
79
|
+
string(payload.artifactRef, "artifactRef");
|
|
80
|
+
return request;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class EvolutionRawCryptoShred {
|
|
84
|
+
constructor({ tenantId, ports } = {}) {
|
|
85
|
+
this.tenantId = string(tenantId, "tenantId");
|
|
86
|
+
this._verifyDeletionReceipt = capture(ports, "verifyDeletionReceipt");
|
|
87
|
+
this._destroyKey = capture(ports, "destroyKey");
|
|
88
|
+
this._confirmKeyDestroyed = capture(ports, "confirmKeyDestroyed");
|
|
89
|
+
this._retainTombstone = capture(ports, "retainTombstone");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async shred(call) {
|
|
93
|
+
const request = verifyPruningCall(call, this.tenantId);
|
|
94
|
+
const target = request.payload;
|
|
95
|
+
const deletion = await this._verifyDeletionReceipt({
|
|
96
|
+
tenantId: this.tenantId,
|
|
97
|
+
receiptDigest: target.receiptDigest,
|
|
98
|
+
});
|
|
99
|
+
if (
|
|
100
|
+
deletion?.authenticated !== true ||
|
|
101
|
+
deletion.decision !== "delete" ||
|
|
102
|
+
deletion.tenantId !== this.tenantId ||
|
|
103
|
+
deletion.receiptDigest !== target.receiptDigest ||
|
|
104
|
+
deletion.evidenceRef !== target.evidenceRef ||
|
|
105
|
+
deletion.sourceDigest !== target.sourceDigest ||
|
|
106
|
+
deletion.artifactRef !== target.artifactRef ||
|
|
107
|
+
deletion.rawArtifactRef !== target.rawArtifactRef ||
|
|
108
|
+
deletion.rawCipherDigest !== target.rawCipherDigest ||
|
|
109
|
+
deletion.keyRef !== target.keyRef
|
|
110
|
+
)
|
|
111
|
+
throw new Error("Raw deletion receipt was substituted");
|
|
112
|
+
const destructionCore = {
|
|
113
|
+
schema: EVOLUTION_RAW_CRYPTO_SHRED_SCHEMA,
|
|
114
|
+
tenantId: this.tenantId,
|
|
115
|
+
planDigest: request.planDigest,
|
|
116
|
+
wikiStateDigest: request.wikiStateDigest,
|
|
117
|
+
evidenceRef: target.evidenceRef,
|
|
118
|
+
rawArtifactRef: target.rawArtifactRef,
|
|
119
|
+
rawCipherDigest: target.rawCipherDigest,
|
|
120
|
+
keyRef: target.keyRef,
|
|
121
|
+
deletionReceiptDigest: target.receiptDigest,
|
|
122
|
+
};
|
|
123
|
+
const destructionRequest = freeze({
|
|
124
|
+
...destructionCore,
|
|
125
|
+
requestDigest: hash(EVOLUTION_RAW_CRYPTO_SHRED_SCHEMA, destructionCore),
|
|
126
|
+
});
|
|
127
|
+
const destroyed = await this._destroyKey(destructionRequest);
|
|
128
|
+
if (
|
|
129
|
+
destroyed?.authenticated !== true ||
|
|
130
|
+
destroyed.durable !== true ||
|
|
131
|
+
destroyed.destroyed !== true ||
|
|
132
|
+
destroyed.keyRef !== target.keyRef ||
|
|
133
|
+
destroyed.requestDigest !== destructionRequest.requestDigest ||
|
|
134
|
+
!DIGEST.test(destroyed.receiptDigest ?? "")
|
|
135
|
+
)
|
|
136
|
+
throw new Error("Raw encryption key destruction was not durable");
|
|
137
|
+
const confirmation = await this._confirmKeyDestroyed({
|
|
138
|
+
tenantId: this.tenantId,
|
|
139
|
+
keyRef: target.keyRef,
|
|
140
|
+
destructionReceiptDigest: destroyed.receiptDigest,
|
|
141
|
+
});
|
|
142
|
+
if (
|
|
143
|
+
confirmation?.authenticated !== true ||
|
|
144
|
+
confirmation.destroyed !== true ||
|
|
145
|
+
confirmation.keyRef !== target.keyRef ||
|
|
146
|
+
confirmation.destructionReceiptDigest !== destroyed.receiptDigest ||
|
|
147
|
+
!DIGEST.test(confirmation.receiptDigest ?? "")
|
|
148
|
+
)
|
|
149
|
+
throw new Error("Raw encryption key destruction could not be confirmed");
|
|
150
|
+
const tombstoneCore = {
|
|
151
|
+
schema: EVOLUTION_RAW_DELETION_TOMBSTONE_SCHEMA,
|
|
152
|
+
tenantId: this.tenantId,
|
|
153
|
+
pruningRequestDigest: call.requestDigest,
|
|
154
|
+
destructionRequestDigest: destructionRequest.requestDigest,
|
|
155
|
+
destructionReceiptDigest: destroyed.receiptDigest,
|
|
156
|
+
confirmationReceiptDigest: confirmation.receiptDigest,
|
|
157
|
+
evidenceRef: target.evidenceRef,
|
|
158
|
+
rawArtifactRef: target.rawArtifactRef,
|
|
159
|
+
rawCipherDigest: target.rawCipherDigest,
|
|
160
|
+
deletionReceiptDigest: target.receiptDigest,
|
|
161
|
+
};
|
|
162
|
+
const tombstone = freeze({
|
|
163
|
+
...tombstoneCore,
|
|
164
|
+
tombstoneDigest: hash(
|
|
165
|
+
EVOLUTION_RAW_DELETION_TOMBSTONE_SCHEMA,
|
|
166
|
+
tombstoneCore,
|
|
167
|
+
),
|
|
168
|
+
});
|
|
169
|
+
const retained = await this._retainTombstone({ tombstone });
|
|
170
|
+
if (
|
|
171
|
+
retained?.authenticated !== true ||
|
|
172
|
+
retained.durable !== true ||
|
|
173
|
+
retained.tombstoneDigest !== tombstone.tombstoneDigest ||
|
|
174
|
+
!DIGEST.test(retained.receiptDigest ?? "")
|
|
175
|
+
)
|
|
176
|
+
throw new Error("Raw deletion tombstone was not durably retained");
|
|
177
|
+
return freeze({
|
|
178
|
+
authenticated: true,
|
|
179
|
+
durable: true,
|
|
180
|
+
requestDigest: call.requestDigest,
|
|
181
|
+
receiptDigest: retained.receiptDigest,
|
|
182
|
+
tombstoneDigest: tombstone.tombstoneDigest,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
EVOLUTION_WORKBENCH_BATCH_PLAN_SCHEMA,
|
|
5
|
+
filterEvolutionWorkbenchProjection,
|
|
6
|
+
} from "./evolution-workbench-projection.js";
|
|
7
|
+
import { verifySkillPromotionReviewPacketArtifact } from "./skill-promotion-review.js";
|
|
8
|
+
|
|
9
|
+
export const EVOLUTION_WORKBENCH_BATCH_ITEM_REQUEST_SCHEMA =
|
|
10
|
+
"chainlesschain.evolution-workbench-batch-item-request/v1";
|
|
11
|
+
export const EVOLUTION_WORKBENCH_BATCH_EXECUTION_SCHEMA =
|
|
12
|
+
"chainlesschain.evolution-workbench-batch-execution/v1";
|
|
13
|
+
|
|
14
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
15
|
+
|
|
16
|
+
function canonical(value) {
|
|
17
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
18
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
19
|
+
return `{${Object.keys(value)
|
|
20
|
+
.sort()
|
|
21
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
22
|
+
.join(",")}}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function hash(domain, value) {
|
|
26
|
+
return `sha256:${createHash("sha256")
|
|
27
|
+
.update(domain)
|
|
28
|
+
.update("\0")
|
|
29
|
+
.update(canonical(value))
|
|
30
|
+
.digest("hex")}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function clone(value) {
|
|
34
|
+
return value == null ? value : structuredClone(value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function freeze(value) {
|
|
38
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
39
|
+
Object.freeze(value);
|
|
40
|
+
for (const child of Object.values(value)) freeze(child);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function verifyPlan(input, tenantId) {
|
|
46
|
+
if (
|
|
47
|
+
input?.schema !== EVOLUTION_WORKBENCH_BATCH_PLAN_SCHEMA ||
|
|
48
|
+
input.tenantId !== tenantId ||
|
|
49
|
+
!DIGEST.test(input?.planDigest ?? "")
|
|
50
|
+
)
|
|
51
|
+
throw new TypeError("Workbench batch plan is invalid");
|
|
52
|
+
const core = clone(input);
|
|
53
|
+
delete core.planDigest;
|
|
54
|
+
if (hash(EVOLUTION_WORKBENCH_BATCH_PLAN_SCHEMA, core) !== input.planDigest)
|
|
55
|
+
throw new Error("Workbench batch plan digest is invalid");
|
|
56
|
+
return freeze(clone(input));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function itemRequest(plan, packet) {
|
|
60
|
+
const core = {
|
|
61
|
+
schema: EVOLUTION_WORKBENCH_BATCH_ITEM_REQUEST_SCHEMA,
|
|
62
|
+
tenantId: plan.tenantId,
|
|
63
|
+
planDigest: plan.planDigest,
|
|
64
|
+
sourceProjectionDigest: plan.sourceProjectionDigest,
|
|
65
|
+
packetDigest: packet.packetDigest,
|
|
66
|
+
candidateId: packet.candidateId,
|
|
67
|
+
candidateContentDigest: packet.candidateContentDigest,
|
|
68
|
+
decision: plan.decision,
|
|
69
|
+
reason: plan.reason,
|
|
70
|
+
requestedBy: plan.requestedBy,
|
|
71
|
+
requiredHumanQuorum: packet.requiredHumanQuorum,
|
|
72
|
+
contentRiskDigest: packet.contentRisk.contentRiskDigest,
|
|
73
|
+
contentRiskDetected: packet.contentRisk.detected,
|
|
74
|
+
};
|
|
75
|
+
return freeze({
|
|
76
|
+
...core,
|
|
77
|
+
requestDigest: hash(EVOLUTION_WORKBENCH_BATCH_ITEM_REQUEST_SCHEMA, core),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export class EvolutionWorkbenchBatchExecutor {
|
|
82
|
+
constructor({ tenantId, ports } = {}) {
|
|
83
|
+
if (typeof tenantId !== "string" || tenantId.trim() === "")
|
|
84
|
+
throw new TypeError("tenantId is required");
|
|
85
|
+
this.tenantId = tenantId;
|
|
86
|
+
for (const name of [
|
|
87
|
+
"loadProjection",
|
|
88
|
+
"resolvePacket",
|
|
89
|
+
"requestHumanDecision",
|
|
90
|
+
"retainDecision",
|
|
91
|
+
"commitExecutionItem",
|
|
92
|
+
]) {
|
|
93
|
+
if (typeof ports?.[name] !== "function")
|
|
94
|
+
throw new TypeError(
|
|
95
|
+
`Workbench batch executor port ${name} is required`,
|
|
96
|
+
);
|
|
97
|
+
this[`_${name}`] = ports[name].bind(ports);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async execute(input) {
|
|
102
|
+
const plan = verifyPlan(input, this.tenantId);
|
|
103
|
+
const projection = await this._loadProjection({
|
|
104
|
+
tenantId: this.tenantId,
|
|
105
|
+
projectionDigest: plan.sourceProjectionDigest,
|
|
106
|
+
});
|
|
107
|
+
filterEvolutionWorkbenchProjection(projection, { limit: 1 });
|
|
108
|
+
if (
|
|
109
|
+
projection.tenantId !== plan.tenantId ||
|
|
110
|
+
projection.runId !== plan.runId ||
|
|
111
|
+
projection.skillName !== plan.skillName ||
|
|
112
|
+
projection.projectionDigest !== plan.sourceProjectionDigest
|
|
113
|
+
)
|
|
114
|
+
throw new Error("Workbench batch source projection changed");
|
|
115
|
+
const pending = new Map(
|
|
116
|
+
projection.candidates
|
|
117
|
+
.filter(({ status }) => status === "pending")
|
|
118
|
+
.map((candidate) => [candidate.packetDigest, candidate]),
|
|
119
|
+
);
|
|
120
|
+
const items = [];
|
|
121
|
+
for (const packetDigest of plan.packetDigests) {
|
|
122
|
+
if (!pending.has(packetDigest))
|
|
123
|
+
throw new Error("Workbench batch packet is no longer pending");
|
|
124
|
+
const packet = verifySkillPromotionReviewPacketArtifact(
|
|
125
|
+
await this._resolvePacket({ tenantId: this.tenantId, packetDigest }),
|
|
126
|
+
);
|
|
127
|
+
if (
|
|
128
|
+
packet.packetDigest !== packetDigest ||
|
|
129
|
+
packet.candidateId !== pending.get(packetDigest).candidateId
|
|
130
|
+
)
|
|
131
|
+
throw new Error("Workbench batch packet was substituted");
|
|
132
|
+
const request = itemRequest(plan, packet);
|
|
133
|
+
const decision = await this._requestHumanDecision(request);
|
|
134
|
+
const expectedDecision =
|
|
135
|
+
plan.decision === "approve" ? "approved" : "rejected";
|
|
136
|
+
if (
|
|
137
|
+
decision?.tenantId !== this.tenantId ||
|
|
138
|
+
decision.packetDigest !== packetDigest ||
|
|
139
|
+
decision.candidateId !== packet.candidateId ||
|
|
140
|
+
decision.decision !== expectedDecision ||
|
|
141
|
+
decision.automated !== false ||
|
|
142
|
+
decision.reason !== plan.reason ||
|
|
143
|
+
decision.requestDigest !== request.requestDigest ||
|
|
144
|
+
!DIGEST.test(decision.receiptDigest ?? "") ||
|
|
145
|
+
typeof decision.signature !== "string" ||
|
|
146
|
+
decision.signature.length < 32
|
|
147
|
+
)
|
|
148
|
+
throw new Error("Workbench batch human decision is not exactly bound");
|
|
149
|
+
const retained = await this._retainDecision({
|
|
150
|
+
packetDigest,
|
|
151
|
+
decision,
|
|
152
|
+
});
|
|
153
|
+
if (
|
|
154
|
+
retained?.persisted !== true ||
|
|
155
|
+
retained.receiptDigest !== decision.receiptDigest
|
|
156
|
+
)
|
|
157
|
+
throw new Error("Workbench batch decision was not durably retained");
|
|
158
|
+
const itemCore = {
|
|
159
|
+
packetDigest,
|
|
160
|
+
requestDigest: request.requestDigest,
|
|
161
|
+
decisionReceiptDigest: decision.receiptDigest,
|
|
162
|
+
};
|
|
163
|
+
const item = freeze({
|
|
164
|
+
...itemCore,
|
|
165
|
+
itemDigest: hash(
|
|
166
|
+
"chainlesschain.evolution-workbench-batch-execution-item/v1",
|
|
167
|
+
itemCore,
|
|
168
|
+
),
|
|
169
|
+
});
|
|
170
|
+
const committed = await this._commitExecutionItem({
|
|
171
|
+
tenantId: this.tenantId,
|
|
172
|
+
planDigest: plan.planDigest,
|
|
173
|
+
item,
|
|
174
|
+
});
|
|
175
|
+
if (
|
|
176
|
+
committed?.authenticated !== true ||
|
|
177
|
+
committed.durable !== true ||
|
|
178
|
+
committed.itemDigest !== item.itemDigest
|
|
179
|
+
)
|
|
180
|
+
throw new Error("Workbench batch execution item was not committed");
|
|
181
|
+
items.push(item);
|
|
182
|
+
}
|
|
183
|
+
const core = {
|
|
184
|
+
schema: EVOLUTION_WORKBENCH_BATCH_EXECUTION_SCHEMA,
|
|
185
|
+
tenantId: this.tenantId,
|
|
186
|
+
planDigest: plan.planDigest,
|
|
187
|
+
sourceProjectionDigest: plan.sourceProjectionDigest,
|
|
188
|
+
items,
|
|
189
|
+
};
|
|
190
|
+
return freeze({
|
|
191
|
+
...core,
|
|
192
|
+
executionDigest: hash(EVOLUTION_WORKBENCH_BATCH_EXECUTION_SCHEMA, core),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { types as utilTypes } from "node:util";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildEvolutionWorkbenchBatchPlan,
|
|
5
|
+
filterEvolutionWorkbenchProjection,
|
|
6
|
+
} from "./evolution-workbench-projection.js";
|
|
7
|
+
import {
|
|
8
|
+
buildEvolutionWorkbenchRollbackPlan,
|
|
9
|
+
compareEvolutionWorkbenchVersions,
|
|
10
|
+
} from "./evolution-workbench-version-control.js";
|
|
11
|
+
|
|
12
|
+
const HOSTS = new WeakSet();
|
|
13
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
14
|
+
|
|
15
|
+
function capture(owner, method, label) {
|
|
16
|
+
if (
|
|
17
|
+
!owner ||
|
|
18
|
+
typeof owner !== "object" ||
|
|
19
|
+
utilTypes.isProxy(owner) ||
|
|
20
|
+
typeof owner[method] !== "function"
|
|
21
|
+
) {
|
|
22
|
+
throw new TypeError(`${label}.${method}() is required`);
|
|
23
|
+
}
|
|
24
|
+
return (...args) => Reflect.apply(owner[method], owner, args);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function text(value, label) {
|
|
28
|
+
if (typeof value !== "string" || value.trim() !== value || value === "") {
|
|
29
|
+
throw new TypeError(`${label} is required`);
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function digest(value, label) {
|
|
35
|
+
if (!DIGEST.test(value ?? "")) throw new TypeError(`${label} is invalid`);
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function identity(value, tenantId) {
|
|
40
|
+
if (
|
|
41
|
+
value?.authenticated !== true ||
|
|
42
|
+
value.durable !== true ||
|
|
43
|
+
value.automated !== false ||
|
|
44
|
+
value.tenantId !== tenantId ||
|
|
45
|
+
typeof value.subjectId !== "string" ||
|
|
46
|
+
value.subjectId.trim() === "" ||
|
|
47
|
+
!DIGEST.test(value.receiptDigest ?? "")
|
|
48
|
+
) {
|
|
49
|
+
throw new Error("Workbench CLI requires a durable human identity");
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function retainProjection(retain, projection) {
|
|
55
|
+
const result = await retain({
|
|
56
|
+
tenantId: projection.tenantId,
|
|
57
|
+
projection,
|
|
58
|
+
});
|
|
59
|
+
if (
|
|
60
|
+
result?.authenticated !== true ||
|
|
61
|
+
result.durable !== true ||
|
|
62
|
+
result.projectionDigest !== projection.projectionDigest
|
|
63
|
+
) {
|
|
64
|
+
throw new Error("Workbench projection was not durably retained");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function createEvolutionWorkbenchCliHost({
|
|
69
|
+
tenantId: tenantIdInput,
|
|
70
|
+
projectionLoader,
|
|
71
|
+
projectionAuthority,
|
|
72
|
+
identityProvider,
|
|
73
|
+
activeStateReader,
|
|
74
|
+
batchExecutor,
|
|
75
|
+
rollbackExecutor,
|
|
76
|
+
} = {}) {
|
|
77
|
+
const tenantId = text(tenantIdInput, "tenantId");
|
|
78
|
+
const loadProjection = capture(projectionLoader, "load", "projectionLoader");
|
|
79
|
+
const retain = capture(projectionAuthority, "retain", "projectionAuthority");
|
|
80
|
+
const resolveIdentity = capture(
|
|
81
|
+
identityProvider,
|
|
82
|
+
"current",
|
|
83
|
+
"identityProvider",
|
|
84
|
+
);
|
|
85
|
+
const readActiveState = capture(
|
|
86
|
+
activeStateReader,
|
|
87
|
+
"read",
|
|
88
|
+
"activeStateReader",
|
|
89
|
+
);
|
|
90
|
+
const executeBatch = capture(batchExecutor, "execute", "batchExecutor");
|
|
91
|
+
const executeRollback = capture(
|
|
92
|
+
rollbackExecutor,
|
|
93
|
+
"execute",
|
|
94
|
+
"rollbackExecutor",
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
async function projection() {
|
|
98
|
+
const value = await loadProjection({ tenantId });
|
|
99
|
+
filterEvolutionWorkbenchProjection(value, { limit: 1 });
|
|
100
|
+
if (value.tenantId !== tenantId) {
|
|
101
|
+
throw new Error("Workbench projection crossed its tenant boundary");
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const host = Object.freeze({
|
|
107
|
+
tenantId,
|
|
108
|
+
async list(options = {}) {
|
|
109
|
+
return filterEvolutionWorkbenchProjection(await projection(), options);
|
|
110
|
+
},
|
|
111
|
+
async compare(leftPacketDigest, rightPacketDigest) {
|
|
112
|
+
return compareEvolutionWorkbenchVersions(await projection(), {
|
|
113
|
+
leftPacketDigest: digest(leftPacketDigest, "left packet digest"),
|
|
114
|
+
rightPacketDigest: digest(rightPacketDigest, "right packet digest"),
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
async review({ packetDigests, decision, reason } = {}) {
|
|
118
|
+
const current = await projection();
|
|
119
|
+
const actor = identity(await resolveIdentity({ tenantId }), tenantId);
|
|
120
|
+
const plan = buildEvolutionWorkbenchBatchPlan(current, {
|
|
121
|
+
packetDigests,
|
|
122
|
+
decision,
|
|
123
|
+
reason,
|
|
124
|
+
requestedBy: actor.subjectId,
|
|
125
|
+
});
|
|
126
|
+
await retainProjection(retain, current);
|
|
127
|
+
return executeBatch(plan);
|
|
128
|
+
},
|
|
129
|
+
async rollback({ fromPacketDigest, toPacketDigest, reason } = {}) {
|
|
130
|
+
const current = await projection();
|
|
131
|
+
const actor = identity(await resolveIdentity({ tenantId }), tenantId);
|
|
132
|
+
const from = current.candidates.find(
|
|
133
|
+
({ packetDigest }) => packetDigest === fromPacketDigest,
|
|
134
|
+
);
|
|
135
|
+
if (!from || from.actualUsage.active !== true) {
|
|
136
|
+
throw new Error("Workbench rollback source is not active");
|
|
137
|
+
}
|
|
138
|
+
const active = await readActiveState({
|
|
139
|
+
tenantId,
|
|
140
|
+
skillName: current.skillName,
|
|
141
|
+
});
|
|
142
|
+
if (
|
|
143
|
+
active?.authenticated !== true ||
|
|
144
|
+
active.durable !== true ||
|
|
145
|
+
active.tenantId !== tenantId ||
|
|
146
|
+
active.skillName !== current.skillName ||
|
|
147
|
+
active.contentDigest !== from.candidateContentDigest ||
|
|
148
|
+
!DIGEST.test(active.stateDigest ?? "")
|
|
149
|
+
) {
|
|
150
|
+
throw new Error("Workbench active state does not match the projection");
|
|
151
|
+
}
|
|
152
|
+
const plan = buildEvolutionWorkbenchRollbackPlan(current, {
|
|
153
|
+
fromPacketDigest: digest(fromPacketDigest, "from packet digest"),
|
|
154
|
+
toPacketDigest: digest(toPacketDigest, "to packet digest"),
|
|
155
|
+
expectedActiveStateDigest: active.stateDigest,
|
|
156
|
+
requestedBy: actor.subjectId,
|
|
157
|
+
reason,
|
|
158
|
+
});
|
|
159
|
+
await retainProjection(retain, current);
|
|
160
|
+
return executeRollback(plan);
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
HOSTS.add(host);
|
|
164
|
+
return host;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function isEvolutionWorkbenchCliHost(value) {
|
|
168
|
+
return HOSTS.has(value);
|
|
169
|
+
}
|