figma-console-mcp-cli 0.2.1 → 0.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/README.md +17 -4
- package/dist/index.js +40 -20
- package/dist/index.js.map +1 -1
- package/dist/steps/auth.js +6 -1
- package/dist/steps/auth.js.map +1 -1
- package/dist/steps/clientDetect.d.ts +2 -0
- package/dist/steps/clientDetect.js +62 -12
- package/dist/steps/clientDetect.js.map +1 -1
- package/dist/steps/configure.d.ts +5 -1
- package/dist/steps/configure.js +22 -12
- package/dist/steps/configure.js.map +1 -1
- package/dist/steps/connection.d.ts +2 -1
- package/dist/steps/connection.js +39 -131
- package/dist/steps/connection.js.map +1 -1
- package/dist/steps/doctor.d.ts +1 -0
- package/dist/steps/doctor.js +192 -0
- package/dist/steps/doctor.js.map +1 -0
- package/dist/steps/healthCheck.d.ts +2 -2
- package/dist/steps/healthCheck.js +60 -109
- package/dist/steps/healthCheck.js.map +1 -1
- package/dist/steps/installMethod.d.ts +7 -0
- package/dist/steps/installMethod.js +110 -0
- package/dist/steps/installMethod.js.map +1 -0
- package/dist/steps/systemCheck.js.map +1 -1
- package/dist/utils/config.d.ts +3 -1
- package/dist/utils/config.js +22 -3
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/constants.d.ts +4 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/platform.d.ts +1 -0
- package/dist/utils/platform.js +7 -1
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/process.d.ts +7 -0
- package/dist/utils/process.js +67 -0
- package/dist/utils/process.js.map +1 -0
- package/package.json +5 -6
package/README.md
CHANGED
|
@@ -16,9 +16,23 @@ The wizard walks you through:
|
|
|
16
16
|
2. **Authentication** — prompts for your Figma Personal Access Token
|
|
17
17
|
3. **Client detection** — finds installed AI clients and lets you pick which to configure
|
|
18
18
|
4. **Configuration** — injects the MCP server config into each client
|
|
19
|
-
5. **Connection setup** —
|
|
19
|
+
5. **Connection setup** — install the Bridge plugin and get setup instructions
|
|
20
20
|
6. **Health check** — verifies the connection to Figma is working
|
|
21
21
|
|
|
22
|
+
## Doctor Command
|
|
23
|
+
|
|
24
|
+
Already set up? Use `doctor` to audit and manage your integrations:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx figma-console-mcp-cli doctor
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The doctor command scans all supported clients and shows their integration status, then lets you:
|
|
31
|
+
|
|
32
|
+
- **Update** your Figma token across all configured clients
|
|
33
|
+
- **Remove** the integration from selected clients
|
|
34
|
+
- **Add** the integration to newly-installed clients
|
|
35
|
+
|
|
22
36
|
## Supported Clients
|
|
23
37
|
|
|
24
38
|
- Claude Code
|
|
@@ -26,10 +40,9 @@ The wizard walks you through:
|
|
|
26
40
|
- Cursor
|
|
27
41
|
- Windsurf
|
|
28
42
|
|
|
29
|
-
## Connection
|
|
43
|
+
## Connection Method
|
|
30
44
|
|
|
31
|
-
- **Desktop Bridge Plugin**
|
|
32
|
-
- **CDP Debug Mode** — relaunch Figma with remote debugging enabled on port 9222
|
|
45
|
+
- **Desktop Bridge Plugin** — install a Figma plugin, no restart needed
|
|
33
46
|
|
|
34
47
|
## Requirements
|
|
35
48
|
|
package/dist/index.js
CHANGED
|
@@ -1,38 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command } from
|
|
3
|
-
import chalk from
|
|
4
|
-
import { runSystemCheck } from
|
|
5
|
-
import { promptForToken } from
|
|
6
|
-
import { detectAndSelectClients } from
|
|
7
|
-
import { configureClients } from
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { runSystemCheck } from './steps/systemCheck.js';
|
|
5
|
+
import { promptForToken } from './steps/auth.js';
|
|
6
|
+
import { detectAndSelectClients } from './steps/clientDetect.js';
|
|
7
|
+
import { configureClients } from './steps/configure.js';
|
|
8
|
+
import { selectInstallMethod } from './steps/installMethod.js';
|
|
9
|
+
import { setupConnection } from './steps/connection.js';
|
|
10
|
+
import { runHealthCheck } from './steps/healthCheck.js';
|
|
11
|
+
import { runDoctor } from './steps/doctor.js';
|
|
10
12
|
const program = new Command();
|
|
11
13
|
program
|
|
12
|
-
.name(
|
|
13
|
-
.description(
|
|
14
|
-
.version(
|
|
14
|
+
.name('figma-console-mcp-cli')
|
|
15
|
+
.description('Configure Figma Console MCP across AI coding clients')
|
|
16
|
+
.version('0.2.1')
|
|
15
17
|
.action(async () => {
|
|
16
|
-
console.log(chalk.bold.cyan(
|
|
18
|
+
console.log(chalk.bold.cyan('\n Figma Console MCP — Setup Wizard\n'));
|
|
17
19
|
try {
|
|
18
20
|
await runSystemCheck();
|
|
19
|
-
const token = await promptForToken();
|
|
20
21
|
const clients = await detectAndSelectClients();
|
|
21
22
|
if (clients.length === 0) {
|
|
22
|
-
console.log(chalk.yellow(
|
|
23
|
+
console.log(chalk.yellow('\nNo clients selected. Exiting.\n'));
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
|
-
const
|
|
26
|
+
const token = await promptForToken();
|
|
27
|
+
const installMethod = await selectInstallMethod();
|
|
28
|
+
const configured = await configureClients(clients, token, installMethod);
|
|
26
29
|
if (configured.length === 0) {
|
|
27
|
-
console.log(chalk.yellow(
|
|
30
|
+
console.log(chalk.yellow('\nNo clients were configured. Exiting.\n'));
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
await runHealthCheck(configured
|
|
33
|
+
await setupConnection(installMethod);
|
|
34
|
+
await runHealthCheck(configured);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err.name === 'ExitPromptError') {
|
|
38
|
+
console.log(chalk.dim('\nSetup cancelled.\n'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
console.error(chalk.red(`\nError: ${err instanceof Error ? err.message : err}\n`));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
program
|
|
46
|
+
.command('doctor')
|
|
47
|
+
.description('Diagnose and manage Figma Console MCP integrations')
|
|
48
|
+
.action(async () => {
|
|
49
|
+
console.log(chalk.bold.cyan('\n Figma Console MCP — Doctor\n'));
|
|
50
|
+
try {
|
|
51
|
+
await runDoctor();
|
|
32
52
|
}
|
|
33
53
|
catch (err) {
|
|
34
|
-
if (err.name ===
|
|
35
|
-
console.log(chalk.dim(
|
|
54
|
+
if (err.name === 'ExitPromptError') {
|
|
55
|
+
console.log(chalk.dim('\nDoctor cancelled.\n'));
|
|
36
56
|
return;
|
|
37
57
|
}
|
|
38
58
|
console.error(chalk.red(`\nError: ${err instanceof Error ? err.message : err}\n`));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/steps/auth.js
CHANGED
|
@@ -5,9 +5,14 @@ export async function promptForToken() {
|
|
|
5
5
|
console.log(` Generate a Personal Access Token at:\n ${chalk.cyan('https://developers.figma.com/docs/rest-api/authentication/#generate-a-personal-access-token')}\n`);
|
|
6
6
|
while (true) {
|
|
7
7
|
const token = await password({
|
|
8
|
-
message: 'Paste your Figma Personal Access Token:',
|
|
8
|
+
message: 'Paste your Figma Personal Access Token (or leave empty to exit):',
|
|
9
9
|
mask: '*',
|
|
10
10
|
});
|
|
11
|
+
if (!token) {
|
|
12
|
+
const error = new Error('Setup cancelled');
|
|
13
|
+
error.name = 'ExitPromptError';
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
11
16
|
if (token.startsWith('figd_')) {
|
|
12
17
|
console.log(chalk.green(' ✓ Token accepted'));
|
|
13
18
|
return token;
|
package/dist/steps/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/steps/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CACT,6CAA6C,KAAK,CAAC,IAAI,CACrD,6FAA6F,CAC9F,IAAI,CACN,CAAC;IAEF,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC;YAC3B,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/steps/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CACT,6CAA6C,KAAK,CAAC,IAAI,CACrD,6FAA6F,CAC9F,IAAI,CACN,CAAC;IAEF,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC;YAC3B,OAAO,EACL,kEAAkE;YACpE,IAAI,EAAE,GAAG;SACV,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC3C,KAAK,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAC/B,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC/C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,2DAA2D,CAAC,CACvE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -1,57 +1,101 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { exec } from 'node:child_process';
|
|
3
3
|
import { checkbox } from '@inquirer/prompts';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import { getPlatform, getAppDataPath, resolveConfigPath } from '../utils/platform.js';
|
|
6
|
-
|
|
5
|
+
import { getPlatform, getAppDataPath, resolveConfigPath, } from '../utils/platform.js';
|
|
6
|
+
import { readJsonConfig } from '../utils/config.js';
|
|
7
|
+
function execAsync(cmd) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
exec(cmd, { encoding: 'utf-8' }, (err, stdout) => {
|
|
10
|
+
if (err)
|
|
11
|
+
reject(err);
|
|
12
|
+
else
|
|
13
|
+
resolve(stdout);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function isCommandAvailable(cmd) {
|
|
7
18
|
try {
|
|
8
|
-
|
|
19
|
+
await execAsync(`which ${cmd}`);
|
|
9
20
|
return true;
|
|
10
21
|
}
|
|
11
22
|
catch {
|
|
12
23
|
return false;
|
|
13
24
|
}
|
|
14
25
|
}
|
|
15
|
-
function
|
|
26
|
+
function isJsonClientConfigured(configPath) {
|
|
27
|
+
const config = readJsonConfig(configPath);
|
|
28
|
+
const mcpServers = config.mcpServers;
|
|
29
|
+
return mcpServers?.['figma-console'] !== undefined;
|
|
30
|
+
}
|
|
31
|
+
async function isClaudeCodeConfigured() {
|
|
32
|
+
try {
|
|
33
|
+
const output = await execAsync('claude mcp list');
|
|
34
|
+
return output.includes('figma-console');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function getClients() {
|
|
16
41
|
const platform = getPlatform();
|
|
17
42
|
const appData = getAppDataPath();
|
|
18
43
|
const claudeDesktopPath = platform === 'windows'
|
|
19
44
|
? `${appData}\\Claude\\claude_desktop_config.json`
|
|
20
45
|
: `${appData}/Claude/claude_desktop_config.json`;
|
|
46
|
+
const cursorPath = resolveConfigPath('.cursor', 'mcp.json');
|
|
47
|
+
const windsurfPath = resolveConfigPath('.codeium', 'windsurf', 'mcp_config.json');
|
|
48
|
+
const claudeCodeDetected = await isCommandAvailable('claude');
|
|
21
49
|
return [
|
|
22
50
|
{
|
|
23
51
|
name: 'Claude Code',
|
|
24
52
|
id: 'claude-code',
|
|
25
53
|
configPath: null,
|
|
26
|
-
detected:
|
|
54
|
+
detected: claudeCodeDetected,
|
|
55
|
+
configured: claudeCodeDetected && (await isClaudeCodeConfigured()),
|
|
27
56
|
},
|
|
28
57
|
{
|
|
29
58
|
name: 'Claude Desktop',
|
|
30
59
|
id: 'claude-desktop',
|
|
31
60
|
configPath: claudeDesktopPath,
|
|
32
61
|
detected: fs.existsSync(claudeDesktopPath),
|
|
62
|
+
configured: fs.existsSync(claudeDesktopPath) &&
|
|
63
|
+
isJsonClientConfigured(claudeDesktopPath),
|
|
33
64
|
},
|
|
34
65
|
{
|
|
35
66
|
name: 'Cursor',
|
|
36
67
|
id: 'cursor',
|
|
37
|
-
configPath:
|
|
38
|
-
detected: fs.existsSync(
|
|
68
|
+
configPath: cursorPath,
|
|
69
|
+
detected: fs.existsSync(cursorPath),
|
|
70
|
+
configured: fs.existsSync(cursorPath) && isJsonClientConfigured(cursorPath),
|
|
39
71
|
},
|
|
40
72
|
{
|
|
41
73
|
name: 'Windsurf',
|
|
42
74
|
id: 'windsurf',
|
|
43
|
-
configPath:
|
|
44
|
-
detected: fs.existsSync(
|
|
75
|
+
configPath: windsurfPath,
|
|
76
|
+
detected: fs.existsSync(windsurfPath),
|
|
77
|
+
configured: fs.existsSync(windsurfPath) && isJsonClientConfigured(windsurfPath),
|
|
45
78
|
},
|
|
46
79
|
];
|
|
47
80
|
}
|
|
48
81
|
export async function detectAndSelectClients() {
|
|
49
82
|
console.log(chalk.bold('\n🔎 Client Detection\n'));
|
|
50
|
-
const
|
|
83
|
+
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
84
|
+
const msg = 'Scanning for AI clients…';
|
|
85
|
+
let frame = 0;
|
|
86
|
+
const spinner = setInterval(() => {
|
|
87
|
+
const f = SPINNER[frame % SPINNER.length];
|
|
88
|
+
process.stdout.write(`\r ${chalk.cyan(f)} ${msg}`);
|
|
89
|
+
frame++;
|
|
90
|
+
}, 80);
|
|
91
|
+
const clients = await getClients();
|
|
92
|
+
clearInterval(spinner);
|
|
93
|
+
process.stdout.write(`\r${' '.repeat(msg.length + 6)}\r`);
|
|
51
94
|
const detected = clients.filter((c) => c.detected);
|
|
52
95
|
const notDetected = clients.filter((c) => !c.detected);
|
|
53
96
|
for (const c of detected) {
|
|
54
|
-
|
|
97
|
+
const tag = c.configured ? chalk.cyan(' (already configured)') : '';
|
|
98
|
+
console.log(chalk.green(` ✓ ${c.name} detected`) + tag);
|
|
55
99
|
}
|
|
56
100
|
for (const c of notDetected) {
|
|
57
101
|
console.log(chalk.dim(` · ${c.name} not found`));
|
|
@@ -60,6 +104,12 @@ export async function detectAndSelectClients() {
|
|
|
60
104
|
console.log(chalk.yellow('\n No supported clients detected.'));
|
|
61
105
|
return [];
|
|
62
106
|
}
|
|
107
|
+
const hasConfigured = detected.some((c) => c.configured);
|
|
108
|
+
if (hasConfigured) {
|
|
109
|
+
console.log(chalk.dim('\n Tip: To update your Figma token or remove the integration from configured'));
|
|
110
|
+
console.log(chalk.dim(' clients, quit and run: ') +
|
|
111
|
+
chalk.cyan('npx figma-console-mcp-cli doctor'));
|
|
112
|
+
}
|
|
63
113
|
console.log('');
|
|
64
114
|
const selected = await checkbox({
|
|
65
115
|
message: 'Select clients to configure:',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clientDetect.js","sourceRoot":"","sources":["../../src/steps/clientDetect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"clientDetect.js","sourceRoot":"","sources":["../../src/steps/clientDetect.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { Client } from './clientDetect.js';
|
|
2
|
-
|
|
2
|
+
import type { InstallMethod } from './installMethod.js';
|
|
3
|
+
export declare function configureClients(clients: Client[], token: string, method?: InstallMethod): Promise<Client[]>;
|
|
4
|
+
export declare function isFigmaConsoleConfigured(): boolean;
|
|
5
|
+
export declare function configureClaudeCode(token: string, method?: InstallMethod): Promise<boolean>;
|
|
6
|
+
export declare function configureJsonClient(client: Client, token: string, method?: InstallMethod): void;
|
package/dist/steps/configure.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { select } from '@inquirer/prompts';
|
|
4
|
-
import { readJsonConfig, writeJsonConfig, mergeServerConfig } from '../utils/config.js';
|
|
4
|
+
import { readJsonConfig, writeJsonConfig, mergeServerConfig, } from '../utils/config.js';
|
|
5
5
|
import { getPlatform } from '../utils/platform.js';
|
|
6
|
-
export async function configureClients(clients, token) {
|
|
6
|
+
export async function configureClients(clients, token, method = { type: 'npx' }) {
|
|
7
7
|
console.log(chalk.bold('\n⚙️ Configuring MCP Server\n'));
|
|
8
8
|
const configured = [];
|
|
9
9
|
for (const client of clients) {
|
|
10
10
|
try {
|
|
11
11
|
if (client.id === 'claude-code') {
|
|
12
|
-
const ok = await configureClaudeCode(token);
|
|
12
|
+
const ok = await configureClaudeCode(token, method);
|
|
13
13
|
if (!ok) {
|
|
14
14
|
console.log(chalk.yellow(` ⊘ ${client.name} skipped`));
|
|
15
15
|
continue;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
else if (client.configPath) {
|
|
19
|
-
configureJsonClient(client, token);
|
|
19
|
+
configureJsonClient(client, token, method);
|
|
20
20
|
}
|
|
21
21
|
configured.push(client);
|
|
22
22
|
console.log(chalk.green(` ✓ ${client.name} configured`));
|
|
@@ -33,7 +33,10 @@ function isClaudeRunning() {
|
|
|
33
33
|
const cmd = getPlatform() === 'windows'
|
|
34
34
|
? 'tasklist /FI "IMAGENAME eq claude.exe" /NH'
|
|
35
35
|
: 'pgrep -x claude';
|
|
36
|
-
const output = execSync(cmd, {
|
|
36
|
+
const output = execSync(cmd, {
|
|
37
|
+
encoding: 'utf-8',
|
|
38
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
39
|
+
});
|
|
37
40
|
if (getPlatform() === 'windows') {
|
|
38
41
|
return output.includes('claude.exe');
|
|
39
42
|
}
|
|
@@ -43,7 +46,7 @@ function isClaudeRunning() {
|
|
|
43
46
|
return false; // pgrep exits 1 if no match
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
|
-
function isFigmaConsoleConfigured() {
|
|
49
|
+
export function isFigmaConsoleConfigured() {
|
|
47
50
|
try {
|
|
48
51
|
const output = execSync('claude mcp list', {
|
|
49
52
|
encoding: 'utf-8',
|
|
@@ -55,7 +58,14 @@ function isFigmaConsoleConfigured() {
|
|
|
55
58
|
return false;
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
|
-
|
|
61
|
+
function buildClaudeCodeCommand(method) {
|
|
62
|
+
if (method.type === 'local') {
|
|
63
|
+
return `node ${method.path}`;
|
|
64
|
+
}
|
|
65
|
+
return 'npx -y figma-console-mcp@latest';
|
|
66
|
+
}
|
|
67
|
+
export async function configureClaudeCode(token, method = { type: 'npx' }) {
|
|
68
|
+
const serverCommand = buildClaudeCodeCommand(method);
|
|
59
69
|
while (isClaudeRunning()) {
|
|
60
70
|
console.log(chalk.yellow('\n ⚠ Claude Code appears to be running.'));
|
|
61
71
|
console.log(chalk.yellow(' It holds a lock that prevents `claude mcp add` from succeeding.'));
|
|
@@ -63,13 +73,13 @@ async function configureClaudeCode(token) {
|
|
|
63
73
|
const action = await select({
|
|
64
74
|
message: 'What would you like to do?',
|
|
65
75
|
choices: [
|
|
66
|
-
{ name:
|
|
76
|
+
{ name: "I've closed Claude Code — retry", value: 'retry' },
|
|
67
77
|
{ name: 'Skip Claude Code setup', value: 'skip' },
|
|
68
78
|
],
|
|
69
79
|
});
|
|
70
80
|
if (action === 'skip') {
|
|
71
81
|
console.log(chalk.dim(' Skipped. You can configure manually later:'));
|
|
72
|
-
console.log(chalk.dim(` claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=<token> -e ENABLE_MCP_APPS=true --
|
|
82
|
+
console.log(chalk.dim(` claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=<token> -e ENABLE_MCP_APPS=true -- ${serverCommand}`));
|
|
73
83
|
return false;
|
|
74
84
|
}
|
|
75
85
|
// action === 'retry' → loop continues, re-checks isClaudeRunning()
|
|
@@ -77,13 +87,13 @@ async function configureClaudeCode(token) {
|
|
|
77
87
|
if (isFigmaConsoleConfigured()) {
|
|
78
88
|
execSync('claude mcp remove figma-console -s user', { stdio: 'ignore' });
|
|
79
89
|
}
|
|
80
|
-
execSync(`claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=${token} -e ENABLE_MCP_APPS=true --
|
|
90
|
+
execSync(`claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=${token} -e ENABLE_MCP_APPS=true -- ${serverCommand}`, { stdio: 'ignore' });
|
|
81
91
|
return true;
|
|
82
92
|
}
|
|
83
|
-
function configureJsonClient(client, token) {
|
|
93
|
+
export function configureJsonClient(client, token, method = { type: 'npx' }) {
|
|
84
94
|
const configPath = client.configPath;
|
|
85
95
|
const existing = readJsonConfig(configPath);
|
|
86
|
-
const merged = mergeServerConfig(existing, token);
|
|
96
|
+
const merged = mergeServerConfig(existing, token, method);
|
|
87
97
|
writeJsonConfig(configPath, merged);
|
|
88
98
|
}
|
|
89
99
|
//# sourceMappingURL=configure.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/steps/configure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/steps/configure.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { InstallMethod } from './installMethod.js';
|
|
2
|
+
export declare function setupConnection(installMethod: InstallMethod): Promise<void>;
|
package/dist/steps/connection.js
CHANGED
|
@@ -1,140 +1,48 @@
|
|
|
1
|
-
import { spawnSync } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
description: "Relaunch Figma with remote debugging enabled",
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
});
|
|
26
|
-
if (method === "bridge") {
|
|
27
|
-
await setupBridge();
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { MANIFEST_PATH_SUFFIX } from '../utils/constants.js';
|
|
6
|
+
export async function setupConnection(installMethod) {
|
|
7
|
+
console.log(chalk.bold('\n🔌 Figma Connection Method\n'));
|
|
8
|
+
const repoDir = installMethod.type === 'local'
|
|
9
|
+
? dirname(dirname(installMethod.path))
|
|
10
|
+
: undefined;
|
|
11
|
+
await setupBridge(repoDir);
|
|
12
|
+
}
|
|
13
|
+
async function setupBridge(existingRepoDir) {
|
|
14
|
+
console.log(chalk.bold('\n Desktop Bridge Setup:\n'));
|
|
15
|
+
let manifestPath;
|
|
16
|
+
if (existingRepoDir) {
|
|
17
|
+
manifestPath = join(existingRepoDir, MANIFEST_PATH_SUFFIX);
|
|
18
|
+
if (!existsSync(manifestPath)) {
|
|
19
|
+
console.log(chalk.red(`\n Error: Bridge manifest not found at: ${manifestPath}`));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
28
22
|
}
|
|
29
23
|
else {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const result = spawnSync("git", ["--version"], {
|
|
37
|
-
encoding: "utf-8",
|
|
38
|
-
timeout: 5_000,
|
|
39
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
24
|
+
console.log(chalk.dim(' Locating plugin path…'));
|
|
25
|
+
const result = spawnSync('npx', ['figma-console-mcp@latest', '--print-path'], {
|
|
26
|
+
encoding: 'utf-8',
|
|
27
|
+
timeout: 60_000,
|
|
28
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
29
|
+
shell: true,
|
|
40
30
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
function isExistingClone(dir) {
|
|
48
|
-
return (existsSync(join(dir, ".git")) &&
|
|
49
|
-
existsSync(join(dir, "figma-desktop-bridge", "manifest.json")));
|
|
50
|
-
}
|
|
51
|
-
function cloneOrUpdateRepo(targetDir) {
|
|
52
|
-
const manifestPath = join(targetDir, "figma-desktop-bridge", "manifest.json");
|
|
53
|
-
if (isExistingClone(targetDir)) {
|
|
54
|
-
console.log(chalk.dim(" Existing clone detected — pulling latest…"));
|
|
55
|
-
try {
|
|
56
|
-
spawnSync("git", ["-C", targetDir, "pull"], {
|
|
57
|
-
encoding: "utf-8",
|
|
58
|
-
timeout: 30_000,
|
|
59
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
// non-fatal — existing clone is still usable
|
|
31
|
+
if (result.status !== 0) {
|
|
32
|
+
console.log(chalk.red(`\n Error: Failed to run npx figma-console-mcp@latest --print-path`));
|
|
33
|
+
if (result.stderr) {
|
|
34
|
+
console.log(chalk.red(` ${result.stderr.trim()}`));
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
64
37
|
}
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
if (existsSync(targetDir)) {
|
|
68
|
-
throw new Error(`Directory already exists but is not the figma-console-mcp repo: ${targetDir}`);
|
|
69
|
-
}
|
|
70
|
-
console.log(chalk.dim(" Cloning figma-console-mcp…"));
|
|
71
|
-
const result = spawnSync("git", ["clone", REPO_URL, targetDir], {
|
|
72
|
-
encoding: "utf-8",
|
|
73
|
-
timeout: 60_000,
|
|
74
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
75
|
-
});
|
|
76
|
-
if (result.status !== 0) {
|
|
77
|
-
const stderr = result.stderr?.trim() ?? "unknown error";
|
|
78
|
-
throw new Error(`git clone failed: ${stderr}`);
|
|
79
|
-
}
|
|
80
|
-
if (!existsSync(manifestPath)) {
|
|
81
|
-
throw new Error(`Clone succeeded but manifest not found at: ${manifestPath}`);
|
|
82
|
-
}
|
|
83
|
-
return manifestPath;
|
|
84
|
-
}
|
|
85
|
-
function showManualFallback() {
|
|
86
|
-
console.log(chalk.yellow("\n Automatic setup unavailable. Manual steps:\n"));
|
|
87
|
-
console.log(` 1. Clone the repo manually:\n`);
|
|
88
|
-
console.log(chalk.cyan(` git clone ${REPO_URL}\n`));
|
|
89
|
-
console.log(" 2. Open Figma Desktop");
|
|
90
|
-
console.log(" 3. Go to Plugins → Development → Import plugin from manifest…");
|
|
91
|
-
console.log(" 4. Select: <clone-dir>/figma-desktop-bridge/manifest.json\n");
|
|
92
|
-
console.log(" 5. Run the plugin: Plugins → Development → Figma Console Bridge\n");
|
|
93
|
-
}
|
|
94
|
-
async function setupBridge() {
|
|
95
|
-
console.log(chalk.bold("\n Desktop Bridge Setup:\n"));
|
|
96
|
-
if (!isGitInstalled()) {
|
|
97
|
-
console.log(chalk.yellow(" git is not installed or not on PATH."));
|
|
98
|
-
showManualFallback();
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
const defaultDir = join(getHomedir(), DEFAULT_CLONE_DIR_NAME);
|
|
102
|
-
const targetDir = await input({
|
|
103
|
-
message: "Where should we clone figma-console-mcp?",
|
|
104
|
-
default: defaultDir,
|
|
105
|
-
});
|
|
106
|
-
let manifestPath;
|
|
107
|
-
try {
|
|
108
|
-
manifestPath = cloneOrUpdateRepo(targetDir.trim());
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
112
|
-
console.log(chalk.red(`\n Error: ${msg}`));
|
|
113
|
-
showManualFallback();
|
|
38
|
+
console.log(result.stdout);
|
|
114
39
|
return;
|
|
115
40
|
}
|
|
116
|
-
console.log(chalk.bold(
|
|
117
|
-
console.log(
|
|
118
|
-
console.log(
|
|
119
|
-
console.log(
|
|
41
|
+
console.log(chalk.bold('\n Next steps:\n'));
|
|
42
|
+
console.log(' 1. Open Figma Desktop');
|
|
43
|
+
console.log(' 2. Go to Plugins → Development → Import plugin from manifest…');
|
|
44
|
+
console.log(' 3. Select this file:\n');
|
|
120
45
|
console.log(chalk.cyan(` ${manifestPath}\n`));
|
|
121
|
-
console.log(
|
|
122
|
-
}
|
|
123
|
-
function setupCDP() {
|
|
124
|
-
const platform = getPlatform();
|
|
125
|
-
console.log(chalk.bold("\n CDP Debug Mode Setup:\n"));
|
|
126
|
-
if (platform === "macos") {
|
|
127
|
-
console.log(" Close Figma if running, then launch with:\n");
|
|
128
|
-
console.log(chalk.cyan(" open -a Figma --args --remote-debugging-port=9222\n"));
|
|
129
|
-
}
|
|
130
|
-
else if (platform === "windows") {
|
|
131
|
-
console.log(" Close Figma if running, then launch with:\n");
|
|
132
|
-
console.log(chalk.cyan(' "%LOCALAPPDATA%\\Figma\\Figma.exe" --remote-debugging-port=9222\n'));
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
console.log(" Close Figma if running, then relaunch with the flag:\n");
|
|
136
|
-
console.log(chalk.cyan(" figma --remote-debugging-port=9222\n"));
|
|
137
|
-
}
|
|
138
|
-
console.log(" Figma must be restarted with this flag each time you want CDP access.");
|
|
46
|
+
console.log(' 4. Run the plugin: Plugins → Development → Figma Console Bridge\n');
|
|
139
47
|
}
|
|
140
48
|
//# sourceMappingURL=connection.js.map
|