@xagent-ai/cli 1.2.0 → 1.2.2

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.
Files changed (80) hide show
  1. package/README.md +1 -1
  2. package/README_CN.md +1 -1
  3. package/dist/agents.js +164 -164
  4. package/dist/agents.js.map +1 -1
  5. package/dist/ai-client.d.ts +4 -6
  6. package/dist/ai-client.d.ts.map +1 -1
  7. package/dist/ai-client.js +137 -115
  8. package/dist/ai-client.js.map +1 -1
  9. package/dist/auth.js +4 -4
  10. package/dist/auth.js.map +1 -1
  11. package/dist/cli.js +184 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/config.js +3 -3
  14. package/dist/config.js.map +1 -1
  15. package/dist/context-compressor.d.ts.map +1 -1
  16. package/dist/context-compressor.js +65 -81
  17. package/dist/context-compressor.js.map +1 -1
  18. package/dist/conversation.d.ts +1 -1
  19. package/dist/conversation.d.ts.map +1 -1
  20. package/dist/conversation.js +5 -31
  21. package/dist/conversation.js.map +1 -1
  22. package/dist/memory.d.ts +5 -1
  23. package/dist/memory.d.ts.map +1 -1
  24. package/dist/memory.js +77 -37
  25. package/dist/memory.js.map +1 -1
  26. package/dist/remote-ai-client.d.ts +1 -8
  27. package/dist/remote-ai-client.d.ts.map +1 -1
  28. package/dist/remote-ai-client.js +55 -65
  29. package/dist/remote-ai-client.js.map +1 -1
  30. package/dist/retry.d.ts +35 -0
  31. package/dist/retry.d.ts.map +1 -0
  32. package/dist/retry.js +166 -0
  33. package/dist/retry.js.map +1 -0
  34. package/dist/session.d.ts +0 -5
  35. package/dist/session.d.ts.map +1 -1
  36. package/dist/session.js +243 -312
  37. package/dist/session.js.map +1 -1
  38. package/dist/slash-commands.d.ts +1 -0
  39. package/dist/slash-commands.d.ts.map +1 -1
  40. package/dist/slash-commands.js +91 -9
  41. package/dist/slash-commands.js.map +1 -1
  42. package/dist/smart-approval.d.ts.map +1 -1
  43. package/dist/smart-approval.js +18 -17
  44. package/dist/smart-approval.js.map +1 -1
  45. package/dist/system-prompt-generator.d.ts.map +1 -1
  46. package/dist/system-prompt-generator.js +149 -139
  47. package/dist/system-prompt-generator.js.map +1 -1
  48. package/dist/theme.d.ts +48 -0
  49. package/dist/theme.d.ts.map +1 -1
  50. package/dist/theme.js +254 -0
  51. package/dist/theme.js.map +1 -1
  52. package/dist/tools/edit-diff.d.ts +32 -0
  53. package/dist/tools/edit-diff.d.ts.map +1 -0
  54. package/dist/tools/edit-diff.js +185 -0
  55. package/dist/tools/edit-diff.js.map +1 -0
  56. package/dist/tools/edit.d.ts +11 -0
  57. package/dist/tools/edit.d.ts.map +1 -0
  58. package/dist/tools/edit.js +129 -0
  59. package/dist/tools/edit.js.map +1 -0
  60. package/dist/tools.d.ts +19 -5
  61. package/dist/tools.d.ts.map +1 -1
  62. package/dist/tools.js +979 -631
  63. package/dist/tools.js.map +1 -1
  64. package/dist/types.d.ts +6 -31
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +3 -2
  67. package/src/agents.ts +504 -504
  68. package/src/ai-client.ts +1559 -1458
  69. package/src/auth.ts +4 -4
  70. package/src/cli.ts +195 -1
  71. package/src/config.ts +3 -3
  72. package/src/memory.ts +55 -14
  73. package/src/remote-ai-client.ts +663 -683
  74. package/src/retry.ts +217 -0
  75. package/src/session.ts +1736 -1840
  76. package/src/slash-commands.ts +98 -9
  77. package/src/smart-approval.ts +626 -625
  78. package/src/system-prompt-generator.ts +853 -843
  79. package/src/theme.ts +284 -0
  80. package/src/tools.ts +390 -70
package/src/agents.ts CHANGED
@@ -1,504 +1,504 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import os from 'os';
4
- import { AgentConfig, ExecutionMode } from './types.js';
5
- import { getToolRegistry } from './tools.js';
6
-
7
- export class AgentManager {
8
- private agents: Map<string, AgentConfig> = new Map();
9
- private globalAgentsPath: string;
10
- private projectAgentsPath: string;
11
-
12
- constructor(projectRoot?: string) {
13
- this.globalAgentsPath = path.join(os.homedir(), '.xagent', 'agents');
14
- this.projectAgentsPath = projectRoot
15
- ? path.join(projectRoot, '.xagent', 'agents')
16
- : '';
17
- }
18
-
19
- async loadAgents(): Promise<void> {
20
- // First load DEFAULT_AGENTS
21
- for (const agent of DEFAULT_AGENTS) {
22
- this.agents.set(agent.agentType, agent);
23
- }
24
-
25
- // Then load from file system (can override defaults)
26
- await this.loadAgentsFromDirectory(this.globalAgentsPath);
27
- if (this.projectAgentsPath) {
28
- await this.loadAgentsFromDirectory(this.projectAgentsPath);
29
- }
30
- }
31
-
32
- private async loadAgentsFromDirectory(dirPath: string): Promise<void> {
33
- try {
34
- const files = await fs.readdir(dirPath);
35
-
36
- for (const file of files) {
37
- const filePath = path.join(dirPath, file);
38
-
39
- // Support both .md (markdown) and .json config files
40
- if (file.endsWith('.md')) {
41
- const content = await fs.readFile(filePath, 'utf-8');
42
- const agent = this.parseAgentConfig(content);
43
-
44
- if (agent) {
45
- this.agents.set(agent.agentType, agent);
46
- }
47
- } else if (file.endsWith('.json') && file !== 'agent-config.example.json') {
48
- const content = await fs.readFile(filePath, 'utf-8');
49
- this.applyJsonAgentConfig(content);
50
- }
51
- }
52
- } catch (error) {
53
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
54
- console.error(`Failed to load agents from ${dirPath}:`, error);
55
- }
56
- }
57
- }
58
-
59
- private applyJsonAgentConfig(content: string): void {
60
- try {
61
- const parsed = JSON.parse(content);
62
-
63
- if (parsed.agents && typeof parsed.agents === 'object') {
64
- for (const [agentType, config] of Object.entries(parsed.agents)) {
65
- const agentConfig = config as any;
66
- const existingAgent = this.agents.get(agentType);
67
-
68
- if (existingAgent) {
69
- // Merge config into existing agent
70
- if (agentConfig.allowedTools) {
71
- existingAgent.allowedTools = agentConfig.allowedTools;
72
- }
73
- if (agentConfig.description) {
74
- existingAgent.description = agentConfig.description;
75
- }
76
- }
77
- }
78
- }
79
- } catch (error) {
80
- console.error('Failed to apply JSON agent config:', error);
81
- }
82
- }
83
-
84
- private parseAgentConfig(content: string): AgentConfig | null {
85
- const frontMatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
86
-
87
- if (!frontMatterMatch) {
88
- return null;
89
- }
90
-
91
- try {
92
- const frontMatter = frontMatterMatch[1];
93
- const config: any = {};
94
-
95
- frontMatter.split('\n').forEach(line => {
96
- const colonIndex = line.indexOf(':');
97
- if (colonIndex > 0) {
98
- const key = line.slice(0, colonIndex).trim();
99
- const value = line.slice(colonIndex + 1).trim();
100
-
101
- if (key === 'allowedTools' || key === 'allowedMcps') {
102
- config[key] = value ? value.split(',').map(s => s.trim()) : [];
103
- } else if (key === 'isInheritTools' || key === 'isInheritMcps' || key === 'proactive') {
104
- config[key] = value === 'true';
105
- } else {
106
- config[key] = value;
107
- }
108
- }
109
- });
110
-
111
- return {
112
- agentType: config.agentType,
113
- systemPrompt: config.systemPrompt,
114
- whenToUse: config.whenToUse,
115
- model: config.model,
116
- allowedTools: config.allowedTools,
117
- allowedMcps: config.allowedMcps,
118
- isInheritMcps: config.isInheritMcps ?? true,
119
- proactive: config.proactive ?? false,
120
- color: config.color,
121
- name: config.name,
122
- description: config.description
123
- };
124
- } catch (error) {
125
- console.error('Failed to parse agent config:', error);
126
- return null;
127
- }
128
- }
129
-
130
- getAgent(agentType: string): AgentConfig | undefined {
131
- return this.agents.get(agentType);
132
- }
133
-
134
- getAllAgents(): AgentConfig[] {
135
- return Array.from(this.agents.values());
136
- }
137
-
138
- async addAgent(agent: AgentConfig, scope: 'global' | 'project' = 'global'): Promise<void> {
139
- const agentsPath = scope === 'global' ? this.globalAgentsPath : this.projectAgentsPath;
140
-
141
- if (!agentsPath) {
142
- throw new Error('Project agents path not set');
143
- }
144
-
145
- await fs.mkdir(agentsPath, { recursive: true });
146
-
147
- const filePath = path.join(agentsPath, `${agent.agentType}.md`);
148
- const content = this.formatAgentConfig(agent);
149
-
150
- await fs.writeFile(filePath, content, 'utf-8');
151
- this.agents.set(agent.agentType, agent);
152
- }
153
-
154
- private formatAgentConfig(agent: AgentConfig): string {
155
- let content = '---\n';
156
-
157
- content += `agentType: "${agent.agentType}"\n`;
158
- content += `systemPrompt: "${agent.systemPrompt}"\n`;
159
- content += `whenToUse: "${agent.whenToUse}"\n`;
160
-
161
- if (agent.model) {
162
- content += `model: "${agent.model}"\n`;
163
- }
164
-
165
- if (agent.allowedTools && agent.allowedTools.length > 0) {
166
- content += `allowedTools: [${agent.allowedTools.map(t => `"${t}"`).join(', ')}]\n`;
167
- }
168
-
169
- if (agent.allowedMcps && agent.allowedMcps.length > 0) {
170
- content += `allowedMcps: [${agent.allowedMcps.map(m => `"${m}"`).join(', ')}]\n`;
171
- }
172
-
173
- if (agent.isInheritMcps !== undefined) {
174
- content += `isInheritMcps: ${agent.isInheritMcps}\n`;
175
- }
176
-
177
- if (agent.proactive !== undefined) {
178
- content += `proactive: ${agent.proactive}\n`;
179
- }
180
-
181
- if (agent.color) {
182
- content += `color: "${agent.color}"\n`;
183
- }
184
-
185
- if (agent.name) {
186
- content += `name: "${agent.name}"\n`;
187
- }
188
-
189
- if (agent.description) {
190
- content += `description: "${agent.description}"\n`;
191
- }
192
-
193
- content += '---\n\n';
194
- content += `# ${agent.name || agent.agentType}\n\n`;
195
- content += agent.description || `Agent for ${agent.whenToUse}`;
196
-
197
- return content;
198
- }
199
-
200
- async removeAgent(agentType: string, scope: 'global' | 'project' = 'global'): Promise<void> {
201
- const agentsPath = scope === 'global' ? this.globalAgentsPath : this.projectAgentsPath;
202
-
203
- if (!agentsPath) {
204
- throw new Error('Project agents path not set');
205
- }
206
-
207
- const filePath = path.join(agentsPath, `${agentType}.md`);
208
-
209
- try {
210
- await fs.unlink(filePath);
211
- this.agents.delete(agentType);
212
- } catch (error: any) {
213
- if (error.code !== 'ENOENT') {
214
- throw error;
215
- }
216
- }
217
- }
218
-
219
- getAvailableToolsForAgent(agent: AgentConfig, executionMode: ExecutionMode): string[] {
220
- const toolRegistry = getToolRegistry();
221
- const allTools = toolRegistry.getAll();
222
-
223
- // general-purpose agent: tools are determined by execution mode
224
- if (agent.agentType === 'general-purpose') {
225
- return allTools
226
- .filter(tool => tool.allowedModes.includes(executionMode))
227
- .map(tool => tool.name);
228
- }
229
-
230
- // Other subagents: only use their own allowedTools configuration
231
- // This keeps tool permissions consistent regardless of main agent's mode
232
- return agent.allowedTools || [];
233
- }
234
-
235
- getAvailableMcpsForAgent(agent: AgentConfig): string[] {
236
- if (!agent.isInheritMcps) {
237
- return agent.allowedMcps || [];
238
- }
239
-
240
- return agent.allowedMcps || [];
241
- }
242
- }
243
-
244
- let agentManagerInstance: AgentManager | null = null;
245
-
246
- export function getAgentManager(projectRoot?: string): AgentManager {
247
- if (!agentManagerInstance) {
248
- agentManagerInstance = new AgentManager(projectRoot);
249
- }
250
- return agentManagerInstance;
251
- }
252
-
253
- export const DEFAULT_AGENTS: AgentConfig[] = [
254
- {
255
- agentType: 'general-purpose',
256
- systemPrompt: `You are xAgent CLI, an interactive command-line assistant focused on software engineering tasks.
257
-
258
- ## Self Introduction
259
-
260
- When users ask you to introduce yourself, respond with:
261
-
262
- I am xAgent CLI, your intelligent life assistant and computer automation expert.
263
-
264
- As your **AI-powered PC companion**, I help you:
265
- - **Automate your digital life** - Handle repetitive tasks, manage files, and streamline workflows
266
- - **Control your computer** - Navigate browsers, fill forms, click elements, and perform desktop operations
267
- - **Boost productivity** - Write code, fix bugs, search information, and execute commands seamlessly
268
-
269
- Core capabilities:
270
- - **Life Automation & PC Smart Management** - Your intelligent assistant for everyday computing
271
- - **Browser automation** - Navigate, fill forms, click, and interact with web pages
272
- - **Desktop control** - Perform mouse, keyboard, and system operations
273
- - **Software engineering** - Code analysis, debugging, refactoring, and testing
274
- - **Project management** - Build, test, and deploy applications
275
- - **Version control** - Git operations and collaboration
276
-
277
- Key features:
278
- - Multi-mode execution (DEFAULT, YOLO, ACCEPT_EDITS, PLAN, SMART)
279
- - 2-level thinking mode (Off, On)
280
- - Rich toolset (file ops, code search, Web search, GUI automation, etc.)
281
- - Interactive dialogue and task management
282
- - Support for multiple AI models
283
- - **GUI Subagent** for visual web and desktop automation
284
-
285
- Usage: npm start
286
-
287
- Enter /help to view all available commands.
288
-
289
- ## Your Capabilities
290
-
291
- You can:
292
- - **Automate your computer** - Control browsers, desktop apps, mouse, and keyboard via sub-agent
293
- - **Manage files and folders** - Read, write, organize, and search your digital workspace
294
- - **Office document creation and editing - Create and edit documents, presentations, and spreadsheets
295
- - **Execute commands** - Run shell commands and automate workflows
296
- - **Code and build** - Analyze, write, debug, refactor, and test software
297
- - **Search and research** - Find information locally and from the web
298
- - **Delegate to specialists** - Use expert subagents for complex tasks (gui-subagent, explore-agent, plan-agent, etc.)
299
- - **Create todo lists** - Track progress and manage complex tasks
300
-
301
- ## CRITICAL: IMMEDIATE TOOL EXECUTION
302
- **YOU MUST CALL TOOLS IMMEDIATELY when needed - DO NOT say "let me..." or "I will..." first!**
303
-
304
- ## GUI SUBAGENT DELEGATION
305
-
306
- For visual tasks (opening apps, browsing, desktop interactions), use gui subagent directly. The GUI subagent will handle:
307
- - Mouse clicks and keyboard input
308
- - Browser navigation and web interactions
309
- - Desktop application control
310
- - Screenshot-based action execution
311
-
312
- Simply invoke sub-agent with the user's instruction, and the GUI subagent will perform the visual automation.
313
-
314
- ## ABSOLUTE FORBIDDEN: NEVER RUN BASH COMMANDS FOR GUI TASKS!
315
-
316
- When user asks to "open/enter/browse/view/access" ANYTHING involving:
317
- - Opening files, folders, applications, or websites
318
- - Navigating to directories or locations
319
- - Interacting with desktop UI elements
320
- - Browsing visual content
321
-
322
- 🚫 **THIS IS NOT A RECOMMENDATION - IT IS A HARD RULE:**
323
- - NEVER run: cd, ls, dir, cat, type, curl, wget
324
- - NEVER use bash/powershell for GUI tasks
325
-
326
- ✅ **ONLY USE sub-agent:**
327
- - sub-agent handles ALL visual interactions
328
- - sub-agent for: opening apps, folders, websites, clicking, typing
329
- - sub-agent for: desktop control, browser navigation, file browsing
330
-
331
- 🚫 **WRONG EXAMPLES (NE DO THIS):**
332
- - User: "open my computer" → DO NOT run: shell:ThisPC
333
- - User: "open downloads" → DO NOT run: shell:Downloads
334
- - User: "open WeChat" → DO NOT run: start wechat.exe
335
-
336
- ✅ **CORRECT EXAMPLES (ALWAYS DO THIS):**
337
- - User: "open my computer" → Use gui subagent
338
- - User: "open downloads" → Use gui subagent
339
- - User: "open WeChat" → Use gui subagent
340
- - User: "open Baidu" → Use gui subagent with open_url action
341
- `,
342
- whenToUse: 'Default agent for general tasks. Delegates to specialized agents when appropriate.',
343
- // Tool permissions are determined by execution mode (YOLO/PLAN/ACCEPT_EDITS/SMART)
344
- isInheritMcps: true,
345
- proactive: false,
346
- color: '#2ECC71',
347
- name: 'General Purpose',
348
- description: 'Default agent for general tasks. Has access to all tools and can delegate to specialized subagents.'
349
- },
350
- {
351
- agentType: 'plan-agent',
352
- systemPrompt: `You are an expert planning agent specialized in task analysis, decomposition, and strategy formulation.
353
-
354
- Your core responsibilities:
355
- 1. Analyze complex requests and break them into manageable steps
356
- 2. Identify dependencies and potential risks
357
- 3. Create structured plans with clear milestones
358
- 4. Provide estimates for effort and complexity
359
- 5. Suggest optimal execution order for tasks
360
-
361
- When planning:
362
- - Always start by understanding the full scope of the request
363
- - Break down large tasks into smaller, actionable steps
364
- - Identify which steps can be done in parallel vs. sequence
365
- - Flag any assumptions or unknowns that need clarification
366
- - Consider edge cases and error scenarios
367
-
368
- Output format:
369
- Provide plans in a structured format with:
370
- - Executive summary of the task
371
- - Step-by-step breakdown with numbered items
372
- - Dependencies between steps
373
- - Estimated complexity for each step
374
- - Any questions or clarifications needed`,
375
- whenToUse: 'Use for analyzing complex tasks, creating implementation plans, and breaking down requirements',
376
- allowedTools: ['Read', 'Grep', 'Bash', 'ListDirectory', 'web_search', 'todo_write', 'todo_read', 'ReadBashOutput', 'web_fetch', 'ask_user_question', 'exit_plan_mode', 'image_read'],
377
- isInheritMcps: true,
378
- proactive: false,
379
- color: '#9B59B6',
380
- name: 'Plan Agent',
381
- description: 'Specialized in task planning, analysis, and strategy formulation. Creates detailed implementation plans and identifies potential issues before execution.'
382
- },
383
- {
384
- agentType: 'explore-agent',
385
- systemPrompt: `You are an expert exploration agent specialized in codebase analysis, architecture discovery, and code understanding.
386
-
387
- Your core responsibilities:
388
- 1. Explore and understand codebase structure
389
- 2. Identify key components and their relationships
390
- 3. Trace data flows and control flows
391
- 4. Find relevant code for specific features
392
- 5. Document architecture and design patterns
393
-
394
- When exploring:
395
- - Start with high-level structure (directory layout, key files)
396
- - Use file exploration tools to understand project organization
397
- - Trace imports and dependencies to understand relationships
398
- - Look for configuration files, entry points, and key modules
399
- - Identify patterns and conventions used in the codebase
400
- - Document your findings in a clear, structured manner
401
-
402
- CRITICAL - When to stop exploring and return results:
403
- - After you have gathered enough information to provide a comprehensive overview
404
- - When you have explored the key directories and files relevant to the task
405
- - When you have identified the main components and their relationships
406
- - DO NOT continue making tool calls once you have sufficient information
407
- - Return your findings in the "plain text content" of your response, not as tool calls
408
-
409
- Output format:
410
- Provide exploration results with:
411
- - Project overview and structure
412
- - Key files and their purposes
413
- - Dependencies and relationships
414
- - Architecture patterns identified
415
- - Recommendations for next steps
416
-
417
- Remember: Your goal is to explore AND REPORT your findings, not to explore endlessly. Once you have gathered the necessary information, stop making tool calls and provide your comprehensive analysis in your response content.`,
418
- whenToUse: 'Use for exploring codebase structure, understanding architecture, and finding relevant code',
419
- allowedTools: ['Read', 'Grep', 'Bash', 'ListDirectory', 'SearchCodebase', 'ReadBashOutput'],
420
- isInheritMcps: true,
421
- proactive: false,
422
- color: '#3498DB',
423
- name: 'Explore Agent',
424
- description: 'Specialized in codebase exploration and architecture analysis. Helps understand project structure, find relevant code, and trace dependencies.'
425
- },
426
- {
427
- agentType: 'frontend-tester',
428
- systemPrompt: `You are an expert frontend testing agent specialized in creating and running tests for web applications.
429
-
430
- Your core responsibilities:
431
- 1. Write unit tests for frontend components
432
- 2. Create integration tests for user interactions
433
- 3. Set up test configurations and fixtures
434
- 4. Run tests and analyze results
435
- 5. Debug and fix failing tests
436
- 6. Improve test coverage
437
-
438
- When testing:
439
- - Understand the component structure and props
440
- - Identify critical paths and user interactions
441
- - Create tests that cover both happy paths and edge cases
442
- - Use appropriate testing libraries and frameworks
443
- - Mock external dependencies as needed
444
- - Ensure tests are independent and repeatable
445
-
446
- Testing priorities:
447
- 1. Critical user flows and interactions
448
- 2. Error handling and boundary conditions
449
- 3. State management and data flow
450
- 4. Accessibility and user experience
451
- 5. Performance considerations`,
452
- whenToUse: 'Use for creating and running frontend tests, ensuring code quality and reliability',
453
- allowedTools: ['Read', 'Write', 'Grep', 'Bash', 'ListDirectory'],
454
- isInheritMcps: true,
455
- proactive: true,
456
- color: '#E74C3C',
457
- name: 'Frontend Tester',
458
- description: 'Specialized in frontend testing including unit tests, integration tests, and end-to-end tests for web applications.'
459
- },
460
- {
461
- agentType: 'code-reviewer',
462
- systemPrompt: 'You are an expert code reviewer. Analyze code for quality, security, performance, and best practices.',
463
- whenToUse: 'Use when reviewing code, checking for bugs, or ensuring code quality',
464
- allowedTools: ['Read', 'Grep', 'SearchCodebase'],
465
- isInheritMcps: true,
466
- proactive: true,
467
- color: '#FF6B6B',
468
- name: 'Code Reviewer',
469
- description: 'Specialized in code review, bug detection, and quality assurance.'
470
- },
471
- {
472
- agentType: 'frontend-developer',
473
- systemPrompt: 'You are a frontend development expert specializing in React, TypeScript, and modern web technologies.',
474
- whenToUse: 'Use for frontend development tasks, UI components, and web application features',
475
- allowedTools: ['Read', 'Write', 'Grep', 'Bash', 'ListDirectory'],
476
- isInheritMcps: true,
477
- proactive: true,
478
- color: '#4ECDC4',
479
- name: 'Frontend Developer',
480
- description: 'Specialized in frontend development using React, TypeScript, and modern web technologies.'
481
- },
482
- {
483
- agentType: 'backend-developer',
484
- systemPrompt: 'You are a backend development expert specializing in Node.js, databases, APIs, and server-side architecture.',
485
- whenToUse: 'Use for backend development tasks, API design, and server-side logic',
486
- allowedTools: ['Read', 'Write', 'Grep', 'Bash', 'ListDirectory'],
487
- isInheritMcps: true,
488
- proactive: true,
489
- color: '#45B7D1',
490
- name: 'Backend Developer',
491
- description: 'Specialized in backend development using Node.js, databases, APIs, and server-side architecture.'
492
- },
493
- {
494
- agentType: 'gui-subagent',
495
- systemPrompt: '', // GUI Subagent uses its own built-in system prompt from gui-agent.ts
496
- whenToUse: 'Use for browser/desktop automation tasks, web scraping, form filling, and visual interactions',
497
- isInheritMcps: false,
498
- proactive: false,
499
- color: '#9B59B6',
500
- name: 'GUI Subagent',
501
- description: 'Specialized in browser/desktop automation using GUI interactions. Controls mouse, keyboard, and navigation via gui subagent.',
502
- model: 'guiSubagentModel'
503
- }
504
- ];
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { AgentConfig, ExecutionMode } from './types.js';
5
+ import { getToolRegistry } from './tools.js';
6
+
7
+ export class AgentManager {
8
+ private agents: Map<string, AgentConfig> = new Map();
9
+ private globalAgentsPath: string;
10
+ private projectAgentsPath: string;
11
+
12
+ constructor(projectRoot?: string) {
13
+ this.globalAgentsPath = path.join(os.homedir(), '.xagent', 'agents');
14
+ this.projectAgentsPath = projectRoot
15
+ ? path.join(projectRoot, '.xagent', 'agents')
16
+ : '';
17
+ }
18
+
19
+ async loadAgents(): Promise<void> {
20
+ // First load DEFAULT_AGENTS
21
+ for (const agent of DEFAULT_AGENTS) {
22
+ this.agents.set(agent.agentType, agent);
23
+ }
24
+
25
+ // Then load from file system (can override defaults)
26
+ await this.loadAgentsFromDirectory(this.globalAgentsPath);
27
+ if (this.projectAgentsPath) {
28
+ await this.loadAgentsFromDirectory(this.projectAgentsPath);
29
+ }
30
+ }
31
+
32
+ private async loadAgentsFromDirectory(dirPath: string): Promise<void> {
33
+ try {
34
+ const files = await fs.readdir(dirPath);
35
+
36
+ for (const file of files) {
37
+ const filePath = path.join(dirPath, file);
38
+
39
+ // Support both .md (markdown) and .json config files
40
+ if (file.endsWith('.md')) {
41
+ const content = await fs.readFile(filePath, 'utf-8');
42
+ const agent = this.parseAgentConfig(content);
43
+
44
+ if (agent) {
45
+ this.agents.set(agent.agentType, agent);
46
+ }
47
+ } else if (file.endsWith('.json') && file !== 'agent-config.example.json') {
48
+ const content = await fs.readFile(filePath, 'utf-8');
49
+ this.applyJsonAgentConfig(content);
50
+ }
51
+ }
52
+ } catch (error) {
53
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
54
+ console.error(`Failed to load agents from ${dirPath}:`, error);
55
+ }
56
+ }
57
+ }
58
+
59
+ private applyJsonAgentConfig(content: string): void {
60
+ try {
61
+ const parsed = JSON.parse(content);
62
+
63
+ if (parsed.agents && typeof parsed.agents === 'object') {
64
+ for (const [agentType, config] of Object.entries(parsed.agents)) {
65
+ const agentConfig = config as any;
66
+ const existingAgent = this.agents.get(agentType);
67
+
68
+ if (existingAgent) {
69
+ // Merge config into existing agent
70
+ if (agentConfig.allowedTools) {
71
+ existingAgent.allowedTools = agentConfig.allowedTools;
72
+ }
73
+ if (agentConfig.description) {
74
+ existingAgent.description = agentConfig.description;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ } catch (error) {
80
+ console.error('Failed to apply JSON agent config:', error);
81
+ }
82
+ }
83
+
84
+ private parseAgentConfig(content: string): AgentConfig | null {
85
+ const frontMatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
86
+
87
+ if (!frontMatterMatch) {
88
+ return null;
89
+ }
90
+
91
+ try {
92
+ const frontMatter = frontMatterMatch[1];
93
+ const config: any = {};
94
+
95
+ frontMatter.split('\n').forEach(line => {
96
+ const colonIndex = line.indexOf(':');
97
+ if (colonIndex > 0) {
98
+ const key = line.slice(0, colonIndex).trim();
99
+ const value = line.slice(colonIndex + 1).trim();
100
+
101
+ if (key === 'allowedTools' || key === 'allowedMcps') {
102
+ config[key] = value ? value.split(',').map(s => s.trim()) : [];
103
+ } else if (key === 'isInheritTools' || key === 'isInheritMcps' || key === 'proactive') {
104
+ config[key] = value === 'true';
105
+ } else {
106
+ config[key] = value;
107
+ }
108
+ }
109
+ });
110
+
111
+ return {
112
+ agentType: config.agentType,
113
+ systemPrompt: config.systemPrompt,
114
+ whenToUse: config.whenToUse,
115
+ model: config.model,
116
+ allowedTools: config.allowedTools,
117
+ allowedMcps: config.allowedMcps,
118
+ isInheritMcps: config.isInheritMcps ?? true,
119
+ proactive: config.proactive ?? false,
120
+ color: config.color,
121
+ name: config.name,
122
+ description: config.description
123
+ };
124
+ } catch (error) {
125
+ console.error('Failed to parse agent config:', error);
126
+ return null;
127
+ }
128
+ }
129
+
130
+ getAgent(agentType: string): AgentConfig | undefined {
131
+ return this.agents.get(agentType);
132
+ }
133
+
134
+ getAllAgents(): AgentConfig[] {
135
+ return Array.from(this.agents.values());
136
+ }
137
+
138
+ async addAgent(agent: AgentConfig, scope: 'global' | 'project' = 'global'): Promise<void> {
139
+ const agentsPath = scope === 'global' ? this.globalAgentsPath : this.projectAgentsPath;
140
+
141
+ if (!agentsPath) {
142
+ throw new Error('Project agents path not set');
143
+ }
144
+
145
+ await fs.mkdir(agentsPath, { recursive: true });
146
+
147
+ const filePath = path.join(agentsPath, `${agent.agentType}.md`);
148
+ const content = this.formatAgentConfig(agent);
149
+
150
+ await fs.writeFile(filePath, content, 'utf-8');
151
+ this.agents.set(agent.agentType, agent);
152
+ }
153
+
154
+ private formatAgentConfig(agent: AgentConfig): string {
155
+ let content = '---\n';
156
+
157
+ content += `agentType: "${agent.agentType}"\n`;
158
+ content += `systemPrompt: "${agent.systemPrompt}"\n`;
159
+ content += `whenToUse: "${agent.whenToUse}"\n`;
160
+
161
+ if (agent.model) {
162
+ content += `model: "${agent.model}"\n`;
163
+ }
164
+
165
+ if (agent.allowedTools && agent.allowedTools.length > 0) {
166
+ content += `allowedTools: [${agent.allowedTools.map(t => `"${t}"`).join(', ')}]\n`;
167
+ }
168
+
169
+ if (agent.allowedMcps && agent.allowedMcps.length > 0) {
170
+ content += `allowedMcps: [${agent.allowedMcps.map(m => `"${m}"`).join(', ')}]\n`;
171
+ }
172
+
173
+ if (agent.isInheritMcps !== undefined) {
174
+ content += `isInheritMcps: ${agent.isInheritMcps}\n`;
175
+ }
176
+
177
+ if (agent.proactive !== undefined) {
178
+ content += `proactive: ${agent.proactive}\n`;
179
+ }
180
+
181
+ if (agent.color) {
182
+ content += `color: "${agent.color}"\n`;
183
+ }
184
+
185
+ if (agent.name) {
186
+ content += `name: "${agent.name}"\n`;
187
+ }
188
+
189
+ if (agent.description) {
190
+ content += `description: "${agent.description}"\n`;
191
+ }
192
+
193
+ content += '---\n\n';
194
+ content += `# ${agent.name || agent.agentType}\n\n`;
195
+ content += agent.description || `Agent for ${agent.whenToUse}`;
196
+
197
+ return content;
198
+ }
199
+
200
+ async removeAgent(agentType: string, scope: 'global' | 'project' = 'global'): Promise<void> {
201
+ const agentsPath = scope === 'global' ? this.globalAgentsPath : this.projectAgentsPath;
202
+
203
+ if (!agentsPath) {
204
+ throw new Error('Project agents path not set');
205
+ }
206
+
207
+ const filePath = path.join(agentsPath, `${agentType}.md`);
208
+
209
+ try {
210
+ await fs.unlink(filePath);
211
+ this.agents.delete(agentType);
212
+ } catch (error: any) {
213
+ if (error.code !== 'ENOENT') {
214
+ throw error;
215
+ }
216
+ }
217
+ }
218
+
219
+ getAvailableToolsForAgent(agent: AgentConfig, executionMode: ExecutionMode): string[] {
220
+ const toolRegistry = getToolRegistry();
221
+ const allTools = toolRegistry.getAll();
222
+
223
+ // general-purpose agent: tools are determined by execution mode
224
+ if (agent.agentType === 'general-purpose') {
225
+ return allTools
226
+ .filter(tool => tool.allowedModes.includes(executionMode))
227
+ .map(tool => tool.name);
228
+ }
229
+
230
+ // Other subagents: only use their own allowedTools configuration
231
+ // This keeps tool permissions consistent regardless of main agent's mode
232
+ return agent.allowedTools || [];
233
+ }
234
+
235
+ getAvailableMcpsForAgent(agent: AgentConfig): string[] {
236
+ if (!agent.isInheritMcps) {
237
+ return agent.allowedMcps || [];
238
+ }
239
+
240
+ return agent.allowedMcps || [];
241
+ }
242
+ }
243
+
244
+ let agentManagerInstance: AgentManager | null = null;
245
+
246
+ export function getAgentManager(projectRoot?: string): AgentManager {
247
+ if (!agentManagerInstance) {
248
+ agentManagerInstance = new AgentManager(projectRoot);
249
+ }
250
+ return agentManagerInstance;
251
+ }
252
+
253
+ export const DEFAULT_AGENTS: AgentConfig[] = [
254
+ {
255
+ agentType: 'general-purpose',
256
+ systemPrompt: `You are xAgent CLI, an interactive command-line assistant focused on software engineering tasks.
257
+
258
+ ## Self Introduction
259
+
260
+ When users ask you to introduce yourself, respond with:
261
+
262
+ I am xAgent CLI, your intelligent life assistant and computer automation expert.
263
+
264
+ As your **AI-powered PC companion**, I help you:
265
+ - **Automate your digital life** - Handle repetitive tasks, manage files, and streamline workflows
266
+ - **Control your computer** - Navigate browsers, fill forms, click elements, and perform desktop operations
267
+ - **Boost productivity** - Write code, fix bugs, search information, and execute commands seamlessly
268
+
269
+ Core capabilities:
270
+ - **Life Automation & PC Smart Management** - Your intelligent assistant for everyday computing
271
+ - **Browser automation** - Navigate, fill forms, click, and interact with web pages
272
+ - **Desktop control** - Perform mouse, keyboard, and system operations
273
+ - **Software engineering** - Code analysis, debugging, refactoring, and testing
274
+ - **Project management** - Build, test, and deploy applications
275
+ - **Version control** - Git operations and collaboration
276
+
277
+ Key features:
278
+ - Multi-mode execution (DEFAULT, YOLO, ACCEPT_EDITS, PLAN, SMART)
279
+ - 2-level thinking mode (Off, On)
280
+ - Rich toolset (file ops, code search, Web search, GUI automation, etc.)
281
+ - Interactive dialogue and task management
282
+ - Support for multiple AI models
283
+ - **GUI Subagent** for visual web and desktop automation
284
+
285
+ Usage: npm start
286
+
287
+ Enter /help to view all available commands.
288
+
289
+ ## Your Capabilities
290
+
291
+ You can:
292
+ - **Automate your computer** - Control browsers, desktop apps, mouse, and keyboard via sub-agent
293
+ - **Manage files and folders** - Read, write, organize, and search your digital workspace
294
+ - **Office document creation and editing - Create and edit documents, presentations, and spreadsheets
295
+ - **Execute commands** - Run shell commands and automate workflows
296
+ - **Code and build** - Analyze, write, debug, refactor, and test software
297
+ - **Search and research** - Find information locally and from the web
298
+ - **Delegate to specialists** - Use expert subagents for complex tasks (gui-subagent, explore-agent, plan-agent, etc.)
299
+ - **Create todo lists** - Track progress and manage complex tasks
300
+
301
+ ## CRITICAL: IMMEDIATE TOOL EXECUTION
302
+ **YOU MUST CALL TOOLS IMMEDIATELY when needed - DO NOT say "let me..." or "I will..." first!**
303
+
304
+ ## GUI SUBAGENT DELEGATION
305
+
306
+ For visual tasks (opening apps, browsing, desktop interactions), use gui subagent directly. The GUI subagent will handle:
307
+ - Mouse clicks and keyboard input
308
+ - Browser navigation and web interactions
309
+ - Desktop application control
310
+ - Screenshot-based action execution
311
+
312
+ Simply invoke sub-agent with the user's instruction, and the GUI subagent will perform the visual automation.
313
+
314
+ ## ABSOLUTE FORBIDDEN: NEVER RUN BASH COMMANDS FOR GUI TASKS!
315
+
316
+ When user asks to "open/enter/browse/view/access" ANYTHING involving:
317
+ - Opening files, folders, applications, or websites
318
+ - Navigating to directories or locations
319
+ - Interacting with desktop UI elements
320
+ - Browsing visual content
321
+
322
+ 🚫 **THIS IS NOT A RECOMMENDATION - IT IS A HARD RULE:**
323
+ - NEVER run: cd, ls, dir, cat, type, curl, wget
324
+ - NEVER use bash/powershell for GUI tasks
325
+
326
+ ✅ **ONLY USE sub-agent:**
327
+ - sub-agent handles ALL visual interactions
328
+ - sub-agent for: opening apps, folders, websites, clicking, typing
329
+ - sub-agent for: desktop control, browser navigation, file browsing
330
+
331
+ 🚫 **WRONG EXAMPLES (NE DO THIS):**
332
+ - User: "open my computer" → DO NOT run: shell:ThisPC
333
+ - User: "open downloads" → DO NOT run: shell:Downloads
334
+ - User: "open WeChat" → DO NOT run: start wechat.exe
335
+
336
+ ✅ **CORRECT EXAMPLES (ALWAYS DO THIS):**
337
+ - User: "open my computer" → Use gui subagent
338
+ - User: "open downloads" → Use gui subagent
339
+ - User: "open WeChat" → Use gui subagent
340
+ - User: "open Baidu" → Use gui subagent with open_url action
341
+ `,
342
+ whenToUse: 'Default agent for general tasks. Delegates to specialized agents when appropriate.',
343
+ // Tool permissions are determined by execution mode (YOLO/PLAN/ACCEPT_EDITS/SMART)
344
+ isInheritMcps: true,
345
+ proactive: false,
346
+ color: '#2ECC71',
347
+ name: 'General Purpose',
348
+ description: 'Default agent for general tasks. Has access to all tools and can delegate to specialized subagents.'
349
+ },
350
+ {
351
+ agentType: 'plan-agent',
352
+ systemPrompt: `You are an expert planning agent specialized in task analysis, decomposition, and strategy formulation.
353
+
354
+ Your core responsibilities:
355
+ 1. Analyze complex requests and break them into manageable steps
356
+ 2. Identify dependencies and potential risks
357
+ 3. Create structured plans with clear milestones
358
+ 4. Provide estimates for effort and complexity
359
+ 5. Suggest optimal execution order for tasks
360
+
361
+ When planning:
362
+ - Always start by understanding the full scope of the request
363
+ - Break down large tasks into smaller, actionable steps
364
+ - Identify which steps can be done in parallel vs. sequence
365
+ - Flag any assumptions or unknowns that need clarification
366
+ - Consider edge cases and error scenarios
367
+
368
+ Output format:
369
+ Provide plans in a structured format with:
370
+ - Executive summary of the task
371
+ - Step-by-step breakdown with numbered items
372
+ - Dependencies between steps
373
+ - Estimated complexity for each step
374
+ - Any questions or clarifications needed`,
375
+ whenToUse: 'Use for analyzing complex tasks, creating implementation plans, and breaking down requirements',
376
+ allowedTools: ['Read', 'Grep', 'Bash', 'ListDirectory', 'web_search', 'todo_write', 'todo_read', 'ReadBashOutput', 'web_fetch', 'ask_user_question', 'exit_plan_mode', 'image_read'],
377
+ isInheritMcps: true,
378
+ proactive: false,
379
+ color: '#9B59B6',
380
+ name: 'Plan Agent',
381
+ description: 'Specialized in task planning, analysis, and strategy formulation. Creates detailed implementation plans and identifies potential issues before execution.'
382
+ },
383
+ {
384
+ agentType: 'explore-agent',
385
+ systemPrompt: `You are an expert exploration agent specialized in codebase analysis, architecture discovery, and code understanding.
386
+
387
+ Your core responsibilities:
388
+ 1. Explore and understand codebase structure
389
+ 2. Identify key components and their relationships
390
+ 3. Trace data flows and control flows
391
+ 4. Find relevant code for specific features
392
+ 5. Document architecture and design patterns
393
+
394
+ When exploring:
395
+ - Start with high-level structure (directory layout, key files)
396
+ - Use file exploration tools to understand project organization
397
+ - Trace imports and dependencies to understand relationships
398
+ - Look for configuration files, entry points, and key modules
399
+ - Identify patterns and conventions used in the codebase
400
+ - Document your findings in a clear, structured manner
401
+
402
+ CRITICAL - When to stop exploring and return results:
403
+ - After you have gathered enough information to provide a comprehensive overview
404
+ - When you have explored the key directories and files relevant to the task
405
+ - When you have identified the main components and their relationships
406
+ - DO NOT continue making tool calls once you have sufficient information
407
+ - Return your findings in the "plain text content" of your response, not as tool calls
408
+
409
+ Output format:
410
+ Provide exploration results with:
411
+ - Project overview and structure
412
+ - Key files and their purposes
413
+ - Dependencies and relationships
414
+ - Architecture patterns identified
415
+ - Recommendations for next steps
416
+
417
+ Remember: Your goal is to explore AND REPORT your findings, not to explore endlessly. Once you have gathered the necessary information, stop making tool calls and provide your comprehensive analysis in your response content.`,
418
+ whenToUse: 'Use for exploring codebase structure, understanding architecture, and finding relevant code',
419
+ allowedTools: ['Read', 'Grep', 'Bash', 'ListDirectory', 'SearchFiles', 'ReadBashOutput'],
420
+ isInheritMcps: true,
421
+ proactive: false,
422
+ color: '#3498DB',
423
+ name: 'Explore Agent',
424
+ description: 'Specialized in codebase exploration and architecture analysis. Helps understand project structure, find relevant code, and trace dependencies.'
425
+ },
426
+ {
427
+ agentType: 'frontend-tester',
428
+ systemPrompt: `You are an expert frontend testing agent specialized in creating and running tests for web applications.
429
+
430
+ Your core responsibilities:
431
+ 1. Write unit tests for frontend components
432
+ 2. Create integration tests for user interactions
433
+ 3. Set up test configurations and fixtures
434
+ 4. Run tests and analyze results
435
+ 5. Debug and fix failing tests
436
+ 6. Improve test coverage
437
+
438
+ When testing:
439
+ - Understand the component structure and props
440
+ - Identify critical paths and user interactions
441
+ - Create tests that cover both happy paths and edge cases
442
+ - Use appropriate testing libraries and frameworks
443
+ - Mock external dependencies as needed
444
+ - Ensure tests are independent and repeatable
445
+
446
+ Testing priorities:
447
+ 1. Critical user flows and interactions
448
+ 2. Error handling and boundary conditions
449
+ 3. State management and data flow
450
+ 4. Accessibility and user experience
451
+ 5. Performance considerations`,
452
+ whenToUse: 'Use for creating and running frontend tests, ensuring code quality and reliability',
453
+ allowedTools: ['Read', 'Write', 'Grep', 'Bash', 'ListDirectory'],
454
+ isInheritMcps: true,
455
+ proactive: true,
456
+ color: '#E74C3C',
457
+ name: 'Frontend Tester',
458
+ description: 'Specialized in frontend testing including unit tests, integration tests, and end-to-end tests for web applications.'
459
+ },
460
+ {
461
+ agentType: 'code-reviewer',
462
+ systemPrompt: 'You are an expert code reviewer. Analyze code for quality, security, performance, and best practices.',
463
+ whenToUse: 'Use when reviewing code, checking for bugs, or ensuring code quality',
464
+ allowedTools: ['Read', 'Grep', 'SearchFiles'],
465
+ isInheritMcps: true,
466
+ proactive: true,
467
+ color: '#FF6B6B',
468
+ name: 'Code Reviewer',
469
+ description: 'Specialized in code review, bug detection, and quality assurance.'
470
+ },
471
+ {
472
+ agentType: 'frontend-developer',
473
+ systemPrompt: 'You are a frontend development expert specializing in React, TypeScript, and modern web technologies.',
474
+ whenToUse: 'Use for frontend development tasks, UI components, and web application features',
475
+ allowedTools: ['Read', 'Write', 'Grep', 'Bash', 'ListDirectory'],
476
+ isInheritMcps: true,
477
+ proactive: true,
478
+ color: '#4ECDC4',
479
+ name: 'Frontend Developer',
480
+ description: 'Specialized in frontend development using React, TypeScript, and modern web technologies.'
481
+ },
482
+ {
483
+ agentType: 'backend-developer',
484
+ systemPrompt: 'You are a backend development expert specializing in Node.js, databases, APIs, and server-side architecture.',
485
+ whenToUse: 'Use for backend development tasks, API design, and server-side logic',
486
+ allowedTools: ['Read', 'Write', 'Grep', 'Bash', 'ListDirectory'],
487
+ isInheritMcps: true,
488
+ proactive: true,
489
+ color: '#45B7D1',
490
+ name: 'Backend Developer',
491
+ description: 'Specialized in backend development using Node.js, databases, APIs, and server-side architecture.'
492
+ },
493
+ {
494
+ agentType: 'gui-subagent',
495
+ systemPrompt: '', // GUI Subagent uses its own built-in system prompt from gui-agent.ts
496
+ whenToUse: 'Use for browser/desktop automation tasks, web scraping, form filling, and visual interactions',
497
+ isInheritMcps: false,
498
+ proactive: false,
499
+ color: '#9B59B6',
500
+ name: 'GUI Subagent',
501
+ description: 'Specialized in browser/desktop automation using GUI interactions. Controls mouse, keyboard, and navigation via gui subagent.',
502
+ model: 'guiSubagentModel'
503
+ }
504
+ ];