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.
- package/README.md +61 -11
- package/bin/chainlesschain.js +7 -52
- package/completions/_cc +209 -0
- package/completions/cc.bash +18 -0
- package/completions/cc.fish +13 -0
- package/completions/cc.ps1 +226 -0
- package/package.json +10 -2
- package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
- package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
- package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
- package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
- package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
- package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
- package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
- package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
- package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
- package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
- package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
- package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
- package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
- package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
- package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
- package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
- package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
- package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
- package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/cli-help.js +181 -0
- package/src/command-help-index.json +181 -0
- package/src/command-manifest.json +1107 -175
- package/src/command-surface-policy.js +197 -0
- package/src/commands/agent.js +98 -33
- package/src/commands/artifacts.js +400 -2
- package/src/commands/background-session.js +41 -3
- package/src/commands/checkpoint-managed.js +1059 -0
- package/src/commands/checkpoint-restore-recovery.js +1476 -0
- package/src/commands/checkpoint.js +950 -22
- package/src/commands/compact.js +101 -25
- package/src/commands/config.js +506 -20
- package/src/commands/doctor.js +4 -1
- package/src/commands/hub.js +1 -1
- package/src/commands/mcp.js +688 -24
- package/src/commands/pack.js +16 -2
- package/src/commands/plugin.js +20 -12
- package/src/commands/session-mcp-recovery.js +218 -0
- package/src/commands/session.js +470 -110
- package/src/commands/setup.js +36 -10
- package/src/commands/skill.js +181 -110
- package/src/commands/status.js +21 -5
- package/src/commands/team-distributed.js +3324 -0
- package/src/commands/team.js +1130 -74
- package/src/commands/update.js +68 -6
- package/src/constants.js +11 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/action-protocol.js +10 -0
- package/src/gateways/ws/session-protocol.js +555 -27
- package/src/gateways/ws/ws-agent-handler.js +541 -14
- package/src/gateways/ws/ws-session-gateway.js +129 -22
- package/src/gateways/ws/ws-session-state.js +431 -0
- package/src/harness/background-task-manager.js +233 -36
- package/src/harness/jsonl-session-store.js +2551 -167
- package/src/harness/mcp-client.js +802 -61
- package/src/harness/prompt-compressor.js +227 -27
- package/src/harness/session-index.js +89 -38
- package/src/harness/session-list-index.js +254 -0
- package/src/harness/structured-handoff.js +410 -0
- package/src/lazy-dispatch.js +747 -84
- package/src/lib/__tests__/logger.test.js +50 -2
- package/src/lib/advisor-runtime.js +1047 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +120 -26
- package/src/lib/agent-session-export.js +20 -0
- package/src/lib/agent-team/task-lease.js +271 -3
- package/src/lib/agent-team/team-adjudication.js +1501 -0
- package/src/lib/agent-team/team-budget.js +4 -1
- package/src/lib/agent-team/team-control-store.js +582 -0
- package/src/lib/agent-team/team-distributed-queue.js +5246 -0
- package/src/lib/agent-team/team-process-checkpoint.js +211 -0
- package/src/lib/agent-team/team-runner.js +543 -24
- package/src/lib/agent-team/team-worktree.js +1403 -95
- package/src/lib/artifact-store.js +131 -8
- package/src/lib/background-agent-supervisor.js +185 -13
- package/src/lib/background-interaction-journal.js +37 -9
- package/src/lib/background-launch-profile.js +1058 -0
- package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
- package/src/lib/checkpoint-restore-orchestrator.js +987 -0
- package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
- package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
- package/src/lib/checkpoint-restore-recovery.js +884 -0
- package/src/lib/checkpoint-restore-retention.js +126 -0
- package/src/lib/checkpoint-restore-saga.js +5079 -0
- package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
- package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
- package/src/lib/checkpoint-store.js +1688 -97
- package/src/lib/checkpoint-timeline-authority.js +522 -0
- package/src/lib/checkpoint-timeline.js +642 -0
- package/src/lib/config-keys.js +18 -119
- package/src/lib/config-manager.js +446 -27
- package/src/lib/config-redaction.js +57 -0
- package/src/lib/config-schema.js +853 -0
- package/src/lib/cowork-mcp-tools.js +5 -0
- package/src/lib/cowork-task-runner.js +458 -63
- package/src/lib/delivery-coordinator.js +1234 -0
- package/src/lib/delivery-evidence.js +450 -0
- package/src/lib/doctor-checkup.js +199 -14
- package/src/lib/executable-path.js +34 -0
- package/src/lib/fatal-handler.js +16 -0
- package/src/lib/file-checkpoint.js +4909 -186
- package/src/lib/file-lines.js +125 -0
- package/src/lib/headless-config-command.js +16 -5
- package/src/lib/hook-runner.cjs +139 -38
- package/src/lib/hooks-v2-workspace-context.js +10 -0
- package/src/lib/impacted-gate-selector.js +424 -0
- package/src/lib/interaction-adapter.js +62 -0
- package/src/lib/jsonl-session-store.js +1 -35
- package/src/lib/logger.js +66 -14
- package/src/lib/managed-checkpoint-render.js +60 -0
- package/src/lib/managed-tool-checkpoint.js +194 -0
- package/src/lib/mcp-call-ledger-store.js +1069 -0
- package/src/lib/mcp-call-ledger.js +747 -0
- package/src/lib/mcp-client.js +5 -0
- package/src/lib/mcp-conflict-scheduler.js +468 -0
- package/src/lib/mcp-effect-contract.js +102 -0
- package/src/lib/mcp-headers-helper-trust.js +145 -0
- package/src/lib/mcp-headers-helper.js +616 -0
- package/src/lib/mcp-host-recovery-runtime.js +131 -0
- package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
- package/src/lib/mcp-recovery-adjudication.js +443 -0
- package/src/lib/output-context.js +86 -0
- package/src/lib/packer/file-identity.js +170 -0
- package/src/lib/packer/index.js +3 -0
- package/src/lib/packer/native-update-state.js +277 -0
- package/src/lib/packer/pack-update-applier.js +1983 -136
- package/src/lib/packer/pack-update-checker.js +34 -0
- package/src/lib/packer/pack-update-downloader.js +875 -86
- package/src/lib/packer/pack-update-signature.js +86 -0
- package/src/lib/packer/pkg-config-generator.js +6 -0
- package/src/lib/paths.js +65 -10
- package/src/lib/plan-mode.js +831 -14
- package/src/lib/plan-persistence.js +540 -0
- package/src/lib/plugin-runtime/hooks.js +227 -69
- package/src/lib/plugin-runtime/plugin-options.js +189 -44
- package/src/lib/pr-automation-policy.js +146 -8
- package/src/lib/process-execution-broker/credential-agent.js +7 -0
- package/src/lib/process-execution-broker/index.js +491 -13
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
- package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
- package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
- package/src/lib/project-instructions.js +165 -29
- package/src/lib/project-mcp-trust.js +67 -0
- package/src/lib/public-ide-capability-manifest.js +272 -0
- package/src/lib/public-ide-capability-validation.js +351 -0
- package/src/lib/secret-store.js +267 -43
- package/src/lib/secure-file-identity.js +433 -0
- package/src/lib/secure-fs.js +1089 -0
- package/src/lib/security-audit.js +58 -0
- package/src/lib/service-manager.js +34 -13
- package/src/lib/session-budget-runtime.js +1452 -0
- package/src/lib/session-host-snapshot.js +388 -0
- package/src/lib/session-message-provenance.js +429 -0
- package/src/lib/session-projection.js +804 -0
- package/src/lib/session-resource-budget.js +1495 -0
- package/src/lib/settings-hooks.cjs +138 -22
- package/src/lib/settings-loader.cjs +25 -2
- package/src/lib/side-effect-ledger-store.js +45 -23
- package/src/lib/skill-execution-identity.js +217 -0
- package/src/lib/skill-loader.js +299 -18
- package/src/lib/sub-agent-context.js +236 -28
- package/src/lib/sub-agent-registry.js +5 -0
- package/src/lib/subagent-contract.js +94 -0
- package/src/lib/todo-manager.js +185 -18
- package/src/lib/todo-persistence.js +417 -0
- package/src/lib/turn-binding-store.js +41 -23
- package/src/lib/turn-binding.js +160 -2
- package/src/lib/with-file-lock.js +165 -24
- package/src/lib/ws-chat-handler.js +21 -0
- package/src/program-base.js +18 -0
- package/src/repl/advisor-command.js +103 -0
- package/src/repl/agent-repl.js +2175 -146
- package/src/repl/btw-command.js +93 -10
- package/src/repl/clipboard-image.js +119 -0
- package/src/repl/config-summary.js +64 -108
- package/src/repl/prompt-editor.js +233 -0
- package/src/repl/prompt-interactions.js +344 -0
- package/src/repl/prompt-stash.js +354 -0
- package/src/repl/prompt-suggestions.js +312 -0
- package/src/repl/repl-keybindings.js +227 -0
- package/src/repl/session-recap.js +217 -0
- package/src/repl/slash-command-registry.js +22 -0
- package/src/repl/terminal-layout.js +88 -0
- package/src/runtime/agent-core.js +1630 -447
- package/src/runtime/coding-agent-contract-shared.cjs +13 -1
- package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
- package/src/runtime/diagnostics.js +32 -13
- package/src/runtime/headless-runner.js +310 -118
- package/src/runtime/headless-stream.js +356 -95
- package/src/runtime/mcp-config.js +148 -14
- package/src/runtime/policies/agent-policy.js +14 -0
- package/src/runtime/status-diagnostics-lite.js +137 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
- package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
- package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
- package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
package/src/commands/mcp.js
CHANGED
|
@@ -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)
|
|
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
|
|
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 =
|
|
135
|
+
const row = visible.find((entry) => entry.name === serverName);
|
|
109
136
|
if (!row) {
|
|
110
|
-
const names =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
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
|
|
630
|
-
|
|
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
|
|
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 =
|
|
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")
|