coding-tool-x 3.5.2 → 3.5.4
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/CHANGELOG.md +15 -0
- package/dist/web/assets/Analytics-CmN09J9U.js +25 -0
- package/dist/web/assets/{ConfigTemplates-uvPIB9bY.js → ConfigTemplates-CeTAPmep.js} +1 -1
- package/dist/web/assets/{Home-C3w31EDB.js → Home-BYtCM3rK.js} +1 -1
- package/dist/web/assets/{PluginManager-CfvgUebQ.js → PluginManager-OAH1eMO0.js} +1 -1
- package/dist/web/assets/{ProjectList-C16vMDcU.js → ProjectList-B0pIy1cv.js} +1 -1
- package/dist/web/assets/{SessionList-DWuhaeMb.js → SessionList-DbB6ASiA.js} +1 -1
- package/dist/web/assets/{SkillManager-CRMUhw4v.js → SkillManager-wp1dhL1z.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-BOX_nqej.js → WorkspaceManager-Ce6wQoKb.js} +1 -1
- package/dist/web/assets/{icons-B5Pl4lrD.js → icons-DlxD2wZJ.js} +1 -1
- package/dist/web/assets/{index-B1ujw2sM.js → index-CHwVofQH.js} +2 -2
- package/dist/web/assets/{naive-ui-Bdxp09n2.js → naive-ui-BaTCPPL5.js} +1 -1
- package/dist/web/assets/{vendors-CKPV1OAU.js → vendors-Fza9uSYn.js} +1 -1
- package/dist/web/assets/vue-vendor-aWwwFAao.js +45 -0
- package/dist/web/index.html +5 -5
- package/package.json +2 -2
- package/src/commands/daemon.js +87 -44
- package/src/index.js +21 -10
- package/src/server/index.js +5 -1
- package/src/server/services/mcp-client.js +37 -13
- package/dist/web/assets/Analytics-B653rHbb.js +0 -39
- package/dist/web/assets/vue-vendor-3bf-fPGP.js +0 -45
package/src/index.js
CHANGED
|
@@ -6,30 +6,24 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const { loadConfig } = require('./config/loader');
|
|
9
|
-
const { showMainMenu } = require('./ui/menu');
|
|
10
|
-
const { handleList } = require('./commands/list');
|
|
11
|
-
const { handleSearch } = require('./commands/search');
|
|
12
|
-
const { switchProject } = require('./commands/switch');
|
|
13
9
|
const { resetConfig } = require('./reset-config');
|
|
14
|
-
const { handleChannelManagement, handleAddChannel, handleChannelStatus } = require('./commands/channels');
|
|
15
|
-
const { handleToggleProxy } = require('./commands/toggle-proxy');
|
|
16
|
-
const { handlePortConfig } = require('./commands/port-config');
|
|
17
|
-
const { handleSwitchCliType } = require('./commands/cli-type');
|
|
18
10
|
const { handleStart, handleStop, handleRestart, handleStatus } = require('./commands/daemon');
|
|
19
11
|
const { handleProxyStart: proxyStart, handleProxyStop: proxyStop, handleProxyRestart, handleProxyStatus: proxyStatus } = require('./commands/proxy-control');
|
|
20
12
|
const { handleLogs } = require('./commands/logs');
|
|
21
13
|
const { handleStats, handleStatsExport } = require('./commands/stats');
|
|
22
14
|
const { handleDoctor } = require('./commands/doctor');
|
|
23
15
|
const { handleUpdate } = require('./commands/update');
|
|
24
|
-
const { workspaceMenu } = require('./commands/workspace');
|
|
25
16
|
const { ensureStorageDirMigrated } = require('./config/paths');
|
|
26
17
|
const PluginManager = require('./plugins/plugin-manager');
|
|
27
18
|
const eventBus = require('./plugins/event-bus');
|
|
28
19
|
const chalk = require('chalk');
|
|
29
|
-
const inquirer = require('inquirer');
|
|
30
20
|
const path = require('path');
|
|
31
21
|
const fs = require('fs');
|
|
32
22
|
|
|
23
|
+
function getInquirer() {
|
|
24
|
+
return require('inquirer');
|
|
25
|
+
}
|
|
26
|
+
|
|
33
27
|
// 读取版本号
|
|
34
28
|
function getVersion() {
|
|
35
29
|
const packagePath = path.join(__dirname, '../package.json');
|
|
@@ -338,6 +332,7 @@ async function main() {
|
|
|
338
332
|
|
|
339
333
|
// port 命令 - 配置端口
|
|
340
334
|
if (args[0] === 'port') {
|
|
335
|
+
const { handlePortConfig } = require('./commands/port-config');
|
|
341
336
|
await handlePortConfig();
|
|
342
337
|
return;
|
|
343
338
|
}
|
|
@@ -400,6 +395,7 @@ async function main() {
|
|
|
400
395
|
|
|
401
396
|
while (true) {
|
|
402
397
|
// 显示主菜单
|
|
398
|
+
const { showMainMenu } = require('./ui/menu');
|
|
403
399
|
const action = await showMainMenu(config);
|
|
404
400
|
|
|
405
401
|
// 发送命令开始事件
|
|
@@ -409,7 +405,9 @@ async function main() {
|
|
|
409
405
|
|
|
410
406
|
switch (action) {
|
|
411
407
|
case 'list':
|
|
408
|
+
const { handleList } = require('./commands/list');
|
|
412
409
|
await handleList(config, async () => {
|
|
410
|
+
const { switchProject } = require('./commands/switch');
|
|
413
411
|
const switched = await switchProject(config);
|
|
414
412
|
if (switched) {
|
|
415
413
|
// 重新加载配置以获取最新的项目设置
|
|
@@ -420,7 +418,9 @@ async function main() {
|
|
|
420
418
|
break;
|
|
421
419
|
|
|
422
420
|
case 'search':
|
|
421
|
+
const { handleSearch } = require('./commands/search');
|
|
423
422
|
await handleSearch(config, async () => {
|
|
423
|
+
const { switchProject } = require('./commands/switch');
|
|
424
424
|
const switched = await switchProject(config);
|
|
425
425
|
if (switched) {
|
|
426
426
|
config = loadConfig();
|
|
@@ -430,11 +430,14 @@ async function main() {
|
|
|
430
430
|
break;
|
|
431
431
|
|
|
432
432
|
case 'switch':
|
|
433
|
+
const { switchProject } = require('./commands/switch');
|
|
433
434
|
const switched = await switchProject(config);
|
|
434
435
|
if (switched) {
|
|
435
436
|
config = loadConfig();
|
|
436
437
|
// 切换成功后自动进入会话列表
|
|
438
|
+
const { handleList } = require('./commands/list');
|
|
437
439
|
await handleList(config, async () => {
|
|
440
|
+
const { switchProject } = require('./commands/switch');
|
|
438
441
|
const switched = await switchProject(config);
|
|
439
442
|
if (switched) {
|
|
440
443
|
config = loadConfig();
|
|
@@ -445,26 +448,32 @@ async function main() {
|
|
|
445
448
|
break;
|
|
446
449
|
|
|
447
450
|
case 'workspace':
|
|
451
|
+
const { workspaceMenu } = require('./commands/workspace');
|
|
448
452
|
await workspaceMenu();
|
|
449
453
|
break;
|
|
450
454
|
|
|
451
455
|
case 'switch-cli-type':
|
|
456
|
+
const { handleSwitchCliType } = require('./commands/cli-type');
|
|
452
457
|
await handleSwitchCliType();
|
|
453
458
|
config = loadConfig(); // 重新加载配置以获取新的类型
|
|
454
459
|
break;
|
|
455
460
|
|
|
456
461
|
case 'switch-channel':
|
|
462
|
+
const { handleChannelManagement } = require('./commands/channels');
|
|
457
463
|
await handleChannelManagement();
|
|
458
464
|
break;
|
|
459
465
|
case 'channel-status':
|
|
466
|
+
const { handleChannelStatus } = require('./commands/channels');
|
|
460
467
|
await handleChannelStatus();
|
|
461
468
|
break;
|
|
462
469
|
|
|
463
470
|
case 'toggle-proxy':
|
|
471
|
+
const { handleToggleProxy } = require('./commands/toggle-proxy');
|
|
464
472
|
await handleToggleProxy();
|
|
465
473
|
break;
|
|
466
474
|
|
|
467
475
|
case 'add-channel':
|
|
476
|
+
const { handleAddChannel } = require('./commands/channels');
|
|
468
477
|
await handleAddChannel();
|
|
469
478
|
break;
|
|
470
479
|
|
|
@@ -475,6 +484,7 @@ async function main() {
|
|
|
475
484
|
}
|
|
476
485
|
|
|
477
486
|
case 'port-config':
|
|
487
|
+
const { handlePortConfig } = require('./commands/port-config');
|
|
478
488
|
await handlePortConfig();
|
|
479
489
|
break;
|
|
480
490
|
|
|
@@ -484,6 +494,7 @@ async function main() {
|
|
|
484
494
|
|
|
485
495
|
case 'plugin-menu': {
|
|
486
496
|
const { handlePluginCommand } = require('./commands/plugin');
|
|
497
|
+
const inquirer = getInquirer();
|
|
487
498
|
|
|
488
499
|
// Show plugin management submenu
|
|
489
500
|
const pluginAction = await inquirer.prompt([{
|
package/src/server/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
-
const inquirer = require('inquirer');
|
|
5
4
|
const { loadConfig } = require('../config/loader');
|
|
6
5
|
const { PATHS, ensureStorageDirMigrated } = require('../config/paths');
|
|
7
6
|
const { startWebSocketServer: attachWebSocketServer } = require('./websocket-server');
|
|
@@ -25,6 +24,10 @@ const { startOpenCodeProxyServer, collectProxyModelList } = require('./opencode-
|
|
|
25
24
|
const { createRemoteMutationGuard } = require('./services/network-access');
|
|
26
25
|
const { createApiRequestLogger } = require('./services/request-logger');
|
|
27
26
|
|
|
27
|
+
function getInquirer() {
|
|
28
|
+
return require('inquirer');
|
|
29
|
+
}
|
|
30
|
+
|
|
28
31
|
function isInteractivePortConflictMode(options = {}) {
|
|
29
32
|
if (options.interactive === false) {
|
|
30
33
|
return false;
|
|
@@ -73,6 +76,7 @@ async function startServer(port, host = '127.0.0.1', options = {}) {
|
|
|
73
76
|
shouldKill = true;
|
|
74
77
|
} else if (interactiveMode) {
|
|
75
78
|
// 询问用户是否关闭占用端口的进程
|
|
79
|
+
const inquirer = getInquirer();
|
|
76
80
|
const answer = await inquirer.prompt([
|
|
77
81
|
{
|
|
78
82
|
type: 'list',
|
|
@@ -204,6 +204,8 @@ class McpClient extends EventEmitter {
|
|
|
204
204
|
// HTTP/SSE transport state
|
|
205
205
|
this._sseAbortController = null;
|
|
206
206
|
this._httpSessionUrl = null;
|
|
207
|
+
this._httpSessionId = null;
|
|
208
|
+
this._negotiatedProtocolVersion = MCP_PROTOCOL_VERSION;
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
// --------------------------------------------------------------------------
|
|
@@ -249,11 +251,12 @@ class McpClient extends EventEmitter {
|
|
|
249
251
|
}
|
|
250
252
|
});
|
|
251
253
|
|
|
254
|
+
this._negotiatedProtocolVersion = result.protocolVersion || MCP_PROTOCOL_VERSION;
|
|
252
255
|
this._serverCapabilities = result.capabilities || {};
|
|
253
256
|
this._serverInfo = result.serverInfo || {};
|
|
254
257
|
|
|
255
258
|
// Send initialized notification (no response expected)
|
|
256
|
-
this._notify('notifications/initialized', {});
|
|
259
|
+
await this._notify('notifications/initialized', {});
|
|
257
260
|
|
|
258
261
|
this._initialized = true;
|
|
259
262
|
this.emit('initialized', result);
|
|
@@ -654,11 +657,18 @@ class McpClient extends EventEmitter {
|
|
|
654
657
|
'Content-Type': 'application/json',
|
|
655
658
|
'Content-Length': Buffer.byteLength(body),
|
|
656
659
|
'Accept': 'application/json, text/event-stream',
|
|
660
|
+
...(msg.method !== 'initialize'
|
|
661
|
+
? {
|
|
662
|
+
'MCP-Protocol-Version': this._negotiatedProtocolVersion || MCP_PROTOCOL_VERSION,
|
|
663
|
+
...(this._httpSessionId ? { 'Mcp-Session-Id': this._httpSessionId } : {})
|
|
664
|
+
}
|
|
665
|
+
: {}),
|
|
657
666
|
...this._spec.headers
|
|
658
667
|
}
|
|
659
668
|
};
|
|
660
669
|
|
|
661
670
|
const req = client.request(options, (res) => {
|
|
671
|
+
this._captureHttpResponseMetadata(res);
|
|
662
672
|
let data = '';
|
|
663
673
|
res.on('data', (chunk) => { data += chunk.toString(); });
|
|
664
674
|
res.on('end', () => {
|
|
@@ -669,7 +679,19 @@ class McpClient extends EventEmitter {
|
|
|
669
679
|
return;
|
|
670
680
|
}
|
|
671
681
|
|
|
682
|
+
const isNotification = msg.id === undefined || msg.id === null;
|
|
672
683
|
const contentType = res.headers['content-type'] || '';
|
|
684
|
+
const trimmedData = data.trim();
|
|
685
|
+
|
|
686
|
+
if (!trimmedData) {
|
|
687
|
+
if (isNotification || res.statusCode === 202 || res.statusCode === 204) {
|
|
688
|
+
resolve();
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
reject(new McpClientError('Empty HTTP response for request'));
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
673
695
|
|
|
674
696
|
// JSON response (direct response to JSON-RPC)
|
|
675
697
|
if (contentType.includes('application/json')) {
|
|
@@ -690,12 +712,6 @@ class McpClient extends EventEmitter {
|
|
|
690
712
|
return;
|
|
691
713
|
}
|
|
692
714
|
|
|
693
|
-
// Accepted with no body (202, notifications)
|
|
694
|
-
if (res.statusCode === 202 || !data.trim()) {
|
|
695
|
-
resolve();
|
|
696
|
-
return;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
715
|
// Try parsing as JSON anyway
|
|
700
716
|
try {
|
|
701
717
|
const parsed = JSON.parse(data);
|
|
@@ -761,6 +777,8 @@ class McpClient extends EventEmitter {
|
|
|
761
777
|
/** @private */
|
|
762
778
|
_disconnectHttp() {
|
|
763
779
|
this._httpSessionUrl = null;
|
|
780
|
+
this._httpSessionId = null;
|
|
781
|
+
this._negotiatedProtocolVersion = MCP_PROTOCOL_VERSION;
|
|
764
782
|
}
|
|
765
783
|
|
|
766
784
|
// --------------------------------------------------------------------------
|
|
@@ -807,7 +825,7 @@ class McpClient extends EventEmitter {
|
|
|
807
825
|
}
|
|
808
826
|
|
|
809
827
|
/** @private */
|
|
810
|
-
_notify(method, params) {
|
|
828
|
+
async _notify(method, params) {
|
|
811
829
|
const msg = {
|
|
812
830
|
jsonrpc: JSONRPC_VERSION,
|
|
813
831
|
method,
|
|
@@ -817,14 +835,20 @@ class McpClient extends EventEmitter {
|
|
|
817
835
|
try {
|
|
818
836
|
if (this._type === 'stdio') {
|
|
819
837
|
this._sendStdio(msg);
|
|
838
|
+
return;
|
|
820
839
|
} else {
|
|
821
|
-
|
|
822
|
-
this._sendHttp(msg).catch((err) => {
|
|
823
|
-
this.emit('error', new McpClientError(`Notification send failed: ${err.message}`));
|
|
824
|
-
});
|
|
840
|
+
await this._sendHttp(msg);
|
|
825
841
|
}
|
|
826
842
|
} catch (err) {
|
|
827
|
-
|
|
843
|
+
throw new McpClientError(`Notification send failed: ${err.message}`);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/** @private */
|
|
848
|
+
_captureHttpResponseMetadata(res) {
|
|
849
|
+
const sessionId = res && res.headers ? res.headers['mcp-session-id'] : null;
|
|
850
|
+
if (typeof sessionId === 'string' && sessionId.trim()) {
|
|
851
|
+
this._httpSessionId = sessionId.trim();
|
|
828
852
|
}
|
|
829
853
|
}
|
|
830
854
|
|