chainlesschain 0.163.7 → 0.164.0

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 (252) hide show
  1. package/package.json +5 -1
  2. package/scripts/macos-mcp-launcher-build.mjs +317 -0
  3. package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
  4. package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
  5. package/src/assets/web-panel/assets/{AIOps-axqQfwv8.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DV-Ro0By.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-Bt72WEVu.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-BtepG55E.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-B7KaJ7S_.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-FNFaUg7A.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DFb6J2wQ.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-CC7YBhyj.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-RkgTNVtj.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-hHEmGZy-.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CAP9YhHv.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-z5wXOQP1.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-DVaDJnxy.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-CJmaRDR5.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-DF29_2bI.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-DtkQkBzn.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-xoHDxp7I.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-BUm-R7ht.js → Cowork-DvGZrhbO.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-Cgl14ZkB.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-BNcbmoqh.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-Bwja0Zo9.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-Bk5XjEdJ.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-Ci36Oitq.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer--U04ZN4q.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2gNPR2s.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-C4KghYn7.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-QL7x_Q_0.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-F3Ryltwm.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-2HassK5k.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DoBIp7oe.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference--W01QhZ-.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-DmvwqGpT.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-BBJ4yAel.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/{MarkdownRenderer-BLCZMzhJ.js → MarkdownRenderer-GmB6DOr6.js} +1 -1
  39. package/src/assets/web-panel/assets/{Marketplace-D5lNngSI.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CkEVOMKH.js → McpTools-D7kGGbO7.js} +4 -4
  41. package/src/assets/web-panel/assets/{Memory-B1Ow1xVE.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-SgYbUfb6.js → MobileBridge-CtrR0Tas.js} +1 -1
  43. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
  44. package/src/assets/web-panel/assets/{Mtc-DcTXSSma.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-Dt3WG4oj.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-B9B38UZx.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-B0S4GGvG.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-DZ5U58Ng.js → Notes-BxMBFcIp.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-PjL5ZW34.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-DrAX2ESt.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-Cv1GYs-c.js → Organization-SQzIPdqC.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-Bbkp_PL3.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BD8QUgoZ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-BO-2PeaB.js → PdhVaultBrowser-BxPJZsD3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-D_OPVa02.js → Permissions-CLnDnPAz.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-mh-pEmaB.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-6JC2EDdb.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-CUshzUAG.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-Cs2Aalri.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-1ak49tcj.js → ProjectSettings-CxQkvl0k.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-CXXxvafH.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-PTcDsF58.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-CDwucrJw.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CJlLVRXR.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-DlN-ETsO.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-DI23LR6m.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-Cl7UQMrM.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-CexHNfh8.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-BneBWvRN.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-DX7Phgrp.js → Security-Mq2F9Nro.js} +4 -4
  72. package/src/assets/web-panel/assets/{Services-BWXO8Mte.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DCyOjKPJ.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-CXqERsTB.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-bhbrbz8E.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-3IPU0HBZ.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-DBNTQLbM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-quP0bkN-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-BouWmgho.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-qv0D9s7z.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-BxvbE8BB.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D-IeLnJ2.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-CFMKKyVG.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-L8as3UuJ.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-MxmA4VZG.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C0VvJYRi.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-Bf5QZj8N.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BIJ9riRz.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-B8p9Mhkw.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-BVsuaPen.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-BfkjoKpV.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DeAlsWK8.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-Cs97bz5j.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BqbG60LH.js → createContext-BRCSvYxj.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-i_RY0b1X.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BOVkf1K3.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B-3tEpTc.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D2B4VPyP.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BkBi5TmC.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-79V_zv1s.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-U4f5izHz.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DiSkx4UB.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-dIHr4B_u.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CIG8fQ2_.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DqBgBpgp.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-ZxO_-E8a.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DUUrv141.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bm7lLR4c.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-COdGA-8n.js → index-C5KAQFPQ.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CED2PL_y.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-YXgLng0K.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-0-agYlWL.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B5UkyA3c.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B1CbOH1i.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-s1opAL-M.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-yObj1O4n.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CgsqdnRV.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Dk7-v4hP.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B-JVTrpr.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CeWoNHau.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CE2VtTlp.js → index-D2GjI2oe.js} +1 -1
  124. package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
  125. package/src/assets/web-panel/assets/{index-DmbfhJUP.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BESLFt4q.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-PT_5sBMA.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-gyFpvL7l.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BYUVuwKt.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BcUXAB2s.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Dk2qouAz.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D9evtvg2.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BuLQobzW.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Cf3WCLmy.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CG3PRyAL.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-C9h9yKL3.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BvmLsPdu.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-CoL4ekU1.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-C4pMy6xV.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-DPuJfNxx.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-D0KEeaK2.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BpkyINxt.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DQI_wOq8.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DYfdDiRg.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-B5dtvb0D.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-CF310mSj.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-D1Qp4BLp.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-C7_iyvJK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-DZUt_fIm.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-D3dsi0lZ.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-WdbOlvdQ.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +6 -6
  154. package/src/commands/automation.js +103 -1
  155. package/src/commands/cowork.js +174 -19
  156. package/src/commands/permissions.js +240 -16
  157. package/src/commands/plugin.js +1293 -56
  158. package/src/commands/session-location.js +276 -0
  159. package/src/commands/session.js +2 -0
  160. package/src/commands/team-merge-review.js +937 -0
  161. package/src/commands/team.js +2 -0
  162. package/src/data/changelog.json +27 -1
  163. package/src/gateways/ws/action-protocol.js +35 -10
  164. package/src/gateways/ws/remote-session-protocol.js +24 -1
  165. package/src/gateways/ws/ws-agent-handler.js +12 -0
  166. package/src/gateways/ws/ws-server.js +48 -12
  167. package/src/harness/jsonl-session-store.js +341 -24
  168. package/src/harness/mcp-client.js +8 -1
  169. package/src/harness/remote-session-audit.js +1 -0
  170. package/src/harness/remote-session-crypto.js +210 -2
  171. package/src/harness/remote-session-registry.js +159 -6
  172. package/src/harness/session-list-index.js +233 -14
  173. package/src/lib/agent-authority.js +6 -0
  174. package/src/lib/agent-schedule-store.js +139 -28
  175. package/src/lib/agent-team/team-merge-review-store.js +765 -0
  176. package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
  177. package/src/lib/agent-team/team-merge-review.js +1847 -0
  178. package/src/lib/automation-center-incidents.js +314 -0
  179. package/src/lib/automation-center-runtime.js +448 -0
  180. package/src/lib/automation-center.js +182 -38
  181. package/src/lib/automation-engine.js +41 -0
  182. package/src/lib/automation-execution-authority.js +241 -12
  183. package/src/lib/automation-execution-incident.js +737 -0
  184. package/src/lib/background-agent-keeper-client.js +248 -0
  185. package/src/lib/background-agent-keeper-protocol.js +147 -0
  186. package/src/lib/background-agent-supervisor.js +520 -40
  187. package/src/lib/background-interaction-resolver.js +12 -0
  188. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  189. package/src/lib/cowork-cron.js +85 -14
  190. package/src/lib/cowork-workflow.js +336 -16
  191. package/src/lib/dynamic-workflow-facade.js +648 -0
  192. package/src/lib/execution-location-contract.js +551 -0
  193. package/src/lib/execution-location-runtime.js +130 -0
  194. package/src/lib/ide-context.js +94 -6
  195. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  196. package/src/lib/packer/pkg-config-generator.js +2 -0
  197. package/src/lib/permission-authority.js +77 -0
  198. package/src/lib/permission-side-effect-center.js +495 -0
  199. package/src/lib/plugin-runtime/install.js +514 -13
  200. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  201. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  202. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  203. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  204. package/src/lib/plugin-security.js +60 -3
  205. package/src/lib/process-execution-broker/index.js +1095 -57
  206. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  207. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  208. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  209. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  210. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  211. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  212. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  213. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  214. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  215. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  216. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  217. package/src/lib/public-ide-capability-manifest.js +3 -0
  218. package/src/lib/remote-approval-bridge.js +123 -17
  219. package/src/lib/remote-membership-authority.js +632 -0
  220. package/src/lib/remote-membership-coordinator.js +2409 -0
  221. package/src/lib/remote-membership-host-store.js +1750 -0
  222. package/src/lib/scheduler-kernel/agenda-adapter.js +17 -7
  223. package/src/lib/scheduler-kernel/automation-adapter.js +105 -11
  224. package/src/lib/scheduler-kernel/automation-event-adapter.js +87 -11
  225. package/src/lib/scheduler-kernel/contract.js +91 -0
  226. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +12 -1
  227. package/src/lib/scheduler-kernel/loop-adapter.js +7 -1
  228. package/src/lib/scheduler-kernel/routine-adapter.js +7 -1
  229. package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
  230. package/src/lib/scheduler-kernel/runtime.js +176 -3
  231. package/src/lib/scheduler-kernel/store.js +1253 -45
  232. package/src/lib/scoped-permission-store.js +369 -0
  233. package/src/lib/session-anti-rollback-anchor.js +262 -5
  234. package/src/lib/sub-agent-context.js +4 -0
  235. package/src/lib/workflow-definition-contract.js +149 -0
  236. package/src/repl/agent-repl.js +41 -7
  237. package/src/repl/chat-repl.js +2 -0
  238. package/src/repl/clipboard-image.js +735 -16
  239. package/src/repl/ide-status.js +1 -1
  240. package/src/repl/prompt-interactions.js +59 -6
  241. package/src/runtime/agent-core.js +93 -3
  242. package/src/runtime/headless-runner.js +30 -25
  243. package/src/runtime/headless-stream.js +32 -25
  244. package/src/runtime/mcp-config.js +81 -10
  245. package/src/workers/background-agent-keeper.js +498 -0
  246. package/src/workers/background-agent-worker.js +358 -13
  247. package/src/workers/background-turn-bootstrap.js +143 -0
  248. package/src/assets/web-panel/assets/MobileProjects-BWdOvQAj.js +0 -1
  249. package/src/assets/web-panel/assets/Projects-BV4oApsm.js +0 -1
  250. package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +0 -1
  251. package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +0 -1
  252. package/src/assets/web-panel/assets/index-ChVT0p9u.js +0 -1
@@ -45,7 +45,7 @@ export function renderIdeStatus(mcp, diag = null) {
45
45
  lines.push(` tools: ${tools.map((t) => IDE_PREFIX + t).join(", ")}`);
46
46
  lines.push(
47
47
  " selection/diagnostics auto-share each turn · " +
48
- "@selection / @diagnostics expand on demand",
48
+ "@selection / @diagnostics / @terminal / @context expand on demand",
49
49
  );
50
50
  return lines.join("\n");
51
51
  }
@@ -18,6 +18,8 @@ import {
18
18
  } from "./repl-keybindings.js";
19
19
  import {
20
20
  detectClipboardImageCapability,
21
+ MAX_CLIPBOARD_IMAGE_ATTACHMENTS,
22
+ MAX_CLIPBOARD_IMAGE_TOTAL_BYTES,
21
23
  readClipboardImageChip,
22
24
  } from "./clipboard-image.js";
23
25
  import { layoutTerminalText } from "./terminal-layout.js";
@@ -36,6 +38,12 @@ function safeErrorText(value) {
36
38
  .join("\n");
37
39
  }
38
40
 
41
+ function boundedClipboardQueueLimit(value, fallback, maximum) {
42
+ const parsed = Number(value);
43
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) return fallback;
44
+ return Math.min(parsed, maximum);
45
+ }
46
+
39
47
  export const PROMPT_INTERACTION_SLASH_COMMANDS = Object.freeze([
40
48
  Object.freeze({
41
49
  name: "/recap",
@@ -136,6 +144,17 @@ export class PromptInteractionController {
136
144
  this.persistSuggestionEnabled = options.persistSuggestionEnabled;
137
145
  this.clipboardBinding = options.clipboardBinding || null;
138
146
  this.clipboardImageChips = [];
147
+ this.clipboardImageBytes = 0;
148
+ this.maxClipboardImageAttachments = boundedClipboardQueueLimit(
149
+ options.maxClipboardImageAttachments,
150
+ MAX_CLIPBOARD_IMAGE_ATTACHMENTS,
151
+ MAX_CLIPBOARD_IMAGE_ATTACHMENTS,
152
+ );
153
+ this.maxClipboardImageTotalBytes = boundedClipboardQueueLimit(
154
+ options.maxClipboardImageTotalBytes,
155
+ MAX_CLIPBOARD_IMAGE_TOTAL_BYTES,
156
+ MAX_CLIPBOARD_IMAGE_TOTAL_BYTES,
157
+ );
139
158
 
140
159
  const validated = validateReplKeybindings(options.keybindings || {});
141
160
  this.keybindingDiagnostics = validated.errors.slice();
@@ -279,12 +298,38 @@ export class PromptInteractionController {
279
298
  this._print(result.reason, { error: true });
280
299
  return { handled: true, action: "paste-image", ...result };
281
300
  }
282
- const result = await readClipboardImageChip(this.clipboardBinding);
301
+ if (
302
+ this.clipboardImageChips.length >= this.maxClipboardImageAttachments
303
+ ) {
304
+ const result = {
305
+ ok: false,
306
+ supported: true,
307
+ mode: detectClipboardImageCapability(this.clipboardBinding).mode,
308
+ reason: `Clipboard attachment queue is limited to ${this.maxClipboardImageAttachments} images.`,
309
+ };
310
+ this._print(result.reason, { error: true });
311
+ return { handled: true, action: "paste-image", ...result };
312
+ }
313
+ let result = await readClipboardImageChip(this.clipboardBinding);
283
314
  if (result.ok) {
284
- this.clipboardImageChips.push(result.chip);
285
- this._print(
286
- `Image attached from clipboard (${result.mediaType}, ${result.bytes} bytes).`,
287
- );
315
+ if (
316
+ this.clipboardImageBytes + result.bytes >
317
+ this.maxClipboardImageTotalBytes
318
+ ) {
319
+ result = {
320
+ ok: false,
321
+ supported: true,
322
+ mode: result.mode,
323
+ reason: `Clipboard attachment queue exceeds ${this.maxClipboardImageTotalBytes} bytes.`,
324
+ };
325
+ this._print(result.reason, { error: true });
326
+ } else {
327
+ this.clipboardImageChips.push(result.chip);
328
+ this.clipboardImageBytes += result.bytes;
329
+ this._print(
330
+ `Image attached from clipboard (${result.mediaType}, ${result.bytes} bytes).`,
331
+ );
332
+ }
288
333
  } else {
289
334
  this._print(result.reason, { error: true });
290
335
  }
@@ -371,12 +416,20 @@ export class PromptInteractionController {
371
416
  takeClipboardImageChips() {
372
417
  const chips = this.clipboardImageChips.slice();
373
418
  this.clipboardImageChips.length = 0;
419
+ this.clipboardImageBytes = 0;
374
420
  return chips;
375
421
  }
376
422
 
423
+ clearClipboardImageChips() {
424
+ const cleared = this.clipboardImageChips.length;
425
+ this.clipboardImageChips.length = 0;
426
+ this.clipboardImageBytes = 0;
427
+ return cleared;
428
+ }
429
+
377
430
  dispose() {
378
431
  this.suggestions.dispose();
379
- this.clipboardImageChips.length = 0;
432
+ this.clearClipboardImageChips();
380
433
  }
381
434
  }
382
435
 
@@ -2401,20 +2401,88 @@ export async function executeTool(name, args, context = {}) {
2401
2401
  // shell-policy denylist also still applies.
2402
2402
  // No matching rule + no host policy → every existing layer runs unchanged
2403
2403
  // (default behaviour is byte-for-byte).
2404
- const settingsVerdict = context.permissionRules
2404
+ let permissionAuthority = null;
2405
+ let effectivePermissionRules = context.permissionRules || null;
2406
+ if (typeof context.permissionRulesProvider === "function") {
2407
+ try {
2408
+ permissionAuthority = await context.permissionRulesProvider({
2409
+ cwd,
2410
+ tool: name,
2411
+ args,
2412
+ });
2413
+ effectivePermissionRules =
2414
+ permissionAuthority?.rules || permissionAuthority || null;
2415
+ if (
2416
+ effectivePermissionRules &&
2417
+ (!Array.isArray(effectivePermissionRules.allow) ||
2418
+ !Array.isArray(effectivePermissionRules.ask) ||
2419
+ !Array.isArray(effectivePermissionRules.deny))
2420
+ ) {
2421
+ throw new TypeError(
2422
+ "permission authority provider returned an invalid ruleset",
2423
+ );
2424
+ }
2425
+ } catch (error) {
2426
+ return {
2427
+ error:
2428
+ `[Permission Authority] Tool "${name}" was blocked because the current permission authority could not be resolved. ` +
2429
+ "No tool side effect was started.",
2430
+ policy: {
2431
+ decision: "blocked",
2432
+ via: "permission-authority-load",
2433
+ code: error?.code || "CC_PERMISSION_AUTHORITY_UNAVAILABLE",
2434
+ },
2435
+ };
2436
+ }
2437
+ }
2438
+ const evaluatedSettingsVerdict = effectivePermissionRules
2405
2439
  ? evaluatePermissionRules({
2406
2440
  tool: name,
2407
2441
  args,
2408
2442
  cwd,
2409
- rules: context.permissionRules,
2443
+ rules: effectivePermissionRules,
2410
2444
  })
2411
2445
  : { decision: null, rule: null };
2446
+ const permissionRuleSource = evaluatedSettingsVerdict.rule
2447
+ ? permissionAuthority?.sources?.[
2448
+ `${evaluatedSettingsVerdict.decision}:${evaluatedSettingsVerdict.rule}`
2449
+ ] || null
2450
+ : null;
2451
+ const matchedScopedRule = permissionRuleSource?.startsWith("scoped:")
2452
+ ? permissionAuthority?.scoped?.rules?.find(
2453
+ (record) =>
2454
+ record.status === "active" &&
2455
+ `scoped:${record.id}` === permissionRuleSource,
2456
+ )
2457
+ : null;
2458
+ const settingsVerdict = {
2459
+ ...evaluatedSettingsVerdict,
2460
+ source: permissionRuleSource,
2461
+ priority:
2462
+ evaluatedSettingsVerdict.decision === "deny"
2463
+ ? 1
2464
+ : evaluatedSettingsVerdict.decision === "ask"
2465
+ ? 3
2466
+ : evaluatedSettingsVerdict.decision === "allow"
2467
+ ? 4
2468
+ : null,
2469
+ scopedRule: matchedScopedRule || null,
2470
+ };
2412
2471
 
2413
2472
  // 1. settings deny
2414
2473
  if (settingsVerdict.decision === "deny") {
2415
2474
  return {
2416
2475
  error: `[Permission] Tool "${name}" denied by settings rule: ${settingsVerdict.rule}. This is a configured policy — retrying won't help; tell the user if the task genuinely needs it.`,
2417
- policy: { decision: "deny", rule: settingsVerdict.rule, via: "settings" },
2476
+ policy: {
2477
+ decision: "deny",
2478
+ rule: settingsVerdict.rule,
2479
+ via: "settings",
2480
+ source: settingsVerdict.source,
2481
+ priority: settingsVerdict.priority,
2482
+ scopedRuleId: settingsVerdict.scopedRule?.id || null,
2483
+ revision: settingsVerdict.scopedRule?.revision || null,
2484
+ expiresAt: settingsVerdict.scopedRule?.expiresAt || null,
2485
+ },
2418
2486
  };
2419
2487
  }
2420
2488
 
@@ -2523,6 +2591,11 @@ export async function executeTool(name, args, context = {}) {
2523
2591
  decision: "ask",
2524
2592
  rule: settingsVerdict.rule,
2525
2593
  via: "settings",
2594
+ source: settingsVerdict.source,
2595
+ priority: settingsVerdict.priority,
2596
+ scopedRuleId: settingsVerdict.scopedRule?.id || null,
2597
+ revision: settingsVerdict.scopedRule?.revision || null,
2598
+ expiresAt: settingsVerdict.scopedRule?.expiresAt || null,
2526
2599
  },
2527
2600
  };
2528
2601
  }
@@ -2865,6 +2938,7 @@ export async function executeTool(name, args, context = {}) {
2865
2938
  backgroundUsageFailureState: context.backgroundUsageFailureState || null,
2866
2939
  planManager,
2867
2940
  permissionRules: context.permissionRules || null,
2941
+ permissionRulesProvider: context.permissionRulesProvider || null,
2868
2942
  effectiveAllowedToolNames: context.effectiveAllowedToolNames ?? null,
2869
2943
  hostManagedToolPolicy: context.hostManagedToolPolicy || null,
2870
2944
  externalToolDescriptors: context.externalToolDescriptors || null,
@@ -6873,6 +6947,16 @@ async function executeToolInner(
6873
6947
  });
6874
6948
  }
6875
6949
  try {
6950
+ if (localToolExecutor.op === "list-templates") {
6951
+ const resourceTemplates =
6952
+ typeof mcpClient.listResourceTemplates === "function"
6953
+ ? mcpClient.listResourceTemplates(args?.server || undefined)
6954
+ : [];
6955
+ return attachDescriptor({
6956
+ count: resourceTemplates.length,
6957
+ resourceTemplates,
6958
+ });
6959
+ }
6876
6960
  if (localToolExecutor.op === "list") {
6877
6961
  const resources =
6878
6962
  typeof mcpClient.listResources === "function"
@@ -8709,6 +8793,9 @@ async function _executeSpawnSubAgent(args, ctx) {
8709
8793
  // Parent execution authority is inherited as a tighten-only bundle and is
8710
8794
  // re-enforced by the child's executeTool path on every provider tool call.
8711
8795
  ...(ctx.permissionRules ? { permissionRules: ctx.permissionRules } : {}),
8796
+ ...(ctx.permissionRulesProvider
8797
+ ? { permissionRulesProvider: ctx.permissionRulesProvider }
8798
+ : {}),
8712
8799
  ...(childHostManagedToolPolicy
8713
8800
  ? { hostManagedToolPolicy: childHostManagedToolPolicy }
8714
8801
  : {}),
@@ -11341,6 +11428,9 @@ export async function* agentLoop(messages, options) {
11341
11428
  : options.additionalDirectories || null,
11342
11429
  sandbox: options.sandbox || null,
11343
11430
  permissionRules: hermeticExecution ? null : options.permissionRules || null,
11431
+ permissionRulesProvider: hermeticExecution
11432
+ ? null
11433
+ : options.permissionRulesProvider || null,
11344
11434
  permissionConfirm: hermeticExecution
11345
11435
  ? null
11346
11436
  : options.permissionConfirm || null,
@@ -65,6 +65,7 @@ import {
65
65
  reconcileSideEffects,
66
66
  classifyToolSideEffect,
67
67
  } from "../lib/side-effect-ledger.js";
68
+ import { collectToolResourceIdentifiers } from "../lib/permission-side-effect-center.js";
68
69
  import { DiffReviewFollowUpTracker } from "../lib/diff-review-follow-up.js";
69
70
  import { SIDE_EFFECT_LEDGER_EVENT } from "../lib/side-effect-ledger-store.js";
70
71
  import {
@@ -105,6 +106,7 @@ import {
105
106
  exitCodeForEndReason,
106
107
  } from "../lib/exit-codes.cjs";
107
108
  import { isolationLevel } from "../lib/agent-sandbox.js";
109
+ import { captureAmbientExecutionLocation } from "../lib/execution-location-runtime.js";
108
110
  import { createBackgroundPhaseReporter } from "../lib/background-phase-reporter.js";
109
111
  import { createBackgroundInteractionClient } from "../lib/background-interaction-resolver.js";
110
112
  import { withQuietStdout } from "./quiet-stdout.js";
@@ -738,34 +740,26 @@ async function runAgentHeadlessInWorkspace(
738
740
  let permissionRules = hermeticExecution
739
741
  ? null
740
742
  : options.permissionRules || null;
743
+ let permissionRulesProvider = hermeticExecution
744
+ ? null
745
+ : options.permissionRulesProvider || null;
741
746
  let managedSettings = null;
742
747
  let settingsFiles = [];
743
748
  if (!hermeticExecution) {
744
- try {
745
- const { loadSettings, applyManagedPermissionPolicy } =
746
- await import("../lib/settings-loader.cjs");
747
- const loaded = loadSettings({
748
- cwd,
749
- settingsFile: options.settingsFile,
750
- managedSettingsFile: options.managedSettingsFile,
751
- });
752
- managedSettings = loaded.managed;
753
- settingsFiles = Array.isArray(loaded.files) ? loaded.files : [];
754
- if (!permissionRules) {
755
- const total =
756
- loaded.rules.allow.length +
757
- loaded.rules.ask.length +
758
- loaded.rules.deny.length;
759
- permissionRules = total > 0 ? loaded.rules : null;
760
- } else if (managedSettings) {
761
- permissionRules = applyManagedPermissionPolicy(
762
- permissionRules,
763
- managedSettings,
764
- );
765
- }
766
- } catch (error) {
767
- if (error?.code === "CC_MANAGED_SETTINGS_INVALID") throw error;
768
- // Preserve caller-provided rules; absent settings keep legacy behavior.
749
+ const { createPermissionRulesProvider, loadPermissionAuthority } =
750
+ await import("../lib/permission-authority.js");
751
+ const authorityOptions = {
752
+ cwd,
753
+ settingsFile: options.settingsFile,
754
+ managedSettingsFile: options.managedSettingsFile,
755
+ baseRules: options.permissionRules || null,
756
+ };
757
+ const loaded = loadPermissionAuthority(authorityOptions);
758
+ managedSettings = loaded.managed;
759
+ settingsFiles = Array.isArray(loaded.files) ? loaded.files : [];
760
+ permissionRules = loaded.hasRules ? loaded.rules : null;
761
+ if (!permissionRulesProvider) {
762
+ permissionRulesProvider = createPermissionRulesProvider(authorityOptions);
769
763
  }
770
764
  }
771
765
 
@@ -1719,6 +1713,10 @@ async function runAgentHeadlessInWorkspace(
1719
1713
  provider,
1720
1714
  model,
1721
1715
  observabilityScope: options.observabilityScope,
1716
+ executionLocation: captureAmbientExecutionLocation({
1717
+ provider,
1718
+ model,
1719
+ }),
1722
1720
  });
1723
1721
  }
1724
1722
  // Persist the expanded content so a resumed session faithfully replays
@@ -2163,6 +2161,7 @@ async function runAgentHeadlessInWorkspace(
2163
2161
  hookDb: hermeticExecution ? null : db,
2164
2162
  approvalGate: hermeticExecution ? null : approvalGate,
2165
2163
  permissionRules: hermeticExecution ? null : permissionRules,
2164
+ permissionRulesProvider: hermeticExecution ? null : permissionRulesProvider,
2166
2165
  settingsHooks: hermeticExecution ? null : settingsHooks,
2167
2166
  // Seed the subagent-contract CEILING with this run's permission mode so a
2168
2167
  // spawned sub-agent inherits/tightens from it (tighten-only): a
@@ -2758,6 +2757,12 @@ async function runAgentHeadlessInWorkspace(
2758
2757
  // and countDuplicateCommittedEffects can measure `0` repeats.
2759
2758
  meta: {
2760
2759
  tool: event.tool,
2760
+ toolUseId: telemetryToolId,
2761
+ turnId: event.turn_id || null,
2762
+ resources: collectToolResourceIdentifiers(
2763
+ event.tool,
2764
+ event.args,
2765
+ ),
2761
2766
  idempotencyKey: operationIdempotencyKey({
2762
2767
  tool: event.tool,
2763
2768
  args: event.args,
@@ -60,6 +60,7 @@ import {
60
60
  expandIdeMentions,
61
61
  } from "../lib/ide-context.js";
62
62
  import { detectVersionSkew, versionSkewMessage } from "../lib/version-skew.js";
63
+ import { captureAmbientExecutionLocation } from "../lib/execution-location-runtime.js";
63
64
  import {
64
65
  resolveAgentMcp,
65
66
  resolvePermissionPromptTool,
@@ -114,6 +115,7 @@ import {
114
115
  reconcileSideEffects,
115
116
  classifyToolSideEffect,
116
117
  } from "../lib/side-effect-ledger.js";
118
+ import { collectToolResourceIdentifiers } from "../lib/permission-side-effect-center.js";
117
119
  import { DiffReviewFollowUpTracker } from "../lib/diff-review-follow-up.js";
118
120
  import {
119
121
  loadSideEffectLedger,
@@ -909,6 +911,12 @@ async function runTurn(
909
911
  // and countDuplicateCommittedEffects can measure `0` repeats.
910
912
  meta: {
911
913
  tool: event.tool,
914
+ toolUseId: toolUseId || null,
915
+ turnId: event.turn_id || null,
916
+ resources: collectToolResourceIdentifiers(
917
+ event.tool,
918
+ event.args,
919
+ ),
912
920
  idempotencyKey: operationIdempotencyKey({
913
921
  tool: event.tool,
914
922
  args: event.args,
@@ -1608,33 +1616,27 @@ async function runAgentHeadlessStreamInWorkspace(
1608
1616
  // .claude/settings.json permission rules (deny > ask > allow); see
1609
1617
  // runAgentHeadless for the full semantics. null = no file → unchanged.
1610
1618
  let permissionRules = options.permissionRules || null;
1619
+ let permissionRulesProvider = options.permissionRulesProvider || null;
1611
1620
  let managedSettings = null;
1612
1621
  let settingsFiles = [];
1613
- try {
1614
- const { loadSettings, applyManagedPermissionPolicy } =
1615
- await import("../lib/settings-loader.cjs");
1616
- const loaded = loadSettings({
1617
- cwd,
1618
- settingsFile: options.settingsFile,
1619
- managedSettingsFile: options.managedSettingsFile,
1620
- });
1621
- managedSettings = loaded.managed;
1622
- settingsFiles = Array.isArray(loaded.files) ? loaded.files : [];
1623
- if (!permissionRules) {
1624
- const total =
1625
- loaded.rules.allow.length +
1626
- loaded.rules.ask.length +
1627
- loaded.rules.deny.length;
1628
- permissionRules = total > 0 ? loaded.rules : null;
1629
- } else if (managedSettings) {
1630
- permissionRules = applyManagedPermissionPolicy(
1631
- permissionRules,
1632
- managedSettings,
1633
- );
1634
- }
1635
- } catch (error) {
1636
- if (error?.code === "CC_MANAGED_SETTINGS_INVALID") throw error;
1637
- // Preserve caller-provided rules; absent settings keep legacy behavior.
1622
+ const { createPermissionRulesProvider, loadPermissionAuthority } =
1623
+ await import("../lib/permission-authority.js");
1624
+ const authorityOptions = {
1625
+ cwd,
1626
+ settingsFile: options.settingsFile,
1627
+ managedSettingsFile: options.managedSettingsFile,
1628
+ baseRules: options.permissionRules || null,
1629
+ };
1630
+ const loadedPermissionAuthority = loadPermissionAuthority(authorityOptions);
1631
+ managedSettings = loadedPermissionAuthority.managed;
1632
+ settingsFiles = Array.isArray(loadedPermissionAuthority.files)
1633
+ ? loadedPermissionAuthority.files
1634
+ : [];
1635
+ permissionRules = loadedPermissionAuthority.hasRules
1636
+ ? loadedPermissionAuthority.rules
1637
+ : null;
1638
+ if (!permissionRulesProvider) {
1639
+ permissionRulesProvider = createPermissionRulesProvider(authorityOptions);
1638
1640
  }
1639
1641
 
1640
1642
  // .claude/settings.json `hooks` block (decision-capable PreToolUse/PostToolUse).
@@ -2368,6 +2370,10 @@ async function runAgentHeadlessStreamInWorkspace(
2368
2370
  provider,
2369
2371
  model,
2370
2372
  observabilityScope: options.observabilityScope,
2373
+ executionLocation: captureAmbientExecutionLocation({
2374
+ provider,
2375
+ model,
2376
+ }),
2371
2377
  }),
2372
2378
  "startSession",
2373
2379
  );
@@ -2791,6 +2797,7 @@ async function runAgentHeadlessStreamInWorkspace(
2791
2797
  hookDb: db,
2792
2798
  approvalGate,
2793
2799
  permissionRules,
2800
+ permissionRulesProvider,
2794
2801
  settingsHooks,
2795
2802
  toolAdmission: options.toolAdmission || null,
2796
2803
  classifyAllShell,
@@ -332,7 +332,8 @@ export function mcpAuthHint(url, errMessage) {
332
332
  * @param {object} servers `{ name: { command|url, args, env, transport, headers } }`
333
333
  * @param {object} [deps] { writeErr, createClient }
334
334
  * @returns {Promise<{mcpClient, extraToolDefinitions, externalToolExecutors,
335
- * externalToolDescriptors, connected}>}
335
+ * externalToolDescriptors, connected, resources,
336
+ * resourceTemplates, prompts}>}
336
337
  */
337
338
  export async function setupMcpFromConfig(servers, deps = {}) {
338
339
  const writeErr = deps.writeErr || (() => {});
@@ -354,6 +355,7 @@ export async function setupMcpFromConfig(servers, deps = {}) {
354
355
  externalToolDescriptors: {},
355
356
  connected: [],
356
357
  resources: [],
358
+ resourceTemplates: [],
357
359
  prompts: [],
358
360
  };
359
361
  if (!(result._mcpServerNameReservations instanceof Set)) {
@@ -362,9 +364,12 @@ export async function setupMcpFromConfig(servers, deps = {}) {
362
364
  configurable: true,
363
365
  });
364
366
  }
365
- // Back-fill the resource/prompt accumulators when an older `deps.into` object
366
- // (created before this field existed) is passed in.
367
+ // Back-fill the resource/template/prompt accumulators when an older
368
+ // `deps.into` object (created before these fields existed) is passed in.
367
369
  if (!Array.isArray(result.resources)) result.resources = [];
370
+ if (!Array.isArray(result.resourceTemplates)) {
371
+ result.resourceTemplates = [];
372
+ }
368
373
  if (!Array.isArray(result.prompts)) result.prompts = [];
369
374
  // Per-server usage instructions from the MCP initialize response (surfaced
370
375
  // by tool search; absent for servers that send none).
@@ -477,6 +482,9 @@ export async function setupMcpFromConfig(servers, deps = {}) {
477
482
  toolMetadataError = error;
478
483
  }
479
484
  const resources = Array.isArray(res?.resources) ? res.resources : [];
485
+ const resourceTemplates = Array.isArray(res?.resourceTemplates)
486
+ ? res.resourceTemplates
487
+ : [];
480
488
  const prompts = Array.isArray(res?.prompts) ? res.prompts : [];
481
489
  // A server can connect (initialize OK) yet have its tools/list fail — the
482
490
  // mcp-client surfaces that as `res.toolsError` (Claude-Code 2.1.181
@@ -507,6 +515,10 @@ export async function setupMcpFromConfig(servers, deps = {}) {
507
515
  if (!r || !r.uri) continue;
508
516
  result.resources.push({ ...r, server: name });
509
517
  }
518
+ for (const template of resourceTemplates) {
519
+ if (!template || !template.uriTemplate) continue;
520
+ result.resourceTemplates.push({ ...template, server: name });
521
+ }
510
522
  for (const p of prompts) {
511
523
  if (!p || !p.name) continue;
512
524
  result.prompts.push({ ...p, server: name });
@@ -566,13 +578,16 @@ export async function setupMcpFromConfig(servers, deps = {}) {
566
578
  }
567
579
  }
568
580
 
569
- // Expose MCP resources to the LLM as two generic tools (Claude-Code parity:
570
- // ListMcpResourcesTool / ReadMcpResourceTool). Registered once, only when at
571
- // least one connected server advertises a resource, and re-entrant safe for
572
- // accumulating `deps.into` batches.
573
- if (result.resources.length > 0) {
581
+ // Expose MCP resources to the LLM as generic read-only tools. A
582
+ // templates-only server still needs the read tool so the model can
583
+ // instantiate a URI template and explicitly read that URI. Registration is
584
+ // re-entrant safe for accumulating `deps.into` batches.
585
+ if (result.resources.length > 0 || result.resourceTemplates.length > 0) {
574
586
  registerMcpResourceTools(result);
575
587
  }
588
+ if (result.resourceTemplates.length > 0) {
589
+ registerMcpResourceTemplateTool(result);
590
+ }
576
591
 
577
592
  return result;
578
593
  }
@@ -615,14 +630,14 @@ export function registerMcpResourceTools(result) {
615
630
  name: "read_mcp_resource",
616
631
  description:
617
632
  "Read the contents of an MCP resource by its URI. Use " +
618
- "list_mcp_resources first to discover available URIs.",
633
+ "list_mcp_resources or list_mcp_resource_templates first to discover a URI.",
619
634
  parameters: {
620
635
  type: "object",
621
636
  properties: {
622
637
  server: {
623
638
  type: "string",
624
639
  description:
625
- "MCP server name that owns the resource (from list_mcp_resources).",
640
+ "MCP server name that owns the resource or resource template.",
626
641
  },
627
642
  uri: {
628
643
  type: "string",
@@ -689,6 +704,62 @@ export function registerMcpResourceTools(result) {
689
704
  };
690
705
  }
691
706
 
707
+ /** Register the read-only resource-template discovery tool once. */
708
+ function registerMcpResourceTemplateTool(result) {
709
+ const {
710
+ extraToolDefinitions,
711
+ externalToolExecutors,
712
+ externalToolDescriptors,
713
+ } = result;
714
+ if (externalToolExecutors.list_mcp_resource_templates) return;
715
+
716
+ extraToolDefinitions.push({
717
+ type: "function",
718
+ function: {
719
+ name: "list_mcp_resource_templates",
720
+ description:
721
+ "List URI templates exposed by connected MCP servers. Fill a template " +
722
+ "with concrete arguments, then pass the resulting URI and returned " +
723
+ "server name to read_mcp_resource.",
724
+ parameters: {
725
+ type: "object",
726
+ properties: {
727
+ server: {
728
+ type: "string",
729
+ description: "Optional MCP server name to filter by.",
730
+ },
731
+ },
732
+ },
733
+ },
734
+ });
735
+ externalToolExecutors.list_mcp_resource_templates = {
736
+ kind: "mcp-resource",
737
+ op: "list-templates",
738
+ };
739
+ externalToolDescriptors.list_mcp_resource_templates = {
740
+ name: "list_mcp_resource_templates",
741
+ kind: "mcp-resource",
742
+ category: "mcp",
743
+ source: "mcp",
744
+ isReadOnly: true,
745
+ riskLevel: "low",
746
+ effectContract: {
747
+ version: 1,
748
+ declaredEffect: "read",
749
+ authorizedEffect: "read",
750
+ riskLevel: "low",
751
+ sourceTrusted: true,
752
+ provenance: "host:mcp-resource-wrapper",
753
+ annotations: {
754
+ readOnlyHint: true,
755
+ destructiveHint: false,
756
+ idempotentHint: true,
757
+ openWorldHint: false,
758
+ },
759
+ },
760
+ };
761
+ }
762
+
692
763
  /**
693
764
  * Read + parse a `--mcp-config` file and connect its servers.
694
765
  * Throws on an unreadable/empty config (fail fast — the user asked for MCP).