# Next Session Pickup — EXTRACT-006 + combined release

> 生成时间：2026-05-18  
> 上次 session 结束状态：CANONICAL-007 ✅ (commit 63a9cdaf)；EXTRACT-006 范围已确认；版本策略 = Phase 6.8 + Tier 2-E/F + CANONICAL-007 + EXTRACT-006 合并一次 release

---

## 1. 当前进度快照

```
Phase 6.8 canonicalTheme axis      ✅ commit 136ddc4b
Tier 2-E figma-url-to-canonical    ✅ commit 27c90388
Tier 2-F lint-skills               ✅ commit 27c90388
CANONICAL-007 Pagination → Button  ✅ commit 63a9cdaf
EXTRACT-006 extract Styles         🔲 next task (~3-4h)
Release wrap-up                    🔲 after EXTRACT-006
```

package.json version 当前：**0.4.0**（changeset 已有，`pnpm changeset version` 将在 release 时执行）

---

## 2. EXTRACT-006 — 详细规格

### 变更文件（仅 2 个）

**`figma-sync/api.mjs`** — 加一个函数：

```js
export async function getFileStyles() {
  return get(`/files/${FILE_KEY}/styles`)
}
```

Figma REST API: `GET /v1/files/{file_key}/styles`  
返回：`{ styles: [ { key, node_id, name, styleType, description, ... } ] }`  
styleType 值：`TEXT` | `EFFECT` | `FILL` | `GRID`

---

**`figma-sync/extract.mjs`** — 加 `extractStyles()` 函数并 wire-in：

```js
import { ..., getFileStyles } from './api.mjs'

export async function extractStyles() {
  // 1. 拉 style list
  const { styles } = await getFileStyles()

  // 2. 按 styleType 分组，收集 node_id
  const byType = { TEXT: [], EFFECT: [], FILL: [], GRID: [] }
  for (const s of styles) {
    const bucket = byType[s.styleType]
    if (bucket) bucket.push(s)
  }

  // 3. getNodes 拿各类型详情（分批，每次 ≤200 ids）
  // TEXT → node.style 字段：fontFamily/fontWeight/fontSize/lineHeight/letterSpacing
  // EFFECT → node.effects[] 字段：type/radius/spread/offset/color
  // FILL → node.fills[] 字段：type/color/opacity

  // 4. 输出 schema 与现有 figma-data/normalized/figma-styles.json 兼容：
  // {
  //   _meta: { extractedAt, source: 'figma-api', figmaFileKey },
  //   textStyles:   { [name]: { fontFamily, fontWeight, fontSize, lineHeight, lineHeightPercent, letterSpacing } },
  //   effectStyles: { [name]: { type, layers: [...], cssBoxShadow } },
  //   fillStyles:   { [name]: { type, color, opacity } },
  //   gridStyles:   { [name]: { pattern, sectionSize, ... } },
  // }
  // 注意：保留现有 canonicalToken / usage 字段（如已有则不覆盖，merge 而非替换）

  saveJson('normalized/figma-styles.json', output, ['_meta.extractedAt'])
}
```

Wire-in（在 `if (process.argv[1] ===...)`  블록 추가）：
```js
  try {
    await extractStyles()
  } catch (error) {
    console.warn(`styles: skipped (${error.message})`)
  }
```

---

### Schema 兼容性约束

现有文件 `figma-data/normalized/figma-styles.json` 有：
- `textStyles` — 7 entries，字段 `fontFamily/fontWeight/fontSize/lineHeight/lineHeightPercent/letterSpacing/canonicalToken`
- `effectStyles` — 4 entries，字段 `type/layers/cssBoxShadow/canonicalToken/usage`
- `scaleTokens` — 手动维护，**不改动，不覆盖**
- `_alignment_decisions` — 手动维护，**不改动，不覆盖**

策略：`extractStyles()` 只更新 `textStyles` / `effectStyles` / `fillStyles` / `gridStyles`；`scaleTokens` 和 `_alignment_decisions` 从现有文件读取并原样保留。

---

### idempotency

用现有 `saveJson(relPath, data, ['_meta.extractedAt'])` 模式。提取结果不变时不写文件（防止 pre-commit hook 误报 figma-data 变更）。

---

### 批量 getNodes 注意事项

Figma `getNodes` 支持 `ids` 参数，URL 长度限制约 2000 chars。每个 node_id 约 15 chars → 每批 ≤ 100 ids 安全。如有大量 styles，分批循环。

---

## 3. Verify 命令（executor 完成后）

```bash
pnpm exec vue-tsc --noEmit          # 0 errors
pnpm test                           # 117 passed | 1 skipped
node figma-sync/extract.mjs --dry-run 2>/dev/null || echo "no dry-run flag"
# 如果 Figma API 可用，实跑：
# pnpm sync:extract
# 验证 figma-data/normalized/figma-styles.json 的 textStyles/effectStyles 字段被更新
```

---

## 4. Release wrap-up（EXTRACT-006 完成后执行）

步骤：
1. 更新 `.changeset/v050-button-canonical-theme.md` — 把 CANONICAL-007 + EXTRACT-006 加入描述
2. `pnpm changeset version` → 版本升到 0.5.0
3. 更新 `CHANGELOG.md` — 合并 4 项内容（Phase 6.8 / Tier 2-E/F / CANONICAL-007 / EXTRACT-006）
4. `STATUS.md` 当前版本升 v0.5.0
5. tracker 补 EXTRACT-006 ✅ 行 + v0.5.0 ✅ shipped 证据
6. commit `release: v0.5.0`
7. **用户 ack** → `git tag v0.5.0 && git push origin v0.5.0`
8. CI 监控 → Packages 实物 verify
9. 回填证据 → wrap-up commit → push

---

## 5. 起手第一句话（新 session）

```
按 docs/internal/_plans/next-session-pickup-2026-05-18-extract-006.md 接手，做 EXTRACT-006
```
