@shirayner/ace 0.1.1-snapshot.1 → 0.1.1-snapshot.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/package.json +1 -1
- package/src/commands/init.js +59 -128
- package/src/core/ui.js +44 -144
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -4,85 +4,46 @@ import { createRequire } from 'module';
|
|
|
4
4
|
import { PRESETS, ROLES, COMPONENTS } from '../core/constants.js';
|
|
5
5
|
import { Installer } from '../core/installer.js';
|
|
6
6
|
import {
|
|
7
|
-
printBanner,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
colors, icons, componentIcons, componentLabels,
|
|
7
|
+
printBanner, stepDone, stepMerge, stepSkip, stepFail,
|
|
8
|
+
doneMessage, doneWithErrors,
|
|
9
|
+
colors, icons, componentLabels,
|
|
11
10
|
} from '../core/ui.js';
|
|
12
11
|
|
|
13
12
|
const require = createRequire(import.meta.url);
|
|
14
13
|
const pkg = require('../../package.json');
|
|
15
14
|
|
|
16
15
|
export async function initCommand(options) {
|
|
17
|
-
// ─── Banner ──────────────────────────────────────────────────────
|
|
18
16
|
printBanner(pkg.version);
|
|
19
17
|
|
|
20
18
|
let role = 'fullstack';
|
|
21
19
|
let preset = options.preset;
|
|
22
20
|
|
|
23
|
-
// ─── Interactive
|
|
21
|
+
// ─── Interactive: ask role only ─────────────────────────────
|
|
24
22
|
if (options.interaction !== false) {
|
|
25
23
|
const answers = await inquirer.prompt([
|
|
26
24
|
{
|
|
27
25
|
type: 'list',
|
|
28
26
|
name: 'role',
|
|
29
|
-
message:
|
|
27
|
+
message: 'Role',
|
|
30
28
|
choices: Object.entries(ROLES).map(([key, val]) => ({
|
|
31
|
-
name: `${colors.white(val.label)}
|
|
29
|
+
name: `${colors.white(val.label)} ${colors.dim(val.description)}`,
|
|
32
30
|
value: key,
|
|
33
31
|
short: val.label,
|
|
34
32
|
})),
|
|
35
33
|
default: 'fullstack',
|
|
36
34
|
prefix: colors.brand('?'),
|
|
37
35
|
},
|
|
38
|
-
{
|
|
39
|
-
type: 'list',
|
|
40
|
-
name: 'preset',
|
|
41
|
-
message: `${icons.package} Installation scope?`,
|
|
42
|
-
choices: [
|
|
43
|
-
{
|
|
44
|
-
name: `${colors.white('Full')} ${colors.dim('—')} ${colors.muted('All components (rules, plugin, hooks, safety guards, memory)')}`,
|
|
45
|
-
value: 'full',
|
|
46
|
-
short: 'Full',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: `${colors.white('Safe')} ${colors.dim('—')} ${colors.muted('Core + rules + plugin + safety guards + memory')}`,
|
|
50
|
-
value: 'safe',
|
|
51
|
-
short: 'Safe',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: `${colors.white('Minimal')} ${colors.dim('—')} ${colors.muted('Core + rules + plugin only')}`,
|
|
55
|
-
value: 'minimal',
|
|
56
|
-
short: 'Minimal',
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
default: 'full',
|
|
60
|
-
prefix: colors.brand('?'),
|
|
61
|
-
},
|
|
62
36
|
]);
|
|
63
37
|
role = answers.role;
|
|
64
|
-
preset = answers.preset;
|
|
65
38
|
}
|
|
66
39
|
|
|
67
40
|
const components = PRESETS[preset];
|
|
68
41
|
if (!components) {
|
|
69
|
-
console.error(colors.error(
|
|
42
|
+
console.error(` ${colors.error(icons.cross)} Unknown preset: ${preset}. Use: ${Object.keys(PRESETS).join(', ')}`);
|
|
70
43
|
process.exit(1);
|
|
71
44
|
}
|
|
72
45
|
|
|
73
|
-
// ───
|
|
74
|
-
console.log();
|
|
75
|
-
console.log(` ${colors.dim('│')} ${colors.dim('Role')} ${colors.white(ROLES[role].label)}`);
|
|
76
|
-
console.log(` ${colors.dim('│')} ${colors.dim('Preset')} ${colors.white(preset)}`);
|
|
77
|
-
console.log(` ${colors.dim('│')} ${colors.dim('Scope')} ${components.map(c => componentLabels[c] || c).join(colors.dim(', '))}`);
|
|
78
|
-
if (options.force) {
|
|
79
|
-
console.log(` ${colors.dim('│')} ${colors.warning(`${icons.warn} Force mode — existing files will be overwritten`)}`);
|
|
80
|
-
}
|
|
81
|
-
if (options.dryRun) {
|
|
82
|
-
console.log(` ${colors.dim('│')} ${colors.accent(`${icons.info} Dry-run mode — no changes will be made`)}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ─── Conflict detection & category confirmation ──────────────────
|
|
46
|
+
// ─── Conflict detection ─────────────────────────────────────
|
|
86
47
|
const installer = new Installer({
|
|
87
48
|
force: options.force,
|
|
88
49
|
dryRun: options.dryRun,
|
|
@@ -98,118 +59,88 @@ export async function initCommand(options) {
|
|
|
98
59
|
const conflictKeys = Object.keys(conflicts);
|
|
99
60
|
|
|
100
61
|
if (conflictKeys.length > 0) {
|
|
101
|
-
|
|
102
|
-
sectionHeader(icons.warn, 'Existing files detected');
|
|
103
|
-
console.log(` ${colors.dim('│')} ${colors.muted('Some files already exist. Choose how to handle each category:')}`);
|
|
104
|
-
console.log(` ${colors.dim('│')} ${colors.muted(`CLAUDE.md ${icons.arrowR} always smart-merge (append new refs only)`)}`);
|
|
105
|
-
console.log(` ${colors.dim('│')} ${colors.muted(`settings.json ${icons.arrowR} always deep-merge (preserve your settings)`)}`);
|
|
106
|
-
|
|
107
|
-
for (const componentName of conflictKeys) {
|
|
108
|
-
const { files } = conflicts[componentName];
|
|
109
|
-
const icon = componentIcons[componentName] || icons.file;
|
|
110
|
-
const label = componentLabels[componentName] || componentName;
|
|
111
|
-
|
|
112
|
-
conflictHeader(label, icon, files.length);
|
|
113
|
-
for (const f of files) {
|
|
114
|
-
conflictFile(f.replace(/\\/g, '/'));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
62
|
+
const totalFiles = conflictKeys.reduce((sum, k) => sum + conflicts[k].files.length, 0);
|
|
117
63
|
|
|
64
|
+
console.log(` ${colors.warning(icons.warn)} ${totalFiles} existing file(s) found.`);
|
|
118
65
|
console.log();
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
resolutions = conflictAnswers;
|
|
66
|
+
|
|
67
|
+
const { action } = await inquirer.prompt([
|
|
68
|
+
{
|
|
69
|
+
type: 'list',
|
|
70
|
+
name: 'action',
|
|
71
|
+
message: 'How to handle?',
|
|
72
|
+
choices: [
|
|
73
|
+
{
|
|
74
|
+
name: `${colors.white('Keep existing')} ${colors.dim('merge compatible, skip rest')}`,
|
|
75
|
+
value: 'skip',
|
|
76
|
+
short: 'Keep',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: `${colors.warning('Overwrite all')} ${colors.dim('replace with latest')}`,
|
|
80
|
+
value: 'overwrite',
|
|
81
|
+
short: 'Overwrite',
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
default: 'skip',
|
|
85
|
+
prefix: colors.brand('?'),
|
|
86
|
+
},
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
for (const key of conflictKeys) {
|
|
90
|
+
resolutions[key] = action;
|
|
91
|
+
}
|
|
147
92
|
}
|
|
148
93
|
}
|
|
149
94
|
|
|
150
|
-
// Apply resolutions to installer
|
|
151
95
|
installer.resolutions = resolutions;
|
|
152
96
|
|
|
153
|
-
// ───
|
|
97
|
+
// ─── Install ────────────────────────────────────────────────
|
|
98
|
+
if (options.dryRun) {
|
|
99
|
+
console.log(` ${colors.dim('dry-run — no changes will be made')}`);
|
|
100
|
+
}
|
|
154
101
|
console.log();
|
|
155
|
-
sectionHeader(icons.rocket, 'Installing components');
|
|
156
102
|
|
|
157
103
|
for (const componentName of components) {
|
|
158
104
|
const component = COMPONENTS[componentName];
|
|
159
105
|
if (!component) continue;
|
|
160
106
|
|
|
161
|
-
const icon = componentIcons[componentName] || icons.file;
|
|
162
107
|
const label = componentLabels[componentName] || componentName;
|
|
163
|
-
|
|
164
108
|
const beforeInstalled = installer.results.installed.length;
|
|
165
109
|
const beforeMerged = installer.results.merged.length;
|
|
166
110
|
const beforeSkipped = installer.results.skipped.length;
|
|
167
111
|
|
|
168
112
|
try {
|
|
169
113
|
await installer.installComponent(componentName, component);
|
|
114
|
+
|
|
170
115
|
const newInstalled = installer.results.installed.length - beforeInstalled;
|
|
171
116
|
const newMerged = installer.results.merged.length - beforeMerged;
|
|
172
117
|
const newSkipped = installer.results.skipped.length - beforeSkipped;
|
|
173
118
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
119
|
+
if (newMerged > 0 && newInstalled === 0 && newSkipped === 0) {
|
|
120
|
+
stepMerge(label, 'merged');
|
|
121
|
+
} else if (newSkipped > 0 && newInstalled === 0 && newMerged === 0) {
|
|
122
|
+
stepSkip(label, 'unchanged');
|
|
123
|
+
} else {
|
|
124
|
+
const count = newInstalled + newMerged;
|
|
125
|
+
const detail = count > 0 ? `${count} file${count > 1 ? 's' : ''}` : '';
|
|
126
|
+
stepDone(label, detail);
|
|
127
|
+
}
|
|
181
128
|
} catch (err) {
|
|
182
|
-
stepFail(
|
|
129
|
+
stepFail(label, err.message);
|
|
183
130
|
installer.results.errors.push({ component: componentName, error: err.message });
|
|
184
131
|
}
|
|
185
132
|
}
|
|
186
133
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// ─── Detailed file list ──────────────────────────────────────────
|
|
190
|
-
if (installed.length > 0 || merged.length > 0 || skipped.length > 0) {
|
|
191
|
-
separator();
|
|
192
|
-
sectionHeader(icons.file, 'File details');
|
|
193
|
-
for (const f of installed) fileEntry('install', f.replace(/\\/g, '/'));
|
|
194
|
-
for (const m of merged) {
|
|
195
|
-
const detail = m.added ? ` (${m.added.length} refs)` : '';
|
|
196
|
-
fileEntry('merge', `${m.file.replace(/\\/g, '/')}${detail}`);
|
|
197
|
-
}
|
|
198
|
-
for (const f of skipped) fileEntry('skip', f.replace(/\\/g, '/'));
|
|
199
|
-
for (const e of errors) fileEntry('error', `${(e.file || e.component).replace(/\\/g, '/')}: ${e.error}`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// ─── Summary ─────────────────────────────────────────────────────
|
|
203
|
-
summaryBox({
|
|
204
|
-
installed: installed.length,
|
|
205
|
-
merged: merged.length,
|
|
206
|
-
skipped: skipped.length,
|
|
207
|
-
errors: errors.length,
|
|
208
|
-
});
|
|
134
|
+
// ─── Summary ────────────────────────────────────────────────
|
|
135
|
+
const { installed, merged, skipped, errors } = installer.results;
|
|
209
136
|
|
|
210
137
|
if (errors.length === 0) {
|
|
211
|
-
doneMessage(
|
|
138
|
+
doneMessage({
|
|
139
|
+
installed: installed.length,
|
|
140
|
+
merged: merged.length,
|
|
141
|
+
skipped: skipped.length,
|
|
142
|
+
});
|
|
212
143
|
} else {
|
|
213
|
-
doneWithErrors();
|
|
144
|
+
doneWithErrors({ errors: errors.length });
|
|
214
145
|
}
|
|
215
146
|
}
|
package/src/core/ui.js
CHANGED
|
@@ -1,177 +1,77 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
|
|
3
|
-
// ─── Icons
|
|
3
|
+
// ─── Icons (minimal set) ────────────────────────────────────
|
|
4
4
|
export const icons = {
|
|
5
|
-
ace:
|
|
6
|
-
check:
|
|
7
|
-
cross:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
dot:
|
|
11
|
-
|
|
12
|
-
warn: '⚠',
|
|
13
|
-
info: 'ℹ',
|
|
14
|
-
skip: '◇',
|
|
15
|
-
merge: '⇄',
|
|
16
|
-
folder: '▸',
|
|
17
|
-
shield: '🛡',
|
|
18
|
-
gear: '⚙',
|
|
19
|
-
rocket: '🚀',
|
|
20
|
-
sparkles: '✨',
|
|
21
|
-
package: '📦',
|
|
22
|
-
file: '📄',
|
|
23
|
-
brain: '🧠',
|
|
24
|
-
hook: '🪝',
|
|
25
|
-
guard: '🔒',
|
|
26
|
-
memory: '💾',
|
|
27
|
-
plug: '🔌',
|
|
5
|
+
ace: '◆',
|
|
6
|
+
check: '✔',
|
|
7
|
+
cross: '✖',
|
|
8
|
+
warn: '⚠',
|
|
9
|
+
skip: '◇',
|
|
10
|
+
dot: '·',
|
|
11
|
+
merge: '~',
|
|
28
12
|
};
|
|
29
13
|
|
|
30
|
-
// ─── Colors
|
|
14
|
+
// ─── Colors ─────────────────────────────────────────────────
|
|
31
15
|
export const colors = {
|
|
32
|
-
brand:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
blue: chalk.hex('#3B82F6'), // blue
|
|
16
|
+
brand: chalk.hex('#7C3AED'),
|
|
17
|
+
success: chalk.hex('#10B981'),
|
|
18
|
+
warning: chalk.hex('#F59E0B'),
|
|
19
|
+
error: chalk.hex('#EF4444'),
|
|
20
|
+
dim: chalk.hex('#6B7280'),
|
|
21
|
+
muted: chalk.hex('#9CA3AF'),
|
|
22
|
+
white: chalk.hex('#F9FAFB'),
|
|
23
|
+
blue: chalk.hex('#3B82F6'),
|
|
41
24
|
};
|
|
42
25
|
|
|
43
|
-
// ───
|
|
26
|
+
// ─── Banner (single line) ───────────────────────────────────
|
|
44
27
|
export function printBanner(version) {
|
|
45
|
-
const purple = colors.brand;
|
|
46
|
-
const dim = colors.dim;
|
|
47
|
-
|
|
48
|
-
console.log();
|
|
49
|
-
console.log(purple(' ╔═══╗ ╔═══╗ ╔═══╗'));
|
|
50
|
-
console.log(purple(' ╠═══╣ ║ ╠═══╝'));
|
|
51
|
-
console.log(purple(' ║ ║ ╚═══╝ ╚═══╗'));
|
|
52
28
|
console.log();
|
|
53
|
-
console.log(`
|
|
29
|
+
console.log(` ${colors.brand.bold('◆ ace')} ${colors.dim(`v${version}`)}`);
|
|
54
30
|
console.log();
|
|
55
31
|
}
|
|
56
32
|
|
|
57
|
-
// ───
|
|
58
|
-
export function
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ─── Step indicator ──────────────────────────────────────────────────
|
|
63
|
-
export function stepStart(label) {
|
|
64
|
-
process.stdout.write(` ${colors.dim('│')}\n`);
|
|
65
|
-
process.stdout.write(` ${colors.brand(icons.dot)} ${label}\n`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function stepDone(label) {
|
|
69
|
-
process.stdout.write(` ${colors.success(icons.check)} ${label}\n`);
|
|
33
|
+
// ─── Step indicators ────────────────────────────────────────
|
|
34
|
+
export function stepDone(label, detail) {
|
|
35
|
+
const d = detail ? colors.dim(` ${detail}`) : '';
|
|
36
|
+
console.log(` ${colors.success(icons.check)} ${label}${d}`);
|
|
70
37
|
}
|
|
71
38
|
|
|
72
|
-
export function
|
|
73
|
-
|
|
39
|
+
export function stepMerge(label, detail) {
|
|
40
|
+
const d = detail ? colors.dim(` ${detail}`) : '';
|
|
41
|
+
console.log(` ${colors.blue(icons.merge)} ${label}${d}`);
|
|
74
42
|
}
|
|
75
43
|
|
|
76
|
-
export function
|
|
77
|
-
|
|
44
|
+
export function stepSkip(label, detail) {
|
|
45
|
+
const d = detail ? colors.dim(` ${detail}`) : '';
|
|
46
|
+
console.log(` ${colors.muted(icons.skip)} ${colors.muted(label)}${d}`);
|
|
78
47
|
}
|
|
79
48
|
|
|
80
|
-
export function stepFail(label) {
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ─── File list (compact) ─────────────────────────────────────────────
|
|
85
|
-
export function fileEntry(action, filePath) {
|
|
86
|
-
const prefix = {
|
|
87
|
-
install: ` ${colors.success('+')}`,
|
|
88
|
-
merge: ` ${colors.blue('~')}`,
|
|
89
|
-
skip: ` ${colors.muted('-')}`,
|
|
90
|
-
overwrite:` ${colors.warning('!')}`,
|
|
91
|
-
error: ` ${colors.error('✖')}`,
|
|
92
|
-
};
|
|
93
|
-
const color = {
|
|
94
|
-
install: colors.success,
|
|
95
|
-
merge: colors.blue,
|
|
96
|
-
skip: colors.muted,
|
|
97
|
-
overwrite:colors.warning,
|
|
98
|
-
error: colors.error,
|
|
99
|
-
};
|
|
100
|
-
console.log(`${prefix[action] || ' '} ${(color[action] || colors.dim)(filePath)}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ─── Summary Box ─────────────────────────────────────────────────────
|
|
104
|
-
export function summaryBox(stats) {
|
|
105
|
-
const { installed, merged, skipped, errors } = stats;
|
|
106
|
-
|
|
107
|
-
console.log();
|
|
108
|
-
console.log(` ${colors.dim('╭─────────────────────────────────────╮')}`);
|
|
109
|
-
console.log(` ${colors.dim('│')} ${colors.white.bold('Installation Summary')} ${colors.dim('│')}`);
|
|
110
|
-
console.log(` ${colors.dim('├─────────────────────────────────────┤')}`);
|
|
111
|
-
|
|
112
|
-
if (installed > 0) {
|
|
113
|
-
console.log(` ${colors.dim('│')} ${colors.success(icons.check)} ${colors.success(`${installed} installed`)}${pad(installed, 'installed')}${colors.dim('│')}`);
|
|
114
|
-
}
|
|
115
|
-
if (merged > 0) {
|
|
116
|
-
console.log(` ${colors.dim('│')} ${colors.blue(icons.merge)} ${colors.blue(`${merged} merged`)}${pad(merged, 'merged')}${colors.dim('│')}`);
|
|
117
|
-
}
|
|
118
|
-
if (skipped > 0) {
|
|
119
|
-
console.log(` ${colors.dim('│')} ${colors.muted(icons.skip)} ${colors.muted(`${skipped} skipped`)}${pad(skipped, 'skipped')}${colors.dim('│')}`);
|
|
120
|
-
}
|
|
121
|
-
if (errors > 0) {
|
|
122
|
-
console.log(` ${colors.dim('│')} ${colors.error(icons.cross)} ${colors.error(`${errors} errors`)}${pad(errors, 'errors')}${colors.dim('│')}`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
console.log(` ${colors.dim('╰─────────────────────────────────────╯')}`);
|
|
49
|
+
export function stepFail(label, detail) {
|
|
50
|
+
const d = detail ? colors.dim(` ${detail}`) : '';
|
|
51
|
+
console.log(` ${colors.error(icons.cross)} ${label}${d}`);
|
|
126
52
|
}
|
|
127
53
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
54
|
+
// ─── Done messages ──────────────────────────────────────────
|
|
55
|
+
export function doneMessage(stats) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
if (stats.installed > 0) parts.push(`${stats.installed} installed`);
|
|
58
|
+
if (stats.merged > 0) parts.push(`${stats.merged} merged`);
|
|
59
|
+
if (stats.skipped > 0) parts.push(`${stats.skipped} skipped`);
|
|
134
60
|
|
|
135
|
-
// ─── Final message ───────────────────────────────────────────────────
|
|
136
|
-
export function doneMessage() {
|
|
137
61
|
console.log();
|
|
138
|
-
console.log(` ${icons.
|
|
139
|
-
console.log(` ${colors.dim(`Run ${chalk.white('ace doctor')} to verify
|
|
62
|
+
console.log(` ${colors.success(icons.check)} ${colors.success.bold('Done.')} ${colors.dim(parts.join(', '))}`);
|
|
63
|
+
console.log(` ${colors.dim(` Run ${chalk.white('ace doctor')} to verify.`)}`);
|
|
140
64
|
console.log();
|
|
141
65
|
}
|
|
142
66
|
|
|
143
|
-
export function doneWithErrors() {
|
|
67
|
+
export function doneWithErrors(stats) {
|
|
144
68
|
console.log();
|
|
145
|
-
console.log(` ${icons.warn} ${colors.warning.bold('
|
|
146
|
-
console.log(` ${colors.dim(`Run ${chalk.white('ace doctor')} to diagnose.`)}`);
|
|
147
|
-
console.log();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// ─── Separator ───────────────────────────────────────────────────────
|
|
151
|
-
export function separator() {
|
|
152
|
-
console.log(` ${colors.dim('│')}`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ─── Conflict prompt helpers ─────────────────────────────────────────
|
|
156
|
-
export function conflictHeader(componentName, icon, fileCount) {
|
|
69
|
+
console.log(` ${colors.warning(icons.warn)} ${colors.warning.bold('Done with errors.')} ${colors.dim(`${stats.errors} failed`)}`);
|
|
70
|
+
console.log(` ${colors.dim(` Run ${chalk.white('ace doctor')} to diagnose.`)}`);
|
|
157
71
|
console.log();
|
|
158
|
-
console.log(` ${colors.warning(icons.warn)} ${icon} ${colors.white.bold(componentName)} — ${colors.warning(`${fileCount} file(s) already exist`)}`);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function conflictFile(filePath) {
|
|
162
|
-
console.log(` ${colors.dim(icons.arrowR)} ${colors.muted(filePath)}`);
|
|
163
72
|
}
|
|
164
73
|
|
|
165
|
-
// ─── Component
|
|
166
|
-
export const componentIcons = {
|
|
167
|
-
core: icons.gear,
|
|
168
|
-
rules: icons.brain,
|
|
169
|
-
plugin: icons.plug,
|
|
170
|
-
hooks: icons.hook,
|
|
171
|
-
hookify: icons.guard,
|
|
172
|
-
memory: icons.memory,
|
|
173
|
-
};
|
|
174
|
-
|
|
74
|
+
// ─── Component labels ───────────────────────────────────────
|
|
175
75
|
export const componentLabels = {
|
|
176
76
|
core: 'Core Config',
|
|
177
77
|
rules: 'Rules',
|