@burgan-tech/vnext-workflow-cli 1.0.0 → 1.0.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/.github/CODEOWNERS +2 -0
- package/README.md +244 -82
- package/bin/workflow.js +0 -0
- package/package.json +5 -5
- package/src/commands/check.js +62 -22
- package/src/commands/config.js +5 -6
- package/src/commands/csx.js +125 -44
- package/src/commands/reset.js +198 -80
- package/src/commands/sync.js +189 -107
- package/src/commands/update.js +217 -99
- package/src/lib/api.js +52 -34
- package/src/lib/config.js +43 -5
- package/src/lib/csx.js +130 -57
- package/src/lib/discover.js +131 -29
- package/src/lib/vnextConfig.js +124 -0
- package/src/lib/workflow.js +86 -39
package/src/commands/csx.js
CHANGED
|
@@ -2,83 +2,164 @@ const chalk = require('chalk');
|
|
|
2
2
|
const ora = require('ora');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const config = require('../lib/config');
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
const { getDomain } = require('../lib/vnextConfig');
|
|
6
|
+
const { processCsxFile, getGitChangedCsx, findAllCsx } = require('../lib/csx');
|
|
7
|
+
|
|
8
|
+
// Logging helpers
|
|
9
|
+
const LOG = {
|
|
10
|
+
separator: () => console.log(chalk.cyan('═'.repeat(60))),
|
|
11
|
+
subSeparator: () => console.log(chalk.cyan('─'.repeat(60))),
|
|
12
|
+
header: (text) => {
|
|
13
|
+
console.log();
|
|
14
|
+
LOG.separator();
|
|
15
|
+
console.log(chalk.cyan.bold(` ${text}`));
|
|
16
|
+
LOG.separator();
|
|
17
|
+
},
|
|
18
|
+
success: (text) => console.log(chalk.green(` ✓ ${text}`)),
|
|
19
|
+
error: (text) => console.log(chalk.red(` ✗ ${text}`)),
|
|
20
|
+
warning: (text) => console.log(chalk.yellow(` ⚠ ${text}`)),
|
|
21
|
+
info: (text) => console.log(chalk.dim(` ○ ${text}`)),
|
|
22
|
+
component: (type, name, status, detail = '') => {
|
|
23
|
+
const typeLabel = chalk.cyan(`[${type}]`);
|
|
24
|
+
const nameLabel = chalk.white(name);
|
|
25
|
+
if (status === 'success') {
|
|
26
|
+
console.log(` ${typeLabel} ${chalk.green('✓')} ${nameLabel} ${chalk.dim(detail)}`);
|
|
27
|
+
} else if (status === 'error') {
|
|
28
|
+
console.log(` ${typeLabel} ${chalk.red('✗')} ${nameLabel}`);
|
|
29
|
+
if (detail) console.log(chalk.red(` └─ ${detail}`));
|
|
30
|
+
} else if (status === 'skip') {
|
|
31
|
+
console.log(` ${typeLabel} ${chalk.dim('○')} ${nameLabel} ${chalk.dim(detail)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
10
35
|
|
|
11
36
|
async function csxCommand(options) {
|
|
12
|
-
|
|
37
|
+
LOG.header('CSX UPDATE');
|
|
13
38
|
|
|
14
39
|
const projectRoot = config.get('PROJECT_ROOT');
|
|
40
|
+
|
|
41
|
+
// Check domain
|
|
42
|
+
try {
|
|
43
|
+
const domain = getDomain(projectRoot);
|
|
44
|
+
console.log(chalk.dim(` Domain: ${domain}`));
|
|
45
|
+
console.log();
|
|
46
|
+
} catch (error) {
|
|
47
|
+
LOG.error(`Failed to read vnext.config.json: ${error.message}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
15
51
|
let csxFiles = [];
|
|
16
52
|
|
|
17
|
-
//
|
|
53
|
+
// Which CSX files to process?
|
|
18
54
|
if (options.file) {
|
|
19
|
-
//
|
|
55
|
+
// Specific file
|
|
20
56
|
const filePath = path.isAbsolute(options.file)
|
|
21
57
|
? options.file
|
|
22
58
|
: path.join(projectRoot, options.file);
|
|
23
59
|
csxFiles = [filePath];
|
|
24
|
-
console.log(chalk.blue(`
|
|
60
|
+
console.log(chalk.blue(` File: ${path.basename(filePath)}\n`));
|
|
25
61
|
} else if (options.all) {
|
|
26
|
-
//
|
|
27
|
-
const spinner = ora('
|
|
28
|
-
|
|
29
|
-
|
|
62
|
+
// All CSX files
|
|
63
|
+
const spinner = ora(' Finding all CSX files...').start();
|
|
64
|
+
try {
|
|
65
|
+
csxFiles = await findAllCsx(projectRoot);
|
|
66
|
+
spinner.succeed(chalk.green(` ${csxFiles.length} CSX files found`));
|
|
67
|
+
} catch (error) {
|
|
68
|
+
spinner.fail(chalk.red(` CSX scan error: ${error.message}`));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
30
71
|
} else {
|
|
31
|
-
// Git
|
|
32
|
-
const spinner = ora('
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
72
|
+
// Changed files in Git (default)
|
|
73
|
+
const spinner = ora(' Finding changed CSX files in Git...').start();
|
|
74
|
+
try {
|
|
75
|
+
csxFiles = await getGitChangedCsx(projectRoot);
|
|
76
|
+
|
|
77
|
+
if (csxFiles.length === 0) {
|
|
78
|
+
spinner.info(chalk.yellow(' No changed CSX files in Git'));
|
|
79
|
+
console.log(chalk.green('\n ✓ All CSX files up to date\n'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
spinner.succeed(chalk.green(` ${csxFiles.length} changed CSX files found`));
|
|
84
|
+
} catch (error) {
|
|
85
|
+
spinner.fail(chalk.red(` CSX scan error: ${error.message}`));
|
|
38
86
|
return;
|
|
39
87
|
}
|
|
40
|
-
|
|
41
|
-
spinner.succeed(chalk.green(`${csxFiles.length} değişen CSX dosyası bulundu`));
|
|
42
88
|
}
|
|
43
89
|
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
90
|
+
// Process each CSX file
|
|
91
|
+
const results = { success: 0, failed: 0, errors: [] };
|
|
92
|
+
const updatedFiles = [];
|
|
93
|
+
|
|
94
|
+
console.log(chalk.blue('\n Writing CSX files to JSONs...\n'));
|
|
47
95
|
|
|
48
|
-
console.log();
|
|
49
96
|
for (const csxFile of csxFiles) {
|
|
50
97
|
const fileName = path.basename(csxFile);
|
|
51
|
-
const spinner = ora(`İşleniyor: ${fileName}`).start();
|
|
52
98
|
|
|
53
99
|
try {
|
|
54
100
|
const result = await processCsxFile(csxFile, projectRoot);
|
|
55
101
|
|
|
56
102
|
if (result.success) {
|
|
57
|
-
|
|
58
|
-
|
|
103
|
+
LOG.component('CSX', fileName, 'success', `→ ${result.updatedJsonCount} JSON, ${result.totalUpdates} refs`);
|
|
104
|
+
results.success++;
|
|
105
|
+
updatedFiles.push({
|
|
106
|
+
file: fileName,
|
|
107
|
+
jsonCount: result.updatedJsonCount,
|
|
108
|
+
totalUpdates: result.totalUpdates,
|
|
109
|
+
jsonFiles: result.jsonFiles
|
|
110
|
+
});
|
|
59
111
|
} else {
|
|
60
|
-
|
|
61
|
-
failCount++;
|
|
112
|
+
LOG.component('CSX', fileName, 'skip', result.message);
|
|
62
113
|
}
|
|
63
114
|
} catch (error) {
|
|
64
|
-
|
|
65
|
-
|
|
115
|
+
LOG.component('CSX', fileName, 'error', error.message);
|
|
116
|
+
results.failed++;
|
|
117
|
+
results.errors.push({ file: fileName, error: error.message });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// SUMMARY REPORT
|
|
122
|
+
LOG.header('CSX UPDATE SUMMARY');
|
|
123
|
+
|
|
124
|
+
// Results
|
|
125
|
+
console.log(chalk.white.bold('\n Results:\n'));
|
|
126
|
+
|
|
127
|
+
const successLabel = results.success > 0 ? chalk.green(`${results.success} success`) : chalk.dim('0 success');
|
|
128
|
+
const failedLabel = results.failed > 0 ? chalk.red(`, ${results.failed} failed`) : '';
|
|
129
|
+
console.log(` ${chalk.cyan('CSX Files'.padEnd(16))} : ${successLabel}${failedLabel}`);
|
|
130
|
+
|
|
131
|
+
// Updated JSON details
|
|
132
|
+
if (updatedFiles.length > 0) {
|
|
133
|
+
console.log();
|
|
134
|
+
LOG.subSeparator();
|
|
135
|
+
console.log(chalk.white.bold('\n Updated JSON Files:\n'));
|
|
136
|
+
|
|
137
|
+
for (const item of updatedFiles) {
|
|
138
|
+
console.log(chalk.green(` ${item.file}:`));
|
|
139
|
+
for (const json of item.jsonFiles) {
|
|
140
|
+
console.log(chalk.dim(` └─ ${json.file} (${json.updates} refs)`));
|
|
141
|
+
}
|
|
66
142
|
}
|
|
67
143
|
}
|
|
68
144
|
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
145
|
+
// Errors
|
|
146
|
+
if (results.errors.length > 0) {
|
|
147
|
+
console.log();
|
|
148
|
+
LOG.subSeparator();
|
|
149
|
+
console.log(chalk.red.bold('\n ERRORS:\n'));
|
|
150
|
+
|
|
151
|
+
for (const err of results.errors) {
|
|
152
|
+
console.log(chalk.red(` [CSX] ${err.file}`));
|
|
153
|
+
console.log(chalk.dim(` └─ ${err.error}`));
|
|
154
|
+
}
|
|
76
155
|
}
|
|
77
|
-
console.log(chalk.cyan('─'.repeat(50)));
|
|
78
|
-
console.log();
|
|
79
156
|
|
|
80
|
-
|
|
81
|
-
|
|
157
|
+
LOG.separator();
|
|
158
|
+
|
|
159
|
+
if (results.success > 0 && results.failed === 0) {
|
|
160
|
+
console.log(chalk.green.bold('\n ✓ CSX update completed\n'));
|
|
161
|
+
} else if (results.failed > 0) {
|
|
162
|
+
console.log(chalk.yellow.bold(`\n ⚠ CSX update completed (${results.failed} errors)\n`));
|
|
82
163
|
}
|
|
83
164
|
}
|
|
84
165
|
|
package/src/commands/reset.js
CHANGED
|
@@ -1,161 +1,279 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const ora = require('ora');
|
|
3
3
|
const inquirer = require('inquirer');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { glob } = require('glob');
|
|
4
6
|
const config = require('../lib/config');
|
|
5
7
|
const { discoverComponents } = require('../lib/discover');
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
8
|
+
const { getDomain, getComponentTypes } = require('../lib/vnextConfig');
|
|
9
|
+
const { getJsonMetadata, findAllJson, detectComponentType } = require('../lib/workflow');
|
|
10
|
+
const { publishComponent, reinitializeSystem } = require('../lib/api');
|
|
11
|
+
const { getInstanceId, deleteWorkflow } = require('../lib/db');
|
|
12
|
+
|
|
13
|
+
// Logging helpers
|
|
14
|
+
const LOG = {
|
|
15
|
+
separator: () => console.log(chalk.cyan('═'.repeat(60))),
|
|
16
|
+
subSeparator: () => console.log(chalk.cyan('─'.repeat(60))),
|
|
17
|
+
header: (text) => {
|
|
18
|
+
console.log();
|
|
19
|
+
LOG.separator();
|
|
20
|
+
console.log(chalk.cyan.bold(` ${text}`));
|
|
21
|
+
LOG.separator();
|
|
22
|
+
},
|
|
23
|
+
success: (text) => console.log(chalk.green(` ✓ ${text}`)),
|
|
24
|
+
error: (text) => console.log(chalk.red(` ✗ ${text}`)),
|
|
25
|
+
warning: (text) => console.log(chalk.yellow(` ⚠ ${text}`)),
|
|
26
|
+
info: (text) => console.log(chalk.dim(` ○ ${text}`)),
|
|
27
|
+
component: (type, name, status, detail = '') => {
|
|
28
|
+
const typeLabel = chalk.cyan(`[${type}]`);
|
|
29
|
+
const nameLabel = chalk.white(name);
|
|
30
|
+
if (status === 'success') {
|
|
31
|
+
console.log(` ${typeLabel} ${chalk.green('✓')} ${nameLabel} ${chalk.dim(detail)}`);
|
|
32
|
+
} else if (status === 'error') {
|
|
33
|
+
console.log(` ${typeLabel} ${chalk.red('✗')} ${nameLabel}`);
|
|
34
|
+
if (detail) console.log(chalk.red(` └─ ${detail}`));
|
|
35
|
+
} else if (status === 'skip') {
|
|
36
|
+
console.log(` ${typeLabel} ${chalk.dim('○')} ${nameLabel} ${chalk.dim(detail)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
8
40
|
|
|
9
41
|
async function resetCommand(options) {
|
|
10
|
-
|
|
42
|
+
LOG.header('COMPONENT RESET (Force Update)');
|
|
11
43
|
|
|
12
44
|
const projectRoot = config.get('PROJECT_ROOT');
|
|
13
|
-
|
|
45
|
+
|
|
46
|
+
// Get domain from vnext.config.json
|
|
47
|
+
let domain, componentTypes;
|
|
48
|
+
try {
|
|
49
|
+
domain = getDomain(projectRoot);
|
|
50
|
+
componentTypes = getComponentTypes(projectRoot);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
LOG.error(`Failed to read vnext.config.json: ${error.message}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
14
55
|
|
|
15
56
|
// DB Config
|
|
57
|
+
const useDockerValue = config.get('USE_DOCKER');
|
|
16
58
|
const dbConfig = {
|
|
17
59
|
host: config.get('DB_HOST'),
|
|
18
60
|
port: config.get('DB_PORT'),
|
|
19
61
|
database: config.get('DB_NAME'),
|
|
20
62
|
user: config.get('DB_USER'),
|
|
21
63
|
password: config.get('DB_PASSWORD'),
|
|
22
|
-
useDocker:
|
|
64
|
+
useDocker: useDockerValue === true || useDockerValue === 'true',
|
|
23
65
|
dockerContainer: config.get('DOCKER_POSTGRES_CONTAINER')
|
|
24
66
|
};
|
|
25
67
|
|
|
26
68
|
// API Config
|
|
27
69
|
const apiConfig = {
|
|
28
70
|
baseUrl: config.get('API_BASE_URL'),
|
|
29
|
-
version: config.get('API_VERSION')
|
|
71
|
+
version: config.get('API_VERSION'),
|
|
72
|
+
domain: domain
|
|
30
73
|
};
|
|
31
74
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
75
|
+
console.log(chalk.dim(` Domain: ${domain}`));
|
|
76
|
+
console.log(chalk.dim(` API: ${apiConfig.baseUrl}`));
|
|
77
|
+
console.log();
|
|
78
|
+
|
|
79
|
+
// Discover folders
|
|
80
|
+
const spinner = ora(' Scanning folders...').start();
|
|
81
|
+
let discovered;
|
|
82
|
+
try {
|
|
83
|
+
discovered = await discoverComponents(projectRoot);
|
|
84
|
+
spinner.succeed(chalk.green(' Folders discovered'));
|
|
85
|
+
} catch (error) {
|
|
86
|
+
spinner.fail(chalk.red(` Folder scan error: ${error.message}`));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Build choices dynamically
|
|
91
|
+
const choices = [];
|
|
92
|
+
for (const [type, folderName] of Object.entries(componentTypes)) {
|
|
93
|
+
if (discovered[type]) {
|
|
94
|
+
choices.push({ name: `${type} (${folderName}/)`, value: type });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
choices.push(new inquirer.Separator());
|
|
99
|
+
choices.push({ name: 'ALL (All folders)', value: 'ALL' });
|
|
100
|
+
|
|
101
|
+
// User selection
|
|
50
102
|
const { selected } = await inquirer.prompt([{
|
|
51
103
|
type: 'list',
|
|
52
104
|
name: 'selected',
|
|
53
|
-
message: '
|
|
105
|
+
message: 'Which folder to reset?',
|
|
54
106
|
choices: choices
|
|
55
107
|
}]);
|
|
56
108
|
|
|
57
|
-
//
|
|
109
|
+
// Find files
|
|
58
110
|
let jsonFiles = [];
|
|
59
111
|
|
|
60
112
|
if (selected === 'ALL') {
|
|
61
|
-
|
|
113
|
+
const files = await findAllJson(discovered);
|
|
114
|
+
jsonFiles = files.map(f => ({
|
|
115
|
+
path: f,
|
|
116
|
+
type: detectComponentType(f, projectRoot),
|
|
117
|
+
fileName: path.basename(f)
|
|
118
|
+
}));
|
|
62
119
|
} else {
|
|
63
120
|
const dir = discovered[selected];
|
|
64
121
|
if (!dir) {
|
|
65
|
-
|
|
122
|
+
LOG.error(`${selected} folder not found`);
|
|
66
123
|
return;
|
|
67
124
|
}
|
|
68
125
|
|
|
69
|
-
//
|
|
70
|
-
const fs = require('fs').promises;
|
|
71
|
-
const path = require('path');
|
|
72
|
-
const { glob } = require('glob');
|
|
73
|
-
|
|
126
|
+
// Find JSONs in this folder only
|
|
74
127
|
const pattern = path.join(dir, '**/*.json');
|
|
75
|
-
|
|
128
|
+
const files = await glob(pattern, {
|
|
129
|
+
ignore: [
|
|
130
|
+
'**/.meta/**',
|
|
131
|
+
'**/.meta',
|
|
132
|
+
'**/*.diagram.json',
|
|
133
|
+
'**/package*.json',
|
|
134
|
+
'**/*config*.json'
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
jsonFiles = files.map(f => ({
|
|
139
|
+
path: f,
|
|
140
|
+
type: selected,
|
|
141
|
+
fileName: path.basename(f)
|
|
142
|
+
}));
|
|
76
143
|
}
|
|
77
144
|
|
|
78
145
|
if (jsonFiles.length === 0) {
|
|
79
|
-
|
|
146
|
+
LOG.warning('No JSON files found');
|
|
147
|
+
console.log();
|
|
80
148
|
return;
|
|
81
149
|
}
|
|
82
150
|
|
|
83
|
-
//
|
|
84
|
-
|
|
151
|
+
// Final confirmation
|
|
152
|
+
LOG.warning(`${jsonFiles.length} components will be reset!`);
|
|
153
|
+
console.log();
|
|
85
154
|
|
|
86
155
|
const { confirm } = await inquirer.prompt([{
|
|
87
156
|
type: 'confirm',
|
|
88
157
|
name: 'confirm',
|
|
89
|
-
message: '
|
|
158
|
+
message: 'Continue?',
|
|
90
159
|
default: false
|
|
91
160
|
}]);
|
|
92
161
|
|
|
93
162
|
if (!confirm) {
|
|
94
|
-
|
|
163
|
+
LOG.warning('Operation cancelled.');
|
|
164
|
+
console.log();
|
|
95
165
|
return;
|
|
96
166
|
}
|
|
97
167
|
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
168
|
+
// Group by component type
|
|
169
|
+
const componentStats = {};
|
|
170
|
+
const errors = [];
|
|
101
171
|
|
|
102
|
-
console.log();
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
172
|
+
console.log(chalk.blue('\n Resetting components...\n'));
|
|
173
|
+
|
|
174
|
+
for (const jsonInfo of jsonFiles) {
|
|
175
|
+
const { path: jsonPath, type, fileName } = jsonInfo;
|
|
176
|
+
|
|
177
|
+
// Initialize stats
|
|
178
|
+
if (!componentStats[type]) {
|
|
179
|
+
componentStats[type] = { success: 0, failed: 0, skipped: 0, deleted: 0 };
|
|
180
|
+
}
|
|
106
181
|
|
|
107
182
|
try {
|
|
108
|
-
const
|
|
183
|
+
const metadata = await getJsonMetadata(jsonPath);
|
|
109
184
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
185
|
+
if (!metadata.key || !metadata.version) {
|
|
186
|
+
LOG.component(type, fileName, 'skip', 'no key/version');
|
|
187
|
+
componentStats[type].skipped++;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Detect flow type
|
|
192
|
+
const flow = metadata.flow || detectComponentType(jsonPath, projectRoot);
|
|
193
|
+
|
|
194
|
+
// Check if exists in DB
|
|
195
|
+
const existingId = await getInstanceId(dbConfig, flow, metadata.key, metadata.version);
|
|
196
|
+
|
|
197
|
+
// If exists, delete first (force reset)
|
|
198
|
+
let wasDeleted = false;
|
|
199
|
+
if (existingId) {
|
|
200
|
+
await deleteWorkflow(dbConfig, flow, existingId);
|
|
201
|
+
wasDeleted = true;
|
|
202
|
+
componentStats[type].deleted++;
|
|
125
203
|
}
|
|
126
|
-
|
|
127
|
-
|
|
204
|
+
|
|
205
|
+
// Publish to API
|
|
206
|
+
const result = await publishComponent(apiConfig.baseUrl, metadata.data);
|
|
207
|
+
|
|
208
|
+
if (result.success) {
|
|
209
|
+
const action = wasDeleted ? 'reset' : 'created';
|
|
210
|
+
LOG.component(type, fileName, 'success', `→ ${action}`);
|
|
211
|
+
componentStats[type].success++;
|
|
212
|
+
} else {
|
|
213
|
+
LOG.component(type, fileName, 'error', result.error);
|
|
214
|
+
componentStats[type].failed++;
|
|
215
|
+
errors.push({ type, file: fileName, error: result.error });
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
const errorMsg = error.message || 'Unknown error';
|
|
219
|
+
LOG.component(type, fileName, 'error', errorMsg);
|
|
220
|
+
componentStats[type].failed++;
|
|
221
|
+
errors.push({ type, file: fileName, error: errorMsg });
|
|
128
222
|
}
|
|
129
223
|
}
|
|
130
224
|
|
|
131
225
|
// Re-initialize
|
|
132
|
-
|
|
226
|
+
const totalSuccess = Object.values(componentStats).reduce((sum, s) => sum + s.success, 0);
|
|
227
|
+
|
|
228
|
+
if (totalSuccess > 0) {
|
|
133
229
|
console.log();
|
|
134
|
-
const reinitSpinner = ora('
|
|
230
|
+
const reinitSpinner = ora(' Re-initializing system...').start();
|
|
135
231
|
const reinitSuccess = await reinitializeSystem(apiConfig.baseUrl, apiConfig.version);
|
|
136
232
|
|
|
137
233
|
if (reinitSuccess) {
|
|
138
|
-
reinitSpinner.succeed(chalk.green('
|
|
234
|
+
reinitSpinner.succeed(chalk.green(' System re-initialized'));
|
|
139
235
|
} else {
|
|
140
|
-
reinitSpinner.warn(chalk.yellow('
|
|
236
|
+
reinitSpinner.warn(chalk.yellow(' System re-initialization failed (continuing)'));
|
|
141
237
|
}
|
|
142
238
|
}
|
|
143
239
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
console.log(chalk.
|
|
149
|
-
|
|
150
|
-
|
|
240
|
+
// SUMMARY REPORT
|
|
241
|
+
LOG.header('RESET SUMMARY');
|
|
242
|
+
|
|
243
|
+
// Component statistics
|
|
244
|
+
console.log(chalk.white.bold('\n Component Reset Results:\n'));
|
|
245
|
+
|
|
246
|
+
for (const [type, stats] of Object.entries(componentStats)) {
|
|
247
|
+
const successLabel = stats.success > 0 ? chalk.green(`${stats.success} reset`) : '';
|
|
248
|
+
const deletedLabel = stats.deleted > 0 ? chalk.yellow(`${stats.deleted} deleted`) : '';
|
|
249
|
+
const failedLabel = stats.failed > 0 ? chalk.red(`${stats.failed} failed`) : '';
|
|
250
|
+
const skippedLabel = stats.skipped > 0 ? chalk.dim(`${stats.skipped} skipped`) : '';
|
|
251
|
+
|
|
252
|
+
const parts = [successLabel, deletedLabel, failedLabel, skippedLabel].filter(Boolean);
|
|
253
|
+
console.log(` ${chalk.cyan(type.padEnd(12))} : ${parts.join(', ') || chalk.dim('0')}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Errors
|
|
257
|
+
if (errors.length > 0) {
|
|
258
|
+
console.log();
|
|
259
|
+
LOG.subSeparator();
|
|
260
|
+
console.log(chalk.red.bold('\n ERRORS:\n'));
|
|
261
|
+
|
|
262
|
+
for (const err of errors) {
|
|
263
|
+
console.log(chalk.red(` [${err.type}] ${err.file}`));
|
|
264
|
+
console.log(chalk.dim(` └─ ${err.error}`));
|
|
265
|
+
}
|
|
151
266
|
}
|
|
152
|
-
console.log(chalk.cyan('═'.repeat(50)));
|
|
153
|
-
console.log();
|
|
154
267
|
|
|
155
|
-
|
|
156
|
-
|
|
268
|
+
LOG.separator();
|
|
269
|
+
|
|
270
|
+
const totalFailed = Object.values(componentStats).reduce((sum, s) => sum + s.failed, 0);
|
|
271
|
+
|
|
272
|
+
if (totalSuccess > 0 && totalFailed === 0) {
|
|
273
|
+
console.log(chalk.green.bold('\n ✓ Reset completed\n'));
|
|
274
|
+
} else if (totalFailed > 0) {
|
|
275
|
+
console.log(chalk.yellow.bold(`\n ⚠ Reset completed (${totalFailed} errors)\n`));
|
|
157
276
|
}
|
|
158
277
|
}
|
|
159
278
|
|
|
160
279
|
module.exports = resetCommand;
|
|
161
|
-
|