figma-cache-toolchain 2.0.1 → 2.0.3
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 +2 -2
- package/cursor-bootstrap/AGENT-SETUP-PROMPT.md +43 -60
- package/cursor-bootstrap/examples/README.md +10 -6
- package/cursor-bootstrap/examples/generated-ui-reset.css.template +32 -0
- package/cursor-bootstrap/examples/ui-1to1-preflight.template.md +80 -0
- package/cursor-bootstrap/managed-files.json +41 -0
- package/cursor-bootstrap/rules/02-figma-stack-adapter.mdc +15 -25
- package/cursor-bootstrap/rules/03-figma-ui-implementation-hard-constraints.mdc +58 -0
- package/cursor-bootstrap/rules/04-ui-baseline-governance.mdc +35 -0
- package/cursor-bootstrap/skills/figma-ui-dual-mode-execution/SKILL.md +37 -0
- package/figma-cache/docs/README.md +1 -1
- package/figma-cache/figma-cache.js +10 -4
- package/figma-cache/js/cursor-bootstrap-cli.js +218 -186
- package/package.json +75 -74
package/README.md
CHANGED
|
@@ -32,9 +32,9 @@ npx figma-cache cursor init
|
|
|
32
32
|
|
|
33
33
|
该命令会:
|
|
34
34
|
|
|
35
|
-
-
|
|
35
|
+
- 默认安全模式:保留已有 `.cursor/rules/`、`.cursor/skills/`,仅补缺失文件
|
|
36
36
|
- 新增通用规则:`.cursor/rules/00-output-token-budget.mdc`(全任务低 token 输出基线)
|
|
37
|
-
-
|
|
37
|
+
- 若需覆盖现有模板,可使用 `npx figma-cache cursor init --overwrite`
|
|
38
38
|
- 确保根目录存在 `figma-cache.config.js`
|
|
39
39
|
- 刷新根目录 `AGENT-SETUP-PROMPT.md`
|
|
40
40
|
- 同步刷新 `figma-cache/docs/colleague-guide-zh.md`
|
|
@@ -1,60 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- 除非用户明确要求,禁止在 chat 中贴出 `get_design_context` 全文;原始内容仅保存到 `mcp-raw/*`。
|
|
45
|
-
|
|
46
|
-
## 硬约束(违反则视为未完成)
|
|
47
|
-
|
|
48
|
-
- **不要**修改 `node_modules/{{NPM_PACKAGE_NAME}}/` 下已发布包内文件(应无此必要)。
|
|
49
|
-
- **不要**修改 `figma-cache/figma-cache.js` 或破坏 Core「框架中立」语义。
|
|
50
|
-
- **不要**把业务路由名、具体组件库 API 写进 `figma-cache/files/**` 下的 `meta.json` / `raw.json` / `spec.md`。
|
|
51
|
-
|
|
52
|
-
## 可选参考(仅在用户需要 Vue2+Vuetify2 时)
|
|
53
|
-
|
|
54
|
-
包内附带参考文本(**不在 init 时复制到 .cursor**):
|
|
55
|
-
`node_modules/{{NPM_PACKAGE_NAME}}/cursor-bootstrap/examples/vue2-vuetify2-adapter.reference.mdc`
|
|
56
|
-
若用户明确要求该栈,可读入后改写为第 4 步的 Adapter 规则内容。
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
**开始执行:**读完本文件后立刻按上述顺序操作仓库文件,直至全部完成。
|
|
1
|
+
# Figma Cache:请 Agent 一次性完成项目适配(精简)
|
|
2
|
+
|
|
3
|
+
> 前提:你在用户业务项目根目录;以下模板来自 `{{NPM_PACKAGE_NAME}}`。
|
|
4
|
+
|
|
5
|
+
## 必做(按序)
|
|
6
|
+
1. 读取项目栈事实(package.json + 构建配置)。
|
|
7
|
+
2. 合并/创建 `figma-cache.config.js`(不破坏用户已有逻辑)。
|
|
8
|
+
3. 生成 `.cursor/rules/02-figma-<stack>-adapter.mdc`。
|
|
9
|
+
4. 验证新 adapter 可用(语法 + 最小执行验证)。
|
|
10
|
+
5. 补全 `figma:cache:*` scripts(缺失时)。
|
|
11
|
+
|
|
12
|
+
## 老项目 UI 基线(默认 B0)
|
|
13
|
+
1. 复制模板:
|
|
14
|
+
`node_modules/{{NPM_PACKAGE_NAME}}/cursor-bootstrap/examples/generated-ui-reset.css.template`
|
|
15
|
+
-> 项目 `src/styles/generated-ui-reset.css`
|
|
16
|
+
2. 在入口(如 `src/main.ts`)单次引入。
|
|
17
|
+
3. 后续生成组件根节点统一加:`generate-ui-reset`。
|
|
18
|
+
4. 若用户要求更强控制,再升级 B1/B2。
|
|
19
|
+
|
|
20
|
+
## 生成完成后清理临时模板文件(强制)
|
|
21
|
+
- 删除 `.cursor/rules/02-figma-stack-adapter.mdc`
|
|
22
|
+
- 删除 `AGENT-SETUP-PROMPT.md`
|
|
23
|
+
|
|
24
|
+
## 规则优先级
|
|
25
|
+
- 缓存层:`01-figma-cache-core.mdc`
|
|
26
|
+
- UI 实现:`03-figma-ui-implementation-hard-constraints.mdc`
|
|
27
|
+
- 基线治理:`04-ui-baseline-governance.mdc`
|
|
28
|
+
- 输出约束:`00-output-token-budget.mdc`
|
|
29
|
+
|
|
30
|
+
## UI 标签口径
|
|
31
|
+
- 默认优先 `div/span/img`
|
|
32
|
+
- 默认禁用 `p/ul/li/ol/h1-h6`(除非用户明确要求)
|
|
33
|
+
- `input/select/textarea/a` 可直接使用
|
|
34
|
+
- 原生 `button` 默认禁用(封装或 UI 库按钮除外)
|
|
35
|
+
- `role/aria-*` 默认不强制
|
|
36
|
+
- `data-node-id/data-name` 默认不输出(调试模式除外)
|
|
37
|
+
|
|
38
|
+
## 输出约束
|
|
39
|
+
- 结果优先,不贴 MCP 长原文。
|
|
40
|
+
- 仅输出:结论、关键改动、验证结果、下一步。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
开始执行:直接落文件并完成验证。
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
# 栈相关参考(不随 `cursor init` 复制)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本目录存放可选参考与模板文件:
|
|
4
4
|
|
|
5
5
|
| 文件 | 说明 |
|
|
6
|
-
|
|
7
|
-
| `vue2-vuetify2-adapter.reference.mdc` | 历史
|
|
8
|
-
|
|
9
|
-
将参考规则复制进 `.cursor/rules/` 后,建议同步 `figma-cache.config.js` 的 adapter 提示策略:默认使用 `FIGMA_CACHE_ADAPTER_DOC_MODE=cache-root`(目录级单文件),仅在明确需要节点文档时改为 `node`。
|
|
6
|
+
|---|---|
|
|
7
|
+
| `vue2-vuetify2-adapter.reference.mdc` | 历史 Vue2 + Vuetify2 参考规则 |
|
|
8
|
+
| `generated-ui-reset.css.template` | 老项目 B0 局部 reset 模板(推荐默认) |
|
|
10
9
|
|
|
10
|
+
## B0 推荐用法(目标业务项目)
|
|
11
|
+
1. 复制模板到项目:`src/styles/generated-ui-reset.css`
|
|
12
|
+
2. 在入口(如 `src/main.ts`)引入一次
|
|
13
|
+
3. 生成组件根节点加 `generate-ui-reset`
|
|
11
14
|
|
|
15
|
+
说明:B0 仅做局部基线,不污染全局;B1/B2 见 `04-ui-baseline-governance.mdc`。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* Generated UI local reset (scoped) */
|
|
2
|
+
|
|
3
|
+
:where(.generate-ui-reset),
|
|
4
|
+
:where(.generate-ui-reset *) {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:where(.generate-ui-reset img),
|
|
9
|
+
:where(.generate-ui-reset svg),
|
|
10
|
+
:where(.generate-ui-reset video),
|
|
11
|
+
:where(.generate-ui-reset canvas) {
|
|
12
|
+
display: block;
|
|
13
|
+
max-width: 100%;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:where(.generate-ui-reset input),
|
|
17
|
+
:where(.generate-ui-reset select),
|
|
18
|
+
:where(.generate-ui-reset textarea),
|
|
19
|
+
:where(.generate-ui-reset button),
|
|
20
|
+
:where(.generate-ui-reset a) {
|
|
21
|
+
font: inherit;
|
|
22
|
+
color: inherit;
|
|
23
|
+
letter-spacing: inherit;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Optional strict mode for high-fidelity pages only */
|
|
27
|
+
:where(.generate-ui-reset--strict input),
|
|
28
|
+
:where(.generate-ui-reset--strict select),
|
|
29
|
+
:where(.generate-ui-reset--strict textarea) {
|
|
30
|
+
margin: 0;
|
|
31
|
+
border-radius: 0;
|
|
32
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# UI 1:1 实现前预检模板
|
|
2
|
+
|
|
3
|
+
> 用途:在“开始写组件前”完成事实快照、状态对照与预检,降低返工。
|
|
4
|
+
> 适用:Figma 缓存驱动实现(任意 nodeId)。
|
|
5
|
+
|
|
6
|
+
## 0. 基本信息
|
|
7
|
+
|
|
8
|
+
- fileKey:
|
|
9
|
+
- nodeId:
|
|
10
|
+
- cachePath:
|
|
11
|
+
- 实现目标页面/组件路径:
|
|
12
|
+
- 执行模式(短流程 / 严格流程):
|
|
13
|
+
|
|
14
|
+
## 1. 设计值快照(Design Facts)
|
|
15
|
+
|
|
16
|
+
### 1.1 结构与尺寸
|
|
17
|
+
|
|
18
|
+
- 根容器(宽/高/圆角/边框/背景):
|
|
19
|
+
- 关键子容器尺寸:
|
|
20
|
+
- 宽度策略(固定 / 自适应,仅可选一):
|
|
21
|
+
- 对齐策略(左/右/居中):
|
|
22
|
+
|
|
23
|
+
### 1.2 文案
|
|
24
|
+
|
|
25
|
+
- 标签文本:
|
|
26
|
+
- 值文本:
|
|
27
|
+
- 选项文本:
|
|
28
|
+
|
|
29
|
+
### 1.3 Token
|
|
30
|
+
|
|
31
|
+
- 字体(size/line-height/weight/letter-spacing):
|
|
32
|
+
- 主文本色:
|
|
33
|
+
- 次文本色:
|
|
34
|
+
- 背景色:
|
|
35
|
+
- 边框色:
|
|
36
|
+
- 状态色(hover/focus/selected):
|
|
37
|
+
|
|
38
|
+
### 1.4 交互与语义
|
|
39
|
+
|
|
40
|
+
- 交互触发(click/esc/outside/keyboard):
|
|
41
|
+
- 语义角色(combobox/listbox/option 等):
|
|
42
|
+
- 禁止项(本任务):
|
|
43
|
+
|
|
44
|
+
## 2. 状态对照表(必须填写)
|
|
45
|
+
|
|
46
|
+
| 状态 | 背景 | 边框 | 文本 | 图标 | 数据状态 | 是否实现 |
|
|
47
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
48
|
+
| default | | | | | | [ ] |
|
|
49
|
+
| hover | | | | | | [ ] |
|
|
50
|
+
| focus | | | | | | [ ] |
|
|
51
|
+
| active | | | | | | [ ] |
|
|
52
|
+
| expanded | | | | | | [ ] |
|
|
53
|
+
| selected | | | | | | [ ] |
|
|
54
|
+
| unselected | | | | | | [ ] |
|
|
55
|
+
| disabled(若存在) | | | | | | [ ] |
|
|
56
|
+
|
|
57
|
+
## 3. 1:1 预检清单(实现前)
|
|
58
|
+
|
|
59
|
+
- [ ] 已读取 `spec.md` / `raw.json` / `state-map.md` / `mcp-raw-get-design-context.txt`
|
|
60
|
+
- [ ] 冲突裁决规则确认:`mcp-raw-get-design-context.txt` 优先
|
|
61
|
+
- [ ] 全组件盒模型策略一致(建议 `box-border`)
|
|
62
|
+
- [ ] 文本溢出策略明确(`min-w-0` + `truncate` 或等效)
|
|
63
|
+
- [ ] 弹层锚定触发器(非页面硬编码定位)
|
|
64
|
+
- [ ] 图标策略确认(项目图标库优先;兜底 `inline svg`)
|
|
65
|
+
- [ ] 禁止使用 Figma 临时远程资产 URL 作为运行时图标
|
|
66
|
+
- [ ] 禁止无意义标签嵌套
|
|
67
|
+
- [ ] 默认无横向滚动
|
|
68
|
+
|
|
69
|
+
## 4. 实现后验收(最小)
|
|
70
|
+
|
|
71
|
+
- [ ] 改动文件 lint 通过
|
|
72
|
+
- [ ] 关键状态可见且可切换(至少 default/expanded/selected/unselected)
|
|
73
|
+
- [ ] 关键视觉项(尺寸/对齐/图标居中)通过
|
|
74
|
+
- [ ] 输出“设计值 -> 代码映射”
|
|
75
|
+
|
|
76
|
+
## 5. 失败反馈(固定三段)
|
|
77
|
+
|
|
78
|
+
1. 失败原因
|
|
79
|
+
2. 定位信息(文件/字段/样式项)
|
|
80
|
+
3. 修复动作
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"managedFiles": [
|
|
3
|
+
{
|
|
4
|
+
"from": "rules/00-output-token-budget.mdc",
|
|
5
|
+
"to": ".cursor/rules/00-output-token-budget.mdc"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"from": "rules/01-figma-cache-core.mdc",
|
|
9
|
+
"to": ".cursor/rules/01-figma-cache-core.mdc"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"from": "rules/02-figma-stack-adapter.mdc",
|
|
13
|
+
"to": ".cursor/rules/02-figma-stack-adapter.mdc"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"from": "rules/03-figma-ui-implementation-hard-constraints.mdc",
|
|
17
|
+
"to": ".cursor/rules/03-figma-ui-implementation-hard-constraints.mdc"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"from": "rules/04-ui-baseline-governance.mdc",
|
|
21
|
+
"to": ".cursor/rules/04-ui-baseline-governance.mdc"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"from": "rules/figma-local-cache-first.mdc",
|
|
25
|
+
"to": ".cursor/rules/figma-local-cache-first.mdc"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"from": "skills/figma-mcp-local-cache/SKILL.md",
|
|
29
|
+
"to": ".cursor/skills/figma-mcp-local-cache/SKILL.md"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"from": "skills/figma-ui-dual-mode-execution/SKILL.md",
|
|
33
|
+
"to": ".cursor/skills/figma-ui-dual-mode-execution/SKILL.md"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"retiredFiles": [
|
|
37
|
+
".cursor/skills/ui-baseline-governance/SKILL.md",
|
|
38
|
+
".cursor/rules/04-command-execution-anti-regression.mdc",
|
|
39
|
+
".cursor/rules/commit-conventions.mdc"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -1,32 +1,22 @@
|
|
|
1
|
-
---
|
|
2
|
-
description:
|
|
1
|
+
---
|
|
2
|
+
description: 栈占位模板(仅生成期使用):生成完成后删除本文件与 AGENT-SETUP-PROMPT.md
|
|
3
3
|
alwaysApply: false
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Figma
|
|
7
|
-
|
|
8
|
-
本文件是 **通用脚手架**,不绑定 Vue / React / 任何组件库。若你已有具体栈的 Adapter 规则(例如 `02-figma-vuetify2-adapter.mdc`、`02-figma-react-mui-adapter.mdc`),可将本文件删除,或在 Cursor 设置中不再引用本文件。
|
|
9
|
-
|
|
10
|
-
## 第一步:用 Agent 生成栈专属规则
|
|
11
|
-
|
|
12
|
-
在项目根执行 `npx figma-cache cursor init` 后,打开 **`AGENT-SETUP-PROMPT.md`**,在 Cursor 里 **`@AGENT-SETUP-PROMPT.md`** 或整篇粘贴给 Agent,让其按文档顺序执行(含推断栈、生成配置、删除本占位文件)。若你更习惯手写,也可自行新建 `02-figma-<栈>-adapter.mdc` 与 `figma-cache.config.js`,再删除本文件。
|
|
13
|
-
|
|
14
|
-
生成后,**01-figma-cache-core** 仍只负责缓存与校验;**表现层**仅由你的 `02-figma-*-adapter` 约束。
|
|
15
|
-
|
|
16
|
-
## 与 01 的固定边界
|
|
17
|
-
|
|
18
|
-
- **单一事实来源**:实现 UI 时只从 `raw.json`、`spec.md`、`state-map.md`、`meta.json` 取数;不在这些通用文件里写入框架专有代码或路由名。
|
|
19
|
-
- **仅当任务包含「写/改业务 UI」且缓存可读**时,才应用具体栈的 Adapter;纯缓存维护、只跑 CLI,不触发表现层规则。
|
|
20
|
-
|
|
21
|
-
## React 直复用(选用规则)
|
|
6
|
+
# Figma -> UI Stack Adapter(占位模板)
|
|
22
7
|
|
|
23
|
-
|
|
8
|
+
本文件仅用于生成阶段引导,非长期规则。
|
|
24
9
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
## 生成流程(强制)
|
|
11
|
+
1. 基于项目栈生成 `.cursor/rules/02-figma-<stack>-adapter.mdc`。
|
|
12
|
+
2. 验证新 adapter 可用(语法 + 最小执行验证)。
|
|
13
|
+
3. 删除临时模板文件:
|
|
14
|
+
- `.cursor/rules/02-figma-stack-adapter.mdc`
|
|
15
|
+
- `AGENT-SETUP-PROMPT.md`
|
|
29
16
|
|
|
30
|
-
##
|
|
17
|
+
## 边界
|
|
18
|
+
- `01-figma-cache-core` 仅负责缓存与校验。
|
|
19
|
+
- 业务 UI 实现约束由新生成的 `02-figma-<stack>-adapter.mdc` + `03/04` 规则承接。
|
|
31
20
|
|
|
32
|
-
|
|
21
|
+
## 说明
|
|
22
|
+
- 若用户明确要求保留任务书或占位模板,可不删除,并在汇报中说明原因。
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Figma 缓存驱动 UI 实现硬约束(统一版:含一次性交付与证据映射)
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Figma UI 实现硬约束(统一版)
|
|
7
|
+
|
|
8
|
+
边界:仅约束缓存可读后的业务 UI 实现,不负责 MCP 拉取。
|
|
9
|
+
|
|
10
|
+
## 0) 压缩级别(先选)
|
|
11
|
+
- L0 严格:高保真/复杂交互/历史漂移(完整对齐 + 全状态 + 强校验)。
|
|
12
|
+
- L1 标准(默认):精简事实清单 + 核心状态 + lint。
|
|
13
|
+
- L2 快速:仅“先看效果”场景,先静态后补交互。
|
|
14
|
+
|
|
15
|
+
## 1) 首版必读(强制)
|
|
16
|
+
- `spec.md` / `raw.json` / `state-map.md` / `mcp-raw-get-design-context.txt`
|
|
17
|
+
|
|
18
|
+
## 2) 裁决顺序(强制)
|
|
19
|
+
- 信息冲突:回到 `mcp-raw-get-design-context.txt`。
|
|
20
|
+
- 仍无法裁决:先问用户,禁止猜测。
|
|
21
|
+
|
|
22
|
+
## 3) 视觉与布局(强制)
|
|
23
|
+
- 颜色/字体/几何/间距使用明确值,不用近似值。
|
|
24
|
+
- 默认 `box-border`,文本溢出显式处理。
|
|
25
|
+
- 禁止无依据横向滚动与布局抖动。
|
|
26
|
+
|
|
27
|
+
## 4) 标签与控件(最新口径)
|
|
28
|
+
- 默认优先:`div` / `span` / `img`。
|
|
29
|
+
- 默认禁用:`p` / `ul` / `li` / `ol` / `h1-h6`(除非用户明确要求)。
|
|
30
|
+
- 可直接使用:`input` / `select` / `textarea` / `a`。
|
|
31
|
+
- 原生 `button` 默认禁用;仅封装按钮或 UI 库按钮可用。
|
|
32
|
+
- `role` / `aria-*` 默认不强制。
|
|
33
|
+
|
|
34
|
+
## 5) 元数据策略
|
|
35
|
+
- `data-node-id` / `data-name` 默认不输出到最终业务代码。
|
|
36
|
+
- 仅在调试映射模式下临时保留。
|
|
37
|
+
|
|
38
|
+
## 6) 状态与交互(强制)
|
|
39
|
+
- 覆盖缓存声明状态(至少 `default / expanded / selected / unselected`,若存在)。
|
|
40
|
+
- 仅实现缓存声明或用户要求交互,不私增。
|
|
41
|
+
|
|
42
|
+
## 7) 一次性交付判定(强制)
|
|
43
|
+
- 信息充分(结构/文案/token/状态交互无关键缺口)时:必须一次性完成结构、样式、状态、基础响应式与可访问性,并同轮完成至少一项核心校验。
|
|
44
|
+
- 信息不足时:必须一次性列出“缺失字段 + 影响范围 + 最小补充需求”,并标注“受限还原”。
|
|
45
|
+
|
|
46
|
+
## 8) 证据映射(强制)
|
|
47
|
+
- 交付说明至少覆盖:布局结构、核心文案、主要颜色/字体 token、状态/交互判断。
|
|
48
|
+
- 每项实现事实必须给一个主来源(`raw.json/spec.md/state-map.md/mcp-raw-get-design-context.txt`)。
|
|
49
|
+
- 若引用 `mcp-raw`,仅用于补缺口/消歧,不重复主来源事实。
|
|
50
|
+
- 若 `raw/spec` 与 `mcp-raw` 冲突,先报告冲突再给采用依据。
|
|
51
|
+
|
|
52
|
+
## 9) 验收与失败反馈
|
|
53
|
+
- 每轮至少执行改动文件 lint。
|
|
54
|
+
- 声称“1:1 完成”前,至少补一项构建/类型/核心测试。
|
|
55
|
+
- 失败反馈固定三段:
|
|
56
|
+
1. 失败原因
|
|
57
|
+
2. 定位信息(文件 + 项)
|
|
58
|
+
3. 修复动作
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: UI 基线治理(分级精简版:判型、局部基线、验证回滚)
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI Baseline Governance(分级)
|
|
7
|
+
|
|
8
|
+
## 0) 项目判型
|
|
9
|
+
- 老项目:命中任一(页面多 / 已有 reset / UI 框架 / 全局样式风险)。
|
|
10
|
+
- 新项目:均不命中且页面少。
|
|
11
|
+
- 不确定:按老项目。
|
|
12
|
+
|
|
13
|
+
## 1) 策略
|
|
14
|
+
- 新项目:可一次性全局基线。
|
|
15
|
+
- 老项目:局部基线优先,分层分批,可回滚。
|
|
16
|
+
|
|
17
|
+
## 2) 基线实施级别(按效果选)
|
|
18
|
+
- B0 保守(老项目默认):
|
|
19
|
+
- 复制模板 `node_modules/{{NPM_PACKAGE_NAME}}/cursor-bootstrap/examples/generated-ui-reset.css.template`
|
|
20
|
+
-> 项目 `src/styles/generated-ui-reset.css`。
|
|
21
|
+
- 在入口(如 `src/main.ts`)单次引入。
|
|
22
|
+
- 生成组件根节点统一加 `generate-ui-reset`。
|
|
23
|
+
- B1 中等:页面级作用域基线(新页面/新模块)。
|
|
24
|
+
- B2 激进:全局基线(仅新项目或明确授权)。
|
|
25
|
+
|
|
26
|
+
## 3) 最小联动约束
|
|
27
|
+
- 默认 `box-border`。
|
|
28
|
+
- 弹层锚定触发器。
|
|
29
|
+
- 图标优先项目图标系统,兜底 `inline svg`。
|
|
30
|
+
|
|
31
|
+
## 4) 验收输出
|
|
32
|
+
1. 判型结论 + 证据
|
|
33
|
+
2. 本轮级别(B0/B1/B2)
|
|
34
|
+
3. 影响范围 + 回滚方式
|
|
35
|
+
4. lint + 可视验证
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: figma-ui-dual-mode-execution
|
|
3
|
+
description: 仅用 nodeId 或 Figma 链接触发 UI 实现,支持 L0/L1/L2 压缩级别,并内置基线判型与 B0/B1/B2 选择。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Figma UI Dual Mode Execution(分级)
|
|
7
|
+
|
|
8
|
+
## 执行步骤(固定)
|
|
9
|
+
1. 规范化 nodeId 并命中缓存目录。
|
|
10
|
+
2. 读取 `spec/raw/state-map/design-context`。
|
|
11
|
+
3. 选择压缩级别:L0/L1/L2(默认 L1)。
|
|
12
|
+
4. 输出事实对齐清单并实现挂载。
|
|
13
|
+
5. lint 验证并输出映射结论。
|
|
14
|
+
|
|
15
|
+
## 压缩级别
|
|
16
|
+
- L0:高保真严格流程(预检文档 + 完整状态)。
|
|
17
|
+
- L1:标准流程(精简清单 + 核心状态)。
|
|
18
|
+
- L2:快速看效果(先静态后补交互)。
|
|
19
|
+
|
|
20
|
+
## 基线治理(并入)
|
|
21
|
+
- 项目判型:新项目 / 老项目 / 不确定(不确定按老项目)。
|
|
22
|
+
- 基线级别:B0/B1/B2(老项目默认 B0)。
|
|
23
|
+
- B0(默认):
|
|
24
|
+
- 复制模板到 `src/styles/generated-ui-reset.css`
|
|
25
|
+
- 入口单次引入
|
|
26
|
+
- 生成组件根节点加 `generate-ui-reset`
|
|
27
|
+
- B1:仅新页面/模块范围启用作用域基线。
|
|
28
|
+
- B2:全局基线,仅新项目或明确授权。
|
|
29
|
+
- 若与规则冲突,以 `.cursor/rules/04-ui-baseline-governance.mdc` 为准。
|
|
30
|
+
|
|
31
|
+
## 标签口径
|
|
32
|
+
- 默认 `div/span/img`
|
|
33
|
+
- 默认禁 `p/ul/li/ol/h1-h6`
|
|
34
|
+
- `input/select/textarea/a` 允许
|
|
35
|
+
- 原生 `button` 默认禁用(封装/UI 库按钮除外)
|
|
36
|
+
- `role/aria-*` 默认不强制
|
|
37
|
+
- `data-node-id/data-name` 默认不输出
|
|
@@ -134,7 +134,7 @@ npm run figma:cache:init
|
|
|
134
134
|
- **项目根**仍需:`figma-cache.config.js`、`.cursor/` 规则与 Skill、`AGENT-SETUP-PROMPT.md`(或由等价流程生成)。
|
|
135
135
|
- Vue2+Vuetify2 参考 Adapter:`cursor-bootstrap/examples/vue2-vuetify2-adapter.reference.mdc`(npm 安装时在 `node_modules/.../cursor-bootstrap/examples/`)。
|
|
136
136
|
|
|
137
|
-
说明:Cursor **不会**在 `npm install` 时写入 `.cursor/`;`npx figma-cache cursor init` 负责从包内复制模板。`cursor init`
|
|
137
|
+
说明:Cursor **不会**在 `npm install` 时写入 `.cursor/`;`npx figma-cache cursor init` 负责从包内复制模板。`cursor init` 默认**保留**同名模板(安全模式);使用 `--overwrite` 可覆盖为最新版本;并会下发通用低 token 规则 `00-output-token-budget.mdc`;**`AGENT-SETUP-PROMPT.md` 每次 `cursor init` 均刷新**。
|
|
138
138
|
|
|
139
139
|
## package.json scripts 示例
|
|
140
140
|
|
|
@@ -353,7 +353,7 @@ function run() {
|
|
|
353
353
|
console.log(` ${ex} flow show --flow=<flowId>`);
|
|
354
354
|
console.log(` ${ex} flow mermaid --flow=<flowId>`);
|
|
355
355
|
console.log(
|
|
356
|
-
`${ex} cursor init [--force] # default
|
|
356
|
+
`${ex} cursor init [--overwrite] [--force] # default safe mode; --overwrite forces replacement; --force keeps legacy behavior (no overwrite)`,
|
|
357
357
|
);
|
|
358
358
|
process.exit(1);
|
|
359
359
|
}
|
|
@@ -362,12 +362,18 @@ function run() {
|
|
|
362
362
|
const sub = args[0];
|
|
363
363
|
if (sub !== "init") {
|
|
364
364
|
console.error(
|
|
365
|
-
"Usage: figma-cache cursor init [--force] #
|
|
365
|
+
"Usage: figma-cache cursor init [--overwrite] [--force] # --overwrite replaces existing templates; --force keeps legacy no-overwrite behavior",
|
|
366
366
|
);
|
|
367
367
|
process.exit(1);
|
|
368
368
|
}
|
|
369
|
-
const
|
|
370
|
-
|
|
369
|
+
const hasOverwrite = args.includes("--overwrite");
|
|
370
|
+
const hasForce = args.includes("--force");
|
|
371
|
+
if (hasOverwrite && hasForce) {
|
|
372
|
+
console.error("Do not use --overwrite and --force together. Choose one mode.");
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
const overwrite = hasOverwrite;
|
|
376
|
+
copyCursorBootstrap({ overwrite, legacyForce: hasForce }, {
|
|
371
377
|
fs,
|
|
372
378
|
path,
|
|
373
379
|
ROOT,
|
|
@@ -1,186 +1,218 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
function readUtf8IfExists(fs, absPath) {
|
|
4
|
-
if (!fs.existsSync(absPath)) {
|
|
5
|
-
return "";
|
|
6
|
-
}
|
|
7
|
-
return fs.readFileSync(absPath, "utf8");
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
fs
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
function readUtf8IfExists(fs, absPath) {
|
|
4
|
+
if (!fs.existsSync(absPath)) {
|
|
5
|
+
return "";
|
|
6
|
+
}
|
|
7
|
+
return fs.readFileSync(absPath, "utf8");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function loadManagedManifest({ fs, path, CURSOR_BOOTSTRAP_DIR, normalizeSlash }) {
|
|
11
|
+
const manifestPath = path.join(CURSOR_BOOTSTRAP_DIR, "managed-files.json");
|
|
12
|
+
if (!fs.existsSync(manifestPath)) {
|
|
13
|
+
console.error(`[figma-cache] missing managed files manifest: ${normalizeSlash(manifestPath)}`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(`[figma-cache] invalid managed files manifest: ${error.message}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { managedFiles, retiredFiles } = parsed || {};
|
|
26
|
+
if (!Array.isArray(managedFiles) || managedFiles.length === 0) {
|
|
27
|
+
console.error("[figma-cache] managed-files.json must contain non-empty managedFiles");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const pairs = managedFiles.map((item, index) => {
|
|
32
|
+
if (!item || typeof item.from !== "string" || typeof item.to !== "string") {
|
|
33
|
+
console.error(`[figma-cache] invalid managedFiles[${index}] item`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
from: item.from,
|
|
38
|
+
to: item.to,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const retired = Array.isArray(retiredFiles)
|
|
43
|
+
? retiredFiles.filter((item) => typeof item === "string" && item.trim())
|
|
44
|
+
: [];
|
|
45
|
+
|
|
46
|
+
return { pairs, retired };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function copyCursorBootstrap(options, deps) {
|
|
50
|
+
const {
|
|
51
|
+
fs,
|
|
52
|
+
path,
|
|
53
|
+
ROOT,
|
|
54
|
+
CACHE_DIR,
|
|
55
|
+
CURSOR_BOOTSTRAP_DIR,
|
|
56
|
+
normalizeSlash,
|
|
57
|
+
readSelfNpmPackageName,
|
|
58
|
+
packageDir,
|
|
59
|
+
} = deps;
|
|
60
|
+
const {
|
|
61
|
+
overwrite = false,
|
|
62
|
+
legacyForce = false,
|
|
63
|
+
} = options || {};
|
|
64
|
+
|
|
65
|
+
const { pairs, retired } = loadManagedManifest({ fs, path, CURSOR_BOOTSTRAP_DIR, normalizeSlash });
|
|
66
|
+
|
|
67
|
+
if (!fs.existsSync(CURSOR_BOOTSTRAP_DIR)) {
|
|
68
|
+
console.error(
|
|
69
|
+
`[figma-cache] cursor-bootstrap not found at ${normalizeSlash(CURSOR_BOOTSTRAP_DIR)} (broken package install?)`
|
|
70
|
+
);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let copied = 0;
|
|
75
|
+
let skipped = 0;
|
|
76
|
+
pairs.forEach(({ from: relFrom, to: relTo }) => {
|
|
77
|
+
const absFrom = path.join(CURSOR_BOOTSTRAP_DIR, relFrom);
|
|
78
|
+
const absTo = path.join(ROOT, relTo);
|
|
79
|
+
if (!fs.existsSync(absFrom)) {
|
|
80
|
+
console.error(`[figma-cache] missing template file: ${normalizeSlash(absFrom)}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
fs.mkdirSync(path.dirname(absTo), { recursive: true });
|
|
84
|
+
if (fs.existsSync(absTo) && !overwrite) {
|
|
85
|
+
skipped += 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
fs.copyFileSync(absFrom, absTo);
|
|
89
|
+
copied += 1;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const retiredDeleted = retired
|
|
93
|
+
.map((relPath) => {
|
|
94
|
+
const abs = path.join(ROOT, relPath);
|
|
95
|
+
if (!fs.existsSync(abs)) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
fs.unlinkSync(abs);
|
|
99
|
+
return normalizeSlash(relPath);
|
|
100
|
+
})
|
|
101
|
+
.filter(Boolean);
|
|
102
|
+
|
|
103
|
+
const configTemplatePath = path.join(CURSOR_BOOTSTRAP_DIR, "figma-cache.config.example.js");
|
|
104
|
+
const projectConfigPath = path.join(ROOT, "figma-cache.config.js");
|
|
105
|
+
const legacyExamplePath = path.join(ROOT, "figma-cache.config.example.js");
|
|
106
|
+
|
|
107
|
+
if (!fs.existsSync(configTemplatePath)) {
|
|
108
|
+
console.error(`[figma-cache] missing template file: ${normalizeSlash(configTemplatePath)}`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const hadProjectConfig = fs.existsSync(projectConfigPath);
|
|
113
|
+
const hadLegacyExample = fs.existsSync(legacyExamplePath);
|
|
114
|
+
const configTemplateBody = fs.readFileSync(configTemplatePath, "utf8");
|
|
115
|
+
|
|
116
|
+
let configAction = "skipped";
|
|
117
|
+
let configSource = "existing";
|
|
118
|
+
if (hadProjectConfig && !overwrite) {
|
|
119
|
+
configAction = "skipped";
|
|
120
|
+
configSource = "existing";
|
|
121
|
+
} else if (!hadProjectConfig && hadLegacyExample && !overwrite) {
|
|
122
|
+
fs.copyFileSync(legacyExamplePath, projectConfigPath);
|
|
123
|
+
configAction = "created";
|
|
124
|
+
configSource = "legacy-example";
|
|
125
|
+
} else {
|
|
126
|
+
fs.writeFileSync(projectConfigPath, configTemplateBody, "utf8");
|
|
127
|
+
configAction = hadProjectConfig ? "overwritten" : "created";
|
|
128
|
+
configSource = "template";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let legacyExampleStatus = "not-found";
|
|
132
|
+
if (fs.existsSync(legacyExamplePath)) {
|
|
133
|
+
const legacyBody = readUtf8IfExists(fs, legacyExamplePath);
|
|
134
|
+
const projectBody = readUtf8IfExists(fs, projectConfigPath);
|
|
135
|
+
const sameAsTemplate = legacyBody === configTemplateBody;
|
|
136
|
+
const sameAsProject = projectBody && legacyBody === projectBody;
|
|
137
|
+
if (sameAsTemplate || sameAsProject) {
|
|
138
|
+
fs.unlinkSync(legacyExamplePath);
|
|
139
|
+
legacyExampleStatus = "deleted";
|
|
140
|
+
} else {
|
|
141
|
+
legacyExampleStatus = "kept-customized";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const agentSrc = path.join(CURSOR_BOOTSTRAP_DIR, "AGENT-SETUP-PROMPT.md");
|
|
146
|
+
const agentDest = path.join(ROOT, "AGENT-SETUP-PROMPT.md");
|
|
147
|
+
if (!fs.existsSync(agentSrc)) {
|
|
148
|
+
console.error(`[figma-cache] missing ${normalizeSlash(agentSrc)}`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let agentBody = fs.readFileSync(agentSrc, "utf8");
|
|
153
|
+
const npmPkg = readSelfNpmPackageName();
|
|
154
|
+
agentBody = agentBody.replace(/\{\{NPM_PACKAGE_NAME\}\}/g, npmPkg);
|
|
155
|
+
fs.writeFileSync(agentDest, agentBody, "utf8");
|
|
156
|
+
|
|
157
|
+
const colleagueSrc = path.join(packageDir, "docs", "colleague-guide-zh.md");
|
|
158
|
+
const colleagueDest = path.join(CACHE_DIR, "docs", "colleague-guide-zh.md");
|
|
159
|
+
if (!fs.existsSync(colleagueSrc)) {
|
|
160
|
+
console.error(`[figma-cache] missing ${normalizeSlash(colleagueSrc)} (broken package install?)`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
const colleagueSameFile = path.resolve(colleagueSrc) === path.resolve(colleagueDest);
|
|
164
|
+
if (!colleagueSameFile) {
|
|
165
|
+
fs.mkdirSync(path.dirname(colleagueDest), { recursive: true });
|
|
166
|
+
fs.copyFileSync(colleagueSrc, colleagueDest);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log(
|
|
170
|
+
JSON.stringify(
|
|
171
|
+
{
|
|
172
|
+
ok: true,
|
|
173
|
+
root: normalizeSlash(ROOT),
|
|
174
|
+
copied,
|
|
175
|
+
skipped,
|
|
176
|
+
overwrite,
|
|
177
|
+
legacyForce,
|
|
178
|
+
retiredDeleted,
|
|
179
|
+
hint: skipped
|
|
180
|
+
? "Some template files were skipped (default safe mode keeps existing files)."
|
|
181
|
+
: overwrite
|
|
182
|
+
? "Done. Existing .cursor templates were overwritten by latest bootstrap."
|
|
183
|
+
: "Done.",
|
|
184
|
+
configFile: normalizeSlash(projectConfigPath),
|
|
185
|
+
configAction,
|
|
186
|
+
configSource,
|
|
187
|
+
legacyExampleFile: normalizeSlash(legacyExamplePath),
|
|
188
|
+
legacyExampleStatus,
|
|
189
|
+
agentPromptFile: normalizeSlash(agentDest),
|
|
190
|
+
colleagueGuideFile: normalizeSlash(colleagueDest),
|
|
191
|
+
colleagueGuideSynced: !colleagueSameFile,
|
|
192
|
+
colleagueGuideNote: colleagueSameFile
|
|
193
|
+
? "colleague-guide-zh.md already at package path (toolchain dev tree); no copy."
|
|
194
|
+
: "colleague-guide-zh.md refreshed under FIGMA_CACHE_DIR/docs (default figma-cache/docs/).",
|
|
195
|
+
agentPromptNote:
|
|
196
|
+
"AGENT-SETUP-PROMPT.md is refreshed every run. Next: @ it in Cursor; after Agent finishes, run npm run figma:cache:init (or npx figma-cache init if scripts are missing).",
|
|
197
|
+
npmPackageName: npmPkg,
|
|
198
|
+
},
|
|
199
|
+
null,
|
|
200
|
+
2
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
console.log(
|
|
204
|
+
"\n" +
|
|
205
|
+
"================================================================\n" +
|
|
206
|
+
"下一步(请按顺序):\n" +
|
|
207
|
+
"1) 在 Cursor 对话中输入 @AGENT-SETUP-PROMPT.md,并说明「按该文档执行」\n" +
|
|
208
|
+
" (每次 cursor init 都会刷新该文件;无需再整篇粘贴。)\n" +
|
|
209
|
+
"2) 待 Agent 完成后,在项目根初始化本地缓存索引:\n" +
|
|
210
|
+
" npm run figma:cache:init\n" +
|
|
211
|
+
" 若尚未补全 npm scripts,请改用:npx figma-cache init\n" +
|
|
212
|
+
"================================================================\n"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = {
|
|
217
|
+
copyCursorBootstrap,
|
|
218
|
+
};
|
package/package.json
CHANGED
|
@@ -1,74 +1,75 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "figma-cache-toolchain",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "Figma link normalization, local cache index, validation, and Node CLI (framework-agnostic core).",
|
|
5
|
-
"homepage": "https://github.com/907086379/figma-cache-toolchain#readme",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"figma",
|
|
8
|
-
"cache",
|
|
9
|
-
"cli",
|
|
10
|
-
"design-tokens",
|
|
11
|
-
"mcp"
|
|
12
|
-
],
|
|
13
|
-
"license": "MIT",
|
|
14
|
-
"engines": {
|
|
15
|
-
"node": ">=16.20.0"
|
|
16
|
-
},
|
|
17
|
-
"bin": {
|
|
18
|
-
"figma-cache": "bin/figma-cache.js"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"LICENSE",
|
|
22
|
-
"bin",
|
|
23
|
-
"cursor-bootstrap",
|
|
24
|
-
"figma-cache/figma-cache.js",
|
|
25
|
-
"figma-cache/js/flow-cli.js",
|
|
26
|
-
"figma-cache/js/validate-cli.js",
|
|
27
|
-
"figma-cache/js/budget-cli.js",
|
|
28
|
-
"figma-cache/js/index-store.js",
|
|
29
|
-
"figma-cache/js/cursor-bootstrap-cli.js",
|
|
30
|
-
"figma-cache/js/entry-files.js",
|
|
31
|
-
"figma-cache/js/backfill-cli.js",
|
|
32
|
-
"figma-cache/js/project-config.js",
|
|
33
|
-
"figma-cache/js/upsert-core.js",
|
|
34
|
-
"figma-cache/docs/*.md"
|
|
35
|
-
],
|
|
36
|
-
"publishConfig": {
|
|
37
|
-
"registry": "https://registry.npmjs.org/"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"test": "npm run cursor:shadow:check && npm run docs:encoding:check && node tests/rules-guard.js && node tests/smoke.js",
|
|
41
|
-
"prepack": "npm run cursor:shadow:check && npm run docs:encoding:check && node bin/figma-cache.js validate",
|
|
42
|
-
"figma:cache:normalize": "node bin/figma-cache.js normalize",
|
|
43
|
-
"figma:cache:get": "node bin/figma-cache.js get",
|
|
44
|
-
"figma:cache:upsert": "node bin/figma-cache.js upsert",
|
|
45
|
-
"figma:cache:ensure": "node bin/figma-cache.js ensure",
|
|
46
|
-
"figma:cache:validate": "node bin/figma-cache.js validate",
|
|
47
|
-
"figma:cache:stale": "node bin/figma-cache.js stale",
|
|
48
|
-
"figma:cache:budget": "node bin/figma-cache.js budget --mcp-only",
|
|
49
|
-
"figma:cache:backfill": "node bin/figma-cache.js backfill",
|
|
50
|
-
"figma:cache:init": "node bin/figma-cache.js init",
|
|
51
|
-
"figma:cache:config": "node bin/figma-cache.js config",
|
|
52
|
-
"figma:cache:flow:init": "node bin/figma-cache.js flow init",
|
|
53
|
-
"figma:cache:flow:add-node": "node bin/figma-cache.js flow add-node",
|
|
54
|
-
"figma:cache:flow:link": "node bin/figma-cache.js flow link",
|
|
55
|
-
"figma:cache:flow:chain": "node bin/figma-cache.js flow chain",
|
|
56
|
-
"figma:cache:flow:show": "node bin/figma-cache.js flow show",
|
|
57
|
-
"figma:cache:flow:mermaid": "node bin/figma-cache.js flow mermaid",
|
|
58
|
-
"figma:cache:cursor:init": "node bin/figma-cache.js cursor init",
|
|
59
|
-
"cursor:shadow:sync": "node scripts/sync-cursor-shadow.js",
|
|
60
|
-
"cursor:shadow:check": "node scripts/check-cursor-shadow.js",
|
|
61
|
-
"docs:encoding:check": "node scripts/check-doc-encoding.js",
|
|
62
|
-
"figma:cache:mobile:spec": "node scripts/mobile/generate-mobile-spec.js"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "figma-cache-toolchain",
|
|
3
|
+
"version": "2.0.3",
|
|
4
|
+
"description": "Figma link normalization, local cache index, validation, and Node CLI (framework-agnostic core).",
|
|
5
|
+
"homepage": "https://github.com/907086379/figma-cache-toolchain#readme",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"figma",
|
|
8
|
+
"cache",
|
|
9
|
+
"cli",
|
|
10
|
+
"design-tokens",
|
|
11
|
+
"mcp"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=16.20.0"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"figma-cache": "bin/figma-cache.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"bin",
|
|
23
|
+
"cursor-bootstrap",
|
|
24
|
+
"figma-cache/figma-cache.js",
|
|
25
|
+
"figma-cache/js/flow-cli.js",
|
|
26
|
+
"figma-cache/js/validate-cli.js",
|
|
27
|
+
"figma-cache/js/budget-cli.js",
|
|
28
|
+
"figma-cache/js/index-store.js",
|
|
29
|
+
"figma-cache/js/cursor-bootstrap-cli.js",
|
|
30
|
+
"figma-cache/js/entry-files.js",
|
|
31
|
+
"figma-cache/js/backfill-cli.js",
|
|
32
|
+
"figma-cache/js/project-config.js",
|
|
33
|
+
"figma-cache/js/upsert-core.js",
|
|
34
|
+
"figma-cache/docs/*.md"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"registry": "https://registry.npmjs.org/"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"test": "npm run cursor:shadow:check && npm run docs:encoding:check && node tests/rules-guard.js && node tests/smoke.js",
|
|
41
|
+
"prepack": "npm run cursor:shadow:check && npm run docs:encoding:check && node bin/figma-cache.js validate",
|
|
42
|
+
"figma:cache:normalize": "node bin/figma-cache.js normalize",
|
|
43
|
+
"figma:cache:get": "node bin/figma-cache.js get",
|
|
44
|
+
"figma:cache:upsert": "node bin/figma-cache.js upsert",
|
|
45
|
+
"figma:cache:ensure": "node bin/figma-cache.js ensure",
|
|
46
|
+
"figma:cache:validate": "node bin/figma-cache.js validate",
|
|
47
|
+
"figma:cache:stale": "node bin/figma-cache.js stale",
|
|
48
|
+
"figma:cache:budget": "node bin/figma-cache.js budget --mcp-only",
|
|
49
|
+
"figma:cache:backfill": "node bin/figma-cache.js backfill",
|
|
50
|
+
"figma:cache:init": "node bin/figma-cache.js init",
|
|
51
|
+
"figma:cache:config": "node bin/figma-cache.js config",
|
|
52
|
+
"figma:cache:flow:init": "node bin/figma-cache.js flow init",
|
|
53
|
+
"figma:cache:flow:add-node": "node bin/figma-cache.js flow add-node",
|
|
54
|
+
"figma:cache:flow:link": "node bin/figma-cache.js flow link",
|
|
55
|
+
"figma:cache:flow:chain": "node bin/figma-cache.js flow chain",
|
|
56
|
+
"figma:cache:flow:show": "node bin/figma-cache.js flow show",
|
|
57
|
+
"figma:cache:flow:mermaid": "node bin/figma-cache.js flow mermaid",
|
|
58
|
+
"figma:cache:cursor:init": "node bin/figma-cache.js cursor init",
|
|
59
|
+
"cursor:shadow:sync": "node scripts/sync-cursor-shadow.js",
|
|
60
|
+
"cursor:shadow:check": "node scripts/check-cursor-shadow.js",
|
|
61
|
+
"docs:encoding:check": "node scripts/check-doc-encoding.js",
|
|
62
|
+
"figma:cache:mobile:spec": "node scripts/mobile/generate-mobile-spec.js",
|
|
63
|
+
"figma:ui:gate": "npm run figma:cache:validate && npm run cursor:shadow:check && npm test"
|
|
64
|
+
},
|
|
65
|
+
"volta": {
|
|
66
|
+
"node": "16.20.2"
|
|
67
|
+
},
|
|
68
|
+
"repository": {
|
|
69
|
+
"type": "git",
|
|
70
|
+
"url": "git+https://github.com/907086379/figma-cache-toolchain.git"
|
|
71
|
+
},
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/907086379/figma-cache-toolchain/issues"
|
|
74
|
+
}
|
|
75
|
+
}
|