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
@@ -15,6 +15,7 @@ import {
15
15
  listSessions,
16
16
  getSession,
17
17
  deleteSession,
18
+ updateSession,
18
19
  exportSessionMarkdown,
19
20
  CONVERSATION_MATURITY_V2,
20
21
  TURN_LIFECYCLE_V2,
@@ -49,7 +50,9 @@ import {
49
50
  import {
50
51
  listJsonlSessions,
51
52
  rebuildMessages,
52
- sessionExists,
53
+ getJsonlSessionMetadata,
54
+ resolveSessionId,
55
+ deleteJsonlSession,
53
56
  readEvents,
54
57
  migrateLegacySessions,
55
58
  migrateLegacySessionsBatch,
@@ -62,11 +65,15 @@ import {
62
65
  readWorkflowSession,
63
66
  } from "../lib/workflow-state-reader.js";
64
67
  import { executionBroker } from "../lib/process-execution-broker/index.js";
68
+ import { registerSessionMcpRecoveryCommands } from "./session-mcp-recovery.js";
65
69
 
66
70
  export const _deps = {
67
71
  execFileSync: (...args) => executionBroker.execFileSync(...args),
68
72
  };
69
73
 
74
+ export const PR_STATUS_SCHEMA = "chainlesschain.session-pr-status";
75
+ export const PR_STATUS_VERSION = 1;
76
+
70
77
  // DB sessions store `updated_at` as SQLite datetime('now') → "YYYY-MM-DD
71
78
  // HH:MM:SS" (UTC, space at index 10); JSONL sessions store toISOString() →
72
79
  // "YYYY-MM-DDTHH:MM:SS.sssZ" (UTC, 'T' at index 10). Both are UTC, so normalize
@@ -90,21 +97,25 @@ function _sessionEpoch(ts) {
90
97
  *
91
98
  * @param {object} signals {branch, prNumber, hasOpenPr, headCommitSha,
92
99
  * branchProtectionSatisfied, reviewApproved, pendingApprovals,
93
- * requiredChecks, checks}
100
+ * requiredChecks, requiredMatrixComplete, checks, ciCommitSha, sideEffects}
94
101
  * @param {{enabled?:boolean}} [opts]
95
102
  * @returns {{statusBar:string, autoMerge:{allow:boolean,reason:string,unmet:string[]}, lines:string[]}}
96
103
  */
97
104
  export async function renderPrStatus(signals = {}, opts = {}) {
98
- const { autoMergeDecision, describePrStatusBar } =
105
+ const { strictAutoMergeDecision, describePrStatusBar } =
99
106
  await import("../lib/pr-automation-policy.js");
100
- const autoMerge = autoMergeDecision({
107
+ const autoMerge = strictAutoMergeDecision({
101
108
  enabled: opts.enabled === true,
102
109
  hasOpenPr: signals.hasOpenPr,
103
110
  branchProtectionSatisfied: signals.branchProtectionSatisfied,
104
111
  reviewApproved: signals.reviewApproved,
105
112
  pendingApprovals: signals.pendingApprovals,
106
113
  requiredChecks: signals.requiredChecks,
114
+ requiredMatrixComplete: signals.requiredMatrixComplete,
107
115
  checks: signals.checks,
116
+ headCommitSha: signals.headCommitSha,
117
+ ciCommitSha: signals.ciCommitSha,
118
+ sideEffects: signals.sideEffects,
108
119
  });
109
120
  const statusBar = describePrStatusBar({
110
121
  branch: signals.branch,
@@ -119,7 +130,15 @@ export async function renderPrStatus(signals = {}, opts = {}) {
119
130
  } else {
120
131
  lines.push(`auto-merge: ✗ blocked (${autoMerge.unmet.join(", ")})`);
121
132
  }
122
- return { statusBar, autoMerge, lines };
133
+ return {
134
+ schema: PR_STATUS_SCHEMA,
135
+ version: PR_STATUS_VERSION,
136
+ headCommitSha: signals.headCommitSha || null,
137
+ ciCommitSha: signals.ciCommitSha || null,
138
+ statusBar,
139
+ autoMerge,
140
+ lines,
141
+ };
123
142
  }
124
143
 
125
144
  /**
@@ -132,11 +151,16 @@ export function mapGhPrToSignals(gh = {}) {
132
151
  const rollup = Array.isArray(gh.statusCheckRollup)
133
152
  ? gh.statusCheckRollup
134
153
  : [];
154
+ const headCommitSha = gh.headRefOid || undefined;
135
155
  return {
136
156
  branch: gh.headRefName || undefined,
137
157
  prNumber: gh.number,
138
158
  hasOpenPr: String(gh.state || "").toUpperCase() === "OPEN",
139
- headCommitSha: gh.headRefOid || undefined,
159
+ headCommitSha,
160
+ // This rollup belongs to the queried headRefOid. The authoritative
161
+ // required-matrix definition is not exposed here, so live auto-merge still
162
+ // fails closed unless another trusted source supplies it.
163
+ ciCommitSha: headCommitSha,
140
164
  reviewApproved: gh.reviewDecision === "APPROVED",
141
165
  // gh doesn't expose branch-protection satisfaction or pending in-app
142
166
  // approvals here; leave them undefined → fail-closed unless a --checks-file
@@ -145,6 +169,7 @@ export function mapGhPrToSignals(gh = {}) {
145
169
  name: c.name || c.context,
146
170
  // check runs use `conclusion`; legacy statuses use `state`.
147
171
  state: c.conclusion || c.state || c.status,
172
+ commitSha: headCommitSha,
148
173
  })),
149
174
  };
150
175
  }
@@ -196,6 +221,8 @@ export function registerSessionCommand(program) {
196
221
  .command("session")
197
222
  .description("Conversation session management");
198
223
 
224
+ registerSessionMcpRecoveryCommands(session);
225
+
199
226
  // session list
200
227
  session
201
228
  .command("list", { isDefault: true })
@@ -258,6 +285,213 @@ export function registerSessionCommand(program) {
258
285
  }
259
286
  });
260
287
 
288
+ // Canonical IDE/control-plane projection. This is the only Sessions
289
+ // Workbench read contract: IDEs must not merge supervisor/index files on
290
+ // their own because that recreates lifecycle and capability drift.
291
+ session
292
+ .command("projection")
293
+ .description("Emit the canonical versioned session projection for IDEs")
294
+ .option("-n, --limit <n>", "Max local sessions", "100")
295
+ .option("--cwd <path>", "Project root for workflow sessions")
296
+ .option("--json", "Output as JSON")
297
+ .action(async (options) => {
298
+ let ctx = null;
299
+ const stdout = console.log;
300
+ const stdoutWrite = process.stdout.write;
301
+ let jsonPayload = null;
302
+ // Some legacy core packages log initialization directly to stdout. Hold
303
+ // stdout until shutdown so --json remains one parseable document.
304
+ if (options.json) {
305
+ console.log = () => {};
306
+ process.stdout.write = (_chunk, encoding, callback) => {
307
+ const done = typeof encoding === "function" ? encoding : callback;
308
+ if (typeof done === "function") done();
309
+ return true;
310
+ };
311
+ }
312
+ try {
313
+ const limit = Math.max(1, parseInt(options.limit) || 100);
314
+ const projectRoot = path.resolve(options.cwd || process.cwd());
315
+ const sourceErrors = {};
316
+ let local = [];
317
+ let background = [];
318
+ let remote = [];
319
+ let team = [];
320
+ let workflow = [];
321
+ let artifacts = [];
322
+ let prLinks = {};
323
+
324
+ try {
325
+ ctx = await bootstrap({ verbose: program.opts().verbose });
326
+ if (ctx.db) {
327
+ local.push(
328
+ ...listSessions(ctx.db.getDatabase(), { limit }).map((item) => ({
329
+ ...item,
330
+ _store: "db",
331
+ })),
332
+ );
333
+ }
334
+ } catch (error) {
335
+ sourceErrors.local = error?.message || String(error);
336
+ }
337
+ try {
338
+ // JSONL is the canonical transcript store and can be read without
339
+ // bootstrapping legacy native DB/config packages (some of which
340
+ // write banners directly to stdout and would corrupt --json).
341
+ local.push(
342
+ ...listJsonlSessions({ limit }).map((item) => ({
343
+ ...item,
344
+ _store: "jsonl",
345
+ })),
346
+ );
347
+ local = rankSessions(local, limit);
348
+ } catch (error) {
349
+ sourceErrors.local = error?.message || String(error);
350
+ }
351
+ try {
352
+ const { listBackgroundAgents } =
353
+ await import("../lib/background-agent-supervisor.js");
354
+ background = listBackgroundAgents({ all: true });
355
+ } catch (error) {
356
+ sourceErrors.background = error?.message || String(error);
357
+ }
358
+ try {
359
+ const { readRemoteControlStates } =
360
+ await import("../lib/remote-control.js");
361
+ remote = readRemoteControlStates();
362
+ } catch (error) {
363
+ sourceErrors.remote = error?.message || String(error);
364
+ }
365
+ try {
366
+ const { listCollaborationRuns } =
367
+ await import("../lib/collaboration-run-store.js");
368
+ team = listCollaborationRuns({ limit }).filter(
369
+ (run) => run?.kind === "team",
370
+ );
371
+ } catch (error) {
372
+ sourceErrors.team = error?.message || String(error);
373
+ }
374
+ try {
375
+ workflow = listWorkflowSessions(projectRoot)
376
+ .slice(0, limit)
377
+ .map((item) => ({
378
+ ...item,
379
+ id: item.sessionId,
380
+ cwd: projectRoot,
381
+ checkpointCwd: projectRoot,
382
+ checkpointSessionId: item.sessionId,
383
+ }));
384
+ } catch (error) {
385
+ sourceErrors.workflow = error?.message || String(error);
386
+ }
387
+ try {
388
+ // A file checkpoint is advertised only after the existing CLI git
389
+ // engine proves that the exact worktree is supported. Copy-mode
390
+ // checkpoints need explicit paths and therefore cannot truthfully be
391
+ // offered as a one-click session action.
392
+ const { isCheckpointAvailable } =
393
+ await import("../lib/checkpoint-store.js");
394
+ const capability = new Map();
395
+ const decorate = (items, pathFor, sessionFor) =>
396
+ items.map((item) => {
397
+ const candidate = pathFor(item);
398
+ if (!candidate) return item;
399
+ const checkpointCwd = path.resolve(candidate);
400
+ let available = capability.get(checkpointCwd);
401
+ if (available === undefined) {
402
+ try {
403
+ available = isCheckpointAvailable(checkpointCwd);
404
+ } catch {
405
+ available = false;
406
+ }
407
+ capability.set(checkpointCwd, available);
408
+ }
409
+ return {
410
+ ...item,
411
+ checkpointAvailable: available === true,
412
+ checkpointCwd,
413
+ checkpointSessionId: sessionFor(item),
414
+ };
415
+ });
416
+ local = decorate(
417
+ local,
418
+ (item) => item?.workspace || item?.cwd,
419
+ (item) => item?.id,
420
+ );
421
+ background = decorate(
422
+ background,
423
+ (item) => item?.cwd,
424
+ (item) => item?.sessionId || item?.id,
425
+ );
426
+ workflow = decorate(
427
+ workflow,
428
+ (item) => item?.checkpointCwd,
429
+ (item) => item?.checkpointSessionId,
430
+ );
431
+ } catch {
432
+ // Capability detection is additive. Missing git support leaves the
433
+ // checkpoint action unavailable with its explicit reason.
434
+ }
435
+ try {
436
+ const { ArtifactStore } = await import("../lib/artifact-store.js");
437
+ artifacts = new ArtifactStore().list();
438
+ } catch {
439
+ // Summaries are optional; absence never removes a session.
440
+ }
441
+ try {
442
+ const { readPrLinkLedger } = await import("../lib/pr-link-ledger.js");
443
+ prLinks = readPrLinkLedger();
444
+ } catch {
445
+ // Summaries are optional; absence never removes a session.
446
+ }
447
+
448
+ const { buildSessionProjection } =
449
+ await import("../lib/session-projection.js");
450
+ const projection = buildSessionProjection({
451
+ local,
452
+ background,
453
+ remote,
454
+ team,
455
+ workflow,
456
+ artifacts,
457
+ prLinks,
458
+ sourceErrors,
459
+ });
460
+ if (options.json) {
461
+ jsonPayload = JSON.stringify(projection, null, 2);
462
+ } else {
463
+ logger.log(
464
+ `${projection.sessions.length} sessions; revision ${projection.revision}`,
465
+ );
466
+ for (const item of projection.sessions) {
467
+ logger.log(
468
+ ` ${item.id} ${item.state} [${item.capabilities.join(", ")}]`,
469
+ );
470
+ }
471
+ }
472
+ } catch (error) {
473
+ const { disconnectedSessionProjection } =
474
+ await import("../lib/session-projection.js");
475
+ if (options.json) {
476
+ jsonPayload = JSON.stringify(
477
+ disconnectedSessionProjection(error?.message || String(error)),
478
+ null,
479
+ 2,
480
+ );
481
+ } else {
482
+ logger.error(`Failed: ${error.message}`);
483
+ }
484
+ process.exitCode = 1;
485
+ } finally {
486
+ if (ctx) await shutdown();
487
+ if (options.json) {
488
+ console.log = stdout;
489
+ process.stdout.write = stdoutWrite;
490
+ stdout(jsonPayload || "{}");
491
+ }
492
+ }
493
+ });
494
+
261
495
  // session show
262
496
  session
263
497
  .command("show")
@@ -266,35 +500,40 @@ export function registerSessionCommand(program) {
266
500
  .option("-n, --limit <n>", "Max messages to show")
267
501
  .option("--json", "Output as JSON")
268
502
  .action(async (id, options) => {
503
+ let ctx = null;
269
504
  try {
270
- const ctx = await bootstrap({ verbose: program.opts().verbose });
271
505
  let sess = null;
272
506
 
273
507
  // Try JSONL first if enabled
274
- if (feature("JSONL_SESSION") && sessionExists(id)) {
275
- const events = readEvents(id);
276
- const startEvent = events.find((e) => e.type === "session_start");
277
- const msgs = rebuildMessages(id);
508
+ const jsonlId = feature("JSONL_SESSION") ? resolveSessionId(id) : null;
509
+ if (jsonlId) {
510
+ const metadata = getJsonlSessionMetadata(jsonlId);
511
+ const msgs = rebuildMessages(jsonlId);
278
512
  sess = {
279
- id,
280
- title: startEvent?.data?.title || "Untitled",
281
- provider: startEvent?.data?.provider || "",
282
- model: startEvent?.data?.model || "",
513
+ id: jsonlId,
514
+ title: metadata?.title || "Untitled",
515
+ provider: metadata?.provider || "",
516
+ model: metadata?.model || "",
283
517
  message_count: msgs.length,
284
518
  messages: msgs,
285
519
  _store: "jsonl",
286
520
  };
287
521
  }
288
522
 
289
- // Fallback to DB
290
- if (!sess && ctx.db) {
523
+ // Version-0 DB adapter is loaded only when the canonical transcript is
524
+ // absent, keeping the JSONL hot path independent from native SQLite.
525
+ if (!sess) {
526
+ ctx = await bootstrap({ verbose: program.opts().verbose });
527
+ }
528
+ if (!sess && ctx?.db) {
291
529
  const db = ctx.db.getDatabase();
292
530
  sess = getSession(db, id);
293
531
  }
294
532
 
295
533
  if (!sess) {
296
534
  logger.error(`Session not found: ${id}`);
297
- process.exit(1);
535
+ process.exitCode = 1;
536
+ return;
298
537
  }
299
538
 
300
539
  // PR/session linking: surface PRs this session created/touched.
@@ -302,7 +541,7 @@ export function registerSessionCommand(program) {
302
541
  const { getPrLinks } = await import("../lib/pr-link-ledger.js");
303
542
  const prLinks = getPrLinks(sess.id);
304
543
  if (prLinks.length > 0) sess.prLinks = prLinks;
305
- } catch (_err) {
544
+ } catch {
306
545
  // PR decoration is cosmetic
307
546
  }
308
547
 
@@ -346,11 +585,11 @@ export function registerSessionCommand(program) {
346
585
  logger.log("");
347
586
  }
348
587
  }
349
-
350
- await shutdown();
351
588
  } catch (err) {
352
589
  logger.error(`Failed: ${err.message}`);
353
- process.exit(1);
590
+ process.exitCode = 1;
591
+ } finally {
592
+ if (ctx) await shutdown();
354
593
  }
355
594
  });
356
595
 
@@ -366,7 +605,7 @@ export function registerSessionCommand(program) {
366
605
  .option("--pr <number>", "Which linked PR to assess (default: newest)")
367
606
  .option(
368
607
  "--checks-file <path>",
369
- "JSON file of PR signals {branch,prNumber,hasOpenPr,branchProtectionSatisfied,reviewApproved,pendingApprovals,requiredChecks,checks} — bypasses gh",
608
+ "JSON PR signals including exact head/CI commits, full required matrix, checks and side-effect adjudication — bypasses gh",
370
609
  )
371
610
  .option("--enable", "Consider auto-merge eligibility (default: off)")
372
611
  .option("--json", "Output as machine-readable JSON")
@@ -452,13 +691,14 @@ export function registerSessionCommand(program) {
452
691
  "Resume even when the transcript hash chain is broken (context is untrusted)",
453
692
  )
454
693
  .action(async (id, options) => {
694
+ let ctx = null;
455
695
  try {
456
- const ctx = await bootstrap({ verbose: program.opts().verbose });
457
696
  let sess = null;
458
697
 
459
698
  // No id → shared interactive picker (TTY + >1) or most-recent fallback
460
699
  // (single / non-TTY / Ctrl-C). Same helper as `cc agent --resume`.
461
700
  if (!id) {
701
+ ctx = await bootstrap({ verbose: program.opts().verbose });
462
702
  const { pickRecentSession } =
463
703
  await import("../lib/session-picker.js");
464
704
  const picked = await pickRecentSession(ctx);
@@ -466,57 +706,64 @@ export function registerSessionCommand(program) {
466
706
  logger.error(
467
707
  "No saved sessions to resume. Use 'chat' or 'agent' to create one.",
468
708
  );
469
- process.exit(1);
709
+ process.exitCode = 1;
710
+ return;
470
711
  }
471
712
  id = picked.id;
472
713
  }
473
714
 
474
715
  // Try JSONL first
475
- if (feature("JSONL_SESSION") && sessionExists(id)) {
716
+ const jsonlId = feature("JSONL_SESSION") ? resolveSessionId(id) : null;
717
+ if (jsonlId) {
476
718
  // Tamper gate: a broken hash chain means the transcript was edited
477
719
  // outside the store — never silently rebuild it as trusted context.
478
720
  const { verifySession } =
479
721
  await import("../harness/jsonl-session-store.js");
480
- const trust = verifySession(id);
722
+ const trust = verifySession(jsonlId);
481
723
  if (trust.status === "tampered") {
482
724
  if (!options.allowTampered) {
483
725
  logger.error(
484
- `Session ${id} transcript failed integrity verification: ${trust.reason}` +
726
+ `Session ${jsonlId} transcript failed integrity verification: ${trust.reason}` +
485
727
  (trust.firstInvalidLine
486
728
  ? ` (line ${trust.firstInvalidLine})`
487
729
  : ""),
488
730
  );
489
731
  logger.error(
490
732
  "Refusing to resume tampered context. Inspect it read-only with " +
491
- `'cc session show ${id}' / 'cc session verify ${id}', or pass --allow-tampered to override.`,
733
+ `'cc session show ${jsonlId}' / 'cc session verify ${jsonlId}', or pass --allow-tampered to override.`,
492
734
  );
493
- process.exit(1);
735
+ process.exitCode = 1;
736
+ return;
494
737
  }
495
738
  logger.warn(
496
739
  `⚠ Resuming a TAMPERED transcript (${trust.reason}) — treat restored context as untrusted.`,
497
740
  );
498
741
  }
499
- const events = readEvents(id);
500
- const startEvent = events.find((e) => e.type === "session_start");
742
+ const metadata = getJsonlSessionMetadata(jsonlId);
501
743
  sess = {
502
- id,
503
- title: startEvent?.data?.title || "Untitled",
504
- provider: startEvent?.data?.provider || "",
505
- model: startEvent?.data?.model || "",
506
- messages: rebuildMessages(id),
744
+ id: jsonlId,
745
+ title: metadata?.title || "Untitled",
746
+ provider: metadata?.provider || "",
747
+ model: metadata?.model || "",
748
+ messages: rebuildMessages(jsonlId),
507
749
  };
508
750
  sess.message_count = sess.messages.length;
509
751
  }
510
752
 
511
- // Fallback to DB
512
- if (!sess && ctx.db) {
753
+ // Version-0 DB adapter is loaded only when the canonical transcript is
754
+ // absent (or the picker required the combined legacy view).
755
+ if (!sess && !ctx) {
756
+ ctx = await bootstrap({ verbose: program.opts().verbose });
757
+ }
758
+ if (!sess && ctx?.db) {
513
759
  const db = ctx.db.getDatabase();
514
760
  sess = getSession(db, id);
515
761
  }
516
762
 
517
763
  if (!sess) {
518
764
  logger.error(`Session not found: ${id}`);
519
- process.exit(1);
765
+ process.exitCode = 1;
766
+ return;
520
767
  }
521
768
 
522
769
  logger.info(
@@ -534,7 +781,9 @@ export function registerSessionCommand(program) {
534
781
  });
535
782
  } catch (err) {
536
783
  logger.error(`Failed: ${err.message}`);
537
- process.exit(1);
784
+ process.exitCode = 1;
785
+ } finally {
786
+ if (ctx) await shutdown();
538
787
  }
539
788
  });
540
789
 
@@ -542,7 +791,7 @@ export function registerSessionCommand(program) {
542
791
  session
543
792
  .command("export")
544
793
  .description(
545
- "Export a session as Markdown (chat-DB session, or JSONL agent session fallback)",
794
+ "Export a session as Markdown (canonical JSONL transcript, then legacy DB fallback)",
546
795
  )
547
796
  .argument(
548
797
  "<id>",
@@ -554,12 +803,25 @@ export function registerSessionCommand(program) {
554
803
  "Do NOT redact detected secrets from the exported transcript (default: redact)",
555
804
  )
556
805
  .action(async (id, options) => {
806
+ let bootstrapped = false;
557
807
  try {
558
808
  let markdown = null;
559
- let bootstrapped = false;
560
809
 
561
- // Primary source: chat-DB sessions (legacy behaviour, unchanged).
562
- if (id !== "last") {
810
+ // Canonical content source: append-only JSONL event log. The legacy DB
811
+ // is consulted only when no matching transcript exists.
812
+ const store = await import("../harness/jsonl-session-store.js");
813
+ const sid =
814
+ id === "last" ? store.getLastSessionId() : store.resolveSessionId(id);
815
+ if (sid) {
816
+ const { renderAgentSessionMarkdown } =
817
+ await import("../lib/agent-session-export.js");
818
+ markdown = renderAgentSessionMarkdown(sid, store.readEvents(sid), {
819
+ exportedAt: new Date().toISOString(),
820
+ });
821
+ }
822
+
823
+ // Version-0 chat DB adapter: read-only migration compatibility.
824
+ if (!markdown && id !== "last") {
563
825
  try {
564
826
  const ctx = await bootstrap({ verbose: program.opts().verbose });
565
827
  bootstrapped = true;
@@ -572,23 +834,10 @@ export function registerSessionCommand(program) {
572
834
  }
573
835
  }
574
836
 
575
- // Fallback: JSONL agent sessions (`cc agent --resume` store) —
576
- // Claude-Code /export parity for agent transcripts.
577
- if (!markdown) {
578
- const store = await import("../harness/jsonl-session-store.js");
579
- const sid = id === "last" ? store.getLastSessionId() : id;
580
- if (sid && store.sessionExists(sid)) {
581
- const { renderAgentSessionMarkdown } =
582
- await import("../lib/agent-session-export.js");
583
- markdown = renderAgentSessionMarkdown(sid, store.readEvents(sid), {
584
- exportedAt: new Date().toISOString(),
585
- });
586
- }
587
- }
588
-
589
837
  if (!markdown) {
590
838
  logger.error(`Session not found: ${id}`);
591
- process.exit(1);
839
+ process.exitCode = 1;
840
+ return;
592
841
  }
593
842
 
594
843
  // §8.1 export gate: a transcript can carry provider tokens, JWTs,
@@ -611,11 +860,11 @@ export function registerSessionCommand(program) {
611
860
  } else {
612
861
  console.log(markdown);
613
862
  }
614
-
615
- if (bootstrapped) await shutdown();
616
863
  } catch (err) {
617
864
  logger.error(`Failed: ${err.message}`);
618
- process.exit(1);
865
+ process.exitCode = 1;
866
+ } finally {
867
+ if (bootstrapped) await shutdown();
619
868
  }
620
869
  });
621
870
 
@@ -634,40 +883,81 @@ export function registerSessionCommand(program) {
634
883
  const store = await import("../harness/jsonl-session-store.js");
635
884
  const q = String(query).toLowerCase();
636
885
  const limit = Number(options.limit) || 20;
637
- const sessions = store.listJsonlSessions({
638
- limit: Number(options.sessions) || 200,
639
- });
640
- const matches = [];
641
- for (const s of sessions) {
642
- if (matches.length >= limit) break;
643
- for (const ev of store.readEvents(s.id)) {
886
+ let source = "sqlite-index";
887
+ let indexDiagnostic = null;
888
+ let matches = [];
889
+ let indexDb = null;
890
+ try {
891
+ const sessionIndex = await import("../harness/session-index.js");
892
+ indexDb = sessionIndex.openIndex();
893
+ sessionIndex.syncIndex(indexDb);
894
+ matches = sessionIndex
895
+ .searchSessions(indexDb, query, { limit })
896
+ .map((hit) => ({
897
+ session: hit.id,
898
+ title: hit.title,
899
+ role: "session",
900
+ when: hit.updated_at || "",
901
+ preview: hit.snippet || hit.title || "",
902
+ }));
903
+ } catch (error) {
904
+ // Native SQLite is optional in development/source installs. The
905
+ // bounded streaming fallback preserves functionality and identifies
906
+ // itself in JSON output instead of silently pretending it was indexed.
907
+ source = "stream-fallback";
908
+ indexDiagnostic = error?.message || String(error);
909
+ const sessions = store.listJsonlSessions({
910
+ limit: Number(options.sessions) || 200,
911
+ });
912
+ for (const s of sessions) {
644
913
  if (matches.length >= limit) break;
645
- if (ev.type !== "user_message" && ev.type !== "assistant_message")
646
- continue;
647
- const text =
648
- typeof ev.data?.content === "string"
649
- ? ev.data.content
650
- : JSON.stringify(ev.data?.content || "");
651
- const idx = text.toLowerCase().indexOf(q);
652
- if (idx === -1) continue;
653
- const from = Math.max(0, idx - 30);
654
- matches.push({
655
- session: s.id,
656
- title: s.title,
657
- role: ev.type === "user_message" ? "user" : "assistant",
658
- // toIsoSafe (not a bare truthy guard): an invalid-but-truthy
659
- // timestamp on a corrupt event would otherwise throw RangeError
660
- // and crash the whole search.
661
- when: store.toIsoSafe(ev.timestamp),
662
- preview: text
663
- .slice(from, idx + q.length + 50)
664
- .replace(/\s+/g, " ")
665
- .trim(),
666
- });
914
+ for (const ev of store.readEvents(s.id)) {
915
+ if (matches.length >= limit) break;
916
+ if (
917
+ ev.type !== "user_message" &&
918
+ ev.type !== "assistant_message"
919
+ ) {
920
+ continue;
921
+ }
922
+ const text =
923
+ typeof ev.data?.content === "string"
924
+ ? ev.data.content
925
+ : JSON.stringify(ev.data?.content || "");
926
+ const at = text.toLowerCase().indexOf(q);
927
+ if (at === -1) continue;
928
+ const from = Math.max(0, at - 30);
929
+ matches.push({
930
+ session: s.id,
931
+ title: s.title,
932
+ role: ev.type === "user_message" ? "user" : "assistant",
933
+ when: store.toIsoSafe(ev.timestamp),
934
+ preview: text
935
+ .slice(from, at + q.length + 50)
936
+ .replace(/\s+/g, " ")
937
+ .trim(),
938
+ });
939
+ }
940
+ }
941
+ } finally {
942
+ try {
943
+ indexDb?.close();
944
+ } catch {
945
+ /* derived index close is best-effort */
667
946
  }
668
947
  }
669
948
  if (options.json) {
670
- console.log(JSON.stringify({ query, matches }, null, 2));
949
+ console.log(
950
+ JSON.stringify(
951
+ {
952
+ query,
953
+ source,
954
+ matches,
955
+ ...(indexDiagnostic ? { indexDiagnostic } : {}),
956
+ },
957
+ null,
958
+ 2,
959
+ ),
960
+ );
671
961
  return;
672
962
  }
673
963
  if (!matches.length) {
@@ -699,37 +989,53 @@ export function registerSessionCommand(program) {
699
989
  .argument("<id>", "Session ID")
700
990
  .option("--force", "Skip confirmation")
701
991
  .action(async (id, options) => {
992
+ let ctx = null;
702
993
  try {
703
- const ctx = await bootstrap({ verbose: program.opts().verbose });
704
- if (!ctx.db) {
705
- logger.error("Database not available");
706
- process.exit(1);
994
+ const jsonlId = resolveSessionId(id);
995
+ let db = null;
996
+ try {
997
+ ctx = await bootstrap({ verbose: program.opts().verbose });
998
+ db = ctx.db?.getDatabase() || null;
999
+ } catch (error) {
1000
+ if (!jsonlId) throw error;
1001
+ }
1002
+ const dbSession = !jsonlId && db ? getSession(db, id) : null;
1003
+ const targetId = jsonlId || dbSession?.id || id;
1004
+
1005
+ if (!jsonlId && !dbSession) {
1006
+ logger.error(`Session not found: ${id}`);
1007
+ process.exitCode = 1;
1008
+ return;
707
1009
  }
708
- const db = ctx.db.getDatabase();
709
1010
 
710
1011
  if (!options.force) {
711
1012
  const { confirm } = await import("@inquirer/prompts");
712
1013
  const ok = await confirm({
713
- message: `Delete session "${id}"?`,
1014
+ message: `Delete session "${targetId}"?`,
714
1015
  });
715
1016
  if (!ok) {
716
1017
  logger.info("Cancelled");
717
- await shutdown();
718
1018
  return;
719
1019
  }
720
1020
  }
721
1021
 
722
- const ok = deleteSession(db, id);
723
- if (ok) {
1022
+ const jsonlDeleted = jsonlId ? deleteJsonlSession(jsonlId) : false;
1023
+ // Remove an exact-id legacy duplicate as part of the same semantic
1024
+ // delete so it cannot reappear after the canonical transcript is gone.
1025
+ const dbDeleted = db
1026
+ ? deleteSession(db, jsonlId || dbSession?.id || id)
1027
+ : false;
1028
+ if (jsonlDeleted || dbDeleted) {
724
1029
  logger.success("Session deleted");
725
1030
  } else {
726
1031
  logger.error(`Session not found: ${id}`);
1032
+ process.exitCode = 1;
727
1033
  }
728
-
729
- await shutdown();
730
1034
  } catch (err) {
731
1035
  logger.error(`Failed: ${err.message}`);
732
- process.exit(1);
1036
+ process.exitCode = 1;
1037
+ } finally {
1038
+ if (ctx) await shutdown();
733
1039
  }
734
1040
  });
735
1041
 
@@ -742,13 +1048,26 @@ export function registerSessionCommand(program) {
742
1048
  .argument("<title...>", "New title")
743
1049
  .option("--json", "Output as JSON")
744
1050
  .action(async (id, title, options) => {
1051
+ let ctx = null;
745
1052
  try {
746
- const { renameSession } =
747
- await import("../harness/jsonl-session-store.js");
748
- const result = renameSession(
749
- id,
1053
+ const normalized = String(
750
1054
  Array.isArray(title) ? title.join(" ") : title,
751
- );
1055
+ ).trim();
1056
+ if (!normalized) throw new Error("A non-empty title is required");
1057
+ const jsonlId = resolveSessionId(id);
1058
+ let result;
1059
+ if (jsonlId) {
1060
+ const { renameSession } =
1061
+ await import("../harness/jsonl-session-store.js");
1062
+ result = renameSession(jsonlId, normalized);
1063
+ } else {
1064
+ ctx = await bootstrap({ verbose: program.opts().verbose });
1065
+ const db = ctx.db?.getDatabase();
1066
+ const legacy = db ? getSession(db, id) : null;
1067
+ if (!legacy) throw new Error(`Session not found: ${id}`);
1068
+ updateSession(db, legacy.id, { title: normalized.slice(0, 200) });
1069
+ result = { id: legacy.id, title: normalized.slice(0, 200) };
1070
+ }
752
1071
  if (options.json) {
753
1072
  console.log(JSON.stringify(result, null, 2));
754
1073
  return;
@@ -758,6 +1077,8 @@ export function registerSessionCommand(program) {
758
1077
  } catch (err) {
759
1078
  logger.error(`Failed: ${err.message}`);
760
1079
  process.exitCode = 1;
1080
+ } finally {
1081
+ if (ctx) await shutdown();
761
1082
  }
762
1083
  });
763
1084
 
@@ -966,6 +1287,45 @@ export function registerSessionCommand(program) {
966
1287
  // list/search without scanning every transcript, and can mirror sessions to a
967
1288
  // configured off-box target (fs/http). The index is a derived cache: safe to
968
1289
  // delete and rebuild from the JSONL at any time.
1290
+ session
1291
+ .command("repair")
1292
+ .description(
1293
+ "Diagnose and repair one crash-partial final transcript record only",
1294
+ )
1295
+ .argument("<id>", "Session ID to repair")
1296
+ .option("--dry-run", "Report the repair without changing the transcript")
1297
+ .option("--json", "Output as JSON")
1298
+ .action(async (id, options) => {
1299
+ try {
1300
+ const store = await import("../harness/jsonl-session-store.js");
1301
+ const result = store.repairSession(id, {
1302
+ dryRun: Boolean(options.dryRun),
1303
+ });
1304
+ if (options.json) {
1305
+ console.log(JSON.stringify(result, null, 2));
1306
+ } else {
1307
+ const label = result.healthy
1308
+ ? chalk.green("healthy")
1309
+ : chalk.yellow(options.dryRun ? "repair-needed" : "attention");
1310
+ logger.log(`${label} ${result.sessionId} (${result.status})`);
1311
+ if (result.action && result.action !== "none") {
1312
+ const prefix = options.dryRun ? "would " : "";
1313
+ logger.log(
1314
+ ` ${prefix}${result.action}` +
1315
+ (result.discardedBytes
1316
+ ? ` (${result.discardedBytes} partial bytes)`
1317
+ : ""),
1318
+ );
1319
+ }
1320
+ if (result.reason) logger.log(` ${chalk.gray(result.reason)}`);
1321
+ }
1322
+ if (!result.healthy) process.exitCode = 1;
1323
+ } catch (err) {
1324
+ logger.error(`Failed: ${err.message}`);
1325
+ process.exitCode = 1;
1326
+ }
1327
+ });
1328
+
969
1329
  session
970
1330
  .command("index")
971
1331
  .description(