chainlesschain 0.162.188 → 0.162.193

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 (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -24,7 +24,6 @@ import {
24
24
  createTrustedMcpServerMap,
25
25
  resolveMcpServerPolicy,
26
26
  normalizeRiskLevel,
27
- normalizeBoolean,
28
27
  selectHigherRiskLevel,
29
28
  } from "../../runtime/coding-agent-managed-tool-policy.cjs";
30
29
  import {
@@ -49,6 +48,19 @@ import {
49
48
  registerHostHooksV2Workspace,
50
49
  releaseRegisteredHostHooksV2Workspace,
51
50
  } from "../../lib/hooks-v2-workspace-context.js";
51
+ import { mcpEffectDescriptorFields } from "../../lib/mcp-effect-contract.js";
52
+ import {
53
+ sanitizePersistedMessages,
54
+ sanitizePersistedNonSystemMessages,
55
+ } from "../../lib/session-message-provenance.js";
56
+ import {
57
+ appendWsSessionStateEvent,
58
+ createWsSessionState,
59
+ getWsSessionStateSnapshot,
60
+ hydrateWsSessionState,
61
+ recoverWsSessionState,
62
+ serializeWsSessionState,
63
+ } from "./ws-session-state.js";
52
64
 
53
65
  function normalizeHostWorkspaceRoot(workspaceRoot) {
54
66
  if (
@@ -65,6 +77,23 @@ function normalizeHostWorkspaceRoot(workspaceRoot) {
65
77
  }
66
78
  }
67
79
 
80
+ function normalizeCanonicalHostSystemPrefix(messages) {
81
+ const clean = sanitizePersistedMessages(messages, { strict: true });
82
+ if (clean.some((message) => message.role !== "system")) {
83
+ throw new TypeError("Canonical WS host prefix must contain only systems");
84
+ }
85
+ return Object.freeze(clean.map((message) => Object.freeze(message)));
86
+ }
87
+
88
+ function bindCanonicalHostSystemPrefix(session, messages) {
89
+ const prefix = normalizeCanonicalHostSystemPrefix(messages);
90
+ Object.defineProperty(session, "_canonicalHostSystemPrefix", {
91
+ configurable: true,
92
+ value: prefix,
93
+ });
94
+ return prefix;
95
+ }
96
+
68
97
  function bindSessionHooksV2Workspace(
69
98
  session,
70
99
  workspaceRoot,
@@ -263,14 +292,15 @@ export class WSSessionManager {
263
292
  type: "object",
264
293
  properties: {},
265
294
  };
295
+ const effectFields = mcpEffectDescriptorFields(mcpTool, {
296
+ sourceTrusted: serverPolicy.trusted === true,
297
+ provenance: `desktop-mcp-registry:${serverName}`,
298
+ });
266
299
  const riskLevel = selectHigherRiskLevel(
267
300
  serverPolicy.securityLevel,
268
301
  normalizeRiskLevel(mcpTool?.risk_level, null),
302
+ effectFields.riskLevel,
269
303
  );
270
- const isReadOnly =
271
- normalizeBoolean(mcpTool?.isReadOnly, false) ||
272
- normalizeBoolean(mcpTool?.is_read_only, false) ||
273
- riskLevel === "low";
274
304
 
275
305
  let toolName = `mcp_${serverName}_${mcpTool?.name || "tool"}`;
276
306
  if (seenNames.has(toolName)) {
@@ -288,7 +318,7 @@ export class WSSessionManager {
288
318
  name: toolName,
289
319
  description: mcpTool?.description || `MCP tool from ${serverName}.`,
290
320
  inputSchema: parsedSchema,
291
- isReadOnly,
321
+ ...effectFields,
292
322
  riskLevel,
293
323
  source: `mcp:${serverName}`,
294
324
  mcpMetadata: {
@@ -495,6 +525,8 @@ export class WSSessionManager {
495
525
  createdAt: new Date().toISOString(),
496
526
  lastActivity: new Date().toISOString(),
497
527
  };
528
+ bindCanonicalHostSystemPrefix(session, messages);
529
+ this._bindSessionStateJournal(session, createWsSessionState());
498
530
  bindSessionHooksV2Workspace(
499
531
  session,
500
532
  hostAuthorizedBaseRoot
@@ -561,6 +593,20 @@ export class WSSessionManager {
561
593
  metadata,
562
594
  );
563
595
  const planManager = this._hydratePlanManager(metadata.planSnapshot);
596
+ const sessionStateJournal = hydrateWsSessionState(
597
+ metadata.sessionState,
598
+ Object.prototype.hasOwnProperty.call(metadata, "planSnapshot")
599
+ ? {
600
+ // Legacy/current metadata migration is pass-through only.
601
+ // PlanModeManager remains the sole owner of Plan hydration and
602
+ // persistence.
603
+ planSnapshot: metadata.planSnapshot,
604
+ }
605
+ : {},
606
+ );
607
+ const stateRecovery = recoverWsSessionState(sessionStateJournal, {
608
+ reason: "process_restart",
609
+ });
564
610
  const externalTools = this._buildSessionExternalTools();
565
611
  let contextEngine = null;
566
612
  let permanentMemory = null;
@@ -618,6 +664,13 @@ export class WSSessionManager {
618
664
  createdAt: dbSession.created_at,
619
665
  lastActivity: new Date().toISOString(),
620
666
  };
667
+ if (Array.isArray(metadata.canonicalHostSystemPrefix)) {
668
+ bindCanonicalHostSystemPrefix(
669
+ session,
670
+ metadata.canonicalHostSystemPrefix,
671
+ );
672
+ }
673
+ this._bindSessionStateJournal(session, sessionStateJournal);
621
674
  const recoveredHooksWorkspaceRoot =
622
675
  metadata.worktreeIsolation !== true &&
623
676
  normalizeHostWorkspaceRoot(baseProjectRoot) ===
@@ -630,6 +683,9 @@ export class WSSessionManager {
630
683
 
631
684
  this._bindPlanManagerPersistence(session);
632
685
  this.sessions.set(session.id, session);
686
+ if (stateRecovery.changed) {
687
+ this._persistSessionState(session.id);
688
+ }
633
689
  return session;
634
690
  } catch (_err) {
635
691
  return null;
@@ -1413,21 +1469,7 @@ export class WSSessionManager {
1413
1469
  * Persist current messages for a session.
1414
1470
  */
1415
1471
  persistMessages(sessionId) {
1416
- const session = this.sessions.get(sessionId);
1417
- if (!session || !this.db) return;
1418
-
1419
- try {
1420
- dbSaveMessages(
1421
- this.db,
1422
- sessionId,
1423
- session.messages,
1424
- this._serializeSessionMetadata(session),
1425
- );
1426
- } catch (_err) {
1427
- // Non-critical
1428
- }
1429
-
1430
- session.lastActivity = new Date().toISOString();
1472
+ this._persistSessionState(sessionId);
1431
1473
  }
1432
1474
 
1433
1475
  _prepareSessionWorkspace(projectRoot, sessionId, options = {}) {
@@ -1462,10 +1504,24 @@ export class WSSessionManager {
1462
1504
  if (!session || !this.db) return;
1463
1505
 
1464
1506
  try {
1507
+ let persistedMessages = session.messages;
1508
+ if (
1509
+ session.canonicalJsonlSession === true &&
1510
+ Array.isArray(session._canonicalHostSystemPrefix)
1511
+ ) {
1512
+ const hostPrefix = normalizeCanonicalHostSystemPrefix(
1513
+ session._canonicalHostSystemPrefix,
1514
+ );
1515
+ const conversation = sanitizePersistedNonSystemMessages(
1516
+ session.messages,
1517
+ { strict: true },
1518
+ );
1519
+ persistedMessages = [...hostPrefix, ...conversation];
1520
+ }
1465
1521
  dbSaveMessages(
1466
1522
  this.db,
1467
1523
  sessionId,
1468
- session.messages,
1524
+ persistedMessages,
1469
1525
  this._serializeSessionMetadata(session),
1470
1526
  );
1471
1527
  } catch (_err) {
@@ -1476,6 +1532,7 @@ export class WSSessionManager {
1476
1532
  }
1477
1533
 
1478
1534
  _serializeSessionMetadata(session) {
1535
+ const sessionStateJournal = this._ensureSessionStateJournal(session);
1479
1536
  return {
1480
1537
  version: 1,
1481
1538
  sessionType: session.type || "agent",
@@ -1489,6 +1546,11 @@ export class WSSessionManager {
1489
1546
  baseUrl: session.baseUrl || null,
1490
1547
  hostManagedToolPolicy: session.hostManagedToolPolicy || null,
1491
1548
  enabledToolNames: session.enabledToolNames || [],
1549
+ canonicalHostSystemPrefix: Array.isArray(
1550
+ session._canonicalHostSystemPrefix,
1551
+ )
1552
+ ? normalizeCanonicalHostSystemPrefix(session._canonicalHostSystemPrefix)
1553
+ : null,
1492
1554
  worktreeIsolation: session.worktreeIsolation === true,
1493
1555
  worktree: session.worktree || null,
1494
1556
  planSnapshot: this._serializePlanManager(session.planManager),
@@ -1501,9 +1563,54 @@ export class WSSessionManager {
1501
1563
  ? session.patchHistory
1502
1564
  : [],
1503
1565
  taskGraph: this._serializeTaskGraph(session.taskGraph),
1566
+ // Additive metadata field: old readers ignore it; new readers replay the
1567
+ // contiguous event tail over the checkpoint before resuming a session.
1568
+ sessionState: serializeWsSessionState(sessionStateJournal),
1504
1569
  };
1505
1570
  }
1506
1571
 
1572
+ _bindSessionStateJournal(session, journal) {
1573
+ if (!session || typeof session !== "object") return;
1574
+ Object.defineProperty(session, "_sessionStateJournal", {
1575
+ value: journal || createWsSessionState(),
1576
+ enumerable: false,
1577
+ writable: true,
1578
+ configurable: true,
1579
+ });
1580
+ Object.defineProperty(session, "_recordSessionStateEvent", {
1581
+ value: (type, payload = {}) =>
1582
+ this.recordSessionStateEvent(session.id, type, payload),
1583
+ enumerable: false,
1584
+ writable: false,
1585
+ configurable: true,
1586
+ });
1587
+ }
1588
+
1589
+ _ensureSessionStateJournal(session) {
1590
+ if (!session?._sessionStateJournal) {
1591
+ this._bindSessionStateJournal(session, createWsSessionState());
1592
+ }
1593
+ return session._sessionStateJournal;
1594
+ }
1595
+
1596
+ /** Record a recovery event and atomically persist it with session messages. */
1597
+ recordSessionStateEvent(sessionId, type, payload = {}) {
1598
+ const session = this.sessions.get(sessionId);
1599
+ if (!session) return null;
1600
+ const journal = this._ensureSessionStateJournal(session);
1601
+ appendWsSessionStateEvent(journal, type, payload);
1602
+ this._persistSessionState(sessionId);
1603
+ return getWsSessionStateSnapshot(journal);
1604
+ }
1605
+
1606
+ /** Detached snapshot suitable for an additive IDE resume payload. */
1607
+ getSessionStateSnapshot(sessionId) {
1608
+ const session = this.sessions.get(sessionId);
1609
+ if (!session) return null;
1610
+ const journal = this._ensureSessionStateJournal(session);
1611
+ return getWsSessionStateSnapshot(journal);
1612
+ }
1613
+
1507
1614
  _hydratePendingPatches(list) {
1508
1615
  const map = new Map();
1509
1616
  if (Array.isArray(list)) {
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Crash-safe, backward-compatible state journal for IDE/WebSocket sessions.
3
+ *
4
+ * The journal is stored inside the existing session metadata row, so messages
5
+ * and recovery state are committed by the same database UPDATE. A compact
6
+ * checkpoint plus a bounded, revision-ordered event tail makes hydration
7
+ * deterministic without changing any existing WebSocket frame.
8
+ *
9
+ * Plan data is deliberately opaque here. This module only preserves an
10
+ * optional `planSnapshot` field for callers that own Plan persistence.
11
+ */
12
+
13
+ export const WS_SESSION_STATE_SCHEMA = "chainlesschain.ws-session-state";
14
+ export const WS_SESSION_STATE_VERSION = 1;
15
+ export const DEFAULT_WS_SESSION_STATE_MAX_EVENTS = 64;
16
+
17
+ const RUN_STATUSES = new Set(["idle", "running", "interrupted"]);
18
+ const APPROVAL_STATUSES = new Set(["pending", "interrupted"]);
19
+
20
+ function own(object, key) {
21
+ return Object.prototype.hasOwnProperty.call(object || {}, key);
22
+ }
23
+
24
+ function cloneJson(value, fallback = null) {
25
+ if (value === undefined) return fallback;
26
+ try {
27
+ return JSON.parse(JSON.stringify(value));
28
+ } catch {
29
+ return fallback;
30
+ }
31
+ }
32
+
33
+ function nonNegativeRevision(value, fallback = 0) {
34
+ return Number.isSafeInteger(value) && value >= 0 ? value : fallback;
35
+ }
36
+
37
+ function timestamp(value, fallback = null) {
38
+ return typeof value === "string" && value.length > 0 ? value : fallback;
39
+ }
40
+
41
+ function normalizeTodoSnapshot(value) {
42
+ if (!value || typeof value !== "object") return null;
43
+ const revision = nonNegativeRevision(value.revision, -1);
44
+ if (revision < 0) return null;
45
+
46
+ return {
47
+ ...(typeof value.schema === "string" ? { schema: value.schema } : {}),
48
+ ...(Number.isSafeInteger(value.version) && value.version >= 0
49
+ ? { version: value.version }
50
+ : {}),
51
+ ...(typeof value.sessionId === "string" || value.sessionId === null
52
+ ? { sessionId: value.sessionId }
53
+ : {}),
54
+ revision,
55
+ todos: Array.isArray(value.todos) ? cloneJson(value.todos, []) : [],
56
+ };
57
+ }
58
+
59
+ function normalizePendingApproval(value) {
60
+ if (!value || typeof value !== "object") return null;
61
+ const requestId =
62
+ typeof value.requestId === "string" && value.requestId.length > 0
63
+ ? value.requestId
64
+ : null;
65
+ if (!requestId) return null;
66
+
67
+ const status = APPROVAL_STATUSES.has(value.status) ? value.status : "pending";
68
+ return {
69
+ requestId,
70
+ status,
71
+ binding:
72
+ typeof value.binding === "string" && value.binding.length > 0
73
+ ? value.binding
74
+ : null,
75
+ tool:
76
+ typeof value.tool === "string" && value.tool.length > 0
77
+ ? value.tool
78
+ : null,
79
+ risk:
80
+ typeof value.risk === "string" && value.risk.length > 0
81
+ ? value.risk
82
+ : null,
83
+ rule:
84
+ typeof value.rule === "string" && value.rule.length > 0
85
+ ? value.rule
86
+ : null,
87
+ requestedAt: timestamp(value.requestedAt),
88
+ interruptedAt: timestamp(value.interruptedAt),
89
+ reason:
90
+ typeof value.reason === "string" && value.reason.length > 0
91
+ ? value.reason
92
+ : null,
93
+ };
94
+ }
95
+
96
+ function normalizeRun(value) {
97
+ const source = value && typeof value === "object" ? value : {};
98
+ const status = RUN_STATUSES.has(source.status) ? source.status : "idle";
99
+ return {
100
+ status,
101
+ requestId:
102
+ typeof source.requestId === "string" && source.requestId.length > 0
103
+ ? source.requestId
104
+ : null,
105
+ startedAt: timestamp(source.startedAt),
106
+ settledAt: timestamp(source.settledAt),
107
+ interruptedAt: timestamp(source.interruptedAt),
108
+ reason:
109
+ typeof source.reason === "string" && source.reason.length > 0
110
+ ? source.reason
111
+ : null,
112
+ };
113
+ }
114
+
115
+ function normalizeSnapshot(value = {}, options = {}) {
116
+ const source = value && typeof value === "object" ? value : {};
117
+ const snapshot = {
118
+ revision: nonNegativeRevision(source.revision),
119
+ todo: normalizeTodoSnapshot(source.todo),
120
+ pendingApproval: normalizePendingApproval(source.pendingApproval),
121
+ run: normalizeRun(source.run),
122
+ };
123
+
124
+ if (own(source, "planSnapshot")) {
125
+ snapshot.planSnapshot = cloneJson(source.planSnapshot);
126
+ } else if (own(options, "planSnapshot")) {
127
+ // Migration seam for metadata written before the journal existed. The
128
+ // value remains opaque; Plan persistence/hydration belongs elsewhere.
129
+ snapshot.planSnapshot = cloneJson(options.planSnapshot);
130
+ }
131
+
132
+ return snapshot;
133
+ }
134
+
135
+ function matchingRequest(currentRequestId, eventRequestId) {
136
+ return (
137
+ !eventRequestId || !currentRequestId || currentRequestId === eventRequestId
138
+ );
139
+ }
140
+
141
+ function applyEvent(snapshot, event) {
142
+ const next = normalizeSnapshot(snapshot);
143
+ const payload =
144
+ event.payload && typeof event.payload === "object" ? event.payload : {};
145
+
146
+ switch (event.type) {
147
+ case "todo.snapshot": {
148
+ const todo = normalizeTodoSnapshot(payload.todo || payload);
149
+ if (!next.todo || (todo && todo.revision >= next.todo.revision)) {
150
+ next.todo = todo;
151
+ }
152
+ break;
153
+ }
154
+
155
+ case "approval.requested":
156
+ next.pendingApproval = normalizePendingApproval({
157
+ ...payload,
158
+ status: "pending",
159
+ requestedAt: payload.requestedAt || event.at,
160
+ });
161
+ break;
162
+
163
+ case "approval.settled":
164
+ if (
165
+ next.pendingApproval &&
166
+ matchingRequest(next.pendingApproval.requestId, payload.requestId)
167
+ ) {
168
+ next.pendingApproval = null;
169
+ }
170
+ break;
171
+
172
+ case "approval.interrupted":
173
+ if (
174
+ next.pendingApproval &&
175
+ matchingRequest(next.pendingApproval.requestId, payload.requestId)
176
+ ) {
177
+ next.pendingApproval = normalizePendingApproval({
178
+ ...next.pendingApproval,
179
+ status: "interrupted",
180
+ interruptedAt: payload.interruptedAt || event.at,
181
+ reason: payload.reason || "session_recovered",
182
+ });
183
+ }
184
+ break;
185
+
186
+ case "run.started":
187
+ next.run = normalizeRun({
188
+ status: "running",
189
+ requestId: payload.requestId || null,
190
+ startedAt: payload.startedAt || event.at,
191
+ });
192
+ break;
193
+
194
+ case "run.settled":
195
+ // A late completion from an explicitly interrupted turn must not erase
196
+ // the interruption marker. The next run.started event supersedes it.
197
+ if (
198
+ next.run.status === "running" &&
199
+ matchingRequest(next.run.requestId, payload.requestId)
200
+ ) {
201
+ next.run = normalizeRun({
202
+ status: "idle",
203
+ settledAt: payload.settledAt || event.at,
204
+ });
205
+ }
206
+ break;
207
+
208
+ case "run.interrupted":
209
+ if (matchingRequest(next.run.requestId, payload.requestId)) {
210
+ next.run = normalizeRun({
211
+ ...next.run,
212
+ status: "interrupted",
213
+ requestId: payload.requestId || next.run.requestId,
214
+ interruptedAt: payload.interruptedAt || event.at,
215
+ reason: payload.reason || "interrupted",
216
+ });
217
+ }
218
+ break;
219
+
220
+ case "plan.snapshot":
221
+ if (own(payload, "planSnapshot")) {
222
+ next.planSnapshot = cloneJson(payload.planSnapshot);
223
+ }
224
+ break;
225
+
226
+ default:
227
+ // Unknown additive events consume their revision but cannot widen state.
228
+ break;
229
+ }
230
+
231
+ next.revision = event.revision;
232
+ return next;
233
+ }
234
+
235
+ function normalizeEvent(value, expectedRevision) {
236
+ if (!value || typeof value !== "object") return null;
237
+ if (value.revision !== expectedRevision) return null;
238
+ if (typeof value.type !== "string" || value.type.length === 0) return null;
239
+ return {
240
+ revision: expectedRevision,
241
+ type: value.type,
242
+ at: timestamp(value.at),
243
+ payload: cloneJson(value.payload, {}),
244
+ };
245
+ }
246
+
247
+ /** Hydrate a journal and replay only its contiguous event prefix. */
248
+ export function hydrateWsSessionState(value, options = {}) {
249
+ const candidate = value && typeof value === "object" ? value : {};
250
+ const schemaSupported =
251
+ (!own(candidate, "schema") ||
252
+ candidate.schema === WS_SESSION_STATE_SCHEMA) &&
253
+ (!own(candidate, "version") ||
254
+ candidate.version === WS_SESSION_STATE_VERSION);
255
+ const source = schemaSupported ? candidate : {};
256
+ const maxEvents =
257
+ Number.isSafeInteger(options.maxEvents) && options.maxEvents > 0
258
+ ? options.maxEvents
259
+ : DEFAULT_WS_SESSION_STATE_MAX_EVENTS;
260
+ const checkpointSource =
261
+ source.snapshot && typeof source.snapshot === "object"
262
+ ? source.snapshot
263
+ : source.checkpoint && typeof source.checkpoint === "object"
264
+ ? source.checkpoint
265
+ : {};
266
+ const checkpoint = normalizeSnapshot(checkpointSource, options);
267
+ let current = normalizeSnapshot(checkpoint);
268
+ const events = [];
269
+ const persistedEvents = Array.isArray(source.events)
270
+ ? source.events.slice(0, maxEvents)
271
+ : [];
272
+
273
+ for (const rawEvent of persistedEvents) {
274
+ const event = normalizeEvent(rawEvent, current.revision + 1);
275
+ // A revision gap/corrupt event terminates replay. Applying a later event
276
+ // could skip an interrupt/deny transition and accidentally widen state.
277
+ if (!event) break;
278
+ current = applyEvent(current, event);
279
+ events.push(event);
280
+ }
281
+
282
+ const journal = {
283
+ schema: WS_SESSION_STATE_SCHEMA,
284
+ version: WS_SESSION_STATE_VERSION,
285
+ snapshot: checkpoint,
286
+ events,
287
+ current,
288
+ maxEvents,
289
+ };
290
+
291
+ compactJournal(journal);
292
+ return journal;
293
+ }
294
+
295
+ export function createWsSessionState(options = {}) {
296
+ const hasPlanSnapshot = own(options, "planSnapshot");
297
+ return hydrateWsSessionState(
298
+ {
299
+ schema: WS_SESSION_STATE_SCHEMA,
300
+ version: WS_SESSION_STATE_VERSION,
301
+ snapshot: {
302
+ revision: 0,
303
+ todo: normalizeTodoSnapshot(options.todo),
304
+ pendingApproval: null,
305
+ run: normalizeRun(),
306
+ ...(hasPlanSnapshot
307
+ ? { planSnapshot: cloneJson(options.planSnapshot) }
308
+ : {}),
309
+ },
310
+ events: [],
311
+ },
312
+ options,
313
+ );
314
+ }
315
+
316
+ function compactJournal(journal) {
317
+ while (journal.events.length > journal.maxEvents) {
318
+ const event = journal.events.shift();
319
+ journal.snapshot = applyEvent(journal.snapshot, event);
320
+ }
321
+ }
322
+
323
+ /** Append and apply one monotonic state event. Mutates the in-memory journal. */
324
+ export function appendWsSessionStateEvent(
325
+ journal,
326
+ type,
327
+ payload = {},
328
+ options = {},
329
+ ) {
330
+ if (!journal || typeof journal !== "object") return null;
331
+ const event = {
332
+ revision: journal.current.revision + 1,
333
+ type: String(type || "unknown"),
334
+ at: timestamp(options.at, new Date().toISOString()),
335
+ payload: cloneJson(payload, {}),
336
+ };
337
+ journal.current = applyEvent(journal.current, event);
338
+ journal.events.push(event);
339
+ compactJournal(journal);
340
+ return cloneJson(event);
341
+ }
342
+
343
+ /** Update the journal from the separately persisted TODO snapshot. */
344
+ export function syncWsSessionTodo(journal, todoSnapshot, options = {}) {
345
+ const todo = normalizeTodoSnapshot(todoSnapshot);
346
+ if (!journal || !todo) return false;
347
+ const current = journal.current?.todo || null;
348
+ if (current && current.revision >= todo.revision) return false;
349
+ appendWsSessionStateEvent(journal, "todo.snapshot", { todo }, options);
350
+ return true;
351
+ }
352
+
353
+ /**
354
+ * Convert state that depended on the dead process into an explicit,
355
+ * fail-closed interruption marker. Pending approvals are retained for UI
356
+ * explanation but can no longer be resolved by a stale session-answer.
357
+ */
358
+ export function recoverWsSessionState(journal, options = {}) {
359
+ if (!journal || typeof journal !== "object") {
360
+ return {
361
+ changed: false,
362
+ runInterrupted: false,
363
+ approvalInterrupted: false,
364
+ };
365
+ }
366
+ const at = timestamp(options.at, new Date().toISOString());
367
+ const reason = options.reason || "process_restart";
368
+ let runInterrupted = false;
369
+ let approvalInterrupted = false;
370
+
371
+ if (journal.current.run?.status === "running") {
372
+ appendWsSessionStateEvent(
373
+ journal,
374
+ "run.interrupted",
375
+ {
376
+ requestId: journal.current.run.requestId,
377
+ interruptedAt: at,
378
+ reason,
379
+ },
380
+ { at },
381
+ );
382
+ runInterrupted = true;
383
+ }
384
+
385
+ if (journal.current.pendingApproval?.status === "pending") {
386
+ appendWsSessionStateEvent(
387
+ journal,
388
+ "approval.interrupted",
389
+ {
390
+ requestId: journal.current.pendingApproval.requestId,
391
+ interruptedAt: at,
392
+ reason,
393
+ },
394
+ { at },
395
+ );
396
+ approvalInterrupted = true;
397
+ }
398
+
399
+ return {
400
+ changed: runInterrupted || approvalInterrupted,
401
+ runInterrupted,
402
+ approvalInterrupted,
403
+ };
404
+ }
405
+
406
+ /** Current replayed state for IDE consumers (detached JSON-safe copy). */
407
+ export function getWsSessionStateSnapshot(journal) {
408
+ if (!journal || typeof journal !== "object") {
409
+ return {
410
+ schema: WS_SESSION_STATE_SCHEMA,
411
+ version: WS_SESSION_STATE_VERSION,
412
+ ...normalizeSnapshot(),
413
+ };
414
+ }
415
+ return {
416
+ schema: WS_SESSION_STATE_SCHEMA,
417
+ version: WS_SESSION_STATE_VERSION,
418
+ ...cloneJson(journal.current, normalizeSnapshot()),
419
+ };
420
+ }
421
+
422
+ /** Persistable journal shape; internal `current` and limits stay in memory. */
423
+ export function serializeWsSessionState(journal) {
424
+ const safe = journal || createWsSessionState();
425
+ return {
426
+ schema: WS_SESSION_STATE_SCHEMA,
427
+ version: WS_SESSION_STATE_VERSION,
428
+ snapshot: cloneJson(safe.snapshot, normalizeSnapshot()),
429
+ events: cloneJson(safe.events, []),
430
+ };
431
+ }