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
@@ -11,12 +11,107 @@
11
11
 
12
12
  import { createHash } from "node:crypto";
13
13
  import { feature, featureVariant } from "../lib/feature-flags.js";
14
+ import {
15
+ DURABLE_SYSTEM_MESSAGE_KINDS,
16
+ markDurableSystemMessage,
17
+ } from "../lib/session-message-provenance.js";
18
+ import {
19
+ buildExtractiveHandoff,
20
+ formatStructuredHandoff,
21
+ parseStructuredHandoff,
22
+ StructuredHandoffValidationError,
23
+ STRUCTURED_HANDOFF_FIELDS,
24
+ } from "./structured-handoff.js";
25
+
26
+ export * from "./structured-handoff.js";
14
27
 
15
28
  // Bounds for the fuzzy near-dup pass in _deduplicate (see there). Generous
16
29
  // enough that real near-dups are still caught; small enough that compaction of
17
30
  // a long, tool-heavy history stays sub-second instead of O(n²·content).
18
31
  const DEDUP_JACCARD_MAX_CHARS = 4000;
19
32
  const DEDUP_FUZZY_WINDOW = 100;
33
+ export const SUMMARY_INPUT_DEFAULT_MAX_CHARS = 24000;
34
+ export const SUMMARY_INPUT_HARD_MAX_CHARS = 32000;
35
+ const SUMMARY_INPUT_MIN_CHARS = 1024;
36
+
37
+ function boundedPositiveInteger(value, fallback, minimum, maximum) {
38
+ const number = Math.floor(Number(value));
39
+ if (!Number.isFinite(number) || number <= 0) return fallback;
40
+ return Math.min(Math.max(number, minimum), maximum);
41
+ }
42
+
43
+ function summaryEntry(message, index) {
44
+ const role = typeof message?.role === "string" ? message.role : "unknown";
45
+ return `[${index}] ${role}: ${getContent(message)
46
+ .replace(/\r\n?/g, "\n")
47
+ .trim()
48
+ .slice(0, 2000)}`;
49
+ }
50
+
51
+ /** Keep the earliest user objective plus as much recent context as fits. */
52
+ function buildBoundedHistory(messages, maxChars) {
53
+ const entries = messages
54
+ .map((message, index) => ({
55
+ index,
56
+ role: message?.role,
57
+ text: summaryEntry(message, index),
58
+ }))
59
+ .filter((entry) => entry.text.trim());
60
+ const all = entries.map((entry) => entry.text).join("\n");
61
+ if (all.length <= maxChars) return all;
62
+
63
+ const firstUser = entries.find((entry) => entry.role === "user");
64
+ const selected = new Map();
65
+ let remaining = maxChars;
66
+ if (firstUser && remaining > 0) {
67
+ const objectiveBudget = Math.min(
68
+ firstUser.text.length,
69
+ Math.max(1, Math.floor(maxChars / 3)),
70
+ );
71
+ selected.set(firstUser.index, firstUser.text.slice(0, objectiveBudget));
72
+ remaining -= objectiveBudget;
73
+ }
74
+
75
+ for (let index = entries.length - 1; index >= 0 && remaining > 0; index--) {
76
+ const entry = entries[index];
77
+ if (selected.has(entry.index)) continue;
78
+ const separator = selected.size > 0 ? 1 : 0;
79
+ if (remaining <= separator) break;
80
+ const text = entry.text.slice(0, remaining - separator);
81
+ if (!text) break;
82
+ selected.set(entry.index, text);
83
+ remaining -= text.length + separator;
84
+ }
85
+
86
+ return [...selected.entries()]
87
+ .sort(([left], [right]) => left - right)
88
+ .map(([, text]) => text)
89
+ .join("\n")
90
+ .slice(0, maxChars);
91
+ }
92
+
93
+ function summaryPrompt(messages, maxChars) {
94
+ const schema = `{${STRUCTURED_HANDOFF_FIELDS.map((field) => `"${field}"`).join(",")}}`;
95
+ const instructions = [
96
+ "Create a durable conversation handoff from the history below.",
97
+ `Return exactly one strict JSON object with all keys in this order: ${schema}.`,
98
+ '"objective" must be a string; every other value must be an array of strings.',
99
+ "Preserve constraints, exact file paths, test evidence, unresolved external side effects, blockers, and actionable next steps. Do not use Markdown.",
100
+ "Conversation history:",
101
+ ].join("\n");
102
+ const historyBudget = Math.max(0, maxChars - instructions.length - 1);
103
+ const history = buildBoundedHistory(messages, historyBudget);
104
+ return `${instructions}\n${history}`.slice(0, maxChars);
105
+ }
106
+
107
+ function boundedFailureMessage(error) {
108
+ const message =
109
+ error instanceof Error ? error.message : String(error || "unknown error");
110
+ return message
111
+ .replace(/[\r\n]+/g, " ")
112
+ .trim()
113
+ .slice(0, 240);
114
+ }
20
115
 
21
116
  export function estimateTokens(text) {
22
117
  if (!text) return 0;
@@ -186,7 +281,8 @@ export function sanitizeToolPairs(messages) {
186
281
  stage1.push({ ...m, tool_calls: kept });
187
282
  } else {
188
283
  // No surviving calls: keep the assistant text if any, else drop it.
189
- const { tool_calls: _drop, ...rest } = m;
284
+ const rest = { ...m };
285
+ delete rest.tool_calls;
190
286
  if (rest.content && String(rest.content).trim()) stage1.push(rest);
191
287
  }
192
288
  } else {
@@ -232,6 +328,12 @@ export class PromptCompressor {
232
328
  }
233
329
  this.similarityThreshold = options.similarityThreshold || 0.9;
234
330
  this.llmQuery = options.llmQuery || null;
331
+ this.summaryInputMaxChars = boundedPositiveInteger(
332
+ options.summaryInputMaxChars,
333
+ SUMMARY_INPUT_DEFAULT_MAX_CHARS,
334
+ SUMMARY_INPUT_MIN_CHARS,
335
+ SUMMARY_INPUT_HARD_MAX_CHARS,
336
+ );
235
337
  }
236
338
 
237
339
  adaptToModel(model, provider) {
@@ -271,6 +373,7 @@ export class PromptCompressor {
271
373
  const originalTokens = estimateMessagesTokens(messages);
272
374
  let result = [...working];
273
375
  const applied = [];
376
+ let summaryStats = null;
274
377
 
275
378
  if (feature("CONTEXT_SNIP")) {
276
379
  const before = result.length;
@@ -290,21 +393,28 @@ export class PromptCompressor {
290
393
  if (result.length < before) applied.push("collapse");
291
394
  }
292
395
 
293
- if (result.length > this.maxMessages) {
294
- result = this._truncate(result);
295
- applied.push("truncate");
296
- }
297
-
396
+ // Semantic handoff must run BEFORE destructive count-based truncation;
397
+ // otherwise long conversations commonly fall under maxTokens only because
398
+ // the facts we needed to summarize were already discarded.
298
399
  const currentTokens = estimateMessagesTokens(result);
299
- if (this.llmQuery && currentTokens > this.maxTokens && result.length > 4) {
300
- try {
301
- result = await this._summarize(result);
400
+ if (
401
+ this.llmQuery &&
402
+ (currentTokens > this.maxTokens || result.length > this.maxMessages) &&
403
+ result.length > 4
404
+ ) {
405
+ const summarized = await this._summarize(result);
406
+ result = summarized.messages;
407
+ summaryStats = summarized.stats;
408
+ if (summaryStats.summaryMode !== "none") {
302
409
  applied.push("summarize");
303
- } catch (_err) {
304
- // Summarization failed — continue with what we have
305
410
  }
306
411
  }
307
412
 
413
+ if (result.length > this.maxMessages) {
414
+ result = this._truncate(result);
415
+ applied.push("truncate");
416
+ }
417
+
308
418
  // Re-insert pinned facts verbatim (order preserved) right after the leading
309
419
  // system messages, so they end up as a sticky facts block at the top.
310
420
  if (pinned.length) {
@@ -330,6 +440,7 @@ export class PromptCompressor {
330
440
  compressedTokens,
331
441
  saved: originalTokens - compressedTokens,
332
442
  ratio: originalTokens > 0 ? compressedTokens / originalTokens : 1,
443
+ ...(summaryStats || {}),
333
444
  };
334
445
 
335
446
  const abVariant = getCompressionVariant();
@@ -417,24 +528,108 @@ export class PromptCompressor {
417
528
  (m) => m.role !== "system" && m !== last,
418
529
  );
419
530
 
420
- if (toSummarize.length < 3) return messages;
421
-
422
- const historyText = toSummarize
423
- .map((m) => `${m.role}: ${getContent(m).slice(0, 500)}`)
424
- .join("\n");
425
-
426
- const summary = await this.llmQuery(
427
- `Summarize this conversation history concisely, preserving key facts and decisions:\n\n${historyText}\n\nSummary:`,
428
- );
531
+ if (toSummarize.length < 3) {
532
+ return {
533
+ messages,
534
+ stats: {
535
+ summaryMode: "none",
536
+ degraded: false,
537
+ degradedReason: null,
538
+ summaryInputChars: 0,
539
+ summaryInputLimit: this.summaryInputMaxChars,
540
+ },
541
+ };
542
+ }
429
543
 
430
- if (!summary) return messages;
544
+ const prompt = summaryPrompt(toSummarize, this.summaryInputMaxChars);
545
+ let summary;
546
+ let summaryMode = "llm-structured";
547
+ let degraded = false;
548
+ let degradedReason = null;
549
+ let rawSummary;
550
+ let summaryUsage = null;
551
+ let summaryProvider = null;
552
+ let summaryModel = null;
553
+ try {
554
+ const queryResult = await this.llmQuery(prompt);
555
+ if (
556
+ queryResult &&
557
+ typeof queryResult === "object" &&
558
+ Object.prototype.hasOwnProperty.call(queryResult, "summary")
559
+ ) {
560
+ rawSummary = queryResult.summary;
561
+ const usage = queryResult.usage;
562
+ if (usage && typeof usage === "object") {
563
+ summaryUsage = {
564
+ inputTokens: Number(usage.input_tokens ?? usage.prompt_tokens) || 0,
565
+ outputTokens:
566
+ Number(usage.output_tokens ?? usage.completion_tokens) || 0,
567
+ cacheReadTokens:
568
+ Number(
569
+ usage.cache_read_input_tokens ?? usage.cache_read_tokens,
570
+ ) || 0,
571
+ cacheCreationTokens:
572
+ Number(
573
+ usage.cache_creation_input_tokens ??
574
+ usage.cache_creation_tokens,
575
+ ) || 0,
576
+ };
577
+ }
578
+ summaryProvider = queryResult.provider || null;
579
+ summaryModel = queryResult.model || null;
580
+ } else {
581
+ rawSummary = queryResult;
582
+ }
583
+ } catch (error) {
584
+ degraded = true;
585
+ summaryMode = "extractive-fallback";
586
+ degradedReason = `llm_query_failed:${boundedFailureMessage(error)}`;
587
+ }
588
+ if (!degraded) {
589
+ try {
590
+ summary = parseStructuredHandoff(rawSummary);
591
+ } catch (error) {
592
+ degraded = true;
593
+ summaryMode = "extractive-fallback";
594
+ degradedReason =
595
+ error instanceof StructuredHandoffValidationError
596
+ ? `invalid_llm_summary:${error.code}`
597
+ : `invalid_llm_summary:normalization_error:${boundedFailureMessage(error)}`;
598
+ }
599
+ }
600
+ if (degraded) {
601
+ summary = buildExtractiveHandoff(toSummarize, {
602
+ maxFallbackSourceChars: Math.min(
603
+ this.summaryInputMaxChars,
604
+ SUMMARY_INPUT_DEFAULT_MAX_CHARS,
605
+ ),
606
+ });
607
+ }
431
608
 
432
609
  const result = [
433
610
  ...system,
434
- { role: "system", content: `[Conversation Summary]\n${summary}` },
611
+ markDurableSystemMessage(
612
+ {
613
+ role: "system",
614
+ content: `[Conversation Summary]\n${formatStructuredHandoff(summary)}`,
615
+ },
616
+ DURABLE_SYSTEM_MESSAGE_KINDS.COMPACT_SUMMARY,
617
+ ),
435
618
  ];
436
619
  if (last) result.push(last);
437
- return result;
620
+ return {
621
+ messages: result,
622
+ stats: {
623
+ summaryMode,
624
+ degraded,
625
+ degradedReason,
626
+ summaryInputChars: prompt.length,
627
+ summaryInputLimit: this.summaryInputMaxChars,
628
+ ...(summaryUsage ? { summaryUsage } : {}),
629
+ ...(summaryProvider ? { summaryProvider } : {}),
630
+ ...(summaryModel ? { summaryModel } : {}),
631
+ },
632
+ };
438
633
  }
439
634
 
440
635
  _snipCompact(messages) {
@@ -515,10 +710,15 @@ export class PromptCompressor {
515
710
  .filter(Boolean);
516
711
  const uniqueTools = [...new Set(toolNames)];
517
712
 
518
- result.push({
519
- role: "system",
520
- content: `[Collapsed ${toolGroup.length} tool messages: ${uniqueTools.join(", ")}]`,
521
- });
713
+ result.push(
714
+ markDurableSystemMessage(
715
+ {
716
+ role: "system",
717
+ content: `[Collapsed ${toolGroup.length} tool messages: ${uniqueTools.join(", ")}]`,
718
+ },
719
+ DURABLE_SYSTEM_MESSAGE_KINDS.COMPACT_TOOL_COLLAPSE,
720
+ ),
721
+ );
522
722
  i = j;
523
723
  continue;
524
724
  }
@@ -17,18 +17,12 @@
17
17
  * without touching the user's home dir.
18
18
  */
19
19
 
20
- import {
21
- existsSync,
22
- mkdirSync,
23
- readdirSync,
24
- statSync,
25
- readFileSync,
26
- } from "node:fs";
20
+ import { existsSync, readdirSync, statSync } from "node:fs";
27
21
  import { join, basename } from "node:path";
28
22
  import { createRequire } from "node:module";
29
23
  import { getHomeDir } from "../lib/paths.js";
30
- import { readEvents, toIsoSafe } from "./jsonl-session-store.js";
31
- import { latestChainHash } from "./transcript-integrity.js";
24
+ import { iterateFileLinesSync } from "../lib/file-lines.js";
25
+ import { ensurePrivateDirectory, ensurePrivateFile } from "../lib/secure-fs.js";
32
26
 
33
27
  const requireCjs = createRequire(import.meta.url);
34
28
 
@@ -50,7 +44,7 @@ function sessionsDir() {
50
44
 
51
45
  function indexPath() {
52
46
  const dir = getHomeDir();
53
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
47
+ ensurePrivateDirectory(dir);
54
48
  return join(dir, "session-index.db");
55
49
  }
56
50
 
@@ -82,43 +76,105 @@ CREATE INDEX IF NOT EXISTS idx_sessions_last_ts ON sessions(last_ts DESC);
82
76
  */
83
77
  export function openIndex({ file } = {}) {
84
78
  const Database = _deps.loadDatabase();
85
- const db = new Database(file || indexPath());
79
+ const target = file || indexPath();
80
+ const db = new Database(target);
86
81
  db.pragma("journal_mode = WAL");
87
82
  db.exec(SCHEMA);
83
+ if (target !== ":memory:") {
84
+ ensurePrivateFile(target);
85
+ ensurePrivateFile(`${target}-wal`);
86
+ ensurePrivateFile(`${target}-shm`);
87
+ }
88
88
  return db;
89
89
  }
90
90
 
91
91
  /** Max characters of concatenated message content indexed per session. */
92
92
  const CONTENT_CAP = 200_000;
93
93
 
94
- function summarizeEvents(id, events) {
95
- const startEvent = events.find((e) => e.type === "session_start");
96
- const lastEvent = events[events.length - 1];
97
- const messageCount = events.filter(
98
- (e) => e.type === "user_message" || e.type === "assistant_message",
99
- ).length;
94
+ function toIsoSafe(value) {
95
+ const number = Number(value);
96
+ if (!Number.isFinite(number)) return "";
97
+ const date = new Date(number);
98
+ return Number.isNaN(date.getTime()) ? "" : date.toISOString();
99
+ }
100
+
101
+ function summarizeSessionFile(id, filePath) {
102
+ let startEvent = null;
103
+ let lastEvent = null;
104
+ let renamedTitle = null;
105
+ let messageCount = 0;
106
+ let eventCount = 0;
107
+ let chainHash = "";
100
108
  const parts = [];
101
109
  let used = 0;
102
- for (const e of events) {
103
- if (e.type !== "user_message" && e.type !== "assistant_message") continue;
104
- const c = e.data?.content;
105
- const s = typeof c === "string" ? c : c == null ? "" : JSON.stringify(c);
106
- if (!s) continue;
107
- parts.push(s);
108
- used += s.length;
109
- if (used >= CONTENT_CAP) break;
110
+ for (const { line } of iterateFileLinesSync(filePath)) {
111
+ let event;
112
+ try {
113
+ event = JSON.parse(line);
114
+ } catch {
115
+ continue;
116
+ }
117
+ eventCount += 1;
118
+ lastEvent = event;
119
+ if (!startEvent && event.type === "session_start") startEvent = event;
120
+ if (event.type === "session_rename" && event.data?.title) {
121
+ renamedTitle = String(event.data.title);
122
+ }
123
+ if (event.type === "user_message" || event.type === "assistant_message") {
124
+ messageCount += 1;
125
+ if (used < CONTENT_CAP) {
126
+ const content = event.data?.content;
127
+ const text =
128
+ typeof content === "string"
129
+ ? content
130
+ : content == null
131
+ ? ""
132
+ : JSON.stringify(content);
133
+ if (text) {
134
+ const bounded = text.slice(0, CONTENT_CAP - used);
135
+ parts.push(bounded);
136
+ used += bounded.length;
137
+ }
138
+ }
139
+ } else if (
140
+ event.type === "ws_turn" &&
141
+ event.data?.schemaVersion === 1 &&
142
+ event.data?.outcome === "completed" &&
143
+ event.data?.user?.role === "user" &&
144
+ event.data?.assistant?.role === "assistant"
145
+ ) {
146
+ messageCount += 2;
147
+ for (const message of [event.data?.user, event.data?.assistant]) {
148
+ if (used >= CONTENT_CAP) break;
149
+ const content = message?.content;
150
+ const text =
151
+ typeof content === "string"
152
+ ? content
153
+ : content == null
154
+ ? ""
155
+ : JSON.stringify(content);
156
+ if (text) {
157
+ const bounded = text.slice(0, CONTENT_CAP - used);
158
+ parts.push(bounded);
159
+ used += bounded.length;
160
+ }
161
+ }
162
+ }
163
+ if (typeof event.hash === "string") chainHash = event.hash;
110
164
  }
165
+ if (!lastEvent) return null;
111
166
  return {
112
167
  id,
113
- title: startEvent?.data?.title || "Untitled",
168
+ title: renamedTitle || startEvent?.data?.title || "Untitled",
114
169
  provider: startEvent?.data?.provider || "",
115
170
  model: startEvent?.data?.model || "",
116
171
  message_count: messageCount,
117
- event_count: events.length,
172
+ event_count: eventCount,
118
173
  created_at: toIsoSafe(startEvent?.timestamp),
119
174
  updated_at: toIsoSafe(lastEvent?.timestamp),
120
175
  last_ts: lastEvent?.timestamp || 0,
121
176
  content: parts.join("\n").slice(0, CONTENT_CAP),
177
+ chain_hash: chainHash,
122
178
  };
123
179
  }
124
180
 
@@ -137,16 +193,10 @@ ON CONFLICT(id) DO UPDATE SET
137
193
  * @returns {boolean} true if a row was written.
138
194
  */
139
195
  export function indexOneSession(db, id, { mtimeMs = 0, sizeBytes = 0 } = {}) {
140
- const events = readEvents(id);
141
- if (events.length === 0) return false;
142
- const s = summarizeEvents(id, events);
143
196
  const filePath = join(sessionsDir(), `${id}.jsonl`);
144
- let chainHash = "";
145
- try {
146
- chainHash = latestChainHash(readFileSync(filePath, "utf-8")) || "";
147
- } catch {
148
- /* chain hash is best-effort */
149
- }
197
+ if (!existsSync(filePath)) return false;
198
+ const s = summarizeSessionFile(id, filePath);
199
+ if (!s) return false;
150
200
  db.prepare(UPSERT_SESSION).run({
151
201
  id: s.id,
152
202
  title: s.title,
@@ -157,7 +207,7 @@ export function indexOneSession(db, id, { mtimeMs = 0, sizeBytes = 0 } = {}) {
157
207
  created_at: s.created_at,
158
208
  updated_at: s.updated_at,
159
209
  last_ts: s.last_ts,
160
- chain_hash: chainHash,
210
+ chain_hash: s.chain_hash,
161
211
  mtime_ms: Math.floor(mtimeMs),
162
212
  size_bytes: sizeBytes,
163
213
  });
@@ -270,7 +320,8 @@ export function searchSessions(db, query, { limit = 20 } = {}) {
270
320
  .replace(/\s+/g, " ")
271
321
  .trim()
272
322
  : "";
273
- const { _text, ...rest } = r;
323
+ const rest = { ...r };
324
+ delete rest._text;
274
325
  return { ...rest, snippet };
275
326
  });
276
327
  }