chainlesschain 0.165.10 → 0.166.1

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 (189) hide show
  1. package/completions/_cc +2 -1
  2. package/completions/cc.bash +2 -2
  3. package/completions/cc.fish +2 -2
  4. package/completions/cc.ps1 +2 -1
  5. package/package.json +1 -1
  6. package/src/assets/web-panel/assets/{AIOps-DoxapYEM.js → AIOps-DwdhBUBc.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-DyiHvT2O.js → ActionButton-Dd1lBEeo.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-CAX06POB.js → Analytics-DuGuuI36.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-JXxcyn0R.js → AppLayout-CvHpSs3M.js} +5 -5
  10. package/src/assets/web-panel/assets/{Artifacts-40nZDb9N.js → Artifacts-BU9F3wJh.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-B_wc8Kcq.js → Audit-DK_n_WFm.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-CReWOiQY.js → BackgroundAgents-qKsxF5tv.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-sXrv9fE6.js → Backup-JS58pSyV.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-CHWmIERI.js → BaseInput-gGl6Ray1.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-DgQrMZCb.js → Chat-B2FZNq3U.js} +6 -6
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Clpgj0fi.js → ChatBubbleRenderer-CZS_bLAr.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-DmRwzt3e.js → Checkbox-tsI0TE22.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-tllAfrrc.js → Codegen-D5kqhfAr.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-CA_wqwEp.js → Col-DdN1TrqS.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-DQ_szKAv.js → Community-DgbEeh6V.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-CjkqX60k.js → Compact-FIm-fRB_.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-CfDNkDex.js → Compliance-B-N0pudf.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-PINc6CPv.js → Cowork-CuMafBpi.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-snYq4WCj.js → Cron-BTwzNFHR.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-CKR7he4B.js → Crosschain-DRoYbLOd.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-Bp5xJSbE.js → DID-CPhnNkz_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-Dn-y6txl.js → Dashboard-DJQftix2.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-D0uEeunr.js → Dropdown-PSAH1Kfy.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-DIhjyeNw.js → EmailListRenderer-PVRqeMiZ.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D2Pv1Hnb.js → FamilyGuardDashboard-CYtnjqjl.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-D6oSp4P4.js → Federation-_-53kTDz.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-s6bzlfQs.js → FormItemContext-DTQ4qGuE.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-B_NTgGP9.js → GenericCardRenderer-ON_NfX8k.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-Dk1lCoBr.js → Git-DUc3w_Bf.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-xOnLBQzd.js → Governance-CktsJ2ku.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-BFVHy-0I.js → Inference-4wUHQvju.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-BXzITB9_.js → KnowledgeGraph-Dq4saPnZ.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BD2M4NPu.js → Logs-Btb50m5s.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-Cre8P8HG.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-awpllI_9.js → Marketplace-D3rSncxx.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-tL0IgbIX.js → McpTools-Bc6Mori_.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CrptLGSN.js → Memory-C-ottUdN.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-DZX-l_BS.js → MobileBridge-C0DITBmP.js} +1 -1
  44. package/src/assets/web-panel/assets/MobileProjects-O6cr0Nal.js +1 -0
  45. package/src/assets/web-panel/assets/{Mtc-dQ5-FjpQ.js → Mtc-B_MXKXvY.js} +6 -6
  46. package/src/assets/web-panel/assets/{MtcAudit-U0nDxDlG.js → MtcAudit-BDkUqWIT.js} +5 -5
  47. package/src/assets/web-panel/assets/{Multisig-D1PpAtiq.js → Multisig-BaxNWm8c.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-phZr6nyZ.js → NLProgramming-UD2GndZc.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-BPzSSUrX.js → Notes-pU7wtMwB.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-AypFEc7p.js → NotificationSettings-BIs6ULr3.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-S3k1qjT-.js → OrderTableRenderer-0NuumnfG.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-BvdQXFPR.js → Organization-C9o-n2lq.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-CUz_jbQC.js → Overflow-CEvMXxCS.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-C0xQ7H_2.js → P2P-C3gQMTK3.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-DJKMjfB8.js → PdhVaultBrowser-D1LVpBOr.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-dkMtmDwK.js → Permissions-Dj5nIi0Y.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-CyHE7fnn.js → PersonalDataHub-uiLYuFcu.js} +6 -6
  58. package/src/assets/web-panel/assets/{Pipeline-_dU0Nwy3.js → Pipeline-CIrmF89x.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-fqLyg57f.js → Privacy-B3K1CUBa.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-COybCr5d.js → ProjectInit-C_wCZ0zW.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-B4DngMZW.js → ProjectSettings-iCitfuNJ.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-D0bMwUBm.js → Projects-BwimeXkW.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-Ba-7WNA8.js → Providers-BLpepgr6.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-X-I8dDMT.js → QrScannerModal-DPy8tjXV.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BCUP0a90.js → QuickAsk-CRq8VhID.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-DtFNmiQZ.js → Recommend-CirlWIiK.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-INR5CIAI.js → RemoteSession-nlnJlKXO.js} +3 -3
  68. package/src/assets/web-panel/assets/{Reputation-B6NfaCc6.js → Reputation-B5aaxee5.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-Dmz76txh.js → Row-lzsTQZlq.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-B7qyFCea.js → RssFeed-C41AzjgC.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-Bi6eS0oY.js → Search-1Hxx3TZ3.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-D9_xim1L.js → Security-8VqwRxAp.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-PI1O-uYU.js → Services-DCm0HHAD.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-B8BrJnk8.js → Skeleton-D6w5gpmW.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-DvSm92dJ.js → Skills-Bw_pUTJB.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-BWyhCoRo.js → Sla-BkMj8Dxu.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-BL9H27jl.js → SpeechSettings-BOmLqW44.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-B7r--6yN.js → SyncSettings-2xKSqFDO.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-sc64p2Jt.js → Tasks-BPAnzVau.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-DEK55RVb.js → Templates-CcOGWgZz.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-DElr8R1l.js → Tenant-CAyzzQWN.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-BywaLBgz.js → Terminal-Daagerkm.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-B5NcgLyS.js → TimelineRenderer-1jGbMj7I.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-COFYqr6A.js → Tokens-CYQ-FQju.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-CfnVS3ij.js → Trigger-C70zRwuR.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-Bz94Gu5k.js → Trust-CeqXfiX_.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-Be10drSk.js → UkeySign-D0j6m1bU.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-CUB_cMem.js → VideoEditing-DFHpM7Yd.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-DxBJJuvG.js → Wallet-BVC2J0Yx.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-BZx5lwT8.js → WebAuthn-BceIN2Gn.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-B4sJikPT.js → WorkflowEditor-Bgeb-i-S.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-Wl-95AgM.js → chat-BmMBqgvz.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-DUSwYVCg.js → colors-sjRzwnyw.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-DkKRDHcU.js → compact-item-DNt6m2bM.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-B5nAVC_Y.js → createContext-DELaLit3.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-Ct8o3bu_.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-rtotsRlA.js → hasIn-dfwk9O8x.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B_KDhTdt.js → index-1w7dha_a.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-C7kGJlSA.js → index-6bjBUhoH.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CN2LNCWW.js → index-B0wkOqE9.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CAtnIdx_.js → index-B4Z4HZcf.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-D7zQADRc.js → index-B7qiZc2Z.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DoBh4Ezg.js → index-BLbvXsxf.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-mwPG3TJQ.js → index-BMnvNNEd.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Ba8raWtd.js → index-BSB9Gin8.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CJWpTdCW.js → index-BXJ68ObJ.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DCCTgytM.js → index-Bs-mWOWt.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-D7Nx-jzS.js → index-BvIQ9sZa.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DUS7KK-i.js → index-BzddvOOb.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-X36Wyd1S.js → index-C2Sxf7yC.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-btxpIsXs.js → index-CAIn5cS9.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CskW4gDB.js → index-CLSqyAcE.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CUDraKtq.js → index-Cbu3-zFd.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Cv38Cwx0.js → index-Clrqtycd.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DupOVIEb.js → index-CpVt6M_8.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-yt994jkW.js → index-CtfYPnsY.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-JWQxvZ4x.js → index-CujMHspH.js} +1 -1
  118. package/src/assets/web-panel/assets/index-D685kO6L.js +1 -0
  119. package/src/assets/web-panel/assets/{index-Bj6mJ7tw.js → index-DC6FlHlP.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DQhlLyT6.js → index-DFOYbzg-.js} +1 -1
  121. package/src/assets/web-panel/assets/index-DTlIRMqX.js +1 -0
  122. package/src/assets/web-panel/assets/{index-BMHNKa11.js → index-DV8q_Hki.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-C3lcOYkZ.js → index-DX3wwu3G.js} +3 -3
  124. package/src/assets/web-panel/assets/{index-CUqLWyY0.js → index-DY2G1Th2.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-cKc70R9h.js → index-DlYL8VP8.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-1J_Q-Ovw.js → index-DnQOc5wo.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CDWNrtvg.js → index-Du62m6pG.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-03w73yRM.js → index-LMfsEdLk.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-YANfaEyE.js → index-OC3qYV4-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dnbdqjxz.js → index-Rt-fym5b.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DfNeBiyO.js → index-WpEDoyTv.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-INU8TpRu.js → index-aj9ObF2R.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CAdTY3kv.js → index-dAF9qRVa.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BxAMRZR0.js → index-dpDeFZNt.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CbqotoPt.js → index-fNwu9CU_.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-Ch5SqZaK.js → index-vCQ3l6DX.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-Ck8wTHsR.js → initDefaultProps-DUt9Xj8y.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-teBWI8ni.js → motion-DdiFPnv7.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-BdxzRStQ.js → move-BJ2VH7Y2.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-DMpcDDsk.js → mtc-parser-BCnX6oOJ.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-BwkyHyWr.js → omit-CyHxlDLV.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-SlaxZUQd.js → pickAttrs-BJiGW3bY.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-BlEZZ3cs.js → placementArrow-DhJ9Rhx8.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-Cl5uK6S5.js → responsiveObserve-C6zpL9bC.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-LlOJWbeE.js → slide-DCbMFRF-.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-DxbwIpQR.js → statusUtils-CNtVLsIq.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-G_P9gils.js → styleChecker-Z078OtUc.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-BDS7KDuK.js → useFlexGapSupport-w4RVmcGs.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-Xx3R_4Qk.js → useFs-D4Xw1XRt.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-ChOtRWax.js → usePersonalDataHub-Bnbd1PgY.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-CAUrMwRC.js → vnode-DSOQxMFN.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-Choqv7b5.js → zoom-DNPE1Wca.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +3 -3
  155. package/src/command-manifest.json +1 -1
  156. package/src/commands/agent.js +1 -1
  157. package/src/commands/graph.js +100 -0
  158. package/src/commands/orchestrate.js +85 -18
  159. package/src/commands/serve.js +39 -0
  160. package/src/commands/team.js +2 -0
  161. package/src/data/changelog.json +27 -1
  162. package/src/generated/cc-agent-protocol.schema.json +2013 -0
  163. package/src/lib/app-server/bounded-queue.js +87 -0
  164. package/src/lib/app-server/cli-agent-kernel-adapter.js +309 -0
  165. package/src/lib/app-server/protocol.js +125 -0
  166. package/src/lib/app-server/rollout-store.js +603 -0
  167. package/src/lib/app-server/server.js +922 -0
  168. package/src/lib/app-server/sqlite-rollout-store.js +315 -0
  169. package/src/lib/app-server/stdio-transport.js +118 -0
  170. package/src/lib/codex-app-server-adapter.js +249 -0
  171. package/src/lib/graph-kernel/adapters.js +238 -0
  172. package/src/lib/graph-kernel/compiler.js +1443 -0
  173. package/src/lib/graph-kernel/eval.js +207 -0
  174. package/src/lib/graph-kernel/event-store.js +101 -0
  175. package/src/lib/graph-kernel/index.js +7 -0
  176. package/src/lib/graph-kernel/runtime.js +3788 -0
  177. package/src/lib/graph-kernel/trace-reducer.js +409 -0
  178. package/src/lib/graph-kernel/trigger-adapter.js +183 -0
  179. package/src/lib/orchestrator.js +2 -1
  180. package/src/lib/record-replay/index.js +1 -0
  181. package/src/lib/record-replay/skill-recorder.js +386 -0
  182. package/src/lib/webhook-security.js +159 -0
  183. package/src/repl/agent-repl.js +5 -4
  184. package/src/repl/prompt-interactions.js +11 -1
  185. package/src/assets/web-panel/assets/MarkdownRenderer-CDSwkj7Y.js +0 -1
  186. package/src/assets/web-panel/assets/MobileProjects-krNyADYi.js +0 -1
  187. package/src/assets/web-panel/assets/devWarning-DFO12EfA.js +0 -1
  188. package/src/assets/web-panel/assets/index-DaDlUWea.js +0 -1
  189. package/src/assets/web-panel/assets/index-xn89TjWJ.js +0 -1
@@ -0,0 +1,603 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { ensureDir, getHomeDir } from "../paths.js";
5
+ import { withFileLock } from "../with-file-lock.js";
6
+
7
+ export const ROLLOUT_EVENT_SCHEMA = "chainlesschain.rollout-event/v1";
8
+ export const ROLLOUT_STORE_SCHEMA = "chainlesschain.rollout-store/v1";
9
+ export const ROLLOUT_STORE_VERSION = 1;
10
+ export const ROLLOUT_STORE_MIN_VERSION = 1;
11
+
12
+ const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$/u;
13
+ const IDEMPOTENCY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/u;
14
+
15
+ function storeError(code, message, details = {}) {
16
+ const error = new Error(message);
17
+ error.name = "RolloutStoreError";
18
+ error.code = code;
19
+ Object.assign(error, details);
20
+ return error;
21
+ }
22
+
23
+ function identifier(value, label = "identifier") {
24
+ const output = String(value || "").trim();
25
+ if (!ID_PATTERN.test(output)) {
26
+ throw storeError("CC_ROLLOUT_INVALID_ARGUMENT", `${label} is invalid`);
27
+ }
28
+ return output;
29
+ }
30
+
31
+ function idempotencyKey(value) {
32
+ if (value == null) return null;
33
+ const output = String(value).trim();
34
+ if (!IDEMPOTENCY_PATTERN.test(output)) {
35
+ throw storeError(
36
+ "CC_ROLLOUT_INVALID_ARGUMENT",
37
+ "idempotencyKey is invalid",
38
+ );
39
+ }
40
+ return output;
41
+ }
42
+
43
+ function stableValue(value) {
44
+ if (Array.isArray(value)) return value.map(stableValue);
45
+ if (!value || typeof value !== "object") {
46
+ if (typeof value === "number" && !Number.isFinite(value)) {
47
+ throw storeError(
48
+ "CC_ROLLOUT_INVALID_ARGUMENT",
49
+ "rollout values must be finite JSON",
50
+ );
51
+ }
52
+ return value;
53
+ }
54
+ const prototype = Object.getPrototypeOf(value);
55
+ if (prototype !== Object.prototype && prototype !== null) {
56
+ throw storeError(
57
+ "CC_ROLLOUT_INVALID_ARGUMENT",
58
+ "rollout values must be plain JSON objects",
59
+ );
60
+ }
61
+ return Object.fromEntries(
62
+ Object.keys(value)
63
+ .filter((key) => value[key] !== undefined)
64
+ .sort()
65
+ .map((key) => [key, stableValue(value[key])]),
66
+ );
67
+ }
68
+
69
+ function canonicalJson(value) {
70
+ return JSON.stringify(stableValue(value));
71
+ }
72
+
73
+ function digest(value) {
74
+ return `sha256:${createHash("sha256").update(canonicalJson(value)).digest("hex")}`;
75
+ }
76
+
77
+ function recordHash(record) {
78
+ const unsigned = { ...record };
79
+ delete unsigned.hash;
80
+ return digest(unsigned);
81
+ }
82
+
83
+ function clone(value) {
84
+ return value == null ? value : JSON.parse(JSON.stringify(value));
85
+ }
86
+
87
+ function timestamp(now) {
88
+ return new Date(now()).toISOString();
89
+ }
90
+
91
+ function buildRecord(input, previous, now) {
92
+ const threadId = identifier(input.threadId, "threadId");
93
+ const record = {
94
+ schema: ROLLOUT_EVENT_SCHEMA,
95
+ schema_version: ROLLOUT_STORE_VERSION,
96
+ thread_id: threadId,
97
+ turn_id: input.turnId == null ? null : identifier(input.turnId, "turnId"),
98
+ item_id: input.itemId == null ? null : identifier(input.itemId, "itemId"),
99
+ event_seq: previous ? previous.event_seq + 1 : 1,
100
+ event_type: identifier(input.eventType, "eventType"),
101
+ tool_use_id:
102
+ input.toolUseId == null ? null : identifier(input.toolUseId, "toolUseId"),
103
+ approval_id:
104
+ input.approvalId == null
105
+ ? null
106
+ : identifier(input.approvalId, "approvalId"),
107
+ trace_id:
108
+ input.traceId == null ? null : identifier(input.traceId, "traceId"),
109
+ parent_id:
110
+ input.parentId == null ? null : identifier(input.parentId, "parentId"),
111
+ idempotency_key: idempotencyKey(input.idempotencyKey),
112
+ timestamp: input.timestamp || timestamp(now),
113
+ payload: stableValue(input.payload ?? null),
114
+ prev_hash: previous?.hash || null,
115
+ };
116
+ return Object.freeze({ ...record, hash: recordHash(record) });
117
+ }
118
+
119
+ function verifyRecords(records, expectedThreadId = null) {
120
+ let previous = null;
121
+ for (const record of records) {
122
+ if (
123
+ !record ||
124
+ record.schema !== ROLLOUT_EVENT_SCHEMA ||
125
+ record.schema_version < ROLLOUT_STORE_MIN_VERSION ||
126
+ record.schema_version > ROLLOUT_STORE_VERSION
127
+ ) {
128
+ throw storeError(
129
+ "CC_ROLLOUT_CORRUPT",
130
+ "rollout contains an unsupported event record",
131
+ );
132
+ }
133
+ if (
134
+ (expectedThreadId && record.thread_id !== expectedThreadId) ||
135
+ record.event_seq !== (previous?.event_seq || 0) + 1 ||
136
+ record.prev_hash !== (previous?.hash || null) ||
137
+ record.hash !== recordHash(record)
138
+ ) {
139
+ throw storeError(
140
+ "CC_ROLLOUT_CORRUPT",
141
+ `rollout hash chain failed at event ${record.event_seq || "unknown"}`,
142
+ );
143
+ }
144
+ previous = record;
145
+ }
146
+ return records;
147
+ }
148
+
149
+ function projectThread(records) {
150
+ if (!records.length) return null;
151
+ const first = records[0];
152
+ const started = first.payload || {};
153
+ let archived = false;
154
+ let title = started.title ?? null;
155
+ let status = "idle";
156
+ for (const event of records) {
157
+ if (event.event_type === "thread.archived") archived = true;
158
+ if (event.event_type === "thread.title_updated") {
159
+ title = event.payload?.title ?? title;
160
+ }
161
+ if (event.event_type === "turn.started") status = "active";
162
+ if (
163
+ event.event_type === "turn.completed" ||
164
+ event.event_type === "turn.failed" ||
165
+ event.event_type === "turn.interrupted"
166
+ ) {
167
+ status = "idle";
168
+ }
169
+ }
170
+ return Object.freeze({
171
+ id: first.thread_id,
172
+ status: archived ? "archived" : status,
173
+ title,
174
+ parentThreadId: started.parentThreadId ?? null,
175
+ createdAt: first.timestamp,
176
+ updatedAt: records.at(-1).timestamp,
177
+ revision: records.at(-1).event_seq,
178
+ headHash: records.at(-1).hash,
179
+ metadata: clone(started.metadata || {}),
180
+ });
181
+ }
182
+
183
+ export function defaultRolloutStoreDirectory() {
184
+ return path.join(getHomeDir(), "app-server", "rollouts");
185
+ }
186
+
187
+ export class JsonlRolloutStore {
188
+ constructor({
189
+ directory = defaultRolloutStoreDirectory(),
190
+ now = Date.now,
191
+ } = {}) {
192
+ this.directory = path.resolve(directory);
193
+ this.now = now;
194
+ }
195
+
196
+ _file(threadId) {
197
+ const safeId = identifier(threadId, "threadId");
198
+ const name = createHash("sha256").update(safeId).digest("hex");
199
+ return path.join(this.directory, `${name}.jsonl`);
200
+ }
201
+
202
+ _ensureDirectory() {
203
+ ensureDir(this.directory);
204
+ }
205
+
206
+ _readUnsafe(threadId, { allowMissing = false } = {}) {
207
+ const file = this._file(threadId);
208
+ let text;
209
+ try {
210
+ text = fs.readFileSync(file, "utf8");
211
+ } catch (error) {
212
+ if (allowMissing && error?.code === "ENOENT") return [];
213
+ if (error?.code === "ENOENT") {
214
+ throw storeError(
215
+ "CC_ROLLOUT_THREAD_NOT_FOUND",
216
+ `thread does not exist: ${threadId}`,
217
+ );
218
+ }
219
+ throw storeError(
220
+ "CC_ROLLOUT_UNAVAILABLE",
221
+ `could not read rollout for ${threadId}`,
222
+ { cause: error },
223
+ );
224
+ }
225
+ const records = text
226
+ .split(/\r?\n/u)
227
+ .filter(Boolean)
228
+ .map((line, index) => {
229
+ try {
230
+ return JSON.parse(line);
231
+ } catch (cause) {
232
+ throw storeError(
233
+ "CC_ROLLOUT_CORRUPT",
234
+ `invalid rollout JSON at line ${index + 1}`,
235
+ { cause },
236
+ );
237
+ }
238
+ });
239
+ return verifyRecords(records, identifier(threadId, "threadId"));
240
+ }
241
+
242
+ start({
243
+ threadId = randomUUID(),
244
+ title = null,
245
+ parentThreadId = null,
246
+ metadata = {},
247
+ } = {}) {
248
+ const safeThreadId = identifier(threadId, "threadId");
249
+ this._ensureDirectory();
250
+ const file = this._file(safeThreadId);
251
+ return withFileLock(
252
+ file,
253
+ () => {
254
+ const existing = this._readUnsafe(safeThreadId, { allowMissing: true });
255
+ if (existing.length) return projectThread(existing);
256
+ const record = buildRecord(
257
+ {
258
+ threadId: safeThreadId,
259
+ eventType: "thread.started",
260
+ idempotencyKey: `thread:${safeThreadId}`,
261
+ payload: {
262
+ title: title == null ? null : String(title).slice(0, 512),
263
+ parentThreadId:
264
+ parentThreadId == null
265
+ ? null
266
+ : identifier(parentThreadId, "parentThreadId"),
267
+ metadata: stableValue(metadata),
268
+ },
269
+ },
270
+ null,
271
+ this.now,
272
+ );
273
+ fs.writeFileSync(file, `${JSON.stringify(record)}\n`, {
274
+ encoding: "utf8",
275
+ flag: "wx",
276
+ mode: 0o600,
277
+ });
278
+ return projectThread([record]);
279
+ },
280
+ { failIfUnavailable: true, timeoutMs: 10_000 },
281
+ );
282
+ }
283
+
284
+ append(input) {
285
+ const safeThreadId = identifier(input?.threadId, "threadId");
286
+ this._ensureDirectory();
287
+ const file = this._file(safeThreadId);
288
+ return withFileLock(
289
+ file,
290
+ () => {
291
+ const records = this._readUnsafe(safeThreadId);
292
+ const key = idempotencyKey(input.idempotencyKey);
293
+ if (key) {
294
+ const duplicate = records.find(
295
+ (record) => record.idempotency_key === key,
296
+ );
297
+ if (duplicate) {
298
+ const candidatePayload = stableValue(input.payload ?? null);
299
+ if (
300
+ duplicate.event_type !== input.eventType ||
301
+ canonicalJson(duplicate.payload) !==
302
+ canonicalJson(candidatePayload)
303
+ ) {
304
+ throw storeError(
305
+ "CC_ROLLOUT_IDEMPOTENCY_CONFLICT",
306
+ `idempotency key was reused with different content: ${key}`,
307
+ );
308
+ }
309
+ return clone(duplicate);
310
+ }
311
+ }
312
+ const record = buildRecord(input, records.at(-1), this.now);
313
+ fs.appendFileSync(file, `${JSON.stringify(record)}\n`, "utf8");
314
+ return clone(record);
315
+ },
316
+ { failIfUnavailable: true, timeoutMs: 10_000 },
317
+ );
318
+ }
319
+
320
+ read(threadId, { afterSeq = 0, limit = 10_000 } = {}) {
321
+ const safeLimit = Math.max(1, Math.min(100_000, Number(limit) || 10_000));
322
+ return clone(
323
+ this._readUnsafe(threadId)
324
+ .filter((record) => record.event_seq > Number(afterSeq || 0))
325
+ .slice(0, safeLimit),
326
+ );
327
+ }
328
+
329
+ resume(threadId) {
330
+ return projectThread(this._readUnsafe(threadId));
331
+ }
332
+
333
+ list({ includeArchived = false, limit = 100 } = {}) {
334
+ this._ensureDirectory();
335
+ const output = [];
336
+ for (const entry of fs.readdirSync(this.directory, {
337
+ withFileTypes: true,
338
+ })) {
339
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
340
+ const file = path.join(this.directory, entry.name);
341
+ let first;
342
+ try {
343
+ first = JSON.parse(
344
+ fs.readFileSync(file, "utf8").split(/\r?\n/u).find(Boolean),
345
+ );
346
+ } catch (cause) {
347
+ throw storeError(
348
+ "CC_ROLLOUT_CORRUPT",
349
+ `could not inspect rollout ${entry.name}`,
350
+ { cause },
351
+ );
352
+ }
353
+ const projection = this.resume(first.thread_id);
354
+ if (includeArchived || projection.status !== "archived")
355
+ output.push(projection);
356
+ }
357
+ return output
358
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))
359
+ .slice(0, Math.max(1, Math.min(10_000, Number(limit) || 100)));
360
+ }
361
+
362
+ forkThread(sourceThreadId, { threadId = randomUUID(), title = null } = {}) {
363
+ const sourceRecords = this._readUnsafe(sourceThreadId);
364
+ const source = projectThread(sourceRecords);
365
+ const target = this.start({
366
+ threadId,
367
+ title: title ?? source.title,
368
+ parentThreadId: source.id,
369
+ metadata: source.metadata,
370
+ });
371
+ this.append({
372
+ threadId: target.id,
373
+ eventType: "thread.forked",
374
+ idempotencyKey: `fork:${source.id}:${source.headHash}`,
375
+ payload: {
376
+ sourceThreadId: source.id,
377
+ sourceEventSeq: source.revision,
378
+ sourceHeadHash: source.headHash,
379
+ },
380
+ });
381
+ return this.resume(target.id);
382
+ }
383
+
384
+ checkpoint(threadId, payload = {}) {
385
+ return this.append({
386
+ threadId,
387
+ eventType: "rollout.checkpoint",
388
+ idempotencyKey: payload.idempotencyKey || null,
389
+ payload: { ...payload, idempotencyKey: undefined },
390
+ });
391
+ }
392
+
393
+ compact(
394
+ threadId,
395
+ { summary, retainedState, idempotencyKey: key = null } = {},
396
+ ) {
397
+ if (typeof summary !== "string" || !summary.trim()) {
398
+ throw storeError(
399
+ "CC_ROLLOUT_INVALID_ARGUMENT",
400
+ "compaction summary is required",
401
+ );
402
+ }
403
+ return this.append({
404
+ threadId,
405
+ eventType: "rollout.compacted",
406
+ idempotencyKey: key,
407
+ payload: { summary, retainedState: stableValue(retainedState ?? {}) },
408
+ });
409
+ }
410
+
411
+ archive(threadId) {
412
+ this.append({
413
+ threadId,
414
+ eventType: "thread.archived",
415
+ idempotencyKey: `archive:${threadId}`,
416
+ payload: {},
417
+ });
418
+ return this.resume(threadId);
419
+ }
420
+
421
+ migrate({
422
+ fromVersion,
423
+ toVersion = ROLLOUT_STORE_VERSION,
424
+ dryRun = true,
425
+ } = {}) {
426
+ if (
427
+ Number(fromVersion) < ROLLOUT_STORE_MIN_VERSION ||
428
+ Number(fromVersion) > ROLLOUT_STORE_VERSION ||
429
+ Number(toVersion) !== ROLLOUT_STORE_VERSION
430
+ ) {
431
+ throw storeError(
432
+ "CC_ROLLOUT_MIGRATION_UNSUPPORTED",
433
+ `rollout migration ${fromVersion} -> ${toVersion} is unsupported`,
434
+ );
435
+ }
436
+ return Object.freeze({
437
+ schema: ROLLOUT_STORE_SCHEMA,
438
+ fromVersion: Number(fromVersion),
439
+ toVersion: Number(toVersion),
440
+ dryRun: dryRun !== false,
441
+ changes: 0,
442
+ backupRequired: false,
443
+ });
444
+ }
445
+ }
446
+
447
+ export class MemoryRolloutStore {
448
+ constructor({ now = Date.now } = {}) {
449
+ this.now = now;
450
+ this.records = new Map();
451
+ }
452
+
453
+ start({
454
+ threadId = randomUUID(),
455
+ title = null,
456
+ parentThreadId = null,
457
+ metadata = {},
458
+ } = {}) {
459
+ const safeThreadId = identifier(threadId, "threadId");
460
+ if (this.records.has(safeThreadId)) return this.resume(safeThreadId);
461
+ const first = buildRecord(
462
+ {
463
+ threadId: safeThreadId,
464
+ eventType: "thread.started",
465
+ idempotencyKey: `thread:${safeThreadId}`,
466
+ payload: { title, parentThreadId, metadata },
467
+ },
468
+ null,
469
+ this.now,
470
+ );
471
+ this.records.set(safeThreadId, [first]);
472
+ return projectThread([first]);
473
+ }
474
+
475
+ append(input) {
476
+ const threadId = identifier(input?.threadId, "threadId");
477
+ const records = this.records.get(threadId);
478
+ if (!records) {
479
+ throw storeError(
480
+ "CC_ROLLOUT_THREAD_NOT_FOUND",
481
+ `thread does not exist: ${threadId}`,
482
+ );
483
+ }
484
+ const key = idempotencyKey(input.idempotencyKey);
485
+ const duplicate = key
486
+ ? records.find((record) => record.idempotency_key === key)
487
+ : null;
488
+ if (duplicate) {
489
+ if (
490
+ duplicate.event_type !== input.eventType ||
491
+ canonicalJson(duplicate.payload) !==
492
+ canonicalJson(input.payload ?? null)
493
+ ) {
494
+ throw storeError(
495
+ "CC_ROLLOUT_IDEMPOTENCY_CONFLICT",
496
+ `idempotency key was reused with different content: ${key}`,
497
+ );
498
+ }
499
+ return clone(duplicate);
500
+ }
501
+ const record = buildRecord(input, records.at(-1), this.now);
502
+ records.push(record);
503
+ return clone(record);
504
+ }
505
+
506
+ read(threadId, { afterSeq = 0, limit = 10_000 } = {}) {
507
+ const records = this.records.get(identifier(threadId, "threadId"));
508
+ if (!records) {
509
+ throw storeError(
510
+ "CC_ROLLOUT_THREAD_NOT_FOUND",
511
+ `thread does not exist: ${threadId}`,
512
+ );
513
+ }
514
+ return clone(
515
+ records
516
+ .filter((record) => record.event_seq > Number(afterSeq || 0))
517
+ .slice(0, limit),
518
+ );
519
+ }
520
+
521
+ resume(threadId) {
522
+ return projectThread(this.read(threadId));
523
+ }
524
+
525
+ list({ includeArchived = false, limit = 100 } = {}) {
526
+ return [...this.records.keys()]
527
+ .map((threadId) => this.resume(threadId))
528
+ .filter((thread) => includeArchived || thread.status !== "archived")
529
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))
530
+ .slice(0, limit);
531
+ }
532
+
533
+ forkThread(sourceThreadId, { threadId = randomUUID(), title = null } = {}) {
534
+ const source = this.resume(sourceThreadId);
535
+ const target = this.start({
536
+ threadId,
537
+ title: title ?? source.title,
538
+ parentThreadId: source.id,
539
+ metadata: source.metadata,
540
+ });
541
+ this.append({
542
+ threadId: target.id,
543
+ eventType: "thread.forked",
544
+ idempotencyKey: `fork:${source.id}:${source.headHash}`,
545
+ payload: {
546
+ sourceThreadId: source.id,
547
+ sourceEventSeq: source.revision,
548
+ sourceHeadHash: source.headHash,
549
+ },
550
+ });
551
+ return this.resume(target.id);
552
+ }
553
+
554
+ checkpoint(threadId, payload = {}) {
555
+ return this.append({
556
+ threadId,
557
+ eventType: "rollout.checkpoint",
558
+ idempotencyKey: payload.idempotencyKey || null,
559
+ payload: { ...payload, idempotencyKey: undefined },
560
+ });
561
+ }
562
+
563
+ compact(threadId, options = {}) {
564
+ return this.append({
565
+ threadId,
566
+ eventType: "rollout.compacted",
567
+ idempotencyKey: options.idempotencyKey || null,
568
+ payload: {
569
+ summary: String(options.summary || ""),
570
+ retainedState: options.retainedState || {},
571
+ },
572
+ });
573
+ }
574
+
575
+ archive(threadId) {
576
+ this.append({
577
+ threadId,
578
+ eventType: "thread.archived",
579
+ idempotencyKey: `archive:${threadId}`,
580
+ payload: {},
581
+ });
582
+ return this.resume(threadId);
583
+ }
584
+
585
+ migrate(options = {}) {
586
+ return Object.freeze({
587
+ schema: ROLLOUT_STORE_SCHEMA,
588
+ fromVersion: Number(options.fromVersion || 1),
589
+ toVersion: Number(options.toVersion || 1),
590
+ dryRun: options.dryRun !== false,
591
+ changes: 0,
592
+ backupRequired: false,
593
+ });
594
+ }
595
+ }
596
+
597
+ export const _rolloutStoreInternals = Object.freeze({
598
+ buildRecord,
599
+ canonicalJson,
600
+ digest,
601
+ projectThread,
602
+ verifyRecords,
603
+ });