@morya-ui/setup 0.3.3 → 0.3.4

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.
Files changed (31) hide show
  1. package/README.md +103 -103
  2. package/bin/morya-ui-setup.js +14 -14
  3. package/catalog/skills.json +46 -46
  4. package/package.json +5 -3
  5. package/src/cli.mjs +335 -335
  6. package/src/copy-template.mjs +78 -78
  7. package/src/fs-utils.mjs +24 -24
  8. package/src/install.mjs +63 -63
  9. package/src/mcp.mjs +50 -50
  10. package/src/package-json.mjs +30 -30
  11. package/src/skills.mjs +223 -223
  12. package/src/styles.mjs +119 -119
  13. package/template/.agents/skills/morya-ui-pages/SKILL.md +184 -164
  14. package/template/.agents/skills/morya-ui-pages/evals/evals.json +89 -89
  15. package/template/.agents/skills/morya-ui-pages/references/component-index.md +99 -99
  16. package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +32 -0
  17. package/template/.agents/skills/morya-ui-pages/references/design-system.md +101 -100
  18. package/template/.agents/skills/morya-ui-pages/references/feedback.md +68 -68
  19. package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +107 -34
  20. package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +141 -119
  21. package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +64 -61
  22. package/template/.agents/skills/morya-ui-pages/references/style-presets.md +73 -0
  23. package/template/.agents/skills/morya-ui-pages/references/surfaces.md +91 -89
  24. package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +221 -196
  25. package/template/.cursor/rules/coding-style.mdc +41 -41
  26. package/template/.cursor/rules/component-usage.mdc +41 -41
  27. package/template/.cursor/rules/design-system.mdc +17 -17
  28. package/template/.cursor/rules/page-layout.mdc +97 -78
  29. package/template/DESIGN.md +59 -59
  30. package/template/scripts/check-raw-colors.mjs +74 -74
  31. package/LICENSE +0 -21
package/src/cli.mjs CHANGED
@@ -1,335 +1,335 @@
1
- import { existsSync } from 'node:fs'
2
- import { dirname, join, resolve } from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
- import { copyTemplate } from './copy-template.mjs'
5
- import { readJson } from './fs-utils.mjs'
6
- import { installMoryaUi } from './install.mjs'
7
- import { mergeMcpConfig } from './mcp.mjs'
8
- import { ensureCheckColorsScript } from './package-json.mjs'
9
- import {
10
- buildAiInclude,
11
- installSkillsCli,
12
- loadSkillsCatalog,
13
- parseSkillsFlag,
14
- resolveSkillSelection,
15
- } from './skills.mjs'
16
- import { ensureStylesImport } from './styles.mjs'
17
-
18
- const __dirname = dirname(fileURLToPath(import.meta.url))
19
- const PKG_ROOT = resolve(__dirname, '..')
20
- const TEMPLATE_ROOT = join(PKG_ROOT, 'template')
21
-
22
- const MODES = new Set(['app', 'ai', 'full'])
23
-
24
- /** Mode → default skips (user --skip-* can only add more skips). */
25
- const MODE_DEFAULTS = {
26
- full: {},
27
- app: { skipTemplate: true, skipMcp: true, skipScripts: true },
28
- ai: { skipInstall: true, skipStyles: true },
29
- }
30
-
31
- const SKIP_FLAGS = {
32
- '--skip-install': 'skipInstall',
33
- '--skip-template': 'skipTemplate',
34
- '--skip-mcp': 'skipMcp',
35
- '--skip-styles': 'skipStyles',
36
- '--skip-scripts': 'skipScripts',
37
- }
38
-
39
- export function printHelp() {
40
- const { skills } = loadSkillsCatalog()
41
- const skillList = skills.map((s) => {
42
- const tag = s.required ? 'required' : s.default ? 'default' : 'optional'
43
- const via = s.install === 'skills-cli' ? ' [skills-cli latest]' : ''
44
- return ` ${s.id.padEnd(24)} (${tag})${via} ${s.description}`
45
- }).join('\n')
46
-
47
- console.log(`Usage: morya-ui-setup [command] [options]
48
-
49
- Commands:
50
- (default) / full Install morya-ui, AI template, MCP, styles, check:colors
51
- app Install morya-ui and inject styles.css
52
- ai Copy Agent skills / rules / DESIGN,
53
- merge Cursor MCP, add check:colors
54
-
55
- Default command:
56
- - install morya-ui
57
- - copy DESIGN.md, selected Agent skills, Cursor rules
58
- - merge .cursor/mcp.json for @morya-ui/mcp
59
- - inject import 'morya-ui/styles.css' into the app entry when found
60
- - add check:colors script when missing
61
-
62
- Options:
63
- --cwd <dir> Target project root (default: process.cwd())
64
- --pm <name> Package manager: pnpm | yarn | npm (auto-detect by lockfile)
65
- --skills <list> Comma-separated skill ids, or "all" (skips interactive prompt)
66
- --yes Use default skills without prompting (CI / non-interactive)
67
- --force Overwrite existing template files and MCP server entry
68
- --dry-run Print actions without writing or installing
69
- --skip-install Skip dependency install
70
- --skip-template Skip copying AI template files
71
- --skip-mcp Skip writing .cursor/mcp.json
72
- --skip-styles Skip injecting styles.css
73
- --skip-scripts Skip adding check:colors to package.json
74
- -h, --help Show this help
75
-
76
- Skills:
77
- ${skillList}
78
- `)
79
- }
80
-
81
- /**
82
- * @param {string[]} argv
83
- */
84
- export function parseArgs(argv) {
85
- const options = {
86
- mode: 'full',
87
- cwd: process.cwd(),
88
- pm: undefined,
89
- skills: undefined,
90
- yes: false,
91
- force: false,
92
- dryRun: false,
93
- skipInstall: false,
94
- skipTemplate: false,
95
- skipMcp: false,
96
- skipStyles: false,
97
- skipScripts: false,
98
- help: false,
99
- }
100
-
101
- for (let i = 0; i < argv.length; i++) {
102
- const arg = argv[i]
103
- if (arg === '-h' || arg === '--help') {
104
- options.help = true
105
- continue
106
- }
107
- if (MODES.has(arg)) {
108
- options.mode = arg
109
- continue
110
- }
111
- if (arg === '--force') {
112
- options.force = true
113
- continue
114
- }
115
- if (arg === '--dry-run') {
116
- options.dryRun = true
117
- continue
118
- }
119
- if (arg === '--yes' || arg === '-y') {
120
- options.yes = true
121
- continue
122
- }
123
- if (SKIP_FLAGS[arg]) {
124
- options[SKIP_FLAGS[arg]] = true
125
- continue
126
- }
127
- if (arg === '--cwd') {
128
- const value = argv[++i]
129
- if (!value) throw new Error('--cwd requires a path')
130
- options.cwd = resolve(value)
131
- continue
132
- }
133
- if (arg.startsWith('--cwd=')) {
134
- options.cwd = resolve(arg.slice('--cwd='.length))
135
- continue
136
- }
137
- if (arg === '--pm') {
138
- const value = argv[++i]
139
- if (!value) throw new Error('--pm requires pnpm, yarn, or npm')
140
- options.pm = value
141
- continue
142
- }
143
- if (arg.startsWith('--pm=')) {
144
- options.pm = arg.slice('--pm='.length)
145
- continue
146
- }
147
- if (arg === '--skills') {
148
- const value = argv[++i]
149
- if (!value) throw new Error('--skills requires a comma-separated list or "all"')
150
- options.skills = value
151
- continue
152
- }
153
- if (arg.startsWith('--skills=')) {
154
- options.skills = arg.slice('--skills='.length)
155
- continue
156
- }
157
- throw new Error(`Unknown argument: ${arg}`)
158
- }
159
-
160
- const defaults = MODE_DEFAULTS[options.mode] || {}
161
- for (const [key, value] of Object.entries(defaults)) {
162
- if (value) options[key] = true
163
- }
164
-
165
- return options
166
- }
167
-
168
- function rel(cwd, path) {
169
- if (!path) return ''
170
- return path.startsWith(cwd) ? path.slice(cwd.length).replace(/^[\\/]/, '') || path : path
171
- }
172
-
173
- /**
174
- * @param {string} cwd
175
- */
176
- function hasMoryaUiDependency(cwd) {
177
- const path = join(cwd, 'package.json')
178
- if (!existsSync(path)) return false
179
- try {
180
- const pkg = readJson(path)
181
- return Boolean(
182
- pkg.dependencies?.['morya-ui']
183
- || pkg.devDependencies?.['morya-ui']
184
- || pkg.peerDependencies?.['morya-ui'],
185
- )
186
- } catch {
187
- return false
188
- }
189
- }
190
-
191
- /**
192
- * @param {ReturnType<typeof parseArgs>} options
193
- */
194
- export async function runSetup(options) {
195
- const {
196
- mode,
197
- cwd,
198
- force,
199
- dryRun,
200
- skipInstall,
201
- skipTemplate,
202
- skipMcp,
203
- skipStyles,
204
- skipScripts,
205
- pm,
206
- skills: skillsFlag,
207
- yes,
208
- } = options
209
-
210
- console.log(`@morya-ui/setup [${mode}] → ${cwd}${dryRun ? ' (dry-run)' : ''}`)
211
- console.log('')
212
-
213
- if (mode === 'ai' && !hasMoryaUiDependency(cwd)) {
214
- console.log(
215
- 'Warning: morya-ui is not listed in package.json. Run `npx @morya-ui/setup app` first (or pnpm add morya-ui).',
216
- )
217
- console.log('')
218
- }
219
-
220
- const catalog = loadSkillsCatalog()
221
- let selectedSkills = []
222
- let aiInclude
223
-
224
- const needsTemplate = !skipTemplate && (mode === 'ai' || mode === 'full')
225
- if (needsTemplate) {
226
- if (skillsFlag != null) {
227
- selectedSkills = parseSkillsFlag(skillsFlag, catalog.skills)
228
- } else {
229
- selectedSkills = await resolveSkillSelection(catalog.skills, {
230
- skipPrompt: yes || dryRun,
231
- })
232
- }
233
- aiInclude = buildAiInclude(selectedSkills, catalog.skills)
234
- console.log(`Skills: ${selectedSkills.join(', ')}`)
235
- console.log('')
236
- }
237
-
238
- const install = installMoryaUi(cwd, { pm, dryRun, skipInstall })
239
-
240
- const template = skipTemplate
241
- ? { copied: [], skipped: [], forced: [], skippedStep: true }
242
- : copyTemplate(TEMPLATE_ROOT, cwd, {
243
- force,
244
- dryRun,
245
- include: aiInclude,
246
- })
247
-
248
- const remoteSkills = skipTemplate || !selectedSkills.length
249
- ? { installed: [], commands: [], skipped: true }
250
- : installSkillsCli(cwd, selectedSkills, catalog.skills, { dryRun })
251
-
252
- const mcp = skipMcp
253
- ? { path: join(cwd, '.cursor', 'mcp.json'), action: 'skipped-flag' }
254
- : mergeMcpConfig(cwd, { force, dryRun })
255
-
256
- const styles = skipStyles
257
- ? { action: 'skipped', reason: 'skip-styles' }
258
- : ensureStylesImport(cwd, { dryRun })
259
-
260
- const scripts = skipScripts
261
- ? { action: 'skipped-flag' }
262
- : ensureCheckColorsScript(cwd, { force, dryRun })
263
-
264
- console.log('--- Summary ---')
265
- if (install.skipped) {
266
- console.log(`Install: skipped (${install.reason}) — would run: ${install.command}`)
267
- } else {
268
- console.log(`Install: ok (${install.pm}) — ${install.command}`)
269
- }
270
-
271
- if (template.skippedStep) {
272
- console.log('Template: skipped (--skip-template or app mode)')
273
- } else {
274
- console.log(
275
- `Template: ${template.copied.length} copied, ${template.forced.length} overwritten, ${template.skipped.length} skipped`,
276
- )
277
- if (selectedSkills.length) console.log(` skills: ${selectedSkills.join(', ')}`)
278
- if (template.skipped.length && template.skipped.length <= 8) {
279
- for (const file of template.skipped) console.log(` skip ${file}`)
280
- } else if (template.skipped.length > 8) {
281
- for (const file of template.skipped.slice(0, 5)) console.log(` skip ${file}`)
282
- console.log(` … and ${template.skipped.length - 5} more (use --force to overwrite)`)
283
- }
284
- }
285
-
286
- if (remoteSkills.skipped) {
287
- // no companions selected or template step skipped
288
- } else if (remoteSkills.dryRun) {
289
- console.log(`Skills CLI: dry-run — would install ${remoteSkills.installed.join(', ')}`)
290
- for (const command of remoteSkills.commands) console.log(` $ ${command}`)
291
- } else {
292
- console.log(`Skills CLI: installed ${remoteSkills.installed.join(', ')} (latest)`)
293
- }
294
-
295
- if (mcp.action === 'skipped-flag') {
296
- console.log('MCP: skipped (--skip-mcp or app mode)')
297
- } else {
298
- console.log(`MCP: ${mcp.action} (${rel(cwd, mcp.path) || '.cursor/mcp.json'})`)
299
- }
300
-
301
- if (styles.reason === 'skip-styles') {
302
- console.log('Styles: skipped (--skip-styles or ai mode)')
303
- } else if (styles.action === 'injected') {
304
- console.log(`Styles: injected into ${rel(cwd, styles.path)}`)
305
- } else if (styles.action === 'skipped') {
306
- console.log(`Styles: skipped (${styles.reason}) in ${rel(cwd, styles.path)}`)
307
- } else {
308
- console.log('Styles: no entry file found — add manually:')
309
- console.log(" import 'morya-ui/styles.css'")
310
- }
311
-
312
- if (scripts.action === 'skipped-flag') {
313
- console.log('Scripts: skipped (--skip-scripts or app mode)')
314
- } else {
315
- console.log(`Scripts: check:colors ${scripts.action}`)
316
- }
317
-
318
- console.log('')
319
- console.log('Next:')
320
- if (mode === 'app') {
321
- console.log(' 1. Ensure the styles.css import is in your app entry.')
322
- console.log(' 2. Optional AI pack: npx @morya-ui/setup ai')
323
- } else if (mode === 'ai') {
324
- console.log(' 1. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
325
- console.log(' 2. Have the agent read DESIGN.md before generating pages.')
326
- console.log(' 3. Optional: pnpm check:colors')
327
- } else {
328
- console.log(' 1. Ensure the styles.css import is in your app entry.')
329
- console.log(' 2. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
330
- console.log(' 3. Have the agent read DESIGN.md before generating pages.')
331
- console.log(' 4. Optional: pnpm check:colors')
332
- }
333
-
334
- return { mode, install, template, remoteSkills, mcp, styles, scripts, skills: selectedSkills }
335
- }
1
+ import { existsSync } from 'node:fs'
2
+ import { dirname, join, resolve } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { copyTemplate } from './copy-template.mjs'
5
+ import { readJson } from './fs-utils.mjs'
6
+ import { installMoryaUi } from './install.mjs'
7
+ import { mergeMcpConfig } from './mcp.mjs'
8
+ import { ensureCheckColorsScript } from './package-json.mjs'
9
+ import {
10
+ buildAiInclude,
11
+ installSkillsCli,
12
+ loadSkillsCatalog,
13
+ parseSkillsFlag,
14
+ resolveSkillSelection,
15
+ } from './skills.mjs'
16
+ import { ensureStylesImport } from './styles.mjs'
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url))
19
+ const PKG_ROOT = resolve(__dirname, '..')
20
+ const TEMPLATE_ROOT = join(PKG_ROOT, 'template')
21
+
22
+ const MODES = new Set(['app', 'ai', 'full'])
23
+
24
+ /** Mode → default skips (user --skip-* can only add more skips). */
25
+ const MODE_DEFAULTS = {
26
+ full: {},
27
+ app: { skipTemplate: true, skipMcp: true, skipScripts: true },
28
+ ai: { skipInstall: true, skipStyles: true },
29
+ }
30
+
31
+ const SKIP_FLAGS = {
32
+ '--skip-install': 'skipInstall',
33
+ '--skip-template': 'skipTemplate',
34
+ '--skip-mcp': 'skipMcp',
35
+ '--skip-styles': 'skipStyles',
36
+ '--skip-scripts': 'skipScripts',
37
+ }
38
+
39
+ export function printHelp() {
40
+ const { skills } = loadSkillsCatalog()
41
+ const skillList = skills.map((s) => {
42
+ const tag = s.required ? 'required' : s.default ? 'default' : 'optional'
43
+ const via = s.install === 'skills-cli' ? ' [skills-cli latest]' : ''
44
+ return ` ${s.id.padEnd(24)} (${tag})${via} ${s.description}`
45
+ }).join('\n')
46
+
47
+ console.log(`Usage: morya-ui-setup [command] [options]
48
+
49
+ Commands:
50
+ (default) / full Install morya-ui, AI template, MCP, styles, check:colors
51
+ app Install morya-ui and inject styles.css
52
+ ai Copy Agent skills / rules / DESIGN,
53
+ merge Cursor MCP, add check:colors
54
+
55
+ Default command:
56
+ - install morya-ui
57
+ - copy DESIGN.md, selected Agent skills, Cursor rules
58
+ - merge .cursor/mcp.json for @morya-ui/mcp
59
+ - inject import 'morya-ui/styles.css' into the app entry when found
60
+ - add check:colors script when missing
61
+
62
+ Options:
63
+ --cwd <dir> Target project root (default: process.cwd())
64
+ --pm <name> Package manager: pnpm | yarn | npm (auto-detect by lockfile)
65
+ --skills <list> Comma-separated skill ids, or "all" (skips interactive prompt)
66
+ --yes Use default skills without prompting (CI / non-interactive)
67
+ --force Overwrite existing template files and MCP server entry
68
+ --dry-run Print actions without writing or installing
69
+ --skip-install Skip dependency install
70
+ --skip-template Skip copying AI template files
71
+ --skip-mcp Skip writing .cursor/mcp.json
72
+ --skip-styles Skip injecting styles.css
73
+ --skip-scripts Skip adding check:colors to package.json
74
+ -h, --help Show this help
75
+
76
+ Skills:
77
+ ${skillList}
78
+ `)
79
+ }
80
+
81
+ /**
82
+ * @param {string[]} argv
83
+ */
84
+ export function parseArgs(argv) {
85
+ const options = {
86
+ mode: 'full',
87
+ cwd: process.cwd(),
88
+ pm: undefined,
89
+ skills: undefined,
90
+ yes: false,
91
+ force: false,
92
+ dryRun: false,
93
+ skipInstall: false,
94
+ skipTemplate: false,
95
+ skipMcp: false,
96
+ skipStyles: false,
97
+ skipScripts: false,
98
+ help: false,
99
+ }
100
+
101
+ for (let i = 0; i < argv.length; i++) {
102
+ const arg = argv[i]
103
+ if (arg === '-h' || arg === '--help') {
104
+ options.help = true
105
+ continue
106
+ }
107
+ if (MODES.has(arg)) {
108
+ options.mode = arg
109
+ continue
110
+ }
111
+ if (arg === '--force') {
112
+ options.force = true
113
+ continue
114
+ }
115
+ if (arg === '--dry-run') {
116
+ options.dryRun = true
117
+ continue
118
+ }
119
+ if (arg === '--yes' || arg === '-y') {
120
+ options.yes = true
121
+ continue
122
+ }
123
+ if (SKIP_FLAGS[arg]) {
124
+ options[SKIP_FLAGS[arg]] = true
125
+ continue
126
+ }
127
+ if (arg === '--cwd') {
128
+ const value = argv[++i]
129
+ if (!value) throw new Error('--cwd requires a path')
130
+ options.cwd = resolve(value)
131
+ continue
132
+ }
133
+ if (arg.startsWith('--cwd=')) {
134
+ options.cwd = resolve(arg.slice('--cwd='.length))
135
+ continue
136
+ }
137
+ if (arg === '--pm') {
138
+ const value = argv[++i]
139
+ if (!value) throw new Error('--pm requires pnpm, yarn, or npm')
140
+ options.pm = value
141
+ continue
142
+ }
143
+ if (arg.startsWith('--pm=')) {
144
+ options.pm = arg.slice('--pm='.length)
145
+ continue
146
+ }
147
+ if (arg === '--skills') {
148
+ const value = argv[++i]
149
+ if (!value) throw new Error('--skills requires a comma-separated list or "all"')
150
+ options.skills = value
151
+ continue
152
+ }
153
+ if (arg.startsWith('--skills=')) {
154
+ options.skills = arg.slice('--skills='.length)
155
+ continue
156
+ }
157
+ throw new Error(`Unknown argument: ${arg}`)
158
+ }
159
+
160
+ const defaults = MODE_DEFAULTS[options.mode] || {}
161
+ for (const [key, value] of Object.entries(defaults)) {
162
+ if (value) options[key] = true
163
+ }
164
+
165
+ return options
166
+ }
167
+
168
+ function rel(cwd, path) {
169
+ if (!path) return ''
170
+ return path.startsWith(cwd) ? path.slice(cwd.length).replace(/^[\\/]/, '') || path : path
171
+ }
172
+
173
+ /**
174
+ * @param {string} cwd
175
+ */
176
+ function hasMoryaUiDependency(cwd) {
177
+ const path = join(cwd, 'package.json')
178
+ if (!existsSync(path)) return false
179
+ try {
180
+ const pkg = readJson(path)
181
+ return Boolean(
182
+ pkg.dependencies?.['morya-ui']
183
+ || pkg.devDependencies?.['morya-ui']
184
+ || pkg.peerDependencies?.['morya-ui'],
185
+ )
186
+ } catch {
187
+ return false
188
+ }
189
+ }
190
+
191
+ /**
192
+ * @param {ReturnType<typeof parseArgs>} options
193
+ */
194
+ export async function runSetup(options) {
195
+ const {
196
+ mode,
197
+ cwd,
198
+ force,
199
+ dryRun,
200
+ skipInstall,
201
+ skipTemplate,
202
+ skipMcp,
203
+ skipStyles,
204
+ skipScripts,
205
+ pm,
206
+ skills: skillsFlag,
207
+ yes,
208
+ } = options
209
+
210
+ console.log(`@morya-ui/setup [${mode}] → ${cwd}${dryRun ? ' (dry-run)' : ''}`)
211
+ console.log('')
212
+
213
+ if (mode === 'ai' && !hasMoryaUiDependency(cwd)) {
214
+ console.log(
215
+ 'Warning: morya-ui is not listed in package.json. Run `npx @morya-ui/setup app` first (or pnpm add morya-ui).',
216
+ )
217
+ console.log('')
218
+ }
219
+
220
+ const catalog = loadSkillsCatalog()
221
+ let selectedSkills = []
222
+ let aiInclude
223
+
224
+ const needsTemplate = !skipTemplate && (mode === 'ai' || mode === 'full')
225
+ if (needsTemplate) {
226
+ if (skillsFlag != null) {
227
+ selectedSkills = parseSkillsFlag(skillsFlag, catalog.skills)
228
+ } else {
229
+ selectedSkills = await resolveSkillSelection(catalog.skills, {
230
+ skipPrompt: yes || dryRun,
231
+ })
232
+ }
233
+ aiInclude = buildAiInclude(selectedSkills, catalog.skills)
234
+ console.log(`Skills: ${selectedSkills.join(', ')}`)
235
+ console.log('')
236
+ }
237
+
238
+ const install = installMoryaUi(cwd, { pm, dryRun, skipInstall })
239
+
240
+ const template = skipTemplate
241
+ ? { copied: [], skipped: [], forced: [], skippedStep: true }
242
+ : copyTemplate(TEMPLATE_ROOT, cwd, {
243
+ force,
244
+ dryRun,
245
+ include: aiInclude,
246
+ })
247
+
248
+ const remoteSkills = skipTemplate || !selectedSkills.length
249
+ ? { installed: [], commands: [], skipped: true }
250
+ : installSkillsCli(cwd, selectedSkills, catalog.skills, { dryRun })
251
+
252
+ const mcp = skipMcp
253
+ ? { path: join(cwd, '.cursor', 'mcp.json'), action: 'skipped-flag' }
254
+ : mergeMcpConfig(cwd, { force, dryRun })
255
+
256
+ const styles = skipStyles
257
+ ? { action: 'skipped', reason: 'skip-styles' }
258
+ : ensureStylesImport(cwd, { dryRun })
259
+
260
+ const scripts = skipScripts
261
+ ? { action: 'skipped-flag' }
262
+ : ensureCheckColorsScript(cwd, { force, dryRun })
263
+
264
+ console.log('--- Summary ---')
265
+ if (install.skipped) {
266
+ console.log(`Install: skipped (${install.reason}) — would run: ${install.command}`)
267
+ } else {
268
+ console.log(`Install: ok (${install.pm}) — ${install.command}`)
269
+ }
270
+
271
+ if (template.skippedStep) {
272
+ console.log('Template: skipped (--skip-template or app mode)')
273
+ } else {
274
+ console.log(
275
+ `Template: ${template.copied.length} copied, ${template.forced.length} overwritten, ${template.skipped.length} skipped`,
276
+ )
277
+ if (selectedSkills.length) console.log(` skills: ${selectedSkills.join(', ')}`)
278
+ if (template.skipped.length && template.skipped.length <= 8) {
279
+ for (const file of template.skipped) console.log(` skip ${file}`)
280
+ } else if (template.skipped.length > 8) {
281
+ for (const file of template.skipped.slice(0, 5)) console.log(` skip ${file}`)
282
+ console.log(` … and ${template.skipped.length - 5} more (use --force to overwrite)`)
283
+ }
284
+ }
285
+
286
+ if (remoteSkills.skipped) {
287
+ // no companions selected or template step skipped
288
+ } else if (remoteSkills.dryRun) {
289
+ console.log(`Skills CLI: dry-run — would install ${remoteSkills.installed.join(', ')}`)
290
+ for (const command of remoteSkills.commands) console.log(` $ ${command}`)
291
+ } else {
292
+ console.log(`Skills CLI: installed ${remoteSkills.installed.join(', ')} (latest)`)
293
+ }
294
+
295
+ if (mcp.action === 'skipped-flag') {
296
+ console.log('MCP: skipped (--skip-mcp or app mode)')
297
+ } else {
298
+ console.log(`MCP: ${mcp.action} (${rel(cwd, mcp.path) || '.cursor/mcp.json'})`)
299
+ }
300
+
301
+ if (styles.reason === 'skip-styles') {
302
+ console.log('Styles: skipped (--skip-styles or ai mode)')
303
+ } else if (styles.action === 'injected') {
304
+ console.log(`Styles: injected into ${rel(cwd, styles.path)}`)
305
+ } else if (styles.action === 'skipped') {
306
+ console.log(`Styles: skipped (${styles.reason}) in ${rel(cwd, styles.path)}`)
307
+ } else {
308
+ console.log('Styles: no entry file found — add manually:')
309
+ console.log(" import 'morya-ui/styles.css'")
310
+ }
311
+
312
+ if (scripts.action === 'skipped-flag') {
313
+ console.log('Scripts: skipped (--skip-scripts or app mode)')
314
+ } else {
315
+ console.log(`Scripts: check:colors ${scripts.action}`)
316
+ }
317
+
318
+ console.log('')
319
+ console.log('Next:')
320
+ if (mode === 'app') {
321
+ console.log(' 1. Ensure the styles.css import is in your app entry.')
322
+ console.log(' 2. Optional AI pack: npx @morya-ui/setup ai')
323
+ } else if (mode === 'ai') {
324
+ console.log(' 1. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
325
+ console.log(' 2. Have the agent read DESIGN.md before generating pages.')
326
+ console.log(' 3. Optional: pnpm check:colors')
327
+ } else {
328
+ console.log(' 1. Ensure the styles.css import is in your app entry.')
329
+ console.log(' 2. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
330
+ console.log(' 3. Have the agent read DESIGN.md before generating pages.')
331
+ console.log(' 4. Optional: pnpm check:colors')
332
+ }
333
+
334
+ return { mode, install, template, remoteSkills, mcp, styles, scripts, skills: selectedSkills }
335
+ }