@createlex/figma-swiftui-mcp 1.3.1 → 1.4.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/companion/setup.cjs +85 -1
- package/package.json +1 -1
package/companion/setup.cjs
CHANGED
|
@@ -6,10 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Supported targets:
|
|
8
8
|
* - Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json)
|
|
9
|
-
* - Claude Code (~/.claude.json → mcpServers)
|
|
9
|
+
* - Claude Code (~/.claude.json → mcpServers) (covers CLI + desktop + web)
|
|
10
10
|
* - Cursor (~/.cursor/mcp.json)
|
|
11
11
|
* - Windsurf (~/.codeium/windsurf/mcp_config.json)
|
|
12
12
|
* - VS Code (~/.vscode/mcp.json — user-level)
|
|
13
|
+
* - OpenCode (~/.config/opencode/opencode.json → mcp)
|
|
14
|
+
* - Codex CLI (~/.codex/config.toml → [mcp_servers.figma-swiftui])
|
|
15
|
+
* - Gemini CLI (~/.gemini/settings.json)
|
|
13
16
|
* - Antigravity (~/.gemini/antigravity/mcp_config.json)
|
|
14
17
|
*/
|
|
15
18
|
|
|
@@ -118,6 +121,26 @@ function getTargets({ nodePath, scriptPath }) {
|
|
|
118
121
|
entry: stdioEntry,
|
|
119
122
|
wrapKey: null, // VS Code uses { servers: { ... } } at top level
|
|
120
123
|
},
|
|
124
|
+
{
|
|
125
|
+
name: 'OpenCode',
|
|
126
|
+
path: path.join(home, '.config', 'opencode', 'opencode.json'),
|
|
127
|
+
key: 'mcp',
|
|
128
|
+
entry: scriptPath
|
|
129
|
+
? { type: 'local', command: [nodePath, scriptPath, 'start'], enabled: true }
|
|
130
|
+
: { type: 'local', command: [resolveNpxPath(), '-y', '@createlex/figma-swiftui-mcp', 'start'], enabled: true },
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'Codex CLI',
|
|
134
|
+
path: path.join(home, '.codex', 'config.toml'),
|
|
135
|
+
format: 'toml',
|
|
136
|
+
entry: { command: stdioEntry.command, args: stdioEntry.args },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'Gemini CLI',
|
|
140
|
+
path: path.join(home, '.gemini', 'settings.json'),
|
|
141
|
+
key: 'mcpServers',
|
|
142
|
+
entry: stdioEntry,
|
|
143
|
+
},
|
|
121
144
|
{
|
|
122
145
|
name: 'Antigravity (Gemini)',
|
|
123
146
|
path: path.join(home, '.gemini', 'antigravity', 'mcp_config.json'),
|
|
@@ -145,6 +168,48 @@ function writeJsonSafe(filePath, data) {
|
|
|
145
168
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
146
169
|
}
|
|
147
170
|
|
|
171
|
+
// ── TOML helpers (minimal, for Codex config.toml) ────────────────────
|
|
172
|
+
// We only need to append/check a [mcp_servers.<name>] section — no full
|
|
173
|
+
// TOML parser required.
|
|
174
|
+
|
|
175
|
+
function tomlHasServer(raw, serverName) {
|
|
176
|
+
const pattern = new RegExp(`^\\[mcp_servers\\.${serverName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\]`, 'm');
|
|
177
|
+
return pattern.test(raw);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function tomlFormatValue(v) {
|
|
181
|
+
if (typeof v === 'string') return `"${v.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
182
|
+
if (typeof v === 'boolean') return v ? 'true' : 'false';
|
|
183
|
+
if (typeof v === 'number') return String(v);
|
|
184
|
+
if (Array.isArray(v)) return `[${v.map(tomlFormatValue).join(', ')}]`;
|
|
185
|
+
return `"${v}"`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function buildTomlSection(serverName, entry) {
|
|
189
|
+
const lines = [`[mcp_servers.${serverName}]`];
|
|
190
|
+
for (const [k, v] of Object.entries(entry)) {
|
|
191
|
+
if (k === 'env' && typeof v === 'object') continue; // handle env as sub-table
|
|
192
|
+
lines.push(`${k} = ${tomlFormatValue(v)}`);
|
|
193
|
+
}
|
|
194
|
+
if (entry.env && Object.keys(entry.env).length > 0) {
|
|
195
|
+
lines.push(`[mcp_servers.${serverName}.env]`);
|
|
196
|
+
for (const [ek, ev] of Object.entries(entry.env)) {
|
|
197
|
+
lines.push(`${ek} = ${tomlFormatValue(ev)}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return lines.join('\n') + '\n';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function appendTomlServer(filePath, serverName, entry, dryRun) {
|
|
204
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
205
|
+
if (tomlHasServer(raw, serverName)) return false; // already present
|
|
206
|
+
const section = '\n' + buildTomlSection(serverName, entry);
|
|
207
|
+
if (!dryRun) {
|
|
208
|
+
fs.appendFileSync(filePath, section, 'utf-8');
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
|
|
148
213
|
// ── Main ──────────────────────────────────────────────────────────────
|
|
149
214
|
function runSetup(flags = {}) {
|
|
150
215
|
const force = flags.force || false;
|
|
@@ -177,6 +242,25 @@ function runSetup(flags = {}) {
|
|
|
177
242
|
continue;
|
|
178
243
|
}
|
|
179
244
|
|
|
245
|
+
// ── TOML targets (Codex) ──────────────────────────────────────
|
|
246
|
+
if (target.format === 'toml') {
|
|
247
|
+
const raw = fs.readFileSync(target.path, 'utf-8');
|
|
248
|
+
if (tomlHasServer(raw, MCP_KEY) && !force) {
|
|
249
|
+
console.log(` ✅ ${target.name} — already configured`);
|
|
250
|
+
skipped++;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (dryRun) {
|
|
254
|
+
console.log(` 🟡 ${target.name} — would configure (dry run)`);
|
|
255
|
+
} else {
|
|
256
|
+
appendTomlServer(target.path, MCP_KEY, target.entry, false);
|
|
257
|
+
console.log(` ✅ ${target.name} — configured!`);
|
|
258
|
+
}
|
|
259
|
+
configured++;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ── JSON targets ────────────────────────────────────────────
|
|
180
264
|
const config = readJsonSafe(target.path);
|
|
181
265
|
if (!config) {
|
|
182
266
|
console.log(` ⚠️ ${target.name} — could not parse config`);
|
package/package.json
CHANGED