@xagent-ai/cli 1.0.1 → 1.1.1
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/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/README.md +280 -280
- package/README_CN.md +3 -3
- package/dist/ai-client.d.ts.map +1 -1
- package/dist/ai-client.js +84 -82
- package/dist/ai-client.js.map +1 -1
- package/dist/auth.d.ts +0 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +75 -105
- package/dist/auth.js.map +1 -1
- package/dist/cli.js +166 -13
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +48 -7
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts +5 -5
- package/dist/context-compressor.js +8 -8
- package/dist/context-compressor.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.d.ts +7 -0
- package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +6 -3
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/action-parser/constants.d.ts +6 -0
- package/dist/gui-subagent/action-parser/constants.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/constants.js +5 -3
- package/dist/gui-subagent/action-parser/constants.js.map +1 -1
- package/dist/gui-subagent/action-parser/index.d.ts +6 -0
- package/dist/gui-subagent/action-parser/index.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/index.js +5 -3
- package/dist/gui-subagent/action-parser/index.js.map +1 -1
- package/dist/gui-subagent/action-parser/types.d.ts +4 -0
- package/dist/gui-subagent/action-parser/types.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/types.js +3 -3
- package/dist/gui-subagent/agent/gui-agent.d.ts +39 -0
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +164 -89
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/agent/index.d.ts +1 -1
- package/dist/gui-subagent/agent/index.d.ts.map +1 -1
- package/dist/gui-subagent/agent/index.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +27 -1
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +6 -0
- package/dist/gui-subagent/index.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +140 -29
- package/dist/mcp.js.map +1 -1
- package/dist/remote-ai-client.d.ts +111 -0
- package/dist/remote-ai-client.d.ts.map +1 -0
- package/dist/remote-ai-client.js +558 -0
- package/dist/remote-ai-client.js.map +1 -0
- package/dist/sdk-output-adapter.d.ts +232 -0
- package/dist/sdk-output-adapter.d.ts.map +1 -0
- package/dist/sdk-output-adapter.js +636 -0
- package/dist/sdk-output-adapter.js.map +1 -0
- package/dist/sdk-session-v2.d.ts +13 -0
- package/dist/sdk-session-v2.d.ts.map +1 -0
- package/dist/sdk-session-v2.js +46 -0
- package/dist/sdk-session-v2.js.map +1 -0
- package/dist/sdk-session.d.ts +13 -0
- package/dist/sdk-session.d.ts.map +1 -0
- package/dist/sdk-session.js +48 -0
- package/dist/sdk-session.js.map +1 -0
- package/dist/session-manager.js +3 -3
- package/dist/session-manager.js.map +1 -1
- package/dist/session.d.ts +46 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +564 -117
- package/dist/session.js.map +1 -1
- package/dist/skill-invoker.d.ts +40 -4
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +310 -1184
- package/dist/skill-invoker.js.map +1 -1
- package/dist/skill-loader.d.ts +15 -1
- package/dist/skill-loader.d.ts.map +1 -1
- package/dist/skill-loader.js +49 -32
- package/dist/skill-loader.js.map +1 -1
- package/dist/slash-commands.d.ts +4 -2
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +149 -15
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts +2 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +29 -3
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.d.ts +4 -5
- package/dist/system-prompt-generator.d.ts.map +1 -1
- package/dist/system-prompt-generator.js +131 -81
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/tools.d.ts +17 -6
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +264 -211
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/docs/architecture/mcp-integration-guide.md +194 -131
- package/docs/architecture/overview.md +169 -93
- package/docs/architecture/tool-system-design.md +56 -11
- package/docs/cli/commands.md +238 -189
- package/docs/smart-mode.md +281 -257
- package/docs/third-party-models.md +247 -256
- package/package.json +6 -2
- package/src/ai-client.ts +107 -105
- package/src/auth.ts +82 -116
- package/src/cancellation.ts +1 -1
- package/src/cli.ts +178 -13
- package/src/config.ts +57 -8
- package/src/context-compressor.ts +8 -8
- package/src/gui-subagent/action-parser/actionParser.ts +6 -3
- package/src/gui-subagent/action-parser/constants.ts +5 -3
- package/src/gui-subagent/action-parser/index.ts +5 -3
- package/src/gui-subagent/action-parser/types.ts +3 -3
- package/src/gui-subagent/agent/gui-agent.ts +210 -103
- package/src/gui-subagent/agent/index.ts +1 -1
- package/src/gui-subagent/index.ts +26 -2
- package/src/index.ts +18 -18
- package/src/logger.ts +1 -1
- package/src/mcp.ts +149 -30
- package/src/remote-ai-client.ts +671 -0
- package/src/session-manager.ts +3 -3
- package/src/session.ts +742 -178
- package/src/skill-invoker.ts +340 -1293
- package/src/skill-loader.ts +55 -34
- package/src/slash-commands.ts +165 -15
- package/src/smart-approval.ts +34 -3
- package/src/system-prompt-generator.ts +145 -88
- package/src/tools.ts +309 -224
- package/src/types.ts +0 -1
- package/scripts/init-skills-path.js +0 -58
package/src/mcp.ts
CHANGED
|
@@ -12,6 +12,7 @@ export class MCPServer {
|
|
|
12
12
|
private process: ChildProcess | null = null;
|
|
13
13
|
private tools: Map<string, MCPTool> = new Map();
|
|
14
14
|
private isConnected: boolean = false;
|
|
15
|
+
private sessionId: string | null = null; // Save MCP session-id
|
|
15
16
|
|
|
16
17
|
constructor(config: MCPServerConfig) {
|
|
17
18
|
this.config = config;
|
|
@@ -167,9 +168,15 @@ export class MCPServer {
|
|
|
167
168
|
{ headers }
|
|
168
169
|
);
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
|
|
171
|
+
// Save session-id for subsequent requests (MCP HTTP protocol requirement)
|
|
172
|
+
const mcpSessionId = response.headers['mcp-session-id'];
|
|
173
|
+
if (mcpSessionId) {
|
|
174
|
+
this.sessionId = mcpSessionId;
|
|
172
175
|
}
|
|
176
|
+
|
|
177
|
+
// Some MCP servers return SSE-over-HTTP format, so we always call loadTools
|
|
178
|
+
// which handles both regular JSON and SSE format responses
|
|
179
|
+
await this.loadTools(headers);
|
|
173
180
|
} catch (error: any) {
|
|
174
181
|
console.error(`HTTP connection failed: ${error.message}`);
|
|
175
182
|
if (error.response) {
|
|
@@ -212,6 +219,12 @@ export class MCPServer {
|
|
|
212
219
|
throw new Error(`SSE initialize failed: ${initResponse.status} ${initResponse.statusText}`);
|
|
213
220
|
}
|
|
214
221
|
|
|
222
|
+
// Save session-id (MCP SSE protocol requirement)
|
|
223
|
+
const mcpSessionId = initResponse.headers.get('mcp-session-id');
|
|
224
|
+
if (mcpSessionId) {
|
|
225
|
+
this.sessionId = mcpSessionId;
|
|
226
|
+
}
|
|
227
|
+
|
|
215
228
|
// For SSE endpoints, try to load tools via a separate POST request
|
|
216
229
|
await this.loadTools(headers);
|
|
217
230
|
|
|
@@ -243,10 +256,15 @@ export class MCPServer {
|
|
|
243
256
|
}
|
|
244
257
|
} catch (error: any) {
|
|
245
258
|
clearTimeout(timeoutId);
|
|
259
|
+
const serverInfo = this.config.url || this.config.command || 'MCP server';
|
|
246
260
|
if (error.name === 'AbortError') {
|
|
247
|
-
console.error(
|
|
261
|
+
console.error(`\n❌ SSE connection timed out`);
|
|
262
|
+
console.error(` Server: ${serverInfo}`);
|
|
263
|
+
console.error(` The server is not responding. Please try again later.`);
|
|
248
264
|
} else {
|
|
249
|
-
console.error(
|
|
265
|
+
console.error(`\n❌ SSE connection failed`);
|
|
266
|
+
console.error(` Server: ${serverInfo}`);
|
|
267
|
+
console.error(` ${error.message}`);
|
|
250
268
|
}
|
|
251
269
|
throw error;
|
|
252
270
|
}
|
|
@@ -266,8 +284,15 @@ export class MCPServer {
|
|
|
266
284
|
}
|
|
267
285
|
|
|
268
286
|
private handleJsonRpcMessage(message: any): void {
|
|
269
|
-
|
|
287
|
+
// Handle response format: {id: 1, result: {tools: [...]}}
|
|
288
|
+
if (message.result && message.result.tools) {
|
|
270
289
|
this.handleToolsList(message.result);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Handle notification format: {method: 'tools/list', params: {...}}
|
|
294
|
+
if (message.method === 'tools/list') {
|
|
295
|
+
this.handleToolsList(message.params);
|
|
271
296
|
} else if (message.method === 'notifications/initialized') {
|
|
272
297
|
console.log('MCP Server initialized');
|
|
273
298
|
}
|
|
@@ -282,6 +307,7 @@ export class MCPServer {
|
|
|
282
307
|
private handleToolsList(result: any): void {
|
|
283
308
|
if (result && result.tools) {
|
|
284
309
|
for (const tool of result.tools) {
|
|
310
|
+
if (!tool.name || typeof tool.name !== 'string' || tool.name.trim() === '') continue;
|
|
285
311
|
this.tools.set(tool.name, tool);
|
|
286
312
|
}
|
|
287
313
|
console.log(`Loaded ${result.tools.length} tools from MCP Server`);
|
|
@@ -297,6 +323,17 @@ export class MCPServer {
|
|
|
297
323
|
const axios = (await import('axios')).default;
|
|
298
324
|
|
|
299
325
|
try {
|
|
326
|
+
// Build headers with session-id for MCP protocol
|
|
327
|
+
const requestHeaders: Record<string, string> = {
|
|
328
|
+
'Content-Type': 'application/json',
|
|
329
|
+
...this.config.headers,
|
|
330
|
+
...headers
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
if (this.sessionId) {
|
|
334
|
+
requestHeaders['MCP-session-id'] = this.sessionId;
|
|
335
|
+
}
|
|
336
|
+
|
|
300
337
|
const response = await axios.post(
|
|
301
338
|
this.config.url,
|
|
302
339
|
{
|
|
@@ -305,25 +342,27 @@ export class MCPServer {
|
|
|
305
342
|
method: 'tools/list'
|
|
306
343
|
},
|
|
307
344
|
{
|
|
308
|
-
headers:
|
|
309
|
-
'Content-Type': 'application/json',
|
|
310
|
-
...this.config.headers,
|
|
311
|
-
...headers
|
|
312
|
-
},
|
|
345
|
+
headers: requestHeaders,
|
|
313
346
|
timeout: 10000
|
|
314
347
|
}
|
|
315
348
|
);
|
|
316
349
|
|
|
317
350
|
let resultData = response.data;
|
|
318
351
|
|
|
319
|
-
//
|
|
352
|
+
// Auto-detect response format (HTTP vs SSE)
|
|
353
|
+
const contentType = response.headers['content-type'] || '';
|
|
320
354
|
const dataStr = response.data?.toString() || '';
|
|
321
|
-
|
|
355
|
+
|
|
356
|
+
const isSSE = contentType.includes('text/event-stream') ||
|
|
357
|
+
dataStr.startsWith('id:') ||
|
|
358
|
+
dataStr.startsWith('data:');
|
|
359
|
+
|
|
360
|
+
if (isSSE) {
|
|
322
361
|
// Parse SSE format: "id:1\nevent:message\ndata:{...}"
|
|
323
|
-
const dataMatch = dataStr.match(/data:(
|
|
362
|
+
const dataMatch = dataStr.match(/data:(.+)$/m);
|
|
324
363
|
if (dataMatch) {
|
|
325
364
|
try {
|
|
326
|
-
resultData = JSON.parse(dataMatch[1]);
|
|
365
|
+
resultData = JSON.parse(dataMatch[1].trim());
|
|
327
366
|
} catch (e: any) {
|
|
328
367
|
console.error(`Failed to parse SSE data: ${e.message}`);
|
|
329
368
|
}
|
|
@@ -332,11 +371,17 @@ export class MCPServer {
|
|
|
332
371
|
|
|
333
372
|
if (resultData?.result?.tools) {
|
|
334
373
|
this.handleToolsList(resultData.result);
|
|
374
|
+
} else if (resultData?.tools) {
|
|
375
|
+
this.handleToolsList(resultData);
|
|
335
376
|
} else if (resultData?.error) {
|
|
336
|
-
console.error(
|
|
377
|
+
console.error(`\n❌ MCP server returned an error`);
|
|
378
|
+
console.error(` ${resultData.error.message || 'Unknown error'}`);
|
|
337
379
|
}
|
|
338
380
|
} catch (error: any) {
|
|
339
|
-
|
|
381
|
+
const serverInfo = this.config.url || this.config.command || 'MCP server';
|
|
382
|
+
console.error(`\n❌ Failed to load MCP tools`);
|
|
383
|
+
console.error(` Server: ${serverInfo}`);
|
|
384
|
+
console.error(` ${error.message}`);
|
|
340
385
|
}
|
|
341
386
|
}
|
|
342
387
|
|
|
@@ -371,15 +416,67 @@ export class MCPServer {
|
|
|
371
416
|
const axios = (await import('axios')).default;
|
|
372
417
|
|
|
373
418
|
try {
|
|
419
|
+
// Build headers with auth token
|
|
420
|
+
const headers: Record<string, string> = {
|
|
421
|
+
'Content-Type': 'application/json',
|
|
422
|
+
'Accept': 'application/json, text/event-stream',
|
|
423
|
+
...this.config.headers
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
if (this.config.authToken) {
|
|
427
|
+
if (this.config.authToken.startsWith('Bearer ')) {
|
|
428
|
+
headers['Authorization'] = this.config.authToken;
|
|
429
|
+
} else {
|
|
430
|
+
headers['Authorization'] = `Bearer ${this.config.authToken}`;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Add session-id to request headers (MCP HTTP protocol requirement)
|
|
435
|
+
if (this.sessionId) {
|
|
436
|
+
headers['MCP-session-id'] = this.sessionId;
|
|
437
|
+
}
|
|
438
|
+
|
|
374
439
|
const response = await axios.post(this.config.url!, message, {
|
|
375
|
-
headers
|
|
376
|
-
'Content-Type': 'application/json',
|
|
377
|
-
...this.config.headers
|
|
378
|
-
},
|
|
440
|
+
headers,
|
|
379
441
|
timeout: this.config.timeout || 30000
|
|
380
442
|
});
|
|
381
443
|
|
|
382
|
-
|
|
444
|
+
// Update session-id if new one provided in response
|
|
445
|
+
const responseSessionId = response.headers['mcp-session-id'];
|
|
446
|
+
if (responseSessionId) {
|
|
447
|
+
this.sessionId = responseSessionId;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Auto-detect response format (HTTP vs SSE)
|
|
451
|
+
const contentType = response.headers['content-type'] || '';
|
|
452
|
+
let resultData;
|
|
453
|
+
|
|
454
|
+
if (contentType.includes('text/event-stream') ||
|
|
455
|
+
(typeof response.data === 'string' && response.data.startsWith('id:'))) {
|
|
456
|
+
// Parse SSE format: "id:1\nevent:message\ndata:{...}"
|
|
457
|
+
const sseData = response.data;
|
|
458
|
+
const dataMatch = sseData.match(/data:(.+)$/m);
|
|
459
|
+
if (dataMatch) {
|
|
460
|
+
try {
|
|
461
|
+
resultData = JSON.parse(dataMatch[1].trim());
|
|
462
|
+
} catch (e: any) {
|
|
463
|
+
throw new Error(`Failed to parse SSE data: ${e.message}`);
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
throw new Error('No data field found in SSE response');
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
// Direct JSON response
|
|
470
|
+
resultData = response.data;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Check for error response
|
|
474
|
+
if (resultData?.isError) {
|
|
475
|
+
const errorMsg = resultData?.content?.[0]?.text || 'Unknown error';
|
|
476
|
+
throw new Error(`MCP server error: ${errorMsg}`);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return resultData?.result;
|
|
383
480
|
} catch (error: any) {
|
|
384
481
|
throw new Error(`MCP Tool call failed: ${error.message}`);
|
|
385
482
|
}
|
|
@@ -398,18 +495,31 @@ export class MCPServer {
|
|
|
398
495
|
|
|
399
496
|
const responseHandler = (data: Buffer) => {
|
|
400
497
|
try {
|
|
401
|
-
const
|
|
498
|
+
const rawResponse = data.toString();
|
|
499
|
+
const response = JSON.parse(rawResponse);
|
|
500
|
+
|
|
501
|
+
if (process.env.DEBUG === 'mcp' || process.env.DEBUG === 'all') {
|
|
502
|
+
console.log('\n========== MCP STDIO Raw Response ==========');
|
|
503
|
+
console.log('Raw:', rawResponse);
|
|
504
|
+
console.log('Parsed:', JSON.stringify(response, null, 2));
|
|
505
|
+
console.log('==========================================\n');
|
|
506
|
+
}
|
|
507
|
+
|
|
402
508
|
if (response.id === message.id) {
|
|
403
509
|
clearTimeout(timeout);
|
|
404
510
|
this.process?.stdout?.off('data', responseHandler);
|
|
405
511
|
|
|
406
512
|
if (response.error) {
|
|
407
|
-
reject(new Error(response.error.message));
|
|
513
|
+
reject(new Error(`MCP tool error: ${response.error.message || 'Unknown error'}`));
|
|
408
514
|
} else {
|
|
409
515
|
resolve(response.result);
|
|
410
516
|
}
|
|
411
517
|
}
|
|
412
518
|
} catch (error) {
|
|
519
|
+
console.error('\n========== MCP STDIO Parse Error ==========');
|
|
520
|
+
console.error('Raw data:', data.toString());
|
|
521
|
+
console.error('Error:', error);
|
|
522
|
+
console.error('==========================================\n');
|
|
413
523
|
reject(error);
|
|
414
524
|
}
|
|
415
525
|
};
|
|
@@ -452,7 +562,7 @@ export class MCPManager {
|
|
|
452
562
|
async connectServer(name: string): Promise<void> {
|
|
453
563
|
const server = this.servers.get(name);
|
|
454
564
|
if (!server) {
|
|
455
|
-
throw new Error(`MCP
|
|
565
|
+
throw new Error(`MCP server not found: ${name}. Please check the server name and try again.`);
|
|
456
566
|
}
|
|
457
567
|
await server.connect();
|
|
458
568
|
}
|
|
@@ -463,7 +573,7 @@ export class MCPManager {
|
|
|
463
573
|
try {
|
|
464
574
|
await server.connect();
|
|
465
575
|
} catch (error) {
|
|
466
|
-
console.error(`Failed to connect MCP
|
|
576
|
+
console.error(`Failed to connect MCP server ${name}:`, error);
|
|
467
577
|
}
|
|
468
578
|
}
|
|
469
579
|
);
|
|
@@ -506,6 +616,7 @@ export class MCPManager {
|
|
|
506
616
|
|
|
507
617
|
this.servers.forEach((server, serverName) => {
|
|
508
618
|
server.getTools().forEach(tool => {
|
|
619
|
+
if (!tool.name) return;
|
|
509
620
|
allTools.set(`${serverName}__${tool.name}`, tool);
|
|
510
621
|
});
|
|
511
622
|
});
|
|
@@ -514,11 +625,13 @@ export class MCPManager {
|
|
|
514
625
|
}
|
|
515
626
|
|
|
516
627
|
async callTool(toolName: string, params: any): Promise<any> {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (
|
|
628
|
+
// Split only on the first __ to preserve underscores in tool names
|
|
629
|
+
const firstUnderscoreIndex = toolName.indexOf('__');
|
|
630
|
+
if (firstUnderscoreIndex === -1) {
|
|
520
631
|
throw new Error(`Invalid tool name format: ${toolName}`);
|
|
521
632
|
}
|
|
633
|
+
const serverName = toolName.substring(0, firstUnderscoreIndex);
|
|
634
|
+
const actualToolName = toolName.substring(firstUnderscoreIndex + 2);
|
|
522
635
|
|
|
523
636
|
const server = this.servers.get(serverName);
|
|
524
637
|
if (!server) {
|
|
@@ -538,12 +651,18 @@ export class MCPManager {
|
|
|
538
651
|
|
|
539
652
|
this.servers.forEach((server, serverName) => {
|
|
540
653
|
server.getTools().forEach(tool => {
|
|
654
|
+
if (!tool.name) return;
|
|
655
|
+
|
|
541
656
|
tools.push({
|
|
542
657
|
type: 'function',
|
|
543
658
|
function: {
|
|
544
659
|
name: `${serverName}__${tool.name}`,
|
|
545
|
-
description: tool.description
|
|
546
|
-
parameters: tool.inputSchema
|
|
660
|
+
description: tool.description || `MCP tool: ${tool.name}`,
|
|
661
|
+
parameters: tool.inputSchema || {
|
|
662
|
+
type: 'object',
|
|
663
|
+
properties: {},
|
|
664
|
+
required: []
|
|
665
|
+
}
|
|
547
666
|
}
|
|
548
667
|
});
|
|
549
668
|
});
|