chainlesschain 0.166.15 → 0.166.17

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.
Files changed (202) hide show
  1. package/README.md +3 -3
  2. package/completions/_cc +1 -1
  3. package/completions/cc.bash +1 -1
  4. package/completions/cc.fish +1 -1
  5. package/completions/cc.ps1 +1 -1
  6. package/package.json +2 -2
  7. package/src/assets/web-panel/assets/{AIOps-To-6rimH.js → AIOps-CVW2n2rh.js} +1 -1
  8. package/src/assets/web-panel/assets/{ActionButton-CpdCnTv3.js → ActionButton-DtuM163O.js} +1 -1
  9. package/src/assets/web-panel/assets/{Analytics-DK7VNES_.js → Analytics-BXvl_qHu.js} +3 -3
  10. package/src/assets/web-panel/assets/{AppLayout-NZ5FvhCx.js → AppLayout-VDBTFKOp.js} +5 -5
  11. package/src/assets/web-panel/assets/{Artifacts-NXceQPmN.js → Artifacts-BNz2xCiG.js} +1 -1
  12. package/src/assets/web-panel/assets/{Audit-B2d64DH2.js → Audit-DTu9Hn9P.js} +1 -1
  13. package/src/assets/web-panel/assets/{BackgroundAgents-ByYgvEVY.js → BackgroundAgents-D2OCPzLe.js} +1 -1
  14. package/src/assets/web-panel/assets/{Backup-BXvQLDvN.js → Backup-C9M-vG7G.js} +1 -1
  15. package/src/assets/web-panel/assets/{BaseInput-C4GZk-As.js → BaseInput-BUkCNiUQ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Chat-CvPuohL8.js → Chat-OJ2ajF7l.js} +5 -5
  17. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DTftcclX.js → ChatBubbleRenderer-BdZt76Ab.js} +1 -1
  18. package/src/assets/web-panel/assets/{Checkbox-C8dQGIqD.js → Checkbox-C1gXKDsc.js} +1 -1
  19. package/src/assets/web-panel/assets/{Codegen-DRM6S1W4.js → Codegen-BXbznLg7.js} +1 -1
  20. package/src/assets/web-panel/assets/{Col-BDM8l-r5.js → Col-CbCq5N0i.js} +1 -1
  21. package/src/assets/web-panel/assets/{Community-Bvmfi1fX.js → Community-V8Ks6Yun.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compact-DGQTCima.js → Compact-DkeHQTpQ.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compliance-D_0C-2P6.js → Compliance-JeLKwn4Q.js} +1 -1
  24. package/src/assets/web-panel/assets/{Cowork-3C_q99ok.js → Cowork-azfetcBz.js} +3 -3
  25. package/src/assets/web-panel/assets/{Cron-CIiMQ1Hl.js → Cron-Q691i_Gp.js} +2 -2
  26. package/src/assets/web-panel/assets/{Crosschain-peebGnES.js → Crosschain-BLjDRbr_.js} +1 -1
  27. package/src/assets/web-panel/assets/{DID-OkX4KB9T.js → DID-D8ptXplK.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dashboard-D9lm0Wxa.js → Dashboard-Ctj2VVZL.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dropdown-CitActXx.js → Dropdown-D8VgkMJ8.js} +1 -1
  30. package/src/assets/web-panel/assets/EmailListRenderer-CQPe5S6q.js +1 -0
  31. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CBWAi8XL.js → FamilyGuardDashboard-ySA-7SiN.js} +1 -1
  32. package/src/assets/web-panel/assets/{Federation-afj8jDcp.js → Federation-1PMD-fBf.js} +1 -1
  33. package/src/assets/web-panel/assets/{FormItemContext-Dabt59KY.js → FormItemContext-C_jr6U4Q.js} +1 -1
  34. package/src/assets/web-panel/assets/{GenericCardRenderer-BQpXA9kj.js → GenericCardRenderer-Bu3bKf2B.js} +1 -1
  35. package/src/assets/web-panel/assets/{Git-D2p2Moo1.js → Git-Dv4Fa_T5.js} +2 -2
  36. package/src/assets/web-panel/assets/{Governance-DkFfPykv.js → Governance-DOEy1n1k.js} +1 -1
  37. package/src/assets/web-panel/assets/{Inference-C1DKpeN2.js → Inference-DkvqzWcJ.js} +1 -1
  38. package/src/assets/web-panel/assets/{KnowledgeGraph-CjfVg4oQ.js → KnowledgeGraph-DdUJK949.js} +1 -1
  39. package/src/assets/web-panel/assets/{Logs-D-zMvdSf.js → Logs-CRelcdUZ.js} +2 -2
  40. package/src/assets/web-panel/assets/{MarkdownRenderer-jzEpGkbc.js → MarkdownRenderer-0AHbbTA4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Marketplace-DfAjJLyS.js → Marketplace-BuuBKsev.js} +1 -1
  42. package/src/assets/web-panel/assets/{McpTools-BGDHQES1.js → McpTools-DlgpEmA1.js} +3 -3
  43. package/src/assets/web-panel/assets/{Memory-BYqrGAPS.js → Memory-DTfdqUGy.js} +2 -2
  44. package/src/assets/web-panel/assets/{MobileBridge-CQ6FEtty.js → MobileBridge-CXLE5ZFO.js} +1 -1
  45. package/src/assets/web-panel/assets/{MobileProjects-BpMvh5JW.js → MobileProjects-Dz25OB0n.js} +1 -1
  46. package/src/assets/web-panel/assets/{Mtc-CWH25SrU.js → Mtc-kEL0fhgD.js} +2 -2
  47. package/src/assets/web-panel/assets/{MtcAudit-D6DiLmei.js → MtcAudit-BE4UvFJU.js} +2 -2
  48. package/src/assets/web-panel/assets/{Multisig-BSxRN4jD.js → Multisig-CSApSn8c.js} +3 -3
  49. package/src/assets/web-panel/assets/{NLProgramming-C0FDPKT4.js → NLProgramming-D11FpKWx.js} +1 -1
  50. package/src/assets/web-panel/assets/{Notes-VKR78bH-.js → Notes-CDL-D2CS.js} +3 -3
  51. package/src/assets/web-panel/assets/{NotificationSettings-DLSklSZB.js → NotificationSettings-C0Q6lO-c.js} +1 -1
  52. package/src/assets/web-panel/assets/OrderTableRenderer-ZRE0OKbj.js +1 -0
  53. package/src/assets/web-panel/assets/{Organization-BB3pB27e.js → Organization-Dc-maVAq.js} +4 -4
  54. package/src/assets/web-panel/assets/{Overflow-Cr7bzwcs.js → Overflow-B5mUpSvi.js} +1 -1
  55. package/src/assets/web-panel/assets/{P2P-D1fkMMzI.js → P2P-TjXV53wq.js} +2 -2
  56. package/src/assets/web-panel/assets/PdhVaultBrowser-DvV2btIr.js +7 -0
  57. package/src/assets/web-panel/assets/{Permissions-c3Ijv0v4.js → Permissions-DKRzQ2O6.js} +4 -4
  58. package/src/assets/web-panel/assets/{PersonalDataHub-BJwbh3P2.js → PersonalDataHub-Dx2eqft8.js} +4 -4
  59. package/src/assets/web-panel/assets/{Pipeline-C4fhXafB.js → Pipeline-CnYZMB5p.js} +1 -1
  60. package/src/assets/web-panel/assets/{Privacy-DzSx3CD-.js → Privacy-BonKpPnp.js} +1 -1
  61. package/src/assets/web-panel/assets/{ProjectInit-D9fL5fED.js → ProjectInit-DWO0Du3J.js} +2 -2
  62. package/src/assets/web-panel/assets/{ProjectSettings-CB5FVrOR.js → ProjectSettings-C9jqyYRv.js} +2 -2
  63. package/src/assets/web-panel/assets/{Projects-DWhwdgfY.js → Projects-CYpKwXbz.js} +1 -1
  64. package/src/assets/web-panel/assets/{Providers-B9ZH4faS.js → Providers-CW-fkwJq.js} +1 -1
  65. package/src/assets/web-panel/assets/{QrScannerModal-BLKDHT8_.js → QrScannerModal-Cw0J3Zud.js} +1 -1
  66. package/src/assets/web-panel/assets/{QuickAsk-D1oYUcSY.js → QuickAsk-BH4A4IpR.js} +1 -1
  67. package/src/assets/web-panel/assets/{Recommend-CC2nmrOD.js → Recommend-CDwMwJus.js} +1 -1
  68. package/src/assets/web-panel/assets/{RemoteSession-qW9QF4-r.js → RemoteSession-DKIPwzTf.js} +2 -2
  69. package/src/assets/web-panel/assets/{Reputation-BDWqfzcr.js → Reputation-CklDj7qS.js} +1 -1
  70. package/src/assets/web-panel/assets/{Row-BBV2iCjT.js → Row-DJWZKsH0.js} +1 -1
  71. package/src/assets/web-panel/assets/{RssFeed-CcwrNwZB.js → RssFeed-BfSLCewo.js} +3 -3
  72. package/src/assets/web-panel/assets/{Search-Dr6fZ0D_.js → Search-B0IST--x.js} +1 -1
  73. package/src/assets/web-panel/assets/{Security-BPzaoCU6.js → Security-h1sYNWtt.js} +4 -4
  74. package/src/assets/web-panel/assets/{Services-BoKUU1I_.js → Services-Gh0-oxI_.js} +2 -2
  75. package/src/assets/web-panel/assets/{Skeleton-C8lT8GUg.js → Skeleton-CNDV_jOs.js} +1 -1
  76. package/src/assets/web-panel/assets/{Skills-DPpWeicz.js → Skills-ByCLTh1n.js} +1 -1
  77. package/src/assets/web-panel/assets/{Sla-UiijzpMU.js → Sla-BfyrJTJz.js} +1 -1
  78. package/src/assets/web-panel/assets/{SpeechSettings-DoofrLwS.js → SpeechSettings-BQzo9kNX.js} +1 -1
  79. package/src/assets/web-panel/assets/{SyncSettings-DXnyfTDw.js → SyncSettings-B6fS6z_1.js} +2 -2
  80. package/src/assets/web-panel/assets/{Tasks-g_WHjKeg.js → Tasks-C-uKCP-l.js} +1 -1
  81. package/src/assets/web-panel/assets/{Templates-DRuCh9g2.js → Templates-D6oDy7wL.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tenant-QHIq1pH1.js → Tenant-D3LT2wNQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Terminal-G0fuI216.js → Terminal-BteLcv_O.js} +2 -2
  84. package/src/assets/web-panel/assets/{TimelineRenderer-4MT7SpGk.js → TimelineRenderer-DHHuxfqH.js} +1 -1
  85. package/src/assets/web-panel/assets/{Tokens-B5xT5umA.js → Tokens-BRQeykXw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trigger-D7HPbNgc.js → Trigger-p2XaFWEu.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trust-CxH69dU5.js → Trust-BxadBMft.js} +1 -1
  88. package/src/assets/web-panel/assets/{UkeySign-CPPosveH.js → UkeySign-DRBP7LDk.js} +1 -1
  89. package/src/assets/web-panel/assets/{VideoEditing-Du5lGwAt.js → VideoEditing-CZ3NZkh7.js} +1 -1
  90. package/src/assets/web-panel/assets/{Wallet-BBIGNESK.js → Wallet-C3NTBN7G.js} +4 -4
  91. package/src/assets/web-panel/assets/{WebAuthn-Cc3HSGmv.js → WebAuthn-C7LVgMlb.js} +5 -5
  92. package/src/assets/web-panel/assets/{WorkflowEditor-DBoVPNCh.js → WorkflowEditor-0_Iveog7.js} +1 -1
  93. package/src/assets/web-panel/assets/{chat-DHcjgiem.js → chat-DzzluYo3.js} +1 -1
  94. package/src/assets/web-panel/assets/{colors-DrRrvJIV.js → colors-DSMYXpaj.js} +1 -1
  95. package/src/assets/web-panel/assets/{compact-item-BuY_sAoN.js → compact-item-W76u1VSV.js} +1 -1
  96. package/src/assets/web-panel/assets/{createContext-CepH1Fha.js → createContext-otsESjb5.js} +1 -1
  97. package/src/assets/web-panel/assets/devWarning-BztaXF84.js +1 -0
  98. package/src/assets/web-panel/assets/{hasIn-Dh80Ot6o.js → hasIn-3sNLrvug.js} +1 -1
  99. package/src/assets/web-panel/assets/index-4jP_hG_4.js +1 -0
  100. package/src/assets/web-panel/assets/{index-LBkSOwky.js → index-B1I1AYJs.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-B0rvJjId.js → index-B5LOYdYm.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-D6tOVlq-.js → index-B9X_jqXe.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D7lstbTh.js → index-BA8mZxd-.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BPDEOOlA.js → index-BDlDO2px.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DuSUCH7h.js → index-BJsQio5O.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CEfVkKIY.js → index-BRsD1PT2.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CYydOga6.js → index-BXLx9HfA.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DkZP_QaB.js → index-BcGJtmHM.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BnVIvc15.js → index-BdtmEKat.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DuRYBWrj.js → index-BpcQYzP7.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-By0qqC3S.js → index-C2aht9-M.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C10033eO.js → index-CE7tSow-.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-9crgJ3Id.js → index-CENWwjef.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CNQK9DIr.js → index-CKoFyHYQ.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DUNyTmkS.js → index-Cg86EzNp.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CnRK8_Dd.js → index-ClOFeZ-t.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BW9Pycxh.js → index-CtFOt5x1.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-D5_K3GKu.js → index-D7A5U2IH.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DRy3_beb.js → index-DH4cl52p.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DWANFMlq.js → index-DLDh1OW3.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-C5vhNRqS.js → index-DMmdIpLA.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Ca5d64IH.js → index-DS9WYDMf.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-zGH9zH3w.js → index-DTA8Iavv.js} +3 -3
  124. package/src/assets/web-panel/assets/{index-BoRy2yup.js → index-DZKAzEge.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Cx21_p3m.js → index-DdU7IkKX.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B9Gh-SOn.js → index-Ddd4mird.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CiUx-tkV.js → index-DmpaC2yk.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DYN49m7k.js → index-GlIOE4ja.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CUnd5hyp.js → index-MhQQ3h8q.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CW_23-gU.js → index-NaO9AE-F.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-0TYLnd11.js → index-UUHCwfNq.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-NS9dW1F1.js → index-pVm_iUre.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-hYaigdGm.js → index-q7ftLqNt.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-A5lVwYVq.js → index-uSCkbpZH.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-BtqigRzf.js → index-vBKPcmAP.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-BiZQooWK.js → index-vUmYkqmu.js} +1 -1
  137. package/src/assets/web-panel/assets/index-zxwuAXL5.js +1 -0
  138. package/src/assets/web-panel/assets/{initDefaultProps-nI_X3wKl.js → initDefaultProps-DF6llUXV.js} +1 -1
  139. package/src/assets/web-panel/assets/{motion-LUHbQu_R.js → motion-vtDV8_5K.js} +1 -1
  140. package/src/assets/web-panel/assets/{move-DHI_KvJt.js → move-B6c0bdy2.js} +1 -1
  141. package/src/assets/web-panel/assets/{mtc-parser-AYdL_7Mo.js → mtc-parser-DlLYWuBK.js} +1 -1
  142. package/src/assets/web-panel/assets/{omit-CtV3HRKa.js → omit-BH0zOxLN.js} +1 -1
  143. package/src/assets/web-panel/assets/{pickAttrs-CcJLTOu4.js → pickAttrs-D9di8_In.js} +1 -1
  144. package/src/assets/web-panel/assets/{placementArrow-DHbiLUps.js → placementArrow-BDSngufM.js} +1 -1
  145. package/src/assets/web-panel/assets/{responsiveObserve-BC2DGkWP.js → responsiveObserve-C_EawMvP.js} +1 -1
  146. package/src/assets/web-panel/assets/{slide-B4ga4pPY.js → slide-B_4wShxA.js} +1 -1
  147. package/src/assets/web-panel/assets/{statusUtils-hzphgKfH.js → statusUtils-CbQu6qJ-.js} +1 -1
  148. package/src/assets/web-panel/assets/{styleChecker-IfN9Bxoi.js → styleChecker-CvXJWYXb.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFlexGapSupport-pcGKJ4pT.js → useFlexGapSupport-jjY1XknO.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFs-COXhQpTG.js → useFs-CMXBdsK_.js} +1 -1
  151. package/src/assets/web-panel/assets/{usePersonalDataHub-xp9F9szv.js → usePersonalDataHub-YbAhhPXx.js} +1 -1
  152. package/src/assets/web-panel/assets/{vnode-BdSQy1Ve.js → vnode-BFCTKc0H.js} +1 -1
  153. package/src/assets/web-panel/assets/{zoom-CHCt5P55.js → zoom-CY9aBl5O.js} +1 -1
  154. package/src/assets/web-panel/index.html +1 -1
  155. package/src/command-help-index.json +2 -2
  156. package/src/command-manifest.json +2 -2
  157. package/src/commands/evolution.js +30 -17
  158. package/src/commands/learning.js +95 -9
  159. package/src/commands/team.js +5 -0
  160. package/src/data/changelog.json +28 -2
  161. package/src/lib/agent-team/task-lease.js +12 -1
  162. package/src/lib/capability-manifest.js +212 -1
  163. package/src/lib/evolution/bounded-skill-improvement-pilot.js +498 -0
  164. package/src/lib/evolution/evolution-artifact-ports.js +3277 -0
  165. package/src/lib/evolution/evolution-eval-gate.js +6442 -0
  166. package/src/lib/evolution/evolution-evidence-projector.js +3786 -0
  167. package/src/lib/evolution/evolution-ledger-ports.js +2689 -0
  168. package/src/lib/evolution/evolution-ledger.js +4280 -0
  169. package/src/lib/evolution/evolution-run-runtime-adapter.js +5 -0
  170. package/src/lib/evolution/skill-candidate-registry.js +2258 -0
  171. package/src/lib/evolution/skill-evaluated-promotion-durability.js +899 -0
  172. package/src/lib/evolution/skill-evaluated-promotion.js +481 -0
  173. package/src/lib/evolution/skill-execution-manifest.js +942 -0
  174. package/src/lib/evolution/skill-mutation-authority.js +1677 -0
  175. package/src/lib/evolution/skill-promotion-controller.js +618 -0
  176. package/src/lib/evolution/skill-release-registry.js +3277 -0
  177. package/src/lib/evolution/skill-target-matrix-eval.js +3233 -0
  178. package/src/lib/evolution/skill-writer-inventory-manifest.js +998 -0
  179. package/src/lib/evolution/skill-writer-inventory-validator.js +816 -0
  180. package/src/lib/evolution/wiki-informed-skill-proposer.js +343 -0
  181. package/src/lib/formal-quality-eval-runtime.js +100 -0
  182. package/src/lib/graph-kernel/cutover-contract.js +7 -0
  183. package/src/lib/graph-kernel/cutover-ledger.js +8 -7
  184. package/src/lib/graph-kernel/evidence-digest.js +47 -0
  185. package/src/lib/graph-kernel/evolution-run-runtime-adapter.js +5 -0
  186. package/src/lib/graph-kernel/graph-runtime-surfaces.json +8 -1
  187. package/src/lib/graph-kernel/production-cutover-evidence.js +342 -15
  188. package/src/lib/graph-kernel/production-source-evidence.js +1599 -0
  189. package/src/lib/graph-kernel/retirement-evidence.js +15 -5
  190. package/src/lib/graph-kernel/runtime-surface-manifest.js +67 -2
  191. package/src/lib/headless-manifest.js +3 -1
  192. package/src/lib/hooks-v2-runtime.js +20 -0
  193. package/src/lib/learning/skill-improver.js +311 -43
  194. package/src/lib/learning/skill-synthesizer.js +236 -16
  195. package/src/lib/secure-fs.js +20 -0
  196. package/src/runtime/agent-core.js +68 -0
  197. package/src/assets/web-panel/assets/EmailListRenderer-DSmFkNKV.js +0 -1
  198. package/src/assets/web-panel/assets/OrderTableRenderer-Dpj7D6tC.js +0 -1
  199. package/src/assets/web-panel/assets/PdhVaultBrowser-BiDEbLNA.js +0 -7
  200. package/src/assets/web-panel/assets/devWarning-DIb8j04q.js +0 -1
  201. package/src/assets/web-panel/assets/index-BJc3t4PC.js +0 -1
  202. package/src/assets/web-panel/assets/index-CkksSUnI.js +0 -1
@@ -0,0 +1,618 @@
1
+ import crypto from "node:crypto";
2
+ import { types as utilTypes } from "node:util";
3
+ import {
4
+ SKILL_MUTATION_OPERATIONS,
5
+ SKILL_MUTATION_RECEIPT_KINDS,
6
+ SKILL_MUTATION_ROLES,
7
+ SKILL_MUTATION_TARGET_SCOPES,
8
+ SkillMutationAuthority,
9
+ buildSkillMutationConsumeContext,
10
+ digestSkillMutationReceiptEnvelope,
11
+ digestSkillMutationTransitionSubject,
12
+ verifySkillMutationConsumptionReceipt,
13
+ verifySkillMutationRequest,
14
+ } from "./skill-mutation-authority.js";
15
+ import { captureSkillEvaluatedPromotionProvider } from "./skill-evaluated-promotion.js";
16
+
17
+ const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/u;
18
+ const EMPTY_ACTIVE_DOMAIN = "chainlesschain.skill-active/empty/v1\0";
19
+
20
+ /** The CAS digest used by mutation authority when a Skill has no active release. */
21
+ export const EMPTY_SKILL_ACTIVE_DIGEST = `sha256:${crypto
22
+ .createHash("sha256")
23
+ .update(EMPTY_ACTIVE_DOMAIN, "utf8")
24
+ .digest("hex")}`;
25
+
26
+ const TRANSITION_CAPABILITIES = new WeakMap();
27
+ const EVALUATED_CONTROL_PLANE_OPTION_KEYS = new Set([
28
+ "candidateRegistry",
29
+ "releaseRegistry",
30
+ "authority",
31
+ "evaluatedPromotionProvider",
32
+ ]);
33
+
34
+ export const SKILL_EVALUATED_PROMOTION_CONTROL_PLANE_SCHEMA =
35
+ "chainlesschain.skill-evaluated-promotion-control-plane/v1";
36
+
37
+ export class SkillPromotionControllerError extends Error {
38
+ constructor(code, message, details = {}) {
39
+ super(message, details.cause ? { cause: details.cause } : undefined);
40
+ this.name = "SkillPromotionControllerError";
41
+ this.code = code;
42
+ for (const [key, value] of Object.entries(details)) {
43
+ if (key !== "cause") this[key] = value;
44
+ }
45
+ }
46
+ }
47
+
48
+ function failure(code, message, details = {}) {
49
+ return new SkillPromotionControllerError(code, message, details);
50
+ }
51
+
52
+ function deepFreeze(value, seen = new WeakSet()) {
53
+ if (!value || typeof value !== "object" || seen.has(value)) return value;
54
+ seen.add(value);
55
+ for (const key of Reflect.ownKeys(value)) {
56
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
57
+ if (!descriptor || !("value" in descriptor)) {
58
+ throw failure(
59
+ "SKILL_PROMOTION_INVALID",
60
+ "trusted transition data must contain only own data fields",
61
+ );
62
+ }
63
+ deepFreeze(descriptor.value, seen);
64
+ }
65
+ return Object.freeze(value);
66
+ }
67
+
68
+ function assertDataRecord(value, allowed, label, { required = allowed } = {}) {
69
+ if (
70
+ !value ||
71
+ typeof value !== "object" ||
72
+ Array.isArray(value) ||
73
+ utilTypes.isProxy(value)
74
+ ) {
75
+ throw failure("SKILL_PROMOTION_INVALID", `${label} must be an object`);
76
+ }
77
+ const keys = Reflect.ownKeys(value);
78
+ if (
79
+ keys.some((key) => typeof key !== "string" || !allowed.has(key)) ||
80
+ [...required].some((key) => !Object.hasOwn(value, key))
81
+ ) {
82
+ throw failure(
83
+ "SKILL_PROMOTION_INVALID",
84
+ `${label} must contain exactly the supported fields`,
85
+ );
86
+ }
87
+ for (const key of keys) {
88
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
89
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
90
+ throw failure(
91
+ "SKILL_PROMOTION_INVALID",
92
+ `${label}.${String(key)} must be an own data field`,
93
+ );
94
+ }
95
+ }
96
+ }
97
+
98
+ function assertDigest(value, label) {
99
+ if (typeof value !== "string" || !DIGEST_PATTERN.test(value)) {
100
+ throw failure(
101
+ "SKILL_PROMOTION_INVALID",
102
+ `${label} must be a lowercase sha256 digest`,
103
+ );
104
+ }
105
+ return value;
106
+ }
107
+
108
+ function receiptDigests(request) {
109
+ return deepFreeze(
110
+ Object.fromEntries(
111
+ SKILL_MUTATION_RECEIPT_KINDS.map((kind) => {
112
+ const envelope = request.receipts[`${kind}Receipt`];
113
+ if (typeof envelope !== "string") {
114
+ throw failure(
115
+ "SKILL_PROMOTION_RECEIPTS_INVALID",
116
+ `active mutation requires the ${kind} receipt envelope`,
117
+ );
118
+ }
119
+ return [kind, digestSkillMutationReceiptEnvelope(envelope)];
120
+ }),
121
+ ),
122
+ );
123
+ }
124
+
125
+ function consumeContextFor(request) {
126
+ return buildSkillMutationConsumeContext({
127
+ tenantId: request.tenantId,
128
+ audience: request.audience,
129
+ operationId: request.operationId,
130
+ operation: request.operation,
131
+ transitionSubjectDigest: request.transitionSubjectDigest,
132
+ skillName: request.skillName,
133
+ targetScope: request.targetScope,
134
+ expectedTargetDigest: request.expectedTargetDigest,
135
+ expectedTargetRevision: request.expectedTargetRevision,
136
+ expiresAt: request.expiresAt,
137
+ nonce: request.nonce,
138
+ });
139
+ }
140
+
141
+ function verifyDirectConsumptionReceipt(value, request) {
142
+ let receipt;
143
+ try {
144
+ receipt = verifySkillMutationConsumptionReceipt(value);
145
+ } catch (cause) {
146
+ throw failure(
147
+ "SKILL_PROMOTION_AUTHORITY_REJECTED",
148
+ "authority returned an invalid direct consumption receipt",
149
+ { cause },
150
+ );
151
+ }
152
+ for (const field of [
153
+ "tenantId",
154
+ "audience",
155
+ "operationId",
156
+ "operation",
157
+ "transitionSubjectDigest",
158
+ "skillName",
159
+ "targetScope",
160
+ "expectedTargetDigest",
161
+ "expectedTargetRevision",
162
+ "expiresAt",
163
+ "nonce",
164
+ "requestDigest",
165
+ ]) {
166
+ if (receipt[field] !== request[field]) {
167
+ throw failure(
168
+ "SKILL_PROMOTION_AUTHORITY_REJECTED",
169
+ `authority consumption receipt is not bound to request ${field}`,
170
+ );
171
+ }
172
+ }
173
+ if (receipt.role !== SKILL_MUTATION_ROLES.PROMOTION_CONTROLLER) {
174
+ throw failure(
175
+ "SKILL_PROMOTION_AUTHORITY_REJECTED",
176
+ "active mutation was not consumed by the promotion-controller principal",
177
+ );
178
+ }
179
+ return receipt;
180
+ }
181
+
182
+ function validateAuthorizationInput(value, expectedOperation) {
183
+ assertDataRecord(value, new Set(["capability", "request"]), "authorization");
184
+ const request = verifySkillMutationRequest(value.request);
185
+ if (request.targetScope !== SKILL_MUTATION_TARGET_SCOPES.ACTIVE) {
186
+ throw failure(
187
+ "SKILL_PROMOTION_SCOPE_REJECTED",
188
+ "promotion and rollback require an active-scope authorization",
189
+ );
190
+ }
191
+ if (request.operation !== expectedOperation) {
192
+ throw failure(
193
+ "SKILL_PROMOTION_OPERATION_REJECTED",
194
+ `authorization operation ${request.operation} cannot perform ${expectedOperation}`,
195
+ );
196
+ }
197
+ receiptDigests(request);
198
+ return { capability: value.capability, request };
199
+ }
200
+
201
+ function assertTransitionSubject(request, expectedDigest) {
202
+ if (request.transitionSubjectDigest !== expectedDigest) {
203
+ throw failure(
204
+ "SKILL_PROMOTION_SUBJECT_MISMATCH",
205
+ "authorization transition subject does not match the exact operation target, dependency lock, and active CAS",
206
+ {
207
+ actualTransitionSubjectDigest: request.transitionSubjectDigest,
208
+ expectedTransitionSubjectDigest: expectedDigest,
209
+ },
210
+ );
211
+ }
212
+ }
213
+
214
+ function issueRegistryTransitionCapability(registry, payload) {
215
+ const capability = Object.freeze(Object.create(null));
216
+ TRANSITION_CAPABILITIES.set(capability, {
217
+ registry,
218
+ payload: deepFreeze(payload),
219
+ status: "issued",
220
+ });
221
+ return capability;
222
+ }
223
+
224
+ /**
225
+ * Registry-only broker. It is exported solely to break the module boundary;
226
+ * callers cannot manufacture a WeakMap-backed capability or replay one.
227
+ */
228
+ export function consumeRegistryTransitionCapability(capability, registry) {
229
+ const state =
230
+ capability && typeof capability === "object"
231
+ ? TRANSITION_CAPABILITIES.get(capability)
232
+ : null;
233
+ if (!state || state.registry !== registry) {
234
+ throw failure(
235
+ "SKILL_PROMOTION_TRANSITION_CAPABILITY_INVALID",
236
+ "registry transition capability is forged or bound to another registry",
237
+ );
238
+ }
239
+ if (state.status !== "issued") {
240
+ throw failure(
241
+ "SKILL_PROMOTION_TRANSITION_CAPABILITY_REPLAYED",
242
+ "registry transition capability has already been consumed",
243
+ );
244
+ }
245
+ state.status = "consumed";
246
+ return state.payload;
247
+ }
248
+
249
+ export class SkillPromotionController {
250
+ #tenantId;
251
+
252
+ #registryIdentity;
253
+
254
+ #readCandidate;
255
+
256
+ #readState;
257
+
258
+ #readRelease;
259
+
260
+ #applyTransition;
261
+
262
+ #consumeAuthority;
263
+
264
+ #evaluatedPromotionProvider;
265
+
266
+ #requireEvaluatedPromotion;
267
+
268
+ constructor({
269
+ candidateRegistry,
270
+ releaseRegistry,
271
+ authority,
272
+ evaluatedPromotionProvider = null,
273
+ requireEvaluatedPromotion = false,
274
+ } = {}) {
275
+ if (!candidateRegistry || typeof candidateRegistry.read !== "function") {
276
+ throw failure(
277
+ "SKILL_PROMOTION_CANDIDATE_REGISTRY_REQUIRED",
278
+ "trusted candidate registry is required",
279
+ );
280
+ }
281
+ if (
282
+ !releaseRegistry ||
283
+ typeof releaseRegistry.readState !== "function" ||
284
+ typeof releaseRegistry.readRelease !== "function" ||
285
+ typeof releaseRegistry.applyTransition !== "function"
286
+ ) {
287
+ throw failure(
288
+ "SKILL_PROMOTION_RELEASE_REGISTRY_REQUIRED",
289
+ "trusted release registry facade is required",
290
+ );
291
+ }
292
+ if (
293
+ typeof candidateRegistry.tenantId !== "string" ||
294
+ typeof releaseRegistry.tenantId !== "string" ||
295
+ candidateRegistry.tenantId !== releaseRegistry.tenantId
296
+ ) {
297
+ throw failure(
298
+ "SKILL_PROMOTION_TENANT_MISMATCH",
299
+ "candidate and release registries must capture the same tenant",
300
+ );
301
+ }
302
+ if (
303
+ !(authority instanceof SkillMutationAuthority) ||
304
+ typeof authority.consume !== "function"
305
+ ) {
306
+ throw failure(
307
+ "SKILL_PROMOTION_AUTHORITY_REQUIRED",
308
+ "SkillMutationAuthority.consume is required",
309
+ );
310
+ }
311
+ if (typeof requireEvaluatedPromotion !== "boolean") {
312
+ throw failure(
313
+ "SKILL_PROMOTION_INVALID",
314
+ "requireEvaluatedPromotion must be boolean",
315
+ );
316
+ }
317
+ if (requireEvaluatedPromotion && evaluatedPromotionProvider === null) {
318
+ throw failure(
319
+ "SKILL_PROMOTION_EVALUATION_REQUIRED",
320
+ "evaluated-only promotion requires a captured evidence provider",
321
+ );
322
+ }
323
+
324
+ this.#tenantId = candidateRegistry.tenantId;
325
+ this.#registryIdentity = releaseRegistry;
326
+ this.#readCandidate = candidateRegistry.read.bind(candidateRegistry);
327
+ this.#readState = releaseRegistry.readState.bind(releaseRegistry);
328
+ this.#readRelease = releaseRegistry.readRelease.bind(releaseRegistry);
329
+ this.#applyTransition =
330
+ releaseRegistry.applyTransition.bind(releaseRegistry);
331
+ this.#consumeAuthority = authority.consume.bind(authority);
332
+ this.#evaluatedPromotionProvider =
333
+ evaluatedPromotionProvider === null
334
+ ? null
335
+ : captureSkillEvaluatedPromotionProvider(evaluatedPromotionProvider);
336
+ this.#requireEvaluatedPromotion = requireEvaluatedPromotion;
337
+
338
+ Object.freeze(candidateRegistry);
339
+ Object.freeze(releaseRegistry);
340
+ Object.freeze(authority);
341
+ Object.freeze(this);
342
+ }
343
+
344
+ #currentContentDigest(state) {
345
+ if (state.activeReleaseDigest === null) return EMPTY_SKILL_ACTIVE_DIGEST;
346
+ const active = this.#readRelease(state.activeReleaseDigest);
347
+ if (active.tenantId !== this.#tenantId) {
348
+ throw failure(
349
+ "SKILL_PROMOTION_TENANT_MISMATCH",
350
+ "active release belongs to another tenant",
351
+ );
352
+ }
353
+ return active.contentDigest;
354
+ }
355
+
356
+ #assertRequestCas(request, state, currentContentDigest) {
357
+ if (
358
+ request.skillName !== state.skillName ||
359
+ request.tenantId !== this.#tenantId ||
360
+ state.tenantId !== this.#tenantId ||
361
+ request.expectedTargetRevision !== state.revision ||
362
+ request.expectedTargetDigest !== currentContentDigest
363
+ ) {
364
+ throw failure(
365
+ "SKILL_PROMOTION_CAS_MISMATCH",
366
+ "authorization request is stale for the active Skill state",
367
+ {
368
+ actualRevision: state.revision,
369
+ actualTargetDigest: currentContentDigest,
370
+ },
371
+ );
372
+ }
373
+ }
374
+
375
+ async #consume(capability, request) {
376
+ let directReceipt;
377
+ try {
378
+ directReceipt = await this.#consumeAuthority(
379
+ capability,
380
+ consumeContextFor(request),
381
+ );
382
+ } catch (cause) {
383
+ throw failure(
384
+ "SKILL_PROMOTION_AUTHORITY_REJECTED",
385
+ "SkillMutationAuthority rejected capability consumption",
386
+ { cause },
387
+ );
388
+ }
389
+ return verifyDirectConsumptionReceipt(directReceipt, request);
390
+ }
391
+
392
+ async #promote(input = {}) {
393
+ assertDataRecord(
394
+ input,
395
+ new Set(["authorization", "candidateId"]),
396
+ "promotion input",
397
+ );
398
+ const { candidateId, authorization } = input;
399
+ assertDigest(candidateId, "candidateId");
400
+ const { capability, request } = validateAuthorizationInput(
401
+ authorization,
402
+ SKILL_MUTATION_OPERATIONS.PROMOTE,
403
+ );
404
+ const candidate = this.#readCandidate(candidateId);
405
+ if (
406
+ candidate.candidateId !== candidateId ||
407
+ candidate.skillName !== request.skillName ||
408
+ candidate.tenantId !== this.#tenantId ||
409
+ request.tenantId !== this.#tenantId
410
+ ) {
411
+ throw failure(
412
+ "SKILL_PROMOTION_CANDIDATE_MISMATCH",
413
+ "candidate is not bound to the authorized Skill",
414
+ );
415
+ }
416
+ const state = this.#readState(candidate.skillName);
417
+ const currentContentDigest = this.#currentContentDigest(state);
418
+ this.#assertRequestCas(request, state, currentContentDigest);
419
+ const expectedCandidateParent =
420
+ state.activeReleaseDigest === null ? null : currentContentDigest;
421
+ if (candidate.parentDigest !== expectedCandidateParent) {
422
+ throw failure(
423
+ "SKILL_PROMOTION_PARENT_MISMATCH",
424
+ "candidate parent is not the active content digest",
425
+ );
426
+ }
427
+ const dependencyLockDigest = candidate.dependencyLockDigest;
428
+ assertTransitionSubject(
429
+ request,
430
+ digestSkillMutationTransitionSubject({
431
+ tenantId: request.tenantId,
432
+ skillName: request.skillName,
433
+ operation: SKILL_MUTATION_OPERATIONS.PROMOTE,
434
+ candidateId: candidate.candidateId,
435
+ rollbackTargetReleaseDigest: null,
436
+ dependencyLockDigest,
437
+ expectedActiveContentDigest: currentContentDigest,
438
+ expectedActiveRevision: state.revision,
439
+ }),
440
+ );
441
+
442
+ const consumptionReceipt = await this.#consume(capability, request);
443
+ const transitionCapability = issueRegistryTransitionCapability(
444
+ this.#registryIdentity,
445
+ {
446
+ authorityReceipt: consumptionReceipt,
447
+ candidate,
448
+ dependencyLockDigest,
449
+ expectedParentDigest: currentContentDigest,
450
+ expectedRevision: state.revision,
451
+ mutationRequest: request,
452
+ operation: "promote",
453
+ operationId: request.operationId,
454
+ receiptDigests: receiptDigests(request),
455
+ requestDigest: request.requestDigest,
456
+ transitionSubjectDigest: request.transitionSubjectDigest,
457
+ skillName: request.skillName,
458
+ targetReleaseDigest: null,
459
+ tenantId: this.#tenantId,
460
+ },
461
+ );
462
+ return this.#applyTransition(transitionCapability);
463
+ }
464
+
465
+ async promote(input = {}) {
466
+ if (this.#requireEvaluatedPromotion) {
467
+ throw failure(
468
+ "SKILL_PROMOTION_EVALUATION_REQUIRED",
469
+ "direct promotion is disabled by the evaluated-only controller policy",
470
+ );
471
+ }
472
+ return this.#promote(input);
473
+ }
474
+
475
+ async promoteEvaluated(input = {}) {
476
+ assertDataRecord(
477
+ input,
478
+ new Set(["authorization", "candidateId", "matrixContext"]),
479
+ "evaluated promotion input",
480
+ );
481
+ if (this.#evaluatedPromotionProvider === null) {
482
+ throw failure(
483
+ "SKILL_PROMOTION_EVALUATION_REQUIRED",
484
+ "evaluated promotion requires a captured evidence provider",
485
+ );
486
+ }
487
+ const candidate = this.#readCandidate(input.candidateId);
488
+ const state = this.#readState(candidate.skillName);
489
+ const activeContentDigest = this.#currentContentDigest(state);
490
+ const matrixBinding = await this.#evaluatedPromotionProvider.verify({
491
+ matrixContext: input.matrixContext,
492
+ authorization: input.authorization,
493
+ candidate,
494
+ state,
495
+ activeContentDigest,
496
+ });
497
+ const result = await this.#promote({
498
+ authorization: input.authorization,
499
+ candidateId: input.candidateId,
500
+ });
501
+ return deepFreeze({ ...result, matrixBinding });
502
+ }
503
+
504
+ async rollback(input = {}) {
505
+ assertDataRecord(
506
+ input,
507
+ new Set(["authorization", "targetReleaseDigest"]),
508
+ "rollback input",
509
+ { required: new Set(["authorization"]) },
510
+ );
511
+ const { authorization, targetReleaseDigest = null } = input;
512
+ const { capability, request } = validateAuthorizationInput(
513
+ authorization,
514
+ SKILL_MUTATION_OPERATIONS.ROLLBACK,
515
+ );
516
+ const state = this.#readState(request.skillName);
517
+ const currentContentDigest = this.#currentContentDigest(state);
518
+ this.#assertRequestCas(request, state, currentContentDigest);
519
+ if (state.activeReleaseDigest === null) {
520
+ throw failure(
521
+ "SKILL_PROMOTION_ROLLBACK_REJECTED",
522
+ "a Skill without an active release cannot be rolled back",
523
+ );
524
+ }
525
+ const selected = targetReleaseDigest ?? state.lastKnownGoodReleaseDigest;
526
+ assertDigest(selected, "targetReleaseDigest");
527
+ if (selected !== state.lastKnownGoodReleaseDigest) {
528
+ throw failure(
529
+ "SKILL_PROMOTION_ROLLBACK_REJECTED",
530
+ "rollback target must be the last-known-good release",
531
+ );
532
+ }
533
+ const target = this.#readRelease(selected);
534
+ if (
535
+ request.tenantId !== this.#tenantId ||
536
+ target.tenantId !== this.#tenantId ||
537
+ target.skillName !== request.skillName
538
+ ) {
539
+ throw failure(
540
+ "SKILL_PROMOTION_ROLLBACK_REJECTED",
541
+ "rollback target belongs to another Skill",
542
+ );
543
+ }
544
+ assertTransitionSubject(
545
+ request,
546
+ digestSkillMutationTransitionSubject({
547
+ tenantId: request.tenantId,
548
+ skillName: request.skillName,
549
+ operation: SKILL_MUTATION_OPERATIONS.ROLLBACK,
550
+ candidateId: null,
551
+ rollbackTargetReleaseDigest: target.releaseDigest,
552
+ dependencyLockDigest: target.dependencyLockDigest,
553
+ expectedActiveContentDigest: currentContentDigest,
554
+ expectedActiveRevision: state.revision,
555
+ }),
556
+ );
557
+
558
+ const consumptionReceipt = await this.#consume(capability, request);
559
+ const transitionCapability = issueRegistryTransitionCapability(
560
+ this.#registryIdentity,
561
+ {
562
+ authorityReceipt: consumptionReceipt,
563
+ candidate: null,
564
+ dependencyLockDigest: target.dependencyLockDigest,
565
+ expectedParentDigest: currentContentDigest,
566
+ expectedRevision: state.revision,
567
+ mutationRequest: request,
568
+ operation: "rollback",
569
+ operationId: request.operationId,
570
+ receiptDigests: receiptDigests(request),
571
+ requestDigest: request.requestDigest,
572
+ transitionSubjectDigest: request.transitionSubjectDigest,
573
+ skillName: request.skillName,
574
+ targetReleaseDigest: selected,
575
+ tenantId: this.#tenantId,
576
+ },
577
+ );
578
+ return this.#applyTransition(transitionCapability);
579
+ }
580
+ }
581
+
582
+ /**
583
+ * Builds the narrow promotion surface intended for production adapters.
584
+ *
585
+ * This is a composition primitive, not proof that any production entry point
586
+ * uses it. The returned facade deliberately withholds both the controller and
587
+ * direct promote(), while retaining authorized rollback as the recovery path.
588
+ */
589
+ export function createSkillEvaluatedPromotionControlPlane(options = {}) {
590
+ assertDataRecord(
591
+ options,
592
+ EVALUATED_CONTROL_PLANE_OPTION_KEYS,
593
+ "evaluated promotion control plane options",
594
+ );
595
+ const provider = captureSkillEvaluatedPromotionProvider(
596
+ options.evaluatedPromotionProvider,
597
+ );
598
+ const controller = new SkillPromotionController({
599
+ candidateRegistry: options.candidateRegistry,
600
+ releaseRegistry: options.releaseRegistry,
601
+ authority: options.authority,
602
+ evaluatedPromotionProvider: options.evaluatedPromotionProvider,
603
+ requireEvaluatedPromotion: true,
604
+ });
605
+ return Object.freeze({
606
+ schema: SKILL_EVALUATED_PROMOTION_CONTROL_PLANE_SCHEMA,
607
+ tenantId: options.candidateRegistry.tenantId,
608
+ providerAuthorityId: provider.authorityId,
609
+ providerRevision: provider.revision,
610
+ providerHandlerArtifactDigest: provider.handlerArtifactDigest,
611
+ promoteEvaluated: Object.freeze((input) =>
612
+ controller.promoteEvaluated(input),
613
+ ),
614
+ rollback: Object.freeze((input) => controller.rollback(input)),
615
+ });
616
+ }
617
+
618
+ Object.freeze(SkillPromotionController.prototype);