omgkit 2.24.3 → 2.25.0
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/README.md +37 -0
- package/bin/omgkit.js +68 -14
- package/lib/cli.js +703 -4
- package/package.json +1 -1
- package/plugin/registry.yaml +2 -2
- package/templates/settings.json +6 -0
package/README.md
CHANGED
|
@@ -747,6 +747,8 @@ Generated in `.omgkit/stdrules/` when you run `omgkit init`:
|
|
|
747
747
|
|
|
748
748
|
## CLI Commands
|
|
749
749
|
|
|
750
|
+
### Global Commands
|
|
751
|
+
|
|
750
752
|
```bash
|
|
751
753
|
omgkit install # Install plugin to Claude Code
|
|
752
754
|
omgkit init # Initialize .omgkit/ in project
|
|
@@ -757,6 +759,41 @@ omgkit uninstall # Remove plugin
|
|
|
757
759
|
omgkit help # Show help
|
|
758
760
|
```
|
|
759
761
|
|
|
762
|
+
### Project Upgrade Commands (New)
|
|
763
|
+
|
|
764
|
+
Keep your project up-to-date with the latest OMGKIT features:
|
|
765
|
+
|
|
766
|
+
```bash
|
|
767
|
+
omgkit project:upgrade # Upgrade project to latest OMGKIT version
|
|
768
|
+
omgkit project:upgrade --dry # Preview changes without applying
|
|
769
|
+
omgkit project:rollback # Rollback to previous backup
|
|
770
|
+
omgkit project:backups # List available backups
|
|
771
|
+
omgkit project:version # Show project's OMGKIT version
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
#### Safe Upgrade System
|
|
775
|
+
|
|
776
|
+
OMGKIT's upgrade system is designed with safety first:
|
|
777
|
+
|
|
778
|
+
| Feature | Description |
|
|
779
|
+
|---------|-------------|
|
|
780
|
+
| **Version Tracking** | Each project tracks its OMGKIT version in settings.json |
|
|
781
|
+
| **Smart Merge** | workflow.yaml uses add-only merge (never overwrites your values) |
|
|
782
|
+
| **Protected Files** | config.yaml, sprints/*, artifacts/*, devlogs/* are NEVER modified |
|
|
783
|
+
| **Auto-Backup** | Creates timestamped backup before any changes |
|
|
784
|
+
| **Dry Run** | Preview all changes with `--dry` flag before applying |
|
|
785
|
+
| **Rollback** | One command to restore previous state if needed |
|
|
786
|
+
|
|
787
|
+
#### What Gets Upgraded
|
|
788
|
+
|
|
789
|
+
| File Type | Upgrade Behavior |
|
|
790
|
+
|-----------|-----------------|
|
|
791
|
+
| **stdrules/** | New standards are added, modified ones offer 3-way merge |
|
|
792
|
+
| **workflow.yaml** | Smart merge adds new sections, preserves your customizations |
|
|
793
|
+
| **CLAUDE.md** | Updated with new instructions |
|
|
794
|
+
| **settings.json** | Version updated, structure preserved |
|
|
795
|
+
| **Your files** | NEVER touched (config.yaml, sprints, artifacts, devlogs) |
|
|
796
|
+
|
|
760
797
|
---
|
|
761
798
|
|
|
762
799
|
## Documentation Sync Automation
|
package/bin/omgkit.js
CHANGED
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
doctor,
|
|
22
22
|
uninstallPlugin,
|
|
23
23
|
listComponents,
|
|
24
|
+
upgradeProject,
|
|
25
|
+
rollbackProject,
|
|
26
|
+
listProjectBackups,
|
|
27
|
+
getProjectVersion,
|
|
24
28
|
COLORS,
|
|
25
29
|
BANNER,
|
|
26
30
|
log
|
|
@@ -37,21 +41,33 @@ function showHelp() {
|
|
|
37
41
|
${COLORS.bright}USAGE${COLORS.reset}
|
|
38
42
|
omgkit <command> [options]
|
|
39
43
|
|
|
40
|
-
${COLORS.bright}COMMANDS${COLORS.reset}
|
|
41
|
-
${COLORS.cyan}install${COLORS.reset}
|
|
42
|
-
${COLORS.cyan}
|
|
43
|
-
${COLORS.cyan}
|
|
44
|
-
${COLORS.cyan}
|
|
45
|
-
${COLORS.cyan}
|
|
46
|
-
${COLORS.cyan}
|
|
47
|
-
${COLORS.cyan}
|
|
48
|
-
|
|
44
|
+
${COLORS.bright}GLOBAL COMMANDS${COLORS.reset}
|
|
45
|
+
${COLORS.cyan}install${COLORS.reset} Install OMGKIT plugin to Claude Code
|
|
46
|
+
${COLORS.cyan}update${COLORS.reset} Update OMGKIT plugin (same as install)
|
|
47
|
+
${COLORS.cyan}uninstall${COLORS.reset} Remove OMGKIT plugin
|
|
48
|
+
${COLORS.cyan}doctor${COLORS.reset} Check installation status
|
|
49
|
+
${COLORS.cyan}list${COLORS.reset} List all commands/agents/skills
|
|
50
|
+
${COLORS.cyan}version${COLORS.reset} Show version
|
|
51
|
+
${COLORS.cyan}help${COLORS.reset} Show this help
|
|
52
|
+
|
|
53
|
+
${COLORS.bright}PROJECT COMMANDS${COLORS.reset}
|
|
54
|
+
${COLORS.cyan}init${COLORS.reset} Initialize .omgkit/ in current project
|
|
55
|
+
${COLORS.cyan}project:upgrade${COLORS.reset} Upgrade project to latest OMGKIT version
|
|
56
|
+
${COLORS.cyan}project:rollback${COLORS.reset} Rollback project to previous backup
|
|
57
|
+
${COLORS.cyan}project:backups${COLORS.reset} List available project backups
|
|
58
|
+
${COLORS.cyan}project:version${COLORS.reset} Show project's OMGKIT version
|
|
59
|
+
|
|
60
|
+
${COLORS.bright}UPGRADE OPTIONS${COLORS.reset}
|
|
61
|
+
--dry Show what would change without applying
|
|
62
|
+
--force Skip confirmation prompts
|
|
49
63
|
|
|
50
64
|
${COLORS.bright}EXAMPLES${COLORS.reset}
|
|
51
|
-
omgkit install
|
|
52
|
-
omgkit init
|
|
53
|
-
omgkit
|
|
54
|
-
omgkit
|
|
65
|
+
omgkit install # Install plugin globally
|
|
66
|
+
omgkit init # Initialize project
|
|
67
|
+
omgkit project:upgrade # Upgrade project config
|
|
68
|
+
omgkit project:upgrade --dry # Preview upgrade changes
|
|
69
|
+
omgkit project:rollback # Rollback to last backup
|
|
70
|
+
omgkit doctor # Check status
|
|
55
71
|
|
|
56
72
|
${COLORS.bright}AFTER INSTALLATION${COLORS.reset}
|
|
57
73
|
In Claude Code, type / to see all OMGKIT commands:
|
|
@@ -59,7 +75,7 @@ ${COLORS.bright}AFTER INSTALLATION${COLORS.reset}
|
|
|
59
75
|
Core: /dev:feature, /dev:fix, /planning:plan, /quality:test, /dev:review
|
|
60
76
|
Omega: /omega:10x, /omega:100x, /omega:1000x, /omega:principles
|
|
61
77
|
Sprint: /sprint:vision-set, /sprint:sprint-new, /sprint:team-run
|
|
62
|
-
|
|
78
|
+
Testing: /quality:verify-done, /quality:coverage-check, /quality:test-plan
|
|
63
79
|
|
|
64
80
|
${COLORS.bright}DOCUMENTATION${COLORS.reset}
|
|
65
81
|
https://omg.mintlify.app
|
|
@@ -102,6 +118,44 @@ switch (command) {
|
|
|
102
118
|
if (!result.success) process.exit(1);
|
|
103
119
|
break;
|
|
104
120
|
}
|
|
121
|
+
case 'project:upgrade': {
|
|
122
|
+
const dryRun = args.includes('--dry');
|
|
123
|
+
const force = args.includes('--force');
|
|
124
|
+
const result = upgradeProject({ dryRun, force });
|
|
125
|
+
if (!result.success && !result.upToDate) process.exit(1);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case 'project:rollback': {
|
|
129
|
+
const result = rollbackProject();
|
|
130
|
+
if (!result.success) process.exit(1);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 'project:backups': {
|
|
134
|
+
console.log(BANNER);
|
|
135
|
+
const backups = listProjectBackups();
|
|
136
|
+
if (backups.length === 0) {
|
|
137
|
+
log.info('No backups found');
|
|
138
|
+
} else {
|
|
139
|
+
console.log(`${COLORS.bright}Available Backups${COLORS.reset}\n`);
|
|
140
|
+
backups.forEach((backup, i) => {
|
|
141
|
+
const age = Math.round((Date.now() - backup.created) / 1000 / 60);
|
|
142
|
+
const ageStr = age < 60 ? `${age} minutes ago` : `${Math.round(age / 60)} hours ago`;
|
|
143
|
+
console.log(` ${i + 1}. ${backup.name} (${ageStr})`);
|
|
144
|
+
});
|
|
145
|
+
console.log(`\nTo restore: omgkit project:rollback`);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'project:version': {
|
|
150
|
+
const projectVersion = getProjectVersion();
|
|
151
|
+
const omgkitVersion = getVersion();
|
|
152
|
+
console.log(`Project OMGKIT version: ${projectVersion || 'not tracked (older project)'}`);
|
|
153
|
+
console.log(`Current OMGKIT version: ${omgkitVersion}`);
|
|
154
|
+
if (projectVersion && projectVersion !== omgkitVersion) {
|
|
155
|
+
log.info('Run: omgkit project:upgrade');
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
105
159
|
case 'version':
|
|
106
160
|
case '-v':
|
|
107
161
|
case '--version': {
|
package/lib/cli.js
CHANGED
|
@@ -393,21 +393,33 @@ export function initProject(options = {}) {
|
|
|
393
393
|
{ src: 'CLAUDE.md', dest: 'CLAUDE.md' },
|
|
394
394
|
{ src: 'vision.yaml', dest: '.omgkit/sprints/vision.yaml' },
|
|
395
395
|
{ src: 'backlog.yaml', dest: '.omgkit/sprints/backlog.yaml' },
|
|
396
|
-
{ src: 'settings.json', dest: '.omgkit/settings.json' },
|
|
396
|
+
{ src: 'settings.json', dest: '.omgkit/settings.json', process: true },
|
|
397
397
|
{ src: 'devlogs/README.md', dest: '.omgkit/devlogs/README.md' },
|
|
398
398
|
{ src: 'stdrules/README.md', dest: '.omgkit/stdrules/README.md' },
|
|
399
399
|
{ src: 'stdrules/SKILL_STANDARDS.md', dest: '.omgkit/stdrules/SKILL_STANDARDS.md' },
|
|
400
400
|
{ src: 'stdrules/BEFORE_COMMIT.md', dest: '.omgkit/stdrules/BEFORE_COMMIT.md' },
|
|
401
401
|
{ src: 'stdrules/TESTING_STANDARDS.md', dest: '.omgkit/stdrules/TESTING_STANDARDS.md' },
|
|
402
|
-
{ src: 'artifacts/README.md', dest: '.omgkit/artifacts/README.md' }
|
|
402
|
+
{ src: 'artifacts/README.md', dest: '.omgkit/artifacts/README.md' },
|
|
403
|
+
{ src: 'omgkit/workflow.yaml', dest: '.omgkit/workflow.yaml' }
|
|
403
404
|
];
|
|
404
405
|
|
|
405
|
-
|
|
406
|
+
const version = getVersion();
|
|
407
|
+
const initDate = new Date().toISOString().split('T')[0];
|
|
408
|
+
|
|
409
|
+
templates.forEach(({ src, dest, process: shouldProcess }) => {
|
|
406
410
|
const srcPath = join(templatesDir, src);
|
|
407
411
|
const destPath = join(cwd, dest);
|
|
408
412
|
|
|
409
413
|
if (existsSync(srcPath) && !existsSync(destPath)) {
|
|
410
|
-
|
|
414
|
+
if (shouldProcess) {
|
|
415
|
+
// Process template placeholders
|
|
416
|
+
let content = readFileSync(srcPath, 'utf8');
|
|
417
|
+
content = content.replace(/\{\{OMGKIT_VERSION\}\}/g, version);
|
|
418
|
+
content = content.replace(/\{\{INIT_DATE\}\}/g, initDate);
|
|
419
|
+
writeFileSync(destPath, content);
|
|
420
|
+
} else {
|
|
421
|
+
cpSync(srcPath, destPath);
|
|
422
|
+
}
|
|
411
423
|
createdFiles.push(dest);
|
|
412
424
|
if (!silent) log.success(`Created ${dest}`);
|
|
413
425
|
}
|
|
@@ -934,3 +946,690 @@ export function validatePluginFile(filePath, requiredFields = []) {
|
|
|
934
946
|
result.frontmatter = frontmatter;
|
|
935
947
|
return result;
|
|
936
948
|
}
|
|
949
|
+
|
|
950
|
+
// ============================================================================
|
|
951
|
+
// PROJECT UPGRADE SYSTEM
|
|
952
|
+
// ============================================================================
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Create a hash of file content for change detection
|
|
956
|
+
* @param {string} content - File content
|
|
957
|
+
* @returns {string} Hash string
|
|
958
|
+
*/
|
|
959
|
+
function hashContent(content) {
|
|
960
|
+
let hash = 0;
|
|
961
|
+
for (let i = 0; i < content.length; i++) {
|
|
962
|
+
const char = content.charCodeAt(i);
|
|
963
|
+
hash = ((hash << 5) - hash) + char;
|
|
964
|
+
hash = hash & hash;
|
|
965
|
+
}
|
|
966
|
+
return hash.toString(16);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Deep merge two objects (for YAML config merging)
|
|
971
|
+
* Only adds new keys, never overwrites existing values
|
|
972
|
+
* @param {Object} target - Target object (user's config)
|
|
973
|
+
* @param {Object} source - Source object (new template)
|
|
974
|
+
* @returns {Object} Merged object
|
|
975
|
+
*/
|
|
976
|
+
function deepMergeAddOnly(target, source) {
|
|
977
|
+
const result = { ...target };
|
|
978
|
+
|
|
979
|
+
for (const key of Object.keys(source)) {
|
|
980
|
+
if (!(key in result)) {
|
|
981
|
+
// Key doesn't exist in target, add it
|
|
982
|
+
result[key] = source[key];
|
|
983
|
+
} else if (
|
|
984
|
+
typeof result[key] === 'object' &&
|
|
985
|
+
result[key] !== null &&
|
|
986
|
+
!Array.isArray(result[key]) &&
|
|
987
|
+
typeof source[key] === 'object' &&
|
|
988
|
+
source[key] !== null &&
|
|
989
|
+
!Array.isArray(source[key])
|
|
990
|
+
) {
|
|
991
|
+
// Both are objects, recurse
|
|
992
|
+
result[key] = deepMergeAddOnly(result[key], source[key]);
|
|
993
|
+
}
|
|
994
|
+
// If key exists and is not an object, keep user's value
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return result;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Simple YAML parser for config files
|
|
1002
|
+
* @param {string} content - YAML content
|
|
1003
|
+
* @returns {Object} Parsed object
|
|
1004
|
+
*/
|
|
1005
|
+
function parseSimpleYaml(content) {
|
|
1006
|
+
const result = {};
|
|
1007
|
+
const lines = content.split('\n');
|
|
1008
|
+
const stack = [{ obj: result, indent: -1 }];
|
|
1009
|
+
|
|
1010
|
+
for (const line of lines) {
|
|
1011
|
+
// Skip comments and empty lines
|
|
1012
|
+
if (line.trim().startsWith('#') || line.trim() === '') continue;
|
|
1013
|
+
|
|
1014
|
+
const indent = line.search(/\S/);
|
|
1015
|
+
if (indent === -1) continue;
|
|
1016
|
+
|
|
1017
|
+
const trimmed = line.trim();
|
|
1018
|
+
|
|
1019
|
+
// Pop stack to find parent
|
|
1020
|
+
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
1021
|
+
stack.pop();
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
const parent = stack[stack.length - 1].obj;
|
|
1025
|
+
|
|
1026
|
+
if (trimmed.startsWith('- ')) {
|
|
1027
|
+
// Array item
|
|
1028
|
+
const value = trimmed.substring(2).trim();
|
|
1029
|
+
if (!Array.isArray(parent)) {
|
|
1030
|
+
// Find the key that should be an array
|
|
1031
|
+
const keys = Object.keys(parent);
|
|
1032
|
+
const lastKey = keys[keys.length - 1];
|
|
1033
|
+
if (lastKey && parent[lastKey] === null) {
|
|
1034
|
+
parent[lastKey] = [value];
|
|
1035
|
+
}
|
|
1036
|
+
} else {
|
|
1037
|
+
parent.push(value);
|
|
1038
|
+
}
|
|
1039
|
+
} else if (trimmed.includes(':')) {
|
|
1040
|
+
const colonIndex = trimmed.indexOf(':');
|
|
1041
|
+
const key = trimmed.substring(0, colonIndex).trim();
|
|
1042
|
+
let value = trimmed.substring(colonIndex + 1).trim();
|
|
1043
|
+
|
|
1044
|
+
// Remove quotes if present
|
|
1045
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
1046
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
1047
|
+
value = value.slice(1, -1);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
if (value === '' || value === null) {
|
|
1051
|
+
// Object or array follows
|
|
1052
|
+
parent[key] = {};
|
|
1053
|
+
stack.push({ obj: parent[key], indent });
|
|
1054
|
+
} else if (value === 'true') {
|
|
1055
|
+
parent[key] = true;
|
|
1056
|
+
} else if (value === 'false') {
|
|
1057
|
+
parent[key] = false;
|
|
1058
|
+
} else if (!isNaN(Number(value)) && value !== '') {
|
|
1059
|
+
parent[key] = Number(value);
|
|
1060
|
+
} else {
|
|
1061
|
+
parent[key] = value;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
return result;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Serialize object to simple YAML
|
|
1071
|
+
* @param {Object} obj - Object to serialize
|
|
1072
|
+
* @param {number} indent - Current indentation level
|
|
1073
|
+
* @returns {string} YAML string
|
|
1074
|
+
*/
|
|
1075
|
+
function toSimpleYaml(obj, indent = 0) {
|
|
1076
|
+
const spaces = ' '.repeat(indent);
|
|
1077
|
+
let result = '';
|
|
1078
|
+
|
|
1079
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1080
|
+
if (value === null || value === undefined) {
|
|
1081
|
+
result += `${spaces}${key}:\n`;
|
|
1082
|
+
} else if (Array.isArray(value)) {
|
|
1083
|
+
result += `${spaces}${key}:\n`;
|
|
1084
|
+
for (const item of value) {
|
|
1085
|
+
if (typeof item === 'object') {
|
|
1086
|
+
result += `${spaces} -\n${toSimpleYaml(item, indent + 2)}`;
|
|
1087
|
+
} else {
|
|
1088
|
+
result += `${spaces} - ${item}\n`;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
} else if (typeof value === 'object') {
|
|
1092
|
+
result += `${spaces}${key}:\n${toSimpleYaml(value, indent + 1)}`;
|
|
1093
|
+
} else if (typeof value === 'string' && (value.includes(':') || value.includes('#'))) {
|
|
1094
|
+
result += `${spaces}${key}: "${value}"\n`;
|
|
1095
|
+
} else {
|
|
1096
|
+
result += `${spaces}${key}: ${value}\n`;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
return result;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* Get project settings including version info
|
|
1105
|
+
* @param {string} cwd - Project directory
|
|
1106
|
+
* @returns {Object|null} Settings object or null
|
|
1107
|
+
*/
|
|
1108
|
+
export function getProjectSettings(cwd = process.cwd()) {
|
|
1109
|
+
const settingsPath = join(cwd, '.omgkit', 'settings.json');
|
|
1110
|
+
if (!existsSync(settingsPath)) return null;
|
|
1111
|
+
|
|
1112
|
+
try {
|
|
1113
|
+
return JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
1114
|
+
} catch (e) {
|
|
1115
|
+
return null;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Get project version
|
|
1121
|
+
* @param {string} cwd - Project directory
|
|
1122
|
+
* @returns {string|null} Version string or null
|
|
1123
|
+
*/
|
|
1124
|
+
export function getProjectVersion(cwd = process.cwd()) {
|
|
1125
|
+
const settings = getProjectSettings(cwd);
|
|
1126
|
+
return settings?.omgkit?.version || null;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* Compare semantic versions
|
|
1131
|
+
* @param {string} v1 - First version
|
|
1132
|
+
* @param {string} v2 - Second version
|
|
1133
|
+
* @returns {number} -1 if v1 < v2, 0 if equal, 1 if v1 > v2
|
|
1134
|
+
*/
|
|
1135
|
+
function compareVersions(v1, v2) {
|
|
1136
|
+
const parts1 = v1.split('.').map(Number);
|
|
1137
|
+
const parts2 = v2.split('.').map(Number);
|
|
1138
|
+
|
|
1139
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
1140
|
+
const p1 = parts1[i] || 0;
|
|
1141
|
+
const p2 = parts2[i] || 0;
|
|
1142
|
+
if (p1 < p2) return -1;
|
|
1143
|
+
if (p1 > p2) return 1;
|
|
1144
|
+
}
|
|
1145
|
+
return 0;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Create backup of .omgkit directory
|
|
1150
|
+
* @param {string} cwd - Project directory
|
|
1151
|
+
* @returns {Object} Backup result with path
|
|
1152
|
+
*/
|
|
1153
|
+
export function createProjectBackup(cwd = process.cwd()) {
|
|
1154
|
+
const omgkitDir = join(cwd, '.omgkit');
|
|
1155
|
+
if (!existsSync(omgkitDir)) {
|
|
1156
|
+
return { success: false, error: 'NOT_INITIALIZED' };
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
const now = new Date();
|
|
1160
|
+
const timestamp = now.toISOString().replace(/[:.]/g, '-').split('T').join('-').substring(0, 19);
|
|
1161
|
+
const ms = String(now.getMilliseconds()).padStart(3, '0');
|
|
1162
|
+
const backupDir = join(cwd, `.omgkit-backup-${timestamp}-${ms}`);
|
|
1163
|
+
|
|
1164
|
+
try {
|
|
1165
|
+
cpSync(omgkitDir, backupDir, { recursive: true });
|
|
1166
|
+
return { success: true, path: backupDir, timestamp };
|
|
1167
|
+
} catch (e) {
|
|
1168
|
+
return { success: false, error: e.message };
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* List available backups
|
|
1174
|
+
* @param {string} cwd - Project directory
|
|
1175
|
+
* @returns {Object[]} Array of backup info
|
|
1176
|
+
*/
|
|
1177
|
+
export function listProjectBackups(cwd = process.cwd()) {
|
|
1178
|
+
const backups = [];
|
|
1179
|
+
|
|
1180
|
+
try {
|
|
1181
|
+
const items = readdirSync(cwd);
|
|
1182
|
+
for (const item of items) {
|
|
1183
|
+
if (item.startsWith('.omgkit-backup-')) {
|
|
1184
|
+
const fullPath = join(cwd, item);
|
|
1185
|
+
const stat = statSync(fullPath);
|
|
1186
|
+
if (stat.isDirectory()) {
|
|
1187
|
+
backups.push({
|
|
1188
|
+
name: item,
|
|
1189
|
+
path: fullPath,
|
|
1190
|
+
created: stat.mtime
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
} catch (e) {
|
|
1196
|
+
// Directory read error
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
return backups.sort((a, b) => b.created - a.created);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* Rollback project to a backup
|
|
1204
|
+
* @param {Object} options - Options
|
|
1205
|
+
* @param {string} [options.cwd] - Project directory
|
|
1206
|
+
* @param {string} [options.backupPath] - Specific backup to restore
|
|
1207
|
+
* @param {boolean} [options.silent] - Suppress output
|
|
1208
|
+
* @returns {Object} Result
|
|
1209
|
+
*/
|
|
1210
|
+
export function rollbackProject(options = {}) {
|
|
1211
|
+
const { cwd = process.cwd(), backupPath, silent = false } = options;
|
|
1212
|
+
|
|
1213
|
+
if (!silent) {
|
|
1214
|
+
console.log(BANNER);
|
|
1215
|
+
log.omega('Rolling back project...');
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
const omgkitDir = join(cwd, '.omgkit');
|
|
1219
|
+
let targetBackup = backupPath;
|
|
1220
|
+
|
|
1221
|
+
if (!targetBackup) {
|
|
1222
|
+
// Find most recent backup
|
|
1223
|
+
const backups = listProjectBackups(cwd);
|
|
1224
|
+
if (backups.length === 0) {
|
|
1225
|
+
if (!silent) log.error('No backups found');
|
|
1226
|
+
return { success: false, error: 'NO_BACKUPS' };
|
|
1227
|
+
}
|
|
1228
|
+
targetBackup = backups[0].path;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
if (!existsSync(targetBackup)) {
|
|
1232
|
+
if (!silent) log.error(`Backup not found: ${targetBackup}`);
|
|
1233
|
+
return { success: false, error: 'BACKUP_NOT_FOUND' };
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
try {
|
|
1237
|
+
// Remove current .omgkit
|
|
1238
|
+
if (existsSync(omgkitDir)) {
|
|
1239
|
+
rmSync(omgkitDir, { recursive: true, force: true });
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// Restore from backup
|
|
1243
|
+
cpSync(targetBackup, omgkitDir, { recursive: true });
|
|
1244
|
+
|
|
1245
|
+
if (!silent) {
|
|
1246
|
+
log.success(`Rolled back to: ${targetBackup}`);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
return { success: true, restoredFrom: targetBackup };
|
|
1250
|
+
} catch (e) {
|
|
1251
|
+
if (!silent) log.error(`Rollback failed: ${e.message}`);
|
|
1252
|
+
return { success: false, error: e.message };
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Calculate upgrade changes (dry run)
|
|
1258
|
+
* @param {string} cwd - Project directory
|
|
1259
|
+
* @returns {Object} Changes to be applied
|
|
1260
|
+
*/
|
|
1261
|
+
export function calculateUpgradeChanges(cwd = process.cwd()) {
|
|
1262
|
+
const changes = {
|
|
1263
|
+
settings: [],
|
|
1264
|
+
workflow: [],
|
|
1265
|
+
stdrules: [],
|
|
1266
|
+
newFiles: [],
|
|
1267
|
+
protected: [
|
|
1268
|
+
'config.yaml',
|
|
1269
|
+
'sprints/vision.yaml',
|
|
1270
|
+
'sprints/backlog.yaml',
|
|
1271
|
+
'artifacts/*',
|
|
1272
|
+
'devlogs/*'
|
|
1273
|
+
]
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
const templatesDir = join(getPackageRoot(), 'templates');
|
|
1277
|
+
const omgkitDir = join(cwd, '.omgkit');
|
|
1278
|
+
const currentVersion = getProjectVersion(cwd);
|
|
1279
|
+
const targetVersion = getVersion();
|
|
1280
|
+
|
|
1281
|
+
// Check workflow.yaml changes
|
|
1282
|
+
const workflowTemplatePath = join(templatesDir, 'omgkit', 'workflow.yaml');
|
|
1283
|
+
const workflowProjectPath = join(omgkitDir, 'workflow.yaml');
|
|
1284
|
+
|
|
1285
|
+
if (existsSync(workflowTemplatePath)) {
|
|
1286
|
+
const templateContent = readFileSync(workflowTemplatePath, 'utf8');
|
|
1287
|
+
const templateConfig = parseSimpleYaml(templateContent);
|
|
1288
|
+
|
|
1289
|
+
if (existsSync(workflowProjectPath)) {
|
|
1290
|
+
const projectContent = readFileSync(workflowProjectPath, 'utf8');
|
|
1291
|
+
const projectConfig = parseSimpleYaml(projectContent);
|
|
1292
|
+
|
|
1293
|
+
// Find new top-level sections
|
|
1294
|
+
for (const key of Object.keys(templateConfig)) {
|
|
1295
|
+
if (!(key in projectConfig)) {
|
|
1296
|
+
changes.workflow.push({
|
|
1297
|
+
type: 'add_section',
|
|
1298
|
+
key,
|
|
1299
|
+
value: templateConfig[key]
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
} else {
|
|
1304
|
+
changes.newFiles.push('workflow.yaml');
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Check stdrules updates
|
|
1309
|
+
const stdrulesTemplate = join(templatesDir, 'stdrules');
|
|
1310
|
+
const stdrulesProject = join(omgkitDir, 'stdrules');
|
|
1311
|
+
|
|
1312
|
+
if (existsSync(stdrulesTemplate)) {
|
|
1313
|
+
const templateFiles = readdirSync(stdrulesTemplate).filter(f => f.endsWith('.md'));
|
|
1314
|
+
const settings = getProjectSettings(cwd) || {};
|
|
1315
|
+
const checksums = settings.file_checksums || {};
|
|
1316
|
+
|
|
1317
|
+
for (const file of templateFiles) {
|
|
1318
|
+
const templatePath = join(stdrulesTemplate, file);
|
|
1319
|
+
const projectPath = join(stdrulesProject, file);
|
|
1320
|
+
const templateContent = readFileSync(templatePath, 'utf8');
|
|
1321
|
+
const templateHash = hashContent(templateContent);
|
|
1322
|
+
|
|
1323
|
+
if (!existsSync(projectPath)) {
|
|
1324
|
+
changes.stdrules.push({
|
|
1325
|
+
type: 'new',
|
|
1326
|
+
file,
|
|
1327
|
+
reason: 'File does not exist'
|
|
1328
|
+
});
|
|
1329
|
+
} else {
|
|
1330
|
+
const projectContent = readFileSync(projectPath, 'utf8');
|
|
1331
|
+
const projectHash = hashContent(projectContent);
|
|
1332
|
+
const originalHash = checksums[`stdrules/${file}`];
|
|
1333
|
+
|
|
1334
|
+
// Update only if user hasn't modified the file
|
|
1335
|
+
if (originalHash && projectHash === originalHash && templateHash !== projectHash) {
|
|
1336
|
+
changes.stdrules.push({
|
|
1337
|
+
type: 'update',
|
|
1338
|
+
file,
|
|
1339
|
+
reason: 'Template updated, user has not modified'
|
|
1340
|
+
});
|
|
1341
|
+
} else if (!originalHash && templateHash !== projectHash) {
|
|
1342
|
+
changes.stdrules.push({
|
|
1343
|
+
type: 'skip',
|
|
1344
|
+
file,
|
|
1345
|
+
reason: 'User may have modified (no checksum recorded)'
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Settings.json updates
|
|
1353
|
+
const settingsPath = join(omgkitDir, 'settings.json');
|
|
1354
|
+
if (existsSync(settingsPath)) {
|
|
1355
|
+
const settings = getProjectSettings(cwd);
|
|
1356
|
+
if (!settings?.omgkit) {
|
|
1357
|
+
changes.settings.push({
|
|
1358
|
+
type: 'add',
|
|
1359
|
+
key: 'omgkit',
|
|
1360
|
+
value: { version: targetVersion, initialized_at: null, last_upgraded: null }
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
if (!settings?.file_checksums) {
|
|
1364
|
+
changes.settings.push({
|
|
1365
|
+
type: 'add',
|
|
1366
|
+
key: 'file_checksums',
|
|
1367
|
+
value: {}
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
return {
|
|
1373
|
+
currentVersion,
|
|
1374
|
+
targetVersion,
|
|
1375
|
+
needsUpgrade: compareVersions(targetVersion, currentVersion || '0.0.0') > 0,
|
|
1376
|
+
changes
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
/**
|
|
1381
|
+
* Upgrade project to latest OMGKIT version
|
|
1382
|
+
* @param {Object} options - Options
|
|
1383
|
+
* @param {string} [options.cwd] - Project directory
|
|
1384
|
+
* @param {boolean} [options.dryRun] - Only show what would change
|
|
1385
|
+
* @param {boolean} [options.force] - Skip confirmation
|
|
1386
|
+
* @param {boolean} [options.silent] - Suppress output
|
|
1387
|
+
* @returns {Object} Upgrade result
|
|
1388
|
+
*/
|
|
1389
|
+
export function upgradeProject(options = {}) {
|
|
1390
|
+
const { cwd = process.cwd(), dryRun = false, force = false, silent = false } = options;
|
|
1391
|
+
|
|
1392
|
+
if (!silent) {
|
|
1393
|
+
console.log(BANNER);
|
|
1394
|
+
log.omega('Checking for project upgrades...');
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
const omgkitDir = join(cwd, '.omgkit');
|
|
1398
|
+
|
|
1399
|
+
// Check if project is initialized
|
|
1400
|
+
if (!existsSync(omgkitDir)) {
|
|
1401
|
+
if (!silent) {
|
|
1402
|
+
log.error('Project not initialized. Run: omgkit init');
|
|
1403
|
+
}
|
|
1404
|
+
return { success: false, error: 'NOT_INITIALIZED' };
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// Calculate changes
|
|
1408
|
+
const upgradeInfo = calculateUpgradeChanges(cwd);
|
|
1409
|
+
|
|
1410
|
+
if (!upgradeInfo.needsUpgrade &&
|
|
1411
|
+
upgradeInfo.changes.workflow.length === 0 &&
|
|
1412
|
+
upgradeInfo.changes.stdrules.filter(s => s.type !== 'skip').length === 0 &&
|
|
1413
|
+
upgradeInfo.changes.newFiles.length === 0) {
|
|
1414
|
+
if (!silent) {
|
|
1415
|
+
log.success('Project is up to date!');
|
|
1416
|
+
console.log(` Current version: ${upgradeInfo.currentVersion || 'unknown'}`);
|
|
1417
|
+
console.log(` OMGKIT version: ${upgradeInfo.targetVersion}`);
|
|
1418
|
+
}
|
|
1419
|
+
return { success: true, upToDate: true };
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// Display changes
|
|
1423
|
+
if (!silent) {
|
|
1424
|
+
console.log(`
|
|
1425
|
+
${COLORS.bright}OMGKIT Project Upgrade${COLORS.reset}
|
|
1426
|
+
${'='.repeat(50)}
|
|
1427
|
+
Current version: ${upgradeInfo.currentVersion || 'unknown'}
|
|
1428
|
+
Target version: ${upgradeInfo.targetVersion}
|
|
1429
|
+
|
|
1430
|
+
${COLORS.bright}Changes to be applied:${COLORS.reset}
|
|
1431
|
+
`);
|
|
1432
|
+
|
|
1433
|
+
if (upgradeInfo.changes.workflow.length > 0) {
|
|
1434
|
+
console.log(`${COLORS.cyan}📁 workflow.yaml${COLORS.reset}`);
|
|
1435
|
+
for (const change of upgradeInfo.changes.workflow) {
|
|
1436
|
+
if (change.type === 'add_section') {
|
|
1437
|
+
console.log(` ${COLORS.green}+ ${change.key}: {...}${COLORS.reset}`);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
if (upgradeInfo.changes.stdrules.length > 0) {
|
|
1443
|
+
console.log(`\n${COLORS.cyan}📁 stdrules/${COLORS.reset}`);
|
|
1444
|
+
for (const change of upgradeInfo.changes.stdrules) {
|
|
1445
|
+
if (change.type === 'new') {
|
|
1446
|
+
console.log(` ${COLORS.green}+ ${change.file} (new)${COLORS.reset}`);
|
|
1447
|
+
} else if (change.type === 'update') {
|
|
1448
|
+
console.log(` ${COLORS.yellow}~ ${change.file} (updated)${COLORS.reset}`);
|
|
1449
|
+
} else if (change.type === 'skip') {
|
|
1450
|
+
console.log(` ${COLORS.blue}○ ${change.file} (skipped - may be modified)${COLORS.reset}`);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (upgradeInfo.changes.newFiles.length > 0) {
|
|
1456
|
+
console.log(`\n${COLORS.cyan}📁 New files${COLORS.reset}`);
|
|
1457
|
+
for (const file of upgradeInfo.changes.newFiles) {
|
|
1458
|
+
console.log(` ${COLORS.green}+ ${file}${COLORS.reset}`);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
console.log(`
|
|
1463
|
+
${COLORS.bright}🔒 Protected (no changes):${COLORS.reset}`);
|
|
1464
|
+
for (const protected_ of upgradeInfo.changes.protected) {
|
|
1465
|
+
console.log(` - ${protected_}`);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
if (dryRun) {
|
|
1470
|
+
if (!silent) {
|
|
1471
|
+
console.log(`\n${COLORS.yellow}Dry run - no changes made.${COLORS.reset}`);
|
|
1472
|
+
console.log('Run without --dry to apply changes.');
|
|
1473
|
+
}
|
|
1474
|
+
return { success: true, dryRun: true, changes: upgradeInfo.changes };
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// Create backup before upgrade
|
|
1478
|
+
if (!silent) log.info('\nCreating backup...');
|
|
1479
|
+
const backup = createProjectBackup(cwd);
|
|
1480
|
+
if (!backup.success) {
|
|
1481
|
+
if (!silent) log.error(`Backup failed: ${backup.error}`);
|
|
1482
|
+
return { success: false, error: 'BACKUP_FAILED' };
|
|
1483
|
+
}
|
|
1484
|
+
if (!silent) log.success(`Backup created: ${backup.path}`);
|
|
1485
|
+
|
|
1486
|
+
const templatesDir = join(getPackageRoot(), 'templates');
|
|
1487
|
+
const applied = { workflow: [], stdrules: [], newFiles: [], settings: [] };
|
|
1488
|
+
|
|
1489
|
+
try {
|
|
1490
|
+
// Apply workflow.yaml changes
|
|
1491
|
+
if (upgradeInfo.changes.workflow.length > 0) {
|
|
1492
|
+
const workflowPath = join(omgkitDir, 'workflow.yaml');
|
|
1493
|
+
const workflowTemplatePath = join(templatesDir, 'omgkit', 'workflow.yaml');
|
|
1494
|
+
|
|
1495
|
+
if (existsSync(workflowPath) && existsSync(workflowTemplatePath)) {
|
|
1496
|
+
const projectContent = readFileSync(workflowPath, 'utf8');
|
|
1497
|
+
const templateContent = readFileSync(workflowTemplatePath, 'utf8');
|
|
1498
|
+
|
|
1499
|
+
const projectConfig = parseSimpleYaml(projectContent);
|
|
1500
|
+
const templateConfig = parseSimpleYaml(templateContent);
|
|
1501
|
+
|
|
1502
|
+
const merged = deepMergeAddOnly(projectConfig, templateConfig);
|
|
1503
|
+
|
|
1504
|
+
// Preserve comments from original file by appending new sections
|
|
1505
|
+
let newContent = projectContent;
|
|
1506
|
+
|
|
1507
|
+
for (const change of upgradeInfo.changes.workflow) {
|
|
1508
|
+
if (change.type === 'add_section') {
|
|
1509
|
+
// Find section in template and append
|
|
1510
|
+
const sectionRegex = new RegExp(`^${change.key}:`, 'm');
|
|
1511
|
+
const templateLines = templateContent.split('\n');
|
|
1512
|
+
let inSection = false;
|
|
1513
|
+
let sectionContent = '';
|
|
1514
|
+
|
|
1515
|
+
for (const line of templateLines) {
|
|
1516
|
+
if (line.match(sectionRegex)) {
|
|
1517
|
+
inSection = true;
|
|
1518
|
+
} else if (inSection && line.match(/^\w+:/) && !line.startsWith(' ')) {
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
if (inSection) {
|
|
1523
|
+
sectionContent += line + '\n';
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
if (sectionContent) {
|
|
1528
|
+
newContent = newContent.trimEnd() + '\n\n' + sectionContent;
|
|
1529
|
+
applied.workflow.push(change.key);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
writeFileSync(workflowPath, newContent);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// Apply stdrules updates
|
|
1539
|
+
for (const change of upgradeInfo.changes.stdrules) {
|
|
1540
|
+
if (change.type === 'new' || change.type === 'update') {
|
|
1541
|
+
const templatePath = join(templatesDir, 'stdrules', change.file);
|
|
1542
|
+
const projectPath = join(omgkitDir, 'stdrules', change.file);
|
|
1543
|
+
|
|
1544
|
+
if (existsSync(templatePath)) {
|
|
1545
|
+
cpSync(templatePath, projectPath);
|
|
1546
|
+
applied.stdrules.push(change.file);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
// Apply new files
|
|
1552
|
+
for (const file of upgradeInfo.changes.newFiles) {
|
|
1553
|
+
if (file === 'workflow.yaml') {
|
|
1554
|
+
const templatePath = join(templatesDir, 'omgkit', 'workflow.yaml');
|
|
1555
|
+
const projectPath = join(omgkitDir, 'workflow.yaml');
|
|
1556
|
+
if (existsSync(templatePath)) {
|
|
1557
|
+
cpSync(templatePath, projectPath);
|
|
1558
|
+
applied.newFiles.push(file);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// Update settings.json
|
|
1564
|
+
const settingsPath = join(omgkitDir, 'settings.json');
|
|
1565
|
+
let settings = getProjectSettings(cwd) || {};
|
|
1566
|
+
|
|
1567
|
+
// Add omgkit version tracking
|
|
1568
|
+
if (!settings.omgkit) {
|
|
1569
|
+
settings.omgkit = {};
|
|
1570
|
+
}
|
|
1571
|
+
settings.omgkit.version = upgradeInfo.targetVersion;
|
|
1572
|
+
settings.omgkit.last_upgraded = new Date().toISOString().split('T')[0];
|
|
1573
|
+
|
|
1574
|
+
// Initialize checksums if not present
|
|
1575
|
+
if (!settings.file_checksums) {
|
|
1576
|
+
settings.file_checksums = {};
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
// Update checksums for stdrules files
|
|
1580
|
+
const stdrulesDir = join(omgkitDir, 'stdrules');
|
|
1581
|
+
if (existsSync(stdrulesDir)) {
|
|
1582
|
+
const files = readdirSync(stdrulesDir).filter(f => f.endsWith('.md'));
|
|
1583
|
+
for (const file of files) {
|
|
1584
|
+
const content = readFileSync(join(stdrulesDir, file), 'utf8');
|
|
1585
|
+
settings.file_checksums[`stdrules/${file}`] = hashContent(content);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
1590
|
+
applied.settings.push('version', 'checksums');
|
|
1591
|
+
|
|
1592
|
+
} catch (e) {
|
|
1593
|
+
// Rollback on error
|
|
1594
|
+
if (!silent) {
|
|
1595
|
+
log.error(`Upgrade failed: ${e.message}`);
|
|
1596
|
+
log.info('Rolling back...');
|
|
1597
|
+
}
|
|
1598
|
+
rollbackProject({ cwd, backupPath: backup.path, silent: true });
|
|
1599
|
+
if (!silent) log.success('Rolled back to previous state');
|
|
1600
|
+
return { success: false, error: e.message, rolledBack: true };
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
if (!silent) {
|
|
1604
|
+
console.log(`
|
|
1605
|
+
${COLORS.green}✓ Project upgraded successfully!${COLORS.reset}
|
|
1606
|
+
|
|
1607
|
+
${COLORS.bright}Applied changes:${COLORS.reset}`);
|
|
1608
|
+
|
|
1609
|
+
if (applied.workflow.length > 0) {
|
|
1610
|
+
console.log(` workflow.yaml: Added ${applied.workflow.join(', ')}`);
|
|
1611
|
+
}
|
|
1612
|
+
if (applied.stdrules.length > 0) {
|
|
1613
|
+
console.log(` stdrules/: Updated ${applied.stdrules.join(', ')}`);
|
|
1614
|
+
}
|
|
1615
|
+
if (applied.newFiles.length > 0) {
|
|
1616
|
+
console.log(` New files: ${applied.newFiles.join(', ')}`);
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
console.log(`
|
|
1620
|
+
${COLORS.bright}Backup location:${COLORS.reset} ${backup.path}
|
|
1621
|
+
|
|
1622
|
+
To rollback: omgkit project:rollback
|
|
1623
|
+
|
|
1624
|
+
${COLORS.magenta}🔮 Think Omega. Build Omega. Be Omega.${COLORS.reset}
|
|
1625
|
+
`);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
return {
|
|
1629
|
+
success: true,
|
|
1630
|
+
previousVersion: upgradeInfo.currentVersion,
|
|
1631
|
+
newVersion: upgradeInfo.targetVersion,
|
|
1632
|
+
applied,
|
|
1633
|
+
backupPath: backup.path
|
|
1634
|
+
};
|
|
1635
|
+
}
|
package/package.json
CHANGED
package/plugin/registry.yaml
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# OMGKIT Component Registry
|
|
2
2
|
# Single Source of Truth for Agents, Skills, Commands, Workflows, and MCPs
|
|
3
|
-
# Version: 2.
|
|
3
|
+
# Version: 2.25.0
|
|
4
4
|
# Updated: 2026-01-06
|
|
5
5
|
|
|
6
|
-
version: "2.
|
|
6
|
+
version: "2.25.0"
|
|
7
7
|
|
|
8
8
|
# =============================================================================
|
|
9
9
|
# OPTIMIZED ALIGNMENT PRINCIPLE (OAP)
|