claude-autopm 1.30.1 → 2.1.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/autopm/.claude/mcp/test-server.md +10 -0
- package/autopm/.claude/scripts/github/dependency-tracker.js +554 -0
- package/autopm/.claude/scripts/github/dependency-validator.js +545 -0
- package/autopm/.claude/scripts/github/dependency-visualizer.js +477 -0
- package/autopm/.claude/scripts/pm/lib/epic-discovery.js +119 -0
- package/autopm/.claude/scripts/pm/next.js +56 -58
- package/bin/autopm-poc.js +348 -0
- package/bin/autopm.js +6 -0
- package/lib/ai-providers/AbstractAIProvider.js +524 -0
- package/lib/ai-providers/ClaudeProvider.js +423 -0
- package/lib/ai-providers/TemplateProvider.js +432 -0
- package/lib/cli/commands/agent.js +206 -0
- package/lib/cli/commands/config.js +488 -0
- package/lib/cli/commands/prd.js +345 -0
- package/lib/cli/commands/task.js +206 -0
- package/lib/config/ConfigManager.js +531 -0
- package/lib/errors/AIProviderError.js +164 -0
- package/lib/services/AgentService.js +557 -0
- package/lib/services/EpicService.js +609 -0
- package/lib/services/PRDService.js +1003 -0
- package/lib/services/TaskService.js +760 -0
- package/lib/services/interfaces.js +753 -0
- package/lib/utils/CircuitBreaker.js +165 -0
- package/lib/utils/Encryption.js +201 -0
- package/lib/utils/RateLimiter.js +241 -0
- package/lib/utils/ServiceFactory.js +165 -0
- package/package.json +9 -5
- package/scripts/config/get.js +108 -0
- package/scripts/config/init.js +100 -0
- package/scripts/config/list-providers.js +93 -0
- package/scripts/config/set-api-key.js +107 -0
- package/scripts/config/set-provider.js +201 -0
- package/scripts/config/set.js +139 -0
- package/scripts/config/show.js +181 -0
- package/autopm/.claude/.env +0 -158
- package/autopm/.claude/settings.local.json +0 -9
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { logError } = require('./lib/logger');
|
|
4
|
+
const { findAllEpicDirs } = require('./lib/epic-discovery');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* PM Next Script (Node.js version)
|
|
@@ -106,69 +107,66 @@ function displayTddReminder(addMessage) {
|
|
|
106
107
|
async function findAvailableTasks() {
|
|
107
108
|
const availableTasks = [];
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
110
|
+
// Use shared epic discovery utility
|
|
111
|
+
const epicDirs = findAllEpicDirs();
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
} catch (err) {
|
|
163
|
-
// Skip files we can't read
|
|
113
|
+
for (const epicDir of epicDirs) {
|
|
114
|
+
const { name: epicName, path: epicPath } = epicDir;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const taskFiles = fs.readdirSync(epicPath)
|
|
118
|
+
.filter(file => /^\d+.*\.md$/.test(file))
|
|
119
|
+
.sort();
|
|
120
|
+
|
|
121
|
+
for (const taskFile of taskFiles) {
|
|
122
|
+
const taskPath = path.join(epicPath, taskFile);
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const content = fs.readFileSync(taskPath, 'utf8');
|
|
126
|
+
|
|
127
|
+
// Check if task is open (case-insensitive)
|
|
128
|
+
const statusMatch = content.match(/^status:\s*(.+)$/m);
|
|
129
|
+
const status = statusMatch ? statusMatch[1].trim().toLowerCase() : '';
|
|
130
|
+
|
|
131
|
+
// Skip non-open tasks (only open tasks or tasks without status are available)
|
|
132
|
+
if (status !== 'open' && status !== '') {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check dependencies
|
|
137
|
+
const depsMatch = content.match(/^depends_on:\s*\[(.*?)\]/m);
|
|
138
|
+
const depsStr = depsMatch ? depsMatch[1].trim() : '';
|
|
139
|
+
|
|
140
|
+
// If no dependencies or empty dependencies, task is available
|
|
141
|
+
if (!depsStr || depsStr === '') {
|
|
142
|
+
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
143
|
+
const name = nameMatch ? nameMatch[1].trim() : 'Unnamed Task';
|
|
144
|
+
|
|
145
|
+
const parallelMatch = content.match(/^parallel:\s*(.+)$/m);
|
|
146
|
+
const parallel = parallelMatch ? parallelMatch[1].trim() === 'true' : false;
|
|
147
|
+
|
|
148
|
+
const taskNum = path.basename(taskFile, '.md');
|
|
149
|
+
|
|
150
|
+
availableTasks.push({
|
|
151
|
+
taskNum,
|
|
152
|
+
name,
|
|
153
|
+
epicName,
|
|
154
|
+
parallel
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
// Log file read errors in DEBUG mode
|
|
159
|
+
if (process.env.DEBUG) {
|
|
160
|
+
console.error(`Error reading task file ${taskPath}:`, err.message);
|
|
164
161
|
}
|
|
165
162
|
}
|
|
166
|
-
}
|
|
167
|
-
|
|
163
|
+
}
|
|
164
|
+
} catch (err) {
|
|
165
|
+
// Log directory read errors in DEBUG mode
|
|
166
|
+
if (process.env.DEBUG) {
|
|
167
|
+
console.error(`Error reading epic directory ${epicPath}:`, err.message);
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
} catch (err) {
|
|
171
|
-
// Silently handle errors
|
|
172
170
|
}
|
|
173
171
|
|
|
174
172
|
return availableTasks;
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AutoPM POC - CLI for testing Claude API integration
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* autopm-poc parse <prd-file> - Parse PRD with streaming output
|
|
7
|
+
* autopm-poc parse <prd-file> --json - Parse PRD and output JSON
|
|
8
|
+
* autopm-poc summarize <prd-file> - Get one-paragraph summary
|
|
9
|
+
* autopm-poc test - Test API connection
|
|
10
|
+
*
|
|
11
|
+
* Environment:
|
|
12
|
+
* ANTHROPIC_API_KEY - Required for all operations
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const ClaudeProvider = require('../lib/ai-providers/ClaudeProvider');
|
|
18
|
+
const PRDService = require('../lib/services/PRDService');
|
|
19
|
+
const EpicService = require('../lib/services/EpicService');
|
|
20
|
+
const ConfigManager = require('../lib/config/ConfigManager');
|
|
21
|
+
const ServiceFactory = require('../lib/utils/ServiceFactory');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Print usage information
|
|
25
|
+
*/
|
|
26
|
+
function printUsage() {
|
|
27
|
+
console.log(`
|
|
28
|
+
AutoPM POC - Claude API Integration Demo (Streaming Support)
|
|
29
|
+
=============================================================
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
autopm-poc parse <prd-file> Parse PRD with streaming AI analysis
|
|
33
|
+
autopm-poc extract-epics <prd-file> Extract epics from PRD (streaming)
|
|
34
|
+
autopm-poc summarize <prd-file> Get PRD summary (streaming)
|
|
35
|
+
autopm-poc decompose <epic-file> Decompose epic into tasks (streaming)
|
|
36
|
+
autopm-poc analyze <prd-file> Epic-level PRD analysis (streaming)
|
|
37
|
+
autopm-poc test Test API connection
|
|
38
|
+
autopm-poc help Show this help message
|
|
39
|
+
|
|
40
|
+
Environment Variables:
|
|
41
|
+
ANTHROPIC_API_KEY Required - Your Anthropic API key
|
|
42
|
+
AUTOPM_MASTER_PASSWORD Optional - For encrypted config
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
46
|
+
autopm-poc parse examples/sample-prd.md
|
|
47
|
+
autopm-poc extract-epics examples/sample-prd.md
|
|
48
|
+
autopm-poc summarize examples/sample-prd.md
|
|
49
|
+
autopm-poc decompose .claude/epics/user-auth.md
|
|
50
|
+
autopm-poc analyze examples/sample-prd.md
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Test API connection
|
|
56
|
+
*/
|
|
57
|
+
async function testConnection(provider) {
|
|
58
|
+
console.log('🔍 Testing API connection...\n');
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const result = await provider.complete('Say "Connection successful!"', {
|
|
62
|
+
maxTokens: 50
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log('✅ API Connection Test: SUCCESS');
|
|
66
|
+
console.log(`📝 Response: ${result}\n`);
|
|
67
|
+
return true;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('❌ API Connection Test: FAILED');
|
|
70
|
+
console.error(` Error: ${error.message}\n`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Parse PRD with streaming output
|
|
77
|
+
*/
|
|
78
|
+
async function parsePRDStream(service, content) {
|
|
79
|
+
console.log('🔍 Analyzing PRD with Claude AI...\n');
|
|
80
|
+
console.log('📝 Streaming response:\n');
|
|
81
|
+
console.log('─'.repeat(60));
|
|
82
|
+
|
|
83
|
+
let fullResponse = '';
|
|
84
|
+
try {
|
|
85
|
+
for await (const chunk of service.parseStream(content)) {
|
|
86
|
+
process.stdout.write(chunk);
|
|
87
|
+
fullResponse += chunk;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log('\n' + '─'.repeat(60));
|
|
91
|
+
console.log('\n✅ Analysis complete!');
|
|
92
|
+
console.log(`📊 Total response length: ${fullResponse.length} characters\n`);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('\n❌ Error during parsing:', error.message);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extract epics from PRD with streaming output
|
|
101
|
+
*/
|
|
102
|
+
async function extractEpicsStream(service, content) {
|
|
103
|
+
console.log('🔍 Extracting epics from PRD with Claude AI...\n');
|
|
104
|
+
console.log('📝 Streaming response:\n');
|
|
105
|
+
console.log('─'.repeat(60));
|
|
106
|
+
|
|
107
|
+
let fullResponse = '';
|
|
108
|
+
try {
|
|
109
|
+
for await (const chunk of service.extractEpicsStream(content)) {
|
|
110
|
+
process.stdout.write(chunk);
|
|
111
|
+
fullResponse += chunk;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log('\n' + '─'.repeat(60));
|
|
115
|
+
console.log('\n✅ Epic extraction complete!');
|
|
116
|
+
console.log(`📊 Total response length: ${fullResponse.length} characters\n`);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('\n❌ Error during epic extraction:', error.message);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Summarize PRD with streaming output
|
|
125
|
+
*/
|
|
126
|
+
async function summarizePRDStream(service, content) {
|
|
127
|
+
console.log('🔍 Summarizing PRD with Claude AI...\n');
|
|
128
|
+
console.log('📝 Streaming response:\n');
|
|
129
|
+
console.log('─'.repeat(60));
|
|
130
|
+
|
|
131
|
+
let fullResponse = '';
|
|
132
|
+
try {
|
|
133
|
+
for await (const chunk of service.summarizeStream(content)) {
|
|
134
|
+
process.stdout.write(chunk);
|
|
135
|
+
fullResponse += chunk;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log('\n' + '─'.repeat(60));
|
|
139
|
+
console.log('\n✅ Summary complete!');
|
|
140
|
+
console.log(`📊 Total response length: ${fullResponse.length} characters\n`);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('\n❌ Error during summarization:', error.message);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Decompose epic into tasks with streaming output
|
|
149
|
+
*/
|
|
150
|
+
async function decomposeEpicStream(epicService, content) {
|
|
151
|
+
console.log('🔍 Decomposing epic into tasks with Claude AI...\n');
|
|
152
|
+
console.log('📝 Streaming response:\n');
|
|
153
|
+
console.log('─'.repeat(60));
|
|
154
|
+
|
|
155
|
+
let fullResponse = '';
|
|
156
|
+
try {
|
|
157
|
+
for await (const chunk of epicService.decomposeStream(content)) {
|
|
158
|
+
process.stdout.write(chunk);
|
|
159
|
+
fullResponse += chunk;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log('\n' + '─'.repeat(60));
|
|
163
|
+
console.log('\n✅ Task decomposition complete!');
|
|
164
|
+
console.log(`📊 Total response length: ${fullResponse.length} characters\n`);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error('\n❌ Error during decomposition:', error.message);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Analyze PRD for epic breakdown with streaming output
|
|
173
|
+
*/
|
|
174
|
+
async function analyzePRDStream(epicService, content) {
|
|
175
|
+
console.log('🔍 Analyzing PRD for epic breakdown with Claude AI...\n');
|
|
176
|
+
console.log('📝 Streaming response:\n');
|
|
177
|
+
console.log('─'.repeat(60));
|
|
178
|
+
|
|
179
|
+
let fullResponse = '';
|
|
180
|
+
try {
|
|
181
|
+
for await (const chunk of epicService.analyzeStream(content)) {
|
|
182
|
+
process.stdout.write(chunk);
|
|
183
|
+
fullResponse += chunk;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log('\n' + '─'.repeat(60));
|
|
187
|
+
console.log('\n✅ PRD analysis complete!');
|
|
188
|
+
console.log(`📊 Total response length: ${fullResponse.length} characters\n`);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('\n❌ Error during PRD analysis:', error.message);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Main entry point
|
|
197
|
+
*/
|
|
198
|
+
async function main() {
|
|
199
|
+
const args = process.argv.slice(2);
|
|
200
|
+
const command = args[0];
|
|
201
|
+
|
|
202
|
+
// Handle help
|
|
203
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
204
|
+
printUsage();
|
|
205
|
+
process.exit(0);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Try ConfigManager first, fallback to environment variable
|
|
209
|
+
let prdService;
|
|
210
|
+
let epicService;
|
|
211
|
+
let provider;
|
|
212
|
+
let configManager;
|
|
213
|
+
|
|
214
|
+
const configPath = path.join(process.cwd(), '.autopm', 'config.json');
|
|
215
|
+
if (fs.existsSync(configPath)) {
|
|
216
|
+
try {
|
|
217
|
+
configManager = new ConfigManager(configPath);
|
|
218
|
+
|
|
219
|
+
// Check for master password
|
|
220
|
+
const password = process.env.AUTOPM_MASTER_PASSWORD;
|
|
221
|
+
if (password) {
|
|
222
|
+
configManager.setMasterPassword(password);
|
|
223
|
+
|
|
224
|
+
// Use ServiceFactory to create services and provider
|
|
225
|
+
const factory = new ServiceFactory(configManager);
|
|
226
|
+
provider = factory.createProvider();
|
|
227
|
+
prdService = factory.createPRDService({ provider });
|
|
228
|
+
epicService = factory.createEpicService({ provider });
|
|
229
|
+
console.log('✅ Using configuration from .autopm/config.json\n');
|
|
230
|
+
} else {
|
|
231
|
+
console.log('⚠️ Config file found but AUTOPM_MASTER_PASSWORD not set');
|
|
232
|
+
console.log(' Falling back to ANTHROPIC_API_KEY environment variable\n');
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.log(`⚠️ Error loading config: ${error.message}`);
|
|
236
|
+
console.log(' Falling back to ANTHROPIC_API_KEY environment variable\n');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Fallback to environment variable
|
|
241
|
+
if (!prdService) {
|
|
242
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
243
|
+
if (!apiKey) {
|
|
244
|
+
console.error('❌ Error: No API key found\n');
|
|
245
|
+
console.error('Either:');
|
|
246
|
+
console.error(' 1. Run: autopm config:init (recommended)');
|
|
247
|
+
console.error(' Then: export AUTOPM_MASTER_PASSWORD="your-password"');
|
|
248
|
+
console.error(' 2. Set: export ANTHROPIC_API_KEY="sk-ant-..."\n');
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
provider = new ClaudeProvider(apiKey);
|
|
253
|
+
prdService = new PRDService({ provider });
|
|
254
|
+
epicService = new EpicService({ prdService, provider });
|
|
255
|
+
console.log('✅ Using ANTHROPIC_API_KEY from environment\n');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Handle test command
|
|
259
|
+
if (command === 'test') {
|
|
260
|
+
const success = await testConnection(provider);
|
|
261
|
+
process.exit(success ? 0 : 1);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Handle PRD commands (parse, extract-epics, summarize, analyze)
|
|
265
|
+
if (['parse', 'extract-epics', 'summarize', 'analyze'].includes(command)) {
|
|
266
|
+
const file = args[1];
|
|
267
|
+
|
|
268
|
+
if (!file) {
|
|
269
|
+
console.error(`❌ Error: PRD file required for '${command}' command\n`);
|
|
270
|
+
console.error(`Usage: autopm-poc ${command} <prd-file>\n`);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Check if file exists
|
|
275
|
+
if (!fs.existsSync(file)) {
|
|
276
|
+
console.error(`❌ Error: File not found: ${file}\n`);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Read file content
|
|
281
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
282
|
+
|
|
283
|
+
if (!content.trim()) {
|
|
284
|
+
console.error('❌ Error: PRD file is empty\n');
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
console.log(`📄 Reading PRD from: ${file}`);
|
|
289
|
+
console.log(`📏 File size: ${content.length} characters\n`);
|
|
290
|
+
|
|
291
|
+
// Execute command
|
|
292
|
+
if (command === 'parse') {
|
|
293
|
+
await parsePRDStream(prdService, content);
|
|
294
|
+
} else if (command === 'extract-epics') {
|
|
295
|
+
await extractEpicsStream(prdService, content);
|
|
296
|
+
} else if (command === 'summarize') {
|
|
297
|
+
await summarizePRDStream(prdService, content);
|
|
298
|
+
} else if (command === 'analyze') {
|
|
299
|
+
await analyzePRDStream(epicService, content);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
process.exit(0);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Handle decompose command (for epic files)
|
|
306
|
+
if (command === 'decompose') {
|
|
307
|
+
const file = args[1];
|
|
308
|
+
|
|
309
|
+
if (!file) {
|
|
310
|
+
console.error(`❌ Error: Epic file required for 'decompose' command\n`);
|
|
311
|
+
console.error(`Usage: autopm-poc decompose <epic-file>\n`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Check if file exists
|
|
316
|
+
if (!fs.existsSync(file)) {
|
|
317
|
+
console.error(`❌ Error: File not found: ${file}\n`);
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Read file content
|
|
322
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
323
|
+
|
|
324
|
+
if (!content.trim()) {
|
|
325
|
+
console.error('❌ Error: Epic file is empty\n');
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
console.log(`📄 Reading Epic from: ${file}`);
|
|
330
|
+
console.log(`📏 File size: ${content.length} characters\n`);
|
|
331
|
+
|
|
332
|
+
await decomposeEpicStream(epicService, content);
|
|
333
|
+
process.exit(0);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Unknown command
|
|
337
|
+
console.error(`❌ Error: Unknown command: ${command}\n`);
|
|
338
|
+
printUsage();
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Run main with error handling
|
|
343
|
+
main().catch(err => {
|
|
344
|
+
console.error('❌ Fatal error:', err.message);
|
|
345
|
+
console.error('\nStack trace:');
|
|
346
|
+
console.error(err.stack);
|
|
347
|
+
process.exit(1);
|
|
348
|
+
});
|
package/bin/autopm.js
CHANGED
|
@@ -182,6 +182,12 @@ function main() {
|
|
|
182
182
|
.command(require('./commands/mcp'))
|
|
183
183
|
// Epic management command
|
|
184
184
|
.command(require('./commands/epic'))
|
|
185
|
+
// PRD management command (STANDALONE)
|
|
186
|
+
.command(require('../lib/cli/commands/prd'))
|
|
187
|
+
// Task management command (STANDALONE)
|
|
188
|
+
.command(require('../lib/cli/commands/task'))
|
|
189
|
+
// Agent management command (STANDALONE)
|
|
190
|
+
.command(require('../lib/cli/commands/agent'))
|
|
185
191
|
// Validation command
|
|
186
192
|
.command('validate', 'Validate ClaudeAutoPM configuration and setup',
|
|
187
193
|
(yargs) => {
|