chainlesschain 0.163.7 → 0.164.0

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 (252) hide show
  1. package/package.json +5 -1
  2. package/scripts/macos-mcp-launcher-build.mjs +317 -0
  3. package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
  4. package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
  5. package/src/assets/web-panel/assets/{AIOps-axqQfwv8.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DV-Ro0By.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-Bt72WEVu.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-BtepG55E.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-B7KaJ7S_.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-FNFaUg7A.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DFb6J2wQ.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-CC7YBhyj.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-RkgTNVtj.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-hHEmGZy-.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CAP9YhHv.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-z5wXOQP1.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-DVaDJnxy.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-CJmaRDR5.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-DF29_2bI.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-DtkQkBzn.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-xoHDxp7I.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-BUm-R7ht.js → Cowork-DvGZrhbO.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-Cgl14ZkB.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-BNcbmoqh.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-Bwja0Zo9.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-Bk5XjEdJ.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-Ci36Oitq.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer--U04ZN4q.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2gNPR2s.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-C4KghYn7.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-QL7x_Q_0.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-F3Ryltwm.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-2HassK5k.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DoBIp7oe.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference--W01QhZ-.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-DmvwqGpT.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-BBJ4yAel.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/{MarkdownRenderer-BLCZMzhJ.js → MarkdownRenderer-GmB6DOr6.js} +1 -1
  39. package/src/assets/web-panel/assets/{Marketplace-D5lNngSI.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CkEVOMKH.js → McpTools-D7kGGbO7.js} +4 -4
  41. package/src/assets/web-panel/assets/{Memory-B1Ow1xVE.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-SgYbUfb6.js → MobileBridge-CtrR0Tas.js} +1 -1
  43. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
  44. package/src/assets/web-panel/assets/{Mtc-DcTXSSma.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-Dt3WG4oj.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-B9B38UZx.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-B0S4GGvG.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-DZ5U58Ng.js → Notes-BxMBFcIp.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-PjL5ZW34.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-DrAX2ESt.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-Cv1GYs-c.js → Organization-SQzIPdqC.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-Bbkp_PL3.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BD8QUgoZ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-BO-2PeaB.js → PdhVaultBrowser-BxPJZsD3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-D_OPVa02.js → Permissions-CLnDnPAz.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-mh-pEmaB.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-6JC2EDdb.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-CUshzUAG.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-Cs2Aalri.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-1ak49tcj.js → ProjectSettings-CxQkvl0k.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-CXXxvafH.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-PTcDsF58.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-CDwucrJw.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CJlLVRXR.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-DlN-ETsO.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-DI23LR6m.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-Cl7UQMrM.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-CexHNfh8.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-BneBWvRN.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-DX7Phgrp.js → Security-Mq2F9Nro.js} +4 -4
  72. package/src/assets/web-panel/assets/{Services-BWXO8Mte.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DCyOjKPJ.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-CXqERsTB.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-bhbrbz8E.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-3IPU0HBZ.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-DBNTQLbM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-quP0bkN-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-BouWmgho.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-qv0D9s7z.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-BxvbE8BB.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D-IeLnJ2.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-CFMKKyVG.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-L8as3UuJ.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-MxmA4VZG.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C0VvJYRi.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-Bf5QZj8N.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BIJ9riRz.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-B8p9Mhkw.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-BVsuaPen.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-BfkjoKpV.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DeAlsWK8.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-Cs97bz5j.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BqbG60LH.js → createContext-BRCSvYxj.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-i_RY0b1X.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BOVkf1K3.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B-3tEpTc.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D2B4VPyP.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BkBi5TmC.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-79V_zv1s.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-U4f5izHz.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DiSkx4UB.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-dIHr4B_u.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CIG8fQ2_.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DqBgBpgp.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-ZxO_-E8a.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DUUrv141.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bm7lLR4c.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-COdGA-8n.js → index-C5KAQFPQ.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CED2PL_y.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-YXgLng0K.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-0-agYlWL.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B5UkyA3c.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B1CbOH1i.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-s1opAL-M.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-yObj1O4n.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CgsqdnRV.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Dk7-v4hP.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B-JVTrpr.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CeWoNHau.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CE2VtTlp.js → index-D2GjI2oe.js} +1 -1
  124. package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
  125. package/src/assets/web-panel/assets/{index-DmbfhJUP.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BESLFt4q.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-PT_5sBMA.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-gyFpvL7l.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BYUVuwKt.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BcUXAB2s.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Dk2qouAz.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D9evtvg2.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BuLQobzW.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Cf3WCLmy.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CG3PRyAL.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-C9h9yKL3.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BvmLsPdu.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-CoL4ekU1.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-C4pMy6xV.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-DPuJfNxx.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-D0KEeaK2.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BpkyINxt.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DQI_wOq8.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DYfdDiRg.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-B5dtvb0D.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-CF310mSj.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-D1Qp4BLp.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-C7_iyvJK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-DZUt_fIm.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-D3dsi0lZ.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-WdbOlvdQ.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +6 -6
  154. package/src/commands/automation.js +103 -1
  155. package/src/commands/cowork.js +174 -19
  156. package/src/commands/permissions.js +240 -16
  157. package/src/commands/plugin.js +1293 -56
  158. package/src/commands/session-location.js +276 -0
  159. package/src/commands/session.js +2 -0
  160. package/src/commands/team-merge-review.js +937 -0
  161. package/src/commands/team.js +2 -0
  162. package/src/data/changelog.json +27 -1
  163. package/src/gateways/ws/action-protocol.js +35 -10
  164. package/src/gateways/ws/remote-session-protocol.js +24 -1
  165. package/src/gateways/ws/ws-agent-handler.js +12 -0
  166. package/src/gateways/ws/ws-server.js +48 -12
  167. package/src/harness/jsonl-session-store.js +341 -24
  168. package/src/harness/mcp-client.js +8 -1
  169. package/src/harness/remote-session-audit.js +1 -0
  170. package/src/harness/remote-session-crypto.js +210 -2
  171. package/src/harness/remote-session-registry.js +159 -6
  172. package/src/harness/session-list-index.js +233 -14
  173. package/src/lib/agent-authority.js +6 -0
  174. package/src/lib/agent-schedule-store.js +139 -28
  175. package/src/lib/agent-team/team-merge-review-store.js +765 -0
  176. package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
  177. package/src/lib/agent-team/team-merge-review.js +1847 -0
  178. package/src/lib/automation-center-incidents.js +314 -0
  179. package/src/lib/automation-center-runtime.js +448 -0
  180. package/src/lib/automation-center.js +182 -38
  181. package/src/lib/automation-engine.js +41 -0
  182. package/src/lib/automation-execution-authority.js +241 -12
  183. package/src/lib/automation-execution-incident.js +737 -0
  184. package/src/lib/background-agent-keeper-client.js +248 -0
  185. package/src/lib/background-agent-keeper-protocol.js +147 -0
  186. package/src/lib/background-agent-supervisor.js +520 -40
  187. package/src/lib/background-interaction-resolver.js +12 -0
  188. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  189. package/src/lib/cowork-cron.js +85 -14
  190. package/src/lib/cowork-workflow.js +336 -16
  191. package/src/lib/dynamic-workflow-facade.js +648 -0
  192. package/src/lib/execution-location-contract.js +551 -0
  193. package/src/lib/execution-location-runtime.js +130 -0
  194. package/src/lib/ide-context.js +94 -6
  195. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  196. package/src/lib/packer/pkg-config-generator.js +2 -0
  197. package/src/lib/permission-authority.js +77 -0
  198. package/src/lib/permission-side-effect-center.js +495 -0
  199. package/src/lib/plugin-runtime/install.js +514 -13
  200. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  201. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  202. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  203. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  204. package/src/lib/plugin-security.js +60 -3
  205. package/src/lib/process-execution-broker/index.js +1095 -57
  206. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  207. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  208. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  209. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  210. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  211. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  212. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  213. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  214. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  215. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  216. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  217. package/src/lib/public-ide-capability-manifest.js +3 -0
  218. package/src/lib/remote-approval-bridge.js +123 -17
  219. package/src/lib/remote-membership-authority.js +632 -0
  220. package/src/lib/remote-membership-coordinator.js +2409 -0
  221. package/src/lib/remote-membership-host-store.js +1750 -0
  222. package/src/lib/scheduler-kernel/agenda-adapter.js +17 -7
  223. package/src/lib/scheduler-kernel/automation-adapter.js +105 -11
  224. package/src/lib/scheduler-kernel/automation-event-adapter.js +87 -11
  225. package/src/lib/scheduler-kernel/contract.js +91 -0
  226. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +12 -1
  227. package/src/lib/scheduler-kernel/loop-adapter.js +7 -1
  228. package/src/lib/scheduler-kernel/routine-adapter.js +7 -1
  229. package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
  230. package/src/lib/scheduler-kernel/runtime.js +176 -3
  231. package/src/lib/scheduler-kernel/store.js +1253 -45
  232. package/src/lib/scoped-permission-store.js +369 -0
  233. package/src/lib/session-anti-rollback-anchor.js +262 -5
  234. package/src/lib/sub-agent-context.js +4 -0
  235. package/src/lib/workflow-definition-contract.js +149 -0
  236. package/src/repl/agent-repl.js +41 -7
  237. package/src/repl/chat-repl.js +2 -0
  238. package/src/repl/clipboard-image.js +735 -16
  239. package/src/repl/ide-status.js +1 -1
  240. package/src/repl/prompt-interactions.js +59 -6
  241. package/src/runtime/agent-core.js +93 -3
  242. package/src/runtime/headless-runner.js +30 -25
  243. package/src/runtime/headless-stream.js +32 -25
  244. package/src/runtime/mcp-config.js +81 -10
  245. package/src/workers/background-agent-keeper.js +498 -0
  246. package/src/workers/background-agent-worker.js +358 -13
  247. package/src/workers/background-turn-bootstrap.js +143 -0
  248. package/src/assets/web-panel/assets/MobileProjects-BWdOvQAj.js +0 -1
  249. package/src/assets/web-panel/assets/Projects-BV4oApsm.js +0 -1
  250. package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +0 -1
  251. package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +0 -1
  252. package/src/assets/web-panel/assets/index-ChVT0p9u.js +0 -1
@@ -70,6 +70,7 @@ import {
70
70
  import { createSessionPersistenceFailure } from "../lib/session-persistence-failure.js";
71
71
  import { withSessionHostWriteAuthority } from "../lib/session-host-lease.js";
72
72
  import { createSessionTranscriptStructureProjection } from "../lib/session-transcript-structure.js";
73
+ import { normalizeExecutionLocationBinding } from "../lib/execution-location-contract.js";
73
74
  import {
74
75
  listSessionAntiRollbackIds,
75
76
  publishSessionAntiRollbackAnchor,
@@ -90,11 +91,22 @@ export const _sessionScaleFaultHooks = Object.seal({
90
91
  beforeTranscriptDirectoryFsync: null,
91
92
  afterTranscriptDirectoryFsync: null,
92
93
  afterTranscriptAppend: null,
94
+ beforeTailRepairFsync: null,
95
+ afterTailRepairFsync: null,
93
96
  beforeVerifiedProjectionRepair: null,
94
97
  afterForkCopy: null,
98
+ beforeForkCopyFsync: null,
99
+ afterForkCopyFsync: null,
95
100
  afterForkLineage: null,
101
+ beforeForkLineageFsync: null,
102
+ afterForkLineageFsync: null,
96
103
  afterForkPublish: null,
104
+ beforeForkDirectoryFsync: null,
105
+ afterForkDirectoryFsync: null,
97
106
  afterForkMeta: null,
107
+ beforeDeleteDirectoryFsync: null,
108
+ afterDeleteDirectoryFsync: null,
109
+ afterAntiRollbackPublish: null,
98
110
  });
99
111
 
100
112
  export const WS_TURN_EVENT = "ws_turn";
@@ -575,6 +587,48 @@ function runSessionScaleFaultHook(name, payload) {
575
587
  if (typeof hook === "function") hook(payload);
576
588
  }
577
589
 
590
+ function fsyncRegularFilePath(filePath, payload, beforeHook, afterHook) {
591
+ runSessionScaleFaultHook(beforeHook, payload);
592
+ let descriptor = null;
593
+ try {
594
+ const flags = fsConstants.O_RDWR | Number(fsConstants.O_NOFOLLOW ?? 0);
595
+ descriptor = openSync(filePath, flags);
596
+ const stats = fstatSync(descriptor);
597
+ if (!stats.isFile()) {
598
+ throw new Error(`Session durability target is not a file: ${filePath}`);
599
+ }
600
+ fsyncSync(descriptor);
601
+ runSessionScaleFaultHook(afterHook, payload);
602
+ } finally {
603
+ if (descriptor !== null) closeSync(descriptor);
604
+ }
605
+ }
606
+
607
+ function fsyncParentDirectory(filePath, payload, beforeHook, afterHook) {
608
+ // Node does not expose a usable directory FlushFileBuffers handle on
609
+ // Windows. The file itself is still flushed before publication there.
610
+ if (process.platform === "win32") return;
611
+ runSessionScaleFaultHook(beforeHook, payload);
612
+ let descriptor = null;
613
+ try {
614
+ const flags =
615
+ fsConstants.O_RDONLY |
616
+ Number(fsConstants.O_DIRECTORY ?? 0) |
617
+ Number(fsConstants.O_NOFOLLOW ?? 0);
618
+ descriptor = openSync(dirname(filePath), flags);
619
+ const stats = fstatSync(descriptor);
620
+ if (!stats.isDirectory()) {
621
+ throw new Error(
622
+ `Session durability parent is not a directory: ${dirname(filePath)}`,
623
+ );
624
+ }
625
+ fsyncSync(descriptor);
626
+ runSessionScaleFaultHook(afterHook, payload);
627
+ } finally {
628
+ if (descriptor !== null) closeSync(descriptor);
629
+ }
630
+ }
631
+
578
632
  function getSessionsDir() {
579
633
  const dir = join(getHomeDir(), "sessions");
580
634
  let current = null;
@@ -740,7 +794,6 @@ function inspectPhysicalTail(filePath, { dryRun = false } = {}) {
740
794
  };
741
795
  if (!existsSync(filePath)) return result;
742
796
  const fd = openSync(filePath, "r+");
743
- let normalizeNewline = false;
744
797
  try {
745
798
  const size = fstatSync(fd).size;
746
799
  result.fileSize = size;
@@ -778,7 +831,15 @@ function inspectPhysicalTail(filePath, { dryRun = false } = {}) {
778
831
  // it and normalize before appending the next chained event.
779
832
  result.action = "normalize-newline";
780
833
  result.changed = true;
781
- normalizeNewline = !dryRun;
834
+ if (!dryRun) {
835
+ const newline = Buffer.from("\n", "utf8");
836
+ const written = writeSync(fd, newline, 0, newline.length, size);
837
+ if (written !== newline.length) {
838
+ throw new Error(
839
+ "Session transcript tail repair made no forward progress",
840
+ );
841
+ }
842
+ }
782
843
  } catch (error) {
783
844
  rethrowCanonicalJsonlRecordLimit(error);
784
845
  // Crash tail: discard only the one incomplete physical record.
@@ -790,12 +851,20 @@ function inspectPhysicalTail(filePath, { dryRun = false } = {}) {
790
851
  }
791
852
  }
792
853
  }
854
+ if (!dryRun && result.changed) {
855
+ const payload = Object.freeze({
856
+ filePath,
857
+ action: result.action,
858
+ discardedBytes: result.discardedBytes,
859
+ discardedRecords: result.discardedRecords,
860
+ });
861
+ runSessionScaleFaultHook("beforeTailRepairFsync", payload);
862
+ fsyncSync(fd);
863
+ runSessionScaleFaultHook("afterTailRepairFsync", payload);
864
+ }
793
865
  } finally {
794
866
  closeSync(fd);
795
867
  }
796
- if (normalizeNewline) {
797
- appendFileSync(filePath, "\n", { encoding: "utf8", mode: 0o600 });
798
- }
799
868
  if (!dryRun && result.changed) ensurePrivateFile(filePath);
800
869
  return result;
801
870
  }
@@ -904,6 +973,17 @@ function appendVerifiedWsAuthorityEventLocked(
904
973
  },
905
974
  );
906
975
  publishSessionAntiRollbackWitness(sessionId, nextMeta, filePath, "live");
976
+ runSessionScaleFaultHook(
977
+ "afterAntiRollbackPublish",
978
+ Object.freeze({
979
+ sessionId,
980
+ type,
981
+ event,
982
+ hash,
983
+ meta: nextMeta,
984
+ filePath,
985
+ }),
986
+ );
907
987
  } catch (cause) {
908
988
  const error = new Error(
909
989
  `Session authority anchor could not be persisted: ${sessionId}`,
@@ -1536,6 +1616,17 @@ function appendEventLocked(
1536
1616
  filePath,
1537
1617
  "live",
1538
1618
  );
1619
+ runSessionScaleFaultHook(
1620
+ "afterAntiRollbackPublish",
1621
+ Object.freeze({
1622
+ sessionId,
1623
+ type,
1624
+ event,
1625
+ hash,
1626
+ meta: nextMeta,
1627
+ filePath,
1628
+ }),
1629
+ );
1539
1630
  } catch (cause) {
1540
1631
  const error = new Error(
1541
1632
  `Session authority anchor could not be persisted: ${sessionId}`,
@@ -2205,13 +2296,21 @@ export function verifyAllSessions(options = {}) {
2205
2296
  .map((sessionId) => verifySession(sessionId));
2206
2297
  }
2207
2298
 
2208
- function indexedProjectionMatchesTranscript(meta, verification, validation) {
2299
+ function indexedProjectionMatchesTranscript(
2300
+ meta,
2301
+ verification,
2302
+ validation,
2303
+ transcriptState,
2304
+ ) {
2209
2305
  return (
2210
2306
  verification.status === TRANSCRIPT_CHAIN_STATUS.VERIFIED &&
2211
2307
  validation.valid === true &&
2212
2308
  meta?.deleted !== true &&
2213
2309
  Number(meta?.event_count) === validation.eventCount &&
2214
- (meta?.last_hash ?? null) === (verification.lastHash ?? null)
2310
+ (meta?.last_hash ?? null) === (verification.lastHash ?? null) &&
2311
+ meta?.transcript != null &&
2312
+ transcriptState != null &&
2313
+ samePhysicalTranscriptState(meta.transcript, transcriptState)
2215
2314
  );
2216
2315
  }
2217
2316
 
@@ -2263,6 +2362,10 @@ export function repairSession(sessionId, options = {}) {
2263
2362
  indexRepairRequired: false,
2264
2363
  indexRebuilt: false,
2265
2364
  indexRepairError: null,
2365
+ authorityAnchorRequired: false,
2366
+ authorityAnchored: false,
2367
+ authorityAnchorChanged: false,
2368
+ authorityAnchorError: null,
2266
2369
  discardedBytes: 0,
2267
2370
  discardedRecords: 0,
2268
2371
  healthy: false,
@@ -2288,6 +2391,9 @@ export function repairSession(sessionId, options = {}) {
2288
2391
  ? before.truncatedTail || repair.changed
2289
2392
  : after.truncatedTail) &&
2290
2393
  effectiveValidation.valid;
2394
+ const effectiveTranscriptState = transcriptHealthy
2395
+ ? readPhysicalTranscriptState(filePath)
2396
+ : null;
2291
2397
  const currentMeta = readSessionMeta(dir, sessionId);
2292
2398
  const currentActivity = readLatestSessionActivity(dir, sessionId);
2293
2399
  const indexRepairRequired =
@@ -2296,11 +2402,13 @@ export function repairSession(sessionId, options = {}) {
2296
2402
  currentMeta,
2297
2403
  effective,
2298
2404
  effectiveValidation,
2405
+ effectiveTranscriptState,
2299
2406
  ) ||
2300
2407
  !indexedProjectionMatchesTranscript(
2301
2408
  currentActivity,
2302
2409
  effective,
2303
2410
  effectiveValidation,
2411
+ effectiveTranscriptState,
2304
2412
  ));
2305
2413
  let indexRebuilt = false;
2306
2414
  let indexRepairError = null;
@@ -2315,25 +2423,64 @@ export function repairSession(sessionId, options = {}) {
2315
2423
  };
2316
2424
  }
2317
2425
  }
2426
+ const authorityAnchorRequired =
2427
+ transcriptHealthy &&
2428
+ effective.status === TRANSCRIPT_CHAIN_STATUS.VERIFIED;
2429
+ let authorityAnchored = !authorityAnchorRequired;
2430
+ let authorityAnchorChanged = false;
2431
+ let authorityAnchorError = null;
2432
+ if (
2433
+ !dryRun &&
2434
+ authorityAnchorRequired &&
2435
+ (!indexRepairRequired || indexRebuilt)
2436
+ ) {
2437
+ try {
2438
+ const anchorBefore = readSessionAntiRollbackAnchor(sessionId);
2439
+ assertVerifiedTranscriptAnchor(
2440
+ sessionId,
2441
+ effective,
2442
+ effectiveTranscriptState,
2443
+ );
2444
+ const anchorAfter = readSessionAntiRollbackAnchor(sessionId);
2445
+ authorityAnchored = true;
2446
+ authorityAnchorChanged =
2447
+ JSON.stringify(anchorBefore) !== JSON.stringify(anchorAfter);
2448
+ } catch (cause) {
2449
+ authorityAnchorError = {
2450
+ code: cause?.code || null,
2451
+ message: String(cause?.message || cause),
2452
+ };
2453
+ }
2454
+ }
2318
2455
  const healthy = dryRun
2319
2456
  ? transcriptHealthy && !repair.changed && !indexRepairRequired
2320
- : transcriptHealthy && (!indexRepairRequired || indexRebuilt);
2457
+ : transcriptHealthy &&
2458
+ (!indexRepairRequired || indexRebuilt) &&
2459
+ authorityAnchored;
2321
2460
  return {
2322
2461
  sessionId,
2323
2462
  dryRun,
2324
- changed: repair.changed || indexRebuilt,
2463
+ changed: repair.changed || indexRebuilt || authorityAnchorChanged,
2325
2464
  physicalChanged: repair.changed,
2326
2465
  indexChanged: indexRebuilt,
2327
2466
  wouldChange: dryRun && (repair.changed || indexRepairRequired),
2328
2467
  action:
2329
- repair.action === "none" && indexRepairRequired
2330
- ? "rebuild-index"
2331
- : repair.action,
2468
+ repair.action !== "none"
2469
+ ? repair.action
2470
+ : indexRepairRequired
2471
+ ? "rebuild-index"
2472
+ : authorityAnchorChanged
2473
+ ? "repair-anchor"
2474
+ : "none",
2332
2475
  physicalAction: repair.action,
2333
2476
  indexAction: indexRepairRequired ? "rebuild-index" : "none",
2334
2477
  indexRepairRequired,
2335
2478
  indexRebuilt,
2336
2479
  indexRepairError,
2480
+ authorityAnchorRequired,
2481
+ authorityAnchored,
2482
+ authorityAnchorChanged,
2483
+ authorityAnchorError,
2337
2484
  discardedBytes: repair.discardedBytes,
2338
2485
  discardedRecords: repair.discardedRecords,
2339
2486
  healthy,
@@ -2351,9 +2498,11 @@ export function repairSession(sessionId, options = {}) {
2351
2498
  "transcript remains structurally invalid"
2352
2499
  : indexRepairError
2353
2500
  ? `session metadata index rebuild failed: ${indexRepairError.message}`
2354
- : indexRepairRequired && dryRun
2355
- ? "session metadata index requires rebuild"
2356
- : null,
2501
+ : authorityAnchorError
2502
+ ? `session external authority anchor repair failed: ${authorityAnchorError.message}`
2503
+ : indexRepairRequired && dryRun
2504
+ ? "session metadata index requires rebuild"
2505
+ : null,
2357
2506
  };
2358
2507
  },
2359
2508
  { failIfUnavailable: true },
@@ -2464,11 +2613,59 @@ export function startSession(sessionId, meta = {}) {
2464
2613
  usageTelemetryVersion: 1,
2465
2614
  }
2466
2615
  : {}),
2616
+ ...(meta.executionLocation != null
2617
+ ? {
2618
+ executionLocation: normalizeExecutionLocationBinding(
2619
+ meta.executionLocation,
2620
+ ),
2621
+ }
2622
+ : {}),
2467
2623
  });
2468
2624
 
2469
2625
  return id;
2470
2626
  }
2471
2627
 
2628
+ /** Return the immutable execution-location facts anchored by session_start. */
2629
+ export function getVerifiedSessionExecutionLocationAuthority(sessionId) {
2630
+ return readVerifiedProjection(sessionId, () => {
2631
+ let sessionStartSeen = false;
2632
+ let hasExecutionLocation = false;
2633
+ let executionLocation = null;
2634
+ return {
2635
+ accept(event) {
2636
+ if (event?.type === "session_start" && !sessionStartSeen) {
2637
+ sessionStartSeen = true;
2638
+ if (Object.hasOwn(event.data || {}, "executionLocation")) {
2639
+ hasExecutionLocation = true;
2640
+ executionLocation = event.data.executionLocation;
2641
+ }
2642
+ }
2643
+ },
2644
+ finish(authority) {
2645
+ if (!authority.headHash || authority.eventCount <= 0) {
2646
+ throw unverifiedTranscriptError(sessionId, {
2647
+ status: "empty",
2648
+ reason: "session has no anchored transcript events",
2649
+ });
2650
+ }
2651
+ if (!hasExecutionLocation) {
2652
+ const error = new Error(
2653
+ `session ${sessionId} has no execution-location binding`,
2654
+ );
2655
+ error.code = "SESSION_EXECUTION_LOCATION_MISSING";
2656
+ throw error;
2657
+ }
2658
+ return Object.freeze({
2659
+ sessionId,
2660
+ headHash: authority.headHash,
2661
+ eventCount: authority.eventCount,
2662
+ binding: normalizeExecutionLocationBinding(executionLocation),
2663
+ });
2664
+ },
2665
+ };
2666
+ });
2667
+ }
2668
+
2472
2669
  /** Return the anchored transcript revision used by delivery causality bindings. */
2473
2670
  export function getVerifiedSessionObservabilityAuthority(sessionId) {
2474
2671
  return readVerifiedProjection(sessionId, () => {
@@ -3666,7 +3863,13 @@ export function renameSession(sessionId, title) {
3666
3863
  export function deleteJsonlSession(sessionId) {
3667
3864
  if (isUnsafeSessionId(sessionId)) return false;
3668
3865
  const filePath = sessionPath(sessionId);
3669
- if (!existsSync(filePath) && !hasLiveSessionWitness(sessionId)) return false;
3866
+ if (
3867
+ !existsSync(filePath) &&
3868
+ readSessionPersistenceWitness(sessionId)?.deleted !== true &&
3869
+ !hasLiveSessionWitness(sessionId)
3870
+ ) {
3871
+ return false;
3872
+ }
3670
3873
  return withSessionHostWriterLock(
3671
3874
  sessionId,
3672
3875
  filePath,
@@ -3675,10 +3878,32 @@ export function deleteJsonlSession(sessionId) {
3675
3878
  let existingMeta = readSessionPersistenceWitness(sessionId);
3676
3879
  const marker = readSessionTombstoneMarker(getSessionsDir(), sessionId);
3677
3880
  const externalAnchor = readSessionAntiRollbackAnchor(sessionId);
3678
- if (
3679
- !transcriptExists &&
3680
- (existingMeta === null || existingMeta?.deleted === true)
3681
- ) {
3881
+ if (!transcriptExists && existingMeta?.deleted === true) {
3882
+ // recordSessionDeleted publishes meta before the independent witness.
3883
+ // Re-emit the exact tombstone to settle its file/directory barriers,
3884
+ // then advance the external anchor before an interrupted delete retry
3885
+ // reports success.
3886
+ const timestamp =
3887
+ Math.max(
3888
+ 0,
3889
+ Number(existingMeta.deleted_at_ms) ||
3890
+ Number(existingMeta.updated_at_ms) ||
3891
+ Date.now(),
3892
+ ) || Date.now();
3893
+ const tombstone = recordSessionDeleted(
3894
+ getSessionsDir(),
3895
+ sessionId,
3896
+ timestamp,
3897
+ );
3898
+ publishSessionAntiRollbackWitness(
3899
+ sessionId,
3900
+ tombstone,
3901
+ filePath,
3902
+ "deleted",
3903
+ );
3904
+ return externalAnchor?.status !== "deleted";
3905
+ }
3906
+ if (!transcriptExists && existingMeta === null) {
3682
3907
  return false;
3683
3908
  }
3684
3909
  const deletionWitness =
@@ -3728,6 +3953,15 @@ export function deleteJsonlSession(sessionId) {
3728
3953
  });
3729
3954
  }
3730
3955
  if (transcriptExists) rmSync(filePath, { force: true });
3956
+ // The external tombstone is published only after the absent transcript
3957
+ // directory entry is durable. A retry after an interrupted unlink must
3958
+ // repeat this barrier even though the path is already absent in memory.
3959
+ fsyncParentDirectory(
3960
+ filePath,
3961
+ Object.freeze({ sessionId, filePath, operation: "delete" }),
3962
+ "beforeDeleteDirectoryFsync",
3963
+ "afterDeleteDirectoryFsync",
3964
+ );
3731
3965
  try {
3732
3966
  const tombstone = recordSessionDeleted(getSessionsDir(), sessionId);
3733
3967
  publishSessionAntiRollbackWitness(
@@ -3737,15 +3971,23 @@ export function deleteJsonlSession(sessionId) {
3737
3971
  "deleted",
3738
3972
  );
3739
3973
  } catch (error) {
3740
- // writeMetaAtomic precedes the activity-journal append. If only the
3741
- // rebuildable journal lock/release failed, the durable sidecar still
3742
- // prevents a stale writer from resurrecting this deleted session.
3974
+ // A complete anti-rollback record is readable before its fsync. If
3975
+ // rollback also fails, readback alone cannot prove durability. Only
3976
+ // swallow a post-meta failure after an exact replay has settled the
3977
+ // deleted record through the production persistence path.
3978
+ const tombstone = readSessionMeta(getSessionsDir(), sessionId);
3743
3979
  if (
3744
- readSessionMeta(getSessionsDir(), sessionId)?.deleted !== true ||
3980
+ tombstone?.deleted !== true ||
3745
3981
  readSessionAntiRollbackAnchor(sessionId)?.status !== "deleted"
3746
3982
  ) {
3747
3983
  throw error;
3748
3984
  }
3985
+ publishSessionAntiRollbackWitness(
3986
+ sessionId,
3987
+ tombstone,
3988
+ filePath,
3989
+ "deleted",
3990
+ );
3749
3991
  }
3750
3992
  return true;
3751
3993
  },
@@ -3943,6 +4185,17 @@ export function forkSession(sourceId, options = {}) {
3943
4185
  sessionId: newId,
3944
4186
  filePath: workingPath,
3945
4187
  });
4188
+ fsyncRegularFilePath(
4189
+ workingPath,
4190
+ Object.freeze({
4191
+ sourceId,
4192
+ sessionId: newId,
4193
+ filePath: workingPath,
4194
+ phase: "copy",
4195
+ }),
4196
+ "beforeForkCopyFsync",
4197
+ "afterForkCopyFsync",
4198
+ );
3946
4199
  } else {
3947
4200
  const prefix = compareFilePrefix(workingPath, sourcePath);
3948
4201
  if (prefix.matches && prefix.candidateSize < prefix.fullSize) {
@@ -3963,6 +4216,17 @@ export function forkSession(sourceId, options = {}) {
3963
4216
  sessionId: newId,
3964
4217
  filePath: workingPath,
3965
4218
  });
4219
+ fsyncRegularFilePath(
4220
+ workingPath,
4221
+ Object.freeze({
4222
+ sourceId,
4223
+ sessionId: newId,
4224
+ filePath: workingPath,
4225
+ phase: "copy",
4226
+ }),
4227
+ "beforeForkCopyFsync",
4228
+ "afterForkCopyFsync",
4229
+ );
3966
4230
  }
3967
4231
  }
3968
4232
 
@@ -4027,6 +4291,7 @@ export function forkSession(sourceId, options = {}) {
4027
4291
  target.verification.chainedEvents ===
4028
4292
  sourceVerification.chainedEvents;
4029
4293
 
4294
+ let lineageFsynced = false;
4030
4295
  if (exactSourceCopy) {
4031
4296
  if (targetMeta !== null) {
4032
4297
  throw unverifiedTranscriptError(newId, target.verification);
@@ -4079,6 +4344,19 @@ export function forkSession(sourceId, options = {}) {
4079
4344
  filePath: workingPath,
4080
4345
  event: lineageEvent,
4081
4346
  });
4347
+ fsyncRegularFilePath(
4348
+ workingPath,
4349
+ Object.freeze({
4350
+ sourceId,
4351
+ sessionId: newId,
4352
+ filePath: workingPath,
4353
+ phase: "lineage",
4354
+ event: lineageEvent,
4355
+ }),
4356
+ "beforeForkLineageFsync",
4357
+ "afterForkLineageFsync",
4358
+ );
4359
+ lineageFsynced = true;
4082
4360
  target = inspectTarget();
4083
4361
  targetMeta = readSessionMeta(sessionsDir, newId);
4084
4362
  }
@@ -4133,12 +4411,35 @@ export function forkSession(sourceId, options = {}) {
4133
4411
  throw unverifiedTranscriptError(newId, target.verification);
4134
4412
  }
4135
4413
 
4414
+ // A retry may inherit a complete lineage record from a process that
4415
+ // exited at the pre-fsync hook. Flush that exact verified candidate
4416
+ // before it can cross the rename/publication boundary.
4417
+ if (!lineageFsynced && targetMeta === null) {
4418
+ fsyncRegularFilePath(
4419
+ workingPath,
4420
+ Object.freeze({
4421
+ sourceId,
4422
+ sessionId: newId,
4423
+ filePath: workingPath,
4424
+ phase: "lineage-recovery",
4425
+ event: target.lineageEvent,
4426
+ }),
4427
+ "beforeForkLineageFsync",
4428
+ "afterForkLineageFsync",
4429
+ );
4430
+ lineageFsynced = true;
4431
+ }
4432
+
4136
4433
  const anchorMatchesTarget =
4137
4434
  targetMeta?.deleted !== true &&
4138
4435
  targetMeta?.last_hash === target.verification.lastHash &&
4139
4436
  Number(targetMeta?.event_count) ===
4140
4437
  target.verification.chainedEvents;
4141
4438
  if (anchorMatchesTarget) {
4439
+ // Meta publication precedes the independent machine-local witness.
4440
+ // A process can die in that exact window, so an idempotent fork
4441
+ // retry must settle the external anchor before reporting success.
4442
+ assertVerifiedTranscriptAnchor(newId, target.verification);
4142
4443
  const activity = readLatestSessionActivity(sessionsDir, newId);
4143
4444
  if (
4144
4445
  activity?.deleted === true ||
@@ -4199,6 +4500,22 @@ export function forkSession(sourceId, options = {}) {
4199
4500
  });
4200
4501
  }
4201
4502
 
4503
+ // The sidecar and anti-rollback witness below may only advance after
4504
+ // the final transcript directory entry is durable on POSIX. This is
4505
+ // also required on a retry that inherited the final path from a crash
4506
+ // immediately after rename.
4507
+ fsyncParentDirectory(
4508
+ filePath,
4509
+ Object.freeze({
4510
+ sourceId,
4511
+ sessionId: newId,
4512
+ filePath,
4513
+ operation: "fork-publish",
4514
+ }),
4515
+ "beforeForkDirectoryFsync",
4516
+ "afterForkDirectoryFsync",
4517
+ );
4518
+
4202
4519
  rebuildSessionMetaUnlocked(sessionsDir, newId, filePath);
4203
4520
  runSessionScaleFaultHook("afterForkMeta", {
4204
4521
  sourceId,
@@ -2541,10 +2541,17 @@ export class MCPClient extends EventEmitter {
2541
2541
  MCP_STDIO_CAPSULE_REQUIRED_BOUNDARIES.every((boundary) =>
2542
2542
  effectiveRuntimeSandboxBoundaries.has(boundary),
2543
2543
  );
2544
+ const capsuleUsesMacProcessTreeSandbox =
2545
+ Boolean(stdioCapsuleSandboxExecutionContract) &&
2546
+ process.platform === "darwin" &&
2547
+ MCP_STDIO_CAPSULE_REQUIRED_BOUNDARIES.every((boundary) =>
2548
+ effectiveRuntimeSandboxBoundaries.has(boundary),
2549
+ );
2544
2550
  const capsuleUsesPosixProcessGroup =
2545
2551
  Boolean(stdioCapsuleSandboxExecutionContract) &&
2546
2552
  process.platform !== "win32" &&
2547
- !capsuleUsesLinuxProcessTreeSandbox;
2553
+ !capsuleUsesLinuxProcessTreeSandbox &&
2554
+ !capsuleUsesMacProcessTreeSandbox;
2548
2555
  const launchOptions = {
2549
2556
  ...spawnOptions,
2550
2557
  detached:
@@ -16,6 +16,7 @@ export const REMOTE_SESSION_AUDIT_ACTIONS = Object.freeze([
16
16
  "device.joined",
17
17
  "device.revoked",
18
18
  "device.disconnected",
19
+ "membership.state-error",
19
20
  "session.closed",
20
21
  "control.prompt",
21
22
  "control.approval",