@worldresources/wri-design-systems 2.191.8 → 2.191.10-alpha-ds-cli
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/README.md +35 -1
- package/agents/AGENTS.md +221 -0
- package/agents/setup-ai.mjs +218 -0
- package/agents/setup-ai.sh +146 -0
- package/bin/ds.js +60 -0
- package/dist/index.cjs.js +250 -250
- package/dist/index.esm.js +203 -203
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -34,6 +34,40 @@ npm i @chakra-ui/react @emotion/react
|
|
|
34
34
|
|
|
35
35
|
## Usage
|
|
36
36
|
|
|
37
|
+
### Set up AI tooling
|
|
38
|
+
|
|
39
|
+
Run the DS CLI to set up AI tooling for this design system in your project root (the directory where you run the command).
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
ds setup-ai
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This will:
|
|
46
|
+
|
|
47
|
+
- Install / update AI instruction files (these may be overwritten):
|
|
48
|
+
- `AGENTS.md` content distributed as: `CLAUDE.md`, `GEMINI.md`, `.geminirules`
|
|
49
|
+
- Configure IDE integrations when detected:
|
|
50
|
+
- Cursor: writes `.cursor/rules` and creates `.cursor/mcp.json` (skips if it already exists)
|
|
51
|
+
- VS Code / GitHub Copilot: writes `copilot-instructions.md` and creates `.vscode/mcp.json` (skips if it already exists)
|
|
52
|
+
- Windsurf: writes `.windsurfrules`
|
|
53
|
+
- Cline: writes `.clinerules`
|
|
54
|
+
- Ensure a `.gitignore` block is present (creates `.gitignore` if missing; appends once and never duplicates):
|
|
55
|
+
- `CLAUDE.md`
|
|
56
|
+
- `.windsurfrules`
|
|
57
|
+
- `.clinerules`
|
|
58
|
+
- `copilot-instructions.md`
|
|
59
|
+
- `.cursor/rules`
|
|
60
|
+
- `.cursor/mcp.json`
|
|
61
|
+
- `.vscode/mcp.json`
|
|
62
|
+
- `GEMINI.md`
|
|
63
|
+
- `.geminirules`
|
|
64
|
+
|
|
65
|
+
Optional: run it against a specific path:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
ds setup-ai /path/to/your/project
|
|
69
|
+
```
|
|
70
|
+
|
|
37
71
|
### Create the Project Theme
|
|
38
72
|
|
|
39
73
|
With this custom theme you can change the color scheme according to your Project Theme
|
|
@@ -315,7 +349,7 @@ yarn lint-fix
|
|
|
315
349
|
yarn build
|
|
316
350
|
```
|
|
317
351
|
|
|
318
|
-
## Publish new version
|
|
352
|
+
## Publish new version (manual)
|
|
319
353
|
|
|
320
354
|
```
|
|
321
355
|
npm login
|
package/agents/AGENTS.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# AI Agent Instructions — WRI Design System
|
|
2
|
+
|
|
3
|
+
This file provides context for AI coding agents working on WRI projects.
|
|
4
|
+
It is the **canonical source of truth** — do not edit the IDE-specific copies directly.
|
|
5
|
+
The setup script distributes this file to the correct location for each IDE.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is the WRI Design System?
|
|
10
|
+
|
|
11
|
+
`@worldresources/wri-design-systems` is the **standard component library for all World Resources Institute products**. It is built on top of Chakra UI v3 and provides WRI-branded, pre-styled components shared across multiple projects.
|
|
12
|
+
|
|
13
|
+
Because the library ships its own styles and design tokens, **do not override component styles with custom CSS**. Visual consistency across products depends on this.
|
|
14
|
+
|
|
15
|
+
| Resource | URL |
|
|
16
|
+
| ----------------- | ------------------------------------------------------------------------ |
|
|
17
|
+
| Storybook | https://wri.github.io/wri-design-systems/ |
|
|
18
|
+
| GitHub repo | https://github.com/wri/wri-design-systems |
|
|
19
|
+
| GitHub README | https://github.com/wri/wri-design-systems#readme |
|
|
20
|
+
| Component READMEs | `src/components/<Category>/<ComponentName>/README.md` in the GitHub repo |
|
|
21
|
+
| npm | https://www.npmjs.com/package/@worldresources/wri-design-systems |
|
|
22
|
+
| Style guide | https://zeroheight.com/4221801da |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## MCP Servers
|
|
27
|
+
|
|
28
|
+
Two MCP servers are configured for this project. **Query them before writing any component code** — never assume props or token names from memory.
|
|
29
|
+
|
|
30
|
+
### Storybook MCP
|
|
31
|
+
|
|
32
|
+
Exposes WRI DS component stories, props, and usage patterns directly from the hosted Storybook.
|
|
33
|
+
Use it to verify: which WRI DS components exist, their props, and documented usage examples.
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"wri-storybook": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "storybook-mcp@latest"],
|
|
41
|
+
"env": {
|
|
42
|
+
"STORYBOOK_URL": "https://wri.github.io/wri-design-systems/index.json"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Chakra UI MCP
|
|
50
|
+
|
|
51
|
+
Exposes Chakra UI v3 component props, design tokens, and migration guidance.
|
|
52
|
+
Use it as fallback when a component is not in the WRI DS.
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"chakra-ui": {
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["-y", "@chakra-ui/react-mcp"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
> **Note:** The project setup script configures both MCP servers automatically.
|
|
66
|
+
> Run it once after cloning — see the README for instructions.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Component Hierarchy — Never Skip a Level
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
1. @worldresources/wri-design-systems — always check first
|
|
74
|
+
2. @chakra-ui/react — fallback only
|
|
75
|
+
3. Custom code — last resort; add justification comment
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Level 1 — WRI Design System
|
|
79
|
+
|
|
80
|
+
Check the [Storybook](https://wri.github.io/wri-design-systems/) or query the Storybook MCP first. For detailed props and usage notes, also check the component's individual README in the [GitHub repo](https://github.com/wri/wri-design-systems) at `src/components/<Category>/<ComponentName>/README.md` — for example: [`Panel/README.md`](https://github.com/wri/wri-design-systems/blob/main/src/components/Containers/Panel/README.md).
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// ✅ Correct
|
|
84
|
+
import { Button } from '@worldresources/wri-design-systems'
|
|
85
|
+
;<Button variant='primary'>Save</Button>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Level 2 — Chakra UI (fallback only)
|
|
89
|
+
|
|
90
|
+
Only use Chakra directly if there is **no WRI DS equivalent**. Use the Chakra MCP to verify props — do not rely on memory. Chakra v3 has breaking changes from v2.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// ✅ Acceptable — no WRI DS equivalent exists
|
|
94
|
+
import { Skeleton } from '@chakra-ui/react'
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Level 3 — Custom Code (last resort)
|
|
98
|
+
|
|
99
|
+
When neither the WRI DS nor Chakra covers the use case, you **must**:
|
|
100
|
+
|
|
101
|
+
1. Add a `// [CUSTOM COMPONENT]` comment on the line above the definition.
|
|
102
|
+
This is a searchable marker — find all custom components with "Find in Files" → `[CUSTOM COMPONENT]`.
|
|
103
|
+
2. Add a brief justification explaining why no DS or Chakra component was used.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
// [CUSTOM COMPONENT] — No WRI DS or Chakra equivalent for map tooltip overlay
|
|
107
|
+
const MapTooltip = ({ lat, lng, children }: MapTooltipProps) => {
|
|
108
|
+
...
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Design Tokens
|
|
115
|
+
|
|
116
|
+
WRI DS tokens are defined as Chakra semantic tokens. **Never hardcode values** that have a token equivalent.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
// ❌ Wrong — hardcoded colour
|
|
120
|
+
<Box bg="#2C7D6E" />
|
|
121
|
+
|
|
122
|
+
// ✅ Correct — semantic token
|
|
123
|
+
<Box bg="brand.primary" />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If unsure what tokens exist, use the Chakra MCP (`get_theme`) or check the [style guide](https://zeroheight.com/4221801da).
|
|
127
|
+
|
|
128
|
+
### Color Palette — Authoritative Source
|
|
129
|
+
|
|
130
|
+
The project's `ChakraProvider` in `src/components/Providers/index.tsx` is the **single source of truth for all color overrides** in this project. Before suggesting or using any color token, read that file to see which palette scales are defined and what values they map to.
|
|
131
|
+
|
|
132
|
+
**Do not invent, assume, or guess color token names or values.** The provider only extends the following palette scales:
|
|
133
|
+
|
|
134
|
+
| Scale | Defined steps / tokens | Notes |
|
|
135
|
+
| ------------ | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `neutral` | 100, 200, 300, 400, 500, 600, 700, 800, 900 | Overrides Chakra defaults |
|
|
137
|
+
| `primary` | 100, 200, 300, 400, 500, 600, 700, 800, 900 | Overrides Chakra defaults |
|
|
138
|
+
| `secondary` | 100, 200, 300, 400, 500, 600, 700, 800, 900 | Overrides Chakra defaults |
|
|
139
|
+
| `success` | 100, 200, 300, 500, 900 | Falls back to WRI DS `designSystemStyles` |
|
|
140
|
+
| `warning` | 100, 200, 300, 500, 900 | Falls back to WRI DS `designSystemStyles` |
|
|
141
|
+
| `error` | 100, 200, 300, 500, 900 | Falls back to WRI DS `designSystemStyles` |
|
|
142
|
+
| `accessible` | 'text-on-primary-mids', 'text-on-secondary-mids', 'controls-on-neutral-lights', 'controls-on-neutral-darks' | Use repo-defined keys (for example `text-on-primary-mids`) from WRI DS `designSystemStyles` |
|
|
143
|
+
|
|
144
|
+
For scales not overridden, and for named token sets such as `accessible`, values come from the WRI DS `designSystemStyles` system context — **do not guess these values**. Query the Storybook MCP to verify what values are available. In particular, do not call `getThemedColor('accessible', 100)`; use the actual string token key defined by the design system.
|
|
145
|
+
|
|
146
|
+
### How to Use Color Tokens — `getThemedColor`
|
|
147
|
+
|
|
148
|
+
Colors must always be accessed via `getThemedColor` exported from `@worldresources/wri-design-systems`. **Never use raw token strings as JSX prop values.**
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { getThemedColor } from "@worldresources/wri-design-systems";
|
|
152
|
+
|
|
153
|
+
// ❌ Wrong — raw token string
|
|
154
|
+
<Box bg="primary.500" />
|
|
155
|
+
|
|
156
|
+
// ✅ Correct — use getThemedColor
|
|
157
|
+
<Box bg={getThemedColor('primary', 500)} />
|
|
158
|
+
<Box color={getThemedColor('neutral', 300)} />
|
|
159
|
+
<Box borderColor={getThemedColor('success', 500)} />
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Full function signature:**
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
getThemedColor(
|
|
166
|
+
variant: "neutral" | "primary" | "secondary" | "success" | "warning" | "error" | "accessible",
|
|
167
|
+
index:
|
|
168
|
+
| 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
|
|
169
|
+
| "text-on-primary-mids"
|
|
170
|
+
| "text-on-secondary-mids"
|
|
171
|
+
| "controls-on-neutral-lights"
|
|
172
|
+
| "controls-on-neutral-darks"
|
|
173
|
+
): string
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Rules:**
|
|
177
|
+
|
|
178
|
+
- Only call `getThemedColor` with a `variant`/`index` combination that is confirmed to exist.
|
|
179
|
+
- For overridden scales (`neutral`, `primary`, `secondary`), valid steps are listed in the table above.
|
|
180
|
+
- For non-overridden scales (`success`, `warning`, `error`, `accessible`), query the Storybook MCP before using any step — do not assume which steps are defined.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## What NOT to Do
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
// ❌ Do not use a Chakra component that the WRI DS already wraps
|
|
188
|
+
import { Button } from "@chakra-ui/react" // → use WRI DS Button
|
|
189
|
+
|
|
190
|
+
// ❌ Do not override WRI DS styles
|
|
191
|
+
<Button sx={{ backgroundColor: "red" }}>Delete</Button>
|
|
192
|
+
|
|
193
|
+
// ❌ Do not hardcode design values
|
|
194
|
+
<Text fontSize="14px" color="#333333">Label</Text>
|
|
195
|
+
|
|
196
|
+
// ❌ Do not use raw token strings as color props — always use getThemedColor
|
|
197
|
+
<Box bg="primary.500" /> // → use getThemedColor('primary', 500)
|
|
198
|
+
|
|
199
|
+
// ❌ Do not create custom components without the searchable marker
|
|
200
|
+
const MyButton = () => <button style={{ background: "blue" }}>Click</button>
|
|
201
|
+
|
|
202
|
+
// ❌ Do not skip the hierarchy — always check WRI DS and Chakra before going custom
|
|
203
|
+
|
|
204
|
+
// ❌ Do not use Chakra v2 API — v3 has breaking changes (e.g. colorScheme is removed)
|
|
205
|
+
// Always verify props via the Chakra MCP
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Quick Reference
|
|
211
|
+
|
|
212
|
+
| Question | Where to look |
|
|
213
|
+
| --------------------------------------------- | -------------------------------------------------------------------------- |
|
|
214
|
+
| Does a WRI DS component exist? | [Storybook](https://wri.github.io/wri-design-systems/) or Storybook MCP |
|
|
215
|
+
| Detailed props / usage for a WRI DS component | Component README in GitHub: `src/components/<Category>/<Name>/README.md` |
|
|
216
|
+
| What props does a Chakra component accept? | Chakra MCP → `get_component_props` |
|
|
217
|
+
| What design tokens are available? | Chakra MCP → `get_theme` or [Zeroheight](https://zeroheight.com/4221801da) |
|
|
218
|
+
| Which color scales/steps are overridden here? | Read `src/components/Providers/index.tsx` — that is the source of truth |
|
|
219
|
+
| Which steps exist for non-overridden scales? | Query Storybook MCP — do not guess |
|
|
220
|
+
| How do I use a color in JSX? | `getThemedColor('scale', step)` from `@worldresources/wri-design-systems` |
|
|
221
|
+
| Where are all custom components in this repo? | "Find in Files" → `[CUSTOM COMPONENT]` |
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/setup-ai.js — WRI Design System AI Setup
|
|
3
|
+
// Distributes AGENTS.md to the correct location for each detected IDE.
|
|
4
|
+
// Usage: yarn setup:ai
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
existsSync,
|
|
8
|
+
mkdirSync,
|
|
9
|
+
copyFileSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
readFileSync,
|
|
12
|
+
readdirSync,
|
|
13
|
+
} from 'fs'
|
|
14
|
+
import { join, dirname, relative, resolve } from 'path'
|
|
15
|
+
import { execSync } from 'child_process'
|
|
16
|
+
import { homedir } from 'os'
|
|
17
|
+
import { fileURLToPath } from 'url'
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
20
|
+
const SOURCE = join(__dirname, 'AGENTS.md')
|
|
21
|
+
// Where we write the setup files.
|
|
22
|
+
// Default is the repo root you're currently in when you run the CLI.
|
|
23
|
+
// You can optionally pass a target directory as argv[2].
|
|
24
|
+
const ROOT = resolve(process.argv[2] ?? process.cwd())
|
|
25
|
+
const HOME = homedir()
|
|
26
|
+
|
|
27
|
+
const installed = []
|
|
28
|
+
const skipped = []
|
|
29
|
+
|
|
30
|
+
console.log('\nWRI Design System — AI Setup')
|
|
31
|
+
console.log('==============================')
|
|
32
|
+
|
|
33
|
+
if (!existsSync(SOURCE)) {
|
|
34
|
+
console.error('❌ AGENTS.md not found at', SOURCE)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function installFile(dest, label) {
|
|
41
|
+
mkdirSync(dirname(dest), { recursive: true })
|
|
42
|
+
copyFileSync(SOURCE, dest)
|
|
43
|
+
installed.push(`${label} → ${relative(ROOT, dest)}`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function commandExists(cmd) {
|
|
47
|
+
try {
|
|
48
|
+
execSync(`command -v ${cmd}`, { stdio: 'ignore' })
|
|
49
|
+
return true
|
|
50
|
+
} catch {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function pathExists(...parts) {
|
|
56
|
+
return existsSync(join(...parts))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function dirContains(dir, substring) {
|
|
60
|
+
try {
|
|
61
|
+
return readdirSync(dir).some((f) => f.includes(substring))
|
|
62
|
+
} catch {
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function writeJSON(dest, label, content) {
|
|
68
|
+
if (existsSync(dest)) {
|
|
69
|
+
skipped.push(`${label} (already exists — skipped to avoid overwrite)`)
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
mkdirSync(dirname(dest), { recursive: true })
|
|
73
|
+
writeFileSync(dest, JSON.stringify(content, null, 2) + '\n')
|
|
74
|
+
installed.push(`${label} → ${relative(ROOT, dest)}`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function ensureGitignoreBlock() {
|
|
78
|
+
const gitignorePath = join(ROOT, '.gitignore')
|
|
79
|
+
const marker =
|
|
80
|
+
'# AI setup — generated by agents/setup-ai.js (npx ds setup-ai)'
|
|
81
|
+
const blockLines = [
|
|
82
|
+
marker,
|
|
83
|
+
'CLAUDE.md',
|
|
84
|
+
'.windsurfrules',
|
|
85
|
+
'.clinerules',
|
|
86
|
+
'copilot-instructions.md',
|
|
87
|
+
'.cursor/rules',
|
|
88
|
+
'.cursor/mcp.json',
|
|
89
|
+
'.vscode/mcp.json',
|
|
90
|
+
'GEMINI.md',
|
|
91
|
+
'.geminirules',
|
|
92
|
+
]
|
|
93
|
+
const block = blockLines.join('\n') + '\n'
|
|
94
|
+
|
|
95
|
+
if (!existsSync(gitignorePath)) {
|
|
96
|
+
writeFileSync(gitignorePath, block)
|
|
97
|
+
installed.push('.gitignore → .gitignore')
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const current = readFileSync(gitignorePath, 'utf8')
|
|
102
|
+
if (current.includes(marker)) {
|
|
103
|
+
skipped.push('.gitignore (block already present)')
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const prefix = current.endsWith('\n') ? '\n' : '\n\n'
|
|
108
|
+
writeFileSync(gitignorePath, current + prefix + block)
|
|
109
|
+
installed.push('.gitignore → .gitignore (appended)')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── MCP config objects ────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
const MCP_STORYBOOK_URL = 'https://wri.github.io/wri-design-systems/index.json'
|
|
115
|
+
|
|
116
|
+
const mcpCursor = {
|
|
117
|
+
mcpServers: {
|
|
118
|
+
'wri-storybook': {
|
|
119
|
+
command: 'npx',
|
|
120
|
+
args: ['-y', 'storybook-mcp@latest'],
|
|
121
|
+
env: { STORYBOOK_URL: MCP_STORYBOOK_URL },
|
|
122
|
+
},
|
|
123
|
+
'chakra-ui': {
|
|
124
|
+
command: 'npx',
|
|
125
|
+
args: ['-y', '@chakra-ui/react-mcp'],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const mcpVSCode = {
|
|
131
|
+
servers: {
|
|
132
|
+
'wri-storybook': {
|
|
133
|
+
type: 'stdio',
|
|
134
|
+
command: 'npx',
|
|
135
|
+
args: ['-y', 'storybook-mcp@latest'],
|
|
136
|
+
env: { STORYBOOK_URL: MCP_STORYBOOK_URL },
|
|
137
|
+
},
|
|
138
|
+
'chakra-ui': {
|
|
139
|
+
type: 'stdio',
|
|
140
|
+
command: 'npx',
|
|
141
|
+
args: ['-y', '@chakra-ui/react-mcp'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── IDE detection & file installation ────────────────────────────
|
|
147
|
+
|
|
148
|
+
// Claude Code — always write CLAUDE.md (Claude Code reads both AGENTS.md and CLAUDE.md)
|
|
149
|
+
installFile(join(ROOT, 'CLAUDE.md'), 'Claude Code')
|
|
150
|
+
|
|
151
|
+
// Gemini — always write GEMINI.md and .geminirules for Gemini-based agents
|
|
152
|
+
installFile(join(ROOT, 'GEMINI.md'), 'Gemini')
|
|
153
|
+
installFile(join(ROOT, '.geminirules'), 'Gemini (rules)')
|
|
154
|
+
|
|
155
|
+
// Cursor
|
|
156
|
+
const hasCursor =
|
|
157
|
+
pathExists(HOME, '.cursor') ||
|
|
158
|
+
pathExists('/Applications/Cursor.app') ||
|
|
159
|
+
commandExists('cursor')
|
|
160
|
+
|
|
161
|
+
if (hasCursor) {
|
|
162
|
+
installFile(join(ROOT, '.cursor', 'rules'), 'Cursor (rules)')
|
|
163
|
+
writeJSON(join(ROOT, '.cursor', 'mcp.json'), 'Cursor MCP config', mcpCursor)
|
|
164
|
+
} else {
|
|
165
|
+
skipped.push('Cursor (not detected)')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// GitHub Copilot / VS Code
|
|
169
|
+
const hasVSCode =
|
|
170
|
+
commandExists('code') ||
|
|
171
|
+
pathExists(HOME, '.vscode') ||
|
|
172
|
+
pathExists('/Applications/Visual Studio Code.app')
|
|
173
|
+
|
|
174
|
+
if (hasVSCode) {
|
|
175
|
+
installFile(
|
|
176
|
+
join(ROOT, '.github', 'copilot-instructions.md'),
|
|
177
|
+
'GitHub Copilot',
|
|
178
|
+
)
|
|
179
|
+
writeJSON(join(ROOT, '.vscode', 'mcp.json'), 'VS Code MCP config', mcpVSCode)
|
|
180
|
+
} else {
|
|
181
|
+
skipped.push('GitHub Copilot / VS Code (not detected)')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Windsurf
|
|
185
|
+
const hasWindsurf =
|
|
186
|
+
pathExists(HOME, '.codeium') ||
|
|
187
|
+
pathExists('/Applications/Windsurf.app') ||
|
|
188
|
+
commandExists('windsurf')
|
|
189
|
+
|
|
190
|
+
if (hasWindsurf) {
|
|
191
|
+
installFile(join(ROOT, '.windsurfrules'), 'Windsurf')
|
|
192
|
+
} else {
|
|
193
|
+
skipped.push('Windsurf (not detected)')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Cline (VS Code extension)
|
|
197
|
+
const hasCline = dirContains(join(HOME, '.vscode', 'extensions'), 'cline')
|
|
198
|
+
|
|
199
|
+
if (hasCline) {
|
|
200
|
+
installFile(join(ROOT, '.clinerules'), 'Cline')
|
|
201
|
+
} else {
|
|
202
|
+
skipped.push('Cline (not detected)')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
ensureGitignoreBlock()
|
|
206
|
+
|
|
207
|
+
// ── Summary ───────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
console.log('\n✅ Installed:')
|
|
210
|
+
installed.forEach((item) => console.log(' ', item))
|
|
211
|
+
|
|
212
|
+
if (skipped.length) {
|
|
213
|
+
console.log('\n⏭ Skipped:')
|
|
214
|
+
skipped.forEach((item) => console.log(' ', item))
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
console.log('\nDone. Your AI tools now have full WRI Design System context.')
|
|
218
|
+
console.log('Storybook: https://wri.github.io/wri-design-systems/\n')
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# setup-ai.sh — WRI Design System AI Setup
|
|
3
|
+
# Distributes AGENTS.md to the correct location for each detected IDE.
|
|
4
|
+
# Run once after cloning: bash setup-ai.sh
|
|
5
|
+
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
SOURCE="$SCRIPT_DIR/AGENTS.md"
|
|
10
|
+
INSTALLED=()
|
|
11
|
+
SKIPPED=()
|
|
12
|
+
|
|
13
|
+
echo ""
|
|
14
|
+
echo "WRI Design System — AI Setup"
|
|
15
|
+
echo "=============================="
|
|
16
|
+
|
|
17
|
+
if [ ! -f "$SOURCE" ]; then
|
|
18
|
+
echo "❌ AGENTS.md not found at $SCRIPT_DIR"
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
install_file() {
|
|
23
|
+
local dest="$1"
|
|
24
|
+
local label="$2"
|
|
25
|
+
local dir
|
|
26
|
+
dir="$(dirname "$dest")"
|
|
27
|
+
mkdir -p "$dir"
|
|
28
|
+
cp "$SOURCE" "$dest"
|
|
29
|
+
INSTALLED+=("$label → $dest")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# ── Claude Code / Codex ────────────────────────────────────────
|
|
33
|
+
# AGENTS.md is already the source file in this directory — no copy needed.
|
|
34
|
+
# CLAUDE.md is a copy for Claude Code (reads both AGENTS.md and CLAUDE.md).
|
|
35
|
+
install_file "$SCRIPT_DIR/CLAUDE.md" "Claude Code (CLAUDE.md)"
|
|
36
|
+
|
|
37
|
+
# ── Gemini ─────────────────────────────────────────────────────
|
|
38
|
+
install_file "$SCRIPT_DIR/GEMINI.md" "Gemini"
|
|
39
|
+
install_file "$SCRIPT_DIR/.geminirules" "Gemini (rules)"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ── Cursor ─────────────────────────────────────────────────────
|
|
43
|
+
if [ -d "$HOME/.cursor" ] || [ -d "/Applications/Cursor.app" ] || command -v cursor &>/dev/null; then
|
|
44
|
+
install_file "$SCRIPT_DIR/.cursor/rules" "Cursor"
|
|
45
|
+
else
|
|
46
|
+
SKIPPED+=("Cursor (not detected)")
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# ── GitHub Copilot (VS Code) ────────────────────────────────────
|
|
50
|
+
if command -v code &>/dev/null; then
|
|
51
|
+
install_file "$SCRIPT_DIR/.github/copilot-instructions.md" "GitHub Copilot / VS Code"
|
|
52
|
+
else
|
|
53
|
+
SKIPPED+=("GitHub Copilot (VS Code not detected)")
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# ── Windsurf ───────────────────────────────────────────────────
|
|
57
|
+
if [ -d "$HOME/.codeium" ] || [ -d "/Applications/Windsurf.app" ] || command -v windsurf &>/dev/null; then
|
|
58
|
+
install_file "$SCRIPT_DIR/.windsurfrules" "Windsurf"
|
|
59
|
+
else
|
|
60
|
+
SKIPPED+=("Windsurf (not detected)")
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# ── Cline (VS Code extension) ──────────────────────────────────
|
|
64
|
+
if [ -d "$HOME/.vscode/extensions" ] && ls "$HOME/.vscode/extensions" | grep -q "cline"; then
|
|
65
|
+
install_file "$SCRIPT_DIR/.clinerules" "Cline"
|
|
66
|
+
else
|
|
67
|
+
SKIPPED+=("Cline (not detected)")
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# ── MCP config — .vscode/mcp.json (Copilot) ───────────────────
|
|
71
|
+
if command -v code &>/dev/null; then
|
|
72
|
+
MCP_VSCODE="$SCRIPT_DIR/.vscode/mcp.json"
|
|
73
|
+
if [ ! -f "$MCP_VSCODE" ]; then
|
|
74
|
+
mkdir -p "$SCRIPT_DIR/.vscode"
|
|
75
|
+
cat > "$MCP_VSCODE" << 'EOF'
|
|
76
|
+
{
|
|
77
|
+
"servers": {
|
|
78
|
+
"wri-storybook": {
|
|
79
|
+
"type": "stdio",
|
|
80
|
+
"command": "npx",
|
|
81
|
+
"args": ["-y", "storybook-mcp@latest"],
|
|
82
|
+
"env": {
|
|
83
|
+
"STORYBOOK_URL": "https://wri.github.io/wri-design-systems/index.json"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"chakra-ui": {
|
|
87
|
+
"type": "stdio",
|
|
88
|
+
"command": "npx",
|
|
89
|
+
"args": ["-y", "@chakra-ui/react-mcp"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
EOF
|
|
94
|
+
INSTALLED+=("MCP config → .vscode/mcp.json")
|
|
95
|
+
else
|
|
96
|
+
SKIPPED+=("MCP .vscode/mcp.json (already exists — skipped to avoid overwrite)")
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# ── MCP config — .cursor/mcp.json ─────────────────────────────
|
|
101
|
+
if [ -d "$HOME/.cursor" ] || [ -d "/Applications/Cursor.app" ] || command -v cursor &>/dev/null; then
|
|
102
|
+
MCP_CURSOR="$SCRIPT_DIR/.cursor/mcp.json"
|
|
103
|
+
if [ ! -f "$MCP_CURSOR" ]; then
|
|
104
|
+
mkdir -p "$SCRIPT_DIR/.cursor"
|
|
105
|
+
cat > "$MCP_CURSOR" << 'EOF'
|
|
106
|
+
{
|
|
107
|
+
"mcpServers": {
|
|
108
|
+
"wri-storybook": {
|
|
109
|
+
"command": "npx",
|
|
110
|
+
"args": ["-y", "storybook-mcp@latest"],
|
|
111
|
+
"env": {
|
|
112
|
+
"STORYBOOK_URL": "https://wri.github.io/wri-design-systems/index.json"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"chakra-ui": {
|
|
116
|
+
"command": "npx",
|
|
117
|
+
"args": ["-y", "@chakra-ui/react-mcp"]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
EOF
|
|
122
|
+
INSTALLED+=("MCP config → .cursor/mcp.json")
|
|
123
|
+
else
|
|
124
|
+
SKIPPED+=("MCP .cursor/mcp.json (already exists — skipped to avoid overwrite)")
|
|
125
|
+
fi
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
# ── Summary ────────────────────────────────────────────────────
|
|
129
|
+
echo ""
|
|
130
|
+
echo "✅ Installed:"
|
|
131
|
+
for item in "${INSTALLED[@]}"; do
|
|
132
|
+
echo " $item"
|
|
133
|
+
done
|
|
134
|
+
|
|
135
|
+
if [ ${#SKIPPED[@]} -gt 0 ]; then
|
|
136
|
+
echo ""
|
|
137
|
+
echo "⏭ Skipped:"
|
|
138
|
+
for item in "${SKIPPED[@]}"; do
|
|
139
|
+
echo " $item"
|
|
140
|
+
done
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
echo ""
|
|
144
|
+
echo "Done. Your AI tools now have full WRI Design System context."
|
|
145
|
+
echo "Storybook: https://wri.github.io/wri-design-systems/"
|
|
146
|
+
echo ""
|
package/bin/ds.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require('child_process')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
function printHelp() {
|
|
7
|
+
// Keep output minimal and CLI-friendly.
|
|
8
|
+
console.log(`WRI Design Systems CLI
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
ds setup-ai
|
|
12
|
+
ds setup-ai <target-path>
|
|
13
|
+
`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function runSetupAI(targetPath) {
|
|
17
|
+
const scriptPath = path.join(__dirname, '..', 'agents', 'setup-ai.mjs')
|
|
18
|
+
|
|
19
|
+
const result = spawnSync(
|
|
20
|
+
process.execPath,
|
|
21
|
+
targetPath ? [scriptPath, targetPath] : [scriptPath],
|
|
22
|
+
{
|
|
23
|
+
stdio: 'inherit',
|
|
24
|
+
cwd: process.cwd(),
|
|
25
|
+
env: process.env,
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
process.exit(result.status ?? 1)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const [, , command, ...rest] = process.argv
|
|
33
|
+
|
|
34
|
+
if (!command || command === '-h' || command === '--help') {
|
|
35
|
+
printHelp()
|
|
36
|
+
process.exit(0)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (command === 'setup-ai') {
|
|
40
|
+
if (rest.includes('-h') || rest.includes('--help')) {
|
|
41
|
+
printHelp()
|
|
42
|
+
process.exit(0)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (rest.length === 0) {
|
|
46
|
+
runSetupAI(null)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (rest.length === 1) {
|
|
50
|
+
runSetupAI(rest[0])
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.error('Too many arguments for setup-ai')
|
|
54
|
+
printHelp()
|
|
55
|
+
process.exit(1)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.error(`Unknown command: ${command}`)
|
|
59
|
+
printHelp()
|
|
60
|
+
process.exit(1)
|