hvip-mcp-server 0.2.48 → 0.2.50

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 (2) hide show
  1. package/dist/index.js +1115 -117
  2. package/package.json +65 -64
package/dist/index.js CHANGED
@@ -6,9 +6,6 @@ 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
- };
12
9
  var __commonJS = (cb, mod) => function __require() {
13
10
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
14
11
  };
@@ -33,6 +30,410 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
30
  mod
34
31
  ));
35
32
 
33
+ // node_modules/dotenv/package.json
34
+ var require_package = __commonJS({
35
+ "node_modules/dotenv/package.json"(exports2, module2) {
36
+ module2.exports = {
37
+ name: "dotenv",
38
+ version: "16.6.1",
39
+ description: "Loads environment variables from .env file",
40
+ main: "lib/main.js",
41
+ types: "lib/main.d.ts",
42
+ exports: {
43
+ ".": {
44
+ types: "./lib/main.d.ts",
45
+ require: "./lib/main.js",
46
+ default: "./lib/main.js"
47
+ },
48
+ "./config": "./config.js",
49
+ "./config.js": "./config.js",
50
+ "./lib/env-options": "./lib/env-options.js",
51
+ "./lib/env-options.js": "./lib/env-options.js",
52
+ "./lib/cli-options": "./lib/cli-options.js",
53
+ "./lib/cli-options.js": "./lib/cli-options.js",
54
+ "./package.json": "./package.json"
55
+ },
56
+ scripts: {
57
+ "dts-check": "tsc --project tests/types/tsconfig.json",
58
+ lint: "standard",
59
+ pretest: "npm run lint && npm run dts-check",
60
+ test: "tap run --allow-empty-coverage --disable-coverage --timeout=60000",
61
+ "test:coverage": "tap run --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
62
+ prerelease: "npm test",
63
+ release: "standard-version"
64
+ },
65
+ repository: {
66
+ type: "git",
67
+ url: "git://github.com/motdotla/dotenv.git"
68
+ },
69
+ homepage: "https://github.com/motdotla/dotenv#readme",
70
+ funding: "https://dotenvx.com",
71
+ keywords: [
72
+ "dotenv",
73
+ "env",
74
+ ".env",
75
+ "environment",
76
+ "variables",
77
+ "config",
78
+ "settings"
79
+ ],
80
+ readmeFilename: "README.md",
81
+ license: "BSD-2-Clause",
82
+ devDependencies: {
83
+ "@types/node": "^18.11.3",
84
+ decache: "^4.6.2",
85
+ sinon: "^14.0.1",
86
+ standard: "^17.0.0",
87
+ "standard-version": "^9.5.0",
88
+ tap: "^19.2.0",
89
+ typescript: "^4.8.4"
90
+ },
91
+ engines: {
92
+ node: ">=12"
93
+ },
94
+ browser: {
95
+ fs: false
96
+ }
97
+ };
98
+ }
99
+ });
100
+
101
+ // node_modules/dotenv/lib/main.js
102
+ var require_main = __commonJS({
103
+ "node_modules/dotenv/lib/main.js"(exports2, module2) {
104
+ var fs2 = require("fs");
105
+ var path2 = require("path");
106
+ var os2 = require("os");
107
+ var crypto5 = require("crypto");
108
+ var packageJson = require_package();
109
+ var version2 = packageJson.version;
110
+ var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
111
+ function parse3(src) {
112
+ const obj = {};
113
+ let lines = src.toString();
114
+ lines = lines.replace(/\r\n?/mg, "\n");
115
+ let match;
116
+ while ((match = LINE.exec(lines)) != null) {
117
+ const key = match[1];
118
+ let value = match[2] || "";
119
+ value = value.trim();
120
+ const maybeQuote = value[0];
121
+ value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
122
+ if (maybeQuote === '"') {
123
+ value = value.replace(/\\n/g, "\n");
124
+ value = value.replace(/\\r/g, "\r");
125
+ }
126
+ obj[key] = value;
127
+ }
128
+ return obj;
129
+ }
130
+ function _parseVault(options) {
131
+ options = options || {};
132
+ const vaultPath = _vaultPath(options);
133
+ options.path = vaultPath;
134
+ const result = DotenvModule.configDotenv(options);
135
+ if (!result.parsed) {
136
+ const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
137
+ err.code = "MISSING_DATA";
138
+ throw err;
139
+ }
140
+ const keys = _dotenvKey(options).split(",");
141
+ const length = keys.length;
142
+ let decrypted;
143
+ for (let i = 0; i < length; i++) {
144
+ try {
145
+ const key = keys[i].trim();
146
+ const attrs = _instructions(result, key);
147
+ decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
148
+ break;
149
+ } catch (error2) {
150
+ if (i + 1 >= length) {
151
+ throw error2;
152
+ }
153
+ }
154
+ }
155
+ return DotenvModule.parse(decrypted);
156
+ }
157
+ function _warn(message) {
158
+ console.log(`[dotenv@${version2}][WARN] ${message}`);
159
+ }
160
+ function _debug(message) {
161
+ console.log(`[dotenv@${version2}][DEBUG] ${message}`);
162
+ }
163
+ function _log(message) {
164
+ console.log(`[dotenv@${version2}] ${message}`);
165
+ }
166
+ function _dotenvKey(options) {
167
+ if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
168
+ return options.DOTENV_KEY;
169
+ }
170
+ if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
171
+ return process.env.DOTENV_KEY;
172
+ }
173
+ return "";
174
+ }
175
+ function _instructions(result, dotenvKey) {
176
+ let uri;
177
+ try {
178
+ uri = new URL(dotenvKey);
179
+ } catch (error2) {
180
+ if (error2.code === "ERR_INVALID_URL") {
181
+ const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
182
+ err.code = "INVALID_DOTENV_KEY";
183
+ throw err;
184
+ }
185
+ throw error2;
186
+ }
187
+ const key = uri.password;
188
+ if (!key) {
189
+ const err = new Error("INVALID_DOTENV_KEY: Missing key part");
190
+ err.code = "INVALID_DOTENV_KEY";
191
+ throw err;
192
+ }
193
+ const environment = uri.searchParams.get("environment");
194
+ if (!environment) {
195
+ const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
196
+ err.code = "INVALID_DOTENV_KEY";
197
+ throw err;
198
+ }
199
+ const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
200
+ const ciphertext = result.parsed[environmentKey];
201
+ if (!ciphertext) {
202
+ const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
203
+ err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
204
+ throw err;
205
+ }
206
+ return { ciphertext, key };
207
+ }
208
+ function _vaultPath(options) {
209
+ let possibleVaultPath = null;
210
+ if (options && options.path && options.path.length > 0) {
211
+ if (Array.isArray(options.path)) {
212
+ for (const filepath of options.path) {
213
+ if (fs2.existsSync(filepath)) {
214
+ possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
215
+ }
216
+ }
217
+ } else {
218
+ possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
219
+ }
220
+ } else {
221
+ possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
222
+ }
223
+ if (fs2.existsSync(possibleVaultPath)) {
224
+ return possibleVaultPath;
225
+ }
226
+ return null;
227
+ }
228
+ function _resolveHome(envPath) {
229
+ return envPath[0] === "~" ? path2.join(os2.homedir(), envPath.slice(1)) : envPath;
230
+ }
231
+ function _configVault(options) {
232
+ const debug = Boolean(options && options.debug);
233
+ const quiet = options && "quiet" in options ? options.quiet : true;
234
+ if (debug || !quiet) {
235
+ _log("Loading env from encrypted .env.vault");
236
+ }
237
+ const parsed = DotenvModule._parseVault(options);
238
+ let processEnv = process.env;
239
+ if (options && options.processEnv != null) {
240
+ processEnv = options.processEnv;
241
+ }
242
+ DotenvModule.populate(processEnv, parsed, options);
243
+ return { parsed };
244
+ }
245
+ function configDotenv(options) {
246
+ const dotenvPath = path2.resolve(process.cwd(), ".env");
247
+ let encoding = "utf8";
248
+ const debug = Boolean(options && options.debug);
249
+ const quiet = options && "quiet" in options ? options.quiet : true;
250
+ if (options && options.encoding) {
251
+ encoding = options.encoding;
252
+ } else {
253
+ if (debug) {
254
+ _debug("No encoding is specified. UTF-8 is used by default");
255
+ }
256
+ }
257
+ let optionPaths = [dotenvPath];
258
+ if (options && options.path) {
259
+ if (!Array.isArray(options.path)) {
260
+ optionPaths = [_resolveHome(options.path)];
261
+ } else {
262
+ optionPaths = [];
263
+ for (const filepath of options.path) {
264
+ optionPaths.push(_resolveHome(filepath));
265
+ }
266
+ }
267
+ }
268
+ let lastError;
269
+ const parsedAll = {};
270
+ for (const path3 of optionPaths) {
271
+ try {
272
+ const parsed = DotenvModule.parse(fs2.readFileSync(path3, { encoding }));
273
+ DotenvModule.populate(parsedAll, parsed, options);
274
+ } catch (e) {
275
+ if (debug) {
276
+ _debug(`Failed to load ${path3} ${e.message}`);
277
+ }
278
+ lastError = e;
279
+ }
280
+ }
281
+ let processEnv = process.env;
282
+ if (options && options.processEnv != null) {
283
+ processEnv = options.processEnv;
284
+ }
285
+ DotenvModule.populate(processEnv, parsedAll, options);
286
+ if (debug || !quiet) {
287
+ const keysCount = Object.keys(parsedAll).length;
288
+ const shortPaths = [];
289
+ for (const filePath of optionPaths) {
290
+ try {
291
+ const relative = path2.relative(process.cwd(), filePath);
292
+ shortPaths.push(relative);
293
+ } catch (e) {
294
+ if (debug) {
295
+ _debug(`Failed to load ${filePath} ${e.message}`);
296
+ }
297
+ lastError = e;
298
+ }
299
+ }
300
+ _log(`injecting env (${keysCount}) from ${shortPaths.join(",")}`);
301
+ }
302
+ if (lastError) {
303
+ return { parsed: parsedAll, error: lastError };
304
+ } else {
305
+ return { parsed: parsedAll };
306
+ }
307
+ }
308
+ function config2(options) {
309
+ if (_dotenvKey(options).length === 0) {
310
+ return DotenvModule.configDotenv(options);
311
+ }
312
+ const vaultPath = _vaultPath(options);
313
+ if (!vaultPath) {
314
+ _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
315
+ return DotenvModule.configDotenv(options);
316
+ }
317
+ return DotenvModule._configVault(options);
318
+ }
319
+ function decrypt(encrypted, keyStr) {
320
+ const key = Buffer.from(keyStr.slice(-64), "hex");
321
+ let ciphertext = Buffer.from(encrypted, "base64");
322
+ const nonce = ciphertext.subarray(0, 12);
323
+ const authTag = ciphertext.subarray(-16);
324
+ ciphertext = ciphertext.subarray(12, -16);
325
+ try {
326
+ const aesgcm = crypto5.createDecipheriv("aes-256-gcm", key, nonce);
327
+ aesgcm.setAuthTag(authTag);
328
+ return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
329
+ } catch (error2) {
330
+ const isRange = error2 instanceof RangeError;
331
+ const invalidKeyLength = error2.message === "Invalid key length";
332
+ const decryptionFailed = error2.message === "Unsupported state or unable to authenticate data";
333
+ if (isRange || invalidKeyLength) {
334
+ const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
335
+ err.code = "INVALID_DOTENV_KEY";
336
+ throw err;
337
+ } else if (decryptionFailed) {
338
+ const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
339
+ err.code = "DECRYPTION_FAILED";
340
+ throw err;
341
+ } else {
342
+ throw error2;
343
+ }
344
+ }
345
+ }
346
+ function populate(processEnv, parsed, options = {}) {
347
+ const debug = Boolean(options && options.debug);
348
+ const override = Boolean(options && options.override);
349
+ if (typeof parsed !== "object") {
350
+ const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
351
+ err.code = "OBJECT_REQUIRED";
352
+ throw err;
353
+ }
354
+ for (const key of Object.keys(parsed)) {
355
+ if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
356
+ if (override === true) {
357
+ processEnv[key] = parsed[key];
358
+ }
359
+ if (debug) {
360
+ if (override === true) {
361
+ _debug(`"${key}" is already defined and WAS overwritten`);
362
+ } else {
363
+ _debug(`"${key}" is already defined and was NOT overwritten`);
364
+ }
365
+ }
366
+ } else {
367
+ processEnv[key] = parsed[key];
368
+ }
369
+ }
370
+ }
371
+ var DotenvModule = {
372
+ configDotenv,
373
+ _configVault,
374
+ _parseVault,
375
+ config: config2,
376
+ decrypt,
377
+ parse: parse3,
378
+ populate
379
+ };
380
+ module2.exports.configDotenv = DotenvModule.configDotenv;
381
+ module2.exports._configVault = DotenvModule._configVault;
382
+ module2.exports._parseVault = DotenvModule._parseVault;
383
+ module2.exports.config = DotenvModule.config;
384
+ module2.exports.decrypt = DotenvModule.decrypt;
385
+ module2.exports.parse = DotenvModule.parse;
386
+ module2.exports.populate = DotenvModule.populate;
387
+ module2.exports = DotenvModule;
388
+ }
389
+ });
390
+
391
+ // node_modules/dotenv/lib/env-options.js
392
+ var require_env_options = __commonJS({
393
+ "node_modules/dotenv/lib/env-options.js"(exports2, module2) {
394
+ var options = {};
395
+ if (process.env.DOTENV_CONFIG_ENCODING != null) {
396
+ options.encoding = process.env.DOTENV_CONFIG_ENCODING;
397
+ }
398
+ if (process.env.DOTENV_CONFIG_PATH != null) {
399
+ options.path = process.env.DOTENV_CONFIG_PATH;
400
+ }
401
+ if (process.env.DOTENV_CONFIG_QUIET != null) {
402
+ options.quiet = process.env.DOTENV_CONFIG_QUIET;
403
+ }
404
+ if (process.env.DOTENV_CONFIG_DEBUG != null) {
405
+ options.debug = process.env.DOTENV_CONFIG_DEBUG;
406
+ }
407
+ if (process.env.DOTENV_CONFIG_OVERRIDE != null) {
408
+ options.override = process.env.DOTENV_CONFIG_OVERRIDE;
409
+ }
410
+ if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) {
411
+ options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY;
412
+ }
413
+ module2.exports = options;
414
+ }
415
+ });
416
+
417
+ // node_modules/dotenv/lib/cli-options.js
418
+ var require_cli_options = __commonJS({
419
+ "node_modules/dotenv/lib/cli-options.js"(exports2, module2) {
420
+ var re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/;
421
+ module2.exports = function optionMatcher(args) {
422
+ const options = args.reduce(function(acc, cur) {
423
+ const matches = cur.match(re);
424
+ if (matches) {
425
+ acc[matches[1]] = matches[2];
426
+ }
427
+ return acc;
428
+ }, {});
429
+ if (!("quiet" in options)) {
430
+ options.quiet = "true";
431
+ }
432
+ return options;
433
+ };
434
+ }
435
+ });
436
+
36
437
  // node_modules/ajv/dist/compile/codegen/code.js
37
438
  var require_code = __commonJS({
38
439
  "node_modules/ajv/dist/compile/codegen/code.js"(exports2) {
@@ -10568,34 +10969,51 @@ var require_websocket_server = __commonJS({
10568
10969
  }
10569
10970
  });
10570
10971
 
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_stream2.default,
10580
- default: () => wrapper_default,
10581
- extension: () => import_extension.default,
10582
- subprotocol: () => import_subprotocol.default
10583
- });
10584
- var import_stream2, 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_stream2 = __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;
10972
+ // node_modules/@colbymchenry/codegraph/npm-sdk.js
10973
+ var require_npm_sdk = __commonJS({
10974
+ "node_modules/@colbymchenry/codegraph/npm-sdk.js"(exports2, module2) {
10975
+ "use strict";
10976
+ var path2 = require("path");
10977
+ var os2 = require("os");
10978
+ var fs2 = require("fs");
10979
+ var target = process.platform + "-" + process.arch;
10980
+ var pkg = "@colbymchenry/codegraph-" + target;
10981
+ module2.exports = require(resolveLibrary());
10982
+ function resolveLibrary() {
10983
+ try {
10984
+ return require.resolve(pkg + "/lib/dist/index.js");
10985
+ } catch (e) {
10986
+ }
10987
+ var cached2 = cachedLibrary();
10988
+ if (cached2) return cached2;
10989
+ throw new Error(
10990
+ "codegraph: the programmatic API is unavailable because the platform bundle\n(" + pkg + ") is not installed.\nThe compiled library ships inside that per-platform optional dependency.\nFixes:\n - install from the official npm registry so the matching bundle is fetched:\n npm i @colbymchenry/codegraph --registry=https://registry.npmjs.org\n - or run the CLI once (e.g. `npx @colbymchenry/codegraph status`) to\n self-heal the bundle into ~/.codegraph, then require() will find it."
10991
+ );
10992
+ }
10993
+ function cachedLibrary() {
10994
+ try {
10995
+ var version2 = require(path2.join(__dirname, "package.json")).version;
10996
+ var base = process.env.CODEGRAPH_INSTALL_DIR || path2.join(os2.homedir(), ".codegraph");
10997
+ var lib = path2.join(base, "bundles", target + "-" + version2, "lib", "dist", "index.js");
10998
+ if (fs2.existsSync(lib)) return lib;
10999
+ } catch (e) {
11000
+ }
11001
+ return null;
11002
+ }
10596
11003
  }
10597
11004
  });
10598
11005
 
11006
+ // node_modules/dotenv/config.js
11007
+ (function() {
11008
+ require_main().config(
11009
+ Object.assign(
11010
+ {},
11011
+ require_env_options(),
11012
+ require_cli_options()(process.argv)
11013
+ )
11014
+ );
11015
+ })();
11016
+
10599
11017
  // src/index.ts
10600
11018
  var import_node_http = require("node:http");
10601
11019
 
@@ -26665,24 +27083,181 @@ function toResult(data) {
26665
27083
  }
26666
27084
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
26667
27085
  }
27086
+ var OKX_ERROR_MESSAGES = {
27087
+ // 公共 / 系统
27088
+ 5e4: "\u7CFB\u7EDF\u5185\u90E8\u9519\u8BEF",
27089
+ 50001: "\u7CFB\u7EDF\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
27090
+ 50002: "\u7CFB\u7EDF\u5347\u7EA7\u7EF4\u62A4\u4E2D",
27091
+ 50004: "\u8BF7\u6C42\u8D85\u65F6",
27092
+ 50005: "\u63A5\u53E3\u5DF2\u88AB\u51BB\u7ED3\uFF0C\u8BF7\u8054\u7CFB\u5BA2\u670D",
27093
+ 50006: "OK-ACCESS-KEY \u65E0\u6548",
27094
+ 50007: "OK-ACCESS-SIGN \u7B7E\u540D\u9519\u8BEF",
27095
+ 50008: "OK-ACCESS-TIMESTAMP \u65F6\u95F4\u6233\u65E0\u6548",
27096
+ 50009: "OK-ACCESS-PASSPHRASE \u5BC6\u7801\u77ED\u8BED\u9519\u8BEF",
27097
+ 50010: "\u5F53\u524D IP \u4E0D\u5728 API Key \u767D\u540D\u5355\u4E2D",
27098
+ 50011: "\u8BF7\u6C42\u9891\u7387\u8FC7\u5FEB\uFF0C\u5DF2\u89E6\u53D1\u9650\u6D41\u3002\u8BF7\u964D\u4F4E\u8BF7\u6C42\u901F\u7387",
27099
+ 50012: "\u7CFB\u7EDF\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
27100
+ 50013: "\u7CFB\u7EDF\u9519\u8BEF",
27101
+ 50014: "\u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5FC5\u586B\u5B57\u6BB5\u548C\u683C\u5F0F",
27102
+ 50015: "\u4ED3\u4F4D\u5DF2\u88AB\u51BB\u7ED3",
27103
+ 50016: "\u8D26\u6237\u5DF2\u88AB\u51BB\u7ED3",
27104
+ 50017: "\u8D26\u6237\u5DF2\u88AB\u6682\u505C",
27105
+ 50018: "\u8D26\u6237\u7B49\u7EA7\u4E0D\u8DB3",
27106
+ 50019: "\u5408\u7EA6\u5DF2\u5230\u671F",
27107
+ 50020: "\u4F59\u989D\u4E0D\u8DB3",
27108
+ 50021: "\u4FDD\u8BC1\u91D1\u4E0D\u8DB3",
27109
+ 50022: "\u4E0B\u5355\u6570\u91CF\u5C0F\u4E8E\u6700\u5C0F\u9650\u5236",
27110
+ 50023: "\u4E0B\u5355\u6570\u91CF\u8D85\u8FC7\u6700\u5927\u9650\u5236",
27111
+ 50024: "\u6301\u4ED3\u6570\u91CF\u5DF2\u8FBE\u4E0A\u9650",
27112
+ 50025: "\u6302\u5355\u6570\u91CF\u5DF2\u8FBE\u4E0A\u9650",
27113
+ 50026: "\u4E0B\u5355\u4EF7\u683C\u8D85\u51FA\u9650\u4EF7\u8303\u56F4",
27114
+ 50027: "\u4EF7\u683C\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27115
+ 50028: "\u6570\u91CF\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27116
+ 50029: "\u8BE5\u5408\u7EA6\u6682\u4E0D\u53EF\u7528",
27117
+ 50030: "API Key \u65E0\u6B64\u64CD\u4F5C\u6743\u9650",
27118
+ 50031: "API Key \u5DF2\u8FC7\u671F",
27119
+ 50032: "API Key \u672A\u627E\u5230",
27120
+ 50033: "API Key \u672A\u6FC0\u6D3B",
27121
+ 50035: "\u89E6\u53D1\u98CE\u63A7\u89C4\u5219\uFF0C\u4EA4\u6613\u88AB\u62D2\u7EDD",
27122
+ 50036: "\u65E0\u4EA4\u6613\u6743\u9650",
27123
+ 50044: "\u8BA2\u5355\u4E0D\u5B58\u5728",
27124
+ 50045: "\u8BE5\u8BA2\u5355\u4E0D\u53EF\u64A4\u9500",
27125
+ 50046: "\u8BA2\u5355\u5DF2\u5168\u90E8\u6210\u4EA4",
27126
+ 50047: "\u8BA2\u5355\u5DF2\u88AB\u64A4\u9500",
27127
+ 50050: "\u6301\u4ED3\u4E0D\u5B58\u5728",
27128
+ 50051: "\u4ED3\u4F4D\u5DF2\u5E73\u4ED3",
27129
+ 50053: "\u4ED3\u4F4D\u4FDD\u8BC1\u91D1\u4E0D\u8DB3",
27130
+ 50056: "\u4E0B\u5355\u8FC7\u4E8E\u9891\u7E41",
27131
+ 50058: "\u8BE5\u5E01\u79CD\u6682\u4E0D\u652F\u6301",
27132
+ 50059: "\u53C2\u6570\u89E3\u6790\u5931\u8D25",
27133
+ 50060: "\u8D26\u6237\u6A21\u5F0F\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C",
27134
+ 50061: "\u5B50\u8D26\u6237\u8BF7\u6C42\u9891\u7387\u8D85\u9650",
27135
+ 50064: "\u8BE5\u5408\u7EA6\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C",
27136
+ 50068: "\u7CFB\u7EDF\u5347\u7EA7\u4E2D\uFF0C\u6682\u4E0D\u53EF\u7528",
27137
+ 50070: "\u6301\u4ED3\u6A21\u5F0F\u4E0D\u5339\u914D",
27138
+ 50071: "\u4FDD\u8BC1\u91D1\u6A21\u5F0F\u4E0D\u5339\u914D",
27139
+ 50072: "\u6760\u6746\u500D\u6570\u8D85\u51FA\u5141\u8BB8\u8303\u56F4",
27140
+ 50074: "\u89E6\u53D1\u4EF7\u683C\u65E0\u6548",
27141
+ 50080: "\u4E0B\u5355\u4EF7\u683C\u504F\u79BB\u5E02\u573A\u4EF7\u8FC7\u5927",
27142
+ 50082: "\u8D26\u6237\u6743\u76CA\u4E0D\u8DB3",
27143
+ // API Key 相关
27144
+ 50100: "API Key \u5DF2\u88AB\u51BB\u7ED3",
27145
+ 50101: "API Key \u5DF2\u8FC7\u671F",
27146
+ 50102: "\u8BF7\u6C42\u65F6\u95F4\u6233\u4E0E\u670D\u52A1\u5668\u65F6\u95F4\u504F\u5DEE\u8D85\u8FC7 30 \u79D2",
27147
+ 50103: "\u8BF7\u6C42\u5934 OK-ACCESS-KEY \u4E0D\u80FD\u4E3A\u7A7A",
27148
+ 50104: "\u8BF7\u6C42\u5934 OK-ACCESS-SIGN \u7B7E\u540D\u4E0D\u80FD\u4E3A\u7A7A",
27149
+ 50105: "\u8BF7\u6C42\u5934 OK-ACCESS-TIMESTAMP \u4E0D\u80FD\u4E3A\u7A7A",
27150
+ 50106: "\u8BF7\u6C42\u5934 OK-ACCESS-PASSPHRASE \u4E0D\u80FD\u4E3A\u7A7A",
27151
+ 50107: "API Key \u5BF9\u5E94\u7684\u8D26\u6237\u4E0D\u5B58\u5728",
27152
+ 50108: "\u8D26\u6237\u4F59\u989D\u4E0D\u8DB3",
27153
+ 50109: "\u5212\u8F6C\u91D1\u989D\u8D85\u8FC7\u9650\u989D",
27154
+ 50110: "\u5212\u8F6C\u5E01\u79CD\u4E0D\u652F\u6301",
27155
+ 50111: "\u5212\u8F6C\u5931\u8D25",
27156
+ 50120: "API Key \u6743\u9650\u4E0D\u8DB3\uFF0C\u8BF7\u68C0\u67E5\u662F\u5426\u5F00\u901A\u4E86\u6240\u9700\u6743\u9650\uFF08\u8BFB\u53D6/\u4EA4\u6613/\u63D0\u73B0\uFF09",
27157
+ 50121: "API Key \u5DF2\u8FC7\u671F",
27158
+ 50122: "API Key \u672A\u627E\u5230",
27159
+ 50123: "API Key \u672A\u6FC0\u6D3B",
27160
+ 50124: "API Key \u5DF2\u88AB\u5220\u9664",
27161
+ 50125: "API Key \u5DF2\u88AB\u51BB\u7ED3",
27162
+ 50126: "API Key \u5DF2\u88AB\u7981\u7528",
27163
+ // 交易
27164
+ 51e3: "\u53C2\u6570\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u5FC5\u586B\u53C2\u6570",
27165
+ 51001: "\u8BA2\u5355\u7C7B\u578B\u4E0D\u652F\u6301",
27166
+ 51002: "\u8BA2\u5355\u65B9\u5411\u4E0D\u652F\u6301",
27167
+ 51003: "\u8BA2\u5355\u6570\u91CF\u4E0D\u80FD\u4E3A 0 \u6216\u8D1F\u6570",
27168
+ 51004: "\u8BA2\u5355\u4EF7\u683C\u4E0D\u80FD\u4E3A 0 \u6216\u8D1F\u6570",
27169
+ 51005: "\u4FDD\u8BC1\u91D1\u6A21\u5F0F\u4E0D\u652F\u6301",
27170
+ 51006: "\u8BA2\u5355\u4EF7\u683C\u8D85\u51FA\u9650\u4EF7\u8303\u56F4",
27171
+ 51007: "\u8BA2\u5355\u6570\u91CF\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27172
+ 51008: "\u8BA2\u5355\u4EF7\u683C\u7CBE\u5EA6\u4E0D\u7B26\u5408\u8981\u6C42",
27173
+ 51009: "\u8BA2\u5355\u6570\u91CF\u8D85\u51FA\u6700\u5927\u9650\u5236",
27174
+ 51010: "\u8BA2\u5355\u6570\u91CF\u4F4E\u4E8E\u6700\u5C0F\u9650\u5236",
27175
+ 51011: "\u8BE5\u4EA7\u54C1\u4E0D\u652F\u6301\u6B64\u8BA2\u5355\u7C7B\u578B",
27176
+ 51012: "\u8BE5\u4EA7\u54C1\u4E0D\u652F\u6301\u6B64\u4FDD\u8BC1\u91D1\u6A21\u5F0F",
27177
+ 51013: "\u8BE5\u4EA7\u54C1\u4E0D\u652F\u6301\u6B64\u6301\u4ED3\u6A21\u5F0F",
27178
+ 51014: "\u5F53\u524D\u6301\u4ED3\u6A21\u5F0F\u4E0D\u5141\u8BB8\u6B64\u64CD\u4F5C",
27179
+ 51015: "\u5F53\u524D\u8D26\u6237\u6A21\u5F0F\u4E0D\u5141\u8BB8\u6B64\u64CD\u4F5C",
27180
+ 51020: "\u6279\u91CF\u4E0B\u5355\u6570\u91CF\u8D85\u8FC7\u4E0A\u9650",
27181
+ 51021: "\u6279\u91CF\u64CD\u4F5C\u4E2D\u5305\u542B\u91CD\u590D\u8BA2\u5355",
27182
+ 51026: "\u8BA2\u5355\u4EF7\u683C\u8D85\u51FA\u6ED1\u70B9\u4FDD\u62A4\u8303\u56F4",
27183
+ 51027: "\u8BA2\u5355\u5DF2\u8FC7\u671F",
27184
+ 51100: "\u8BE5\u4EA7\u54C1\u4E0D\u5728\u53EF\u4EA4\u6613\u5217\u8868",
27185
+ 51102: "\u6301\u4ED3\u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u65E0\u6CD5\u5E73\u4ED3",
27186
+ 51103: "\u4FDD\u8BC1\u91D1\u6A21\u5F0F\u4E0D\u5339\u914D\uFF0C\u65E0\u6CD5\u5E73\u4ED3",
27187
+ 51104: "\u6760\u6746\u500D\u6570\u4E0D\u5339\u914D",
27188
+ 51107: "\u5E02\u4EF7\u5355\u5F53\u524D\u4E0D\u53EF\u7528",
27189
+ 51108: "\u6B62\u635F\u5355\u5F53\u524D\u4E0D\u53EF\u7528",
27190
+ // 资金
27191
+ 52e3: "\u5212\u8F6C\u5931\u8D25",
27192
+ 52001: "\u63D0\u73B0\u91D1\u989D\u8D85\u8FC7\u9650\u989D",
27193
+ 52002: "\u63D0\u73B0\u5730\u5740\u65E0\u6548",
27194
+ 52003: "\u63D0\u73B0\u94FE\u4E0D\u652F\u6301",
27195
+ 52004: "\u63D0\u73B0\u7F51\u7EDC\u8D39\u4E0D\u8DB3",
27196
+ 52005: "\u63D0\u73B0\u5DF2\u51BB\u7ED3",
27197
+ 52006: "\u5145\u503C\u5730\u5740\u751F\u6210\u5931\u8D25",
27198
+ 52007: "\u8BE5\u5E01\u79CD\u4E0D\u652F\u6301\u5145\u503C",
27199
+ 52008: "\u8BE5\u5E01\u79CD\u4E0D\u652F\u6301\u63D0\u73B0",
27200
+ // 跟单交易
27201
+ 52100: "\u4EA4\u6613\u5458\u4E0D\u5B58\u5728",
27202
+ 52101: "\u4EA4\u6613\u5458\u4E0D\u5BF9\u5916\u516C\u5F00",
27203
+ 52102: "\u8DDF\u5355\u91D1\u989D\u8D85\u51FA\u9650\u5236",
27204
+ 52103: "\u8DDF\u5355\u4EBA\u6570\u5DF2\u8FBE\u4E0A\u9650",
27205
+ 52104: "\u5F53\u524D\u4E0D\u652F\u6301\u8DDF\u5355\u8BE5\u4EA4\u6613\u5458",
27206
+ 52105: "\u8BE5\u4EA4\u6613\u5458\u5DF2\u505C\u6B62\u5E26\u5355",
27207
+ // 策略 / 网格
27208
+ 53e3: "\u7B56\u7565\u59D4\u6258\u521B\u5EFA\u5931\u8D25",
27209
+ 53001: "\u7B56\u7565\u59D4\u6258\u4FEE\u6539\u5931\u8D25",
27210
+ 53002: "\u7B56\u7565\u59D4\u6258\u64A4\u9500\u5931\u8D25",
27211
+ 53003: "\u7B56\u7565\u59D4\u6258\u4E0D\u5B58\u5728",
27212
+ 53004: "\u7B56\u7565\u59D4\u6258\u5DF2\u89E6\u53D1",
27213
+ 53005: "\u7F51\u683C\u7B56\u7565\u521B\u5EFA\u5931\u8D25",
27214
+ 53006: "\u7F51\u683C\u7B56\u7565\u4E0D\u5B58\u5728",
27215
+ 53007: "\u7F51\u683C\u7B56\u7565\u5DF2\u505C\u6B62",
27216
+ 53008: "\u7F51\u683C\u53C2\u6570\u65E0\u6548",
27217
+ // WebSocket
27218
+ 60001: "\u8BA2\u9605\u9891\u9053\u4E0D\u5B58\u5728\u6216\u53C2\u6570\u9519\u8BEF",
27219
+ 60002: "WebSocket \u767B\u5F55\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 API Key",
27220
+ 60003: "WebSocket \u8BA2\u9605\u53C2\u6570\u65E0\u6548",
27221
+ 60004: "WebSocket \u8BF7\u6C42\u9891\u7387\u8FC7\u9AD8",
27222
+ 60005: "WebSocket \u8FDE\u63A5\u6570\u5DF2\u8FBE\u4E0A\u9650",
27223
+ 60006: "WebSocket \u8FDE\u63A5\u88AB\u670D\u52A1\u7AEF\u5173\u95ED",
27224
+ 60007: "WebSocket \u8BE5\u9891\u9053\u9700\u8981\u767B\u5F55",
27225
+ 60008: "WebSocket \u8BE5\u9891\u9053\u4E0D\u9700\u8981\u767B\u5F55",
27226
+ 60009: "WebSocket \u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55",
27227
+ 64008: "\u670D\u52A1\u5347\u7EA7\u4E2D\uFF0C\u8FDE\u63A5\u5373\u5C06\u5173\u95ED\uFF0C\u8BF7\u91CD\u8FDE"
27228
+ };
27229
+ function translateError(code, rawMsg) {
27230
+ const translated = OKX_ERROR_MESSAGES[code];
27231
+ if (translated) return translated;
27232
+ if (code >= 5e4 && code < 50100) return `\u7CFB\u7EDF/\u8BA4\u8BC1\u9519\u8BEF (${code}): ${rawMsg}`;
27233
+ if (code >= 50100 && code < 50200) return `API Key \u9519\u8BEF (${code}): ${rawMsg}`;
27234
+ if (code >= 51e3 && code < 51200) return `\u4EA4\u6613\u53C2\u6570\u9519\u8BEF (${code}): ${rawMsg}`;
27235
+ if (code >= 52e3 && code < 52200) return `\u8D44\u91D1/\u8DDF\u5355\u9519\u8BEF (${code}): ${rawMsg}`;
27236
+ if (code >= 53e3 && code < 54e3) return `\u7B56\u7565\u59D4\u6258\u9519\u8BEF (${code}): ${rawMsg}`;
27237
+ if (code >= 6e4 && code < 65e3) return `WebSocket \u9519\u8BEF (${code}): ${rawMsg}`;
27238
+ return rawMsg;
27239
+ }
26668
27240
  function classifyError(msg) {
26669
27241
  const okxMatch = msg.match(/OKX (\d+):/);
26670
27242
  if (okxMatch && okxMatch[1]) {
26671
27243
  const code = parseInt(okxMatch[1]);
26672
- if (code >= 5e4 && code < 50100) return { errorCode: `OKX_${code}`, errorCategory: "AUTH" };
26673
- if (code >= 51e3) return { errorCode: `OKX_${code}`, errorCategory: "BUSINESS" };
26674
- if (code >= 50004 && code <= 50014) return { errorCode: `OKX_${code}`, errorCategory: "VALIDATION" };
26675
- return { errorCode: `OKX_${code}`, errorCategory: "BUSINESS" };
27244
+ const rawMsg = msg.replace(/^OKX \d+: /, "");
27245
+ const translated = translateError(code, rawMsg);
27246
+ if (code >= 5e4 && code < 50100) return { errorCode: `OKX_${code}`, errorCategory: "AUTH", errorMessage: translated };
27247
+ if (code === 50100 || code === 50101 || code === 50120) return { errorCode: `OKX_${code}`, errorCategory: "AUTH", errorMessage: translated };
27248
+ if (code >= 50004 && code <= 50014) return { errorCode: `OKX_${code}`, errorCategory: "VALIDATION", errorMessage: translated };
27249
+ if (code >= 51e3 && code < 51200) return { errorCode: `OKX_${code}`, errorCategory: "VALIDATION", errorMessage: translated };
27250
+ return { errorCode: `OKX_${code}`, errorCategory: "BUSINESS", errorMessage: translated };
26676
27251
  }
26677
27252
  if (msg.startsWith("HTTP ")) {
26678
27253
  const httpMatch = msg.match(/HTTP (\d+)/);
26679
27254
  const status = httpMatch && httpMatch[1] ? parseInt(httpMatch[1]) : 0;
26680
- if (status === 401 || status === 403) return { errorCode: "HTTP_401", errorCategory: "AUTH" };
26681
- if (status === 429) return { errorCode: "HTTP_429", errorCategory: "RATE_LIMIT" };
26682
- return { errorCode: "NETWORK_ERROR", errorCategory: "NETWORK" };
27255
+ if (status === 401 || status === 403) return { errorCode: "HTTP_401", errorCategory: "AUTH", errorMessage: "API Key \u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5BC6\u94A5\u662F\u5426\u6B63\u786E\u914D\u7F6E" };
27256
+ if (status === 429) return { errorCode: "HTTP_429", errorCategory: "RATE_LIMIT", errorMessage: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u5DF2\u89E6\u53D1\u9650\u6D41\u3002\u8BF7\u7A0D\u7B49\u540E\u91CD\u8BD5" };
27257
+ return { errorCode: "NETWORK_ERROR", errorCategory: "NETWORK", errorMessage: `\u7F51\u7EDC\u9519\u8BEF HTTP ${status}` };
26683
27258
  }
26684
- if (msg.includes("API Key")) return { errorCode: "AUTH_REQUIRED", errorCategory: "AUTH" };
26685
- return { errorCode: "UNKNOWN_ERROR", errorCategory: "BUSINESS" };
27259
+ if (msg.includes("API Key")) return { errorCode: "AUTH_REQUIRED", errorCategory: "AUTH", errorMessage: msg };
27260
+ return { errorCode: "UNKNOWN_ERROR", errorCategory: "BUSINESS", errorMessage: msg };
26686
27261
  }
26687
27262
  function classifyRisk(toolName) {
26688
27263
  const admin = ["okx_set_account_mode", "okx_set_position_mode", "okx_set_settle_currency"];
@@ -26737,12 +27312,13 @@ function classifyRisk(toolName) {
26737
27312
  }
26738
27313
  function toError(e) {
26739
27314
  const msg = e instanceof Error ? e.message : String(e);
26740
- const { errorCode, errorCategory } = classifyError(msg);
27315
+ const { errorCode, errorCategory, errorMessage } = classifyError(msg);
26741
27316
  return {
26742
- content: [{ type: "text", text: msg }],
27317
+ content: [{ type: "text", text: errorMessage }],
26743
27318
  isError: true,
26744
27319
  errorCode,
26745
- errorCategory
27320
+ errorCategory,
27321
+ errorMessage
26746
27322
  };
26747
27323
  }
26748
27324
 
@@ -33757,12 +34333,13 @@ function registerAgentUtils(server, auth) {
33757
34333
  },
33758
34334
  {
33759
34335
  domain: "WebSocket \u5B9E\u65F6",
33760
- what: "\u5B9E\u65F6\u884C\u60C5\u63A8\u9001\u3001\u6210\u4EA4\u63A8\u9001",
33761
- when: ["\u5B9E\u65F6", "\u8BA2\u9605", "\u63A8\u9001", "websocket", "ws", "\u76D1\u542C"],
34336
+ what: "\u5B9E\u65F6\u884C\u60C5\u3001\u8D26\u6237\u3001\u8BA2\u5355\u3001\u7206\u4ED3\u3001\u4EF7\u5DEE\u3001\u5927\u5B97\u63A8\u9001\uFF0855 \u9891\u9053\uFF09",
34337
+ when: ["\u5B9E\u65F6", "\u8BA2\u9605", "\u63A8\u9001", "websocket", "ws", "\u76D1\u542C", "\u7206\u4ED3", "\u5B9E\u65F6\u8BA2\u5355"],
33762
34338
  go_to: "okx_ws_subscribe",
33763
34339
  also: [
33764
- "okx_ws_events \u2014 \u83B7\u53D6\u63A8\u9001\u4E8B\u4EF6",
33765
- "okx_ws_status \u2014 \u8BA2\u9605\u72B6\u6001",
34340
+ "okx_ws_subscribe_private \u2014 \u79C1\u6709\u9891\u9053\uFF08\u8D26\u6237/\u6301\u4ED3/\u8BA2\u5355\uFF0C\u9700Key\uFF09",
34341
+ "okx_ws_events \u2014 \u62C9\u53D6\u7F13\u51B2\u4E8B\u4EF6",
34342
+ "okx_ws_status \u2014 \u67E5\u770B\u8BA2\u9605\u72B6\u6001",
33766
34343
  "okx_ws_close \u2014 \u5173\u95ED\u8BA2\u9605"
33767
34344
  ],
33768
34345
  risk: "READ"
@@ -33779,6 +34356,16 @@ function registerAgentUtils(server, auth) {
33779
34356
  ],
33780
34357
  risk: "READ"
33781
34358
  },
34359
+ {
34360
+ domain: "\u4EE3\u7801\u667A\u80FD",
34361
+ what: "\u67E5\u8BE2 hvip-mcp \u81EA\u8EAB\u4EE3\u7801\u7ED3\u6784\uFF1A\u51FD\u6570\u8C03\u7528\u94FE\u3001\u6A21\u5757\u4F9D\u8D56\u3001\u7B26\u53F7\u641C\u7D22",
34362
+ when: ["\u4EE3\u7801\u7ED3\u6784", "\u8C03\u7528\u94FE", "\u8C01\u8C03\u7528\u4E86", "\u8C01\u88AB\u8C03\u7528", "\u4F9D\u8D56\u5173\u7CFB", "\u4E0A\u4E0B\u6E38", "\u4EE3\u7801\u641C\u7D22"],
34363
+ go_to: "codegraph_status",
34364
+ also: [
34365
+ "codegraph_query \u2014 \u8C03\u7528\u94FE\u8FFD\u8E2A (callers/callees/explore/files)"
34366
+ ],
34367
+ risk: "READ"
34368
+ },
33782
34369
  {
33783
34370
  domain: "\u7CFB\u7EDF\u5DE5\u5177",
33784
34371
  what: "\u504F\u597D\u8BBE\u7F6E\u3001\u53CD\u9988\u7559\u8A00\u3001Agent\u96C6\u7FA4\u7BA1\u7406",
@@ -33844,7 +34431,8 @@ function registerAgentUtils(server, auth) {
33844
34431
  "agent_get_preference": "key? (\u4E0D\u586B\u8FD4\u56DE\u5168\u90E8)",
33845
34432
  "agent_set_preference": "key, value",
33846
34433
  "okx_event_instruments": "eventType? (\u4E0D\u586B\u8FD4\u56DE\u5168\u90E8)",
33847
- "okx_ws_subscribe": "channels (JSON\u6570\u7EC4)",
34434
+ "okx_ws_subscribe": "instId (\u4EA7\u54C1ID), channel (33\u4E2A\u516C\u5F00\u9891\u9053)",
34435
+ "okx_ws_subscribe_private": "instId? (\u4EA7\u54C1ID), channel (22\u4E2A\u79C1\u6709\u9891\u9053\uFF0C\u9700Key)",
33848
34436
  "okx_get_grid_ai_param": "instType, algoOrdType"
33849
34437
  };
33850
34438
  const enrichedDomains = CATALOG.domains.map((d) => ({
@@ -34045,12 +34633,13 @@ function registerAgentUtils(server, auth) {
34045
34633
  ]
34046
34634
  },
34047
34635
  "WebSocket \u5B9E\u65F6": {
34048
- workflow: "okx_ws_subscribe \u8BA2\u9605\u9891\u9053 \u2192 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6",
34636
+ workflow: "okx_ws_subscribe \u516C\u5F00\u9891\u9053 \u2192 okx_ws_subscribe_private \u79C1\u6709\u9891\u9053\uFF08\u9700Key\uFF09\u2192 okx_ws_events \u62C9\u53D6 \u2192 okx_ws_status \u7BA1\u7406",
34049
34637
  tools: [
34050
- { name: "okx_ws_subscribe", auth: "\u516C\u5F00", params: "channels[]", what: "\u8BA2\u9605\u5B9E\u65F6\u9891\u9053\uFF08tickers/trades/books/candles/fundingRate \u7B49\uFF09" },
34051
- { name: "okx_ws_events", auth: "\u516C\u5F00", params: "channel?", what: "\u6536\u53D6\u8BA2\u9605\u7684\u5B9E\u65F6\u63A8\u9001\u4E8B\u4EF6" },
34052
- { name: "okx_ws_status", auth: "\u516C\u5F00", params: "\u65E0", what: "\u5F53\u524D\u8BA2\u9605\u72B6\u6001" },
34053
- { name: "okx_ws_close", auth: "\u516C\u5F00", params: "channel?", what: "\u53D6\u6D88\u8BA2\u9605" }
34638
+ { name: "okx_ws_subscribe", auth: "\u516C\u5F00", params: "instId, channel (33\u516C\u5F00\u9891\u9053)", what: "\u8BA2\u9605\u516C\u5F00\u9891\u9053\uFF1A\u884C\u60C5/\u6DF1\u5EA6/\u7206\u4ED3/\u4EF7\u5DEE/\u5927\u5B97/\u8D44\u91D1\u8D39\u7387\u7B49" },
34639
+ { name: "okx_ws_subscribe_private", auth: "API Key", params: "instId?, channel (22\u79C1\u6709\u9891\u9053)", what: "\u8BA2\u9605\u79C1\u6709\u9891\u9053\uFF1A\u8D26\u6237/\u6301\u4ED3/\u8BA2\u5355/\u7F51\u683C/\u8DDF\u5355\u7B49\u5B9E\u65F6\u63A8\u9001" },
34640
+ { name: "okx_ws_events", auth: "\u516C\u5F00", params: "subscriptionId?, limit?, filter?", what: "\u62C9\u53D6\u7F13\u51B2\u7684\u5B9E\u65F6\u4E8B\u4EF6" },
34641
+ { name: "okx_ws_status", auth: "\u516C\u5F00", params: "\u65E0", what: "\u5F53\u524D\u6240\u6709\u8BA2\u9605+\u7F13\u51B2\u79EF\u538B" },
34642
+ { name: "okx_ws_close", auth: "\u516C\u5F00", params: "subscriptionId?", what: "\u5173\u95ED\u8BA2\u9605" }
34054
34643
  ]
34055
34644
  },
34056
34645
  "\u6A21\u62DF\u4F30\u7B97": {
@@ -34061,6 +34650,13 @@ function registerAgentUtils(server, auth) {
34061
34650
  { name: "okx_position_builder", auth: "API Key (\u4EA4\u6613)", params: "body(JSON)", what: "\u7EC4\u5408\u4FDD\u8BC1\u91D1\u8BD5\u7B97 \u2014 WRITE" }
34062
34651
  ]
34063
34652
  },
34653
+ "\u4EE3\u7801\u667A\u80FD": {
34654
+ workflow: "codegraph_status \u770B\u72B6\u6001 \u2192 codegraph_query \u8FFD\u8E2A\u8C03\u7528\u94FE/\u641C\u7D22\u7B26\u53F7 \u2192 \u7528 Read \u770B\u6E90\u7801\u7EC6\u8282",
34655
+ tools: [
34656
+ { name: "codegraph_status", auth: "\u516C\u5F00", params: "\u65E0", what: "\u77E5\u8BC6\u56FE\u8C31\u72B6\u6001\uFF1A\u8282\u70B9\u6570/\u8FB9\u6570/\u8986\u76D6\u6587\u4EF6/\u6700\u540E\u7D22\u5F15" },
34657
+ { name: "codegraph_query", auth: "\u516C\u5F00", params: "mode (callers|callees|explore|files), symbol?, question?, limit?", what: "\u67E5\u8BE2\u8C03\u7528\u94FE / \u7B26\u53F7\u641C\u7D22 / \u6A21\u5757\u4F9D\u8D56 / \u6309\u6587\u4EF6\u67E5" }
34658
+ ]
34659
+ },
34064
34660
  "\u7CFB\u7EDF\u5DE5\u5177": {
34065
34661
  workflow: "\u6309\u9700\u8C03\u7528\uFF0C\u5404\u5DE5\u5177\u72EC\u7ACB",
34066
34662
  tools: [
@@ -34086,7 +34682,7 @@ function registerAgentUtils(server, auth) {
34086
34682
  "agent_catalog_detail",
34087
34683
  "CAT:[\u7CFB\u7EDF] | ## \u529F\u80FD\uFF1A\u67E5\u770B\u67D0\u4E2A\u4E1A\u52A1\u57DF\u7684\u8BE6\u7EC6\u5DE5\u5177\u6E05\u5355\u2014\u2014\u542B\u6BCF\u4E2A\u5DE5\u5177\u7684\u53C2\u6570\u63D0\u793A\u3001\u9274\u6743\u8981\u6C42\u3001\u63A8\u8350\u8C03\u7528\u987A\u5E8F\n## \u573A\u666F\uFF1AAgent \u5728 agent_catalog \u786E\u5B9A\u57DF\u540E\uFF0C\u8C03\u7528\u6B64\u5DE5\u5177\u83B7\u53D6\u8BE5\u57DF\u6240\u6709\u5DE5\u5177\u7684\u7CBE\u51C6\u4FE1\u606F\u3001\u53C2\u6570\u63D0\u793A\u548C\u5178\u578B workflow\n## \u5173\u952E\u8BCD\uFF1A\u76EE\u5F55\u8BE6\u60C5, catalog detail, \u5DE5\u5177\u6E05\u5355, \u57DF\u8BE6\u60C5, workflow\n## \u53C2\u6570\uFF1A\n## - domain: \u57DF\u540D\u79F0\u3002\u53EF\u53D6\u503C: \u8D26\u6237\u8D44\u4EA7 | \u884C\u60C5\u770B\u76D8 | \u4E0B\u5355\u4EA4\u6613 | \u98CE\u9669\u98CE\u63A7 | \u5E02\u573A\u626B\u63CF | \u76C8\u4E8F\u590D\u76D8 | \u8D44\u91D1\u7BA1\u7406 | \u7B56\u7565\u4EA4\u6613 | \u9884\u6D4B\u5E02\u573A | WebSocket \u5B9E\u65F6 | \u6A21\u62DF\u4F30\u7B97 | \u7CFB\u7EDF\u5DE5\u5177\n## \u9274\u6743\uFF1APUBLIC \u2014 \u7EAF\u7D22\u5F15\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~2KB \u2014 \u5355\u57DF\u8BE6\u60C5\n## \u5173\u8054\uFF1Aagent_catalog \u9009\u57DF \u2192 \u672C\u5DE5\u5177\u83B7\u53D6\u8BE6\u60C5 \u2192 \u76F4\u63A5\u8C03\u7528\u76EE\u6807\u5DE5\u5177",
34088
34684
  {
34089
- domain: external_exports.string().describe("\u57DF\u540D\u79F0\u3002\u53EF\u9009: \u8D26\u6237\u8D44\u4EA7, \u884C\u60C5\u770B\u76D8, \u6280\u672F\u6307\u6807, \u4E0B\u5355\u4EA4\u6613, \u98CE\u9669\u98CE\u63A7, \u5E02\u573A\u626B\u63CF, \u806A\u660E\u94B1, \u76C8\u4E8F\u590D\u76D8, \u8D44\u91D1\u7BA1\u7406, \u7B56\u7565\u4EA4\u6613, \u9884\u6D4B\u5E02\u573A, WebSocket \u5B9E\u65F6, \u6A21\u62DF\u4F30\u7B97, \u7CFB\u7EDF\u5DE5\u5177")
34685
+ domain: external_exports.string().describe("\u57DF\u540D\u79F0\u3002\u53EF\u9009: \u8D26\u6237\u8D44\u4EA7, \u884C\u60C5\u770B\u76D8, \u6280\u672F\u6307\u6807, \u4E0B\u5355\u4EA4\u6613, \u98CE\u9669\u98CE\u63A7, \u5E02\u573A\u626B\u63CF, \u806A\u660E\u94B1, \u76C8\u4E8F\u590D\u76D8, \u8D44\u91D1\u7BA1\u7406, \u7B56\u7565\u4EA4\u6613, \u9884\u6D4B\u5E02\u573A, \u4EE3\u7801\u667A\u80FD, WebSocket \u5B9E\u65F6, \u6A21\u62DF\u4F30\u7B97, \u7CFB\u7EDF\u5DE5\u5177")
34090
34686
  },
34091
34687
  async ({ domain }) => {
34092
34688
  try {
@@ -34992,8 +35588,18 @@ function registerSmartMoneyTools(server, auth) {
34992
35588
  );
34993
35589
  }
34994
35590
 
35591
+ // node_modules/ws/wrapper.mjs
35592
+ var import_stream2 = __toESM(require_stream(), 1);
35593
+ var import_extension = __toESM(require_extension(), 1);
35594
+ var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
35595
+ var import_receiver = __toESM(require_receiver(), 1);
35596
+ var import_sender = __toESM(require_sender(), 1);
35597
+ var import_subprotocol = __toESM(require_subprotocol(), 1);
35598
+ var import_websocket = __toESM(require_websocket(), 1);
35599
+ var import_websocket_server = __toESM(require_websocket_server(), 1);
35600
+ var wrapper_default = import_websocket.default;
35601
+
34995
35602
  // src/adapters/xlayer-ws.ts
34996
- init_wrapper();
34997
35603
  var WS_URL = process.env.XLAYER_WS_URL || "wss://xlayerws.okx.com";
34998
35604
  var MAX_EVENTS = 500;
34999
35605
  var XLayerWSManager = class {
@@ -35263,25 +35869,47 @@ var subCounter = 0;
35263
35869
  var WsManager = class {
35264
35870
  subscriptions = /* @__PURE__ */ new Map();
35265
35871
  events = [];
35266
- ws = null;
35267
- pingTimer = null;
35268
- channelArgs = /* @__PURE__ */ new Map();
35269
- // channel -> instIds
35872
+ wsPub = null;
35873
+ wsPriv = null;
35874
+ pingPub = null;
35875
+ pingPriv = null;
35876
+ // Fix #1: 按 type 拆分 channelArgs,重连时只遍历同类型
35877
+ channelArgsPub = /* @__PURE__ */ new Map();
35878
+ channelArgsPriv = /* @__PURE__ */ new Map();
35879
+ getWs(type) {
35880
+ return type === "public" ? this.wsPub : this.wsPriv;
35881
+ }
35882
+ setWs(type, ws) {
35883
+ if (type === "public") this.wsPub = ws;
35884
+ else this.wsPriv = ws;
35885
+ }
35886
+ getPing(type) {
35887
+ return type === "public" ? this.pingPub : this.pingPriv;
35888
+ }
35889
+ setPing(type, timer) {
35890
+ if (type === "public") this.pingPub = timer;
35891
+ else this.pingPriv = timer;
35892
+ }
35893
+ getChannelArgs(type) {
35894
+ return type === "public" ? this.channelArgsPub : this.channelArgsPriv;
35895
+ }
35270
35896
  async subscribe(opts) {
35271
- const wsModule = await Promise.resolve().then(() => (init_wrapper(), wrapper_exports));
35272
35897
  const id = `sub_${++subCounter}`;
35273
- this.subscriptions.set(id, { id, channel: opts.channel, instId: opts.instId });
35898
+ const type = opts.type || "public";
35899
+ this.subscriptions.set(id, { id, channel: opts.channel, instId: opts.instId, type });
35274
35900
  const arg = { channel: opts.channel, instId: opts.instId };
35275
- if (!this.ws || this.ws.readyState !== wsModule.WebSocket.OPEN) {
35276
- const url = opts.type === "private" ? WS_PRIVATE : WS_PUBLIC;
35277
- await this.connect(wsModule, url, opts.auth);
35278
- }
35279
- if (this.ws?.readyState === wsModule.WebSocket.OPEN) {
35280
- this.ws.send(JSON.stringify({ op: "subscribe", args: [arg] }));
35281
- }
35282
- const ck = opts.channel;
35283
- if (!this.channelArgs.has(ck)) this.channelArgs.set(ck, /* @__PURE__ */ new Set());
35284
- this.channelArgs.get(ck).add(opts.instId);
35901
+ const currentWs = this.getWs(type);
35902
+ if (!currentWs || currentWs.readyState !== wrapper_default.OPEN) {
35903
+ const url = type === "private" ? WS_PRIVATE : WS_PUBLIC;
35904
+ await this.connect(url, opts.auth, type);
35905
+ }
35906
+ const targetWs = this.getWs(type);
35907
+ if (targetWs?.readyState === wrapper_default.OPEN) {
35908
+ targetWs.send(JSON.stringify({ op: "subscribe", args: [arg] }));
35909
+ }
35910
+ const chanArgs = this.getChannelArgs(type);
35911
+ if (!chanArgs.has(opts.channel)) chanArgs.set(opts.channel, /* @__PURE__ */ new Set());
35912
+ chanArgs.get(opts.channel).add(opts.instId);
35285
35913
  return id;
35286
35914
  }
35287
35915
  drain(subId, limit = 20) {
@@ -35312,37 +35940,60 @@ var WsManager = class {
35312
35940
  }
35313
35941
  close(subId) {
35314
35942
  if (subId) {
35943
+ const sub = this.subscriptions.get(subId);
35944
+ if (sub) {
35945
+ const chanArgs = this.getChannelArgs(sub.type);
35946
+ const instIds = chanArgs.get(sub.channel);
35947
+ if (instIds) {
35948
+ instIds.delete(sub.instId);
35949
+ if (instIds.size === 0) chanArgs.delete(sub.channel);
35950
+ }
35951
+ const ws = this.getWs(sub.type);
35952
+ if (ws?.readyState === wrapper_default.OPEN) {
35953
+ try {
35954
+ ws.send(JSON.stringify({ op: "unsubscribe", args: [{ channel: sub.channel, instId: sub.instId }] }));
35955
+ } catch {
35956
+ }
35957
+ }
35958
+ }
35315
35959
  this.subscriptions.delete(subId);
35316
35960
  this.events = this.events.filter((e) => e.subId !== subId);
35317
35961
  return 1;
35318
35962
  }
35319
35963
  const count = this.subscriptions.size;
35320
35964
  this.subscriptions.clear();
35965
+ this.channelArgsPub.clear();
35966
+ this.channelArgsPriv.clear();
35321
35967
  this.events = [];
35322
- if (this.ws) {
35323
- try {
35324
- this.ws.close();
35325
- } catch {
35968
+ for (const ws of [this.wsPub, this.wsPriv]) {
35969
+ if (ws) {
35970
+ try {
35971
+ ws.close();
35972
+ } catch {
35973
+ }
35326
35974
  }
35327
- ;
35328
- this.ws = null;
35329
35975
  }
35330
- if (this.pingTimer) {
35331
- clearInterval(this.pingTimer);
35332
- this.pingTimer = null;
35976
+ this.wsPub = null;
35977
+ this.wsPriv = null;
35978
+ for (const t of [this.pingPub, this.pingPriv]) {
35979
+ if (t) {
35980
+ clearInterval(t);
35981
+ }
35333
35982
  }
35983
+ this.pingPub = null;
35984
+ this.pingPriv = null;
35334
35985
  return count;
35335
35986
  }
35336
- connect(wsModule, url, auth) {
35987
+ connect(url, auth, type) {
35337
35988
  return new Promise((resolve, reject) => {
35338
- const ws = new wsModule.WebSocket(url);
35989
+ const ws = new wrapper_default(url);
35339
35990
  const timeout = setTimeout(() => {
35340
35991
  ws.close();
35341
35992
  reject(new Error("WS \u8FDE\u63A5\u8D85\u65F6(10s)"));
35342
35993
  }, 1e4);
35343
35994
  ws.on("open", () => {
35344
35995
  clearTimeout(timeout);
35345
- if (auth && url.includes("private")) {
35996
+ if (auth && type === "private") {
35346
35997
  const ts = Math.floor(Date.now() / 1e3).toString();
35347
35998
  const sign2 = import_node_crypto2.default.createHmac("sha256", auth.secret).update(ts + "GET/users/self/verify").digest("base64");
35348
35999
  ws.send(JSON.stringify({
@@ -35350,15 +36001,17 @@ var WsManager = class {
35350
36001
  args: [{ apiKey: auth.apiKey, passphrase: auth.passphrase, timestamp: ts, sign: sign2 }]
35351
36002
  }));
35352
36003
  }
35353
- for (const [channel, instIds] of this.channelArgs) {
36004
+ const chanArgs = this.getChannelArgs(type);
36005
+ for (const [channel, instIds] of chanArgs) {
35354
36006
  for (const instId of instIds) {
35355
36007
  ws.send(JSON.stringify({ op: "subscribe", args: [{ channel, instId }] }));
35356
36008
  }
35357
36009
  }
35358
- this.pingTimer = setInterval(() => {
35359
- if (ws.readyState === wsModule.WebSocket.OPEN) ws.send("ping");
36010
+ const timer = setInterval(() => {
36011
+ if (ws.readyState === wrapper_default.OPEN) ws.send("ping");
35360
36012
  }, 25e3);
35361
- this.ws = ws;
36013
+ this.setPing(type, timer);
36014
+ this.setWs(type, ws);
35362
36015
  resolve();
35363
36016
  });
35364
36017
  ws.on("message", (raw) => {
@@ -35366,6 +36019,22 @@ var WsManager = class {
35366
36019
  const msg = raw.toString();
35367
36020
  if (msg === "pong") return;
35368
36021
  const parsed = JSON.parse(msg);
36022
+ if (parsed.event === "error" && parsed.code) {
36023
+ this.events.push({
36024
+ subId: "__error__",
36025
+ channel: parsed.arg?.channel || "unknown",
36026
+ instId: parsed.arg?.instId || "",
36027
+ ts: Date.now(),
36028
+ data: {
36029
+ error: true,
36030
+ code: parsed.code,
36031
+ message: parsed.msg || "WebSocket \u9519\u8BEF",
36032
+ hint: parsed.code === "60001" ? "\u9891\u9053\u540D\u4E0D\u652F\u6301\u6216\u53C2\u6570\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5 channel \u503C" : parsed.code === "60003" ? "\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u8FDE" : parsed.code === "60009" ? "\u79C1\u6709\u9891\u9053\u9700\u8981\u5148 login\uFF08API Key \u7B7E\u540D\uFF09" : `OKX WS \u9519\u8BEF ${parsed.code}`
36033
+ }
36034
+ });
36035
+ if (this.events.length > 1e4) this.events = this.events.slice(-5e3);
36036
+ return;
36037
+ }
35369
36038
  if (parsed.arg && parsed.data) {
35370
36039
  for (const [id, sub] of this.subscriptions) {
35371
36040
  if (sub.channel === parsed.arg.channel && sub.instId === parsed.arg.instId) {
@@ -35389,11 +36058,12 @@ var WsManager = class {
35389
36058
  reject(err);
35390
36059
  });
35391
36060
  ws.on("close", () => {
35392
- if (this.pingTimer) {
35393
- clearInterval(this.pingTimer);
35394
- this.pingTimer = null;
36061
+ const t = this.getPing(type);
36062
+ if (t) {
36063
+ clearInterval(t);
36064
+ this.setPing(type, null);
35395
36065
  }
35396
- this.ws = null;
36066
+ this.setWs(type, null);
35397
36067
  });
35398
36068
  });
35399
36069
  }
@@ -35405,36 +36075,103 @@ function getOrCreateWs() {
35405
36075
  if (!wsManager) wsManager = new WsManager();
35406
36076
  return wsManager;
35407
36077
  }
35408
- var PUBLIC_CHANNELS = [
35409
- "tickers",
35410
- "trades",
35411
- "candle1m",
35412
- "candle5m",
35413
- "candle15m",
35414
- "candle1H",
35415
- "candle4H",
35416
- "candle1D",
35417
- "books5",
35418
- "books",
35419
- "mark-price",
35420
- "funding-rate",
35421
- "open-interest",
35422
- "price-limit",
35423
- "index-tickers"
35424
- ];
35425
- function registerWsTools(server) {
36078
+ var ALL_CHANNELS = {
36079
+ public: [
36080
+ // 行情类(10)
36081
+ "tickers",
36082
+ "trades",
36083
+ "all-trades",
36084
+ "option-trades",
36085
+ "candle1m",
36086
+ "candle5m",
36087
+ "candle15m",
36088
+ "candle1H",
36089
+ "candle4H",
36090
+ "candle1D",
36091
+ // 深度类(2)
36092
+ "books5",
36093
+ "books",
36094
+ // 市场细节(1)
36095
+ "call-auction-details",
36096
+ // 公共数据(10)
36097
+ "mark-price",
36098
+ "mark-price-candles",
36099
+ "index-tickers",
36100
+ "index-candles",
36101
+ "funding-rate",
36102
+ "open-interest",
36103
+ "price-limit",
36104
+ "instruments",
36105
+ "option-summary",
36106
+ "estimated-price",
36107
+ // 风险预警(3)
36108
+ "liquidation-orders",
36109
+ "adl-warning",
36110
+ "status",
36111
+ // 事件合约(1)
36112
+ "event-contract-markets",
36113
+ // 经济日历(1)
36114
+ "economic-calendar",
36115
+ // 价差公开(4)
36116
+ "sprd/tickers",
36117
+ "sprd/candles",
36118
+ "sprd/order-book",
36119
+ "sprd/public-trades",
36120
+ // 大宗公开(3)
36121
+ "public-structure-block-trades",
36122
+ "public-block-trades",
36123
+ "block-tickers"
36124
+ ],
36125
+ private: [
36126
+ // 账户(5)
36127
+ "account",
36128
+ "positions",
36129
+ "balance_and_position",
36130
+ "position-risk-warning",
36131
+ "account-greeks",
36132
+ // 交易(4)
36133
+ "orders",
36134
+ "fills",
36135
+ "algo-orders",
36136
+ "advance-algo-orders",
36137
+ // 网格(4)
36138
+ "spot-grid-algo-orders",
36139
+ "contract-grid-algo-orders",
36140
+ "grid-positions",
36141
+ "grid-sub-orders",
36142
+ // 定投(1)
36143
+ "recurring-buy-orders",
36144
+ // 跟单(1)
36145
+ "lead-trading-notification",
36146
+ // 资金(2)
36147
+ "deposit-info",
36148
+ "withdrawal-info",
36149
+ // 大宗私有(3)
36150
+ "rfqs",
36151
+ "quotes",
36152
+ "structure-block-trades",
36153
+ // 价差私有(2)
36154
+ "sprd/orders",
36155
+ "sprd/trades"
36156
+ ]
36157
+ };
36158
+ function registerWsTools(server, auth) {
35426
36159
  server.tool(
35427
36160
  "okx_ws_subscribe",
35428
- "CAT:[\u884C\u60C5-WS] | ## \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",
36161
+ "CAT:[\u884C\u60C5-WS] | ## \u529F\u80FD\uFF1A\u8BA2\u9605 OKX WebSocket \u5B9E\u65F6\u516C\u5F00\u9891\u9053\uFF0C\u4E8B\u4EF6\u81EA\u52A8\u7F13\u51B2\u5728\u5185\u5B58\u4E2D\n## \u573A\u666F\uFF1AAgent \u9700\u8981\u5B9E\u65F6\u76D1\u63A7\u884C\u60C5\u3001\u7206\u4ED3\u5355\u3001\u8D44\u91D1\u8D39\u7387\u3001\u4EF7\u5DEE/\u5927\u5B97\u5E02\u573A\u65F6\u8C03\u7528\uFF0C\u66FF\u4EE3 REST \u8F6E\u8BE2\n## \u5173\u952E\u8BCD\uFF1AWebSocket, ws, \u5B9E\u65F6\u63A8\u9001, \u5B9E\u65F6\u884C\u60C5, \u8BA2\u9605, subscribe, \u7206\u4ED3, \u8D44\u91D1\u8D39\u7387, \u4EF7\u5DEE, \u5927\u5B97\n## \u53C2\u6570\uFF1A\n## - instId: \u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT\u3001ETH-USDT-SWAP\u3002status/instruments/economic-calendar \u7B49\u5168\u5C40\u9891\u9053\u4E0D\u9700\u8981 instId\n## - channel: \u9891\u9053\u540D\u3002\u53EF\u9009: tickers / trades / all-trades / candle1m~1D / books5 / books / funding-rate / open-interest / price-limit / instruments / mark-price / mark-price-candles / index-tickers / index-candles / option-summary / estimated-price / liquidation-orders / adl-warning / event-contract-markets / economic-calendar / status / sprd/* / public-*-block-trades / block-tickers\n## \u9274\u6743\uFF1APUBLIC \u2014 \u516C\u5F00\u9891\u9053\uFF0C\u65E0\u9700 API Key\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u8BA2\u9605 \u2192 okx_ws_events \u62C9\u53D6 \u2192 okx_ws_close \u5173\u95ED",
35429
36162
  {
35430
- instId: external_exports.string().describe("\u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT"),
35431
- channel: external_exports.string().describe("\u9891\u9053\u540D"),
35432
- instType: external_exports.enum(["SPOT", "SWAP", "FUTURES", "OPTION"]).optional().describe("tickers/trades \u9700\u8981")
36163
+ instId: external_exports.string().describe("\u4EA7\u54C1ID\uFF0C\u5982 BTC-USDT\u3001ETH-USDT-SWAP\u3002\u7EAF\u5168\u5C40\u9891\u9053\uFF08status/instruments/economic-calendar\uFF09\u53EF\u4F20\u7A7A\u5B57\u7B26\u4E32"),
36164
+ channel: external_exports.string().describe("\u9891\u9053\u540D\u3002\u516C\u5F00\u9891\u9053\u5171 33 \u4E2A\uFF0C\u652F\u6301 tickers/trades/candle1m~1D/books5/books/funding-rate/open-interest/price-limit/instruments/mark-price/mark-price-candles/index-tickers/index-candles/option-summary/estimated-price/liquidation-orders/adl-warning/event-contract-markets/economic-calendar/status/sprd\u7CFB\u5217/public-block-trades\u7CFB\u5217/block-tickers"),
36165
+ instType: external_exports.enum(["SPOT", "SWAP", "FUTURES", "OPTION"]).optional().describe("\u90E8\u5206\u9891\u9053\u9700\u8981\u4EA7\u54C1\u7C7B\u578B")
35433
36166
  },
35434
36167
  async ({ instId, channel }) => {
35435
36168
  try {
35436
- if (!PUBLIC_CHANNELS.includes(channel)) {
35437
- return toError(new Error(`\u9891\u9053 "${channel}" \u4E0D\u652F\u6301\u3002\u652F\u6301: ${PUBLIC_CHANNELS.join(" ")}`));
36169
+ if (!ALL_CHANNELS.public.includes(channel)) {
36170
+ return toError(new Error(
36171
+ `\u9891\u9053 "${channel}" \u975E\u516C\u5F00\u9891\u9053\u3002
36172
+ \u516C\u5F00\u9891\u9053(${ALL_CHANNELS.public.length}\u4E2A): ${ALL_CHANNELS.public.join(" ")}
36173
+ \u79C1\u6709\u9891\u9053\u8BF7\u7528 okx_ws_subscribe_private\u3002`
36174
+ ));
35438
36175
  }
35439
36176
  const ws = getOrCreateWs();
35440
36177
  const subId = await ws.subscribe({ channel, instId: instId.toUpperCase(), type: "public" });
@@ -35443,8 +36180,48 @@ function registerWsTools(server) {
35443
36180
  subscriptionId: subId,
35444
36181
  channel,
35445
36182
  instId: instId.toUpperCase(),
36183
+ type: "public",
36184
+ buffered: ws.countBuffered(subId),
36185
+ hint: `\u5DF2\u8BA2\u9605 ${instId || "\u5168\u5C40"} ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6\u3002`,
36186
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
36187
+ });
36188
+ } catch (e) {
36189
+ return toError(e);
36190
+ }
36191
+ }
36192
+ );
36193
+ server.tool(
36194
+ "okx_ws_subscribe_private",
36195
+ "CAT:[\u884C\u60C5-WS] | ## \u529F\u80FD\uFF1A\u8BA2\u9605 OKX WebSocket \u79C1\u6709\u9891\u9053\u2014\u2014\u5B9E\u65F6\u63A8\u9001\u8D26\u6237\u4F59\u989D\u3001\u6301\u4ED3\u53D8\u52A8\u3001\u8BA2\u5355\u6210\u4EA4\u3001\u7F51\u683C/\u7B56\u7565/\u8DDF\u5355\u72B6\u6001\n## \u573A\u666F\uFF1AAgent \u9700\u8981\u5B9E\u65F6\u8DDF\u8E2A\u8D26\u6237\u53D8\u5316\uFF08\u975E\u8F6E\u8BE2 REST\uFF09\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1AWebSocket, ws, \u79C1\u6709\u9891\u9053, \u5B9E\u65F6\u8D26\u6237, \u8BA2\u5355\u63A8\u9001, positions, orders, \u7F51\u683C, \u8DDF\u5355\n## \u53C2\u6570\uFF1A\n## - instId: \u4EA7\u54C1ID\u3002account/positions/balance_and_position \u7B49\u8D26\u6237\u7EA7\u9891\u9053\u53EF\u4E0D\u4F20\n## - channel: \u79C1\u6709\u9891\u9053\u540D\u3002\u53EF\u9009: account / positions / balance_and_position / position-risk-warning / account-greeks / orders / fills / algo-orders / advance-algo-orders / spot-grid-algo-orders / contract-grid-algo-orders / grid-positions / grid-sub-orders / recurring-buy-orders / lead-trading-notification / deposit-info / withdrawal-info / rfqs / quotes / structure-block-trades / sprd/orders / sprd/trades\n## \u9274\u6743\uFF1A\u26A0\uFE0F \u9700\u8981 API Key\uFF08\u5FC5\u987B\u5F00\u901A\u8BFB\u53D6\u6743\u9650\uFF09\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\u8BA2\u9605\uFF0C\u4F46\u9700 API Key\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~500B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u8BA2\u9605 \u2192 okx_ws_events \u62C9\u53D6 \u2192 okx_ws_close \u5173\u95ED",
36196
+ {
36197
+ instId: external_exports.string().optional().describe("\u4EA7\u54C1ID\u3002\u8D26\u6237\u7EA7\u9891\u9053\u53EF\u4E0D\u4F20\uFF08\u5982 account/positions/balances\uFF09"),
36198
+ channel: external_exports.string().describe("\u79C1\u6709\u9891\u9053\u540D\u3002\u5171 22 \u4E2A: account / positions / balance_and_position / position-risk-warning / account-greeks / orders / fills / algo-orders / advance-algo-orders / spot-grid-algo-orders / contract-grid-algo-orders / grid-positions / grid-sub-orders / recurring-buy-orders / lead-trading-notification / deposit-info / withdrawal-info / rfqs / quotes / structure-block-trades / sprd/orders / sprd/trades")
36199
+ },
36200
+ async ({ instId, channel }) => {
36201
+ if (!auth) return toError(AUTH_REQUIRED);
36202
+ try {
36203
+ if (!ALL_CHANNELS.private.includes(channel)) {
36204
+ return toError(new Error(
36205
+ `\u9891\u9053 "${channel}" \u975E\u79C1\u6709\u9891\u9053\u3002
36206
+ \u79C1\u6709\u9891\u9053(${ALL_CHANNELS.private.length}\u4E2A): ${ALL_CHANNELS.private.join(" ")}
36207
+ \u516C\u5F00\u9891\u9053\u8BF7\u7528 okx_ws_subscribe\u3002`
36208
+ ));
36209
+ }
36210
+ const ws = getOrCreateWs();
36211
+ const subId = await ws.subscribe({
36212
+ channel,
36213
+ instId: (instId || "").toUpperCase(),
36214
+ type: "private",
36215
+ auth
36216
+ });
36217
+ return toResult({
36218
+ subscribed: true,
36219
+ subscriptionId: subId,
36220
+ channel,
36221
+ instId: (instId || "\u5168\u5C40").toUpperCase(),
36222
+ type: "private",
35446
36223
  buffered: ws.countBuffered(subId),
35447
- hint: `\u5DF2\u8BA2\u9605 ${instId.toUpperCase()} ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u4E8B\u4EF6\u3002`,
36224
+ hint: `\u5DF2\u8BA2\u9605\u79C1\u6709\u9891\u9053 ${channel}\u3002\u8C03\u7528 okx_ws_events \u62C9\u53D6\u5B9E\u65F6\u4E8B\u4EF6\u3002`,
35448
36225
  tsIso: (/* @__PURE__ */ new Date()).toISOString()
35449
36226
  });
35450
36227
  } catch (e) {
@@ -35519,7 +36296,6 @@ function registerWsTools(server) {
35519
36296
  }
35520
36297
 
35521
36298
  // src/adapters/agent-hub.ts
35522
- init_wrapper();
35523
36299
  var MAX_ROOM_MESSAGES = 200;
35524
36300
  var AgentHub = class {
35525
36301
  wss = null;
@@ -36068,6 +36844,227 @@ function registerAgentHubTools(server) {
36068
36844
  );
36069
36845
  }
36070
36846
 
36847
+ // src/tools/codegraph.ts
36848
+ var _cg = null;
36849
+ var _cgInitError = null;
36850
+ var _cgInitDone = false;
36851
+ async function getCodeGraph() {
36852
+ if (_cgInitDone) return _cg;
36853
+ try {
36854
+ const mod = await Promise.resolve().then(() => __toESM(require_npm_sdk()));
36855
+ const CodeGraph = mod.CodeGraph || mod.default?.CodeGraph;
36856
+ _cg = await CodeGraph.open(".");
36857
+ _cgInitDone = true;
36858
+ return _cg;
36859
+ } catch (e) {
36860
+ _cgInitError = e.message || String(e);
36861
+ _cgInitDone = true;
36862
+ return null;
36863
+ }
36864
+ }
36865
+ function registerCodeGraphTools(server) {
36866
+ server.tool(
36867
+ "codegraph_status",
36868
+ "CAT:[\u4EE3\u7801\u667A\u80FD] | ## \u529F\u80FD\uFF1A\u68C0\u67E5\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u72B6\u6001\u2014\u2014\u8282\u70B9\u6570\u3001\u8FB9\u6570\u3001\u8986\u76D6\u6587\u4EF6\u3001\u88AB\u8C03\u7528\u6700\u591A\u7684\u51FD\u6570\n## \u573A\u666F\uFF1AAgent \u9996\u6B21\u8FDE\u63A5\u65F6\u786E\u8BA4\u56FE\u8C31\u662F\u5426\u5C31\u7EEA\uFF0C\u6216\u7528\u6237\u95EE\u300Chvip \u4EE3\u7801\u7ED3\u6784\u80FD\u67E5\u5417\u300D\u65F6\u786E\u8BA4\n## \u5173\u952E\u8BCD\uFF1A\u4EE3\u7801\u56FE\u8C31, codegraph, \u77E5\u8BC6\u56FE\u8C31, \u7D22\u5F15\u72B6\u6001, \u8C03\u7528\u6392\u884C\n## \u53C2\u6570\uFF1A\u65E0\n## \u9274\u6743\uFF1APUBLIC \u2014 \u672C\u5730\u8BFB\u6570\u636E\u5E93\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~800B\n## \u5173\u8054\uFF1A\u672C\u5DE5\u5177\u786E\u8BA4\u72B6\u6001 \u2192 codegraph_query \u8FFD\u8E2A\u8C03\u7528\u94FE/\u641C\u7D22\u7B26\u53F7",
36869
+ {},
36870
+ async () => {
36871
+ try {
36872
+ const cg = await getCodeGraph();
36873
+ if (!cg) {
36874
+ return toResult({
36875
+ status: "unavailable",
36876
+ reason: _cgInitError || "CodeGraph \u5F15\u64CE\u52A0\u8F7D\u5931\u8D25",
36877
+ how_to_setup: "npm i @colbymchenry/codegraph && codegraph index",
36878
+ alternatives: "\u56FE\u8C31\u4E0D\u53EF\u7528\u65F6\uFF0C\u4ECD\u53EF\u7528\u672C\u5DE5\u5177\u8FD4\u56DE\u7684\u8282\u70B9\u6570\u548C\u8FB9\u6570\u4E86\u89E3\u4EE3\u7801\u89C4\u6A21",
36879
+ tsIso: (/* @__PURE__ */ new Date()).toISOString(),
36880
+ _summary: "\u4EE3\u7801\u56FE\u8C31\u672A\u5C31\u7EEA\u3002\u8BF7\u8FD0\u884C codegraph index \u751F\u6210\u6570\u636E\u5E93\u3002"
36881
+ });
36882
+ }
36883
+ const stats = await cg.getStats();
36884
+ let topCalled = [];
36885
+ try {
36886
+ const allExported = await cg.getNodesByKind("function").then((nodes) => nodes.filter((n) => n.isExported)).catch(() => []);
36887
+ const sample = allExported.slice(0, 50);
36888
+ const withCounts = await Promise.all(
36889
+ sample.map(async (n) => {
36890
+ try {
36891
+ const callers = await cg.getCallers(n.id, 1);
36892
+ return { name: n.name, file: n.filePath, callers: callers?.length || 0 };
36893
+ } catch {
36894
+ return { name: n.name, file: n.filePath, callers: 0 };
36895
+ }
36896
+ })
36897
+ );
36898
+ topCalled = withCounts.sort((a, b) => b.callers - a.callers).slice(0, 5);
36899
+ } catch {
36900
+ }
36901
+ const status = {
36902
+ status: "ready",
36903
+ stats: {
36904
+ nodes: stats.nodeCount,
36905
+ edges: stats.edgeCount,
36906
+ files: stats.fileCount,
36907
+ byKind: stats.nodesByKind,
36908
+ byLanguage: stats.filesByLanguage,
36909
+ dbSize: stats.dbSizeBytes ? `${(stats.dbSizeBytes / 1024 / 1024).toFixed(1)} MB` : "unknown"
36910
+ },
36911
+ topCalled,
36912
+ queryHint: "\u7528 codegraph_query \u67E5\u8C03\u7528\u94FE\u3002\u4F8B: codegraph_query({ mode: 'callers', symbol: 'toResult' })",
36913
+ tsIso: (/* @__PURE__ */ new Date()).toISOString(),
36914
+ _summary: `\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u5C31\u7EEA\u3002${stats.nodeCount} \u4E2A\u8282\u70B9\uFF0C${stats.edgeCount} \u6761\u5173\u7CFB\uFF0C\u8986\u76D6 ${stats.fileCount} \u4E2A\u6587\u4EF6\u3002${topCalled.length ? `\u88AB\u8C03\u6700\u591A: ${topCalled.slice(0, 3).map((f) => f.name).join("\u3001")}` : ""}`
36915
+ };
36916
+ return toResult(status);
36917
+ } catch (e) {
36918
+ return toError(e);
36919
+ }
36920
+ }
36921
+ );
36922
+ server.tool(
36923
+ "codegraph_query",
36924
+ "CAT:[\u4EE3\u7801\u667A\u80FD] | ## \u529F\u80FD\uFF1A\u67E5\u8BE2\u4EE3\u7801\u77E5\u8BC6\u56FE\u8C31\u2014\u2014\u8FFD\u8E2A\u8C03\u7528\u94FE\u3001\u641C\u7D22\u7B26\u53F7\u3001\u63A2\u7D22\u6A21\u5757\u4F9D\u8D56\u3001\u6309\u6587\u4EF6\u5217\u51FA\u7B26\u53F7\n## \u573A\u666F\uFF1AAgent \u56DE\u7B54\u300CtoResult \u88AB\u54EA\u4E9B\u5DE5\u5177\u8C03\u7528\u300D\u300CregisterMarketTools \u7684\u4E0A\u4E0B\u6E38\u300D\u300C\u4EE3\u7801\u91CC\u54EA\u91CC\u5904\u7406\u4E86 WebSocket\u300D\u65F6\u8C03\u7528\n## \u5173\u952E\u8BCD\uFF1Acodegraph, \u8C03\u7528\u94FE, callers, callees, \u4F9D\u8D56, \u4EE3\u7801\u641C\u7D22, \u7B26\u53F7\u67E5\u8BE2, \u4E0A\u4E0B\u6E38, \u5F71\u54CD\u5206\u6790\n## \u53C2\u6570\uFF1A\n## - mode: \u67E5\u8BE2\u6A21\u5F0F\u3002callers=\u8C01\u8C03\u7528\u5B83, callees=\u5B83\u8C03\u7528\u8C01, search=\u5168\u6587\u641C\u7D22, file=\u6309\u6587\u4EF6\u5217\u51FA\n## - symbol: \u7B26\u53F7\u540D/\u8282\u70B9ID (callers/callees/file \u6A21\u5F0F)\n## - query: \u641C\u7D22\u8BCD (search \u6A21\u5F0F)\n## - limit: \u8FD4\u56DE\u6570\uFF0C\u9ED8\u8BA4 15\n## \u9274\u6743\uFF1APUBLIC \u2014 \u672C\u5730\u8BFB\u6570\u636E\u5E93\n## \u98CE\u9669\uFF1AREAD \u2014 \u53EA\u8BFB\n## \u8FD4\u56DE\u91CF\uFF1A\u5FAE\u5C0F ~2KB\n## \u5173\u8054\uFF1Acodegraph_status \u770B\u72B6\u6001 \u2192 \u672C\u5DE5\u5177\u67E5\u8BE2 \u2192 Agent \u5B9A\u4F4D\u6E90\u7801",
36925
+ {
36926
+ mode: external_exports.enum(["callers", "callees", "search", "file"]).describe("callers=\u8C01\u8C03\u7528\u5B83, callees=\u5B83\u8C03\u7528\u8C01, search=\u5168\u6587\u641C\u7D22, file=\u6309\u6587\u4EF6\u5217\u51FA\u7B26\u53F7"),
36927
+ symbol: external_exports.string().optional().describe("\u7B26\u53F7\u540D\uFF08\u5982 toResult\uFF09\u6216\u6587\u4EF6\u540D\uFF08\u5982 agent-utils.ts\uFF09"),
36928
+ query: external_exports.string().optional().describe("\u641C\u7D22\u8BCD\uFF08search \u6A21\u5F0F\uFF09\uFF0C\u5982 'websocket \u8FDE\u63A5'"),
36929
+ limit: external_exports.number().int().min(1).max(100).optional().describe("\u8FD4\u56DE\u6570\uFF0C\u9ED8\u8BA4 15")
36930
+ },
36931
+ async ({ mode, symbol, query, limit }) => {
36932
+ try {
36933
+ const cg = await getCodeGraph();
36934
+ if (!cg) return toError("\u4EE3\u7801\u56FE\u8C31\u4E0D\u53EF\u7528\u3002\u8BF7\u5148\u8C03 codegraph_status \u68C0\u67E5\u72B6\u6001\u3002");
36935
+ const n = limit || 15;
36936
+ if (mode === "search") {
36937
+ const q = query || symbol || "";
36938
+ if (!q) return toError("search \u6A21\u5F0F\u9700\u8981 query \u6216 symbol \u53C2\u6570");
36939
+ const results = await cg.searchNodes(q, { limit: n });
36940
+ if (!results?.length) {
36941
+ return toResult({
36942
+ mode: "search",
36943
+ query: q,
36944
+ found: false,
36945
+ hint: `\u672A\u627E\u5230\u4E0E "${q}" \u76F8\u5173\u7684\u7B26\u53F7\u3002\u8BD5\u8BD5\u51FD\u6570\u540D\uFF08\u5982 registerTools\uFF09\u6216\u6587\u4EF6\u540D\u3002`,
36946
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
36947
+ });
36948
+ }
36949
+ const items = await Promise.all(results.slice(0, n).map(async (r) => {
36950
+ const node = r.node || r;
36951
+ let callerCount = 0, calleeCount = 0;
36952
+ try {
36953
+ callerCount = (await cg.getCallers(node.id, 1))?.length || 0;
36954
+ } catch {
36955
+ }
36956
+ try {
36957
+ calleeCount = (await cg.getCallees(node.id, 1))?.length || 0;
36958
+ } catch {
36959
+ }
36960
+ return {
36961
+ id: node.id,
36962
+ name: node.name,
36963
+ kind: node.kind,
36964
+ file: node.filePath,
36965
+ line: node.startLine,
36966
+ signature: node.signature?.slice(0, 120),
36967
+ stats: { callers: callerCount, callees: calleeCount }
36968
+ };
36969
+ }));
36970
+ return toResult({
36971
+ mode: "search",
36972
+ query: q,
36973
+ total: results.length,
36974
+ results: items,
36975
+ _summary: `\u641C\u7D22 "${q}" \u627E\u5230 ${results.length} \u4E2A\u7B26\u53F7\u3002${items.slice(0, 3).map((i) => `${i.name}(${i.kind})`).join(" | ")}`,
36976
+ hint: `\u627E\u5230\u5177\u4F53\u7B26\u53F7\u540E\uFF0C\u7528 codegraph_query({ mode: 'callers', symbol: '<id>' }) \u8FFD\u8E2A\u8C03\u7528\u94FE\u3002`,
36977
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
36978
+ });
36979
+ }
36980
+ if (mode === "callers") {
36981
+ if (!symbol) return toError("callers \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570");
36982
+ const nodes = await cg.getNodesByName(symbol);
36983
+ if (!nodes?.length) {
36984
+ return toResult({ mode: "callers", symbol, found: false, tsIso: (/* @__PURE__ */ new Date()).toISOString() });
36985
+ }
36986
+ const results = await Promise.all(nodes.slice(0, 5).map(async (node) => {
36987
+ const callers = await cg.getCallers(node.id, 1);
36988
+ return {
36989
+ target: { id: node.id, name: node.name, kind: node.kind, file: node.filePath, line: node.startLine },
36990
+ callers: (callers || []).slice(0, n).map((c) => ({
36991
+ name: c.name,
36992
+ kind: c.kind,
36993
+ file: c.filePath,
36994
+ line: c.line,
36995
+ relation: c.edgeKind
36996
+ })),
36997
+ total: callers?.length || 0
36998
+ };
36999
+ }));
37000
+ const total = results.reduce((s, r) => s + r.total, 0);
37001
+ return toResult({
37002
+ mode: "callers",
37003
+ symbol,
37004
+ matched: nodes.length,
37005
+ results,
37006
+ _summary: `"${symbol}" \u5339\u914D ${nodes.length} \u4E2A\u7B26\u53F7\uFF0C\u5171 ${total} \u4E2A\u8C03\u7528\u8005\u3002`,
37007
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
37008
+ });
37009
+ }
37010
+ if (mode === "callees") {
37011
+ if (!symbol) return toError("callees \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570");
37012
+ const nodes = await cg.getNodesByName(symbol);
37013
+ if (!nodes?.length) {
37014
+ return toResult({ mode: "callees", symbol, found: false, tsIso: (/* @__PURE__ */ new Date()).toISOString() });
37015
+ }
37016
+ const results = await Promise.all(nodes.slice(0, 5).map(async (node) => {
37017
+ const callees = await cg.getCallees(node.id, 1);
37018
+ return {
37019
+ source: { id: node.id, name: node.name, kind: node.kind, file: node.filePath, line: node.startLine },
37020
+ callees: (callees || []).slice(0, n).map((c) => ({
37021
+ name: c.name,
37022
+ kind: c.kind,
37023
+ file: c.filePath,
37024
+ line: c.line,
37025
+ relation: c.edgeKind
37026
+ })),
37027
+ total: callees?.length || 0
37028
+ };
37029
+ }));
37030
+ const total = results.reduce((s, r) => s + r.total, 0);
37031
+ return toResult({
37032
+ mode: "callees",
37033
+ symbol,
37034
+ matched: nodes.length,
37035
+ results,
37036
+ _summary: `"${symbol}" \u5339\u914D ${nodes.length} \u4E2A\u7B26\u53F7\uFF0C\u5171\u8C03\u7528 ${total} \u4E2A\u4E0B\u6E38\u3002`,
37037
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
37038
+ });
37039
+ }
37040
+ if (mode === "file") {
37041
+ if (!symbol) return toError("file \u6A21\u5F0F\u9700\u8981 symbol \u53C2\u6570\uFF08\u6587\u4EF6\u540D\uFF09");
37042
+ const files = await cg.getFiles({ pattern: symbol });
37043
+ const fileInfo = files?.[0];
37044
+ const symbols = fileInfo ? await cg.getNodesInFile(fileInfo.path) : [];
37045
+ return toResult({
37046
+ mode: "file",
37047
+ file: symbol,
37048
+ fileInfo: fileInfo ? { path: fileInfo.path, language: fileInfo.language, size: fileInfo.size } : null,
37049
+ symbols: (symbols || []).slice(0, n).map((s) => ({
37050
+ name: s.name,
37051
+ kind: s.kind,
37052
+ line: s.startLine,
37053
+ signature: s.signature?.slice(0, 120),
37054
+ exported: s.isExported
37055
+ })),
37056
+ _summary: `\u6587\u4EF6 "${symbol}" \u5305\u542B ${symbols?.length || 0} \u4E2A\u7B26\u53F7\u3002`,
37057
+ tsIso: (/* @__PURE__ */ new Date()).toISOString()
37058
+ });
37059
+ }
37060
+ return toError(`\u672A\u77E5\u6A21\u5F0F: ${mode}`);
37061
+ } catch (e) {
37062
+ return toError(e);
37063
+ }
37064
+ }
37065
+ );
37066
+ }
37067
+
36071
37068
  // src/index.ts
36072
37069
  function resolveExecutionMode() {
36073
37070
  if (process.env.MCP_EXECUTION_ENABLED === "false") {
@@ -36121,8 +37118,9 @@ function registerAllTools(server, auth, readOnly) {
36121
37118
  registerIndicatorTools(server);
36122
37119
  registerSmartMoneyTools(server, auth);
36123
37120
  registerXLayerWSTools(server);
36124
- registerWsTools(server);
37121
+ registerWsTools(server, auth);
36125
37122
  registerAgentHubTools(server);
37123
+ registerCodeGraphTools(server);
36126
37124
  return { skipped, skipLog };
36127
37125
  }
36128
37126
  async function startHttp(server, version2, auth, readOnly, skipped) {
@@ -36215,7 +37213,7 @@ async function startStdio(server, version2, auth, readOnly, skipped, skipLog) {
36215
37213
  await server.connect(transport);
36216
37214
  }
36217
37215
  async function main() {
36218
- const VERSION = "0.2.48";
37216
+ const VERSION = "0.2.50";
36219
37217
  const auth = getAuth();
36220
37218
  const mode = resolveTransportMode();
36221
37219
  const exec = resolveExecutionMode();
@@ -36223,7 +37221,7 @@ async function main() {
36223
37221
  const server = new McpServer({
36224
37222
  name: "hvip-mcp",
36225
37223
  version: VERSION,
36226
- description: "hvip MCP Server \u2014 362 \u5DE5\u5177\u8986\u76D6 97.7% OKX REST API\uFF0C\u542B\u4EA4\u6613/\u884C\u60C5/\u8D44\u91D1/\u7B56\u7565/\u9884\u6D4B\u5E02\u573A/\u6280\u672F\u6307\u6807/Smart Money\uFF08\u975E OKX \u5B98\u65B9\u4EA7\u54C1\uFF09\u3002\u4ED3\u5E93: https://github.com/okx-wallet-H/hvip-mcp"
37224
+ description: "hvip MCP Server \u2014 365 \u5DE5\u5177\u8986\u76D6 97.7% OKX REST API\uFF0C\u542B\u4EA4\u6613/\u884C\u60C5/\u8D44\u91D1/\u7B56\u7565/\u9884\u6D4B\u5E02\u573A/\u6280\u672F\u6307\u6807/Smart Money/WebSocket/\u4EE3\u7801\u56FE\u8C31\uFF08\u975E OKX \u5B98\u65B9\u4EA7\u54C1\uFF09\u3002\u4ED3\u5E93: https://github.com/okx-wallet-H/hvip-mcp"
36227
37225
  });
36228
37226
  const { skipped, skipLog } = registerAllTools(server, auth, readOnly);
36229
37227
  if (mode === "http") {