chainlesschain 0.162.147 → 0.162.149

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 (257) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DywJ7xTv.js → AIOps-BJif14yR.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-BTlqcY-q.js → ActionButton-CXek6gJY.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-FdG1Mvwy.js → Analytics-BgQhdAJi.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CVsnbvN1.js → AppLayout-DTYl5NtR.js} +5 -5
  8. package/src/assets/web-panel/assets/{Audit-ITdpJ7vR.js → Audit-BzATQAeR.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BfXqnXo1.js → Backup-BzdPEQhL.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-C09ip3_E.js → BaseInput-BM0KVh8E.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-qdkhB42l.js → Chat-D7fHXHkz.js} +6 -6
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-D2KfETZD.js → ChatBubbleRenderer-Wm34RR-b.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-j6WZCuff.js → Checkbox-CAiSQ9vO.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-CGZ-K3uK.js → Codegen-Df40CrEe.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-CIlPOAu6.js → Col-DIT2fNFU.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-sY-i-hic.js → Community-CSTIbW2k.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DcoEfyL8.js → Compact-DtqXZZUi.js} +1 -1
  18. package/src/assets/web-panel/assets/Compliance-CUtzw6o7.js +1 -0
  19. package/src/assets/web-panel/assets/{Cowork-DLY_fkLv.js → Cowork-CezmlnmU.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-D049pZBC.js → Cron-P4BITarg.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-DCXdE8M9.js → Crosschain-BRRiYwvq.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-JCvPZtjW.js → DID-L5ijB9i4.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-Cg2xu3iE.js → Dashboard-CFxro4ob.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DjJLjbLh.js → Dropdown-BmAFCQ71.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DugNcSLR.js → EmailListRenderer-DJBCEuon.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-J6Nb-E30.js → FamilyGuardDashboard-z4oLq6eT.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-CQ3Ttpbl.js → Federation-DsVCpHMF.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-Cz0NKag4.js → FormItemContext-DP3bP5th.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-NYcMP6iz.js → GenericCardRenderer-BAXP2Gc6.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-B4hYN18N.js → Git-I3g_bAw9.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DOQPCcC0.js → Governance-jHS5-ioS.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-HtLF746W.js → Inference-CPL7sfx9.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-BXrk8rMm.js → KnowledgeGraph-Jf236h4C.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DS0JnD3-.js → Logs-Cm2tcSKg.js} +2 -2
  35. package/src/assets/web-panel/assets/{Marketplace-Cqnjihrz.js → Marketplace-CZK82rhi.js} +1 -1
  36. package/src/assets/web-panel/assets/{McpTools-Cx3Psk-U.js → McpTools-CZCeji7a.js} +5 -5
  37. package/src/assets/web-panel/assets/{Memory-BjyysPtj.js → Memory-3l2KVS9k.js} +2 -2
  38. package/src/assets/web-panel/assets/MobileBridge-D3Arxfeg.css +1 -0
  39. package/src/assets/web-panel/assets/MobileBridge-VYdpoLh6.js +1 -0
  40. package/src/assets/web-panel/assets/{MobileProjects-Xwf-fdOQ.js → MobileProjects-CiB9cmm1.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-Djkql5m5.js → Mtc-wCFZbBuL.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-D2BAZlu0.js → MtcAudit-1a3THIyG.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-ByqP1ZzH.js → Multisig-DMzLB2hG.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-C_kn0nE2.js → NLProgramming-D9wZbf6l.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-7l7eXHPq.js → Notes-hrFe2ZM-.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BrCDoitw.js → NotificationSettings-CHGX5Jwm.js} +1 -1
  47. package/src/assets/web-panel/assets/OrderTableRenderer-CRIFE2Tj.js +1 -0
  48. package/src/assets/web-panel/assets/{Organization-DdoNAxsM.js → Organization-By7FkhtY.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Bw7R6dE3.js → Overflow--khGSzJn.js} +1 -1
  50. package/src/assets/web-panel/assets/{OverrideContext-C2r4vyBb.js → OverrideContext-BlgL9440.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-DJNtBugA.js → P2P-CAG9dH35.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-Dwhd5_ue.js → PdhVaultBrowser-B3SQZmK9.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-BYoSfhPR.js → Permissions-D35ec6JA.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-aYCYJbnH.js → PersonalDataHub-CxBF7hW_.js} +2 -2
  55. package/src/assets/web-panel/assets/{Pipeline-DJp6CprF.js → Pipeline-s6EtOO1s.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-Cq9HZweR.js → Privacy-BbJYmWmO.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-CmF0HsSt.js → ProjectInit-VGQq1jMT.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-P8V5Aea2.js → ProjectSettings-B1ew3Teh.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-CGcNIs_g.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-D589v0q2.js → Providers-mrO47FIK.js} +1 -1
  61. package/src/assets/web-panel/assets/QrScannerModal-IJF2mHyw.js +1 -0
  62. package/src/assets/web-panel/assets/{MobileBridge-zJpPuf4E.css → QrScannerModal-NwAHNfiJ.css} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-lvRV2osB.js → QuickAsk-CU0wN_Z0.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-sb84MTpY.js → Recommend-DhN37R6G.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-D_xOX_hu.js +4 -0
  66. package/src/assets/web-panel/assets/{Reputation-d9Y3vy-W.js → Reputation-D_Ssv7uH.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-DMdhLUTp.js → Row-Kx5dKxX7.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-OL-SMDkz.js → RssFeed-BlGwqZkY.js} +2 -2
  69. package/src/assets/web-panel/assets/{Search-BjStLKq1.js → Search-hLFQzxpb.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-MeI411qr.js → Security-DMlvsVt4.js} +2 -2
  71. package/src/assets/web-panel/assets/{Services-UajosuhT.js → Services-Bd0Qsj2m.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-CGpG-QJ1.js → Skeleton-DFclq9X3.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-C6P2RPY-.js → Skills-BNtln2qY.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-B_fPprgw.js → Sla-Dch5H19G.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-CqxLjSlQ.js → SpeechSettings-2UfQcU1g.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-DixSfFOQ.js → SyncSettings-CD9YQr4i.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-PavzPBxc.js → Tasks-BNu-7MzI.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-BYdGRnfX.js → Templates-D1n9CaIR.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-BQLgnarD.js → Tenant-DenL3iBW.js} +1 -1
  80. package/src/assets/web-panel/assets/Terminal-ZzU0Io1Y.js +3 -0
  81. package/src/assets/web-panel/assets/{TimelineRenderer-Bv7uZRM7.js → TimelineRenderer-D87IfukO.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-DxhgszRJ.js → Tokens-BkiZc8E3.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-nQYHayuc.js → Trigger-BNRSytGN.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-CvqZDuZ4.js → Trust-Bwbd4X2m.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DaR8GV2I.js → UkeySign-B8O2bs0o.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-C6Mpsokw.js → VideoEditing-C2fL8zmH.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-B57VRrWc.js → Wallet-BORYDdE1.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-BbtEEtpq.js → WebAuthn-C0V5S2FM.js} +4 -4
  89. package/src/assets/web-panel/assets/{WorkflowEditor-C5LwvKmH.js → WorkflowEditor-2dR0fcHL.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-MzuPR5jh.js → chat-BmuAFAn8.js} +1 -1
  91. package/src/assets/web-panel/assets/{collapseMotion-mxzzcDsg.js → collapseMotion-DVfhbsdP.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-HyW8mi_y.js → colors-CN3smMcK.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-DvUSzWAp.js → compact-item-DCnxb4kW.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-4MppZl7X.js → createContext-vlR43pHn.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DxwmsL4j.js +1 -0
  96. package/src/assets/web-panel/assets/{echarts-jxgIOFUZ.js → echarts-CL0F2SnX.js} +1 -1
  97. package/src/assets/web-panel/assets/{hasIn-D9q3CJ-u.js → hasIn-D04tHYFd.js} +1 -1
  98. package/src/assets/web-panel/assets/{icons-DP3uiYxy.js → icons-BsDmGpcT.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-C9I5MuJ0.js → index-0DnaZGkC.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Caqtu6Et.js → index-430S68MN.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-eOQO6KnV.js → index-B78xL3s2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Ci6adKh8.js → index-BTPEZTk1.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CifKUNtV.js → index-BXRg8GFQ.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-D7TDMMfu.js → index-BasvsWDM.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DNYqw0MO.js → index-BeGDEXFs.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-m0b6Fj9q.js → index-BqhASEL4.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BF2JsbiX.js → index-BudvKQfG.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DFqvWeGc.js → index-C-6NO5il.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-SDblbKj6.js → index-C5Sxb1sE.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-UUMCA2Sq.js → index-CP9m9Ggr.js} +4 -4
  111. package/src/assets/web-panel/assets/{index--Bm6OqmU.js → index-CTOCnIQ7.js} +1 -1
  112. package/src/assets/web-panel/assets/index-Cg2ldRfU.js +1 -0
  113. package/src/assets/web-panel/assets/{index-Dv7ffI2g.js → index-ClhAHDK3.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BcunsBIx.js → index-CnXebZLL.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CvAqCAo9.js → index-CngCC8hC.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DcMkjb92.js → index-Cr-A0FYJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BFGfC5RS.js → index-CsAsCPJ6.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DDZ6fP5Z.js → index-D28DeAAB.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CgIfXOD9.js → index-D5LZVZ0L.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DmZ6-suL.js → index-D65_XseV.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Cs-RKRUM.js → index-D8vwp4qp.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B994UQfE.js → index-DDwLgQY9.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Btz8pU68.js → index-DIpY0qM5.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-B5E4DhVc.js → index-DTWg-18U.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-D2jrnaq3.js → index-DTtRscUa.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BmCo2Xdp.js → index-DYAtmqiv.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Zvtru2oE.js → index-D_n8_vfI.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CLAZs1Vd.js → index-DbADHwhr.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CucRo4Vz.js → index-DbVsQBOH.js} +1 -1
  130. package/src/assets/web-panel/assets/index-Dwzo-dtJ.js +1 -0
  131. package/src/assets/web-panel/assets/{index-C0DiL97c.js → index-HhNjnCfe.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Bl-E4W4q.js → index-ToUh2b1-.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-ryFLxB1p.js → index-TslMTwNy.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BGQtFso0.js → index-_FIkN3jd.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-zLwYpvX0.js → index-hpvvtAZ3.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-Dvg5xYuP.js → index-jzR7Ujuw.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-xvUVuFnA.js → index-ljuBiQW9.js} +1 -1
  138. package/src/assets/web-panel/assets/{initDefaultProps-CC--PMsC.js → initDefaultProps-C3wUb4je.js} +1 -1
  139. package/src/assets/web-panel/assets/{motion-DdrBjRF1.js → motion-D-jYFUNA.js} +1 -1
  140. package/src/assets/web-panel/assets/{move-D712Gwl2.js → move-tqb8nwJ2.js} +1 -1
  141. package/src/assets/web-panel/assets/{mtc-parser-39y-keKO.js → mtc-parser-DSOjMJMz.js} +1 -1
  142. package/src/assets/web-panel/assets/{omit-6Y51gDB9.js → omit-CJ7VimIW.js} +1 -1
  143. package/src/assets/web-panel/assets/{pickAttrs-Cy6EHbq9.js → pickAttrs-qXiG1iT3.js} +1 -1
  144. package/src/assets/web-panel/assets/{placementArrow-BYxdAm0p.js → placementArrow-CkGBcy1Z.js} +1 -1
  145. package/src/assets/web-panel/assets/{responsiveObserve-C9R6q_cr.js → responsiveObserve-D3WvTlLO.js} +1 -1
  146. package/src/assets/web-panel/assets/{slide-CXUJlilB.js → slide-BEE2ftge.js} +1 -1
  147. package/src/assets/web-panel/assets/{statusUtils-DOtrOeql.js → statusUtils-CsfBpxiG.js} +1 -1
  148. package/src/assets/web-panel/assets/{styleChecker-D5r39o92.js → styleChecker-xPrIiJPI.js} +1 -1
  149. package/src/assets/web-panel/assets/useFlexGapSupport-C5Yd-SCR.js +1 -0
  150. package/src/assets/web-panel/assets/{useFs-BkrT-Zbc.js → useFs-D_MDS8HI.js} +1 -1
  151. package/src/assets/web-panel/assets/{useMergedState-Cl2q1fes.js → useMergedState-Dc9sO2d7.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-BwnnnZjU.js → usePersonalDataHub-BqJh-usA.js} +1 -1
  153. package/src/assets/web-panel/assets/{useRefs-DD9q4mOT.js → useRefs-CAeFRzPf.js} +1 -1
  154. package/src/assets/web-panel/assets/{useState-BK4hy8Ma.js → useState-LwExUYDO.js} +1 -1
  155. package/src/assets/web-panel/assets/{vendor-BvqAck49.js → vendor-BMxUs6UX.js} +16 -16
  156. package/src/assets/web-panel/assets/{vnode-SU-N4pum.js → vnode-chm_p-gz.js} +1 -1
  157. package/src/assets/web-panel/assets/{zoom-DHScfpTP.js → zoom-3-YDNz0Z.js} +1 -1
  158. package/src/assets/web-panel/index.html +3 -3
  159. package/src/assets/web-panel/remote-session-sw.js +43 -0
  160. package/src/command-manifest.json +22 -1
  161. package/src/commands/agent.js +44 -5
  162. package/src/commands/codeintel.js +252 -0
  163. package/src/commands/eval.js +248 -0
  164. package/src/commands/plugin.js +354 -0
  165. package/src/commands/serve.js +10 -0
  166. package/src/commands/team.js +456 -0
  167. package/src/gateways/remote-session-relay.js +160 -0
  168. package/src/gateways/ws/message-dispatcher.js +77 -2
  169. package/src/gateways/ws/remote-session-protocol.js +466 -0
  170. package/src/gateways/ws/ws-server.js +299 -0
  171. package/src/harness/golden-transcript.js +65 -0
  172. package/src/harness/mcp-client.js +6 -2
  173. package/src/harness/prompt-compressor.js +27 -1
  174. package/src/harness/remote-command-ledger.js +158 -0
  175. package/src/harness/remote-session-audit-sink.js +132 -0
  176. package/src/harness/remote-session-audit.js +110 -0
  177. package/src/harness/remote-session-crypto.js +217 -0
  178. package/src/harness/remote-session-push-apns.js +246 -0
  179. package/src/harness/remote-session-push-errors.js +15 -0
  180. package/src/harness/remote-session-push-fcm.js +238 -0
  181. package/src/harness/remote-session-push-huawei.js +174 -0
  182. package/src/harness/remote-session-push-oppo.js +171 -0
  183. package/src/harness/remote-session-push-senders.js +42 -0
  184. package/src/harness/remote-session-push-vivo.js +179 -0
  185. package/src/harness/remote-session-push-web.js +299 -0
  186. package/src/harness/remote-session-push-xiaomi.js +99 -0
  187. package/src/harness/remote-session-push.js +104 -0
  188. package/src/harness/remote-session-registry.js +420 -0
  189. package/src/index.js +6 -0
  190. package/src/lib/agent-core.js +2 -0
  191. package/src/lib/agent-sandbox.js +161 -5
  192. package/src/lib/agent-team/task-lease.js +434 -0
  193. package/src/lib/agent-team/team-budget.js +165 -0
  194. package/src/lib/agent-team/team-mailbox.js +106 -0
  195. package/src/lib/agent-team/team-runner.js +266 -0
  196. package/src/lib/agent-team/team-worktree.js +204 -0
  197. package/src/lib/agents.js +18 -0
  198. package/src/lib/async-hook-supervisor.cjs +305 -0
  199. package/src/lib/did-manager.js +6 -4
  200. package/src/lib/eval/runner.js +163 -0
  201. package/src/lib/eval/tasks.js +456 -0
  202. package/src/lib/eval/trend.js +185 -0
  203. package/src/lib/lsp/__tests__/code-intelligence.integration.test.js +129 -0
  204. package/src/lib/lsp/__tests__/code-intelligence.test.js +228 -0
  205. package/src/lib/lsp/__tests__/jsonrpc-stream.test.js +104 -0
  206. package/src/lib/lsp/__tests__/lsp-client.test.js +258 -0
  207. package/src/lib/lsp/__tests__/lsp-manager.test.js +264 -0
  208. package/src/lib/lsp/__tests__/lsp-server-registry.test.js +128 -0
  209. package/src/lib/lsp/code-intelligence.js +356 -0
  210. package/src/lib/lsp/jsonrpc-stream.js +139 -0
  211. package/src/lib/lsp/lsp-client.js +318 -0
  212. package/src/lib/lsp/lsp-manager.js +323 -0
  213. package/src/lib/lsp/lsp-server-registry.js +196 -0
  214. package/src/lib/mcp-oauth.js +23 -6
  215. package/src/lib/plugin-monitor-supervisor.js +238 -0
  216. package/src/lib/plugin-runtime/agents.js +51 -0
  217. package/src/lib/plugin-runtime/bin.js +100 -0
  218. package/src/lib/plugin-runtime/hooks.js +100 -0
  219. package/src/lib/plugin-runtime/install.js +388 -0
  220. package/src/lib/plugin-runtime/lsp.js +75 -0
  221. package/src/lib/plugin-runtime/manifest.js +458 -0
  222. package/src/lib/plugin-runtime/mcp.js +89 -0
  223. package/src/lib/plugin-runtime/monitors.js +100 -0
  224. package/src/lib/plugin-runtime/policy.js +144 -0
  225. package/src/lib/plugin-runtime/reload.js +79 -0
  226. package/src/lib/plugin-runtime/scopes.js +197 -0
  227. package/src/lib/plugin-runtime/settings.js +119 -0
  228. package/src/lib/plugin-runtime/signature.js +107 -0
  229. package/src/lib/plugin-runtime/skills.js +43 -0
  230. package/src/lib/plugin-runtime/trust.js +140 -0
  231. package/src/lib/sandbox-egress-proxy.js +162 -0
  232. package/src/lib/sandbox-network-policy.js +134 -0
  233. package/src/lib/sandbox-v2.js +10 -4
  234. package/src/lib/session-manager.js +7 -3
  235. package/src/lib/settings-hook-events.cjs +78 -6
  236. package/src/lib/settings-hooks.cjs +29 -3
  237. package/src/lib/settings-loader.cjs +35 -1
  238. package/src/lib/skill-loader.js +18 -0
  239. package/src/lib/telemetry/span-recorder.js +237 -0
  240. package/src/repl/agent-repl.js +400 -4
  241. package/src/runtime/agent-core.js +546 -52
  242. package/src/runtime/agent-runtime.js +8 -13
  243. package/src/runtime/coding-agent-contract-shared.cjs +82 -8
  244. package/src/runtime/coding-agent-policy.cjs +32 -7
  245. package/src/runtime/fallback-model.js +134 -7
  246. package/src/runtime/headless-runner.js +353 -108
  247. package/src/runtime/mcp-config.js +46 -0
  248. package/src/runtime/policies/agent-policy.js +2 -0
  249. package/src/assets/web-panel/assets/Compliance-T8EtTecW.js +0 -1
  250. package/src/assets/web-panel/assets/MobileBridge-CYaITZ7w.js +0 -1
  251. package/src/assets/web-panel/assets/OrderTableRenderer-CmtqIdwr.js +0 -1
  252. package/src/assets/web-panel/assets/Projects-DPd5-lNS.js +0 -1
  253. package/src/assets/web-panel/assets/Terminal-BzOHpq-B.js +0 -3
  254. package/src/assets/web-panel/assets/devWarning-6YJJMjSH.js +0 -1
  255. package/src/assets/web-panel/assets/index-D_oeGLr6.js +0 -1
  256. package/src/assets/web-panel/assets/index-Qa57YG19.js +0 -1
  257. package/src/assets/web-panel/assets/useFlexGapSupport-DfAD5U4Z.js +0 -1
@@ -315,9 +315,14 @@ export async function runAgentHeadless(options = {}, deps = {}) {
315
315
  const { loadHooks, projectHookTrustNotice } =
316
316
  await import("../lib/settings-hooks.cjs");
317
317
  const loaded = loadHooks({ cwd, settingsFile: options.settingsFile });
318
+ // Fold in installed plugins' hooks/hooks.json (Phase 3.3c) — plugins ADD
319
+ // to the user's settings hooks, never replace them.
320
+ const { mergePluginHooks } =
321
+ await import("../lib/plugin-runtime/hooks.js");
322
+ const effectiveHooks = mergePluginHooks(loaded.hooks, { cwd });
318
323
  settingsHooks =
319
- loaded.hooks && Object.keys(loaded.hooks).length > 0
320
- ? loaded.hooks
324
+ effectiveHooks && Object.keys(effectiveHooks).length > 0
325
+ ? effectiveHooks
321
326
  : null;
322
327
  // First-run trust notice for an untrusted/cloned repo's shell-running
323
328
  // hooks (Claude-Code 2.1.195 parity). Best-effort, stderr-only.
@@ -335,6 +340,26 @@ export async function runAgentHeadless(options = {}, deps = {}) {
335
340
  }
336
341
  }
337
342
 
343
+ // Put trusted plugins' bin/ executables on PATH for this headless run (Phase
344
+ // 3.3n) so run_shell can invoke them by name. Trust-gated. The process exits
345
+ // at the end of the run, so no explicit restore is needed.
346
+ try {
347
+ const { applyPluginBinPath } = await import("../lib/plugin-runtime/bin.js");
348
+ applyPluginBinPath({ cwd });
349
+ } catch {
350
+ /* best-effort — plugin bin PATH never blocks a headless run */
351
+ }
352
+
353
+ // Apply trusted plugins' default env vars for this run (Phase 3.3o) — only for
354
+ // keys not already set; the process exits at the end so no restore is needed.
355
+ try {
356
+ const { applyPluginSettingsEnv } =
357
+ await import("../lib/plugin-runtime/settings.js");
358
+ applyPluginSettingsEnv({ cwd });
359
+ } catch {
360
+ /* best-effort — plugin settings never block a headless run */
361
+ }
362
+
338
363
  // autoMode.classifyAllShell (Claude-Code 2.1.193): route the built-in
339
364
  // verification allowlist through the shell-policy classifier instead of
340
365
  // fast-pathing it. Explicit option wins; otherwise read settings.json.
@@ -668,6 +693,31 @@ export async function runAgentHeadless(options = {}, deps = {}) {
668
693
  }
669
694
  }
670
695
 
696
+ // settings.json SessionResume hooks: fire when a persisted session's prior
697
+ // history is actually being replayed (--resume / --continue with real
698
+ // history), distinct from SessionStart (which also fires on a fresh startup).
699
+ // A SessionResume hook can react to "we're picking an existing conversation
700
+ // back up" — e.g. re-run a workspace sanity check. Observe-only, best-effort.
701
+ if (settingsHooks && resumeId && history.length > 0) {
702
+ try {
703
+ const { runObserveHooks } =
704
+ await import("../lib/settings-hook-events.cjs");
705
+ runObserveHooks(
706
+ settingsHooks,
707
+ "SessionResume",
708
+ {
709
+ session_id: sessionId,
710
+ resumed_from: resumeId,
711
+ history_messages: history.length,
712
+ cwd,
713
+ },
714
+ { cwd },
715
+ );
716
+ } catch (_err) {
717
+ // observe-only
718
+ }
719
+ }
720
+
671
721
  // --image <path>: attach vision input to the user turn. buildUserContent
672
722
  // returns the plain string when there are no images, so text-only runs are
673
723
  // byte-for-byte unchanged; with images it builds an OpenAI-style multimodal
@@ -810,9 +860,40 @@ export async function runAgentHeadless(options = {}, deps = {}) {
810
860
  }
811
861
  }
812
862
 
863
+ // --otlp <file>: attach an OpenTelemetry recorder so the real agent loop's
864
+ // model/tool/retry spans are captured and exported as OTLP/JSON on exit.
865
+ // Off by default (zero cost) — only built when a path is requested.
866
+ let _otlpRecorder = null;
867
+ if (options.otlp) {
868
+ try {
869
+ const { TelemetryRecorder } =
870
+ await import("../lib/telemetry/span-recorder.js");
871
+ _otlpRecorder = new TelemetryRecorder({ serviceName: "cc-agent" });
872
+ } catch {
873
+ _otlpRecorder = null; // telemetry is best-effort, never blocks the run
874
+ }
875
+ }
876
+
877
+ // Async-hook supervisor for headless: without one, `async:true` hooks
878
+ // (PostToolUse / Stop) were silently skipped in `cc agent -p` (they only ran
879
+ // in the REPL). Create one when settings hooks are present so background
880
+ // checks run + get reaped here too. Fire-and-forget; drained after the loop.
881
+ let _hookSupervisor = null;
882
+ if (settingsHooks) {
883
+ try {
884
+ const { AsyncHookSupervisor } =
885
+ await import("../lib/async-hook-supervisor.cjs");
886
+ _hookSupervisor = new AsyncHookSupervisor();
887
+ } catch {
888
+ _hookSupervisor = null; // async hooks are best-effort
889
+ }
890
+ }
891
+
813
892
  const loopOptions = {
814
893
  model,
815
894
  provider,
895
+ recorder: _otlpRecorder,
896
+ hookSupervisor: _hookSupervisor,
816
897
  // Extended thinking (Anthropic; opt-in via --think/--ultrathink). null/off
817
898
  // → chatWithTools sends no thinking field. thinkingBudget (--thinking-budget)
818
899
  // is the legacy-model budget_tokens override; ignored when thinking is off.
@@ -950,126 +1031,224 @@ export async function runAgentHeadless(options = {}, deps = {}) {
950
1031
  goal_id: boundGoalId,
951
1032
  });
952
1033
 
1034
+ // --auto-rewake: after a turn finishes, run the async Stop hooks and, if an
1035
+ // `asyncRewake` check FAILED, append its report as a new user turn and re-run
1036
+ // the agent to fix it — bounded by `maxRewakes` (default 1). OPT-IN: when off
1037
+ // (the default), rewakeBudget is 0 and the loop below runs exactly once, so
1038
+ // one-shot `cc agent -p` behavior is byte-for-byte unchanged and no script is
1039
+ // surprised by a silent re-run. `_asyncStopHandled` tells the finally the
1040
+ // async Stop hooks already fired here so they aren't fired twice.
1041
+ const autoRewake = options.autoRewake === true;
1042
+ let rewakeBudget = autoRewake
1043
+ ? Number.isFinite(options.maxRewakes)
1044
+ ? options.maxRewakes
1045
+ : 1
1046
+ : 0;
1047
+ let _asyncStopHandled = false;
1048
+ const _settleAsyncStop = async () => {
1049
+ if (!settingsHooks || !_hookSupervisor) return { rewakes: [], results: [] };
1050
+ const { dispatchAsyncHooks } =
1051
+ await import("../lib/settings-hook-events.cjs");
1052
+ dispatchAsyncHooks(
1053
+ settingsHooks,
1054
+ "Stop",
1055
+ { reason: endReason, cwd, session_id: sessionId },
1056
+ { cwd, supervisor: _hookSupervisor },
1057
+ );
1058
+ const waitMs = Number.isFinite(options.asyncHookWaitMs)
1059
+ ? options.asyncHookWaitMs
1060
+ : 5000;
1061
+ const started = Date.now();
1062
+ while (
1063
+ _hookSupervisor.runningCount() > 0 &&
1064
+ Date.now() - started < waitMs
1065
+ ) {
1066
+ await new Promise((r) => setTimeout(r, 50));
1067
+ }
1068
+ return {
1069
+ rewakes: _hookSupervisor.drainRewakes(),
1070
+ results: _hookSupervisor.drainResults(),
1071
+ };
1072
+ };
1073
+
953
1074
  try {
954
- for await (const event of runLoop(messages, loopOptions)) {
955
- switch (event.type) {
956
- case "checkpoint": {
957
- if (isText)
958
- writeErr(` ⎌ checkpoint ${event.id} (before ${event.tool})\n`);
959
- emitStream({ type: "checkpoint", id: event.id, tool: event.tool });
960
- break;
961
- }
962
- case "tool-executing": {
963
- const line = ` [${event.tool}] ${formatToolArgs(event.tool, event.args)}`;
964
- if (isText) writeErr(line + "\n");
965
- emitStream({
966
- type: "tool_use",
967
- tool: event.tool,
968
- args: event.args,
969
- });
970
- toolCalls.push({ tool: event.tool, args: event.args });
971
- break;
972
- }
973
- case "tool-result": {
974
- const err = event.error || event.result?.error || null;
975
- if (isText && err) writeErr(` Error: ${err}\n`);
976
- emitStream({
977
- type: "tool_result",
978
- tool: event.tool,
979
- is_error: Boolean(err),
980
- error: err,
981
- result: event.result,
982
- });
983
- if (toolCalls.length > 0) {
984
- toolCalls[toolCalls.length - 1].is_error = Boolean(err);
1075
+ // eslint-disable-next-line no-constant-condition
1076
+ while (true) {
1077
+ for await (const event of runLoop(messages, loopOptions)) {
1078
+ switch (event.type) {
1079
+ case "checkpoint": {
1080
+ if (isText)
1081
+ writeErr(` ⎌ checkpoint ${event.id} (before ${event.tool})\n`);
1082
+ emitStream({ type: "checkpoint", id: event.id, tool: event.tool });
1083
+ break;
1084
+ }
1085
+ case "tool-executing": {
1086
+ const line = ` [${event.tool}] ${formatToolArgs(event.tool, event.args)}`;
1087
+ if (isText) writeErr(line + "\n");
1088
+ emitStream({
1089
+ type: "tool_use",
1090
+ tool: event.tool,
1091
+ args: event.args,
1092
+ });
1093
+ toolCalls.push({ tool: event.tool, args: event.args });
1094
+ break;
985
1095
  }
986
- // Track policy denials (not plain tool failures) for the end-of-run
987
- // summary. The preceding tool-executing pushed the args.
988
- if (err) {
989
- const last = toolCalls[toolCalls.length - 1];
990
- const denial = classifyDenial({
1096
+ case "tool-result": {
1097
+ const err = event.error || event.result?.error || null;
1098
+ if (isText && err) writeErr(` Error: ${err}\n`);
1099
+ emitStream({
1100
+ type: "tool_result",
991
1101
  tool: event.tool,
1102
+ is_error: Boolean(err),
1103
+ error: err,
992
1104
  result: event.result,
993
- error: event.error,
994
- argsSummary:
995
- last && last.tool === event.tool
996
- ? formatToolArgs(event.tool, last.args)
997
- : "",
998
1105
  });
999
- if (denial) {
1000
- recordDenial(denials, {
1001
- ...denial,
1002
- at: deps.now ? deps.now() : Date.now(),
1106
+ if (toolCalls.length > 0) {
1107
+ toolCalls[toolCalls.length - 1].is_error = Boolean(err);
1108
+ }
1109
+ // Track policy denials (not plain tool failures) for the end-of-run
1110
+ // summary. The preceding tool-executing pushed the args.
1111
+ if (err) {
1112
+ const last = toolCalls[toolCalls.length - 1];
1113
+ const denial = classifyDenial({
1114
+ tool: event.tool,
1115
+ result: event.result,
1116
+ error: event.error,
1117
+ argsSummary:
1118
+ last && last.tool === event.tool
1119
+ ? formatToolArgs(event.tool, last.args)
1120
+ : "",
1003
1121
  });
1122
+ if (denial) {
1123
+ recordDenial(denials, {
1124
+ ...denial,
1125
+ at: deps.now ? deps.now() : Date.now(),
1126
+ });
1127
+ }
1004
1128
  }
1129
+ break;
1005
1130
  }
1006
- break;
1007
- }
1008
- case "token-usage": {
1009
- usage.input_tokens += event.usage?.input_tokens || 0;
1010
- usage.output_tokens += event.usage?.output_tokens || 0;
1011
- // Carry prompt-cache tokens into accumulated usage (cost accuracy).
1012
- usage.cache_read_input_tokens +=
1013
- event.usage?.cache_read_input_tokens || 0;
1014
- usage.cache_creation_input_tokens +=
1015
- event.usage?.cache_creation_input_tokens || 0;
1016
- emitStream({ type: "token_usage", usage: event.usage });
1017
- if (costBudget) {
1018
- costBudget.add({
1019
- provider: event.provider,
1020
- model: event.model,
1021
- usage: event.usage,
1022
- });
1023
- if (costBudget.shouldWarnInactive()) {
1024
- const m = `cost cap $${options.maxCostUsd} set but model "${event.model}" is unpriced/free — cap inactive`;
1025
- if (isText) writeErr(` ${m}\n`);
1026
- emitStream({ type: "cost_warning", message: m });
1027
- }
1028
- if (costBudget.exceeded()) {
1029
- endReason = "cost-budget-exhausted";
1030
- stopForCost = true;
1031
- if (isText)
1032
- writeErr(
1033
- ` ⛔ cost budget $${options.maxCostUsd} reached (spent ≈$${costBudget.spentUsd}) — stopping\n`,
1034
- );
1035
- emitStream({
1036
- type: "cost_budget_exhausted",
1037
- limit_usd: options.maxCostUsd,
1038
- spent_usd: costBudget.spentUsd,
1131
+ case "token-usage": {
1132
+ usage.input_tokens += event.usage?.input_tokens || 0;
1133
+ usage.output_tokens += event.usage?.output_tokens || 0;
1134
+ // Carry prompt-cache tokens into accumulated usage (cost accuracy).
1135
+ usage.cache_read_input_tokens +=
1136
+ event.usage?.cache_read_input_tokens || 0;
1137
+ usage.cache_creation_input_tokens +=
1138
+ event.usage?.cache_creation_input_tokens || 0;
1139
+ emitStream({ type: "token_usage", usage: event.usage });
1140
+ if (costBudget) {
1141
+ costBudget.add({
1142
+ provider: event.provider,
1143
+ model: event.model,
1144
+ usage: event.usage,
1039
1145
  });
1146
+ if (costBudget.shouldWarnInactive()) {
1147
+ const m = `cost cap $${options.maxCostUsd} set but model "${event.model}" is unpriced/free — cap inactive`;
1148
+ if (isText) writeErr(` ${m}\n`);
1149
+ emitStream({ type: "cost_warning", message: m });
1150
+ }
1151
+ if (costBudget.exceeded()) {
1152
+ endReason = "cost-budget-exhausted";
1153
+ stopForCost = true;
1154
+ if (isText)
1155
+ writeErr(
1156
+ ` ⛔ cost budget $${options.maxCostUsd} reached (spent ≈$${costBudget.spentUsd}) — stopping\n`,
1157
+ );
1158
+ emitStream({
1159
+ type: "cost_budget_exhausted",
1160
+ limit_usd: options.maxCostUsd,
1161
+ spent_usd: costBudget.spentUsd,
1162
+ });
1163
+ }
1040
1164
  }
1165
+ break;
1041
1166
  }
1042
- break;
1167
+ case "iteration-warning": {
1168
+ if (isText) writeErr(` ${event.message}\n`);
1169
+ emitStream({ type: "iteration_warning", message: event.message });
1170
+ break;
1171
+ }
1172
+ case "iteration-budget-exhausted": {
1173
+ endReason = "max_turns";
1174
+ emitStream({
1175
+ type: "iteration_budget_exhausted",
1176
+ budget: event.budget,
1177
+ });
1178
+ break;
1179
+ }
1180
+ case "response-complete": {
1181
+ finalText = event.content || "";
1182
+ break;
1183
+ }
1184
+ case "run-ended": {
1185
+ if (event.reason) endReason = event.reason;
1186
+ break;
1187
+ }
1188
+ default:
1189
+ // slot-filling, run-started, etc. — surfaced only in stream mode.
1190
+ if (isStream && event.type) emitStream(event);
1191
+ break;
1043
1192
  }
1044
- case "iteration-warning": {
1045
- if (isText) writeErr(` ${event.message}\n`);
1046
- emitStream({ type: "iteration_warning", message: event.message });
1047
- break;
1193
+ // Hard cost cap reached: stop consuming the loop so no further paid LLM
1194
+ // call is made (break out of the for-await, not just the switch).
1195
+ if (stopForCost) break;
1196
+ }
1197
+ // ── auto-rewake re-drive (opt-in via --auto-rewake) ─────────────────
1198
+ // Under auto-rewake, settle the async Stop hooks after EVERY turn (so the
1199
+ // final turn's background check still runs). If an asyncRewake check
1200
+ // failed and re-drive budget remains, append its report as a new user
1201
+ // turn and loop; if a rewake failed but budget is spent, surface it and
1202
+ // stop. When auto-rewake is off, this whole block is skipped and the
1203
+ // `finally` handles Stop exactly as before (default behavior unchanged).
1204
+ if (
1205
+ autoRewake &&
1206
+ _hookSupervisor &&
1207
+ !stopForCost &&
1208
+ endReason !== "max_turns" &&
1209
+ endReason !== "cost-budget-exhausted"
1210
+ ) {
1211
+ const { rewakes, results } = await _settleAsyncStop();
1212
+ _asyncStopHandled = true;
1213
+ for (const rs of results) {
1214
+ if (rs.additionalContext)
1215
+ writeErr(`[async-hook] ${rs.command}: ${rs.additionalContext}\n`);
1048
1216
  }
1049
- case "iteration-budget-exhausted": {
1050
- endReason = "max_turns";
1051
- emitStream({
1052
- type: "iteration_budget_exhausted",
1053
- budget: event.budget,
1217
+ if (rewakes.length > 0 && rewakeBudget > 0) {
1218
+ rewakeBudget--;
1219
+ const detail = rewakes
1220
+ .map(
1221
+ (rw) =>
1222
+ `- ${rw.command} failed` +
1223
+ `${rw.exitCode != null ? ` (exit ${rw.exitCode})` : ""}` +
1224
+ `${rw.error ? `: ${rw.error}` : ""}`,
1225
+ )
1226
+ .join("\n");
1227
+ messages.push({
1228
+ role: "user",
1229
+ content:
1230
+ `A background check flagged a problem after your last turn:\n${detail}\n` +
1231
+ `Investigate and fix it, then confirm it passes.`,
1054
1232
  });
1055
- break;
1056
- }
1057
- case "response-complete": {
1058
- finalText = event.content || "";
1059
- break;
1233
+ if (isText)
1234
+ writeErr(
1235
+ ` ↻ async-hook rewake — re-engaging agent (${rewakeBudget} re-drive(s) left)\n`,
1236
+ );
1237
+ emitStream({ type: "rewake", remaining: rewakeBudget });
1238
+ finalText = "";
1239
+ endReason = "complete";
1240
+ continue; // re-drive: run another agent turn
1060
1241
  }
1061
- case "run-ended": {
1062
- if (event.reason) endReason = event.reason;
1063
- break;
1242
+ // A rewake fired but no budget remains — surface it (couldn't auto-fix).
1243
+ for (const rw of rewakes) {
1244
+ writeErr(
1245
+ `[async-hook REWAKE] ${rw.command} failed` +
1246
+ `${rw.exitCode != null ? ` (exit ${rw.exitCode})` : ""}` +
1247
+ `${rw.error ? `: ${rw.error}` : ""}\n`,
1248
+ );
1064
1249
  }
1065
- default:
1066
- // slot-filling, run-started, etc. — surfaced only in stream mode.
1067
- if (isStream && event.type) emitStream(event);
1068
- break;
1069
1250
  }
1070
- // Hard cost cap reached: stop consuming the loop so no further paid LLM
1071
- // call is made (break out of the for-await, not just the switch).
1072
- if (stopForCost) break;
1251
+ break;
1073
1252
  }
1074
1253
  } catch (err) {
1075
1254
  const message = err?.message || String(err);
@@ -1118,11 +1297,56 @@ export async function runAgentHeadless(options = {}, deps = {}) {
1118
1297
  } catch {
1119
1298
  // best-effort — never mask the run's own outcome
1120
1299
  }
1121
- // settings.json SessionEnd hooks (observe-only) when the run finishes.
1300
+ // settings.json Stop + SessionEnd hooks when the run finishes. Stop is the
1301
+ // canonical async-hook trigger ("run the test suite at turn end"); fire its
1302
+ // async hooks fire-and-forget, then settle so a fast background check can
1303
+ // report back within this one-shot run.
1122
1304
  if (settingsHooks) {
1123
1305
  try {
1124
- const { runObserveHooks } =
1306
+ const { runObserveHooks, dispatchAsyncHooks } =
1125
1307
  await import("../lib/settings-hook-events.cjs");
1308
+ const stopPayload = { reason: endReason, cwd, session_id: sessionId };
1309
+ runObserveHooks(settingsHooks, "Stop", stopPayload, { cwd });
1310
+ // Skip the async Stop dispatch/settle here if the auto-rewake re-drive
1311
+ // loop already fired + drained it this run (avoids double-execution).
1312
+ if (_hookSupervisor && !_asyncStopHandled) {
1313
+ dispatchAsyncHooks(settingsHooks, "Stop", stopPayload, {
1314
+ cwd,
1315
+ supervisor: _hookSupervisor,
1316
+ });
1317
+ // Bounded settle: wait for in-flight async hooks (Stop + any
1318
+ // PostToolUse dispatched during the loop) to finish, capped so a
1319
+ // slow/hung check can never stall the run. Default 5s; tunable.
1320
+ const waitMs = Number.isFinite(options.asyncHookWaitMs)
1321
+ ? options.asyncHookWaitMs
1322
+ : 5000;
1323
+ const started = Date.now();
1324
+ while (
1325
+ _hookSupervisor.runningCount() > 0 &&
1326
+ Date.now() - started < waitMs
1327
+ ) {
1328
+ await new Promise((r) => setTimeout(r, 50));
1329
+ }
1330
+ // Surface any results/rewakes out-of-band on stderr (never touches the
1331
+ // stdout envelope). A rewake means a background check FAILED and would
1332
+ // re-engage the agent in an interactive session — flag it clearly so a
1333
+ // headless caller/CI can react.
1334
+ for (const rw of _hookSupervisor.drainRewakes()) {
1335
+ writeErr(
1336
+ `[async-hook REWAKE] ${rw.command} failed` +
1337
+ `${rw.exitCode != null ? ` (exit ${rw.exitCode})` : ""}` +
1338
+ `${rw.error ? `: ${rw.error}` : ""}\n`,
1339
+ );
1340
+ }
1341
+ for (const rs of _hookSupervisor.drainResults()) {
1342
+ if (rs.additionalContext) {
1343
+ writeErr(`[async-hook] ${rs.command}: ${rs.additionalContext}\n`);
1344
+ }
1345
+ }
1346
+ }
1347
+ // Always reap the supervisor (kills any straggler child + detaches the
1348
+ // exit reaper), whether the async Stop was handled here or in re-drive.
1349
+ if (_hookSupervisor) _hookSupervisor.stopAll();
1126
1350
  runObserveHooks(
1127
1351
  settingsHooks,
1128
1352
  "SessionEnd",
@@ -1130,7 +1354,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
1130
1354
  { cwd },
1131
1355
  );
1132
1356
  } catch {
1133
- // observe-only
1357
+ // observe-only + best-effort async surfacing
1134
1358
  }
1135
1359
  }
1136
1360
  }
@@ -1259,6 +1483,27 @@ export async function runAgentHeadless(options = {}, deps = {}) {
1259
1483
  writeOut(finalText + (finalText.endsWith("\n") ? "" : "\n"));
1260
1484
  }
1261
1485
 
1486
+ // --otlp: write the captured spans/counters as OTLP/JSON. Best-effort — a
1487
+ // write failure logs to stderr but never changes the run's exit code.
1488
+ if (_otlpRecorder && options.otlp) {
1489
+ try {
1490
+ const fsp = await import("node:fs");
1491
+ fsp.writeFileSync(
1492
+ options.otlp,
1493
+ JSON.stringify(_otlpRecorder.toOtlp(), null, 2),
1494
+ "utf-8",
1495
+ );
1496
+ if (!isStream) {
1497
+ const sum = _otlpRecorder.summary();
1498
+ process.stderr.write(
1499
+ `[otlp] ${sum.spanCount} span(s) → ${options.otlp}\n`,
1500
+ );
1501
+ }
1502
+ } catch (err) {
1503
+ process.stderr.write(`[otlp] export failed: ${err.message}\n`);
1504
+ }
1505
+ }
1506
+
1262
1507
  return { exitCode: isError ? 1 : 0, result: finalText, isError };
1263
1508
  }
1264
1509
 
@@ -33,6 +33,7 @@ import {
33
33
  jetbrainsServerToMcpConfig,
34
34
  isInJetbrainsContext,
35
35
  } from "../lib/jetbrains-bridge.js";
36
+ import { collectPluginMcpServers } from "../lib/plugin-runtime/mcp.js";
36
37
 
37
38
  /**
38
39
  * Normalize a parsed config object into a `{ name: serverConfig }` map.
@@ -644,6 +645,39 @@ export async function loadProjectMcp(opts = {}, deps = {}) {
644
645
  return setupMcpFromConfig(servers, deps);
645
646
  }
646
647
 
648
+ /**
649
+ * Load MCP servers declared by installed plugins' `.mcp.json` (Phase 3.3g —
650
+ * plugin MCP component reaches the agent's tool surface).
651
+ *
652
+ * Unlike a project `.mcp.json` (opt-in via --project-mcp because ANY cloned repo
653
+ * can carry one), plugin MCP servers load by default: installing AND trusting a
654
+ * plugin IS the explicit user action. `collectPluginMcpServers` already trust-
655
+ * gates — only user/local-scope plugins and `cc plugin trust`-ed project plugins
656
+ * contribute — so a server never spawns from an untrusted cloned-repo plugin.
657
+ *
658
+ * Chains onto `deps.into` after the registered + project servers, so those win
659
+ * on a name clash (the plugin ADDS servers without overriding the user's own).
660
+ *
661
+ * @param {object} opts { cwd, scopes }
662
+ * @param {object} [deps] { collect, writeErr, into, ... setupMcpFromConfig deps }
663
+ */
664
+ export async function loadPluginMcp(opts = {}, deps = {}) {
665
+ const collect = deps.collect || collectPluginMcpServers;
666
+ const writeErr = deps.writeErr || (() => {});
667
+ let servers = {};
668
+ try {
669
+ ({ servers } = collect({ cwd: opts.cwd, scopes: opts.scopes }));
670
+ } catch {
671
+ return deps.into || null;
672
+ }
673
+ const names = Object.keys(servers || {});
674
+ if (names.length === 0) return deps.into || null;
675
+ writeErr(
676
+ ` mcp: ${names.length} server(s) from trusted plugin(s): ${names.join(", ")}\n`,
677
+ );
678
+ return setupMcpFromConfig(servers, deps);
679
+ }
680
+
647
681
  /**
648
682
  * Resolve the full MCP tool surface for one agent run: the ad-hoc
649
683
  * `--mcp-config` file (if any) PLUS registered auto-connect servers (unless
@@ -665,6 +699,7 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
665
699
  const doFile = deps.loadMcpConfig || loadMcpConfig;
666
700
  const doReg = deps.loadRegisteredMcp || loadRegisteredMcp;
667
701
  const doProject = deps.loadProjectMcp || loadProjectMcp;
702
+ const doPlugin = deps.loadPluginMcp || loadPluginMcp;
668
703
  const doIde = deps.loadIdeMcp || loadIdeMcp;
669
704
  const doPdh = deps.loadPdhMcp || loadPdhMcp;
670
705
  const doJetbrains = deps.loadJetbrainsMcp || loadJetbrainsMcp;
@@ -712,6 +747,17 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
712
747
  { ...fwd, into: result || undefined },
713
748
  );
714
749
  }
750
+ // Installed-plugin `.mcp.json` servers (Claude-Code parity). Loads by default
751
+ // (no opt-in flag): unlike a project `.mcp.json`, a plugin only contributes
752
+ // when it is installed AND trusted (trust-gated inside collectPluginMcpServers)
753
+ // — that install+trust IS the explicit consent. Registered + project servers
754
+ // above win on a name clash. `pluginMcp:false` hard-skips it.
755
+ if (args.pluginMcp !== false) {
756
+ result = await doPlugin(
757
+ { cwd: args.cwd, scopes: args.pluginScopes },
758
+ { ...fwd, into: result || undefined },
759
+ );
760
+ }
715
761
  if (args.ide !== false) {
716
762
  const env = args.env || process.env;
717
763
  const inIde = (deps.isInIdeTerminal || isInIdeTerminal)(env);
@@ -26,6 +26,8 @@ export function resolveAgentPolicy({
26
26
  noStream: overrides.noStream === true,
27
27
  parkOnExit: overrides.parkOnExit === false ? false : true,
28
28
  bundlePath: overrides.bundlePath || null,
29
+ remoteSessionRelayUrl: overrides.remoteSessionRelayUrl || null,
30
+ remoteSessionPeerId: overrides.remoteSessionPeerId || null,
29
31
  additionalDirectories: Array.isArray(overrides.additionalDirectories)
30
32
  ? overrides.additionalDirectories
31
33
  : [],