@ynhcj/xiaoyi 2.2.7 → 2.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/channel.js CHANGED
@@ -381,6 +381,18 @@ exports.xiaoyiPlugin = {
381
381
  console.log("=".repeat(60) + "\n");
382
382
  return;
383
383
  }
384
+ // ==================== CHECK EMPTY RESPONSE ====================
385
+ // If response is empty, don't clear timeout (let it trigger)
386
+ if (!completeText || completeText.length === 0) {
387
+ console.log("\n" + "=".repeat(60));
388
+ console.log(`[TIMEOUT] Empty response detected`);
389
+ console.log(` Session: ${message.sessionId}`);
390
+ console.log(` Elapsed: ${elapsed}ms`);
391
+ console.log(` Action: KEEPING TIMEOUT (session conflict detected)`);
392
+ console.log("=".repeat(60) + "\n");
393
+ // Don't send anything, and don't clear timeout
394
+ return;
395
+ }
384
396
  console.log("\n" + "-".repeat(60));
385
397
  console.log(`XiaoYi: [DELIVER] AI response received`);
386
398
  console.log(` Elapsed: ${elapsed}ms`);
@@ -421,9 +433,16 @@ exports.xiaoyiPlugin = {
421
433
  console.log(`XiaoYi: [IDLE] Processing complete`);
422
434
  console.log(` Total time: ${elapsed}ms`);
423
435
  console.log(` Final length: ${accumulatedText.length} chars`);
436
+ // Only clear timeout if we have a valid response
437
+ // If empty, keep timeout running to handle session conflict
438
+ if (accumulatedText.length > 0) {
439
+ runtime.markSessionCompleted(message.sessionId);
440
+ console.log(`[TIMEOUT] Timeout cleared (valid response)\n`);
441
+ }
442
+ else {
443
+ console.log(`[TIMEOUT] Keeping timeout (no valid response)\n`);
444
+ }
424
445
  console.log("=".repeat(60) + "\n");
425
- // Clear timeout on completion
426
- runtime.markSessionCompleted(message.sessionId);
427
446
  },
428
447
  },
429
448
  replyOptions: undefined,
@@ -15,6 +15,10 @@ export declare class XiaoYiWebSocketManager extends EventEmitter {
15
15
  private reconnectTimeout2?;
16
16
  private activeTasks;
17
17
  constructor(config: XiaoYiChannelConfig);
18
+ /**
19
+ * Check if URL is wss + IP format (skip certificate verification)
20
+ */
21
+ private isWssWithIp;
18
22
  /**
19
23
  * Resolve configuration with defaults and backward compatibility
20
24
  */
package/dist/websocket.js CHANGED
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.XiaoYiWebSocketManager = void 0;
7
7
  const ws_1 = __importDefault(require("ws"));
8
8
  const events_1 = require("events");
9
+ const url_1 = require("url");
9
10
  const auth_1 = require("./auth");
10
11
  const types_1 = require("./types");
11
12
  class XiaoYiWebSocketManager extends events_1.EventEmitter {
@@ -38,6 +39,47 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
38
39
  console.log(` Server 1: ${this.config.wsUrl1}`);
39
40
  console.log(` Server 2: ${this.config.wsUrl2}`);
40
41
  }
42
+ /**
43
+ * Check if URL is wss + IP format (skip certificate verification)
44
+ */
45
+ isWssWithIp(urlString) {
46
+ try {
47
+ const url = new url_1.URL(urlString);
48
+ // Check if protocol is wss
49
+ if (url.protocol !== 'wss:') {
50
+ return false;
51
+ }
52
+ const hostname = url.hostname;
53
+ // Check for IPv4 address (e.g., 192.168.1.1)
54
+ const ipv4Regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
55
+ if (ipv4Regex.test(hostname)) {
56
+ // Validate each octet is 0-255
57
+ const octets = hostname.split('.');
58
+ return octets.every(octet => {
59
+ const num = parseInt(octet, 10);
60
+ return num >= 0 && num <= 255;
61
+ });
62
+ }
63
+ // Check for IPv6 address (e.g., [::1] or 2001:db8::1)
64
+ // IPv6 in URL might be wrapped in brackets
65
+ const ipv6Regex = /^[\[::0-9a-fA-F]+$/;
66
+ const ipv6WithoutBrackets = hostname.replace(/[\[\]]/g, '');
67
+ // Simple check for IPv6: contains colons and valid hex characters
68
+ if (hostname.includes('[') && hostname.includes(']')) {
69
+ return ipv6Regex.test(hostname);
70
+ }
71
+ // Check for plain IPv6 format
72
+ if (hostname.includes(':')) {
73
+ const ipv6RegexPlain = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
74
+ return ipv6RegexPlain.test(ipv6WithoutBrackets);
75
+ }
76
+ return false;
77
+ }
78
+ catch (error) {
79
+ console.warn(`[WS Manager] Invalid URL format: ${urlString}`);
80
+ return false;
81
+ }
82
+ }
41
83
  /**
42
84
  * Resolve configuration with defaults and backward compatibility
43
85
  */
@@ -96,8 +138,14 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
96
138
  console.log(`[Server1] Connecting to ${this.config.wsUrl1}...`);
97
139
  try {
98
140
  const authHeaders = this.auth.generateAuthHeaders();
141
+ // Check if URL is wss + IP format, skip certificate verification
142
+ const skipCertVerify = this.isWssWithIp(this.config.wsUrl1);
143
+ if (skipCertVerify) {
144
+ console.log(`[Server1] WSS + IP detected, skipping certificate verification`);
145
+ }
99
146
  this.ws1 = new ws_1.default(this.config.wsUrl1, {
100
147
  headers: authHeaders,
148
+ rejectUnauthorized: !skipCertVerify,
101
149
  });
102
150
  this.setupWebSocketHandlers(this.ws1, 'server1');
103
151
  await new Promise((resolve, reject) => {
@@ -136,8 +184,14 @@ class XiaoYiWebSocketManager extends events_1.EventEmitter {
136
184
  console.log(`[Server2] Connecting to ${this.config.wsUrl2}...`);
137
185
  try {
138
186
  const authHeaders = this.auth.generateAuthHeaders();
187
+ // Check if URL is wss + IP format, skip certificate verification
188
+ const skipCertVerify = this.isWssWithIp(this.config.wsUrl2);
189
+ if (skipCertVerify) {
190
+ console.log(`[Server2] WSS + IP detected, skipping certificate verification`);
191
+ }
139
192
  this.ws2 = new ws_1.default(this.config.wsUrl2, {
140
193
  headers: authHeaders,
194
+ rejectUnauthorized: !skipCertVerify,
141
195
  });
142
196
  this.setupWebSocketHandlers(this.ws2, 'server2');
143
197
  await new Promise((resolve, reject) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi",
3
- "version": "2.2.7",
3
+ "version": "2.2.9",
4
4
  "description": "XiaoYi channel plugin for OpenClaw",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",