@gecho-ai/gecho-bridge 1.1.37 → 1.1.38-beta.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/.claude-plugin/plugin.json +2 -2
- package/README.md +54 -6
- package/README.zh.md +59 -6
- package/action-result.js +53 -0
- package/bridge-service.js +187 -0
- package/bridge-startup.js +336 -0
- package/dist/mcp-client.cjs +176 -15
- package/dist/server.cjs +1129 -24
- package/distribution-skills/amazon/publish.json +11 -0
- package/distribution-skills/amazon-product/publish.json +11 -0
- package/distribution-skills/amazon-reviews/publish.json +11 -0
- package/distribution-skills/amazon-search/publish.json +11 -0
- package/distribution-skills/facebook-reels-search/SKILL.md +289 -0
- package/distribution-skills/facebook-reels-search/_meta.json +5 -0
- package/distribution-skills/facebook-reels-search/publish.json +31 -0
- package/distribution-skills/tiktok-influencer/publish.json +11 -0
- package/distribution-skills/tiktok-insight/publish.json +11 -0
- package/distribution-skills/tiktok-product/publish.json +11 -0
- package/distribution-skills/tiktok-search/publish.json +11 -0
- package/distribution-skills/tiktok-shop/publish.json +11 -0
- package/distribution-skills/tiktok-shop-search/publish.json +11 -0
- package/distribution-skills/tiktok-video/publish.json +11 -0
- package/distribution-skills/tiktok-video-search/publish.json +11 -0
- package/distribution-skills/x/publish.json +11 -0
- package/distribution-skills/x-post-detail/publish.json +11 -0
- package/distribution-skills/x-search/publish.json +11 -0
- package/distribution-skills/youtube-shorts-search/SKILL.md +289 -0
- package/distribution-skills/youtube-shorts-search/_meta.json +5 -0
- package/distribution-skills/youtube-shorts-search/publish.json +31 -0
- package/distribution-skills-zh-CN/amazon/SKILL.md +398 -0
- package/distribution-skills-zh-CN/amazon/_meta.json +5 -0
- package/distribution-skills-zh-CN/amazon/publish.json +31 -0
- package/distribution-skills-zh-CN/amazon/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/amazon-product/SKILL.md +299 -0
- package/distribution-skills-zh-CN/amazon-product/_meta.json +5 -0
- package/distribution-skills-zh-CN/amazon-product/publish.json +31 -0
- package/distribution-skills-zh-CN/amazon-product/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/amazon-reviews/SKILL.md +300 -0
- package/distribution-skills-zh-CN/amazon-reviews/_meta.json +5 -0
- package/distribution-skills-zh-CN/amazon-reviews/publish.json +31 -0
- package/distribution-skills-zh-CN/amazon-reviews/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/amazon-search/SKILL.md +300 -0
- package/distribution-skills-zh-CN/amazon-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/amazon-search/publish.json +31 -0
- package/distribution-skills-zh-CN/amazon-search/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/facebook-reels-search/SKILL.md +289 -0
- package/distribution-skills-zh-CN/facebook-reels-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/facebook-reels-search/publish.json +31 -0
- package/distribution-skills-zh-CN/facebook-reels-search/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-influencer/SKILL.md +308 -0
- package/distribution-skills-zh-CN/tiktok-influencer/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-influencer/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-influencer/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-insight/SKILL.md +362 -0
- package/distribution-skills-zh-CN/tiktok-insight/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-insight/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-insight/skillhub-publish.json +6 -0
- package/distribution-skills-zh-CN/tiktok-product/SKILL.md +298 -0
- package/distribution-skills-zh-CN/tiktok-product/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-product/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-product/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-search/SKILL.md +470 -0
- package/distribution-skills-zh-CN/tiktok-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-search/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-search/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-shop/SKILL.md +359 -0
- package/distribution-skills-zh-CN/tiktok-shop/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-shop/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-shop/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-shop-search/SKILL.md +299 -0
- package/distribution-skills-zh-CN/tiktok-shop-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-shop-search/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-shop-search/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-video/SKILL.md +380 -0
- package/distribution-skills-zh-CN/tiktok-video/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-video/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-video/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/tiktok-video-search/SKILL.md +306 -0
- package/distribution-skills-zh-CN/tiktok-video-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/tiktok-video-search/publish.json +31 -0
- package/distribution-skills-zh-CN/tiktok-video-search/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/x/SKILL.md +360 -0
- package/distribution-skills-zh-CN/x/_meta.json +5 -0
- package/distribution-skills-zh-CN/x/publish.json +31 -0
- package/distribution-skills-zh-CN/x/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/x-post-detail/SKILL.md +299 -0
- package/distribution-skills-zh-CN/x-post-detail/_meta.json +5 -0
- package/distribution-skills-zh-CN/x-post-detail/publish.json +31 -0
- package/distribution-skills-zh-CN/x-post-detail/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/x-search/SKILL.md +299 -0
- package/distribution-skills-zh-CN/x-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/x-search/publish.json +31 -0
- package/distribution-skills-zh-CN/x-search/skillhub-publish.json +1 -0
- package/distribution-skills-zh-CN/youtube-shorts-search/SKILL.md +289 -0
- package/distribution-skills-zh-CN/youtube-shorts-search/_meta.json +5 -0
- package/distribution-skills-zh-CN/youtube-shorts-search/publish.json +31 -0
- package/distribution-skills-zh-CN/youtube-shorts-search/skillhub-publish.json +1 -0
- package/mcp-client.js +118 -10
- package/openclaw.plugin.json +2 -2
- package/package.json +23 -5
- package/scheduled-task-scheduler.js +261 -0
- package/scheduled-task-store.js +268 -0
- package/scheduled-task.js +244 -0
- package/server.js +420 -19
package/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Gecho Bridge 🚀
|
|
2
2
|
|
|
3
|
-
**Gecho Bridge connects AI clients such as OpenClaw, Hermes, Trae, and Claude Code to a live Chrome browser through MCP and the Gecho Chrome extension.** Use it to search TikTok videos, collect structured metadata, save JSON results, and run async product, trend, competitor, and content insight workflows.
|
|
3
|
+
**Gecho Bridge connects AI clients such as OpenClaw, Hermes, Trae, and Claude Code to a live Chrome browser through MCP and the Gecho Chrome extension.** Use it to search TikTok videos, YouTube Shorts, Facebook Reels, X posts, and Amazon products, collect structured metadata, save JSON results, and run async product, trend, competitor, and content insight workflows.
|
|
4
4
|
|
|
5
5
|
## ⚠️ Critical Prerequisite: Read Before Use
|
|
6
6
|
|
|
7
|
-
Gecho Bridge cannot work from the README, Skill page, or MCP config alone. Before the first
|
|
7
|
+
Gecho Bridge cannot work from the README, Skill page, or MCP config alone. Before the first platform search or insight job, all 3 items below are required:
|
|
8
8
|
|
|
9
9
|
1. **Configure Gecho Bridge MCP** in your AI client.
|
|
10
10
|
2. **Install the Gecho Chrome extension** and log in to your Gecho account.
|
|
11
|
-
3. **Log in to
|
|
11
|
+
3. **Log in to the target platform in Chrome** and keep the logged-in platform tab open.
|
|
12
12
|
|
|
13
|
-
If any of these are missing,
|
|
13
|
+
If any of these are missing, the selected platform tool may fail even if the Skill or plugin is installed.
|
|
14
14
|
|
|
15
15
|
## 🚀 3-Step Quick Start
|
|
16
16
|
|
|
@@ -125,6 +125,49 @@ A new team Skill also requires at least one team category ID. For an existing Sk
|
|
|
125
125
|
|
|
126
126
|
Official documentation: [CLI installation](https://skillhub.cn/install/skillhub.md), [community publishing](https://skillhub.cn/ai/release.md), [enterprise publishing](https://skillhub.cn/enterprise/dashboard/publish), and [enterprise API keys](https://skillhub.cn/enterprise/dashboard/keys).
|
|
127
127
|
|
|
128
|
+
### WorkBuddy Skill Packaging
|
|
129
|
+
|
|
130
|
+
WorkBuddy uses a separate Skill package format, so a Tencent SkillHub staging copy must not be uploaded directly.
|
|
131
|
+
The repository creates Git-ignored copies under `tmp/workbuddy-publish/`, adds
|
|
132
|
+
`display_name`, `display_name_en`, `description_zh`, `description_en`, `version`, and `author`, and packages
|
|
133
|
+
each Skill using WorkBuddy's official `skills/<skill-name>/SKILL.md` layout.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Create WorkBuddy-only staging copies
|
|
137
|
+
npm run skillhub:workbuddy:stage
|
|
138
|
+
|
|
139
|
+
# Build all English and Chinese ZIPs and validate their structure
|
|
140
|
+
npm run skillhub:workbuddy:dry-run
|
|
141
|
+
|
|
142
|
+
# Prepare one Chinese Skill
|
|
143
|
+
npm run skillhub:workbuddy:dry-run -- \
|
|
144
|
+
--skill tiktok-video-search --locale zh-CN
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
ZIP files are written to `tmp/workbuddy-publish/archives/` (each must be no larger than 3MB) for manual upload to the
|
|
148
|
+
[WorkBuddy Open Platform](https://open.workbuddy.cn/). The script has no login or submit command and never uses
|
|
149
|
+
Tencent SkillHub `skh_...` or `sk-ent-...` credentials. See the official [WorkBuddy Skill documentation](https://open.workbuddy.cn/docs/skill).
|
|
150
|
+
|
|
151
|
+
### WorkBuddy Open Platform Connector
|
|
152
|
+
|
|
153
|
+
WorkBuddy's open platform Connector publication is separate from Skill publication. The Connector ZIP contains the
|
|
154
|
+
platform metadata and the MCP startup configuration; it is not one of the Skill ZIPs above.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Build and validate the Connector ZIP for the current package version
|
|
158
|
+
npm run skillhub:workbuddy:connector:dry-run
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The uploadable file is generated at:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
tmp/workbuddy-connector/gecho-bridge-workbuddy-v1.1.37.zip
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
It uses the public `@gecho-ai/gecho-bridge@1.1.37` npm package as a local Stdio MCP server. The generated ZIP contains
|
|
168
|
+
`connector-meta.json`, `mcp.json`, `icon.svg`, and a concise Connector Skill. It is only staged locally; this command
|
|
169
|
+
does not upload or submit a review request. See the official [WorkBuddy Connector documentation](https://open.workbuddy.cn/docs/connector).
|
|
170
|
+
|
|
128
171
|
### Option 2: One-Click Setup in Hermes (Hermes Skill Hub)
|
|
129
172
|
You can quickly add the service to Hermes and restart it with the following commands:
|
|
130
173
|
```bash
|
|
@@ -167,7 +210,7 @@ After the environment is configured and your AI client has restarted, you can di
|
|
|
167
210
|
### ✅ Self-Check Before First Use
|
|
168
211
|
1. `gecho-bridge` MCP is configured, or the `@gecho-ai/gecho-bridge-bundle` plugin is installed.
|
|
169
212
|
2. The [Gecho browser extension](https://chromewebstore.google.com/detail/pjkaeenpekolahdbccjfenjcmanemlbj?utm_source=item-share-cb) is installed.
|
|
170
|
-
3.
|
|
213
|
+
3. The target platform is open in Chrome and the account is logged in (TikTok, YouTube, Facebook, X, or Amazon as applicable).
|
|
171
214
|
4. The Gecho extension is logged in to a Gecho account and online.
|
|
172
215
|
5. The TikTok page is not stuck or left on a CAPTCHA page.
|
|
173
216
|
|
|
@@ -185,8 +228,9 @@ Focused single-tool Skills are also available:
|
|
|
185
228
|
- **Amazon**: `amazon-search`, `amazon-product`, `amazon-reviews`.
|
|
186
229
|
- **TikTok**: `tiktok-video-search` for keyword-based video search; `tiktok-video` for a specific video’s detail, comments, and replies; `tiktok-influencer`, `tiktok-insight`, `tiktok-product`, and `tiktok-shop-search` for focused workflows.
|
|
187
230
|
- **X**: `x-search` and `x-post-detail`.
|
|
231
|
+
- **Short-form video**: `youtube-shorts-search` for YouTube Shorts and `facebook-reels-search` for Facebook Reels.
|
|
188
232
|
|
|
189
|
-
Use `tiktok-video-search` when you want to discover videos by keyword. Use `tiktok-video` when you already have a video URL and need its detail data. If you want the full TikTok research workflow, use `tiktok-search`.
|
|
233
|
+
Use `tiktok-video-search`, `youtube-shorts-search`, or `facebook-reels-search` when you want to discover short-form videos by keyword. Use `tiktok-video` when you already have a video URL and need its detail data. If you want the full TikTok research workflow, use `tiktok-search`.
|
|
190
234
|
|
|
191
235
|
### 🔍 Basic Search (`tiktok_search`)
|
|
192
236
|
Suitable for quickly retrieving and collecting video data.
|
|
@@ -237,6 +281,8 @@ If installation is successful, you should see `Status: loaded` and `MCP servers:
|
|
|
237
281
|
### 2. Note about the local background service
|
|
238
282
|
- Gecho Bridge automatically starts a local service on demand so the MCP client can talk to the browser extension.
|
|
239
283
|
- This service only listens on `127.0.0.1` and is expected to stay available while you use the plugin.
|
|
284
|
+
- You can also manage it independently with `npm run server:start`, `npm run server:status`, and `npm run server:stop`.
|
|
285
|
+
- To run it after user login, use `npx gecho-bridge-server install`; remove the startup entry with `npx gecho-bridge-server uninstall`.
|
|
240
286
|
- If Chrome or the extension was restarted and requests start failing, first run `openclaw gateway restart`, then try again.
|
|
241
287
|
|
|
242
288
|
### 3. Error: Extension not connected
|
|
@@ -285,6 +331,8 @@ npm run server
|
|
|
285
331
|
- **Client layer** (`mcp-client.js`): The standard MCP STDIO integration layer, responsible for communicating with clients such as OpenClaw, Hermes, and Trae, and declaring the Tools specification.
|
|
286
332
|
- **Service layer** (`server.js`): The local resident service layer, responsible for communicating with the browser extension via WebSocket and executing the actual scraping and persistence. (Supports a Lazy Start mechanism and launches only when needed.)
|
|
287
333
|
|
|
334
|
+
See [`docs/scheduled-flywheel-bridge.md`](docs/scheduled-flywheel-bridge.md) for scheduled flywheel APIs, standalone Bridge operation, and user-level login startup.
|
|
335
|
+
|
|
288
336
|
## License
|
|
289
337
|
|
|
290
338
|
MIT
|
package/README.zh.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Gecho Bridge 🚀
|
|
2
2
|
|
|
3
|
-
**Gecho Bridge 通过 MCP 和 Gecho Chrome 扩展,把 OpenClaw、Hermes、Trae、Claude Code 等 AI 客户端连接到真实 Chrome 浏览器。** 你可以用它搜索 TikTok
|
|
3
|
+
**Gecho Bridge 通过 MCP 和 Gecho Chrome 扩展,把 OpenClaw、Hermes、Trae、Claude Code 等 AI 客户端连接到真实 Chrome 浏览器。** 你可以用它搜索 TikTok 视频、YouTube Shorts、Facebook Reels、X 帖子和 Amazon 商品,采集结构化元数据、保存 JSON 结果,并运行异步的产品、趋势、竞品和内容洞察工作流。
|
|
4
4
|
|
|
5
5
|
## ⚠️ 重要前置:使用前必看
|
|
6
6
|
|
|
7
|
-
Gecho Bridge 不能只靠 README、Skill 页面或 MCP
|
|
7
|
+
Gecho Bridge 不能只靠 README、Skill 页面或 MCP 配置单独运行。首次搜索平台内容或运行洞察任务前,必须同时满足下面 3 个条件:
|
|
8
8
|
|
|
9
9
|
1. **在 AI 客户端中配置 Gecho Bridge MCP**。
|
|
10
10
|
2. **安装 Gecho Chrome 扩展**,并在扩展中登录 Gecho 账号。
|
|
11
|
-
3. **在 Chrome
|
|
11
|
+
3. **在 Chrome 中登录目标平台**,并保持已登录的平台标签页打开。
|
|
12
12
|
|
|
13
|
-
如果任一条件缺失,即使 Skill 或 Plugin
|
|
13
|
+
如果任一条件缺失,即使 Skill 或 Plugin 已安装,所选平台的搜索功能也可能无法正常运行。
|
|
14
14
|
|
|
15
15
|
## 🚀 3 步快速上手
|
|
16
16
|
|
|
@@ -125,6 +125,54 @@ npm run skillhub:tencent:publish -- \
|
|
|
125
125
|
|
|
126
126
|
官方文档:[CLI 安装](https://skillhub.cn/install/skillhub.md)、[公共发布](https://skillhub.cn/ai/release.md)、[企业发布控制台](https://skillhub.cn/enterprise/dashboard/publish)、[企业 API Key](https://skillhub.cn/enterprise/dashboard/keys)。
|
|
127
127
|
|
|
128
|
+
### WorkBuddy Skill 发布准备
|
|
129
|
+
|
|
130
|
+
WorkBuddy 使用独立的 Skill 包格式,不能直接上传腾讯 SkillHub 副本。项目会从源 Skill 创建被 Git 忽略的
|
|
131
|
+
`tmp/workbuddy-publish/` 副本,补齐 `display_name`、`display_name_en`、`description_zh`、
|
|
132
|
+
`description_en`、`version` 和 `author`,并按 WorkBuddy 官方要求使用
|
|
133
|
+
`skills/<skill-name>/SKILL.md` 目录结构打包。
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# 只生成 WorkBuddy 临时副本
|
|
137
|
+
npm run skillhub:workbuddy:stage
|
|
138
|
+
|
|
139
|
+
# 生成全部中英文 ZIP,并进行本地结构校验
|
|
140
|
+
npm run skillhub:workbuddy:dry-run
|
|
141
|
+
|
|
142
|
+
# 只准备一个中文 Skill
|
|
143
|
+
npm run skillhub:workbuddy:dry-run -- \
|
|
144
|
+
--skill tiktok-video-search --locale zh-CN
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
输出的 ZIP 位于 `tmp/workbuddy-publish/archives/`(单个不超过 3MB),可在 [WorkBuddy 开放平台](https://open.workbuddy.cn/)
|
|
148
|
+
手动上传。脚本没有登录或自动提交功能,不会使用腾讯 SkillHub 的 `skh_...` 或 `sk-ent-...` Key。
|
|
149
|
+
WorkBuddy 官方格式参考:[Skill 文档](https://open.workbuddy.cn/docs/skill)。
|
|
150
|
+
|
|
151
|
+
### Aily SkillHub 发布
|
|
152
|
+
|
|
153
|
+
Aily 当前通过网页上传 Skill 压缩包。项目提供了浏览器自动化脚本,复用已登录的 Edge,
|
|
154
|
+
从 `tmp/manual-skill-packages/manifest.tsv` 读取压缩包,并使用每个 Skill 的
|
|
155
|
+
`publish.json` 中 `platforms.aily-skillhub.displayName` 自动填写展示名称。
|
|
156
|
+
|
|
157
|
+
首次使用需要完全退出 Edge 后,以远程调试端口启动,再在该窗口登录 Aily:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
/Applications/Microsoft\ Edge.app/Contents/MacOS/Microsoft\ Edge \
|
|
161
|
+
--remote-debugging-port=9222
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
然后执行:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npm run skill:package:manual
|
|
168
|
+
npm run skillhub:aily:dry-run -- --skill tiktok-shop-search --locale zh-CN
|
|
169
|
+
npm run skillhub:aily:publish -- --skill tiktok-shop-search --locale zh-CN
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
脚本只修改网页表单,不修改源 Skill,也不保存浏览器凭证;发布结果写入
|
|
173
|
+
`tmp/aily-browser-publish/results.json`。完整参数和批量发布方式见
|
|
174
|
+
[`scripts/README.md`](scripts/README.md)。
|
|
175
|
+
|
|
128
176
|
### 方式二:在 Hermes 中一键配置 (Hermes Skill Hub)
|
|
129
177
|
你可以通过以下命令将服务快捷添加到 Hermes 并重启:
|
|
130
178
|
```bash
|
|
@@ -167,7 +215,7 @@ claude mcp add gecho-bridge -- npx -y @gecho-ai/gecho-bridge@latest
|
|
|
167
215
|
### ✅ 首次使用前自检
|
|
168
216
|
1. 已配置 `gecho-bridge` MCP,或已安装 `@gecho-ai/gecho-bridge-bundle` Plugin。
|
|
169
217
|
2. 已安装 [Gecho 浏览器扩展](https://chromewebstore.google.com/detail/pjkaeenpekolahdbccjfenjcmanemlbj?utm_source=item-share-cb)。
|
|
170
|
-
3. Chrome
|
|
218
|
+
3. Chrome 中已打开目标平台并登录账号(按任务选择 TikTok、YouTube、Facebook、X 或 Amazon)。
|
|
171
219
|
4. Gecho 扩展已登录 Gecho 账号并处于在线状态。
|
|
172
220
|
5. TikTok 页面未卡住或未停在验证码页面。
|
|
173
221
|
|
|
@@ -185,8 +233,9 @@ Gecho 提供四个聚合 Skill:
|
|
|
185
233
|
- **Amazon**:`amazon-search`、`amazon-product`、`amazon-reviews`。
|
|
186
234
|
- **TikTok**:`tiktok-video-search` 用于按关键词搜索视频;`tiktok-video` 用于指定视频的详情、评论和回复;另有 `tiktok-influencer`、`tiktok-insight`、`tiktok-product` 和 `tiktok-shop-search`。
|
|
187
235
|
- **X**:`x-search` 和 `x-post-detail`。
|
|
236
|
+
- **短视频**:`youtube-shorts-search` 用于 YouTube Shorts,`facebook-reels-search` 用于 Facebook Reels。
|
|
188
237
|
|
|
189
|
-
|
|
238
|
+
需要按关键词发现短视频时使用 `tiktok-video-search`、`youtube-shorts-search` 或 `facebook-reels-search`;已有视频 URL、需要获取视频详情时使用 `tiktok-video`。需要完整 TikTok 研究工作流时,使用 `tiktok-search`。
|
|
190
239
|
|
|
191
240
|
### 🔍 基础搜索 (`tiktok_search`)
|
|
192
241
|
适用于快速检索和收集视频数据。
|
|
@@ -237,6 +286,8 @@ openclaw plugins info @gecho-ai/gecho-bridge-bundle
|
|
|
237
286
|
### 2. 关于本地后台服务的说明
|
|
238
287
|
- Gecho Bridge 会在需要时自动拉起本地服务,用来让 MCP 客户端和浏览器扩展通信。
|
|
239
288
|
- 这个服务只监听 `127.0.0.1`,在你使用插件期间保持可用属于正常行为。
|
|
289
|
+
- 也可以独立管理服务:`npm run server:start`、`npm run server:status`、`npm run server:stop`。
|
|
290
|
+
- 如需用户登录后自动运行,可执行 `npx gecho-bridge-server install`;卸载启动项执行 `npx gecho-bridge-server uninstall`。
|
|
240
291
|
- 如果你重启了 Chrome 或扩展,随后请求开始失败,先执行一次 `openclaw gateway restart`,再重试。
|
|
241
292
|
|
|
242
293
|
### 3. 报错:提示扩展未连接
|
|
@@ -285,6 +336,8 @@ npm run server
|
|
|
285
336
|
- **Client 层** (`mcp-client.js`):标准 MCP STDIO 接入层,负责与 OpenClaw/Hermes/Trae 等客户端通信,并声明 Tools 规范。
|
|
286
337
|
- **Service 层** (`server.js`):本地常驻服务层,负责与浏览器扩展通过 WebSocket 通信,执行实际抓取与落盘。(支持 Lazy Start 机制,仅在需要时自动拉起)。
|
|
287
338
|
|
|
339
|
+
自动飞轮的定时任务接口、Bridge 独立运行和用户级开机启动说明见 [`docs/scheduled-flywheel-bridge.md`](docs/scheduled-flywheel-bridge.md)。
|
|
340
|
+
|
|
288
341
|
## License
|
|
289
342
|
|
|
290
343
|
MIT
|
package/action-result.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const ACTION_RESULT_METADATA_FIELDS = ["meta", "errorCode", "errorMessage"];
|
|
2
|
+
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function hasOwn(value, key) {
|
|
8
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getActionResultMetadata(result) {
|
|
12
|
+
const metadata = {};
|
|
13
|
+
if (!isRecord(result)) return metadata;
|
|
14
|
+
|
|
15
|
+
for (const field of ACTION_RESULT_METADATA_FIELDS) {
|
|
16
|
+
if (hasOwn(result, field)) metadata[field] = result[field];
|
|
17
|
+
}
|
|
18
|
+
return metadata;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createActionResultEnvelope(message) {
|
|
22
|
+
const source = isRecord(message) ? message : {};
|
|
23
|
+
return {
|
|
24
|
+
data: source.data,
|
|
25
|
+
...getActionResultMetadata(source)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function normalizeActionResult(result) {
|
|
30
|
+
if (!isRecord(result) || !hasOwn(result, "data")) return { data: result };
|
|
31
|
+
return {
|
|
32
|
+
data: result.data,
|
|
33
|
+
...getActionResultMetadata(result)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isHardActionResultFailure(result) {
|
|
38
|
+
if (!isRecord(result)) return false;
|
|
39
|
+
|
|
40
|
+
const hasFailure = ["errorCode", "errorMessage"].some((field) => {
|
|
41
|
+
return hasOwn(result, field) && result[field] !== undefined && result[field] !== null && result[field] !== "";
|
|
42
|
+
});
|
|
43
|
+
if (!hasFailure) return false;
|
|
44
|
+
|
|
45
|
+
return String(result.meta?.status || "").toLowerCase() !== "partial";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
createActionResultEnvelope,
|
|
50
|
+
getActionResultMetadata,
|
|
51
|
+
isHardActionResultFailure,
|
|
52
|
+
normalizeActionResult
|
|
53
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
"use strict";
|
|
4
|
+
|
|
5
|
+
const http = require("node:http");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
const { spawn } = require("node:child_process");
|
|
8
|
+
const packageJson = require("./package.json");
|
|
9
|
+
const { getDefaultDataDir } = require("./data-dir");
|
|
10
|
+
const {
|
|
11
|
+
getStartupStatus,
|
|
12
|
+
installStartup,
|
|
13
|
+
uninstallStartup
|
|
14
|
+
} = require("./bridge-startup");
|
|
15
|
+
|
|
16
|
+
const HTTP_PORT = Number(process.env.GECHO_HTTP_PORT || 18793);
|
|
17
|
+
const SERVICE_BASE_URL = `http://127.0.0.1:${HTTP_PORT}`;
|
|
18
|
+
const SERVICE_PATH = path.join(__dirname, "server.js");
|
|
19
|
+
const SERVICE_PROTOCOL_VERSION = 2;
|
|
20
|
+
const START_TIMEOUT_MS = Math.max(1000, Number(process.env.GECHO_SERVICE_START_TIMEOUT_MS || 10000));
|
|
21
|
+
const POLL_INTERVAL_MS = 200;
|
|
22
|
+
|
|
23
|
+
function requestJson(requestPath, method = "GET") {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const request = http.request(`${SERVICE_BASE_URL}${requestPath}`, { method }, (response) => {
|
|
26
|
+
let body = "";
|
|
27
|
+
response.setEncoding("utf8");
|
|
28
|
+
response.on("data", (chunk) => { body += chunk; });
|
|
29
|
+
response.on("end", () => {
|
|
30
|
+
let parsed = {};
|
|
31
|
+
try { parsed = JSON.parse(body || "{}"); } catch (_error) {}
|
|
32
|
+
resolve({
|
|
33
|
+
ok: response.statusCode >= 200 && response.statusCode < 300,
|
|
34
|
+
statusCode: response.statusCode || 0,
|
|
35
|
+
body: parsed
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
request.on("error", () => resolve({ ok: false, statusCode: 0, body: {} }));
|
|
40
|
+
request.setTimeout(800, () => {
|
|
41
|
+
request.destroy();
|
|
42
|
+
resolve({ ok: false, statusCode: 0, body: {} });
|
|
43
|
+
});
|
|
44
|
+
request.end();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function expectedDataDir() {
|
|
49
|
+
return path.resolve(process.env.GECHO_DATA_DIR || getDefaultDataDir());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isCompatibleService(info) {
|
|
53
|
+
if (!info || info.status !== "ok") return false;
|
|
54
|
+
if (Number(info.serviceProtocolVersion || 0) !== SERVICE_PROTOCOL_VERSION) return false;
|
|
55
|
+
if (info.packageVersion && info.packageVersion !== packageJson.version) return false;
|
|
56
|
+
return !info.dataDir || path.resolve(String(info.dataDir)) === expectedDataDir();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function getServiceInfo() {
|
|
60
|
+
const response = await requestJson("/ping");
|
|
61
|
+
return response.ok ? response.body : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function waitForService({ running = true, timeoutMs = START_TIMEOUT_MS } = {}) {
|
|
65
|
+
const startedAt = Date.now();
|
|
66
|
+
while (Date.now() - startedAt <= timeoutMs) {
|
|
67
|
+
const info = await getServiceInfo();
|
|
68
|
+
if (running ? isCompatibleService(info) : !info) return info;
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function stopService() {
|
|
75
|
+
const info = await getServiceInfo();
|
|
76
|
+
if (!info) return { status: "not running" };
|
|
77
|
+
|
|
78
|
+
await requestJson("/shutdown", "POST");
|
|
79
|
+
const stopped = await waitForService({ running: false });
|
|
80
|
+
if (stopped === null && Number.isInteger(Number(info.pid)) && Number(info.pid) > 0) {
|
|
81
|
+
try { process.kill(Number(info.pid), "SIGTERM"); } catch (_error) {}
|
|
82
|
+
await waitForService({ running: false, timeoutMs: 3000 });
|
|
83
|
+
}
|
|
84
|
+
return { status: "stopped", pid: info.pid || null };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function startService() {
|
|
88
|
+
const current = await getServiceInfo();
|
|
89
|
+
if (isCompatibleService(current)) {
|
|
90
|
+
return { status: "already running", pid: current.pid || null };
|
|
91
|
+
}
|
|
92
|
+
if (current) await stopService();
|
|
93
|
+
|
|
94
|
+
const child = spawn(process.execPath, [SERVICE_PATH], {
|
|
95
|
+
cwd: __dirname,
|
|
96
|
+
env: process.env,
|
|
97
|
+
detached: true,
|
|
98
|
+
stdio: "ignore",
|
|
99
|
+
windowsHide: true
|
|
100
|
+
});
|
|
101
|
+
child.unref();
|
|
102
|
+
const started = await waitForService();
|
|
103
|
+
if (!started) {
|
|
104
|
+
const error = new Error("Bridge service did not become ready");
|
|
105
|
+
error.code = "BRIDGE_SERVICE_START_FAILED";
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
return { status: "started", pid: started.pid || child.pid || null };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function printStatus() {
|
|
112
|
+
const info = await getServiceInfo();
|
|
113
|
+
if (info) {
|
|
114
|
+
process.stdout.write(`${JSON.stringify(info)}\n`);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
process.stdout.write(`${JSON.stringify({ status: "not running", url: SERVICE_BASE_URL })}\n`);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function printUsage() {
|
|
122
|
+
process.stdout.write([
|
|
123
|
+
"Usage: gecho-bridge-server <start|status|stop|restart|install|uninstall|startup-status>",
|
|
124
|
+
"",
|
|
125
|
+
" start Start the standalone local Bridge service",
|
|
126
|
+
" status Print Bridge health and scheduler status",
|
|
127
|
+
" stop Stop the local Bridge service",
|
|
128
|
+
" restart Restart the local Bridge service",
|
|
129
|
+
" install Install a user-level login startup entry",
|
|
130
|
+
" uninstall Remove the user-level login startup entry",
|
|
131
|
+
" startup-status Print login startup configuration status",
|
|
132
|
+
""
|
|
133
|
+
].join("\n"));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function main(argv = process.argv.slice(2)) {
|
|
137
|
+
const command = String(argv[0] || "start").trim().toLowerCase();
|
|
138
|
+
if (command === "status") {
|
|
139
|
+
const running = await printStatus();
|
|
140
|
+
process.exitCode = running ? 0 : 1;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (command === "start") {
|
|
144
|
+
process.stdout.write(`${JSON.stringify(await startService())}\n`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (command === "stop") {
|
|
148
|
+
process.stdout.write(`${JSON.stringify(await stopService())}\n`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (command === "restart") {
|
|
152
|
+
await stopService();
|
|
153
|
+
process.stdout.write(`${JSON.stringify(await startService())}\n`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (command === "install") {
|
|
157
|
+
process.stdout.write(`${JSON.stringify(installStartup())}\n`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (command === "uninstall") {
|
|
161
|
+
process.stdout.write(`${JSON.stringify(uninstallStartup())}\n`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (command === "startup-status") {
|
|
165
|
+
const status = getStartupStatus();
|
|
166
|
+
process.stdout.write(`${JSON.stringify(status)}\n`);
|
|
167
|
+
process.exitCode = status.configured ? 0 : 1;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
printUsage();
|
|
171
|
+
process.exitCode = 2;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (require.main === module) {
|
|
175
|
+
main().catch((error) => {
|
|
176
|
+
console.error(`gecho-bridge-server: ${error.message || error}`);
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = {
|
|
182
|
+
getServiceInfo,
|
|
183
|
+
isCompatibleService,
|
|
184
|
+
main,
|
|
185
|
+
startService,
|
|
186
|
+
stopService
|
|
187
|
+
};
|