proagents 1.6.12 → 1.6.15
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/.cursorrules +16 -2
- package/.proagents/.learning/global/common-patterns.template.json +60 -0
- package/.proagents/.learning/global/user-preferences.template.json +78 -0
- package/.proagents/.windsurfrules +16 -2
- package/.proagents/AGENTS.md +55 -0
- package/.proagents/AI_INSTRUCTIONS.md +1252 -53
- package/.proagents/ANTIGRAVITY.md +16 -2
- package/.proagents/BOLT.md +16 -2
- package/.proagents/CHATGPT.md +16 -2
- package/.proagents/CLAUDE.md +16 -2
- package/.proagents/GEMINI.md +16 -2
- package/.proagents/GROQ.md +16 -2
- package/.proagents/KIRO.md +16 -2
- package/.proagents/LOVABLE.md +16 -2
- package/.proagents/PROAGENTS.md +52 -26
- package/.proagents/REPLIT.md +16 -2
- package/.proagents/active-features/_index.template.json +75 -0
- package/.proagents/changelog/_recent.template.md +51 -0
- package/.proagents/docs/command-details.md +985 -82
- package/.proagents/worklog/_context.md +31 -1
- package/.proagents/worklog/_context.template.md +82 -0
- package/.proagents/worklog/ai-stats.json +19 -0
- package/.proagents/worklog/ai-stats.template.json +54 -0
- package/README.md +85 -1
- package/bin/proagents.js +132 -1
- package/lib/commands/ai.js +103 -11
- package/lib/commands/changelog.js +389 -0
- package/lib/commands/completion.js +413 -0
- package/lib/commands/config.js +248 -0
- package/lib/commands/doctor.js +222 -25
- package/lib/commands/help.js +22 -2
- package/lib/commands/init.js +171 -2
- package/lib/commands/open.js +188 -0
- package/lib/commands/release.js +1007 -0
- package/lib/commands/restore.js +150 -0
- package/lib/commands/stats.js +320 -0
- package/lib/commands/uninstall.js +98 -4
- package/lib/commands/upgrade.js +102 -10
- package/lib/commands/version.js +140 -0
- package/package.json +1 -1
package/lib/commands/doctor.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
import yaml from 'js-yaml';
|
|
5
6
|
|
|
@@ -98,7 +99,9 @@ function checkPlatformSync(targetDir) {
|
|
|
98
99
|
const content = readFileSync(configPath, 'utf-8');
|
|
99
100
|
const config = yaml.load(content);
|
|
100
101
|
configPlatforms = config?.platforms || config?.ai_platforms || [];
|
|
101
|
-
} catch {
|
|
102
|
+
} catch {
|
|
103
|
+
// Config file unreadable - will be caught by other checks
|
|
104
|
+
}
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
// Check each platform file
|
|
@@ -134,7 +137,7 @@ function checkPlatformSync(targetDir) {
|
|
|
134
137
|
* Check for lock file
|
|
135
138
|
*/
|
|
136
139
|
function checkLockFile(targetDir) {
|
|
137
|
-
const lockPath = join(targetDir, 'proagents', '.lock');
|
|
140
|
+
const lockPath = join(targetDir, '.proagents', '.lock');
|
|
138
141
|
const checks = [];
|
|
139
142
|
|
|
140
143
|
if (existsSync(lockPath)) {
|
|
@@ -163,18 +166,187 @@ function checkLockFile(targetDir) {
|
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
/**
|
|
166
|
-
*
|
|
169
|
+
* Extended checks for --full mode
|
|
167
170
|
*/
|
|
168
|
-
|
|
171
|
+
function checkExtended(targetDir) {
|
|
169
172
|
const checks = [];
|
|
170
173
|
|
|
174
|
+
// Check changelog size
|
|
175
|
+
const recentPath = join(targetDir, '.proagents', 'changelog', '_recent.md');
|
|
176
|
+
if (existsSync(recentPath)) {
|
|
177
|
+
try {
|
|
178
|
+
const content = readFileSync(recentPath, 'utf-8');
|
|
179
|
+
const entries = (content.match(/^### /gm) || []).length;
|
|
180
|
+
if (entries > 50) {
|
|
181
|
+
checks.push({ name: 'Changelog size', status: 'warning', message: `${entries} entries (consider archiving)` });
|
|
182
|
+
} else {
|
|
183
|
+
checks.push({ name: 'Changelog size', status: 'ok', message: `${entries} entries` });
|
|
184
|
+
}
|
|
185
|
+
} catch {
|
|
186
|
+
checks.push({ name: 'Changelog size', status: 'skip', message: 'Could not read' });
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
checks.push({ name: 'Changelog', status: 'info', message: 'No recent changelog' });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Check activity log freshness
|
|
193
|
+
const activityPath = join(targetDir, '.proagents', 'activity.log');
|
|
194
|
+
if (existsSync(activityPath)) {
|
|
195
|
+
try {
|
|
196
|
+
const content = readFileSync(activityPath, 'utf-8');
|
|
197
|
+
const lines = content.trim().split('\n').filter(l => l && !l.startsWith('#') && !l.includes('Activity Log'));
|
|
198
|
+
if (lines.length > 0) {
|
|
199
|
+
const lastLine = lines[lines.length - 1];
|
|
200
|
+
const dateMatch = lastLine.match(/^\[?(\d{4}-\d{2}-\d{2})/);
|
|
201
|
+
if (dateMatch) {
|
|
202
|
+
const lastDate = new Date(dateMatch[1]);
|
|
203
|
+
const daysAgo = Math.floor((Date.now() - lastDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
204
|
+
if (daysAgo > 7) {
|
|
205
|
+
checks.push({ name: 'Activity log', status: 'warning', message: `Last entry ${daysAgo} days ago` });
|
|
206
|
+
} else if (daysAgo > 0) {
|
|
207
|
+
checks.push({ name: 'Activity log', status: 'ok', message: `Last entry ${daysAgo} day(s) ago` });
|
|
208
|
+
} else {
|
|
209
|
+
checks.push({ name: 'Activity log', status: 'ok', message: 'Activity today' });
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
checks.push({ name: 'Activity log', status: 'ok', message: `${lines.length} entries` });
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
checks.push({ name: 'Activity log', status: 'info', message: 'No entries yet' });
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
checks.push({ name: 'Activity log', status: 'skip', message: 'Could not read' });
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
checks.push({ name: 'Activity log', status: 'info', message: 'No activity log' });
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check for stale feature branches
|
|
171
225
|
try {
|
|
172
|
-
|
|
226
|
+
const branches = execSync('git branch --list "feature/*" 2>/dev/null', { encoding: 'utf-8' }).trim();
|
|
227
|
+
if (branches) {
|
|
228
|
+
const branchCount = branches.split('\n').filter(b => b.trim()).length;
|
|
229
|
+
if (branchCount > 5) {
|
|
230
|
+
checks.push({ name: 'Feature branches', status: 'warning', message: `${branchCount} branches (consider cleanup)` });
|
|
231
|
+
} else if (branchCount > 0) {
|
|
232
|
+
checks.push({ name: 'Feature branches', status: 'ok', message: `${branchCount} active` });
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
checks.push({ name: 'Feature branches', status: 'ok', message: 'None' });
|
|
236
|
+
}
|
|
237
|
+
} catch {
|
|
238
|
+
checks.push({ name: 'Feature branches', status: 'skip', message: 'Not a git repo or no feature branches' });
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Check active features
|
|
242
|
+
const featuresPath = join(targetDir, '.proagents', 'active-features', '_index.json');
|
|
243
|
+
if (existsSync(featuresPath)) {
|
|
244
|
+
try {
|
|
245
|
+
const content = readFileSync(featuresPath, 'utf-8');
|
|
246
|
+
const index = JSON.parse(content);
|
|
247
|
+
const activeCount = index.active_features?.length || 0;
|
|
248
|
+
const completedCount = index.completed_features?.length || 0;
|
|
249
|
+
|
|
250
|
+
if (activeCount > 0) {
|
|
251
|
+
checks.push({ name: 'Active features', status: 'ok', message: `${activeCount} active, ${completedCount} completed` });
|
|
252
|
+
} else {
|
|
253
|
+
checks.push({ name: 'Active features', status: 'info', message: `None active, ${completedCount} completed` });
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
checks.push({ name: 'Active features', status: 'skip', message: 'Could not read index' });
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
checks.push({ name: 'Active features', status: 'info', message: 'No features tracked' });
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Check worklog context
|
|
263
|
+
const contextPath = join(targetDir, '.proagents', 'worklog', '_context.md');
|
|
264
|
+
if (existsSync(contextPath)) {
|
|
265
|
+
checks.push({ name: 'Worklog context', status: 'ok', message: 'Present' });
|
|
266
|
+
} else {
|
|
267
|
+
checks.push({ name: 'Worklog context', status: 'warning', message: 'Missing (cross-AI sync may be affected)' });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Check for required folders
|
|
271
|
+
const requiredFolders = [
|
|
272
|
+
{ path: '.proagents/prompts', name: 'Prompts folder' },
|
|
273
|
+
{ path: '.proagents/templates', name: 'Templates folder' },
|
|
274
|
+
{ path: '.proagents/changelog', name: 'Changelog folder' },
|
|
275
|
+
{ path: '.proagents/worklog', name: 'Worklog folder' }
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
for (const folder of requiredFolders) {
|
|
279
|
+
if (existsSync(join(targetDir, folder.path))) {
|
|
280
|
+
checks.push({ name: folder.name, status: 'ok', message: 'Present' });
|
|
281
|
+
} else {
|
|
282
|
+
checks.push({ name: folder.name, status: 'warning', message: 'Missing' });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return checks;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Compare semantic versions
|
|
291
|
+
* Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
|
|
292
|
+
*/
|
|
293
|
+
function compareVersions(v1, v2) {
|
|
294
|
+
const parts1 = v1.split('.').map(Number);
|
|
295
|
+
const parts2 = v2.split('.').map(Number);
|
|
296
|
+
|
|
297
|
+
for (let i = 0; i < 3; i++) {
|
|
298
|
+
const p1 = parts1[i] || 0;
|
|
299
|
+
const p2 = parts2[i] || 0;
|
|
300
|
+
if (p1 < p2) return -1;
|
|
301
|
+
if (p1 > p2) return 1;
|
|
302
|
+
}
|
|
303
|
+
return 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Check version (CLI, project, and npm)
|
|
308
|
+
*/
|
|
309
|
+
async function checkVersion(targetDir) {
|
|
310
|
+
const checks = [];
|
|
311
|
+
const recommendations = [];
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
// Get CLI version from package.json
|
|
173
315
|
const packagePath = new URL('../../package.json', import.meta.url);
|
|
174
316
|
const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
checks.push({ name: '
|
|
317
|
+
const cliVersion = packageJson.version;
|
|
318
|
+
|
|
319
|
+
checks.push({ name: 'CLI version', status: 'info', message: `v${cliVersion}` });
|
|
320
|
+
|
|
321
|
+
// Get project version from .proagents/.version
|
|
322
|
+
const projectVersionPath = join(targetDir, '.proagents', '.version');
|
|
323
|
+
let projectVersion = null;
|
|
324
|
+
|
|
325
|
+
if (existsSync(projectVersionPath)) {
|
|
326
|
+
try {
|
|
327
|
+
projectVersion = readFileSync(projectVersionPath, 'utf-8').trim();
|
|
328
|
+
|
|
329
|
+
if (projectVersion === cliVersion) {
|
|
330
|
+
checks.push({ name: 'Project version', status: 'ok', message: `v${projectVersion} (synced with CLI)` });
|
|
331
|
+
} else if (compareVersions(projectVersion, cliVersion) < 0) {
|
|
332
|
+
checks.push({ name: 'Project version', status: 'warning', message: `v${projectVersion} (outdated)` });
|
|
333
|
+
recommendations.push({
|
|
334
|
+
issue: 'Project framework is outdated',
|
|
335
|
+
action: 'Run `npx proagents init` to update framework files'
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
checks.push({ name: 'Project version', status: 'info', message: `v${projectVersion}` });
|
|
339
|
+
}
|
|
340
|
+
} catch {
|
|
341
|
+
checks.push({ name: 'Project version', status: 'warning', message: 'Could not read version file' });
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
checks.push({ name: 'Project version', status: 'warning', message: 'No version marker (older installation)' });
|
|
345
|
+
recommendations.push({
|
|
346
|
+
issue: 'No version tracking',
|
|
347
|
+
action: 'Run `npx proagents init` to update and add version tracking'
|
|
348
|
+
});
|
|
349
|
+
}
|
|
178
350
|
|
|
179
351
|
// Try to fetch latest version from npm (with timeout)
|
|
180
352
|
try {
|
|
@@ -190,20 +362,24 @@ async function checkVersion() {
|
|
|
190
362
|
const data = await response.json();
|
|
191
363
|
const latestVersion = data.version;
|
|
192
364
|
|
|
193
|
-
if (
|
|
194
|
-
checks.push({ name: '
|
|
365
|
+
if (compareVersions(cliVersion, latestVersion) >= 0) {
|
|
366
|
+
checks.push({ name: 'npm registry', status: 'ok', message: `v${latestVersion} (up to date)` });
|
|
195
367
|
} else {
|
|
196
|
-
checks.push({ name: '
|
|
368
|
+
checks.push({ name: 'npm registry', status: 'warning', message: `v${latestVersion} available` });
|
|
369
|
+
recommendations.push({
|
|
370
|
+
issue: 'CLI update available',
|
|
371
|
+
action: 'Run `npm update -g proagents` to update CLI'
|
|
372
|
+
});
|
|
197
373
|
}
|
|
198
374
|
}
|
|
199
375
|
} catch {
|
|
200
|
-
checks.push({ name: '
|
|
376
|
+
checks.push({ name: 'npm registry', status: 'skip', message: 'Could not check (offline?)' });
|
|
201
377
|
}
|
|
202
|
-
} catch {
|
|
203
|
-
checks.push({ name: 'Version', status: 'error', message:
|
|
378
|
+
} catch (error) {
|
|
379
|
+
checks.push({ name: 'Version', status: 'error', message: `Could not read version: ${error.message}` });
|
|
204
380
|
}
|
|
205
381
|
|
|
206
|
-
return checks;
|
|
382
|
+
return { checks, recommendations };
|
|
207
383
|
}
|
|
208
384
|
|
|
209
385
|
/**
|
|
@@ -248,16 +424,14 @@ function printChecks(title, checks) {
|
|
|
248
424
|
/**
|
|
249
425
|
* Doctor command - check health of ProAgents installation
|
|
250
426
|
*/
|
|
251
|
-
export async function doctorCommand() {
|
|
427
|
+
export async function doctorCommand(options = {}) {
|
|
252
428
|
const targetDir = process.cwd();
|
|
429
|
+
const isFullMode = options.full || false;
|
|
253
430
|
|
|
254
|
-
console.log(chalk.bold('\nProAgents Doctor'));
|
|
255
|
-
console.log(chalk.gray('
|
|
431
|
+
console.log(chalk.bold('\nProAgents Doctor' + (isFullMode ? ' (Full)' : '')));
|
|
432
|
+
console.log(chalk.gray('═'.repeat(40)));
|
|
256
433
|
console.log(chalk.gray(`Checking: ${targetDir}\n`));
|
|
257
434
|
|
|
258
|
-
let hasErrors = false;
|
|
259
|
-
let hasWarnings = false;
|
|
260
|
-
|
|
261
435
|
// Run all checks
|
|
262
436
|
const installChecks = checkInstallation(targetDir);
|
|
263
437
|
printChecks('Installation', installChecks);
|
|
@@ -271,14 +445,32 @@ export async function doctorCommand() {
|
|
|
271
445
|
const lockChecks = checkLockFile(targetDir);
|
|
272
446
|
printChecks('Lock Status', lockChecks);
|
|
273
447
|
|
|
274
|
-
const
|
|
275
|
-
printChecks('Version',
|
|
448
|
+
const versionResult = await checkVersion(targetDir);
|
|
449
|
+
printChecks('Version', versionResult.checks);
|
|
450
|
+
|
|
451
|
+
// Extended checks for --full mode
|
|
452
|
+
let extendedChecks = [];
|
|
453
|
+
if (isFullMode) {
|
|
454
|
+
extendedChecks = checkExtended(targetDir);
|
|
455
|
+
printChecks('Extended Health Checks', extendedChecks);
|
|
456
|
+
}
|
|
276
457
|
|
|
277
458
|
// Count issues
|
|
278
|
-
const allChecks = [...installChecks, ...configChecks, ...platformChecks, ...lockChecks, ...
|
|
459
|
+
const allChecks = [...installChecks, ...configChecks, ...platformChecks, ...lockChecks, ...versionResult.checks, ...extendedChecks];
|
|
279
460
|
const errors = allChecks.filter(c => c.status === 'error').length;
|
|
280
461
|
const warnings = allChecks.filter(c => c.status === 'warning').length;
|
|
281
462
|
|
|
463
|
+
// Recommendations section (if any)
|
|
464
|
+
if (versionResult.recommendations && versionResult.recommendations.length > 0) {
|
|
465
|
+
console.log(chalk.bold('\nRecommendations'));
|
|
466
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
467
|
+
|
|
468
|
+
for (const rec of versionResult.recommendations) {
|
|
469
|
+
console.log(chalk.yellow(` ⚡ ${rec.issue}`));
|
|
470
|
+
console.log(chalk.cyan(` → ${rec.action}`));
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
282
474
|
// Summary
|
|
283
475
|
console.log(chalk.bold('\nSummary'));
|
|
284
476
|
console.log(chalk.gray('─'.repeat(40)));
|
|
@@ -298,8 +490,13 @@ export async function doctorCommand() {
|
|
|
298
490
|
console.log(chalk.gray('Run `npx proagents init` to fix installation issues.'));
|
|
299
491
|
}
|
|
300
492
|
if (platformChecks.some(c => c.status === 'warning')) {
|
|
301
|
-
console.log(chalk.gray('Run `
|
|
493
|
+
console.log(chalk.gray('Run `npx proagents ai add` to fix platform sync issues.'));
|
|
302
494
|
}
|
|
303
495
|
console.log('');
|
|
304
496
|
}
|
|
497
|
+
|
|
498
|
+
// Hint for full mode
|
|
499
|
+
if (!isFullMode) {
|
|
500
|
+
console.log(chalk.gray('Run `proagents doctor --full` for extended health checks.\n'));
|
|
501
|
+
}
|
|
305
502
|
}
|
package/lib/commands/help.js
CHANGED
|
@@ -53,10 +53,30 @@ export async function helpCommand() {
|
|
|
53
53
|
console.log(chalk.bold.white('Status & Info'));
|
|
54
54
|
console.log(chalk.gray('─'.repeat(40)));
|
|
55
55
|
console.log(chalk.cyan('proagents status') + ' Show ProAgents status');
|
|
56
|
+
console.log(chalk.cyan('proagents version') + ' Show detailed version info');
|
|
57
|
+
console.log(chalk.cyan('proagents doctor') + ' Health check installation');
|
|
56
58
|
console.log(chalk.cyan('proagents docs') + ' Open documentation');
|
|
57
59
|
console.log(chalk.cyan('proagents commands') + ' Show this help');
|
|
58
|
-
console.log(
|
|
59
|
-
|
|
60
|
+
console.log('');
|
|
61
|
+
|
|
62
|
+
// Release & Maintenance
|
|
63
|
+
console.log(chalk.bold.white('Release & Maintenance'));
|
|
64
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
65
|
+
console.log(chalk.cyan('proagents release') + ' Interactive release notes');
|
|
66
|
+
console.log(chalk.gray(' Types: -t detailed | short | client | developer | hotfix | prerelease'));
|
|
67
|
+
console.log(chalk.gray(' Filters:'));
|
|
68
|
+
console.log(chalk.cyan(' --include fixes') + ' Only include bug fixes');
|
|
69
|
+
console.log(chalk.cyan(' --include features') + ' Only include features');
|
|
70
|
+
console.log(chalk.cyan(' --exclude docs,deps') + ' Exclude docs and deps');
|
|
71
|
+
console.log(chalk.cyan(' --module auth') + ' Filter by module name');
|
|
72
|
+
console.log(chalk.cyan(' --path src/lib') + ' Filter by file path');
|
|
73
|
+
console.log(chalk.gray(' Options:'));
|
|
74
|
+
console.log(chalk.cyan(' --append') + ' Append to existing notes');
|
|
75
|
+
console.log(chalk.cyan(' --bump') + ' Suggest version bump');
|
|
76
|
+
console.log(chalk.cyan(' --prerelease beta') + ' Mark as beta/rc/alpha');
|
|
77
|
+
console.log(chalk.cyan(' --since v1.0.0') + ' From specific tag');
|
|
78
|
+
console.log(chalk.cyan('proagents upgrade') + ' Upgrade .proagents folder');
|
|
79
|
+
console.log(chalk.cyan('proagents uninstall') + ' Remove ProAgents from project');
|
|
60
80
|
console.log('');
|
|
61
81
|
|
|
62
82
|
// Commands for AI Assistants
|
package/lib/commands/init.js
CHANGED
|
@@ -14,8 +14,133 @@ const PRESERVE_PATHS = [
|
|
|
14
14
|
'active-features', // User's work in progress
|
|
15
15
|
'.learning', // Learned patterns
|
|
16
16
|
'cache', // Cached analysis
|
|
17
|
+
'changelog', // Change history (user data)
|
|
18
|
+
'worklog', // Work context (user data)
|
|
19
|
+
'sessions', // Session data
|
|
20
|
+
'backups', // User backups
|
|
17
21
|
];
|
|
18
22
|
|
|
23
|
+
// Files within PRESERVE_PATHS that should always be UPDATED (framework files)
|
|
24
|
+
// These patterns match files that should be overwritten with latest framework version
|
|
25
|
+
const UPDATE_WITHIN_PRESERVED = [
|
|
26
|
+
'README.md', // Documentation
|
|
27
|
+
'entry-template.md', // Changelog entry template
|
|
28
|
+
'*.template.md', // All template markdown files
|
|
29
|
+
'*.template.json', // All template JSON files
|
|
30
|
+
'schemas', // Schema folders
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Backup user data before fresh install
|
|
35
|
+
* Returns object mapping path to temp backup location
|
|
36
|
+
*/
|
|
37
|
+
function backupUserData(proagentsDir) {
|
|
38
|
+
const preserved = {};
|
|
39
|
+
for (const path of PRESERVE_PATHS) {
|
|
40
|
+
const fullPath = join(proagentsDir, path);
|
|
41
|
+
if (existsSync(fullPath)) {
|
|
42
|
+
const tempPath = join(proagentsDir, '..', `.proagents-backup-${path.replace(/\//g, '-')}`);
|
|
43
|
+
try {
|
|
44
|
+
cpSync(fullPath, tempPath, { recursive: true });
|
|
45
|
+
preserved[path] = tempPath;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
// Silently continue if backup fails
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return preserved;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Restore user data after fresh install
|
|
56
|
+
*/
|
|
57
|
+
function restoreUserData(proagentsDir, preserved) {
|
|
58
|
+
for (const [path, tempPath] of Object.entries(preserved)) {
|
|
59
|
+
const fullPath = join(proagentsDir, path);
|
|
60
|
+
if (existsSync(tempPath)) {
|
|
61
|
+
try {
|
|
62
|
+
// Remove the framework's empty/default version
|
|
63
|
+
if (existsSync(fullPath)) {
|
|
64
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
// Restore user's data
|
|
67
|
+
cpSync(tempPath, fullPath, { recursive: true });
|
|
68
|
+
// Clean up temp backup
|
|
69
|
+
rmSync(tempPath, { recursive: true, force: true });
|
|
70
|
+
} catch (err) {
|
|
71
|
+
// Silently continue if restore fails
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Update framework files within preserved paths
|
|
79
|
+
* After restoring user data, this copies framework files like README.md, *.template.*, schemas/
|
|
80
|
+
*/
|
|
81
|
+
function updateFrameworkInPreserved(sourceDir, proagentsDir) {
|
|
82
|
+
for (const preservedPath of PRESERVE_PATHS) {
|
|
83
|
+
const sourcePath = join(sourceDir, preservedPath);
|
|
84
|
+
const targetPath = join(proagentsDir, preservedPath);
|
|
85
|
+
|
|
86
|
+
if (!existsSync(sourcePath) || !existsSync(targetPath)) continue;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
// Update README.md if exists
|
|
90
|
+
const sourceReadme = join(sourcePath, 'README.md');
|
|
91
|
+
const targetReadme = join(targetPath, 'README.md');
|
|
92
|
+
if (existsSync(sourceReadme)) {
|
|
93
|
+
cpSync(sourceReadme, targetReadme, { force: true });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Update entry-template.md (for changelog)
|
|
97
|
+
const sourceEntryTemplate = join(sourcePath, 'entry-template.md');
|
|
98
|
+
const targetEntryTemplate = join(targetPath, 'entry-template.md');
|
|
99
|
+
if (existsSync(sourceEntryTemplate)) {
|
|
100
|
+
cpSync(sourceEntryTemplate, targetEntryTemplate, { force: true });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Update schemas folder if exists
|
|
104
|
+
const sourceSchemas = join(sourcePath, 'schemas');
|
|
105
|
+
const targetSchemas = join(targetPath, 'schemas');
|
|
106
|
+
if (existsSync(sourceSchemas)) {
|
|
107
|
+
if (existsSync(targetSchemas)) {
|
|
108
|
+
rmSync(targetSchemas, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
cpSync(sourceSchemas, targetSchemas, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Update all *.template.md and *.template.json files
|
|
114
|
+
if (existsSync(sourcePath)) {
|
|
115
|
+
const entries = readdirSync(sourcePath, { withFileTypes: true });
|
|
116
|
+
for (const entry of entries) {
|
|
117
|
+
if (entry.isFile() && (entry.name.endsWith('.template.md') || entry.name.endsWith('.template.json'))) {
|
|
118
|
+
cpSync(join(sourcePath, entry.name), join(targetPath, entry.name), { force: true });
|
|
119
|
+
}
|
|
120
|
+
// Also check subdirectories (like .learning/global/)
|
|
121
|
+
if (entry.isDirectory()) {
|
|
122
|
+
const subPath = join(sourcePath, entry.name);
|
|
123
|
+
const subTargetPath = join(targetPath, entry.name);
|
|
124
|
+
if (existsSync(subPath)) {
|
|
125
|
+
const subEntries = readdirSync(subPath, { withFileTypes: true });
|
|
126
|
+
for (const subEntry of subEntries) {
|
|
127
|
+
if (subEntry.isFile() && (subEntry.name.endsWith('.template.md') || subEntry.name.endsWith('.template.json'))) {
|
|
128
|
+
if (!existsSync(subTargetPath)) {
|
|
129
|
+
mkdirSync(subTargetPath, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
cpSync(join(subPath, subEntry.name), join(subTargetPath, subEntry.name), { force: true });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
// Silently continue if update fails
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
19
144
|
// Config file is handled specially - merged not preserved
|
|
20
145
|
const CONFIG_FILE = 'proagents.config.yaml';
|
|
21
146
|
|
|
@@ -41,7 +166,6 @@ const FRAMEWORK_FOLDERS = [
|
|
|
41
166
|
'api-versioning',
|
|
42
167
|
'approval-workflows',
|
|
43
168
|
'automation',
|
|
44
|
-
'changelog',
|
|
45
169
|
'cicd',
|
|
46
170
|
'collaboration',
|
|
47
171
|
'compliance',
|
|
@@ -89,6 +213,7 @@ const FRAMEWORK_FILES = [
|
|
|
89
213
|
'GETTING-STARTED-STORY.md',
|
|
90
214
|
'slash-commands.json',
|
|
91
215
|
'AI_INSTRUCTIONS.md', // Universal instructions kept for reference
|
|
216
|
+
'AGENTS.md', // Universal AI instruction file (works with most AI platforms)
|
|
92
217
|
];
|
|
93
218
|
|
|
94
219
|
// Project type definitions for detection
|
|
@@ -610,7 +735,7 @@ function checkIncompleteSetup(targetDir) {
|
|
|
610
735
|
}
|
|
611
736
|
|
|
612
737
|
// Check 2: No AI instruction files at all = incomplete
|
|
613
|
-
const aiFiles = ['CLAUDE.md', '.cursorrules', '.windsurfrules', 'CHATGPT.md', 'GEMINI.md'];
|
|
738
|
+
const aiFiles = ['AGENTS.md', 'CLAUDE.md', '.cursorrules', '.windsurfrules', 'CHATGPT.md', 'GEMINI.md'];
|
|
614
739
|
const hasAnyAiFile = aiFiles.some(f => existsSync(join(targetDir, f)));
|
|
615
740
|
if (!hasAnyAiFile) {
|
|
616
741
|
return true;
|
|
@@ -666,6 +791,27 @@ async function promptIncompleteSetupChoice() {
|
|
|
666
791
|
return 'continue';
|
|
667
792
|
}
|
|
668
793
|
|
|
794
|
+
/**
|
|
795
|
+
* Confirm destructive "Restart fresh" action
|
|
796
|
+
*/
|
|
797
|
+
async function confirmRestartFresh() {
|
|
798
|
+
const rl = createInterface({
|
|
799
|
+
input: process.stdin,
|
|
800
|
+
output: process.stdout
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
const question = (prompt) => new Promise(resolve => rl.question(prompt, resolve));
|
|
804
|
+
|
|
805
|
+
console.log(chalk.red.bold('\n⚠️ WARNING: This will DELETE all data in .proagents/'));
|
|
806
|
+
console.log(chalk.yellow(' Including: changelog, worklog, sessions, learning data, etc.'));
|
|
807
|
+
console.log(chalk.gray(' This action cannot be undone.\n'));
|
|
808
|
+
|
|
809
|
+
const answer = await question(chalk.red('Type "DELETE" to confirm, or press Enter to cancel: '));
|
|
810
|
+
rl.close();
|
|
811
|
+
|
|
812
|
+
return answer.trim().toUpperCase() === 'DELETE';
|
|
813
|
+
}
|
|
814
|
+
|
|
669
815
|
/**
|
|
670
816
|
* Prompt user for .gitignore preference
|
|
671
817
|
*/
|
|
@@ -980,6 +1126,12 @@ export async function initCommand(options = {}) {
|
|
|
980
1126
|
console.log(chalk.cyan('\nContinuing setup...\n'));
|
|
981
1127
|
// Fall through to fresh install (but keep .proagents folder)
|
|
982
1128
|
} else if (choice === 'restart') {
|
|
1129
|
+
// Confirm destructive action
|
|
1130
|
+
const confirmed = await confirmRestartFresh();
|
|
1131
|
+
if (!confirmed) {
|
|
1132
|
+
console.log(chalk.yellow('\nCancelled. No changes made.\n'));
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
983
1135
|
console.log(chalk.cyan('\nRestarting fresh setup...\n'));
|
|
984
1136
|
rmSync(proagentsDir, { recursive: true, force: true });
|
|
985
1137
|
// Fall through to fresh install
|
|
@@ -1025,7 +1177,21 @@ export async function initCommand(options = {}) {
|
|
|
1025
1177
|
|
|
1026
1178
|
// Fresh install or force overwrite
|
|
1027
1179
|
console.log(chalk.gray('Copying framework files...'));
|
|
1180
|
+
|
|
1181
|
+
// Backup user data if .proagents exists (to preserve changelog, worklog, etc.)
|
|
1182
|
+
const userDataBackup = existsSync(proagentsDir) ? backupUserData(proagentsDir) : {};
|
|
1183
|
+
|
|
1028
1184
|
cpSync(sourceDir, proagentsDir, { recursive: true, force: true });
|
|
1185
|
+
|
|
1186
|
+
// Restore user data after framework copy
|
|
1187
|
+
if (Object.keys(userDataBackup).length > 0) {
|
|
1188
|
+
restoreUserData(proagentsDir, userDataBackup);
|
|
1189
|
+
// Update framework files within preserved paths (README.md, templates, schemas)
|
|
1190
|
+
updateFrameworkInPreserved(sourceDir, proagentsDir);
|
|
1191
|
+
console.log(chalk.green('✓ Preserved user data (changelog, worklog, sessions, etc.)'));
|
|
1192
|
+
console.log(chalk.green('✓ Updated templates and documentation in preserved folders'));
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1029
1195
|
console.log(chalk.green('✓ Framework files copied to ./.proagents/'));
|
|
1030
1196
|
|
|
1031
1197
|
// Create config if not skipped
|
|
@@ -1397,6 +1563,9 @@ async function smartUpdate(sourceDir, targetDir) {
|
|
|
1397
1563
|
}
|
|
1398
1564
|
}
|
|
1399
1565
|
|
|
1566
|
+
// Update framework files within preserved paths (templates, README, schemas)
|
|
1567
|
+
updateFrameworkInPreserved(sourceDir, targetDir);
|
|
1568
|
+
|
|
1400
1569
|
console.log(chalk.gray('\nTip: Use "proagents ai add" to add more AI platforms'));
|
|
1401
1570
|
}
|
|
1402
1571
|
|