claude-flow-novice 2.5.2 → 2.6.0
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/.claude/agents/CLAUDE.md +740 -978
- package/.claude/agents/core-agents/cost-savings-cfn-loop-coordinator.md +47 -2
- package/.claude/agents/custom/agent-builder.md +637 -0
- package/.claude/api-configs/config-current-zai-config.env +62 -0
- package/.claude/api-configs/config-test-zai-config.env +62 -0
- package/.claude/api-configs/env-backups/before-anthropic-20251020-025404.env +62 -0
- package/.claude/api-configs/env-backups/before-restore-20251020-025431.env +62 -0
- package/.claude/artifacts/reflection-merge-logs/cli-agent-spawning-v2.5.2-merge-report.md +61 -0
- package/.claude/commands/cfn-loop-epic.md +41 -17
- package/.claude/commands/cfn-loop.md +43 -30
- package/.claude/commands/custom-routing-activate.md +37 -123
- package/.claude/commands/custom-routing-deactivate.md +27 -124
- package/.claude/commands/switch-api.md +41 -16
- package/.claude/skills/agent-execution/execute-agent.sh +126 -0
- package/.claude/skills/redis-coordination/AGENT_LOGGING.md +280 -0
- package/.claude/skills/redis-coordination/agent-log.sh +124 -0
- package/.claude/skills/redis-coordination/init-swarm.sh +6 -1
- package/.claude/skills/redis-coordination/invoke-waiting-mode.sh +62 -5
- package/.claude/skills/redis-coordination/orchestrate-cfn-loop.sh +68 -8
- package/.claude/skills/redis-coordination/orchestrate-cfn-loop.sh.backup-1760949407 +933 -0
- package/.claude/skills/redis-coordination/store-epic-context.sh +123 -0
- package/.claude/skills/redis-coordination/test-iteration-feedback.sh +320 -0
- package/.claude/skills/skill-builder/SKILL.md +910 -0
- package/CLAUDE.md +76 -2
- package/dist/cli/agent-command.js +151 -0
- package/dist/cli/agent-command.js.map +1 -0
- package/dist/cli/agent-definition-parser.js +176 -0
- package/dist/cli/agent-definition-parser.js.map +1 -0
- package/dist/cli/agent-executor.js +176 -0
- package/dist/cli/agent-executor.js.map +1 -0
- package/dist/cli/agent-prompt-builder.js +188 -0
- package/dist/cli/agent-prompt-builder.js.map +1 -0
- package/dist/cli/agent-spawn.js +46 -1
- package/dist/cli/agent-spawn.js.map +1 -1
- package/dist/cli/anthropic-client.js +242 -0
- package/dist/cli/anthropic-client.js.map +1 -0
- package/dist/cli/cli-agent-context.js +353 -0
- package/dist/cli/cli-agent-context.js.map +1 -0
- package/dist/cli/cli-agent-context.test.js +451 -0
- package/dist/cli/cli-agent-context.test.js.map +1 -0
- package/dist/cli/index.js +115 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/iteration-history.js +188 -0
- package/dist/cli/iteration-history.js.map +1 -0
- package/package.json +3 -1
- package/scripts/switch-api.sh +233 -0
package/CLAUDE.md
CHANGED
|
@@ -6,6 +6,35 @@
|
|
|
6
6
|
|
|
7
7
|
## 1) Critical Rules (Single Source of Truth)
|
|
8
8
|
|
|
9
|
+
### Core Operational Rules
|
|
10
|
+
* **Use agents for all non-trivial work** (≥4 steps or any multi-file / research / testing / architecture / security / integration / refactor / feature)
|
|
11
|
+
* **Initialize swarm before any multi-agent work**
|
|
12
|
+
* **Batch operations**: one message per related batch (spawn, file edits, bash, todos, memory ops)
|
|
13
|
+
* **Run post-edit hook after every file edit** inclusive of .md files and await the response
|
|
14
|
+
* **Never work solo** on multi-step tasks. Spawn parallel specialists
|
|
15
|
+
* **Never mix implementers and validators in the same message**
|
|
16
|
+
* **Never run tests inside agents.** Execute once; agents read results
|
|
17
|
+
* **Never save to project root.** Use proper subdirs
|
|
18
|
+
* **No guides/summaries/reports** unless explicitly asked
|
|
19
|
+
* **Use spartan language and give answers in plain english**
|
|
20
|
+
* **Concise summaries only** - no code examples unless requested
|
|
21
|
+
* **Redis persistence enables swarm recovery** - swarm state survives interruptions
|
|
22
|
+
* **ALL agent communication MUST use Redis pub/sub** - no direct file coordination
|
|
23
|
+
|
|
24
|
+
**Consensus thresholds:**
|
|
25
|
+
* Gate (agent self-confidence): **≥0.75 each**
|
|
26
|
+
* Validators consensus: **≥0.90**
|
|
27
|
+
|
|
28
|
+
### CTO Delegation Persona
|
|
29
|
+
* **Act as a busy CTO** who delegates all non-trivial work to specialized agents
|
|
30
|
+
* **Define clear success criteria** for implementation (working code, passing tests, documented features)
|
|
31
|
+
* **Never define adoption criteria** (user engagement, rollout strategy, training plans)
|
|
32
|
+
* **Ruthlessly delegate** - if task requires >3 steps, spawn agents immediately
|
|
33
|
+
* **Provide context, not solutions** - agents figure out implementation details
|
|
34
|
+
* **Success = implementation complete** - not "users love it" or "team adopts it"
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
9
38
|
### Skills-Based Coordination
|
|
10
39
|
**Core Skills:**
|
|
11
40
|
- Redis Coordination (`.claude/skills/redis-coordination/SKILL.md`)
|
|
@@ -120,7 +149,11 @@ Task("cost-savings-cfn-loop-coordinator", `
|
|
|
120
149
|
**Config:** `.claude/hooks/post-edit.config.json`
|
|
121
150
|
**Skill:** `.claude/skills/hook-pipeline/SKILL.md`
|
|
122
151
|
|
|
123
|
-
## 2)
|
|
152
|
+
## 2) When Agents Are Mandatory (Triggers)
|
|
153
|
+
|
|
154
|
+
If **any** apply, spawn agents:
|
|
155
|
+
|
|
156
|
+
* > 3 distinct steps • multiple files • research+implement+test • design decisions • code review/quality • security/performance/compliance • system integration • docs generation • refactor/optimize • any feature work
|
|
124
157
|
|
|
125
158
|
### Skill Selection Criteria
|
|
126
159
|
**Mandatory Skill Spawning Triggers:**
|
|
@@ -140,6 +173,19 @@ npx claude-flow-novice swarm "Task Description" \
|
|
|
140
173
|
--strategy development
|
|
141
174
|
```
|
|
142
175
|
|
|
176
|
+
### Single Agent vs Coordinator
|
|
177
|
+
|
|
178
|
+
**Use Single Agent:**
|
|
179
|
+
* 1 specialized task (coding, reviewing, testing)
|
|
180
|
+
* No dependencies on other agents
|
|
181
|
+
* Straightforward execution
|
|
182
|
+
|
|
183
|
+
**Use Coordinator:**
|
|
184
|
+
* Multiple agents needed (2+)
|
|
185
|
+
* Sequential dependencies (Loop 3 → Loop 2 → Product Owner)
|
|
186
|
+
* Iteration/consensus required
|
|
187
|
+
* CFN Loop workflows
|
|
188
|
+
|
|
143
189
|
## 3) Coordination Patterns
|
|
144
190
|
|
|
145
191
|
**Redis Coordination Patterns**
|
|
@@ -425,4 +471,32 @@ Implement comprehensive test suites that validate both functional requirements a
|
|
|
425
471
|
- Maintenance Schedule: `planning/skills/MAINTENANCE_SCHEDULE.md`
|
|
426
472
|
|
|
427
473
|
**Migration Analytics:**
|
|
428
|
-
See `.artifacts/analytics/context-reduction-report.json`
|
|
474
|
+
See `.artifacts/analytics/context-reduction-report.json`
|
|
475
|
+
## Adaptive Context Extensions: CLI Agent Spawning Insights (v2.5.2)
|
|
476
|
+
|
|
477
|
+
### Strategy Patterns
|
|
478
|
+
|
|
479
|
+
#### PATTERN-001: Environment Configuration
|
|
480
|
+
- **Context**: CLI Entrypoints
|
|
481
|
+
- **Insight**: Always explicitly load environment configurations using 'import dotenv/config' to ensure provider-specific settings are correctly read and applied across different execution contexts.
|
|
482
|
+
- **Tags**: environment, configuration, cli, dotenv
|
|
483
|
+
- **Confidence**: 0.95
|
|
484
|
+
- **Priority**: 9/10
|
|
485
|
+
|
|
486
|
+
### Domain Insights
|
|
487
|
+
|
|
488
|
+
#### PATTERN-002: Multi-Provider API Integration
|
|
489
|
+
- **Context**: API Provider Configuration
|
|
490
|
+
- **Insight**: Create explicit provider-specific mappings that account for endpoint differences, model naming conventions, and protocol variations to ensure robust cross-provider compatibility.
|
|
491
|
+
- **Tags**: api-integration, provider-mapping, resilience, configuration
|
|
492
|
+
- **Confidence**: 0.92
|
|
493
|
+
- **Priority**: 8/10
|
|
494
|
+
|
|
495
|
+
### Edge Case Handling
|
|
496
|
+
|
|
497
|
+
#### PATTERN-004: Resilient API Call Mechanisms
|
|
498
|
+
- **Context**: Error Handling and Timeout Management
|
|
499
|
+
- **Insight**: Configure explicit timeouts and retry mechanisms for API calls to prevent indefinite hanging and provide built-in resilience, with provider-specific timeout and retry configurations.
|
|
500
|
+
- **Tags**: error-handling, timeout, resilience, api-calls
|
|
501
|
+
- **Confidence**: 0.90
|
|
502
|
+
- **Priority**: 9/10
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Command Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles `npx claude-flow-novice agent <type> [options]` commands.
|
|
5
|
+
* Orchestrates agent definition parsing, prompt building, and execution.
|
|
6
|
+
*/ import { parseAgentDefinition, listAgentDefinitions } from './agent-definition-parser.js';
|
|
7
|
+
import { buildAgentPrompt } from './agent-prompt-builder.js';
|
|
8
|
+
import { executeAgent } from './agent-executor.js';
|
|
9
|
+
/**
|
|
10
|
+
* Display agent command help
|
|
11
|
+
*/ export function displayAgentHelp() {
|
|
12
|
+
console.log(`
|
|
13
|
+
Claude Flow Novice - Agent Spawning
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
npx claude-flow-novice agent <type> [options]
|
|
17
|
+
|
|
18
|
+
Arguments:
|
|
19
|
+
<type> Agent type (e.g., rust-enterprise-developer, coder, reviewer)
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--task-id <id> Task identifier for CFN Loop coordination
|
|
23
|
+
--iteration <n> Iteration number (default: 1)
|
|
24
|
+
--context <text> Task context/description
|
|
25
|
+
--mode <mode> Execution mode (cli, api, hybrid)
|
|
26
|
+
--priority <n> Task priority (1-10)
|
|
27
|
+
--parent-task-id <id> Parent task identifier
|
|
28
|
+
--list List all available agents
|
|
29
|
+
--help Show this help message
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
# Simple agent spawn
|
|
33
|
+
npx claude-flow-novice agent coder --context "Implement JWT auth"
|
|
34
|
+
|
|
35
|
+
# CFN Loop agent
|
|
36
|
+
npx claude-flow-novice agent rust-enterprise-developer \\
|
|
37
|
+
--task-id task-123 \\
|
|
38
|
+
--iteration 1 \\
|
|
39
|
+
--mode standard
|
|
40
|
+
|
|
41
|
+
# List available agents
|
|
42
|
+
npx claude-flow-novice agent --list
|
|
43
|
+
|
|
44
|
+
Available Agents:
|
|
45
|
+
Agents are defined in .claude/agents/ directory:
|
|
46
|
+
- core-agents/ Production-ready core agents
|
|
47
|
+
- specialized/ Domain-specific specialists
|
|
48
|
+
- development/ Development-focused agents
|
|
49
|
+
- security/ Security-focused agents
|
|
50
|
+
- custom/ Your custom agents
|
|
51
|
+
|
|
52
|
+
Documentation:
|
|
53
|
+
See .claude/agents/CLAUDE.md for agent creation guide
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* List all available agent definitions
|
|
58
|
+
*/ export async function listAgents() {
|
|
59
|
+
console.log('Searching for agent definitions...\n');
|
|
60
|
+
const agents = await listAgentDefinitions();
|
|
61
|
+
if (agents.length === 0) {
|
|
62
|
+
console.log('No agent definitions found in .claude/agents/');
|
|
63
|
+
console.log('\nTo create agents, see: .claude/agents/CLAUDE.md');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log(`Found ${agents.length} agent(s):\n`);
|
|
67
|
+
// Group by category
|
|
68
|
+
const grouped = {};
|
|
69
|
+
for (const agent of agents){
|
|
70
|
+
const parts = agent.split('/');
|
|
71
|
+
const category = parts.length > 1 ? parts[0] : 'root';
|
|
72
|
+
const name = parts.length > 1 ? parts.slice(1).join('/') : parts[0];
|
|
73
|
+
if (!grouped[category]) {
|
|
74
|
+
grouped[category] = [];
|
|
75
|
+
}
|
|
76
|
+
grouped[category].push(name);
|
|
77
|
+
}
|
|
78
|
+
// Display grouped agents
|
|
79
|
+
for (const [category, names] of Object.entries(grouped).sort()){
|
|
80
|
+
console.log(`${category}/`);
|
|
81
|
+
for (const name of names.sort()){
|
|
82
|
+
console.log(` - ${name}`);
|
|
83
|
+
}
|
|
84
|
+
console.log('');
|
|
85
|
+
}
|
|
86
|
+
console.log('Usage:');
|
|
87
|
+
console.log(' npx claude-flow-novice agent <name> [options]');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Execute agent command
|
|
91
|
+
*/ export async function agentCommand(agentType, options) {
|
|
92
|
+
// Handle --list flag
|
|
93
|
+
if (options.list) {
|
|
94
|
+
await listAgents();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Handle --help flag
|
|
98
|
+
if (options.help || !agentType) {
|
|
99
|
+
displayAgentHelp();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
console.log(`[agent-command] Spawning agent: ${agentType}`);
|
|
104
|
+
console.log('');
|
|
105
|
+
// Step 1: Parse agent definition
|
|
106
|
+
console.log('[1/3] Parsing agent definition...');
|
|
107
|
+
const definition = await parseAgentDefinition(agentType);
|
|
108
|
+
console.log(` ✓ Found: ${definition.name}`);
|
|
109
|
+
console.log(` ✓ Type: ${definition.type || 'specialist'}`);
|
|
110
|
+
console.log(` ✓ Model: ${definition.model}`);
|
|
111
|
+
console.log(` ✓ Tools: ${definition.tools.join(', ')}`);
|
|
112
|
+
console.log('');
|
|
113
|
+
// Step 2: Build agent prompt
|
|
114
|
+
console.log('[2/3] Building agent prompt...');
|
|
115
|
+
const taskContext = {
|
|
116
|
+
taskId: options.taskId,
|
|
117
|
+
iteration: options.iteration,
|
|
118
|
+
context: options.context,
|
|
119
|
+
mode: options.mode,
|
|
120
|
+
priority: options.priority,
|
|
121
|
+
parentTaskId: options.parentTaskId
|
|
122
|
+
};
|
|
123
|
+
const prompt = await buildAgentPrompt(definition, taskContext);
|
|
124
|
+
console.log(` ✓ Prompt size: ${prompt.length} characters`);
|
|
125
|
+
console.log(` ✓ CFN Loop protocol: ${prompt.includes('CFN Loop Redis Completion Protocol') ? 'included' : 'not applicable'}`);
|
|
126
|
+
console.log(` ✓ Iteration history: ${prompt.includes('## Iteration History') ? 'included' : 'not applicable'}`);
|
|
127
|
+
console.log('');
|
|
128
|
+
// Step 3: Execute agent
|
|
129
|
+
console.log('[3/3] Executing agent...');
|
|
130
|
+
const result = await executeAgent(definition, prompt, taskContext);
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log('=== Execution Result ===');
|
|
133
|
+
console.log(`Agent ID: ${result.agentId}`);
|
|
134
|
+
console.log(`Status: ${result.success ? '✓ Success' : '✗ Failed'}`);
|
|
135
|
+
console.log(`Exit Code: ${result.exitCode}`);
|
|
136
|
+
if (result.error) {
|
|
137
|
+
console.error(`Error: ${result.error}`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
if (result.output) {
|
|
141
|
+
console.log('\nOutput:');
|
|
142
|
+
console.log(result.output);
|
|
143
|
+
}
|
|
144
|
+
process.exit(result.exitCode);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error('\n[agent-command] Error:', error instanceof Error ? error.message : String(error));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
//# sourceMappingURL=agent-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/agent-command.ts"],"sourcesContent":["/**\r\n * Agent Command Handler\r\n *\r\n * Handles `npx claude-flow-novice agent <type> [options]` commands.\r\n * Orchestrates agent definition parsing, prompt building, and execution.\r\n */\r\n\r\nimport { parseAgentDefinition, listAgentDefinitions } from './agent-definition-parser.js';\r\nimport { buildAgentPrompt, TaskContext } from './agent-prompt-builder.js';\r\nimport { executeAgent } from './agent-executor.js';\r\n\r\nexport interface AgentCommandOptions {\r\n taskId?: string;\r\n iteration?: number;\r\n context?: string;\r\n mode?: string;\r\n priority?: number;\r\n parentTaskId?: string;\r\n list?: boolean;\r\n help?: boolean;\r\n}\r\n\r\n/**\r\n * Display agent command help\r\n */\r\nexport function displayAgentHelp(): void {\r\n console.log(`\r\nClaude Flow Novice - Agent Spawning\r\n\r\nUsage:\r\n npx claude-flow-novice agent <type> [options]\r\n\r\nArguments:\r\n <type> Agent type (e.g., rust-enterprise-developer, coder, reviewer)\r\n\r\nOptions:\r\n --task-id <id> Task identifier for CFN Loop coordination\r\n --iteration <n> Iteration number (default: 1)\r\n --context <text> Task context/description\r\n --mode <mode> Execution mode (cli, api, hybrid)\r\n --priority <n> Task priority (1-10)\r\n --parent-task-id <id> Parent task identifier\r\n --list List all available agents\r\n --help Show this help message\r\n\r\nExamples:\r\n # Simple agent spawn\r\n npx claude-flow-novice agent coder --context \"Implement JWT auth\"\r\n\r\n # CFN Loop agent\r\n npx claude-flow-novice agent rust-enterprise-developer \\\\\r\n --task-id task-123 \\\\\r\n --iteration 1 \\\\\r\n --mode standard\r\n\r\n # List available agents\r\n npx claude-flow-novice agent --list\r\n\r\nAvailable Agents:\r\n Agents are defined in .claude/agents/ directory:\r\n - core-agents/ Production-ready core agents\r\n - specialized/ Domain-specific specialists\r\n - development/ Development-focused agents\r\n - security/ Security-focused agents\r\n - custom/ Your custom agents\r\n\r\nDocumentation:\r\n See .claude/agents/CLAUDE.md for agent creation guide\r\n`);\r\n}\r\n\r\n/**\r\n * List all available agent definitions\r\n */\r\nexport async function listAgents(): Promise<void> {\r\n console.log('Searching for agent definitions...\\n');\r\n\r\n const agents = await listAgentDefinitions();\r\n\r\n if (agents.length === 0) {\r\n console.log('No agent definitions found in .claude/agents/');\r\n console.log('\\nTo create agents, see: .claude/agents/CLAUDE.md');\r\n return;\r\n }\r\n\r\n console.log(`Found ${agents.length} agent(s):\\n`);\r\n\r\n // Group by category\r\n const grouped: Record<string, string[]> = {};\r\n\r\n for (const agent of agents) {\r\n const parts = agent.split('/');\r\n const category = parts.length > 1 ? parts[0] : 'root';\r\n const name = parts.length > 1 ? parts.slice(1).join('/') : parts[0];\r\n\r\n if (!grouped[category]) {\r\n grouped[category] = [];\r\n }\r\n grouped[category].push(name);\r\n }\r\n\r\n // Display grouped agents\r\n for (const [category, names] of Object.entries(grouped).sort()) {\r\n console.log(`${category}/`);\r\n for (const name of names.sort()) {\r\n console.log(` - ${name}`);\r\n }\r\n console.log('');\r\n }\r\n\r\n console.log('Usage:');\r\n console.log(' npx claude-flow-novice agent <name> [options]');\r\n}\r\n\r\n/**\r\n * Execute agent command\r\n */\r\nexport async function agentCommand(\r\n agentType: string | undefined,\r\n options: AgentCommandOptions\r\n): Promise<void> {\r\n // Handle --list flag\r\n if (options.list) {\r\n await listAgents();\r\n return;\r\n }\r\n\r\n // Handle --help flag\r\n if (options.help || !agentType) {\r\n displayAgentHelp();\r\n return;\r\n }\r\n\r\n try {\r\n console.log(`[agent-command] Spawning agent: ${agentType}`);\r\n console.log('');\r\n\r\n // Step 1: Parse agent definition\r\n console.log('[1/3] Parsing agent definition...');\r\n const definition = await parseAgentDefinition(agentType);\r\n console.log(` ✓ Found: ${definition.name}`);\r\n console.log(` ✓ Type: ${definition.type || 'specialist'}`);\r\n console.log(` ✓ Model: ${definition.model}`);\r\n console.log(` ✓ Tools: ${definition.tools.join(', ')}`);\r\n console.log('');\r\n\r\n // Step 2: Build agent prompt\r\n console.log('[2/3] Building agent prompt...');\r\n const taskContext: TaskContext = {\r\n taskId: options.taskId,\r\n iteration: options.iteration,\r\n context: options.context,\r\n mode: options.mode,\r\n priority: options.priority,\r\n parentTaskId: options.parentTaskId,\r\n };\r\n\r\n const prompt = await buildAgentPrompt(definition, taskContext);\r\n console.log(` ✓ Prompt size: ${prompt.length} characters`);\r\n console.log(` ✓ CFN Loop protocol: ${prompt.includes('CFN Loop Redis Completion Protocol') ? 'included' : 'not applicable'}`);\r\n console.log(` ✓ Iteration history: ${prompt.includes('## Iteration History') ? 'included' : 'not applicable'}`);\r\n console.log('');\r\n\r\n // Step 3: Execute agent\r\n console.log('[3/3] Executing agent...');\r\n const result = await executeAgent(definition, prompt, taskContext);\r\n\r\n console.log('');\r\n console.log('=== Execution Result ===');\r\n console.log(`Agent ID: ${result.agentId}`);\r\n console.log(`Status: ${result.success ? '✓ Success' : '✗ Failed'}`);\r\n console.log(`Exit Code: ${result.exitCode}`);\r\n\r\n if (result.error) {\r\n console.error(`Error: ${result.error}`);\r\n process.exit(1);\r\n }\r\n\r\n if (result.output) {\r\n console.log('\\nOutput:');\r\n console.log(result.output);\r\n }\r\n\r\n process.exit(result.exitCode);\r\n } catch (error) {\r\n console.error('\\n[agent-command] Error:', error instanceof Error ? error.message : String(error));\r\n process.exit(1);\r\n }\r\n}\r\n"],"names":["parseAgentDefinition","listAgentDefinitions","buildAgentPrompt","executeAgent","displayAgentHelp","console","log","listAgents","agents","length","grouped","agent","parts","split","category","name","slice","join","push","names","Object","entries","sort","agentCommand","agentType","options","list","help","definition","type","model","tools","taskContext","taskId","iteration","context","mode","priority","parentTaskId","prompt","includes","result","agentId","success","exitCode","error","process","exit","output","Error","message","String"],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Definition Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses agent definition files (.md) with YAML frontmatter and markdown content.
|
|
5
|
+
* Supports agent definitions in .claude/agents/ directory structure.
|
|
6
|
+
*/ import fs from 'fs/promises';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { glob } from 'glob';
|
|
9
|
+
/**
|
|
10
|
+
* Parse YAML frontmatter from markdown content
|
|
11
|
+
*/ function parseFrontmatter(content) {
|
|
12
|
+
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
|
|
13
|
+
const match = content.match(frontmatterRegex);
|
|
14
|
+
if (!match) {
|
|
15
|
+
return {
|
|
16
|
+
frontmatter: {},
|
|
17
|
+
body: content
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const [, yamlContent, body] = match;
|
|
21
|
+
// Simple YAML parser (handles basic key-value pairs, arrays, and objects)
|
|
22
|
+
const frontmatter = {};
|
|
23
|
+
const lines = yamlContent.split('\n');
|
|
24
|
+
let currentKey = '';
|
|
25
|
+
let currentArray = [];
|
|
26
|
+
let isInArray = false;
|
|
27
|
+
let isInObject = false;
|
|
28
|
+
let currentObject = {};
|
|
29
|
+
let objectKey = '';
|
|
30
|
+
for (const line of lines){
|
|
31
|
+
const trimmed = line.trim();
|
|
32
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
33
|
+
// Array item
|
|
34
|
+
if (trimmed.startsWith('- ')) {
|
|
35
|
+
if (!isInArray) {
|
|
36
|
+
isInArray = true;
|
|
37
|
+
currentArray = [];
|
|
38
|
+
}
|
|
39
|
+
currentArray.push(trimmed.substring(2).trim());
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// End of array
|
|
43
|
+
if (isInArray && !trimmed.startsWith('- ')) {
|
|
44
|
+
frontmatter[currentKey] = currentArray;
|
|
45
|
+
isInArray = false;
|
|
46
|
+
currentArray = [];
|
|
47
|
+
}
|
|
48
|
+
// Object field (indented key-value)
|
|
49
|
+
if (trimmed.match(/^\s+\w+:/) && isInObject) {
|
|
50
|
+
const [objKey, ...objValueParts] = trimmed.split(':');
|
|
51
|
+
const objValue = objValueParts.join(':').trim().replace(/^["']|["']$/g, '');
|
|
52
|
+
currentObject[objKey.trim()] = objValue;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Key-value pair
|
|
56
|
+
const colonIndex = trimmed.indexOf(':');
|
|
57
|
+
if (colonIndex !== -1) {
|
|
58
|
+
const key = trimmed.substring(0, colonIndex).trim();
|
|
59
|
+
const value = trimmed.substring(colonIndex + 1).trim();
|
|
60
|
+
// Check if this starts an object
|
|
61
|
+
if (value === '') {
|
|
62
|
+
isInObject = true;
|
|
63
|
+
currentObject = {};
|
|
64
|
+
objectKey = key;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// End previous object if any
|
|
68
|
+
if (isInObject && !trimmed.match(/^\s+/)) {
|
|
69
|
+
frontmatter[objectKey] = currentObject;
|
|
70
|
+
isInObject = false;
|
|
71
|
+
currentObject = {};
|
|
72
|
+
}
|
|
73
|
+
currentKey = key;
|
|
74
|
+
// Multi-line string (starts with |)
|
|
75
|
+
if (value === '|') {
|
|
76
|
+
continue; // Will be handled by next lines
|
|
77
|
+
}
|
|
78
|
+
// Remove quotes
|
|
79
|
+
const cleanValue = value.replace(/^["']|["']$/g, '');
|
|
80
|
+
frontmatter[key] = cleanValue;
|
|
81
|
+
} else if (currentKey && trimmed && !isInArray && !isInObject) {
|
|
82
|
+
// Continuation of multi-line string
|
|
83
|
+
const existingValue = frontmatter[currentKey];
|
|
84
|
+
frontmatter[currentKey] = existingValue ? `${existingValue}\n${trimmed}` : trimmed;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Handle trailing array or object
|
|
88
|
+
if (isInArray) {
|
|
89
|
+
frontmatter[currentKey] = currentArray;
|
|
90
|
+
}
|
|
91
|
+
if (isInObject) {
|
|
92
|
+
frontmatter[objectKey] = currentObject;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
frontmatter,
|
|
96
|
+
body: body.trim()
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Find agent definition file by agent type/name
|
|
101
|
+
*/ async function findAgentFile(agentType, baseDir = '.claude/agents') {
|
|
102
|
+
// Normalize agent type (handle both kebab-case and underscores)
|
|
103
|
+
const normalizedType = agentType.toLowerCase().replace(/_/g, '-');
|
|
104
|
+
// Search patterns (in order of priority)
|
|
105
|
+
const patterns = [
|
|
106
|
+
// Exact match in any subdirectory
|
|
107
|
+
`${baseDir}/**/${normalizedType}.md`,
|
|
108
|
+
// Match with different casing
|
|
109
|
+
`${baseDir}/**/*${normalizedType}*.md`
|
|
110
|
+
];
|
|
111
|
+
for (const pattern of patterns){
|
|
112
|
+
const files = await glob(pattern, {
|
|
113
|
+
nodir: true,
|
|
114
|
+
absolute: true
|
|
115
|
+
});
|
|
116
|
+
if (files.length > 0) {
|
|
117
|
+
// Prefer exact match over partial match
|
|
118
|
+
const exactMatch = files.find((f)=>{
|
|
119
|
+
const basename = path.basename(f, '.md').toLowerCase();
|
|
120
|
+
return basename === normalizedType;
|
|
121
|
+
});
|
|
122
|
+
return exactMatch || files[0];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Parse agent definition from file
|
|
129
|
+
*/ export async function parseAgentDefinition(agentType) {
|
|
130
|
+
// Find agent file
|
|
131
|
+
const filePath = await findAgentFile(agentType);
|
|
132
|
+
if (!filePath) {
|
|
133
|
+
throw new Error(`Agent definition not found: ${agentType}`);
|
|
134
|
+
}
|
|
135
|
+
// Read file content
|
|
136
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
137
|
+
// Parse frontmatter and body
|
|
138
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
139
|
+
// Extract category from path
|
|
140
|
+
const relativePath = path.relative('.claude/agents', filePath);
|
|
141
|
+
const category = relativePath.includes('/') ? relativePath.split('/')[0] : undefined;
|
|
142
|
+
// Build agent definition
|
|
143
|
+
const definition = {
|
|
144
|
+
name: frontmatter.name || agentType,
|
|
145
|
+
description: frontmatter.description || '',
|
|
146
|
+
tools: Array.isArray(frontmatter.tools) ? frontmatter.tools : [],
|
|
147
|
+
model: frontmatter.model || 'haiku',
|
|
148
|
+
type: frontmatter.type,
|
|
149
|
+
color: frontmatter.color,
|
|
150
|
+
acl_level: frontmatter.acl_level ? parseInt(String(frontmatter.acl_level), 10) : undefined,
|
|
151
|
+
capabilities: frontmatter.capabilities,
|
|
152
|
+
validation_hooks: frontmatter.validation_hooks,
|
|
153
|
+
lifecycle: frontmatter.lifecycle,
|
|
154
|
+
content: body,
|
|
155
|
+
filePath,
|
|
156
|
+
category
|
|
157
|
+
};
|
|
158
|
+
return definition;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* List all available agent definitions
|
|
162
|
+
*/ export async function listAgentDefinitions(baseDir = '.claude/agents') {
|
|
163
|
+
const pattern = `${baseDir}/**/*.md`;
|
|
164
|
+
const files = await glob(pattern, {
|
|
165
|
+
nodir: true
|
|
166
|
+
});
|
|
167
|
+
return files.map((f)=>path.basename(f, '.md'));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Check if agent definition includes CFN Loop protocol
|
|
171
|
+
*/ export function hasCFNLoopProtocol(definition) {
|
|
172
|
+
const content = definition.content.toLowerCase();
|
|
173
|
+
return content.includes('cfn loop') && content.includes('redis completion protocol') || content.includes('invoke-waiting-mode.sh');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//# sourceMappingURL=agent-definition-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/agent-definition-parser.ts"],"sourcesContent":["/**\r\n * Agent Definition Parser\r\n *\r\n * Parses agent definition files (.md) with YAML frontmatter and markdown content.\r\n * Supports agent definitions in .claude/agents/ directory structure.\r\n */\r\n\r\nimport fs from 'fs/promises';\r\nimport path from 'path';\r\nimport { glob } from 'glob';\r\n\r\nexport interface AgentDefinition {\r\n // YAML frontmatter fields\r\n name: string;\r\n description: string;\r\n tools: string[];\r\n model: 'haiku' | 'sonnet' | 'opus';\r\n type?: string;\r\n color?: string;\r\n acl_level?: number;\r\n capabilities?: string[];\r\n validation_hooks?: string[];\r\n lifecycle?: {\r\n pre_task?: string;\r\n post_task?: string;\r\n };\r\n\r\n // Parsed markdown content\r\n content: string;\r\n\r\n // File metadata\r\n filePath: string;\r\n category?: string; // e.g., 'core-agents', 'specialized', 'custom'\r\n}\r\n\r\n/**\r\n * Parse YAML frontmatter from markdown content\r\n */\r\nfunction parseFrontmatter(content: string): { frontmatter: Record<string, any>; body: string } {\r\n const frontmatterRegex = /^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/;\r\n const match = content.match(frontmatterRegex);\r\n\r\n if (!match) {\r\n return { frontmatter: {}, body: content };\r\n }\r\n\r\n const [, yamlContent, body] = match;\r\n\r\n // Simple YAML parser (handles basic key-value pairs, arrays, and objects)\r\n const frontmatter: Record<string, any> = {};\r\n const lines = yamlContent.split('\\n');\r\n let currentKey = '';\r\n let currentArray: string[] = [];\r\n let isInArray = false;\r\n let isInObject = false;\r\n let currentObject: Record<string, string> = {};\r\n let objectKey = '';\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed.startsWith('#')) continue;\r\n\r\n // Array item\r\n if (trimmed.startsWith('- ')) {\r\n if (!isInArray) {\r\n isInArray = true;\r\n currentArray = [];\r\n }\r\n currentArray.push(trimmed.substring(2).trim());\r\n continue;\r\n }\r\n\r\n // End of array\r\n if (isInArray && !trimmed.startsWith('- ')) {\r\n frontmatter[currentKey] = currentArray;\r\n isInArray = false;\r\n currentArray = [];\r\n }\r\n\r\n // Object field (indented key-value)\r\n if (trimmed.match(/^\\s+\\w+:/) && isInObject) {\r\n const [objKey, ...objValueParts] = trimmed.split(':');\r\n const objValue = objValueParts.join(':').trim().replace(/^[\"']|[\"']$/g, '');\r\n currentObject[objKey.trim()] = objValue;\r\n continue;\r\n }\r\n\r\n // Key-value pair\r\n const colonIndex = trimmed.indexOf(':');\r\n if (colonIndex !== -1) {\r\n const key = trimmed.substring(0, colonIndex).trim();\r\n const value = trimmed.substring(colonIndex + 1).trim();\r\n\r\n // Check if this starts an object\r\n if (value === '') {\r\n isInObject = true;\r\n currentObject = {};\r\n objectKey = key;\r\n continue;\r\n }\r\n\r\n // End previous object if any\r\n if (isInObject && !trimmed.match(/^\\s+/)) {\r\n frontmatter[objectKey] = currentObject;\r\n isInObject = false;\r\n currentObject = {};\r\n }\r\n\r\n currentKey = key;\r\n\r\n // Multi-line string (starts with |)\r\n if (value === '|') {\r\n continue; // Will be handled by next lines\r\n }\r\n\r\n // Remove quotes\r\n const cleanValue = value.replace(/^[\"']|[\"']$/g, '');\r\n frontmatter[key] = cleanValue;\r\n } else if (currentKey && trimmed && !isInArray && !isInObject) {\r\n // Continuation of multi-line string\r\n const existingValue = frontmatter[currentKey];\r\n frontmatter[currentKey] = existingValue\r\n ? `${existingValue}\\n${trimmed}`\r\n : trimmed;\r\n }\r\n }\r\n\r\n // Handle trailing array or object\r\n if (isInArray) {\r\n frontmatter[currentKey] = currentArray;\r\n }\r\n if (isInObject) {\r\n frontmatter[objectKey] = currentObject;\r\n }\r\n\r\n return { frontmatter, body: body.trim() };\r\n}\r\n\r\n/**\r\n * Find agent definition file by agent type/name\r\n */\r\nasync function findAgentFile(agentType: string, baseDir: string = '.claude/agents'): Promise<string | null> {\r\n // Normalize agent type (handle both kebab-case and underscores)\r\n const normalizedType = agentType.toLowerCase().replace(/_/g, '-');\r\n\r\n // Search patterns (in order of priority)\r\n const patterns = [\r\n // Exact match in any subdirectory\r\n `${baseDir}/**/${normalizedType}.md`,\r\n // Match with different casing\r\n `${baseDir}/**/*${normalizedType}*.md`,\r\n ];\r\n\r\n for (const pattern of patterns) {\r\n const files = await glob(pattern, { nodir: true, absolute: true });\r\n if (files.length > 0) {\r\n // Prefer exact match over partial match\r\n const exactMatch = files.find(f => {\r\n const basename = path.basename(f, '.md').toLowerCase();\r\n return basename === normalizedType;\r\n });\r\n return exactMatch || files[0];\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Parse agent definition from file\r\n */\r\nexport async function parseAgentDefinition(agentType: string): Promise<AgentDefinition> {\r\n // Find agent file\r\n const filePath = await findAgentFile(agentType);\r\n\r\n if (!filePath) {\r\n throw new Error(`Agent definition not found: ${agentType}`);\r\n }\r\n\r\n // Read file content\r\n const content = await fs.readFile(filePath, 'utf-8');\r\n\r\n // Parse frontmatter and body\r\n const { frontmatter, body } = parseFrontmatter(content);\r\n\r\n // Extract category from path\r\n const relativePath = path.relative('.claude/agents', filePath);\r\n const category = relativePath.includes('/')\r\n ? relativePath.split('/')[0]\r\n : undefined;\r\n\r\n // Build agent definition\r\n const definition: AgentDefinition = {\r\n name: frontmatter.name || agentType,\r\n description: frontmatter.description || '',\r\n tools: Array.isArray(frontmatter.tools) ? frontmatter.tools : [],\r\n model: frontmatter.model || 'haiku',\r\n type: frontmatter.type,\r\n color: frontmatter.color,\r\n acl_level: frontmatter.acl_level ? parseInt(String(frontmatter.acl_level), 10) : undefined,\r\n capabilities: frontmatter.capabilities,\r\n validation_hooks: frontmatter.validation_hooks,\r\n lifecycle: frontmatter.lifecycle,\r\n content: body,\r\n filePath,\r\n category,\r\n };\r\n\r\n return definition;\r\n}\r\n\r\n/**\r\n * List all available agent definitions\r\n */\r\nexport async function listAgentDefinitions(baseDir: string = '.claude/agents'): Promise<string[]> {\r\n const pattern = `${baseDir}/**/*.md`;\r\n const files = await glob(pattern, { nodir: true });\r\n\r\n return files.map(f => path.basename(f, '.md'));\r\n}\r\n\r\n/**\r\n * Check if agent definition includes CFN Loop protocol\r\n */\r\nexport function hasCFNLoopProtocol(definition: AgentDefinition): boolean {\r\n const content = definition.content.toLowerCase();\r\n return (\r\n content.includes('cfn loop') &&\r\n content.includes('redis completion protocol') ||\r\n content.includes('invoke-waiting-mode.sh')\r\n );\r\n}\r\n"],"names":["fs","path","glob","parseFrontmatter","content","frontmatterRegex","match","frontmatter","body","yamlContent","lines","split","currentKey","currentArray","isInArray","isInObject","currentObject","objectKey","line","trimmed","trim","startsWith","push","substring","objKey","objValueParts","objValue","join","replace","colonIndex","indexOf","key","value","cleanValue","existingValue","findAgentFile","agentType","baseDir","normalizedType","toLowerCase","patterns","pattern","files","nodir","absolute","length","exactMatch","find","f","basename","parseAgentDefinition","filePath","Error","readFile","relativePath","relative","category","includes","undefined","definition","name","description","tools","Array","isArray","model","type","color","acl_level","parseInt","String","capabilities","validation_hooks","lifecycle","listAgentDefinitions","map","hasCFNLoopProtocol"],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Executor
|
|
3
|
+
*
|
|
4
|
+
* Executes CLI-spawned agents by:
|
|
5
|
+
* 1. Checking custom routing configuration (z.ai vs Anthropic)
|
|
6
|
+
* 2. Invoking the appropriate API
|
|
7
|
+
* 3. Managing agent lifecycle and output
|
|
8
|
+
*/ import { spawn } from 'child_process';
|
|
9
|
+
import { getAgentId } from './agent-prompt-builder.js';
|
|
10
|
+
import { buildCLIAgentSystemPrompt, loadContextFromEnv } from './cli-agent-context.js';
|
|
11
|
+
import fs from 'fs/promises';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import os from 'os';
|
|
14
|
+
/**
|
|
15
|
+
* Check if custom routing (z.ai) is enabled
|
|
16
|
+
*/ async function isCustomRoutingEnabled() {
|
|
17
|
+
// Check environment variable
|
|
18
|
+
if (process.env.CLAUDE_API_PROVIDER === 'zai') {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Check config file (.claude/config/api-provider.json)
|
|
22
|
+
try {
|
|
23
|
+
const configPath = path.join('.claude', 'config', 'api-provider.json');
|
|
24
|
+
const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
|
|
25
|
+
return config.provider === 'zai' || config.provider === 'z.ai';
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get API provider configuration
|
|
32
|
+
*/ async function getAPIProvider() {
|
|
33
|
+
const customEnabled = await isCustomRoutingEnabled();
|
|
34
|
+
return customEnabled ? 'zai' : 'anthropic';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute agent using direct API calls
|
|
38
|
+
*/ async function executeViaAPI(definition, prompt, context) {
|
|
39
|
+
const agentId = getAgentId(definition, context);
|
|
40
|
+
console.log(`[agent-executor] Executing agent via API: ${definition.name}`);
|
|
41
|
+
console.log(`[agent-executor] Agent ID: ${agentId}`);
|
|
42
|
+
console.log(`[agent-executor] Model: ${definition.model}`);
|
|
43
|
+
console.log('');
|
|
44
|
+
try {
|
|
45
|
+
// Build system prompt with natural language context (Phase 1 enhancement)
|
|
46
|
+
console.log('[agent-executor] Building system prompt with context...');
|
|
47
|
+
const contextOptions = loadContextFromEnv();
|
|
48
|
+
// Override agent type with definition name
|
|
49
|
+
contextOptions.agentType = definition.name;
|
|
50
|
+
// Override iteration/taskId if provided in context
|
|
51
|
+
if (context.taskId) contextOptions.taskId = context.taskId;
|
|
52
|
+
if (context.iteration) contextOptions.iteration = context.iteration;
|
|
53
|
+
const systemPrompt = await buildCLIAgentSystemPrompt(contextOptions);
|
|
54
|
+
console.log('[agent-executor] System prompt built successfully');
|
|
55
|
+
console.log('');
|
|
56
|
+
// Dynamic import to avoid bundling issues
|
|
57
|
+
const { executeAgentAPI } = await import('./anthropic-client.js');
|
|
58
|
+
const result = await executeAgentAPI(definition.name, agentId, definition.model, prompt, systemPrompt);
|
|
59
|
+
return {
|
|
60
|
+
success: result.success,
|
|
61
|
+
agentId,
|
|
62
|
+
output: result.output,
|
|
63
|
+
error: result.error,
|
|
64
|
+
exitCode: result.success ? 0 : 1
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('[agent-executor] API execution failed:', error);
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
agentId,
|
|
71
|
+
error: error instanceof Error ? error.message : String(error),
|
|
72
|
+
exitCode: 1
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Execute agent using shell script (fallback/simulation)
|
|
78
|
+
*/ async function executeViaScript(definition, prompt, context) {
|
|
79
|
+
const agentId = getAgentId(definition, context);
|
|
80
|
+
// Write prompt to temporary file
|
|
81
|
+
const tmpDir = os.tmpdir();
|
|
82
|
+
const promptFile = path.join(tmpDir, `agent-${agentId}-${Date.now()}.md`);
|
|
83
|
+
await fs.writeFile(promptFile, prompt, 'utf-8');
|
|
84
|
+
console.log(`[agent-executor] Executing agent via script: ${definition.name}`);
|
|
85
|
+
console.log(`[agent-executor] Agent ID: ${agentId}`);
|
|
86
|
+
console.log(`[agent-executor] Model: ${definition.model}`);
|
|
87
|
+
console.log(`[agent-executor] Prompt file: ${promptFile}`);
|
|
88
|
+
return new Promise((resolve)=>{
|
|
89
|
+
const scriptPath = path.join('.claude', 'skills', 'agent-execution', 'execute-agent.sh');
|
|
90
|
+
// Build environment variables
|
|
91
|
+
const env = {
|
|
92
|
+
...process.env,
|
|
93
|
+
AGENT_TYPE: definition.name,
|
|
94
|
+
AGENT_ID: agentId,
|
|
95
|
+
AGENT_MODEL: definition.model,
|
|
96
|
+
AGENT_TOOLS: definition.tools.join(','),
|
|
97
|
+
TASK_ID: context.taskId || '',
|
|
98
|
+
ITERATION: String(context.iteration || 1),
|
|
99
|
+
MODE: context.mode || 'cli',
|
|
100
|
+
PROMPT_FILE: promptFile
|
|
101
|
+
};
|
|
102
|
+
// Check if execute script exists
|
|
103
|
+
fs.access(scriptPath).then(()=>{
|
|
104
|
+
// Use execution script
|
|
105
|
+
const proc = spawn('bash', [
|
|
106
|
+
scriptPath
|
|
107
|
+
], {
|
|
108
|
+
env,
|
|
109
|
+
stdio: 'inherit'
|
|
110
|
+
});
|
|
111
|
+
proc.on('exit', (code)=>{
|
|
112
|
+
resolve({
|
|
113
|
+
success: code === 0,
|
|
114
|
+
agentId,
|
|
115
|
+
exitCode: code || 0
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
proc.on('error', (err)=>{
|
|
119
|
+
resolve({
|
|
120
|
+
success: false,
|
|
121
|
+
agentId,
|
|
122
|
+
error: err.message,
|
|
123
|
+
exitCode: 1
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}).catch(()=>{
|
|
127
|
+
// Fallback: Print prompt
|
|
128
|
+
console.log('\n=== Agent Prompt ===');
|
|
129
|
+
console.log(prompt.substring(0, 500) + '...');
|
|
130
|
+
console.log('\n[agent-executor] Execution script not found');
|
|
131
|
+
console.log('[agent-executor] Using simulation mode\n');
|
|
132
|
+
resolve({
|
|
133
|
+
success: true,
|
|
134
|
+
agentId,
|
|
135
|
+
output: prompt,
|
|
136
|
+
exitCode: 0
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Main agent execution function
|
|
143
|
+
*/ export async function executeAgent(definition, prompt, context, options = {}) {
|
|
144
|
+
const method = options.method || 'auto';
|
|
145
|
+
// Auto-select execution method
|
|
146
|
+
if (method === 'auto') {
|
|
147
|
+
// Try API execution first, fallback to script if API key not available
|
|
148
|
+
try {
|
|
149
|
+
return await executeViaAPI(definition, prompt, context);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error instanceof Error && error.message.includes('API key not found')) {
|
|
152
|
+
console.log('[agent-executor] API key not found, using script fallback');
|
|
153
|
+
return executeViaScript(definition, prompt, context);
|
|
154
|
+
}
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (method === 'api') {
|
|
159
|
+
return executeViaAPI(definition, prompt, context);
|
|
160
|
+
}
|
|
161
|
+
return executeViaScript(definition, prompt, context);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Write agent output to file for debugging
|
|
165
|
+
*/ export async function saveAgentOutput(agentId, output, outputDir = '.claude/tmp/agent-output') {
|
|
166
|
+
await fs.mkdir(outputDir, {
|
|
167
|
+
recursive: true
|
|
168
|
+
});
|
|
169
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
170
|
+
const filename = `${agentId}-${timestamp}.txt`;
|
|
171
|
+
const filepath = path.join(outputDir, filename);
|
|
172
|
+
await fs.writeFile(filepath, output, 'utf-8');
|
|
173
|
+
return filepath;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//# sourceMappingURL=agent-executor.js.map
|