ghost-bridge 0.5.0 → 0.5.1

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/dist/server.js CHANGED
@@ -3228,8 +3228,8 @@ var require_utils = __commonJS({
3228
3228
  }
3229
3229
  return ind;
3230
3230
  }
3231
- function removeDotSegments(path2) {
3232
- let input = path2;
3231
+ function removeDotSegments(path3) {
3232
+ let input = path3;
3233
3233
  const output = [];
3234
3234
  let nextSlash = -1;
3235
3235
  let len = 0;
@@ -3428,8 +3428,8 @@ var require_schemes = __commonJS({
3428
3428
  wsComponent.secure = void 0;
3429
3429
  }
3430
3430
  if (wsComponent.resourceName) {
3431
- const [path2, query] = wsComponent.resourceName.split("?");
3432
- wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
3431
+ const [path3, query] = wsComponent.resourceName.split("?");
3432
+ wsComponent.path = path3 && path3 !== "/" ? path3 : void 0;
3433
3433
  wsComponent.query = query;
3434
3434
  wsComponent.resourceName = void 0;
3435
3435
  }
@@ -6782,12 +6782,12 @@ var require_dist = __commonJS({
6782
6782
  throw new Error(`Unknown format "${name}"`);
6783
6783
  return f;
6784
6784
  };
6785
- function addFormats(ajv, list, fs2, exportName) {
6785
+ function addFormats(ajv, list, fs3, exportName) {
6786
6786
  var _a2;
6787
6787
  var _b;
6788
6788
  (_a2 = (_b = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6789
6789
  for (const f of list)
6790
- ajv.addFormat(f, fs2[f]);
6790
+ ajv.addFormat(f, fs3[f]);
6791
6791
  }
6792
6792
  module.exports = exports = formatsPlugin;
6793
6793
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -15012,8 +15012,8 @@ function getErrorMap() {
15012
15012
 
15013
15013
  // node_modules/zod/v3/helpers/parseUtil.js
15014
15014
  var makeIssue = (params) => {
15015
- const { data, path: path2, errorMaps, issueData } = params;
15016
- const fullPath = [...path2, ...issueData.path || []];
15015
+ const { data, path: path3, errorMaps, issueData } = params;
15016
+ const fullPath = [...path3, ...issueData.path || []];
15017
15017
  const fullIssue = {
15018
15018
  ...issueData,
15019
15019
  path: fullPath
@@ -15128,11 +15128,11 @@ var errorUtil;
15128
15128
 
15129
15129
  // node_modules/zod/v3/types.js
15130
15130
  var ParseInputLazyPath = class {
15131
- constructor(parent, value, path2, key) {
15131
+ constructor(parent, value, path3, key) {
15132
15132
  this._cachedPath = [];
15133
15133
  this.parent = parent;
15134
15134
  this.data = value;
15135
- this._path = path2;
15135
+ this._path = path3;
15136
15136
  this._key = key;
15137
15137
  }
15138
15138
  get path() {
@@ -18776,10 +18776,10 @@ function mergeDefs(...defs) {
18776
18776
  function cloneDef(schema) {
18777
18777
  return mergeDefs(schema._zod.def);
18778
18778
  }
18779
- function getElementAtPath(obj, path2) {
18780
- if (!path2)
18779
+ function getElementAtPath(obj, path3) {
18780
+ if (!path3)
18781
18781
  return obj;
18782
- return path2.reduce((acc, key) => acc?.[key], obj);
18782
+ return path3.reduce((acc, key) => acc?.[key], obj);
18783
18783
  }
18784
18784
  function promiseAllObject(promisesObj) {
18785
18785
  const keys = Object.keys(promisesObj);
@@ -19162,11 +19162,11 @@ function aborted(x, startIndex = 0) {
19162
19162
  }
19163
19163
  return false;
19164
19164
  }
19165
- function prefixIssues(path2, issues) {
19165
+ function prefixIssues(path3, issues) {
19166
19166
  return issues.map((iss) => {
19167
19167
  var _a2;
19168
19168
  (_a2 = iss).path ?? (_a2.path = []);
19169
- iss.path.unshift(path2);
19169
+ iss.path.unshift(path3);
19170
19170
  return iss;
19171
19171
  });
19172
19172
  }
@@ -28520,9 +28520,21 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
28520
28520
  var import_js_beautify = __toESM(require_js(), 1);
28521
28521
  import crypto from "crypto";
28522
28522
  import net from "net";
28523
- import fs from "fs";
28523
+ import fs2 from "fs";
28524
28524
  import os from "os";
28525
+ import path2 from "path";
28526
+
28527
+ // lib/version.js
28528
+ import fs from "fs";
28525
28529
  import path from "path";
28530
+ import { fileURLToPath } from "url";
28531
+ var __filename = fileURLToPath(import.meta.url);
28532
+ var __dirname = path.dirname(__filename);
28533
+ var packageJsonPath = path.resolve(__dirname, "../package.json");
28534
+ var packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
28535
+ var GHOST_BRIDGE_VERSION = packageJson.version;
28536
+
28537
+ // src/server.js
28526
28538
  var BASE_PORT = Number(process.env.GHOST_BRIDGE_PORT || 33333);
28527
28539
  var MAX_PORT_RETRIES = 10;
28528
28540
  function getMonthlyToken() {
@@ -28532,7 +28544,7 @@ function getMonthlyToken() {
28532
28544
  }
28533
28545
  var WS_TOKEN = process.env.GHOST_BRIDGE_TOKEN || getMonthlyToken();
28534
28546
  var RESPONSE_TIMEOUT = 8e3;
28535
- var PORT_INFO_FILE = path.join(os.tmpdir(), "ghost-bridge-port.json");
28547
+ var PORT_INFO_FILE = path2.join(os.tmpdir(), "ghost-bridge-port.json");
28536
28548
  var chromeConnection = null;
28537
28549
  var activeConnection = null;
28538
28550
  var actualPort = BASE_PORT;
@@ -28552,12 +28564,12 @@ function isProcessRunning(pid) {
28552
28564
  }
28553
28565
  function getExistingService() {
28554
28566
  try {
28555
- if (!fs.existsSync(PORT_INFO_FILE)) return null;
28556
- const info = JSON.parse(fs.readFileSync(PORT_INFO_FILE, "utf-8"));
28567
+ if (!fs2.existsSync(PORT_INFO_FILE)) return null;
28568
+ const info = JSON.parse(fs2.readFileSync(PORT_INFO_FILE, "utf-8"));
28557
28569
  if (!info.pid || !info.port) return null;
28558
28570
  if (!isProcessRunning(info.pid)) {
28559
28571
  log(`\u65E7\u670D\u52A1 PID ${info.pid} \u5DF2\u4E0D\u5B58\u5728\uFF0C\u6E05\u7406\u65E7\u4FE1\u606F`);
28560
- fs.unlinkSync(PORT_INFO_FILE);
28572
+ fs2.unlinkSync(PORT_INFO_FILE);
28561
28573
  return null;
28562
28574
  }
28563
28575
  return info;
@@ -28636,14 +28648,14 @@ async function initWebSocketService() {
28636
28648
  } else {
28637
28649
  log(`\u274C \u73B0\u6709\u670D\u52A1\u9A8C\u8BC1\u5931\u8D25\uFF0C\u542F\u52A8\u65B0\u670D\u52A1...`);
28638
28650
  try {
28639
- fs.unlinkSync(PORT_INFO_FILE);
28651
+ fs2.unlinkSync(PORT_INFO_FILE);
28640
28652
  } catch {
28641
28653
  }
28642
28654
  }
28643
28655
  }
28644
28656
  const wss2 = await startWebSocketServer();
28645
28657
  isMainInstance = true;
28646
- fs.writeFileSync(
28658
+ fs2.writeFileSync(
28647
28659
  PORT_INFO_FILE,
28648
28660
  JSON.stringify({
28649
28661
  port: actualPort,
@@ -28858,7 +28870,7 @@ async function askChrome(command, params = {}, options = {}) {
28858
28870
  });
28859
28871
  }
28860
28872
  function jsonText(data) {
28861
- return typeof data === "string" ? data : JSON.stringify(data, null, 2);
28873
+ return typeof data === "string" ? data : JSON.stringify(data);
28862
28874
  }
28863
28875
  function buildSnippet(source, line, column, { beautifyEnabled = true, contextLines = 20 } = {}) {
28864
28876
  const result = {};
@@ -28896,11 +28908,32 @@ function buildSnippet(source, line, column, { beautifyEnabled = true, contextLin
28896
28908
  return result;
28897
28909
  }
28898
28910
  var server = new Server(
28899
- { name: "ghost-bridge", version: "0.4.0" },
28911
+ { name: "ghost-bridge", version: GHOST_BRIDGE_VERSION },
28900
28912
  { capabilities: { tools: {} } }
28901
28913
  );
28902
28914
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
28903
28915
  tools: [
28916
+ {
28917
+ name: "inspect_page",
28918
+ description: "\u3010\u9875\u9762\u5206\u6790\u5165\u53E3\u3011\u5F53\u7528\u6237\u8981\u6C42\u5206\u6790\u5F53\u524D\u9875\u9762/\u7F51\u7AD9/\u7F51\u9875\u3001\u7406\u89E3\u9875\u9762\u7ED3\u6784\u3001\u5FEB\u901F\u67E5\u770B\u5F53\u524D\u6807\u7B7E\u5185\u5BB9\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u9ED8\u8BA4\u8FD4\u56DE\u9875\u9762\u5143\u6570\u636E\u3001\u7ED3\u6784\u5316\u5185\u5BB9\u6458\u8981\u548C\u53EF\u4EA4\u4E92\u5143\u7D20\u6982\u89C8\uFF0C\u9002\u5408\u4F5C\u4E3A\u540E\u7EED\u622A\u56FE\u3001\u4EA4\u4E92\u3001\u7F51\u7EDC\u6392\u67E5\u524D\u7684\u7B2C\u4E00\u6B65\u3002",
28919
+ inputSchema: {
28920
+ type: "object",
28921
+ properties: {
28922
+ selector: {
28923
+ type: "string",
28924
+ description: "CSS \u9009\u62E9\u5668\uFF0C\u9650\u5B9A\u5206\u6790\u8303\u56F4\u3002\u4E0D\u6307\u5B9A\u5219\u5206\u6790\u6574\u4E2A\u9875\u9762"
28925
+ },
28926
+ includeInteractive: {
28927
+ type: "boolean",
28928
+ description: "\u662F\u5426\u5305\u542B\u4EA4\u4E92\u5143\u7D20\u6982\u89C8\uFF0C\u9ED8\u8BA4 true"
28929
+ },
28930
+ maxElements: {
28931
+ type: "number",
28932
+ description: "\u4EA4\u4E92\u5143\u7D20\u6982\u89C8\u7684\u6700\u5927\u6570\u91CF\uFF0C\u9ED8\u8BA4 30"
28933
+ }
28934
+ }
28935
+ }
28936
+ },
28904
28937
  {
28905
28938
  name: "get_server_info",
28906
28939
  description: "\u83B7\u53D6 ghost-bridge \u670D\u52A1\u5668\u72B6\u6001\uFF0C\u5305\u62EC\u5F53\u524D WebSocket \u7AEF\u53E3\u3001\u8FDE\u63A5\u72B6\u6001\u7B49",
@@ -28908,8 +28941,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28908
28941
  },
28909
28942
  {
28910
28943
  name: "get_last_error",
28911
- description: "\u83B7\u53D6\u5F53\u524D\u6807\u7B7E\u6700\u8FD1\u7684\u5F02\u5E38/\u62A5\u9519\u5806\u6808\u4E0E\u5143\u6570\u636E\uFF08\u65E0 sourcemap \u53CB\u597D\uFF09",
28912
- inputSchema: { type: "object", properties: {} }
28944
+ description: "\u83B7\u53D6\u5F53\u524D\u6807\u7B7E\u6700\u8FD1\u7684\u5F02\u5E38/\u62A5\u9519\u5806\u6808\u4E0E\u5143\u6570\u636E\uFF08\u65E0 sourcemap \u53CB\u597D\uFF09\u3002\u9ED8\u8BA4\u53EA\u8FD4\u56DE error \u7EA7\u522B\u7684\u6700\u8FD1 20 \u6761\u3002",
28945
+ inputSchema: {
28946
+ type: "object",
28947
+ properties: {
28948
+ severity: {
28949
+ type: "string",
28950
+ enum: ["error", "warn", "info", "all"],
28951
+ description: "\u65E5\u5FD7\u7EA7\u522B\u8FC7\u6EE4\uFF0C\u9ED8\u8BA4 error"
28952
+ },
28953
+ limit: {
28954
+ type: "number",
28955
+ description: "\u8FD4\u56DE\u6761\u6570\u9650\u5236\uFF0C\u9ED8\u8BA4 20\uFF0C\u6700\u5927 100"
28956
+ }
28957
+ }
28958
+ }
28913
28959
  },
28914
28960
  {
28915
28961
  name: "get_script_source",
@@ -28964,7 +29010,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28964
29010
  },
28965
29011
  {
28966
29012
  name: "list_network_requests",
28967
- description: "\u5217\u51FA\u6355\u83B7\u7684\u7F51\u7EDC\u8BF7\u6C42\uFF0C\u652F\u6301\u6309 URL\u3001\u65B9\u6CD5\u3001\u72B6\u6001\u3001\u7C7B\u578B\u8FC7\u6EE4",
29013
+ description: "\u5217\u51FA\u6355\u83B7\u7684\u7F51\u7EDC\u8BF7\u6C42\uFF0C\u652F\u6301\u6309 URL\u3001\u65B9\u6CD5\u3001\u72B6\u6001\u3001\u7C7B\u578B\u8FC7\u6EE4\u3002\u9ED8\u8BA4\u6309\u6392\u969C\u4F18\u5148\u7EA7\u6392\u5E8F\uFF1A\u5931\u8D25\u8BF7\u6C42\u3001\u8FDB\u884C\u4E2D\u8BF7\u6C42\u3001XHR/Fetch \u4F1A\u4F18\u5148\u5C55\u793A\u3002",
28968
29014
  inputSchema: {
28969
29015
  type: "object",
28970
29016
  properties: {
@@ -28972,7 +29018,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
28972
29018
  method: { type: "string", description: "\u8BF7\u6C42\u65B9\u6CD5\uFF1AGET/POST/PUT/DELETE \u7B49" },
28973
29019
  status: { type: "string", description: "\u72B6\u6001\uFF1Asuccess/error/failed/pending" },
28974
29020
  resourceType: { type: "string", description: "\u8D44\u6E90\u7C7B\u578B\uFF1AXHR/Fetch/Script/Image \u7B49" },
28975
- limit: { type: "number", description: "\u8FD4\u56DE\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 50" }
29021
+ limit: { type: "number", description: "\u8FD4\u56DE\u6570\u91CF\u9650\u5236\uFF0C\u9ED8\u8BA4 50" },
29022
+ priorityMode: {
29023
+ type: "string",
29024
+ enum: ["debug", "api", "recent"],
29025
+ description: "\u6392\u5E8F\u6A21\u5F0F\uFF1Adebug=\u6392\u969C\u4F18\u5148\uFF08\u9ED8\u8BA4\uFF09\uFF0Capi=\u63A5\u53E3\u4F18\u5148\uFF0Crecent=\u6309\u65F6\u95F4\u5012\u5E8F"
29026
+ }
28976
29027
  }
28977
29028
  }
28978
29029
  },
@@ -29012,7 +29063,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29012
29063
  },
29013
29064
  {
29014
29065
  name: "capture_screenshot",
29015
- description: "\u3010\u63A8\u8350\u7528\u4E8E\u89C6\u89C9\u5206\u6790\u3011\u622A\u53D6\u5F53\u524D\u9875\u9762\u7684\u622A\u56FE\uFF0C\u8FD4\u56DE base64 \u56FE\u7247\u3002\u9002\u7528\u4E8E\uFF1A1) \u67E5\u770B\u9875\u9762\u5B9E\u9645\u89C6\u89C9\u6548\u679C 2) \u6392\u67E5 UI/\u6837\u5F0F/\u5E03\u5C40/\u989C\u8272\u95EE\u9898 3) \u9A8C\u8BC1\u9875\u9762\u6E32\u67D3 4) \u5206\u6790\u5143\u7D20\u4F4D\u7F6E\u548C\u95F4\u8DDD 5) \u67E5\u770B\u56FE\u7247/\u56FE\u6807\u7B49\u89C6\u89C9\u5185\u5BB9\u3002\u5F53\u9700\u8981\u770B\u5230\u9875\u9762\u300C\u957F\u4EC0\u4E48\u6837\u300D\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u5982\u4EC5\u9700\u6587\u672C/\u94FE\u63A5\u7B49\u4FE1\u606F\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u66F4\u5FEB\u7684 get_page_content\u3002",
29066
+ description: "\u3010\u63A8\u8350\u7528\u4E8E\u89C6\u89C9\u5206\u6790\u3011\u622A\u53D6\u5F53\u524D\u9875\u9762\u7684\u622A\u56FE\uFF0C\u8FD4\u56DE base64 \u56FE\u7247\u3002\u9002\u7528\u4E8E\uFF1A1) \u67E5\u770B\u9875\u9762\u5B9E\u9645\u89C6\u89C9\u6548\u679C 2) \u6392\u67E5 UI/\u6837\u5F0F/\u5E03\u5C40/\u989C\u8272\u95EE\u9898 3) \u9A8C\u8BC1\u9875\u9762\u6E32\u67D3 4) \u5206\u6790\u5143\u7D20\u4F4D\u7F6E\u548C\u95F4\u8DDD 5) \u67E5\u770B\u56FE\u7247/\u56FE\u6807\u7B49\u89C6\u89C9\u5185\u5BB9\u3002\u5F53\u7528\u6237\u8BF4\u201C\u770B\u770B\u8FD9\u4E2A\u9875\u9762\u957F\u4EC0\u4E48\u6837\u201D\u201C\u5E2E\u6211\u5206\u6790\u754C\u9762/\u5E03\u5C40/\u6837\u5F0F\u201D\u65F6\uFF0C\u5E94\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u5F53\u9700\u8981\u770B\u5230\u9875\u9762\u300C\u957F\u4EC0\u4E48\u6837\u300D\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u5982\u4EC5\u9700\u6587\u672C/\u94FE\u63A5\u7B49\u4FE1\u606F\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u66F4\u5FEB\u7684 get_page_content\u3002",
29016
29067
  inputSchema: {
29017
29068
  type: "object",
29018
29069
  properties: {
@@ -29044,7 +29095,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29044
29095
  },
29045
29096
  {
29046
29097
  name: "get_page_content",
29047
- description: "\u3010\u63A8\u8350\u7528\u4E8E\u5FEB\u901F\u83B7\u53D6\u9875\u9762\u5185\u5BB9\u3011\u63D0\u53D6\u5F53\u524D\u9875\u9762\u7684\u6587\u672C\u3001HTML \u6216\u7ED3\u6784\u5316\u6570\u636E\u3002\u6BD4 capture_screenshot \u66F4\u5FEB\u66F4\u8F7B\u91CF\uFF0C\u9002\u7528\u4E8E\uFF1A1) \u83B7\u53D6\u9875\u9762\u6587\u5B57\u5185\u5BB9 2) \u63D0\u53D6\u94FE\u63A5/\u6309\u94AE/\u8868\u5355\u7B49\u5143\u7D20 3) \u5206\u6790 DOM \u7ED3\u6784 4) \u83B7\u53D6\u9875\u9762\u5143\u6570\u636E\uFF08title/description\uFF09\u3002\u5F53\u9700\u8981\u6587\u672C\u4FE1\u606F\u800C\u975E\u89C6\u89C9\u6548\u679C\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u6CE8\u610F\uFF1A\u4E0D\u652F\u6301 iframe \u5185\u5BB9\uFF0C\u4E0D\u53CD\u6620 CSS \u6837\u5F0F\u3002",
29098
+ description: "\u3010\u63A8\u8350\u7528\u4E8E\u5FEB\u901F\u83B7\u53D6\u9875\u9762\u5185\u5BB9\u3011\u63D0\u53D6\u5F53\u524D\u9875\u9762\u7684\u6587\u672C\u3001HTML \u6216\u7ED3\u6784\u5316\u6570\u636E\u3002\u6BD4 capture_screenshot \u66F4\u5FEB\u66F4\u8F7B\u91CF\uFF0C\u9002\u7528\u4E8E\uFF1A1) \u83B7\u53D6\u9875\u9762\u6587\u5B57\u5185\u5BB9 2) \u63D0\u53D6\u94FE\u63A5/\u6309\u94AE/\u8868\u5355\u7B49\u5143\u7D20 3) \u5206\u6790 DOM \u7ED3\u6784 4) \u83B7\u53D6\u9875\u9762\u5143\u6570\u636E\uFF08title/description\uFF09\u3002\u5F53\u7528\u6237\u8BF4\u201C\u5206\u6790\u8FD9\u4E2A\u9875\u9762/\u7F51\u7AD9\u201D\u201C\u770B\u770B\u9875\u9762\u91CC\u6709\u4EC0\u4E48\u5185\u5BB9\u201D\u4E14\u4E0D\u5F3A\u8C03\u89C6\u89C9\u6548\u679C\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u5F53\u9700\u8981\u6587\u672C\u4FE1\u606F\u800C\u975E\u89C6\u89C9\u6548\u679C\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u6B64\u5DE5\u5177\u3002\u6CE8\u610F\uFF1A\u4E0D\u652F\u6301 iframe \u5185\u5BB9\uFF0C\u4E0D\u53CD\u6620 CSS \u6837\u5F0F\u3002",
29048
29099
  inputSchema: {
29049
29100
  type: "object",
29050
29101
  properties: {
@@ -29070,7 +29121,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29070
29121
  },
29071
29122
  {
29072
29123
  name: "get_interactive_snapshot",
29073
- description: "\u3010\u64CD\u4F5C\u9875\u9762\u524D\u5FC5\u987B\u5148\u8C03\u7528\u3011\u626B\u63CF\u5F53\u524D\u9875\u9762\u6240\u6709\u53EF\u89C1\u7684\u53EF\u4EA4\u4E92\u5143\u7D20\uFF08\u6309\u94AE/\u94FE\u63A5/\u8F93\u5165\u6846/\u4E0B\u62C9\u6846\u7B49\uFF09\uFF0C\u8FD4\u56DE\u5E26\u6709 ref \u77ED\u6807\u8BC6\uFF08\u5982 e1, e2, e3\uFF09\u7684\u7CBE\u7B80\u5217\u8868\uFF0C\u5305\u542B\u5143\u7D20\u7C7B\u578B\u3001\u6587\u672C\u548C\u4F4D\u7F6E\u3002Token \u6781\u7701\uFF08\u901A\u5E38 < 1000 tokens\uFF09\uFF0C\u4E13\u4E3A AI \u64CD\u4F5C\u9875\u9762\u800C\u8BBE\u8BA1\u3002\u83B7\u53D6\u540E\u53EF\u901A\u8FC7 dispatch_action \u5DE5\u5177\u4F7F\u7528 ref \u6807\u8BC6\u6765\u70B9\u51FB\u3001\u586B\u5199\u3001\u6309\u952E\u7B49\u3002\u652F\u6301 Shadow DOM \u7A7F\u900F\u3002\n\u26A0\uFE0F \u4EC5\u7528\u4E8E\u4EA4\u4E92\u64CD\u4F5C\u524D\u7684\u5143\u7D20\u5B9A\u4F4D\u3002\u5982\u9700\u6392\u67E5 UI/CSS \u5E03\u5C40\u95EE\u9898\uFF0C\u8BF7\u4F7F\u7528 capture_screenshot \u6216 get_page_content\u3002",
29124
+ description: "\u3010\u64CD\u4F5C\u9875\u9762\u524D\u5FC5\u987B\u5148\u8C03\u7528\u3011\u626B\u63CF\u5F53\u524D\u9875\u9762\u6240\u6709\u53EF\u89C1\u7684\u53EF\u4EA4\u4E92\u5143\u7D20\uFF08\u6309\u94AE/\u94FE\u63A5/\u8F93\u5165\u6846/\u4E0B\u62C9\u6846\u7B49\uFF09\uFF0C\u8FD4\u56DE\u5E26\u6709 ref \u77ED\u6807\u8BC6\uFF08\u5982 e1, e2, e3\uFF09\u7684\u7CBE\u7B80\u5217\u8868\uFF0C\u5305\u542B\u5143\u7D20\u7C7B\u578B\u3001\u6587\u672C\u548C\u4F4D\u7F6E\u3002Token \u6781\u7701\uFF08\u901A\u5E38 < 1000 tokens\uFF09\uFF0C\u4E13\u4E3A AI \u64CD\u4F5C\u9875\u9762\u800C\u8BBE\u8BA1\u3002\u5F53\u7528\u6237\u8981\u6C42\u70B9\u51FB\u3001\u8F93\u5165\u3001\u767B\u5F55\u3001\u63D0\u4EA4\u8868\u5355\u3001\u6253\u5F00\u83DC\u5355\u7B49\u64CD\u4F5C\u65F6\uFF0C\u5E94\u4E3B\u52A8\u4F7F\u7528\u6B64\u5DE5\u5177\u5F00\u59CB\u5B9A\u4F4D\u5143\u7D20\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\u83B7\u53D6\u540E\u53EF\u901A\u8FC7 dispatch_action \u5DE5\u5177\u4F7F\u7528 ref \u6807\u8BC6\u6765\u70B9\u51FB\u3001\u586B\u5199\u3001\u6309\u952E\u7B49\u3002\u652F\u6301 Shadow DOM \u7A7F\u900F\u3002\n\u26A0\uFE0F \u4EC5\u7528\u4E8E\u4EA4\u4E92\u64CD\u4F5C\u524D\u7684\u5143\u7D20\u5B9A\u4F4D\u3002\u5982\u9700\u6392\u67E5 UI/CSS \u5E03\u5C40\u95EE\u9898\uFF0C\u8BF7\u4F7F\u7528 capture_screenshot \u6216 get_page_content\u3002",
29074
29125
  inputSchema: {
29075
29126
  type: "object",
29076
29127
  properties: {
@@ -29091,7 +29142,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29091
29142
  },
29092
29143
  {
29093
29144
  name: "dispatch_action",
29094
- description: "\u3010\u64CD\u4F5C\u9875\u9762\u5143\u7D20\u3011\u5BF9 get_interactive_snapshot \u8FD4\u56DE\u7684\u5143\u7D20\u6267\u884C\u52A8\u4F5C\u3002\u901A\u8FC7 ref \u6807\u8BC6\uFF08\u5982 e1, e5\uFF09\u7CBE\u51C6\u5B9A\u4F4D\u5143\u7D20\uFF0C\u4F7F\u7528 CDP \u7269\u7406\u7EA7\u6A21\u62DF\u6267\u884C\u64CD\u4F5C\uFF0C\u517C\u5BB9\u6240\u6709\u524D\u7AEF\u6846\u67B6\uFF08React/Vue/Angular\uFF09\uFF0C\u6210\u529F\u7387\u6781\u9AD8\u3002\n\u652F\u6301\u7684\u52A8\u4F5C\uFF1Aclick\uFF08\u70B9\u51FB\uFF09\u3001fill\uFF08\u586B\u5199\u8F93\u5165\u6846\uFF09\u3001press\uFF08\u6309\u952E\u5982 Enter\uFF09\u3001scroll\uFF08\u6EDA\u52A8\uFF09\u3001select\uFF08\u4E0B\u62C9\u9009\u62E9\uFF09\u3001hover\uFF08\u60AC\u505C\uFF09\u3001focus\uFF08\u805A\u7126\uFF09\u3002\n\u26A0\uFE0F \u4F7F\u7528\u524D\u5FC5\u987B\u5148\u8C03\u7528 get_interactive_snapshot \u83B7\u53D6\u5143\u7D20\u5217\u8868\u3002\u64CD\u4F5C\u540E\u5EFA\u8BAE\u7528 capture_screenshot \u6216\u518D\u6B21 get_interactive_snapshot \u9A8C\u8BC1\u7ED3\u679C\u3002",
29145
+ description: "\u3010\u64CD\u4F5C\u9875\u9762\u5143\u7D20\u3011\u5BF9 get_interactive_snapshot \u8FD4\u56DE\u7684\u5143\u7D20\u6267\u884C\u52A8\u4F5C\u3002\u901A\u8FC7 ref \u6807\u8BC6\uFF08\u5982 e1, e5\uFF09\u7CBE\u51C6\u5B9A\u4F4D\u5143\u7D20\uFF0C\u4F7F\u7528 CDP \u7269\u7406\u7EA7\u6A21\u62DF\u6267\u884C\u64CD\u4F5C\uFF0C\u517C\u5BB9\u6240\u6709\u524D\u7AEF\u6846\u67B6\uFF08React/Vue/Angular\uFF09\uFF0C\u6210\u529F\u7387\u6781\u9AD8\u3002\n\u5F53\u7528\u6237\u660E\u786E\u5E0C\u671B\u5728\u9875\u9762\u4E0A\u6267\u884C\u70B9\u51FB\u3001\u8F93\u5165\u3001\u56DE\u8F66\u3001\u6EDA\u52A8\u3001\u9009\u62E9\u7B49\u64CD\u4F5C\u65F6\uFF0C\u5E94\u7ED3\u5408 get_interactive_snapshot \u4E3B\u52A8\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C\u65E0\u9700\u7528\u6237\u663E\u5F0F\u63D0\u5230 ghost-bridge\u3002\n\u652F\u6301\u7684\u52A8\u4F5C\uFF1Aclick\uFF08\u70B9\u51FB\uFF09\u3001fill\uFF08\u586B\u5199\u8F93\u5165\u6846\uFF09\u3001press\uFF08\u6309\u952E\u5982 Enter\uFF09\u3001scroll\uFF08\u6EDA\u52A8\uFF09\u3001select\uFF08\u4E0B\u62C9\u9009\u62E9\uFF09\u3001hover\uFF08\u60AC\u505C\uFF09\u3001focus\uFF08\u805A\u7126\uFF09\u3002\n\u26A0\uFE0F \u4F7F\u7528\u524D\u5FC5\u987B\u5148\u8C03\u7528 get_interactive_snapshot \u83B7\u53D6\u5143\u7D20\u5217\u8868\u3002\u64CD\u4F5C\u540E\u5EFA\u8BAE\u7528 capture_screenshot \u6216\u518D\u6B21 get_interactive_snapshot \u9A8C\u8BC1\u7ED3\u679C\u3002",
29095
29146
  inputSchema: {
29096
29147
  type: "object",
29097
29148
  properties: {
@@ -29134,6 +29185,48 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
29134
29185
  const name = request.params.name;
29135
29186
  const args = request.params.arguments || {};
29136
29187
  try {
29188
+ if (name === "inspect_page") {
29189
+ const { selector, includeInteractive = true, maxElements = 30 } = args;
29190
+ const page = await askChrome("getPageContent", {
29191
+ mode: "structured",
29192
+ selector,
29193
+ maxLength: 2e4,
29194
+ includeMetadata: true
29195
+ });
29196
+ let interactive = null;
29197
+ if (includeInteractive) {
29198
+ interactive = await askChrome("getInteractiveSnapshot", {
29199
+ selector,
29200
+ includeText: true,
29201
+ maxElements
29202
+ });
29203
+ }
29204
+ const links = page?.counts?.links;
29205
+ const buttons = page?.counts?.buttons;
29206
+ const forms = page?.counts?.forms;
29207
+ const interactiveCount = Array.isArray(interactive?.elements) ? interactive.elements.length : Array.isArray(interactive) ? interactive.length : void 0;
29208
+ return {
29209
+ content: [
29210
+ {
29211
+ type: "text",
29212
+ text: jsonText({
29213
+ summary: {
29214
+ title: page?.metadata?.title,
29215
+ url: page?.metadata?.url,
29216
+ description: page?.metadata?.description,
29217
+ links,
29218
+ buttons,
29219
+ forms,
29220
+ interactiveCount
29221
+ },
29222
+ page,
29223
+ interactive,
29224
+ nextStepHint: "\u5982\u679C\u9700\u8981\u770B\u89C6\u89C9\u6548\u679C\uFF0C\u7EE7\u7EED\u7528 capture_screenshot\uFF1B\u5982\u679C\u9700\u8981\u70B9\u51FB\u6216\u8F93\u5165\uFF0C\u7EE7\u7EED\u7528 dispatch_action\uFF1B\u5982\u679C\u9700\u8981\u6392\u67E5\u8BF7\u6C42\u6216\u6027\u80FD\uFF0C\u7EE7\u7EED\u7528 list_network_requests / perf_metrics\u3002"
29225
+ })
29226
+ }
29227
+ ]
29228
+ };
29229
+ }
29137
29230
  if (name === "get_server_info") {
29138
29231
  let chromeOk, clientsCount;
29139
29232
  if (isMainInstance) {
@@ -29155,7 +29248,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
29155
29248
  type: "text",
29156
29249
  text: jsonText({
29157
29250
  service: "ghost-bridge",
29158
- version: "0.3.0",
29251
+ version: GHOST_BRIDGE_VERSION,
29159
29252
  role: isMainInstance ? "\u4E3B\u5B9E\u4F8B (WebSocket Server)" : "\u5BA2\u6237\u7AEF (\u8FDE\u63A5\u5230\u4E3B\u5B9E\u4F8B)",
29160
29253
  wsPort: actualPort,
29161
29254
  wsUrl: `ws://localhost:${actualPort}`,
@@ -29170,7 +29263,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
29170
29263
  };
29171
29264
  }
29172
29265
  if (name === "get_last_error") {
29173
- const data = await askChrome("getLastError");
29266
+ const { severity = "error", limit = 20 } = args;
29267
+ const data = await askChrome("getLastError", { severity, limit });
29174
29268
  return { content: [{ type: "text", text: jsonText(data) }] };
29175
29269
  }
29176
29270
  if (name === "get_script_source") {
@@ -29227,8 +29321,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
29227
29321
  return { content: [{ type: "text", text: jsonText(res) }] };
29228
29322
  }
29229
29323
  if (name === "list_network_requests") {
29230
- const { filter, method, status, resourceType, limit } = args;
29231
- const res = await askChrome("listNetworkRequests", { filter, method, status, resourceType, limit });
29324
+ const { filter, method, status, resourceType, limit, priorityMode = "debug" } = args;
29325
+ const res = await askChrome("listNetworkRequests", { filter, method, status, resourceType, limit, priorityMode });
29232
29326
  return { content: [{ type: "text", text: jsonText(res) }] };
29233
29327
  }
29234
29328
  if (name === "get_network_detail") {
@@ -29331,10 +29425,10 @@ function cleanup() {
29331
29425
  log("\u{1F9F9} \u6B63\u5728\u6E05\u7406...");
29332
29426
  if (isMainInstance) {
29333
29427
  try {
29334
- if (fs.existsSync(PORT_INFO_FILE)) {
29335
- const info = JSON.parse(fs.readFileSync(PORT_INFO_FILE, "utf-8"));
29428
+ if (fs2.existsSync(PORT_INFO_FILE)) {
29429
+ const info = JSON.parse(fs2.readFileSync(PORT_INFO_FILE, "utf-8"));
29336
29430
  if (info.pid === process.pid) {
29337
- fs.unlinkSync(PORT_INFO_FILE);
29431
+ fs2.unlinkSync(PORT_INFO_FILE);
29338
29432
  log("\u{1F4DD} \u5DF2\u5220\u9664\u7AEF\u53E3\u4FE1\u606F\u6587\u4EF6");
29339
29433
  }
29340
29434
  }
@@ -29364,10 +29458,10 @@ process.on("SIGTERM", () => {
29364
29458
  process.on("exit", () => {
29365
29459
  if (isMainInstance) {
29366
29460
  try {
29367
- if (fs.existsSync(PORT_INFO_FILE)) {
29368
- const info = JSON.parse(fs.readFileSync(PORT_INFO_FILE, "utf-8"));
29461
+ if (fs2.existsSync(PORT_INFO_FILE)) {
29462
+ const info = JSON.parse(fs2.readFileSync(PORT_INFO_FILE, "utf-8"));
29369
29463
  if (info.pid === process.pid) {
29370
- fs.unlinkSync(PORT_INFO_FILE);
29464
+ fs2.unlinkSync(PORT_INFO_FILE);
29371
29465
  }
29372
29466
  }
29373
29467
  } catch {
@@ -167,10 +167,7 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
167
167
  status: "pending",
168
168
  }
169
169
  requestMap.set(params.requestId, entry)
170
- if (requestMap.size > CONFIG.maxRequestsTracked * 2) {
171
- const firstKey = requestMap.keys().next().value
172
- requestMap.delete(firstKey)
173
- }
170
+ trimPendingRequests()
174
171
  }
175
172
 
176
173
  if (method === "Network.responseReceived") {
@@ -241,8 +238,114 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
241
238
 
242
239
  function pushNetworkRequest(entry) {
243
240
  networkRequests.unshift(entry)
244
- if (networkRequests.length > CONFIG.maxRequestsTracked) {
245
- networkRequests.pop()
241
+ trimNetworkRequests()
242
+ }
243
+
244
+ function getApiSignalScore(entry) {
245
+ const url = (entry.url || '').toLowerCase()
246
+ let score = 0
247
+ if (url.includes('/api/')) score += 80
248
+ if (url.includes('graphql')) score += 80
249
+ if (url.includes('/rpc/')) score += 60
250
+ if (url.includes('/rest/')) score += 40
251
+ if ((entry.method || 'GET').toUpperCase() !== 'GET') score += 25
252
+ return score
253
+ }
254
+
255
+ function getResourceTypeScore(entry, mode = 'debug') {
256
+ const type = (entry.resourceType || '').toLowerCase()
257
+ const debugScores = {
258
+ fetch: 140,
259
+ xhr: 140,
260
+ websocket: 120,
261
+ document: 90,
262
+ script: 45,
263
+ stylesheet: 25,
264
+ other: 0,
265
+ image: -40,
266
+ font: -40,
267
+ media: -50,
268
+ }
269
+ const apiScores = {
270
+ fetch: 220,
271
+ xhr: 220,
272
+ websocket: 160,
273
+ document: 40,
274
+ script: -10,
275
+ stylesheet: -20,
276
+ other: 0,
277
+ image: -80,
278
+ font: -80,
279
+ media: -90,
280
+ }
281
+ const table = mode === 'api' ? apiScores : debugScores
282
+ return table[type] ?? table.other
283
+ }
284
+
285
+ function getStatusScore(entry) {
286
+ if (entry.status === 'failed') return 360
287
+ if (entry.status === 'error') return 330
288
+ if (entry.status === 'pending') return 280
289
+ if ((entry.statusCode || 0) >= 500) return 340
290
+ if ((entry.statusCode || 0) >= 400) return 300
291
+ return 80
292
+ }
293
+
294
+ function getNetworkPriorityScore(entry, mode = 'debug') {
295
+ if (mode === 'recent') {
296
+ return entry.timestamp || 0
297
+ }
298
+
299
+ let score = getStatusScore(entry)
300
+ score += getResourceTypeScore(entry, mode)
301
+ score += getApiSignalScore(entry)
302
+
303
+ if (entry.fromCache) score -= 20
304
+ if ((entry.encodedDataLength || 0) === 0 && entry.status === 'success') score -= 10
305
+
306
+ return score
307
+ }
308
+
309
+ function compareNetworkEntries(a, b, mode = 'debug') {
310
+ if (mode === 'recent') {
311
+ return (b.timestamp || 0) - (a.timestamp || 0)
312
+ }
313
+
314
+ const scoreDiff = getNetworkPriorityScore(b, mode) - getNetworkPriorityScore(a, mode)
315
+ if (scoreDiff !== 0) return scoreDiff
316
+ return (b.timestamp || 0) - (a.timestamp || 0)
317
+ }
318
+
319
+ function trimNetworkRequests() {
320
+ while (networkRequests.length > CONFIG.maxRequestsTracked) {
321
+ let worstIndex = 0
322
+ for (let i = 1; i < networkRequests.length; i++) {
323
+ const candidate = networkRequests[i]
324
+ const worst = networkRequests[worstIndex]
325
+ const cmp = compareNetworkEntries(candidate, worst, 'debug')
326
+ if (cmp < 0 || (cmp === 0 && (candidate.timestamp || 0) < (worst.timestamp || 0))) {
327
+ worstIndex = i
328
+ }
329
+ }
330
+ networkRequests.splice(worstIndex, 1)
331
+ }
332
+ }
333
+
334
+ function trimPendingRequests() {
335
+ while (requestMap.size > CONFIG.maxRequestsTracked * 2) {
336
+ const entries = [...requestMap.entries()]
337
+ let worstKey = entries[0]?.[0]
338
+ let worstValue = entries[0]?.[1]
339
+ for (let i = 1; i < entries.length; i++) {
340
+ const [key, value] = entries[i]
341
+ const cmp = compareNetworkEntries(value, worstValue, 'debug')
342
+ if (cmp < 0 || (cmp === 0 && (value.timestamp || 0) < (worstValue.timestamp || 0))) {
343
+ worstKey = key
344
+ worstValue = value
345
+ }
346
+ }
347
+ if (!worstKey) break
348
+ requestMap.delete(worstKey)
246
349
  }
247
350
  }
248
351
 
@@ -376,10 +479,15 @@ async function detachAllTargets() {
376
479
 
377
480
  // ========== 命令处理 ==========
378
481
 
379
- async function handleGetLastError() {
482
+ async function handleGetLastError(params = {}) {
380
483
  await ensureAttached()
381
- const events = lastErrors.slice(0, CONFIG.maxErrors)
382
- const counts = events.reduce(
484
+ const severity = params.severity || "error"
485
+ const limit = Math.max(1, Math.min(params.limit || 20, CONFIG.maxErrors))
486
+ const allEvents = lastErrors.slice(0, CONFIG.maxErrors)
487
+ const filteredEvents = severity === "all"
488
+ ? allEvents
489
+ : allEvents.filter((event) => (event.severity || "info") === severity)
490
+ const counts = allEvents.reduce(
383
491
  (acc, e) => {
384
492
  acc.total++
385
493
  acc[e.severity || "info"] = (acc[e.severity || "info"] || 0) + 1
@@ -387,12 +495,17 @@ async function handleGetLastError() {
387
495
  },
388
496
  { total: 0 }
389
497
  )
498
+ const events = filteredEvents.slice(0, limit)
390
499
  return {
391
500
  lastErrorLocation,
392
501
  summary: {
393
502
  count: events.length,
503
+ cachedCount: allEvents.length,
504
+ filteredCount: filteredEvents.length,
505
+ requestedSeverity: severity,
506
+ limit,
394
507
  severityCount: counts,
395
- lastTimestamp: events[0]?.timestamp,
508
+ lastTimestamp: filteredEvents[0]?.timestamp || allEvents[0]?.timestamp,
396
509
  },
397
510
  recent: events,
398
511
  }
@@ -530,7 +643,7 @@ async function handleEval(params = {}) {
530
643
 
531
644
  async function handleListNetworkRequests(params = {}) {
532
645
  await ensureAttached()
533
- const { filter, method, status, resourceType, limit = 50 } = params
646
+ const { filter, method, status, resourceType, limit = 50, priorityMode = 'debug' } = params
534
647
 
535
648
  let results = [...networkRequests]
536
649
  const pending = [...requestMap.values()].map(r => ({ ...r, status: "pending" }))
@@ -547,11 +660,13 @@ async function handleListNetworkRequests(params = {}) {
547
660
  results = results.filter(r => r.resourceType?.toLowerCase() === lowerType)
548
661
  }
549
662
 
663
+ results.sort((a, b) => compareNetworkEntries(a, b, priorityMode))
550
664
  results = results.slice(0, limit)
551
665
 
552
666
  return {
553
667
  total: networkRequests.length + requestMap.size,
554
668
  filtered: results.length,
669
+ priorityMode,
555
670
  requests: results.map(r => ({
556
671
  requestId: r.requestId,
557
672
  url: r.url,
@@ -1243,7 +1358,7 @@ async function handleCommand(message) {
1243
1358
  }
1244
1359
  try {
1245
1360
  let result
1246
- if (command === "getLastError") result = await handleGetLastError()
1361
+ if (command === "getLastError") result = await handleGetLastError(params)
1247
1362
  else if (command === "getScriptSource") result = await handleGetScriptSource(params)
1248
1363
  else if (command === "coverageSnapshot") result = await handleCoverageSnapshot(params)
1249
1364
  else if (command === "findByString") result = await handleFindByString(params)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Ghost Bridge",
4
- "version": "0.5.0",
4
+ "version": "0.5.1",
5
5
  "description": "Zero-restart Chrome debugger bridge for Claude MCP, optimized for no-sourcemap production debugging.",
6
6
  "permissions": [
7
7
  "debugger",
@@ -34,4 +34,4 @@
34
34
  "background": {
35
35
  "service_worker": "background.js"
36
36
  }
37
- }
37
+ }
@@ -176,44 +176,16 @@
176
176
  z-index: 2;
177
177
  }
178
178
 
179
- .status-ping {
180
- position: absolute;
181
- top: 0;
182
- left: 0;
183
- width: 100%;
184
- height: 100%;
185
- border-radius: 50%;
186
- z-index: 1;
187
- opacity: 0;
188
- }
189
-
190
179
  /* Connected State */
191
180
  .connected .status-dot { background: #00d2ff; box-shadow: 0 0 10px #00d2ff; }
192
- .connected .status-ping {
193
- background: #00d2ff;
194
- animation: ping-slow 3s cubic-bezier(0, 0, 0.2, 1) infinite;
195
- }
196
181
 
197
182
  /* Connecting/Scanning State */
198
183
  .connecting .status-dot { background: #a252ff; box-shadow: 0 0 12px #a252ff; }
199
- .connecting .status-ping {
200
- background: #a252ff;
201
- animation: ping-fast 1.5s cubic-bezier(0, 0, 0.2, 1) infinite;
202
- }
203
184
 
204
185
  /* Disconnected/Error State */
205
186
  .disconnected .status-dot { background: #4b5563; }
206
187
  .error .status-dot { background: #ef4444; box-shadow: 0 0 8px #ef4444; }
207
188
 
208
- @keyframes ping-fast {
209
- 0% { transform: scale(1); opacity: 0.8; }
210
- 75%, 100% { transform: scale(2.5); opacity: 0; }
211
- }
212
- @keyframes ping-slow {
213
- 0% { transform: scale(1); opacity: 0.6; }
214
- 75%, 100% { transform: scale(2.2); opacity: 0; }
215
- }
216
-
217
189
  .status-text {
218
190
  font-size: 15px;
219
191
  font-weight: 600;
@@ -452,7 +424,6 @@
452
424
  <div class="status-card" id="statusCard">
453
425
  <div class="status-row">
454
426
  <div class="status-dot-wrapper" id="dotWrapper">
455
- <div class="status-ping"></div>
456
427
  <div class="status-dot"></div>
457
428
  </div>
458
429
  <span class="status-text" id="statusText">Checking...</span>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghost-bridge",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Ghost Bridge: Zero-restart Chrome debugger bridge for Claude MCP. Includes CLI for easy setup.",
@@ -49,4 +49,4 @@
49
49
  "js-beautify": "^1.14.11",
50
50
  "ws": "^8.14.2"
51
51
  }
52
- }
52
+ }