agentic-flow 1.0.7 → 1.0.8

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.
@@ -0,0 +1,451 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Management CLI - Create, list, and manage custom agents
4
+ * Supports both npm package agents and local .claude/agents
5
+ * Includes conflict detection and deduplication
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs';
8
+ import { join, dirname, relative, extname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import { createInterface } from 'readline';
11
+ // Get package root and default paths
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ const packageRoot = join(__dirname, '../..');
15
+ const packageAgentsDir = join(packageRoot, '.claude/agents');
16
+ const localAgentsDir = join(process.cwd(), '.claude/agents');
17
+ export class AgentManager {
18
+ /**
19
+ * Find all agent files from both package and local directories
20
+ * Deduplicates by preferring local over package
21
+ */
22
+ findAllAgents() {
23
+ const agents = new Map();
24
+ // Load package agents first
25
+ if (existsSync(packageAgentsDir)) {
26
+ this.scanAgentsDirectory(packageAgentsDir, 'package', agents);
27
+ }
28
+ // Load local agents (overrides package agents with same relative path)
29
+ if (existsSync(localAgentsDir)) {
30
+ this.scanAgentsDirectory(localAgentsDir, 'local', agents);
31
+ }
32
+ return agents;
33
+ }
34
+ /**
35
+ * Recursively scan directory for agent markdown files
36
+ */
37
+ scanAgentsDirectory(dir, source, agents) {
38
+ const baseDir = source === 'package' ? packageAgentsDir : localAgentsDir;
39
+ try {
40
+ const entries = readdirSync(dir);
41
+ for (const entry of entries) {
42
+ const fullPath = join(dir, entry);
43
+ const stat = statSync(fullPath);
44
+ if (stat.isDirectory()) {
45
+ this.scanAgentsDirectory(fullPath, source, agents);
46
+ }
47
+ else if (extname(entry) === '.md' && entry !== 'README.md') {
48
+ const relativePath = relative(baseDir, fullPath);
49
+ const agentInfo = this.parseAgentFile(fullPath, source, relativePath);
50
+ if (agentInfo) {
51
+ // Use relative path as key for deduplication
52
+ // Local agents override package agents
53
+ const existingAgent = agents.get(relativePath);
54
+ if (!existingAgent || source === 'local') {
55
+ agents.set(relativePath, agentInfo);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ catch (error) {
62
+ console.error(`Error scanning directory ${dir}: ${error.message}`);
63
+ }
64
+ }
65
+ /**
66
+ * Parse agent markdown file and extract metadata
67
+ */
68
+ parseAgentFile(filePath, source, relativePath) {
69
+ try {
70
+ const content = readFileSync(filePath, 'utf-8');
71
+ // Try frontmatter format first
72
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
73
+ if (frontmatterMatch) {
74
+ const [, frontmatter] = frontmatterMatch;
75
+ const meta = {};
76
+ frontmatter.split('\n').forEach(line => {
77
+ const match = line.match(/^(\w+):\s*(.+)$/);
78
+ if (match) {
79
+ const [, key, value] = match;
80
+ meta[key] = value.replace(/^["']|["']$/g, '');
81
+ }
82
+ });
83
+ if (meta.name && meta.description) {
84
+ return {
85
+ name: meta.name,
86
+ description: meta.description,
87
+ category: this.getCategoryFromPath(relativePath),
88
+ filePath,
89
+ source,
90
+ relativePath
91
+ };
92
+ }
93
+ }
94
+ // Fallback: extract from markdown headers
95
+ const nameMatch = content.match(/^#\s+(.+)$/m);
96
+ const descMatch = content.match(/^##\s+Description\s*\n\s*(.+)$/m);
97
+ if (nameMatch) {
98
+ return {
99
+ name: nameMatch[1].trim(),
100
+ description: descMatch ? descMatch[1].trim() : 'No description available',
101
+ category: this.getCategoryFromPath(relativePath),
102
+ filePath,
103
+ source,
104
+ relativePath
105
+ };
106
+ }
107
+ return null;
108
+ }
109
+ catch (error) {
110
+ return null;
111
+ }
112
+ }
113
+ /**
114
+ * Get category from file path
115
+ */
116
+ getCategoryFromPath(relativePath) {
117
+ const parts = relativePath.split('/');
118
+ return parts.length > 1 ? parts[0] : 'custom';
119
+ }
120
+ /**
121
+ * List all agents with deduplication
122
+ */
123
+ list(format = 'summary') {
124
+ const agents = this.findAllAgents();
125
+ if (format === 'json') {
126
+ const agentList = Array.from(agents.values()).map(a => ({
127
+ name: a.name,
128
+ description: a.description,
129
+ category: a.category,
130
+ source: a.source,
131
+ path: a.relativePath
132
+ }));
133
+ console.log(JSON.stringify(agentList, null, 2));
134
+ return;
135
+ }
136
+ // Group by category
137
+ const byCategory = new Map();
138
+ for (const agent of agents.values()) {
139
+ const category = agent.category;
140
+ if (!byCategory.has(category)) {
141
+ byCategory.set(category, []);
142
+ }
143
+ byCategory.get(category).push(agent);
144
+ }
145
+ // Sort categories
146
+ const sortedCategories = Array.from(byCategory.keys()).sort();
147
+ console.log('\n📦 Available Agents:');
148
+ console.log('═'.repeat(80));
149
+ for (const category of sortedCategories) {
150
+ const categoryAgents = byCategory.get(category).sort((a, b) => a.name.localeCompare(b.name));
151
+ console.log(`\n${category.toUpperCase()}:`);
152
+ for (const agent of categoryAgents) {
153
+ const sourceIcon = agent.source === 'local' ? '📝' : '📦';
154
+ if (format === 'detailed') {
155
+ console.log(` ${sourceIcon} ${agent.name}`);
156
+ console.log(` ${agent.description}`);
157
+ console.log(` Source: ${agent.source} (${agent.relativePath})`);
158
+ }
159
+ else {
160
+ console.log(` ${sourceIcon} ${agent.name.padEnd(30)} ${agent.description.substring(0, 45)}...`);
161
+ }
162
+ }
163
+ }
164
+ console.log(`\n📊 Total: ${agents.size} agents`);
165
+ console.log(` 📝 Local: ${Array.from(agents.values()).filter(a => a.source === 'local').length}`);
166
+ console.log(` 📦 Package: ${Array.from(agents.values()).filter(a => a.source === 'package').length}`);
167
+ console.log('');
168
+ }
169
+ /**
170
+ * Create a new agent
171
+ */
172
+ async create(options) {
173
+ let { name, description, category, systemPrompt, tools } = options;
174
+ // Interactive mode
175
+ if (options.interactive) {
176
+ const rl = createInterface({
177
+ input: process.stdin,
178
+ output: process.stdout
179
+ });
180
+ const question = (prompt) => {
181
+ return new Promise(resolve => rl.question(prompt, resolve));
182
+ };
183
+ console.log('\n🤖 Create New Agent');
184
+ console.log('═'.repeat(80));
185
+ name = await question('Agent name (e.g., my-custom-agent): ');
186
+ description = await question('Description: ');
187
+ category = await question('Category (default: custom): ') || 'custom';
188
+ systemPrompt = await question('System prompt: ');
189
+ const toolsInput = await question('Tools (comma-separated, optional): ');
190
+ tools = toolsInput ? toolsInput.split(',').map(t => t.trim()) : [];
191
+ rl.close();
192
+ }
193
+ // Validate required fields
194
+ if (!name || !description || !systemPrompt) {
195
+ throw new Error('Name, description, and system prompt are required');
196
+ }
197
+ // Normalize name to kebab-case
198
+ const kebabName = name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
199
+ // Check for conflicts
200
+ const agents = this.findAllAgents();
201
+ const conflictingAgent = Array.from(agents.values()).find(a => a.name.toLowerCase() === kebabName.toLowerCase());
202
+ if (conflictingAgent) {
203
+ console.log(`\n⚠️ Warning: Agent "${conflictingAgent.name}" already exists`);
204
+ console.log(` Source: ${conflictingAgent.source}`);
205
+ console.log(` Path: ${conflictingAgent.relativePath}`);
206
+ const rl = createInterface({
207
+ input: process.stdin,
208
+ output: process.stdout
209
+ });
210
+ const answer = await new Promise(resolve => {
211
+ rl.question('\nCreate in local .claude/agents anyway? (y/N): ', resolve);
212
+ });
213
+ rl.close();
214
+ if (answer.toLowerCase() !== 'y') {
215
+ console.log('Cancelled.');
216
+ return;
217
+ }
218
+ }
219
+ // Create directory structure
220
+ const targetCategory = category || 'custom';
221
+ const targetDir = join(localAgentsDir, targetCategory);
222
+ if (!existsSync(targetDir)) {
223
+ mkdirSync(targetDir, { recursive: true });
224
+ }
225
+ // Generate markdown content
226
+ const markdown = this.generateAgentMarkdown({
227
+ name: kebabName,
228
+ description: description,
229
+ category: targetCategory,
230
+ tools
231
+ }, systemPrompt);
232
+ const filePath = join(targetDir, `${kebabName}.md`);
233
+ if (existsSync(filePath)) {
234
+ throw new Error(`Agent file already exists at ${filePath}`);
235
+ }
236
+ writeFileSync(filePath, markdown, 'utf8');
237
+ console.log(`\n✅ Agent created successfully!`);
238
+ console.log(` Name: ${kebabName}`);
239
+ console.log(` Category: ${targetCategory}`);
240
+ console.log(` Path: ${filePath}`);
241
+ console.log(`\n📝 Usage:`);
242
+ console.log(` npx agentic-flow --agent ${kebabName} --task "Your task"`);
243
+ console.log('');
244
+ }
245
+ /**
246
+ * Generate agent markdown with frontmatter
247
+ */
248
+ generateAgentMarkdown(metadata, systemPrompt) {
249
+ const toolsLine = metadata.tools && metadata.tools.length > 0
250
+ ? `tools: ${metadata.tools.join(', ')}`
251
+ : '';
252
+ return `---
253
+ name: ${metadata.name}
254
+ description: ${metadata.description}
255
+ ${metadata.color ? `color: ${metadata.color}` : ''}
256
+ ${toolsLine}
257
+ ---
258
+
259
+ ${systemPrompt}
260
+
261
+ ## Usage
262
+
263
+ \`\`\`bash
264
+ npx agentic-flow --agent ${metadata.name} --task "Your task"
265
+ \`\`\`
266
+
267
+ ## Examples
268
+
269
+ ### Example 1
270
+ \`\`\`bash
271
+ npx agentic-flow --agent ${metadata.name} --task "Example task description"
272
+ \`\`\`
273
+
274
+ ---
275
+ *Created: ${new Date().toISOString()}*
276
+ *Source: local*
277
+ `;
278
+ }
279
+ /**
280
+ * Get information about a specific agent
281
+ */
282
+ info(name) {
283
+ const agents = this.findAllAgents();
284
+ const agent = Array.from(agents.values()).find(a => a.name.toLowerCase() === name.toLowerCase());
285
+ if (!agent) {
286
+ console.log(`\n❌ Agent "${name}" not found`);
287
+ console.log('\nUse "agentic-flow agent list" to see all available agents\n');
288
+ return;
289
+ }
290
+ console.log('\n📋 Agent Information');
291
+ console.log('═'.repeat(80));
292
+ console.log(`Name: ${agent.name}`);
293
+ console.log(`Description: ${agent.description}`);
294
+ console.log(`Category: ${agent.category}`);
295
+ console.log(`Source: ${agent.source === 'local' ? '📝 Local' : '📦 Package'}`);
296
+ console.log(`Path: ${agent.relativePath}`);
297
+ console.log(`Full Path: ${agent.filePath}`);
298
+ console.log('');
299
+ // Show content preview
300
+ try {
301
+ const content = readFileSync(agent.filePath, 'utf-8');
302
+ console.log('Preview:');
303
+ console.log('─'.repeat(80));
304
+ const lines = content.split('\n').slice(0, 20);
305
+ console.log(lines.join('\n'));
306
+ if (content.split('\n').length > 20) {
307
+ console.log('...');
308
+ }
309
+ console.log('');
310
+ }
311
+ catch (error) {
312
+ console.log('Could not read agent file\n');
313
+ }
314
+ }
315
+ /**
316
+ * Check for conflicts between package and local agents
317
+ */
318
+ checkConflicts() {
319
+ console.log('\n🔍 Checking for agent conflicts...');
320
+ console.log('═'.repeat(80));
321
+ const packageAgents = new Map();
322
+ const localAgents = new Map();
323
+ if (existsSync(packageAgentsDir)) {
324
+ this.scanAgentsDirectory(packageAgentsDir, 'package', packageAgents);
325
+ }
326
+ if (existsSync(localAgentsDir)) {
327
+ this.scanAgentsDirectory(localAgentsDir, 'local', localAgents);
328
+ }
329
+ // Find conflicts (same relative path in both)
330
+ const conflicts = [];
331
+ for (const [relativePath, localAgent] of localAgents) {
332
+ const packageAgent = packageAgents.get(relativePath);
333
+ if (packageAgent) {
334
+ conflicts.push({ path: relativePath, package: packageAgent, local: localAgent });
335
+ }
336
+ }
337
+ if (conflicts.length === 0) {
338
+ console.log('\n✅ No conflicts found!\n');
339
+ return;
340
+ }
341
+ console.log(`\n⚠️ Found ${conflicts.length} conflict(s):\n`);
342
+ for (const conflict of conflicts) {
343
+ console.log(`📁 ${conflict.path}`);
344
+ console.log(` 📦 Package: ${conflict.package.name}`);
345
+ console.log(` ${conflict.package.description}`);
346
+ console.log(` 📝 Local: ${conflict.local.name}`);
347
+ console.log(` ${conflict.local.description}`);
348
+ console.log(` ℹ️ Local version will be used\n`);
349
+ }
350
+ }
351
+ }
352
+ /**
353
+ * CLI command handler
354
+ */
355
+ export async function handleAgentCommand(args) {
356
+ const command = args[0];
357
+ const manager = new AgentManager();
358
+ switch (command) {
359
+ case undefined:
360
+ case 'help':
361
+ console.log(`
362
+ 🤖 Agent Management CLI
363
+
364
+ USAGE:
365
+ npx agentic-flow agent <command> [options]
366
+
367
+ COMMANDS:
368
+ list [format] List all available agents
369
+ format: summary (default), detailed, json
370
+
371
+ create Create a new agent interactively
372
+ create --name NAME Create agent with CLI arguments
373
+ --description DESC
374
+ --category CAT
375
+ --prompt PROMPT
376
+ [--tools TOOLS]
377
+
378
+ info <name> Show detailed information about an agent
379
+
380
+ conflicts Check for conflicts between package and local agents
381
+
382
+ help Show this help message
383
+
384
+ EXAMPLES:
385
+ # List all agents
386
+ npx agentic-flow agent list
387
+
388
+ # List with details
389
+ npx agentic-flow agent list detailed
390
+
391
+ # Create agent interactively
392
+ npx agentic-flow agent create
393
+
394
+ # Create agent with CLI
395
+ npx agentic-flow agent create --name my-agent --description "My custom agent" --prompt "You are a helpful assistant"
396
+
397
+ # Get agent info
398
+ npx agentic-flow agent info coder
399
+
400
+ # Check conflicts
401
+ npx agentic-flow agent conflicts
402
+
403
+ AGENT LOCATIONS:
404
+ 📦 Package: ${packageAgentsDir}
405
+ 📝 Local: ${localAgentsDir}
406
+
407
+ Note: Local agents override package agents with the same path.
408
+ `);
409
+ break;
410
+ case 'list':
411
+ const format = args[1] || 'summary';
412
+ manager.list(format);
413
+ break;
414
+ case 'create':
415
+ const nameIdx = args.indexOf('--name');
416
+ const descIdx = args.indexOf('--description');
417
+ const catIdx = args.indexOf('--category');
418
+ const promptIdx = args.indexOf('--prompt');
419
+ const toolsIdx = args.indexOf('--tools');
420
+ if (nameIdx === -1 || descIdx === -1 || promptIdx === -1) {
421
+ // Interactive mode
422
+ await manager.create({ interactive: true });
423
+ }
424
+ else {
425
+ // CLI mode
426
+ await manager.create({
427
+ name: args[nameIdx + 1],
428
+ description: args[descIdx + 1],
429
+ category: catIdx !== -1 ? args[catIdx + 1] : 'custom',
430
+ systemPrompt: args[promptIdx + 1],
431
+ tools: toolsIdx !== -1 ? args[toolsIdx + 1].split(',').map(t => t.trim()) : []
432
+ });
433
+ }
434
+ break;
435
+ case 'info':
436
+ if (!args[1]) {
437
+ console.log('\n❌ Please specify an agent name\n');
438
+ console.log('Usage: npx agentic-flow agent info <name>\n');
439
+ process.exit(1);
440
+ }
441
+ manager.info(args[1]);
442
+ break;
443
+ case 'conflicts':
444
+ manager.checkConflicts();
445
+ break;
446
+ default:
447
+ console.log(`\n❌ Unknown command: ${command}\n`);
448
+ console.log('Use "npx agentic-flow agent help" for usage information\n');
449
+ process.exit(1);
450
+ }
451
+ }
package/dist/cli-proxy.js CHANGED
@@ -10,6 +10,7 @@ import { parseArgs } from "./utils/cli.js";
10
10
  import { getAgent, listAgents } from "./utils/agentLoader.js";
11
11
  import { directApiAgent } from "./agents/directApiAgent.js";
12
12
  import { handleConfigCommand } from "./cli/config-wizard.js";
13
+ import { handleAgentCommand } from "./cli/agent-manager.js";
13
14
  import { readFileSync } from 'fs';
14
15
  import { resolve, dirname } from 'path';
15
16
  import { fileURLToPath } from 'url';
@@ -36,6 +37,12 @@ class AgenticFlowCLI {
36
37
  await handleConfigCommand(configArgs);
37
38
  process.exit(0);
38
39
  }
40
+ if (options.mode === 'agent-manager') {
41
+ // Handle agent management commands
42
+ const agentArgs = process.argv.slice(3); // Skip 'node', 'cli-proxy.js', 'agent'
43
+ await handleAgentCommand(agentArgs);
44
+ process.exit(0);
45
+ }
39
46
  if (options.mode === 'mcp') {
40
47
  // Run standalone MCP server directly
41
48
  const { spawn } = await import('child_process');
@@ -235,6 +242,7 @@ USAGE:
235
242
  COMMANDS:
236
243
  config [subcommand] Manage environment configuration (interactive wizard)
237
244
  mcp <command> [server] Manage MCP servers (start, stop, status, list)
245
+ agent <command> Agent management (list, create, info, conflicts)
238
246
  --list, -l List all available agents
239
247
  --agent, -a <name> Run specific agent mode
240
248
 
@@ -254,12 +262,37 @@ MCP COMMANDS:
254
262
 
255
263
  Available servers: claude-flow, flow-nexus, agentic-payments, all (default)
256
264
 
265
+ AGENT COMMANDS:
266
+ npx agentic-flow agent list [format] List all agents (summary/detailed/json)
267
+ npx agentic-flow agent create Create new custom agent (interactive)
268
+ npx agentic-flow agent info <name> Show detailed agent information
269
+ npx agentic-flow agent conflicts Check for package/local conflicts
270
+
257
271
  OPTIONS:
258
- --task, -t <task> Task description for agent mode
259
- --model, -m <model> Model to use (triggers OpenRouter if contains "/")
260
- --provider, -p <name> Provider to use (anthropic, openrouter, onnx)
261
- --stream, -s Enable real-time streaming output
262
- --help, -h Show this help message
272
+ --task, -t <task> Task description for agent mode
273
+ --model, -m <model> Model to use (triggers OpenRouter if contains "/")
274
+ --provider, -p <name> Provider to use (anthropic, openrouter, onnx)
275
+ --stream, -s Enable real-time streaming output
276
+ --help, -h Show this help message
277
+
278
+ API CONFIGURATION:
279
+ --anthropic-key <key> Override ANTHROPIC_API_KEY environment variable
280
+ --openrouter-key <key> Override OPENROUTER_API_KEY environment variable
281
+
282
+ AGENT BEHAVIOR:
283
+ --temperature <0.0-1.0> Sampling temperature (creativity control)
284
+ --max-tokens <number> Maximum tokens in response
285
+
286
+ DIRECTORY:
287
+ --agents-dir <path> Custom agents directory (default: .claude/agents)
288
+
289
+ OUTPUT:
290
+ --output <text|json|md> Output format (text/json/markdown)
291
+ --verbose Enable verbose logging for debugging
292
+
293
+ EXECUTION:
294
+ --timeout <ms> Execution timeout in milliseconds
295
+ --retry Auto-retry on transient errors
263
296
 
264
297
  EXAMPLES:
265
298
  # MCP Server Management
@@ -288,11 +321,11 @@ OPENROUTER MODELS:
288
321
  - google/gemini-2.5-flash-preview (fastest)
289
322
  - See https://openrouter.ai/models for full list
290
323
 
291
- MCP TOOLS (203+ available):
292
- claude-flow-sdk: 6 in-process tools (memory, swarm coordination)
324
+ MCP TOOLS (209+ available):
325
+ agentic-flow: 6 tools (agent execution, creation, management)
293
326
  • claude-flow: 101 tools (neural networks, GitHub, workflows, DAA)
294
327
  • flow-nexus: 96 cloud tools (sandboxes, distributed swarms, templates)
295
- • agentic-payments: Payment authorization and multi-agent consensus
328
+ • agentic-payments: 6 tools (payment authorization, multi-agent consensus)
296
329
 
297
330
  For more information: https://github.com/ruvnet/agentic-flow
298
331
  `);
@@ -19,7 +19,7 @@ console.error('🚀 Starting Agentic-Flow MCP Server (stdio)...');
19
19
  console.error('📦 Local agentic-flow tools available');
20
20
  const server = new FastMCP({
21
21
  name: 'agentic-flow',
22
- version: '1.0.7'
22
+ version: '1.0.8'
23
23
  });
24
24
  // Tool: Run agentic-flow agent
25
25
  server.addTool({
@@ -124,7 +124,138 @@ server.addTool({
124
124
  }
125
125
  }
126
126
  });
127
- console.error('✅ Registered 2 tools: agentic_flow_agent, agentic_flow_list_agents');
127
+ // Tool: Create custom agent
128
+ server.addTool({
129
+ name: 'agentic_flow_create_agent',
130
+ description: 'Create a new custom agent in .claude/agents directory. Supports conflict detection and will warn if agent already exists in package or local directories.',
131
+ parameters: z.object({
132
+ name: z.string().describe('Agent name (will be converted to kebab-case, e.g., my-custom-agent)'),
133
+ description: z.string().describe('Agent description (what this agent does)'),
134
+ systemPrompt: z.string().describe('System prompt that defines the agent behavior and personality'),
135
+ category: z.string().optional().default('custom').describe('Category/folder to organize the agent (default: custom)'),
136
+ tools: z.array(z.string()).optional().describe('Optional list of tools this agent can use (e.g., ["web-search", "code-execution"])')
137
+ }),
138
+ execute: async ({ name, description, systemPrompt, category, tools }) => {
139
+ try {
140
+ let cmd = `npx --yes agentic-flow agent create --name "${name}" --description "${description}" --prompt "${systemPrompt}"`;
141
+ if (category && category !== 'custom')
142
+ cmd += ` --category "${category}"`;
143
+ if (tools && tools.length > 0)
144
+ cmd += ` --tools "${tools.join(',')}"`;
145
+ const result = execSync(cmd, {
146
+ encoding: 'utf-8',
147
+ maxBuffer: 10 * 1024 * 1024,
148
+ timeout: 60000,
149
+ input: 'y\n' // Auto-confirm if conflict exists
150
+ });
151
+ return JSON.stringify({
152
+ success: true,
153
+ name,
154
+ category: category || 'custom',
155
+ message: 'Agent created successfully',
156
+ output: result.trim()
157
+ }, null, 2);
158
+ }
159
+ catch (error) {
160
+ throw new Error(`Failed to create agent: ${error.message}`);
161
+ }
162
+ }
163
+ });
164
+ // Tool: List agents with source information
165
+ server.addTool({
166
+ name: 'agentic_flow_list_all_agents',
167
+ description: 'List all available agents including both package agents and custom local agents. Shows source (package or local) and handles deduplication.',
168
+ parameters: z.object({
169
+ format: z.enum(['summary', 'detailed', 'json']).optional().default('summary').describe('Output format: summary (brief list), detailed (full info), json (structured data)'),
170
+ filterSource: z.enum(['all', 'package', 'local']).optional().default('all').describe('Filter by source: all, package (npm distribution), or local (custom .claude/agents)')
171
+ }),
172
+ execute: async ({ format, filterSource }) => {
173
+ try {
174
+ const cmd = `npx --yes agentic-flow agent list ${format || 'summary'}`;
175
+ const result = execSync(cmd, {
176
+ encoding: 'utf-8',
177
+ maxBuffer: 10 * 1024 * 1024,
178
+ timeout: 30000
179
+ });
180
+ if (format === 'json') {
181
+ const agents = JSON.parse(result);
182
+ const filtered = filterSource && filterSource !== 'all'
183
+ ? agents.filter((a) => a.source === filterSource)
184
+ : agents;
185
+ return JSON.stringify({
186
+ success: true,
187
+ count: filtered.length,
188
+ filterSource: filterSource || 'all',
189
+ agents: filtered
190
+ }, null, 2);
191
+ }
192
+ return JSON.stringify({
193
+ success: true,
194
+ filterSource: filterSource || 'all',
195
+ output: result.trim()
196
+ }, null, 2);
197
+ }
198
+ catch (error) {
199
+ throw new Error(`Failed to list agents: ${error.message}`);
200
+ }
201
+ }
202
+ });
203
+ // Tool: Get agent information
204
+ server.addTool({
205
+ name: 'agentic_flow_agent_info',
206
+ description: 'Get detailed information about a specific agent including its source, description, category, and system prompt preview.',
207
+ parameters: z.object({
208
+ name: z.string().describe('Agent name to get information about')
209
+ }),
210
+ execute: async ({ name }) => {
211
+ try {
212
+ const cmd = `npx --yes agentic-flow agent info "${name}"`;
213
+ const result = execSync(cmd, {
214
+ encoding: 'utf-8',
215
+ maxBuffer: 10 * 1024 * 1024,
216
+ timeout: 30000
217
+ });
218
+ return JSON.stringify({
219
+ success: true,
220
+ agent: name,
221
+ output: result.trim()
222
+ }, null, 2);
223
+ }
224
+ catch (error) {
225
+ throw new Error(`Failed to get agent info: ${error.message}`);
226
+ }
227
+ }
228
+ });
229
+ // Tool: Check for agent conflicts
230
+ server.addTool({
231
+ name: 'agentic_flow_check_conflicts',
232
+ description: 'Check for conflicts between package agents and local custom agents. Identifies agents with the same relative path in both locations.',
233
+ parameters: z.object({}),
234
+ execute: async () => {
235
+ try {
236
+ const cmd = `npx --yes agentic-flow agent conflicts`;
237
+ const result = execSync(cmd, {
238
+ encoding: 'utf-8',
239
+ maxBuffer: 10 * 1024 * 1024,
240
+ timeout: 30000
241
+ });
242
+ return JSON.stringify({
243
+ success: true,
244
+ output: result.trim()
245
+ }, null, 2);
246
+ }
247
+ catch (error) {
248
+ throw new Error(`Failed to check conflicts: ${error.message}`);
249
+ }
250
+ }
251
+ });
252
+ console.error('✅ Registered 6 tools:');
253
+ console.error(' • agentic_flow_agent (execute agent)');
254
+ console.error(' • agentic_flow_list_agents (list 66+ agents)');
255
+ console.error(' • agentic_flow_create_agent (create custom agent)');
256
+ console.error(' • agentic_flow_list_all_agents (list with sources)');
257
+ console.error(' • agentic_flow_agent_info (get agent details)');
258
+ console.error(' • agentic_flow_check_conflicts (conflict detection)');
128
259
  console.error('🔌 Starting stdio transport...');
129
260
  server.start({ transportType: 'stdio' }).then(() => {
130
261
  console.error('✅ Agentic-Flow MCP server running on stdio');
@@ -79,25 +79,70 @@ function findAgentFiles(dir) {
79
79
  return files;
80
80
  }
81
81
  /**
82
- * Load all agents from .claude/agents directory
82
+ * Load all agents from .claude/agents directory with deduplication
83
+ * Local agents (.claude/agents in CWD) override package agents
83
84
  */
84
85
  export function loadAgents(agentsDir) {
85
86
  const agents = new Map();
86
- // Priority: explicit parameter > env var > package default > current working directory
87
- const targetDir = agentsDir
88
- || process.env.AGENTS_DIR
89
- || (existsSync(defaultAgentsDir) ? defaultAgentsDir : join(process.cwd(), '.claude/agents'));
90
- logger.info('Loading agents from directory', { agentsDir: targetDir });
91
- const agentFiles = findAgentFiles(targetDir);
92
- logger.debug('Found agent files', { count: agentFiles.length });
93
- for (const filePath of agentFiles) {
94
- const agent = parseAgentFile(filePath);
95
- if (agent) {
96
- agents.set(agent.name, agent);
97
- logger.debug('Loaded agent', { name: agent.name, description: agent.description.substring(0, 100) });
87
+ const agentsByRelativePath = new Map();
88
+ // If explicit directory is provided, use only that
89
+ if (agentsDir) {
90
+ logger.info('Loading agents from explicit directory', { agentsDir });
91
+ const agentFiles = findAgentFiles(agentsDir);
92
+ for (const filePath of agentFiles) {
93
+ const agent = parseAgentFile(filePath);
94
+ if (agent) {
95
+ agents.set(agent.name, agent);
96
+ }
97
+ }
98
+ return agents;
99
+ }
100
+ // Otherwise, load from both package and local with deduplication
101
+ const localAgentsDir = join(process.cwd(), '.claude/agents');
102
+ // 1. Load package agents first (if they exist)
103
+ if (existsSync(defaultAgentsDir)) {
104
+ logger.info('Loading package agents', { agentsDir: defaultAgentsDir });
105
+ const packageFiles = findAgentFiles(defaultAgentsDir);
106
+ logger.debug('Found package agent files', { count: packageFiles.length });
107
+ for (const filePath of packageFiles) {
108
+ const agent = parseAgentFile(filePath);
109
+ if (agent) {
110
+ const relativePath = filePath.substring(defaultAgentsDir.length + 1);
111
+ agentsByRelativePath.set(relativePath, agent);
112
+ agents.set(agent.name, agent);
113
+ logger.debug('Loaded package agent', { name: agent.name, path: relativePath });
114
+ }
115
+ }
116
+ }
117
+ // 2. Load local agents (override package agents with same relative path)
118
+ if (existsSync(localAgentsDir) && localAgentsDir !== defaultAgentsDir) {
119
+ logger.info('Loading local agents', { agentsDir: localAgentsDir });
120
+ const localFiles = findAgentFiles(localAgentsDir);
121
+ logger.debug('Found local agent files', { count: localFiles.length });
122
+ for (const filePath of localFiles) {
123
+ const agent = parseAgentFile(filePath);
124
+ if (agent) {
125
+ const relativePath = filePath.substring(localAgentsDir.length + 1);
126
+ const existingAgent = agentsByRelativePath.get(relativePath);
127
+ if (existingAgent) {
128
+ logger.info('Local agent overrides package agent', {
129
+ name: agent.name,
130
+ path: relativePath
131
+ });
132
+ // Remove old agent
133
+ agents.delete(existingAgent.name);
134
+ }
135
+ agentsByRelativePath.set(relativePath, agent);
136
+ agents.set(agent.name, agent);
137
+ logger.debug('Loaded local agent', { name: agent.name, path: relativePath });
138
+ }
98
139
  }
99
140
  }
100
- logger.info('Agents loaded successfully', { count: agents.size });
141
+ logger.info('Agents loaded successfully', {
142
+ total: agents.size,
143
+ package: existsSync(defaultAgentsDir) ? findAgentFiles(defaultAgentsDir).length : 0,
144
+ local: existsSync(localAgentsDir) ? findAgentFiles(localAgentsDir).length : 0
145
+ });
101
146
  return agents;
102
147
  }
103
148
  /**
package/dist/utils/cli.js CHANGED
@@ -16,6 +16,11 @@ export function parseArgs() {
16
16
  options.mode = 'config';
17
17
  return options;
18
18
  }
19
+ // Check for agent management command
20
+ if (args[0] === 'agent') {
21
+ options.mode = 'agent-manager';
22
+ return options;
23
+ }
19
24
  for (let i = 0; i < args.length; i++) {
20
25
  const arg = args[i];
21
26
  switch (arg) {
@@ -48,6 +53,38 @@ export function parseArgs() {
48
53
  case '-l':
49
54
  options.mode = 'list';
50
55
  break;
56
+ // API Configuration
57
+ case '--anthropic-key':
58
+ options.anthropicApiKey = args[++i];
59
+ break;
60
+ case '--openrouter-key':
61
+ options.openrouterApiKey = args[++i];
62
+ break;
63
+ // Agent Behavior
64
+ case '--temperature':
65
+ options.temperature = parseFloat(args[++i]);
66
+ break;
67
+ case '--max-tokens':
68
+ options.maxTokens = parseInt(args[++i], 10);
69
+ break;
70
+ // Directory Configuration
71
+ case '--agents-dir':
72
+ options.agentsDir = args[++i];
73
+ break;
74
+ // Output Options
75
+ case '--output':
76
+ options.outputFormat = args[++i];
77
+ break;
78
+ case '--verbose':
79
+ options.verbose = true;
80
+ break;
81
+ // Execution Control
82
+ case '--timeout':
83
+ options.timeout = parseInt(args[++i], 10);
84
+ break;
85
+ case '--retry':
86
+ options.retryOnError = true;
87
+ break;
51
88
  }
52
89
  }
53
90
  return options;
@@ -61,6 +98,8 @@ USAGE:
61
98
 
62
99
  COMMANDS:
63
100
  mcp <command> [server] Manage MCP servers (start, stop, status, list)
101
+ config [command] Configuration wizard (set, get, list, delete, reset)
102
+ agent <command> Agent management (list, create, info, conflicts)
64
103
  --list, -l List all available agents
65
104
  --agent, -a <name> Run specific agent mode
66
105
  (default) Run parallel mode (3 agents)
@@ -74,28 +113,67 @@ MCP COMMANDS:
74
113
  Available servers: claude-flow, flow-nexus, agentic-payments, all (default)
75
114
 
76
115
  OPTIONS:
77
- --task, -t <task> Task description for agent mode
78
- --model, -m <model> Model to use (supports OpenRouter models)
79
- --provider, -p <name> Provider to use (anthropic, openrouter, onnx)
80
- --stream, -s Enable real-time streaming output
81
- --help, -h Show this help message
116
+ --task, -t <task> Task description for agent mode
117
+ --model, -m <model> Model to use (supports OpenRouter models)
118
+ --provider, -p <name> Provider (anthropic, openrouter, onnx)
119
+ --stream, -s Enable real-time streaming output
120
+
121
+ API CONFIGURATION:
122
+ --anthropic-key <key> Override ANTHROPIC_API_KEY
123
+ --openrouter-key <key> Override OPENROUTER_API_KEY
124
+
125
+ AGENT BEHAVIOR:
126
+ --temperature <0.0-1.0> Sampling temperature (creativity)
127
+ --max-tokens <number> Maximum response tokens
128
+
129
+ DIRECTORY:
130
+ --agents-dir <path> Custom agents directory
131
+
132
+ OUTPUT:
133
+ --output <text|json|md> Output format
134
+ --verbose Enable verbose logging
135
+
136
+ EXECUTION:
137
+ --timeout <ms> Execution timeout
138
+ --retry Auto-retry on errors
139
+
140
+ --help, -h Show this help message
82
141
 
83
142
  EXAMPLES:
143
+ # Agent Management
144
+ npx agentic-flow agent list # List all agents with sources
145
+ npx agentic-flow agent create # Interactive agent creator
146
+ npx agentic-flow agent info coder # Get agent details
147
+ npx agentic-flow agent conflicts # Check for conflicts
148
+
149
+ # Configuration
150
+ npx agentic-flow config # Interactive config wizard
151
+ npx agentic-flow config set PROVIDER openrouter
152
+ npx agentic-flow config list # View all settings
153
+
84
154
  # MCP Server Management
85
155
  npx agentic-flow mcp start # Start all MCP servers
86
- npx agentic-flow mcp start claude-flow # Start specific server
87
- npx agentic-flow mcp list # List all 203+ MCP tools
88
- npx agentic-flow mcp status # Check server status
156
+ npx agentic-flow mcp list # List all 209+ MCP tools
157
+
158
+ # Agent Execution (Basic)
159
+ npx agentic-flow --list # List all agents
160
+ npx agentic-flow --agent coder --task "Build REST API"
161
+
162
+ # Agent Execution (Advanced)
163
+ npx agentic-flow --agent coder --task "Build API" \\
164
+ --provider openrouter \\
165
+ --model "meta-llama/llama-3.1-8b-instruct" \\
166
+ --temperature 0.7 \\
167
+ --max-tokens 2000 \\
168
+ --output json \\
169
+ --verbose
89
170
 
90
- # Agent Execution
91
- npx agentic-flow --list # List all 150+ agents
92
- npx agentic-flow --agent researcher --task "Analyze AI trends"
93
- npx agentic-flow --agent coder --task "Build REST API" --model "meta-llama/llama-3.1-8b-instruct"
94
- npx agentic-flow --agent coder --task "Create hello world" --provider onnx
95
- npx agentic-flow --agent coder --task "Build REST API" --stream
171
+ # Agent Execution (Custom)
172
+ npx agentic-flow --agent my-custom-agent --task "Your task" \\
173
+ --agents-dir ./my-agents
96
174
 
97
175
  # Parallel Mode
98
- npx agentic-flow # Run 3 agents in parallel (requires TOPIC, DIFF, DATASET)
176
+ npx agentic-flow # Run 3 agents in parallel
99
177
 
100
178
  ENVIRONMENT VARIABLES:
101
179
  ANTHROPIC_API_KEY Anthropic API key (for Claude models)
@@ -111,11 +189,11 @@ ENVIRONMENT VARIABLES:
111
189
  ENABLE_STREAMING Enable streaming (true/false)
112
190
  HEALTH_PORT Health check port (default: 8080)
113
191
 
114
- MCP TOOLS (203+ available):
115
- claude-flow-sdk: 6 in-process tools (memory, swarm coordination)
192
+ MCP TOOLS (209+ available):
193
+ agentic-flow: 6 tools (agent execution, creation, management)
116
194
  • claude-flow: 101 tools (neural networks, GitHub, workflows, DAA)
117
195
  • flow-nexus: 96 cloud tools (sandboxes, distributed swarms, templates)
118
- • agentic-payments: Payment authorization and multi-agent consensus
196
+ • agentic-payments: 6 tools (payment authorization, multi-agent consensus)
119
197
 
120
198
  For more information, visit: https://github.com/ruvnet/agentic-flow
121
199
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-flow",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Production-ready AI agent orchestration platform with 66 specialized agents, 111 MCP tools, and autonomous multi-agent swarms. Built by @ruvnet with Claude Agent SDK, neural networks, memory persistence, GitHub integration, and distributed consensus protocols.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",