chainlesschain 0.163.1 → 0.163.3

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 (191) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-Cn7quRgL.js → AIOps-DIY6KxV-.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-YqMX3ueH.js → ActionButton-BXH0muPt.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-Bxmy1b7Y.js → Analytics-D39w8vmg.js} +2 -2
  5. package/src/assets/web-panel/assets/{AppLayout-DBOw69jE.js → AppLayout-CUU1zvLs.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-mq1nyzN1.js → Artifacts-D8azHO3T.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-mMiKtZ0D.js → Audit-D0tAwXTg.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-WBUjpYVh.js → BackgroundAgents-C29mhJll.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-c25OoJgs.js → Backup-D6Aa1Gro.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BbfWhZ4-.js → BaseInput-B1uoHbPQ.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CVVzsTwU.js → Chat-Bs4DLOR5.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CVCjZJ04.js → ChatBubbleRenderer-DUYIBSle.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-C9o2HK-1.js → Checkbox-CNcBPEa4.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-B7X5LfKc.js → Codegen-CIY89763.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-jpPj2Pur.js → Col-CsPYFmgo.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-Dti6bHxN.js → Community-BBocEge4.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-S4ZsLt3W.js → Compact-TQ8Ux0Lf.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Bge0sQ3O.js → Compliance-DfBsZTft.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-C4XyzVI7.js → Cowork-Cg-I6FVH.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-CPR0v2xy.js → Cron-DTQzfRTp.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-DAX8lDaj.js → Crosschain-DGxEKGpR.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-fBHPa0QH.js → DID-DLZ1RDSr.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-vvaUTafU.js → Dashboard-XneICKNI.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DyaQM63v.js → Dropdown-BRU00J1-.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-CAF0wiU2.js → EmailListRenderer-BzCbJuAy.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-ia-WzDRs.js → FamilyGuardDashboard-D7BRyNBG.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-Cz3gHoT5.js → Federation-D9DeFIhW.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CJQDJr4Q.js → FormItemContext-6rAtA9Ko.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-B05BZlQp.js → GenericCardRenderer-8Hqy80pU.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-DT0YcQnI.js → Git-Cmvkj1rt.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Bqbl6m5Q.js → Governance-BRiQUjjw.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BdebLR0N.js → Inference-CKN_EzVf.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-M36b8YYV.js → KnowledgeGraph-BCDHwpwQ.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-5LN_XL43.js → Logs-DK9ovhaB.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-BCb1Dm8l.js → MarkdownRenderer-D53pHiHy.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-BkIin-QY.js → Marketplace-BILPGakp.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-Bkppx8Uj.js → McpTools-DTVCOr9-.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-Qk9wg_Ib.js → Memory-Hzc1iow4.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-BsTDU3Aj.js → MobileBridge-GXfgnGYV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-CrZW5I28.js → MobileProjects-B-3TJWsS.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BMkmgtsA.js → Mtc-DwSJMWtK.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-6m4CC0Yn.js → MtcAudit-D2uxf-DA.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-BZ8yB7QV.js → Multisig-DG6kbKK0.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CxitAMIO.js → NLProgramming-f5p49EDU.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-Bv0msnHu.js → Notes-FUgHyzSD.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-DeVMqM3P.js → NotificationSettings-DCHGee7e.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-CXBSWa3R.js → OrderTableRenderer-Dm6LlIoa.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-b_G5Vs1Q.js → Organization-BawA7qAg.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-DW7riOmA.js → Overflow-D6a5wZU1.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CtpQNYjL.js → P2P-K8WavwnA.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-Ba63yT4l.js → PdhVaultBrowser-4JAJYaqx.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DnzyeB67.js → Permissions-BDWvi8PD.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DbPZ7HWw.js → PersonalDataHub-DF_K4E9i.js} +3 -3
  54. package/src/assets/web-panel/assets/{Pipeline-gs_HOThJ.js → Pipeline-BYeZlesI.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-CZlQ1EjE.js → Privacy-BIHlgnIc.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DQp__Ccb.js → ProjectInit-Cvf-6B5P.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-C7h2sOWZ.js → ProjectSettings-CnwfJrRz.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-b-jPXzF4.js +1 -0
  59. package/src/assets/web-panel/assets/Providers-CxC7JuYv.js +1 -0
  60. package/src/assets/web-panel/assets/{QrScannerModal-B_8M1-FC.js → QrScannerModal-VLf3gAfL.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-Bpycr8WD.js → QuickAsk-B5vGjRiF.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Z4TrcNzs.js → Recommend--UW4iYs-.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-BD6TsJlS.js → RemoteSession-DMSPcfKR.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-IKxDXHEu.js → Reputation-kQXlEHmj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-DbmR20tJ.js → Row-CxGu3pit.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-CLjA5PPf.js → RssFeed-Bi5lo8MZ.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-Bm3owbIU.js → Search-Cq_H5RTh.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-CY4RyOuq.js → Security-YFbmkaQS.js} +2 -2
  69. package/src/assets/web-panel/assets/{Services-CYO9qrd_.js → Services-DLOGdaLm.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-ClF51Go6.js → Skeleton-CteIxb3D.js} +1 -1
  71. package/src/assets/web-panel/assets/Skills-CccopaIZ.js +1 -0
  72. package/src/assets/web-panel/assets/{Sla-zqpDUxzP.js → Sla-AzfEQKX1.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-DPSi8Qco.js → SpeechSettings-ekGo5l77.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-CqABopsQ.js → SyncSettings-BmZmAgYH.js} +2 -2
  75. package/src/assets/web-panel/assets/Tasks-D7q3Z4uL.js +1 -0
  76. package/src/assets/web-panel/assets/{Templates-Dzl6f0M2.js → Templates-CX1Tgeka.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-XeZkw40a.js → Tenant-Zc59jF4i.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-CYw2YzPm.js → Terminal-CXOD7y83.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-Bc2pko4i.js → TimelineRenderer-B1aBHPBo.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-CfCenOHx.js → Tokens-zALlOq_U.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DTz-_YqV.js → Trigger-CQfJMXaq.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-CB3tt3Z6.js → Trust-BU0RcM-w.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-y1ykmMvU.js → UkeySign-IFZ3HsbH.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-UlZ_lX0e.js → VideoEditing-BzslgW0v.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-DMBaHTha.js → Wallet-BZAcQNS6.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Cksm-hBI.js → WebAuthn-CBK1DMi0.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-BhOa40sX.js → WorkflowEditor-BlMTPzO-.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-DNbeSTDO.js → chat-B51-8QVn.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-9zz8gBmW.js → colors-504RTByU.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-D7aoVv-5.js → compact-item-C-GP6IQM.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-DYg7B8nd.js → createContext-DOkIj7ID.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-kB0nCNwN.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-BNbhkcoI.js → hasIn-DN7V-_FW.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DeD1wWA8.js → index--n-ZciV3.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Da0SysnX.js → index-7jIqHbzw.js} +1 -1
  96. package/src/assets/web-panel/assets/{index--TvoQ6UC.js → index-B2-x9bS8.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-m2pXS3W2.js → index-BFIFJ5Dr.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CzDDeZBo.js → index-B_vGU-Js.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-gNKj00Fx.js → index-Bkxhaeta.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C8LC0nvw.js → index-By6u5IV1.js} +1 -1
  101. package/src/assets/web-panel/assets/index-Bya64sZE.js +1 -0
  102. package/src/assets/web-panel/assets/{index-B8irlIUK.js → index-C0k_Nqg9.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-B9zUawcE.js → index-C3TSohzc.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BPojutcZ.js → index-C4DV_5uA.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-ZPDbEh-L.js → index-C8UltbXK.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-jS6NASar.js → index-C9_48OzU.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-67GdrUx2.js → index-CKTfZyfU.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CYu-F-gp.js → index-CP2A226L.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Cq3l0L7C.js → index-CUhQpiYv.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DtQzs0hH.js → index-CX78k-qf.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Bdxe0nrD.js → index-CYopNjcJ.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-uc8Rz96X.js → index-Cao5DZy7.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DnTM8FWK.js → index-CfiEM64n.js} +3 -3
  114. package/src/assets/web-panel/assets/{index-DHskwmwI.js → index-ConjaJro.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CA72qB1n.js → index-CqcLo5WV.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Dn-JFqEi.js → index-CySTJKeq.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DUWmZ059.js → index-D1phyca8.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-_-Vt1Wqk.js → index-D9LyiN-L.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DIljkSt9.js → index-DA2f1UV3.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B9TzVW7i.js → index-DAOpQvl_.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CRKukX1W.js → index-DE-hmI2l.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DIMVe3HJ.js → index-DEMPUVa3.js} +1 -1
  123. package/src/assets/web-panel/assets/index-D_FWpDZM.js +1 -0
  124. package/src/assets/web-panel/assets/{index-FlBuITVG.js → index-DaA__-q1.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Cqy-hqD9.js → index-FcV8J_Qz.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CpEIwp4A.js → index-P2mfY27Z.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-nnmo3ipi.js → index-et5JIPHO.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-SmEIFaRm.js → index-f4Bo4KXm.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DMrqEsOS.js → index-kAqQXfP6.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CV06YdPO.js → index-kt_5rfcZ.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CN6-OEgS.js → index-so8eIIxF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BRd1zkLB.js → index-yYTQZypF.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-D0mTMUGz.js → initDefaultProps-CPYEIdpV.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-DK16p4-o.js → motion-Cjim9pxs.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-DalC20HC.js → move-DuU-cgz3.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-B5RusszF.js → mtc-parser-DJHNAkta.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-C9Mhitht.js → omit-DSQBgdBj.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-51xQLgwM.js → pickAttrs-CTmT_j5m.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-CJzIqp8u.js → placementArrow-Lfm6v-r4.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-HQvC19u4.js → responsiveObserve-CgrcPcDi.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-C6hhabOp.js → slide-CuE3110i.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-Q1r48-oc.js → statusUtils-DiK5nbpf.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-UakVWrHs.js → styleChecker-DPEJdQaZ.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-Dmv94cxx.js → useFlexGapSupport-CnnodGmp.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DrxOnt_V.js → useFs-DWF84Yav.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-BVf2M-Hg.js → usePersonalDataHub-a5b5Dw2f.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-BzzW9qKH.js → vnode-DAluzXOq.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-C1ZvMgAZ.js → zoom-Dokg7uAZ.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +1 -1
  151. package/src/commands/agenda.js +6 -5
  152. package/src/commands/agent.js +237 -75
  153. package/src/commands/agents.js +6 -0
  154. package/src/commands/background-session.js +11 -1
  155. package/src/commands/mcp.js +245 -30
  156. package/src/data/changelog.json +28 -2
  157. package/src/harness/mcp-client.js +256 -43
  158. package/src/harness/worktree-isolator.js +26 -3
  159. package/src/lib/agent-worktree.js +41 -2
  160. package/src/lib/background-agent-supervisor.js +790 -186
  161. package/src/lib/background-command-argv.js +318 -0
  162. package/src/lib/background-launch-profile.js +1 -0
  163. package/src/lib/background-phase-reporter.js +22 -2
  164. package/src/lib/background-worktree-policy.js +109 -0
  165. package/src/lib/cowork-mcp-tools.js +52 -6
  166. package/src/lib/cowork-task-runner.js +1 -0
  167. package/src/lib/cowork-task-templates.js +1 -0
  168. package/src/lib/mcp-headers-helper.js +76 -8
  169. package/src/lib/mcp-sandbox-policy.js +155 -0
  170. package/src/lib/mcp-stdio-executable-identity.js +75 -11
  171. package/src/lib/mcp-stdio-execution-authority.js +168 -0
  172. package/src/lib/mcp-stdio-workspace-authority.js +252 -0
  173. package/src/lib/plugin-runtime/sandbox-policy.js +42 -2
  174. package/src/lib/process-execution-broker/index.js +495 -126
  175. package/src/lib/process-execution-broker/platform-sandbox.js +1424 -189
  176. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  177. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  178. package/src/lib/process-execution-broker/windows-sandbox.cs +5 -4
  179. package/src/lib/process-tree-termination.js +17 -1
  180. package/src/lib/skill-mcp.js +74 -3
  181. package/src/lib/web-fetch.js +4 -4
  182. package/src/runtime/agent-runtime.js +61 -8
  183. package/src/runtime/mcp-config.js +238 -28
  184. package/src/workers/background-agent-worker.js +492 -71
  185. package/src/assets/web-panel/assets/Projects-DdCpNRNt.js +0 -1
  186. package/src/assets/web-panel/assets/Providers-CyvtUkUf.js +0 -1
  187. package/src/assets/web-panel/assets/Skills-CCCEmSf5.js +0 -1
  188. package/src/assets/web-panel/assets/Tasks-4dbAJng4.js +0 -1
  189. package/src/assets/web-panel/assets/devWarning-uadaGF_y.js +0 -1
  190. package/src/assets/web-panel/assets/index-C7zhie9M.js +0 -1
  191. package/src/assets/web-panel/assets/index-Cmbg0Wbr.js +0 -1
@@ -11,7 +11,14 @@
11
11
  */
12
12
 
13
13
  import crypto from "node:crypto";
14
+ import fs from "node:fs";
15
+ import path from "node:path";
14
16
  import { isProxy } from "node:util/types";
17
+ import {
18
+ currentHostHooksV2WorkspaceBinding,
19
+ resolveHostHooksV2WorkspaceBinding,
20
+ } from "./hooks-v2-workspace-context.js";
21
+ import { resolvePluginWorkspaceAuthority } from "./plugin-runtime/sandbox-policy.js";
15
22
 
16
23
  export const MCP_STDIO_LOCAL_CODE_TRUST_REQUIRED_CODE =
17
24
  "CC_MCP_STDIO_LOCAL_CODE_TRUST_REQUIRED";
@@ -155,6 +162,10 @@ function invocationSnapshot(serverName, config) {
155
162
  command,
156
163
  args: Object.freeze(args),
157
164
  env: Object.freeze(env.map((entry) => Object.freeze(entry))),
165
+ runtimeKind: scalar(
166
+ dataProperty(config, "runtimeKind", null),
167
+ "runtimeKind",
168
+ ),
158
169
  transport: scalar(dataProperty(config, "transport", null), "transport"),
159
170
  origin: scalar(dataProperty(config, "origin", null), "origin"),
160
171
  policy: scalar(dataProperty(config, "policy", null), "policy"),
@@ -171,6 +182,7 @@ function invocationSnapshot(serverName, config) {
171
182
  dataProperty(config, "projectPath", null),
172
183
  "projectPath",
173
184
  ),
185
+ cwd: scalar(dataProperty(config, "cwd", null), "cwd"),
174
186
  pluginId: scalar(dataProperty(config, "pluginId", null), "pluginId"),
175
187
  pluginVersion: scalar(
176
188
  dataProperty(config, "pluginVersion", null),
@@ -201,6 +213,8 @@ function comparableSnapshot(snapshot) {
201
213
  projectMcpWorkspaceAuthority: _projectAuthority,
202
214
  ...plain
203
215
  } = snapshot;
216
+ void _pluginAuthority;
217
+ void _projectAuthority;
204
218
  return plain;
205
219
  }
206
220
 
@@ -220,11 +234,122 @@ function sameSnapshot(expected, actual) {
220
234
  );
221
235
  }
222
236
 
237
+ function directoryGeneration(stat) {
238
+ return stat.birthtimeNs > 0n
239
+ ? `birth:${stat.birthtimeNs.toString()}`
240
+ : `ctime:${stat.ctimeNs.toString()}`;
241
+ }
242
+
243
+ function captureDirectoryIdentity(value, base, label) {
244
+ if (typeof value !== "string" || value.length === 0 || value.includes("\0")) {
245
+ throw new TypeError(`${label} must be a non-empty directory path`);
246
+ }
247
+ const requestedPath = path.isAbsolute(value)
248
+ ? path.resolve(value)
249
+ : path.resolve(base, value);
250
+ let canonicalRoot;
251
+ let stat;
252
+ try {
253
+ const implementation = fs.realpathSync.native || fs.realpathSync;
254
+ canonicalRoot = implementation.call(fs.realpathSync, requestedPath);
255
+ stat = fs.statSync(canonicalRoot, { bigint: true });
256
+ } catch (cause) {
257
+ throw new TypeError(`${label} must resolve to an existing directory`, {
258
+ cause,
259
+ });
260
+ }
261
+ if (!stat.isDirectory()) {
262
+ throw new TypeError(`${label} must resolve to a directory`);
263
+ }
264
+ return Object.freeze({
265
+ requestedPath,
266
+ canonicalRoot,
267
+ device: stat.dev,
268
+ inode: stat.ino,
269
+ generation: directoryGeneration(stat),
270
+ });
271
+ }
272
+
273
+ function sameDirectoryIdentity(expected, actual) {
274
+ return (
275
+ expected.canonicalRoot === actual.canonicalRoot &&
276
+ expected.device === actual.device &&
277
+ expected.inode === actual.inode &&
278
+ expected.generation === actual.generation
279
+ );
280
+ }
281
+
282
+ function verifyDirectoryIdentity(binding) {
283
+ try {
284
+ return sameDirectoryIdentity(
285
+ binding,
286
+ captureDirectoryIdentity(
287
+ binding.requestedPath,
288
+ process.cwd(),
289
+ "approved MCP stdio cwd",
290
+ ),
291
+ );
292
+ } catch {
293
+ return false;
294
+ }
295
+ }
296
+
297
+ function approvedWorkspaceRoot(snapshot, workspaceRoot, workspaceBinding) {
298
+ if (snapshot.origin === "plugin:mcp") {
299
+ const pluginRoot = resolvePluginWorkspaceAuthority(
300
+ snapshot.pluginWorkspaceAuthority,
301
+ {
302
+ origin: snapshot.origin,
303
+ pluginId: snapshot.pluginId,
304
+ pluginVersion: snapshot.pluginVersion,
305
+ pluginSource: snapshot.pluginSource,
306
+ },
307
+ );
308
+ if (pluginRoot) return pluginRoot;
309
+ }
310
+ if (workspaceBinding != null) {
311
+ const resolvedBinding =
312
+ resolveHostHooksV2WorkspaceBinding(workspaceBinding);
313
+ if (!resolvedBinding?.workspaceRoot) {
314
+ throw new TypeError(
315
+ "approved MCP stdio workspace binding is invalid or stale",
316
+ );
317
+ }
318
+ return resolvedBinding.workspaceRoot;
319
+ }
320
+ if (typeof workspaceRoot === "string" && workspaceRoot.length > 0) {
321
+ return workspaceRoot;
322
+ }
323
+ const hostRoot = currentHostHooksV2WorkspaceBinding()?.workspaceRoot;
324
+ if (hostRoot) return hostRoot;
325
+ if (typeof snapshot.projectPath === "string" && snapshot.projectPath) {
326
+ return snapshot.projectPath;
327
+ }
328
+ return process.cwd();
329
+ }
330
+
331
+ function captureApprovedCwd(snapshot, workspaceRoot, workspaceBinding) {
332
+ if (snapshot.sandboxPolicy == null || snapshot.cwd == null) return null;
333
+ return captureDirectoryIdentity(
334
+ snapshot.cwd,
335
+ approvedWorkspaceRoot(snapshot, workspaceRoot, workspaceBinding),
336
+ "approved MCP stdio cwd",
337
+ );
338
+ }
339
+
340
+ function staleDirectoryError(serverName) {
341
+ return authorityError(
342
+ MCP_STDIO_EXECUTION_AUTHORITY_STALE_CODE,
343
+ `MCP stdio working directory for "${String(serverName)}" changed after approval`,
344
+ );
345
+ }
346
+
223
347
  function materializeSnapshot(snapshot) {
224
348
  return {
225
349
  command: snapshot.command,
226
350
  args: [...snapshot.args],
227
351
  env: Object.fromEntries(snapshot.env),
352
+ runtimeKind: snapshot.runtimeKind,
228
353
  transport: snapshot.transport,
229
354
  origin: snapshot.origin,
230
355
  policy: snapshot.policy,
@@ -232,6 +357,7 @@ function materializeSnapshot(snapshot) {
232
357
  configScope: snapshot.configScope,
233
358
  configSource: snapshot.configSource,
234
359
  projectPath: snapshot.projectPath,
360
+ cwd: snapshot.cwd,
235
361
  pluginId: snapshot.pluginId,
236
362
  pluginVersion: snapshot.pluginVersion,
237
363
  pluginSource: snapshot.pluginSource,
@@ -249,6 +375,8 @@ export function issueMcpStdioExecutionAuthority({
249
375
  config,
250
376
  approvalKind,
251
377
  approvalSource,
378
+ workspaceRoot,
379
+ workspaceBinding,
252
380
  }) {
253
381
  if (!APPROVAL_KINDS.has(approvalKind)) {
254
382
  throw new TypeError("MCP stdio approval kind is not recognized");
@@ -256,6 +384,11 @@ export function issueMcpStdioExecutionAuthority({
256
384
  const source = scalar(approvalSource, "approvalSource", { nullable: false });
257
385
  if (!source.trim()) throw new TypeError("approvalSource must not be empty");
258
386
  const snapshot = invocationSnapshot(serverName, config);
387
+ const cwdIdentity = captureApprovedCwd(
388
+ snapshot,
389
+ workspaceRoot,
390
+ workspaceBinding,
391
+ );
259
392
  const token = Object.freeze({});
260
393
  issuedAuthorities.set(
261
394
  token,
@@ -264,6 +397,7 @@ export function issueMcpStdioExecutionAuthority({
264
397
  approvalSource: source,
265
398
  fingerprint: snapshotDigest(snapshot),
266
399
  snapshot,
400
+ cwdIdentity,
267
401
  }),
268
402
  );
269
403
  return token;
@@ -304,6 +438,9 @@ export function consumeMcpStdioExecutionAuthority(
304
438
  `MCP stdio invocation for "${String(serverName)}" changed after approval`,
305
439
  );
306
440
  }
441
+ if (issued.cwdIdentity && !verifyDirectoryIdentity(issued.cwdIdentity)) {
442
+ throw staleDirectoryError(serverName);
443
+ }
307
444
  const approval = Object.freeze({
308
445
  approvalKind: issued.approvalKind,
309
446
  approvalSource: issued.approvalSource,
@@ -331,6 +468,9 @@ export function renewMcpStdioExecutionAuthority(
331
468
  `MCP stdio reconnect invocation for "${String(serverName)}" changed after approval`,
332
469
  );
333
470
  }
471
+ if (issued.cwdIdentity && !verifyDirectoryIdentity(issued.cwdIdentity)) {
472
+ throw staleDirectoryError(serverName);
473
+ }
334
474
  const token = Object.freeze({});
335
475
  issuedAuthorities.set(token, issued);
336
476
  return token;
@@ -347,6 +487,34 @@ export function materializeApprovedMcpStdioInvocation(approval) {
347
487
  return materializeSnapshot(issued.snapshot);
348
488
  }
349
489
 
490
+ export function verifyMcpStdioApprovedWorkingDirectory(
491
+ approval,
492
+ workingDirectory,
493
+ ) {
494
+ const issued = renewableApprovals.get(approval);
495
+ if (!issued) {
496
+ throw authorityError(
497
+ MCP_STDIO_LOCAL_CODE_TRUST_REQUIRED_CODE,
498
+ "MCP stdio working directory requires a consumed execution approval",
499
+ );
500
+ }
501
+ if (!issued.cwdIdentity) return true;
502
+ let actual;
503
+ try {
504
+ actual = captureDirectoryIdentity(
505
+ workingDirectory,
506
+ process.cwd(),
507
+ "materialized MCP stdio cwd",
508
+ );
509
+ } catch {
510
+ throw staleDirectoryError(issued.snapshot.serverName);
511
+ }
512
+ if (!sameDirectoryIdentity(issued.cwdIdentity, actual)) {
513
+ throw staleDirectoryError(issued.snapshot.serverName);
514
+ }
515
+ return true;
516
+ }
517
+
350
518
  /**
351
519
  * Return only the content-free provenance needed to key a durable executable
352
520
  * identity. The approval object itself remains an unforgeable WeakMap-backed
@@ -0,0 +1,252 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { isProxy } from "node:util/types";
4
+ import { resolveHostHooksV2WorkspaceBinding } from "./hooks-v2-workspace-context.js";
5
+ import { normalizeMcpSandboxPolicy } from "./mcp-sandbox-policy.js";
6
+ import { resolvePluginWorkspaceAuthority } from "./plugin-runtime/sandbox-policy.js";
7
+ import { resolveProjectMcpWorkspaceAuthority } from "./project-mcp-trust.js";
8
+
9
+ export const MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE =
10
+ "CC_MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED";
11
+ export const MCP_STDIO_SANDBOX_CWD_INVALID_CODE =
12
+ "CC_MCP_STDIO_SANDBOX_CWD_INVALID";
13
+
14
+ function workspaceError(code, message, cause) {
15
+ const error = new Error(message, cause ? { cause } : undefined);
16
+ error.code = code;
17
+ return error;
18
+ }
19
+
20
+ function dataProperty(owner, key, fallback) {
21
+ if (!owner || typeof owner !== "object" || isProxy(owner)) {
22
+ throw workspaceError(
23
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
24
+ "MCP stdio sandbox config must be a non-Proxy object",
25
+ );
26
+ }
27
+ const descriptor = Object.getOwnPropertyDescriptor(owner, key);
28
+ if (!descriptor) return fallback;
29
+ if (!("value" in descriptor)) {
30
+ throw workspaceError(
31
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
32
+ `MCP stdio sandbox config.${key} must be an own data property`,
33
+ );
34
+ }
35
+ return descriptor.value;
36
+ }
37
+
38
+ function canonicalDirectory(value, label) {
39
+ if (typeof value !== "string" || value.length === 0 || value.includes("\0")) {
40
+ throw workspaceError(
41
+ MCP_STDIO_SANDBOX_CWD_INVALID_CODE,
42
+ `${label} must be a non-empty directory path`,
43
+ );
44
+ }
45
+ try {
46
+ const canonical = fs.realpathSync.native(path.resolve(value));
47
+ if (!fs.statSync(canonical).isDirectory()) {
48
+ throw new Error("not a directory");
49
+ }
50
+ return canonical;
51
+ } catch (cause) {
52
+ throw workspaceError(
53
+ MCP_STDIO_SANDBOX_CWD_INVALID_CODE,
54
+ `${label} must resolve to an existing directory`,
55
+ cause,
56
+ );
57
+ }
58
+ }
59
+
60
+ function isPathInside(root, candidate) {
61
+ const relative = path.relative(root, candidate);
62
+ return (
63
+ relative === "" ||
64
+ (relative !== ".." &&
65
+ !relative.startsWith(`..${path.sep}`) &&
66
+ !path.isAbsolute(relative))
67
+ );
68
+ }
69
+
70
+ function sandboxPolicyFromConfig(config, serverName) {
71
+ const raw = dataProperty(config, "sandboxPolicy", null);
72
+ return normalizeMcpSandboxPolicy(raw, {
73
+ label: `MCP stdio server "${serverName}" sandboxPolicy`,
74
+ });
75
+ }
76
+
77
+ function pluginRootFromConfig(config, deps) {
78
+ if (dataProperty(config, "origin", null) !== "plugin:mcp") return null;
79
+ const resolvePlugin =
80
+ deps.resolvePluginWorkspaceAuthority || resolvePluginWorkspaceAuthority;
81
+ return resolvePlugin(dataProperty(config, "pluginWorkspaceAuthority", null), {
82
+ origin: "plugin:mcp",
83
+ pluginId: dataProperty(config, "pluginId", null),
84
+ pluginVersion: dataProperty(config, "pluginVersion", null),
85
+ pluginSource: dataProperty(config, "pluginSource", null),
86
+ });
87
+ }
88
+
89
+ function isProjectFileSource(configScope, configSource) {
90
+ return (
91
+ configScope === "project" &&
92
+ typeof configSource === "string" &&
93
+ path.basename(configSource).toLowerCase() === ".mcp.json"
94
+ );
95
+ }
96
+
97
+ function requirePublicWorkspaceRoot(
98
+ serverName,
99
+ config,
100
+ workspaceBinding,
101
+ deps,
102
+ ) {
103
+ const resolveHost =
104
+ deps.resolveHostWorkspaceBinding || resolveHostHooksV2WorkspaceBinding;
105
+ const binding = resolveHost(workspaceBinding);
106
+ if (!binding?.workspaceRoot) {
107
+ throw workspaceError(
108
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
109
+ `Policy-bearing MCP stdio server "${serverName}" requires a trusted host workspace`,
110
+ );
111
+ }
112
+ const hostRoot = canonicalDirectory(
113
+ binding.workspaceRoot,
114
+ `MCP stdio server "${serverName}" host workspace`,
115
+ );
116
+ const configScope = dataProperty(config, "configScope", null);
117
+ const projectPath = dataProperty(config, "projectPath", null);
118
+ const configSource = dataProperty(config, "configSource", null);
119
+ const projectAuthority = dataProperty(
120
+ config,
121
+ "projectMcpWorkspaceAuthority",
122
+ null,
123
+ );
124
+ const projectFileSource = isProjectFileSource(configScope, configSource);
125
+
126
+ if (
127
+ configScope === "project" &&
128
+ (projectFileSource || projectAuthority) &&
129
+ !projectPath
130
+ ) {
131
+ throw workspaceError(
132
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
133
+ `Project MCP stdio server "${serverName}" is missing its project workspace`,
134
+ );
135
+ }
136
+
137
+ if ((configScope === "local" || configScope === "project") && projectPath) {
138
+ const projectRoot = canonicalDirectory(
139
+ projectPath,
140
+ `MCP stdio server "${serverName}" project workspace`,
141
+ );
142
+ if (!isPathInside(projectRoot, hostRoot)) {
143
+ throw workspaceError(
144
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
145
+ `MCP stdio server "${serverName}" does not belong to the trusted host workspace`,
146
+ );
147
+ }
148
+
149
+ if (projectAuthority || projectFileSource) {
150
+ const resolveProject =
151
+ deps.resolveProjectMcpWorkspaceAuthority ||
152
+ resolveProjectMcpWorkspaceAuthority;
153
+ const authorityRoot = resolveProject(projectAuthority, {
154
+ configSource,
155
+ serverName,
156
+ url: dataProperty(config, "url", null),
157
+ transport: dataProperty(config, "transport", null),
158
+ headersHelper: dataProperty(config, "headersHelper", null),
159
+ });
160
+ let canonicalAuthorityRoot = null;
161
+ try {
162
+ canonicalAuthorityRoot = authorityRoot
163
+ ? canonicalDirectory(
164
+ authorityRoot,
165
+ `MCP stdio server "${serverName}" project authority`,
166
+ )
167
+ : null;
168
+ } catch {
169
+ canonicalAuthorityRoot = null;
170
+ }
171
+ if (canonicalAuthorityRoot !== projectRoot) {
172
+ throw workspaceError(
173
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
174
+ `Project MCP stdio server "${serverName}" is missing its trusted file authority`,
175
+ );
176
+ }
177
+ }
178
+ }
179
+
180
+ return hostRoot;
181
+ }
182
+
183
+ function requestedWorkingDirectory(config, trustedRoot, serverName) {
184
+ const requested = dataProperty(config, "cwd", null);
185
+ if (requested == null || requested === "") return trustedRoot;
186
+ if (typeof requested !== "string" || requested.includes("\0")) {
187
+ throw workspaceError(
188
+ MCP_STDIO_SANDBOX_CWD_INVALID_CODE,
189
+ `MCP stdio server "${serverName}" cwd must be a path`,
190
+ );
191
+ }
192
+ const candidate = canonicalDirectory(
193
+ path.isAbsolute(requested)
194
+ ? requested
195
+ : path.resolve(trustedRoot, requested),
196
+ `MCP stdio server "${serverName}" cwd`,
197
+ );
198
+ if (!isPathInside(trustedRoot, candidate)) {
199
+ throw workspaceError(
200
+ MCP_STDIO_SANDBOX_CWD_INVALID_CODE,
201
+ `MCP stdio server "${serverName}" cwd escapes its trusted workspace`,
202
+ );
203
+ }
204
+ return candidate;
205
+ }
206
+
207
+ /**
208
+ * Resolve source-declared MCP isolation against an opaque host/plugin
209
+ * workspace capability. A policy-bearing launch never derives authority from
210
+ * process.cwd(); the selected cwd is canonical, existing, and contained by the
211
+ * trusted root before executable identity or Broker contract issuance.
212
+ */
213
+ export function resolveMcpStdioSandboxContext(
214
+ { serverName, config, workspaceBinding },
215
+ deps = {},
216
+ ) {
217
+ const name = String(serverName || "unknown");
218
+ const sandboxPolicy = sandboxPolicyFromConfig(config, name);
219
+ const pluginWorkspaceRoot = pluginRootFromConfig(config, deps);
220
+
221
+ if (!sandboxPolicy) {
222
+ return Object.freeze({
223
+ sandboxPolicy: null,
224
+ pluginWorkspaceRoot,
225
+ workingDirectory: pluginWorkspaceRoot,
226
+ });
227
+ }
228
+
229
+ if (
230
+ dataProperty(config, "origin", null) === "plugin:mcp" &&
231
+ !pluginWorkspaceRoot
232
+ ) {
233
+ throw workspaceError(
234
+ MCP_STDIO_SANDBOX_WORKSPACE_REQUIRED_CODE,
235
+ `Plugin MCP stdio server "${name}" is missing its trusted workspace authority`,
236
+ );
237
+ }
238
+
239
+ const trustedRoot = pluginWorkspaceRoot
240
+ ? canonicalDirectory(
241
+ pluginWorkspaceRoot,
242
+ `Plugin MCP stdio server "${name}" workspace`,
243
+ )
244
+ : requirePublicWorkspaceRoot(name, config, workspaceBinding, deps);
245
+ const workingDirectory = requestedWorkingDirectory(config, trustedRoot, name);
246
+
247
+ return Object.freeze({
248
+ sandboxPolicy,
249
+ pluginWorkspaceRoot,
250
+ workingDirectory,
251
+ });
252
+ }
@@ -20,6 +20,28 @@ const SUPPORTED_BOUNDARIES = new Set(PLUGIN_SANDBOX_BOUNDARIES);
20
20
  const PLUGIN_WORKSPACE_AUTHORITY_KIND = "trusted-plugin-workspace";
21
21
  const pluginWorkspaceAuthorities = new WeakMap();
22
22
 
23
+ function directoryGeneration(stat) {
24
+ return stat.birthtimeNs > 0n
25
+ ? `birth:${stat.birthtimeNs.toString()}`
26
+ : `ctime:${stat.ctimeNs.toString()}`;
27
+ }
28
+
29
+ function directoryIdentity(stat) {
30
+ return Object.freeze({
31
+ device: stat.dev,
32
+ inode: stat.ino,
33
+ generation: directoryGeneration(stat),
34
+ });
35
+ }
36
+
37
+ function sameDirectoryIdentity(left, right) {
38
+ return (
39
+ left.device === right.dev &&
40
+ left.inode === right.ino &&
41
+ left.generation === directoryGeneration(right)
42
+ );
43
+ }
44
+
23
45
  function invalidPolicy(message) {
24
46
  const error = new Error(message);
25
47
  error.code = "ERR_PLUGIN_SANDBOX_POLICY_INVALID";
@@ -69,7 +91,7 @@ export function issuePluginWorkspaceAuthority(value = {}) {
69
91
  try {
70
92
  const implementation = fs.realpathSync.native || fs.realpathSync;
71
93
  canonicalRoot = implementation.call(fs.realpathSync, requestedRoot);
72
- stat = fs.statSync(canonicalRoot);
94
+ stat = fs.statSync(canonicalRoot, { bigint: true });
73
95
  } catch {
74
96
  throw invalidPolicy("trusted plugin workspace root is unavailable");
75
97
  }
@@ -92,7 +114,11 @@ export function issuePluginWorkspaceAuthority(value = {}) {
92
114
  });
93
115
  pluginWorkspaceAuthorities.set(
94
116
  authority,
95
- Object.freeze({ root: canonicalRoot, provenance }),
117
+ Object.freeze({
118
+ root: canonicalRoot,
119
+ identity: directoryIdentity(stat),
120
+ provenance,
121
+ }),
96
122
  );
97
123
  return authority;
98
124
  }
@@ -117,6 +143,20 @@ export function resolvePluginWorkspaceAuthority(authority, provenance = {}) {
117
143
  ) {
118
144
  return null;
119
145
  }
146
+ try {
147
+ const implementation = fs.realpathSync.native || fs.realpathSync;
148
+ const currentRoot = implementation.call(fs.realpathSync, binding.root);
149
+ const currentStat = fs.statSync(currentRoot, { bigint: true });
150
+ if (
151
+ currentRoot !== binding.root ||
152
+ !currentStat.isDirectory() ||
153
+ !sameDirectoryIdentity(binding.identity, currentStat)
154
+ ) {
155
+ return null;
156
+ }
157
+ } catch {
158
+ return null;
159
+ }
120
160
  return binding.root;
121
161
  }
122
162