chainlesschain 0.166.21 → 0.166.24
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 +67 -9
- package/package.json +4 -3
- package/src/assets/web-panel/assets/{AIOps-BjMnsUci.js → AIOps-DR-MWcZc.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DdYFP03A.js → ActionButton-DT8B7sEb.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bb8TuuK_.js → Analytics-asjh3dQJ.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Kn3TIOtk.js → AppLayout-DivQ491i.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-4IxpqI_b.js → Artifacts-DPH2uUmy.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BOV2caqU.js → Audit-Bp2nLyc-.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-B86k-ay4.js → BackgroundAgents-CHS28khl.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-C5_ie1e3.js → Backup-CKeaFSfz.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-xpwg6QCW.js → BaseInput-CxwM9BAH.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CVZOcZau.js → Chat-DYLDwaCv.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-D8fPYhUu.js → ChatBubbleRenderer-DdBJDBP0.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-MKTq3zdP.js → Checkbox-uYTWOB8j.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-JUk3wzep.js → Codegen-CvYa_dwT.js} +1 -1
- package/src/assets/web-panel/assets/{Col-JPvTA0kC.js → Col-CanMAX4m.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Tqgl87NQ.js → Community-B4WaDtHw.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BuAFYBmN.js → Compact-K93Uof_3.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CXS9WIPZ.js → Compliance-CKeDLgUW.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Ds2bFHrr.js → Cowork-P93grAeB.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-C_dV_OeW.js → Cron-BSHnMtDn.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BsO6tIRo.js → Crosschain-epAOpUVJ.js} +1 -1
- package/src/assets/web-panel/assets/{DID-rNOFqBac.js → DID-ByjXfP7t.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-C2fcKKVY.js → Dashboard-QztTU8tb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Y7Ndr0X_.js → Dropdown-DhUc9yhN.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DcP_uPmL.js → EmailListRenderer-C2sLhJJN.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Cwn3gDzk.js → FamilyGuardDashboard-CdfbWNDn.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-ClQuOsqb.js → Federation-CcF_R7NW.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DfwtmlcK.js → FormItemContext-Cm_X2IBk.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-zNZhtbC5.js → GenericCardRenderer-DUi4NWlb.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BZmdW-G5.js → Git-4Sq5FjBt.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CqBk4lEn.js → Governance-Dx2_v4V6.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Dbmt3ZXk.js → Inference-7Vr1xekR.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-hMTH6qf3.js → KnowledgeGraph-Cnd2XOzf.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CkiYgiW2.js → Logs-B66QPVf-.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BL1FElXg.js → MarkdownRenderer-PLsEvhly.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CbB6wfin.js → Marketplace-BMIK9BmC.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BSwiFtte.js → McpTools-BDbyp3J_.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-B03PeHrz.js → Memory-CJdzfZGi.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CRGrnd-X.js → MobileBridge-C2TH5Y3-.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CE_5v2kO.js → MobileProjects-D1dYXkvV.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Dp11QVx1.js → Mtc-B-4A1I1j.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CYu-3JBu.js → MtcAudit-Bgcc9UOl.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CGyJ0Xl3.js → Multisig-DqOe-etP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CoWi_ov1.js → NLProgramming-7VnhzE_6.js} +1 -1
- package/src/assets/web-panel/assets/Notes-BxawpeUQ.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-DX4I2b4W.js → NotificationSettings-Cr08G2aE.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Ce8bEGlK.js +1 -0
- package/src/assets/web-panel/assets/{Organization-oopLO_tk.js → Organization-BC7lveGv.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BFVvjMyf.js → Overflow-CakOW-G0.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CBy5t-Tk.js → P2P-Cf8CaOBZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser--YWJNsu6.js → PdhVaultBrowser-Dc7b98W9.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C2dZ8scb.js → Permissions-DGJyMEfS.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Bs3l7Hlx.js → PersonalDataHub-DNIwSdwu.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-DEBWbZuD.js → Pipeline-5B1S12wa.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CjHBb6NU.js → Privacy-CMB6Ke5t.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-D2WipUz5.js → ProjectInit-D5PqTFiT.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B6WfnrGB.js → ProjectSettings-CbKNdSjV.js} +2 -2
- package/src/assets/web-panel/assets/Projects-ccXaHzYL.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CCv5M_Dv.js → Providers-CJF5_-Gs.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CGthxU54.js → QrScannerModal-CT6iEAdi.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CnPmXPFb.js → QuickAsk-Ci0h9mJ_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Df_tGEa9.js → Recommend-Da5mobZu.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Z58N0Loe.js → RemoteSession-BaCY8eey.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CZTBQ2Vt.js → Reputation-CaITfTsI.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CdK3YpCQ.js → Row-DtUDamyP.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CFMVT5sb.js → RssFeed-DX27gFpg.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DrF8RIvD.js → Search-DFL69osN.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Ddk2f2DM.js → Security-BqGeoWv-.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CCuK-VOo.js → Services-3z1WnEAc.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DxCpHzeM.js → Skeleton-C_OJQQ9Z.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-t2oTDgcv.js → Skills-BY7aT6Mo.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Df63M9_R.js → Sla-BZv7DSaD.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-6lJKLhCn.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-COd_tgPp.js → SyncSettings-B6D7STlI.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CzDCcrik.js → Tasks-Co_FCZAO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D-vfxTGA.js → Templates-CnY-9fgz.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BlpT_Gxc.js → Tenant-B71yXfZ8.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D5rq52Hg.js → Terminal-Dd_P7awo.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DdoMndkK.js → TimelineRenderer-CvIEMyli.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BhgBsI6g.js → Tokens-DknFBGOi.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DwwzoikZ.js → Trigger-D_4nJONB.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-HkTpzXFb.js → Trust-BNl21fa7.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D9nk6Ehe.js → UkeySign-CFrCI7uK.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BKk0rfoy.js → VideoEditing-BVfY6JLg.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-IVWIU_Lq.js → Wallet-Cj9CAK0J.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CFTCpfsG.js → WebAuthn-DcqZlzA3.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Dnf4Obif.js → WorkflowEditor-Dfr_dMld.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D2snERdj.js → chat-Yv6UF0AD.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DKEjK1N1.js → colors-CDW_-1fs.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BEDLwQdt.js → compact-item-BYOQvd-6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DA9iW1a0.js → createContext-BCGO0BiP.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-H-kXSuf-.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-5l2xEcY9.js → hasIn-DY-70cfQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7_W_rYd.js → index-366wfQBU.js} +1 -1
- package/src/assets/web-panel/assets/index-B0o4MeNK.js +1 -0
- package/src/assets/web-panel/assets/{index-CxEtQYdi.js → index-B9ZogJJM.js} +1 -1
- package/src/assets/web-panel/assets/{index-B00GeekA.js → index-B9m5QAMg.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7sKbM5s.js → index-BBs2mv5M.js} +1 -1
- package/src/assets/web-panel/assets/{index-CX1x4AFn.js → index-BFv1hzF6.js} +1 -1
- package/src/assets/web-panel/assets/index-BVafOL_I.js +1 -0
- package/src/assets/web-panel/assets/{index-DU2TXJu-.js → index-BXlEx4UH.js} +1 -1
- package/src/assets/web-panel/assets/{index-e-e40id6.js → index-BayRTE5w.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXet1xol.js → index-Bb9nyts1.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7z4zB_a.js → index-Bf_Va0S-.js} +1 -1
- package/src/assets/web-panel/assets/{index-fccZmC_h.js → index-Br3wQLVY.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqc8tdIF.js → index-BvK4fjkk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BO9dQjpt.js → index-C40UdtlS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Csfb-7hw.js → index-C4UJA2ju.js} +1 -1
- package/src/assets/web-panel/assets/{index-Td8ZwyoC.js → index-CB_Iw73G.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ5lY2zx.js → index-CCwWp3mT.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpqtbXdE.js → index-CFa2fPCk.js} +1 -1
- package/src/assets/web-panel/assets/{index-NJieh3T1.js → index-CIyHxV4u.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbkghqn_.js → index-CUP-A2_h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqwPFbOb.js → index-CUo27q9J.js} +3 -3
- package/src/assets/web-panel/assets/{index-B4QYBliR.js → index-CaT8trvf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgfImyZI.js → index-CnZNbcux.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbd7eEex.js → index-Cy2NE6AO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbTPvp2_.js → index-CzeEEazr.js} +1 -1
- package/src/assets/web-panel/assets/{index-5pW4t1iD.js → index-D--TEyDj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg2a9owQ.js → index-DCtsjhhT.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_eCoZgW.js → index-DLOf7BSz.js} +1 -1
- package/src/assets/web-panel/assets/{index-7P1b8HZo.js → index-DM5c4pc-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRPrHE7h.js → index-DRFC2Qt0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bq5P3piS.js → index-DT_qVaaV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjWltbi_.js → index-DUDoRk9r.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkMKuqUs.js → index-Dg-AQYDf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLoalqRX.js → index-DuIPq5MX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGlotREA.js → index-NYVBUAVN.js} +1 -1
- package/src/assets/web-panel/assets/{index-yYEQXYaU.js → index-NaCESahy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmruhzFi.js → index-RjIMPG0u.js} +1 -1
- package/src/assets/web-panel/assets/{index-fgYk0QXO.js → index-Y9akzgFO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvV03Ayk.js → index-hZ0Eyrrw.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CPrcB1TC.js → initDefaultProps-CG99CcR4.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BQ7mWRh_.js → motion-Z7MH0_0G.js} +1 -1
- package/src/assets/web-panel/assets/{move-CzOEq99p.js → move-BX67lOdq.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BlQI5jrw.js → mtc-parser-CmAbG1fE.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DlW4gxmv.js → omit-DiU5tI1_.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BBYms5nP.js → pickAttrs-BGfvLrYL.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-az2MPJ_7.js → placementArrow-CggLEgaJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D1-ibEol.js → responsiveObserve-t3nlghPZ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DHGqa4GA.js → slide-BkV4dL9s.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CYGDo6lD.js → statusUtils-qec1PUoC.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Cl2EM9K6.js → styleChecker-ChjX6T8D.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DdYhzuv1.js → useFlexGapSupport-B1jLoZcM.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DWumPuBW.js → useFs-C3X53s4E.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DxAO-Aqi.js → usePersonalDataHub-DOvbbnkZ.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CplsQf_N.js → vnode-Ie0TEVFT.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cw5HXNSG.js → zoom-CRUMVS8l.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +18 -1
- package/src/commands/evolution-benchmark.js +72 -0
- package/src/commands/evolution.js +2 -0
- package/src/commands/governed-skill-marketplace.js +142 -0
- package/src/commands/marketplace.js +4 -1
- package/src/commands/serve.js +41 -0
- package/src/commands/skill.js +3 -0
- package/src/data/changelog.json +39 -0
- package/src/gateways/ws/ws-agent-handler.js +59 -2
- package/src/gateways/ws/ws-server.js +2 -0
- package/src/harness/golden-transcript.js +1 -0
- package/src/harness/prompt-compressor.js +51 -5
- package/src/harness/provider-backed-compaction.js +28 -1
- package/src/harness/remote-session-registry.js +15 -3
- package/src/index.js +30 -4
- package/src/lazy-dispatch.js +15 -1
- package/src/lib/advisor-runtime.js +55 -2
- package/src/lib/app-server/cli-agent-kernel-adapter.js +4 -0
- package/src/lib/app-server/graph-runtime.js +32 -0
- package/src/lib/app-server/server.js +45 -1
- package/src/lib/app-server/websocket-transport.js +23 -0
- package/src/lib/autonomous-agent.js +63 -13
- package/src/lib/cowork/ab-comparator-cli.js +4 -3
- package/src/lib/cowork/debate-review-cli.js +4 -3
- package/src/lib/cowork/decision-kb-cli.js +5 -0
- package/src/lib/cowork-adapter.js +38 -16
- package/src/lib/evolution/agent-evolution-ingress.js +95 -15
- package/src/lib/evolution/agent-evolution-runtime-composition.js +82 -0
- package/src/lib/evolution/agent-evolution-session-lifecycle.js +46 -0
- package/src/lib/evolution/agent-model-projection.js +217 -0
- package/src/lib/evolution/bounded-descriptor-read.js +29 -0
- package/src/lib/evolution/controlled-skill-pilot-ledger-adapter.js +551 -0
- package/src/lib/evolution/controlled-skill-production-pilot.js +308 -18
- package/src/lib/evolution/evidence-backed-wiki-maintainer.js +10 -1
- package/src/lib/evolution/evidence-json-text.js +236 -0
- package/src/lib/evolution/evolution-artifact-ports.js +202 -21
- package/src/lib/evolution/evolution-deployment-loader.js +369 -0
- package/src/lib/evolution/evolution-eval-child-evidence-ledger-adapter.js +373 -0
- package/src/lib/evolution/evolution-eval-gate.js +14 -1
- package/src/lib/evolution/evolution-eval-process-supervisor-worker.mjs +14 -0
- package/src/lib/evolution/evolution-eval-process-supervisor.js +607 -0
- package/src/lib/evolution/evolution-evidence-artifact-adapter.js +14 -1
- package/src/lib/evolution/evolution-evidence-projector.js +240 -37
- package/src/lib/evolution/evolution-file-witness.js +153 -30
- package/src/lib/evolution/evolution-ledger-ports.js +1027 -66
- package/src/lib/evolution/evolution-ledger.js +66 -2
- package/src/lib/evolution/evolution-raw-crypto-shred.js +29 -15
- package/src/lib/evolution/evolution-raw-deletion-ledger-adapter.js +865 -0
- package/src/lib/evolution/evolution-release-train-domain-stages.js +769 -0
- package/src/lib/evolution/evolution-release-train-ledger-adapter.js +335 -0
- package/src/lib/evolution/evolution-release-train-stage-output-ledger-adapter.js +333 -0
- package/src/lib/evolution/evolution-release-train.js +586 -0
- package/src/lib/evolution/evolution-workbench-batch-executor.js +101 -144
- package/src/lib/evolution/evolution-workbench-control-ports.js +203 -0
- package/src/lib/evolution/evolution-workbench-file-resources.js +403 -0
- package/src/lib/evolution/evolution-workbench-projection.js +152 -25
- package/src/lib/evolution/evolution-workbench-registry-source.js +482 -0
- package/src/lib/evolution/evolution-workbench-review-ledger-adapter.js +823 -0
- package/src/lib/evolution/evolution-workbench-review-protocol.js +157 -0
- package/src/lib/evolution/evolution-workbench-rollback-authorization.js +57 -0
- package/src/lib/evolution/evolution-workbench-rollback-ledger-adapter.js +1016 -0
- package/src/lib/evolution/evolution-workbench-runtime.js +133 -0
- package/src/lib/evolution/evolution-workbench-version-control.js +70 -36
- package/src/lib/evolution/evolvable-artifact-ledger-adapter.js +736 -0
- package/src/lib/evolution/governed-knowledge-artifact-lifecycle.js +364 -0
- package/src/lib/evolution/governed-knowledge-candidate-rejection.js +343 -0
- package/src/lib/evolution/governed-knowledge-dependency-authority.js +227 -44
- package/src/lib/evolution/governed-knowledge-dependency-ledger-executor.js +95 -83
- package/src/lib/evolution/governed-knowledge-merge-ledger-executor.js +29 -2
- package/src/lib/evolution/governed-knowledge-merge-publisher-authority.js +31 -3
- package/src/lib/evolution/governed-knowledge-record.js +148 -0
- package/src/lib/evolution/governed-knowledge-revocation-record.js +135 -0
- package/src/lib/evolution/governed-knowledge-skill-rollback.js +475 -0
- package/src/lib/evolution/governed-knowledge-sync-ledger-adapter.js +92 -6
- package/src/lib/evolution/governed-knowledge-sync-merge-publisher.js +57 -4
- package/src/lib/evolution/governed-knowledge-sync.js +332 -99
- package/src/lib/evolution/governed-knowledge-wiki-tombstone.js +462 -0
- package/src/lib/evolution/governed-skill-marketplace-badge.js +208 -0
- package/src/lib/evolution/governed-skill-marketplace-candidate.js +330 -0
- package/src/lib/evolution/governed-skill-marketplace-cli-host.js +308 -0
- package/src/lib/evolution/governed-skill-marketplace-ledger-adapter.js +420 -0
- package/src/lib/evolution/governed-skill-marketplace.js +288 -5
- package/src/lib/evolution/governed-wiki-pruning-journal.js +302 -0
- package/src/lib/evolution/governed-wiki-pruning-ledger-adapter.js +459 -0
- package/src/lib/evolution/governed-wiki-pruning-maintenance.js +576 -0
- package/src/lib/evolution/governed-wiki-pruning-plan-authority.js +169 -0
- package/src/lib/evolution/governed-wiki-pruning-raw-shred.js +207 -0
- package/src/lib/evolution/governed-wiki-pruning-retrieval.js +587 -0
- package/src/lib/evolution/governed-wiki-pruning-runtime.js +153 -0
- package/src/lib/evolution/governed-wiki-pruning-skill-rollback.js +360 -0
- package/src/lib/evolution/governed-wiki-pruning.js +322 -143
- package/src/lib/evolution/independent-skill-revocation-source.js +231 -0
- package/src/lib/evolution/knowledge-wiki-source-admission.js +124 -0
- package/src/lib/evolution/knowledge-wiki-source-provenance.js +359 -0
- package/src/lib/evolution/progressive-canary-external-watchdog.js +578 -0
- package/src/lib/evolution/progressive-canary-traffic-worker.js +628 -0
- package/src/lib/evolution/progressive-canary-watchdog-file-store.js +285 -0
- package/src/lib/evolution/progressive-canary-watchdog-node-pki.js +265 -0
- package/src/lib/evolution/skill-candidate-registry.js +22 -0
- package/src/lib/evolution/skill-promotion-controller.js +25 -0
- package/src/lib/evolution/skill-promotion-review-ledger-adapter.js +100 -0
- package/src/lib/evolution/skill-registry-transition-ledger-adapter.js +131 -2
- package/src/lib/evolution/skill-release-registry.js +25 -4
- package/src/lib/evolution/skill-retrieval-revocation-authority.js +361 -0
- package/src/lib/evolution/skill-retrieval-revocation-ledger-adapter.js +346 -0
- package/src/lib/evolution/skill-revocation-propagation.js +467 -0
- package/src/lib/evolution/skill-target-matrix-eval.js +162 -11
- package/src/lib/evolution/skill-wiki-reconciliation.js +985 -0
- package/src/lib/evolution/skill-writer-inventory-manifest.js +15 -12
- package/src/lib/evolution/statistical-progressive-canary.js +845 -0
- package/src/lib/evolution/structured-memory-agent-control-plane.js +120 -0
- package/src/lib/evolution/structured-memory-authority-ledger-adapter.js +5 -1
- package/src/lib/evolution/structured-memory-promotion-receipt-writer.js +126 -0
- package/src/lib/evolution/wiki-informed-skill-proposer.js +127 -21
- package/src/lib/evolution/wiki-maintainer-ledger-adapter.js +760 -100
- package/src/lib/evolution/wiki-revision-protocol.js +120 -0
- package/src/lib/evolution/wiki-skill-proposal-ledger-adapter.js +307 -0
- package/src/lib/evolution/wiki-target-tombstone-revision.js +101 -0
- package/src/lib/evolution/wikiskill-benchmark-cli-host.js +178 -0
- package/src/lib/evolution/wikiskill-benchmark-execution-host.js +702 -0
- package/src/lib/evolution/wikiskill-benchmark-ledger-adapter.js +613 -0
- package/src/lib/evolution/wikiskill-benchmark.js +574 -0
- package/src/lib/goal-assess.js +17 -10
- package/src/lib/interactive-planner.js +9 -1
- package/src/lib/iteration-budget.js +16 -2
- package/src/lib/micro-compact.js +4 -1
- package/src/lib/model-failure-policy.js +21 -0
- package/src/lib/process-execution-broker/index.js +1 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +33 -15
- package/src/lib/read-file-page.js +191 -0
- package/src/lib/runnable-provider.js +2 -1
- package/src/lib/session-host-lease.js +11 -16
- package/src/lib/skill-retrieval-router.js +22 -1
- package/src/repl/agent-repl.js +127 -33
- package/src/runtime/agent-core.js +224 -80
- package/src/runtime/agent-runtime.js +43 -0
- package/src/runtime/coding-agent-contract-shared.cjs +7 -1
- package/src/runtime/fallback-model.js +143 -62
- package/src/runtime/headless-runner.js +54 -10
- package/src/runtime/headless-stream.js +53 -6
- package/src/runtime/runtime-factory.js +41 -2
- package/src/assets/web-panel/assets/Notes-CgU9DDo9.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-CwHc15Zs.js +0 -1
- package/src/assets/web-panel/assets/Projects-FF_thRi6.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-l7ox6KuX.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DyhgpXPf.js +0 -1
- package/src/assets/web-panel/assets/index-Ck1jhFE0.js +0 -1
- package/src/assets/web-panel/assets/index-c8jJEHVs.js +0 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { lstat, mkdir, readdir, realpath } from "node:fs/promises";
|
|
4
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { withFileLock } from "../with-file-lock.js";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createProgressiveCanaryHeartbeatSource,
|
|
9
|
+
createProgressiveCanaryWatchdogIncidentStore,
|
|
10
|
+
} from "./progressive-canary-external-watchdog.js";
|
|
11
|
+
|
|
12
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
13
|
+
const MAX_RECORD_BYTES = 1024 * 1024;
|
|
14
|
+
const MAX_HEARTBEATS = 10_000;
|
|
15
|
+
|
|
16
|
+
function sha(value) {
|
|
17
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function digest(value, label) {
|
|
21
|
+
if (!DIGEST.test(value ?? "")) throw new TypeError(`${label} is invalid`);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function safeName(value) {
|
|
26
|
+
return digest(value, "record digest").slice(7);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function assertDirectory(path, label) {
|
|
30
|
+
const info = await lstat(path);
|
|
31
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
32
|
+
throw new Error(`${label} is not a physical directory`);
|
|
33
|
+
return realpath(path);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function readRecord(path, label) {
|
|
37
|
+
let info;
|
|
38
|
+
try {
|
|
39
|
+
info = fs.lstatSync(path);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error.code === "ENOENT") return null;
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
if (
|
|
45
|
+
!info.isFile() ||
|
|
46
|
+
info.isSymbolicLink() ||
|
|
47
|
+
info.nlink !== 1 ||
|
|
48
|
+
info.size < 2 ||
|
|
49
|
+
info.size > MAX_RECORD_BYTES
|
|
50
|
+
)
|
|
51
|
+
throw new Error(`${label} is not an admissible regular file`);
|
|
52
|
+
const bytes = fs.readFileSync(path);
|
|
53
|
+
if (bytes.length !== info.size)
|
|
54
|
+
throw new Error(`${label} changed during readback`);
|
|
55
|
+
let value;
|
|
56
|
+
try {
|
|
57
|
+
value = JSON.parse(bytes.toString("utf8"));
|
|
58
|
+
} catch (cause) {
|
|
59
|
+
throw new Error(`${label} is not JSON`, { cause });
|
|
60
|
+
}
|
|
61
|
+
// null denotes an absent file to callers, never a present JSON payload.
|
|
62
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
63
|
+
throw new Error(`${label} must contain an object`);
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function replaceRecord(path, value, label) {
|
|
68
|
+
const encoded = Buffer.from(JSON.stringify(value), "utf8");
|
|
69
|
+
if (encoded.length < 2 || encoded.length > MAX_RECORD_BYTES)
|
|
70
|
+
throw new TypeError(`${label} exceeds its size bound`);
|
|
71
|
+
const stagingPath = `${path}.staging-${randomBytes(32).toString("hex")}`;
|
|
72
|
+
let descriptor;
|
|
73
|
+
let staged = false;
|
|
74
|
+
try {
|
|
75
|
+
descriptor = fs.openSync(stagingPath, "wx", 0o600);
|
|
76
|
+
staged = true;
|
|
77
|
+
fs.writeFileSync(descriptor, encoded);
|
|
78
|
+
fs.fsyncSync(descriptor);
|
|
79
|
+
fs.closeSync(descriptor);
|
|
80
|
+
descriptor = undefined;
|
|
81
|
+
// All writers hold the same strict cross-process lock. Readers only see
|
|
82
|
+
// the old complete record or the new complete record, never a wx-created
|
|
83
|
+
// empty/partial reservation. Staging names are outside the reader index.
|
|
84
|
+
fs.renameSync(stagingPath, path);
|
|
85
|
+
staged = false;
|
|
86
|
+
} finally {
|
|
87
|
+
if (descriptor !== undefined) fs.closeSync(descriptor);
|
|
88
|
+
if (staged) fs.unlinkSync(stagingPath);
|
|
89
|
+
}
|
|
90
|
+
const readback = readRecord(path, label);
|
|
91
|
+
if (JSON.stringify(readback) !== encoded.toString("utf8"))
|
|
92
|
+
throw new Error(`${label} durable readback differs`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function writeOnce(path, value, label) {
|
|
96
|
+
return withFileLock(
|
|
97
|
+
path,
|
|
98
|
+
() => {
|
|
99
|
+
const prior = readRecord(path, label);
|
|
100
|
+
if (prior !== null) {
|
|
101
|
+
if (JSON.stringify(prior) !== JSON.stringify(value))
|
|
102
|
+
throw new Error(`${label} conflicts with an existing record`);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
replaceRecord(path, value, label);
|
|
106
|
+
return true;
|
|
107
|
+
},
|
|
108
|
+
{ failIfUnavailable: true },
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function heartbeatName(receipt) {
|
|
113
|
+
if (!Number.isSafeInteger(receipt?.sequence) || receipt.sequence < 0)
|
|
114
|
+
throw new TypeError("heartbeat sequence is invalid");
|
|
115
|
+
digest(receipt.receiptDigest, "heartbeat receiptDigest");
|
|
116
|
+
return `${String(receipt.sequence).padStart(16, "0")}-${safeName(
|
|
117
|
+
receipt.receiptDigest,
|
|
118
|
+
)}.json`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function createProgressiveCanaryWatchdogFileStore({
|
|
122
|
+
rootDir,
|
|
123
|
+
planDigest,
|
|
124
|
+
hostId,
|
|
125
|
+
} = {}) {
|
|
126
|
+
if (typeof rootDir !== "string" || !isAbsolute(rootDir))
|
|
127
|
+
throw new TypeError("watchdog rootDir must be absolute");
|
|
128
|
+
digest(planDigest, "planDigest");
|
|
129
|
+
if (typeof hostId !== "string" || hostId.length < 1)
|
|
130
|
+
throw new TypeError("hostId is required");
|
|
131
|
+
const requestedRoot = resolve(rootDir);
|
|
132
|
+
await mkdir(requestedRoot, { recursive: true, mode: 0o700 });
|
|
133
|
+
const root = await assertDirectory(requestedRoot, "watchdog root");
|
|
134
|
+
const heartbeatsDir = join(root, "heartbeats");
|
|
135
|
+
const incidentsDir = join(root, "incidents");
|
|
136
|
+
const reservationsDir = join(root, "reservations");
|
|
137
|
+
await mkdir(heartbeatsDir, { recursive: true, mode: 0o700 });
|
|
138
|
+
await mkdir(incidentsDir, { recursive: true, mode: 0o700 });
|
|
139
|
+
await mkdir(reservationsDir, { recursive: true, mode: 0o700 });
|
|
140
|
+
await Promise.all([
|
|
141
|
+
assertDirectory(heartbeatsDir, "heartbeat directory"),
|
|
142
|
+
assertDirectory(incidentsDir, "incident directory"),
|
|
143
|
+
assertDirectory(reservationsDir, "reservation directory"),
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
async function publishHeartbeat(receipt) {
|
|
147
|
+
if (
|
|
148
|
+
receipt?.planDigest !== planDigest ||
|
|
149
|
+
receipt?.hostId !== hostId ||
|
|
150
|
+
!DIGEST.test(receipt?.receiptDigest ?? "")
|
|
151
|
+
)
|
|
152
|
+
throw new Error("heartbeat belongs to another watchdog store");
|
|
153
|
+
const path = join(heartbeatsDir, heartbeatName(receipt));
|
|
154
|
+
await writeOnce(path, receipt, "heartbeat record");
|
|
155
|
+
return Object.freeze({
|
|
156
|
+
authenticated: true,
|
|
157
|
+
durable: true,
|
|
158
|
+
receiptDigest: receipt.receiptDigest,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const heartbeatSource = createProgressiveCanaryHeartbeatSource({
|
|
163
|
+
async readLatest(binding) {
|
|
164
|
+
if (binding?.planDigest !== planDigest || binding?.hostId !== hostId)
|
|
165
|
+
throw new Error("heartbeat source binding differs");
|
|
166
|
+
const names = (await readdir(heartbeatsDir)).filter((name) =>
|
|
167
|
+
/^\d{16}-[a-f0-9]{64}\.json$/u.test(name),
|
|
168
|
+
);
|
|
169
|
+
if (names.length > MAX_HEARTBEATS)
|
|
170
|
+
throw new Error("heartbeat store exceeds its bounded history");
|
|
171
|
+
if (names.length === 0)
|
|
172
|
+
return Object.freeze({
|
|
173
|
+
authenticated: false,
|
|
174
|
+
durable: true,
|
|
175
|
+
receipt: null,
|
|
176
|
+
});
|
|
177
|
+
names.sort().reverse();
|
|
178
|
+
const receipt = await readRecord(
|
|
179
|
+
join(heartbeatsDir, names[0]),
|
|
180
|
+
"latest heartbeat",
|
|
181
|
+
);
|
|
182
|
+
if (
|
|
183
|
+
receipt?.planDigest !== planDigest ||
|
|
184
|
+
receipt?.hostId !== hostId ||
|
|
185
|
+
heartbeatName(receipt) !== names[0]
|
|
186
|
+
)
|
|
187
|
+
throw new Error("latest heartbeat filename binding differs");
|
|
188
|
+
if (names.length > 1 && names[1].slice(0, 16) === names[0].slice(0, 16))
|
|
189
|
+
throw new Error("latest heartbeat sequence is equivocated");
|
|
190
|
+
return Object.freeze({
|
|
191
|
+
authenticated: true,
|
|
192
|
+
durable: true,
|
|
193
|
+
receipt,
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const incidentStore = createProgressiveCanaryWatchdogIncidentStore({
|
|
199
|
+
async reserve(binding) {
|
|
200
|
+
if (binding?.planDigest !== planDigest)
|
|
201
|
+
throw new Error("incident reservation belongs to another plan");
|
|
202
|
+
const incidentDigest = digest(binding.incidentDigest, "incidentDigest");
|
|
203
|
+
if (
|
|
204
|
+
!Number.isSafeInteger(binding.observedAt) ||
|
|
205
|
+
binding.observedAt < 0 ||
|
|
206
|
+
!Number.isSafeInteger(binding.leaseDurationMs) ||
|
|
207
|
+
binding.leaseDurationMs < 1_000
|
|
208
|
+
)
|
|
209
|
+
throw new TypeError("incident reservation lease is invalid");
|
|
210
|
+
const path = join(reservationsDir, `${safeName(incidentDigest)}.json`);
|
|
211
|
+
const reservation = {
|
|
212
|
+
planDigest,
|
|
213
|
+
incidentDigest,
|
|
214
|
+
nonce: randomBytes(32).toString("base64url"),
|
|
215
|
+
acquiredAt: binding.observedAt,
|
|
216
|
+
expiresAt: binding.observedAt + binding.leaseDurationMs,
|
|
217
|
+
};
|
|
218
|
+
const acquired = withFileLock(
|
|
219
|
+
path,
|
|
220
|
+
() => {
|
|
221
|
+
const current = readRecord(path, "incident reservation");
|
|
222
|
+
if (current !== null) {
|
|
223
|
+
if (
|
|
224
|
+
current.planDigest !== planDigest ||
|
|
225
|
+
current.incidentDigest !== incidentDigest ||
|
|
226
|
+
!Number.isSafeInteger(current.expiresAt)
|
|
227
|
+
)
|
|
228
|
+
throw new Error("incident reservation binding is invalid");
|
|
229
|
+
if (current.expiresAt >= binding.observedAt) return false;
|
|
230
|
+
}
|
|
231
|
+
replaceRecord(path, reservation, "incident reservation");
|
|
232
|
+
return true;
|
|
233
|
+
},
|
|
234
|
+
{ failIfUnavailable: true },
|
|
235
|
+
);
|
|
236
|
+
return Object.freeze({
|
|
237
|
+
authenticated: true,
|
|
238
|
+
durable: true,
|
|
239
|
+
acquired,
|
|
240
|
+
incidentDigest,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
async load(binding) {
|
|
244
|
+
if (binding?.planDigest !== planDigest)
|
|
245
|
+
throw new Error("incident load belongs to another plan");
|
|
246
|
+
const incidentDigest = digest(binding.incidentDigest, "incidentDigest");
|
|
247
|
+
const value = await readRecord(
|
|
248
|
+
join(incidentsDir, `${safeName(incidentDigest)}.json`),
|
|
249
|
+
"watchdog incident",
|
|
250
|
+
);
|
|
251
|
+
if (
|
|
252
|
+
value &&
|
|
253
|
+
(value.planDigest !== planDigest ||
|
|
254
|
+
value.incidentDigest !== incidentDigest)
|
|
255
|
+
)
|
|
256
|
+
throw new Error("watchdog incident filename binding differs");
|
|
257
|
+
return value;
|
|
258
|
+
},
|
|
259
|
+
async commit(incident) {
|
|
260
|
+
if (
|
|
261
|
+
incident?.planDigest !== planDigest ||
|
|
262
|
+
!DIGEST.test(incident?.incidentDigest ?? "")
|
|
263
|
+
)
|
|
264
|
+
throw new Error("watchdog incident belongs to another plan");
|
|
265
|
+
await writeOnce(
|
|
266
|
+
join(incidentsDir, `${safeName(incident.incidentDigest)}.json`),
|
|
267
|
+
incident,
|
|
268
|
+
"watchdog incident",
|
|
269
|
+
);
|
|
270
|
+
return Object.freeze({
|
|
271
|
+
authenticated: true,
|
|
272
|
+
durable: true,
|
|
273
|
+
incidentDigest: incident.incidentDigest,
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
return Object.freeze({
|
|
279
|
+
rootDir: root,
|
|
280
|
+
storeDigest: sha(`${planDigest}\0${hostId}\0${root}`),
|
|
281
|
+
publishHeartbeat,
|
|
282
|
+
heartbeatSource,
|
|
283
|
+
incidentStore,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createHash,
|
|
3
|
+
createPrivateKey,
|
|
4
|
+
createPublicKey,
|
|
5
|
+
sign,
|
|
6
|
+
verify,
|
|
7
|
+
} from "node:crypto";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
createProgressiveCanaryExternalRollbackAuthority,
|
|
11
|
+
createProgressiveCanaryHeartbeatAuthority,
|
|
12
|
+
} from "./progressive-canary-external-watchdog.js";
|
|
13
|
+
|
|
14
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
15
|
+
const ACTION_RECEIPT_SCHEMA =
|
|
16
|
+
"chainlesschain.progressive-canary-watchdog-action-receipt/v1";
|
|
17
|
+
|
|
18
|
+
function canonical(value) {
|
|
19
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
20
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
21
|
+
return `{${Object.keys(value)
|
|
22
|
+
.sort()
|
|
23
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
24
|
+
.join(",")}}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function sha(bytes) {
|
|
28
|
+
return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function domainDigest(value) {
|
|
32
|
+
return sha(`${ACTION_RECEIPT_SCHEMA}\0${canonical(value)}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function publicKeyObject(input, label) {
|
|
36
|
+
let key;
|
|
37
|
+
try {
|
|
38
|
+
key = input?.type === "public" ? input : createPublicKey(input);
|
|
39
|
+
} catch (cause) {
|
|
40
|
+
throw new TypeError(`${label} is invalid`, { cause });
|
|
41
|
+
}
|
|
42
|
+
if (key.asymmetricKeyType !== "ed25519")
|
|
43
|
+
throw new TypeError(`${label} must be Ed25519`);
|
|
44
|
+
return key;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function privateKeyObject(input, label) {
|
|
48
|
+
let key;
|
|
49
|
+
try {
|
|
50
|
+
key = input?.type === "private" ? input : createPrivateKey(input);
|
|
51
|
+
} catch (cause) {
|
|
52
|
+
throw new TypeError(`${label} is invalid`, { cause });
|
|
53
|
+
}
|
|
54
|
+
if (key.asymmetricKeyType !== "ed25519")
|
|
55
|
+
throw new TypeError(`${label} must be Ed25519`);
|
|
56
|
+
return key;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function progressiveCanaryPublicKeySpkiDigest(publicKeyInput) {
|
|
60
|
+
const key = publicKeyObject(publicKeyInput, "publicKey");
|
|
61
|
+
return sha(key.export({ type: "spki", format: "der" }));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function signatureBytes(value) {
|
|
65
|
+
if (typeof value !== "string" || value.length < 32) return null;
|
|
66
|
+
const bytes = Buffer.from(value, "base64url");
|
|
67
|
+
return bytes.toString("base64url") === value ? bytes : null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function signer(privateKeyInput, publicKeyInput, expectedDigest, label) {
|
|
71
|
+
const publicKey = publicKeyObject(publicKeyInput, `${label} publicKey`);
|
|
72
|
+
if (progressiveCanaryPublicKeySpkiDigest(publicKey) !== expectedDigest)
|
|
73
|
+
throw new Error(`${label} public key does not match the watchdog plan`);
|
|
74
|
+
const privateKey =
|
|
75
|
+
privateKeyInput === null || privateKeyInput === undefined
|
|
76
|
+
? null
|
|
77
|
+
: privateKeyObject(privateKeyInput, `${label} privateKey`);
|
|
78
|
+
if (
|
|
79
|
+
privateKey &&
|
|
80
|
+
progressiveCanaryPublicKeySpkiDigest(createPublicKey(privateKey)) !==
|
|
81
|
+
expectedDigest
|
|
82
|
+
)
|
|
83
|
+
throw new Error(`${label} private key does not match its public key`);
|
|
84
|
+
return Object.freeze({ privateKey, publicKey });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createNodeProgressiveCanaryHeartbeatAuthority({
|
|
88
|
+
plan,
|
|
89
|
+
privateKey = null,
|
|
90
|
+
publicKey,
|
|
91
|
+
now = Date.now,
|
|
92
|
+
} = {}) {
|
|
93
|
+
const keys = signer(
|
|
94
|
+
privateKey,
|
|
95
|
+
publicKey,
|
|
96
|
+
plan?.heartbeatAuthority?.publicKeySpkiDigest,
|
|
97
|
+
"heartbeat authority",
|
|
98
|
+
);
|
|
99
|
+
return createProgressiveCanaryHeartbeatAuthority({
|
|
100
|
+
plan,
|
|
101
|
+
now,
|
|
102
|
+
attestor: async (payload) => {
|
|
103
|
+
if (!keys.privateKey)
|
|
104
|
+
throw new Error("heartbeat signing key is unavailable in this process");
|
|
105
|
+
return sign(
|
|
106
|
+
null,
|
|
107
|
+
Buffer.from(canonical(payload), "utf8"),
|
|
108
|
+
keys.privateKey,
|
|
109
|
+
).toString("base64url");
|
|
110
|
+
},
|
|
111
|
+
verifier: async ({ payload, signature }) => {
|
|
112
|
+
const bytes = signatureBytes(signature);
|
|
113
|
+
return (
|
|
114
|
+
bytes !== null &&
|
|
115
|
+
verify(
|
|
116
|
+
null,
|
|
117
|
+
Buffer.from(canonical(payload), "utf8"),
|
|
118
|
+
keys.publicKey,
|
|
119
|
+
bytes,
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function validateEffect(value, action, plan, request) {
|
|
127
|
+
if (
|
|
128
|
+
value?.authenticated !== true ||
|
|
129
|
+
value?.durable !== true ||
|
|
130
|
+
value.incidentDigest !== request.incidentDigest ||
|
|
131
|
+
!DIGEST.test(value.effectDigest ?? "")
|
|
132
|
+
)
|
|
133
|
+
throw new Error(`${action} effect was not durably authenticated`);
|
|
134
|
+
if (
|
|
135
|
+
action === "kill" &&
|
|
136
|
+
(value.hostId !== plan.hostId || value.processAbsent !== true)
|
|
137
|
+
)
|
|
138
|
+
throw new Error("kill effect did not prove the host process is absent");
|
|
139
|
+
if (
|
|
140
|
+
action === "rollback" &&
|
|
141
|
+
(value.baselineDigest !== plan.baselineDigest ||
|
|
142
|
+
!DIGEST.test(value.activeStateDigest ?? ""))
|
|
143
|
+
)
|
|
144
|
+
throw new Error("rollback effect did not prove the LKG readback");
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function actionCore(plan, request, action, effect) {
|
|
149
|
+
return {
|
|
150
|
+
schema: ACTION_RECEIPT_SCHEMA,
|
|
151
|
+
authenticated: true,
|
|
152
|
+
durable: true,
|
|
153
|
+
action,
|
|
154
|
+
planDigest: plan.planDigest,
|
|
155
|
+
incidentDigest: request.incidentDigest,
|
|
156
|
+
authorityId: plan.rollbackAuthority.id,
|
|
157
|
+
authorityRevision: plan.rollbackAuthority.revision,
|
|
158
|
+
handlerDigest: plan.rollbackAuthority.handlerDigest,
|
|
159
|
+
publicKeySpkiDigest: plan.rollbackAuthority.publicKeySpkiDigest,
|
|
160
|
+
effectDigest: effect.effectDigest,
|
|
161
|
+
...(action === "kill"
|
|
162
|
+
? { hostId: plan.hostId }
|
|
163
|
+
: {
|
|
164
|
+
baselineDigest: plan.baselineDigest,
|
|
165
|
+
activeStateDigest: effect.activeStateDigest,
|
|
166
|
+
}),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function createNodeProgressiveCanaryExternalRollbackAuthority({
|
|
171
|
+
plan,
|
|
172
|
+
privateKey,
|
|
173
|
+
publicKey,
|
|
174
|
+
killHost,
|
|
175
|
+
rollbackToBaseline,
|
|
176
|
+
} = {}) {
|
|
177
|
+
if (
|
|
178
|
+
typeof killHost !== "function" ||
|
|
179
|
+
typeof rollbackToBaseline !== "function"
|
|
180
|
+
)
|
|
181
|
+
throw new TypeError("Node watchdog effect ports are required");
|
|
182
|
+
const keys = signer(
|
|
183
|
+
privateKey,
|
|
184
|
+
publicKey,
|
|
185
|
+
plan?.rollbackAuthority?.publicKeySpkiDigest,
|
|
186
|
+
"rollback authority",
|
|
187
|
+
);
|
|
188
|
+
if (!keys.privateKey)
|
|
189
|
+
throw new TypeError("rollback authority privateKey is required");
|
|
190
|
+
|
|
191
|
+
async function issue(action, request, perform) {
|
|
192
|
+
const effect = validateEffect(
|
|
193
|
+
await perform(request),
|
|
194
|
+
action,
|
|
195
|
+
plan,
|
|
196
|
+
request,
|
|
197
|
+
);
|
|
198
|
+
const core = actionCore(plan, request, action, effect);
|
|
199
|
+
const signature = sign(
|
|
200
|
+
null,
|
|
201
|
+
Buffer.from(canonical(core), "utf8"),
|
|
202
|
+
keys.privateKey,
|
|
203
|
+
).toString("base64url");
|
|
204
|
+
const signed = { ...core, signature };
|
|
205
|
+
return Object.freeze({
|
|
206
|
+
...signed,
|
|
207
|
+
receiptDigest: domainDigest(signed),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function verifyReceipt({ request, receipt }) {
|
|
212
|
+
if (
|
|
213
|
+
receipt?.schema !== ACTION_RECEIPT_SCHEMA ||
|
|
214
|
+
receipt.receiptDigest !==
|
|
215
|
+
domainDigest(
|
|
216
|
+
Object.fromEntries(
|
|
217
|
+
Object.entries(receipt).filter(([key]) => key !== "receiptDigest"),
|
|
218
|
+
),
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
return false;
|
|
222
|
+
const signature = signatureBytes(receipt.signature);
|
|
223
|
+
if (!signature) return false;
|
|
224
|
+
const signed = structuredClone(receipt);
|
|
225
|
+
delete signed.receiptDigest;
|
|
226
|
+
const unsigned = structuredClone(signed);
|
|
227
|
+
delete unsigned.signature;
|
|
228
|
+
const expected = actionCore(
|
|
229
|
+
plan,
|
|
230
|
+
request,
|
|
231
|
+
receipt.action,
|
|
232
|
+
receipt.action === "kill"
|
|
233
|
+
? {
|
|
234
|
+
effectDigest: receipt.effectDigest,
|
|
235
|
+
}
|
|
236
|
+
: {
|
|
237
|
+
effectDigest: receipt.effectDigest,
|
|
238
|
+
activeStateDigest: receipt.activeStateDigest,
|
|
239
|
+
},
|
|
240
|
+
);
|
|
241
|
+
return (
|
|
242
|
+
canonical(unsigned) === canonical(expected) &&
|
|
243
|
+
verify(
|
|
244
|
+
null,
|
|
245
|
+
Buffer.from(canonical(unsigned), "utf8"),
|
|
246
|
+
keys.publicKey,
|
|
247
|
+
signature,
|
|
248
|
+
)
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return createProgressiveCanaryExternalRollbackAuthority({
|
|
253
|
+
plan,
|
|
254
|
+
killHost: (request) =>
|
|
255
|
+
issue("kill", request, (value) =>
|
|
256
|
+
killHost({ ...value, hostId: plan.hostId }),
|
|
257
|
+
),
|
|
258
|
+
rollbackToBaseline: (request) =>
|
|
259
|
+
issue("rollback", request, (value) =>
|
|
260
|
+
rollbackToBaseline({ ...value, baselineDigest: plan.baselineDigest }),
|
|
261
|
+
),
|
|
262
|
+
verifyKill: verifyReceipt,
|
|
263
|
+
verifyRollback: verifyReceipt,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
@@ -1529,6 +1529,19 @@ function normalizeRegistryOptions(options) {
|
|
|
1529
1529
|
* This class deliberately has no active pointer or promotion API. A later
|
|
1530
1530
|
* promotion controller can consume verified drafts through read().
|
|
1531
1531
|
*/
|
|
1532
|
+
const CANDIDATE_READERS = new WeakMap();
|
|
1533
|
+
|
|
1534
|
+
export function captureSkillCandidateRegistryReader(registry) {
|
|
1535
|
+
const reader = CANDIDATE_READERS.get(registry);
|
|
1536
|
+
if (
|
|
1537
|
+
!reader ||
|
|
1538
|
+
Object.getPrototypeOf(registry) !== SkillCandidateRegistry.prototype
|
|
1539
|
+
) {
|
|
1540
|
+
throw new TypeError("a genuine SkillCandidateRegistry reader is required");
|
|
1541
|
+
}
|
|
1542
|
+
return reader;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1532
1545
|
export class SkillCandidateRegistry {
|
|
1533
1546
|
constructor(options) {
|
|
1534
1547
|
const {
|
|
@@ -1578,6 +1591,13 @@ export class SkillCandidateRegistry {
|
|
|
1578
1591
|
);
|
|
1579
1592
|
}
|
|
1580
1593
|
Object.freeze(this);
|
|
1594
|
+
CANDIDATE_READERS.set(
|
|
1595
|
+
this,
|
|
1596
|
+
Object.freeze({
|
|
1597
|
+
tenantId,
|
|
1598
|
+
read: Object.freeze(SkillCandidateRegistry.prototype.read.bind(this)),
|
|
1599
|
+
}),
|
|
1600
|
+
);
|
|
1581
1601
|
}
|
|
1582
1602
|
|
|
1583
1603
|
_initializeDirectory(
|
|
@@ -2905,3 +2925,5 @@ export class SkillCandidateRegistry {
|
|
|
2905
2925
|
return Object.freeze(candidates);
|
|
2906
2926
|
}
|
|
2907
2927
|
}
|
|
2928
|
+
|
|
2929
|
+
Object.freeze(SkillCandidateRegistry.prototype);
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
issueRegistryTransitionCapability,
|
|
20
20
|
} from "./skill-registry-transition-capability.js";
|
|
21
21
|
import { captureSkillPromotionReviewProvider } from "./skill-promotion-review.js";
|
|
22
|
+
import { captureSkillReleaseRegistryReader } from "./skill-release-registry.js";
|
|
22
23
|
|
|
23
24
|
const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/u;
|
|
24
25
|
const EMPTY_ACTIVE_DOMAIN = "chainlesschain.skill-active/empty/v1\0";
|
|
@@ -47,6 +48,16 @@ const EVALUATED_CONTROL_PLANE_REQUIRED_KEYS = new Set([
|
|
|
47
48
|
export const SKILL_EVALUATED_PROMOTION_CONTROL_PLANE_SCHEMA =
|
|
48
49
|
"chainlesschain.skill-evaluated-promotion-control-plane/v1";
|
|
49
50
|
const EVALUATED_PROMOTION_CONTROL_PLANES = new WeakSet();
|
|
51
|
+
const ROLLBACK_PROVIDERS = new WeakMap();
|
|
52
|
+
|
|
53
|
+
export function captureSkillRollbackProvider(value, releaseRegistry) {
|
|
54
|
+
const entry = ROLLBACK_PROVIDERS.get(value);
|
|
55
|
+
if (!entry || entry.registry !== releaseRegistry)
|
|
56
|
+
throw new TypeError(
|
|
57
|
+
"a branded rollback provider for the same release registry is required",
|
|
58
|
+
);
|
|
59
|
+
return entry.provider;
|
|
60
|
+
}
|
|
50
61
|
|
|
51
62
|
export class SkillPromotionControllerError extends Error {
|
|
52
63
|
constructor(code, message, details = {}) {
|
|
@@ -546,6 +557,20 @@ export class SkillPromotionController {
|
|
|
546
557
|
});
|
|
547
558
|
}
|
|
548
559
|
|
|
560
|
+
createRollbackProvider() {
|
|
561
|
+
captureSkillReleaseRegistryReader(this.#registryIdentity);
|
|
562
|
+
const provider = Object.freeze({
|
|
563
|
+
tenantId: this.#tenantId,
|
|
564
|
+
rollback: (input) =>
|
|
565
|
+
SkillPromotionController.prototype.rollback.call(this, input),
|
|
566
|
+
});
|
|
567
|
+
ROLLBACK_PROVIDERS.set(provider, {
|
|
568
|
+
registry: this.#registryIdentity,
|
|
569
|
+
provider,
|
|
570
|
+
});
|
|
571
|
+
return provider;
|
|
572
|
+
}
|
|
573
|
+
|
|
549
574
|
async rollback(input = {}) {
|
|
550
575
|
assertDataRecord(
|
|
551
576
|
input,
|