figma-console-mcp-cli 0.1.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/dist/index.d.ts +2 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/steps/auth.d.ts +1 -0
- package/dist/steps/auth.js +18 -0
- package/dist/steps/auth.js.map +1 -0
- package/dist/steps/clientDetect.d.ts +7 -0
- package/dist/steps/clientDetect.js +74 -0
- package/dist/steps/clientDetect.js.map +1 -0
- package/dist/steps/configure.d.ts +2 -0
- package/dist/steps/configure.js +89 -0
- package/dist/steps/configure.js.map +1 -0
- package/dist/steps/connection.d.ts +1 -0
- package/dist/steps/connection.js +140 -0
- package/dist/steps/connection.js.map +1 -0
- package/dist/steps/healthCheck.d.ts +2 -0
- package/dist/steps/healthCheck.js +215 -0
- package/dist/steps/healthCheck.js.map +1 -0
- package/dist/steps/systemCheck.d.ts +1 -0
- package/dist/steps/systemCheck.js +33 -0
- package/dist/steps/systemCheck.js.map +1 -0
- package/dist/utils/config.d.ts +3 -0
- package/dist/utils/config.js +36 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/manifest.d.ts +1 -0
- package/dist/utils/manifest.js +76 -0
- package/dist/utils/manifest.js.map +1 -0
- package/dist/utils/platform.d.ts +6 -0
- package/dist/utils/platform.js +32 -0
- package/dist/utils/platform.js.map +1 -0
- package/package.json +27 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 { setupConnection } from "./steps/connection.js";
|
|
9
|
+
import { runHealthCheck } from "./steps/healthCheck.js";
|
|
10
|
+
const program = new Command();
|
|
11
|
+
program
|
|
12
|
+
.name("figma-console-mcp-cli")
|
|
13
|
+
.description("Configure Figma Console MCP across AI coding clients")
|
|
14
|
+
.version("1.0.0")
|
|
15
|
+
.action(async () => {
|
|
16
|
+
console.log(chalk.bold.cyan("\n Figma Console MCP ā Setup Wizard\n"));
|
|
17
|
+
try {
|
|
18
|
+
await runSystemCheck();
|
|
19
|
+
const token = await promptForToken();
|
|
20
|
+
const clients = await detectAndSelectClients();
|
|
21
|
+
if (clients.length === 0) {
|
|
22
|
+
console.log(chalk.yellow("\nNo clients selected. Exiting.\n"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const configured = await configureClients(clients, token);
|
|
26
|
+
if (configured.length === 0) {
|
|
27
|
+
console.log(chalk.yellow("\nNo clients were configured. Exiting.\n"));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const method = await setupConnection();
|
|
31
|
+
await runHealthCheck(configured, method);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (err.name === "ExitPromptError") {
|
|
35
|
+
console.log(chalk.dim("\nSetup cancelled.\n"));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
console.error(chalk.red(`\nError: ${err instanceof Error ? err.message : err}\n`));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
program.parse();
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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;AAExD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,uBAAuB,CAAC;KAC7B,WAAW,CAAC,sDAAsD,CAAC;KACnE,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC,CAAC;IAEvE,IAAI,CAAC;QACH,MAAM,cAAc,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,MAAM,sBAAsB,EAAE,CAAC;QAE/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,mCAAmC,CAAC,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0CAA0C,CAAC,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;QACvC,MAAM,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAAyB,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC;YAC/C,OAAO;QACT,CAAC;QACD,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CACpE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function promptForToken(): Promise<string>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { password } from '@inquirer/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
export async function promptForToken() {
|
|
4
|
+
console.log(chalk.bold('\nš Figma Authentication\n'));
|
|
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
|
+
while (true) {
|
|
7
|
+
const token = await password({
|
|
8
|
+
message: 'Paste your Figma Personal Access Token:',
|
|
9
|
+
mask: '*',
|
|
10
|
+
});
|
|
11
|
+
if (token.startsWith('figd_')) {
|
|
12
|
+
console.log(chalk.green(' ā Token accepted'));
|
|
13
|
+
return token;
|
|
14
|
+
}
|
|
15
|
+
console.log(chalk.red(' ā Invalid token ā must start with "figd_". Try again.\n'));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +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,EAAE,yCAAyC;YAClD,IAAI,EAAE,GAAG;SACV,CAAC,CAAC;QAEH,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,CAAC,KAAK,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC,CAAC;IACtF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { checkbox } from '@inquirer/prompts';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { getPlatform, getAppDataPath, resolveConfigPath } from '../utils/platform.js';
|
|
6
|
+
function isCommandAvailable(cmd) {
|
|
7
|
+
try {
|
|
8
|
+
execSync(`which ${cmd}`, { stdio: 'ignore' });
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function getClients() {
|
|
16
|
+
const platform = getPlatform();
|
|
17
|
+
const appData = getAppDataPath();
|
|
18
|
+
const claudeDesktopPath = platform === 'windows'
|
|
19
|
+
? `${appData}\\Claude\\claude_desktop_config.json`
|
|
20
|
+
: `${appData}/Claude/claude_desktop_config.json`;
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
name: 'Claude Code',
|
|
24
|
+
id: 'claude-code',
|
|
25
|
+
configPath: null,
|
|
26
|
+
detected: isCommandAvailable('claude'),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Claude Desktop',
|
|
30
|
+
id: 'claude-desktop',
|
|
31
|
+
configPath: claudeDesktopPath,
|
|
32
|
+
detected: fs.existsSync(claudeDesktopPath),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Cursor',
|
|
36
|
+
id: 'cursor',
|
|
37
|
+
configPath: resolveConfigPath('.cursor', 'mcp.json'),
|
|
38
|
+
detected: fs.existsSync(resolveConfigPath('.cursor', 'mcp.json')),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Windsurf',
|
|
42
|
+
id: 'windsurf',
|
|
43
|
+
configPath: resolveConfigPath('.codeium', 'windsurf', 'mcp_config.json'),
|
|
44
|
+
detected: fs.existsSync(resolveConfigPath('.codeium', 'windsurf', 'mcp_config.json')),
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
export async function detectAndSelectClients() {
|
|
49
|
+
console.log(chalk.bold('\nš Client Detection\n'));
|
|
50
|
+
const clients = getClients();
|
|
51
|
+
const detected = clients.filter((c) => c.detected);
|
|
52
|
+
const notDetected = clients.filter((c) => !c.detected);
|
|
53
|
+
for (const c of detected) {
|
|
54
|
+
console.log(chalk.green(` ā ${c.name} detected`));
|
|
55
|
+
}
|
|
56
|
+
for (const c of notDetected) {
|
|
57
|
+
console.log(chalk.dim(` Ā· ${c.name} not found`));
|
|
58
|
+
}
|
|
59
|
+
if (detected.length === 0) {
|
|
60
|
+
console.log(chalk.yellow('\n No supported clients detected.'));
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
console.log('');
|
|
64
|
+
const selected = await checkbox({
|
|
65
|
+
message: 'Select clients to configure:',
|
|
66
|
+
choices: detected.map((c) => ({
|
|
67
|
+
name: c.name,
|
|
68
|
+
value: c.id,
|
|
69
|
+
checked: true,
|
|
70
|
+
})),
|
|
71
|
+
});
|
|
72
|
+
return detected.filter((c) => selected.includes(c.id));
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=clientDetect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientDetect.js","sourceRoot":"","sources":["../../src/steps/clientDetect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { select } from '@inquirer/prompts';
|
|
4
|
+
import { readJsonConfig, writeJsonConfig, mergeServerConfig } from '../utils/config.js';
|
|
5
|
+
import { getPlatform } from '../utils/platform.js';
|
|
6
|
+
export async function configureClients(clients, token) {
|
|
7
|
+
console.log(chalk.bold('\nāļø Configuring MCP Server\n'));
|
|
8
|
+
const configured = [];
|
|
9
|
+
for (const client of clients) {
|
|
10
|
+
try {
|
|
11
|
+
if (client.id === 'claude-code') {
|
|
12
|
+
const ok = await configureClaudeCode(token);
|
|
13
|
+
if (!ok) {
|
|
14
|
+
console.log(chalk.yellow(` ā ${client.name} skipped`));
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else if (client.configPath) {
|
|
19
|
+
configureJsonClient(client, token);
|
|
20
|
+
}
|
|
21
|
+
configured.push(client);
|
|
22
|
+
console.log(chalk.green(` ā ${client.name} configured`));
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
26
|
+
console.log(chalk.red(` ā ${client.name} failed: ${message}`));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return configured;
|
|
30
|
+
}
|
|
31
|
+
function isClaudeRunning() {
|
|
32
|
+
try {
|
|
33
|
+
const cmd = getPlatform() === 'windows'
|
|
34
|
+
? 'tasklist /FI "IMAGENAME eq claude.exe" /NH'
|
|
35
|
+
: 'pgrep -x claude';
|
|
36
|
+
const output = execSync(cmd, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
37
|
+
if (getPlatform() === 'windows') {
|
|
38
|
+
return output.includes('claude.exe');
|
|
39
|
+
}
|
|
40
|
+
return true; // pgrep exits 0 only if a match is found
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false; // pgrep exits 1 if no match
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function isFigmaConsoleConfigured() {
|
|
47
|
+
try {
|
|
48
|
+
const output = execSync('claude mcp list', {
|
|
49
|
+
encoding: 'utf-8',
|
|
50
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
51
|
+
});
|
|
52
|
+
return output.includes('figma-console');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function configureClaudeCode(token) {
|
|
59
|
+
while (isClaudeRunning()) {
|
|
60
|
+
console.log(chalk.yellow('\n ā Claude Code appears to be running.'));
|
|
61
|
+
console.log(chalk.yellow(' It holds a lock that prevents `claude mcp add` from succeeding.'));
|
|
62
|
+
console.log(chalk.yellow(' Please quit Claude Code before continuing.\n'));
|
|
63
|
+
const action = await select({
|
|
64
|
+
message: 'What would you like to do?',
|
|
65
|
+
choices: [
|
|
66
|
+
{ name: 'I\'ve closed Claude Code ā retry', value: 'retry' },
|
|
67
|
+
{ name: 'Skip Claude Code setup', value: 'skip' },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
if (action === 'skip') {
|
|
71
|
+
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 -- npx -y figma-console-mcp@latest`));
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
// action === 'retry' ā loop continues, re-checks isClaudeRunning()
|
|
76
|
+
}
|
|
77
|
+
if (isFigmaConsoleConfigured()) {
|
|
78
|
+
execSync('claude mcp remove figma-console -s user', { stdio: 'ignore' });
|
|
79
|
+
}
|
|
80
|
+
execSync(`claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=${token} -e ENABLE_MCP_APPS=true -- npx -y figma-console-mcp@latest`, { stdio: 'ignore' });
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
function configureJsonClient(client, token) {
|
|
84
|
+
const configPath = client.configPath;
|
|
85
|
+
const existing = readJsonConfig(configPath);
|
|
86
|
+
const merged = mergeServerConfig(existing, token);
|
|
87
|
+
writeJsonConfig(configPath, merged);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=configure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/steps/configure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function setupConnection(): Promise<"bridge" | "cdp">;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { input, select } from "@inquirer/prompts";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { getHomedir, getPlatform } from "../utils/platform.js";
|
|
7
|
+
const REPO_URL = "https://github.com/southleft/figma-console-mcp.git";
|
|
8
|
+
const DEFAULT_CLONE_DIR_NAME = "figma-console-mcp";
|
|
9
|
+
export async function setupConnection() {
|
|
10
|
+
console.log(chalk.bold("\nš Figma Connection Method\n"));
|
|
11
|
+
const method = await select({
|
|
12
|
+
message: "How do you want to connect to Figma?",
|
|
13
|
+
choices: [
|
|
14
|
+
{
|
|
15
|
+
name: "Desktop Bridge Plugin (Recommended)",
|
|
16
|
+
value: "bridge",
|
|
17
|
+
description: "Install a Figma plugin ā no restart needed",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "CDP Debug Mode",
|
|
21
|
+
value: "cdp",
|
|
22
|
+
description: "Relaunch Figma with remote debugging enabled",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
if (method === "bridge") {
|
|
27
|
+
await setupBridge();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
setupCDP();
|
|
31
|
+
}
|
|
32
|
+
return method;
|
|
33
|
+
}
|
|
34
|
+
function isGitInstalled() {
|
|
35
|
+
try {
|
|
36
|
+
const result = spawnSync("git", ["--version"], {
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
timeout: 5_000,
|
|
39
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
40
|
+
});
|
|
41
|
+
return result.status === 0;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
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
|
|
64
|
+
}
|
|
65
|
+
return manifestPath;
|
|
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();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.log(chalk.bold("\n Next steps:\n"));
|
|
117
|
+
console.log(" 1. Open Figma Desktop");
|
|
118
|
+
console.log(" 2. Go to Plugins ā Development ā Import plugin from manifestā¦");
|
|
119
|
+
console.log(" 3. Select this file:\n");
|
|
120
|
+
console.log(chalk.cyan(` ${manifestPath}\n`));
|
|
121
|
+
console.log(" 4. Run the plugin: Plugins ā Development ā Figma Console Bridge\n");
|
|
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.");
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/steps/connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { confirm, select } from "@inquirer/prompts";
|
|
5
|
+
const BRIDGE_PORTS = [
|
|
6
|
+
9223, 9224, 9225, 9226, 9227, 9228, 9229, 9230, 9231, 9232,
|
|
7
|
+
];
|
|
8
|
+
const BRIDGE_TIMEOUT_MS = 60_000;
|
|
9
|
+
function tryListen(server, port) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
server.once("error", () => resolve(false));
|
|
12
|
+
server.listen(port, "127.0.0.1", () => resolve(true));
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function restoreStdin() {
|
|
16
|
+
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
17
|
+
process.stdin.setRawMode(false);
|
|
18
|
+
process.stdin.pause();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Start a temporary WebSocket server on the first available bridge port,
|
|
23
|
+
* show a cancellable spinner, and wait for the Figma Bridge plugin to connect.
|
|
24
|
+
*
|
|
25
|
+
* Returns "connected" if the plugin connected, "cancelled" if the user pressed
|
|
26
|
+
* Escape, or "timeout" if the timeout expired.
|
|
27
|
+
* If all ports are already in use, assumes healthy (returns "connected").
|
|
28
|
+
*/
|
|
29
|
+
async function waitForBridgeWithCancel() {
|
|
30
|
+
const server = createServer();
|
|
31
|
+
let bound = false;
|
|
32
|
+
for (const port of BRIDGE_PORTS) {
|
|
33
|
+
bound = await tryListen(server, port);
|
|
34
|
+
if (bound)
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
if (!bound) {
|
|
38
|
+
return "connected";
|
|
39
|
+
}
|
|
40
|
+
const spinnerMessage = "Waiting for Bridge plugin... (press Escape to cancel)";
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
let resolved = false;
|
|
43
|
+
const cleanup = () => {
|
|
44
|
+
if (resolved)
|
|
45
|
+
return;
|
|
46
|
+
resolved = true;
|
|
47
|
+
clearInterval(spinnerInterval);
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
// Clear spinner line
|
|
50
|
+
process.stdout.write(`\r${" ".repeat(spinnerMessage.length + 6)}\r`);
|
|
51
|
+
server.close();
|
|
52
|
+
restoreStdin();
|
|
53
|
+
process.removeListener("exit", restoreStdin);
|
|
54
|
+
};
|
|
55
|
+
// Spinner
|
|
56
|
+
let frame = 0;
|
|
57
|
+
const SPINNER_FRAMES = ["ā ", "ā ", "ā ¹", "ā ø", "ā ¼", "ā “", "ā ¦", "ā §", "ā ", "ā "];
|
|
58
|
+
const spinnerInterval = setInterval(() => {
|
|
59
|
+
const f = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
|
|
60
|
+
process.stdout.write(`\r ${chalk.cyan(f)} ${spinnerMessage}`);
|
|
61
|
+
frame++;
|
|
62
|
+
}, 80);
|
|
63
|
+
// Timeout
|
|
64
|
+
const timer = setTimeout(() => {
|
|
65
|
+
cleanup();
|
|
66
|
+
resolve("timeout");
|
|
67
|
+
}, BRIDGE_TIMEOUT_MS);
|
|
68
|
+
// Escape listener
|
|
69
|
+
if (process.stdin.isTTY) {
|
|
70
|
+
process.stdin.setRawMode(true);
|
|
71
|
+
process.stdin.resume();
|
|
72
|
+
process.stdin.setEncoding("utf8");
|
|
73
|
+
process.on("exit", restoreStdin);
|
|
74
|
+
const onData = (data) => {
|
|
75
|
+
if (data === "\x1b") {
|
|
76
|
+
process.stdin.removeListener("data", onData);
|
|
77
|
+
cleanup();
|
|
78
|
+
resolve("cancelled");
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
process.stdin.on("data", onData);
|
|
82
|
+
// Remove data listener when server closes from other paths
|
|
83
|
+
server.on("close", () => {
|
|
84
|
+
process.stdin.removeListener("data", onData);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// WebSocket upgrade
|
|
88
|
+
server.on("upgrade", (req, socket) => {
|
|
89
|
+
const key = req.headers["sec-websocket-key"];
|
|
90
|
+
if (typeof key === "string") {
|
|
91
|
+
const accept = createHash("sha1")
|
|
92
|
+
.update(key + "258EAFA5-E914-47DA-95CA-5AB5E34B13E5")
|
|
93
|
+
.digest("base64");
|
|
94
|
+
socket.write("HTTP/1.1 101 Switching Protocols\r\n" +
|
|
95
|
+
"Upgrade: websocket\r\n" +
|
|
96
|
+
"Connection: Upgrade\r\n" +
|
|
97
|
+
`Sec-WebSocket-Accept: ${accept}\r\n` +
|
|
98
|
+
"\r\n");
|
|
99
|
+
}
|
|
100
|
+
socket.destroy();
|
|
101
|
+
cleanup();
|
|
102
|
+
resolve("connected");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async function checkCdp() {
|
|
107
|
+
try {
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
110
|
+
const res = await fetch("http://localhost:9222", {
|
|
111
|
+
signal: controller.signal,
|
|
112
|
+
});
|
|
113
|
+
clearTimeout(timeout);
|
|
114
|
+
return res.ok || res.status > 0;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const SPINNER_FRAMES = ["ā ", "ā ", "ā ¹", "ā ø", "ā ¼", "ā “", "ā ¦", "ā §", "ā ", "ā "];
|
|
121
|
+
async function withSpinner(message, fn) {
|
|
122
|
+
let i = 0;
|
|
123
|
+
const id = setInterval(() => {
|
|
124
|
+
const frame = SPINNER_FRAMES[i % SPINNER_FRAMES.length];
|
|
125
|
+
process.stdout.write(`\r ${chalk.cyan(frame)} ${message}`);
|
|
126
|
+
i++;
|
|
127
|
+
}, 80);
|
|
128
|
+
try {
|
|
129
|
+
const result = await fn();
|
|
130
|
+
process.stdout.write(`\r${" ".repeat(message.length + 6)}\r`);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
clearInterval(id);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
export async function runHealthCheck(clients, method) {
|
|
138
|
+
console.log(chalk.bold("\nš„ Health Check\n"));
|
|
139
|
+
if (method === "cdp") {
|
|
140
|
+
const ready = await confirm({
|
|
141
|
+
message: "Have you relaunched Figma with the --remote-debugging-port flag?",
|
|
142
|
+
default: true,
|
|
143
|
+
});
|
|
144
|
+
if (!ready) {
|
|
145
|
+
console.log(chalk.yellow("\n Complete the setup steps above, then run the wizard again.\n"));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
let healthy = false;
|
|
150
|
+
while (!healthy) {
|
|
151
|
+
if (method === "cdp") {
|
|
152
|
+
healthy = await withSpinner("Checking CDP endpoint...", checkCdp);
|
|
153
|
+
if (healthy) {
|
|
154
|
+
console.log(chalk.green(" ā Figma CDP endpoint reachable (localhost:9222)"));
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.log(chalk.yellow(" ā Figma CDP endpoint not reachable ā launch Figma with the connection method you chose"));
|
|
158
|
+
}
|
|
159
|
+
if (!healthy) {
|
|
160
|
+
const action = await select({
|
|
161
|
+
message: "What would you like to do?",
|
|
162
|
+
choices: [
|
|
163
|
+
{ name: "Retry health check", value: "retry" },
|
|
164
|
+
{ name: "Exit setup", value: "exit" },
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
if (action === "exit") {
|
|
168
|
+
console.log(chalk.yellow("\n Setup incomplete. Run the wizard again when ready.\n"));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
console.log("");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
console.log(chalk.cyan("\n ā Start (or restart) the Figma Console Bridge plugin in Figma now.\n"));
|
|
176
|
+
const result = await waitForBridgeWithCancel();
|
|
177
|
+
if (result === "connected") {
|
|
178
|
+
console.log(chalk.green(" ā Bridge plugin connected"));
|
|
179
|
+
healthy = true;
|
|
180
|
+
}
|
|
181
|
+
else if (result === "cancelled") {
|
|
182
|
+
console.log(chalk.yellow("\n Setup cancelled. Run the wizard again when ready.\n"));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
console.log(chalk.yellow(" ā Bridge plugin not detected ā make sure you started/restarted the plugin after seeing this prompt"));
|
|
187
|
+
const action = await select({
|
|
188
|
+
message: "What would you like to do?",
|
|
189
|
+
choices: [
|
|
190
|
+
{ name: "Retry health check", value: "retry" },
|
|
191
|
+
{ name: "Exit setup", value: "exit" },
|
|
192
|
+
],
|
|
193
|
+
});
|
|
194
|
+
if (action === "exit") {
|
|
195
|
+
console.log(chalk.yellow("\n Setup incomplete. Run the wizard again when ready.\n"));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
console.log("");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Success dashboard
|
|
203
|
+
console.log(chalk.bold.green("\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"));
|
|
204
|
+
console.log(chalk.bold.green(" ā
Setup Complete!"));
|
|
205
|
+
console.log(chalk.bold.green("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n"));
|
|
206
|
+
console.log(chalk.bold(" Configured clients:"));
|
|
207
|
+
for (const c of clients) {
|
|
208
|
+
console.log(chalk.green(` ⢠${c.name}`));
|
|
209
|
+
}
|
|
210
|
+
console.log(chalk.bold("\n Try these prompts in your AI client:\n"));
|
|
211
|
+
console.log(chalk.dim(' "Take a screenshot of the current Figma file"'));
|
|
212
|
+
console.log(chalk.dim(' "List all components in the design system"'));
|
|
213
|
+
console.log(chalk.dim(' "Create a 400Ć300 frame with a blue background"\n'));
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=healthCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"healthCheck.js","sourceRoot":"","sources":["../../src/steps/healthCheck.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runSystemCheck(): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getPlatform, getLocalAppDataPath } from '../utils/platform.js';
|
|
5
|
+
export async function runSystemCheck() {
|
|
6
|
+
console.log(chalk.bold('\nš System Check\n'));
|
|
7
|
+
// Node version check
|
|
8
|
+
const nodeVersion = process.version;
|
|
9
|
+
const major = parseInt(nodeVersion.slice(1).split('.')[0], 10);
|
|
10
|
+
if (major >= 18) {
|
|
11
|
+
console.log(chalk.green(` ā Node.js ${nodeVersion}`));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log(chalk.red(` ā Node.js ${nodeVersion} ā version 18+ required`));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
// Figma Desktop check
|
|
18
|
+
const platform = getPlatform();
|
|
19
|
+
let figmaInstalled = false;
|
|
20
|
+
if (platform === 'macos') {
|
|
21
|
+
figmaInstalled = fs.existsSync('/Applications/Figma.app');
|
|
22
|
+
}
|
|
23
|
+
else if (platform === 'windows') {
|
|
24
|
+
figmaInstalled = fs.existsSync(path.join(getLocalAppDataPath(), 'Figma', 'Figma.exe'));
|
|
25
|
+
}
|
|
26
|
+
if (figmaInstalled) {
|
|
27
|
+
console.log(chalk.green(' ā Figma Desktop detected'));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(chalk.yellow(' ā Figma Desktop not found ā install from https://figma.com/downloads'));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=systemCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"systemCheck.js","sourceRoot":"","sources":["../../src/steps/systemCheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAE/C,qBAAqB;IACrB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/D,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,WAAW,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,WAAW,yBAAyB,CAAC,CAAC,CAAC;QAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,sBAAsB;IACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;IAC5D,CAAC;SAAM,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,cAAc,GAAG,EAAE,CAAC,UAAU,CAC5B,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CACvD,CAAC;IACJ,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACzD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wEAAwE,CAAC,CAAC,CAAC;IACtG,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function readJsonConfig(filePath: string): Record<string, unknown>;
|
|
2
|
+
export declare function writeJsonConfig(filePath: string, data: Record<string, unknown>): void;
|
|
3
|
+
export declare function mergeServerConfig(existing: Record<string, unknown>, token: string): Record<string, unknown>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function readJsonConfig(filePath) {
|
|
4
|
+
try {
|
|
5
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
6
|
+
return JSON.parse(content);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return {};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function writeJsonConfig(filePath, data) {
|
|
13
|
+
const dir = path.dirname(filePath);
|
|
14
|
+
if (!fs.existsSync(dir)) {
|
|
15
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
18
|
+
}
|
|
19
|
+
export function mergeServerConfig(existing, token) {
|
|
20
|
+
const mcpServers = existing.mcpServers || {};
|
|
21
|
+
return {
|
|
22
|
+
...existing,
|
|
23
|
+
mcpServers: {
|
|
24
|
+
...mcpServers,
|
|
25
|
+
'figma-console': {
|
|
26
|
+
command: 'npx',
|
|
27
|
+
args: ['-y', 'figma-console-mcp@latest'],
|
|
28
|
+
env: {
|
|
29
|
+
FIGMA_ACCESS_TOKEN: token,
|
|
30
|
+
ENABLE_MCP_APPS: 'true',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,IAA6B;IAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,QAAiC,EACjC,KAAa;IAEb,MAAM,UAAU,GAAI,QAAQ,CAAC,UAAsC,IAAI,EAAE,CAAC;IAC1E,OAAO;QACL,GAAG,QAAQ;QACX,UAAU,EAAE;YACV,GAAG,UAAU;YACb,eAAe,EAAE;gBACf,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,IAAI,EAAE,0BAA0B,CAAC;gBACxC,GAAG,EAAE;oBACH,kBAAkB,EAAE,KAAK;oBACzB,eAAe,EAAE,MAAM;iBACxB;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveManifestPath(): string | null;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
export function resolveManifestPath() {
|
|
6
|
+
return resolveViaNpx() ?? resolveViaNpmRoot();
|
|
7
|
+
}
|
|
8
|
+
function resolveViaNpx() {
|
|
9
|
+
// 1. Try running the command itself
|
|
10
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
11
|
+
try {
|
|
12
|
+
const result = spawnSync("npx", ["-y", "figma-console-mcp@latest", "--print-path"], {
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
timeout: 10_000,
|
|
15
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
16
|
+
});
|
|
17
|
+
const output = (result.stdout || "") + (result.stderr || "");
|
|
18
|
+
if (output) {
|
|
19
|
+
const match = output.match(/[^\s"']+\/manifest\.json|[^\s"']+\\manifest\.json/);
|
|
20
|
+
if (match)
|
|
21
|
+
return match[0].trim();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// retry
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// 2. Fallback: Search the NPX cache directly
|
|
29
|
+
try {
|
|
30
|
+
const npxDir = join(homedir(), ".npm", "_npx");
|
|
31
|
+
if (existsSync(npxDir)) {
|
|
32
|
+
const result = spawnSync("find", [npxDir, "-name", "manifest.json"], {
|
|
33
|
+
encoding: "utf-8",
|
|
34
|
+
timeout: 5_000,
|
|
35
|
+
});
|
|
36
|
+
if (result.stdout) {
|
|
37
|
+
const found = result.stdout
|
|
38
|
+
.split("\n")
|
|
39
|
+
.find((line) => line.includes("figma-console-mcp") &&
|
|
40
|
+
line.includes("figma-desktop-bridge"));
|
|
41
|
+
if (found)
|
|
42
|
+
return found.trim();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// ignore
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function resolveViaNpmRoot() {
|
|
52
|
+
const subpath = join("figma-console-mcp", "figma-desktop-bridge", "manifest.json");
|
|
53
|
+
for (const args of [["-g"], []]) {
|
|
54
|
+
try {
|
|
55
|
+
const result = spawnSync("npm", ["root", ...args], {
|
|
56
|
+
encoding: "utf-8",
|
|
57
|
+
timeout: 5_000,
|
|
58
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
59
|
+
});
|
|
60
|
+
if (result.status === 0 && result.stdout) {
|
|
61
|
+
const root = result.stdout.trim().split("\n")[0];
|
|
62
|
+
if (root) {
|
|
63
|
+
const candidate = join(root, subpath);
|
|
64
|
+
if (existsSync(candidate)) {
|
|
65
|
+
return candidate;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// try next
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/utils/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type Platform = 'macos' | 'windows' | 'linux';
|
|
2
|
+
export declare function getPlatform(): Platform;
|
|
3
|
+
export declare function getHomedir(): string;
|
|
4
|
+
export declare function resolveConfigPath(...segments: string[]): string;
|
|
5
|
+
export declare function getAppDataPath(): string;
|
|
6
|
+
export declare function getLocalAppDataPath(): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function getPlatform() {
|
|
4
|
+
switch (os.platform()) {
|
|
5
|
+
case 'darwin':
|
|
6
|
+
return 'macos';
|
|
7
|
+
case 'win32':
|
|
8
|
+
return 'windows';
|
|
9
|
+
default:
|
|
10
|
+
return 'linux';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function getHomedir() {
|
|
14
|
+
return os.homedir();
|
|
15
|
+
}
|
|
16
|
+
export function resolveConfigPath(...segments) {
|
|
17
|
+
return path.join(getHomedir(), ...segments);
|
|
18
|
+
}
|
|
19
|
+
export function getAppDataPath() {
|
|
20
|
+
const platform = getPlatform();
|
|
21
|
+
if (platform === 'windows') {
|
|
22
|
+
return process.env.APPDATA || path.join(getHomedir(), 'AppData', 'Roaming');
|
|
23
|
+
}
|
|
24
|
+
if (platform === 'macos') {
|
|
25
|
+
return path.join(getHomedir(), 'Library', 'Application Support');
|
|
26
|
+
}
|
|
27
|
+
return path.join(getHomedir(), '.config');
|
|
28
|
+
}
|
|
29
|
+
export function getLocalAppDataPath() {
|
|
30
|
+
return process.env.LOCALAPPDATA || path.join(getHomedir(), 'AppData', 'Local');
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,UAAU,WAAW;IACzB,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;QACtB,KAAK,QAAQ;YACX,OAAO,OAAO,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,SAAS,CAAC;QACnB;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAG,QAAkB;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACjF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "figma-console-mcp-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Interactive CLI to configure Figma Console MCP across AI coding clients",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"figma-console-mcp-cli": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsx src/index.ts",
|
|
15
|
+
"start": "node dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@inquirer/prompts": "^7.0.0",
|
|
19
|
+
"chalk": "^5.4.1",
|
|
20
|
+
"commander": "^13.1.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.13.4",
|
|
24
|
+
"tsx": "^4.19.3",
|
|
25
|
+
"typescript": "^5.7.3"
|
|
26
|
+
}
|
|
27
|
+
}
|