chainlesschain 0.165.6 → 0.165.9

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 (251) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-DxwjrnEA.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-JdbYowzn.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-C06GCahv.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BUVEEyi1.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-D_ORzkJd.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-8o_Y5ejG.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-DrkHd5VU.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-CKBZCX11.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-C8HkI399.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-zb2H2Wux.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BDcNpU_F.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-MwPtQmNz.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-3p5QCkFK.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-BPLlhn52.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-C-3dBNOM.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-BUcy-F_b.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-CI8NxT8m.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-DaDEBS-Q.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BSv9HXu5.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-yuiKlJmv.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-D6LfldB0.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-CBhLqG61.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-BG8pIl3O.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-CY92VIE6.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-1Q_ehauM.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-D3XirJIU.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DfI9UuGZ.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-IeCZk2m7.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-DzK4IJAZ.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-BHf5KfmQ.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-BmaxSALS.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-BgePFLA9.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-nqgxpOc4.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Bu8to-86.js} +1 -1
  38. package/src/assets/web-panel/assets/McpTools-BFWTzEk0.js +4 -0
  39. package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-B026G2GA.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-CM2Eeg6I.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-B79Ob3hy.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CxevSZuV.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-X396cPEX.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-HWIB_aZ1.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-gnYD1Xwy.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-Dn2Gf_J1.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-BRKBQ5rq.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-Dy___Cgo.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-cqfccxnt.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CSX4FHN3.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-Bwa4aghp.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-Dhszyjig.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-CXzTyk6e.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-CFCAAJbb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-BPJbx6xt.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-BbiXvEHz.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-B-s7-wSD.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-Dyug206y.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-BtAI5Fwo.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-JpIPmz6N.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-CZdoN64A.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-BwvnoRIT.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-ASMlMQrD.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-BiJzKFKi.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-C80TWLIO.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-C1VNmjmX.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-T2MyGUlG.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-DXM6O83L.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-nv69kU7W.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-AyHWe7Qj.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D6PWLxFI.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BqVeOmNQ.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-BegIPl9M.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BHUI7cox.js → SpeechSettings-CKJn3xk-.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-Th4cnAMl.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BuKfBroh.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-CMuWN8Ac.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-C4je8E8Q.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-agJESOcO.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-D2qDuVZ_.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-Cvmn99rH.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-D_QYIHH8.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-BmzvQLnX.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-D_LopHwH.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-DoWl3PhQ.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-5NYcAkxe.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-B-_Q3ewp.js} +4 -4
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-CHET-gi2.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-C6nvb-n6.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-CTDE9LTX.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-KnemdF8D.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-DUJR3Uek.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-CFNTaby8.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-65HO56Bv.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-B8RtbSkV.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-BHqSqnW7.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-BTetEUWd.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-BXWg1crv.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-BdiC4LOs.js} +1 -1
  101. package/src/assets/web-panel/assets/index-BhJtcPWo.js +1 -0
  102. package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-BuizJo2E.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BwZM1rod.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-C96N9xeL.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-CHfUdnJH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-CKvBF3Ov.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-CSD9_I2_.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-Cc7dbl_p.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-CcF0D7UZ.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-Ceu92a8D.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-CnLpuTAU.js} +1 -1
  112. package/src/assets/web-panel/assets/index-Cq8MWPDT.js +1 -0
  113. package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-CquKnw5r.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CyEtHvEE.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-DF-fcTvQ.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-DF1Y0Vuw.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Bissefox.js → index-DJyPeBBk.js} +3 -3
  118. package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-DP-PbO11.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-DZgCRMxk.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-DfJzS3Qa.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-DqPpJkte.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-DzReoLyh.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-JGTiDeOW.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-NUR0If7O.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-NtAcnJYW.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-OmuhFYKE.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-Wlc7o_C8.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-bxTPfdri.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-k6uorYmf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-ox6mIwE2.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-rVDD7AAR.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-u0h6QqVV.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-v-mtxmWH.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-qEt8dI-t.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-DetKPWy-.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-BeNYeDV2.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-C0q0MK_T.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-DLKkrKpE.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-Bw1tWsY8.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-DeesBLbd.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-bqLhxHhn.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-DGCXRoQm.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-H-re3Egl.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-BXg4qGX_.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-CKLb2KA6.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-CTAhHeyw.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-BQ4pDh5g.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-jrSK6j4j.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-fOQE24pw.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +3 -3
  152. package/src/commands/agent.js +91 -60
  153. package/src/commands/git.js +39 -0
  154. package/src/commands/plugin.js +17 -2
  155. package/src/commands/session-group.js +131 -0
  156. package/src/commands/session-location.js +48 -0
  157. package/src/commands/session.js +11 -0
  158. package/src/commands/sync-providers.js +4 -1
  159. package/src/commands/update.js +1 -0
  160. package/src/data/changelog.json +40 -1
  161. package/src/gateways/ws/mcp-topic-handlers.js +167 -0
  162. package/src/gateways/ws/ws-agent-handler.js +20 -12
  163. package/src/harness/jsonl-session-store.js +279 -37
  164. package/src/harness/mcp-client.js +701 -91
  165. package/src/harness/session-index.js +15 -4
  166. package/src/lib/agent-network.js +166 -29
  167. package/src/lib/agent-router.js +62 -6
  168. package/src/lib/agent-sandbox.js +7 -1
  169. package/src/lib/agent-worktree.js +8 -1
  170. package/src/lib/auto-mode-safety-classifier.js +3 -17
  171. package/src/lib/background-agent-keeper-protocol.js +26 -6
  172. package/src/lib/background-agent-supervisor.js +17 -1
  173. package/src/lib/browser-evidence.js +1405 -0
  174. package/src/lib/chrome-connector.js +465 -79
  175. package/src/lib/claude-code-bridge.js +159 -54
  176. package/src/lib/claude-project-auto-memory.js +481 -0
  177. package/src/lib/claude-project-storage-layout.js +104 -0
  178. package/src/lib/cloud/cloud-client.js +40 -0
  179. package/src/lib/cowork-workflow.js +69 -6
  180. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  181. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  182. package/src/lib/execution-location-target-preflight.js +333 -0
  183. package/src/lib/execution-location-target.js +783 -13
  184. package/src/lib/external-agent-adapters.js +269 -0
  185. package/src/lib/file-lines.js +6 -1
  186. package/src/lib/gateway-client-resilience.js +571 -0
  187. package/src/lib/gitlab-mr-worktree.js +176 -0
  188. package/src/lib/hooks-v2-producers.js +119 -15
  189. package/src/lib/hooks-v2-workspace-context.js +44 -1
  190. package/src/lib/host-resource-budget.js +295 -0
  191. package/src/lib/ide-context.js +15 -2
  192. package/src/lib/ipfs-storage.js +127 -25
  193. package/src/lib/llm-config-defaults.js +43 -0
  194. package/src/lib/mcp-lifecycle-authority.js +887 -0
  195. package/src/lib/mcp-oauth.js +101 -20
  196. package/src/lib/mcp-tls.js +103 -3
  197. package/src/lib/orchestrator.js +47 -0
  198. package/src/lib/paths.js +260 -32
  199. package/src/lib/permission-request.js +48 -0
  200. package/src/lib/plugin-runtime/bin.js +3 -1
  201. package/src/lib/plugin-runtime/hooks.js +3 -1
  202. package/src/lib/plugin-runtime/install.js +117 -1
  203. package/src/lib/plugin-runtime/lsp.js +4 -4
  204. package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
  205. package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
  206. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  207. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  208. package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
  209. package/src/lib/plugin-runtime/mcp.js +3 -1
  210. package/src/lib/plugin-runtime/monitors.js +3 -1
  211. package/src/lib/plugin-runtime/remote-source.js +151 -6
  212. package/src/lib/plugin-runtime/settings.js +3 -1
  213. package/src/lib/plugin-runtime/trust.js +274 -13
  214. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  215. package/src/lib/process-execution-broker/index.js +15 -1
  216. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  217. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  218. package/src/lib/project-mcp-trust.js +165 -10
  219. package/src/lib/resume-session.js +9 -6
  220. package/src/lib/session-core-singletons.js +26 -11
  221. package/src/lib/session-host-lease.js +52 -16
  222. package/src/lib/session-lifecycle-scope.js +153 -0
  223. package/src/lib/session-message-fabric.js +168 -21
  224. package/src/lib/session-projection.js +244 -4
  225. package/src/lib/session-store-guard.js +3 -1
  226. package/src/lib/session-workbench-store.js +466 -0
  227. package/src/lib/shell-approval.js +7 -5
  228. package/src/lib/spellcheck.js +211 -0
  229. package/src/lib/sub-agent-context.js +9 -9
  230. package/src/lib/sync-cli-db.js +485 -129
  231. package/src/lib/sync-credentials.js +31 -20
  232. package/src/lib/web-fetch.js +112 -40
  233. package/src/lib/web-search.js +127 -61
  234. package/src/lib/workflow-engine.js +42 -11
  235. package/src/lib/workspace-trust.js +793 -0
  236. package/src/repl/agent-repl.js +124 -5
  237. package/src/repl/permission-prompt.js +10 -12
  238. package/src/runtime/agent-core.js +311 -18
  239. package/src/runtime/agent-runtime.js +12 -1
  240. package/src/runtime/bootstrap.js +37 -13
  241. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  242. package/src/runtime/headless-runner.js +234 -36
  243. package/src/runtime/headless-stream.js +181 -6
  244. package/src/runtime/mcp-config.js +298 -8
  245. package/src/runtime/policies/agent-policy.js +8 -0
  246. package/src/runtime/status-diagnostics-lite.js +9 -1
  247. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
  248. package/src/assets/web-panel/assets/McpTools-DFaIhOfu.js +0 -7
  249. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
  250. package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
  251. package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
@@ -27,6 +27,7 @@ import {
27
27
  sameInteractionBinding,
28
28
  } from "../lib/interaction-binding.js";
29
29
  import {
30
+ addHooksV2EventObserver,
30
31
  emitHooksV2Event,
31
32
  executeHooksV2Event,
32
33
  resolvePromptExpansion,
@@ -42,6 +43,7 @@ import { composeSystemPrompt } from "./system-prompt.js";
42
43
  import { collapseConsecutiveMessagesInPlace } from "./message-roles.js";
43
44
  import { sanitizeToolPairs } from "../harness/prompt-compressor.js";
44
45
  import { compactConversationWithProvider } from "../harness/provider-backed-compaction.js";
46
+ import { HostResourceBudget } from "../lib/host-resource-budget.js";
45
47
  import { projectCanonicalResumeMessages } from "../lib/session-message-provenance.js";
46
48
  import { isAbortError } from "../lib/abort-utils.js";
47
49
  import { expandFileRefsAsync } from "./file-ref-expander.js";
@@ -65,6 +67,7 @@ import {
65
67
  resolveAgentMcp,
66
68
  resolvePermissionPromptTool,
67
69
  makePermissionPromptConfirmer,
70
+ readHeadlessMcpConfigErrors,
68
71
  } from "./mcp-config.js";
69
72
  import { maybeApplyToolSearch } from "./mcp-tool-search.js";
70
73
  import {
@@ -398,6 +401,9 @@ export function planSnapshot(pm) {
398
401
  const MAX_PLAN_REVIEW_SNAPSHOT_CHARS = 24000;
399
402
  const MAX_PLAN_REVIEW_COMMENTS = 64;
400
403
  const MAX_PLAN_REVIEW_COMMENT_CHARS = 2000;
404
+ const HOST_EVENT_BACKLOG_CODE = "CC_HOST_EVENT_BACKLOG_EXHAUSTED";
405
+ const HOST_EVENT_BACKLOG_ERROR =
406
+ "CC_HOST_EVENT_BACKLOG_EXHAUSTED: event backlog limit reached";
401
407
 
402
408
  function boundedReviewString(value, limit) {
403
409
  return String(value == null ? "" : value).slice(0, limit);
@@ -1463,6 +1469,11 @@ async function runAgentHeadlessStreamInWorkspace(
1463
1469
  deps[STREAM_SESSION_ID] ||
1464
1470
  options.sessionId ||
1465
1471
  `headless-stream-${Date.now()}-${process.pid}`;
1472
+ // The input stream may drive many turns. Allocate once at the stream-run
1473
+ // boundary so every turn (and its nested agents) shares cache/backlog limits.
1474
+ // SessionResourceBudget remains separately leased by executeTool.
1475
+ const hostResourceBudget =
1476
+ options.hostResourceBudget || new HostResourceBudget();
1466
1477
  const persist =
1467
1478
  (Boolean(options.sessionId) || options.observabilityScope != null) &&
1468
1479
  options.ephemeral !== true;
@@ -1483,6 +1494,10 @@ async function runAgentHeadlessStreamInWorkspace(
1483
1494
  fieldGate,
1484
1495
  });
1485
1496
  const emit = streamCoalescer.emit;
1497
+ const removeHookObserver =
1498
+ options.includeHookEvents === true
1499
+ ? addHooksV2EventObserver(sessionId, (event) => emit(event))
1500
+ : null;
1486
1501
  streamCleanup.setOutputCleanup(() => streamCoalescer.flush?.());
1487
1502
 
1488
1503
  const hasInjectedSessionStore =
@@ -2484,6 +2499,20 @@ async function runAgentHeadlessStreamInWorkspace(
2484
2499
  let sanitizeRolesNextTurn =
2485
2500
  resumedMessages > 0 && messages[messages.length - 1]?.role === "user";
2486
2501
 
2502
+ // `system:init` intentionally precedes MCP connection so stream consumers
2503
+ // receive their manifest promptly. Validation itself is local and side-effect
2504
+ // free, so preflight just its bounded, redacted projection here; the normal
2505
+ // resolver below remains authoritative for parsing and connection.
2506
+ let initialMcpServerErrors = [];
2507
+ if (options.mcpConfig) {
2508
+ try {
2509
+ initialMcpServerErrors = readHeadlessMcpConfigErrors(options.mcpConfig);
2510
+ } catch {
2511
+ // The normal resolver reports unreadable/malformed files as its existing
2512
+ // config error result. Never place filesystem/parser details in init.
2513
+ }
2514
+ }
2515
+
2487
2516
  emit({
2488
2517
  type: "system",
2489
2518
  subtype: "init",
@@ -2512,6 +2541,9 @@ async function runAgentHeadlessStreamInWorkspace(
2512
2541
  mcp: Boolean(options.mcpConfig) || options.useRegisteredMcp !== false,
2513
2542
  enabledToolNames,
2514
2543
  }),
2544
+ ...(initialMcpServerErrors.length > 0
2545
+ ? { mcp_server_errors: initialMcpServerErrors }
2546
+ : {}),
2515
2547
  slash_commands: [...SESSION_SLASH_COMMANDS],
2516
2548
  input_format: "stream-json",
2517
2549
  additional_directories: additionalDirectories,
@@ -2591,6 +2623,7 @@ async function runAgentHeadlessStreamInWorkspace(
2591
2623
  },
2592
2624
  {
2593
2625
  writeErr,
2626
+ mcpConfigWarnings: false,
2594
2627
  loadMcpConfig: deps.loadMcpConfig,
2595
2628
  loadRegisteredMcp: deps.loadRegisteredMcp,
2596
2629
  loadIdeMcp: deps.loadIdeMcp,
@@ -2836,6 +2869,78 @@ async function runAgentHeadlessStreamInWorkspace(
2836
2869
  }
2837
2870
  }
2838
2871
 
2872
+ const streamInteraction = {};
2873
+ if (interactiveQuestions) streamInteraction.askUser = interactionAskUser;
2874
+ if (options.includeHookEvents === true) {
2875
+ streamInteraction.emit = (kind, payload = {}) => {
2876
+ const subAgentId =
2877
+ typeof payload.subAgentId === "string" && payload.subAgentId.trim()
2878
+ ? payload.subAgentId.slice(0, 160)
2879
+ : null;
2880
+ if (!subAgentId) return;
2881
+ const base = {
2882
+ schema_version: 1,
2883
+ subagent_id: subAgentId,
2884
+ parent_id:
2885
+ typeof payload.parentSessionId === "string" &&
2886
+ payload.parentSessionId.trim()
2887
+ ? payload.parentSessionId.slice(0, 160)
2888
+ : sessionId,
2889
+ ...(typeof payload.role === "string" && payload.role.trim()
2890
+ ? { role: payload.role.trim().slice(0, 96) }
2891
+ : {}),
2892
+ };
2893
+ if (kind === "sub-agent.started") {
2894
+ emit({
2895
+ type: "subagent_started",
2896
+ ...base,
2897
+ background: payload.background === true,
2898
+ });
2899
+ } else if (
2900
+ kind === "sub-agent.completed" ||
2901
+ kind === "sub-agent.failed"
2902
+ ) {
2903
+ emit({
2904
+ type: "subagent_completed",
2905
+ ...base,
2906
+ status: kind === "sub-agent.failed" ? "failed" : "completed",
2907
+ background: payload.background === true,
2908
+ ...(Number.isFinite(payload.iterationCount)
2909
+ ? {
2910
+ iteration_count: Math.max(
2911
+ 0,
2912
+ Math.floor(payload.iterationCount),
2913
+ ),
2914
+ }
2915
+ : {}),
2916
+ });
2917
+ } else if (kind === "sub-agent.progress") {
2918
+ emit({
2919
+ type: "subagent_progress",
2920
+ ...base,
2921
+ event_type:
2922
+ typeof payload.event_type === "string"
2923
+ ? payload.event_type.slice(0, 96)
2924
+ : "unknown",
2925
+ ...(typeof payload.tool === "string" && payload.tool
2926
+ ? { tool: payload.tool.slice(0, 128) }
2927
+ : {}),
2928
+ ...(Number.isFinite(payload.iteration_count)
2929
+ ? {
2930
+ iteration_count: Math.max(
2931
+ 0,
2932
+ Math.floor(payload.iteration_count),
2933
+ ),
2934
+ }
2935
+ : {}),
2936
+ ...(Number.isFinite(payload.token_count)
2937
+ ? { token_count: Math.max(0, Math.floor(payload.token_count)) }
2938
+ : {}),
2939
+ });
2940
+ }
2941
+ };
2942
+ }
2943
+
2839
2944
  const loopOptionsBase = {
2840
2945
  model,
2841
2946
  provider,
@@ -2849,6 +2954,7 @@ async function runAgentHeadlessStreamInWorkspace(
2849
2954
  additionalDirectories,
2850
2955
  sessionId,
2851
2956
  sessionBudget: options.sessionBudget || null,
2957
+ hostResourceBudget,
2852
2958
  sessionHostSnapshot: canonicalResume?.snapshot || null,
2853
2959
  // Auto-checkpoint (Claude-Code parity): snapshot the work tree before each
2854
2960
  // mutating tool so a stream consumer (e.g. the IDE chat panel) can rewind.
@@ -2877,9 +2983,8 @@ async function runAgentHeadlessStreamInWorkspace(
2877
2983
  // ask_user_question round-trip (opt-in via CC_INTERACTIVE_QUESTIONS): give
2878
2984
  // the tool handler an askUser that emits question_request + blocks on stdin.
2879
2985
  // Absent → agent-core returns user_not_reachable (graceful proceed).
2880
- interaction: interactiveQuestions
2881
- ? { askUser: interactionAskUser }
2882
- : undefined,
2986
+ interaction:
2987
+ Object.keys(streamInteraction).length > 0 ? streamInteraction : undefined,
2883
2988
  prepareCall: goalPrepareCallFn,
2884
2989
  // --mcp-config wiring (tool defs + dispatch map + live client).
2885
2990
  mcpClient: mcp?.mcpClient || null,
@@ -3081,13 +3186,43 @@ async function runAgentHeadlessStreamInWorkspace(
3081
3186
  // Stop / Claude-Code Esc parity) instead of waiting in line behind it.
3082
3187
  // Normal events queue for the serial turn loop below; interrupts act on the
3083
3188
  // live per-turn AbortController and are never queued.
3189
+ // A normal input can contain arbitrary user data, so retain it only while it
3190
+ // is waiting for the serial turn loop. Interrupts/approvals/answers remain
3191
+ // out-of-band controls and never consume a queue slot.
3084
3192
  const queue = [];
3085
3193
  let wakeQueue = null;
3086
3194
  let inputDone = false;
3087
3195
  let currentAbort = null;
3196
+ let inputBacklogFailure = false;
3088
3197
  let slashRequestSeq = 0;
3089
3198
  const inputLines = readJsonLines(input);
3090
- streamCleanup.setInputCancel(() => inputLines.return?.());
3199
+ const releaseQueuedInputEvents = () => {
3200
+ while (queue.length > 0) {
3201
+ const queued = queue.shift();
3202
+ try {
3203
+ queued?.lease?.release?.();
3204
+ } catch {
3205
+ // Drain every opaque slot even when an injected test authority has a
3206
+ // faulty disposer. Its payload is deliberately never inspected here.
3207
+ }
3208
+ }
3209
+ };
3210
+ const failInputEventBacklog = () => {
3211
+ if (inputBacklogFailure) return;
3212
+ inputBacklogFailure = true;
3213
+ releaseQueuedInputEvents();
3214
+ // A flood can happen while a model turn is running. Abort that turn before
3215
+ // surfacing the stable host diagnostic; otherwise it could continue to do
3216
+ // paid/tool work after the host has refused its input backlog.
3217
+ currentAbort?.abort();
3218
+ streamCleanup.setReason("host_event_backlog_exhausted");
3219
+ streamCleanup.requestStop();
3220
+ wakeQueue?.();
3221
+ };
3222
+ streamCleanup.setInputCancel(() => {
3223
+ releaseQueuedInputEvents();
3224
+ return inputLines.return?.();
3225
+ });
3091
3226
  (async () => {
3092
3227
  try {
3093
3228
  for await (const line of inputLines) {
@@ -3157,7 +3292,26 @@ async function runAgentHeadlessStreamInWorkspace(
3157
3292
  );
3158
3293
  continue;
3159
3294
  }
3160
- queue.push(parsed);
3295
+ try {
3296
+ if (typeof hostResourceBudget?.admitEvent !== "function") {
3297
+ throw new TypeError(
3298
+ "host resource budget does not provide admitEvent()",
3299
+ );
3300
+ }
3301
+ const lease = hostResourceBudget.admitEvent();
3302
+ if (!lease || typeof lease.release !== "function") {
3303
+ throw new TypeError(
3304
+ "host resource budget event admission is invalid",
3305
+ );
3306
+ }
3307
+ queue.push({ parsed, lease });
3308
+ } catch {
3309
+ // Refuse the whole input stream rather than dropping one unbounded
3310
+ // event and then accepting more. The externally-visible error below
3311
+ // is fixed and contains none of the rejected line's content.
3312
+ failInputEventBacklog();
3313
+ break;
3314
+ }
3161
3315
  if (wakeQueue) wakeQueue();
3162
3316
  }
3163
3317
  } catch {
@@ -3177,7 +3331,15 @@ async function runAgentHeadlessStreamInWorkspace(
3177
3331
  })();
3178
3332
  const nextEvent = async () => {
3179
3333
  for (;;) {
3180
- if (queue.length > 0) return queue.shift();
3334
+ if (queue.length > 0) {
3335
+ const queued = queue.shift();
3336
+ try {
3337
+ return queued.parsed;
3338
+ } finally {
3339
+ // The serial loop now owns the event; it is no longer backlog.
3340
+ queued.lease.release();
3341
+ }
3342
+ }
3181
3343
  if (inputDone || options.signal?.aborted) return null;
3182
3344
  await new Promise((r) => {
3183
3345
  let settled = false;
@@ -3198,6 +3360,18 @@ async function runAgentHeadlessStreamInWorkspace(
3198
3360
  for (;;) {
3199
3361
  await deps.outputFlow?.wait?.();
3200
3362
  const parsed = await nextEvent();
3363
+ if (inputBacklogFailure) {
3364
+ emit({
3365
+ type: "result",
3366
+ subtype: "error_host_resource_budget",
3367
+ is_error: true,
3368
+ code: HOST_EVENT_BACKLOG_CODE,
3369
+ error: HOST_EVENT_BACKLOG_ERROR,
3370
+ session_id: sessionId,
3371
+ });
3372
+ sawError = true;
3373
+ break;
3374
+ }
3201
3375
  if (parsed == null) break; // stdin closed
3202
3376
  sessionHostLease?.assert?.();
3203
3377
  if (turnBindingPersistenceError) {
@@ -4309,6 +4483,7 @@ async function runAgentHeadlessStreamInWorkspace(
4309
4483
  : "completed",
4310
4484
  );
4311
4485
  await streamCleanup.cleanup();
4486
+ removeHookObserver?.();
4312
4487
 
4313
4488
  if (!pipeState.closed) {
4314
4489
  emit({ type: "system", subtype: "end", session_id: sessionId, turns });
@@ -51,7 +51,15 @@ import {
51
51
  normalizeMcpSandboxPolicy,
52
52
  readMcpStdioCwd,
53
53
  } from "../lib/mcp-sandbox-policy.js";
54
- import { normalizeMcpTlsConfig } from "../lib/mcp-tls.js";
54
+ import {
55
+ MCP_TLS_MANAGED_SOURCE_REQUIRED_CODE,
56
+ MCP_TLS_MANAGED_SOURCE_REQUIRED_MESSAGE,
57
+ provisionManagedMcpTlsConfig,
58
+ } from "../lib/mcp-tls.js";
59
+ import {
60
+ McpLifecycleAuthority,
61
+ defaultMcpLifecycleAuthorityPath,
62
+ } from "../lib/mcp-lifecycle-authority.js";
55
63
 
56
64
  function invalidSandboxPolicy(message) {
57
65
  const error = new TypeError(message);
@@ -135,12 +143,203 @@ function headersHelperField(value) {
135
143
  : {};
136
144
  }
137
145
 
146
+ const MCP_CONFIG_ERROR_TYPES = new Set([
147
+ "invalid_config",
148
+ "invalid_name",
149
+ "unknown_type",
150
+ "url_missing_type",
151
+ "reserved_name",
152
+ ]);
153
+
154
+ const MCP_CONFIG_TRANSPORT_TYPES = new Set([
155
+ "stdio",
156
+ "http",
157
+ "https",
158
+ "sse",
159
+ "ws",
160
+ "wss",
161
+ ]);
162
+
163
+ function mcpConfigError(name, type, message) {
164
+ return {
165
+ // The entry name is intentionally retained: callers need to associate a
166
+ // skipped config with the declaration that supplied it. Keep its size
167
+ // bounded, while all other fields are fixed host-owned strings.
168
+ name: String(name || "<unnamed>").slice(0, 256),
169
+ type: MCP_CONFIG_ERROR_TYPES.has(type) ? type : "invalid_config",
170
+ message,
171
+ };
172
+ }
173
+
174
+ function mcpConfigEntries(raw) {
175
+ const block =
176
+ raw && typeof raw === "object" && !Array.isArray(raw)
177
+ ? raw.mcpServers || raw.servers || raw
178
+ : null;
179
+ return block && typeof block === "object" && !Array.isArray(block)
180
+ ? Object.entries(block)
181
+ : [];
182
+ }
183
+
184
+ function mcpConfigEntryError(name, config) {
185
+ if (!name || typeof name !== "string" || name.trim().length === 0) {
186
+ return mcpConfigError(
187
+ name,
188
+ "invalid_name",
189
+ "MCP server name must be a non-empty string.",
190
+ );
191
+ }
192
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
193
+ return mcpConfigError(
194
+ name,
195
+ "invalid_config",
196
+ "MCP server configuration must be an object.",
197
+ );
198
+ }
199
+
200
+ const configuredType =
201
+ typeof config.type === "string" && config.type.trim()
202
+ ? config.type.trim().toLowerCase()
203
+ : typeof config.transport === "string" && config.transport.trim()
204
+ ? config.transport.trim().toLowerCase()
205
+ : null;
206
+ if (configuredType && !MCP_CONFIG_TRANSPORT_TYPES.has(configuredType)) {
207
+ return mcpConfigError(
208
+ name,
209
+ "unknown_type",
210
+ "MCP server transport type is not supported.",
211
+ );
212
+ }
213
+
214
+ const hasCommand =
215
+ typeof config.command === "string" && config.command.trim().length > 0;
216
+ const hasUrl = typeof config.url === "string" && config.url.trim().length > 0;
217
+ if (hasCommand && hasUrl) {
218
+ return mcpConfigError(
219
+ name,
220
+ "invalid_config",
221
+ "MCP server configuration must specify one transport endpoint.",
222
+ );
223
+ }
224
+ if (
225
+ configuredType === "stdio" &&
226
+ !hasCommand &&
227
+ config.disabled !== true &&
228
+ config.enabled !== false
229
+ ) {
230
+ return mcpConfigError(
231
+ name,
232
+ "invalid_config",
233
+ "Stdio MCP server configuration requires a command.",
234
+ );
235
+ }
236
+ if (
237
+ configuredType &&
238
+ configuredType !== "stdio" &&
239
+ !hasUrl &&
240
+ config.disabled !== true &&
241
+ config.enabled !== false
242
+ ) {
243
+ return mcpConfigError(
244
+ name,
245
+ "invalid_config",
246
+ "Remote MCP server configuration requires a URL.",
247
+ );
248
+ }
249
+ if (
250
+ !hasCommand &&
251
+ !hasUrl &&
252
+ config.disabled !== true &&
253
+ config.enabled !== false
254
+ ) {
255
+ return mcpConfigError(
256
+ name,
257
+ "invalid_config",
258
+ "MCP server configuration requires a command or URL.",
259
+ );
260
+ }
261
+ return null;
262
+ }
263
+
264
+ /**
265
+ * Validate one explicit `--mcp-config` document without connecting to any
266
+ * server. Invalid entries are independently skipped; the fixed diagnostic
267
+ * shape is safe to expose in headless `system:init` output.
268
+ *
269
+ * This intentionally retains ChainlessChain's legacy URL inference when no
270
+ * `type`/`transport` is given. Explicit, unknown transport types are rejected
271
+ * before any DNS, process spawn, or transport construction.
272
+ */
273
+ export function parseHeadlessMcpConfig(raw) {
274
+ const servers = {};
275
+ const errors = [];
276
+ for (const [name, config] of mcpConfigEntries(raw)) {
277
+ const entryError = mcpConfigEntryError(name, config);
278
+ if (entryError) {
279
+ errors.push(entryError);
280
+ continue;
281
+ }
282
+ try {
283
+ // Claude-style config calls the field `type`; the established cc shape
284
+ // calls it `transport`. Preserve an explicit transport when both exist.
285
+ const normalizedConfig =
286
+ config.transport == null && typeof config.type === "string"
287
+ ? { ...config, transport: config.type }
288
+ : config;
289
+ const parsed = parseMcpServers({
290
+ mcpServers: { [name]: normalizedConfig },
291
+ });
292
+ if (!parsed[name]) {
293
+ errors.push(
294
+ mcpConfigError(
295
+ name,
296
+ "invalid_config",
297
+ "MCP server configuration is invalid.",
298
+ ),
299
+ );
300
+ continue;
301
+ }
302
+ servers[name] = parsed[name];
303
+ } catch (error) {
304
+ if (error?.code === MCP_SANDBOX_POLICY_INVALID_CODE) {
305
+ throw error;
306
+ }
307
+ // Non-authority config parsers can still reject malformed nested values.
308
+ // Do not reflect their raw message into NDJSON because it may contain a
309
+ // filesystem path or user-supplied secret.
310
+ errors.push(
311
+ mcpConfigError(
312
+ name,
313
+ "invalid_config",
314
+ "MCP server configuration is invalid.",
315
+ ),
316
+ );
317
+ }
318
+ }
319
+ return { servers, errors };
320
+ }
321
+
322
+ /** Read just the safe validation projection for a `--mcp-config` file. */
323
+ export function readHeadlessMcpConfigErrors(filePath, deps = {}) {
324
+ const readFile = deps.readFile || ((p) => fs.readFileSync(p, "utf-8"));
325
+ const raw = JSON.parse(readFile(filePath));
326
+ return parseHeadlessMcpConfig(raw).errors;
327
+ }
328
+
138
329
  /**
139
330
  * Normalize a parsed config object into a `{ name: serverConfig }` map.
140
331
  * Accepts the Claude-Code shape `{ "mcpServers": { ... } }`, the bundle shape
141
332
  * `{ "servers": { ... } }`, or a bare `{ name: cfg }` map.
142
333
  */
143
- export function parseMcpServers(raw) {
334
+ function unmanagedMcpTlsConfigError() {
335
+ // Configuration parsing errors are surfaced in headless diagnostics. Keep
336
+ // this entirely host-owned: do not disclose source paths or any TLS field.
337
+ const error = new Error(MCP_TLS_MANAGED_SOURCE_REQUIRED_MESSAGE);
338
+ error.code = MCP_TLS_MANAGED_SOURCE_REQUIRED_CODE;
339
+ return error;
340
+ }
341
+
342
+ function parseMcpServersForSource(raw, { provisionManagedTls = false } = {}) {
144
343
  const block =
145
344
  (raw && typeof raw === "object" && (raw.mcpServers || raw.servers)) ||
146
345
  raw ||
@@ -208,22 +407,50 @@ export function parseMcpServers(raw) {
208
407
  ...(Number.isFinite(cfg.maxToolResultNodes)
209
408
  ? { maxToolResultNodes: cfg.maxToolResultNodes }
210
409
  : {}),
410
+ ...(Number.isFinite(cfg.toolIdleTimeoutMs)
411
+ ? { toolIdleTimeoutMs: cfg.toolIdleTimeoutMs }
412
+ : {}),
413
+ ...(cfg.discoveryCache === true ||
414
+ (cfg.discoveryCache && typeof cfg.discoveryCache === "object")
415
+ ? { discoveryCache: cfg.discoveryCache }
416
+ : {}),
211
417
  ...headersHelperField(cfg.headersHelper),
212
418
  ...(cfg.configScope ? { configScope: cfg.configScope } : {}),
213
419
  ...(cfg.configSource ? { configSource: cfg.configSource } : {}),
214
- ...(cfg.tls != null ? { tls: normalizeMcpTlsConfig(cfg.tls) } : {}),
420
+ ...(cfg.tls != null
421
+ ? provisionManagedTls
422
+ ? { tls: provisionManagedMcpTlsConfig(cfg.tls) }
423
+ : (() => {
424
+ throw unmanagedMcpTlsConfigError();
425
+ })()
426
+ : {}),
427
+ ...(cfg.disabled === true || cfg.enabled === false
428
+ ? { disabled: true }
429
+ : {}),
215
430
  };
216
431
  }
217
432
  return out;
218
433
  }
219
434
 
435
+ /**
436
+ * Parse an unprivileged MCP configuration source. TLS material is deliberately
437
+ * rejected here; only `loadManagedMcp` invokes the source-specific parser that
438
+ * can mint the opaque managed TLS provenance.
439
+ */
440
+ export function parseMcpServers(raw) {
441
+ return parseMcpServersForSource(raw);
442
+ }
443
+
220
444
  /** Load organization-provisioned MCP servers as the highest-precedence layer. */
221
445
  export async function loadManagedMcp(settings, deps = {}) {
222
446
  const block = settings?.managedMcpServers || settings?.mcpServers;
223
447
  if (!block || typeof block !== "object" || Array.isArray(block)) {
224
448
  return deps.into || null;
225
449
  }
226
- const servers = parseMcpServers({ mcpServers: block });
450
+ const servers = parseMcpServersForSource(
451
+ { mcpServers: block },
452
+ { provisionManagedTls: true },
453
+ );
227
454
  const nameReservations = mcpServerNameReservations(deps);
228
455
  for (const config of Object.values(servers)) {
229
456
  config.configScope = "managed";
@@ -339,11 +566,30 @@ export function mcpAuthHint(url, errMessage) {
339
566
  */
340
567
  export async function setupMcpFromConfig(servers, deps = {}) {
341
568
  const writeErr = deps.writeErr || (() => {});
569
+ const mcpLifecycleAuthority =
570
+ deps.mcpLifecycleAuthority || new McpLifecycleAuthority();
342
571
  const createClient =
343
572
  deps.createClient ||
344
573
  (() =>
345
- new MCPClient({ eventRuntimeStore: deps.eventRuntimeStore || null }));
574
+ new MCPClient({
575
+ eventRuntimeStore: deps.eventRuntimeStore || null,
576
+ lifecycleAuthority: mcpLifecycleAuthority,
577
+ sessionId: deps.sessionId,
578
+ }));
346
579
  servers = filterMcpServersByPolicy(servers, deps.mcpPolicy, writeErr);
580
+ const enabledServers = {};
581
+ for (const [name, config] of Object.entries(servers)) {
582
+ if (config?.disabled === true || config?.enabled === false) {
583
+ mcpLifecycleAuthority.markDisabled({
584
+ name,
585
+ sessionId: deps.sessionId || "default",
586
+ config,
587
+ });
588
+ } else {
589
+ enabledServers[name] = config;
590
+ }
591
+ }
592
+ servers = enabledServers;
347
593
  const nameReservations = mcpServerNameReservations(deps);
348
594
  const previouslyReservedNames = new Set(nameReservations);
349
595
 
@@ -373,6 +619,29 @@ export async function setupMcpFromConfig(servers, deps = {}) {
373
619
  result.resourceTemplates = [];
374
620
  }
375
621
  if (!Array.isArray(result.prompts)) result.prompts = [];
622
+ if (!Array.isArray(result.mcpServerErrors)) {
623
+ result.mcpServerErrors = [];
624
+ }
625
+ if (Array.isArray(deps.mcpServerErrors)) {
626
+ for (const error of deps.mcpServerErrors) {
627
+ if (!error || typeof error !== "object") continue;
628
+ const normalized = mcpConfigError(
629
+ error.name,
630
+ error.type,
631
+ error.message || "MCP server configuration is invalid.",
632
+ );
633
+ if (
634
+ !result.mcpServerErrors.some(
635
+ (current) =>
636
+ current.name === normalized.name &&
637
+ current.type === normalized.type &&
638
+ current.message === normalized.message,
639
+ )
640
+ ) {
641
+ result.mcpServerErrors.push(normalized);
642
+ }
643
+ }
644
+ }
376
645
  // Per-server usage instructions from the MCP initialize response (surfaced
377
646
  // by tool search; absent for servers that send none).
378
647
  if (
@@ -779,20 +1048,31 @@ export async function loadMcpConfig(filePath, deps = {}) {
779
1048
  `--mcp-config: cannot read/parse "${filePath}": ${err.message}`,
780
1049
  );
781
1050
  }
782
- const servers = parseMcpServers(raw);
783
- if (Object.keys(servers).length === 0) {
1051
+ const { servers, errors } = parseHeadlessMcpConfig(raw);
1052
+ if (Object.keys(servers).length === 0 && errors.length === 0) {
784
1053
  throw new Error(
785
1054
  `--mcp-config: no servers found in "${filePath}" ` +
786
1055
  `(expected {"mcpServers": {"name": {"command": "..."}}}).`,
787
1056
  );
788
1057
  }
1058
+ if (errors.length > 0 && deps.mcpConfigWarnings !== false) {
1059
+ const count = errors.length;
1060
+ const noun = count === 1 ? "server" : "servers";
1061
+ deps.writeErr?.(
1062
+ `Warning: ${count} MCP ${noun} skipped due to invalid config:\n` +
1063
+ errors.map((error) => ` ${error.name}: ${error.message}\n`).join(""),
1064
+ );
1065
+ }
789
1066
  authorizeStdioServers(
790
1067
  servers,
791
1068
  "explicit-config",
792
1069
  () => path.resolve(filePath),
793
1070
  { failFast: true },
794
1071
  );
795
- return setupMcpFromConfig(servers, deps);
1072
+ return setupMcpFromConfig(servers, {
1073
+ ...deps,
1074
+ mcpServerErrors: errors,
1075
+ });
796
1076
  }
797
1077
 
798
1078
  /**
@@ -1317,6 +1597,15 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
1317
1597
  (runtimeEnv.CC_EVENT_RUNTIME_DURABLE === "1"
1318
1598
  ? new EventRuntimeStore()
1319
1599
  : null);
1600
+ const mcpLifecycleAuthority =
1601
+ deps.mcpLifecycleAuthority ||
1602
+ args.mcpLifecycleAuthority ||
1603
+ new McpLifecycleAuthority({
1604
+ statePath:
1605
+ deps.mcpLifecycleStatePath ||
1606
+ args.mcpLifecycleStatePath ||
1607
+ defaultMcpLifecycleAuthorityPath(),
1608
+ });
1320
1609
  const serverNameReservations =
1321
1610
  deps.mcpServerNameReservations instanceof Set
1322
1611
  ? deps.mcpServerNameReservations
@@ -1341,6 +1630,7 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
1341
1630
  cwd: args.cwd || deps.cwd || process.cwd(),
1342
1631
  ...(args.sessionId != null ? { sessionId: args.sessionId } : {}),
1343
1632
  ...(eventRuntimeStore ? { eventRuntimeStore } : {}),
1633
+ mcpLifecycleAuthority,
1344
1634
  mcpPolicy,
1345
1635
  mcpServerNameReservations: serverNameReservations,
1346
1636
  };