@createlex/figma-swiftui-mcp 1.0.4 → 1.0.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.
@@ -13,16 +13,19 @@ function printHelp() {
13
13
  Usage:
14
14
  npx ${PACKAGE_NAME} login
15
15
  npx ${PACKAGE_NAME} start [--project /path/to/Xcode/source]
16
+ npx ${PACKAGE_NAME} setup [--force] [--dry-run]
16
17
 
17
18
  Commands:
18
19
  login Open the CreateLex browser login flow and save ~/.createlex/auth.json
19
20
  start Start the local figma-swiftui MCP runtime and localhost bridge
21
+ setup Auto-configure MCP in Cursor, Claude, VS Code, Windsurf, and more
20
22
  help Show this help message
21
23
  version Show the package version
22
24
 
23
25
  Examples:
24
26
  npx ${PACKAGE_NAME} login
25
27
  npx ${PACKAGE_NAME} start --project /Users/you/MyApp/MyApp
28
+ npx ${PACKAGE_NAME} setup
26
29
  npm install -g ${PACKAGE_NAME}
27
30
  ${CLI_NAME} start --project /Users/you/MyApp/MyApp
28
31
  `);
@@ -56,6 +59,24 @@ Description:
56
59
  return;
57
60
  }
58
61
 
62
+ if (command === 'setup') {
63
+ console.log(`${CLI_NAME} setup
64
+
65
+ Usage:
66
+ npx ${PACKAGE_NAME} setup [--force] [--dry-run]
67
+
68
+ Options:
69
+ --force Overwrite existing figma-swiftui config entries
70
+ --dry-run Show what would be configured without writing
71
+
72
+ Description:
73
+ Detects installed IDEs (Cursor, Claude Desktop, Claude Code, VS Code,
74
+ Windsurf, Antigravity) and adds the figma-swiftui MCP server entry
75
+ to each config file automatically.
76
+ `);
77
+ return;
78
+ }
79
+
59
80
  printHelp();
60
81
  }
61
82
 
@@ -104,6 +125,20 @@ switch (command) {
104
125
  }
105
126
  runNode(resolveEntry('start'), args);
106
127
  break;
128
+ case 'setup':
129
+ if (wantsHelp) {
130
+ printCommandHelp('setup');
131
+ break;
132
+ }
133
+ {
134
+ const { runSetup } = require(path.join(__dirname, '..', 'companion', 'setup.cjs'));
135
+ const flags = {
136
+ force: args.includes('--force'),
137
+ dryRun: args.includes('--dry-run'),
138
+ };
139
+ runSetup(flags);
140
+ }
141
+ break;
107
142
  case 'help':
108
143
  case '--help':
109
144
  case '-h':
@@ -0,0 +1,225 @@
1
+ /**
2
+ * figma-swiftui-mcp setup
3
+ *
4
+ * Auto-detect installed IDEs / CLI tools and add the figma-swiftui MCP
5
+ * server entry to each config file.
6
+ *
7
+ * Supported targets:
8
+ * - Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json)
9
+ * - Claude Code (~/.claude.json → mcpServers)
10
+ * - Cursor (~/.cursor/mcp.json)
11
+ * - Windsurf (~/.codeium/windsurf/mcp_config.json)
12
+ * - VS Code (~/.vscode/mcp.json — user-level)
13
+ * - Antigravity (~/.gemini/antigravity/mcp_config.json)
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const fs = require('node:fs');
19
+ const path = require('node:path');
20
+ const os = require('node:os');
21
+
22
+ const MCP_KEY = 'figma-swiftui';
23
+
24
+ // ── Resolve the absolute path to the bin script and node ─────────────
25
+ // IDEs (Cursor, VS Code, etc.) do NOT source shell profiles, so
26
+ // `#!/usr/bin/env node` fails when node is managed by nvm/fnm/volta.
27
+ // Instead we record the absolute node path and the bin script separately.
28
+ function resolvePaths() {
29
+ const nodePath = process.execPath; // absolute path to node binary
30
+
31
+ // Try to find the bin JS file
32
+ const binScript = process.argv[1];
33
+ if (binScript) {
34
+ const resolved = fs.realpathSync(binScript);
35
+ const dir = path.dirname(resolved);
36
+ // Check for the .js bin entry point
37
+ const jsCandidate = path.join(dir, 'figma-swiftui-mcp.js');
38
+ if (fs.existsSync(jsCandidate)) {
39
+ return { nodePath, scriptPath: jsCandidate };
40
+ }
41
+ // Check for the wrapper (symlink without .js)
42
+ const candidate = path.join(dir, 'figma-swiftui-mcp');
43
+ if (fs.existsSync(candidate)) {
44
+ // Resolve symlinks to get the actual .js file
45
+ const real = fs.realpathSync(candidate);
46
+ return { nodePath, scriptPath: real };
47
+ }
48
+ }
49
+
50
+ // Fallback: search PATH for the binary, then resolve to its .js source
51
+ const whichCmd = require('node:child_process')
52
+ .execSync('which figma-swiftui-mcp 2>/dev/null || true')
53
+ .toString()
54
+ .trim();
55
+ if (whichCmd) {
56
+ const real = fs.realpathSync(whichCmd);
57
+ return { nodePath, scriptPath: real };
58
+ }
59
+
60
+ // Last resort: use npx invocation
61
+ return { nodePath, scriptPath: null };
62
+ }
63
+
64
+ // ── Resolve absolute npx path for fallback ───────────────────────────
65
+ function resolveNpxPath() {
66
+ try {
67
+ const npxPath = require('node:child_process')
68
+ .execSync('which npx 2>/dev/null || true')
69
+ .toString()
70
+ .trim();
71
+ return npxPath || 'npx';
72
+ } catch {
73
+ return 'npx';
74
+ }
75
+ }
76
+
77
+ // ── IDE config definitions ────────────────────────────────────────────
78
+ function getTargets({ nodePath, scriptPath }) {
79
+ const home = os.homedir();
80
+
81
+ // Use absolute node path + script to avoid #!/usr/bin/env node failures
82
+ // in IDEs that don't source shell profiles (nvm/fnm/volta).
83
+ const stdioEntry = scriptPath
84
+ ? { command: nodePath, args: [scriptPath, 'start'] }
85
+ : { command: resolveNpxPath(), args: ['-y', '@createlex/figma-swiftui-mcp', 'start'] };
86
+
87
+ const stdioEntryWithType = { type: 'stdio', ...stdioEntry };
88
+
89
+ return [
90
+ {
91
+ name: 'Claude Desktop',
92
+ path: path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
93
+ key: 'mcpServers',
94
+ entry: stdioEntry,
95
+ },
96
+ {
97
+ name: 'Claude Code',
98
+ path: path.join(home, '.claude.json'),
99
+ key: 'mcpServers',
100
+ entry: stdioEntryWithType,
101
+ },
102
+ {
103
+ name: 'Cursor',
104
+ path: path.join(home, '.cursor', 'mcp.json'),
105
+ key: 'mcpServers',
106
+ entry: stdioEntry,
107
+ },
108
+ {
109
+ name: 'Windsurf',
110
+ path: path.join(home, '.codeium', 'windsurf', 'mcp_config.json'),
111
+ key: 'mcpServers',
112
+ entry: stdioEntry,
113
+ },
114
+ {
115
+ name: 'VS Code (user)',
116
+ path: path.join(home, '.vscode', 'mcp.json'),
117
+ key: 'servers',
118
+ entry: stdioEntry,
119
+ wrapKey: null, // VS Code uses { servers: { ... } } at top level
120
+ },
121
+ {
122
+ name: 'Antigravity (Gemini)',
123
+ path: path.join(home, '.gemini', 'antigravity', 'mcp_config.json'),
124
+ key: 'mcpServers',
125
+ entry: { ...stdioEntry, env: {}, disabled: false },
126
+ },
127
+ ];
128
+ }
129
+
130
+ // ── Read / write helpers ──────────────────────────────────────────────
131
+ function readJsonSafe(filePath) {
132
+ try {
133
+ const raw = fs.readFileSync(filePath, 'utf-8');
134
+ return JSON.parse(raw);
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+
140
+ function writeJsonSafe(filePath, data) {
141
+ const dir = path.dirname(filePath);
142
+ if (!fs.existsSync(dir)) {
143
+ fs.mkdirSync(dir, { recursive: true });
144
+ }
145
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
146
+ }
147
+
148
+ // ── Main ──────────────────────────────────────────────────────────────
149
+ function runSetup(flags = {}) {
150
+ const force = flags.force || false;
151
+ const dryRun = flags.dryRun || false;
152
+
153
+ const paths = resolvePaths();
154
+
155
+ console.log();
156
+ console.log(' 🔧 figma-swiftui-mcp setup');
157
+ console.log(' ─────────────────────────────────────');
158
+ console.log(` Node: ${paths.nodePath}`);
159
+ if (paths.scriptPath) {
160
+ console.log(` Script: ${paths.scriptPath}`);
161
+ } else {
162
+ console.log(' Script: not found — will use npx fallback');
163
+ }
164
+ console.log();
165
+
166
+ const targets = getTargets(paths);
167
+ let configured = 0;
168
+ let skipped = 0;
169
+ let notInstalled = 0;
170
+
171
+ for (const target of targets) {
172
+ const exists = fs.existsSync(target.path);
173
+
174
+ if (!exists) {
175
+ console.log(` ⚪ ${target.name} — not installed (${path.basename(target.path)} not found)`);
176
+ notInstalled++;
177
+ continue;
178
+ }
179
+
180
+ const config = readJsonSafe(target.path);
181
+ if (!config) {
182
+ console.log(` ⚠️ ${target.name} — could not parse config`);
183
+ skipped++;
184
+ continue;
185
+ }
186
+
187
+ // Ensure the server container key exists
188
+ if (!config[target.key]) {
189
+ config[target.key] = {};
190
+ }
191
+
192
+ const servers = config[target.key];
193
+
194
+ // Check if already configured
195
+ if (servers[MCP_KEY] && !force) {
196
+ console.log(` ✅ ${target.name} — already configured`);
197
+ skipped++;
198
+ continue;
199
+ }
200
+
201
+ // Add the entry
202
+ servers[MCP_KEY] = target.entry;
203
+
204
+ if (dryRun) {
205
+ console.log(` 🟡 ${target.name} — would configure (dry run)`);
206
+ } else {
207
+ writeJsonSafe(target.path, config);
208
+ console.log(` ✅ ${target.name} — configured!`);
209
+ }
210
+ configured++;
211
+ }
212
+
213
+ console.log();
214
+ console.log(` ─────────────────────────────────────`);
215
+ console.log(` ${configured} configured · ${skipped} skipped · ${notInstalled} not installed`);
216
+
217
+ if (configured > 0 && !dryRun) {
218
+ console.log();
219
+ console.log(' 💡 Restart your IDE(s) for the new MCP config to take effect.');
220
+ }
221
+
222
+ console.log();
223
+ }
224
+
225
+ module.exports = { runSetup };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@createlex/figma-swiftui-mcp",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "CreateLex MCP runtime for Figma-to-SwiftUI generation and Xcode export",
5
5
  "bin": {
6
6
  "figma-swiftui-mcp": "bin/figma-swiftui-mcp.js"
@@ -13,6 +13,7 @@
13
13
  "companion/mcp-server.mjs",
14
14
  "companion/package.json",
15
15
  "companion/server.js",
16
+ "companion/setup.cjs",
16
17
  "companion/xcode-writer.cjs",
17
18
  "README.md"
18
19
  ],