@gecho-ai/gecho-bridge 1.1.27 → 1.1.28

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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@gecho-ai/gecho-bridge",
3
- "version": "1.1.27",
3
+ "version": "1.1.28",
4
4
  "description": "TikTok Search Tool for OpenClaw"
5
5
  }
@@ -33854,7 +33854,7 @@ var require_package = __commonJS({
33854
33854
  "package.json"(exports2, module2) {
33855
33855
  module2.exports = {
33856
33856
  name: "@gecho-ai/gecho-bridge",
33857
- version: "1.1.27",
33857
+ version: "1.1.28",
33858
33858
  description: "TikTok Search and Insight tools for OpenClaw, connecting LLMs to TikTok via Chrome Extension.",
33859
33859
  main: "mcp-client.js",
33860
33860
  bin: {
package/dist/server.cjs CHANGED
@@ -3640,7 +3640,7 @@ var require_package = __commonJS({
3640
3640
  "package.json"(exports2, module2) {
3641
3641
  module2.exports = {
3642
3642
  name: "@gecho-ai/gecho-bridge",
3643
- version: "1.1.27",
3643
+ version: "1.1.28",
3644
3644
  description: "TikTok Search and Insight tools for OpenClaw, connecting LLMs to TikTok via Chrome Extension.",
3645
3645
  main: "mcp-client.js",
3646
3646
  bin: {
@@ -3717,10 +3717,13 @@ var MAX_PERSISTED_JOBS = Number(process["env"].GECHO_MAX_PERSISTED_JOBS || 2e3);
3717
3717
  var CLEANUP_INTERVAL_MS = Number(process["env"].GECHO_CLEANUP_INTERVAL_MS || 10 * 60 * 1e3);
3718
3718
  var EXTENSION_CONNECT_TIMEOUT_MS = Math.max(1e3, Number(process["env"].GECHO_EXTENSION_CONNECT_TIMEOUT_MS || 3e4));
3719
3719
  var EXTENSION_CONNECT_POLL_MS = 500;
3720
+ var EXTENSION_READY_GRACE_MS = Math.max(0, Number(process["env"].GECHO_EXTENSION_READY_GRACE_MS || 1500));
3720
3721
  var AUTO_LAUNCH_BROWSER = process["env"].GECHO_AUTO_LAUNCH_BROWSER !== "0";
3721
3722
  var AUTO_LAUNCH_BROWSER_DRY_RUN = process["env"].GECHO_AUTO_LAUNCH_BROWSER_DRY_RUN === "1";
3722
3723
  var AUTO_LAUNCH_BROWSER_COOLDOWN_MS = Math.max(0, Number(process["env"].GECHO_AUTO_LAUNCH_BROWSER_COOLDOWN_MS || 1e4));
3723
3724
  var extensionSocket = null;
3725
+ var wss = null;
3726
+ var lastExtensionConnectedAt = 0;
3724
3727
  var lastBrowserConnection = null;
3725
3728
  var browserLaunchPromise = null;
3726
3729
  var lastBrowserLaunchAt = 0;
@@ -3728,6 +3731,12 @@ var pendingRequests = /* @__PURE__ */ new Map();
3728
3731
  var requestIdCounter = 1;
3729
3732
  var shuttingDown = false;
3730
3733
  var lastDispatchedRequestId = "";
3734
+ var BRIDGE_TRACE_LIMIT = 100;
3735
+ var bridgeTrace = [];
3736
+ function traceBridgeEvent(event, details = {}) {
3737
+ bridgeTrace.push({ at: Date.now(), event, ...details });
3738
+ if (bridgeTrace.length > BRIDGE_TRACE_LIMIT) bridgeTrace.shift();
3739
+ }
3731
3740
  var asyncJobs = /* @__PURE__ */ new Map();
3732
3741
  var requestIndex = /* @__PURE__ */ new Map();
3733
3742
  var ASYNC_ATTEMPT_TIMEOUT_MS = 36e4;
@@ -3800,8 +3809,22 @@ async function writeFileAtomicAsync(targetPath, content) {
3800
3809
  }
3801
3810
  }
3802
3811
  }
3812
+ function getOpenExtensionSocket() {
3813
+ if (extensionSocket && extensionSocket.readyState === 1) {
3814
+ return extensionSocket;
3815
+ }
3816
+ if (wss) {
3817
+ for (const socket of wss.clients) {
3818
+ if (socket.readyState === 1) {
3819
+ extensionSocket = socket;
3820
+ return socket;
3821
+ }
3822
+ }
3823
+ }
3824
+ return null;
3825
+ }
3803
3826
  function isExtensionConnected() {
3804
- return !!extensionSocket && extensionSocket.readyState === 1;
3827
+ return !!getOpenExtensionSocket();
3805
3828
  }
3806
3829
  function normalizeBrowserName(value) {
3807
3830
  const normalized = String(value || "").trim().toLowerCase();
@@ -3997,16 +4020,34 @@ function waitForExtensionConnection(timeoutMs = EXTENSION_CONNECT_TIMEOUT_MS) {
3997
4020
  }, EXTENSION_CONNECT_POLL_MS);
3998
4021
  });
3999
4022
  }
4023
+ async function waitForExtensionReadyGracePeriod() {
4024
+ const remainingMs = Math.max(0, EXTENSION_READY_GRACE_MS - (Date.now() - lastExtensionConnectedAt));
4025
+ if (remainingMs === 0) return isExtensionConnected();
4026
+ traceBridgeEvent("extension_ready_grace_wait_started", { remainingMs });
4027
+ await new Promise((resolve) => setTimeout(resolve, remainingMs));
4028
+ const connected = isExtensionConnected();
4029
+ traceBridgeEvent("extension_ready_grace_wait_finished", { connected });
4030
+ return connected;
4031
+ }
4000
4032
  async function ensureExtensionConnection(action) {
4001
4033
  if (isExtensionConnected()) {
4034
+ traceBridgeEvent("extension_already_connected", { action });
4002
4035
  return { connected: true, launch: { attempted: false, launched: false, reason: "already_connected" } };
4003
4036
  }
4037
+ traceBridgeEvent("extension_connection_wait_started", { action });
4004
4038
  const launch = await launchBrowserForExtension();
4005
4039
  console.log(
4006
4040
  `\u23F3 Extension not connected yet. Waiting up to ${EXTENSION_CONNECT_TIMEOUT_MS / 1e3}s (action: ${action}, browser: ${launch.browser || "unknown"})`
4007
4041
  );
4008
4042
  const connected = await waitForExtensionConnection();
4009
- return { connected, launch };
4043
+ const ready = connected && await waitForExtensionReadyGracePeriod();
4044
+ traceBridgeEvent("extension_connection_wait_finished", {
4045
+ action,
4046
+ connected: ready,
4047
+ browser: launch.browser || "",
4048
+ launchReason: launch.reason || ""
4049
+ });
4050
+ return { connected: ready, launch };
4010
4051
  }
4011
4052
  function extensionConnectionError(connection) {
4012
4053
  const launch = connection?.launch || {};
@@ -4470,6 +4511,7 @@ async function runAsyncAttempt({ jobId, action, params, payload, attempt }) {
4470
4511
  }
4471
4512
  const requestId = `${jobId}:a${attempt}`;
4472
4513
  lastDispatchedRequestId = requestId;
4514
+ traceBridgeEvent("action_dispatched", { action, requestId, async: true });
4473
4515
  requestIndex.set(requestId, { jobId, attempt, updatedAt: Date.now() });
4474
4516
  schedulePersistRequestIndex();
4475
4517
  appendJobEvent(jobId, "attempt_started", { attempt, requestId });
@@ -4552,16 +4594,19 @@ function gracefulShutdown(reason) {
4552
4594
  }
4553
4595
  }
4554
4596
  }
4555
- var wss = new WebSocketServer({ port: WS_PORT, host: "127.0.0.1" });
4597
+ wss = new WebSocketServer({ port: WS_PORT, host: "127.0.0.1" });
4556
4598
  wss.on("connection", (ws, request) => {
4557
4599
  const browser = detectBrowserFromUserAgent(request?.headers?.["user-agent"]);
4558
4600
  if (browser) persistLastBrowserConnection(browser);
4559
4601
  console.log(`\u2705 Browser extension connected to Service Layer${browser ? ` (${browser})` : ""}`);
4560
4602
  extensionSocket = ws;
4603
+ lastExtensionConnectedAt = Date.now();
4604
+ traceBridgeEvent("extension_connected", { browser, clientCount: wss.clients.size });
4561
4605
  ws.on("message", (message) => {
4562
4606
  try {
4563
4607
  const parsed = JSON.parse(message);
4564
4608
  if (parsed.method === "action_progress" && parsed.requestId) {
4609
+ traceBridgeEvent("extension_progress", { requestId: parsed.requestId });
4565
4610
  const pending = pendingRequests.get(parsed.requestId);
4566
4611
  if (!pending) {
4567
4612
  console.warn(`WARN action_progress requestId not found: ${parsed.requestId}`);
@@ -4581,6 +4626,7 @@ wss.on("connection", (ws, request) => {
4581
4626
  }
4582
4627
  }
4583
4628
  if (parsed.method === "action_result" && parsed.requestId) {
4629
+ traceBridgeEvent("extension_result", { requestId: parsed.requestId });
4584
4630
  console.log(`\u{1F4E9} Received result from extension (ID: ${parsed.requestId})`);
4585
4631
  const pending = pendingRequests.get(parsed.requestId);
4586
4632
  if (pending) {
@@ -4614,9 +4660,11 @@ wss.on("connection", (ws, request) => {
4614
4660
  });
4615
4661
  ws.on("close", () => {
4616
4662
  console.log("\u274C Browser extension disconnected");
4663
+ traceBridgeEvent("extension_disconnected", { clientCount: wss.clients.size });
4617
4664
  if (extensionSocket === ws) extensionSocket = null;
4618
4665
  });
4619
4666
  ws.on("error", (error) => {
4667
+ traceBridgeEvent("extension_socket_error", { message: error.message });
4620
4668
  console.warn(`Browser extension WebSocket error: ${error.message}`);
4621
4669
  });
4622
4670
  });
@@ -4651,7 +4699,8 @@ var server = http.createServer(async (req, res) => {
4651
4699
  autoBrowserLaunch: {
4652
4700
  enabled: AUTO_LAUNCH_BROWSER,
4653
4701
  browser: getBrowserToLaunch() || null
4654
- }
4702
+ },
4703
+ bridgeTrace: bridgeTrace.slice(-30)
4655
4704
  }));
4656
4705
  }
4657
4706
  if (req.method === "POST" && req.url === "/shutdown") {
@@ -4771,6 +4820,7 @@ var server = http.createServer(async (req, res) => {
4771
4820
  console.log(`\u{1F680} Dispatching action: [${action}]`);
4772
4821
  const requestId = `svc-${Date.now()}-${requestIdCounter++}`;
4773
4822
  lastDispatchedRequestId = requestId;
4823
+ traceBridgeEvent("action_dispatched", { action, requestId, async: false });
4774
4824
  const { action: _a, ...params } = payload;
4775
4825
  const result = await new Promise((resolve) => {
4776
4826
  const timeoutId = setTimeout(() => {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "tiktok-influencer",
3
- "version": "1.1.27",
3
+ "version": "1.1.28",
4
4
  "type": "mcp"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "tiktok-insight",
3
- "version": "1.1.27",
3
+ "version": "1.1.28",
4
4
  "type": "mcp"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "tiktok-video-search",
3
- "version": "1.1.27",
3
+ "version": "1.1.28",
4
4
  "type": "mcp"
5
5
  }
@@ -2,7 +2,7 @@
2
2
  "id": "gecho-ai-gecho-bridge",
3
3
  "name": "@gecho-ai/gecho-bridge",
4
4
  "description": "TikTok Search and Insight tools for OpenClaw, connecting LLMs to TikTok via Chrome Extension.",
5
- "version": "1.1.27",
5
+ "version": "1.1.28",
6
6
  "skills": [
7
7
  "./skills"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gecho-ai/gecho-bridge",
3
- "version": "1.1.27",
3
+ "version": "1.1.28",
4
4
  "description": "TikTok Search and Insight tools for OpenClaw, connecting LLMs to TikTok via Chrome Extension.",
5
5
  "main": "mcp-client.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -30,11 +30,14 @@ const MAX_PERSISTED_JOBS = Number(process["env"].GECHO_MAX_PERSISTED_JOBS || 200
30
30
  const CLEANUP_INTERVAL_MS = Number(process["env"].GECHO_CLEANUP_INTERVAL_MS || 10 * 60 * 1000);
31
31
  const EXTENSION_CONNECT_TIMEOUT_MS = Math.max(1000, Number(process["env"].GECHO_EXTENSION_CONNECT_TIMEOUT_MS || 30000));
32
32
  const EXTENSION_CONNECT_POLL_MS = 500;
33
+ const EXTENSION_READY_GRACE_MS = Math.max(0, Number(process["env"].GECHO_EXTENSION_READY_GRACE_MS || 1500));
33
34
  const AUTO_LAUNCH_BROWSER = process["env"].GECHO_AUTO_LAUNCH_BROWSER !== "0";
34
35
  const AUTO_LAUNCH_BROWSER_DRY_RUN = process["env"].GECHO_AUTO_LAUNCH_BROWSER_DRY_RUN === "1";
35
36
  const AUTO_LAUNCH_BROWSER_COOLDOWN_MS = Math.max(0, Number(process["env"].GECHO_AUTO_LAUNCH_BROWSER_COOLDOWN_MS || 10000));
36
37
 
37
38
  let extensionSocket = null;
39
+ let wss = null;
40
+ let lastExtensionConnectedAt = 0;
38
41
  let lastBrowserConnection = null;
39
42
  let browserLaunchPromise = null;
40
43
  let lastBrowserLaunchAt = 0;
@@ -42,6 +45,13 @@ const pendingRequests = new Map();
42
45
  let requestIdCounter = 1;
43
46
  let shuttingDown = false;
44
47
  let lastDispatchedRequestId = "";
48
+ const BRIDGE_TRACE_LIMIT = 100;
49
+ const bridgeTrace = [];
50
+
51
+ function traceBridgeEvent(event, details = {}) {
52
+ bridgeTrace.push({ at: Date.now(), event, ...details });
53
+ if (bridgeTrace.length > BRIDGE_TRACE_LIMIT) bridgeTrace.shift();
54
+ }
45
55
 
46
56
  // --- 异步任务管理 ---
47
57
  const asyncJobs = new Map();
@@ -114,8 +124,29 @@ async function writeFileAtomicAsync(targetPath, content) {
114
124
  }
115
125
  }
116
126
 
127
+ function getOpenExtensionSocket() {
128
+ if (extensionSocket && extensionSocket.readyState === 1) {
129
+ return extensionSocket;
130
+ }
131
+
132
+ // Chrome can briefly create overlapping WebSocket connections while an
133
+ // extension service worker is starting or reconnecting. Do not rely on a
134
+ // single mutable reference in that window: recover an open client directly
135
+ // from the WebSocket server before declaring the extension disconnected.
136
+ if (wss) {
137
+ for (const socket of wss.clients) {
138
+ if (socket.readyState === 1) {
139
+ extensionSocket = socket;
140
+ return socket;
141
+ }
142
+ }
143
+ }
144
+
145
+ return null;
146
+ }
147
+
117
148
  function isExtensionConnected() {
118
- return !!extensionSocket && extensionSocket.readyState === 1;
149
+ return !!getOpenExtensionSocket();
119
150
  }
120
151
 
121
152
  function normalizeBrowserName(value) {
@@ -350,18 +381,38 @@ function waitForExtensionConnection(timeoutMs = EXTENSION_CONNECT_TIMEOUT_MS) {
350
381
  });
351
382
  }
352
383
 
384
+ async function waitForExtensionReadyGracePeriod() {
385
+ const remainingMs = Math.max(0, EXTENSION_READY_GRACE_MS - (Date.now() - lastExtensionConnectedAt));
386
+ if (remainingMs === 0) return isExtensionConnected();
387
+
388
+ traceBridgeEvent("extension_ready_grace_wait_started", { remainingMs });
389
+ await new Promise(resolve => setTimeout(resolve, remainingMs));
390
+ const connected = isExtensionConnected();
391
+ traceBridgeEvent("extension_ready_grace_wait_finished", { connected });
392
+ return connected;
393
+ }
394
+
353
395
  async function ensureExtensionConnection(action) {
354
396
  if (isExtensionConnected()) {
397
+ traceBridgeEvent("extension_already_connected", { action });
355
398
  return { connected: true, launch: { attempted: false, launched: false, reason: "already_connected" } };
356
399
  }
357
400
 
401
+ traceBridgeEvent("extension_connection_wait_started", { action });
358
402
  const launch = await launchBrowserForExtension();
359
403
  console.log(
360
404
  `⏳ Extension not connected yet. Waiting up to ${EXTENSION_CONNECT_TIMEOUT_MS / 1000}s ` +
361
405
  `(action: ${action}, browser: ${launch.browser || "unknown"})`
362
406
  );
363
407
  const connected = await waitForExtensionConnection();
364
- return { connected, launch };
408
+ const ready = connected && await waitForExtensionReadyGracePeriod();
409
+ traceBridgeEvent("extension_connection_wait_finished", {
410
+ action,
411
+ connected: ready,
412
+ browser: launch.browser || "",
413
+ launchReason: launch.reason || ""
414
+ });
415
+ return { connected: ready, launch };
365
416
  }
366
417
 
367
418
  function extensionConnectionError(connection) {
@@ -896,6 +947,7 @@ async function runAsyncAttempt({ jobId, action, params, payload, attempt }) {
896
947
 
897
948
  const requestId = `${jobId}:a${attempt}`;
898
949
  lastDispatchedRequestId = requestId;
950
+ traceBridgeEvent("action_dispatched", { action, requestId, async: true });
899
951
  requestIndex.set(requestId, { jobId, attempt, updatedAt: Date.now() });
900
952
  schedulePersistRequestIndex();
901
953
  appendJobEvent(jobId, "attempt_started", { attempt, requestId });
@@ -989,18 +1041,21 @@ function gracefulShutdown(reason) {
989
1041
  }
990
1042
 
991
1043
  // --- WebSocket Server (与插件通信) ---
992
- const wss = new WebSocketServer({ port: WS_PORT, host: "127.0.0.1" });
1044
+ wss = new WebSocketServer({ port: WS_PORT, host: "127.0.0.1" });
993
1045
 
994
1046
  wss.on("connection", (ws, request) => {
995
1047
  const browser = detectBrowserFromUserAgent(request?.headers?.["user-agent"]);
996
1048
  if (browser) persistLastBrowserConnection(browser);
997
1049
  console.log(`✅ Browser extension connected to Service Layer${browser ? ` (${browser})` : ""}`);
998
1050
  extensionSocket = ws;
1051
+ lastExtensionConnectedAt = Date.now();
1052
+ traceBridgeEvent("extension_connected", { browser, clientCount: wss.clients.size });
999
1053
 
1000
1054
  ws.on("message", (message) => {
1001
1055
  try {
1002
1056
  const parsed = JSON.parse(message);
1003
1057
  if (parsed.method === "action_progress" && parsed.requestId) {
1058
+ traceBridgeEvent("extension_progress", { requestId: parsed.requestId });
1004
1059
  const pending = pendingRequests.get(parsed.requestId);
1005
1060
  if (!pending) {
1006
1061
  console.warn(`WARN action_progress requestId not found: ${parsed.requestId}`);
@@ -1020,6 +1075,7 @@ wss.on("connection", (ws, request) => {
1020
1075
  }
1021
1076
  }
1022
1077
  if (parsed.method === "action_result" && parsed.requestId) {
1078
+ traceBridgeEvent("extension_result", { requestId: parsed.requestId });
1023
1079
  console.log(`📩 Received result from extension (ID: ${parsed.requestId})`);
1024
1080
  const pending = pendingRequests.get(parsed.requestId);
1025
1081
  if (pending) {
@@ -1054,10 +1110,12 @@ wss.on("connection", (ws, request) => {
1054
1110
 
1055
1111
  ws.on("close", () => {
1056
1112
  console.log("❌ Browser extension disconnected");
1113
+ traceBridgeEvent("extension_disconnected", { clientCount: wss.clients.size });
1057
1114
  if (extensionSocket === ws) extensionSocket = null;
1058
1115
  });
1059
1116
 
1060
1117
  ws.on("error", (error) => {
1118
+ traceBridgeEvent("extension_socket_error", { message: error.message });
1061
1119
  console.warn(`Browser extension WebSocket error: ${error.message}`);
1062
1120
  });
1063
1121
  });
@@ -1098,7 +1156,8 @@ const server = http.createServer(async (req, res) => {
1098
1156
  autoBrowserLaunch: {
1099
1157
  enabled: AUTO_LAUNCH_BROWSER,
1100
1158
  browser: getBrowserToLaunch() || null
1101
- }
1159
+ },
1160
+ bridgeTrace: bridgeTrace.slice(-30)
1102
1161
  }));
1103
1162
  }
1104
1163
 
@@ -1238,6 +1297,7 @@ const server = http.createServer(async (req, res) => {
1238
1297
  console.log(`🚀 Dispatching action: [${action}]`);
1239
1298
  const requestId = `svc-${Date.now()}-${requestIdCounter++}`;
1240
1299
  lastDispatchedRequestId = requestId;
1300
+ traceBridgeEvent("action_dispatched", { action, requestId, async: false });
1241
1301
  // 通用透传逻辑:将 payload 中的所有参数(除去 action)作为 params 传给插件
1242
1302
  const { action: _a, ...params } = payload;
1243
1303
  const result = await new Promise((resolve) => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "slug": "tiktok-search",
3
- "version": "1.1.27",
3
+ "version": "1.1.28",
4
4
  "type": "mcp",
5
5
  "publishedAt": 1775894233000
6
6
  }