@morya-ui/setup 0.3.4 → 0.3.6
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/LICENSE +21 -0
- package/README.md +119 -103
- package/bin/morya-ui-setup.js +14 -14
- package/catalog/skills.json +46 -46
- package/package.json +4 -5
- package/src/__tests__/mcp.test.mjs +141 -0
- package/src/cli.mjs +330 -335
- package/src/copy-template.mjs +78 -78
- package/src/fs-utils.mjs +24 -24
- package/src/install.mjs +134 -63
- package/src/mcp.mjs +220 -50
- package/src/package-json.mjs +30 -30
- package/src/skills.mjs +224 -223
- package/src/styles.mjs +119 -119
- package/template/.agents/skills/morya-ui-pages/SKILL.md +191 -184
- package/template/.agents/skills/morya-ui-pages/evals/evals.json +89 -89
- package/template/.agents/skills/morya-ui-pages/references/component-index.md +99 -99
- package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +72 -5
- package/template/.agents/skills/morya-ui-pages/references/design-system.md +101 -101
- package/template/.agents/skills/morya-ui-pages/references/feedback.md +68 -68
- package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +62 -107
- package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +133 -141
- package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +76 -64
- package/template/.agents/skills/morya-ui-pages/references/style-presets.md +68 -73
- package/template/.agents/skills/morya-ui-pages/references/surfaces.md +91 -91
- package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +131 -221
- package/template/.cursor/rules/coding-style.mdc +41 -41
- package/template/.cursor/rules/component-usage.mdc +41 -41
- package/template/.cursor/rules/design-system.mdc +18 -17
- package/template/.cursor/rules/page-layout.mdc +97 -97
- package/template/AGENTS.md +33 -0
- package/template/DESIGN.md +81 -59
- package/template/scripts/check-raw-colors.mjs +74 -74
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Morya UI contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,103 +1,119 @@
|
|
|
1
|
-
# @morya-ui/setup
|
|
2
|
-
|
|
3
|
-
One-shot setup for consumer Vue projects using [`morya-ui`](https://www.npmjs.com/package/morya-ui).
|
|
4
|
-
|
|
5
|
-
Docs (zh/en):
|
|
6
|
-
|
|
7
|
-
- [One-shot setup](https://morya-space.github.io/morya-ui/docs/setup) — CLI commands and options
|
|
8
|
-
- [AI setup](https://morya-space.github.io/morya-ui/docs/ai-setup) — Agent workflow
|
|
9
|
-
- [Agent Skill](https://morya-space.github.io/morya-ui/docs/agent-skill) — `morya-ui-pages` behavior
|
|
10
|
-
- [Quick start](https://morya-space.github.io/morya-ui/docs/quick-start) — install and first component
|
|
11
|
-
|
|
12
|
-
Installs the UI library
|
|
13
|
-
|
|
14
|
-
## Usage
|
|
15
|
-
|
|
16
|
-
In your app project root:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npx @morya-ui/setup
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
On a TTY, `full` / `ai` will prompt for optional Agent skills (required `morya-ui-pages` is always included).
|
|
23
|
-
|
|
24
|
-
Other common commands:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# AI config + MCP
|
|
28
|
-
npx @morya-ui/setup ai
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
npx @morya-ui/setup app
|
|
32
|
-
|
|
33
|
-
# Non-interactive skill selection
|
|
34
|
-
npx @morya-ui/setup ai --yes
|
|
35
|
-
npx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design,impeccable
|
|
36
|
-
npx @morya-ui/setup ai --skills=all
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| `--
|
|
50
|
-
| `--
|
|
51
|
-
| `--
|
|
52
|
-
| `--
|
|
53
|
-
| `--
|
|
54
|
-
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- `
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
1
|
+
# @morya-ui/setup
|
|
2
|
+
|
|
3
|
+
One-shot setup for consumer Vue projects using [`morya-ui`](https://www.npmjs.com/package/morya-ui).
|
|
4
|
+
|
|
5
|
+
Docs (zh/en):
|
|
6
|
+
|
|
7
|
+
- [One-shot setup](https://morya-space.github.io/morya-ui/docs/setup) — CLI commands and options
|
|
8
|
+
- [AI setup](https://morya-space.github.io/morya-ui/docs/ai-setup) — Agent workflow
|
|
9
|
+
- [Agent Skill](https://morya-space.github.io/morya-ui/docs/agent-skill) — `morya-ui-pages` behavior
|
|
10
|
+
- [Quick start](https://morya-space.github.io/morya-ui/docs/quick-start) — install and first component
|
|
11
|
+
|
|
12
|
+
Installs / upgrades the UI library and any existing `@morya-ui/*` packages to **latest**, copies first-party Agent skills / Cursor rules / design docs from `design-kit`, installs optional companion skills at **latest** via the [skills CLI](https://skills.sh/), merges MCP for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp) across Cursor / VS Code / Zed (plus portable `.mcp.json`), and injects `import 'morya-ui/styles.css'`.
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
In your app project root:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @morya-ui/setup
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
On a TTY, `full` / `ai` will prompt for optional Agent skills (required `morya-ui-pages` is always included).
|
|
23
|
+
|
|
24
|
+
Other common commands:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Upgrade deps + AI config + MCP (skips styles injection)
|
|
28
|
+
npx @morya-ui/setup ai
|
|
29
|
+
|
|
30
|
+
# Upgrade deps + styles only
|
|
31
|
+
npx @morya-ui/setup app
|
|
32
|
+
|
|
33
|
+
# Non-interactive skill selection
|
|
34
|
+
npx @morya-ui/setup ai --yes
|
|
35
|
+
npx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design,impeccable
|
|
36
|
+
npx @morya-ui/setup ai --skills=all
|
|
37
|
+
|
|
38
|
+
# Only Cursor + VS Code MCP targets (still writes .mcp.json)
|
|
39
|
+
npx @morya-ui/setup ai --editors=cursor,vscode
|
|
40
|
+
|
|
41
|
+
# Refresh AI template / MCP without touching dependencies
|
|
42
|
+
npx @morya-ui/setup ai --skip-install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Options
|
|
46
|
+
|
|
47
|
+
| Flag | Meaning |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `--cwd <dir>` | Target project root (default: current directory) |
|
|
50
|
+
| `--pm pnpm\|yarn\|npm` | Package manager (default: detect from lockfile, else `pnpm`) |
|
|
51
|
+
| `--skills <list>` | Comma-separated skill ids, or `all` (skips the prompt) |
|
|
52
|
+
| `--editors <list>` | MCP targets: `cursor`, `vscode`, `zed`, or `all` (default: all three). Always also writes root `.mcp.json` |
|
|
53
|
+
| `--yes` / `-y` | Use default skills without prompting |
|
|
54
|
+
| `--force` | Overwrite existing template files and the `morya-ui` MCP entry |
|
|
55
|
+
| `--dry-run` | Print actions without writing or installing |
|
|
56
|
+
| `--skip-install` | Do not install / upgrade `morya-ui` or `@morya-ui/*` |
|
|
57
|
+
| `--skip-template` | Do not copy AI skill / rules / docs (also skips companion skill install) |
|
|
58
|
+
| `--skip-mcp` | Do not write editor MCP configs or `.mcp.json` |
|
|
59
|
+
| `--skip-styles` | Do not inject `styles.css` |
|
|
60
|
+
| `--skip-scripts` | Do not add `check:colors` to `package.json` |
|
|
61
|
+
| `-h`, `--help` | Show help |
|
|
62
|
+
|
|
63
|
+
### Skills
|
|
64
|
+
|
|
65
|
+
| Id | Default | Install | Role |
|
|
66
|
+
| --- | --- | --- | --- |
|
|
67
|
+
| `morya-ui-pages` | required | template (from this package) | Page generation with `M*` + snippets / decisions (composition-first) |
|
|
68
|
+
| `frontend-design` | optional | skills CLI → `anthropics/skills` (latest) | Express / brand visual taste |
|
|
69
|
+
| `fixing-accessibility` | optional | skills CLI → `ibelick/ui-skills` (latest) | A11y audit and targeted fixes |
|
|
70
|
+
| `impeccable` | optional | skills CLI → `pbakaus/impeccable` (latest) | Named polish / audit / redesign passes |
|
|
71
|
+
|
|
72
|
+
Catalog: [`catalog/skills.json`](./catalog/skills.json).
|
|
73
|
+
|
|
74
|
+
### Conflict policy
|
|
75
|
+
|
|
76
|
+
- Dependencies: always install / upgrade `morya-ui@latest` and any existing `@morya-ui/*` (e.g. `@morya-ui/nuxt`) to `@latest` unless `--skip-install`.
|
|
77
|
+
- Template files and `.cursor/rules/*`: **skip** if the destination exists (unless `--force`).
|
|
78
|
+
- Companion skills (`skills-cli`): always reinstall/update to **latest** when selected.
|
|
79
|
+
- MCP configs: merge other servers / settings; skip existing `morya-ui` entry unless `--force`. New or forced entries use `npx -y @morya-ui/mcp@latest`.
|
|
80
|
+
- `package.json` `check:colors`: add only if missing (unless `--force`).
|
|
81
|
+
- Styles: inject only when an entry file is found and the import is not already present.
|
|
82
|
+
|
|
83
|
+
### What gets copied / installed
|
|
84
|
+
|
|
85
|
+
From the package `template/` (synced from repo `design-kit/`):
|
|
86
|
+
|
|
87
|
+
- `DESIGN.md` — core design contract (principles, tokens, bans)
|
|
88
|
+
- `AGENTS.md` — portable always-on agent checklist (editor-neutral)
|
|
89
|
+
- `.agents/skills/morya-ui-pages/` — first-party page skill
|
|
90
|
+
- `.cursor/rules/` — Cursor-specific always-apply rules
|
|
91
|
+
- `scripts/check-raw-colors.mjs`
|
|
92
|
+
|
|
93
|
+
Via `npx skills add …` when optional companions are selected:
|
|
94
|
+
|
|
95
|
+
- `.agents/skills/frontend-design/`, `fixing-accessibility/`, and/or `impeccable/` (latest upstream)
|
|
96
|
+
|
|
97
|
+
### MCP (multi-editor)
|
|
98
|
+
|
|
99
|
+
| Editor | Path | JSON key |
|
|
100
|
+
| --- | --- | --- |
|
|
101
|
+
| Cursor | `.cursor/mcp.json` | `mcpServers.morya-ui` |
|
|
102
|
+
| VS Code | `.vscode/mcp.json` | `servers.morya-ui` |
|
|
103
|
+
| Zed | `.zed/settings.json` | `context_servers.morya-ui` |
|
|
104
|
+
| Portable | `.mcp.json` | `mcpServers.morya-ui` |
|
|
105
|
+
|
|
106
|
+
Shared server payload:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"command": "npx",
|
|
111
|
+
"args": ["-y", "@morya-ui/mcp@latest"]
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
VS Code entries also set `"type": "stdio"`. Root `.mcp.json` is always written when MCP is not skipped (useful for Agent Host / cross-tool discovery).
|
|
116
|
+
|
|
117
|
+
Claude Code / Windsurf / other clients: configure manually with the same `command` / `args` (see [Agent MCP](https://morya-space.github.io/morya-ui/docs/mcp)).
|
|
118
|
+
|
|
119
|
+
Reload MCP in your editor after install.
|
package/bin/morya-ui-setup.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { parseArgs, printHelp, runSetup } from '../src/cli.mjs'
|
|
3
|
-
|
|
4
|
-
try {
|
|
5
|
-
const options = parseArgs(process.argv.slice(2))
|
|
6
|
-
if (options.help) {
|
|
7
|
-
printHelp()
|
|
8
|
-
process.exit(0)
|
|
9
|
-
}
|
|
10
|
-
await runSetup(options)
|
|
11
|
-
} catch (error) {
|
|
12
|
-
console.error(error instanceof Error ? error.message : error)
|
|
13
|
-
process.exit(1)
|
|
14
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs, printHelp, runSetup } from '../src/cli.mjs'
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
const options = parseArgs(process.argv.slice(2))
|
|
6
|
+
if (options.help) {
|
|
7
|
+
printHelp()
|
|
8
|
+
process.exit(0)
|
|
9
|
+
}
|
|
10
|
+
await runSetup(options)
|
|
11
|
+
} catch (error) {
|
|
12
|
+
console.error(error instanceof Error ? error.message : error)
|
|
13
|
+
process.exit(1)
|
|
14
|
+
}
|
package/catalog/skills.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"skills": [
|
|
3
|
-
{
|
|
4
|
-
"id": "morya-ui-pages",
|
|
5
|
-
"name": "Morya UI Pages",
|
|
6
|
-
"description": "Build admin and product pages with M* components, golden layouts, and tokens.",
|
|
7
|
-
"required": true,
|
|
8
|
-
"default": true,
|
|
9
|
-
"install": "template",
|
|
10
|
-
"path": ".agents/skills/morya-ui-pages"
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"id": "frontend-design",
|
|
14
|
-
"name": "Frontend Design",
|
|
15
|
-
"description": "Distinctive visual direction for Express / brand surfaces; use after morya-ui-pages contract (taste only; still remediate with M*).",
|
|
16
|
-
"required": false,
|
|
17
|
-
"default": false,
|
|
18
|
-
"install": "skills-cli",
|
|
19
|
-
"source": "anthropics/skills",
|
|
20
|
-
"skill": "frontend-design",
|
|
21
|
-
"path": ".agents/skills/frontend-design"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"id": "fixing-accessibility",
|
|
25
|
-
"name": "Fixing Accessibility",
|
|
26
|
-
"description": "Audit and fix names, keyboard, focus, forms, and WCAG basics.",
|
|
27
|
-
"required": false,
|
|
28
|
-
"default": false,
|
|
29
|
-
"install": "skills-cli",
|
|
30
|
-
"source": "ibelick/ui-skills",
|
|
31
|
-
"skill": "fixing-accessibility",
|
|
32
|
-
"path": ".agents/skills/fixing-accessibility"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"id": "impeccable",
|
|
36
|
-
"name": "Impeccable",
|
|
37
|
-
"description": "Named polish / audit / bolder / quieter passes; pair with morya-ui-pages Operate/Persuade modes (latest from pbakaus/impeccable).",
|
|
38
|
-
"required": false,
|
|
39
|
-
"default": false,
|
|
40
|
-
"install": "skills-cli",
|
|
41
|
-
"source": "pbakaus/impeccable",
|
|
42
|
-
"skill": "impeccable",
|
|
43
|
-
"path": ".agents/skills/impeccable"
|
|
44
|
-
}
|
|
45
|
-
]
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"skills": [
|
|
3
|
+
{
|
|
4
|
+
"id": "morya-ui-pages",
|
|
5
|
+
"name": "Morya UI Pages",
|
|
6
|
+
"description": "Build admin and product pages with M* components, golden layouts, and tokens.",
|
|
7
|
+
"required": true,
|
|
8
|
+
"default": true,
|
|
9
|
+
"install": "template",
|
|
10
|
+
"path": ".agents/skills/morya-ui-pages"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "frontend-design",
|
|
14
|
+
"name": "Frontend Design",
|
|
15
|
+
"description": "Distinctive visual direction for Express / brand surfaces; use after morya-ui-pages contract (taste only; still remediate with M*).",
|
|
16
|
+
"required": false,
|
|
17
|
+
"default": false,
|
|
18
|
+
"install": "skills-cli",
|
|
19
|
+
"source": "anthropics/skills",
|
|
20
|
+
"skill": "frontend-design",
|
|
21
|
+
"path": ".agents/skills/frontend-design"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "fixing-accessibility",
|
|
25
|
+
"name": "Fixing Accessibility",
|
|
26
|
+
"description": "Audit and fix names, keyboard, focus, forms, and WCAG basics.",
|
|
27
|
+
"required": false,
|
|
28
|
+
"default": false,
|
|
29
|
+
"install": "skills-cli",
|
|
30
|
+
"source": "ibelick/ui-skills",
|
|
31
|
+
"skill": "fixing-accessibility",
|
|
32
|
+
"path": ".agents/skills/fixing-accessibility"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "impeccable",
|
|
36
|
+
"name": "Impeccable",
|
|
37
|
+
"description": "Named polish / audit / bolder / quieter passes; pair with morya-ui-pages Operate/Persuade modes (latest from pbakaus/impeccable).",
|
|
38
|
+
"required": false,
|
|
39
|
+
"default": false,
|
|
40
|
+
"install": "skills-cli",
|
|
41
|
+
"source": "pbakaus/impeccable",
|
|
42
|
+
"skill": "impeccable",
|
|
43
|
+
"path": ".agents/skills/impeccable"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morya-ui/setup",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
5
|
-
"
|
|
6
|
-
"description": "One-shot setup for morya-ui: install the library, Cursor MCP, Agent skills, and design config.",
|
|
4
|
+
"version": "0.3.6",
|
|
5
|
+
"description": "One-shot setup for morya-ui: install the library, multi-editor MCP, Agent skills, and design config.",
|
|
7
6
|
"license": "MIT",
|
|
8
7
|
"homepage": "https://github.com/morya-space/morya-ui/tree/main/packages/setup#readme",
|
|
9
8
|
"repository": {
|
|
@@ -33,6 +32,6 @@
|
|
|
33
32
|
"scripts": {
|
|
34
33
|
"sync-template": "node ./scripts/sync-template.mjs",
|
|
35
34
|
"build": "pnpm run sync-template",
|
|
36
|
-
"
|
|
35
|
+
"test": "node --test src/__tests__/**/*.test.mjs"
|
|
37
36
|
}
|
|
38
|
-
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import { afterEach, describe, it } from 'node:test'
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_EDITORS,
|
|
8
|
+
SERVER_CONFIG,
|
|
9
|
+
VSCODE_SERVER_CONFIG,
|
|
10
|
+
mergeMcpConfig,
|
|
11
|
+
parseEditorsFlag,
|
|
12
|
+
} from '../mcp.mjs'
|
|
13
|
+
|
|
14
|
+
/** @type {string[]} */
|
|
15
|
+
const temps = []
|
|
16
|
+
|
|
17
|
+
function makeCwd() {
|
|
18
|
+
const cwd = mkdtempSync(join(tmpdir(), 'morya-setup-mcp-'))
|
|
19
|
+
temps.push(cwd)
|
|
20
|
+
return cwd
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
while (temps.length) {
|
|
25
|
+
rmSync(temps.pop(), { recursive: true, force: true })
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
function readJson(path) {
|
|
30
|
+
return JSON.parse(readFileSync(path, 'utf8'))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('parseEditorsFlag', () => {
|
|
34
|
+
it('defaults to all known editors', () => {
|
|
35
|
+
assert.deepEqual(parseEditorsFlag(), [...DEFAULT_EDITORS])
|
|
36
|
+
assert.deepEqual(parseEditorsFlag('all'), [...DEFAULT_EDITORS])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('parses and dedupes a subset', () => {
|
|
40
|
+
assert.deepEqual(parseEditorsFlag('zed,cursor,zed'), ['zed', 'cursor'])
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('rejects unknown editors', () => {
|
|
44
|
+
assert.throws(() => parseEditorsFlag('cursor,windsurf'), /Unknown editor/)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('mergeMcpConfig', () => {
|
|
49
|
+
it('creates cursor, vscode, zed, and portable configs', () => {
|
|
50
|
+
const cwd = makeCwd()
|
|
51
|
+
const { results } = mergeMcpConfig(cwd)
|
|
52
|
+
|
|
53
|
+
assert.equal(results.length, 4)
|
|
54
|
+
assert.deepEqual(
|
|
55
|
+
results.map((r) => r.editor),
|
|
56
|
+
['cursor', 'vscode', 'zed', 'portable'],
|
|
57
|
+
)
|
|
58
|
+
assert.ok(results.every((r) => r.action === 'created'))
|
|
59
|
+
|
|
60
|
+
assert.deepEqual(readJson(join(cwd, '.cursor', 'mcp.json')), {
|
|
61
|
+
mcpServers: { 'morya-ui': SERVER_CONFIG },
|
|
62
|
+
})
|
|
63
|
+
assert.deepEqual(readJson(join(cwd, '.vscode', 'mcp.json')), {
|
|
64
|
+
servers: { 'morya-ui': VSCODE_SERVER_CONFIG },
|
|
65
|
+
})
|
|
66
|
+
assert.deepEqual(readJson(join(cwd, '.zed', 'settings.json')), {
|
|
67
|
+
context_servers: { 'morya-ui': SERVER_CONFIG },
|
|
68
|
+
})
|
|
69
|
+
assert.deepEqual(readJson(join(cwd, '.mcp.json')), {
|
|
70
|
+
mcpServers: { 'morya-ui': SERVER_CONFIG },
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('skips existing morya-ui entries unless force', () => {
|
|
75
|
+
const cwd = makeCwd()
|
|
76
|
+
mkdirSync(join(cwd, '.cursor'), { recursive: true })
|
|
77
|
+
writeFileSync(
|
|
78
|
+
join(cwd, '.cursor', 'mcp.json'),
|
|
79
|
+
JSON.stringify({
|
|
80
|
+
mcpServers: {
|
|
81
|
+
other: { command: 'echo' },
|
|
82
|
+
'morya-ui': { command: 'old' },
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
'utf8',
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
const skipped = mergeMcpConfig(cwd, { editors: ['cursor'] })
|
|
89
|
+
const cursorSkip = skipped.results.find((r) => r.editor === 'cursor')
|
|
90
|
+
assert.equal(cursorSkip.action, 'skipped')
|
|
91
|
+
assert.equal(readJson(join(cwd, '.cursor', 'mcp.json')).mcpServers['morya-ui'].command, 'old')
|
|
92
|
+
assert.ok(readJson(join(cwd, '.cursor', 'mcp.json')).mcpServers.other)
|
|
93
|
+
|
|
94
|
+
const forced = mergeMcpConfig(cwd, { editors: ['cursor'], force: true })
|
|
95
|
+
const cursorForce = forced.results.find((r) => r.editor === 'cursor')
|
|
96
|
+
assert.equal(cursorForce.action, 'forced')
|
|
97
|
+
const data = readJson(join(cwd, '.cursor', 'mcp.json'))
|
|
98
|
+
assert.deepEqual(data.mcpServers['morya-ui'], SERVER_CONFIG)
|
|
99
|
+
assert.ok(data.mcpServers.other)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('merges Zed settings without wiping unrelated keys', () => {
|
|
103
|
+
const cwd = makeCwd()
|
|
104
|
+
mkdirSync(join(cwd, '.zed'), { recursive: true })
|
|
105
|
+
writeFileSync(
|
|
106
|
+
join(cwd, '.zed', 'settings.json'),
|
|
107
|
+
JSON.stringify({
|
|
108
|
+
theme: 'One Dark',
|
|
109
|
+
context_servers: {
|
|
110
|
+
other: { command: 'keep-me' },
|
|
111
|
+
},
|
|
112
|
+
}),
|
|
113
|
+
'utf8',
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
const { results } = mergeMcpConfig(cwd, { editors: ['zed'] })
|
|
117
|
+
assert.equal(results.find((r) => r.editor === 'zed').action, 'merged')
|
|
118
|
+
|
|
119
|
+
const zed = readJson(join(cwd, '.zed', 'settings.json'))
|
|
120
|
+
assert.equal(zed.theme, 'One Dark')
|
|
121
|
+
assert.deepEqual(zed.context_servers.other, { command: 'keep-me' })
|
|
122
|
+
assert.deepEqual(zed.context_servers['morya-ui'], SERVER_CONFIG)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('respects editors subset and still writes portable', () => {
|
|
126
|
+
const cwd = makeCwd()
|
|
127
|
+
const { results } = mergeMcpConfig(cwd, { editors: ['vscode'] })
|
|
128
|
+
assert.deepEqual(
|
|
129
|
+
results.map((r) => r.editor),
|
|
130
|
+
['vscode', 'portable'],
|
|
131
|
+
)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('dry-run does not write files', () => {
|
|
135
|
+
const cwd = makeCwd()
|
|
136
|
+
const { results } = mergeMcpConfig(cwd, { dryRun: true })
|
|
137
|
+
assert.ok(results.every((r) => r.action === 'created' && r.dryRun))
|
|
138
|
+
assert.throws(() => readFileSync(join(cwd, '.cursor', 'mcp.json')), /ENOENT/)
|
|
139
|
+
assert.throws(() => readFileSync(join(cwd, '.mcp.json')), /ENOENT/)
|
|
140
|
+
})
|
|
141
|
+
})
|