hvip-mcp-server 0.2.42 → 0.2.43

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.
Files changed (3) hide show
  1. package/README.md +101 -101
  2. package/dist/index.js +520 -42
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,101 +1,101 @@
1
- # hvip MCP Server
2
-
3
- > OKX API 全景图 —— 让任何 AI Agent 都能使用 OKX 的全部能力。
4
-
5
- [![npm version](https://img.shields.io/npm/v/hvip-mcp-server)](https://www.npmjs.com/package/hvip-mcp-server)
6
- [![License](https://img.shields.io/npm/l/hvip-mcp-server)](https://github.com/okx-wallet-H/hvip-mcp/blob/master/LICENSE)
7
- [![GitHub stars](https://img.shields.io/github/stars/okx-wallet-H/hvip-mcp)](https://github.com/okx-wallet-H/hvip-mcp)
8
-
9
- 📦 **仓库**: [github.com/okx-wallet-H/hvip-mcp](https://github.com/okx-wallet-H/hvip-mcp)
10
- 🐛 **Issue**: [提交反馈](https://github.com/okx-wallet-H/hvip-mcp/issues/new)
11
- 📖 **贡献**: [CONTRIBUTING.md](./CONTRIBUTING.md)
12
-
13
- ---
14
-
15
- ## 快速开始
16
-
17
- ### 1. Claude Desktop 接入
18
-
19
- 在 Claude Desktop 配置中添加:
20
-
21
- ```json
22
- {
23
- "mcpServers": {
24
- "hvip-mcp": {
25
- "command": "npx",
26
- "args": ["-y", "hvip-mcp-server"],
27
- "env": {
28
- "OKX_API_KEY": "<你的API Key>",
29
- "OKX_SECRET_KEY": "<你的Secret Key>",
30
- "OKX_PASSPHRASE": "<你的Passphrase>"
31
- }
32
- }
33
- }
34
- }
35
- ```
36
-
37
- ### 2. 直接运行
38
-
39
- ```bash
40
- npx hvip-mcp-server
41
- ```
42
-
43
- ### 3. 本地开发
44
-
45
- ```bash
46
- git clone https://github.com/okx-wallet-H/hvip-mcp.git
47
- cd hvip-mcp
48
- npm install
49
- npm run build
50
- npm start
51
- ```
52
-
53
- ---
54
-
55
- ## 工具覆盖
56
-
57
- | 模块 | 工具数 | 说明 |
58
- |------|--------|------|
59
- | 🔹 **交易类** | 40+ | 下单/撤单/改单/批量/策略委托 |
60
- | 🔹 **行情类** | 30+ | Ticker/K线/深度/资金费率/标记价 |
61
- | 🔹 **数据类** | 50+ | 产品信息/多空比/买卖量/PCR/统计数据 |
62
- | 🔹 **资金类** | 40+ | 划转/提现/充值/余额/持仓/杠杆 |
63
- | 🔹 **策略类** | 20+ | 网格/信号/跟单/价差/RFQ |
64
- | 🔹 **金融类** | 15+ | 赚币/质押/借贷/法币 |
65
- | 🔹 **预测市场** | 9+ | 事件/市场/深度/套利检测 |
66
- | 🔹 **Skill 组合** | 4 | 账户全景/市场速览/下单预检/反馈 |
67
-
68
- **304 个 MCP 工具 · 覆盖 97.7% OKX REST API · P0 P1 全部清零**
69
-
70
- ---
71
-
72
- ## 架构
73
-
74
- ```
75
- 原子层 (300+ 工具) → AI Agent 直接调用
76
-
77
- Skill 组合层 (4 个) → 串联多工具,一次完成复杂任务
78
-
79
- 反馈通道 → GitHub Issues → 新 Skill 需求 → AI Agent 自行实现并提 PR
80
- ```
81
-
82
- ---
83
-
84
- ## 贡献
85
-
86
- AI Agent 或开发者都可以贡献 Skill:
87
-
88
- 1. 阅读 [`CLAUDE.md`](./CLAUDE.md) 了解项目规范
89
- 2. 阅读 [`CONTRIBUTING.md`](./CONTRIBUTING.md) 了解提交流程
90
- 3. Fork → 创建 Skill → 提 PR → Review → 合并
91
-
92
- 每个 Skill 串联多个原子工具,解决一个具体的使用场景。
93
-
94
- ---
95
-
96
- ## 文档
97
-
98
- - [`CLAUDE.md`](./CLAUDE.md) — AI Agent 项目指南
99
- - [`CONTRIBUTING.md`](./CONTRIBUTING.md) — Skill 贡献流程
100
- - [`docs/OKX-MCP-API对接标准-v0.1.8.md`](./docs/OKX-MCP-API对接标准-v0.1.8.md) — API 对接规范
101
- - [`docs/OKX-MCP-防幻觉对接SOP-v1.0.md`](./docs/OKX-MCP-防幻觉对接SOP-v1.0.md) — 防幻觉 SOP
1
+ # hvip MCP Server
2
+
3
+ > OKX API 全景图 —— 让任何 AI Agent 都能使用 OKX 的全部能力。
4
+
5
+ [![npm version](https://img.shields.io/npm/v/hvip-mcp-server)](https://www.npmjs.com/package/hvip-mcp-server)
6
+ [![License](https://img.shields.io/npm/l/hvip-mcp-server)](https://github.com/okx-wallet-H/hvip-mcp/blob/master/LICENSE)
7
+ [![GitHub stars](https://img.shields.io/github/stars/okx-wallet-H/hvip-mcp)](https://github.com/okx-wallet-H/hvip-mcp)
8
+
9
+ 📦 **仓库**: [github.com/okx-wallet-H/hvip-mcp](https://github.com/okx-wallet-H/hvip-mcp)
10
+ 🐛 **Issue**: [提交反馈](https://github.com/okx-wallet-H/hvip-mcp/issues/new)
11
+ 📖 **贡献**: [CONTRIBUTING.md](./CONTRIBUTING.md)
12
+
13
+ ---
14
+
15
+ ## 快速开始
16
+
17
+ ### 1. Claude Desktop 接入
18
+
19
+ 在 Claude Desktop 配置中添加:
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "hvip-mcp": {
25
+ "command": "npx",
26
+ "args": ["-y", "hvip-mcp-server"],
27
+ "env": {
28
+ "OKX_API_KEY": "<你的API Key>",
29
+ "OKX_SECRET_KEY": "<你的Secret Key>",
30
+ "OKX_PASSPHRASE": "<你的Passphrase>"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### 2. 直接运行
38
+
39
+ ```bash
40
+ npx hvip-mcp-server
41
+ ```
42
+
43
+ ### 3. 本地开发
44
+
45
+ ```bash
46
+ git clone https://github.com/okx-wallet-H/hvip-mcp.git
47
+ cd hvip-mcp
48
+ npm install
49
+ npm run build
50
+ npm start
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 工具覆盖
56
+
57
+ | 模块 | 工具数 | 说明 |
58
+ |------|--------|------|
59
+ | 🔹 **交易类** | 40+ | 下单/撤单/改单/批量/策略委托 |
60
+ | 🔹 **行情类** | 30+ | Ticker/K线/深度/资金费率/标记价 |
61
+ | 🔹 **数据类** | 50+ | 产品信息/多空比/买卖量/PCR/统计数据 |
62
+ | 🔹 **资金类** | 40+ | 划转/提现/充值/余额/持仓/杠杆 |
63
+ | 🔹 **策略类** | 20+ | 网格/信号/跟单/价差/RFQ |
64
+ | 🔹 **金融类** | 15+ | 赚币/质押/借贷/法币 |
65
+ | 🔹 **预测市场** | 9+ | 事件/市场/深度/套利检测 |
66
+ | 🔹 **Skill 组合** | 4 | 账户全景/市场速览/下单预检/反馈 |
67
+
68
+ **304 个 MCP 工具 · 覆盖 97.7% OKX REST API · P0 P1 全部清零**
69
+
70
+ ---
71
+
72
+ ## 架构
73
+
74
+ ```
75
+ 原子层 (300+ 工具) → AI Agent 直接调用
76
+
77
+ Skill 组合层 (4 个) → 串联多工具,一次完成复杂任务
78
+
79
+ 反馈通道 → GitHub Issues → 新 Skill 需求 → AI Agent 自行实现并提 PR
80
+ ```
81
+
82
+ ---
83
+
84
+ ## 贡献
85
+
86
+ AI Agent 或开发者都可以贡献 Skill:
87
+
88
+ 1. 阅读 [`CLAUDE.md`](./CLAUDE.md) 了解项目规范
89
+ 2. 阅读 [`CONTRIBUTING.md`](./CONTRIBUTING.md) 了解提交流程
90
+ 3. Fork → 创建 Skill → 提 PR → Review → 合并
91
+
92
+ 每个 Skill 串联多个原子工具,解决一个具体的使用场景。
93
+
94
+ ---
95
+
96
+ ## 文档
97
+
98
+ - [`CLAUDE.md`](./CLAUDE.md) — AI Agent 项目指南
99
+ - [`CONTRIBUTING.md`](./CONTRIBUTING.md) — Skill 贡献流程
100
+ - [`docs/OKX-MCP-API对接标准-v0.1.8.md`](./docs/OKX-MCP-API对接标准-v0.1.8.md) — API 对接规范
101
+ - [`docs/OKX-MCP-防幻觉对接SOP-v1.0.md`](./docs/OKX-MCP-防幻觉对接SOP-v1.0.md) — 防幻觉 SOP
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __commonJS = (cb, mod) => function __require() {
10
13
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
14
  };
@@ -10565,6 +10568,34 @@ var require_websocket_server = __commonJS({
10565
10568
  }
10566
10569
  });
10567
10570
 
10571
+ // node_modules/ws/wrapper.mjs
10572
+ var wrapper_exports = {};
10573
+ __export(wrapper_exports, {
10574
+ PerMessageDeflate: () => import_permessage_deflate.default,
10575
+ Receiver: () => import_receiver.default,
10576
+ Sender: () => import_sender.default,
10577
+ WebSocket: () => import_websocket.default,
10578
+ WebSocketServer: () => import_websocket_server.default,
10579
+ createWebSocketStream: () => import_stream.default,
10580
+ default: () => wrapper_default,
10581
+ extension: () => import_extension.default,
10582
+ subprotocol: () => import_subprotocol.default
10583
+ });
10584
+ var import_stream, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
10585
+ var init_wrapper = __esm({
10586
+ "node_modules/ws/wrapper.mjs"() {
10587
+ import_stream = __toESM(require_stream(), 1);
10588
+ import_extension = __toESM(require_extension(), 1);
10589
+ import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
10590
+ import_receiver = __toESM(require_receiver(), 1);
10591
+ import_sender = __toESM(require_sender(), 1);
10592
+ import_subprotocol = __toESM(require_subprotocol(), 1);
10593
+ import_websocket = __toESM(require_websocket(), 1);
10594
+ import_websocket_server = __toESM(require_websocket_server(), 1);
10595
+ wrapper_default = import_websocket.default;
10596
+ }
10597
+ });
10598
+
10568
10599
  // node_modules/zod/v3/external.js
10569
10600
  var external_exports = {};
10570
10601
  __export(external_exports, {
@@ -29728,7 +29759,7 @@ function registerOutcomesTools(server) {
29728
29759
  );
29729
29760
  server.tool(
29730
29761
  "okx_predictions_split",
29731
- "## \u529F\u80FD\uFF1A\u5C06 xp \u62C6\u5206\u4E3A YES \u548C NO \u4EE3\u5E01\n## \u573A\u666F\uFF1A\u62C6\u5206\u8D44\u91D1\u5230 YES/NO \u53CC\u65B9\u5411\uFF0C\u53C2\u4E0E\u9884\u6D4B\u5E02\u573A\n## \u5173\u952E\u8BCD\uFF1A\u62C6\u5206, split, xp, YES, NO\n## \u53C2\u6570\uFF1A\n## - amount: \u62C6\u5206\u6570\u91CF\uFF08\u5FC5\u586B\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08EIP-712\uFF09\n## \u98CE\u9669\uFF1AWRITE \u2014 \u8D44\u91D1\u64CD\u4F5C\uFF0C\u9700\u7528\u6237\u786E\u8BA4\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1Aokx_predictions_balance \u67E5\u4F59\u989D \u2192 \u672C\u5DE5\u5177\u62C6\u5206",
29762
+ "## \u529F\u80FD\uFF1A\u5C06 xp \u62C6\u5206\u4E3A YES \u548C NO \u4EE3\u5E01\n## \u573A\u666F\uFF1A\u62C6\u5206\u8D44\u91D1\u5230 YES/NO \u53CC\u65B9\u5411\uFF0C\u53C2\u4E0E\u9884\u6D4B\u5E02\u573A\n## \u5173\u952E\u8BCD\uFF1A\u62C6\u5206, split, xp\n## \u53C2\u6570\uFF1A\n## - amount: \u62C6\u5206\u6570\u91CF\uFF08\u5FC5\u586B\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08EIP-712\uFF09\n## \u98CE\u9669\uFF1AWRITE \u2014 \u8D44\u91D1\u64CD\u4F5C\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1Aokx_predictions_balance \u2192 \u672C\u5DE5\u5177",
29732
29763
  { amount: external_exports.string().describe("\u62C6\u5206\u6570\u91CF\uFF08\u5FC5\u586B\uFF09") },
29733
29764
  async ({ amount }) => {
29734
29765
  const auth = getAuth();
@@ -29743,7 +29774,7 @@ function registerOutcomesTools(server) {
29743
29774
  );
29744
29775
  server.tool(
29745
29776
  "okx_predictions_merge",
29746
- "## \u529F\u80FD\uFF1A\u5C06 YES+NO \u5408\u5E76\u4E3A xp\n## \u573A\u666F\uFF1A\u9000\u51FA\u9884\u6D4B\u5E02\u573A\u4ED3\u4F4D\uFF0C\u56DE\u6536\u8D44\u91D1\n## \u5173\u952E\u8BCD\uFF1A\u5408\u5E76, merge, YES, NO, xp\n## \u53C2\u6570\uFF1A\n## - amount: \u5408\u5E76\u6570\u91CF\uFF08\u5FC5\u586B\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08EIP-712\uFF09\n## \u98CE\u9669\uFF1AWRITE \u2014 \u8D44\u91D1\u64CD\u4F5C\uFF0C\u9700\u7528\u6237\u786E\u8BA4\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1Aokx_predictions_split \u62C6\u5206 \u2192 \u672C\u5DE5\u5177\u5408\u5E76",
29777
+ "## \u529F\u80FD\uFF1A\u5C06 YES+NO \u5408\u5E76\u4E3A xp\n## \u573A\u666F\uFF1A\u9000\u51FA\u9884\u6D4B\u5E02\u573A\u4ED3\u4F4D\uFF0C\u56DE\u6536\u8D44\u91D1\n## \u5173\u952E\u8BCD\uFF1A\u5408\u5E76, merge, xp\n## \u53C2\u6570\uFF1A\n## - amount: \u5408\u5E76\u6570\u91CF\uFF08\u5FC5\u586B\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08EIP-712\uFF09\n## \u98CE\u9669\uFF1AWRITE \u2014 \u8D44\u91D1\u64CD\u4F5C\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1Aokx_predictions_split \u2192 \u672C\u5DE5\u5177",
29747
29778
  { amount: external_exports.string().describe("\u5408\u5E76\u6570\u91CF\uFF08\u5FC5\u586B\uFF09") },
29748
29779
  async ({ amount }) => {
29749
29780
  const auth = getAuth();
@@ -29758,7 +29789,7 @@ function registerOutcomesTools(server) {
29758
29789
  );
29759
29790
  server.tool(
29760
29791
  "okx_predictions_redeem",
29761
- "## \u529F\u80FD\uFF1A\u7ED3\u7B97\u540E\u8D4E\u56DE\u83B7\u80DC\u4EE3\u5E01\u4E3A xp\n## \u573A\u666F\uFF1A\u4E8B\u4EF6\u7ED3\u7B97\u540E\uFF0C\u5C06\u83B7\u80DC\u7684 YES/NO \u4EE3\u5E01\u6309 1:1 \u5151\u56DE xp\n## \u5173\u952E\u8BCD\uFF1A\u8D4E\u56DE, redeem, \u7ED3\u7B97, \u5151\u56DE\n## \u53C2\u6570\uFF1A\n## - assetId: \u8D44\u4EA7ID\uFF08\u53EF\u9009\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08EIP-712\uFF09\n## \u98CE\u9669\uFF1AWRITE \u2014 \u8D4E\u56DE\u64CD\u4F5C\uFF0C\u9700\u7528\u6237\u786E\u8BA4\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u4E8B\u4EF6\u7ED3\u7B97 \u2192 \u672C\u5DE5\u5177\u8D4E\u56DE \u2192 okx_predictions_balance \u67E5\u4F59\u989D",
29792
+ "## \u529F\u80FD\uFF1A\u7ED3\u7B97\u540E\u8D4E\u56DE\u83B7\u80DC\u4EE3\u5E01\u4E3A xp\n## \u573A\u666F\uFF1A\u4E8B\u4EF6\u7ED3\u7B97\u540E\u5151\u56DE\n## \u5173\u952E\u8BCD\uFF1A\u8D4E\u56DE, redeem, \u7ED3\u7B97\n## \u53C2\u6570\uFF1A\n## - assetId: \u8D44\u4EA7ID\uFF08\u53EF\u9009\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08EIP-712\uFF09\n## \u98CE\u9669\uFF1AWRITE \u2014 \u8D44\u91D1\u64CD\u4F5C\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u4E8B\u4EF6\u7ED3\u7B97 \u2192 \u672C\u5DE5\u5177 \u2192 okx_predictions_balance",
29762
29793
  { assetId: external_exports.string().optional().describe("\u8D44\u4EA7ID") },
29763
29794
  async ({ assetId }) => {
29764
29795
  const auth = getAuth();
@@ -29775,7 +29806,7 @@ function registerOutcomesTools(server) {
29775
29806
  );
29776
29807
  server.tool(
29777
29808
  "okx_predictions_balance",
29778
- "## \u529F\u80FD\uFF1A\u67E5\u8BE2 Outcomes \u8D26\u6237 xp \u4F59\u989D\n## \u573A\u666F\uFF1A\u67E5\u770B\u9884\u6D4B\u5E02\u573A\u53EF\u7528\u8D44\u91D1\n## \u5173\u952E\u8BCD\uFF1A\u4F59\u989D, balance, xp\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08\u53EA\u8BFB\uFF09\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u67E5\u8BE2\uFF0CAgent \u53EF\u81EA\u52A8\u8C03\u7528\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u67E5\u4F59\u989D \u2192 okx_predictions_positions \u770B\u6301\u4ED3",
29809
+ "## \u529F\u80FD\uFF1A\u67E5\u8BE2 Outcomes \u8D26\u6237 xp \u4F59\u989D\n## \u573A\u666F\uFF1A\u67E5\u770B\u9884\u6D4B\u5E02\u573A\u53EF\u7528\u8D44\u91D1\n## \u5173\u952E\u8BCD\uFF1A\u4F59\u989D, balance, xp\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08\u53EA\u8BFB\uFF09\n## \u98CE\u9669\uFF1AREAD\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177 \u2192 okx_predictions_positions",
29779
29810
  {},
29780
29811
  async () => {
29781
29812
  const auth = getAuth();
@@ -29790,7 +29821,7 @@ function registerOutcomesTools(server) {
29790
29821
  );
29791
29822
  server.tool(
29792
29823
  "okx_predictions_trades",
29793
- "## \u529F\u80FD\uFF1A\u67E5\u8BE2 Outcomes \u6210\u4EA4\u8BB0\u5F55\n## \u573A\u666F\uFF1A\u67E5\u770B\u5386\u53F2\u6210\u4EA4\u660E\u7EC6\n## \u5173\u952E\u8BCD\uFF1A\u6210\u4EA4\u8BB0\u5F55, trades, \u5386\u53F2\u6210\u4EA4\n## \u53C2\u6570\uFF1A\n## - marketId: \u5E02\u573AID\uFF08\u53EF\u9009\uFF09\n## - limit: \u8FD4\u56DE\u6761\u6570\uFF08\u53EF\u9009\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08\u53EA\u8BFB\uFF09\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u67E5\u8BE2\uFF0CAgent \u53EF\u81EA\u52A8\u8C03\u7528\n## \u8FD4\u56DE\u91CF\uFF1A\u4E2D\u7B49 ~5KB\n## \u5173\u8054\uFF1Aokx_predictions_positions \u6301\u4ED3 \u2192 \u672C\u5DE5\u5177\u67E5\u770B\u6210\u4EA4",
29824
+ "## \u529F\u80FD\uFF1A\u67E5\u8BE2 Outcomes \u6210\u4EA4\u8BB0\u5F55\n## \u573A\u666F\uFF1A\u67E5\u770B\u5386\u53F2\u6210\u4EA4\u660E\u7EC6\n## \u5173\u952E\u8BCD\uFF1A\u6210\u4EA4\u8BB0\u5F55, trades, \u5386\u53F2\u6210\u4EA4\n## \u53C2\u6570\uFF1A\n## - marketId: \u5E02\u573AID\uFF08\u53EF\u9009\uFF09\n## - limit: \u8FD4\u56DE\u6761\u6570\uFF08\u53EF\u9009\uFF09\n## \u9274\u6743\uFF1A\u9700\u8981 API Key\uFF08\u53EA\u8BFB\uFF09\n## \u98CE\u9669\uFF1AREAD\n## \u8FD4\u56DE\u91CF\uFF1A\u4E2D\u7B49 ~5KB\n## \u5173\u8054\uFF1Aokx_predictions_positions \u2192 \u672C\u5DE5\u5177",
29794
29825
  {
29795
29826
  marketId: external_exports.string().optional().describe("\u5E02\u573AID"),
29796
29827
  limit: external_exports.number().int().min(1).max(100).optional().describe("\u8FD4\u56DE\u6761\u6570")
@@ -31555,18 +31586,8 @@ function registerAgentUtils(server, auth) {
31555
31586
  );
31556
31587
  }
31557
31588
 
31558
- // node_modules/ws/wrapper.mjs
31559
- var import_stream = __toESM(require_stream(), 1);
31560
- var import_extension = __toESM(require_extension(), 1);
31561
- var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
31562
- var import_receiver = __toESM(require_receiver(), 1);
31563
- var import_sender = __toESM(require_sender(), 1);
31564
- var import_subprotocol = __toESM(require_subprotocol(), 1);
31565
- var import_websocket = __toESM(require_websocket(), 1);
31566
- var import_websocket_server = __toESM(require_websocket_server(), 1);
31567
- var wrapper_default = import_websocket.default;
31568
-
31569
31589
  // src/adapters/xlayer-ws.ts
31590
+ init_wrapper();
31570
31591
  var WS_URL = process.env.XLAYER_WS_URL || "wss://xlayerws.okx.com";
31571
31592
  var MAX_EVENTS = 500;
31572
31593
  var XLayerWSManager = class {
@@ -31828,16 +31849,286 @@ function registerXLayerWSTools(server) {
31828
31849
  );
31829
31850
  }
31830
31851
 
31852
+ // src/adapters/ws.ts
31853
+ var import_node_crypto2 = __toESM(require("node:crypto"));
31854
+ var WS_PUBLIC = "wss://ws.okx.com:8443/ws/v5/public";
31855
+ var WS_PRIVATE = "wss://ws.okx.com:8443/ws/v5/private";
31856
+ var subCounter = 0;
31857
+ var WsManager = class {
31858
+ subscriptions = /* @__PURE__ */ new Map();
31859
+ events = [];
31860
+ ws = null;
31861
+ pingTimer = null;
31862
+ channelArgs = /* @__PURE__ */ new Map();
31863
+ // channel -> instIds
31864
+ async subscribe(opts) {
31865
+ const wsModule = await Promise.resolve().then(() => (init_wrapper(), wrapper_exports));
31866
+ const id = `sub_${++subCounter}`;
31867
+ this.subscriptions.set(id, { id, channel: opts.channel, instId: opts.instId });
31868
+ const arg = { channel: opts.channel, instId: opts.instId };
31869
+ if (!this.ws || this.ws.readyState !== wsModule.WebSocket.OPEN) {
31870
+ const url = opts.type === "private" ? WS_PRIVATE : WS_PUBLIC;
31871
+ await this.connect(wsModule, url, opts.auth);
31872
+ }
31873
+ if (this.ws?.readyState === wsModule.WebSocket.OPEN) {
31874
+ this.ws.send(JSON.stringify({ op: "subscribe", args: [arg] }));
31875
+ }
31876
+ const ck = opts.channel;
31877
+ if (!this.channelArgs.has(ck)) this.channelArgs.set(ck, /* @__PURE__ */ new Set());
31878
+ this.channelArgs.get(ck).add(opts.instId);
31879
+ return id;
31880
+ }
31881
+ drain(subId, limit = 20) {
31882
+ let batch;
31883
+ if (subId) {
31884
+ batch = this.events.filter((e) => e.subId === subId);
31885
+ this.events = this.events.filter((e) => e.subId !== subId);
31886
+ } else {
31887
+ batch = this.events.splice(0, limit);
31888
+ }
31889
+ return batch.slice(0, limit);
31890
+ }
31891
+ countBuffered(subId) {
31892
+ if (subId) return this.events.filter((e) => e.subId === subId).length;
31893
+ return this.events.length;
31894
+ }
31895
+ countAllBuffered() {
31896
+ return this.events.length;
31897
+ }
31898
+ getStatus() {
31899
+ return [...this.subscriptions.values()].map((s) => ({
31900
+ id: s.id,
31901
+ active: true,
31902
+ channel: s.channel,
31903
+ instId: s.instId,
31904
+ buffered: this.countBuffered(s.id)
31905
+ }));
31906
+ }
31907
+ close(subId) {
31908
+ if (subId) {
31909
+ this.subscriptions.delete(subId);
31910
+ this.events = this.events.filter((e) => e.subId !== subId);
31911
+ return 1;
31912
+ }
31913
+ const count = this.subscriptions.size;
31914
+ this.subscriptions.clear();
31915
+ this.events = [];
31916
+ if (this.ws) {
31917
+ try {
31918
+ this.ws.close();
31919
+ } catch {
31920
+ }
31921
+ ;
31922
+ this.ws = null;
31923
+ }
31924
+ if (this.pingTimer) {
31925
+ clearInterval(this.pingTimer);
31926
+ this.pingTimer = null;
31927
+ }
31928
+ return count;
31929
+ }
31930
+ connect(wsModule, url, auth) {
31931
+ return new Promise((resolve, reject) => {
31932
+ const ws = new wsModule.WebSocket(url);
31933
+ const timeout = setTimeout(() => {
31934
+ ws.close();
31935
+ reject(new Error("WS \u8FDE\u63A5\u8D85\u65F6(10s)"));
31936
+ }, 1e4);
31937
+ ws.on("open", () => {
31938
+ clearTimeout(timeout);
31939
+ if (auth && url.includes("private")) {
31940
+ const ts = Math.floor(Date.now() / 1e3).toString();
31941
+ const sign2 = import_node_crypto2.default.createHmac("sha256", auth.secret).update(ts + "GET/users/self/verify").digest("base64");
31942
+ ws.send(JSON.stringify({
31943
+ op: "login",
31944
+ args: [{ apiKey: auth.apiKey, passphrase: auth.passphrase, timestamp: ts, sign: sign2 }]
31945
+ }));
31946
+ }
31947
+ for (const [channel, instIds] of this.channelArgs) {
31948
+ for (const instId of instIds) {
31949
+ ws.send(JSON.stringify({ op: "subscribe", args: [{ channel, instId }] }));
31950
+ }
31951
+ }
31952
+ this.pingTimer = setInterval(() => {
31953
+ if (ws.readyState === wsModule.WebSocket.OPEN) ws.send("ping");
31954
+ }, 25e3);
31955
+ this.ws = ws;
31956
+ resolve();
31957
+ });
31958
+ ws.on("message", (raw) => {
31959
+ try {
31960
+ const msg = raw.toString();
31961
+ if (msg === "pong") return;
31962
+ const parsed = JSON.parse(msg);
31963
+ if (parsed.arg && parsed.data) {
31964
+ for (const [id, sub] of this.subscriptions) {
31965
+ if (sub.channel === parsed.arg.channel && sub.instId === parsed.arg.instId) {
31966
+ this.events.push({
31967
+ subId: id,
31968
+ channel: parsed.arg.channel || sub.channel,
31969
+ instId: parsed.arg.instId || sub.instId,
31970
+ ts: Date.now(),
31971
+ data: parsed.data
31972
+ });
31973
+ if (this.events.length > 1e4) this.events = this.events.slice(-5e3);
31974
+ break;
31975
+ }
31976
+ }
31977
+ }
31978
+ } catch {
31979
+ }
31980
+ });
31981
+ ws.on("error", (err) => {
31982
+ clearTimeout(timeout);
31983
+ reject(err);
31984
+ });
31985
+ ws.on("close", () => {
31986
+ if (this.pingTimer) {
31987
+ clearInterval(this.pingTimer);
31988
+ this.pingTimer = null;
31989
+ }
31990
+ this.ws = null;
31991
+ });
31992
+ });
31993
+ }
31994
+ };
31995
+
31996
+ // src/tools/ws.ts
31997
+ var wsManager = null;
31998
+ function getOrCreateWs() {
31999
+ if (!wsManager) wsManager = new WsManager();
32000
+ return wsManager;
32001
+ }
32002
+ var PUBLIC_CHANNELS = [
32003
+ "tickers",
32004
+ "trades",
32005
+ "candle1m",
32006
+ "candle5m",
32007
+ "candle15m",
32008
+ "candle1H",
32009
+ "candle4H",
32010
+ "candle1D",
32011
+ "books5",
32012
+ "books",
32013
+ "mark-price",
32014
+ "funding-rate",
32015
+ "open-interest",
32016
+ "price-limit",
32017
+ "index-tickers"
32018
+ ];
32019
+ function registerWsTools(server) {
32020
+ server.tool(
32021
+ "okx_ws_subscribe",
32022
+ "## \u529F\u80FD\uFF1A\u8BA2\u9605OKX WebSocket\u5B9E\u65F6\u6570\u636E\uFF0C\u4E8B\u4EF6\u81EA\u52A8\u7F13\u51B2\u5728\u5185\u5B58\u4E2D\n## \u573A\u666F\uFF1AAgent \u9700\u8981\u5B9E\u65F6\u76D1\u63A7\u884C\u60C5\u53D8\u5316\u800C\u975E\u8F6E\u8BE2\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1AWebSocket, ws, \u5B9E\u65F6\u63A8\u9001, \u5B9E\u65F6\u884C\u60C5, \u8BA2\u9605, subscribe, \u6D41\u5F0F\n## \u53C2\u6570\uFF1A\n## - instId: \u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT\u3001ETH-USDT-SWAP\n## - channel: \u9891\u9053\u540D\u3002(tickers/trades/candle1m~1D/books5/books\u7B49)\n## - instType: SPOT/SWAP/FUTURES/OPTION\uFF08tickers/trades \u9891\u9053\u9700\u8981\uFF09\n## \u9274\u6743\uFF1APUBLIC \u2014 \u516C\u5F00\u9891\u9053\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u8BA2\u9605\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u8BA2\u9605 \u2192 okx_ws_events \u62C9\u53D6 \u2192 \u51B3\u7B56 \u2192 okx_ws_close \u5173\u95ED",
32023
+ {
32024
+ instId: external_exports.string().describe("\u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT"),
32025
+ channel: external_exports.string().describe("\u9891\u9053\u540D"),
32026
+ instType: external_exports.enum(["SPOT", "SWAP", "FUTURES", "OPTION"]).optional().describe("tickers/trades \u9700\u8981")
32027
+ },
32028
+ async ({ instId, channel }) => {
32029
+ try {
32030
+ if (!PUBLIC_CHANNELS.includes(channel)) {
32031
+ return toError(new Error(`\u9891\u9053 "${channel}" \u4E0D\u652F\u6301\u3002\u652F\u6301: ${PUBLIC_CHANNELS.join(" ")}`));
32032
+ }
32033
+ const ws = getOrCreateWs();
32034
+ const subId = await ws.subscribe({ channel, instId: instId.toUpperCase(), type: "public" });
32035
+ return toResult({
32036
+ subscribed: true,
32037
+ subscriptionId: subId,
32038
+ channel,
32039
+ instId: instId.toUpperCase(),
32040
+ buffered: ws.countBuffered(subId),
32041
+ hint: `\u5DF2\u8BA2\u9605 ${instId.toUpperCase()} ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6\u3002`,
32042
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32043
+ });
32044
+ } catch (e) {
32045
+ return toError(e);
32046
+ }
32047
+ }
32048
+ );
32049
+ server.tool(
32050
+ "okx_ws_events",
32051
+ "## \u529F\u80FD\uFF1A\u62C9\u53D6 okx_ws_subscribe \u7F13\u51B2\u7684\u5B9E\u65F6\u4E8B\u4EF6\uFF0C\u6BCF\u6B21\u62C9\u53D6\u540E\u6E05\u7A7A\n## \u573A\u666F\uFF1AAgent \u5B9A\u671F\u68C0\u67E5\u6700\u65B0\u884C\u60C5\u3001\u4EE3\u66FF\u8F6E\u8BE2 REST API\n## \u5173\u952E\u8BCD\uFF1A\u62C9\u53D6, poll, \u4E8B\u4EF6, events, \u7F13\u51B2\u533A, \u6700\u65B0\u6D88\u606F\n## \u53C2\u6570\uFF1A\n## - subscriptionId: \u8BA2\u9605ID\uFF08\u9009\u586B\uFF0C\u4E0D\u586B\u8FD4\u56DE\u5168\u90E8\uFF09\n## - limit: \u6700\u5927\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA420\n## - filter: \u8FC7\u6EE4\u5173\u952E\u8BCD\n## \u9274\u6743\uFF1APUBLIC \u2014 \u8BFB\u5185\u5B58\u7F13\u51B2\u533A\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u53D7 limit \u63A7\u5236\uFF0C\u9ED8\u8BA4 ~2KB\n## \u5173\u8054\uFF1Aokx_ws_subscribe \u8BA2\u9605 \u2192 \u672C\u5DE5\u5177\u62C9\u53D6 \u2192 \u51B3\u7B56",
32052
+ {
32053
+ subscriptionId: external_exports.string().optional().describe("\u8BA2\u9605ID"),
32054
+ limit: external_exports.number().int().min(1).max(50).default(20).describe("\u6700\u5927\u8FD4\u56DE\u6761\u6570"),
32055
+ filter: external_exports.string().optional().describe("\u8FC7\u6EE4\u5173\u952E\u8BCD")
32056
+ },
32057
+ async ({ subscriptionId, limit, filter }) => {
32058
+ try {
32059
+ const ws = getOrCreateWs();
32060
+ let events = ws.drain(subscriptionId, limit);
32061
+ if (filter) {
32062
+ const kw = filter.toLowerCase();
32063
+ events = events.filter((e) => JSON.stringify(e).toLowerCase().includes(kw));
32064
+ }
32065
+ events = events.slice(0, limit);
32066
+ return toResult({
32067
+ events,
32068
+ count: events.length,
32069
+ active: ws.getStatus().filter((s) => s.active),
32070
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32071
+ });
32072
+ } catch (e) {
32073
+ return toError(e);
32074
+ }
32075
+ }
32076
+ );
32077
+ server.tool(
32078
+ "okx_ws_status",
32079
+ "## \u529F\u80FD\uFF1A\u67E5\u770B\u5F53\u524D\u6240\u6709 WebSocket \u8BA2\u9605\u72B6\u6001\u53CA\u7F13\u51B2\u533A\u4E8B\u4EF6\u6570\u91CF\n## \u573A\u666F\uFF1AAgent \u67E5\u770B\u8BA2\u9605\u5217\u8868\u3001\u7F13\u51B2\u533A\u79EF\u538B\u60C5\u51B5\n## \u5173\u952E\u8BCD\uFF1A\u72B6\u6001, status, \u8BA2\u9605\u5217\u8868, \u7F13\u51B2\u533A, \u8FDE\u63A5\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1APUBLIC\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1Aokx_ws_subscribe \u2192 \u672C\u5DE5\u5177 \u2192 okx_ws_close \u5173\u95ED",
32080
+ {},
32081
+ async () => {
32082
+ try {
32083
+ const ws = getOrCreateWs();
32084
+ return toResult({
32085
+ subscriptions: ws.getStatus(),
32086
+ totalBuffered: ws.countAllBuffered(),
32087
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32088
+ });
32089
+ } catch (e) {
32090
+ return toError(e);
32091
+ }
32092
+ }
32093
+ );
32094
+ server.tool(
32095
+ "okx_ws_close",
32096
+ "## \u529F\u80FD\uFF1A\u5173\u95ED\u6307\u5B9A\u6216\u6240\u6709 WebSocket \u8BA2\u9605\uFF0C\u91CA\u653E\u8FDE\u63A5\u8D44\u6E90\n## \u573A\u666F\uFF1AAgent \u5B8C\u6210\u76D1\u63A7\u540E\u6E05\u7406\n## \u5173\u952E\u8BCD\uFF1A\u5173\u95ED, close, \u53D6\u6D88\u8BA2\u9605, \u65AD\u5F00, \u505C\u6B62\n## \u53C2\u6570\uFF1A\n## - subscriptionId: \u8981\u5173\u95ED\u7684\u8BA2\u9605ID\uFF08\u4E0D\u4F20\u5173\u95ED\u6240\u6709\uFF09\n## \u9274\u6743\uFF1APUBLIC\n## \u98CE\u9669\uFF1AWRITE \u2014 \u4F1A\u65AD\u5F00\u8FDE\u63A5\uFF0C\u4F46\u65E0\u8D44\u91D1\u98CE\u9669\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~200B\n## \u5173\u8054\uFF1Aokx_ws_status \u2192 \u672C\u5DE5\u5177\u5173\u95ED",
32097
+ {
32098
+ subscriptionId: external_exports.string().optional().describe("\u8BA2\u9605ID\uFF0C\u4E0D\u4F20\u5173\u95ED\u6240\u6709")
32099
+ },
32100
+ async ({ subscriptionId }) => {
32101
+ try {
32102
+ const ws = getOrCreateWs();
32103
+ const closed = ws.close(subscriptionId);
32104
+ return toResult({
32105
+ closed,
32106
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32107
+ });
32108
+ } catch (e) {
32109
+ return toError(e);
32110
+ }
32111
+ }
32112
+ );
32113
+ }
32114
+
31831
32115
  // src/adapters/agent-hub.ts
32116
+ init_wrapper();
32117
+ var MAX_ROOM_MESSAGES = 200;
31832
32118
  var AgentHub = class {
31833
32119
  wss = null;
31834
32120
  agents = /* @__PURE__ */ new Map();
31835
32121
  tasks = /* @__PURE__ */ new Map();
32122
+ rooms = /* @__PURE__ */ new Map();
31836
32123
  heartbeatTimer = null;
32124
+ version = "0.0.0";
31837
32125
  // ── 启动 ──
31838
- start(port, host = "0.0.0.0") {
32126
+ start(port, host = "0.0.0.0", version2 = "0.0.0") {
32127
+ this.version = version2;
31839
32128
  this.wss = new import_websocket_server.default({ port, host });
31840
- console.log(`[AgentHub] WS Server started on ws://${host}:${port}`);
32129
+ console.log(`[AgentHub] WS Server v${version2} started on ws://${host}:${port}`);
32130
+ this.ensureRoom("#lobby");
32131
+ this.ensureRoom("#review");
31841
32132
  this.wss.on("connection", (ws) => {
31842
32133
  let agentId = null;
31843
32134
  ws.on("message", (raw) => {
@@ -31849,19 +32140,7 @@ var AgentHub = class {
31849
32140
  }
31850
32141
  });
31851
32142
  ws.on("close", () => {
31852
- if (agentId) {
31853
- const info = this.agents.get(agentId);
31854
- console.log(`[AgentHub] Agent \u79BB\u7EBF: ${agentId} (${info?.name || "?"})`);
31855
- this.agents.delete(agentId);
31856
- for (const [tid, t] of this.tasks) {
31857
- if (t.assignedTo === agentId && t.status === "assigned") {
31858
- t.status = "unassigned";
31859
- t.assignedTo = void 0;
31860
- t.claimedAt = void 0;
31861
- this.broadcast({ type: "task:released", taskId: tid, reason: "Agent \u79BB\u7EBF" });
31862
- }
31863
- }
31864
- }
32143
+ if (agentId) this.handleDisconnect(agentId);
31865
32144
  });
31866
32145
  ws.on("error", () => {
31867
32146
  });
@@ -31892,6 +32171,19 @@ var AgentHub = class {
31892
32171
  case "task:done":
31893
32172
  this.handleDone(msg);
31894
32173
  break;
32174
+ // ── Room ──
32175
+ case "room:join":
32176
+ this.handleRoomJoin(authAgentId, msg);
32177
+ break;
32178
+ case "room:leave":
32179
+ this.handleRoomLeave(authAgentId, msg);
32180
+ break;
32181
+ case "room:message":
32182
+ this.handleRoomMessage(authAgentId, msg);
32183
+ break;
32184
+ case "room:history":
32185
+ this.handleRoomHistory(ws, msg);
32186
+ break;
31895
32187
  default:
31896
32188
  this.send(ws, { type: "error", message: `\u672A\u77E5\u6D88\u606F\u7C7B\u578B: ${msg.type}` });
31897
32189
  }
@@ -31915,13 +32207,25 @@ var AgentHub = class {
31915
32207
  status: "idle",
31916
32208
  lastSeen: Date.now()
31917
32209
  });
32210
+ this.joinRoom(agentId, "#lobby");
31918
32211
  console.log(`[AgentHub] Agent \u6CE8\u518C: ${agentId} (${name}) skills: [${capabilities.join(", ")}]`);
31919
32212
  this.send(ws, {
31920
32213
  type: "agent:registered",
31921
32214
  agentId,
32215
+ currentVersion: this.version,
31922
32216
  message: `\u5DF2\u6CE8\u518C\u3002\u53EF\u7528\u4EFB\u52A1: ${this.getUnassignedTasks().join(", ") || "\u65E0"}`,
31923
32217
  pendingTasks: this.getUnassignedTasks()
31924
32218
  });
32219
+ const agentVersion = String(msg.version || "");
32220
+ if (agentVersion && agentVersion !== this.version) {
32221
+ this.send(ws, {
32222
+ type: "agent:upgrade",
32223
+ current: this.version,
32224
+ yourVersion: agentVersion,
32225
+ message: `hvip MCP \u5DF2\u5347\u7EA7\u5230 v${this.version}\uFF0C\u4F60\u5F53\u524D v${agentVersion}\u3002\u8BF7 git pull && npm run build \u540E\u91CD\u8FDE\u3002`
32226
+ });
32227
+ this.sendToRoom("#lobby", "system", `${agentId} \u7248\u672C\u8FC7\u65E7 (v${agentVersion})\uFF0C\u5DF2\u63D0\u9192\u5347\u7EA7\u5230 v${this.version}`);
32228
+ }
31925
32229
  if (capabilities.length > 0) {
31926
32230
  for (const tid of this.getUnassignedTasks()) {
31927
32231
  if (capabilities.includes(tid)) {
@@ -31930,6 +32234,30 @@ var AgentHub = class {
31930
32234
  }
31931
32235
  }
31932
32236
  }
32237
+ handleDisconnect(agentId) {
32238
+ const info = this.agents.get(agentId);
32239
+ console.log(`[AgentHub] Agent \u79BB\u7EBF: ${agentId} (${info?.name || "?"})`);
32240
+ for (const [, room] of this.rooms) {
32241
+ if (room.members.has(agentId)) {
32242
+ room.members.delete(agentId);
32243
+ this.sendToRoomMembers(room, {
32244
+ type: "room:member_left",
32245
+ roomId: agentId,
32246
+ // fixed below
32247
+ agentId
32248
+ });
32249
+ }
32250
+ }
32251
+ this.agents.delete(agentId);
32252
+ for (const [tid, t] of this.tasks) {
32253
+ if (t.assignedTo === agentId && t.status === "assigned") {
32254
+ t.status = "unassigned";
32255
+ t.assignedTo = void 0;
32256
+ t.claimedAt = void 0;
32257
+ this.broadcast({ type: "task:released", taskId: tid, reason: "Agent \u79BB\u7EBF" });
32258
+ }
32259
+ }
32260
+ }
31933
32261
  // ── Agent 心跳 ──
31934
32262
  handleAgentStatus(agentId) {
31935
32263
  const a = this.agents.get(agentId);
@@ -31956,6 +32284,7 @@ var AgentHub = class {
31956
32284
  task.claimedAt = Date.now();
31957
32285
  const a = this.agents.get(agentId);
31958
32286
  if (a) a.status = "working";
32287
+ this.joinRoom(agentId, `#task-${taskId}`);
31959
32288
  console.log(`[AgentHub] ${agentId} \u8BA4\u9886 ${taskId}`);
31960
32289
  this.sendTo(agentId, {
31961
32290
  type: "task:assigned",
@@ -31982,6 +32311,8 @@ var AgentHub = class {
31982
32311
  const a = this.agents.get(agentId);
31983
32312
  if (a) a.status = "idle";
31984
32313
  console.log(`[AgentHub] ${agentId} \u5B8C\u6210 ${taskId}: ${result}`);
32314
+ this.sendToRoom(`#task-${taskId}`, agentId, `\u5DF2\u5B8C\u6210 ${taskId}: ${result} (branch: ${branch})\uFF0C\u7B49\u5F85\u5BA1\u6838\u3002`);
32315
+ this.sendToRoom("#review", agentId, `${taskId} \u63D0\u4EA4\u5B8C\u6210\uFF0Cbranch: ${branch}`);
31985
32316
  this.broadcast({
31986
32317
  type: "task:completed",
31987
32318
  taskId,
@@ -31991,7 +32322,7 @@ var AgentHub = class {
31991
32322
  message: `${agentId} \u5DF2\u5B8C\u6210 ${taskId}\uFF0C\u7B49\u5F85\u5BA1\u6838`
31992
32323
  });
31993
32324
  }
31994
- // ── 派发任务到指定 Agent ──
32325
+ // ── 派发任务 ──
31995
32326
  dispatchTaskTo(taskId, agentId) {
31996
32327
  if (!this.tasks.has(taskId)) {
31997
32328
  this.tasks.set(taskId, { status: "unassigned" });
@@ -32005,7 +32336,7 @@ var AgentHub = class {
32005
32336
  url: `https://github.com/okx-wallet-H/hvip-mcp/blob/master/tasks/${taskId}.md`
32006
32337
  });
32007
32338
  }
32008
- // ── 审核 ──
32339
+ // ── 审核 + 自动通知房间 ──
32009
32340
  reviewTask(taskId, verdict, feedback) {
32010
32341
  const task = this.tasks.get(taskId);
32011
32342
  if (!task) return;
@@ -32016,10 +32347,101 @@ var AgentHub = class {
32016
32347
  task.assignedTo = void 0;
32017
32348
  task.claimedAt = void 0;
32018
32349
  }
32350
+ const roomId = `#task-${taskId}`;
32351
+ const msg = verdict === "approved" ? `\u2705 ${taskId} \u5BA1\u6838\u901A\u8FC7\u3002\u5DF2\u5408\u5E76\u5230 master \u5E76\u5220\u9664\u8FDC\u7A0B\u5206\u652F\u3002` : `\u274C ${taskId} \u5BA1\u6838\u4E0D\u901A\u8FC7\u3002${feedback || "\u8BF7\u4FEE\u6539\u540E\u91CD\u65B0 push\u3002"}`;
32352
+ this.sendToRoom(roomId, "reviewer", msg);
32353
+ this.sendToRoom("#review", "reviewer", `${taskId}: ${verdict}`);
32019
32354
  if (task.assignedTo) {
32020
32355
  this.sendTo(task.assignedTo, { type: "task:review", taskId, verdict, feedback });
32021
32356
  }
32022
32357
  }
32358
+ // ══════════════════════════════════════════════════════════════════════
32359
+ // Room 操作
32360
+ // ══════════════════════════════════════════════════════════════════════
32361
+ ensureRoom(roomId) {
32362
+ let room = this.rooms.get(roomId);
32363
+ if (!room) {
32364
+ room = { messages: [], members: /* @__PURE__ */ new Set() };
32365
+ this.rooms.set(roomId, room);
32366
+ }
32367
+ return room;
32368
+ }
32369
+ joinRoom(agentId, roomId) {
32370
+ const room = this.ensureRoom(roomId);
32371
+ if (room.members.has(agentId)) return;
32372
+ room.members.add(agentId);
32373
+ const a = this.agents.get(agentId);
32374
+ if (a) {
32375
+ this.send(a.ws, {
32376
+ type: "room:joined",
32377
+ roomId,
32378
+ members: [...room.members],
32379
+ recentMessages: room.messages.slice(-5)
32380
+ });
32381
+ }
32382
+ this.sendToRoomMembers(room, { type: "room:member_joined", roomId, agentId });
32383
+ console.log(`[AgentHub] ${agentId} \u2192 ${roomId}`);
32384
+ }
32385
+ leaveRoom(agentId, roomId) {
32386
+ const room = this.rooms.get(roomId);
32387
+ if (!room) return;
32388
+ room.members.delete(agentId);
32389
+ this.sendToRoomMembers(room, { type: "room:member_left", roomId, agentId });
32390
+ if (roomId !== "#lobby" && roomId !== "#review" && room.members.size === 0) {
32391
+ this.rooms.delete(roomId);
32392
+ }
32393
+ }
32394
+ sendToRoom(roomId, from, text) {
32395
+ const room = this.ensureRoom(roomId);
32396
+ const msg = { roomId, from, text, ts: (/* @__PURE__ */ new Date()).toISOString() };
32397
+ room.messages.push(msg);
32398
+ if (room.messages.length > MAX_ROOM_MESSAGES) room.messages.shift();
32399
+ const raw = JSON.stringify({ type: "room:message", ...msg });
32400
+ for (const agentId of room.members) {
32401
+ const a = this.agents.get(agentId);
32402
+ if (a && a.ws.readyState === import_websocket.default.OPEN) a.ws.send(raw);
32403
+ }
32404
+ }
32405
+ getRoomHistory(roomId, limit = 50) {
32406
+ const room = this.rooms.get(roomId);
32407
+ if (!room) return [];
32408
+ return room.messages.slice(-limit);
32409
+ }
32410
+ getRooms() {
32411
+ return [...this.rooms.entries()].map(([id, r]) => ({
32412
+ roomId: id,
32413
+ members: [...r.members],
32414
+ messageCount: r.messages.length
32415
+ }));
32416
+ }
32417
+ // ── Room message handlers ────────────────────────────────────────────
32418
+ handleRoomJoin(agentId, msg) {
32419
+ if (!agentId) return;
32420
+ this.joinRoom(agentId, String(msg.roomId || ""));
32421
+ }
32422
+ handleRoomLeave(agentId, msg) {
32423
+ if (!agentId) return;
32424
+ this.leaveRoom(agentId, String(msg.roomId || ""));
32425
+ }
32426
+ handleRoomMessage(agentId, msg) {
32427
+ if (!agentId) return;
32428
+ const roomId = String(msg.roomId || "");
32429
+ const text = String(msg.text || "");
32430
+ if (!roomId || !text) return;
32431
+ this.sendToRoom(roomId, agentId, text);
32432
+ }
32433
+ handleRoomHistory(ws, msg) {
32434
+ const roomId = String(msg.roomId || "");
32435
+ const limit = Number(msg.limit) || 50;
32436
+ this.send(ws, { type: "room:history", roomId, messages: this.getRoomHistory(roomId, limit) });
32437
+ }
32438
+ sendToRoomMembers(room, msg) {
32439
+ const raw = JSON.stringify(msg);
32440
+ for (const agentId of room.members) {
32441
+ const a = this.agents.get(agentId);
32442
+ if (a && a.ws.readyState === import_websocket.default.OPEN) a.ws.send(raw);
32443
+ }
32444
+ }
32023
32445
  // ── 链上事件桥接 ──
32024
32446
  bridgeChainEvent(event) {
32025
32447
  this.broadcast({ type: "chain:event", data: event, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -32070,7 +32492,8 @@ var AgentHub = class {
32070
32492
  result: t.result,
32071
32493
  branch: t.branch
32072
32494
  }));
32073
- return { agents, tasks, agentCount: agents.length, taskCount: tasks.length };
32495
+ const rooms = this.getRooms();
32496
+ return { agents, tasks, rooms, agentCount: agents.length, taskCount: tasks.length };
32074
32497
  }
32075
32498
  // ── 关闭 ──
32076
32499
  close() {
@@ -32081,18 +32504,19 @@ var AgentHub = class {
32081
32504
  this.wss?.close();
32082
32505
  this.agents.clear();
32083
32506
  this.tasks.clear();
32507
+ this.rooms.clear();
32084
32508
  }
32085
32509
  };
32086
32510
  var agentHub = new AgentHub();
32087
- function startAgentHub(port, host = "0.0.0.0") {
32088
- agentHub.start(port, host);
32511
+ function startAgentHub(port, host = "0.0.0.0", version2 = "0.0.0") {
32512
+ agentHub.start(port, host, version2);
32089
32513
  }
32090
32514
 
32091
32515
  // src/tools/agent-hub.ts
32092
32516
  function registerAgentHubTools(server) {
32093
32517
  server.tool(
32094
32518
  "agent_hub_status",
32095
- "## \u529F\u80FD\uFF1A\u67E5\u770B Agent Hub \u5168\u666F\uFF1A\u6240\u6709\u5728\u7EBF Agent\u3001\u4EFB\u52A1\u5206\u914D\u72B6\u6001\u3001\u4EFB\u52A1\u8FDB\u5EA6\n## \u573A\u666F\uFF1A\u7528\u4E8E\u5DE1\u68C0 Agent \u96C6\u7FA4\u5065\u5EB7\u72B6\u51B5\u3001\u4E86\u89E3\u54EA\u4E9B\u4EFB\u52A1\u5728\u63A8\u8FDB\u3001\u54EA\u4E2A Agent \u7A7A\u95F2\u53EF\u6D3E\u6D3B\n## \u5173\u952E\u8BCD\uFF1AAgent Hub, \u96C6\u7FA4\u72B6\u6001, \u4EFB\u52A1\u8FDB\u5EA6, \u5728\u7EBFAgent, \u8C03\u5EA6\u9762\u677F\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1APUBLIC \u2014 Agent Hub \u5185\u90E8\u63A5\u53E3\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u72B6\u6001\u67E5\u8BE2\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~1KB\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u67E5\u770B\u5168\u5C40 \u2192 agent_hub_dispatch \u6D3E\u53D1\u4EFB\u52A1 \u2192 agent_hub_review \u5BA1\u6838\u7ED3\u679C",
32519
+ "## \u529F\u80FD\uFF1A\u67E5\u770B Agent Hub \u5168\u666F\uFF1A\u6240\u6709\u5728\u7EBF Agent\u3001\u4EFB\u52A1\u5206\u914D\u3001\u623F\u95F4\u6D88\u606F\n## \u573A\u666F\uFF1A\u7528\u4E8E\u5DE1\u68C0 Agent \u96C6\u7FA4\u5065\u5EB7\u72B6\u51B5\u3001\u4E86\u89E3\u54EA\u4E9B\u4EFB\u52A1\u5728\u63A8\u8FDB\u3001\u54EA\u4E2A Agent \u7A7A\u95F2\u53EF\u6D3E\u6D3B\n## \u5173\u952E\u8BCD\uFF1AAgent Hub, \u96C6\u7FA4\u72B6\u6001, \u4EFB\u52A1\u8FDB\u5EA6, \u5728\u7EBFAgent, \u8C03\u5EA6\u9762\u677F, \u623F\u95F4\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1APUBLIC \u2014 Agent Hub \u5185\u90E8\u63A5\u53E3\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u72B6\u6001\u67E5\u8BE2\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~2KB\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u67E5\u770B\u5168\u5C40 \u2192 agent_hub_dispatch \u6D3E\u53D1\u4EFB\u52A1 \u2192 agent_room_send \u53D1\u6D88\u606F",
32096
32520
  {},
32097
32521
  async () => {
32098
32522
  try {
@@ -32104,7 +32528,7 @@ function registerAgentHubTools(server) {
32104
32528
  );
32105
32529
  server.tool(
32106
32530
  "agent_hub_dispatch",
32107
- "## \u529F\u80FD\uFF1A\u5411\u6307\u5B9A Agent \u6216\u5168\u4F53\u5728\u7EBF Agent \u6D3E\u53D1\u4EFB\u52A1\n## \u573A\u666F\uFF1A\u7528\u4E8E\u624B\u52A8\u5C06\u4EFB\u52A1\u6C60\u4E2D\u7684\u5DE5\u5355\u5206\u53D1\u7ED9\u7A7A\u95F2 Agent\u3001\u8865\u5145\u81EA\u52A8\u6D3E\u53D1\u672A\u8986\u76D6\u7684\u4EFB\u52A1\n## \u5173\u952E\u8BCD\uFF1A\u6D3E\u53D1, dispatch, \u4EFB\u52A1\u5206\u914D, \u8C03\u5EA6, assign\n## \u53C2\u6570\uFF1A\n## - taskId: \u4EFB\u52A1\u7F16\u53F7\uFF08T-001 ~ T-006\uFF09\n## - agentId: \u76EE\u6807 Agent ID\uFF08\u9009\u586B\uFF0C\u4E0D\u586B\u5219\u627E\u7B2C\u4E00\u4E2A\u5339\u914D\u7684\uFF09\n## \u9274\u6743\uFF1APUBLIC \u2014 \u8C03\u5EA6\u63A7\u5236\u63A5\u53E3\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u6D3E\u53D1\u6D88\u606F\uFF0C\u4E0D\u4FEE\u6539\u4EE3\u7801\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~200B\n## \u5173\u8054\uFF1Aagent_hub_status \u67E5\u770B Agent \u72B6\u6001 \u2192 \u672C\u5DE5\u5177\u6D3E\u53D1 \u2192 Agent \u6536\u5230 task:dispatch",
32531
+ "## \u529F\u80FD\uFF1A\u5411\u6307\u5B9A Agent \u6216\u5168\u4F53\u5728\u7EBF Agent \u6D3E\u53D1\u4EFB\u52A1\n## \u573A\u666F\uFF1A\u7528\u4E8E\u624B\u52A8\u5C06\u4EFB\u52A1\u6C60\u4E2D\u7684\u5DE5\u5355\u5206\u53D1\u7ED9\u7A7A\u95F2 Agent\u3001\u8865\u5145\u81EA\u52A8\u6D3E\u53D1\u672A\u8986\u76D6\u7684\u4EFB\u52A1\n## \u5173\u952E\u8BCD\uFF1A\u6D3E\u53D1, dispatch, \u4EFB\u52A1\u5206\u914D, \u8C03\u5EA6, assign\n## \u53C2\u6570\uFF1A\n## - taskId: \u4EFB\u52A1\u7F16\u53F7\n## - agentId: \u76EE\u6807 Agent ID\uFF08\u9009\u586B\uFF0C\u4E0D\u586B\u5219\u627E\u7B2C\u4E00\u4E2A\u5339\u914D\u7684\uFF09\n## \u9274\u6743\uFF1APUBLIC \u2014 \u8C03\u5EA6\u63A7\u5236\u63A5\u53E3\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u6D3E\u53D1\u6D88\u606F\uFF0C\u4E0D\u4FEE\u6539\u4EE3\u7801\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~200B\n## \u5173\u8054\uFF1Aagent_hub_status \u67E5\u770B Agent \u72B6\u6001 \u2192 \u672C\u5DE5\u5177\u6D3E\u53D1 \u2192 Agent \u6536\u5230 task:dispatch",
32108
32532
  {
32109
32533
  taskId: external_exports.enum(["T-001", "T-002", "T-003", "T-004", "T-005", "T-006"]).describe("\u4EFB\u52A1\u7F16\u53F7"),
32110
32534
  agentId: external_exports.string().optional().describe("\u76EE\u6807 Agent ID\u3002\u4E0D\u586B\u5219\u81EA\u52A8\u5339\u914D\u6709\u5BF9\u5E94\u6280\u80FD\u7684 Agent")
@@ -32155,7 +32579,7 @@ function registerAgentHubTools(server) {
32155
32579
  );
32156
32580
  server.tool(
32157
32581
  "agent_hub_review",
32158
- "## \u529F\u80FD\uFF1A\u5BA1\u6838 Agent \u63D0\u4EA4\u7684\u4EFB\u52A1\u7ED3\u679C\uFF0C\u901A\u8FC7/\u9A73\u56DE\n## \u573A\u666F\uFF1A\u7528\u4E8E Agent \u63D0\u4EA4 PR \u540E\u5BA1\u6838\u4EE3\u7801\u3001\u901A\u8FC7\u5219\u6807\u8BB0\u5B8C\u6210\u9A73\u56DE\u5219\u9000\u56DE\u4EFB\u52A1\u6C60\n## \u5173\u952E\u8BCD\uFF1A\u5BA1\u6838, review, \u6279\u51C6, \u9A73\u56DE, approve, reject\n## \u53C2\u6570\uFF1A\n## - taskId: \u4EFB\u52A1\u7F16\u53F7\n## - verdict: \u5BA1\u6838\u7ED3\u679C\u3002approved=\u901A\u8FC7, rejected=\u9A73\u56DE\n## - feedback: \u5BA1\u6838\u610F\u89C1\uFF08\u9A73\u56DE\u65F6\u5FC5\u586B\uFF0C\u8BF4\u660E\u54EA\u91CC\u4E0D\u6EE1\u8DB3\uFF09\n## \u9274\u6743\uFF1APUBLIC \u2014 \u5BA1\u6838\u63A7\u5236\u63A5\u53E3\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u53D1\u6D88\u606F\u901A\u77E5\uFF0C\u4EE3\u7801\u5408\u5E76\u7531\u5B9A\u65F6\u4EFB\u52A1\u6267\u884C\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~200B\n## \u5173\u8054\uFF1Aagent_hub_status \u67E5\u770B\u5B8C\u6210\u72B6\u6001 \u2192 \u672C\u5DE5\u5177\u5BA1\u6838 \u2192 Agent \u6536\u5230 task:review \u2192 \u901A\u8FC7\u5219\u81EA\u52A8\u5408\u5E76",
32582
+ "## \u529F\u80FD\uFF1A\u5BA1\u6838 Agent \u63D0\u4EA4\u7684\u4EFB\u52A1\u7ED3\u679C\uFF0C\u901A\u8FC7/\u9A73\u56DE\uFF0C\u81EA\u52A8\u901A\u77E5\u5BF9\u5E94\u4EFB\u52A1\u623F\u95F4\n## \u573A\u666F\uFF1A\u5BA1\u6838\u5458\u5BA1\u5B8C\u4EE3\u7801\u540E\u53D1\u7ED3\u679C\uFF0CAgent \u5728\u623F\u95F4\u5B9E\u65F6\u6536\u5230\u53CD\u9988\n## \u5173\u952E\u8BCD\uFF1A\u5BA1\u6838, review, \u6279\u51C6, \u9A73\u56DE, approve, reject, \u623F\u95F4\u901A\u77E5\n## \u53C2\u6570\uFF1A\n## - taskId: \u4EFB\u52A1\u7F16\u53F7\n## - verdict: \u5BA1\u6838\u7ED3\u679C\u3002approved=\u901A\u8FC7, rejected=\u9A73\u56DE\n## - feedback: \u5BA1\u6838\u610F\u89C1\uFF08\u9A73\u56DE\u65F6\u5FC5\u586B\uFF09\n## \u9274\u6743\uFF1APUBLIC \u2014 \u5BA1\u6838\u63A7\u5236\u63A5\u53E3\n## \u98CE\u9669\uFF1AREAD \u2014 \u53D1\u6D88\u606F\u901A\u77E5\uFF0C\u4EE3\u7801\u7684\u5408\u5E76\u7531\u5B9A\u65F6\u4EFB\u52A1\u6267\u884C\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~200B\n## \u5173\u8054\uFF1A\u5BA1\u6838\u4E0D\u901A\u8FC7 \u2192 agent_room_send \u53D1\u623F\u95F4\u6D88\u606F \u2192 Agent \u6539\u4EE3\u7801",
32159
32583
  {
32160
32584
  taskId: external_exports.enum(["T-001", "T-002", "T-003", "T-004", "T-005", "T-006"]).describe("\u4EFB\u52A1\u7F16\u53F7"),
32161
32585
  verdict: external_exports.enum(["approved", "rejected"]).describe("\u5BA1\u6838\u7ED3\u679C"),
@@ -32177,7 +32601,59 @@ function registerAgentHubTools(server) {
32177
32601
  taskId,
32178
32602
  verdict,
32179
32603
  feedback: feedback || (verdict === "approved" ? "\u2705 \u901A\u8FC7" : "\u274C \u9A73\u56DE"),
32180
- next: verdict === "approved" ? `\u4EFB\u52A1\u5B8C\u6210\u3002Agent \u5E94\u63D0 PR \u5230 master\u3002` : `\u4EFB\u52A1\u5DF2\u9000\u56DE\u4EFB\u52A1\u6C60\u3002Agent \u5E94\u6839\u636E\u53CD\u9988\u4FEE\u6539\u3002`
32604
+ roomNotice: `\u5BA1\u6838\u7ED3\u679C\u5DF2\u63A8\u9001\u5230 #task-${taskId} \u623F\u95F4`,
32605
+ next: verdict === "approved" ? `\u4EFB\u52A1\u5B8C\u6210\u3002` : `\u4EFB\u52A1\u9000\u56DE\u3002Agent \u5728 #task-${taskId} \u623F\u95F4\u67E5\u770B\u53CD\u9988\u3002`
32606
+ });
32607
+ } catch (e) {
32608
+ return toError(e);
32609
+ }
32610
+ }
32611
+ );
32612
+ server.tool(
32613
+ "agent_room_send",
32614
+ "## \u529F\u80FD\uFF1A\u5411\u6307\u5B9A\u623F\u95F4\u53D1\u9001\u6D88\u606F\uFF0C\u6240\u6709\u623F\u95F4\u6210\u5458\u5B9E\u65F6\u6536\u5230\n## \u573A\u666F\uFF1A\u5BA1\u6838\u5458\u7ED9 Agent \u53D1\u53CD\u9988\u3001\u5728\u4EFB\u52A1\u623F\u95F4\u534F\u8C03\u3001\u5411\u6240\u6709\u4EBA\u5E7F\u64AD\n## \u5173\u952E\u8BCD\uFF1A\u623F\u95F4\u6D88\u606F, room, \u53D1\u9001, \u901A\u77E5, \u5E7F\u64AD\n## \u53C2\u6570\uFF1A\n## - roomId: \u623F\u95F4ID\u3002#lobby / #review / #task-T-XXX\n## - text: \u6D88\u606F\u5185\u5BB9\n## \u9274\u6743\uFF1APUBLIC\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u53D1\u6D88\u606F\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~200B\n## \u5173\u8054\uFF1A\u5BA1\u6838\u4E0D\u901A\u8FC7 \u2192 \u672C\u5DE5\u5177\u53D1 #task-T-XXX \u2192 Agent \u6536\u5230",
32615
+ {
32616
+ roomId: external_exports.string().describe("\u623F\u95F4ID\u3002#lobby / #review / #task-T-003"),
32617
+ text: external_exports.string().describe("\u6D88\u606F\u5185\u5BB9")
32618
+ },
32619
+ async ({ roomId, text }) => {
32620
+ try {
32621
+ agentHub.sendToRoom(roomId, "reviewer", text);
32622
+ return toResult({
32623
+ sent: true,
32624
+ roomId,
32625
+ text,
32626
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32627
+ });
32628
+ } catch (e) {
32629
+ return toError(e);
32630
+ }
32631
+ }
32632
+ );
32633
+ server.tool(
32634
+ "agent_room_view",
32635
+ "## \u529F\u80FD\uFF1A\u67E5\u770B\u623F\u95F4\u5217\u8868\u6216\u6307\u5B9A\u623F\u95F4\u7684\u6D88\u606F\u5386\u53F2\n## \u573A\u666F\uFF1A\u68C0\u67E5\u54EA\u4E9B\u623F\u95F4\u6D3B\u8DC3\u3001\u8BFB\u53D6\u5386\u53F2\u6D88\u606F\u3001\u770B\u8C01\u5728\u623F\u95F4\u91CC\n## \u5173\u952E\u8BCD\uFF1A\u623F\u95F4, room, \u6D88\u606F\u5386\u53F2, \u5728\u7EBF\u6210\u5458\n## \u53C2\u6570\uFF1A\n## - roomId: \u623F\u95F4ID\uFF08\u9009\u586B\uFF0C\u4E0D\u586B\u5217\u51FA\u6240\u6709\u623F\u95F4\uFF09\n## - limit: \u6D88\u606F\u6761\u6570\uFF0C\u9ED8\u8BA4 30\n## \u9274\u6743\uFF1APUBLIC\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~3KB\n## \u5173\u8054\uFF1Aagent_room_send \u53D1\u6D88\u606F \u2192 \u672C\u5DE5\u5177\u67E5\u770B\u5386\u53F2",
32636
+ {
32637
+ roomId: external_exports.string().optional().describe("\u623F\u95F4ID\uFF0C\u4E0D\u586B\u5217\u51FA\u6240\u6709"),
32638
+ limit: external_exports.number().int().min(1).max(200).optional().describe("\u6D88\u606F\u6761\u6570\uFF0C\u9ED8\u8BA430")
32639
+ },
32640
+ async ({ roomId, limit }) => {
32641
+ try {
32642
+ if (roomId) {
32643
+ const msgs = agentHub.getRoomHistory(roomId, limit || 30);
32644
+ return toResult({
32645
+ roomId,
32646
+ messageCount: msgs.length,
32647
+ messages: msgs,
32648
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32649
+ });
32650
+ }
32651
+ const rooms = agentHub.getRooms();
32652
+ return toResult({
32653
+ rooms,
32654
+ count: rooms.length,
32655
+ hint: "\u4F20 roomId \u67E5\u770B\u5177\u4F53\u623F\u95F4\u6D88\u606F\u3002frequent: #lobby #review #task-T-003",
32656
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
32181
32657
  });
32182
32658
  } catch (e) {
32183
32659
  return toError(e);
@@ -32188,9 +32664,10 @@ function registerAgentHubTools(server) {
32188
32664
 
32189
32665
  // src/index.ts
32190
32666
  async function main() {
32667
+ const VERSION = "0.2.43";
32191
32668
  const server = new McpServer({
32192
32669
  name: "hvip-mcp",
32193
- version: "0.2.42",
32670
+ version: "0.2.43",
32194
32671
  description: "hvip MCP Server \u2014 304 \u5DE5\u5177\u8986\u76D6 97.7% OKX REST API\uFF0C\u542B\u4EA4\u6613/\u884C\u60C5/\u8D44\u91D1/\u7B56\u7565/\u9884\u6D4B\u5E02\u573A\uFF08\u975E OKX \u5B98\u65B9\u4EA7\u54C1\uFF09\u3002\u4ED3\u5E93: https://github.com/okx-wallet-H/hvip-mcp"
32195
32672
  });
32196
32673
  const auth = getAuth();
@@ -32213,8 +32690,9 @@ async function main() {
32213
32690
  registerRfqTools(server, auth);
32214
32691
  registerAgentUtils(server, auth);
32215
32692
  registerXLayerWSTools(server);
32693
+ registerWsTools(server);
32216
32694
  registerAgentHubTools(server);
32217
- startAgentHub(parseInt(process.env.WS_AGENT_PORT || "9321"));
32695
+ startAgentHub(parseInt(process.env.WS_AGENT_PORT || "9321"), "0.0.0.0", VERSION);
32218
32696
  const transport = new StdioServerTransport();
32219
32697
  await server.connect(transport);
32220
32698
  }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "hvip-mcp-server",
3
- "version": "0.2.42",
3
+ "version": "0.2.43",
4
4
  "description": "hvip MCP Server — 304 工具覆盖 97.7% OKX REST API,含交易/行情/资金/策略/预测市场(非 OKX 官方产品)",
5
- "homepage": "https://hvip.one",
5
+ "homepage": "https://github.com/okx-wallet-H/hvip-mcp",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/okx-wallet-H/hvip-mcp"