proagents 1.6.12 → 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.
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, writeFileSync, cpSync, mkdirSync, rmSync } from 'fs';
1
+ import { existsSync, readFileSync, writeFileSync, cpSync, mkdirSync, rmSync, readdirSync, statSync } from 'fs';
2
2
  import { join, dirname } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import chalk from 'chalk';
@@ -14,26 +14,112 @@ const PRESERVE_FILES = [
14
14
  'handoff.md',
15
15
  '.lock',
16
16
  'active-features/_index.json',
17
- 'active-features/.gitkeep'
17
+ 'active-features/.gitkeep',
18
+ // Changelog user data
19
+ 'changelog/_recent.md',
20
+ // Worklog user data
21
+ 'worklog/_context.md',
22
+ 'worklog/ai-stats.json'
18
23
  ];
19
24
 
20
- // Folders to preserve (user data)
25
+ // Folders to preserve (user data) - year folders detected dynamically
21
26
  const PRESERVE_FOLDERS = [
22
- 'active-features'
27
+ 'active-features',
28
+ 'changelog/modules',
29
+ 'changelog/features',
30
+ 'worklog'
23
31
  ];
24
32
 
33
+ /**
34
+ * Detect year folders (YYYY format) in changelog directory
35
+ */
36
+ function detectYearFolders(proagentsDir) {
37
+ const changelogDir = join(proagentsDir, 'changelog');
38
+ const yearFolders = [];
39
+
40
+ if (!existsSync(changelogDir)) return yearFolders;
41
+
42
+ try {
43
+ const entries = readdirSync(changelogDir, { withFileTypes: true });
44
+ for (const entry of entries) {
45
+ // Match 4-digit year folders (2020-2099)
46
+ if (entry.isDirectory() && /^20[2-9][0-9]$/.test(entry.name)) {
47
+ yearFolders.push(`changelog/${entry.name}`);
48
+ }
49
+ }
50
+ } catch {
51
+ // Changelog directory doesn't exist or unreadable
52
+ }
53
+
54
+ return yearFolders;
55
+ }
56
+
57
+ /**
58
+ * Recursively read all files in a directory
59
+ */
60
+ function readDirRecursive(dir, baseDir = dir) {
61
+ const files = {};
62
+
63
+ if (!existsSync(dir)) return files;
64
+
65
+ try {
66
+ const entries = readdirSync(dir, { withFileTypes: true });
67
+ for (const entry of entries) {
68
+ const fullPath = join(dir, entry.name);
69
+ const relativePath = fullPath.replace(baseDir + '/', '');
70
+
71
+ if (entry.isDirectory()) {
72
+ Object.assign(files, readDirRecursive(fullPath, baseDir));
73
+ } else {
74
+ try {
75
+ files[relativePath] = readFileSync(fullPath, 'utf-8');
76
+ } catch {
77
+ // Skip unreadable files (binary, permissions, etc.)
78
+ }
79
+ }
80
+ }
81
+ } catch {
82
+ // Directory read failed - return what we have
83
+ }
84
+
85
+ return files;
86
+ }
87
+
25
88
  /**
26
89
  * Backup user files before upgrade
27
90
  */
28
91
  function backupUserFiles(targetDir) {
29
92
  const backups = {};
93
+ const proagentsDir = join(targetDir, '.proagents');
30
94
 
95
+ // Backup individual files
31
96
  for (const file of PRESERVE_FILES) {
32
- const filePath = join(targetDir, 'proagents', file);
97
+ const filePath = join(proagentsDir, file);
33
98
  if (existsSync(filePath)) {
34
99
  try {
35
100
  backups[file] = readFileSync(filePath, 'utf-8');
36
- } catch { }
101
+ } catch {
102
+ // Skip unreadable files
103
+ }
104
+ }
105
+ }
106
+
107
+ // Backup folders recursively
108
+ for (const folder of PRESERVE_FOLDERS) {
109
+ const folderPath = join(proagentsDir, folder);
110
+ if (existsSync(folderPath)) {
111
+ const folderFiles = readDirRecursive(folderPath, proagentsDir);
112
+ Object.assign(backups, folderFiles);
113
+ }
114
+ }
115
+
116
+ // Backup dynamically detected year folders (changelog/2024, changelog/2025, etc.)
117
+ const yearFolders = detectYearFolders(proagentsDir);
118
+ for (const folder of yearFolders) {
119
+ const folderPath = join(proagentsDir, folder);
120
+ if (existsSync(folderPath)) {
121
+ const folderFiles = readDirRecursive(folderPath, proagentsDir);
122
+ Object.assign(backups, folderFiles);
37
123
  }
38
124
  }
39
125
 
@@ -44,8 +130,10 @@ function backupUserFiles(targetDir) {
44
130
  * Restore user files after upgrade
45
131
  */
46
132
  function restoreUserFiles(targetDir, backups) {
133
+ const proagentsDir = join(targetDir, '.proagents');
134
+
47
135
  for (const [file, content] of Object.entries(backups)) {
48
- const filePath = join(targetDir, 'proagents', file);
136
+ const filePath = join(proagentsDir, file);
49
137
  try {
50
138
  // Ensure directory exists
51
139
  mkdirSync(dirname(filePath), { recursive: true });
@@ -61,11 +149,13 @@ function restoreUserFiles(targetDir, backups) {
61
149
  */
62
150
  function getCurrentVersion(targetDir) {
63
151
  // Try to read version from a marker file or package
64
- const markerPath = join(targetDir, 'proagents', '.version');
152
+ const markerPath = join(targetDir, '.proagents', '.version');
65
153
  if (existsSync(markerPath)) {
66
154
  try {
67
155
  return readFileSync(markerPath, 'utf-8').trim();
68
- } catch { }
156
+ } catch {
157
+ // Version file unreadable
158
+ }
69
159
  }
70
160
  return 'unknown';
71
161
  }
@@ -162,7 +252,9 @@ export async function upgradeCommand(options = {}) {
162
252
  // Step 5: Write version marker
163
253
  try {
164
254
  writeFileSync(join(proagentsDir, '.version'), packageVersion);
165
- } catch { }
255
+ } catch {
256
+ // Non-critical: version marker write failed
257
+ }
166
258
 
167
259
  // Summary
168
260
  console.log(chalk.bold('\nUpgrade Complete'));
@@ -0,0 +1,140 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ /**
10
+ * Get CLI version from package.json
11
+ */
12
+ function getCliVersion() {
13
+ try {
14
+ const packagePath = join(__dirname, '..', '..', 'package.json');
15
+ const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
16
+ return packageJson.version;
17
+ } catch (error) {
18
+ console.error(chalk.yellow(`Warning: Could not read CLI version: ${error.message}`));
19
+ return 'unknown';
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Get installed version in current project
25
+ */
26
+ function getProjectVersion(targetDir) {
27
+ const versionPath = join(targetDir, '.proagents', '.version');
28
+
29
+ if (!existsSync(versionPath)) {
30
+ return null;
31
+ }
32
+
33
+ try {
34
+ return readFileSync(versionPath, 'utf-8').trim();
35
+ } catch (error) {
36
+ console.error(chalk.yellow(`Warning: Could not read project version: ${error.message}`));
37
+ return 'unknown';
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Fetch latest version from npm
43
+ */
44
+ async function getLatestVersion() {
45
+ try {
46
+ const controller = new AbortController();
47
+ const timeout = setTimeout(() => controller.abort(), 5000);
48
+
49
+ const response = await fetch('https://registry.npmjs.org/proagents/latest', {
50
+ signal: controller.signal
51
+ });
52
+ clearTimeout(timeout);
53
+
54
+ if (response.ok) {
55
+ const data = await response.json();
56
+ return data.version;
57
+ }
58
+ return null;
59
+ } catch (error) {
60
+ // Network error or timeout - not critical
61
+ return null;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Compare semantic versions
67
+ * Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
68
+ */
69
+ function compareVersions(v1, v2) {
70
+ const parts1 = v1.split('.').map(Number);
71
+ const parts2 = v2.split('.').map(Number);
72
+
73
+ for (let i = 0; i < 3; i++) {
74
+ const p1 = parts1[i] || 0;
75
+ const p2 = parts2[i] || 0;
76
+ if (p1 < p2) return -1;
77
+ if (p1 > p2) return 1;
78
+ }
79
+ return 0;
80
+ }
81
+
82
+ /**
83
+ * Version command - show detailed version information
84
+ */
85
+ export async function versionCommand(options = {}) {
86
+ const targetDir = process.cwd();
87
+
88
+ console.log(chalk.bold('\nProAgents Version Info'));
89
+ console.log(chalk.gray('======================\n'));
90
+
91
+ // CLI Version
92
+ const cliVersion = getCliVersion();
93
+ console.log(` ${chalk.cyan('CLI Version:')} ${chalk.white('v' + cliVersion)}`);
94
+
95
+ // Project Version
96
+ const projectVersion = getProjectVersion(targetDir);
97
+ if (projectVersion) {
98
+ const versionMatch = projectVersion === cliVersion;
99
+ const projectVersionColor = versionMatch ? chalk.green : chalk.yellow;
100
+ console.log(` ${chalk.cyan('Project Version:')} ${projectVersionColor('v' + projectVersion)}`);
101
+
102
+ if (!versionMatch) {
103
+ console.log(chalk.yellow(` ↳ Run 'npx proagents init' to update`));
104
+ }
105
+ } else {
106
+ console.log(` ${chalk.cyan('Project Version:')} ${chalk.gray('Not installed in this directory')}`);
107
+ }
108
+
109
+ // Latest Version (from npm)
110
+ if (!options.offline) {
111
+ process.stdout.write(` ${chalk.cyan('Latest Version:')} `);
112
+ const latestVersion = await getLatestVersion();
113
+
114
+ if (latestVersion) {
115
+ const comparison = compareVersions(cliVersion, latestVersion);
116
+
117
+ if (comparison >= 0) {
118
+ console.log(chalk.green('v' + latestVersion + ' (up to date)'));
119
+ } else {
120
+ console.log(chalk.yellow('v' + latestVersion + ' (update available)'));
121
+ console.log(chalk.yellow(` ↳ Run 'npm update -g proagents' to update`));
122
+ }
123
+ } else {
124
+ console.log(chalk.gray('Could not fetch (offline or npm unavailable)'));
125
+ }
126
+ }
127
+
128
+ // Additional info
129
+ console.log('');
130
+ console.log(` ${chalk.cyan('Node.js:')} ${chalk.white(process.version)}`);
131
+ console.log(` ${chalk.cyan('Platform:')} ${chalk.white(process.platform + ' ' + process.arch)}`);
132
+ console.log('');
133
+
134
+ // Quick tips
135
+ if (projectVersion && projectVersion !== cliVersion) {
136
+ console.log(chalk.bold('Tip:'));
137
+ console.log(chalk.gray(' Your project has an older ProAgents version.'));
138
+ console.log(chalk.gray(' Run `npx proagents init` to update framework files.\n'));
139
+ }
140
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proagents",
3
- "version": "1.6.12",
3
+ "version": "1.6.13",
4
4
  "description": "AI-agnostic development workflow framework that automates the full software development lifecycle",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",