aided-dev 1.0.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/README.md +615 -0
- package/bin/aidev.js +11 -0
- package/dist/agent-creator/creator.d.ts +22 -0
- package/dist/agent-creator/creator.js +393 -0
- package/dist/agent-creator/index.d.ts +1 -0
- package/dist/agent-creator/index.js +1 -0
- package/dist/bmad/index.d.ts +1 -0
- package/dist/bmad/index.js +1 -0
- package/dist/bmad/loader.d.ts +68 -0
- package/dist/bmad/loader.js +482 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +257 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +48 -0
- package/dist/discovery/detector.d.ts +12 -0
- package/dist/discovery/detector.js +272 -0
- package/dist/discovery/documents.d.ts +25 -0
- package/dist/discovery/documents.js +154 -0
- package/dist/discovery/index.d.ts +2 -0
- package/dist/discovery/index.js +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/orchestrator/index.d.ts +3 -0
- package/dist/orchestrator/index.js +3 -0
- package/dist/orchestrator/orchestrator.d.ts +40 -0
- package/dist/orchestrator/orchestrator.js +386 -0
- package/dist/orchestrator/planner.d.ts +44 -0
- package/dist/orchestrator/planner.js +355 -0
- package/dist/postinstall.d.ts +1 -0
- package/dist/postinstall.js +49 -0
- package/package.json +70 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
export const PROJECT_DOC_PATTERNS = {
|
|
5
|
+
brownfieldArchitecture: '{project}-brownfield-architecture.md',
|
|
6
|
+
integrationMap: '{project}-integration-map.md',
|
|
7
|
+
systemAnalysis: '{project}-system-analysis.md',
|
|
8
|
+
};
|
|
9
|
+
const DOC_LOCATIONS = ['', 'docs/', 'doc/', 'documentation/', '.aidev/'];
|
|
10
|
+
export async function detectProjectName(repoPath) {
|
|
11
|
+
const packageJsonPath = path.join(repoPath, 'package.json');
|
|
12
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
13
|
+
try {
|
|
14
|
+
const pkg = await fs.readJson(packageJsonPath);
|
|
15
|
+
if (pkg.name) {
|
|
16
|
+
return pkg.name.replace('@', '').replace('/', '-');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const pyprojectPath = path.join(repoPath, 'pyproject.toml');
|
|
23
|
+
if (await fs.pathExists(pyprojectPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const content = await fs.readFile(pyprojectPath, 'utf-8');
|
|
26
|
+
const nameMatch = content.match(/name\s*=\s*["']([^"']+)["']/);
|
|
27
|
+
if (nameMatch) {
|
|
28
|
+
return nameMatch[1];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const cargoPath = path.join(repoPath, 'Cargo.toml');
|
|
35
|
+
if (await fs.pathExists(cargoPath)) {
|
|
36
|
+
try {
|
|
37
|
+
const content = await fs.readFile(cargoPath, 'utf-8');
|
|
38
|
+
const nameMatch = content.match(/name\s*=\s*["']([^"']+)["']/);
|
|
39
|
+
if (nameMatch) {
|
|
40
|
+
return nameMatch[1];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const goModPath = path.join(repoPath, 'go.mod');
|
|
47
|
+
if (await fs.pathExists(goModPath)) {
|
|
48
|
+
try {
|
|
49
|
+
const content = await fs.readFile(goModPath, 'utf-8');
|
|
50
|
+
const moduleMatch = content.match(/module\s+(\S+)/);
|
|
51
|
+
if (moduleMatch) {
|
|
52
|
+
const parts = moduleMatch[1].split('/');
|
|
53
|
+
return parts[parts.length - 1];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return path.basename(repoPath);
|
|
60
|
+
}
|
|
61
|
+
export async function findProjectNameFromDocs(repoPath) {
|
|
62
|
+
const patterns = [
|
|
63
|
+
'*-brownfield-architecture.md',
|
|
64
|
+
'*-integration-map.md',
|
|
65
|
+
'*-system-analysis.md',
|
|
66
|
+
];
|
|
67
|
+
for (const location of DOC_LOCATIONS) {
|
|
68
|
+
const searchPath = path.join(repoPath, location);
|
|
69
|
+
if (!(await fs.pathExists(searchPath)))
|
|
70
|
+
continue;
|
|
71
|
+
for (const pattern of patterns) {
|
|
72
|
+
const matches = await glob(pattern, { cwd: searchPath });
|
|
73
|
+
if (matches.length > 0) {
|
|
74
|
+
const filename = path.basename(matches[0], '.md');
|
|
75
|
+
for (const suffix of ['-brownfield-architecture', '-integration-map', '-system-analysis']) {
|
|
76
|
+
if (filename.endsWith(suffix)) {
|
|
77
|
+
return filename.slice(0, -suffix.length);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
export async function discoverProjectDocuments(repoPath) {
|
|
86
|
+
let projectName = await detectProjectName(repoPath);
|
|
87
|
+
if (!projectName) {
|
|
88
|
+
projectName = await findProjectNameFromDocs(repoPath);
|
|
89
|
+
}
|
|
90
|
+
if (!projectName) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const docs = {
|
|
94
|
+
projectName,
|
|
95
|
+
};
|
|
96
|
+
for (const location of DOC_LOCATIONS) {
|
|
97
|
+
const basePath = path.join(repoPath, location);
|
|
98
|
+
if (!(await fs.pathExists(basePath)))
|
|
99
|
+
continue;
|
|
100
|
+
if (!docs.brownfieldArchitecture) {
|
|
101
|
+
const archPath = path.join(basePath, `${projectName}-brownfield-architecture.md`);
|
|
102
|
+
if (await fs.pathExists(archPath)) {
|
|
103
|
+
docs.brownfieldArchitecture = {
|
|
104
|
+
path: archPath,
|
|
105
|
+
content: await fs.readFile(archPath, 'utf-8'),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!docs.integrationMap) {
|
|
110
|
+
const intPath = path.join(basePath, `${projectName}-integration-map.md`);
|
|
111
|
+
if (await fs.pathExists(intPath)) {
|
|
112
|
+
docs.integrationMap = {
|
|
113
|
+
path: intPath,
|
|
114
|
+
content: await fs.readFile(intPath, 'utf-8'),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (!docs.systemAnalysis) {
|
|
119
|
+
const sysPath = path.join(basePath, `${projectName}-system-analysis.md`);
|
|
120
|
+
if (await fs.pathExists(sysPath)) {
|
|
121
|
+
docs.systemAnalysis = {
|
|
122
|
+
path: sysPath,
|
|
123
|
+
content: await fs.readFile(sysPath, 'utf-8'),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (docs.brownfieldArchitecture || docs.integrationMap || docs.systemAnalysis) {
|
|
129
|
+
return docs;
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
export function hasDocuments(docs) {
|
|
134
|
+
if (!docs)
|
|
135
|
+
return false;
|
|
136
|
+
return !!(docs.brownfieldArchitecture || docs.integrationMap || docs.systemAnalysis);
|
|
137
|
+
}
|
|
138
|
+
export function formatDocumentsForPrompt(docs) {
|
|
139
|
+
const parts = [];
|
|
140
|
+
parts.push(`## Project Source of Truth: ${docs.projectName}`);
|
|
141
|
+
if (docs.brownfieldArchitecture) {
|
|
142
|
+
parts.push('\n### Brownfield Architecture');
|
|
143
|
+
parts.push(docs.brownfieldArchitecture.content);
|
|
144
|
+
}
|
|
145
|
+
if (docs.integrationMap) {
|
|
146
|
+
parts.push('\n### Integration Map');
|
|
147
|
+
parts.push(docs.integrationMap.content);
|
|
148
|
+
}
|
|
149
|
+
if (docs.systemAnalysis) {
|
|
150
|
+
parts.push('\n### System Analysis');
|
|
151
|
+
parts.push(docs.systemAnalysis.content);
|
|
152
|
+
}
|
|
153
|
+
return parts.join('\n');
|
|
154
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Orchestrator, TaskPlanner, AGENT_CAPABILITIES, type OrchestratorOptions, type WorkflowState, type ExecutionPlan, type PlannedStep, type TaskType, } from './orchestrator/index.js';
|
|
2
|
+
export { BMADLoader, getLoader, findBMADPath, buildSystemPrompt, type AgentConfig, type BMADAgent, type AgentMetadata, type AgentPersona, } from './bmad/index.js';
|
|
3
|
+
export { discoverProjectDocuments, detectStack, formatDocumentsForPrompt, formatStack, PROJECT_DOC_PATTERNS, type ProjectDocuments, type ProjectStack, } from './discovery/index.js';
|
|
4
|
+
export { getConfig, getApiKey, setApiKey, hasApiKey, getConfigPath, } from './config.js';
|
|
5
|
+
export { AgentCreator, quickCreateAgent, type AgentCreatorOptions, } from './agent-creator/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Orchestrator, TaskPlanner, AGENT_CAPABILITIES, } from './orchestrator/index.js';
|
|
2
|
+
export { BMADLoader, getLoader, findBMADPath, buildSystemPrompt, } from './bmad/index.js';
|
|
3
|
+
export { discoverProjectDocuments, detectStack, formatDocumentsForPrompt, formatStack, PROJECT_DOC_PATTERNS, } from './discovery/index.js';
|
|
4
|
+
export { getConfig, getApiKey, setApiKey, hasApiKey, getConfigPath, } from './config.js';
|
|
5
|
+
export { AgentCreator, quickCreateAgent, } from './agent-creator/index.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { Orchestrator, type OrchestratorOptions, type WorkflowState } from './orchestrator.js';
|
|
2
|
+
export { TaskPlanner, AGENT_CAPABILITIES, type ExecutionPlan, type PlannedStep, type TaskType, } from './planner.js';
|
|
3
|
+
export { BMADLoader, getLoader, type AgentConfig } from '../bmad/index.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type ProjectDocuments, type ProjectStack } from '../discovery/index.js';
|
|
2
|
+
import { type ExecutionPlan } from './planner.js';
|
|
3
|
+
export interface OrchestratorOptions {
|
|
4
|
+
repoPath: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
skipPlanning?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface WorkflowState {
|
|
10
|
+
task: string;
|
|
11
|
+
repoPath: string;
|
|
12
|
+
projectDocuments?: ProjectDocuments;
|
|
13
|
+
stack?: ProjectStack;
|
|
14
|
+
plan?: ExecutionPlan;
|
|
15
|
+
outputs: Map<string, string>;
|
|
16
|
+
errors: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare class Orchestrator {
|
|
19
|
+
private client;
|
|
20
|
+
private model;
|
|
21
|
+
private repoPath;
|
|
22
|
+
private verbose;
|
|
23
|
+
private skipPlanning;
|
|
24
|
+
private bmadLoader;
|
|
25
|
+
private agents;
|
|
26
|
+
private planner;
|
|
27
|
+
constructor(options: OrchestratorOptions);
|
|
28
|
+
private loadAgents;
|
|
29
|
+
private getAgent;
|
|
30
|
+
run(task: string): Promise<WorkflowState>;
|
|
31
|
+
private phaseDiscover;
|
|
32
|
+
private phasePlanning;
|
|
33
|
+
private executeplan;
|
|
34
|
+
private executeStep;
|
|
35
|
+
private buildContext;
|
|
36
|
+
private formatOutputTitle;
|
|
37
|
+
private buildStepPrompt;
|
|
38
|
+
private extractTextContent;
|
|
39
|
+
private printSummary;
|
|
40
|
+
}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { discoverProjectDocuments, detectStack, formatDocumentsForPrompt, formatStack, } from '../discovery/index.js';
|
|
5
|
+
import { getLoader } from '../bmad/index.js';
|
|
6
|
+
import { getApiKey } from '../config.js';
|
|
7
|
+
import { TaskPlanner, AGENT_CAPABILITIES, } from './planner.js';
|
|
8
|
+
export class Orchestrator {
|
|
9
|
+
client;
|
|
10
|
+
model;
|
|
11
|
+
repoPath;
|
|
12
|
+
verbose;
|
|
13
|
+
skipPlanning;
|
|
14
|
+
bmadLoader;
|
|
15
|
+
agents = new Map();
|
|
16
|
+
planner = null;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
const apiKey = getApiKey();
|
|
19
|
+
if (!apiKey) {
|
|
20
|
+
throw new Error('Anthropic API key not found. Run `aidev config --api-key <key>` or set ANTHROPIC_API_KEY environment variable.');
|
|
21
|
+
}
|
|
22
|
+
this.client = new Anthropic({ apiKey });
|
|
23
|
+
this.model = options.model || 'claude-sonnet-4-20250514';
|
|
24
|
+
this.repoPath = options.repoPath;
|
|
25
|
+
this.verbose = options.verbose || false;
|
|
26
|
+
this.skipPlanning = options.skipPlanning || false;
|
|
27
|
+
this.bmadLoader = getLoader();
|
|
28
|
+
}
|
|
29
|
+
async loadAgents() {
|
|
30
|
+
const allAgentNames = await this.bmadLoader.listAgents();
|
|
31
|
+
const coreAgents = ['analyst', 'architect', 'dev', 'tea', 'pm', 'sm', 'tech-writer', 'ux-designer'];
|
|
32
|
+
const agentNames = [...new Set([...allAgentNames, ...coreAgents])];
|
|
33
|
+
this.agents = await this.bmadLoader.loadAgents(agentNames);
|
|
34
|
+
if (this.bmadLoader.isAvailable()) {
|
|
35
|
+
console.log(chalk.dim(` BMAD-METHOD: ${this.bmadLoader.getPath()}`));
|
|
36
|
+
console.log(chalk.dim(` Loaded ${this.agents.size} agents`));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.log(chalk.dim(' BMAD-METHOD: Using fallback agents'));
|
|
40
|
+
}
|
|
41
|
+
this.planner = new TaskPlanner(this.client, this.model, this.agents);
|
|
42
|
+
}
|
|
43
|
+
getAgent(name) {
|
|
44
|
+
const nameMap = {
|
|
45
|
+
analyst: 'analyst',
|
|
46
|
+
architect: 'architect',
|
|
47
|
+
developer: 'dev',
|
|
48
|
+
dev: 'dev',
|
|
49
|
+
qa: 'tea',
|
|
50
|
+
tea: 'tea',
|
|
51
|
+
'tech-writer': 'tech-writer',
|
|
52
|
+
'ux-designer': 'ux-designer',
|
|
53
|
+
pm: 'pm',
|
|
54
|
+
sm: 'sm',
|
|
55
|
+
};
|
|
56
|
+
const bmadName = nameMap[name] || name;
|
|
57
|
+
return this.agents.get(bmadName);
|
|
58
|
+
}
|
|
59
|
+
async run(task) {
|
|
60
|
+
const state = {
|
|
61
|
+
task,
|
|
62
|
+
repoPath: this.repoPath,
|
|
63
|
+
outputs: new Map(),
|
|
64
|
+
errors: [],
|
|
65
|
+
};
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(chalk.bgBlue.white(' AI Dev Team - Smart Orchestration '));
|
|
68
|
+
console.log(chalk.dim(`Task: ${task}`));
|
|
69
|
+
console.log('');
|
|
70
|
+
await this.loadAgents();
|
|
71
|
+
await this.phaseDiscover(state);
|
|
72
|
+
if (state.errors.length > 0) {
|
|
73
|
+
this.printSummary(state);
|
|
74
|
+
return state;
|
|
75
|
+
}
|
|
76
|
+
await this.phasePlanning(state);
|
|
77
|
+
if (state.errors.length > 0 || !state.plan) {
|
|
78
|
+
this.printSummary(state);
|
|
79
|
+
return state;
|
|
80
|
+
}
|
|
81
|
+
await this.executeplan(state);
|
|
82
|
+
this.printSummary(state);
|
|
83
|
+
return state;
|
|
84
|
+
}
|
|
85
|
+
async phaseDiscover(state) {
|
|
86
|
+
const spinner = ora('Discovering project context...').start();
|
|
87
|
+
try {
|
|
88
|
+
state.stack = await detectStack(this.repoPath);
|
|
89
|
+
spinner.text = `Detected: ${state.stack.language}`;
|
|
90
|
+
state.projectDocuments = await discoverProjectDocuments(this.repoPath);
|
|
91
|
+
spinner.succeed(chalk.green('Discovery complete'));
|
|
92
|
+
console.log(chalk.dim(` Language: ${state.stack.language}`));
|
|
93
|
+
if (state.stack.framework) {
|
|
94
|
+
console.log(chalk.dim(` Framework: ${state.stack.framework}`));
|
|
95
|
+
}
|
|
96
|
+
if (state.projectDocuments) {
|
|
97
|
+
const docCount = [
|
|
98
|
+
state.projectDocuments.brownfieldArchitecture,
|
|
99
|
+
state.projectDocuments.integrationMap,
|
|
100
|
+
state.projectDocuments.systemAnalysis,
|
|
101
|
+
].filter(Boolean).length;
|
|
102
|
+
console.log(chalk.green(` Found ${docCount} source-of-truth document(s)`));
|
|
103
|
+
}
|
|
104
|
+
console.log('');
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
spinner.fail(chalk.red('Discovery failed'));
|
|
108
|
+
state.errors.push(`Discovery error: ${error}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async phasePlanning(state) {
|
|
112
|
+
if (!this.planner) {
|
|
113
|
+
state.errors.push('Planner not initialized');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const spinner = ora('Analyzing task and creating execution plan...').start();
|
|
117
|
+
try {
|
|
118
|
+
const plan = await this.planner.createPlan(state.task, {
|
|
119
|
+
stack: state.stack,
|
|
120
|
+
hasProjectDocs: !!state.projectDocuments,
|
|
121
|
+
existingCode: state.stack?.language !== 'unknown',
|
|
122
|
+
});
|
|
123
|
+
const validation = this.planner.validatePlan(plan);
|
|
124
|
+
if (!validation.valid) {
|
|
125
|
+
spinner.warn(chalk.yellow('Plan has issues, adjusting...'));
|
|
126
|
+
if (this.verbose) {
|
|
127
|
+
validation.errors.forEach((e) => console.log(chalk.dim(` - ${e}`)));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
state.plan = plan;
|
|
131
|
+
spinner.succeed(chalk.green('Execution plan created'));
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log(chalk.cyan(`Task Type: ${plan.taskType}`));
|
|
134
|
+
console.log(chalk.cyan(`Complexity: ${plan.estimatedComplexity}`));
|
|
135
|
+
console.log(chalk.dim(`Reasoning: ${plan.reasoning}`));
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(chalk.bold('Execution Plan:'));
|
|
138
|
+
for (let i = 0; i < plan.steps.length; i++) {
|
|
139
|
+
const step = plan.steps[i];
|
|
140
|
+
const agent = this.getAgent(step.agent);
|
|
141
|
+
const agentInfo = AGENT_CAPABILITIES[step.agent];
|
|
142
|
+
const icon = agent?.icon || '🤖';
|
|
143
|
+
const name = agent?.name || agentInfo?.name || step.agent;
|
|
144
|
+
const priorityIcon = step.priority === 'required' ? '●' :
|
|
145
|
+
step.priority === 'recommended' ? '◐' : '○';
|
|
146
|
+
console.log(chalk.dim(` ${i + 1}. ${priorityIcon} ${icon} ${name}: ${step.action}`));
|
|
147
|
+
}
|
|
148
|
+
console.log('');
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
spinner.fail(chalk.red('Planning failed'));
|
|
152
|
+
state.errors.push(`Planning error: ${error}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async executeplan(state) {
|
|
156
|
+
if (!state.plan)
|
|
157
|
+
return;
|
|
158
|
+
for (const step of state.plan.steps) {
|
|
159
|
+
const missingDeps = step.dependsOn.filter((dep) => !state.outputs.has(dep));
|
|
160
|
+
if (missingDeps.length > 0 && step.priority === 'required') {
|
|
161
|
+
state.errors.push(`Cannot execute ${step.outputKey}: missing dependencies ${missingDeps.join(', ')}`);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
await this.executeStep(step, state);
|
|
165
|
+
if (step.priority === 'required' &&
|
|
166
|
+
!state.outputs.has(step.outputKey) &&
|
|
167
|
+
state.errors.length > 0) {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async executeStep(step, state) {
|
|
173
|
+
const agent = this.getAgent(step.agent);
|
|
174
|
+
if (!agent) {
|
|
175
|
+
if (step.priority === 'required') {
|
|
176
|
+
state.errors.push(`Agent '${step.agent}' not available`);
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const spinner = ora(`${agent.icon} ${agent.name} (${agent.title}): ${step.action}...`).start();
|
|
181
|
+
try {
|
|
182
|
+
const context = this.buildContext(state, step);
|
|
183
|
+
const prompt = this.buildStepPrompt(step, state);
|
|
184
|
+
const response = await this.client.messages.create({
|
|
185
|
+
model: this.model,
|
|
186
|
+
max_tokens: 8192,
|
|
187
|
+
system: agent.systemPrompt,
|
|
188
|
+
messages: [
|
|
189
|
+
{
|
|
190
|
+
role: 'user',
|
|
191
|
+
content: `${context}\n\n${prompt}`,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
});
|
|
195
|
+
const output = this.extractTextContent(response);
|
|
196
|
+
state.outputs.set(step.outputKey, output);
|
|
197
|
+
spinner.succeed(chalk.green(`${agent.icon} ${step.action} complete`));
|
|
198
|
+
if (this.verbose) {
|
|
199
|
+
console.log(chalk.dim(`\n--- ${step.outputKey} Output ---`));
|
|
200
|
+
console.log(chalk.dim(output.substring(0, 500) + '...'));
|
|
201
|
+
console.log('');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
const errorMsg = `${step.action} failed: ${error}`;
|
|
206
|
+
if (step.priority === 'optional') {
|
|
207
|
+
spinner.warn(chalk.yellow(`${agent.icon} ${step.action} skipped (optional)`));
|
|
208
|
+
}
|
|
209
|
+
else if (step.priority === 'recommended') {
|
|
210
|
+
spinner.warn(chalk.yellow(`${agent.icon} ${step.action} failed (non-blocking)`));
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
spinner.fail(chalk.red(`${agent.icon} ${step.action} failed`));
|
|
214
|
+
state.errors.push(errorMsg);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
buildContext(state, step) {
|
|
219
|
+
const parts = [];
|
|
220
|
+
if (state.stack) {
|
|
221
|
+
parts.push('## Project Stack');
|
|
222
|
+
parts.push(formatStack(state.stack));
|
|
223
|
+
}
|
|
224
|
+
if (state.projectDocuments) {
|
|
225
|
+
parts.push('\n' + formatDocumentsForPrompt(state.projectDocuments));
|
|
226
|
+
}
|
|
227
|
+
for (const dep of step.dependsOn) {
|
|
228
|
+
const depOutput = state.outputs.get(dep);
|
|
229
|
+
if (depOutput) {
|
|
230
|
+
parts.push(`\n## ${this.formatOutputTitle(dep)}`);
|
|
231
|
+
parts.push(depOutput);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return parts.join('\n');
|
|
235
|
+
}
|
|
236
|
+
formatOutputTitle(key) {
|
|
237
|
+
return key
|
|
238
|
+
.replace(/_/g, ' ')
|
|
239
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
240
|
+
}
|
|
241
|
+
buildStepPrompt(step, state) {
|
|
242
|
+
const task = state.task;
|
|
243
|
+
const promptTemplates = {
|
|
244
|
+
prd: `## Task
|
|
245
|
+
${task}
|
|
246
|
+
|
|
247
|
+
## Instructions
|
|
248
|
+
Create a Product Requirements Document (PRD) for this task. Include:
|
|
249
|
+
1. Project overview and goals
|
|
250
|
+
2. Core features (prioritized)
|
|
251
|
+
3. User stories with acceptance criteria
|
|
252
|
+
4. Out of scope items
|
|
253
|
+
5. Success metrics
|
|
254
|
+
6. Technical constraints
|
|
255
|
+
|
|
256
|
+
Respond in a structured markdown format.`,
|
|
257
|
+
architecture: `## Task
|
|
258
|
+
${task}
|
|
259
|
+
|
|
260
|
+
## Instructions
|
|
261
|
+
Design the technical architecture for this project. Include:
|
|
262
|
+
1. Tech stack selection with justification
|
|
263
|
+
2. File/folder structure
|
|
264
|
+
3. API design (endpoints, methods, request/response)
|
|
265
|
+
4. Data models
|
|
266
|
+
5. Framework patterns to follow
|
|
267
|
+
6. Configuration requirements
|
|
268
|
+
|
|
269
|
+
Consider the existing project context and follow established patterns.
|
|
270
|
+
Respond in a structured markdown format with code blocks where appropriate.`,
|
|
271
|
+
implementation: `## Task
|
|
272
|
+
${task}
|
|
273
|
+
|
|
274
|
+
## Instructions
|
|
275
|
+
Implement the code according to the specifications provided.
|
|
276
|
+
- Follow the architecture/design if provided
|
|
277
|
+
- Implement all required functionality
|
|
278
|
+
- Include proper error handling
|
|
279
|
+
- Add inline documentation
|
|
280
|
+
- Follow framework conventions
|
|
281
|
+
|
|
282
|
+
Output each file with its path and complete code.`,
|
|
283
|
+
tests: `## Task
|
|
284
|
+
${task}
|
|
285
|
+
|
|
286
|
+
## Instructions
|
|
287
|
+
Generate comprehensive tests for the implementation:
|
|
288
|
+
- Unit tests for core functions
|
|
289
|
+
- Integration tests for API endpoints
|
|
290
|
+
- Edge cases and error scenarios
|
|
291
|
+
- Use appropriate test framework for the stack
|
|
292
|
+
|
|
293
|
+
Output test files with paths and complete test code.`,
|
|
294
|
+
fix: `## Task
|
|
295
|
+
${task}
|
|
296
|
+
|
|
297
|
+
## Instructions
|
|
298
|
+
Analyze and fix the reported issue:
|
|
299
|
+
1. Identify the root cause
|
|
300
|
+
2. Implement the fix
|
|
301
|
+
3. Ensure no regressions
|
|
302
|
+
4. Document the changes
|
|
303
|
+
|
|
304
|
+
Output the fixed code with explanations.`,
|
|
305
|
+
design: `## Task
|
|
306
|
+
${task}
|
|
307
|
+
|
|
308
|
+
## Instructions
|
|
309
|
+
Create a design document for this task:
|
|
310
|
+
1. Analyze current state
|
|
311
|
+
2. Propose improvements
|
|
312
|
+
3. Define the approach
|
|
313
|
+
4. List changes needed
|
|
314
|
+
|
|
315
|
+
Respond in a structured markdown format.`,
|
|
316
|
+
docs: `## Task
|
|
317
|
+
${task}
|
|
318
|
+
|
|
319
|
+
## Instructions
|
|
320
|
+
Create documentation for this task:
|
|
321
|
+
1. Overview and purpose
|
|
322
|
+
2. Usage instructions
|
|
323
|
+
3. API reference (if applicable)
|
|
324
|
+
4. Examples
|
|
325
|
+
5. Troubleshooting
|
|
326
|
+
|
|
327
|
+
Use clear, technical writing style.`,
|
|
328
|
+
analysis: `## Task
|
|
329
|
+
${task}
|
|
330
|
+
|
|
331
|
+
## Instructions
|
|
332
|
+
Analyze the requirements and provide:
|
|
333
|
+
1. Problem breakdown
|
|
334
|
+
2. Key considerations
|
|
335
|
+
3. Recommendations
|
|
336
|
+
4. Risks and mitigations
|
|
337
|
+
|
|
338
|
+
Be thorough and specific.`,
|
|
339
|
+
};
|
|
340
|
+
const templateKey = Object.keys(promptTemplates).find((key) => step.outputKey.includes(key) || step.action.toLowerCase().includes(key));
|
|
341
|
+
if (templateKey) {
|
|
342
|
+
return promptTemplates[templateKey];
|
|
343
|
+
}
|
|
344
|
+
return `## Task
|
|
345
|
+
${task}
|
|
346
|
+
|
|
347
|
+
## Your Action
|
|
348
|
+
${step.action}
|
|
349
|
+
|
|
350
|
+
## Instructions
|
|
351
|
+
${step.description}
|
|
352
|
+
|
|
353
|
+
Provide your output in a clear, structured format.`;
|
|
354
|
+
}
|
|
355
|
+
extractTextContent(response) {
|
|
356
|
+
return response.content
|
|
357
|
+
.filter((block) => block.type === 'text')
|
|
358
|
+
.map((block) => block.text)
|
|
359
|
+
.join('\n');
|
|
360
|
+
}
|
|
361
|
+
printSummary(state) {
|
|
362
|
+
console.log('');
|
|
363
|
+
if (state.errors.length > 0) {
|
|
364
|
+
console.log(chalk.red('Workflow completed with errors:'));
|
|
365
|
+
for (const error of state.errors) {
|
|
366
|
+
console.log(chalk.red(` - ${error}`));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
console.log(chalk.green('✓ Workflow complete!'));
|
|
371
|
+
}
|
|
372
|
+
if (state.outputs.size > 0) {
|
|
373
|
+
console.log('');
|
|
374
|
+
console.log(chalk.dim('Outputs generated:'));
|
|
375
|
+
for (const key of state.outputs.keys()) {
|
|
376
|
+
console.log(chalk.dim(` - ${this.formatOutputTitle(key)}`));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (state.plan) {
|
|
380
|
+
console.log('');
|
|
381
|
+
console.log(chalk.dim(`Task type: ${state.plan.taskType}`));
|
|
382
|
+
console.log(chalk.dim(`Complexity: ${state.plan.estimatedComplexity}`));
|
|
383
|
+
}
|
|
384
|
+
console.log('');
|
|
385
|
+
}
|
|
386
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import type { AgentConfig } from '../bmad/index.js';
|
|
3
|
+
export interface PlannedStep {
|
|
4
|
+
agent: string;
|
|
5
|
+
action: string;
|
|
6
|
+
description: string;
|
|
7
|
+
dependsOn: string[];
|
|
8
|
+
outputKey: string;
|
|
9
|
+
priority: 'required' | 'recommended' | 'optional';
|
|
10
|
+
}
|
|
11
|
+
export interface ExecutionPlan {
|
|
12
|
+
task: string;
|
|
13
|
+
taskType: TaskType;
|
|
14
|
+
summary: string;
|
|
15
|
+
steps: PlannedStep[];
|
|
16
|
+
estimatedComplexity: 'simple' | 'moderate' | 'complex';
|
|
17
|
+
reasoning: string;
|
|
18
|
+
}
|
|
19
|
+
export type TaskType = 'new_feature' | 'bug_fix' | 'refactor' | 'documentation' | 'testing' | 'code_review' | 'architecture' | 'analysis' | 'general';
|
|
20
|
+
export declare const AGENT_CAPABILITIES: Record<string, {
|
|
21
|
+
name: string;
|
|
22
|
+
capabilities: string[];
|
|
23
|
+
bestFor: string[];
|
|
24
|
+
}>;
|
|
25
|
+
export declare class TaskPlanner {
|
|
26
|
+
private client;
|
|
27
|
+
private model;
|
|
28
|
+
private availableAgents;
|
|
29
|
+
constructor(client: Anthropic, model: string, availableAgents: Map<string, AgentConfig>);
|
|
30
|
+
createPlan(task: string, context: {
|
|
31
|
+
stack?: {
|
|
32
|
+
language: string;
|
|
33
|
+
framework?: string;
|
|
34
|
+
};
|
|
35
|
+
hasProjectDocs: boolean;
|
|
36
|
+
existingCode: boolean;
|
|
37
|
+
}): Promise<ExecutionPlan>;
|
|
38
|
+
private buildAgentDescriptions;
|
|
39
|
+
private createDefaultPlan;
|
|
40
|
+
validatePlan(plan: ExecutionPlan): {
|
|
41
|
+
valid: boolean;
|
|
42
|
+
errors: string[];
|
|
43
|
+
};
|
|
44
|
+
}
|