kiro-spec-engine 1.2.0 → 1.2.2
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/CHANGELOG.md +38 -0
- package/bin/kiro-spec-engine.js +25 -1
- package/lib/utils/validation.js +306 -0
- package/lib/version/version-checker.js +156 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.2] - 2026-01-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **User Documentation**: Comprehensive guides for adoption and upgrade workflows
|
|
14
|
+
- `docs/adoption-guide.md`: Complete guide for adopting existing projects
|
|
15
|
+
- `docs/upgrade-guide.md`: Complete guide for upgrading project versions
|
|
16
|
+
- Step-by-step instructions with examples
|
|
17
|
+
- Troubleshooting sections for common issues
|
|
18
|
+
- Best practices and recommendations
|
|
19
|
+
|
|
20
|
+
### Enhanced
|
|
21
|
+
- Improved documentation structure for better user experience
|
|
22
|
+
- Added practical examples for all adoption modes
|
|
23
|
+
- Added detailed upgrade scenarios with migration examples
|
|
24
|
+
|
|
25
|
+
## [1.2.1] - 2026-01-23
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- **Validation System**: Comprehensive project validation
|
|
29
|
+
- `validateProjectStructure()`: Check required files and directories
|
|
30
|
+
- `validateVersionFile()`: Verify version.json structure
|
|
31
|
+
- `validateDependencies()`: Check Node.js and Python versions
|
|
32
|
+
- `validateProject()`: Complete project validation
|
|
33
|
+
- **Automatic Version Checking**: Detect version mismatches
|
|
34
|
+
- VersionChecker class for automatic version detection
|
|
35
|
+
- Warning display when project version differs from installed kse
|
|
36
|
+
- `--no-version-check` flag to suppress warnings
|
|
37
|
+
- `kse version-info` command for detailed version information
|
|
38
|
+
- **Enhanced Testing**: Added tests for validation and version checking
|
|
39
|
+
- 7 new unit tests for validation system
|
|
40
|
+
- 4 new unit tests for version checker
|
|
41
|
+
- Total: 25 tests passing
|
|
42
|
+
|
|
43
|
+
### Enhanced
|
|
44
|
+
- CLI now checks for version mismatches before command execution
|
|
45
|
+
- Better error messages for validation failures
|
|
46
|
+
- Improved user experience with version information display
|
|
47
|
+
|
|
10
48
|
## [1.2.0] - 2026-01-23
|
|
11
49
|
|
|
12
50
|
### Added
|
package/bin/kiro-spec-engine.js
CHANGED
|
@@ -11,6 +11,7 @@ const doctorCommand = require('../lib/commands/doctor');
|
|
|
11
11
|
const adoptCommand = require('../lib/commands/adopt');
|
|
12
12
|
const upgradeCommand = require('../lib/commands/upgrade');
|
|
13
13
|
const rollbackCommand = require('../lib/commands/rollback');
|
|
14
|
+
const VersionChecker = require('../lib/version/version-checker');
|
|
14
15
|
|
|
15
16
|
const i18n = getI18n();
|
|
16
17
|
const t = (key, params) => i18n.t(key, params);
|
|
@@ -18,6 +19,19 @@ const t = (key, params) => i18n.t(key, params);
|
|
|
18
19
|
// Read version from package.json
|
|
19
20
|
const packageJson = require('../package.json');
|
|
20
21
|
|
|
22
|
+
// Create version checker instance
|
|
23
|
+
const versionChecker = new VersionChecker();
|
|
24
|
+
|
|
25
|
+
// Helper function to check version before command execution
|
|
26
|
+
async function checkVersionBeforeCommand(options = {}) {
|
|
27
|
+
const projectPath = process.cwd();
|
|
28
|
+
const noVersionCheck = options.noVersionCheck || false;
|
|
29
|
+
|
|
30
|
+
if (!noVersionCheck) {
|
|
31
|
+
await versionChecker.checkVersion(projectPath, { noVersionCheck });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
const program = new Command();
|
|
22
36
|
|
|
23
37
|
// 版本和基本信息
|
|
@@ -27,7 +41,8 @@ program
|
|
|
27
41
|
.version(packageJson.version, '-v, --version', 'Display version number')
|
|
28
42
|
.option('-l, --lang <locale>', 'Set language (en/zh)', (locale) => {
|
|
29
43
|
i18n.setLocale(locale);
|
|
30
|
-
})
|
|
44
|
+
})
|
|
45
|
+
.option('--no-version-check', 'Suppress version mismatch warnings');
|
|
31
46
|
|
|
32
47
|
// 初始化项目命令
|
|
33
48
|
program
|
|
@@ -240,6 +255,15 @@ program
|
|
|
240
255
|
}
|
|
241
256
|
});
|
|
242
257
|
|
|
258
|
+
// 版本信息命令
|
|
259
|
+
program
|
|
260
|
+
.command('version-info')
|
|
261
|
+
.description('Display detailed version information')
|
|
262
|
+
.action(async () => {
|
|
263
|
+
const projectPath = process.cwd();
|
|
264
|
+
await versionChecker.displayVersionInfo(projectPath);
|
|
265
|
+
});
|
|
266
|
+
|
|
243
267
|
// 更新项目配置的辅助函数
|
|
244
268
|
async function updateProjectConfig(projectName) {
|
|
245
269
|
const envPath = path.join(process.cwd(), '.kiro/steering/ENVIRONMENT.md');
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides validation functions for project structure, version files,
|
|
5
|
+
* and dependencies. Used for post-operation validation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { pathExists, readJSON } = require('./fs-utils');
|
|
10
|
+
const { spawn } = require('child_process');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validates project structure
|
|
14
|
+
* Checks if all required files and directories exist
|
|
15
|
+
*
|
|
16
|
+
* @param {string} projectPath - Absolute path to project root
|
|
17
|
+
* @returns {Promise<ValidationResult>}
|
|
18
|
+
*/
|
|
19
|
+
async function validateProjectStructure(projectPath) {
|
|
20
|
+
const errors = [];
|
|
21
|
+
const warnings = [];
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const kiroPath = path.join(projectPath, '.kiro');
|
|
25
|
+
|
|
26
|
+
// Check if .kiro/ directory exists
|
|
27
|
+
const kiroExists = await pathExists(kiroPath);
|
|
28
|
+
if (!kiroExists) {
|
|
29
|
+
errors.push('.kiro/ directory not found');
|
|
30
|
+
return { success: false, errors, warnings };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Check required directories
|
|
34
|
+
const requiredDirs = [
|
|
35
|
+
{ path: 'specs', required: false },
|
|
36
|
+
{ path: 'steering', required: true },
|
|
37
|
+
{ path: 'tools', required: true },
|
|
38
|
+
{ path: 'backups', required: false }
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
for (const dir of requiredDirs) {
|
|
42
|
+
const dirPath = path.join(kiroPath, dir.path);
|
|
43
|
+
const exists = await pathExists(dirPath);
|
|
44
|
+
|
|
45
|
+
if (!exists) {
|
|
46
|
+
if (dir.required) {
|
|
47
|
+
errors.push(`Required directory not found: ${dir.path}/`);
|
|
48
|
+
} else {
|
|
49
|
+
warnings.push(`Optional directory not found: ${dir.path}/`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Check required steering files
|
|
55
|
+
const requiredSteeringFiles = [
|
|
56
|
+
{ path: 'steering/CORE_PRINCIPLES.md', required: true },
|
|
57
|
+
{ path: 'steering/ENVIRONMENT.md', required: true },
|
|
58
|
+
{ path: 'steering/CURRENT_CONTEXT.md', required: true },
|
|
59
|
+
{ path: 'steering/RULES_GUIDE.md', required: true }
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
for (const file of requiredSteeringFiles) {
|
|
63
|
+
const filePath = path.join(kiroPath, file.path);
|
|
64
|
+
const exists = await pathExists(filePath);
|
|
65
|
+
|
|
66
|
+
if (!exists) {
|
|
67
|
+
if (file.required) {
|
|
68
|
+
errors.push(`Required file not found: ${file.path}`);
|
|
69
|
+
} else {
|
|
70
|
+
warnings.push(`Optional file not found: ${file.path}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Check required tool files
|
|
76
|
+
const requiredToolFiles = [
|
|
77
|
+
{ path: 'tools/ultrawork_enhancer.py', required: true }
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
for (const file of requiredToolFiles) {
|
|
81
|
+
const filePath = path.join(kiroPath, file.path);
|
|
82
|
+
const exists = await pathExists(filePath);
|
|
83
|
+
|
|
84
|
+
if (!exists) {
|
|
85
|
+
if (file.required) {
|
|
86
|
+
warnings.push(`Tool file not found: ${file.path}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
success: errors.length === 0,
|
|
93
|
+
errors,
|
|
94
|
+
warnings
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
errors.push(`Validation failed: ${error.message}`);
|
|
98
|
+
return { success: false, errors, warnings };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Validates version.json file structure
|
|
104
|
+
*
|
|
105
|
+
* @param {string} projectPath - Absolute path to project root
|
|
106
|
+
* @returns {Promise<ValidationResult>}
|
|
107
|
+
*/
|
|
108
|
+
async function validateVersionFile(projectPath) {
|
|
109
|
+
const errors = [];
|
|
110
|
+
const warnings = [];
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const versionPath = path.join(projectPath, '.kiro', 'version.json');
|
|
114
|
+
|
|
115
|
+
// Check if version.json exists
|
|
116
|
+
const exists = await pathExists(versionPath);
|
|
117
|
+
if (!exists) {
|
|
118
|
+
errors.push('version.json not found');
|
|
119
|
+
return { success: false, errors, warnings };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Read and validate structure
|
|
123
|
+
const versionInfo = await readJSON(versionPath);
|
|
124
|
+
|
|
125
|
+
// Check required fields
|
|
126
|
+
const requiredFields = [
|
|
127
|
+
'kse-version',
|
|
128
|
+
'template-version',
|
|
129
|
+
'created',
|
|
130
|
+
'last-upgraded',
|
|
131
|
+
'upgrade-history'
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
for (const field of requiredFields) {
|
|
135
|
+
if (!(field in versionInfo)) {
|
|
136
|
+
errors.push(`Missing required field in version.json: ${field}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Validate field types
|
|
141
|
+
if (versionInfo['kse-version'] && typeof versionInfo['kse-version'] !== 'string') {
|
|
142
|
+
errors.push('kse-version must be a string');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (versionInfo['template-version'] && typeof versionInfo['template-version'] !== 'string') {
|
|
146
|
+
errors.push('template-version must be a string');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (versionInfo['upgrade-history'] && !Array.isArray(versionInfo['upgrade-history'])) {
|
|
150
|
+
errors.push('upgrade-history must be an array');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Validate upgrade history entries
|
|
154
|
+
if (Array.isArray(versionInfo['upgrade-history'])) {
|
|
155
|
+
versionInfo['upgrade-history'].forEach((entry, index) => {
|
|
156
|
+
if (!entry.from || !entry.to || !entry.date || typeof entry.success !== 'boolean') {
|
|
157
|
+
warnings.push(`Invalid upgrade history entry at index ${index}`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
success: errors.length === 0,
|
|
164
|
+
errors,
|
|
165
|
+
warnings
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
errors.push(`Failed to validate version.json: ${error.message}`);
|
|
169
|
+
return { success: false, errors, warnings };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Validates dependencies (Node.js and Python versions)
|
|
175
|
+
*
|
|
176
|
+
* @param {string} projectPath - Absolute path to project root
|
|
177
|
+
* @returns {Promise<ValidationResult>}
|
|
178
|
+
*/
|
|
179
|
+
async function validateDependencies(projectPath) {
|
|
180
|
+
const errors = [];
|
|
181
|
+
const warnings = [];
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
// Check Node.js version
|
|
185
|
+
const nodeVersion = process.version;
|
|
186
|
+
const nodeMajor = parseInt(nodeVersion.slice(1).split('.')[0]);
|
|
187
|
+
|
|
188
|
+
if (nodeMajor < 16) {
|
|
189
|
+
errors.push(`Node.js version ${nodeVersion} is not supported. Requires Node.js 16+`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Check Python version (if Ultrawork tools are present)
|
|
193
|
+
const toolPath = path.join(projectPath, '.kiro/tools/ultrawork_enhancer.py');
|
|
194
|
+
const toolExists = await pathExists(toolPath);
|
|
195
|
+
|
|
196
|
+
if (toolExists) {
|
|
197
|
+
try {
|
|
198
|
+
const pythonVersion = await checkPythonVersion();
|
|
199
|
+
|
|
200
|
+
if (!pythonVersion) {
|
|
201
|
+
warnings.push('Python not found. Ultrawork tools require Python 3.8+');
|
|
202
|
+
} else {
|
|
203
|
+
const [major, minor] = pythonVersion.split('.').map(Number);
|
|
204
|
+
|
|
205
|
+
if (major < 3 || (major === 3 && minor < 8)) {
|
|
206
|
+
warnings.push(`Python ${pythonVersion} found. Ultrawork tools require Python 3.8+`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
warnings.push('Could not check Python version');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
success: errors.length === 0,
|
|
216
|
+
errors,
|
|
217
|
+
warnings
|
|
218
|
+
};
|
|
219
|
+
} catch (error) {
|
|
220
|
+
errors.push(`Failed to validate dependencies: ${error.message}`);
|
|
221
|
+
return { success: false, errors, warnings };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Checks Python version
|
|
227
|
+
*
|
|
228
|
+
* @returns {Promise<string|null>} - Python version string or null if not found
|
|
229
|
+
*/
|
|
230
|
+
function checkPythonVersion() {
|
|
231
|
+
return new Promise((resolve) => {
|
|
232
|
+
const python = spawn('python', ['--version']);
|
|
233
|
+
let output = '';
|
|
234
|
+
|
|
235
|
+
python.stdout.on('data', (data) => {
|
|
236
|
+
output += data.toString();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
python.stderr.on('data', (data) => {
|
|
240
|
+
output += data.toString();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
python.on('close', (code) => {
|
|
244
|
+
if (code === 0 && output) {
|
|
245
|
+
// Extract version number from "Python 3.x.x"
|
|
246
|
+
const match = output.match(/Python (\d+\.\d+\.\d+)/);
|
|
247
|
+
if (match) {
|
|
248
|
+
resolve(match[1]);
|
|
249
|
+
} else {
|
|
250
|
+
resolve(null);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
resolve(null);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
python.on('error', () => {
|
|
258
|
+
resolve(null);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Timeout after 5 seconds
|
|
262
|
+
setTimeout(() => {
|
|
263
|
+
python.kill();
|
|
264
|
+
resolve(null);
|
|
265
|
+
}, 5000);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Validates complete project (structure + version + dependencies)
|
|
271
|
+
*
|
|
272
|
+
* @param {string} projectPath - Absolute path to project root
|
|
273
|
+
* @returns {Promise<ValidationResult>}
|
|
274
|
+
*/
|
|
275
|
+
async function validateProject(projectPath) {
|
|
276
|
+
const allErrors = [];
|
|
277
|
+
const allWarnings = [];
|
|
278
|
+
|
|
279
|
+
// Run all validations
|
|
280
|
+
const structureResult = await validateProjectStructure(projectPath);
|
|
281
|
+
const versionResult = await validateVersionFile(projectPath);
|
|
282
|
+
const depsResult = await validateDependencies(projectPath);
|
|
283
|
+
|
|
284
|
+
// Combine results
|
|
285
|
+
allErrors.push(...structureResult.errors);
|
|
286
|
+
allErrors.push(...versionResult.errors);
|
|
287
|
+
allErrors.push(...depsResult.errors);
|
|
288
|
+
|
|
289
|
+
allWarnings.push(...structureResult.warnings);
|
|
290
|
+
allWarnings.push(...versionResult.warnings);
|
|
291
|
+
allWarnings.push(...depsResult.warnings);
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
success: allErrors.length === 0,
|
|
295
|
+
errors: allErrors,
|
|
296
|
+
warnings: allWarnings
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
module.exports = {
|
|
301
|
+
validateProjectStructure,
|
|
302
|
+
validateVersionFile,
|
|
303
|
+
validateDependencies,
|
|
304
|
+
validateProject,
|
|
305
|
+
checkPythonVersion
|
|
306
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Checker
|
|
3
|
+
*
|
|
4
|
+
* Automatically detects version mismatches between project and installed kse.
|
|
5
|
+
* Displays warnings and upgrade suggestions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const VersionManager = require('./version-manager');
|
|
10
|
+
|
|
11
|
+
class VersionChecker {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.versionManager = new VersionManager();
|
|
14
|
+
this.suppressWarnings = false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks for version mismatch and displays warning if needed
|
|
19
|
+
*
|
|
20
|
+
* @param {string} projectPath - Absolute path to project root
|
|
21
|
+
* @param {Object} options - Check options
|
|
22
|
+
* @param {boolean} options.noVersionCheck - Suppress warnings
|
|
23
|
+
* @returns {Promise<VersionCheckResult>}
|
|
24
|
+
*/
|
|
25
|
+
async checkVersion(projectPath, options = {}) {
|
|
26
|
+
const { noVersionCheck = false } = options;
|
|
27
|
+
|
|
28
|
+
if (noVersionCheck || this.suppressWarnings) {
|
|
29
|
+
return { mismatch: false, shouldUpgrade: false };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// Read project version
|
|
34
|
+
const projectVersionInfo = await this.versionManager.readVersion(projectPath);
|
|
35
|
+
|
|
36
|
+
if (!projectVersionInfo) {
|
|
37
|
+
// No version.json - project might not be initialized
|
|
38
|
+
return { mismatch: false, shouldUpgrade: false };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const projectVersion = projectVersionInfo['kse-version'];
|
|
42
|
+
|
|
43
|
+
// Get current kse version
|
|
44
|
+
const packageJson = require('../../package.json');
|
|
45
|
+
const kseVersion = packageJson.version;
|
|
46
|
+
|
|
47
|
+
// Check if upgrade is needed
|
|
48
|
+
const needsUpgrade = this.versionManager.needsUpgrade(projectVersion, kseVersion);
|
|
49
|
+
|
|
50
|
+
if (needsUpgrade) {
|
|
51
|
+
this.displayWarning(projectVersion, kseVersion);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
mismatch: needsUpgrade,
|
|
56
|
+
shouldUpgrade: needsUpgrade,
|
|
57
|
+
projectVersion,
|
|
58
|
+
kseVersion
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
// Silently fail - don't block commands if version check fails
|
|
62
|
+
return { mismatch: false, shouldUpgrade: false, error: error.message };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Displays version mismatch warning
|
|
68
|
+
*
|
|
69
|
+
* @param {string} projectVersion - Project version
|
|
70
|
+
* @param {string} kseVersion - Current kse version
|
|
71
|
+
*/
|
|
72
|
+
displayWarning(projectVersion, kseVersion) {
|
|
73
|
+
console.log();
|
|
74
|
+
console.log(chalk.yellow('⚠️ Version Mismatch Detected'));
|
|
75
|
+
console.log(chalk.gray(' Project initialized with kse'), chalk.cyan(`v${projectVersion}`));
|
|
76
|
+
console.log(chalk.gray(' Current kse version:'), chalk.cyan(`v${kseVersion}`));
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.blue('💡 Tip:'), chalk.gray('Run'), chalk.cyan('kse upgrade'), chalk.gray('to update project templates'));
|
|
79
|
+
console.log(chalk.gray(' Or use'), chalk.cyan('--no-version-check'), chalk.gray('to suppress this warning'));
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Checks version and displays detailed information
|
|
85
|
+
*
|
|
86
|
+
* @param {string} projectPath - Absolute path to project root
|
|
87
|
+
* @returns {Promise<void>}
|
|
88
|
+
*/
|
|
89
|
+
async displayVersionInfo(projectPath) {
|
|
90
|
+
try {
|
|
91
|
+
const projectVersionInfo = await this.versionManager.readVersion(projectPath);
|
|
92
|
+
|
|
93
|
+
if (!projectVersionInfo) {
|
|
94
|
+
console.log(chalk.yellow('⚠️ No version information found'));
|
|
95
|
+
console.log(chalk.gray(' This project may not be initialized with kse'));
|
|
96
|
+
console.log(chalk.gray(' Run'), chalk.cyan('kse adopt'), chalk.gray('to adopt this project'));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const packageJson = require('../../package.json');
|
|
101
|
+
const kseVersion = packageJson.version;
|
|
102
|
+
|
|
103
|
+
console.log(chalk.blue('📦 Version Information'));
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(chalk.gray('Project:'));
|
|
106
|
+
console.log(` kse version: ${chalk.cyan(projectVersionInfo['kse-version'])}`);
|
|
107
|
+
console.log(` Template version: ${chalk.cyan(projectVersionInfo['template-version'])}`);
|
|
108
|
+
console.log(` Created: ${chalk.gray(new Date(projectVersionInfo.created).toLocaleString())}`);
|
|
109
|
+
console.log(` Last upgraded: ${chalk.gray(new Date(projectVersionInfo['last-upgraded']).toLocaleString())}`);
|
|
110
|
+
|
|
111
|
+
console.log();
|
|
112
|
+
console.log(chalk.gray('Installed:'));
|
|
113
|
+
console.log(` kse version: ${chalk.cyan(kseVersion)}`);
|
|
114
|
+
|
|
115
|
+
if (projectVersionInfo['upgrade-history'].length > 0) {
|
|
116
|
+
console.log();
|
|
117
|
+
console.log(chalk.gray('Upgrade History:'));
|
|
118
|
+
projectVersionInfo['upgrade-history'].forEach((entry, index) => {
|
|
119
|
+
const icon = entry.success ? chalk.green('✅') : chalk.red('❌');
|
|
120
|
+
const date = new Date(entry.date).toLocaleString();
|
|
121
|
+
console.log(` ${icon} ${entry.from} → ${entry.to} (${date})`);
|
|
122
|
+
if (entry.error) {
|
|
123
|
+
console.log(` ${chalk.red('Error:')} ${entry.error}`);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log();
|
|
129
|
+
|
|
130
|
+
const needsUpgrade = this.versionManager.needsUpgrade(
|
|
131
|
+
projectVersionInfo['kse-version'],
|
|
132
|
+
kseVersion
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (needsUpgrade) {
|
|
136
|
+
console.log(chalk.yellow('⚠️ Upgrade available'));
|
|
137
|
+
console.log(chalk.gray(' Run'), chalk.cyan('kse upgrade'), chalk.gray('to update to'), chalk.cyan(`v${kseVersion}`));
|
|
138
|
+
} else {
|
|
139
|
+
console.log(chalk.green('✅ Project is up to date'));
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.log(chalk.red('❌ Error:'), error.message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Suppresses version check warnings
|
|
148
|
+
*
|
|
149
|
+
* @param {boolean} suppress - Whether to suppress warnings
|
|
150
|
+
*/
|
|
151
|
+
setSuppressWarnings(suppress) {
|
|
152
|
+
this.suppressWarnings = suppress;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = VersionChecker;
|
package/package.json
CHANGED