ghost-bridge 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 <Author>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,156 +1,159 @@
1
- # Ghost Bridge
1
+ # 👻 Ghost Bridge
2
2
 
3
- > 无侵入 Chrome AI 副驾 —— 通过 MCP 让 AI 无缝接管你正在使用的浏览器,实时调试、观察页面、操控交互,无需启动新浏览器实例。
3
+ [![npm version](https://img.shields.io/npm/v/ghost-bridge.svg?style=flat-square)](https://www.npmjs.com/package/ghost-bridge)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
4
5
 
5
- ## 特性
6
+ > **Zero-restart Chrome AI Copilot** — Subvert your workflow. Allow AI to seamlessly take over the browser you're already using, enabling real-time debugging, visual observation, and interactive manipulation without launching a new Chrome instance.
6
7
 
7
- - 🔌 **零配置附加** — 不依赖 `--remote-debugging-port`,通过 Chrome 扩展直接获取 CDP
8
- - 🔍 **无 sourcemap 调试** — 片段截取、字符串搜索、覆盖率分析,在压缩代码中定位问题
9
- - 🌐 **网络请求分析** — 完整记录请求/响应,支持多维度过滤和响应体查看
10
- - 📸 **页面截图与内容提取** — 视觉分析 + 结构化数据提取
11
- - 🎯 **DOM 交互操控** — AI 可直接点击按钮、填写表单、按键提交,使用 CDP 物理级模拟,兼容 React/Vue/Angular
12
- - 📊 **性能诊断** — JS 堆内存、DOM 规模、Layout 开销、Web Vitals、资源加载分析
13
- - 🔄 **多实例支持** — 自动单例管理,多个 MCP 客户端共享同一 Chrome 连接
8
+ ---
14
9
 
15
- ## 快速开始
10
+ ## ✨ Why Ghost Bridge?
16
11
 
17
- ### 1. 安装与初始化
12
+ - 🔌 **Zero-Config Attach** — Bypasses the need for `--remote-debugging-port`. Captures Chrome's native DevTools Protocol directly via an extension.
13
+ - 🔍 **No-Sourcemap Debugging** — Slice code fragments, perform string searches, and analyze coverage to pinpoint bugs straight in minified production code.
14
+ - 🌐 **Deep Network Analysis** — Comprehensive capture of requests/responses with multi-dimensional filtering and response body inspection.
15
+ - 📸 **Visual & Structural Perception** — Full-page or clipped high-fidelity screenshots paired with structural data extraction (titles, links, forms, buttons).
16
+ - 🎯 **DOM Physical Manipulation** — Empowers AI to click, type, and form-submit with CDP-level physical simulation. Fully compatible with complex SPAs (React/Vue/Angular/Svelte).
17
+ - 📊 **Performance Diagnostics** — Get granular engine metrics: JS Heap, Layout recalculations, Web Vitals (TTFB/FCP/LCP), and resource loading speeds.
18
+ - 🔄 **Multi-Client Mastery** — Built-in singleton manager automatically coordinates multiple MCP clients sharing a single Chrome transport.
19
+
20
+ ---
21
+
22
+ ## 🚀 Quick Start
23
+
24
+ ### 1. Install & Initialize
18
25
 
19
26
  ```bash
20
- # 全局安装
27
+ # Install globally
21
28
  npm install -g ghost-bridge
22
29
 
23
- # 自动配置 Claude MCP 并准备扩展
30
+ # Auto-configure MCP (Claude Code, Antigravity, Codex) and prepare the extension directory
24
31
  ghost-bridge init
25
32
  ```
26
33
 
27
- ### 2. 加载 Chrome 扩展
34
+ > **Note on other MCP clients (Cursor, Windsurf, Roo):**
35
+ > `ghost-bridge init` attempts to auto-configure supported clients. If your client isn't auto-detected, simply add the following to your client's MCP configuration file (e.g., `mcp.json`):
36
+ > ```json
37
+ > {
38
+ > "mcpServers": {
39
+ > "ghost-bridge": {
40
+ > "command": "node",
41
+ > "args": ["/absolute/path/to/global/node_modules/ghost-bridge/dist/server.js"]
42
+ > }
43
+ > }
44
+ > }
45
+ > ```
28
46
 
29
- 1. 打开 Chrome,访问 `chrome://extensions`
30
- 2. 开启右上角的 **开发者模式**
31
- 3. 点击 **加载已解压的扩展程序**
32
- 4. 选择目录:`~/.ghost-bridge/extension`
47
+ ### 2. Load the Chrome Extension
33
48
 
34
- > 💡 运行 `ghost-bridge extension --open` 可直接打开该目录
49
+ 1. Open Chrome and navigate to `chrome://extensions`
50
+ 2. Toggle **Developer mode** in the top right corner.
51
+ 3. Click **Load unpacked**
52
+ 4. Select the directory: `~/.ghost-bridge/extension`
35
53
 
36
- ### 3. 连接并使用
54
+ > 💡 *Tip: Run `ghost-bridge extension --open` to reveal the directory directly.*
37
55
 
38
- 1. 点击浏览器工具栏中的 Ghost Bridge 图标
39
- 2. 点击 **连接**,等待状态变为 ✅ 已连接
40
- 3. 打开 Claude Desktop 或 Claude CLI,即可使用所有调试工具
56
+ ### 3. Connect & Command
41
57
 
42
- ## CLI 命令
58
+ 1. Click the **Ghost Bridge** ghost icon in your browser toolbar.
59
+ 2. Click **Connect** and wait for the status to turn to ✅ **ON**.
60
+ 3. Open Claude Desktop or your Claude CLI. All tools are now primed and ready!
43
61
 
44
- | 命令 | 说明 |
45
- |------|------|
46
- | `ghost-bridge init` | 配置 MCP 并复制扩展文件 |
47
- | `ghost-bridge status` | 检查配置状态 |
48
- | `ghost-bridge extension` | 显示扩展安装路径(`--open` 打开目录) |
49
- | `ghost-bridge start` | 手动启动 MCP 服务(通常不需要) |
62
+ ---
50
63
 
51
- ## 工具一览
64
+ ## 🛠️ Tool Arsenal
52
65
 
53
- ### 🔍 基础调试
66
+ ### 🔍 Core Debugging
54
67
 
55
- | 工具 | 说明 |
56
- |------|------|
57
- | `get_server_info` | 获取服务器状态(端口、连接状态、角色) |
58
- | `get_last_error` | 汇总最近的异常 / console 错误 / 网络报错,附行列与脚本标识 |
59
- | `get_script_source` | 抓取目标脚本源码,支持按 URL 片段筛选、指定行列定位、beautify |
60
- | `coverage_snapshot` | 启动执行覆盖率采集(默认 1.5s),返回最活跃的脚本列表 |
61
- | `find_by_string` | 在页面脚本源码中按关键词搜索,返回 200 字符上下文窗口 |
62
- | `symbolic_hints` | 采集资源列表、全局变量 key、localStorage key、UA URL |
63
- | `eval_script` | 在页面执行 JS 表达式(谨慎使用) |
68
+ | Tool | Capability |
69
+ |------|------------|
70
+ | `get_server_info` | Retrieves server instance status, WebSocket ports, and client roles. |
71
+ | `get_last_error` | Aggregates recent exceptions, console errors, and failed network requests with mapped locators. |
72
+ | `get_script_source` | Pulls raw script definitions. Supports URL-fragment filtering, specific line targeting, and beautification. |
73
+ | `coverage_snapshot` | Triggers a quick coverage trace (1.5s default) to identify the most active scripts on the page. |
74
+ | `find_by_string` | Scans page script sources for keywords, returning a 200-character context window. |
75
+ | `symbolic_hints` | Gathers context clues: Resource lists, Global Variable keys, LocalStorage schema, and UA strings. |
76
+ | `eval_script` | Executes raw JavaScript expressions in the page context. *(Use with caution)* |
64
77
 
65
- ### 网络请求分析
78
+ ### 🌍 Network Intelligence
66
79
 
67
- | 工具 | 说明 |
68
- |------|------|
69
- | `list_network_requests` | 列出捕获的网络请求,支持按 URL / 方法 / 状态 / 资源类型过滤 |
70
- | `get_network_detail` | 获取单个请求的详细信息(请求头、响应头、timing),可选获取响应体 |
71
- | `clear_network_requests` | 清空已捕获的网络请求记录 |
80
+ | Tool | Capability |
81
+ |------|------------|
82
+ | `list_network_requests` | Lists captured network traffic. Supports filtering by URL, Method, Status Code, or Resource Type. |
83
+ | `get_network_detail` | Dives deep into a specific request's Headers, Timing, and optional Response Body extraction. |
84
+ | `clear_network_requests` | Wipes the current network capture buffer. |
72
85
 
73
- ### 📸 页面内容
86
+ ### 📸 Page Perception
74
87
 
75
- | 工具 | 说明 |
76
- |------|------|
77
- | `capture_screenshot` | 截取页面截图(支持完整长截图、指定区域、JPEG/PNG 格式) |
78
- | `get_page_content` | 提取页面内容:纯文本 / HTML / 结构化数据(标题、链接、按钮、表单) |
88
+ | Tool | Capability |
89
+ |------|------------|
90
+ | `capture_screenshot` | Captures the viewport or emulates full-page scrolling screenshots. |
91
+ | `get_page_content` | Extracts raw text, sanitized HTML, or structured actionable data representations. |
79
92
 
80
- ### 🎯 页面交互(DOM 操作)
93
+ ### 🎯 Interactive Automation (DOM)
81
94
 
82
- | 工具 | 说明 |
83
- |------|------|
84
- | `get_interactive_snapshot` | 扫描页面所有可见可交互元素,返回带 ref 短标识(e1, e2...)的精简列表,支持 Shadow DOM 穿透 |
85
- | `dispatch_action` | 对目标元素执行动作(click / fill / press / scroll / select / hover / focus),使用 CDP 物理级模拟 |
95
+ | Tool | Capability |
96
+ |------|------------|
97
+ | `get_interactive_snapshot` | Scans for visible interactive elements, returning a concise map `[e1, e2...]`. Pierces open Shadow DOMs. |
98
+ | `dispatch_action` | Dispatches physical UI actions (click, fill, press, hover) against targeted element references (e.g., `e1`). |
86
99
 
87
- **交互工作流示例:**
100
+ **Example Agent Workflow:**
101
+ 1. AI: `get_interactive_snapshot` ➝ `[{ref:"e1", tag:"input", placeholder:"Search..."}, {ref:"e2", tag:"button", text:"Login"}]`
102
+ 2. AI: `dispatch_action({ref: "e1", action: "fill", value: "hello"})`
103
+ 3. AI: `dispatch_action({ref: "e2", action: "click"})`
104
+ 4. AI: `capture_screenshot` to verify state changes.
88
105
 
89
- ```
90
- 1. AI 调用 get_interactive_snapshot
91
- → 返回: [{ref:"e1", tag:"input", placeholder:"Search..."}, {ref:"e2", tag:"button", text:"Login"}]
106
+ ### 📊 Performance Profiling
92
107
 
93
- 2. AI 调用 dispatch_action({ref: "e1", action: "fill", value: "hello"})
94
- → 在搜索框中输入 "hello"
108
+ | Tool | Capability |
109
+ |------|------------|
110
+ | `perf_metrics` | Collects layered performance data (Engine Metrics, Web Vitals, and Resource Load Summaries). |
95
111
 
96
- 3. AI 调用 dispatch_action({ref: "e2", action: "click"})
97
- → 点击 Login 按钮
112
+ ---
98
113
 
99
- 4. AI 调用 capture_screenshot 验证操作结果
100
- ```
114
+ ## ⚙️ Configuration
101
115
 
102
- ### 📊 性能分析
116
+ | Setting | Default | Description |
117
+ |---------|---------|-------------|
118
+ | **Base Port** | `33333` | WS port. Auto-increments if occupied. |
119
+ | **Token** | *Monthly UUID* | Local WS auth token, auto-rotates on the 1st of every month. |
120
+ | **Auto Detach** | `false` | Keeps debugger attached to actively buffer invisible exceptions and network calls. |
103
121
 
104
- | 工具 | 说明 |
105
- |------|------|
106
- | `perf_metrics` | 获取页面性能指标,包含三层数据:|
122
+ **Environment Variables:**
123
+ - `GHOST_BRIDGE_PORT` — Override base port.
124
+ - `GHOST_BRIDGE_TOKEN` Override connection token.
107
125
 
108
- **`perf_metrics` 返回的数据:**
126
+ ---
109
127
 
110
- - **引擎级指标** — JS 堆内存(使用量/总量/占比)、DOM 节点数、事件监听器数、Layout 重排次数与耗时、脚本执行时间
111
- - **Web Vitals** — Navigation Timing 各阶段(DNS / TTFB / DOM Interactive / Load)、FP、FCP、Long Tasks 统计
112
- - **资源加载摘要** — 按类型分组统计(count / size / avgDuration)、最慢资源识别
128
+ ## 🏗️ Architecture
113
129
 
114
- ## 配置
115
-
116
- | 项目 | 默认值 | 说明 |
117
- |------|--------|------|
118
- | 端口 | `33333` | WebSocket 服务端口,自动递增寻找可用端口 |
119
- | Token | 当月自动生成 | 本机 WS 校验,基于当月 1 号时间戳 |
120
- | 自动 Detach | `false` | 保持附加,便于持续捕获异常和网络请求 |
130
+ ```mermaid
131
+ graph LR
132
+ A[Claude CLI/Desktop] <-->|stdio| B(MCP Server\nserver.js)
133
+ B <-->|WebSocket| C(Chrome Extension\nbackground.js)
134
+ C <-->|CDP| D[Browser Tab\nTarget Context]
135
+ ```
121
136
 
122
- 环境变量:
137
+ - **MCP Server**: Spawned by Claude via standard I/O streams. Orchestrates WS connections.
138
+ - **Chrome Extension (MV3)**: Taps into `chrome.debugger` API. Utilizes an Offscreen Document to prevent WS hibernation.
139
+ - **Singleton Design**: If multiple agents spawn servers, the first becomes the master bridge while subsequent instances chain transparently as clients.
123
140
 
124
- - `GHOST_BRIDGE_PORT` — 自定义基础端口
125
- - `GHOST_BRIDGE_TOKEN` — 自定义 token
141
+ ---
126
142
 
127
- ## 架构
143
+ ## ⚠️ Known Limitations
128
144
 
129
- ```
130
- ┌──────────────┐ stdio ┌──────────────┐ WebSocket ┌──────────────┐
131
- │ Claude CLI │ ◄────────────► │ MCP Server │ ◄──────────────►│Chrome Extension│
132
- │ / Desktop │ │ (server.js) │ │(background.js)│
133
- └──────────────┘ └──────────────┘ └──────┬───────┘
134
- │ CDP
135
- ┌─────▼──────┐
136
- │ 浏览器页面 │
137
- └────────────┘
138
- ```
145
+ - **Service Workers Suspending**: MV3 background workers may suspend. We've built robust auto-reconnection logic, but prolonged inactivity might require re-toggling.
146
+ - **DevTools Conflict**: If you manually open Chrome DevTools (F12) on the target tab, `chrome.debugger.attach` may be rejected.
147
+ - **Beautify Overhead**: Beautifying massive single-line bundles is expensive; the server will auto-truncate overly large scripts.
148
+ - **Cross-Origin OOPIF**: Elements and errors deeply embedded in strict Cross-Origin Iframes might evade the primary debugger hook without further multi-target attach logic.
139
149
 
140
- - **MCP Server** — 通过 stdio 被 Claude 拉起,与扩展通过 WebSocket 通信
141
- - **Chrome Extension (MV3)** — 使用 `chrome.debugger` API 附加页面,Offscreen Document 维持 WebSocket 长连接
142
- - **单例模式** — 多个 MCP 客户端自动协调,首个实例为主服务,后续实例作为客户端连接
150
+ ---
143
151
 
144
- ## 已知限制
152
+ ## 🤝 Contributing
145
153
 
146
- - 扩展 Service Worker 可能被挂起,已内置重连策略;若长时间无流量需重新唤醒
147
- - 若目标页面已打开 DevTools,`chrome.debugger.attach` 可能失败,请关闭后重试
148
- - 大体积单行 bundle beautify 可能耗时,服务端对超长源码会截取片段
149
- - 跨月时 token 会自动更新,扩展和服务端需在同月内启动
150
- - DOM 交互:SPA 路由变化后 ref 标识会失效,需重新调用 `get_interactive_snapshot`
151
- - DOM 交互:跨域 iframe 内的元素暂不支持细粒度操作
152
- - DOM 交互:Shadow DOM 内的元素可以被扫描到,但部分封闭模式的 Shadow Root 可能无法穿透
154
+ Contributions, issues, and feature requests are welcome!
155
+ Check out our [Contributing Guide](CONTRIBUTING.md) to get started building tools or improving the bridge.
153
156
 
154
- ## License
157
+ ## 📄 License
155
158
 
156
- MIT
159
+ This project is [MIT](LICENSE) licensed.
package/dist/cli.js CHANGED
@@ -5454,9 +5454,15 @@ var require_lib = __commonJS({
5454
5454
  import path from "path";
5455
5455
  import os2 from "os";
5456
5456
  import { fileURLToPath } from "url";
5457
- function getClaudeConfigPath() {
5457
+ function getClientConfigPaths() {
5458
5458
  const homeDir = os2.homedir();
5459
- return path.join(homeDir, ".claude.json");
5459
+ return [
5460
+ { name: "Claude Code", path: path.join(homeDir, ".claude.json") },
5461
+ { name: "Antigravity", path: path.join(homeDir, ".gemini", "antigravity", "mcp.json") },
5462
+ // Codex config placeholder - exact path depends on how Codex stores user config.
5463
+ // Assuming a common pattern here like ~/.codex/mcp.json or similar.
5464
+ { name: "Codex", path: path.join(homeDir, ".codex", "mcp.json") }
5465
+ ];
5460
5466
  }
5461
5467
  function getExtensionPath() {
5462
5468
  const __filename2 = fileURLToPath(import.meta.url);
@@ -5502,20 +5508,28 @@ function openFolder(folderPath) {
5502
5508
  }
5503
5509
  async function init(options) {
5504
5510
  console.log(source_default.bold("\u{1F47B} Ghost Bridge Initialization"));
5505
- const configPath = getClaudeConfigPath();
5511
+ const clientConfigs = getClientConfigPaths();
5506
5512
  const serverPath = getServerPath();
5507
5513
  const isDryRun = options.dryRun;
5508
- console.log(source_default.dim("Checking Claude configuration..."));
5509
- if (isDryRun) {
5510
- console.log(source_default.yellow(`[Dry Run] Would check config at: ${configPath}`));
5511
- console.log(source_default.yellow(`[Dry Run] Would add MCP server pointing to: ${serverPath}`));
5512
- } else {
5513
- if (!import_fs_extra.default.existsSync(configPath)) {
5514
- console.log(source_default.yellow(`Configuration file not found at ${configPath}, creating/skipping...`));
5514
+ console.log(source_default.dim("Checking MCP Client configurations..."));
5515
+ let configuredCount = 0;
5516
+ for (const client of clientConfigs) {
5517
+ const configPath = client.path;
5518
+ if (isDryRun) {
5519
+ console.log(source_default.yellow(`[Dry Run] Would check ${client.name} config at: ${configPath}`));
5520
+ if (import_fs_extra.default.existsSync(configPath) || client.name === "Claude Code") {
5521
+ console.log(source_default.yellow(`[Dry Run] Would add MCP server logic for ${client.name}`));
5522
+ }
5523
+ continue;
5524
+ }
5525
+ const exists = import_fs_extra.default.existsSync(configPath);
5526
+ if (!exists && client.name !== "Claude Code") {
5527
+ continue;
5528
+ }
5529
+ if (!exists) {
5530
+ console.log(source_default.yellow(`Configuration file not found for ${client.name} at ${configPath}, creating...`));
5515
5531
  await import_fs_extra.default.ensureDir(path2.dirname(configPath));
5516
- if (!import_fs_extra.default.existsSync(configPath)) {
5517
- await import_fs_extra.default.writeJson(configPath, { mcpServers: {} }, { spaces: 2 });
5518
- }
5532
+ await import_fs_extra.default.writeJson(configPath, { mcpServers: {} }, { spaces: 2 });
5519
5533
  }
5520
5534
  try {
5521
5535
  const config = await import_fs_extra.default.readJson(configPath);
@@ -5525,11 +5539,15 @@ async function init(options) {
5525
5539
  args: [serverPath]
5526
5540
  };
5527
5541
  await import_fs_extra.default.writeJson(configPath, config, { spaces: 2 });
5528
- console.log(source_default.green(`\u2705 MCP Server 'ghost-bridge' configured in ${configPath}`));
5542
+ console.log(source_default.green(`\u2705 MCP Server configured for ${source_default.bold(client.name)} in ${configPath}`));
5543
+ configuredCount++;
5529
5544
  } catch (err) {
5530
- console.error(source_default.red(`Failed to update config: ${err.message}`));
5545
+ console.error(source_default.red(`Failed to update config for ${client.name}: ${err.message}`));
5531
5546
  }
5532
5547
  }
5548
+ if (configuredCount === 0 && !isDryRun) {
5549
+ console.log(source_default.yellow("\u26A0\uFE0F No supported MCP clients found to configure automatically."));
5550
+ }
5533
5551
  const sourceExt = getExtensionPath();
5534
5552
  const targetExt = getUserExtensionDir();
5535
5553
  console.log(source_default.dim(`Setting up extension in ${targetExt}...`));
@@ -5617,34 +5635,47 @@ __export(status_exports, {
5617
5635
  });
5618
5636
  async function status() {
5619
5637
  console.log(source_default.bold("\u{1F47B} Ghost Bridge Status"));
5620
- const configPath = getClaudeConfigPath();
5638
+ const clientConfigs = getClientConfigPaths();
5621
5639
  const extDir = getUserExtensionDir();
5622
5640
  const serverPath = getServerPath();
5623
- let mcpStatus = source_default.red("Not Configured");
5624
- let mcpDetails = "";
5625
- if (import_fs_extra3.default.existsSync(configPath)) {
5626
- try {
5627
- const config = await import_fs_extra3.default.readJson(configPath);
5628
- if (config.mcpServers && config.mcpServers["ghost-bridge"]) {
5629
- mcpStatus = source_default.green("Configured");
5630
- const cfg = config.mcpServers["ghost-bridge"];
5631
- const configuredPath = cfg.args[0];
5632
- if (configuredPath === serverPath) {
5633
- mcpDetails = source_default.dim("(Paths match)");
5634
- } else {
5635
- mcpDetails = source_default.yellow(`(Path mismatch)
5636
- Configured: ${configuredPath}
5637
- Current: ${serverPath}`);
5641
+ console.log(source_default.bold.blue("\nMCP Client Configurations:"));
5642
+ let configuredCount = 0;
5643
+ for (const client of clientConfigs) {
5644
+ let mcpStatus = source_default.gray("Not Configured");
5645
+ let mcpDetails = "";
5646
+ const configPath = client.path;
5647
+ if (import_fs_extra3.default.existsSync(configPath)) {
5648
+ try {
5649
+ const config = await import_fs_extra3.default.readJson(configPath);
5650
+ if (config.mcpServers && config.mcpServers["ghost-bridge"]) {
5651
+ mcpStatus = source_default.green("Configured");
5652
+ const cfg = config.mcpServers["ghost-bridge"];
5653
+ const configuredPath = cfg.args[0];
5654
+ if (configuredPath === serverPath) {
5655
+ mcpDetails = source_default.dim("(Paths match)");
5656
+ } else {
5657
+ mcpDetails = source_default.yellow(`(Path mismatch)
5658
+ Configured: ${configuredPath}
5659
+ Current: ${serverPath}`);
5660
+ }
5661
+ configuredCount++;
5638
5662
  }
5663
+ } catch (e) {
5664
+ mcpStatus = source_default.red("Error reading config");
5665
+ }
5666
+ } else {
5667
+ if (client.name === "Claude Code") {
5668
+ mcpStatus = source_default.yellow("Config file not found");
5669
+ } else {
5670
+ mcpStatus = source_default.gray("Not Installed");
5639
5671
  }
5640
- } catch (e) {
5641
- mcpStatus = source_default.red("Error reading config");
5642
5672
  }
5643
- } else {
5644
- mcpStatus = source_default.yellow("Config file not found");
5673
+ console.log(` ${source_default.bold(client.name)}: ${mcpStatus} ${mcpDetails}`);
5674
+ console.log(` Config File: ${source_default.dim(configPath)}`);
5675
+ }
5676
+ if (configuredCount === 0) {
5677
+ console.log(source_default.yellow("\n No MCP clients currently have ghost-bridge configured. Run `ghost-bridge init`."));
5645
5678
  }
5646
- console.log(`MCP Configuration: ${mcpStatus} ${mcpDetails}`);
5647
- console.log(` Config File: ${configPath}`);
5648
5679
  let extStatus = source_default.red("Not Installed (Run init)");
5649
5680
  if (import_fs_extra3.default.existsSync(extDir)) {
5650
5681
  extStatus = source_default.green("Installed");