chatcc-agent 0.3.4 → 0.3.6
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/package.json +3 -3
- package/src/claude-bridge.js +14 -6
- package/src/constants.js +42 -0
- package/src/im-client.js +33 -29
- package/src/index.js +61 -2
- package/src/security.js +5 -4
- package/src/server-info.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatcc-agent",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "CCLink Agent - bridges Claude Code CLI with instant messaging",
|
|
5
5
|
"bin": {
|
|
6
6
|
"chatcc": "src/cli.js"
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"node": ">=16.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@tencentcloud/chat": "
|
|
48
|
-
"ws": "
|
|
47
|
+
"@tencentcloud/chat": "3.6.6",
|
|
48
|
+
"ws": "8.20.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {}
|
|
51
51
|
}
|
package/src/claude-bridge.js
CHANGED
|
@@ -6,6 +6,7 @@ const os = require('os');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const { StreamBuffer } = require('./stream-buffer');
|
|
8
8
|
const { ProcessQueue } = require('./process-queue');
|
|
9
|
+
const { PERMISSION_MODES, PERMISSION_ACTIONS } = require('./constants');
|
|
9
10
|
|
|
10
11
|
class ClaudeBridge {
|
|
11
12
|
|
|
@@ -75,7 +76,7 @@ class ClaudeBridge {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
_requiresApproval(toolName, permissions) {
|
|
78
|
-
if (permissions?.defaultMode ===
|
|
79
|
+
if (permissions?.defaultMode === PERMISSION_MODES.AUTO_ALL) return false;
|
|
79
80
|
|
|
80
81
|
const TOOL_CATEGORY = {
|
|
81
82
|
'Read': 'fileRead', 'read': 'fileRead',
|
|
@@ -87,11 +88,11 @@ class ClaudeBridge {
|
|
|
87
88
|
|
|
88
89
|
// Per-tool setting overrides default mode
|
|
89
90
|
if (category) {
|
|
90
|
-
return (permissions?.[category] ||
|
|
91
|
+
return (permissions?.[category] || PERMISSION_ACTIONS.CONFIRM) !== PERMISSION_ACTIONS.AUTO_ALLOW;
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
// Unknown tools: auto-allow in "
|
|
94
|
-
return permissions?.defaultMode !==
|
|
94
|
+
// Unknown tools: auto-allow in "auto_read" mode, otherwise require approval
|
|
95
|
+
return permissions?.defaultMode !== PERMISSION_MODES.AUTO_READ;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
_writeToStdin(proc, msg) {
|
|
@@ -298,7 +299,7 @@ class ClaudeBridge {
|
|
|
298
299
|
|
|
299
300
|
_spawnCompact(replyTo, sessionID, requestID, options) {
|
|
300
301
|
const { cwd, claudeSessionId, workspaceRestricted, permissions } = options;
|
|
301
|
-
const usePermissionControl = permissions?.defaultMode !==
|
|
302
|
+
const usePermissionControl = permissions?.defaultMode !== PERMISSION_MODES.AUTO_ALL;
|
|
302
303
|
const useStreamInput = usePermissionControl;
|
|
303
304
|
const args = ['--output-format', 'stream-json', '--verbose'];
|
|
304
305
|
|
|
@@ -403,7 +404,7 @@ class ClaudeBridge {
|
|
|
403
404
|
|
|
404
405
|
_spawnClaude(msgID, replyTo, content, sessionID, options = {}) {
|
|
405
406
|
const { cwd, claudeSessionId, images, onClaudeSessionId, onResumeFailed, onSessionTitle, workspaceRestricted = false, permissions = null } = options;
|
|
406
|
-
const usePermissionControl = permissions?.defaultMode !==
|
|
407
|
+
const usePermissionControl = permissions?.defaultMode !== PERMISSION_MODES.AUTO_ALL;
|
|
407
408
|
const useStreamInput = usePermissionControl;
|
|
408
409
|
const args = [
|
|
409
410
|
'--output-format', 'stream-json',
|
|
@@ -582,6 +583,8 @@ class ClaudeBridge {
|
|
|
582
583
|
case 'error':
|
|
583
584
|
this._handleErrorEvent(event, replyTo, msgID, sessionID, streamBuffer, sendStreamEnd);
|
|
584
585
|
break;
|
|
586
|
+
default:
|
|
587
|
+
console.warn(`[Bridge] Unknown Claude event type: ${event.type}`, JSON.stringify(event).slice(0, 200));
|
|
585
588
|
}
|
|
586
589
|
}
|
|
587
590
|
|
|
@@ -611,6 +614,11 @@ class ClaudeBridge {
|
|
|
611
614
|
session_id: sessionID,
|
|
612
615
|
tool_use_id: block.id,
|
|
613
616
|
questions: block.input?.questions || [],
|
|
617
|
+
}, {
|
|
618
|
+
title: 'Claude 有问题',
|
|
619
|
+
desc: '需要您的选择',
|
|
620
|
+
ext: JSON.stringify({ session_id: sessionID, push_type: 'agent_reply' }),
|
|
621
|
+
ignoreBadge: false,
|
|
614
622
|
}).catch(e => console.error('[Bridge] user_question:', e.message));
|
|
615
623
|
} else {
|
|
616
624
|
this._handleToolUseBlock(block, replyTo, msgID, streamBuffer, sessionID, cwd, workspaceRestricted, permissions, useControl, sendStreamEnd);
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission mode identifiers — used in IM protocol between Agent and iOS.
|
|
3
|
+
* Chinese display labels live on the iOS side only.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Protocol versioning — bump CURRENT when introducing breaking changes.
|
|
7
|
+
// MIN is the oldest client/agent version we still support.
|
|
8
|
+
const CURRENT_PROTOCOL_VERSION = 1;
|
|
9
|
+
const MIN_PROTOCOL_VERSION = 1;
|
|
10
|
+
|
|
11
|
+
// Default permission modes (sent as default_mode in session settings)
|
|
12
|
+
const PERMISSION_MODES = {
|
|
13
|
+
CONFIRM_EVERY: 'confirm_every', // 每次确认
|
|
14
|
+
AUTO_READ: 'auto_read', // 自动允许读取
|
|
15
|
+
AUTO_ALL: 'auto_all', // 自动全部允许
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Per-category permission actions (sent as file_read / file_edit / code_exec)
|
|
19
|
+
const PERMISSION_ACTIONS = {
|
|
20
|
+
AUTO_ALLOW: 'auto_allow', // 自动允许
|
|
21
|
+
CONFIRM: 'confirm', // 需要确认
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Map legacy Chinese strings to new identifiers for backward compatibility
|
|
25
|
+
const LEGACY_MODE_MAP = {
|
|
26
|
+
'每次确认': PERMISSION_MODES.CONFIRM_EVERY,
|
|
27
|
+
'自动允许读取': PERMISSION_MODES.AUTO_READ,
|
|
28
|
+
'自动全部允许': PERMISSION_MODES.AUTO_ALL,
|
|
29
|
+
'自动允许': PERMISSION_ACTIONS.AUTO_ALLOW,
|
|
30
|
+
'需要确认': PERMISSION_ACTIONS.CONFIRM,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Normalize a permission value — accepts both new identifiers and legacy Chinese strings.
|
|
35
|
+
* Passes through unknown values (already in new format or custom).
|
|
36
|
+
*/
|
|
37
|
+
function normalizePermission(value) {
|
|
38
|
+
if (!value) return value;
|
|
39
|
+
return LEGACY_MODE_MAP[value] || value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { CURRENT_PROTOCOL_VERSION, MIN_PROTOCOL_VERSION, PERMISSION_MODES, PERMISSION_ACTIONS, LEGACY_MODE_MAP, normalizePermission };
|
package/src/im-client.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
const WebSocket = require('ws');
|
|
2
2
|
global.WebSocket = WebSocket;
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const _origWarn = console.warn;
|
|
7
|
-
const _origErr = console.error;
|
|
4
|
+
const { CURRENT_PROTOCOL_VERSION, MIN_PROTOCOL_VERSION } = require('./constants');
|
|
5
|
+
const PROTOCOL_VERSION = CURRENT_PROTOCOL_VERSION;
|
|
8
6
|
|
|
9
7
|
class IMClient {
|
|
10
8
|
constructor(sdkAppID, userID, userSig, options = {}) {
|
|
@@ -15,19 +13,10 @@ class IMClient {
|
|
|
15
13
|
this._onFatal = options.onFatal || (() => process.exit(1));
|
|
16
14
|
this._onUserSigExpired = options.onUserSigExpired || null;
|
|
17
15
|
|
|
18
|
-
// Suppress SDK noise only during require/create, restore immediately
|
|
19
|
-
console.log = () => {};
|
|
20
|
-
console.warn = () => {};
|
|
21
|
-
console.error = () => {};
|
|
22
|
-
|
|
23
16
|
const TIM = require('@tencentcloud/chat');
|
|
24
17
|
this.TIM = TIM;
|
|
25
18
|
this.tim = TIM.create({ SDKAppID: sdkAppID });
|
|
26
|
-
this.tim.setLogLevel(4);
|
|
27
|
-
|
|
28
|
-
console.log = _origLog;
|
|
29
|
-
console.warn = _origWarn;
|
|
30
|
-
console.error = _origErr;
|
|
19
|
+
this.tim.setLogLevel(4); // Suppress all SDK noise
|
|
31
20
|
|
|
32
21
|
this._messageHandlers = [];
|
|
33
22
|
|
|
@@ -48,9 +37,9 @@ class IMClient {
|
|
|
48
37
|
|
|
49
38
|
this.tim.on(TIM.EVENT.NET_STATE_CHANGE, (event) => {
|
|
50
39
|
if (event.data.state === this.TIM.NET_STATE_DISCONNECTED) {
|
|
51
|
-
|
|
40
|
+
console.log('[IM] Network disconnected');
|
|
52
41
|
} else if (event.data.state === this.TIM.NET_STATE_CONNECTED) {
|
|
53
|
-
|
|
42
|
+
console.log('[IM] Network connected');
|
|
54
43
|
}
|
|
55
44
|
});
|
|
56
45
|
|
|
@@ -64,7 +53,7 @@ class IMClient {
|
|
|
64
53
|
this._lastKickoutTimes = this._lastKickoutTimes.filter(t => now - t < 60000);
|
|
65
54
|
|
|
66
55
|
if (reason === this.TIM.KICKED_OUT_MULTIPLE_ACCOUNT) {
|
|
67
|
-
|
|
56
|
+
console.log('[IM] Kicked out: UserSig expired, requesting refresh...');
|
|
68
57
|
if (this._onUserSigExpired) {
|
|
69
58
|
this._onUserSigExpired().then(newSig => {
|
|
70
59
|
if (newSig) {
|
|
@@ -73,7 +62,7 @@ class IMClient {
|
|
|
73
62
|
this._reconnect();
|
|
74
63
|
}
|
|
75
64
|
}).catch(e => {
|
|
76
|
-
|
|
65
|
+
console.log('[IM] UserSig refresh failed:', e.message);
|
|
77
66
|
});
|
|
78
67
|
return;
|
|
79
68
|
}
|
|
@@ -82,7 +71,7 @@ class IMClient {
|
|
|
82
71
|
// Detect kickout loop: 5+ kickouts in 60s means something is wrong
|
|
83
72
|
if (this._lastKickoutTimes.length >= 5) {
|
|
84
73
|
const backoff = 15000;
|
|
85
|
-
|
|
74
|
+
console.log(`[IM] Kickout loop detected (${this._lastKickoutTimes.length} in 60s). Cooling down ${backoff/1000}s...`);
|
|
86
75
|
this._lastKickoutTimes = [];
|
|
87
76
|
setTimeout(() => {
|
|
88
77
|
this._reconnectAttempts = 0;
|
|
@@ -91,10 +80,10 @@ class IMClient {
|
|
|
91
80
|
return;
|
|
92
81
|
}
|
|
93
82
|
|
|
94
|
-
|
|
83
|
+
console.log('[IM] Kicked out! Attempting reconnect...');
|
|
95
84
|
this._reconnectAttempts++;
|
|
96
85
|
if (this._reconnectAttempts > this._maxReconnectAttempts) {
|
|
97
|
-
|
|
86
|
+
console.log('[IM] Max reconnect attempts reached. Waiting before retry...');
|
|
98
87
|
this._reconnectAttempts = this._maxReconnectAttempts - 3;
|
|
99
88
|
}
|
|
100
89
|
const delay = Math.min(2000 * this._reconnectAttempts, 30000);
|
|
@@ -122,15 +111,15 @@ class IMClient {
|
|
|
122
111
|
|
|
123
112
|
async _reconnect() {
|
|
124
113
|
try {
|
|
125
|
-
|
|
114
|
+
console.log(`[IM] Reconnecting (attempt ${this._reconnectAttempts}/${this._maxReconnectAttempts})...`);
|
|
126
115
|
try { await this.tim.logout(); } catch {}
|
|
127
116
|
await this.login();
|
|
128
|
-
|
|
117
|
+
console.log('[IM] Reconnected successfully');
|
|
129
118
|
} catch (e) {
|
|
130
|
-
|
|
119
|
+
console.log('[IM] Reconnect failed:', e.message);
|
|
131
120
|
this._reconnectAttempts++;
|
|
132
121
|
if (this._reconnectAttempts > this._maxReconnectAttempts) {
|
|
133
|
-
|
|
122
|
+
console.log('[IM] Max reconnect attempts reached. Backing off...');
|
|
134
123
|
this._reconnectAttempts = this._maxReconnectAttempts - 3;
|
|
135
124
|
}
|
|
136
125
|
const delay = Math.min(2000 * this._reconnectAttempts, 30000);
|
|
@@ -146,18 +135,33 @@ class IMClient {
|
|
|
146
135
|
this._messageHandlers.push(handler);
|
|
147
136
|
}
|
|
148
137
|
|
|
149
|
-
async sendCustomMessage(to, ccType, payload = {}) {
|
|
138
|
+
async sendCustomMessage(to, ccType, payload = {}, pushOptions = null) {
|
|
150
139
|
const message = this.tim.createCustomMessage({
|
|
151
140
|
to,
|
|
152
141
|
conversationType: this.TIM.TYPES.CONV_C2C,
|
|
153
142
|
payload: {
|
|
154
|
-
data: JSON.stringify({ cc_type: ccType, ...payload }),
|
|
143
|
+
data: JSON.stringify({ cc_type: ccType, v: PROTOCOL_VERSION, min_v: MIN_PROTOCOL_VERSION, ...payload }),
|
|
155
144
|
description: 'CCLink',
|
|
156
145
|
},
|
|
157
146
|
});
|
|
158
|
-
|
|
147
|
+
|
|
148
|
+
// Default: silent (disablePush). Only messages with explicit pushOptions trigger notifications.
|
|
149
|
+
const sendOpts = {};
|
|
150
|
+
if (pushOptions) {
|
|
151
|
+
sendOpts.offlinePushInfo = {
|
|
152
|
+
title: pushOptions.title || 'CCLink',
|
|
153
|
+
description: pushOptions.desc || '',
|
|
154
|
+
extension: pushOptions.ext || '',
|
|
155
|
+
disablePush: false,
|
|
156
|
+
apnsInfo: { ignoreIOSBadge: pushOptions.ignoreBadge ?? false },
|
|
157
|
+
};
|
|
158
|
+
} else {
|
|
159
|
+
sendOpts.offlinePushInfo = { disablePush: true };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await this.tim.sendMessage(message, sendOpts);
|
|
159
163
|
return message.ID;
|
|
160
164
|
}
|
|
161
165
|
}
|
|
162
166
|
|
|
163
|
-
module.exports = { IMClient };
|
|
167
|
+
module.exports = { IMClient, PROTOCOL_VERSION };
|
package/src/index.js
CHANGED
|
@@ -133,11 +133,34 @@ async function shutdown(signal) {
|
|
|
133
133
|
|
|
134
134
|
process.on('exit', cleanupTempFiles);
|
|
135
135
|
|
|
136
|
+
async function checkForUpdates(agentID, pairedClientIDs) {
|
|
137
|
+
try {
|
|
138
|
+
const { execSync } = require('child_process');
|
|
139
|
+
const currentVersion = getVersion();
|
|
140
|
+
const latestVersion = execSync('npm view chatcc-agent version', {
|
|
141
|
+
encoding: 'utf-8', timeout: 15000,
|
|
142
|
+
}).trim();
|
|
143
|
+
if (latestVersion && latestVersion !== currentVersion) {
|
|
144
|
+
console.log(`[Update] New version available: ${currentVersion} -> ${latestVersion}`);
|
|
145
|
+
for (const clientID of pairedClientIDs) {
|
|
146
|
+
imClient.sendCustomMessage(clientID, 'update_available', {
|
|
147
|
+
current_version: currentVersion,
|
|
148
|
+
latest_version: latestVersion,
|
|
149
|
+
}).catch(() => {});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
// Non-fatal: network issues, npm unavailable, etc.
|
|
154
|
+
console.log('[Update] Check failed:', e.message);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
136
158
|
async function main() {
|
|
137
159
|
// Pre-flight: check Claude CLI is available
|
|
138
160
|
const { execFileSync } = require('child_process');
|
|
139
161
|
try {
|
|
140
|
-
execFileSync('claude', ['--version'], { stdio: 'pipe' });
|
|
162
|
+
const versionOutput = execFileSync('claude', ['--version'], { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
163
|
+
console.log('[Preflight] Claude CLI version:', versionOutput);
|
|
141
164
|
} catch {
|
|
142
165
|
console.error('[Fatal] Claude CLI not found. Install it first: npm install -g @anthropic-ai/claude-code');
|
|
143
166
|
process.exit(1);
|
|
@@ -207,6 +230,13 @@ async function main() {
|
|
|
207
230
|
}
|
|
208
231
|
}
|
|
209
232
|
|
|
233
|
+
// Auto-update check: on startup and every 24h
|
|
234
|
+
checkForUpdates(config.agentUserID, pairedClientIDs);
|
|
235
|
+
const updateInterval = setInterval(() => {
|
|
236
|
+
checkForUpdates(config.agentUserID, pairedClientIDs);
|
|
237
|
+
}, 24 * 60 * 60 * 1000);
|
|
238
|
+
updateInterval.unref();
|
|
239
|
+
|
|
210
240
|
// Setup services
|
|
211
241
|
sessions = new SessionStore(path.join(CHATCC_DIR, 'sessions.json'), {
|
|
212
242
|
maxSessions: MAX_SESSIONS,
|
|
@@ -231,6 +261,11 @@ async function main() {
|
|
|
231
261
|
request_id: reqId,
|
|
232
262
|
path: filePath,
|
|
233
263
|
operation,
|
|
264
|
+
}, {
|
|
265
|
+
title: '权限请求',
|
|
266
|
+
desc: `${operation}: ${filePath.length > 40 ? '...' + filePath.slice(-37) : filePath}`,
|
|
267
|
+
ext: JSON.stringify({ push_type: 'tool_confirm' }),
|
|
268
|
+
ignoreBadge: false,
|
|
234
269
|
}).catch(() => {});
|
|
235
270
|
const timer = setTimeout(() => {
|
|
236
271
|
fileService._pendingPermissions.delete(reqId);
|
|
@@ -408,6 +443,26 @@ async function main() {
|
|
|
408
443
|
break;
|
|
409
444
|
}
|
|
410
445
|
|
|
446
|
+
case 'clear_request': {
|
|
447
|
+
const sid = data.session_id;
|
|
448
|
+
const sess = sessions.get(sid) || null;
|
|
449
|
+
if (!sess || sess.clientID !== from) {
|
|
450
|
+
imClient.sendCustomMessage(from, 'clear_response', {
|
|
451
|
+
request_id: data.request_id, success: false, error: '会话不存在或无权限',
|
|
452
|
+
}).catch(() => {});
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
// Clear Claude session so next message starts fresh
|
|
456
|
+
sess.claudeSessionId = null;
|
|
457
|
+
sess.lastActiveAt = Date.now();
|
|
458
|
+
sessions.set(sid, sess);
|
|
459
|
+
console.log(`[Session] Clear context for ${sid}, claudeSessionId reset`);
|
|
460
|
+
imClient.sendCustomMessage(from, 'clear_response', {
|
|
461
|
+
request_id: data.request_id, success: true,
|
|
462
|
+
}).catch(e => console.error('[Clear] Reply failed:', e.message));
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
|
|
411
466
|
case 'compact_request': {
|
|
412
467
|
const sid = data.session_id;
|
|
413
468
|
const sess = sessions.get(sid) || null;
|
|
@@ -476,7 +531,11 @@ async function main() {
|
|
|
476
531
|
}
|
|
477
532
|
|
|
478
533
|
default:
|
|
479
|
-
console.log('[Message] Unknown cc_type:', data.cc_type);
|
|
534
|
+
console.log('[Message] Unknown cc_type:', data.cc_type, 'v=', data.v || 0);
|
|
535
|
+
imClient.sendCustomMessage(from, 'unknown_type_error', {
|
|
536
|
+
original_type: data.cc_type,
|
|
537
|
+
message: `Unknown cc_type: ${data.cc_type}`,
|
|
538
|
+
}).catch(() => {});
|
|
480
539
|
}
|
|
481
540
|
});
|
|
482
541
|
|
package/src/security.js
CHANGED
|
@@ -163,11 +163,12 @@ function validateTerminalCommand(input) {
|
|
|
163
163
|
|
|
164
164
|
function buildPermissions(data) {
|
|
165
165
|
if (!data) return null;
|
|
166
|
+
const { normalizePermission, PERMISSION_MODES, PERMISSION_ACTIONS } = require('./constants');
|
|
166
167
|
return {
|
|
167
|
-
defaultMode: data.default_mode ||
|
|
168
|
-
fileRead: data.file_read ||
|
|
169
|
-
fileEdit: data.file_edit ||
|
|
170
|
-
codeExec: data.code_exec ||
|
|
168
|
+
defaultMode: normalizePermission(data.default_mode || PERMISSION_MODES.CONFIRM_EVERY),
|
|
169
|
+
fileRead: normalizePermission(data.file_read || PERMISSION_ACTIONS.AUTO_ALLOW),
|
|
170
|
+
fileEdit: normalizePermission(data.file_edit || PERMISSION_ACTIONS.CONFIRM),
|
|
171
|
+
codeExec: normalizePermission(data.code_exec || PERMISSION_ACTIONS.CONFIRM),
|
|
171
172
|
};
|
|
172
173
|
}
|
|
173
174
|
|
package/src/server-info.js
CHANGED
|
@@ -2,6 +2,7 @@ const os = require('os');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { getVersion } = require('./version');
|
|
5
|
+
const { CURRENT_PROTOCOL_VERSION, MIN_PROTOCOL_VERSION } = require('./constants');
|
|
5
6
|
|
|
6
7
|
function collectServerMeta() {
|
|
7
8
|
const suggestedWorkspaces = [];
|
|
@@ -23,6 +24,8 @@ function collectServerMeta() {
|
|
|
23
24
|
cpuCount: os.cpus().length,
|
|
24
25
|
memoryGB: Math.round(os.totalmem() / 1024 / 1024 / 1024),
|
|
25
26
|
agentVersion: getVersion(),
|
|
27
|
+
protocol_version: CURRENT_PROTOCOL_VERSION,
|
|
28
|
+
min_protocol_version: MIN_PROTOCOL_VERSION,
|
|
26
29
|
suggestedWorkspaces: suggestedWorkspaces,
|
|
27
30
|
};
|
|
28
31
|
}
|