figma-generate-personal-token
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesefigma-generate-personal-token
figma-generate-personal-token
Manages the complete lifecycle of : detection, validation, automated generation via browser, and persistence to the project .
FIGMA_TOKEN.envSupports auto-login if and are available in the environment or files.
FIGMA_USERNAMEFIGMA_PASSWORD.env管理的完整生命周期:检测、验证、通过浏览器自动生成,以及持久化到项目的文件中。
FIGMA_TOKEN.env若环境或文件中存在和,则支持自动登录。
.envFIGMA_USERNAMEFIGMA_PASSWORDWorkflow (follow this exact order)
工作流程(严格遵循以下顺序)
Step 1 — Run the main script
步骤1 — 运行主脚本
bash
SCRIPT_OUTPUT=$(python3 .claude/skills/figma-generate-personal-token/scripts/manage-token.py)
EXIT_CODE=$?
echo "$SCRIPT_OUTPUT"
echo "EXIT_CODE=$EXIT_CODE"The script returns:
- → token valid, nothing to do
exit 0 - →
exit 3/FIGMA_USERNAMEfound → auto-login (see Step 2)FIGMA_PASSWORD - → no token/expired or no credentials → manual login (see Step 3)
exit 2 - → unexpected error
exit 1
bash
SCRIPT_OUTPUT=$(python3 .claude/skills/figma-generate-personal-token/scripts/manage-token.py)
EXIT_CODE=$?
echo "$SCRIPT_OUTPUT"
echo "EXIT_CODE=$EXIT_CODE"脚本返回值说明:
- → 令牌有效,无需操作
exit 0 - → 检测到
exit 3/FIGMA_USERNAME→ 自动登录(见步骤2)FIGMA_PASSWORD - → 无令牌/令牌过期 或 无凭据 → 手动登录(见步骤3)
exit 2 - → 意外错误
exit 1
Step 2 — Auto-login with credentials (exit 3)
步骤2 — 使用凭据自动登录(exit 3)
The script found and . Its stdout contains two lines with the values
to use — note: is just the script's output format, not the name of the source
env vars. Extract them from :
FIGMA_USERNAMEFIGMA_PASSWORDFIGMA_AUTO_LOGIN_*$SCRIPT_OUTPUTbash
USERNAME=$(echo "$SCRIPT_OUTPUT" | grep "^FIGMA_AUTO_LOGIN_USERNAME=" | cut -d= -f2-)
PASSWORD=$(echo "$SCRIPT_OUTPUT" | grep "^FIGMA_AUTO_LOGIN_PASSWORD=" | cut -d= -f2-)Open the browser, fill the form and submit in one chain:
bash
agent-browser open "https://www.figma.com/login" && agent-browser wait --load networkidle && agent-browser snapshot -iFill the form (refs come from the snapshot):
@eXbash
agent-browser fill @eX "$USERNAME" && agent-browser fill @eY "$PASSWORD" && agent-browser click @eZWait for post-login redirect:
bash
agent-browser wait --load networkidle --timeout 30000 && agent-browser get urlIf the URL still contains , Figma may require 2FA — wait for the user to complete the flow:
/loginbash
agent-browser wait --fn "!window.location.href.includes('/login')" --timeout 120000Then continue to Step 4.
脚本检测到和。其标准输出包含两行需使用的值——注意:仅为脚本输出格式,并非源环境变量的名称。从中提取:
FIGMA_USERNAMEFIGMA_PASSWORDFIGMA_AUTO_LOGIN_*$SCRIPT_OUTPUTbash
USERNAME=$(echo "$SCRIPT_OUTPUT" | grep "^FIGMA_AUTO_LOGIN_USERNAME=" | cut -d= -f2-)
PASSWORD=$(echo "$SCRIPT_OUTPUT" | grep "^FIGMA_AUTO_LOGIN_PASSWORD=" | cut -d= -f2-)打开浏览器,一次性完成表单填写与提交:
bash
agent-browser open "https://www.figma.com/login" && agent-browser wait --load networkidle && agent-browser snapshot -i填写表单(等引用来自快照):
@eXbash
agent-browser fill @eX "$USERNAME" && agent-browser fill @eY "$PASSWORD" && agent-browser click @eZ等待登录后重定向:
bash
agent-browser wait --load networkidle --timeout 30000 && agent-browser get url若URL仍包含,则Figma可能需要二次验证(2FA)——等待用户完成验证流程:
/loginbash
agent-browser wait --fn "!window.location.href.includes('/login')" --timeout 120000随后继续步骤4。
Step 3 — Manual login (exit 2)
步骤3 — 手动登录(exit 2)
No credentials available. Navigate to settings and immediately check the resulting URL:
bash
agent-browser open "https://www.figma.com/settings" && agent-browser wait --load networkidle && agent-browser get url- If the URL does not contain → already logged in, skip to Step 4 immediately
/login - If the URL contains → inform the user, then wait up to 2 minutes:
/login
bash
agent-browser wait --fn "!window.location.href.includes('/login')" --timeout 120000ℹ️ A browser session from an earlier step in the same conversation may already be authenticated — always check the URL before waiting.
Then continue to Step 4.
无可用凭据。导航至设置页面并立即检查生成的URL:
bash
agent-browser open "https://www.figma.com/settings" && agent-browser wait --load networkidle && agent-browser get url- 若URL不包含→ 已登录,立即跳至步骤4
/login - 若URL包含→ 告知用户,然后等待最多2分钟:
/login
bash
agent-browser wait --fn "!window.location.href.includes('/login')" --timeout 120000ℹ️ 同一会话中之前步骤的浏览器会话可能已完成认证——等待前务必检查URL。
随后继续步骤4。
Step 4 — Open Settings and click the Security tab
步骤4 — 打开设置并点击“安全”标签页
After login, open settings. Figma redirects to the files page but opens the settings dialog automatically:
bash
agent-browser open "https://www.figma.com/settings" && agent-browser wait --load networkidleTake ONE snapshot, grep the Security tab ref, then click it directly:
bash
agent-browser snapshot -i | grep -E "tab.*(Séc|Secur)"
agent-browser click @eREF⚠️ Never useinside a Figma modal — it can close the dialog. ⚠️ Do NOT use JS eval with escaped quotes to find the Security tab — it returnsagent-browser scrollunreliably. Use snapshot refs instead.null
登录后,打开设置页面。Figma会重定向到文件页面,但会自动打开设置对话框:
bash
agent-browser open "https://www.figma.com/settings" && agent-browser wait --load networkidle拍摄一张快照,提取“安全”标签页的引用,然后直接点击:
bash
agent-browser snapshot -i | grep -E "tab.*(Séc|Secur)"
agent-browser click @eREF⚠️ 切勿在Figma模态框内使用——这会关闭对话框。 ⚠️ 不要使用带有转义引号的JS eval来查找“安全”标签页——它会不可靠地返回agent-browser scroll。请使用快照引用。null
Step 5 — Create the token
步骤5 — 创建令牌
Click "Generate new token" via JS with (avoids all shell escaping issues):
--stdinbash
agent-browser eval --stdin <<'EVALEOF'
(() => {
const btn = Array.from(document.querySelectorAll("button"))
.find(b => b.textContent.includes("Générer un nouveau token") || b.textContent.includes("Create new token") || b.textContent.includes("Generate new token"));
if (btn) { btn.scrollIntoView({ block: "center", behavior: "instant" }); btn.click(); return "clicked: " + btn.textContent.trim(); }
return "not found";
})()
EVALEOF
agent-browser wait 500ONE snapshot to get the name input and expiry combobox refs:
bash
agent-browser snapshot -i | grep -E "(textbox|combobox)"Fill the form in a single sequence:
bash
undefined通过带参数的JS点击“Generate new token”按钮(避免所有Shell转义问题):
--stdinbash
agent-browser eval --stdin <<'EVALEOF'
(() => {
const btn = Array.from(document.querySelectorAll("button"))
.find(b => b.textContent.includes("Générer un nouveau token") || b.textContent.includes("Create new token") || b.textContent.includes("Generate new token"));
if (btn) { btn.scrollIntoView({ block: "center", behavior: "instant" }); btn.click(); return "clicked: " + btn.textContent.trim(); }
return "not found";
})()
EVALEOF
agent-browser wait 500拍摄一张快照以获取名称输入框和到期时间下拉框的引用:
bash
agent-browser snapshot -i | grep -E "(textbox|combobox)"一次性完成表单填写:
bash
undefined1. Token name — auto-detect project name from cwd
1. 令牌名称——从当前工作目录自动检测项目名称
PROJECT_NAME=$(basename $(pwd))
agent-browser fill @eNAME_REF "Claude Code - $PROJECT_NAME"
PROJECT_NAME=$(basename $(pwd))
agent-browser fill @eNAME_REF "Claude Code - $PROJECT_NAME"
2. Longest expiry — the combobox is CUSTOM (not a <select>), use click + JS
2. 最长有效期——下拉框为自定义组件(非<select>),使用点击+JS实现
Click the combobox ref to open it:
点击下拉框引用以展开选项:
agent-browser click @eEXPIRY_REF
agent-browser click @eEXPIRY_REF
Then click the last [role="option"] via JS (longest duration):
然后通过JS点击最后一个[role="option"](最长有效期):
agent-browser eval --stdin <<'EVALEOF'
(() => {
const options = Array.from(document.querySelectorAll('[role="option"]'));
const last = options[options.length - 1];
if (last) { last.click(); return "selected: " + last.textContent.trim(); }
return "no options found";
})()
EVALEOF
agent-browser eval --stdin <<'EVALEOF'
(() => {
const options = Array.from(document.querySelectorAll('[role="option"]'));
const last = options[options.length - 1];
if (last) { last.click(); return "selected: " + last.textContent.trim(); }
return "no options found";
})()
EVALEOF
3. Check ALL permissions in one JS call — always use --stdin
3. 一次性勾选所有权限——务必使用--stdin参数
agent-browser eval --stdin <<'EVALEOF'
document.querySelectorAll('input[type="checkbox"]').forEach(cb => { if (!cb.checked) cb.click(); });
document.querySelectorAll('input[type="checkbox"]:checked').length + " checked"
EVALEOF
> ⚠️ **Never use `agent-browser select` for the expiry field** — Figma's expiry combobox is a custom component, not a native `<select>`. It will always fail with "Element is not a \<select\> element". Always use click + JS `[role="option"]`.
Click Generate via JS directly — **no snapshot needed**:
```bash
agent-browser eval --stdin <<'EVALEOF'
(() => {
const btn = Array.from(document.querySelectorAll("button"))
.find(b => b.textContent.trim() === "Générer un token" || b.textContent.trim() === "Generate token");
if (btn && !btn.disabled) { btn.click(); return "clicked"; }
return "not found or disabled: " + Array.from(document.querySelectorAll("button")).map(b => b.textContent.trim()).filter(Boolean).join(", ");
})()
EVALEOF
agent-browser wait 1000agent-browser eval --stdin <<'EVALEOF'
document.querySelectorAll('input[type="checkbox"]').forEach(cb => { if (!cb.checked) cb.click(); });
document.querySelectorAll('input[type="checkbox"]:checked').length + " checked"
EVALEOF
> ⚠️ **切勿对到期时间字段使用`agent-browser select`**——Figma的到期时间下拉框是自定义组件,而非原生`<select>`。使用该命令会始终报错“Element is not a \<select\> element”。请始终使用点击+JS `[role="option"]`的方式。
直接通过JS点击“Generate”按钮——**无需快照**:
```bash
agent-browser eval --stdin <<'EVALEOF'
(() => {
const btn = Array.from(document.querySelectorAll("button"))
.find(b => b.textContent.trim() === "Générer un token" || b.textContent.trim() === "Generate token");
if (btn && !btn.disabled) { btn.click(); return "clicked"; }
return "not found or disabled: " + Array.from(document.querySelectorAll("button")).map(b => b.textContent.trim()).filter(Boolean).join(", ");
})()
EVALEOF
agent-browser wait 1000Step 6 — Retrieve and persist the token
步骤6 — 获取并持久化令牌
Click the Copy button and read via (primary method — most reliable):
pbpastebash
agent-browser eval --stdin <<'EVALEOF'
(() => {
const btn = Array.from(document.querySelectorAll("button"))
.find(b => b.title?.match(/Copi/i) || b.getAttribute("aria-label")?.match(/Copi/i) || b.textContent?.match(/Copi/i));
if (btn) { btn.click(); return "clicked"; }
return "not found";
})()
EVALEOF
agent-browser wait 300
TOKEN_VALUE=$(pbpaste)
echo "Token retrieved: ${TOKEN_VALUE:0:8}..."If returns empty or not a Figma token, try reading from the DOM as a last resort:
pbpastebash
TOKEN_VALUE=$(agent-browser eval --stdin <<'EVALEOF'
Array.from(document.querySelectorAll("input")).find(i => i.value?.startsWith("figd_"))?.value || ""
EVALEOF
)⚠️ Do not use DOM read as primary — Figma's token display field may use internal React state rather than the DOMproperty, causing the read to return empty even when the token is visible on screen. The clipboard approach is always reliable..value
If is still empty after both attempts, stop and report the error — do not call :
TOKEN_VALUE--savebash
if [ -z "$TOKEN_VALUE" ] || [[ "$TOKEN_VALUE" != figd_* ]]; then
echo "❌ Could not retrieve token — check the Figma dialog is still open and the token is visible."
exit 1
fiThen save:
bash
python3 .claude/skills/figma-generate-personal-token/scripts/manage-token.py --save "$TOKEN_VALUE"点击复制按钮并通过读取(首选方法——最可靠):
pbpastebash
agent-browser eval --stdin <<'EVALEOF'
(() => {
const btn = Array.from(document.querySelectorAll("button"))
.find(b => b.title?.match(/Copi/i) || b.getAttribute("aria-label")?.match(/Copi/i) || b.textContent?.match(/Copi/i));
if (btn) { btn.click(); return "clicked"; }
return "not found";
})()
EVALEOF
agent-browser wait 300
TOKEN_VALUE=$(pbpaste)
echo "Token retrieved: ${TOKEN_VALUE:0:8}..."若返回空或非Figma令牌,则尝试从DOM读取作为最后手段:
pbpastebash
TOKEN_VALUE=$(agent-browser eval --stdin <<'EVALEOF'
Array.from(document.querySelectorAll("input")).find(i => i.value?.startsWith("figd_"))?.value || ""
EVALEOF
)⚠️ 不要将DOM读取作为首选方法——Figma的令牌显示字段可能使用内部React状态而非DOM的属性,导致即使令牌在屏幕上可见,读取结果仍为空。剪贴板方法始终可靠。.value
若经过两种尝试后仍为空,则停止操作并报告错误——不要调用:
TOKEN_VALUE--savebash
if [ -z "$TOKEN_VALUE" ] || [[ "$TOKEN_VALUE" != figd_* ]]; then
echo "❌ 无法获取令牌——请检查Figma对话框是否仍处于打开状态且令牌可见。"
exit 1
fi然后保存令牌:
bash
python3 .claude/skills/figma-generate-personal-token/scripts/manage-token.py --save "$TOKEN_VALUE"Step 7 — Close the browser
步骤7 — 关闭浏览器
Always close the browser session after the token has been saved:
bash
agent-browser close令牌保存完成后,务必关闭浏览器会话:
bash
agent-browser closeSupported .env
files (priority order)
.env支持的.env
文件(优先级顺序)
.envThe script searches and updates in this order:
| File | Usage | Priority |
|---|---|---|
| Vite/Next.js — gitignored by default | 1st (read) |
| Standard — write target | 2nd (read) / 1st (write) |
| Local dev | 3rd |
| Dev only | 4th |
The token is always written to . If is not gitignored, a warning is shown.
.env.env脚本按以下顺序搜索并更新文件:
| 文件 | 用途 | 优先级 |
|---|---|---|
| Vite/Next.js——默认被Git忽略 | 1st (读取) |
| 标准文件——写入目标 | 2nd (读取) / 1st (写入) |
| 本地开发环境 | 3rd |
| 仅开发环境 | 4th |
令牌始终写入文件。若未被Git忽略,脚本会显示警告。
.env.envVariables read (credentials)
读取的变量(凭据)
dotenv
FIGMA_USERNAME=your@email.com # or FIGMA_EMAIL
FIGMA_PASSWORD=your_passworddotenv
FIGMA_USERNAME=your@email.com # 或 FIGMA_EMAIL
FIGMA_PASSWORD=your_passwordVariables written (token)
写入的变量(令牌)
dotenv
FIGMA_TOKEN=figd_xxxxxdotenv
FIGMA_TOKEN=figd_xxxxxSecurity
安全说明
- Token is never logged in plaintext (masked: )
figd_W86...zjyM - Password is masked in human-readable output (); the structured exit-3 output prints it in plaintext so the agent can extract it — do not persist
********$SCRIPT_OUTPUT - If is not gitignored, the script shows a warning
.env - Never commit or
FIGMA_USERNAMEin a non-gitignoredFIGMA_PASSWORDfile.env
- 令牌永远不会以明文形式记录(掩码显示:)
figd_W86...zjyM - 密码在人类可读输出中被掩码();结构化的exit-3输出会以明文形式打印密码以便Agent提取——请勿持久化
********$SCRIPT_OUTPUT - 若未被Git忽略,脚本会显示警告
.env - 切勿在未被Git忽略的文件中提交
.env或FIGMA_USERNAMEFIGMA_PASSWORD
Troubleshooting
故障排除
"The generation dialog closes unexpectedly"
→ Always use JS to click the "Generate new token" button — never use a snapshot ref click. The JS approach calls first to ensure the element is in view before clicking.
scrollIntoView"Checkboxes fail partway through"
→ Do not use a shell loop over refs. Use exclusively the JS command in Step 5 which checks everything in a single evaluation.
for" returns empty"
→ Use directly on macOS. It is more reliable and synchronous.
agent-browser clipboard readpbpaste"Figma keeps redirecting without showing tokens"
→ Figma may require 2FA re-authentication. Let the user complete the flow in the visible browser.
"Permission denied on .env"
→ then retry.
chmod 644 .env"Token generated but immediately invalid"
→ Figma may have a propagation delay of a few seconds. The script retries automatically 3 times with a 2s interval.
"Auto-login fails despite valid credentials"
→ Verify and are correct via manual login.
→ If 2FA is enabled, auto-login will stop at the 2FA step — the user must complete it manually.
FIGMA_USERNAMEFIGMA_PASSWORD"Expiry select fails with 'Element is not a <select> element'"
→ Figma's expiry field is a custom combobox, not a native . Do not use . Instead: click the combobox ref to open it, then click the last via JS (see Step 5).
<select>agent-browser select[role="option"]"DOM input read returns empty even though the token is visible on screen"
→ Figma's token display input uses internal React state; may not reflect the rendered text. Always use the Copy button + as the primary retrieval method (see Step 6).
.valuepbpaste“生成对话框意外关闭”
→ 始终使用JS点击“Generate new token”按钮——切勿使用快照引用点击。JS方法会先调用确保元素可见后再点击。
scrollIntoView“勾选复选框中途失败”
→ 不要对引用使用Shell 循环。请完全使用步骤5中的JS命令,它会在单次求值中完成所有勾选操作。
for“返回空”
→ 在macOS上直接使用。它更可靠且同步。
agent-browser clipboard readpbpaste“Figma持续重定向而不显示令牌”
→ Figma可能需要重新进行二次验证(2FA)。让用户在可见的浏览器中完成验证流程。
“文件权限被拒绝”
→ 执行后重试。
.envchmod 644 .env“令牌已生成但立即无效”
→ Figma可能存在几秒的传播延迟。脚本会自动重试3次,每次间隔2秒。
“凭据有效但自动登录失败”
→ 通过手动登录验证和是否正确。
→ 若启用了2FA,自动登录会在2FA步骤停止——用户必须手动完成验证。
FIGMA_USERNAMEFIGMA_PASSWORD“到期时间选择失败,报错'Element is not a <select> element'”
→ Figma的到期时间字段是自定义下拉框,而非原生。请勿使用。正确做法:点击下拉框引用展开选项,然后通过JS点击最后一个(见步骤5)。
<select>agent-browser select[role="option"]“DOM输入框读取返回空,但令牌在屏幕上可见”
→ Figma的令牌显示输入框使用内部React状态;可能无法反映渲染的文本。请始终使用复制按钮+作为首选获取方法(见步骤6)。
.valuepbpaste