@kevisual/cnb 0.0.7 → 0.0.10

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.
@@ -5,6 +5,8 @@ import { CNB_ENV } from "@/common/cnb-env.ts";
5
5
 
6
6
  // 执行技能 get-cnb-port-uri,端口为4096
7
7
  // 执行技能 get-cnb-port-uri,端口为51515
8
+
9
+ // TODO: 获取仓库的
8
10
  app.route({
9
11
  path: 'cnb',
10
12
  key: 'get-cnb-port-uri',
package/dist/keep.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ interface KeepAliveConfig {
2
+ wsUrl: string;
3
+ cookie: string;
4
+ reconnectInterval?: number;
5
+ maxReconnectAttempts?: number;
6
+ pingInterval?: number;
7
+ onMessage?: (data: Buffer | string) => void;
8
+ onConnect?: () => void;
9
+ onDisconnect?: (code: number) => void;
10
+ onError?: (error: Error) => void;
11
+ onSign?: (data: {
12
+ type: string;
13
+ data: string;
14
+ signedData: string;
15
+ }) => void;
16
+ debug?: boolean;
17
+ }
18
+ interface ParsedMessage {
19
+ type: string;
20
+ raw: Buffer;
21
+ payload?: any;
22
+ }
23
+ type MessageHandler = (msg: ParsedMessage) => void;
24
+ declare class WSKeepAlive {
25
+ private ws;
26
+ private config;
27
+ private reconnectAttempts;
28
+ private pingTimer;
29
+ private messageHandlers;
30
+ private url;
31
+ constructor(config: KeepAliveConfig);
32
+ private log;
33
+ private parseMessage;
34
+ connect(): void;
35
+ private startPing;
36
+ private stopPing;
37
+ private handleReconnect;
38
+ onMessage(handler: MessageHandler): () => boolean;
39
+ disconnect(): void;
40
+ }
41
+ declare function createKeepAlive(config: KeepAliveConfig): WSKeepAlive;
42
+
43
+ export { WSKeepAlive, createKeepAlive };
44
+ export type { KeepAliveConfig, ParsedMessage };
package/dist/keep.js ADDED
@@ -0,0 +1,148 @@
1
+ // src/workspace/keep-live.ts
2
+ import WebSocket from "ws";
3
+
4
+ class WSKeepAlive {
5
+ ws = null;
6
+ config;
7
+ reconnectAttempts = 0;
8
+ pingTimer = null;
9
+ messageHandlers = new Set;
10
+ url;
11
+ constructor(config) {
12
+ this.config = {
13
+ wsUrl: config.wsUrl,
14
+ cookie: config.cookie,
15
+ reconnectInterval: config.reconnectInterval ?? 5000,
16
+ maxReconnectAttempts: config.maxReconnectAttempts ?? 3,
17
+ pingInterval: config.pingInterval ?? 30000,
18
+ onMessage: config.onMessage ?? (() => {}),
19
+ onConnect: config.onConnect ?? (() => {}),
20
+ onDisconnect: config.onDisconnect ?? (() => {}),
21
+ onError: config.onError ?? (() => {}),
22
+ onSign: config.onSign ?? (() => {}),
23
+ debug: config.debug ?? false
24
+ };
25
+ this.url = new URL(this.config.wsUrl);
26
+ }
27
+ log(message) {
28
+ if (!this.config.debug)
29
+ return;
30
+ const timestamp = new Date().toISOString();
31
+ const msg = `[${timestamp}] ${message}`;
32
+ console.log(msg);
33
+ }
34
+ parseMessage(data) {
35
+ const result = { type: "unknown", raw: data };
36
+ if (data.length < 14) {
37
+ result.type = "raw";
38
+ return result;
39
+ }
40
+ const prefix = data.slice(0, 13);
41
+ const msgType = prefix[0];
42
+ const jsonStart = data.indexOf(113);
43
+ if (jsonStart !== -1) {
44
+ try {
45
+ const jsonStr = data.slice(jsonStart + 1).toString();
46
+ const payload = JSON.parse(jsonStr);
47
+ result.type = `binary(0x${msgType.toString(16)})`;
48
+ result.payload = payload;
49
+ if (payload.type === "sign" && this.config.onSign) {
50
+ this.config.onSign(payload);
51
+ }
52
+ return result;
53
+ } catch {
54
+ result.type = "binary(json-parse-error)";
55
+ return result;
56
+ }
57
+ }
58
+ result.type = "raw";
59
+ return result;
60
+ }
61
+ connect() {
62
+ const { wsUrl, cookie, debug } = this.config;
63
+ this.log(`Connecting to ${wsUrl}...`);
64
+ this.ws = new WebSocket(wsUrl, {
65
+ headers: {
66
+ Origin: this.url.origin,
67
+ Cookie: cookie,
68
+ "Cache-Control": "no-cache",
69
+ "Accept-Language": "zh-CN,zh;q=0.9",
70
+ Pragma: "no-cache",
71
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
72
+ "Sec-WebSocket-Extensions": "permessage-deflate"
73
+ }
74
+ });
75
+ this.ws.on("open", () => {
76
+ debug && this.log("Connected!");
77
+ this.reconnectAttempts = 0;
78
+ this.config.onConnect();
79
+ this.startPing();
80
+ });
81
+ this.ws.on("message", (data) => {
82
+ if (Buffer.isBuffer(data)) {
83
+ const parsed = this.parseMessage(data);
84
+ this.config.onMessage(parsed?.raw ?? data);
85
+ this.messageHandlers.forEach((handler) => {
86
+ if (parsed)
87
+ handler(parsed);
88
+ });
89
+ } else {
90
+ this.config.onMessage(data);
91
+ }
92
+ });
93
+ this.ws.on("close", (code) => {
94
+ debug && this.log(`Disconnected (code: ${code})`);
95
+ this.stopPing();
96
+ this.config.onDisconnect(code);
97
+ this.handleReconnect();
98
+ });
99
+ this.ws.on("error", (err) => {
100
+ debug && this.log(`Error: ${err.message}`);
101
+ this.config.onError(err);
102
+ });
103
+ }
104
+ startPing() {
105
+ this.stopPing();
106
+ this.pingTimer = setInterval(() => {
107
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
108
+ this.ws.ping();
109
+ this.log("Sent ping");
110
+ }
111
+ }, this.config.pingInterval);
112
+ }
113
+ stopPing() {
114
+ if (this.pingTimer) {
115
+ clearInterval(this.pingTimer);
116
+ this.pingTimer = null;
117
+ }
118
+ }
119
+ handleReconnect() {
120
+ if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
121
+ this.log(`Max reconnect attempts (${this.config.maxReconnectAttempts}) reached. Giving up.`);
122
+ return;
123
+ }
124
+ this.reconnectAttempts++;
125
+ this.log(`Reconnecting in ${this.config.reconnectInterval}ms... (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
126
+ setTimeout(() => this.connect(), this.config.reconnectInterval);
127
+ }
128
+ onMessage(handler) {
129
+ this.messageHandlers.add(handler);
130
+ return () => this.messageHandlers.delete(handler);
131
+ }
132
+ disconnect() {
133
+ this.stopPing();
134
+ if (this.ws) {
135
+ this.ws.close();
136
+ this.ws = null;
137
+ }
138
+ }
139
+ }
140
+ function createKeepAlive(config) {
141
+ const client = new WSKeepAlive(config);
142
+ client.connect();
143
+ return client;
144
+ }
145
+ export {
146
+ createKeepAlive,
147
+ WSKeepAlive
148
+ };
package/dist/opencode.js CHANGED
@@ -17243,7 +17243,7 @@ function requireStream() {
17243
17243
  if (!duplex.push(data))
17244
17244
  ws.pause();
17245
17245
  });
17246
- ws.once("error", function error(err) {
17246
+ ws.once("error", function error2(err) {
17247
17247
  if (duplex.destroyed)
17248
17248
  return;
17249
17249
  terminateOnDestroy = false;
@@ -17261,7 +17261,7 @@ function requireStream() {
17261
17261
  return;
17262
17262
  }
17263
17263
  let called = false;
17264
- ws.once("error", function error(err2) {
17264
+ ws.once("error", function error2(err2) {
17265
17265
  called = true;
17266
17266
  callback(err2);
17267
17267
  });
@@ -32161,7 +32161,7 @@ function date5(params) {
32161
32161
 
32162
32162
  // node_modules/.pnpm/zod@4.1.8/node_modules/zod/v4/classic/external.js
32163
32163
  config3(en_default());
32164
- // node_modules/.pnpm/@opencode-ai+plugin@1.1.39/node_modules/@opencode-ai/plugin/dist/tool.js
32164
+ // node_modules/.pnpm/@opencode-ai+plugin@1.1.44/node_modules/@opencode-ai/plugin/dist/tool.js
32165
32165
  function tool2(input) {
32166
32166
  return input;
32167
32167
  }
@@ -52972,7 +52972,7 @@ var init_crypto = __esm(() => {
52972
52972
  } catch (e) {
52973
52973
  errorProto = getProto(getProto(e)), INTRINSICS["%Error.prototype%"] = errorProto;
52974
52974
  }
52975
- var errorProto, doEval = function doEval(name) {
52975
+ var errorProto, doEval = function doEval2(name) {
52976
52976
  var value;
52977
52977
  if (name === "%AsyncFunction%")
52978
52978
  value = getEvalledConstructor("async function () {}");
@@ -52981,11 +52981,11 @@ var init_crypto = __esm(() => {
52981
52981
  else if (name === "%AsyncGeneratorFunction%")
52982
52982
  value = getEvalledConstructor("async function* () {}");
52983
52983
  else if (name === "%AsyncGenerator%") {
52984
- var fn = doEval("%AsyncGeneratorFunction%");
52984
+ var fn = doEval2("%AsyncGeneratorFunction%");
52985
52985
  if (fn)
52986
52986
  value = fn.prototype;
52987
52987
  } else if (name === "%AsyncIteratorPrototype%") {
52988
- var gen = doEval("%AsyncGenerator%");
52988
+ var gen = doEval2("%AsyncGenerator%");
52989
52989
  if (gen && getProto)
52990
52990
  value = getProto(gen.prototype);
52991
52991
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/cnb",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,9 +21,10 @@
21
21
  "@kevisual/ai": "^0.0.24",
22
22
  "@kevisual/context": "^0.0.4",
23
23
  "@kevisual/types": "^0.0.12",
24
- "@opencode-ai/plugin": "^1.1.39",
25
- "@types/bun": "^1.3.7",
24
+ "@opencode-ai/plugin": "^1.1.44",
25
+ "@types/bun": "^1.3.8",
26
26
  "@types/node": "^25.1.0",
27
+ "@types/ws": "^8.18.1",
27
28
  "dotenv": "^17.2.3"
28
29
  },
29
30
  "publishConfig": {
@@ -35,11 +36,13 @@
35
36
  "@kevisual/use-config": "^1.0.28",
36
37
  "es-toolkit": "^1.44.0",
37
38
  "nanoid": "^5.1.6",
39
+ "ws": "npm:@kevisual/ws",
38
40
  "zod": "^4.3.6"
39
41
  },
40
42
  "exports": {
41
43
  ".": "./mod.ts",
42
44
  "./opencode": "./dist/opencode.js",
45
+ "./keep": "./dist/keep.js",
43
46
  "./src/*": "./src/*",
44
47
  "./agent/*": "./agent/*"
45
48
  }
package/src/keep.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './workspace/keep-live.ts';
@@ -0,0 +1,187 @@
1
+ // WebSocket Keep-Alive Client Library
2
+ import WebSocket from "ws";
3
+
4
+ export interface KeepAliveConfig {
5
+ wsUrl: string;
6
+ cookie: string;
7
+ reconnectInterval?: number;
8
+ maxReconnectAttempts?: number;
9
+ pingInterval?: number;
10
+ onMessage?: (data: Buffer | string) => void;
11
+ onConnect?: () => void;
12
+ onDisconnect?: (code: number) => void;
13
+ onError?: (error: Error) => void;
14
+ onSign?: (data: { type: string; data: string; signedData: string }) => void;
15
+ debug?: boolean;
16
+ }
17
+
18
+ export interface ParsedMessage {
19
+ type: string;
20
+ raw: Buffer;
21
+ payload?: any;
22
+ }
23
+
24
+ type MessageHandler = (msg: ParsedMessage) => void;
25
+
26
+ export class WSKeepAlive {
27
+ private ws: WebSocket | null = null;
28
+ private config: Required<KeepAliveConfig>;
29
+ private reconnectAttempts = 0;
30
+ private pingTimer: NodeJS.Timeout | null = null;
31
+ private messageHandlers: Set<MessageHandler> = new Set();
32
+ private url: URL;
33
+
34
+ constructor(config: KeepAliveConfig) {
35
+ this.config = {
36
+ wsUrl: config.wsUrl,
37
+ cookie: config.cookie,
38
+ reconnectInterval: config.reconnectInterval ?? 5000,
39
+ maxReconnectAttempts: config.maxReconnectAttempts ?? 3,
40
+ pingInterval: config.pingInterval ?? 30000,
41
+ onMessage: config.onMessage ?? (() => {}),
42
+ onConnect: config.onConnect ?? (() => {}),
43
+ onDisconnect: config.onDisconnect ?? (() => {}),
44
+ onError: config.onError ?? (() => {}),
45
+ onSign: config.onSign ?? (() => {}),
46
+ debug: config.debug ?? false,
47
+ };
48
+ this.url = new URL(this.config.wsUrl);
49
+ }
50
+
51
+ private log(message: string) {
52
+ if (!this.config.debug) return;
53
+ const timestamp = new Date().toISOString();
54
+ const msg = `[${timestamp}] ${message}`;
55
+ console.log(msg);
56
+ }
57
+
58
+ private parseMessage(data: Buffer): ParsedMessage | null {
59
+ const result: ParsedMessage = { type: "unknown", raw: data };
60
+
61
+ if (data.length < 14) {
62
+ result.type = "raw";
63
+ return result;
64
+ }
65
+
66
+ const prefix = data.slice(0, 13);
67
+ const msgType = prefix[0];
68
+ const jsonStart = data.indexOf(0x71); // 0x71 = 'q'
69
+
70
+ if (jsonStart !== -1) {
71
+ try {
72
+ const jsonStr = data.slice(jsonStart + 1).toString();
73
+ const payload = JSON.parse(jsonStr);
74
+ result.type = `binary(0x${msgType.toString(16)})`;
75
+ result.payload = payload;
76
+
77
+ // 特殊处理 sign 类型
78
+ if (payload.type === "sign" && this.config.onSign) {
79
+ this.config.onSign(payload);
80
+ }
81
+ return result;
82
+ } catch {
83
+ result.type = "binary(json-parse-error)";
84
+ return result;
85
+ }
86
+ }
87
+
88
+ result.type = "raw";
89
+ return result;
90
+ }
91
+
92
+ connect() {
93
+ const { wsUrl, cookie, debug } = this.config;
94
+ this.log(`Connecting to ${wsUrl}...`);
95
+
96
+ this.ws = new WebSocket(wsUrl, {
97
+ headers: {
98
+ "Origin": this.url.origin,
99
+ "Cookie": cookie,
100
+ "Cache-Control": "no-cache",
101
+ "Accept-Language": "zh-CN,zh;q=0.9",
102
+ "Pragma": "no-cache",
103
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
104
+ "Sec-WebSocket-Extensions": "permessage-deflate",
105
+ }
106
+ });
107
+
108
+ this.ws.on("open", () => {
109
+ debug && this.log("Connected!");
110
+ this.reconnectAttempts = 0;
111
+ this.config.onConnect();
112
+ this.startPing();
113
+ });
114
+
115
+ this.ws.on("message", (data: any) => {
116
+ if (Buffer.isBuffer(data)) {
117
+ const parsed = this.parseMessage(data);
118
+ this.config.onMessage(parsed?.raw ?? data);
119
+
120
+ this.messageHandlers.forEach(handler => {
121
+ if (parsed) handler(parsed);
122
+ });
123
+ } else {
124
+ this.config.onMessage(data);
125
+ }
126
+ });
127
+
128
+ this.ws.on("close", (code: number) => {
129
+ debug && this.log(`Disconnected (code: ${code})`);
130
+ this.stopPing();
131
+ this.config.onDisconnect(code);
132
+ this.handleReconnect();
133
+ });
134
+
135
+ this.ws.on("error", (err: Error) => {
136
+ debug && this.log(`Error: ${err.message}`);
137
+ this.config.onError(err);
138
+ });
139
+ }
140
+
141
+ private startPing() {
142
+ this.stopPing();
143
+ this.pingTimer = setInterval(() => {
144
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
145
+ this.ws.ping();
146
+ this.log("Sent ping");
147
+ }
148
+ }, this.config.pingInterval);
149
+ }
150
+
151
+ private stopPing() {
152
+ if (this.pingTimer) {
153
+ clearInterval(this.pingTimer);
154
+ this.pingTimer = null;
155
+ }
156
+ }
157
+
158
+ private handleReconnect() {
159
+ if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
160
+ this.log(`Max reconnect attempts (${this.config.maxReconnectAttempts}) reached. Giving up.`);
161
+ return;
162
+ }
163
+ this.reconnectAttempts++;
164
+ this.log(`Reconnecting in ${this.config.reconnectInterval}ms... (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
165
+ setTimeout(() => this.connect(), this.config.reconnectInterval);
166
+ }
167
+
168
+ onMessage(handler: MessageHandler) {
169
+ this.messageHandlers.add(handler);
170
+ return () => this.messageHandlers.delete(handler);
171
+ }
172
+
173
+ disconnect() {
174
+ this.stopPing();
175
+ if (this.ws) {
176
+ this.ws.close();
177
+ this.ws = null;
178
+ }
179
+ }
180
+ }
181
+
182
+ // 便捷函数:快速创建并启动
183
+ export function createKeepAlive(config: KeepAliveConfig): WSKeepAlive {
184
+ const client = new WSKeepAlive(config);
185
+ client.connect();
186
+ return client;
187
+ }