chainlesschain 0.165.6 → 0.165.8

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 (238) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-B3gWmXjo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-G9pdT-0e.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-Ca30J7m2.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BtVTm8PU.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-BhViNa6u.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-DhKq-FnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-BL0SVbnE.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-BWkblnFi.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-ClaRNrF8.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-sZE2Z77o.js} +4 -4
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BAfKOnRe.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-Cvhay5WM.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-BpejL-4N.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-g2Ki6g_1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-D2xKbNo9.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-DbL1Pds3.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-DGtZCV4c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-4kQpoNsI.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BxTYXXAN.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-k0J0LT2N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-BaqhoPgN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-T4RVPIM1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-DszOToWq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-C9KJU7HF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-BI-_2xZX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DsnDEPsl.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-BLncAKKK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-BPQhGXDn.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-CyElbUQW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-CcSntBQD.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-CNEtr-wz.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Dd2notAJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DFaIhOfu.js → McpTools-BBsN2CSW.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-Dg2uTvwx.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-r1YMRiJV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-C-89kSm4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CrPZcVgf.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-sxi7hqJb.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-CAgOMfF1.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-DafaPts3.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-CJM-xUW_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-L0ZjfAh_.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-DeLtgAD8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CKC2b10z.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-eyf2rzY1.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-B8p3W6JK.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-BnRMxTq3.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-DjCNI1li.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-u6gXLbWT.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-BZAw4tkM.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-B1Tr72q7.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-DO7HFuBQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-BjCztyhj.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-ZWyCUbR1.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-DhDjeW4G.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-R_CN2MuU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-uxFcujeu.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-DX8D7rks.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-BYahQILD.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-CUSQ2tm-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-CnN_S8Cs.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-DcZlh-O4.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-ZhBOjzIX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D5Qnq_lI.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BC9cZ3Be.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-DauJ3E8_.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-DUvJbSct.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BXa-5noQ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-JxaiUt_3.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-BW4ERQN8.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-DltUbdtv.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-D_VEV60K.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-CCXTCs0R.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-lkGRIPcG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-BfGeQ9HX.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-BEC7pYvc.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-BZdG24o0.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-yoEddedp.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-BXZEprOW.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-gg0bzZal.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-DjRVRuin.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-su-dieAc.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-Ci3S8oKF.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-D8F10heH.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-11wtYQiF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-1IgxgALJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-1agckWSq.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-5JqhujnR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-6Tniqk1s.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-8Z-8BIlN.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-BCI5v0yB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-BDJntYmJ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-BGzixOGZ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-BMMOVoLD.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-BTFpdBtt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-Ba_HyPnE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-BbF1IHof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-BgT9su_e.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BzPB6kGZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-C6ygzplr.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-CC3ZDjzY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-CEmXRhAE.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CJGOlduY.js +1 -0
  113. package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CMPqd5Cv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-COWd8uGx.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-CPIYSp4H.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-CR0h6seT.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-CUmDhC4j.js} +1 -1
  118. package/src/assets/web-panel/assets/index-CkBCN5yH.js +1 -0
  119. package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-CusgZPtc.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-DBAETXft.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-DIJ2qFOC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-Dbq4NMET.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-DkMEF5VT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-DkfQR3hM.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-DnLucOn9.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-DugB_aKa.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Bissefox.js → index-DyLUarhZ.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-T6_6ygJZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-Tu8eWqh-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-W7XUgdVL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-dHZinfko.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-jyNgp5FI.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-Cv4p8e4w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-B8EwmMOw.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-B8R9F8TK.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-DoFYz5Bp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-CHWYLBjI.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-CXuPDO77.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-BaAtUUon.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-DCc4zcDD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-B_lx89oZ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-DE8DPmR0.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-1ktXOsL_.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-xH89-wjh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-DscvfW5p.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-RdMKQta7.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-Z3wTni2T.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-B0iChCsm.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +3 -3
  151. package/src/commands/agent.js +91 -60
  152. package/src/commands/git.js +39 -0
  153. package/src/commands/plugin.js +17 -2
  154. package/src/commands/session-group.js +131 -0
  155. package/src/commands/session-location.js +48 -0
  156. package/src/commands/session.js +11 -0
  157. package/src/commands/sync-providers.js +4 -1
  158. package/src/commands/update.js +1 -0
  159. package/src/data/changelog.json +27 -1
  160. package/src/gateways/ws/ws-agent-handler.js +20 -12
  161. package/src/harness/jsonl-session-store.js +279 -37
  162. package/src/harness/mcp-client.js +701 -91
  163. package/src/harness/session-index.js +15 -4
  164. package/src/lib/agent-worktree.js +8 -1
  165. package/src/lib/auto-mode-safety-classifier.js +3 -17
  166. package/src/lib/background-agent-keeper-protocol.js +26 -6
  167. package/src/lib/background-agent-supervisor.js +17 -1
  168. package/src/lib/browser-evidence.js +1405 -0
  169. package/src/lib/chrome-connector.js +465 -79
  170. package/src/lib/claude-project-auto-memory.js +481 -0
  171. package/src/lib/claude-project-storage-layout.js +104 -0
  172. package/src/lib/cloud/cloud-client.js +40 -0
  173. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  174. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  175. package/src/lib/execution-location-target-preflight.js +333 -0
  176. package/src/lib/execution-location-target.js +783 -13
  177. package/src/lib/file-lines.js +6 -1
  178. package/src/lib/gateway-client-resilience.js +571 -0
  179. package/src/lib/gitlab-mr-worktree.js +176 -0
  180. package/src/lib/hooks-v2-producers.js +119 -15
  181. package/src/lib/hooks-v2-workspace-context.js +44 -1
  182. package/src/lib/host-resource-budget.js +295 -0
  183. package/src/lib/ide-context.js +15 -2
  184. package/src/lib/llm-config-defaults.js +43 -0
  185. package/src/lib/mcp-lifecycle-authority.js +887 -0
  186. package/src/lib/mcp-oauth.js +101 -20
  187. package/src/lib/mcp-tls.js +103 -3
  188. package/src/lib/paths.js +260 -32
  189. package/src/lib/permission-request.js +48 -0
  190. package/src/lib/plugin-runtime/bin.js +3 -1
  191. package/src/lib/plugin-runtime/hooks.js +3 -1
  192. package/src/lib/plugin-runtime/install.js +117 -1
  193. package/src/lib/plugin-runtime/lsp.js +4 -4
  194. package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
  195. package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
  196. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  197. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  198. package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
  199. package/src/lib/plugin-runtime/mcp.js +3 -1
  200. package/src/lib/plugin-runtime/monitors.js +3 -1
  201. package/src/lib/plugin-runtime/remote-source.js +151 -6
  202. package/src/lib/plugin-runtime/settings.js +3 -1
  203. package/src/lib/plugin-runtime/trust.js +274 -13
  204. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  205. package/src/lib/process-execution-broker/index.js +15 -1
  206. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  207. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  208. package/src/lib/project-mcp-trust.js +165 -10
  209. package/src/lib/resume-session.js +9 -6
  210. package/src/lib/session-core-singletons.js +26 -11
  211. package/src/lib/session-host-lease.js +52 -16
  212. package/src/lib/session-lifecycle-scope.js +153 -0
  213. package/src/lib/session-message-fabric.js +168 -21
  214. package/src/lib/session-projection.js +244 -4
  215. package/src/lib/session-store-guard.js +3 -1
  216. package/src/lib/session-workbench-store.js +466 -0
  217. package/src/lib/spellcheck.js +211 -0
  218. package/src/lib/sub-agent-context.js +9 -9
  219. package/src/lib/sync-cli-db.js +485 -129
  220. package/src/lib/sync-credentials.js +31 -20
  221. package/src/lib/web-fetch.js +112 -40
  222. package/src/lib/web-search.js +127 -61
  223. package/src/lib/workspace-trust.js +793 -0
  224. package/src/repl/agent-repl.js +124 -5
  225. package/src/repl/permission-prompt.js +10 -12
  226. package/src/runtime/agent-core.js +311 -18
  227. package/src/runtime/bootstrap.js +37 -13
  228. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  229. package/src/runtime/headless-runner.js +234 -36
  230. package/src/runtime/headless-stream.js +181 -6
  231. package/src/runtime/mcp-config.js +298 -8
  232. package/src/runtime/policies/agent-policy.js +8 -0
  233. package/src/runtime/status-diagnostics-lite.js +9 -1
  234. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
  235. package/src/assets/web-panel/assets/SpeechSettings-BHUI7cox.js +0 -1
  236. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
  237. package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
  238. package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
@@ -0,0 +1,481 @@
1
+ /**
2
+ * Project-scoped Claude-compatible automatic memory.
3
+ *
4
+ * The project directory name is only a launcher-selected storage bucket. A
5
+ * durable binding to the canonical repository/directory identity prevents a
6
+ * reused bucket from silently inheriting memory from an unrelated workspace.
7
+ * Linked Git worktrees intentionally share the common repository identity.
8
+ */
9
+
10
+ import {
11
+ existsSync,
12
+ lstatSync,
13
+ readdirSync,
14
+ readFileSync,
15
+ realpathSync,
16
+ writeFileSync,
17
+ } from "node:fs";
18
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
19
+ import {
20
+ CLAUDE_CONFIG_DIR_ENV,
21
+ resolveClaudeProjectStorageDir,
22
+ } from "./claude-project-storage-layout.js";
23
+ import {
24
+ assertSafeConfigDataRoot,
25
+ ensureClaudeProjectStorageTree,
26
+ resolveConfigDataRoot,
27
+ } from "./paths.js";
28
+ import {
29
+ ensurePrivateDirectory,
30
+ ensurePrivateFile,
31
+ repairPrivatePaths,
32
+ } from "./secure-fs.js";
33
+ import { resolveCanonicalWorkspaceRepoIdentity } from "./workspace-trust.js";
34
+
35
+ export const CLAUDE_AUTO_MEMORY_BINDING_SCHEMA =
36
+ "chainlesschain.claude-project-auto-memory-binding/v1";
37
+ export const CLAUDE_AUTO_MEMORY_BINDING_FILE =
38
+ ".chainlesschain-auto-memory-binding-v1.json";
39
+ export const CLAUDE_AUTO_MEMORY_MAX_SETTINGS_BYTES = 256 * 1024;
40
+ export const CLAUDE_AUTO_MEMORY_MAX_BINDING_BYTES = 4096;
41
+ export const CLAUDE_AUTO_MEMORY_MAX_EXISTING_FILES = 512;
42
+
43
+ const LAUNCH_ENV_KEYS = Object.freeze([
44
+ "CHAINLESSCHAIN_HOME",
45
+ CLAUDE_CONFIG_DIR_ENV,
46
+ "CLAUDE_CODE_PROJECT_DIR_NAME",
47
+ "CLAUDE_CODE_DISABLE_AUTO_MEMORY",
48
+ "CC_MANAGED_SETTINGS",
49
+ // Managed settings default path is derived from these trusted launcher
50
+ // values on Windows; include them so a project settings env map cannot
51
+ // redirect that authority after the snapshot.
52
+ "ProgramData",
53
+ "PROGRAMDATA",
54
+ ]);
55
+
56
+ function autoMemoryError(code, message) {
57
+ const error = new Error(message);
58
+ error.code = code;
59
+ return error;
60
+ }
61
+
62
+ function owns(object, key) {
63
+ return Object.prototype.hasOwnProperty.call(object, key);
64
+ }
65
+
66
+ function pathContains(parent, candidate) {
67
+ const relation = relative(parent, candidate);
68
+ return (
69
+ relation === "" ||
70
+ (relation !== ".." &&
71
+ !relation.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) &&
72
+ !isAbsolute(relation))
73
+ );
74
+ }
75
+
76
+ function isDeviceNamespace(value) {
77
+ const windows = String(value).replaceAll("/", "\\");
78
+ return windows.startsWith("\\\\?\\") || windows.startsWith("\\\\.\\");
79
+ }
80
+
81
+ function boundedObjectFromFile(filePath, maximumBytes) {
82
+ try {
83
+ const entry = lstatSync(filePath);
84
+ if (
85
+ entry.isSymbolicLink() ||
86
+ !entry.isFile() ||
87
+ entry.size < 1 ||
88
+ entry.size > maximumBytes
89
+ ) {
90
+ return null;
91
+ }
92
+ const text = readFileSync(filePath, "utf8");
93
+ if (Buffer.byteLength(text, "utf8") > maximumBytes) return null;
94
+ const parsed = JSON.parse(text);
95
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
96
+ ? parsed
97
+ : null;
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+
103
+ function configuredAutoMemoryDirectory(settings) {
104
+ if (!settings || typeof settings !== "object") {
105
+ return { defined: false, value: null };
106
+ }
107
+ const candidates = [
108
+ settings.autoMemoryDirectory,
109
+ settings.autoMemory?.directory,
110
+ settings.memory?.autoMemoryDirectory,
111
+ ];
112
+ for (const value of candidates) {
113
+ if (value === undefined) continue;
114
+ return {
115
+ defined: true,
116
+ value: typeof value === "string" ? value.trim() : null,
117
+ };
118
+ }
119
+ return { defined: false, value: null };
120
+ }
121
+
122
+ function defaultManagedSettingsPath(env) {
123
+ if (env.CC_MANAGED_SETTINGS) return env.CC_MANAGED_SETTINGS;
124
+ if (process.platform === "win32") {
125
+ const base = env.ProgramData || env.PROGRAMDATA || "C:\\ProgramData";
126
+ return join(base, "ChainlessChain", "managed-settings.json");
127
+ }
128
+ return "/etc/chainlesschain/managed-settings.json";
129
+ }
130
+
131
+ function isTrustedSettingsLocation(filePath, workspaceRoot) {
132
+ if (typeof filePath !== "string" || !filePath || !isAbsolute(filePath)) {
133
+ return false;
134
+ }
135
+ if (isDeviceNamespace(filePath)) return false;
136
+ try {
137
+ return !pathContains(resolve(workspaceRoot), resolve(filePath));
138
+ } catch {
139
+ return false;
140
+ }
141
+ }
142
+
143
+ function resolveTrustedDirectorySetting({ configRoot, workspaceRoot, env }) {
144
+ const userFile = join(configRoot, "settings.json");
145
+ const managedFile = defaultManagedSettingsPath(env);
146
+ const sources = [
147
+ { source: "user", file: userFile },
148
+ { source: "managed", file: managedFile },
149
+ ];
150
+ let selected = null;
151
+ for (const candidate of sources) {
152
+ if (!isTrustedSettingsLocation(candidate.file, workspaceRoot)) continue;
153
+ const setting = configuredAutoMemoryDirectory(
154
+ boundedObjectFromFile(
155
+ candidate.file,
156
+ CLAUDE_AUTO_MEMORY_MAX_SETTINGS_BYTES,
157
+ ),
158
+ );
159
+ if (!setting.defined) continue;
160
+ // Managed settings are deliberately last/highest precedence.
161
+ selected = { ...setting, source: candidate.source };
162
+ }
163
+ return selected;
164
+ }
165
+
166
+ function resolveCustomMemoryDirectory(value, workspaceRoot, options = {}) {
167
+ if (
168
+ typeof value !== "string" ||
169
+ !value ||
170
+ value.includes("\0") ||
171
+ isDeviceNamespace(value) ||
172
+ !isAbsolute(value)
173
+ ) {
174
+ throw autoMemoryError(
175
+ "CC_AUTO_MEMORY_DIRECTORY_INVALID",
176
+ "autoMemoryDirectory is not a safe absolute owner-only directory",
177
+ );
178
+ }
179
+ const candidate = resolve(value);
180
+ if (pathContains(resolve(workspaceRoot), candidate)) {
181
+ throw autoMemoryError(
182
+ "CC_AUTO_MEMORY_DIRECTORY_INVALID",
183
+ "autoMemoryDirectory must not be inside the workspace",
184
+ );
185
+ }
186
+ try {
187
+ assertSafeConfigDataRoot(candidate, { env: options.env });
188
+ ensurePrivateDirectory(candidate, {
189
+ // Do not assume inherited ACLs are safe: an existing custom directory
190
+ // can retain a broad explicit ACE even below a protected config root.
191
+ applyWindowsAcl: true,
192
+ failIfUnavailable: true,
193
+ });
194
+ const dailyDir = join(candidate, "daily");
195
+ if (process.platform === "win32") {
196
+ ensurePrivateDirectory(dailyDir, {
197
+ applyWindowsAcl: false,
198
+ failIfUnavailable: true,
199
+ });
200
+ repairPrivatePaths([dailyDir], { platform: "win32" });
201
+ } else {
202
+ ensurePrivateDirectory(dailyDir, { failIfUnavailable: true });
203
+ }
204
+ const canonical = realpathSync.native
205
+ ? realpathSync.native(candidate)
206
+ : realpathSync(candidate);
207
+ if (pathContains(resolve(workspaceRoot), canonical)) {
208
+ throw autoMemoryError(
209
+ "CC_AUTO_MEMORY_DIRECTORY_INVALID",
210
+ "autoMemoryDirectory must not resolve inside the workspace",
211
+ );
212
+ }
213
+ return canonical;
214
+ } catch (error) {
215
+ if (error?.code === "CC_AUTO_MEMORY_DIRECTORY_INVALID") throw error;
216
+ throw autoMemoryError(
217
+ "CC_AUTO_MEMORY_DIRECTORY_INVALID",
218
+ "autoMemoryDirectory could not be secured",
219
+ );
220
+ }
221
+ }
222
+
223
+ function ensureClaudeProjectConfigRoot(configRoot) {
224
+ try {
225
+ ensurePrivateDirectory(configRoot, {
226
+ applyWindowsAcl: true,
227
+ failIfUnavailable: true,
228
+ });
229
+ } catch {
230
+ throw autoMemoryError(
231
+ "CC_AUTO_MEMORY_STORAGE_UNAVAILABLE",
232
+ "project automatic memory storage could not be secured",
233
+ );
234
+ }
235
+ }
236
+
237
+ function readBinding(bindingPath) {
238
+ try {
239
+ ensurePrivateFile(bindingPath, {
240
+ // Existing binding files can retain explicit broad ACLs even if their
241
+ // parent is protected. Verify/repair the file itself before trusting it.
242
+ applyWindowsAcl: true,
243
+ failIfUnavailable: true,
244
+ });
245
+ } catch {
246
+ throw autoMemoryError(
247
+ "CC_AUTO_MEMORY_BINDING_INVALID",
248
+ "project automatic memory binding is unavailable",
249
+ );
250
+ }
251
+ const binding = boundedObjectFromFile(
252
+ bindingPath,
253
+ CLAUDE_AUTO_MEMORY_MAX_BINDING_BYTES,
254
+ );
255
+ if (
256
+ !binding ||
257
+ Object.keys(binding).length !== 2 ||
258
+ binding.schema !== CLAUDE_AUTO_MEMORY_BINDING_SCHEMA ||
259
+ !/^[a-f0-9]{64}$/u.test(binding.repositoryId || "")
260
+ ) {
261
+ throw autoMemoryError(
262
+ "CC_AUTO_MEMORY_BINDING_INVALID",
263
+ "project automatic memory binding is invalid",
264
+ );
265
+ }
266
+ return binding;
267
+ }
268
+
269
+ function bindMemoryDirectory(memoryDirectory, repositoryId) {
270
+ const bindingPath = join(memoryDirectory, CLAUDE_AUTO_MEMORY_BINDING_FILE);
271
+ if (existsSync(bindingPath)) {
272
+ const binding = readBinding(bindingPath);
273
+ if (binding.repositoryId !== repositoryId) {
274
+ throw autoMemoryError(
275
+ "CC_AUTO_MEMORY_IDENTITY_MISMATCH",
276
+ "project automatic memory belongs to another workspace",
277
+ );
278
+ }
279
+ return;
280
+ }
281
+
282
+ const serialized = `${JSON.stringify({
283
+ schema: CLAUDE_AUTO_MEMORY_BINDING_SCHEMA,
284
+ repositoryId,
285
+ })}\n`;
286
+ try {
287
+ writeFileSync(bindingPath, serialized, {
288
+ encoding: "utf8",
289
+ mode: 0o600,
290
+ flag: "wx",
291
+ });
292
+ } catch (error) {
293
+ if (error?.code !== "EEXIST") {
294
+ throw autoMemoryError(
295
+ "CC_AUTO_MEMORY_BINDING_INVALID",
296
+ "project automatic memory binding could not be created",
297
+ );
298
+ }
299
+ }
300
+ const binding = readBinding(bindingPath);
301
+ if (binding.repositoryId !== repositoryId) {
302
+ throw autoMemoryError(
303
+ "CC_AUTO_MEMORY_IDENTITY_MISMATCH",
304
+ "project automatic memory belongs to another workspace",
305
+ );
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Existing memory files may predate the protected directory tree and carry a
311
+ * broad explicit ACL of their own. Repair every bounded, content-bearing file
312
+ * before CLIPermanentMemory can read it; an unexpectedly large tree fails
313
+ * closed instead of turning startup into an unbounded ACL walk.
314
+ */
315
+ function secureExistingAutomaticMemoryFiles(memoryDirectory) {
316
+ const candidates = [join(memoryDirectory, "MEMORY.md")];
317
+ const dailyDirectory = join(memoryDirectory, "daily");
318
+ try {
319
+ const entries = readdirSync(dailyDirectory, { withFileTypes: true })
320
+ .filter((entry) => entry.name.endsWith(".md"))
321
+ .sort((left, right) => left.name.localeCompare(right.name));
322
+ if (entries.length > CLAUDE_AUTO_MEMORY_MAX_EXISTING_FILES) {
323
+ throw autoMemoryError(
324
+ "CC_AUTO_MEMORY_STORAGE_UNAVAILABLE",
325
+ "project automatic memory contains too many existing note files",
326
+ );
327
+ }
328
+ for (const entry of entries) {
329
+ candidates.push(join(dailyDirectory, entry.name));
330
+ }
331
+ for (const filePath of candidates) {
332
+ if (!existsSync(filePath)) continue;
333
+ ensurePrivateFile(filePath, {
334
+ applyWindowsAcl: true,
335
+ failIfUnavailable: true,
336
+ });
337
+ }
338
+ } catch (error) {
339
+ if (error?.code === "CC_AUTO_MEMORY_STORAGE_UNAVAILABLE") throw error;
340
+ throw autoMemoryError(
341
+ "CC_AUTO_MEMORY_STORAGE_UNAVAILABLE",
342
+ "project automatic memory files could not be secured",
343
+ );
344
+ }
345
+ }
346
+
347
+ function isAutoMemoryDisabled(env) {
348
+ const value = String(env.CLAUDE_CODE_DISABLE_AUTO_MEMORY || "")
349
+ .trim()
350
+ .toLowerCase();
351
+ return value === "1" || value === "true";
352
+ }
353
+
354
+ /** Capture storage-affecting environment authority before settings merge. */
355
+ export function captureClaudeStorageLaunchEnvironment(env = process.env) {
356
+ const snapshot = {};
357
+ for (const key of LAUNCH_ENV_KEYS) {
358
+ if (typeof env[key] === "string") snapshot[key] = env[key];
359
+ }
360
+ return Object.freeze(snapshot);
361
+ }
362
+
363
+ /**
364
+ * Settings files may contribute a generic child-process `env` map, but they
365
+ * must never be able to redirect the parent process's canonical storage.
366
+ */
367
+ export function restoreClaudeStorageLaunchEnvironment(
368
+ snapshot,
369
+ env = process.env,
370
+ ) {
371
+ for (const key of LAUNCH_ENV_KEYS) {
372
+ if (owns(snapshot || {}, key)) env[key] = snapshot[key];
373
+ else delete env[key];
374
+ }
375
+ }
376
+
377
+ /** Validate configuration/root and project-name authority before side effects. */
378
+ export function validateClaudeStorageLaunchEnvironment(snapshot, options = {}) {
379
+ const env = snapshot || process.env;
380
+ const root = resolveConfigDataRoot({
381
+ env,
382
+ cwd: options.cwd || process.cwd(),
383
+ });
384
+ if (root.source === "claude") {
385
+ resolveClaudeProjectStorageDir(root.path, { env });
386
+ }
387
+ return root;
388
+ }
389
+
390
+ /**
391
+ * Build the memory plan consumed by the real REPL lifecycle. It deliberately
392
+ * returns no filesystem location for disabled/error states, so callers cannot
393
+ * accidentally fall back to a workspace-local directory.
394
+ */
395
+ export function resolveClaudeProjectAutoMemory(options = {}) {
396
+ const env = options.launchEnv || process.env;
397
+ const cwd = options.cwd || process.cwd();
398
+ let root;
399
+ let projectStorage;
400
+ try {
401
+ root = resolveConfigDataRoot({ env, cwd });
402
+ projectStorage =
403
+ root.source === "claude"
404
+ ? resolveClaudeProjectStorageDir(root.path, { env })
405
+ : null;
406
+ } catch (error) {
407
+ return Object.freeze({
408
+ mode: "project",
409
+ enabled: false,
410
+ memoryDir: null,
411
+ source: null,
412
+ reason: error?.code || "CC_AUTO_MEMORY_STORAGE_UNAVAILABLE",
413
+ });
414
+ }
415
+
416
+ if (!projectStorage) {
417
+ return Object.freeze({
418
+ mode: "legacy",
419
+ // Native CHAINLESSCHAIN_HOME precedence disables the Claude layout as a
420
+ // whole, including its project-only auto-memory controls.
421
+ enabled: true,
422
+ memoryDir: null,
423
+ source: null,
424
+ reason: null,
425
+ });
426
+ }
427
+ if (isAutoMemoryDisabled(env)) {
428
+ return Object.freeze({
429
+ mode: "project",
430
+ enabled: false,
431
+ memoryDir: null,
432
+ source: null,
433
+ reason: "disabled",
434
+ });
435
+ }
436
+
437
+ try {
438
+ const identity = resolveCanonicalWorkspaceRepoIdentity(cwd);
439
+ const workspaceRoot = identity.canonicalWorkspaceRoot;
440
+ // Settings inside the config root become trusted only after its own
441
+ // owner-only boundary is established. The project descendants are secured
442
+ // below after we know whether default or custom memory is selected.
443
+ ensureClaudeProjectConfigRoot(root.path);
444
+ const configured = resolveTrustedDirectorySetting({
445
+ configRoot: root.path,
446
+ workspaceRoot,
447
+ env,
448
+ });
449
+ const memoryDir = configured?.defined
450
+ ? resolveCustomMemoryDirectory(configured.value, workspaceRoot, { env })
451
+ : join(projectStorage, "memory");
452
+ if (!configured?.defined) {
453
+ // Includes the daily-note directory used by the actual permanent-memory
454
+ // lifecycle, so an older broad descendant cannot leak project memory.
455
+ ensureClaudeProjectStorageTree(root.path, projectStorage, {
456
+ extraDirectories: [memoryDir, join(memoryDir, "daily")],
457
+ });
458
+ } else {
459
+ ensureClaudeProjectStorageTree(root.path, projectStorage);
460
+ }
461
+ bindMemoryDirectory(memoryDir, identity.repositoryId);
462
+ secureExistingAutomaticMemoryFiles(memoryDir);
463
+ return Object.freeze({
464
+ mode: "project",
465
+ enabled: true,
466
+ memoryDir,
467
+ source: configured?.source || "default",
468
+ // Hash-only identity supports diagnostics/tests without exposing a path.
469
+ repositoryId: identity.repositoryId,
470
+ reason: null,
471
+ });
472
+ } catch (error) {
473
+ return Object.freeze({
474
+ mode: "project",
475
+ enabled: false,
476
+ memoryDir: null,
477
+ source: null,
478
+ reason: error?.code || "CC_AUTO_MEMORY_STORAGE_UNAVAILABLE",
479
+ });
480
+ }
481
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Claude-Code-compatible project storage layout.
3
+ *
4
+ * This module intentionally has no dependency on `paths.js`: session storage,
5
+ * config-root resolution, and the write guard all need the same small
6
+ * environment-only decision without creating an import cycle. The caller
7
+ * supplies the already-validated configuration root.
8
+ */
9
+
10
+ import { join } from "node:path";
11
+
12
+ export const CLAUDE_PROJECT_DIR_NAME_ENV = "CLAUDE_CODE_PROJECT_DIR_NAME";
13
+ export const CLAUDE_CONFIG_DIR_ENV = "CLAUDE_CONFIG_DIR";
14
+ export const CLAUDE_PROJECT_DIR_NAME_MAX_BYTES = 128;
15
+
16
+ const SAFE_PROJECT_DIR_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/u;
17
+ const WINDOWS_RESERVED_SEGMENTS = new Set([
18
+ "CON",
19
+ "PRN",
20
+ "AUX",
21
+ "NUL",
22
+ "COM1",
23
+ "COM2",
24
+ "COM3",
25
+ "COM4",
26
+ "COM5",
27
+ "COM6",
28
+ "COM7",
29
+ "COM8",
30
+ "COM9",
31
+ "LPT1",
32
+ "LPT2",
33
+ "LPT3",
34
+ "LPT4",
35
+ "LPT5",
36
+ "LPT6",
37
+ "LPT7",
38
+ "LPT8",
39
+ "LPT9",
40
+ ]);
41
+
42
+ function layoutError(message, code) {
43
+ const error = new Error(message);
44
+ error.code = code;
45
+ return error;
46
+ }
47
+
48
+ /**
49
+ * A native explicit storage root always wins. This prevents an ambient
50
+ * Claude-compatible variable from silently splitting canonical CLI state.
51
+ */
52
+ export function usesClaudeConfigDirectory(env = process.env) {
53
+ if (env?.CHAINLESSCHAIN_HOME) return false;
54
+ return (
55
+ typeof env?.[CLAUDE_CONFIG_DIR_ENV] === "string" &&
56
+ env[CLAUDE_CONFIG_DIR_ENV].trim().length > 0
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Normalize a project directory name to one portable path segment. Project
62
+ * names arrive only from the launcher environment; accepting a filesystem
63
+ * spelling here would turn a transcript selector into a path traversal input.
64
+ */
65
+ export function validateClaudeProjectDirectoryName(value) {
66
+ if (typeof value !== "string") {
67
+ throw layoutError(
68
+ "CLAUDE_CODE_PROJECT_DIR_NAME must be a string",
69
+ "CLAUDE_PROJECT_DIR_NAME_UNSAFE",
70
+ );
71
+ }
72
+ const name = value.normalize("NFC");
73
+ if (
74
+ name !== value ||
75
+ !name ||
76
+ Buffer.byteLength(name, "utf8") > CLAUDE_PROJECT_DIR_NAME_MAX_BYTES ||
77
+ !SAFE_PROJECT_DIR_NAME.test(name) ||
78
+ name === "." ||
79
+ name === ".." ||
80
+ name.endsWith(".") ||
81
+ name.endsWith(" ") ||
82
+ WINDOWS_RESERVED_SEGMENTS.has(name.split(".")[0].toUpperCase())
83
+ ) {
84
+ throw layoutError(
85
+ "CLAUDE_CODE_PROJECT_DIR_NAME must be a bounded portable path segment",
86
+ "CLAUDE_PROJECT_DIR_NAME_UNSAFE",
87
+ );
88
+ }
89
+ return name;
90
+ }
91
+
92
+ /**
93
+ * Return null when the Claude-compatible project layout is not active. In
94
+ * particular, a project name alone does nothing: Claude Code only honors it
95
+ * alongside CLAUDE_CONFIG_DIR, and CHAINLESSCHAIN_HOME retains precedence.
96
+ */
97
+ export function resolveClaudeProjectStorageDir(homeDir, options = {}) {
98
+ const env = options.env || process.env;
99
+ if (!usesClaudeConfigDirectory(env)) return null;
100
+ const rawName = env[CLAUDE_PROJECT_DIR_NAME_ENV];
101
+ if (rawName === undefined || rawName === null || rawName === "") return null;
102
+ const name = validateClaudeProjectDirectoryName(rawName);
103
+ return join(String(homeDir), "projects", name);
104
+ }
@@ -27,6 +27,7 @@ import {
27
27
  } from "node:fs";
28
28
  import { join } from "node:path";
29
29
  import { getHomeDir } from "../paths.js";
30
+ import { ResilientGatewayClient } from "../gateway-client-resilience.js";
30
31
 
31
32
  export const _deps = { fetch: (...a) => globalThis.fetch(...a) };
32
33
 
@@ -85,6 +86,18 @@ export class CloudClient {
85
86
  }
86
87
  this.token = opts.token || null;
87
88
  this.deps = { ..._deps, ...(opts.deps || {}) };
89
+ // Event streaming remains opt-in for a Runner endpoint, but uses the same
90
+ // bounded recovery layer as every other gateway client. TLS material and
91
+ // proxy authorization are providers so each reconnect can rotate them
92
+ // without putting certificate paths or credentials into persisted config.
93
+ this.gateway =
94
+ opts.gateway ||
95
+ new ResilientGatewayClient({
96
+ baseUrl: this.baseUrl,
97
+ fetch: this.deps.fetch,
98
+ tlsProvider: opts.tlsProvider,
99
+ proxyAuthHelper: opts.proxyAuthHelper,
100
+ });
88
101
  }
89
102
 
90
103
  _headers(extra = {}) {
@@ -126,6 +139,33 @@ export class CloudClient {
126
139
  async result(jobId) {
127
140
  return this._json("GET", `/v1/jobs/${encodeURIComponent(jobId)}/result`);
128
141
  }
142
+
143
+ /**
144
+ * Stream a Runner job's SSE events with bounded idle recovery. The runner's
145
+ * event endpoint is deliberately separate from polling so older private
146
+ * runners remain compatible with status()/result().
147
+ */
148
+ async events(jobId, options = {}) {
149
+ if (!/^[\w.-]+$/.test(String(jobId || ""))) {
150
+ throw new Error(`invalid job id: ${jobId}`);
151
+ }
152
+ // Keep Runner event authentication identical to polling. The resilience
153
+ // layer rejects proxy authentication in caller headers, so this remains an
154
+ // origin-only credential.
155
+ if (!this.token) {
156
+ return this.gateway.stream(
157
+ `/v1/jobs/${encodeURIComponent(jobId)}/events`,
158
+ options,
159
+ );
160
+ }
161
+ return this.gateway.stream(`/v1/jobs/${encodeURIComponent(jobId)}/events`, {
162
+ ...options,
163
+ headers: {
164
+ ...(options.headers || {}),
165
+ Authorization: `Bearer ${this.token}`,
166
+ },
167
+ });
168
+ }
129
169
  }
130
170
 
131
171
  export const TERMINAL_CLOUD_STATUS = new Set(["done", "failed"]);