chainlesschain 0.166.47 → 0.166.56

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 (180) hide show
  1. package/README.md +22 -0
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-CDpT0WXV.js → AIOps-CBFnwYRX.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-BNfUljWx.js → ActionButton-Sl4eXWpR.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-C9323DEx.js → Analytics-DB0lD9Kb.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CRrjb2db.js → AppLayout-j77EmkRK.js} +3 -3
  8. package/src/assets/web-panel/assets/{Artifacts-Db-DGqJS.js → Artifacts-CU3izCW9.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-CJdHRJ0W.js → Audit-C44fSibb.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-_RSCnTYs.js → BackgroundAgents-pM_NnJW3.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-8GFQi-dM.js → Backup-AOHXqhxN.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-C87NtgUZ.js → BaseInput-DaYc8oA_.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-DcTMWS8G.js → Chat-CmlCAXxW.js} +5 -5
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-5ZDPTW_H.js → ChatBubbleRenderer-CkCSkJDJ.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-DM9EmYee.js → Checkbox-DISI7iaA.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-M2YqDRNN.js → Codegen-BYpeKUpf.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-oB1LLxyf.js → Col-Dk6VwWGq.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-TcVZK5tF.js → Community-BDyTedMu.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-XKmq-3K_.js → Compact-CTNlGM9X.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-C6CBiDRy.js → Compliance-C_tw3IdT.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-Dz9CGqXH.js → Cowork-cduHWEmo.js} +4 -4
  22. package/src/assets/web-panel/assets/{Cron-CxJDgDVL.js → Cron-Dqotjv-s.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-DMP0JsaQ.js → Crosschain-ByW7RsJQ.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-I5IQeogb.js → DID-BI-lafPj.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-BfLW2MXj.js → Dashboard-8m50TRZL.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BK8EjAlh.js → Dropdown-CN3hmRTc.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-C3iqSv5I.js → EmailListRenderer-t0lzxsDT.js} +1 -1
  28. package/src/assets/web-panel/assets/EvolutionSettings-DabpA3cQ.js +1 -0
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-T19rnqm-.js → FamilyGuardDashboard-BYN4UshY.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-CozrbPMy.js → Federation-n44OtIXp.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-k1dCLNNJ.js → FormItemContext-B-WXDu_I.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-DbaW_Jvt.js → GenericCardRenderer-Bm7v-mTf.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-CQHRyEIt.js → Git-BMIS6sbo.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-BMJYZgMy.js → Governance-B1EhHobE.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-B7mpNU7V.js → Inference-Dy_HJWHo.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-Br0Blg6B.js → KnowledgeGraph-BVdfUbZy.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-HIdk0S6M.js → Logs-Dph_oLQk.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-CNHYqcxm.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-Bkfq69UP.js → Marketplace-Bw4HWORj.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-dtmx0bHO.js → McpTools-Be6DPfA1.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-CrRlOuEf.js → Memory-DlvLafC9.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-D4ZIZiAH.js → MobileBridge-Upc_Jwlt.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-C90Rw7GE.js → MobileProjects-I17jrUbY.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-CC6k_uh4.js → Mtc-DyBzY0GH.js} +4 -4
  45. package/src/assets/web-panel/assets/{MtcAudit-T_CUIYUy.js → MtcAudit-2-7xAwEo.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-N_e0RRWk.js → Multisig-DtUZpFmZ.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-Iq3VzEv0.js → NLProgramming-iInH7jBr.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-B5sKJUJt.js → Notes-BO3Z3vaS.js} +4 -4
  49. package/src/assets/web-panel/assets/{NotificationSettings-K8UVp8qQ.js → NotificationSettings-ClX_0jFE.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-BWNyM-6m.js → OrderTableRenderer-Czw742w4.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-DMO1NJxI.js → Organization-BATEx24i.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-BBY6b31Z.js → Overflow-B_PXMNia.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-DmsL0y0v.js → P2P-BSiE8PqT.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-C65AX_RY.js → PdhVaultBrowser-BbklUgZY.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-CWcpRtWa.js → Permissions-B7bpflT_.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub--ZNDIdsn.js → PersonalDataHub-BWZS4BLy.js} +3 -3
  57. package/src/assets/web-panel/assets/{Pipeline-DCdj5NGb.js → Pipeline-DP2YSs6H.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-BRKu7Q3E.js → Privacy-DB9ptoH0.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-BJ7ozIAb.js → ProjectInit-BAfePyYk.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-B2cVLiXW.js → ProjectSettings-BEXn4Cm3.js} +2 -2
  61. package/src/assets/web-panel/assets/{Projects-Ce9r_W-p.js → Projects-BzSs0rzn.js} +1 -1
  62. package/src/assets/web-panel/assets/{Providers-BDespvGZ.js → Providers-CRX9TdRO.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-BUNO4fDU.js → QrScannerModal-DUWcSY5L.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-D2TUqeBV.js → QuickAsk-Cgo3Z_hs.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-BNNQPHBH.js → Recommend-Dcinx0IW.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-D2t1V_Cm.js → RemoteSession-BMZzTnAN.js} +2 -2
  67. package/src/assets/web-panel/assets/{Reputation-DVK5hEqI.js → Reputation-BdZzpOp9.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-BB9RTwmE.js → Row-DqM8GVcx.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-DmEO7liZ.js → RssFeed-Soj_QBK3.js} +2 -2
  70. package/src/assets/web-panel/assets/{Search-UwEYjnDB.js → Search-Cn2es0-v.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-DebqSsMp.js → Security-t7C4hz3n.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-CuuPts3C.js → Services-ChF-e_Uf.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DbWpmbgf.js → Skeleton-BiPIyK-2.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-BaK7SxzT.js → Skills-HgkKJenJ.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-BFHv51Jb.js → Sla-BSfluv_k.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-B9b1R6uK.js → SpeechSettings-Sm0Gz9tM.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-BnO0CN02.js → SyncSettings-DlhBMnfU.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-Dy01Vq49.js → Tasks-C7OUvsnp.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-BCy2AMHc.js → Templates-CrMtw87y.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-4Tx9y_Y1.js → Tenant-DSNSB6j5.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-CPOoUH8J.js → Terminal-Cmh78FQg.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-C85GlJzu.js → TimelineRenderer-BE8b8lHR.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-_xneFBGF.js → Tokens-BrtgdIvJ.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-BizG4rTr.js → Trigger-HCmaoKDp.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-Dh8EIn3n.js → Trust-GASQ4F-2.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C5NWoHWQ.js → UkeySign-B8kSzWGr.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-0YfrySL6.js → VideoEditing-Nn-clhv5.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BZVH8Ags.js → Wallet-DdYMKTYk.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-kNofa6vm.js → WebAuthn-xJXUr_eK.js} +3 -3
  90. package/src/assets/web-panel/assets/{WorkflowEditor-BNO34_j0.js → WorkflowEditor-CbSa87av.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-ifQ2FlwD.js → chat-CVrNLGUV.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-1TL8H6EH.js → colors-e2veLfIA.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-DBfRjs_T.js → compact-item-CNd7nhUq.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-Bs6V4iBf.js → createContext-DEudTVqv.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DW7he-SA.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-Bz6LMY_0.js → hasIn-BlSAFZa3.js} +1 -1
  97. package/src/assets/web-panel/assets/{index--WvT2Il3.js → index-0y7tHZdT.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DMVktlxG.js → index-4ZT0vIJt.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-B6RClMZl.js → index-7-7rr4Mf.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BB1Af7Fv.js → index-B1C1wS5c.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-lUL3bD2z.js → index-BG-VNepa.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CtB45Hok.js → index-BMIhGZUR.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DOww5Qny.js → index-BRNCKg4q.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BiZ7Nz5-.js → index-B_UNX_xq.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C9QYxq61.js → index-BmVFeSEq.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BoCTDcn6.js → index-Bp4Gcn9u.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CXtiLagi.js → index-BpH6T1gA.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-B5SJCUZ7.js → index-BptI9bLu.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Cn7EIWmI.js → index-Bqeb4jnC.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DvM2xBUA.js → index-Bwtt-0CQ.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-EK3XtMxA.js → index-C4h_Bvd2.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DDhy4eCS.js → index-C6zGNZ5H.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-rGhS02f8.js → index-CHMrAZiR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BQL_tldd.js → index-CK6Rb66R.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C7d6QlfR.js → index-CU4Y4VVN.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Cykt9BbN.js → index-CWuv47z0.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BXJXMaZe.js → index-CYNoXhxl.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-f_7L9GvP.js → index-CgVwz2jD.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-vHtnQsnV.js → index-ClROBPWd.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BhPDhmvN.js → index-D7yJceTZ.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Cu_V6ZJH.js → index-DFv-nsIT.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CNKHoXWI.js → index-DFzvcZ3Q.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-vb1XIxEB.js → index-DJ5gsewX.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DWPp-d07.js → index-DVORJydf.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-pOUFfRdN.js → index-D_D7lcnQ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-cNwsev6n.js → index-DtrqgNBl.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CBh48_Mh.js → index-DwjWRUTf.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BxqC3LiO.js → index-DyFZ7gDd.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-XJIV7HEw.js → index-Ec6VBiV-.js} +1 -1
  130. package/src/assets/web-panel/assets/index-IkoHuWRe.js +1 -0
  131. package/src/assets/web-panel/assets/{index-CXVBQ82k.js → index-Jk99aZIr.js} +3 -3
  132. package/src/assets/web-panel/assets/{index-84mi5rsv.js → index-Lm9pm1zm.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-C6c0j-Ki.js → index-MuTb62K6.js} +1 -1
  134. package/src/assets/web-panel/assets/index-MwqsDbb1.js +1 -0
  135. package/src/assets/web-panel/assets/{index-DEPPzM8I.js → index-hzUfIn4u.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-DpRIjwTt.js → initDefaultProps-C6fpNcA5.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-CG4_9o-Z.js → motion-Bjh9Come.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-Dku1fXtf.js → move-DFa4ul-_.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-BvAVeX-3.js → mtc-parser-KoYqA_e5.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-DFu0x78D.js → omit-ByTjP-wG.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-CmI-FNcK.js → pickAttrs-CG_rmTxx.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-CGERYewB.js → placementArrow-LDePZ8V9.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-D7G8bF5J.js → responsiveObserve-DZFzH4RR.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-B2sXwWXy.js → slide-DfXQyTvD.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-DI5yh0n3.js → statusUtils-CuhqsJfO.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-deGJ5dp_.js → styleChecker-qqVjJw5u.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-OqHBXEmi.js → useFlexGapSupport-BPxnCxcb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-Dqgx0Qv_.js → useFs-D11NLCjV.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-Be-lveh2.js → usePersonalDataHub-HbZVcaCX.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-CFxB876W.js → vnode-CZHQlfTu.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-BFOYrl4e.js → zoom-CV3rUknJ.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/commands/context.js +31 -11
  154. package/src/commands/evolution-deployment.js +70 -0
  155. package/src/commands/plugin.js +36 -5
  156. package/src/data/changelog.json +78 -0
  157. package/src/gateways/ws/evolution-deployment-topic-handlers.js +20 -0
  158. package/src/generated/cc-agent-protocol.schema.json +44 -1
  159. package/src/harness/prompt-compressor.js +12 -4
  160. package/src/lib/background-agent-list-index.js +222 -0
  161. package/src/lib/background-agent-supervisor.js +38 -0
  162. package/src/lib/codex-app-server-adapter.js +1 -0
  163. package/src/lib/context-memory-kernel/provider-context.js +69 -4
  164. package/src/lib/deferred-question-context.js +160 -4
  165. package/src/lib/eval/plugin-suite.js +286 -22
  166. package/src/lib/evolution/evolution-deployment-config.js +16 -1
  167. package/src/lib/evolution/evolution-deployment-profile.js +102 -58
  168. package/src/lib/evolution/evolution-test-deployment.js +386 -0
  169. package/src/lib/model-context-window.js +3 -2
  170. package/src/lib/runtime-usage-ledger.js +5 -0
  171. package/src/lib/session-host-snapshot.js +16 -0
  172. package/src/repl/agent-repl.js +19 -4
  173. package/src/runtime/agent-core.js +13 -0
  174. package/src/runtime/headless-runner.js +4 -0
  175. package/src/runtime/headless-stream.js +171 -14
  176. package/src/assets/web-panel/assets/EvolutionSettings-BJmBzpW6.js +0 -1
  177. package/src/assets/web-panel/assets/MarkdownRenderer-HxeocBHy.js +0 -1
  178. package/src/assets/web-panel/assets/devWarning-BHnbnuYL.js +0 -1
  179. package/src/assets/web-panel/assets/index-CsRz9-ZH.js +0 -1
  180. package/src/assets/web-panel/assets/index-DnjMFf3m.js +0 -1
@@ -1,11 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { readFile } from "node:fs/promises";
3
- import {
4
- readFileSync,
5
- renameSync,
6
- unlinkSync,
7
- writeFileSync,
8
- } from "node:fs";
3
+ import { readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
9
4
  import { dirname, isAbsolute, join } from "node:path";
10
5
  import { resolveConfigDataRoot } from "../paths.js";
11
6
  import {
@@ -16,7 +11,7 @@ import {
16
11
  import { withFileLock } from "../with-file-lock.js";
17
12
 
18
13
  export const EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA =
19
- "chainlesschain.evolution-deployment-profile/v4";
14
+ "chainlesschain.evolution-deployment-profile/v5";
20
15
 
21
16
  const LEGACY_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA =
22
17
  "chainlesschain.evolution-deployment-profile/v1";
@@ -24,6 +19,8 @@ const PREVIOUS_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA =
24
19
  "chainlesschain.evolution-deployment-profile/v2";
25
20
  const PRIOR_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA =
26
21
  "chainlesschain.evolution-deployment-profile/v3";
22
+ const LAST_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA =
23
+ "chainlesschain.evolution-deployment-profile/v4";
27
24
  const DIGEST = /^sha256:[a-f0-9]{64}$/u;
28
25
  const MAX_TRUST_ROOT_REVISION_FLOORS = 64;
29
26
 
@@ -47,6 +44,8 @@ function normalizeProfile(value) {
47
44
  PREVIOUS_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA,
48
45
  PRIOR_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA,
49
46
  ].includes(value.schema);
47
+ const beforeDeploymentMode =
48
+ legacy || value.schema === LAST_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA;
50
49
  const expected =
51
50
  value.schema === LEGACY_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
52
51
  ? ["descriptorPath", "enabled", "schema", "trustRootPath"]
@@ -58,31 +57,44 @@ function normalizeProfile(value) {
58
57
  "schema",
59
58
  "trustRootPath",
60
59
  ]
61
- : value.schema === PRIOR_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
62
- ? [
63
- "activeTrustRootDigest",
64
- "descriptorPath",
65
- "enabled",
66
- "revisionFloors",
67
- "schema",
68
- "trustRootPath",
69
- ]
70
- : [
71
- "activeTrustRootDigest",
72
- "descriptorPath",
73
- "enabled",
74
- "revisionFloors",
75
- "revokedDescriptorRevisions",
76
- "schema",
77
- "trustRootPath",
78
- ];
60
+ : value.schema === PRIOR_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
61
+ ? [
62
+ "activeTrustRootDigest",
63
+ "descriptorPath",
64
+ "enabled",
65
+ "revisionFloors",
66
+ "schema",
67
+ "trustRootPath",
68
+ ]
69
+ : value.schema === LAST_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
70
+ ? [
71
+ "activeTrustRootDigest",
72
+ "descriptorPath",
73
+ "enabled",
74
+ "revisionFloors",
75
+ "revokedDescriptorRevisions",
76
+ "schema",
77
+ "trustRootPath",
78
+ ]
79
+ : [
80
+ "activeTrustRootDigest",
81
+ "deploymentMode",
82
+ "descriptorPath",
83
+ "enabled",
84
+ "revisionFloors",
85
+ "revokedDescriptorRevisions",
86
+ "schema",
87
+ "testPrivateKeyPath",
88
+ "trustRootPath",
89
+ ];
79
90
  if (JSON.stringify(keys) !== JSON.stringify(expected.sort()))
80
91
  throw new TypeError("evolution deployment profile has unexpected fields");
81
92
  if (
82
93
  value.schema !== EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA &&
83
94
  value.schema !== LEGACY_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA &&
84
95
  value.schema !== PREVIOUS_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA &&
85
- value.schema !== PRIOR_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
96
+ value.schema !== PRIOR_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA &&
97
+ value.schema !== LAST_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
86
98
  )
87
99
  throw new TypeError("evolution deployment profile schema is invalid");
88
100
  if (typeof value.enabled !== "boolean")
@@ -103,10 +115,30 @@ function normalizeProfile(value) {
103
115
  const activeTrustRootDigest = legacy
104
116
  ? null
105
117
  : normalizeTrustRootDigest(value.activeTrustRootDigest);
106
- const revokedDescriptorRevisions =
107
- value.schema === EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA
108
- ? normalizeRevokedDescriptorRevisions(value.revokedDescriptorRevisions)
109
- : {};
118
+ const revokedDescriptorRevisions = [
119
+ EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA,
120
+ LAST_EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA,
121
+ ].includes(value.schema)
122
+ ? normalizeRevokedDescriptorRevisions(value.revokedDescriptorRevisions)
123
+ : {};
124
+ const deploymentMode = beforeDeploymentMode
125
+ ? "managed"
126
+ : value.deploymentMode;
127
+ if (!["managed", "test"].includes(deploymentMode))
128
+ throw new TypeError("evolution deployment profile mode is invalid");
129
+ const testPrivateKeyPath = beforeDeploymentMode
130
+ ? null
131
+ : value.testPrivateKeyPath;
132
+ if (
133
+ (deploymentMode === "test" &&
134
+ (typeof testPrivateKeyPath !== "string" ||
135
+ !isAbsolute(testPrivateKeyPath))) ||
136
+ (deploymentMode === "managed" && testPrivateKeyPath !== null)
137
+ ) {
138
+ throw new TypeError(
139
+ "evolution deployment profile test private key path is invalid",
140
+ );
141
+ }
110
142
  return Object.freeze({
111
143
  schema: EVOLUTION_DEPLOYMENT_PROFILE_SCHEMA,
112
144
  enabled: value.enabled,
@@ -115,6 +147,8 @@ function normalizeProfile(value) {
115
147
  revisionFloors,
116
148
  activeTrustRootDigest,
117
149
  revokedDescriptorRevisions,
150
+ deploymentMode,
151
+ testPrivateKeyPath,
118
152
  });
119
153
  }
120
154
 
@@ -156,12 +190,16 @@ function normalizeTrustRootDigest(value) {
156
190
 
157
191
  function normalizeRevisionFloors(value) {
158
192
  if (!value || typeof value !== "object" || Array.isArray(value))
159
- throw new TypeError("evolution deployment profile revisionFloors is invalid");
193
+ throw new TypeError(
194
+ "evolution deployment profile revisionFloors is invalid",
195
+ );
160
196
  const entries = Object.entries(value).sort(([left], [right]) =>
161
197
  left.localeCompare(right),
162
198
  );
163
199
  if (entries.length > MAX_TRUST_ROOT_REVISION_FLOORS)
164
- throw new TypeError("evolution deployment profile revisionFloors is too large");
200
+ throw new TypeError(
201
+ "evolution deployment profile revisionFloors is too large",
202
+ );
165
203
  for (const [trustRootDigest, revision] of entries) {
166
204
  if (!DIGEST.test(trustRootDigest))
167
205
  throw new TypeError(
@@ -228,6 +266,8 @@ function profileFromInput(input) {
228
266
  revisionFloors: input?.revisionFloors || {},
229
267
  activeTrustRootDigest: input?.activeTrustRootDigest,
230
268
  revokedDescriptorRevisions: input?.revokedDescriptorRevisions || {},
269
+ deploymentMode: input?.deploymentMode || "managed",
270
+ testPrivateKeyPath: input?.testPrivateKeyPath || null,
231
271
  });
232
272
  }
233
273
 
@@ -251,29 +291,34 @@ export async function readEvolutionDeploymentProfile(options = {}) {
251
291
 
252
292
  export async function writeEvolutionDeploymentProfile(input, options = {}) {
253
293
  const proposed = profileFromInput(input);
254
- return updateEvolutionDeploymentProfile((current) => ({
255
- ...proposed,
256
- // This lower-level writer cannot authenticate a descriptor, so it never
257
- // lowers or erases a floor established by configureEvolutionDeployment().
258
- revisionFloors: Object.fromEntries(
259
- Object.keys({
260
- ...(current?.revisionFloors || {}),
261
- ...proposed.revisionFloors,
262
- }).map((trustRootDigest) => [
263
- trustRootDigest,
264
- Math.max(
265
- current?.revisionFloors?.[trustRootDigest] || 0,
266
- proposed.revisionFloors[trustRootDigest] || 0,
267
- ),
268
- ]),
269
- ),
270
- activeTrustRootDigest:
271
- proposed.activeTrustRootDigest || current?.activeTrustRootDigest,
272
- revokedDescriptorRevisions: {
273
- ...(current?.revokedDescriptorRevisions || {}),
274
- ...(proposed.revokedDescriptorRevisions || {}),
275
- },
276
- }), options);
294
+ return updateEvolutionDeploymentProfile(
295
+ (current) => ({
296
+ ...proposed,
297
+ // This lower-level writer cannot authenticate a descriptor, so it never
298
+ // lowers or erases a floor established by configureEvolutionDeployment().
299
+ revisionFloors: Object.fromEntries(
300
+ Object.keys({
301
+ ...(current?.revisionFloors || {}),
302
+ ...proposed.revisionFloors,
303
+ }).map((trustRootDigest) => [
304
+ trustRootDigest,
305
+ Math.max(
306
+ current?.revisionFloors?.[trustRootDigest] || 0,
307
+ proposed.revisionFloors[trustRootDigest] || 0,
308
+ ),
309
+ ]),
310
+ ),
311
+ activeTrustRootDigest:
312
+ proposed.activeTrustRootDigest || current?.activeTrustRootDigest,
313
+ revokedDescriptorRevisions: {
314
+ ...(current?.revokedDescriptorRevisions || {}),
315
+ ...(proposed.revokedDescriptorRevisions || {}),
316
+ },
317
+ deploymentMode: proposed.deploymentMode,
318
+ testPrivateKeyPath: proposed.testPrivateKeyPath,
319
+ }),
320
+ options,
321
+ );
277
322
  }
278
323
 
279
324
  /**
@@ -335,9 +380,8 @@ export function assertEvolutionDeploymentDescriptorNotRevoked(
335
380
  profile,
336
381
  descriptor,
337
382
  ) {
338
- const revoked = profile?.revokedDescriptorRevisions?.[
339
- descriptor?.trustRootDigest
340
- ];
383
+ const revoked =
384
+ profile?.revokedDescriptorRevisions?.[descriptor?.trustRootDigest];
341
385
  if (!revoked?.includes(descriptor?.revision)) return;
342
386
  const error = new Error(
343
387
  `evolution deployment descriptor revision ${descriptor.revision} is revoked`,
@@ -0,0 +1,386 @@
1
+ import {
2
+ createPrivateKey,
3
+ createPublicKey,
4
+ generateKeyPairSync,
5
+ randomUUID,
6
+ sign as signBytes,
7
+ } from "node:crypto";
8
+ import {
9
+ existsSync,
10
+ mkdirSync,
11
+ readFileSync,
12
+ renameSync,
13
+ unlinkSync,
14
+ writeFileSync,
15
+ } from "node:fs";
16
+ import { dirname, isAbsolute, join, resolve } from "node:path";
17
+ import { configureEvolutionDeployment } from "./evolution-deployment-config.js";
18
+ import {
19
+ EVOLUTION_DEPLOYMENT_DESCRIPTOR_SCHEMA,
20
+ computeEvolutionDeploymentDigest,
21
+ serializeEvolutionDeploymentDescriptorPayload,
22
+ verifyEvolutionDeployment,
23
+ } from "./evolution-deployment-loader.js";
24
+ import {
25
+ getEvolutionDeploymentProfilePath,
26
+ readEvolutionDeploymentProfile,
27
+ } from "./evolution-deployment-profile.js";
28
+ import {
29
+ EVOLUTION_DEPLOYMENT_ROOT_ROTATION_SCHEMA,
30
+ serializeEvolutionDeploymentRootRotationPayload,
31
+ } from "./evolution-deployment-root-rotation.js";
32
+ import {
33
+ PRIVATE_FILE_MODE,
34
+ ensurePrivateDirectory,
35
+ ensurePrivateFile,
36
+ } from "../secure-fs.js";
37
+
38
+ export const EVOLUTION_TEST_DEPLOYMENT_COMMANDS = Object.freeze([
39
+ "agent",
40
+ "ask",
41
+ "chat",
42
+ "compact",
43
+ "complete",
44
+ "cowork",
45
+ "desktop",
46
+ "evolution",
47
+ "hub",
48
+ "learning",
49
+ "marketplace",
50
+ "orchestrate",
51
+ "serve",
52
+ "skill",
53
+ "stream",
54
+ "ui",
55
+ ]);
56
+
57
+ const TEST_PRIVATE_KEY_FILE = "test-signing-private.pem";
58
+ const TEST_TRUST_ROOT_FILE = "test-signing-public.pem";
59
+ const TEST_DESCRIPTOR_FILE = "test-deployment.json";
60
+ const TEST_README_FILE = "README-TEST-ONLY.txt";
61
+ const MAX_MODULE_BYTES = 4 * 1024 * 1024;
62
+
63
+ function writePrivateAtomic(filePath, value) {
64
+ ensurePrivateDirectory(dirname(filePath));
65
+ const temporaryPath = join(
66
+ dirname(filePath),
67
+ `.${filePath.split(/[\\/]/u).at(-1)}.${randomUUID()}.tmp`,
68
+ );
69
+ try {
70
+ writeFileSync(temporaryPath, value, {
71
+ flag: "wx",
72
+ mode: PRIVATE_FILE_MODE,
73
+ });
74
+ ensurePrivateFile(temporaryPath);
75
+ renameSync(temporaryPath, filePath);
76
+ ensurePrivateFile(filePath);
77
+ } catch (error) {
78
+ try {
79
+ unlinkSync(temporaryPath);
80
+ } catch {
81
+ // The temporary file was not created or has already been renamed.
82
+ }
83
+ throw error;
84
+ }
85
+ }
86
+
87
+ function assertNoEnvironmentOverride(env) {
88
+ if (
89
+ env.CHAINLESSCHAIN_EVOLUTION_DEPLOYMENT_DESCRIPTOR ||
90
+ env.CHAINLESSCHAIN_EVOLUTION_DEPLOYMENT_TRUST_ROOT
91
+ ) {
92
+ throw new Error(
93
+ "test deployment setup requires the Evolution deployment environment overrides to be unset",
94
+ );
95
+ }
96
+ }
97
+
98
+ function normalizeCommands(commands) {
99
+ const value =
100
+ commands === undefined
101
+ ? [...EVOLUTION_TEST_DEPLOYMENT_COMMANDS]
102
+ : typeof commands === "string"
103
+ ? commands
104
+ .split(",")
105
+ .map((command) => command.trim())
106
+ .filter(Boolean)
107
+ : Array.isArray(commands)
108
+ ? [...commands]
109
+ : null;
110
+ if (!value || value.length === 0 || new Set(value).size !== value.length)
111
+ throw new TypeError(
112
+ "test deployment commands must be a non-empty unique list",
113
+ );
114
+ return value.sort();
115
+ }
116
+
117
+ function readRevision(descriptorPath) {
118
+ if (!existsSync(descriptorPath)) return 0;
119
+ try {
120
+ const descriptor = JSON.parse(readFileSync(descriptorPath, "utf8"));
121
+ if (!Number.isSafeInteger(descriptor.revision) || descriptor.revision < 1)
122
+ throw new Error("revision is invalid");
123
+ return descriptor.revision;
124
+ } catch (error) {
125
+ throw new Error(
126
+ "existing test deployment descriptor cannot be refreshed",
127
+ error instanceof Error ? { cause: error } : undefined,
128
+ );
129
+ }
130
+ }
131
+
132
+ function assertSigningPair(privateKeyBytes, trustRootBytes) {
133
+ let privateKey;
134
+ let actualPublic;
135
+ let expectedPublic;
136
+ try {
137
+ privateKey = createPrivateKey(privateKeyBytes);
138
+ actualPublic = createPublicKey(privateKey).export({
139
+ type: "spki",
140
+ format: "der",
141
+ });
142
+ expectedPublic = createPublicKey(trustRootBytes).export({
143
+ type: "spki",
144
+ format: "der",
145
+ });
146
+ } catch {
147
+ throw new Error("test deployment signing key pair is invalid");
148
+ }
149
+ if (!Buffer.from(actualPublic).equals(Buffer.from(expectedPublic)))
150
+ throw new Error(
151
+ "test deployment signing key does not match its trust root",
152
+ );
153
+ return privateKey;
154
+ }
155
+
156
+ function claimFreshTestRoot(profilePath) {
157
+ const parent = dirname(profilePath);
158
+ const preferred = join(parent, "test-deployment");
159
+ ensurePrivateDirectory(parent);
160
+ for (const candidate of [
161
+ preferred,
162
+ join(parent, `test-deployment-${randomUUID()}`),
163
+ ]) {
164
+ try {
165
+ mkdirSync(candidate, { mode: 0o700 });
166
+ ensurePrivateDirectory(candidate);
167
+ return candidate;
168
+ } catch (error) {
169
+ if (error?.code !== "EEXIST") throw error;
170
+ }
171
+ }
172
+ throw new Error("could not allocate a private test deployment directory");
173
+ }
174
+
175
+ function testReadme({ modulePath, descriptorPath, trustRootPath }) {
176
+ return `ChainlessChain Skill evolution development environment / 仅限测试开发
177
+
178
+ This directory contains an automatically generated Ed25519 TEST key. It is not
179
+ a production certificate, HSM/KMS identity, reviewer identity, or production
180
+ approval. Automatic active promotion remains HOLD.
181
+
182
+ 本目录包含自动生成的 Ed25519 测试密钥,只用于正式部署前联调。它不属于生产证书、
183
+ HSM/KMS 身份或审核身份,也不会解除人工审核和 automatic active promotion HOLD。
184
+
185
+ Deployment host: ${modulePath}
186
+ Signed descriptor: ${descriptorPath}
187
+ Test trust root: ${trustRootPath}
188
+
189
+ Re-run "cc evolution deployment init-test --module <absolute-path>" after the
190
+ host module changes. When the managed descriptor and trust root are available,
191
+ run "cc evolution deployment replace-test --descriptor <path> --trust-root <path>".
192
+
193
+ 部署宿主模块变更后请重新执行 init-test 刷新摘要和签名。正式 descriptor 与 trust
194
+ root 到位后执行 replace-test;CLI 会用测试根签发一次根轮换证明并切换到正式配置。
195
+ `;
196
+ }
197
+
198
+ /**
199
+ * Generate or refresh a local-only Ed25519 deployment wrapper for an existing
200
+ * development host. The ordinary descriptor verifier and profile writer remain
201
+ * the only activation path; this helper never bypasses deployment admission.
202
+ */
203
+ export async function initializeEvolutionTestDeployment(
204
+ { modulePath, commands, enabled = true },
205
+ options = {},
206
+ ) {
207
+ const env = options.env || process.env;
208
+ const resolveRealPath =
209
+ options.resolveRealPath ||
210
+ (async (value) => {
211
+ const { realpath } = await import("node:fs/promises");
212
+ return realpath(value);
213
+ });
214
+ assertNoEnvironmentOverride(env);
215
+ if (typeof modulePath !== "string" || !modulePath.trim())
216
+ throw new TypeError(
217
+ "an absolute test deployment host module path is required",
218
+ );
219
+ const requestedModulePath = modulePath.trim();
220
+ if (!isAbsolute(requestedModulePath))
221
+ throw new TypeError("test deployment host module path must be absolute");
222
+ const realModulePath = await resolveRealPath(requestedModulePath);
223
+ const moduleBytes = readFileSync(realModulePath);
224
+ if (moduleBytes.byteLength === 0 || moduleBytes.byteLength > MAX_MODULE_BYTES)
225
+ throw new Error("test deployment host module size is invalid");
226
+
227
+ const saved = await readEvolutionDeploymentProfile(options);
228
+ if (saved.error) throw new Error(saved.error);
229
+ if (saved.profile && saved.profile.deploymentMode !== "test") {
230
+ const error = new Error(
231
+ "a managed Evolution deployment profile already exists; test setup will not replace it",
232
+ );
233
+ error.code = "EVOLUTION_TEST_DEPLOYMENT_MANAGED_PROFILE_EXISTS";
234
+ throw error;
235
+ }
236
+
237
+ const requestedTestRoot = saved.profile
238
+ ? dirname(saved.profile.descriptorPath)
239
+ : claimFreshTestRoot(
240
+ options.filePath || getEvolutionDeploymentProfilePath(options),
241
+ );
242
+ ensurePrivateDirectory(requestedTestRoot);
243
+ // macOS exposes /var through the /private/var real path. Persist and compare
244
+ // the physical path so a refresh does not mistake those aliases for two
245
+ // different credential directories.
246
+ const testRoot = await resolveRealPath(requestedTestRoot);
247
+ const privateKeyPath = join(testRoot, TEST_PRIVATE_KEY_FILE);
248
+ const trustRootPath = join(testRoot, TEST_TRUST_ROOT_FILE);
249
+ const descriptorPath = join(testRoot, TEST_DESCRIPTOR_FILE);
250
+ let privateKeyBytes;
251
+ let trustRootBytes;
252
+ let generated = false;
253
+ if (saved.profile) {
254
+ const [savedDescriptorPath, savedTrustRootPath, savedPrivateKeyPath] =
255
+ await Promise.all([
256
+ resolveRealPath(saved.profile.descriptorPath),
257
+ resolveRealPath(saved.profile.trustRootPath),
258
+ resolveRealPath(saved.profile.testPrivateKeyPath),
259
+ ]);
260
+ if (
261
+ resolve(savedDescriptorPath) !== resolve(descriptorPath) ||
262
+ resolve(savedTrustRootPath) !== resolve(trustRootPath) ||
263
+ resolve(savedPrivateKeyPath) !== resolve(privateKeyPath)
264
+ ) {
265
+ throw new Error("saved test deployment paths are inconsistent");
266
+ }
267
+ ensurePrivateFile(privateKeyPath);
268
+ ensurePrivateFile(trustRootPath);
269
+ privateKeyBytes = readFileSync(privateKeyPath);
270
+ trustRootBytes = readFileSync(trustRootPath);
271
+ } else {
272
+ const { privateKey, publicKey } = generateKeyPairSync("ed25519");
273
+ privateKeyBytes = privateKey.export({ type: "pkcs8", format: "pem" });
274
+ trustRootBytes = publicKey.export({ type: "spki", format: "pem" });
275
+ writePrivateAtomic(privateKeyPath, privateKeyBytes);
276
+ writePrivateAtomic(trustRootPath, trustRootBytes);
277
+ generated = true;
278
+ }
279
+ const privateKey = assertSigningPair(privateKeyBytes, trustRootBytes);
280
+ const descriptor = {
281
+ schema: EVOLUTION_DEPLOYMENT_DESCRIPTOR_SCHEMA,
282
+ revision: readRevision(descriptorPath) + 1,
283
+ modulePath: realModulePath,
284
+ moduleDigest: computeEvolutionDeploymentDigest(moduleBytes),
285
+ trustRootDigest: computeEvolutionDeploymentDigest(trustRootBytes),
286
+ commands: normalizeCommands(commands),
287
+ };
288
+ descriptor.signature = signBytes(
289
+ null,
290
+ Buffer.from(serializeEvolutionDeploymentDescriptorPayload(descriptor)),
291
+ privateKey,
292
+ ).toString("base64");
293
+ writePrivateAtomic(
294
+ descriptorPath,
295
+ `${JSON.stringify(descriptor, null, 2)}\n`,
296
+ );
297
+ writePrivateAtomic(
298
+ join(testRoot, TEST_README_FILE),
299
+ testReadme({ modulePath: realModulePath, descriptorPath, trustRootPath }),
300
+ );
301
+
302
+ const status = await configureEvolutionDeployment(
303
+ {
304
+ descriptorPath,
305
+ trustRootPath,
306
+ enabled,
307
+ deploymentMode: "test",
308
+ testPrivateKeyPath: privateKeyPath,
309
+ },
310
+ options,
311
+ );
312
+ return Object.freeze({
313
+ ...status,
314
+ generated,
315
+ testRootPath: testRoot,
316
+ warning:
317
+ "TEST ONLY: local development credentials; automatic active promotion remains HOLD",
318
+ });
319
+ }
320
+
321
+ /** Replace an active generated test root with an operator-signed deployment. */
322
+ export async function replaceEvolutionTestDeployment(
323
+ { descriptorPath, trustRootPath },
324
+ options = {},
325
+ ) {
326
+ const env = options.env || process.env;
327
+ assertNoEnvironmentOverride(env);
328
+ const saved = await readEvolutionDeploymentProfile(options);
329
+ if (saved.error) throw new Error(saved.error);
330
+ if (saved.profile?.deploymentMode !== "test") {
331
+ const error = new Error(
332
+ "the saved Evolution deployment is not a generated test deployment",
333
+ );
334
+ error.code = "EVOLUTION_TEST_DEPLOYMENT_NOT_ACTIVE";
335
+ throw error;
336
+ }
337
+ const destination = await verifyEvolutionDeployment(
338
+ { descriptorPath, trustRootPath },
339
+ options,
340
+ );
341
+ ensurePrivateFile(saved.profile.testPrivateKeyPath);
342
+ ensurePrivateFile(saved.profile.trustRootPath);
343
+ const privateKeyBytes = readFileSync(saved.profile.testPrivateKeyPath);
344
+ const fromTrustRootBytes = readFileSync(saved.profile.trustRootPath);
345
+ const privateKey = assertSigningPair(privateKeyBytes, fromTrustRootBytes);
346
+ if (
347
+ computeEvolutionDeploymentDigest(fromTrustRootBytes) !==
348
+ saved.profile.activeTrustRootDigest
349
+ ) {
350
+ throw new Error(
351
+ "generated test trust root does not match the active profile",
352
+ );
353
+ }
354
+ const rotation = {
355
+ schema: EVOLUTION_DEPLOYMENT_ROOT_ROTATION_SCHEMA,
356
+ fromTrustRootDigest: saved.profile.activeTrustRootDigest,
357
+ toTrustRootDigest: destination.descriptor.trustRootDigest,
358
+ minimumDescriptorRevision: destination.descriptor.revision,
359
+ };
360
+ rotation.signature = signBytes(
361
+ null,
362
+ Buffer.from(serializeEvolutionDeploymentRootRotationPayload(rotation)),
363
+ privateKey,
364
+ ).toString("base64");
365
+ const rotationPath = join(
366
+ dirname(saved.profile.descriptorPath),
367
+ "managed-root-rotation.json",
368
+ );
369
+ writePrivateAtomic(rotationPath, `${JSON.stringify(rotation, null, 2)}\n`);
370
+ const status = await configureEvolutionDeployment(
371
+ {
372
+ descriptorPath,
373
+ trustRootPath,
374
+ rootRotationPath: rotationPath,
375
+ enabled: true,
376
+ deploymentMode: "managed",
377
+ testPrivateKeyPath: null,
378
+ },
379
+ options,
380
+ );
381
+ return Object.freeze({
382
+ ...status,
383
+ replacedTestDeployment: true,
384
+ rootRotationPath: rotationPath,
385
+ });
386
+ }
@@ -2,6 +2,7 @@ import { resolveModelCapabilityProfile } from "./model-capabilities.js";
2
2
 
3
3
  export { CONTEXT_WINDOWS } from "./model-context-catalog.js";
4
4
 
5
- export function getContextWindow(model, provider) {
6
- return resolveModelCapabilityProfile({ model, provider }).contextWindowTokens;
5
+ export function getContextWindow(model, provider, options = {}) {
6
+ return resolveModelCapabilityProfile({ ...options, model, provider })
7
+ .contextWindowTokens;
7
8
  }
@@ -162,6 +162,11 @@ export function projectRuntimeTokenUsage(event = {}) {
162
162
  ...(projectedOperationId ? { operationId: projectedOperationId } : {}),
163
163
  ...(event.source ? { source: source(event.source) } : {}),
164
164
  ...(attribution ? { attribution } : {}),
165
+ ...(Number.isSafeInteger(event.contextWindow) &&
166
+ event.contextWindow >= 1024 &&
167
+ event.contextWindow <= 16777216
168
+ ? { contextWindow: event.contextWindow }
169
+ : {}),
165
170
  };
166
171
  }
167
172