chainlesschain 0.164.0 → 0.165.2

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 (228) hide show
  1. package/README.md +248 -2
  2. package/package.json +7 -4
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-D2MEn7fI.js → AIOps-lS1R0Cza.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-lCW_4Gf0.js → ActionButton-BmlgBPsj.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-Bs7i-nsS.js → Analytics-CNKczv1S.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CK7B6S_j.js → AppLayout-BuZGJARQ.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-C8ILjpyo.js → Artifacts-Dm73Sl-O.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-Bb9cNaWc.js → Audit-BGMW7A5e.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-sC9ooXIf.js → BackgroundAgents-BQ6M54JR.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-D-DrsplT.js → Backup-DBzGP0bR.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-uCNZpwSK.js → BaseInput-D1mLCoOV.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-CsDK1uE9.js → Chat-BUfcN7p8.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-OqSDt50w.js → ChatBubbleRenderer-CY5m8ZHg.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-JhTXM1-K.js → Checkbox-Du0Yg5Pi.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-BbzZLnyD.js → Codegen-B2RXziHW.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-D4VW4m4j.js → Col-DWhekOrR.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-BXrYawxV.js → Community-HQhrkon4.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-DCihGy1u.js → Compact-izHNb4uz.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-DlyZ-lk8.js → Compliance-BDwLy41-.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DvGZrhbO.js → Cowork-DFJhLa7K.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-DUncZi8h.js → Cron-DYY9RG7-.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-C_hLuUcm.js → Crosschain-rr7tJTtv.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-b6YSUqxr.js → DID-D2sfHRLi.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-uvM15Cfb.js → Dashboard-q_eGdhha.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-D1-Nd4qY.js → Dropdown-Cufrh2Bz.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-8ApvL6Zc.js → EmailListRenderer-B-kdv10f.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-LYJt8811.js → FamilyGuardDashboard-D21XjgfG.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BbI3HGpv.js → Federation-CAwRTLZH.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-DSoEKuFu.js → FormItemContext-vx3daNDF.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-B0S9OWd5.js → GenericCardRenderer-CRWY2wU4.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-DIs9Zhf3.js → Git-Q6SwauyD.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-jzZXrxcl.js → Governance-BJ1q4IQZ.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-JUPjf2ZI.js → Inference-CSWjROgD.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-DxnfJvlP.js → KnowledgeGraph-fzuQsWuY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-iXiz8BEE.js → Logs-DVF8Mnns.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-Y3Xch312.js → Marketplace-BQP7LOA4.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-D7kGGbO7.js → McpTools-BNlJCmNc.js} +4 -4
  40. package/src/assets/web-panel/assets/{Memory-Do_hVxzh.js → Memory-DLLg5WQ4.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-CtrR0Tas.js → MobileBridge-CR2skNAF.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-BxVavObl.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-qo5QCTGd.js → Mtc-B17pgqMI.js} +4 -4
  44. package/src/assets/web-panel/assets/{MtcAudit-cq5mnjYj.js → MtcAudit-4UmV5cIL.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-Bq0MAQHw.js → Multisig-DoMEXEcU.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-DdWE6Vi2.js → NLProgramming-h9DMXFX4.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BxMBFcIp.js → Notes-Cihn-xX8.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-RTrAcbUe.js → NotificationSettings-BE6ZGa3R.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-DJbpGqzT.js → OrderTableRenderer-CnwojoSI.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-SQzIPdqC.js → Organization-B2vpwmjb.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-02yECh22.js → Overflow-C4z28R0-.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-BNg4pNCM.js → P2P-BVlFkwhW.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-BxPJZsD3.js → PdhVaultBrowser-BXbEdL5B.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-CLnDnPAz.js → Permissions-C28xs4lp.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-C5m0AjGf.js → PersonalDataHub-Dgl_rBjM.js} +4 -4
  56. package/src/assets/web-panel/assets/{Pipeline-VwOf5Dhv.js → Pipeline-3QUIhrKI.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-CC0W2hZd.js → Privacy-8Gh33OZ5.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-Dz893Bob.js → ProjectInit-BNmg4tZi.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-CxQkvl0k.js → ProjectSettings-vgMfeCf9.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-BhtAVilc.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-DeB9IkxK.js → Providers-CXoOa8eX.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-OCeoaswn.js → QrScannerModal-BhfTF0oS.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-DenotaAj.js → QuickAsk-C746HEAj.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-Cies_jjI.js → Recommend-BSej8Eo0.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-f3gmnlG3.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-CW0mvxgZ.js → Reputation-CyvybpkN.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-SEd32qZU.js → Row-DwV2PeYn.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-BSwnJ3Lm.js → RssFeed-11GrzjZy.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-xe2m8bkC.js → Search-BjKXkrAY.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-Mq2F9Nro.js → Security-eWiFb9Yk.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-BKGw2V3P.js → Services-CdCsMAtt.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DW95-Rxf.js → Skeleton-4Q2UTKQ5.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CHgChCv_.js → Skills-v4rtYrRj.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-tKh6k3R7.js → Sla-CRhsFvd_.js} +1 -1
  75. package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +1 -0
  76. package/src/assets/web-panel/assets/{SyncSettings-D0Fw8fVL.js → SyncSettings-D16zonl7.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-20x1GB3D.js → Tasks-Xxozz0i_.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-DJ-lts-a.js → Templates-CXJpPtCT.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-BFdGpbs7.js → Tenant-XRV0L1ZF.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-Xpx61vHL.js → Terminal-CYuO1i_w.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-C6UIvyZQ.js → TimelineRenderer-BXqitWsu.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-Dellq08f.js → Tokens-BvPrDHIy.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-VKw8d0J-.js → Trigger-DhCrSTf5.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-DNftdKT5.js → Trust-DmsuZD6K.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DX9VAKJI.js → UkeySign-D_yrts5C.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-B2h3jO8q.js → VideoEditing-B01ihPrm.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-CjGkof7f.js → Wallet-DpUjKa-N.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-2Zfcu55P.js → WebAuthn-CL07yON6.js} +4 -4
  89. package/src/assets/web-panel/assets/{WorkflowEditor-B9eZ8UxZ.js → WorkflowEditor-CLMflnRr.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-CQNfD-YO.js → chat-DtUqe8h_.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-D4usyFT2.js → colors-DPKrgVfy.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-s4TpjvjX.js → compact-item-BTt2GtOm.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-BRCSvYxj.js → createContext-D_VeUc1J.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-AdkUbkV-.js → hasIn-1kndiylj.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BIoG5yYf.js → index-2eyAXE3d.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-nXyk8GZ9.js → index-4bna2_SR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B2V-eKfK.js → index-8nz_fmlj.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D_XBHopw.js → index-B9KvcS7R.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-s_buFMEG.js → index-BAXfRKfG.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DZT36ZYq.js → index-BHpBMWCh.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BMcimU-2.js → index-BaZAbw9A.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DzRjHxEv.js → index-BepLZwgB.js} +1 -1
  104. package/src/assets/web-panel/assets/{index--00U6vXZ.js → index-Bhudc_Ez.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C7Y8Aluc.js → index-BlDNVgBt.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BtobShro.js → index-By5n8up9.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cvyt-zhm.js → index-CHG-KcS4.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CPcM-eqo.js +1 -0
  109. package/src/assets/web-panel/assets/{index-MMN9V6JF.js → index-CX81qSM4.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Bad4VNvz.js → index-CauoBQkH.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CCsM_Ybx.js → index-CcO04eDn.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DARsAyUp.js → index-CtF7EN49.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C5KAQFPQ.js → index-CzjkKUmR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-RfMr79MW.js → index-D95OFht7.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DdCB70SS.js → index-DFIZ_1Sf.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CYdoQsa1.js → index-DG2MZQ3f.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BPhkFZ1I.js → index-DJ8vXGOa.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-_IRVsV9X.js → index-Dbbymxpj.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DVKfQ0Ux.js → index-DdkplL9R.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CkwiSLhU.js → index-DfGl8CqG.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CJVEOa4i.js → index-DfKBRdSS.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C1mJtE6q.js → index-DsJCDUJG.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BgiXR_-_.js → index-Dwqmtk65.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CJCFe2Qf.js → index-DxdTdBix.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-C484EJiS.js → index-FzdwcSy2.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B4JJCfQ2.js → index-GsoUQ2M7.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CQhAVU5t.js → index-brCInrzq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CKC1t3Ic.js → index-dVc-CXY4.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BQ3DXBtD.js → index-fk2Rjacw.js} +3 -3
  130. package/src/assets/web-panel/assets/{index-Cduu2Hhr.js → index-l1BETrDb.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bw2MEnUk.js → index-m31Ka8hZ.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D2GjI2oe.js → index-ocf06EVQ.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CJdQrZth.js → index-sDoMHTNA.js} +1 -1
  134. package/src/assets/web-panel/assets/index-xeSyVoRe.js +1 -0
  135. package/src/assets/web-panel/assets/{initDefaultProps-Blmpk7HL.js → initDefaultProps-CvyYJd7z.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-DPBJMv1n.js → motion-DYZkhUdz.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-ButdzCM7.js → move-slnJRVT1.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-cyRC_QCe.js → mtc-parser-DVc0CKmy.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-1epSV7hz.js → omit-BCXAtHCq.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-DuPY8xJs.js → pickAttrs-DBsemz_K.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-6XZqarhe.js → placementArrow-BRtkJ-nv.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-B40pXBWM.js → responsiveObserve-Cebq7EZn.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-jbZ9Wu4n.js → slide-DT7qvId2.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-BKQQcVy4.js → statusUtils-pQiITLkG.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-NiKfWjUT.js → styleChecker-c-19BVKQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-bQUCvPeb.js → useFlexGapSupport-DsS5-0bE.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-CUGji7ph.js → useFs-CxGiMe5n.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-4veyN2N2.js → usePersonalDataHub-D9btVID5.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-1-nLug-Z.js → vnode-CUYFsFEN.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-dhCeRDMo.js → zoom-CXmn_35j.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +1 -1
  153. package/src/commands/cowork.js +559 -62
  154. package/src/commands/plugin.js +819 -64
  155. package/src/commands/session-location.js +318 -7
  156. package/src/constants.js +2 -2
  157. package/src/data/changelog.json +28 -2
  158. package/src/gateways/ws/action-protocol.js +293 -19
  159. package/src/gateways/ws/message-dispatcher.js +30 -0
  160. package/src/gateways/ws/remote-session-protocol.js +542 -35
  161. package/src/gateways/ws/ws-approval-gate.js +5 -0
  162. package/src/gateways/ws/ws-server.js +462 -38
  163. package/src/harness/jsonl-session-store.js +638 -2
  164. package/src/harness/prompt-compressor.js +4 -0
  165. package/src/harness/remote-session-audit.js +1 -0
  166. package/src/harness/remote-session-crypto.js +750 -50
  167. package/src/harness/remote-session-registry.js +795 -27
  168. package/src/lib/auto-mode-config.js +98 -3
  169. package/src/lib/background-agent-keeper-client.js +29 -0
  170. package/src/lib/background-agent-keeper-protocol.js +158 -10
  171. package/src/lib/background-agent-supervisor.js +870 -48
  172. package/src/lib/background-session-transport.js +23 -6
  173. package/src/lib/background-turn-bootstrap-protocol.js +64 -0
  174. package/src/lib/cowork-task-runner.js +70 -0
  175. package/src/lib/cowork-workflow.js +887 -62
  176. package/src/lib/delivery-production-adapter.js +38 -2
  177. package/src/lib/doctor-checkup.js +34 -10
  178. package/src/lib/dynamic-workflow-draft.js +535 -0
  179. package/src/lib/dynamic-workflow-facade.js +1105 -17
  180. package/src/lib/dynamic-workflow-runtime.js +2974 -0
  181. package/src/lib/execution-location-contract.js +111 -7
  182. package/src/lib/execution-location-runtime.js +3 -1
  183. package/src/lib/execution-location-target.js +910 -0
  184. package/src/lib/llm-providers.js +1 -0
  185. package/src/lib/mcp-call-ledger-store.js +35 -0
  186. package/src/lib/mcp-call-ledger.js +30 -0
  187. package/src/lib/mcp-stdio-package-materialization.js +1 -1
  188. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
  189. package/src/lib/plugin-runtime/install.js +4956 -657
  190. package/src/lib/plugin-runtime/manifest.js +3 -1
  191. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
  192. package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
  193. package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
  194. package/src/lib/plugin-runtime/marketplace-network.js +317 -0
  195. package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
  196. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
  197. package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
  198. package/src/lib/plugin-runtime/policy.js +21 -6
  199. package/src/lib/plugin-runtime/publisher-trust.js +332 -0
  200. package/src/lib/plugin-runtime/remote-source.js +323 -27
  201. package/src/lib/plugin-runtime/scopes.js +317 -41
  202. package/src/lib/plugin-runtime/transaction-journal.js +806 -0
  203. package/src/lib/public-ide-capability-manifest.js +1 -1
  204. package/src/lib/remote-approval-bridge.js +745 -108
  205. package/src/lib/remote-control.js +2 -0
  206. package/src/lib/remote-membership-coordinator.js +612 -46
  207. package/src/lib/remote-membership-host-store.js +59 -10
  208. package/src/lib/runtime-provenance-ledger.js +171 -46
  209. package/src/lib/shell-approval.js +169 -6
  210. package/src/lib/sub-agent-context.js +268 -2
  211. package/src/lib/task-model-selector.js +1 -1
  212. package/src/lib/with-file-lock.js +167 -42
  213. package/src/repl/agent-repl.js +70 -29
  214. package/src/repl/remote-approval.js +29 -7
  215. package/src/runtime/agent-core.js +1695 -194
  216. package/src/runtime/headless-runner.js +22 -5
  217. package/src/runtime/headless-stream.js +19 -3
  218. package/src/workers/background-agent-keeper.js +279 -58
  219. package/src/workers/background-agent-worker.js +7 -0
  220. package/src/workers/background-turn-bootstrap.js +29 -2
  221. package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +0 -1
  222. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +0 -1
  223. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +0 -1
  224. package/src/assets/web-panel/assets/RemoteSession-Dxzl5n2T.js +0 -5
  225. package/src/assets/web-panel/assets/SpeechSettings-D6UL3dA5.js +0 -1
  226. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +0 -1
  227. package/src/assets/web-panel/assets/index-C61cnl3K.js +0 -1
  228. package/src/assets/web-panel/assets/index-D4XFHxBr.js +0 -1
@@ -1460,6 +1460,8 @@ async function runAgentHeadlessInWorkspace(
1460
1460
  if (!hermeticExecution) {
1461
1461
  try {
1462
1462
  approvalGate = await getApprovalGate();
1463
+ approvalGate =
1464
+ approvalGate?.createSessionScope?.(sessionId) || approvalGate;
1463
1465
  if (approvalGate && (options.permissionMode || "default") === "auto") {
1464
1466
  // autoMode.decisions: user-configured riskLevel → allow/ask/deny
1465
1467
  // classifier. Only wrap when settings actually customize the map so the
@@ -1483,6 +1485,7 @@ async function runAgentHeadlessInWorkspace(
1483
1485
  }
1484
1486
  }
1485
1487
  if (approvalGate) {
1488
+ approvalGate.setAuthorizationConsumer?.(null);
1486
1489
  if (typeof approvalGate.setSessionPolicy === "function") {
1487
1490
  approvalGate.setSessionPolicy(sessionId, perm.sessionPolicy);
1488
1491
  }
@@ -1980,6 +1983,18 @@ async function runAgentHeadlessInWorkspace(
1980
1983
  !options.permissionPromptTool
1981
1984
  ) {
1982
1985
  try {
1986
+ if (
1987
+ !approvalGate ||
1988
+ typeof approvalGate.setConfirmer !== "function" ||
1989
+ typeof approvalGate.setAuthorizationConsumer !== "function" ||
1990
+ typeof approvalGate.consumeAuthorization !== "function"
1991
+ ) {
1992
+ const error = new Error(
1993
+ "installed session-core cannot bind and consume durable remote approval",
1994
+ );
1995
+ error.code = "CC_REMOTE_APPROVAL_GATE_UNAVAILABLE";
1996
+ throw error;
1997
+ }
1983
1998
  const { startHeadlessRemoteApproval } =
1984
1999
  await import("../lib/remote-approval-bridge.js");
1985
2000
  _remoteApproval = await (
@@ -1989,11 +2004,12 @@ async function runAgentHeadlessInWorkspace(
1989
2004
  writeErr,
1990
2005
  isText,
1991
2006
  });
1992
- if (approvalGate && typeof approvalGate.setConfirmer === "function") {
1993
- approvalGate.setConfirmer(
1994
- _bgPhase.wrapConfirmer(_remoteApproval.confirmer),
1995
- );
1996
- }
2007
+ approvalGate.setConfirmer(
2008
+ _bgPhase.wrapConfirmer(_remoteApproval.confirmer),
2009
+ );
2010
+ approvalGate.setAuthorizationConsumer(
2011
+ _remoteApproval.consumeAuthorization,
2012
+ );
1997
2013
  } catch (err) {
1998
2014
  // Remote approval could not come up → keep headless fail-closed rather
1999
2015
  // than running un-gated; say why so the user can fix pairing.
@@ -3274,6 +3290,7 @@ async function runAgentHeadlessInWorkspace(
3274
3290
  await cleanupDeadline.run("remote-approval", () =>
3275
3291
  _remoteApproval?.close?.(),
3276
3292
  );
3293
+ approvalGate?.setAuthorizationConsumer?.(null);
3277
3294
  // settings.json Stop + SessionEnd hooks when the run finishes. Stop is the
3278
3295
  // canonical async-hook trigger ("run the test suite at turn end"); fire its
3279
3296
  // async hooks fire-and-forget, then settle so a fast background check can
@@ -2059,6 +2059,8 @@ async function runAgentHeadlessStreamInWorkspace(
2059
2059
  let approvalGate = null;
2060
2060
  try {
2061
2061
  approvalGate = await getApprovalGate();
2062
+ approvalGate =
2063
+ approvalGate?.createSessionScope?.(sessionId) || approvalGate;
2062
2064
  if (approvalGate && (options.permissionMode || "default") === "auto") {
2063
2065
  // autoMode.decisions: user-configured riskLevel → allow/ask/deny
2064
2066
  // classifier (same wiring as headless-runner). Only wrap when settings
@@ -2082,6 +2084,7 @@ async function runAgentHeadlessStreamInWorkspace(
2082
2084
  }
2083
2085
  }
2084
2086
  if (approvalGate) {
2087
+ approvalGate.setAuthorizationConsumer?.(null);
2085
2088
  approvalGate.setSessionPolicy?.(sessionId, perm.sessionPolicy);
2086
2089
  approvalGate.setConfirmer?.(
2087
2090
  interactive && perm.allowInteractiveApprovals
@@ -2742,6 +2745,18 @@ async function runAgentHeadlessStreamInWorkspace(
2742
2745
  options.interactiveApprovals !== true
2743
2746
  ) {
2744
2747
  try {
2748
+ if (
2749
+ !approvalGate ||
2750
+ typeof approvalGate.setConfirmer !== "function" ||
2751
+ typeof approvalGate.setAuthorizationConsumer !== "function" ||
2752
+ typeof approvalGate.consumeAuthorization !== "function"
2753
+ ) {
2754
+ const error = new Error(
2755
+ "installed session-core cannot bind and consume durable remote approval",
2756
+ );
2757
+ error.code = "CC_REMOTE_APPROVAL_GATE_UNAVAILABLE";
2758
+ throw error;
2759
+ }
2745
2760
  const startRemoteApproval =
2746
2761
  deps.startHeadlessRemoteApproval ||
2747
2762
  (await import("../lib/remote-approval-bridge.js"))
@@ -2757,9 +2772,10 @@ async function runAgentHeadlessStreamInWorkspace(
2757
2772
  remote_session_id: _remoteApproval.pairing.remoteSessionId,
2758
2773
  expires_at: _remoteApproval.pairing.expiresAt,
2759
2774
  });
2760
- if (approvalGate && typeof approvalGate.setConfirmer === "function") {
2761
- approvalGate.setConfirmer(_remoteApproval.confirmer);
2762
- }
2775
+ approvalGate.setConfirmer(_remoteApproval.confirmer);
2776
+ approvalGate.setAuthorizationConsumer(
2777
+ _remoteApproval.consumeAuthorization,
2778
+ );
2763
2779
  } catch (err) {
2764
2780
  emit({
2765
2781
  type: "remote_control",
@@ -27,11 +27,15 @@ import {
27
27
  BACKGROUND_AGENT_KEEPER_ARMED,
28
28
  BACKGROUND_AGENT_KEEPER_CLEANUP_CONFIRM_TIMEOUT_MS,
29
29
  BACKGROUND_AGENT_KEEPER_HELLO,
30
+ BACKGROUND_AGENT_KEEPER_HEARTBEAT,
31
+ BACKGROUND_AGENT_KEEPER_HEARTBEAT_TIMEOUT_MS,
32
+ BACKGROUND_AGENT_KEEPER_PERSIST_RETRY_TIMEOUT_MS,
30
33
  BACKGROUND_AGENT_KEEPER_PROTOCOL_VERSION,
31
34
  BACKGROUND_AGENT_KEEPER_READY,
32
35
  BACKGROUND_AGENT_KEEPER_RETIRE,
33
36
  BACKGROUND_AGENT_KEEPER_RETIRED,
34
37
  BACKGROUND_AGENT_KEEPER_STATE_LOCK_TIMEOUT_MS,
38
+ cleanupBackgroundAgentKeeperPipeDirectory,
35
39
  createBackgroundAgentKeeperMessage,
36
40
  normalizeBackgroundAgentKeeperHello,
37
41
  normalizeBackgroundAgentKeeperTurn,
@@ -40,6 +44,50 @@ import {
40
44
 
41
45
  const STARTUP_TIMEOUT_MS = 30_000;
42
46
  const HEARTBEAT_INTERVAL_MS = 1_000;
47
+ const KEEPER_PERSIST_RETRY_DELAY_MS = 50;
48
+
49
+ function delay(ms) {
50
+ return new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
51
+ }
52
+
53
+ /**
54
+ * Retry a cleanup-critical state mutation after a worker is hard-killed.
55
+ *
56
+ * A worker can disappear while it owns the cross-process state lock. Windows
57
+ * may keep that terminated PID observable briefly, so the strict lock cannot
58
+ * immediately prove the owner dead and correctly fails closed. The keeper is
59
+ * the only remaining owner of the armed turn; it must wait for that transient
60
+ * fence instead of turning a lock exception into an unhandled rejection and
61
+ * exiting with the durable projection still `armed`.
62
+ */
63
+ export async function retryKeeperPersistence(operation, options = {}) {
64
+ const now = options.now || Date.now;
65
+ const sleep = options.sleep || delay;
66
+ const timeoutMs = Math.max(
67
+ 0,
68
+ Number(
69
+ options.timeoutMs ?? BACKGROUND_AGENT_KEEPER_PERSIST_RETRY_TIMEOUT_MS,
70
+ ),
71
+ );
72
+ const retryDelayMs = Math.max(
73
+ 1,
74
+ Number(options.retryDelayMs ?? KEEPER_PERSIST_RETRY_DELAY_MS),
75
+ );
76
+ const deadline = now() + timeoutMs;
77
+ let attempts = 0;
78
+ let error = null;
79
+ for (;;) {
80
+ attempts += 1;
81
+ try {
82
+ return { result: operation(), error: null, attempts };
83
+ } catch (cause) {
84
+ error = cause;
85
+ }
86
+ const remaining = deadline - now();
87
+ if (remaining <= 0) return { result: null, error, attempts };
88
+ await sleep(Math.min(retryDelayMs, remaining));
89
+ }
90
+ }
43
91
 
44
92
  function writeMessage(socket, message) {
45
93
  if (!socket || socket.destroyed) return false;
@@ -59,6 +107,71 @@ export function keeperWorkerIdentityAlive(
59
107
  return probe(Number(workerPid), Number(workerStartedAt));
60
108
  }
61
109
 
110
+ function reportKeeperPersistenceFailure(stage, error) {
111
+ try {
112
+ writeSync(
113
+ 2,
114
+ `[background-agent-keeper] ${stage} persistence failed: ${error?.stack || error?.message || String(error)}\n`,
115
+ );
116
+ } catch {
117
+ // The inherited diagnostic handle may already be closed.
118
+ }
119
+ }
120
+
121
+ export function runBackgroundAgentKeeperHeartbeat({
122
+ finishing,
123
+ workerSocket,
124
+ authenticatedHello,
125
+ authenticatedWorkerStartedAt,
126
+ workerHeartbeatAt,
127
+ armedTurn,
128
+ persistKeeper,
129
+ finishForWorkerDisconnect,
130
+ now = Date.now,
131
+ workerIdentityAlive = keeperWorkerIdentityAlive,
132
+ reportPersistenceFailure = reportKeeperPersistenceFailure,
133
+ }) {
134
+ if (finishing) return false;
135
+ const currentTime = now();
136
+ const workerHeartbeatExpired =
137
+ workerSocket &&
138
+ authenticatedHello &&
139
+ Number.isFinite(workerHeartbeatAt) &&
140
+ currentTime - workerHeartbeatAt >
141
+ BACKGROUND_AGENT_KEEPER_HEARTBEAT_TIMEOUT_MS;
142
+ if (
143
+ workerSocket &&
144
+ authenticatedHello &&
145
+ (workerHeartbeatExpired ||
146
+ (armedTurn &&
147
+ !workerIdentityAlive(
148
+ authenticatedHello.workerPid,
149
+ authenticatedWorkerStartedAt,
150
+ )))
151
+ ) {
152
+ // A Windows named-pipe handle and process object can remain observable
153
+ // after its worker dies if a platform helper retained a duplicate.
154
+ // Socket EOF and PID visibility are therefore not sufficient lifetime
155
+ // signals. The authenticated application heartbeat provides an
156
+ // independent bounded fence, while the PID/start anchor remains the
157
+ // immediate path on platforms that report death promptly.
158
+ finishForWorkerDisconnect();
159
+ workerSocket.destroy();
160
+ return false;
161
+ }
162
+ try {
163
+ persistKeeper({ keeperHeartbeatAt: currentTime });
164
+ return true;
165
+ } catch (error) {
166
+ try {
167
+ reportPersistenceFailure("heartbeat", error);
168
+ } catch {
169
+ // Diagnostics are best effort and must not escape the timer callback.
170
+ }
171
+ return false;
172
+ }
173
+ }
174
+
62
175
  function stateOwnsTurn(state, turn) {
63
176
  return Boolean(
64
177
  state &&
@@ -90,35 +203,77 @@ function persistKeeperTurn(job, turn, patch) {
90
203
  );
91
204
  }
92
205
 
206
+ export function stopBackgroundAgentKeeperTurnTrees(targets, options = {}) {
207
+ const platform = options.platform || process.platform;
208
+ const processAlive = options.isProcessAlive || isProcessAlive;
209
+ const processTreeExecutionAlive =
210
+ options.isProcessTreeExecutionAlive ||
211
+ isBackgroundProcessTreeExecutionAlive;
212
+ const stopTree = options.stopProcessTree || stopBackgroundAgentChildTree;
213
+ const failures = [];
214
+ let precedingTreeStopSucceeded = false;
215
+ for (const target of targets) {
216
+ // On Windows the wrapper's taskkill /T also retires its runtime child.
217
+ // Avoid starting a second bounded taskkill for a target the first tree
218
+ // operation already proved absent; under 20-way churn that redundant
219
+ // command can consume the keeper's entire cleanup SLO. Never skip the
220
+ // first root merely because its leader exited: POSIX descendants can keep
221
+ // executing in the leader's process group and still require a group kill.
222
+ if (precedingTreeStopSucceeded && !processAlive(target.pid)) continue;
223
+ try {
224
+ stopTree(target.pid, {
225
+ signal: "SIGKILL",
226
+ expectedStartedAt: target.startedAt,
227
+ processGroup: target.processGroup,
228
+ strictIdentity: true,
229
+ allowDirectFallback: false,
230
+ });
231
+ precedingTreeStopSucceeded = true;
232
+ } catch (error) {
233
+ // A detached POSIX group can keep executing after its leader exits. Do
234
+ // not discard the strict stop failure from a leader-only liveness probe;
235
+ // the group-aware residual check preserves the actionable identity
236
+ // reason while descendants remain executable.
237
+ const leaderAlive = processAlive(target.pid);
238
+ const residualAlive =
239
+ leaderAlive ||
240
+ (platform !== "win32" &&
241
+ target.processGroup === true &&
242
+ processTreeExecutionAlive(target.pid, target.startedAt));
243
+ if (residualAlive) {
244
+ failures.push(error?.message || String(error));
245
+ }
246
+ }
247
+ }
248
+ return failures;
249
+ }
250
+
93
251
  async function cleanupTurn(job, turn, reason) {
94
252
  const requestedAt = Date.now();
95
- persistKeeperTurn(job, turn, {
96
- turnKeeperStatus: "cleanup-requested",
97
- turnKeeperCleanupReason: reason,
98
- turnKeeperCleanupRequestedAt: requestedAt,
99
- });
253
+ const requestedPersistence = await retryKeeperPersistence(() =>
254
+ persistKeeperTurn(job, turn, {
255
+ turnKeeperStatus: "cleanup-requested",
256
+ turnKeeperCleanupReason: reason,
257
+ turnKeeperCleanupRequestedAt: requestedAt,
258
+ }),
259
+ );
100
260
 
101
261
  const targets = [
102
- { pid: turn.agentPid, startedAt: turn.agentStartedAt },
262
+ {
263
+ pid: turn.agentPid,
264
+ startedAt: turn.agentStartedAt,
265
+ processGroup: true,
266
+ },
103
267
  {
104
268
  pid: turn.agentRuntimePid,
105
269
  startedAt: turn.agentRuntimeStartedAt,
270
+ processGroup: false,
106
271
  },
107
272
  ].filter(
108
273
  (target, index, values) =>
109
274
  values.findIndex((candidate) => candidate.pid === target.pid) === index,
110
275
  );
111
- const failures = [];
112
- for (const target of targets) {
113
- try {
114
- stopBackgroundAgentChildTree(target.pid, { signal: "SIGKILL" });
115
- } catch (error) {
116
- // A preceding wrapper/group signal may already have retired this root.
117
- if (isProcessAlive(target.pid)) {
118
- failures.push(error?.message || String(error));
119
- }
120
- }
121
- }
276
+ const failures = stopBackgroundAgentKeeperTurnTrees(targets);
122
277
 
123
278
  const deadline =
124
279
  Date.now() + BACKGROUND_AGENT_KEEPER_CLEANUP_CONFIRM_TIMEOUT_MS;
@@ -132,19 +287,37 @@ async function cleanupTurn(job, turn, reason) {
132
287
  );
133
288
  }
134
289
  const confirmed = alive.length === 0 && failures.length === 0;
135
- persistKeeperTurn(job, turn, {
136
- turnKeeperStatus: confirmed ? "retired" : "cleanup-unconfirmed",
137
- turnKeeperCleanupReason: reason,
138
- turnKeeperCleanupRequestedAt: requestedAt,
139
- turnKeeperCleanupConfirmedAt: confirmed ? Date.now() : null,
140
- turnKeeperCleanupError:
141
- failures.length > 0
142
- ? failures.join("; ").slice(0, 1_000)
143
- : alive.length > 0
144
- ? `process tree still executable: ${alive.map(({ pid }) => pid).join(",")}`
145
- : null,
290
+ let finalPersistenceAttempts = 0;
291
+ const finalPersistence = await retryKeeperPersistence(() => {
292
+ finalPersistenceAttempts += 1;
293
+ return persistKeeperTurn(job, turn, {
294
+ turnKeeperStatus: confirmed ? "retired" : "cleanup-unconfirmed",
295
+ turnKeeperCleanupReason: reason,
296
+ turnKeeperCleanupRequestedAt: requestedAt,
297
+ turnKeeperCleanupConfirmedAt: confirmed ? Date.now() : null,
298
+ turnKeeperCleanupError:
299
+ failures.length > 0
300
+ ? failures.join("; ").slice(0, 1_000)
301
+ : alive.length > 0
302
+ ? `process tree still executable: ${alive.map(({ pid }) => pid).join(",")}`
303
+ : null,
304
+ turnKeeperPersistenceRetries:
305
+ Math.max(0, requestedPersistence.attempts - 1) +
306
+ Math.max(0, finalPersistenceAttempts - 1),
307
+ });
146
308
  });
147
- return { confirmed, failures, alive };
309
+ const persistenceError = finalPersistence.error
310
+ ? finalPersistence.error?.message || String(finalPersistence.error)
311
+ : finalPersistence.result?.applied === false
312
+ ? "keeper cleanup state no longer owned"
313
+ : null;
314
+ if (persistenceError) failures.push(persistenceError);
315
+ return {
316
+ confirmed: confirmed && !persistenceError,
317
+ failures,
318
+ alive,
319
+ persistenceError,
320
+ };
148
321
  }
149
322
 
150
323
  export async function runBackgroundAgentKeeper(jobFile, options = {}) {
@@ -182,6 +355,7 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
182
355
  let candidateSocket = null;
183
356
  let authenticatedHello = null;
184
357
  let authenticatedWorkerStartedAt = null;
358
+ let workerHeartbeatAt = null;
185
359
  let armedTurn = null;
186
360
  let finishing = false;
187
361
  let finishResolve;
@@ -206,17 +380,50 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
206
380
  if (finishing) return false;
207
381
  finishing = true;
208
382
  const active = armedTurn;
209
- void (
210
- active
211
- ? cleanupTurn(job, active, "worker-disconnected")
212
- : Promise.resolve({ confirmed: true })
213
- ).finally(() => {
214
- persistKeeper({
215
- keeperStatus: active ? "worker-disconnected" : "closed",
216
- keeperEndedAt: Date.now(),
217
- });
383
+ void (async () => {
384
+ let cleanup;
385
+ try {
386
+ cleanup = active
387
+ ? await cleanupTurn(job, active, "worker-disconnected")
388
+ : { confirmed: true, failures: [], alive: [] };
389
+ } catch (error) {
390
+ cleanup = {
391
+ confirmed: false,
392
+ failures: [error?.message || String(error)],
393
+ alive: [],
394
+ };
395
+ }
396
+ // Closing the keeper must never be skipped because one final metadata
397
+ // update throws. Retry the critical status write, retain the failure in
398
+ // the log, and always settle the server promise without an unhandled
399
+ // rejection.
400
+ const persisted = await retryKeeperPersistence(() =>
401
+ persistKeeper({
402
+ keeperStatus: active
403
+ ? cleanup.confirmed
404
+ ? "worker-disconnected"
405
+ : "cleanup-unconfirmed"
406
+ : "closed",
407
+ keeperEndedAt: Date.now(),
408
+ ...(cleanup.failures.length > 0
409
+ ? {
410
+ keeperError: cleanup.failures.join("; ").slice(0, 1_000),
411
+ }
412
+ : {}),
413
+ }),
414
+ );
415
+ if (persisted.error) {
416
+ try {
417
+ writeSync(
418
+ 2,
419
+ `[background-agent-keeper] final state persistence failed: ${persisted.error?.stack || persisted.error?.message || String(persisted.error)}\n`,
420
+ );
421
+ } catch {
422
+ // The inherited diagnostic handle may already be closed.
423
+ }
424
+ }
218
425
  server.close(() => finishResolve({ status: "closed" }));
219
- });
426
+ })();
220
427
  return true;
221
428
  };
222
429
 
@@ -267,6 +474,7 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
267
474
  authenticated = true;
268
475
  authenticatedHello = hello;
269
476
  authenticatedWorkerStartedAt = Number(current.startedAt);
477
+ workerHeartbeatAt = Date.now();
270
478
  workerSocket = socket;
271
479
  clearTimeout(helloTimer);
272
480
  persistKeeper({ keeperStatus: "ready", keeperReadyAt: Date.now() });
@@ -284,6 +492,20 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
284
492
  return;
285
493
  }
286
494
 
495
+ if (message.type === BACKGROUND_AGENT_KEEPER_HEARTBEAT) {
496
+ if (
497
+ message.id !== authenticatedHello.id ||
498
+ message.workerGeneration !==
499
+ authenticatedHello.workerGeneration ||
500
+ Number(message.workerPid) !== authenticatedHello.workerPid
501
+ ) {
502
+ socket.destroy();
503
+ return;
504
+ }
505
+ workerHeartbeatAt = Date.now();
506
+ return;
507
+ }
508
+
287
509
  if (
288
510
  message.type !== BACKGROUND_AGENT_KEEPER_ARM &&
289
511
  message.type !== BACKGROUND_AGENT_KEEPER_RETIRE
@@ -413,26 +635,20 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
413
635
  socket.once("error", disconnected);
414
636
  });
415
637
 
416
- const heartbeat = setInterval(() => {
417
- if (
418
- workerSocket &&
419
- authenticatedHello &&
420
- armedTurn &&
421
- !keeperWorkerIdentityAlive(
422
- authenticatedHello.workerPid,
638
+ const heartbeat = setInterval(
639
+ () =>
640
+ runBackgroundAgentKeeperHeartbeat({
641
+ finishing,
642
+ workerSocket,
643
+ authenticatedHello,
423
644
  authenticatedWorkerStartedAt,
424
- )
425
- ) {
426
- // A Windows named-pipe handle can remain open after its worker dies if a
427
- // platform helper retained a duplicate. Socket EOF alone is therefore
428
- // not a sufficient lifetime signal. The generation-bound worker PID and
429
- // its durable launch anchor provide an independent identity fence.
430
- finishForWorkerDisconnect();
431
- workerSocket.destroy();
432
- return;
433
- }
434
- persistKeeper({ keeperHeartbeatAt: Date.now() });
435
- }, HEARTBEAT_INTERVAL_MS);
645
+ workerHeartbeatAt,
646
+ armedTurn,
647
+ persistKeeper,
648
+ finishForWorkerDisconnect,
649
+ }),
650
+ HEARTBEAT_INTERVAL_MS,
651
+ );
436
652
  heartbeat.unref?.();
437
653
  const startupTimer = setTimeout(
438
654
  () => {
@@ -464,6 +680,11 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
464
680
  } catch {
465
681
  // Already removed or never materialized.
466
682
  }
683
+ try {
684
+ cleanupBackgroundAgentKeeperPipeDirectory(job.pipePath);
685
+ } catch {
686
+ // Another keeper can still own a sibling socket in the shared namespace.
687
+ }
467
688
  }
468
689
  return {
469
690
  ...result,
@@ -1472,6 +1472,13 @@ async function main() {
1472
1472
  },
1473
1473
  onStop: () => {
1474
1474
  if (!child) return;
1475
+ // An explicit stop owns this turn's termination. Detach the bootstrap
1476
+ // release callback before killing the child so a late IPC EPIPE cannot
1477
+ // reclassify the intentional stop as a post-spawn launch failure. The
1478
+ // child termination settlement remains attached and advances any
1479
+ // queued follow-up turn after the tree is confirmed closed.
1480
+ detachTurnBootstrapHandler?.();
1481
+ detachTurnBootstrapHandler = null;
1475
1482
  // The agent child is detached into its own group on POSIX; Windows
1476
1483
  // requires brokered taskkill /T /F so tool grandchildren cannot
1477
1484
  // survive an attached-session stop.
@@ -14,6 +14,7 @@ import {
14
14
  BACKGROUND_TURN_BOOTSTRAP_RELEASE,
15
15
  backgroundTurnBootstrapBindingFromEnvironment,
16
16
  clearBackgroundTurnBootstrapEnvironment,
17
+ containReleasedBackgroundTurnDisconnect,
17
18
  createBackgroundTurnBootstrapMessage,
18
19
  matchesBackgroundTurnBootstrapMessage,
19
20
  removeBackgroundTurnBootstrapImport,
@@ -31,12 +32,16 @@ function releaseTimeoutMs() {
31
32
  return Math.max(10, Math.min(TEST_RELEASE_TIMEOUT_MAX_MS, requested));
32
33
  }
33
34
 
34
- function failClosed(message) {
35
+ function reportFailure(message) {
35
36
  try {
36
37
  writeSync(2, `[background-turn-bootstrap] ${message}\n`);
37
38
  } catch {
38
39
  // The inherited diagnostic handle may already be closed.
39
40
  }
41
+ }
42
+
43
+ function failClosed(message) {
44
+ reportFailure(message);
40
45
  process.exit(1);
41
46
  }
42
47
 
@@ -68,6 +73,28 @@ await new Promise((resolve) => {
68
73
  failClosed(message);
69
74
  };
70
75
 
76
+ const containDisconnectOnce = (message) => {
77
+ if (failed) return;
78
+ failed = true;
79
+ if (timer) clearTimeout(timer);
80
+ if (readyTimer) clearInterval(readyTimer);
81
+ // Emit the original diagnostic before SIGSTOP freezes this process and
82
+ // every descendant in its detached POSIX group. If the stop fails (or a
83
+ // later SIGCONT lets the helper's fail-safe SIGKILL fail), retain the
84
+ // historical single-process fail-closed exit.
85
+ reportFailure(message);
86
+ if (
87
+ containReleasedBackgroundTurnDisconnect({
88
+ released,
89
+ currentPid: binding.pid,
90
+ onResumedKillFailure: () => process.exit(1),
91
+ })
92
+ ) {
93
+ return;
94
+ }
95
+ process.exit(1);
96
+ };
97
+
71
98
  const onMessage = (message) => {
72
99
  if (message?.type !== BACKGROUND_TURN_BOOTSTRAP_RELEASE) return;
73
100
  if (released) {
@@ -109,7 +136,7 @@ await new Promise((resolve) => {
109
136
  // supervising worker remains fail-closed even after the real CLI starts.
110
137
  process.on("message", onMessage);
111
138
  process.once("disconnect", () =>
112
- failOnce("worker IPC disconnected before turn completion"),
139
+ containDisconnectOnce("worker IPC disconnected before turn completion"),
113
140
  );
114
141
  timer = setTimeout(
115
142
  () => failOnce("timed out waiting for durable turn release"),
@@ -1 +0,0 @@
1
- import{P as c,J as p,b as s}from"./vendor-Bn1JzzAn.js";import{r as a}from"./markdown-Yo_c6Krv.js";import{_ as d}from"./index-BQ3DXBtD.js";const _={__name:"MarkdownRenderer",props:{content:{type:String,default:""}},setup(t,{expose:o}){o();const e=t,r=s(()=>a(e.content||"")),n={props:e,rendered:r,computed:s,get renderMarkdown(){return a}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}},i=["innerHTML"];function m(t,o,e,r,n,u){return c(),p("div",{class:"markdown-content",innerHTML:r.rendered},null,8,i)}const M=d(_,[["render",m],["__scopeId","data-v-0b0b9f63"],["__file","/tmp/cc-web-panel-J6U3Mt/repo/packages/web-panel/src/components/MarkdownRenderer.vue"]]);export{M};
@@ -1 +0,0 @@
1
- import{I as n,J as g,c as l,K as r,N as u,P as h,U as o,R as t,Q as b}from"./vendor-Bn1JzzAn.js";import{_ as v,b as m}from"./index-BQ3DXBtD.js";import{a8 as M,M as y}from"./icons-DG5UD-6K.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return y},get FolderOutlined(){return M}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",k,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",w,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),b(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),b(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const N=v(B,[["render",T],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-J6U3Mt/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};