proagents 1.6.8 → 1.6.10
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/.proagents/AI_INSTRUCTIONS.md +216 -3291
- package/.proagents/docs/README.md +27 -0
- package/.proagents/docs/command-details.md +813 -0
- package/.proagents/docs/testing.md +241 -0
- package/.proagents/prompts/06-testing.md +172 -0
- package/.proagents/prompts/07-documentation.md +62 -0
- package/.proagents/prompts/10-debug-logs.md +1130 -0
- package/README.md +22 -0
- package/lib/commands/ai.js +148 -19
- package/lib/commands/config.js +39 -12
- package/lib/commands/init.js +94 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -184,6 +184,9 @@ Type these in any AI assistant (Claude, ChatGPT, Gemini, Cursor, etc.):
|
|
|
184
184
|
| `pa:r` | `pa:requirements` |
|
|
185
185
|
| `pa:p` | `pa:plan` |
|
|
186
186
|
| `pa:i` | `pa:implement` |
|
|
187
|
+
| `pa:rev` | `pa:review` |
|
|
188
|
+
| `pa:dbg` | `pa:debug` |
|
|
189
|
+
| `pa:l` | `pa:logs` |
|
|
187
190
|
|
|
188
191
|
### Core Commands
|
|
189
192
|
| Command | Description |
|
|
@@ -366,6 +369,25 @@ Type these in any AI assistant (Claude, ChatGPT, Gemini, Cursor, etc.):
|
|
|
366
369
|
| `pa:duplication` | Find duplicate code blocks |
|
|
367
370
|
| `pa:hotspots` | Find frequently changed files |
|
|
368
371
|
|
|
372
|
+
### Debug & Logs
|
|
373
|
+
| Command | Description |
|
|
374
|
+
|---------|-------------|
|
|
375
|
+
| `pa:debug` | Start debug session |
|
|
376
|
+
| `pa:debug-add` | Add debug logs to code |
|
|
377
|
+
| `pa:debug-add "file"` | Add logs to specific file |
|
|
378
|
+
| `pa:debug-trace "func"` | Add entry/exit logs to function |
|
|
379
|
+
| `pa:debug-var "var"` | Track variable changes |
|
|
380
|
+
| `pa:debug-api` | Add API request/response logging |
|
|
381
|
+
| `pa:debug-state` | Add state change logging |
|
|
382
|
+
| `pa:debug-error` | Add error boundary logging |
|
|
383
|
+
| `pa:debug-web` | Web console debugging |
|
|
384
|
+
| `pa:debug-rn` | React Native debugging |
|
|
385
|
+
| `pa:debug-android` | Android native (logcat) |
|
|
386
|
+
| `pa:debug-ios` | iOS native debugging |
|
|
387
|
+
| `pa:logs` | View recent logs |
|
|
388
|
+
| `pa:logs-filter "term"` | Filter logs by term |
|
|
389
|
+
| `pa:debug-clean` | Remove all debug statements |
|
|
390
|
+
|
|
369
391
|
### Testing Advanced
|
|
370
392
|
| Command | Description |
|
|
371
393
|
|---------|-------------|
|
package/lib/commands/ai.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, cpSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
1
|
+
import { existsSync, cpSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { createInterface } from 'readline';
|
|
@@ -49,8 +49,9 @@ export function getPlatformById(id) {
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Interactive platform selection using readline
|
|
52
|
+
* @param {string[]} previouslySelected - Previously selected platforms (from interrupted setup)
|
|
52
53
|
*/
|
|
53
|
-
export async function selectPlatforms() {
|
|
54
|
+
export async function selectPlatforms(previouslySelected = []) {
|
|
54
55
|
const rl = createInterface({
|
|
55
56
|
input: process.stdin,
|
|
56
57
|
output: process.stdout
|
|
@@ -63,12 +64,16 @@ export async function selectPlatforms() {
|
|
|
63
64
|
|
|
64
65
|
let index = 1;
|
|
65
66
|
const indexMap = {};
|
|
67
|
+
const preSelectedIndices = [];
|
|
66
68
|
|
|
67
69
|
// IDE-based platforms
|
|
68
70
|
console.log(chalk.cyan.bold(` ${AI_PLATFORMS.ide.label}:`));
|
|
69
71
|
for (const platform of AI_PLATFORMS.ide.platforms) {
|
|
70
|
-
|
|
72
|
+
const wasSelected = previouslySelected && previouslySelected.includes(platform.id);
|
|
73
|
+
const marker = wasSelected ? chalk.green(' ✓ (previously selected)') : '';
|
|
74
|
+
console.log(chalk.white(` ${index}. ${platform.name}`) + chalk.gray(` - ${platform.desc}`) + marker);
|
|
71
75
|
indexMap[index] = platform.id;
|
|
76
|
+
if (wasSelected) preSelectedIndices.push(index);
|
|
72
77
|
index++;
|
|
73
78
|
}
|
|
74
79
|
|
|
@@ -77,16 +82,29 @@ export async function selectPlatforms() {
|
|
|
77
82
|
// Web-based platforms
|
|
78
83
|
console.log(chalk.cyan.bold(` ${AI_PLATFORMS.web.label}:`));
|
|
79
84
|
for (const platform of AI_PLATFORMS.web.platforms) {
|
|
80
|
-
|
|
85
|
+
const wasSelected = previouslySelected && previouslySelected.includes(platform.id);
|
|
86
|
+
const marker = wasSelected ? chalk.green(' ✓ (previously selected)') : '';
|
|
87
|
+
console.log(chalk.white(` ${index}. ${platform.name}`) + chalk.gray(` - ${platform.desc}`) + marker);
|
|
81
88
|
indexMap[index] = platform.id;
|
|
89
|
+
if (wasSelected) preSelectedIndices.push(index);
|
|
82
90
|
index++;
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
console.log('');
|
|
86
94
|
|
|
87
|
-
|
|
95
|
+
// Show default based on previous selection
|
|
96
|
+
const defaultHint = preSelectedIndices.length > 0
|
|
97
|
+
? `Enter for previous: ${preSelectedIndices.join(',')}`
|
|
98
|
+
: 'e.g., 1,2,3 or "all"';
|
|
99
|
+
|
|
100
|
+
const answer = await question(chalk.yellow(`Your selection (${defaultHint}): `));
|
|
88
101
|
rl.close();
|
|
89
102
|
|
|
103
|
+
// If user just pressed enter and we have previous selections, use them
|
|
104
|
+
if (answer.trim() === '' && preSelectedIndices.length > 0) {
|
|
105
|
+
return previouslySelected;
|
|
106
|
+
}
|
|
107
|
+
|
|
90
108
|
if (answer.toLowerCase() === 'all') {
|
|
91
109
|
return getAllPlatforms().map(p => p.id);
|
|
92
110
|
}
|
|
@@ -131,6 +149,46 @@ function extractProagentsSection(content) {
|
|
|
131
149
|
return null;
|
|
132
150
|
}
|
|
133
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Remove only ProAgents section from a file, keep user's original content
|
|
154
|
+
* Returns: 'deleted' (file removed), 'cleaned' (section removed), 'skipped' (no ProAgents section)
|
|
155
|
+
*/
|
|
156
|
+
function removeProagentsSectionFromFile(filePath) {
|
|
157
|
+
try {
|
|
158
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
159
|
+
|
|
160
|
+
const startIndex = content.indexOf(PROAGENTS_START);
|
|
161
|
+
const endIndex = content.indexOf(PROAGENTS_END);
|
|
162
|
+
|
|
163
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
164
|
+
// Has ProAgents section - remove it, keep the rest
|
|
165
|
+
const before = content.substring(0, startIndex).trim();
|
|
166
|
+
const after = content.substring(endIndex + PROAGENTS_END.length).trim();
|
|
167
|
+
const remaining = (before + '\n\n' + after).trim();
|
|
168
|
+
|
|
169
|
+
if (remaining.length === 0) {
|
|
170
|
+
// File only had ProAgents content - delete it
|
|
171
|
+
rmSync(filePath, { force: true });
|
|
172
|
+
return 'deleted';
|
|
173
|
+
} else {
|
|
174
|
+
// File has other content - keep it, remove only ProAgents section
|
|
175
|
+
writeFileSync(filePath, remaining + '\n');
|
|
176
|
+
return 'cleaned';
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
// No ProAgents markers - file was created by ProAgents (not merged)
|
|
180
|
+
// Check if it's a ProAgents-generated file by looking for ProAgents reference
|
|
181
|
+
if (content.includes('proagents') || content.includes('ProAgents') || content.includes('.proagents/')) {
|
|
182
|
+
rmSync(filePath, { force: true });
|
|
183
|
+
return 'deleted';
|
|
184
|
+
}
|
|
185
|
+
return 'skipped';
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
return 'skipped';
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
134
192
|
/**
|
|
135
193
|
* Merge ProAgents instructions with existing file content
|
|
136
194
|
* - If file doesn't exist: create with ProAgents content
|
|
@@ -247,6 +305,51 @@ export function loadPlatformConfig(configPath) {
|
|
|
247
305
|
}
|
|
248
306
|
}
|
|
249
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Check if a file contains ProAgents content
|
|
310
|
+
*/
|
|
311
|
+
function hasProagentsContent(filePath) {
|
|
312
|
+
try {
|
|
313
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
314
|
+
// Check for ProAgents markers or references
|
|
315
|
+
return content.includes(PROAGENTS_START) ||
|
|
316
|
+
content.includes('.proagents/') ||
|
|
317
|
+
content.includes('ProAgents Commands');
|
|
318
|
+
} catch {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Detect installed platforms by checking for actual files with ProAgents content
|
|
325
|
+
* Only counts as installed if the file has ProAgents-related content
|
|
326
|
+
*/
|
|
327
|
+
export function detectInstalledPlatforms(targetDir) {
|
|
328
|
+
const installed = [];
|
|
329
|
+
|
|
330
|
+
for (const platform of getAllPlatforms()) {
|
|
331
|
+
const filePath = join(targetDir, platform.file);
|
|
332
|
+
if (existsSync(filePath) && hasProagentsContent(filePath)) {
|
|
333
|
+
installed.push(platform.id);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return installed;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get installed platforms - combines config and file detection
|
|
342
|
+
* Returns platforms that are either in config OR have files present
|
|
343
|
+
*/
|
|
344
|
+
export function getInstalledPlatforms(targetDir, configPath) {
|
|
345
|
+
const fromConfig = loadPlatformConfig(configPath);
|
|
346
|
+
const fromFiles = detectInstalledPlatforms(targetDir);
|
|
347
|
+
|
|
348
|
+
// Merge both sources, remove duplicates
|
|
349
|
+
const combined = [...new Set([...fromConfig, ...fromFiles])];
|
|
350
|
+
return combined;
|
|
351
|
+
}
|
|
352
|
+
|
|
250
353
|
/**
|
|
251
354
|
* Show available platforms that can be added
|
|
252
355
|
*/
|
|
@@ -294,7 +397,7 @@ export async function aiAddCommand() {
|
|
|
294
397
|
const targetDir = process.cwd();
|
|
295
398
|
const proagentsDir = join(targetDir, '.proagents');
|
|
296
399
|
const sourceDir = join(__dirname, '..', '..', '.proagents');
|
|
297
|
-
const configPath = join(
|
|
400
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
298
401
|
|
|
299
402
|
// Check if proagents is initialized
|
|
300
403
|
if (!existsSync(proagentsDir)) {
|
|
@@ -302,8 +405,8 @@ export async function aiAddCommand() {
|
|
|
302
405
|
return;
|
|
303
406
|
}
|
|
304
407
|
|
|
305
|
-
//
|
|
306
|
-
const currentIds =
|
|
408
|
+
// Detect from both config AND actual files
|
|
409
|
+
const currentIds = getInstalledPlatforms(targetDir, configPath);
|
|
307
410
|
|
|
308
411
|
console.log(chalk.bold.blue('\nProAgents - Add AI Platform'));
|
|
309
412
|
console.log(chalk.blue('===========================\n'));
|
|
@@ -361,7 +464,7 @@ export async function aiAddCommand() {
|
|
|
361
464
|
}
|
|
362
465
|
|
|
363
466
|
console.log(chalk.gray('\nAI instruction files added to project root.'));
|
|
364
|
-
console.log(chalk.gray('Config updated in
|
|
467
|
+
console.log(chalk.gray('Config updated in proagents.config.yaml\n'));
|
|
365
468
|
}
|
|
366
469
|
|
|
367
470
|
/**
|
|
@@ -370,9 +473,10 @@ export async function aiAddCommand() {
|
|
|
370
473
|
export function aiListCommand() {
|
|
371
474
|
const targetDir = process.cwd();
|
|
372
475
|
const proagentsDir = join(targetDir, '.proagents');
|
|
373
|
-
const configPath = join(
|
|
476
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
374
477
|
|
|
375
|
-
|
|
478
|
+
// Detect from both config AND actual files
|
|
479
|
+
const currentIds = getInstalledPlatforms(targetDir, configPath);
|
|
376
480
|
|
|
377
481
|
console.log(chalk.bold.blue('\nProAgents - AI Platforms'));
|
|
378
482
|
console.log(chalk.blue('========================\n'));
|
|
@@ -387,17 +491,18 @@ export function aiListCommand() {
|
|
|
387
491
|
export async function aiRemoveCommand() {
|
|
388
492
|
const targetDir = process.cwd();
|
|
389
493
|
const proagentsDir = join(targetDir, '.proagents');
|
|
390
|
-
const configPath = join(
|
|
494
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
391
495
|
|
|
392
496
|
if (!existsSync(proagentsDir)) {
|
|
393
497
|
console.log(chalk.red('\n✗ ProAgents not initialized.\n'));
|
|
394
498
|
return;
|
|
395
499
|
}
|
|
396
500
|
|
|
397
|
-
|
|
501
|
+
// Detect from both config AND actual files
|
|
502
|
+
const currentIds = getInstalledPlatforms(targetDir, configPath);
|
|
398
503
|
|
|
399
504
|
if (currentIds.length === 0) {
|
|
400
|
-
console.log(chalk.yellow('\nNo AI platforms
|
|
505
|
+
console.log(chalk.yellow('\nNo AI platforms installed.\n'));
|
|
401
506
|
return;
|
|
402
507
|
}
|
|
403
508
|
|
|
@@ -443,12 +548,36 @@ export async function aiRemoveCommand() {
|
|
|
443
548
|
return;
|
|
444
549
|
}
|
|
445
550
|
|
|
446
|
-
// Remove from config
|
|
551
|
+
// Remove from config
|
|
447
552
|
const newIds = currentIds.filter(id => !toRemove.includes(id));
|
|
448
553
|
savePlatformConfig(newIds, configPath);
|
|
449
554
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
555
|
+
// Remove ProAgents sections from AI files (smart removal - keeps user content)
|
|
556
|
+
const results = { deleted: [], cleaned: [], skipped: [] };
|
|
557
|
+
|
|
558
|
+
for (const id of toRemove) {
|
|
559
|
+
const platform = getPlatformById(id);
|
|
560
|
+
if (!platform) continue;
|
|
561
|
+
|
|
562
|
+
const filePath = join(targetDir, platform.file);
|
|
563
|
+
if (existsSync(filePath)) {
|
|
564
|
+
const result = removeProagentsSectionFromFile(filePath);
|
|
565
|
+
if (result === 'deleted') {
|
|
566
|
+
results.deleted.push(platform.name);
|
|
567
|
+
} else if (result === 'cleaned') {
|
|
568
|
+
results.cleaned.push(platform.name);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// Show results
|
|
574
|
+
console.log('');
|
|
575
|
+
if (results.deleted.length > 0) {
|
|
576
|
+
console.log(chalk.green(`✓ Removed: ${results.deleted.join(', ')}`));
|
|
577
|
+
}
|
|
578
|
+
if (results.cleaned.length > 0) {
|
|
579
|
+
console.log(chalk.green(`✓ Cleaned ProAgents section from: ${results.cleaned.join(', ')} (kept your custom config)`));
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
console.log(chalk.gray('\nConfig updated in proagents.config.yaml\n'));
|
|
454
583
|
}
|
package/lib/commands/config.js
CHANGED
|
@@ -28,12 +28,12 @@ export function configListCommand() {
|
|
|
28
28
|
// 1. Main Config
|
|
29
29
|
console.log(chalk.cyan.bold('1. Main Configuration'));
|
|
30
30
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
31
|
-
const configPath = join(
|
|
31
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
32
32
|
if (existsSync(configPath)) {
|
|
33
|
-
console.log(chalk.green(' ✓ ') + chalk.white('
|
|
33
|
+
console.log(chalk.green(' ✓ ') + chalk.white('proagents.config.yaml'));
|
|
34
34
|
console.log(chalk.gray(' Checkpoints, git settings, parallel features, etc.\n'));
|
|
35
35
|
} else {
|
|
36
|
-
console.log(chalk.yellow(' ○ ') + chalk.white('
|
|
36
|
+
console.log(chalk.yellow(' ○ ') + chalk.white('proagents.config.yaml') + chalk.gray(' (not created)\n'));
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// 2. AI Platforms
|
|
@@ -184,7 +184,7 @@ export function configListCommand() {
|
|
|
184
184
|
*/
|
|
185
185
|
export function configShowCommand() {
|
|
186
186
|
const targetDir = process.cwd();
|
|
187
|
-
const configPath = join(targetDir, '
|
|
187
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
188
188
|
|
|
189
189
|
console.log('\n' + chalk.bold.blue('ProAgents Current Configuration'));
|
|
190
190
|
console.log(chalk.blue('================================\n'));
|
|
@@ -198,7 +198,7 @@ export function configShowCommand() {
|
|
|
198
198
|
const content = readFileSync(configPath, 'utf-8');
|
|
199
199
|
const config = yaml.load(content);
|
|
200
200
|
|
|
201
|
-
console.log(chalk.cyan('File: ') + chalk.white('
|
|
201
|
+
console.log(chalk.cyan('File: ') + chalk.white('proagents.config.yaml\n'));
|
|
202
202
|
console.log(chalk.gray('─────────────────────────────────────────────\n'));
|
|
203
203
|
console.log(content);
|
|
204
204
|
} catch (error) {
|
|
@@ -212,7 +212,7 @@ export function configShowCommand() {
|
|
|
212
212
|
*/
|
|
213
213
|
export function configEditCommand() {
|
|
214
214
|
const targetDir = process.cwd();
|
|
215
|
-
const configPath = join(targetDir, '
|
|
215
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
216
216
|
|
|
217
217
|
if (!existsSync(configPath)) {
|
|
218
218
|
console.log(chalk.yellow('\nConfig file not found. Run "proagents init" first.\n'));
|
|
@@ -220,7 +220,7 @@ export function configEditCommand() {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
console.log(chalk.cyan('\nTo edit configuration:\n'));
|
|
223
|
-
console.log(chalk.white(' Open: ') + chalk.green('
|
|
223
|
+
console.log(chalk.white(' Open: ') + chalk.green('proagents.config.yaml'));
|
|
224
224
|
console.log(chalk.white(' Docs: ') + chalk.green('.proagents/config/README.md\n'));
|
|
225
225
|
}
|
|
226
226
|
|
|
@@ -261,7 +261,7 @@ function parseValue(value) {
|
|
|
261
261
|
*/
|
|
262
262
|
export function configSetCommand(key, value) {
|
|
263
263
|
const targetDir = process.cwd();
|
|
264
|
-
const configPath = join(targetDir, '
|
|
264
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
265
265
|
|
|
266
266
|
console.log('');
|
|
267
267
|
|
|
@@ -297,7 +297,7 @@ export function configSetCommand(key, value) {
|
|
|
297
297
|
*/
|
|
298
298
|
export function configGetCommand(key) {
|
|
299
299
|
const targetDir = process.cwd();
|
|
300
|
-
const configPath = join(targetDir, '
|
|
300
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
301
301
|
|
|
302
302
|
console.log('');
|
|
303
303
|
|
|
@@ -324,13 +324,25 @@ export function configGetCommand(key) {
|
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Save config setup progress (for resume after interrupt)
|
|
329
|
+
*/
|
|
330
|
+
function saveSetupProgress(configPath, config, step) {
|
|
331
|
+
config._config_setup = {
|
|
332
|
+
last_step: step,
|
|
333
|
+
timestamp: new Date().toISOString()
|
|
334
|
+
};
|
|
335
|
+
const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120 });
|
|
336
|
+
writeFileSync(configPath, yamlContent);
|
|
337
|
+
}
|
|
338
|
+
|
|
327
339
|
/**
|
|
328
340
|
* Command: proagents config setup
|
|
329
341
|
* Interactive wizard for main configuration
|
|
330
342
|
*/
|
|
331
343
|
export async function configSetupCommand() {
|
|
332
344
|
const targetDir = process.cwd();
|
|
333
|
-
const configPath = join(targetDir, '
|
|
345
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
334
346
|
|
|
335
347
|
console.log('\n' + chalk.bold.blue('ProAgents Configuration Wizard'));
|
|
336
348
|
console.log(chalk.blue('===============================\n'));
|
|
@@ -366,15 +378,22 @@ export async function configSetupCommand() {
|
|
|
366
378
|
config = yaml.load(readFileSync(configPath, 'utf-8')) || {};
|
|
367
379
|
}
|
|
368
380
|
|
|
381
|
+
// Check for interrupted setup
|
|
382
|
+
if (config._config_setup) {
|
|
383
|
+
console.log(chalk.cyan('📋 Resuming with your previous choices...\n'));
|
|
384
|
+
}
|
|
385
|
+
|
|
369
386
|
console.log(chalk.cyan('Project Settings\n'));
|
|
370
387
|
|
|
371
388
|
// Project settings
|
|
372
389
|
config.project = config.project || {};
|
|
373
390
|
config.project.name = await question('Project name', config.project.name || 'My Project');
|
|
391
|
+
saveSetupProgress(configPath, config, 'project_name');
|
|
374
392
|
|
|
375
393
|
const projectTypes = ['web-frontend', 'fullstack', 'mobile', 'backend'];
|
|
376
394
|
console.log(chalk.gray(' Types: ' + projectTypes.join(', ')));
|
|
377
395
|
config.project.type = await question('Project type', config.project.type || 'fullstack');
|
|
396
|
+
saveSetupProgress(configPath, config, 'project_type');
|
|
378
397
|
|
|
379
398
|
console.log('\n' + chalk.cyan('Checkpoints (pause for approval)\n'));
|
|
380
399
|
|
|
@@ -386,12 +405,14 @@ export async function configSetupCommand() {
|
|
|
386
405
|
config.checkpoints.after_implementation = await yesNo('Pause after implementation?', config.checkpoints.after_implementation ?? false);
|
|
387
406
|
config.checkpoints.after_testing = await yesNo('Pause after testing?', config.checkpoints.after_testing ?? false);
|
|
388
407
|
config.checkpoints.before_deployment = await yesNo('Pause before deployment?', config.checkpoints.before_deployment ?? true);
|
|
408
|
+
saveSetupProgress(configPath, config, 'checkpoints');
|
|
389
409
|
|
|
390
410
|
console.log('\n' + chalk.cyan('Git Settings\n'));
|
|
391
411
|
|
|
392
412
|
// Git settings
|
|
393
413
|
config.git = config.git || {};
|
|
394
414
|
config.git.enabled = await yesNo('Enable git integration?', config.git.enabled ?? true);
|
|
415
|
+
saveSetupProgress(configPath, config, 'git_enabled');
|
|
395
416
|
|
|
396
417
|
if (config.git.enabled) {
|
|
397
418
|
config.git.branch_prefix = await question('Branch prefix', config.git.branch_prefix || 'feature/');
|
|
@@ -400,6 +421,7 @@ export async function configSetupCommand() {
|
|
|
400
421
|
console.log(chalk.gray(' Conventions: ' + conventions.join(', ')));
|
|
401
422
|
config.git.commit_convention = await question('Commit convention', config.git.commit_convention || 'conventional');
|
|
402
423
|
config.git.require_pr = await yesNo('Require pull requests?', config.git.require_pr ?? true);
|
|
424
|
+
saveSetupProgress(configPath, config, 'git');
|
|
403
425
|
}
|
|
404
426
|
|
|
405
427
|
console.log('\n' + chalk.cyan('Parallel Features\n'));
|
|
@@ -407,20 +429,25 @@ export async function configSetupCommand() {
|
|
|
407
429
|
// Parallel features
|
|
408
430
|
config.parallel_features = config.parallel_features || {};
|
|
409
431
|
config.parallel_features.enabled = await yesNo('Enable parallel features?', config.parallel_features.enabled ?? true);
|
|
432
|
+
saveSetupProgress(configPath, config, 'parallel_enabled');
|
|
410
433
|
|
|
411
434
|
if (config.parallel_features.enabled) {
|
|
412
435
|
const maxStr = await question('Max concurrent features', String(config.parallel_features.max_concurrent || 3));
|
|
413
436
|
config.parallel_features.max_concurrent = parseInt(maxStr) || 3;
|
|
437
|
+
saveSetupProgress(configPath, config, 'parallel');
|
|
414
438
|
}
|
|
415
439
|
|
|
416
440
|
rl.close();
|
|
417
441
|
|
|
418
|
-
//
|
|
442
|
+
// Remove setup progress marker (setup complete)
|
|
443
|
+
delete config._config_setup;
|
|
444
|
+
|
|
445
|
+
// Save final config
|
|
419
446
|
const header = `# ProAgents Configuration\n# Generated by setup wizard\n# Last updated: ${new Date().toISOString().split('T')[0]}\n\n`;
|
|
420
447
|
const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120 });
|
|
421
448
|
writeFileSync(configPath, header + yamlContent);
|
|
422
449
|
|
|
423
|
-
console.log(chalk.green('\n✓ Configuration saved to proagents
|
|
450
|
+
console.log(chalk.green('\n✓ Configuration saved to proagents.config.yaml\n'));
|
|
424
451
|
|
|
425
452
|
} catch (error) {
|
|
426
453
|
rl.close();
|
package/lib/commands/init.js
CHANGED
|
@@ -697,8 +697,10 @@ async function promptGitignoreChoice() {
|
|
|
697
697
|
|
|
698
698
|
/**
|
|
699
699
|
* Interactive prompt for project configuration
|
|
700
|
+
* @param {string} targetDir - The target directory
|
|
701
|
+
* @param {object} existingConfig - Existing partial config from interrupted setup
|
|
700
702
|
*/
|
|
701
|
-
async function promptProjectConfig(targetDir) {
|
|
703
|
+
async function promptProjectConfig(targetDir, existingConfig = {}) {
|
|
702
704
|
const rl = createInterface({
|
|
703
705
|
input: process.stdin,
|
|
704
706
|
output: process.stdout
|
|
@@ -706,12 +708,19 @@ async function promptProjectConfig(targetDir) {
|
|
|
706
708
|
|
|
707
709
|
const question = (prompt) => new Promise(resolve => rl.question(prompt, resolve));
|
|
708
710
|
|
|
711
|
+
// Get saved values from interrupted setup
|
|
712
|
+
const savedProject = existingConfig.project || {};
|
|
713
|
+
const savedName = savedProject.name;
|
|
714
|
+
const savedType = savedProject.type;
|
|
715
|
+
|
|
709
716
|
// Detect project name
|
|
710
|
-
const detectedName = detectProjectName(targetDir);
|
|
717
|
+
const detectedName = savedName || detectProjectName(targetDir);
|
|
711
718
|
|
|
712
719
|
// Detect project types
|
|
713
720
|
const detectedTypes = detectProjectType(targetDir);
|
|
714
|
-
const topDetectedType =
|
|
721
|
+
const topDetectedType = savedType
|
|
722
|
+
? PROJECT_TYPES.find(t => t.id === savedType)
|
|
723
|
+
: (detectedTypes.length > 0 ? detectedTypes[0] : null);
|
|
715
724
|
|
|
716
725
|
// Detect tech stack
|
|
717
726
|
const detectedTechStack = detectTechStack(targetDir);
|
|
@@ -719,9 +728,16 @@ async function promptProjectConfig(targetDir) {
|
|
|
719
728
|
console.log(chalk.bold('\nProject Configuration'));
|
|
720
729
|
console.log(chalk.gray('─'.repeat(40) + '\n'));
|
|
721
730
|
|
|
731
|
+
// Show resume notice if we have saved values
|
|
732
|
+
if (savedName || savedType) {
|
|
733
|
+
console.log(chalk.cyan('📋 Resuming with your previous choices...\n'));
|
|
734
|
+
}
|
|
735
|
+
|
|
722
736
|
// Project Name
|
|
723
737
|
console.log(chalk.cyan('Project Name'));
|
|
724
|
-
if (
|
|
738
|
+
if (savedName) {
|
|
739
|
+
console.log(chalk.green(` Previously saved: ${savedName}`));
|
|
740
|
+
} else if (detectedName) {
|
|
725
741
|
console.log(chalk.gray(` Detected: ${detectedName}`));
|
|
726
742
|
}
|
|
727
743
|
const nameInput = await question(chalk.yellow(` Enter name (press Enter for "${detectedName}"): `));
|
|
@@ -836,6 +852,44 @@ function applyTemplate(templateId, targetDir) {
|
|
|
836
852
|
};
|
|
837
853
|
}
|
|
838
854
|
|
|
855
|
+
/**
|
|
856
|
+
* Load existing partial config (for resume after interrupted setup)
|
|
857
|
+
*/
|
|
858
|
+
function loadPartialConfig(configPath) {
|
|
859
|
+
if (!existsSync(configPath)) return {};
|
|
860
|
+
|
|
861
|
+
try {
|
|
862
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
863
|
+
return yaml.load(content) || {};
|
|
864
|
+
} catch {
|
|
865
|
+
return {};
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Save partial config progress (called after each setup step)
|
|
871
|
+
*/
|
|
872
|
+
function savePartialConfig(configPath, updates) {
|
|
873
|
+
let config = loadPartialConfig(configPath);
|
|
874
|
+
|
|
875
|
+
// Deep merge updates into config
|
|
876
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
877
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
878
|
+
config[key] = { ...(config[key] || {}), ...value };
|
|
879
|
+
} else {
|
|
880
|
+
config[key] = value;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Add setup progress marker
|
|
885
|
+
config._setup = config._setup || {};
|
|
886
|
+
config._setup.last_step = updates._step || config._setup.last_step;
|
|
887
|
+
config._setup.timestamp = new Date().toISOString();
|
|
888
|
+
|
|
889
|
+
const yamlContent = yaml.dump(config, { indent: 2, lineWidth: 120 });
|
|
890
|
+
writeFileSync(configPath, yamlContent);
|
|
891
|
+
}
|
|
892
|
+
|
|
839
893
|
/**
|
|
840
894
|
* Save project config to proagents.config.yaml
|
|
841
895
|
*/
|
|
@@ -900,6 +954,10 @@ export async function initCommand(options = {}) {
|
|
|
900
954
|
const targetDir = process.cwd();
|
|
901
955
|
const proagentsDir = join(targetDir, '.proagents');
|
|
902
956
|
const sourceDir = join(__dirname, '..', '..', '.proagents');
|
|
957
|
+
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
958
|
+
|
|
959
|
+
// Load any existing partial config (from interrupted setup)
|
|
960
|
+
const existingConfig = loadPartialConfig(configPath);
|
|
903
961
|
|
|
904
962
|
console.log('\n' + chalk.bold.blue('ProAgents Initialization'));
|
|
905
963
|
console.log(chalk.blue('========================\n'));
|
|
@@ -1052,6 +1110,12 @@ Generated by [ProAgents](https://github.com/prakashpro3/proAgents)
|
|
|
1052
1110
|
} else {
|
|
1053
1111
|
console.log(chalk.green('✓ Added .proagents/ local data to .gitignore'));
|
|
1054
1112
|
}
|
|
1113
|
+
|
|
1114
|
+
// Save progress after gitignore choice
|
|
1115
|
+
savePartialConfig(configPath, {
|
|
1116
|
+
gitignore_mode: gitignoreChoice,
|
|
1117
|
+
_step: 'gitignore'
|
|
1118
|
+
});
|
|
1055
1119
|
}
|
|
1056
1120
|
|
|
1057
1121
|
// Create placeholder CHANGELOG.md if not exists
|
|
@@ -1119,10 +1183,19 @@ No releases yet. Use \`pa:release\` to generate release notes.
|
|
|
1119
1183
|
}
|
|
1120
1184
|
console.log(chalk.green(`\n✓ Using template: ${PROJECT_TEMPLATES[options.template].name}`));
|
|
1121
1185
|
} else {
|
|
1122
|
-
// Interactive prompts
|
|
1123
|
-
projectConfig = await promptProjectConfig(targetDir);
|
|
1186
|
+
// Interactive prompts - pass existing config for pre-filling
|
|
1187
|
+
projectConfig = await promptProjectConfig(targetDir, existingConfig);
|
|
1124
1188
|
}
|
|
1125
1189
|
|
|
1190
|
+
// Save progress after project config
|
|
1191
|
+
savePartialConfig(configPath, {
|
|
1192
|
+
project: {
|
|
1193
|
+
name: projectConfig.name,
|
|
1194
|
+
type: projectConfig.type
|
|
1195
|
+
},
|
|
1196
|
+
_step: 'project_config'
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1126
1199
|
// Add ProAgents section to README.md (AI tools auto-read this)
|
|
1127
1200
|
const readmePath = join(targetDir, 'README.md');
|
|
1128
1201
|
const proagentsSection = `
|
|
@@ -1161,9 +1234,16 @@ For detailed commands, see \`./.proagents/PROAGENTS.md\`
|
|
|
1161
1234
|
selectedPlatforms = projectConfig.platforms;
|
|
1162
1235
|
console.log(chalk.gray(` Using template platforms: ${selectedPlatforms.join(', ')}`));
|
|
1163
1236
|
} else {
|
|
1164
|
-
|
|
1237
|
+
// Pass existing config for pre-selection
|
|
1238
|
+
selectedPlatforms = await selectPlatforms(existingConfig.ai_platforms);
|
|
1165
1239
|
}
|
|
1166
1240
|
|
|
1241
|
+
// Save progress after platform selection
|
|
1242
|
+
savePartialConfig(configPath, {
|
|
1243
|
+
ai_platforms: selectedPlatforms,
|
|
1244
|
+
_step: 'platforms'
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1167
1247
|
// Copy AI instruction files for selected platforms (merges with existing files)
|
|
1168
1248
|
const aiResults = copyPlatformFiles(selectedPlatforms, sourceDir, targetDir);
|
|
1169
1249
|
|
|
@@ -1177,11 +1257,16 @@ For detailed commands, see \`./.proagents/PROAGENTS.md\`
|
|
|
1177
1257
|
console.log(chalk.green(`✓ Merged with existing: ${aiResults.merged.join(', ')}`));
|
|
1178
1258
|
}
|
|
1179
1259
|
|
|
1180
|
-
// Save project and platform config
|
|
1181
|
-
const configPath = join(targetDir, 'proagents.config.yaml');
|
|
1260
|
+
// Save final project and platform config (removes _setup marker)
|
|
1182
1261
|
saveProjectConfig(projectConfig, configPath);
|
|
1183
1262
|
savePlatformConfig(selectedPlatforms, configPath);
|
|
1184
1263
|
|
|
1264
|
+
// Clean up setup progress marker
|
|
1265
|
+
const finalConfig = loadPartialConfig(configPath);
|
|
1266
|
+
delete finalConfig._setup;
|
|
1267
|
+
const yamlContent = yaml.dump(finalConfig, { indent: 2, lineWidth: 120 });
|
|
1268
|
+
writeFileSync(configPath, yamlContent);
|
|
1269
|
+
|
|
1185
1270
|
// Success message
|
|
1186
1271
|
console.log(chalk.green('\n✓ ProAgents initialized successfully!\n'));
|
|
1187
1272
|
|