@morya-ui/setup 0.3.2 → 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 -162
  14. package/template/.agents/skills/morya-ui-pages/evals/evals.json +89 -71
  15. package/template/.agents/skills/morya-ui-pages/references/component-index.md +99 -98
  16. package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +1591 -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 -66
  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
@@ -1,78 +1,78 @@
1
- import { cpSync, existsSync, mkdirSync, readdirSync, statSync } from 'node:fs'
2
- import { dirname, join, relative } from 'node:path'
3
-
4
- /**
5
- * Recursively list files under dir (relative to dir).
6
- * @param {string} dir
7
- * @returns {string[]}
8
- */
9
- function listFiles(dir) {
10
- const out = []
11
- function walk(current) {
12
- for (const name of readdirSync(current)) {
13
- const full = join(current, name)
14
- const st = statSync(full)
15
- if (st.isDirectory()) walk(full)
16
- else out.push(relative(dir, full))
17
- }
18
- }
19
- walk(dir)
20
- return out
21
- }
22
-
23
- /**
24
- * @param {string} rel
25
- * @param {string[] | undefined} include
26
- */
27
- function matchesInclude(rel, include) {
28
- if (!include || include.length === 0) return true
29
- const norm = rel.replace(/\\/g, '/')
30
- return include.some((prefix) => {
31
- const p = prefix.replace(/\\/g, '/')
32
- return norm === p || norm.startsWith(`${p}/`)
33
- })
34
- }
35
-
36
- /**
37
- * Copy template tree into target cwd.
38
- * @param {string} templateRoot
39
- * @param {string} cwd
40
- * @param {{ force?: boolean, dryRun?: boolean, include?: string[] }} [options]
41
- * @returns {{ copied: string[], skipped: string[], forced: string[] }}
42
- */
43
- export function copyTemplate(templateRoot, cwd, { force = false, dryRun = false, include } = {}) {
44
- const copied = []
45
- const skipped = []
46
- const forced = []
47
-
48
- if (!existsSync(templateRoot)) {
49
- throw new Error(
50
- `Template missing at ${templateRoot}. Run sync-template / build before publishing.`,
51
- )
52
- }
53
-
54
- const files = listFiles(templateRoot).filter((rel) => matchesInclude(rel, include))
55
- for (const rel of files) {
56
- const from = join(templateRoot, rel)
57
- const to = join(cwd, rel)
58
- const exists = existsSync(to)
59
-
60
- if (exists && !force) {
61
- skipped.push(rel)
62
- continue
63
- }
64
-
65
- if (dryRun) {
66
- if (exists) forced.push(rel)
67
- else copied.push(rel)
68
- continue
69
- }
70
-
71
- mkdirSync(dirname(to), { recursive: true })
72
- cpSync(from, to)
73
- if (exists) forced.push(rel)
74
- else copied.push(rel)
75
- }
76
-
77
- return { copied, skipped, forced }
78
- }
1
+ import { cpSync, existsSync, mkdirSync, readdirSync, statSync } from 'node:fs'
2
+ import { dirname, join, relative } from 'node:path'
3
+
4
+ /**
5
+ * Recursively list files under dir (relative to dir).
6
+ * @param {string} dir
7
+ * @returns {string[]}
8
+ */
9
+ function listFiles(dir) {
10
+ const out = []
11
+ function walk(current) {
12
+ for (const name of readdirSync(current)) {
13
+ const full = join(current, name)
14
+ const st = statSync(full)
15
+ if (st.isDirectory()) walk(full)
16
+ else out.push(relative(dir, full))
17
+ }
18
+ }
19
+ walk(dir)
20
+ return out
21
+ }
22
+
23
+ /**
24
+ * @param {string} rel
25
+ * @param {string[] | undefined} include
26
+ */
27
+ function matchesInclude(rel, include) {
28
+ if (!include || include.length === 0) return true
29
+ const norm = rel.replace(/\\/g, '/')
30
+ return include.some((prefix) => {
31
+ const p = prefix.replace(/\\/g, '/')
32
+ return norm === p || norm.startsWith(`${p}/`)
33
+ })
34
+ }
35
+
36
+ /**
37
+ * Copy template tree into target cwd.
38
+ * @param {string} templateRoot
39
+ * @param {string} cwd
40
+ * @param {{ force?: boolean, dryRun?: boolean, include?: string[] }} [options]
41
+ * @returns {{ copied: string[], skipped: string[], forced: string[] }}
42
+ */
43
+ export function copyTemplate(templateRoot, cwd, { force = false, dryRun = false, include } = {}) {
44
+ const copied = []
45
+ const skipped = []
46
+ const forced = []
47
+
48
+ if (!existsSync(templateRoot)) {
49
+ throw new Error(
50
+ `Template missing at ${templateRoot}. Run sync-template / build before publishing.`,
51
+ )
52
+ }
53
+
54
+ const files = listFiles(templateRoot).filter((rel) => matchesInclude(rel, include))
55
+ for (const rel of files) {
56
+ const from = join(templateRoot, rel)
57
+ const to = join(cwd, rel)
58
+ const exists = existsSync(to)
59
+
60
+ if (exists && !force) {
61
+ skipped.push(rel)
62
+ continue
63
+ }
64
+
65
+ if (dryRun) {
66
+ if (exists) forced.push(rel)
67
+ else copied.push(rel)
68
+ continue
69
+ }
70
+
71
+ mkdirSync(dirname(to), { recursive: true })
72
+ cpSync(from, to)
73
+ if (exists) forced.push(rel)
74
+ else copied.push(rel)
75
+ }
76
+
77
+ return { copied, skipped, forced }
78
+ }
package/src/fs-utils.mjs CHANGED
@@ -1,24 +1,24 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { dirname } from 'node:path'
3
-
4
- export function readJson(path) {
5
- const text = readFileSync(path, 'utf8').replace(/^\uFEFF/, '')
6
- return JSON.parse(text)
7
- }
8
-
9
- export function writeJson(path, value, { dryRun = false } = {}) {
10
- const text = `${JSON.stringify(value, null, 2)}\n`
11
- if (dryRun) return text
12
- mkdirSync(dirname(path), { recursive: true })
13
- writeFileSync(path, text, 'utf8')
14
- return text
15
- }
16
-
17
- export function ensureDir(path, { dryRun = false } = {}) {
18
- if (dryRun || existsSync(path)) return
19
- mkdirSync(path, { recursive: true })
20
- }
21
-
22
- export function fileExists(path) {
23
- return existsSync(path)
24
- }
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { dirname } from 'node:path'
3
+
4
+ export function readJson(path) {
5
+ const text = readFileSync(path, 'utf8').replace(/^\uFEFF/, '')
6
+ return JSON.parse(text)
7
+ }
8
+
9
+ export function writeJson(path, value, { dryRun = false } = {}) {
10
+ const text = `${JSON.stringify(value, null, 2)}\n`
11
+ if (dryRun) return text
12
+ mkdirSync(dirname(path), { recursive: true })
13
+ writeFileSync(path, text, 'utf8')
14
+ return text
15
+ }
16
+
17
+ export function ensureDir(path, { dryRun = false } = {}) {
18
+ if (dryRun || existsSync(path)) return
19
+ mkdirSync(path, { recursive: true })
20
+ }
21
+
22
+ export function fileExists(path) {
23
+ return existsSync(path)
24
+ }
package/src/install.mjs CHANGED
@@ -1,63 +1,63 @@
1
- import { existsSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import { execSync } from 'node:child_process'
4
-
5
- const LOCKFILES = [
6
- { pm: 'pnpm', file: 'pnpm-lock.yaml' },
7
- { pm: 'yarn', file: 'yarn.lock' },
8
- { pm: 'npm', file: 'package-lock.json' },
9
- ]
10
-
11
- export function detectPackageManager(cwd, explicit) {
12
- if (explicit) {
13
- if (!['pnpm', 'yarn', 'npm'].includes(explicit)) {
14
- throw new Error(`Unsupported --pm value: ${explicit}. Use pnpm, yarn, or npm.`)
15
- }
16
- return explicit
17
- }
18
- for (const { pm, file } of LOCKFILES) {
19
- if (existsSync(join(cwd, file))) return pm
20
- }
21
- return 'pnpm'
22
- }
23
-
24
- function installCommand(pm) {
25
- switch (pm) {
26
- case 'pnpm':
27
- return 'pnpm add morya-ui'
28
- case 'yarn':
29
- return 'yarn add morya-ui'
30
- case 'npm':
31
- return 'npm install morya-ui'
32
- default:
33
- throw new Error(`Unknown package manager: ${pm}`)
34
- }
35
- }
36
-
37
- /**
38
- * @returns {{ pm: string, command: string, skipped?: boolean, reason?: string }}
39
- */
40
- export function installMoryaUi(cwd, { pm, dryRun = false, skipInstall = false } = {}) {
41
- const resolved = detectPackageManager(cwd, pm)
42
- const command = installCommand(resolved)
43
-
44
- if (skipInstall) {
45
- return { pm: resolved, command, skipped: true, reason: 'skip-install' }
46
- }
47
-
48
- if (!existsSync(join(cwd, 'package.json'))) {
49
- return {
50
- pm: resolved,
51
- command,
52
- skipped: true,
53
- reason: 'no-package-json',
54
- }
55
- }
56
-
57
- if (dryRun) {
58
- return { pm: resolved, command, skipped: true, reason: 'dry-run' }
59
- }
60
-
61
- execSync(command, { cwd, stdio: 'inherit', shell: true })
62
- return { pm: resolved, command }
63
- }
1
+ import { existsSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { execSync } from 'node:child_process'
4
+
5
+ const LOCKFILES = [
6
+ { pm: 'pnpm', file: 'pnpm-lock.yaml' },
7
+ { pm: 'yarn', file: 'yarn.lock' },
8
+ { pm: 'npm', file: 'package-lock.json' },
9
+ ]
10
+
11
+ export function detectPackageManager(cwd, explicit) {
12
+ if (explicit) {
13
+ if (!['pnpm', 'yarn', 'npm'].includes(explicit)) {
14
+ throw new Error(`Unsupported --pm value: ${explicit}. Use pnpm, yarn, or npm.`)
15
+ }
16
+ return explicit
17
+ }
18
+ for (const { pm, file } of LOCKFILES) {
19
+ if (existsSync(join(cwd, file))) return pm
20
+ }
21
+ return 'pnpm'
22
+ }
23
+
24
+ function installCommand(pm) {
25
+ switch (pm) {
26
+ case 'pnpm':
27
+ return 'pnpm add morya-ui'
28
+ case 'yarn':
29
+ return 'yarn add morya-ui'
30
+ case 'npm':
31
+ return 'npm install morya-ui'
32
+ default:
33
+ throw new Error(`Unknown package manager: ${pm}`)
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @returns {{ pm: string, command: string, skipped?: boolean, reason?: string }}
39
+ */
40
+ export function installMoryaUi(cwd, { pm, dryRun = false, skipInstall = false } = {}) {
41
+ const resolved = detectPackageManager(cwd, pm)
42
+ const command = installCommand(resolved)
43
+
44
+ if (skipInstall) {
45
+ return { pm: resolved, command, skipped: true, reason: 'skip-install' }
46
+ }
47
+
48
+ if (!existsSync(join(cwd, 'package.json'))) {
49
+ return {
50
+ pm: resolved,
51
+ command,
52
+ skipped: true,
53
+ reason: 'no-package-json',
54
+ }
55
+ }
56
+
57
+ if (dryRun) {
58
+ return { pm: resolved, command, skipped: true, reason: 'dry-run' }
59
+ }
60
+
61
+ execSync(command, { cwd, stdio: 'inherit', shell: true })
62
+ return { pm: resolved, command }
63
+ }
package/src/mcp.mjs CHANGED
@@ -1,50 +1,50 @@
1
- import { existsSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import { readJson, writeJson } from './fs-utils.mjs'
4
-
5
- const SERVER_NAME = 'morya-ui'
6
- const SERVER_CONFIG = {
7
- command: 'npx',
8
- args: ['-y', '@morya-ui/mcp'],
9
- }
10
-
11
- /**
12
- * Merge Cursor MCP config for morya-ui.
13
- * @returns {{ path: string, action: 'created' | 'merged' | 'skipped' | 'forced', dryRun?: boolean }}
14
- */
15
- export function mergeMcpConfig(cwd, { force = false, dryRun = false } = {}) {
16
- const path = join(cwd, '.cursor', 'mcp.json')
17
- const exists = existsSync(path)
18
-
19
- let data = { mcpServers: {} }
20
- if (exists) {
21
- try {
22
- data = readJson(path)
23
- } catch {
24
- throw new Error(`Invalid JSON in ${path}`)
25
- }
26
- if (!data || typeof data !== 'object') {
27
- throw new Error(`Invalid MCP config shape in ${path}`)
28
- }
29
- if (!data.mcpServers || typeof data.mcpServers !== 'object') {
30
- data.mcpServers = {}
31
- }
32
- }
33
-
34
- const hasExisting = Boolean(data.mcpServers[SERVER_NAME])
35
- if (hasExisting && !force) {
36
- return { path, action: 'skipped' }
37
- }
38
-
39
- data.mcpServers[SERVER_NAME] = { ...SERVER_CONFIG }
40
-
41
- if (!dryRun) {
42
- writeJson(path, data)
43
- }
44
-
45
- let action = 'created'
46
- if (exists && hasExisting && force) action = 'forced'
47
- else if (exists) action = 'merged'
48
-
49
- return { path, action, dryRun }
50
- }
1
+ import { existsSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { readJson, writeJson } from './fs-utils.mjs'
4
+
5
+ const SERVER_NAME = 'morya-ui'
6
+ const SERVER_CONFIG = {
7
+ command: 'npx',
8
+ args: ['-y', '@morya-ui/mcp'],
9
+ }
10
+
11
+ /**
12
+ * Merge Cursor MCP config for morya-ui.
13
+ * @returns {{ path: string, action: 'created' | 'merged' | 'skipped' | 'forced', dryRun?: boolean }}
14
+ */
15
+ export function mergeMcpConfig(cwd, { force = false, dryRun = false } = {}) {
16
+ const path = join(cwd, '.cursor', 'mcp.json')
17
+ const exists = existsSync(path)
18
+
19
+ let data = { mcpServers: {} }
20
+ if (exists) {
21
+ try {
22
+ data = readJson(path)
23
+ } catch {
24
+ throw new Error(`Invalid JSON in ${path}`)
25
+ }
26
+ if (!data || typeof data !== 'object') {
27
+ throw new Error(`Invalid MCP config shape in ${path}`)
28
+ }
29
+ if (!data.mcpServers || typeof data.mcpServers !== 'object') {
30
+ data.mcpServers = {}
31
+ }
32
+ }
33
+
34
+ const hasExisting = Boolean(data.mcpServers[SERVER_NAME])
35
+ if (hasExisting && !force) {
36
+ return { path, action: 'skipped' }
37
+ }
38
+
39
+ data.mcpServers[SERVER_NAME] = { ...SERVER_CONFIG }
40
+
41
+ if (!dryRun) {
42
+ writeJson(path, data)
43
+ }
44
+
45
+ let action = 'created'
46
+ if (exists && hasExisting && force) action = 'forced'
47
+ else if (exists) action = 'merged'
48
+
49
+ return { path, action, dryRun }
50
+ }
@@ -1,30 +1,30 @@
1
- import { existsSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import { readJson, writeJson } from './fs-utils.mjs'
4
-
5
- const CHECK_COLORS = 'node scripts/check-raw-colors.mjs'
6
-
7
- /**
8
- * @returns {{ action: 'added' | 'skipped' | 'missing-package-json', dryRun?: boolean }}
9
- */
10
- export function ensureCheckColorsScript(cwd, { force = false, dryRun = false } = {}) {
11
- const path = join(cwd, 'package.json')
12
- if (!existsSync(path)) {
13
- return { action: 'missing-package-json' }
14
- }
15
-
16
- const pkg = readJson(path)
17
- pkg.scripts = pkg.scripts || {}
18
-
19
- if (pkg.scripts['check:colors'] && !force) {
20
- return { action: 'skipped' }
21
- }
22
-
23
- pkg.scripts['check:colors'] = CHECK_COLORS
24
-
25
- if (!dryRun) {
26
- writeJson(path, pkg)
27
- }
28
-
29
- return { action: 'added', dryRun }
30
- }
1
+ import { existsSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { readJson, writeJson } from './fs-utils.mjs'
4
+
5
+ const CHECK_COLORS = 'node scripts/check-raw-colors.mjs'
6
+
7
+ /**
8
+ * @returns {{ action: 'added' | 'skipped' | 'missing-package-json', dryRun?: boolean }}
9
+ */
10
+ export function ensureCheckColorsScript(cwd, { force = false, dryRun = false } = {}) {
11
+ const path = join(cwd, 'package.json')
12
+ if (!existsSync(path)) {
13
+ return { action: 'missing-package-json' }
14
+ }
15
+
16
+ const pkg = readJson(path)
17
+ pkg.scripts = pkg.scripts || {}
18
+
19
+ if (pkg.scripts['check:colors'] && !force) {
20
+ return { action: 'skipped' }
21
+ }
22
+
23
+ pkg.scripts['check:colors'] = CHECK_COLORS
24
+
25
+ if (!dryRun) {
26
+ writeJson(path, pkg)
27
+ }
28
+
29
+ return { action: 'added', dryRun }
30
+ }