chainlesschain 0.165.5 → 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 (256) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-CEeYTeDB.js → AIOps-B3gWmXjo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BeRUQ3V2.js → ActionButton-G9pdT-0e.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DrV718XF.js → Analytics-Ca30J7m2.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-Cd2Frt7Q.js → AppLayout-BtVTm8PU.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CUJMlORU.js → Artifacts-BhViNa6u.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CXJcfT6p.js → Audit-DhKq-FnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DOv6Z7H9.js → BackgroundAgents-BL0SVbnE.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BwdDyBI0.js → Backup-BWkblnFi.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BmLn4kYH.js → BaseInput-ClaRNrF8.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-COg8pAW2.js → Chat-sZE2Z77o.js} +4 -4
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-BAfKOnRe.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-BCP4uoU8.js → Checkbox-Cvhay5WM.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-pRt6Y9JI.js → Codegen-BpejL-4N.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DLaprKhS.js → Col-g2Ki6g_1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DyATsz5f.js → Community-D2xKbNo9.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BXAaupZK.js → Compact-DbL1Pds3.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-DpcJBELr.js → Compliance-DGtZCV4c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-DG4EFWyd.js → Cowork-4kQpoNsI.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-F6Oy5n2P.js → Cron-BxTYXXAN.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BOdgtalX.js → Crosschain-k0J0LT2N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-DT1dSkjH.js → DID-BaqhoPgN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-NBUIqWzC.js → Dashboard-T4RVPIM1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-CSpHeMYB.js → Dropdown-DszOToWq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-CEG0xISr.js → EmailListRenderer-C9KJU7HF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BTZ0BZna.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BuuCTn2V.js → Federation-BI-_2xZX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-KAVceevk.js → FormItemContext-DsnDEPsl.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-DnHpcQvW.js → GenericCardRenderer-BLncAKKK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-C_B_0HwB.js → Git-BPQhGXDn.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DPSZuzuu.js → Governance-CyElbUQW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BV-06V7q.js → Inference-CcSntBQD.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-wpDuupn6.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-Bseca1_I.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-d3kM4DDL.js → Marketplace-Dd2notAJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DQ_xZ23i.js → McpTools-BBsN2CSW.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-CRIeYO4L.js → Memory-Dg2uTvwx.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-BsllIa9l.js → MobileBridge-r1YMRiJV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-BUuQy30X.js → MobileProjects-C-89kSm4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BOFDIzrC.js → Mtc-CrPZcVgf.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-BQg-vyvG.js → MtcAudit-sxi7hqJb.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-Bo1jrPdN.js → Multisig-CAgOMfF1.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-Bmod8alw.js → NLProgramming-DafaPts3.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CGGFL8w-.js → Notes-CJM-xUW_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BsZvCJxC.js → NotificationSettings-L0ZjfAh_.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C1-Quo_h.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-BjOeDYOi.js → Organization-DeLtgAD8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-DwVV3l5A.js → Overflow-CKC2b10z.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-Cu3DQT9W.js → P2P-eyf2rzY1.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-Cg0gR7dH.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-CsAXxRN5.js → Permissions-B8p3W6JK.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-C-nNmnYp.js → PersonalDataHub-BnRMxTq3.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-BOnW7nNc.js → Pipeline-DjCNI1li.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-ClLSyGKt.js → Privacy-u6gXLbWT.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DuLvjjq7.js → ProjectInit-BZAw4tkM.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-DQYYbDD9.js → ProjectSettings-B1Tr72q7.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-Drw8MBGK.js → Projects-DO7HFuBQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-ckqHQe6K.js → Providers-BjCztyhj.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DW5BXk-G.js → QrScannerModal-ZWyCUbR1.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-DDLnhNTp.js → QuickAsk-DhDjeW4G.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-PJQ2C91U.js → Recommend-R_CN2MuU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-s6wmda34.js → RemoteSession-uxFcujeu.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-DC2sb-I3.js → Reputation-DX8D7rks.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-hPGk1eGj.js → Row-BYahQILD.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-RIvfZql0.js → RssFeed-CUSQ2tm-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DFg1G1eR.js → Search-CnN_S8Cs.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-D6H5p8Dp.js → Security-DcZlh-O4.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-nxYiFV_w.js → Services-ZhBOjzIX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-BmgFNAdB.js → Skeleton-D5Qnq_lI.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-CsaaD2av.js → Skills-BC9cZ3Be.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-yM5y9yvK.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-CFVhEyyr.js → SyncSettings-DUvJbSct.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DdO02Inn.js → Tasks-BXa-5noQ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-Eo2d8Llu.js → Templates-JxaiUt_3.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-ChESOXgy.js → Tenant-BW4ERQN8.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-BJ7oDxTI.js → Terminal-DltUbdtv.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-hWX0fUvz.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-DVBZQnd-.js → Tokens-D_VEV60K.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-D89cQfVq.js → Trigger-CCXTCs0R.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BIVSb4-V.js → Trust-lkGRIPcG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-B58gWopl.js → UkeySign-BfGeQ9HX.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DhHI7bmG.js → VideoEditing-BEC7pYvc.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-C4FheWS_.js → Wallet-BZdG24o0.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DnPRq-Bx.js → WebAuthn-yoEddedp.js} +3 -3
  87. package/src/assets/web-panel/assets/{WorkflowEditor-BerRPjpJ.js → WorkflowEditor-BXZEprOW.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-BzZ52iKr.js → chat-gg0bzZal.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BI_E4BAn.js → colors-DjRVRuin.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-d50mr3yk.js → compact-item-su-dieAc.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-C6FsQ1IH.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-DLZEMgLP.js → hasIn-D8F10heH.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-D-aBumtY.js → index-11wtYQiF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CjuKZBqJ.js → index-1IgxgALJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-9H_M2jju.js → index-1agckWSq.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DE0V6cp-.js → index-5JqhujnR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Y2-q7QLm.js → index-6Tniqk1s.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DoFtCVZ7.js → index-8Z-8BIlN.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-KNGgO4Wm.js → index-BCI5v0yB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DY4j5zkF.js → index-BDJntYmJ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BZjjdQ62.js → index-BGzixOGZ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BTpIOTfR.js → index-BMMOVoLD.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BB9SqVSt.js → index-BTFpdBtt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-AHr7ryWf.js → index-Ba_HyPnE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Pvf30m8Q.js → index-BbF1IHof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CRN5TRTQ.js → index-BgT9su_e.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CUaEHfQ0.js → index-BzPB6kGZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CdKt9fOd.js → index-C6ygzplr.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Dec0Kf_Z.js → index-CC3ZDjzY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-IPkwSAW_.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-C3k8kevG.js → index-CMPqd5Cv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-A5CDWP7y.js → index-COWd8uGx.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CO8DAF7U.js → index-CPIYSp4H.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CVzuawCX.js → index-CR0h6seT.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Co7s9LsB.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-CLoTQr0W.js → index-CusgZPtc.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B81mo1Et.js → index-DBAETXft.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BcSUl9fA.js → index-DIJ2qFOC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Q5Tn735s.js → index-Dbq4NMET.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-GXE0D8Nx.js → index-DkMEF5VT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-TWG-_D1M.js → index-DkfQR3hM.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BAE3hwev.js → index-DnLucOn9.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CgkoH3_g.js → index-DugB_aKa.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BRGx3w6T.js → index-DyLUarhZ.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-BeM4hfht.js → index-T6_6ygJZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DsscwxPE.js → index-Tu8eWqh-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bmr_vxXD.js → index-W7XUgdVL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BoNZlzhQ.js → index-dHZinfko.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DqkbHHg8.js → index-jyNgp5FI.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-D-4Hzgej.js → initDefaultProps-Cv4p8e4w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-D4Wl4xU7.js → motion-B8EwmMOw.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Cd5eQvL0.js → move-B8R9F8TK.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-B4ilslCW.js → mtc-parser-DoFYz5Bp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-Ckarx-tf.js → omit-CHWYLBjI.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-QJ0bpCmc.js → pickAttrs-CXuPDO77.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-CKHm-tq8.js → placementArrow-BaAtUUon.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-CV6a_w_Y.js → responsiveObserve-DCc4zcDD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-mHpeQFgk.js → slide-B_lx89oZ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-DIaQNQWA.js → statusUtils-DE8DPmR0.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-PJpzavV8.js → styleChecker-1ktXOsL_.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-BH7zTw8S.js → useFlexGapSupport-xH89-wjh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-BDNG3JDd.js → useFs-DscvfW5p.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CY2VWdUg.js → usePersonalDataHub-RdMKQta7.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-D0kw9jhz.js → vnode-Z3wTni2T.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-B5g7TN7r.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 +105 -62
  152. package/src/commands/background-session.js +100 -10
  153. package/src/commands/git.js +39 -0
  154. package/src/commands/mcp.js +5 -0
  155. package/src/commands/plugin.js +160 -29
  156. package/src/commands/remote-control.js +295 -110
  157. package/src/commands/session-group.js +131 -0
  158. package/src/commands/session-location.js +48 -0
  159. package/src/commands/session-message.js +171 -0
  160. package/src/commands/session.js +22 -0
  161. package/src/commands/sync-providers.js +4 -1
  162. package/src/commands/update.js +1 -0
  163. package/src/data/changelog.json +41 -2
  164. package/src/gateways/ws/ws-agent-handler.js +20 -12
  165. package/src/harness/jsonl-session-store.js +279 -37
  166. package/src/harness/mcp-client.js +832 -91
  167. package/src/harness/session-index.js +15 -4
  168. package/src/lib/agent-worktree.js +8 -1
  169. package/src/lib/auto-mode-safety-classifier.js +3 -17
  170. package/src/lib/background-agent-keeper-protocol.js +26 -6
  171. package/src/lib/background-agent-supervisor.js +17 -1
  172. package/src/lib/background-session-transport.js +153 -27
  173. package/src/lib/browser-evidence.js +1405 -0
  174. package/src/lib/chrome-connector.js +465 -79
  175. package/src/lib/claude-project-auto-memory.js +481 -0
  176. package/src/lib/claude-project-storage-layout.js +104 -0
  177. package/src/lib/cloud/cloud-client.js +40 -0
  178. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  179. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  180. package/src/lib/execution-location-target-preflight.js +333 -0
  181. package/src/lib/execution-location-target.js +783 -13
  182. package/src/lib/file-lines.js +6 -1
  183. package/src/lib/gateway-client-resilience.js +571 -0
  184. package/src/lib/gitlab-mr-worktree.js +176 -0
  185. package/src/lib/hooks-v2-producers.js +119 -15
  186. package/src/lib/hooks-v2-workspace-context.js +44 -1
  187. package/src/lib/host-resource-budget.js +295 -0
  188. package/src/lib/ide-context.js +15 -2
  189. package/src/lib/llm-config-defaults.js +43 -0
  190. package/src/lib/mcp-client.js +2 -0
  191. package/src/lib/mcp-headers-helper.js +47 -5
  192. package/src/lib/mcp-lifecycle-authority.js +887 -0
  193. package/src/lib/mcp-oauth.js +156 -26
  194. package/src/lib/mcp-tls.js +330 -0
  195. package/src/lib/output-styles.js +12 -0
  196. package/src/lib/paths.js +260 -32
  197. package/src/lib/permission-request.js +48 -0
  198. package/src/lib/plugin-runtime/bin.js +3 -1
  199. package/src/lib/plugin-runtime/hooks.js +3 -1
  200. package/src/lib/plugin-runtime/install.js +730 -71
  201. package/src/lib/plugin-runtime/lsp.js +4 -4
  202. package/src/lib/plugin-runtime/marketplace-archive-source.js +366 -0
  203. package/src/lib/plugin-runtime/marketplace-catalog.js +63 -6
  204. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  205. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  206. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1 -0
  207. package/src/lib/plugin-runtime/marketplace-source-adapter.js +188 -0
  208. package/src/lib/plugin-runtime/marketplace-source-cache.js +11 -1
  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 +583 -58
  212. package/src/lib/plugin-runtime/settings.js +3 -1
  213. package/src/lib/plugin-runtime/trust.js +274 -13
  214. package/src/lib/plugin-security.js +393 -41
  215. package/src/lib/plugin-source-identity.js +850 -0
  216. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  217. package/src/lib/process-execution-broker/index.js +15 -1
  218. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  219. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  220. package/src/lib/project-mcp-trust.js +165 -10
  221. package/src/lib/remote-approval-bridge.js +136 -46
  222. package/src/lib/remote-control.js +217 -31
  223. package/src/lib/resume-session.js +9 -6
  224. package/src/lib/session-core-singletons.js +26 -11
  225. package/src/lib/session-host-lease.js +52 -16
  226. package/src/lib/session-lifecycle-scope.js +153 -0
  227. package/src/lib/session-message-fabric.js +1252 -0
  228. package/src/lib/session-projection.js +286 -3
  229. package/src/lib/session-runtime-retention.js +155 -0
  230. package/src/lib/session-store-guard.js +3 -1
  231. package/src/lib/session-workbench-store.js +466 -0
  232. package/src/lib/settings-loader.cjs +29 -0
  233. package/src/lib/spellcheck.js +211 -0
  234. package/src/lib/sub-agent-context.js +9 -9
  235. package/src/lib/sync-cli-db.js +485 -129
  236. package/src/lib/sync-credentials.js +31 -20
  237. package/src/lib/web-fetch.js +112 -40
  238. package/src/lib/web-search.js +127 -61
  239. package/src/lib/workspace-trust.js +793 -0
  240. package/src/repl/agent-repl.js +175 -19
  241. package/src/repl/permission-prompt.js +29 -8
  242. package/src/repl/repl-keybindings.js +55 -0
  243. package/src/runtime/agent-core.js +362 -20
  244. package/src/runtime/bootstrap.js +37 -13
  245. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  246. package/src/runtime/headless-runner.js +281 -102
  247. package/src/runtime/headless-stream.js +199 -30
  248. package/src/runtime/mcp-config.js +298 -6
  249. package/src/runtime/policies/agent-policy.js +10 -0
  250. package/src/runtime/status-diagnostics-lite.js +9 -1
  251. package/src/assets/web-panel/assets/ChatBubbleRenderer-4gGkdGgA.js +0 -1
  252. package/src/assets/web-panel/assets/MarkdownRenderer-B4RLp2zs.js +0 -1
  253. package/src/assets/web-panel/assets/SpeechSettings-DPy1XMYh.js +0 -1
  254. package/src/assets/web-panel/assets/devWarning-CagEcIex.js +0 -1
  255. package/src/assets/web-panel/assets/index-pzT9PpOU.js +0 -1
  256. package/src/assets/web-panel/assets/index-z1kFadaX.js +0 -1
@@ -52,6 +52,56 @@ export const _deps = {
52
52
  withStoreLock,
53
53
  };
54
54
 
55
+ /**
56
+ * Resolve the exact IPv4-loopback redirect used by both the listener and the
57
+ * OAuth wire exchange. Pre-registered clients need byte-for-byte redirect URI
58
+ * stability, so explicit values are accepted only in canonical form.
59
+ */
60
+ export function resolveOAuthLoopbackRedirect({
61
+ redirectUri,
62
+ host = "127.0.0.1",
63
+ port = 53682,
64
+ redirectPath = "/callback",
65
+ } = {}) {
66
+ if (redirectUri != null && typeof redirectUri !== "string") {
67
+ throw new Error("OAuth redirectUri must be a string");
68
+ }
69
+ const candidate =
70
+ redirectUri == null ? `http://${host}:${port}${redirectPath}` : redirectUri;
71
+ let parsed;
72
+ try {
73
+ parsed = new URL(candidate);
74
+ } catch {
75
+ throw new Error("OAuth redirectUri must be a valid loopback URL");
76
+ }
77
+ const parsedPort = Number(parsed.port);
78
+ const canonical = `http://127.0.0.1:${parsed.port}${parsed.pathname}`;
79
+ if (
80
+ parsed.protocol !== "http:" ||
81
+ parsed.hostname !== "127.0.0.1" ||
82
+ !parsed.port ||
83
+ !Number.isInteger(parsedPort) ||
84
+ parsedPort < 1 ||
85
+ parsedPort > 65535 ||
86
+ parsed.username ||
87
+ parsed.password ||
88
+ parsed.search ||
89
+ parsed.hash ||
90
+ !parsed.pathname.startsWith("/") ||
91
+ candidate !== canonical
92
+ ) {
93
+ throw new Error(
94
+ "OAuth redirectUri must be an exact canonical http://127.0.0.1:<port>/<path> URL",
95
+ );
96
+ }
97
+ return {
98
+ redirectUri: candidate,
99
+ host: "127.0.0.1",
100
+ port: parsedPort,
101
+ redirectPath: parsed.pathname,
102
+ };
103
+ }
104
+
55
105
  /** Discovery/token requests retry ONCE after a transient error (CC 2.1.191). */
56
106
  const MCP_OAUTH_RETRY_BACKOFF_MS = 300;
57
107
 
@@ -434,7 +484,23 @@ export function loadTokenStore() {
434
484
  }
435
485
 
436
486
  export function getStoredToken(serverUrl) {
437
- return loadTokenStore()[serverKey(serverUrl)] || null;
487
+ const record = loadTokenStore()[serverKey(serverUrl)] || null;
488
+ return record?.revoked === true ? null : record;
489
+ }
490
+
491
+ function tokenRecordRevision(record) {
492
+ return Number.isSafeInteger(record?.credential_revision) &&
493
+ record.credential_revision >= 0
494
+ ? record.credential_revision
495
+ : 0;
496
+ }
497
+
498
+ function tokenRevisionConflict(serverUrl) {
499
+ const error = new Error(
500
+ `MCP OAuth credential changed while it was being refreshed: ${serverKey(serverUrl)}`,
501
+ );
502
+ error.code = "MCP_TOKEN_STORE_REVISION_CONFLICT";
503
+ return error;
438
504
  }
439
505
 
440
506
  // The store holds OAuth access + refresh tokens, so it must not be world-
@@ -592,7 +658,7 @@ export function withStoreLock(file, fn) {
592
658
  }
593
659
  }
594
660
 
595
- export function saveStoredToken(serverUrl, record) {
661
+ export function saveStoredToken(serverUrl, record, options = {}) {
596
662
  const file = tokenStorePath();
597
663
  return _deps.withStoreLock(file, () => {
598
664
  const r = _readStore(file); // re-read inside the lock (latest state)
@@ -604,24 +670,56 @@ export function saveStoredToken(serverUrl, record) {
604
670
  _warnCorruptStoreOnce(file, r.err, archived);
605
671
  }
606
672
  const store = r.store;
607
- store[serverKey(serverUrl)] = { server: serverKey(serverUrl), ...record };
673
+ const key = serverKey(serverUrl);
674
+ const current = store[key] || null;
675
+ if (
676
+ options.expectedRevision != null &&
677
+ (tokenRecordRevision(current) !== options.expectedRevision ||
678
+ current?.revoked === true)
679
+ ) {
680
+ throw tokenRevisionConflict(serverUrl);
681
+ }
682
+ store[key] = {
683
+ ...record,
684
+ server: key,
685
+ credential_revision: tokenRecordRevision(current) + 1,
686
+ revoked: false,
687
+ };
608
688
  _writeStoreSecure(file, store);
609
- return store[serverKey(serverUrl)];
689
+ return store[key];
610
690
  });
611
691
  }
612
692
 
613
- export function deleteStoredToken(serverUrl) {
693
+ function revokeStoredToken(serverUrl, { expectedRevision = null } = {}) {
614
694
  const file = tokenStorePath();
615
695
  return _deps.withStoreLock(file, () => {
616
696
  const store = loadTokenStore(); // re-read inside the lock (latest state)
617
697
  const key = serverKey(serverUrl);
618
- if (!(key in store)) return false;
619
- delete store[key];
698
+ const current = store[key];
699
+ if (!current || current.revoked === true) return false;
700
+ if (
701
+ expectedRevision != null &&
702
+ tokenRecordRevision(current) !== expectedRevision
703
+ ) {
704
+ return false;
705
+ }
706
+ // Keep a revision-only tombstone. An in-flight refresh that read the old
707
+ // credential must not resurrect it after explicit logout/revocation.
708
+ store[key] = {
709
+ server: key,
710
+ credential_revision: tokenRecordRevision(current) + 1,
711
+ revoked: true,
712
+ revoked_at: _deps.now(),
713
+ };
620
714
  _writeStoreSecure(file, store);
621
715
  return true;
622
716
  });
623
717
  }
624
718
 
719
+ export function deleteStoredToken(serverUrl) {
720
+ return revokeStoredToken(serverUrl);
721
+ }
722
+
625
723
  /** True when a record's access token is missing or within `skewMs` of expiry. */
626
724
  export function isTokenExpired(record, { skewMs = 60_000 } = {}) {
627
725
  if (!record || !record.access_token) return true;
@@ -642,6 +740,8 @@ export function isTokenExpired(record, { skewMs = 60_000 } = {}) {
642
740
  * @param {string} serverUrl
643
741
  * @param {{ forceRefresh?: boolean }} [opts]
644
742
  */
743
+ const tokenRefreshFlights = new Map();
744
+
645
745
  export async function ensureValidToken(
646
746
  serverUrl,
647
747
  { forceRefresh = false } = {},
@@ -650,21 +750,52 @@ export async function ensureValidToken(
650
750
  if (!record) return null;
651
751
  if (!forceRefresh && !isTokenExpired(record)) return record.access_token;
652
752
  if (!record.refresh_token || !record.endpoints?.token_endpoint) {
653
- // Can't refresh. On a forced refresh the cached token is known-rejected, so
654
- // hand back null (caller should stop retrying and prompt re-login); on the
655
- // proactive path keep the existing behaviour of using what we have.
656
- return forceRefresh ? null : record.access_token || null;
753
+ // Reaching this branch means the cached access token is expired (including
754
+ // the safety skew) or the server already rejected it. Reusing it would
755
+ // create a deterministic 401/403 loop, so every caller fails closed.
756
+ return null;
657
757
  }
658
- try {
659
- const tok = await refreshAccessToken(
660
- { token_endpoint: record.endpoints.token_endpoint },
661
- { refreshToken: record.refresh_token, clientId: record.client_id },
662
- );
663
- const updated = saveStoredToken(serverUrl, { ...record, ...tok });
664
- return updated.access_token;
665
- } catch {
666
- return forceRefresh ? null : record.access_token || null;
758
+ const key = serverKey(serverUrl);
759
+ let refresh = tokenRefreshFlights.get(key);
760
+ if (!refresh) {
761
+ refresh = (async () => {
762
+ try {
763
+ const tok = await refreshAccessToken(
764
+ { token_endpoint: record.endpoints.token_endpoint },
765
+ { refreshToken: record.refresh_token, clientId: record.client_id },
766
+ );
767
+ const updated = saveStoredToken(
768
+ serverUrl,
769
+ { ...record, ...tok },
770
+ { expectedRevision: tokenRecordRevision(record) },
771
+ );
772
+ return { status: "refreshed", accessToken: updated.access_token };
773
+ } catch (error) {
774
+ if ([400, 401, 403].includes(error?.status)) {
775
+ const revoked = revokeStoredToken(serverUrl, {
776
+ expectedRevision: tokenRecordRevision(record),
777
+ });
778
+ return { status: revoked ? "revoked" : "conflict" };
779
+ }
780
+ return {
781
+ status:
782
+ error?.code === "MCP_TOKEN_STORE_REVISION_CONFLICT"
783
+ ? "conflict"
784
+ : "failed",
785
+ };
786
+ } finally {
787
+ tokenRefreshFlights.delete(key);
788
+ }
789
+ })();
790
+ tokenRefreshFlights.set(key, refresh);
667
791
  }
792
+ const outcome = await refresh;
793
+ if (outcome.status === "refreshed") return outcome.accessToken;
794
+ if (outcome.status === "revoked") return null;
795
+ if (outcome.status === "conflict") {
796
+ return getStoredToken(serverUrl)?.access_token || null;
797
+ }
798
+ return null;
668
799
  }
669
800
 
670
801
  // ── interactive orchestrator ──────────────────────────────────────────────
@@ -794,23 +925,22 @@ export function waitForCallback({
794
925
  * Run the full interactive Authorization Code + PKCE flow and persist the token.
795
926
  *
796
927
  * @param {string} serverUrl
797
- * @param {object} [opts] { scope, clientId, port=53682, host, redirectPath,
798
- * timeout, writeOut }
928
+ * @param {object} [opts] { scope, clientId, redirectUri, port=53682, host,
929
+ * redirectPath, timeout, writeOut }
799
930
  * @returns {Promise<{server, access_token, ...}>} the stored record
800
931
  */
801
932
  export async function authorizeInteractive(serverUrl, opts = {}) {
802
933
  const {
803
934
  scope,
804
935
  clientId: cfgClientId,
805
- port = 53682,
806
- host = "127.0.0.1",
807
- redirectPath = "/callback",
808
936
  timeout = 300_000,
809
937
  writeOut = (s) => process.stdout.write(s),
810
938
  } = opts;
811
939
 
940
+ const { redirectUri, host, port, redirectPath } =
941
+ resolveOAuthLoopbackRedirect(opts);
942
+
812
943
  const metadata = await discoverAuthMetadata(serverUrl);
813
- const redirectUri = `http://${host}:${port}${redirectPath}`;
814
944
 
815
945
  let clientId = cfgClientId;
816
946
  let clientSecret = null;
@@ -0,0 +1,330 @@
1
+ /** Bounded mTLS material loading for HTTP/WebSocket MCP transports. */
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { createHash, X509Certificate } from "node:crypto";
6
+ import { createSecureContext } from "node:tls";
7
+ import { isProxy } from "node:util/types";
8
+ import { Agent } from "undici";
9
+
10
+ export const MCP_TLS_MAX_FILE_BYTES = 1024 * 1024;
11
+ export const MCP_TLS_MANAGED_SOURCE_REQUIRED_CODE =
12
+ "CC_MCP_TLS_MANAGED_SOURCE_REQUIRED";
13
+ export const MCP_TLS_MANAGED_SOURCE_REQUIRED_MESSAGE =
14
+ "MCP TLS configuration is restricted to managed provisioned sources";
15
+
16
+ // TLS file paths are a privileged configuration capability: merely marking a
17
+ // JSON object as `configScope: "managed"` must never let a project, user, or
18
+ // headless config read certificate material. Keep the provisioned snapshot in
19
+ // a module-private WeakMap so it cannot be recreated by JSON, object spread,
20
+ // or a lookalike field supplied by an MCP config source.
21
+ const MANAGED_MCP_TLS_PROVENANCE = new WeakMap();
22
+ const MANAGED_MCP_TLS_SCOPE = "managed";
23
+
24
+ const TLS_KEYS = new Set([
25
+ "certFile",
26
+ "keyFile",
27
+ "caFile",
28
+ "serverName",
29
+ "rejectUnauthorized",
30
+ ]);
31
+
32
+ function tlsError(code, message, cause = undefined) {
33
+ const error = new Error(message, cause ? { cause } : undefined);
34
+ error.code = code;
35
+ return error;
36
+ }
37
+
38
+ function managedTlsSourceRequiredError() {
39
+ // Do not include the claimed scope, source file, certificate path, or any
40
+ // TLS configuration field here. This error is surfaced by headless and MCP
41
+ // connection diagnostics, where config values are not safe to disclose.
42
+ return tlsError(
43
+ MCP_TLS_MANAGED_SOURCE_REQUIRED_CODE,
44
+ MCP_TLS_MANAGED_SOURCE_REQUIRED_MESSAGE,
45
+ );
46
+ }
47
+
48
+ function plainTlsObject(value) {
49
+ if (
50
+ !value ||
51
+ typeof value !== "object" ||
52
+ Array.isArray(value) ||
53
+ isProxy(value)
54
+ ) {
55
+ return null;
56
+ }
57
+ let prototype;
58
+ let descriptors;
59
+ try {
60
+ prototype = Object.getPrototypeOf(value);
61
+ descriptors = Object.getOwnPropertyDescriptors(value);
62
+ } catch {
63
+ return null;
64
+ }
65
+ if (prototype !== Object.prototype && prototype !== null) return null;
66
+ const keys = Reflect.ownKeys(descriptors);
67
+ if (
68
+ keys.some(
69
+ (key) =>
70
+ typeof key !== "string" ||
71
+ !TLS_KEYS.has(key) ||
72
+ !Object.prototype.hasOwnProperty.call(descriptors[key], "value") ||
73
+ descriptors[key].enumerable !== true,
74
+ )
75
+ ) {
76
+ return null;
77
+ }
78
+ return Object.fromEntries(keys.map((key) => [key, descriptors[key].value]));
79
+ }
80
+
81
+ function absoluteFile(value, label) {
82
+ if (value == null || value === "") return null;
83
+ if (typeof value !== "string" || !path.isAbsolute(value)) {
84
+ throw tlsError(
85
+ "CC_MCP_TLS_CONFIG_INVALID",
86
+ `MCP TLS ${label} must be an absolute file path`,
87
+ );
88
+ }
89
+ return path.resolve(value);
90
+ }
91
+
92
+ function validServerName(value) {
93
+ if (typeof value !== "string" || value.length === 0 || value.length > 253) {
94
+ return false;
95
+ }
96
+ return value
97
+ .split(".")
98
+ .every(
99
+ (label) =>
100
+ label.length > 0 &&
101
+ label.length <= 63 &&
102
+ /^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/u.test(label),
103
+ );
104
+ }
105
+
106
+ export function normalizeMcpTlsConfig(value) {
107
+ if (value == null) return null;
108
+ const snapshot = plainTlsObject(value);
109
+ if (!snapshot) {
110
+ throw tlsError(
111
+ "CC_MCP_TLS_CONFIG_INVALID",
112
+ "MCP TLS configuration must be a plain allowlisted data object",
113
+ );
114
+ }
115
+ const certFile = absoluteFile(snapshot.certFile, "certFile");
116
+ const keyFile = absoluteFile(snapshot.keyFile, "keyFile");
117
+ if (Boolean(certFile) !== Boolean(keyFile)) {
118
+ throw tlsError(
119
+ "CC_MCP_TLS_CONFIG_INVALID",
120
+ "MCP TLS certFile and keyFile must be configured together",
121
+ );
122
+ }
123
+ const caFile = absoluteFile(snapshot.caFile, "caFile");
124
+ if (!certFile && !caFile) {
125
+ throw tlsError(
126
+ "CC_MCP_TLS_CONFIG_INVALID",
127
+ "MCP TLS configuration requires a client certificate or CA file",
128
+ );
129
+ }
130
+ const serverName = snapshot.serverName == null ? null : snapshot.serverName;
131
+ if (serverName != null && !validServerName(serverName)) {
132
+ throw tlsError(
133
+ "CC_MCP_TLS_CONFIG_INVALID",
134
+ "MCP TLS serverName must be a valid DNS name",
135
+ );
136
+ }
137
+ if (
138
+ snapshot.rejectUnauthorized != null &&
139
+ typeof snapshot.rejectUnauthorized !== "boolean"
140
+ ) {
141
+ throw tlsError(
142
+ "CC_MCP_TLS_CONFIG_INVALID",
143
+ "MCP TLS rejectUnauthorized must be boolean",
144
+ );
145
+ }
146
+ return {
147
+ certFile,
148
+ keyFile,
149
+ caFile,
150
+ serverName,
151
+ rejectUnauthorized: snapshot.rejectUnauthorized !== false,
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Convert TLS settings from the organization-managed MCP loader into an
157
+ * immutable, non-forgeable configuration capability.
158
+ *
159
+ * This is deliberately separate from `normalizeMcpTlsConfig`: normalization
160
+ * validates data, while provisioning records the trusted source provenance
161
+ * that is required before a certificate/key/CA file can be opened.
162
+ */
163
+ export function provisionManagedMcpTlsConfig(value) {
164
+ const config = normalizeMcpTlsConfig(value);
165
+ if (!config) return null;
166
+ const provisioned = Object.freeze({ ...config });
167
+ MANAGED_MCP_TLS_PROVENANCE.set(
168
+ provisioned,
169
+ Object.freeze({ configScope: MANAGED_MCP_TLS_SCOPE }),
170
+ );
171
+ return provisioned;
172
+ }
173
+
174
+ /**
175
+ * Enforce the managed source boundary before any TLS path is normalized or
176
+ * opened. The private provenance association survives normal config-object
177
+ * spreads because the provisioned `tls` value itself is preserved, but a
178
+ * caller cannot manufacture it from JSON or by setting `configScope`.
179
+ */
180
+ export function assertManagedMcpTlsConfig(value, { configScope } = {}) {
181
+ if (value == null) return null;
182
+ const provenance =
183
+ value && typeof value === "object"
184
+ ? MANAGED_MCP_TLS_PROVENANCE.get(value)
185
+ : null;
186
+ if (
187
+ !provenance ||
188
+ configScope !== MANAGED_MCP_TLS_SCOPE ||
189
+ provenance.configScope !== MANAGED_MCP_TLS_SCOPE
190
+ ) {
191
+ throw managedTlsSourceRequiredError();
192
+ }
193
+ return value;
194
+ }
195
+
196
+ function readTlsFile(filePath, label, fsImpl) {
197
+ if (!filePath) return null;
198
+ let descriptor = null;
199
+ let stat;
200
+ try {
201
+ const link = fsImpl.lstatSync(filePath);
202
+ if (link.isSymbolicLink()) {
203
+ throw tlsError(
204
+ "CC_MCP_TLS_FILE_UNSAFE",
205
+ `MCP TLS ${label} must not be a symbolic link`,
206
+ );
207
+ }
208
+ const constants = fsImpl.constants || fs.constants;
209
+ descriptor = fsImpl.openSync(
210
+ filePath,
211
+ constants.O_RDONLY | (constants.O_NOFOLLOW || 0),
212
+ );
213
+ stat = fsImpl.fstatSync(descriptor);
214
+ } catch (cause) {
215
+ if (descriptor != null) fsImpl.closeSync?.(descriptor);
216
+ if (cause?.code?.startsWith?.("CC_MCP_TLS_")) throw cause;
217
+ throw tlsError(
218
+ "CC_MCP_TLS_FILE_UNAVAILABLE",
219
+ `MCP TLS ${label} could not be inspected`,
220
+ cause,
221
+ );
222
+ }
223
+ if (!stat.isFile() || stat.size <= 0 || stat.size > MCP_TLS_MAX_FILE_BYTES) {
224
+ fsImpl.closeSync?.(descriptor);
225
+ throw tlsError(
226
+ "CC_MCP_TLS_FILE_UNSAFE",
227
+ `MCP TLS ${label} must be a non-empty regular file no larger than ${MCP_TLS_MAX_FILE_BYTES} bytes`,
228
+ );
229
+ }
230
+ if (
231
+ label === "keyFile" &&
232
+ process.platform !== "win32" &&
233
+ (stat.mode & 0o077) !== 0
234
+ ) {
235
+ fsImpl.closeSync?.(descriptor);
236
+ throw tlsError(
237
+ "CC_MCP_TLS_FILE_UNSAFE",
238
+ "MCP TLS keyFile must not be readable or writable by group/other users",
239
+ );
240
+ }
241
+ try {
242
+ return fsImpl.readFileSync(descriptor);
243
+ } catch (cause) {
244
+ throw tlsError(
245
+ "CC_MCP_TLS_FILE_UNAVAILABLE",
246
+ `MCP TLS ${label} could not be read`,
247
+ cause,
248
+ );
249
+ } finally {
250
+ fsImpl.closeSync?.(descriptor);
251
+ }
252
+ }
253
+
254
+ function updateDigestPart(hash, value) {
255
+ const bytes = value || Buffer.alloc(0);
256
+ const length = Buffer.alloc(4);
257
+ length.writeUInt32BE(bytes.length);
258
+ hash.update(length).update(bytes);
259
+ }
260
+
261
+ function validateCertificateBytes(bytes) {
262
+ if (!bytes) return;
263
+ const text = bytes.toString("utf8");
264
+ const pemCertificates = text.match(
265
+ /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/gu,
266
+ );
267
+ if (pemCertificates?.length) {
268
+ for (const certificate of pemCertificates) new X509Certificate(certificate);
269
+ return;
270
+ }
271
+ new X509Certificate(bytes);
272
+ }
273
+
274
+ export function loadMcpTlsMaterial(
275
+ value,
276
+ {
277
+ configScope,
278
+ fsImpl = fs,
279
+ createSecureContextImpl = createSecureContext,
280
+ validateCertificateImpl = validateCertificateBytes,
281
+ } = {},
282
+ ) {
283
+ const config = assertManagedMcpTlsConfig(value, { configScope });
284
+ if (!config) return null;
285
+ const cert = readTlsFile(config.certFile, "certFile", fsImpl);
286
+ const key = readTlsFile(config.keyFile, "keyFile", fsImpl);
287
+ const ca = readTlsFile(config.caFile, "caFile", fsImpl);
288
+ const connectOptions = {
289
+ ...(cert ? { cert } : {}),
290
+ ...(key ? { key } : {}),
291
+ ...(ca ? { ca } : {}),
292
+ ...(config.serverName ? { servername: config.serverName } : {}),
293
+ rejectUnauthorized: config.rejectUnauthorized,
294
+ };
295
+ try {
296
+ // Parse certificates and verify the client cert/key pair before creating a
297
+ // dispatcher or issuing any outbound request. Node/Undici would otherwise
298
+ // discover malformed or mismatched material only during a network dial.
299
+ validateCertificateImpl(cert);
300
+ validateCertificateImpl(ca);
301
+ createSecureContextImpl(connectOptions);
302
+ } catch {
303
+ // TLS parser diagnostics may quote attacker-controlled PEM text or paths.
304
+ // Keep the product error fixed and do not retain the parser error as cause.
305
+ throw tlsError(
306
+ "CC_MCP_TLS_MATERIAL_INVALID",
307
+ "MCP TLS certificate material is invalid or the client key does not match",
308
+ );
309
+ }
310
+ const identityHash = createHash("sha256");
311
+ updateDigestPart(identityHash, cert);
312
+ updateDigestPart(identityHash, key);
313
+ updateDigestPart(identityHash, ca);
314
+ const identityDigest = `sha256:${identityHash.digest("hex")}`;
315
+ return { connectOptions, identityDigest };
316
+ }
317
+
318
+ export function createMcpTlsDispatcher(material) {
319
+ if (!material?.connectOptions) return null;
320
+ return new Agent({ connect: material.connectOptions });
321
+ }
322
+
323
+ export async function closeMcpTlsDispatcher(dispatcher) {
324
+ if (!dispatcher) return;
325
+ if (typeof dispatcher.close === "function") {
326
+ await dispatcher.close();
327
+ } else if (typeof dispatcher.destroy === "function") {
328
+ dispatcher.destroy();
329
+ }
330
+ }
@@ -33,6 +33,18 @@ export const BUILTIN_OUTPUT_STYLES = Object.freeze({
33
33
  body: "",
34
34
  builtin: true,
35
35
  },
36
+ concise: {
37
+ name: "concise",
38
+ description: "Uses short, direct responses with minimal explanation.",
39
+ body: [
40
+ "## Output style: Concise",
41
+ "Respond directly and briefly. Prefer the smallest complete answer that",
42
+ "preserves essential context, decisions, verification results, and safety",
43
+ "warnings. Avoid restating the request, long preambles, and optional",
44
+ "tangents unless the user asks for more detail.",
45
+ ].join("\n"),
46
+ builtin: true,
47
+ },
36
48
  explanatory: {
37
49
  name: "explanatory",
38
50
  description: "Explains the reasoning and trade-offs behind changes.",