proagents 1.6.11 → 1.6.13

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.
@@ -0,0 +1,389 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { execSync } from 'child_process';
4
+ import chalk from 'chalk';
5
+
6
+ /**
7
+ * Get recent changes from _recent.md
8
+ */
9
+ function getRecentChanges(proagentsDir) {
10
+ const recentPath = join(proagentsDir, 'changelog', '_recent.md');
11
+ if (existsSync(recentPath)) {
12
+ return readFileSync(recentPath, 'utf-8');
13
+ }
14
+ return null;
15
+ }
16
+
17
+ /**
18
+ * Add entry to _recent.md
19
+ */
20
+ function addToRecent(proagentsDir, entry) {
21
+ const changelogDir = join(proagentsDir, 'changelog');
22
+ const recentPath = join(changelogDir, '_recent.md');
23
+
24
+ // Ensure directory exists
25
+ if (!existsSync(changelogDir)) {
26
+ mkdirSync(changelogDir, { recursive: true });
27
+ }
28
+
29
+ const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);
30
+ const formattedEntry = `- [${timestamp}] ${entry}\n`;
31
+
32
+ if (existsSync(recentPath)) {
33
+ const existing = readFileSync(recentPath, 'utf-8');
34
+ const lines = existing.split('\n').filter(l => l.trim());
35
+
36
+ // Keep only last 50 entries
37
+ const updatedLines = [formattedEntry.trim(), ...lines].slice(0, 50);
38
+ writeFileSync(recentPath, updatedLines.join('\n') + '\n');
39
+ } else {
40
+ writeFileSync(recentPath, `# Recent Changes\n\n${formattedEntry}`);
41
+ }
42
+
43
+ return { success: true, timestamp };
44
+ }
45
+
46
+ /**
47
+ * Generate changelog from git commits
48
+ */
49
+ function generateFromGit(options = {}) {
50
+ const { since, until, limit = 50 } = options;
51
+
52
+ try {
53
+ let command = 'git log';
54
+
55
+ if (since) {
56
+ command += ` ${since}..${until || 'HEAD'}`;
57
+ } else {
58
+ command += ` -${limit}`;
59
+ }
60
+
61
+ command += ' --pretty=format:"- %s (%h, %an, %ad)" --date=short';
62
+
63
+ const output = execSync(command, { encoding: 'utf-8' });
64
+ return output.trim();
65
+ } catch (error) {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Export changelog to CHANGELOG.md
72
+ */
73
+ function exportChangelog(targetDir, proagentsDir, options = {}) {
74
+ const changelogPath = join(targetDir, 'CHANGELOG.md');
75
+
76
+ let content = `# Changelog
77
+
78
+ All notable changes to this project will be documented in this file.
79
+
80
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
81
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
82
+
83
+ `;
84
+
85
+ // Get recent changes
86
+ const recent = getRecentChanges(proagentsDir);
87
+ if (recent) {
88
+ content += `## [Unreleased]\n\n`;
89
+ // Parse recent changes
90
+ const lines = recent.split('\n').filter(l => l.startsWith('- ['));
91
+ if (lines.length > 0) {
92
+ content += lines.join('\n') + '\n\n';
93
+ }
94
+ }
95
+
96
+ // Add git history if requested
97
+ if (options.includeGit) {
98
+ const gitLog = generateFromGit({ limit: 100 });
99
+ if (gitLog) {
100
+ content += `## Git History\n\n${gitLog}\n`;
101
+ }
102
+ }
103
+
104
+ writeFileSync(changelogPath, content);
105
+ return changelogPath;
106
+ }
107
+
108
+ /**
109
+ * View changelog for a specific feature
110
+ */
111
+ function viewFeatureChangelog(proagentsDir, featureName) {
112
+ const featurePath = join(proagentsDir, 'changelog', 'features', `${featureName}.md`);
113
+ if (existsSync(featurePath)) {
114
+ return readFileSync(featurePath, 'utf-8');
115
+ }
116
+ return null;
117
+ }
118
+
119
+ /**
120
+ * View changelog for a specific module
121
+ */
122
+ function viewModuleChangelog(proagentsDir, moduleName) {
123
+ const modulePath = join(proagentsDir, 'changelog', 'modules', `${moduleName}.md`);
124
+ if (existsSync(modulePath)) {
125
+ return readFileSync(modulePath, 'utf-8');
126
+ }
127
+ return null;
128
+ }
129
+
130
+ /**
131
+ * List available changelogs
132
+ */
133
+ function listChangelogs(proagentsDir) {
134
+ const result = { features: [], modules: [], years: [] };
135
+
136
+ const changelogDir = join(proagentsDir, 'changelog');
137
+ if (!existsSync(changelogDir)) return result;
138
+
139
+ // Features
140
+ const featuresDir = join(changelogDir, 'features');
141
+ if (existsSync(featuresDir)) {
142
+ try {
143
+ result.features = readdirSync(featuresDir)
144
+ .filter(f => f.endsWith('.md'))
145
+ .map(f => f.replace('.md', ''));
146
+ } catch {
147
+ // Directory not readable
148
+ }
149
+ }
150
+
151
+ // Modules
152
+ const modulesDir = join(changelogDir, 'modules');
153
+ if (existsSync(modulesDir)) {
154
+ try {
155
+ result.modules = readdirSync(modulesDir)
156
+ .filter(f => f.endsWith('.md'))
157
+ .map(f => f.replace('.md', ''));
158
+ } catch {
159
+ // Directory not readable
160
+ }
161
+ }
162
+
163
+ // Year folders
164
+ try {
165
+ const entries = readdirSync(changelogDir, { withFileTypes: true });
166
+ result.years = entries
167
+ .filter(e => e.isDirectory() && /^20[2-9][0-9]$/.test(e.name))
168
+ .map(e => e.name);
169
+ } catch {
170
+ // Directory not readable
171
+ }
172
+
173
+ return result;
174
+ }
175
+
176
+ /**
177
+ * Changelog command - manage project changelogs
178
+ */
179
+ export async function changelogCommand(action, value, options = {}) {
180
+ const targetDir = process.cwd();
181
+ const proagentsDir = join(targetDir, '.proagents');
182
+
183
+ // Ensure proagents exists for some commands
184
+ if (!existsSync(proagentsDir) && action !== 'export') {
185
+ console.log(chalk.yellow('\nProAgents is not installed in this project.'));
186
+ console.log(chalk.gray('Run `npx proagents init` to initialize.\n'));
187
+ return;
188
+ }
189
+
190
+ // Handle different actions
191
+ switch (action) {
192
+ case 'add': {
193
+ if (!value) {
194
+ console.log(chalk.red('\nError: Please provide a changelog entry.'));
195
+ console.log(chalk.gray('Usage: proagents changelog add "Fixed login bug"\n'));
196
+ return;
197
+ }
198
+
199
+ const result = addToRecent(proagentsDir, value);
200
+
201
+ if (options.json) {
202
+ console.log(JSON.stringify(result, null, 2));
203
+ } else {
204
+ console.log(chalk.green(`\n✓ Added to changelog: ${value}`));
205
+ console.log(chalk.gray(` Timestamp: ${result.timestamp}\n`));
206
+ }
207
+ break;
208
+ }
209
+
210
+ case 'view':
211
+ case 'show':
212
+ default: {
213
+ console.log(chalk.bold('\nRecent Changes'));
214
+ console.log(chalk.gray('==============\n'));
215
+
216
+ const recent = getRecentChanges(proagentsDir);
217
+ if (recent) {
218
+ // Show last N entries
219
+ const limit = options.limit || 10;
220
+ const lines = recent.split('\n').filter(l => l.startsWith('- ['));
221
+ const display = lines.slice(0, limit);
222
+
223
+ if (display.length > 0) {
224
+ for (const line of display) {
225
+ // Color-code by type
226
+ if (line.toLowerCase().includes('fix')) {
227
+ console.log(chalk.blue(line));
228
+ } else if (line.toLowerCase().includes('feat') || line.toLowerCase().includes('add')) {
229
+ console.log(chalk.green(line));
230
+ } else if (line.toLowerCase().includes('break')) {
231
+ console.log(chalk.red(line));
232
+ } else {
233
+ console.log(line);
234
+ }
235
+ }
236
+ if (lines.length > limit) {
237
+ console.log(chalk.gray(`\n... and ${lines.length - limit} more entries`));
238
+ }
239
+ } else {
240
+ console.log(chalk.gray('No recent changes recorded.'));
241
+ }
242
+ } else {
243
+ console.log(chalk.gray('No changelog found.'));
244
+ }
245
+ console.log('');
246
+ break;
247
+ }
248
+
249
+ case 'list': {
250
+ console.log(chalk.bold('\nAvailable Changelogs'));
251
+ console.log(chalk.gray('====================\n'));
252
+
253
+ const changelogs = listChangelogs(proagentsDir);
254
+
255
+ if (options.json) {
256
+ console.log(JSON.stringify(changelogs, null, 2));
257
+ return;
258
+ }
259
+
260
+ if (changelogs.features.length > 0) {
261
+ console.log(chalk.cyan('Features:'));
262
+ for (const f of changelogs.features) {
263
+ console.log(` • ${f}`);
264
+ }
265
+ console.log('');
266
+ }
267
+
268
+ if (changelogs.modules.length > 0) {
269
+ console.log(chalk.cyan('Modules:'));
270
+ for (const m of changelogs.modules) {
271
+ console.log(` • ${m}`);
272
+ }
273
+ console.log('');
274
+ }
275
+
276
+ if (changelogs.years.length > 0) {
277
+ console.log(chalk.cyan('Years:'));
278
+ for (const y of changelogs.years) {
279
+ console.log(` • ${y}`);
280
+ }
281
+ console.log('');
282
+ }
283
+
284
+ if (changelogs.features.length === 0 && changelogs.modules.length === 0 && changelogs.years.length === 0) {
285
+ console.log(chalk.gray('No changelogs found.\n'));
286
+ }
287
+ break;
288
+ }
289
+
290
+ case 'feature': {
291
+ if (!value) {
292
+ console.log(chalk.red('\nError: Please provide a feature name.'));
293
+ console.log(chalk.gray('Usage: proagents changelog feature <name>\n'));
294
+ return;
295
+ }
296
+
297
+ const featureLog = viewFeatureChangelog(proagentsDir, value);
298
+ if (featureLog) {
299
+ console.log(chalk.bold(`\nFeature Changelog: ${value}`));
300
+ console.log(chalk.gray('─'.repeat(40)));
301
+ console.log(featureLog);
302
+ } else {
303
+ console.log(chalk.yellow(`\nNo changelog found for feature: ${value}\n`));
304
+ }
305
+ break;
306
+ }
307
+
308
+ case 'module': {
309
+ if (!value) {
310
+ console.log(chalk.red('\nError: Please provide a module name.'));
311
+ console.log(chalk.gray('Usage: proagents changelog module <name>\n'));
312
+ return;
313
+ }
314
+
315
+ const moduleLog = viewModuleChangelog(proagentsDir, value);
316
+ if (moduleLog) {
317
+ console.log(chalk.bold(`\nModule Changelog: ${value}`));
318
+ console.log(chalk.gray('─'.repeat(40)));
319
+ console.log(moduleLog);
320
+ } else {
321
+ console.log(chalk.yellow(`\nNo changelog found for module: ${value}\n`));
322
+ }
323
+ break;
324
+ }
325
+
326
+ case 'export': {
327
+ console.log(chalk.bold('\nExporting Changelog'));
328
+ console.log(chalk.gray('===================\n'));
329
+
330
+ const outputPath = exportChangelog(targetDir, proagentsDir, {
331
+ includeGit: options.git
332
+ });
333
+
334
+ if (options.json) {
335
+ console.log(JSON.stringify({ success: true, path: outputPath }, null, 2));
336
+ } else {
337
+ console.log(chalk.green(`✓ Exported to: ${outputPath}\n`));
338
+ }
339
+ break;
340
+ }
341
+
342
+ case 'git': {
343
+ console.log(chalk.bold('\nGit Commit History'));
344
+ console.log(chalk.gray('==================\n'));
345
+
346
+ const gitLog = generateFromGit({
347
+ since: options.since,
348
+ until: options.until,
349
+ limit: options.limit || 20
350
+ });
351
+
352
+ if (gitLog) {
353
+ console.log(gitLog);
354
+ } else {
355
+ console.log(chalk.yellow('Could not retrieve git history.'));
356
+ }
357
+ console.log('');
358
+ break;
359
+ }
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Changelog list subcommand
365
+ */
366
+ export async function changelogListCommand(options = {}) {
367
+ return changelogCommand('list', null, options);
368
+ }
369
+
370
+ /**
371
+ * Changelog add subcommand
372
+ */
373
+ export async function changelogAddCommand(entry, options = {}) {
374
+ return changelogCommand('add', entry, options);
375
+ }
376
+
377
+ /**
378
+ * Changelog export subcommand
379
+ */
380
+ export async function changelogExportCommand(options = {}) {
381
+ return changelogCommand('export', null, options);
382
+ }
383
+
384
+ /**
385
+ * Changelog view subcommand (default)
386
+ */
387
+ export async function changelogViewCommand(options = {}) {
388
+ return changelogCommand('view', null, options);
389
+ }