chainlesschain 0.162.188 → 0.162.193

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 (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -12,7 +12,9 @@ import { bootstrap, shutdown } from "../runtime/bootstrap.js";
12
12
  import {
13
13
  MCPClient,
14
14
  MCPServerConfig,
15
+ MCP_CONFIG_SCOPES,
15
16
  inferTransport,
17
+ normalizeMcpConfigScope,
16
18
  } from "../harness/mcp-client.js";
17
19
  import {
18
20
  validateMcpServer,
@@ -25,6 +27,18 @@ import {
25
27
  import { parseJsonOption } from "../lib/parse-json-option.js";
26
28
  import { resolveMcpAuthTarget, isUrlLike } from "../lib/mcp-auth-target.js";
27
29
  import { notFoundWithSuggestion } from "../lib/suggest-name.js";
30
+ import { findGitProjectRoot } from "../lib/project-root.cjs";
31
+ import { redactConfigObject } from "../lib/config-redaction.js";
32
+ import { registerHostHooksV2Workspace } from "../lib/hooks-v2-workspace-context.js";
33
+ import {
34
+ localMcpHeadersHelperFingerprint,
35
+ recordLocalMcpHeadersHelperTrust,
36
+ revokeLocalMcpHeadersHelperTrust,
37
+ } from "../lib/mcp-headers-helper-trust.js";
38
+ import {
39
+ checkProjectMcpTrust,
40
+ issueProjectMcpWorkspaceAuthority,
41
+ } from "../lib/project-mcp-trust.js";
28
42
  import {
29
43
  CATALOG as REGISTRY_CATALOG,
30
44
  CATEGORIES as REGISTRY_CATEGORIES,
@@ -64,8 +78,14 @@ export function isHeadlessEnv(env = process.env, platform = process.platform) {
64
78
  // Singleton MCP client for session reuse
65
79
  let mcpClient = null;
66
80
 
81
+ function commandWorkspaceBinding() {
82
+ return registerHostHooksV2Workspace(projectMcpLocation(process.cwd()).root);
83
+ }
84
+
67
85
  function getClient() {
68
- if (!mcpClient) mcpClient = new MCPClient();
86
+ if (!mcpClient) {
87
+ mcpClient = new MCPClient({ workspaceBinding: commandWorkspaceBinding() });
88
+ }
69
89
  return mcpClient;
70
90
  }
71
91
 
@@ -78,11 +98,13 @@ function getClient() {
78
98
  async function resolveAuthTargetUrl(program, target) {
79
99
  if (isUrlLike(target)) return resolveMcpAuthTarget(target).url;
80
100
  const ctx = await bootstrap({ verbose: program.opts().verbose });
101
+ const config = ctx.db ? new MCPServerConfig(ctx.db.getDatabase()) : null;
102
+ const rows = config
103
+ ? await effectiveMcpRows(config)
104
+ : await readManagedMcpRows();
81
105
  const lookup = (name) => {
82
106
  try {
83
- return ctx.db
84
- ? new MCPServerConfig(ctx.db.getDatabase()).get(name)
85
- : null;
107
+ return rows.find((row) => row.name === name) || null;
86
108
  } catch {
87
109
  return null; // a lookup failure surfaces as "unknown server" below
88
110
  }
@@ -103,11 +125,16 @@ async function connectForQuery(program, serverName) {
103
125
  }
104
126
  const db = ctx.db.getDatabase();
105
127
  const config = new MCPServerConfig(db);
128
+ const projectFlag = String(process.env.CC_PROJECT_MCP || "").toLowerCase();
129
+ const visible = await effectiveMcpRows(config, {
130
+ includeProjectFile:
131
+ Boolean(serverName) || projectFlag === "1" || projectFlag === "true",
132
+ });
106
133
  let rows;
107
134
  if (serverName) {
108
- const row = config.get(serverName);
135
+ const row = visible.find((entry) => entry.name === serverName);
109
136
  if (!row) {
110
- const names = config.list().map((s) => s.name);
137
+ const names = visible.map((s) => s.name);
111
138
  logger.error(
112
139
  `${notFoundWithSuggestion(serverName, names, { noun: "Server" })}. Use 'mcp add' first.`,
113
140
  );
@@ -116,9 +143,9 @@ async function connectForQuery(program, serverName) {
116
143
  }
117
144
  rows = [row];
118
145
  } else {
119
- rows = config.list();
146
+ rows = visible;
120
147
  }
121
- const client = new MCPClient();
148
+ const client = new MCPClient({ workspaceBinding: commandWorkspaceBinding() });
122
149
  const connected = [];
123
150
  for (const row of rows) {
124
151
  if (!row) continue;
@@ -156,6 +183,259 @@ function toPolicyServer(row) {
156
183
  };
157
184
  }
158
185
 
186
+ export function diagnoseMcpTransportConfig(server = {}) {
187
+ const transport = inferTransport(server);
188
+ const supported = new Set(["stdio", "http", "https", "sse", "ws", "wss"]);
189
+ if (!supported.has(transport)) {
190
+ return {
191
+ ok: false,
192
+ code: "unsupported_transport",
193
+ transport,
194
+ message: `Unsupported MCP transport: ${transport}`,
195
+ };
196
+ }
197
+ if (transport === "stdio") {
198
+ return server.command
199
+ ? { ok: true, code: "ok", transport }
200
+ : {
201
+ ok: false,
202
+ code: "missing_command",
203
+ transport,
204
+ message: "stdio transport requires a command",
205
+ };
206
+ }
207
+ let endpoint;
208
+ try {
209
+ endpoint = new URL(String(server.url || ""));
210
+ } catch {
211
+ return {
212
+ ok: false,
213
+ code: "malformed_url",
214
+ transport,
215
+ message: `${transport} transport requires a valid URL`,
216
+ };
217
+ }
218
+ const expected =
219
+ transport === "sse"
220
+ ? new Set(["http:", "https:"])
221
+ : new Set([`${transport}:`]);
222
+ if (!expected.has(endpoint.protocol)) {
223
+ return {
224
+ ok: false,
225
+ code: "scheme_mismatch",
226
+ transport,
227
+ message: `Transport ${transport} is incompatible with URL scheme ${endpoint.protocol}`,
228
+ };
229
+ }
230
+ if (endpoint.username || endpoint.password) {
231
+ return {
232
+ ok: false,
233
+ code: "url_credentials_forbidden",
234
+ transport,
235
+ message:
236
+ "Credentials must be provided with headers/OAuth, not embedded in the URL",
237
+ };
238
+ }
239
+ return { ok: true, code: "ok", transport };
240
+ }
241
+
242
+ function headersHelperField(value) {
243
+ return typeof value === "string" && value.trim()
244
+ ? { headersHelper: value }
245
+ : {};
246
+ }
247
+
248
+ async function readManagedMcpRows() {
249
+ const { loadManagedSettings } = await import("../lib/settings-loader.cjs");
250
+ const loaded = loadManagedSettings({ env: process.env });
251
+ const block =
252
+ loaded.settings?.managedMcpServers || loaded.settings?.mcpServers || {};
253
+ if (!block || typeof block !== "object" || Array.isArray(block)) return [];
254
+ return Object.entries(block)
255
+ .filter(([, config]) => config && typeof config === "object")
256
+ .map(([name, config]) => ({
257
+ name,
258
+ command: config.command || null,
259
+ args: Array.isArray(config.args) ? config.args : [],
260
+ env: config.env && typeof config.env === "object" ? config.env : {},
261
+ url: config.url || null,
262
+ transport: inferTransport(config),
263
+ headers:
264
+ config.headers && typeof config.headers === "object"
265
+ ? config.headers
266
+ : {},
267
+ ...headersHelperField(config.headersHelper),
268
+ autoConnect: config.autoConnect !== false,
269
+ configScope: "managed",
270
+ configSource: loaded.file,
271
+ projectPath: null,
272
+ }));
273
+ }
274
+
275
+ function projectMcpLocation(cwd = process.cwd()) {
276
+ const root = findGitProjectRoot(cwd, { fs, path }) || path.resolve(cwd);
277
+ return { root, file: path.join(root, ".mcp.json") };
278
+ }
279
+
280
+ function readProjectMcpDocument(cwd = process.cwd()) {
281
+ const location = projectMcpLocation(cwd);
282
+ if (!fs.existsSync(location.file)) {
283
+ return { ...location, document: { mcpServers: {} } };
284
+ }
285
+ let content;
286
+ let document;
287
+ try {
288
+ content = fs.readFileSync(location.file, "utf8");
289
+ document = JSON.parse(content);
290
+ } catch (error) {
291
+ throw new Error(
292
+ `Cannot read project MCP config ${location.file}: ${error.message}`,
293
+ );
294
+ }
295
+ if (!document || typeof document !== "object" || Array.isArray(document)) {
296
+ throw new Error(
297
+ `Project MCP config must be a JSON object: ${location.file}`,
298
+ );
299
+ }
300
+ if (
301
+ document.mcpServers != null &&
302
+ (typeof document.mcpServers !== "object" ||
303
+ Array.isArray(document.mcpServers))
304
+ ) {
305
+ throw new Error(`mcpServers must be an object in ${location.file}`);
306
+ }
307
+ return {
308
+ ...location,
309
+ content,
310
+ document: { ...document, mcpServers: { ...(document.mcpServers || {}) } },
311
+ };
312
+ }
313
+
314
+ export function readProjectMcpRows(cwd = process.cwd()) {
315
+ const { root, file, content, document } = readProjectMcpDocument(cwd);
316
+ let trusted = false;
317
+ try {
318
+ trusted = checkProjectMcpTrust(file, content).status === "trusted";
319
+ } catch {
320
+ // Listing remains available, but execution authority fails closed below.
321
+ }
322
+ return Object.entries(document.mcpServers)
323
+ .filter(([, config]) => config && typeof config === "object")
324
+ .map(([name, config]) => {
325
+ const row = {
326
+ name,
327
+ command: config.command || null,
328
+ args: Array.isArray(config.args) ? config.args : [],
329
+ env: config.env && typeof config.env === "object" ? config.env : {},
330
+ url: config.url || null,
331
+ transport: inferTransport(config),
332
+ headers:
333
+ config.headers && typeof config.headers === "object"
334
+ ? config.headers
335
+ : {},
336
+ ...headersHelperField(config.headersHelper),
337
+ autoConnect: true,
338
+ configScope: "project",
339
+ configSource: file,
340
+ projectPath: root,
341
+ };
342
+ if (trusted && row.headersHelper) {
343
+ row.projectMcpWorkspaceAuthority = issueProjectMcpWorkspaceAuthority({
344
+ file,
345
+ content,
346
+ workspaceRoot: root,
347
+ serverName: name,
348
+ config: row,
349
+ });
350
+ }
351
+ return row;
352
+ });
353
+ }
354
+
355
+ function writeProjectMcpDocument(file, document) {
356
+ const temporary = `${file}.${process.pid}.${Date.now()}.tmp`;
357
+ fs.writeFileSync(temporary, `${JSON.stringify(document, null, 2)}\n`, "utf8");
358
+ try {
359
+ fs.renameSync(temporary, file);
360
+ } catch (error) {
361
+ try {
362
+ fs.unlinkSync(temporary);
363
+ } catch {
364
+ // best-effort temporary-file cleanup
365
+ }
366
+ throw error;
367
+ }
368
+ }
369
+
370
+ export function writeProjectMcpServer(name, server, cwd = process.cwd()) {
371
+ const { file, document } = readProjectMcpDocument(cwd);
372
+ const config = {};
373
+ if (server.command) config.command = server.command;
374
+ if (server.args?.length) config.args = server.args;
375
+ if (server.env && Object.keys(server.env).length > 0) config.env = server.env;
376
+ if (server.url) config.url = server.url;
377
+ if (server.transport) config.transport = server.transport;
378
+ if (server.headers && Object.keys(server.headers).length > 0) {
379
+ config.headers = server.headers;
380
+ }
381
+ Object.assign(config, headersHelperField(server.headersHelper));
382
+ document.mcpServers[name] = config;
383
+ writeProjectMcpDocument(file, document);
384
+ return file;
385
+ }
386
+
387
+ export function removeProjectMcpServer(name, cwd = process.cwd()) {
388
+ const { file, document } = readProjectMcpDocument(cwd);
389
+ if (!Object.hasOwn(document.mcpServers, name)) return false;
390
+ delete document.mcpServers[name];
391
+ writeProjectMcpDocument(file, document);
392
+ return true;
393
+ }
394
+
395
+ function firstMcpRowByName(rows) {
396
+ const names = new Set();
397
+ return rows.filter((row) => {
398
+ if (names.has(row.name)) return false;
399
+ names.add(row.name);
400
+ return true;
401
+ });
402
+ }
403
+
404
+ async function effectiveMcpRows(config, options = {}) {
405
+ const scope = options.scope;
406
+ const cwd = options.cwd || process.cwd();
407
+ const project =
408
+ options.includeProjectFile === false || (scope && scope !== "project")
409
+ ? []
410
+ : readProjectMcpRows(cwd);
411
+ const stored =
412
+ scope === "managed"
413
+ ? []
414
+ : scope
415
+ ? config.list({ scope, cwd, allScopes: options.allScopes === true })
416
+ : options.allScopes === true
417
+ ? config.list({ allScopes: true })
418
+ : [
419
+ ...config.list({ scope: "local", cwd }),
420
+ ...config.list({ scope: "project", cwd }),
421
+ ...config.list({ scope: "user", cwd }),
422
+ ];
423
+ if (scope && scope !== "managed") {
424
+ const rows = scope === "project" ? [...project, ...stored] : stored;
425
+ return firstMcpRowByName(rows);
426
+ }
427
+ const managed = await readManagedMcpRows();
428
+ if (options.allScopes === true) return [...managed, ...project, ...stored];
429
+ const ordered = [
430
+ ...managed,
431
+ ...stored.filter((row) => row.configScope === "local"),
432
+ ...project,
433
+ ...stored.filter((row) => row.configScope === "project"),
434
+ ...stored.filter((row) => row.configScope === "user"),
435
+ ];
436
+ return firstMcpRowByName(ordered);
437
+ }
438
+
159
439
  export function registerMcpCommand(program) {
160
440
  const mcp = program
161
441
  .command("mcp")
@@ -406,9 +686,15 @@ export function registerMcpCommand(program) {
406
686
  // mcp servers — list configured servers
407
687
  mcp
408
688
  .command("servers")
689
+ .alias("list")
409
690
  .description("List configured MCP servers")
410
691
  .option("--json", "Output as JSON")
411
692
  .option("--mode <mode>", "Runtime mode (local | lan | hosted)")
693
+ .option(
694
+ "--scope <scope>",
695
+ `Configuration scope: ${MCP_CONFIG_SCOPES.join(" | ")}`,
696
+ )
697
+ .option("--all-scopes", "Include project-local entries outside cwd")
412
698
  .action(async (options) => {
413
699
  try {
414
700
  const ctx = await bootstrap({ verbose: program.opts().verbose });
@@ -419,7 +705,13 @@ export function registerMcpCommand(program) {
419
705
 
420
706
  const db = ctx.db.getDatabase();
421
707
  const config = new MCPServerConfig(db);
422
- const servers = config.list();
708
+ const scope = options.scope
709
+ ? normalizeMcpConfigScope(options.scope)
710
+ : undefined;
711
+ const servers = await effectiveMcpRows(config, {
712
+ scope,
713
+ allScopes: options.allScopes === true,
714
+ });
423
715
  const mode = resolveMode(options);
424
716
  const annotated = servers.map((s) => {
425
717
  const { allowed, reason, transport } = validateMcpServer(
@@ -440,7 +732,7 @@ export function registerMcpCommand(program) {
440
732
  });
441
733
 
442
734
  if (options.json) {
443
- console.log(JSON.stringify(annotated, null, 2));
735
+ console.log(JSON.stringify(redactConfigObject(annotated), null, 2));
444
736
  } else if (servers.length === 0) {
445
737
  logger.info("No MCP servers configured. Use 'mcp add' to add one.");
446
738
  } else {
@@ -453,6 +745,9 @@ export function registerMcpCommand(program) {
453
745
  ? chalk.green(" [ok]")
454
746
  : chalk.yellow(` [blocked: ${s._reason}]`);
455
747
  logger.log(` ${chalk.cyan(s.name)}${auto}${flag}`);
748
+ logger.log(
749
+ ` ${chalk.gray("Scope:")} ${s.configScope || "user"} ${chalk.gray(`(${s.configSource || "legacy-database"})`)}`,
750
+ );
456
751
  if (s.url) {
457
752
  logger.log(
458
753
  ` ${chalk.gray("URL:")} ${s.url} ${chalk.gray(`[${s.transport || s._transport || "http"}]`)}`,
@@ -462,6 +757,9 @@ export function registerMcpCommand(program) {
462
757
  ` ${chalk.gray("Command:")} ${s.command} ${s.args.join(" ")}`,
463
758
  );
464
759
  }
760
+ if (s.headersHelper) {
761
+ logger.log(` ${chalk.gray("Headers helper:")} configured`);
762
+ }
465
763
  logger.log(
466
764
  ` ${chalk.gray("Compatible:")} ${s._modeCompatibility.join(", ") || "(none)"}`,
467
765
  );
@@ -490,10 +788,19 @@ export function registerMcpCommand(program) {
490
788
  "-t, --transport <kind>",
491
789
  "Transport kind: stdio | http | https | sse | ws | wss",
492
790
  )
791
+ .option(
792
+ "--scope <scope>",
793
+ `Configuration scope: ${MCP_CONFIG_SCOPES.join(" | ")}`,
794
+ "local",
795
+ )
493
796
  .option(
494
797
  "-H, --header <header...>",
495
798
  "HTTP header to include on requests (KEY=VALUE, repeatable)",
496
799
  )
800
+ .option(
801
+ "--headers-helper <command>",
802
+ "Shell command that prints fresh HTTP headers as one JSON object",
803
+ )
497
804
  .option("--auto-connect", "Auto-connect on startup")
498
805
  .option(
499
806
  "--mode <mode>",
@@ -540,17 +847,44 @@ export function registerMcpCommand(program) {
540
847
  }
541
848
  }
542
849
 
850
+ const configScope = normalizeMcpConfigScope(options.scope);
851
+ if (configScope === "managed") {
852
+ throw new Error(
853
+ "Managed MCP configuration is read-only; provision it through managed settings",
854
+ );
855
+ }
856
+ if (
857
+ configScope === "project" &&
858
+ Object.keys(headers).some((key) =>
859
+ /authorization|proxy-authorization|cookie|api[-_]?key|token|secret/i.test(
860
+ key,
861
+ ),
862
+ )
863
+ ) {
864
+ throw new Error(
865
+ "Project-scoped .mcp.json must not contain credential headers; use OAuth login or local/user scope",
866
+ );
867
+ }
868
+
543
869
  const transport =
544
870
  options.transport ||
545
871
  (options.url ? inferTransport({ url: options.url }) : "stdio");
546
872
 
547
- if (options.url) {
548
- try {
549
- new URL(options.url);
550
- } catch (_e) {
551
- logger.error(`Invalid URL: ${options.url}`);
552
- process.exit(1);
553
- }
873
+ if (options.headersHelper && !options.url) {
874
+ throw new Error(
875
+ "--headers-helper is only supported by HTTP, SSE, and WebSocket transports",
876
+ );
877
+ }
878
+
879
+ const transportDiagnostic = diagnoseMcpTransportConfig({
880
+ command: options.command,
881
+ url: options.url,
882
+ transport,
883
+ });
884
+ if (!transportDiagnostic.ok) {
885
+ throw new Error(
886
+ `${transportDiagnostic.code}: ${transportDiagnostic.message}`,
887
+ );
554
888
  }
555
889
 
556
890
  const mode = resolveMode(options);
@@ -570,7 +904,12 @@ export function registerMcpCommand(program) {
570
904
  );
571
905
  }
572
906
 
573
- config.add(name, {
907
+ const workspaceRoot = projectMcpLocation(process.cwd()).root;
908
+ const previousLocal =
909
+ configScope === "local"
910
+ ? config.get(name, { scope: "local", cwd: workspaceRoot })
911
+ : null;
912
+ const storedConfig = {
574
913
  command: options.command || null,
575
914
  args,
576
915
  url: options.url || null,
@@ -578,7 +917,42 @@ export function registerMcpCommand(program) {
578
917
  env: {},
579
918
  autoConnect: !!options.autoConnect,
580
919
  headers: Object.keys(headers).length > 0 ? headers : undefined,
581
- });
920
+ ...headersHelperField(options.headersHelper),
921
+ configScope,
922
+ projectPath: configScope === "local" ? workspaceRoot : null,
923
+ };
924
+ let configSource;
925
+ if (configScope === "project") {
926
+ configSource = writeProjectMcpServer(
927
+ name,
928
+ storedConfig,
929
+ process.cwd(),
930
+ );
931
+ } else {
932
+ if (configScope === "local" && previousLocal?.headersHelper) {
933
+ revokeLocalMcpHeadersHelperTrust({
934
+ workspaceRoot,
935
+ serverName: name,
936
+ url: previousLocal.url,
937
+ transport: previousLocal.transport,
938
+ headersHelper: previousLocal.headersHelper,
939
+ });
940
+ }
941
+ config.add(name, storedConfig);
942
+ if (configScope === "local" && storedConfig.headersHelper) {
943
+ recordLocalMcpHeadersHelperTrust({
944
+ workspaceRoot,
945
+ serverName: name,
946
+ url: storedConfig.url,
947
+ transport: storedConfig.transport,
948
+ headersHelper: storedConfig.headersHelper,
949
+ });
950
+ }
951
+ configSource =
952
+ configScope === "user"
953
+ ? "user-database"
954
+ : `${configScope}:${workspaceRoot}`;
955
+ }
582
956
 
583
957
  const payload = {
584
958
  name,
@@ -587,6 +961,11 @@ export function registerMcpCommand(program) {
587
961
  url: options.url || null,
588
962
  transport,
589
963
  autoConnect: !!options.autoConnect,
964
+ headersHelper: storedConfig.headersHelper
965
+ ? "<configured>"
966
+ : undefined,
967
+ configScope,
968
+ configSource,
590
969
  };
591
970
 
592
971
  if (options.json) {
@@ -602,6 +981,14 @@ export function registerMcpCommand(program) {
602
981
  ` ${chalk.gray("Command:")} ${options.command} ${args.join(" ")}`,
603
982
  );
604
983
  }
984
+ if (configScope === "project") {
985
+ logger.log(
986
+ ` ${chalk.gray("Shared config:")} ${configSource} (run with --project-mcp after trust review)`,
987
+ );
988
+ }
989
+ if (storedConfig.headersHelper) {
990
+ logger.log(` ${chalk.gray("Headers helper:")} configured`);
991
+ }
605
992
  }
606
993
 
607
994
  await shutdown();
@@ -616,7 +1003,11 @@ export function registerMcpCommand(program) {
616
1003
  .command("remove")
617
1004
  .description("Remove an MCP server configuration")
618
1005
  .argument("<name>", "Server name")
619
- .action(async (name) => {
1006
+ .option(
1007
+ "--scope <scope>",
1008
+ `Configuration scope: ${MCP_CONFIG_SCOPES.join(" | ")}`,
1009
+ )
1010
+ .action(async (name, options) => {
620
1011
  try {
621
1012
  const ctx = await bootstrap({ verbose: program.opts().verbose });
622
1013
  if (!ctx.db) {
@@ -626,8 +1017,55 @@ export function registerMcpCommand(program) {
626
1017
 
627
1018
  const db = ctx.db.getDatabase();
628
1019
  const config = new MCPServerConfig(db);
629
- const names = config.list().map((s) => s.name);
630
- const removed = config.remove(name);
1020
+ const scope = options.scope
1021
+ ? normalizeMcpConfigScope(options.scope)
1022
+ : undefined;
1023
+ if (scope === "managed") {
1024
+ throw new Error(
1025
+ "Managed MCP configuration is read-only; change the managed settings source",
1026
+ );
1027
+ }
1028
+ const projectFlag = String(
1029
+ process.env.CC_PROJECT_MCP || "",
1030
+ ).toLowerCase();
1031
+ const visible = await effectiveMcpRows(config, {
1032
+ scope,
1033
+ includeProjectFile:
1034
+ Boolean(name) ||
1035
+ scope === "project" ||
1036
+ projectFlag === "1" ||
1037
+ projectFlag === "true",
1038
+ });
1039
+ const selected = visible.find((row) => row.name === name);
1040
+ if (selected?.configScope === "managed") {
1041
+ throw new Error(
1042
+ "Managed MCP configuration is read-only; change the managed settings source",
1043
+ );
1044
+ }
1045
+ const names = visible.map((s) => s.name);
1046
+ const projectFile = projectMcpLocation(process.cwd()).file;
1047
+ if (
1048
+ selected?.configScope === "local" &&
1049
+ selected.headersHelper &&
1050
+ selected.projectPath
1051
+ ) {
1052
+ revokeLocalMcpHeadersHelperTrust({
1053
+ workspaceRoot: selected.projectPath,
1054
+ serverName: name,
1055
+ url: selected.url,
1056
+ transport: selected.transport,
1057
+ headersHelper: selected.headersHelper,
1058
+ });
1059
+ }
1060
+ const removed =
1061
+ selected?.configScope === "project" &&
1062
+ path.resolve(selected.configSource || "") ===
1063
+ path.resolve(projectFile)
1064
+ ? removeProjectMcpServer(name, process.cwd())
1065
+ : config.remove(name, {
1066
+ scope: selected?.configScope || scope,
1067
+ cwd: process.cwd(),
1068
+ });
631
1069
 
632
1070
  if (removed) {
633
1071
  logger.success(`MCP server "${name}" removed`);
@@ -643,6 +1081,181 @@ export function registerMcpCommand(program) {
643
1081
  });
644
1082
 
645
1083
  // mcp connect — connect to a server
1084
+ mcp
1085
+ .command("get")
1086
+ .description("Show one MCP server configuration and its source")
1087
+ .argument("<name>", "Server name")
1088
+ .option(
1089
+ "--scope <scope>",
1090
+ `Configuration scope: ${MCP_CONFIG_SCOPES.join(" | ")}`,
1091
+ )
1092
+ .option("--json", "Output as JSON")
1093
+ .action(async (name, options) => {
1094
+ try {
1095
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
1096
+ if (!ctx.db) throw new Error("Database not available");
1097
+ const config = new MCPServerConfig(ctx.db.getDatabase());
1098
+ const scope = options.scope
1099
+ ? normalizeMcpConfigScope(options.scope)
1100
+ : undefined;
1101
+ const visible = await effectiveMcpRows(config, { scope });
1102
+ const server = visible.find((row) => row.name === name) || null;
1103
+ if (!server) {
1104
+ throw new Error(
1105
+ notFoundWithSuggestion(
1106
+ name,
1107
+ visible.map((row) => row.name),
1108
+ { noun: "Server" },
1109
+ ),
1110
+ );
1111
+ }
1112
+ if (options.json) {
1113
+ console.log(JSON.stringify(redactConfigObject(server), null, 2));
1114
+ } else {
1115
+ logger.log(chalk.bold(server.name));
1116
+ logger.log(` Scope: ${server.configScope}`);
1117
+ logger.log(` Source: ${server.configSource}`);
1118
+ logger.log(` Transport: ${server.transport}`);
1119
+ logger.log(
1120
+ server.url
1121
+ ? ` URL: ${server.url}`
1122
+ : ` Command: ${server.command} ${(server.args || []).join(" ")}`,
1123
+ );
1124
+ if (server.headersHelper) {
1125
+ logger.log(" Headers helper: configured");
1126
+ }
1127
+ }
1128
+ await shutdown();
1129
+ } catch (err) {
1130
+ logger.error(`Failed: ${err.message}`);
1131
+ process.exitCode = 1;
1132
+ }
1133
+ });
1134
+
1135
+ mcp
1136
+ .command("doctor")
1137
+ .description("Validate MCP configuration and test transport handshakes")
1138
+ .argument("[name]", "Optional server name")
1139
+ .option(
1140
+ "--scope <scope>",
1141
+ `Configuration scope: ${MCP_CONFIG_SCOPES.join(" | ")}`,
1142
+ )
1143
+ .option("--timeout <ms>", "Connect/request timeout", "10000")
1144
+ .option("--json", "Output structured diagnostics as JSON")
1145
+ .action(async (name, options) => {
1146
+ const diagnostics = [];
1147
+ let client = null;
1148
+ try {
1149
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
1150
+ if (!ctx.db) throw new Error("Database not available");
1151
+ const config = new MCPServerConfig(ctx.db.getDatabase());
1152
+ const scope = options.scope
1153
+ ? normalizeMcpConfigScope(options.scope)
1154
+ : undefined;
1155
+ const projectFlag = String(
1156
+ process.env.CC_PROJECT_MCP || "",
1157
+ ).toLowerCase();
1158
+ const visible = await effectiveMcpRows(config, {
1159
+ scope,
1160
+ includeProjectFile:
1161
+ Boolean(name) ||
1162
+ scope === "project" ||
1163
+ projectFlag === "1" ||
1164
+ projectFlag === "true",
1165
+ });
1166
+ const rows = name
1167
+ ? visible.filter((row) => row.name === name)
1168
+ : visible;
1169
+ if (name && rows.length === 0) {
1170
+ throw new Error(
1171
+ notFoundWithSuggestion(
1172
+ name,
1173
+ visible.map((row) => row.name),
1174
+ { noun: "Server" },
1175
+ ),
1176
+ );
1177
+ }
1178
+ const timeoutMs = Math.max(
1179
+ 1,
1180
+ Number.parseInt(options.timeout, 10) || 10000,
1181
+ );
1182
+ for (const row of rows) {
1183
+ const staticCheck = diagnoseMcpTransportConfig(row);
1184
+ const record = {
1185
+ name: row.name,
1186
+ scope: row.configScope,
1187
+ source: row.configSource,
1188
+ transport: staticCheck.transport,
1189
+ ok: false,
1190
+ code: staticCheck.code,
1191
+ message: staticCheck.message || null,
1192
+ };
1193
+ if (!staticCheck.ok) {
1194
+ diagnostics.push(record);
1195
+ continue;
1196
+ }
1197
+ const policy = validateMcpServer(toPolicyServer(row), "local");
1198
+ if (!policy.allowed) {
1199
+ diagnostics.push({
1200
+ ...record,
1201
+ code: "policy_denied",
1202
+ message: policy.reason,
1203
+ });
1204
+ continue;
1205
+ }
1206
+ client = new MCPClient({
1207
+ workspaceBinding: commandWorkspaceBinding(),
1208
+ });
1209
+ try {
1210
+ const connected = await client.connect(row.name, {
1211
+ ...row,
1212
+ connectTimeoutMs: timeoutMs,
1213
+ requestTimeoutMs: timeoutMs,
1214
+ });
1215
+ diagnostics.push({
1216
+ ...record,
1217
+ ok: true,
1218
+ code: "ok",
1219
+ message: null,
1220
+ tools: connected.tools?.length || 0,
1221
+ resources: connected.resources?.length || 0,
1222
+ prompts: connected.prompts?.length || 0,
1223
+ });
1224
+ } catch (error) {
1225
+ diagnostics.push({
1226
+ ...record,
1227
+ code: error?.code || "connect_failed",
1228
+ message: error?.message || String(error),
1229
+ status: error?.status ?? null,
1230
+ closeCode: error?.closeCode ?? null,
1231
+ });
1232
+ } finally {
1233
+ await client.disconnectAll();
1234
+ client = null;
1235
+ }
1236
+ }
1237
+ if (options.json) {
1238
+ console.log(JSON.stringify(diagnostics, null, 2));
1239
+ } else if (diagnostics.length === 0) {
1240
+ logger.info("No MCP servers configured in the selected scope.");
1241
+ } else {
1242
+ for (const row of diagnostics) {
1243
+ const state = row.ok ? chalk.green("ok") : chalk.red(row.code);
1244
+ logger.log(
1245
+ ` ${chalk.cyan(row.name)} [${row.scope}/${row.transport}] ${state}`,
1246
+ );
1247
+ if (row.message) logger.log(` ${chalk.gray(row.message)}`);
1248
+ }
1249
+ }
1250
+ if (diagnostics.some((row) => !row.ok)) process.exitCode = 1;
1251
+ await shutdown();
1252
+ } catch (err) {
1253
+ await client?.disconnectAll?.();
1254
+ logger.error(`MCP doctor failed: ${err.message}`);
1255
+ process.exitCode = 1;
1256
+ }
1257
+ });
1258
+
646
1259
  mcp
647
1260
  .command("connect")
648
1261
  .description("Connect to an MCP server")
@@ -660,10 +1273,13 @@ export function registerMcpCommand(program) {
660
1273
 
661
1274
  const db = ctx.db.getDatabase();
662
1275
  const config = new MCPServerConfig(db);
663
- const serverConfig = config.get(name);
1276
+ const visible = await effectiveMcpRows(config, {
1277
+ includeProjectFile: true,
1278
+ });
1279
+ const serverConfig = visible.find((row) => row.name === name) || null;
664
1280
 
665
1281
  if (!serverConfig) {
666
- const names = config.list().map((s) => s.name);
1282
+ const names = visible.map((s) => s.name);
667
1283
  logger.error(
668
1284
  `${notFoundWithSuggestion(name, names, { noun: "Server" })}. Use 'mcp add' first.`,
669
1285
  );
@@ -998,6 +1614,54 @@ export function registerMcpCommand(program) {
998
1614
  }
999
1615
  });
1000
1616
 
1617
+ // mcp trust-helper — approve one exact workspace-local helper command
1618
+ mcp
1619
+ .command("trust-helper <name>")
1620
+ .description(
1621
+ "Trust the exact headers helper command for a workspace-local MCP server",
1622
+ )
1623
+ .option("--json", "Output as JSON")
1624
+ .action(async (name, options) => {
1625
+ try {
1626
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
1627
+ if (!ctx.db) throw new Error("Database not available");
1628
+ const workspaceRoot = projectMcpLocation(process.cwd()).root;
1629
+ const config = new MCPServerConfig(ctx.db.getDatabase()).get(name, {
1630
+ scope: "local",
1631
+ cwd: workspaceRoot,
1632
+ });
1633
+ if (!config?.headersHelper) {
1634
+ throw new Error(
1635
+ `No workspace-local MCP headers helper is configured for "${name}"`,
1636
+ );
1637
+ }
1638
+ const spec = {
1639
+ workspaceRoot,
1640
+ serverName: name,
1641
+ url: config.url,
1642
+ transport: config.transport,
1643
+ headersHelper: config.headersHelper,
1644
+ };
1645
+ const trusted = recordLocalMcpHeadersHelperTrust(spec);
1646
+ const payload = {
1647
+ name,
1648
+ workspaceRoot,
1649
+ trusted,
1650
+ fingerprint: localMcpHeadersHelperFingerprint(spec).slice(0, 16),
1651
+ };
1652
+ if (options.json) console.log(JSON.stringify(payload, null, 2));
1653
+ else {
1654
+ logger.success(
1655
+ `Trusted headers helper for "${name}" (${payload.fingerprint})`,
1656
+ );
1657
+ }
1658
+ await shutdown();
1659
+ } catch (err) {
1660
+ logger.error(`Failed: ${err.message}`);
1661
+ process.exitCode = 1;
1662
+ }
1663
+ });
1664
+
1001
1665
  // mcp scaffold — generate a boilerplate MCP server project
1002
1666
  mcp
1003
1667
  .command("trust-project")