@noemuch/bridge-ds 2.0.0
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 +147 -0
- package/bin/bridge.js +4 -0
- package/commands/design-workflow.md +1 -0
- package/lib/cli.js +172 -0
- package/lib/mcp-setup.js +47 -0
- package/lib/scaffold.js +120 -0
- package/package.json +39 -0
- package/skills/design-workflow/SKILL.md +205 -0
- package/skills/design-workflow/references/actions/design.md +207 -0
- package/skills/design-workflow/references/actions/done.md +48 -0
- package/skills/design-workflow/references/actions/drop.md +38 -0
- package/skills/design-workflow/references/actions/review.md +149 -0
- package/skills/design-workflow/references/actions/spec.md +128 -0
- package/skills/design-workflow/references/figma-api-rules.md +453 -0
- package/skills/design-workflow/references/knowledge-base/README.md +52 -0
- package/skills/design-workflow/references/onboarding.md +351 -0
- package/skills/design-workflow/references/quality-gates.md +127 -0
- package/skills/design-workflow/references/templates/screen-template.md +127 -0
- package/skills/design-workflow/references/templates/spec-template.md +171 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Noe Chague
|
|
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
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Bridge DS
|
|
2
|
+
|
|
3
|
+
AI-powered design generation in Figma — 100% design system compliant.
|
|
4
|
+
|
|
5
|
+
Bridge turns [Claude Code](https://claude.ai/download) into a designer that knows your design system inside out. It extracts, documents, and uses your real Figma components, tokens, and text styles to generate production-ready designs.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
You describe what you want
|
|
9
|
+
→ Claude consults the knowledge base (your DS, documented)
|
|
10
|
+
→ Claude writes the spec (exact components, tokens, layout)
|
|
11
|
+
→ Claude generates in Figma via figma_execute (real DS components, bound variables)
|
|
12
|
+
→ You review in Figma
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## How it works
|
|
16
|
+
|
|
17
|
+
Bridge is two things:
|
|
18
|
+
|
|
19
|
+
1. **A CLI** (`bridge-ds init`) that scaffolds your project with the design workflow skill
|
|
20
|
+
2. **A Claude Code skill** (`/design-workflow`) that handles the intelligence — spec writing, DS knowledge, Figma generation
|
|
21
|
+
|
|
22
|
+
The transport layer is [figma-console-mcp](https://github.com/southleft/figma-console-mcp), an MCP server that gives Claude native access to Figma (57+ tools).
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Claude Code ──MCP──> figma-console-mcp ──WebSocket──> Figma Desktop
|
|
26
|
+
(your DS library,
|
|
27
|
+
real components,
|
|
28
|
+
bound variables)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Prerequisites
|
|
32
|
+
|
|
33
|
+
- [Claude Code](https://claude.ai/download) installed
|
|
34
|
+
- [Node.js 18+](https://nodejs.org)
|
|
35
|
+
- [Figma Desktop](https://www.figma.com/downloads/) (not the web app)
|
|
36
|
+
- A Figma file with a published design system library
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Install figma-console-mcp
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
claude mcp add figma-console -s user \
|
|
44
|
+
-e FIGMA_ACCESS_TOKEN=figd_YOUR_TOKEN \
|
|
45
|
+
-- npx -y figma-console-mcp@latest
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Get your token from [Figma Settings → Personal access tokens](https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens).
|
|
49
|
+
|
|
50
|
+
### 2. Connect Figma Desktop
|
|
51
|
+
|
|
52
|
+
1. Run `npx figma-console-mcp@latest --print-path` to find the plugin directory
|
|
53
|
+
2. In Figma Desktop: **Plugins → Development → Import plugin from manifest...**
|
|
54
|
+
3. Select `figma-desktop-bridge/manifest.json`
|
|
55
|
+
4. Run the plugin in your Figma file
|
|
56
|
+
|
|
57
|
+
### 3. Initialize your project
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd your-project
|
|
61
|
+
npx @noemuch/bridge-ds init
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This scaffolds:
|
|
65
|
+
- `.claude/skills/design-workflow/` — the workflow skill + references
|
|
66
|
+
- `.claude/commands/design-workflow.md` — the `/design-workflow` slash command
|
|
67
|
+
- `specs/` — directory for active, shipped, and dropped specs
|
|
68
|
+
|
|
69
|
+
### 4. Build your knowledge base
|
|
70
|
+
|
|
71
|
+
Open Claude Code in your project:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
/design-workflow setup
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Claude will:
|
|
78
|
+
1. Extract your entire DS from Figma (`figma_get_design_system_kit`)
|
|
79
|
+
2. Analyze every component, token, and style
|
|
80
|
+
3. Generate intelligent guides (when to use what, decision trees, pattern catalog)
|
|
81
|
+
4. Ask for product screenshots to document layout patterns
|
|
82
|
+
|
|
83
|
+
### 5. Start designing
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
/design-workflow spec a settings page for account information
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Claude consults the knowledge base, identifies the right pattern, components, and tokens, and writes a complete spec. Then:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
/design-workflow design # Generate in Figma (atomic, verified)
|
|
93
|
+
/design-workflow review # Validate against spec
|
|
94
|
+
/design-workflow done # Archive and ship
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## The Workflow
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
setup (once) → spec → design → review → done
|
|
101
|
+
↑ |
|
|
102
|
+
└── iterate ─────────┘
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Spec-first
|
|
106
|
+
No design without a validated specification. Claude knows exactly which components, tokens, and layout patterns to use because it has your DS documented.
|
|
107
|
+
|
|
108
|
+
### Atomic generation
|
|
109
|
+
Designs are generated in 4-6 small sequential scripts (~30-80 lines each). After each step, Claude takes a screenshot and verifies before continuing. Bug in step 3? Fix and re-run step 3 only.
|
|
110
|
+
|
|
111
|
+
### DS-native
|
|
112
|
+
Zero hardcoded hex colors. Zero recreated components. Everything imported from your library via `importComponentByKeyAsync`, bound to variables via `setBoundVariableForPaint`.
|
|
113
|
+
|
|
114
|
+
### Quality gates
|
|
115
|
+
Blocking checks at every phase transition: spec validation, pattern matching, pre-script element audit, visual fidelity review, DS component reuse audit.
|
|
116
|
+
|
|
117
|
+
## Knowledge Base
|
|
118
|
+
|
|
119
|
+
The knowledge base is what makes Bridge different from "just executing Figma scripts". During setup, Claude builds a complete understanding of your DS:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
knowledge-base/
|
|
123
|
+
registries/ ← Raw DS data (components, variables, text styles)
|
|
124
|
+
guides/
|
|
125
|
+
design-patterns.md ← Layout patterns from your product screenshots
|
|
126
|
+
tokens/ ← When to use which color, spacing, typography
|
|
127
|
+
components/ ← Decision tree: "I need X" → use component Y
|
|
128
|
+
patterns/ ← Form, navigation, feedback, multi-step patterns
|
|
129
|
+
assets/ ← Icons, logos, illustrations catalog
|
|
130
|
+
ui-references/ ← Product screenshots for pattern extraction
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Commands
|
|
134
|
+
|
|
135
|
+
| Command | What it does |
|
|
136
|
+
|---------|-------------|
|
|
137
|
+
| `/design-workflow setup` | Extract DS + build knowledge base |
|
|
138
|
+
| `/design-workflow spec {name}` | Write a component or screen spec |
|
|
139
|
+
| `/design-workflow design` | Generate in Figma from active spec |
|
|
140
|
+
| `/design-workflow review` | Validate design against spec + tokens |
|
|
141
|
+
| `/design-workflow done` | Archive spec and ship |
|
|
142
|
+
| `/design-workflow drop` | Abandon with preserved learnings |
|
|
143
|
+
| `/design-workflow status` | Show current state, suggest next action |
|
|
144
|
+
|
|
145
|
+
## License
|
|
146
|
+
|
|
147
|
+
MIT
|
package/bin/bridge.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Read and follow the skill defined in `.claude/skills/design-workflow/SKILL.md`.
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { scaffold } = require('./scaffold');
|
|
3
|
+
const { checkMcp, setupMcp } = require('./mcp-setup');
|
|
4
|
+
|
|
5
|
+
// ── Branding ──────────────────────────────────────────────
|
|
6
|
+
const C = {
|
|
7
|
+
reset: '\x1b[0m',
|
|
8
|
+
bold: '\x1b[1m',
|
|
9
|
+
dim: '\x1b[2m',
|
|
10
|
+
orange: '\x1b[38;2;237;112;46m',
|
|
11
|
+
green: '\x1b[38;2;76;175;80m',
|
|
12
|
+
red: '\x1b[38;2;244;67;54m',
|
|
13
|
+
yellow: '\x1b[38;2;255;193;7m',
|
|
14
|
+
gray: '\x1b[38;2;158;158;158m',
|
|
15
|
+
white: '\x1b[38;2;255;255;255m',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function print(msg = '') { process.stdout.write(msg + '\n'); }
|
|
19
|
+
function header(msg) { print(`\n${C.orange}${C.bold}🧱 ${msg}${C.reset}\n`); }
|
|
20
|
+
function success(msg) { print(`${C.green} ✓ ${msg}${C.reset}`); }
|
|
21
|
+
function info(msg) { print(`${C.white} ℹ ${msg}${C.reset}`); }
|
|
22
|
+
function warn(msg) { print(`${C.yellow} ⚠ ${msg}${C.reset}`); }
|
|
23
|
+
function error(msg) { print(`${C.red} ✗ ${msg}${C.reset}`); }
|
|
24
|
+
function muted(msg) { print(`${C.gray} ${msg}${C.reset}`); }
|
|
25
|
+
function step(n, total, msg) { print(`${C.orange} [${n}/${total}]${C.reset} ${C.bold}${msg}${C.reset}`); }
|
|
26
|
+
|
|
27
|
+
// ── Spinner ───────────────────────────────────────────────
|
|
28
|
+
const FRAMES = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏'];
|
|
29
|
+
class Spinner {
|
|
30
|
+
constructor(msg) { this.msg = msg; this.i = 0; this.id = null; }
|
|
31
|
+
start() {
|
|
32
|
+
this.id = setInterval(() => {
|
|
33
|
+
process.stdout.write(`\r${C.orange} ${FRAMES[this.i++ % FRAMES.length]}${C.reset} ${this.msg}`);
|
|
34
|
+
}, 80);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
stop(result) {
|
|
38
|
+
clearInterval(this.id);
|
|
39
|
+
process.stdout.write('\r' + ' '.repeat(this.msg.length + 10) + '\r');
|
|
40
|
+
if (result) success(result);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ── ASCII Art ─────────────────────────────────────────────
|
|
45
|
+
function banner() {
|
|
46
|
+
print('');
|
|
47
|
+
print(`${C.orange}${C.bold} ┌──────────────────────────────────────┐${C.reset}`);
|
|
48
|
+
print(`${C.orange}${C.bold} │ 🧱 Bridge DS │${C.reset}`);
|
|
49
|
+
print(`${C.orange}${C.bold} │ AI-powered design in Figma │${C.reset}`);
|
|
50
|
+
print(`${C.orange}${C.bold} │ 100% design system compliant │${C.reset}`);
|
|
51
|
+
print(`${C.orange}${C.bold} └──────────────────────────────────────┘${C.reset}`);
|
|
52
|
+
print('');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ── Commands ──────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
async function cmdInit() {
|
|
58
|
+
banner();
|
|
59
|
+
header('Initializing Bridge DS');
|
|
60
|
+
|
|
61
|
+
const cwd = process.cwd();
|
|
62
|
+
const totalSteps = 4;
|
|
63
|
+
|
|
64
|
+
// Step 1: Check prerequisites
|
|
65
|
+
step(1, totalSteps, 'Checking prerequisites');
|
|
66
|
+
const nodeVersion = process.version.replace('v', '').split('.').map(Number);
|
|
67
|
+
if (nodeVersion[0] < 18) {
|
|
68
|
+
error(`Node.js 18+ required (found ${process.version})`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
success(`Node.js ${process.version}`);
|
|
72
|
+
|
|
73
|
+
// Step 2: Configure figma-console-mcp
|
|
74
|
+
step(2, totalSteps, 'Checking figma-console-mcp');
|
|
75
|
+
const mcpConfigured = checkMcp();
|
|
76
|
+
if (mcpConfigured) {
|
|
77
|
+
success('figma-console-mcp is configured');
|
|
78
|
+
} else {
|
|
79
|
+
warn('figma-console-mcp not found in Claude Code settings');
|
|
80
|
+
info('Run this command to add it:');
|
|
81
|
+
print('');
|
|
82
|
+
print(`${C.dim} claude mcp add figma-console -s user \\${C.reset}`);
|
|
83
|
+
print(`${C.dim} -e FIGMA_ACCESS_TOKEN=figd_YOUR_TOKEN \\${C.reset}`);
|
|
84
|
+
print(`${C.dim} -- npx -y figma-console-mcp@latest${C.reset}`);
|
|
85
|
+
print('');
|
|
86
|
+
info('Then re-run: bridge-ds init');
|
|
87
|
+
info('Continuing with file setup...');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Step 3: Scaffold project files
|
|
91
|
+
step(3, totalSteps, 'Scaffolding project files');
|
|
92
|
+
const spinner = new Spinner('Copying skills, commands, templates...').start();
|
|
93
|
+
const result = scaffold(cwd);
|
|
94
|
+
spinner.stop('Project files created');
|
|
95
|
+
|
|
96
|
+
for (const f of result.created) {
|
|
97
|
+
muted(f);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Step 4: Summary
|
|
101
|
+
step(4, totalSteps, 'Done!');
|
|
102
|
+
print('');
|
|
103
|
+
print(`${C.orange}${C.bold} ┌──────────────────────────────────────┐${C.reset}`);
|
|
104
|
+
print(`${C.orange}${C.bold} │ Setup complete! │${C.reset}`);
|
|
105
|
+
print(`${C.orange}${C.bold} │ │${C.reset}`);
|
|
106
|
+
print(`${C.orange}${C.bold} │ Next steps: │${C.reset}`);
|
|
107
|
+
print(`${C.orange}${C.bold} │ 1. Open Claude Code in this project │${C.reset}`);
|
|
108
|
+
print(`${C.orange}${C.bold} │ 2. Run: /design-workflow setup │${C.reset}`);
|
|
109
|
+
print(`${C.orange}${C.bold} │ → Extracts & documents your DS │${C.reset}`);
|
|
110
|
+
print(`${C.orange}${C.bold} │ 3. Run: /design-workflow spec ... │${C.reset}`);
|
|
111
|
+
print(`${C.orange}${C.bold} │ → Start designing! │${C.reset}`);
|
|
112
|
+
print(`${C.orange}${C.bold} └──────────────────────────────────────┘${C.reset}`);
|
|
113
|
+
print('');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function cmdHelp() {
|
|
117
|
+
banner();
|
|
118
|
+
print(`${C.bold} Commands:${C.reset}`);
|
|
119
|
+
print('');
|
|
120
|
+
print(` ${C.orange}init${C.reset} Initialize Bridge DS in current project`);
|
|
121
|
+
print(` Scaffolds skills, commands, and specs directories`);
|
|
122
|
+
print('');
|
|
123
|
+
print(` ${C.orange}help${C.reset} Show this help message`);
|
|
124
|
+
print(` ${C.orange}version${C.reset} Show version`);
|
|
125
|
+
print('');
|
|
126
|
+
print(`${C.bold} Usage:${C.reset}`);
|
|
127
|
+
print('');
|
|
128
|
+
print(` ${C.dim}npx bridge-ds init${C.reset} # Initialize in current project`);
|
|
129
|
+
print(` ${C.dim}bridge-ds help${C.reset} # Show help`);
|
|
130
|
+
print('');
|
|
131
|
+
print(`${C.bold} After init:${C.reset}`);
|
|
132
|
+
print('');
|
|
133
|
+
print(` ${C.dim}/design-workflow setup${C.reset} # Extract & document your DS (in Claude Code)`);
|
|
134
|
+
print(` ${C.dim}/design-workflow spec${C.reset} # Spec a component or screen`);
|
|
135
|
+
print(` ${C.dim}/design-workflow design${C.reset} # Generate in Figma`);
|
|
136
|
+
print(` ${C.dim}/design-workflow review${C.reset} # Validate against spec`);
|
|
137
|
+
print(` ${C.dim}/design-workflow done${C.reset} # Archive & ship`);
|
|
138
|
+
print('');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function cmdVersion() {
|
|
142
|
+
const pkg = require('../package.json');
|
|
143
|
+
print(`bridge-ds v${pkg.version}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── Router ────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
async function run(args) {
|
|
149
|
+
const cmd = args[0] || 'help';
|
|
150
|
+
|
|
151
|
+
switch (cmd) {
|
|
152
|
+
case 'init':
|
|
153
|
+
await cmdInit();
|
|
154
|
+
break;
|
|
155
|
+
case 'help':
|
|
156
|
+
case '--help':
|
|
157
|
+
case '-h':
|
|
158
|
+
cmdHelp();
|
|
159
|
+
break;
|
|
160
|
+
case 'version':
|
|
161
|
+
case '--version':
|
|
162
|
+
case '-v':
|
|
163
|
+
cmdVersion();
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
error(`Unknown command: ${cmd}`);
|
|
167
|
+
cmdHelp();
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = { run };
|
package/lib/mcp-setup.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if figma-console-mcp is configured in Claude Code settings.
|
|
7
|
+
* Checks multiple possible locations.
|
|
8
|
+
*/
|
|
9
|
+
function checkMcp() {
|
|
10
|
+
const locations = [
|
|
11
|
+
// User-level Claude Code settings
|
|
12
|
+
path.join(os.homedir(), '.claude.json'),
|
|
13
|
+
// Project-level settings
|
|
14
|
+
path.join(process.cwd(), '.claude', 'settings.local.json'),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
for (const loc of locations) {
|
|
18
|
+
if (fs.existsSync(loc)) {
|
|
19
|
+
try {
|
|
20
|
+
const content = JSON.parse(fs.readFileSync(loc, 'utf8'));
|
|
21
|
+
const servers = content.mcpServers || {};
|
|
22
|
+
// Check for any figma-console-mcp configuration
|
|
23
|
+
for (const [name, config] of Object.entries(servers)) {
|
|
24
|
+
if (name.includes('figma') && config.command) {
|
|
25
|
+
const args = (config.args || []).join(' ');
|
|
26
|
+
if (args.includes('figma-console-mcp')) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} catch (_) {
|
|
32
|
+
// Ignore parse errors
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Return the MCP add command for the user to run.
|
|
42
|
+
*/
|
|
43
|
+
function getMcpAddCommand() {
|
|
44
|
+
return 'claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=figd_YOUR_TOKEN -- npx -y figma-console-mcp@latest';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { checkMcp, getMcpAddCommand };
|
package/lib/scaffold.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Recursively copy a directory, preserving structure.
|
|
6
|
+
*/
|
|
7
|
+
function copyDir(src, dest) {
|
|
8
|
+
const created = [];
|
|
9
|
+
if (!fs.existsSync(dest)) {
|
|
10
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
13
|
+
const srcPath = path.join(src, entry.name);
|
|
14
|
+
const destPath = path.join(dest, entry.name);
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
created.push(...copyDir(srcPath, destPath));
|
|
17
|
+
} else {
|
|
18
|
+
fs.copyFileSync(srcPath, destPath);
|
|
19
|
+
created.push(destPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return created;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Scaffold Bridge DS into the target project directory.
|
|
27
|
+
* Returns { created: string[] } with relative paths of created files.
|
|
28
|
+
*/
|
|
29
|
+
function scaffold(projectDir) {
|
|
30
|
+
const created = [];
|
|
31
|
+
const pkgRoot = path.resolve(__dirname, '..');
|
|
32
|
+
|
|
33
|
+
// 1. Copy skills/design-workflow → .claude/skills/design-workflow
|
|
34
|
+
const skillsSrc = path.join(pkgRoot, 'skills', 'design-workflow');
|
|
35
|
+
const skillsDest = path.join(projectDir, '.claude', 'skills', 'design-workflow');
|
|
36
|
+
if (fs.existsSync(skillsSrc)) {
|
|
37
|
+
const files = copyDir(skillsSrc, skillsDest);
|
|
38
|
+
created.push(...files.map(f => path.relative(projectDir, f)));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 2. Copy commands/design-workflow.md → .claude/commands/design-workflow.md
|
|
42
|
+
const cmdSrc = path.join(pkgRoot, 'commands', 'design-workflow.md');
|
|
43
|
+
const cmdDest = path.join(projectDir, '.claude', 'commands', 'design-workflow.md');
|
|
44
|
+
if (fs.existsSync(cmdSrc)) {
|
|
45
|
+
fs.mkdirSync(path.dirname(cmdDest), { recursive: true });
|
|
46
|
+
fs.copyFileSync(cmdSrc, cmdDest);
|
|
47
|
+
created.push(path.relative(projectDir, cmdDest));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 3. Create specs/ directory structure
|
|
51
|
+
const specsDirs = [
|
|
52
|
+
'specs/active',
|
|
53
|
+
'specs/backlog',
|
|
54
|
+
'specs/shipped',
|
|
55
|
+
'specs/dropped',
|
|
56
|
+
];
|
|
57
|
+
for (const dir of specsDirs) {
|
|
58
|
+
const fullPath = path.join(projectDir, dir);
|
|
59
|
+
if (!fs.existsSync(fullPath)) {
|
|
60
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
61
|
+
// Add .gitkeep
|
|
62
|
+
const gitkeep = path.join(fullPath, '.gitkeep');
|
|
63
|
+
fs.writeFileSync(gitkeep, '');
|
|
64
|
+
created.push(path.relative(projectDir, gitkeep));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Create history.log if not exists
|
|
69
|
+
const historyLog = path.join(projectDir, 'specs', 'history.log');
|
|
70
|
+
if (!fs.existsSync(historyLog)) {
|
|
71
|
+
fs.writeFileSync(historyLog, '# Design History\n# date | name | type | figma_url | author\n');
|
|
72
|
+
created.push(path.relative(projectDir, historyLog));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 4. Create empty knowledge-base directories
|
|
76
|
+
const kbDirs = [
|
|
77
|
+
'.claude/skills/design-workflow/references/knowledge-base/registries',
|
|
78
|
+
'.claude/skills/design-workflow/references/knowledge-base/guides/tokens',
|
|
79
|
+
'.claude/skills/design-workflow/references/knowledge-base/guides/components',
|
|
80
|
+
'.claude/skills/design-workflow/references/knowledge-base/guides/patterns',
|
|
81
|
+
'.claude/skills/design-workflow/references/knowledge-base/guides/assets',
|
|
82
|
+
'.claude/skills/design-workflow/references/knowledge-base/ui-references/screenshots',
|
|
83
|
+
];
|
|
84
|
+
for (const dir of kbDirs) {
|
|
85
|
+
const fullPath = path.join(projectDir, dir);
|
|
86
|
+
if (!fs.existsSync(fullPath)) {
|
|
87
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
88
|
+
const gitkeep = path.join(fullPath, '.gitkeep');
|
|
89
|
+
if (!fs.existsSync(gitkeep)) {
|
|
90
|
+
fs.writeFileSync(gitkeep, '');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 5. Update .gitignore
|
|
96
|
+
const gitignorePath = path.join(projectDir, '.gitignore');
|
|
97
|
+
const gitignoreEntries = [
|
|
98
|
+
'',
|
|
99
|
+
'# Bridge DS — knowledge base data (regenerated via /design-workflow setup)',
|
|
100
|
+
'.claude/skills/design-workflow/references/knowledge-base/registries/*.json',
|
|
101
|
+
'.claude/skills/design-workflow/references/knowledge-base/ui-references/screenshots/*.png',
|
|
102
|
+
'.claude/skills/design-workflow/references/knowledge-base/ui-references/screenshots/*.jpg',
|
|
103
|
+
];
|
|
104
|
+
const gitignoreBlock = gitignoreEntries.join('\n') + '\n';
|
|
105
|
+
|
|
106
|
+
if (fs.existsSync(gitignorePath)) {
|
|
107
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
108
|
+
if (!content.includes('Bridge DS')) {
|
|
109
|
+
fs.appendFileSync(gitignorePath, gitignoreBlock);
|
|
110
|
+
created.push('.gitignore (updated)');
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
fs.writeFileSync(gitignorePath, 'node_modules/\n.DS_Store\n' + gitignoreBlock);
|
|
114
|
+
created.push('.gitignore');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { created };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = { scaffold };
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@noemuch/bridge-ds",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "AI-powered design generation in Figma — 100% design system compliant. Connects Claude Code to Figma via MCP for spec-first, token-bound, component-native design.",
|
|
5
|
+
"main": "lib/cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"bridge-ds": "./bin/bridge.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"lib/",
|
|
12
|
+
"skills/",
|
|
13
|
+
"commands/",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "node bin/bridge.js help"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"claude-code",
|
|
25
|
+
"figma",
|
|
26
|
+
"design-system",
|
|
27
|
+
"mcp",
|
|
28
|
+
"design-tokens",
|
|
29
|
+
"ai-design",
|
|
30
|
+
"figma-plugin-api"
|
|
31
|
+
],
|
|
32
|
+
"author": "noemuch",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/noemuch/bridge.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/noemuch/bridge"
|
|
39
|
+
}
|