figma-cache-toolchain 2.0.2 → 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.
@@ -1,50 +1,37 @@
1
- ---
2
- name: figma-ui-dual-mode-execution
3
- description: 仅用 nodeId(如 9277-28772)或 Figma 链接触发 UI 实现,自动在短流程与严格流程间切换。
4
- ---
5
-
6
- # Figma UI Dual Mode Execution
7
-
8
- Skill 用于:用户仅提供节点线索(节点目录名、nodeId、或带 node-id 的 Figma 链接)时,自动完成“定位缓存 -> 判定模式 -> 实现与验证”。
9
-
10
- ## 支持输入
11
-
12
- - 节点目录名:如 `9277-28772`
13
- - nodeId:如 `9277:28772`
14
- - Figma 链接:`...node-id=9277-28772`(需转换为 `9277:28772`)
15
-
16
- ## 执行步骤(强制)
17
-
18
- 1. 规范化节点标识:
19
- - `9277-28772` -> `9277:28772`
20
- 2. 在 `figma-cache/index.json` 查命中并定位节点目录。
21
- 3. 读取四份必读文件:
22
- - `spec.md`
23
- - `raw.json`
24
- - `state-map.md`
25
- - `mcp-raw-get-design-context.txt`
26
- 4. 模式选择:
27
- - 默认短流程;
28
- - 命中任一升级条件(老项目/全局样式改动/复杂状态/历史漂移问题/信息冲突)-> 切严格流程。
29
- 5. 预检文档策略(降噪):
30
- - 默认短流程:可跳过完整预检文档,仅输出精简事实清单。
31
- - 严格流程:必须基于 `cursor-bootstrap/examples/ui-1to1-preflight.template.md` 生成并填写“预检文档”(可落到项目 `figma-cache/docs/` 或节点目录旁),至少完成:设计值快照、状态对照表、1:1 预检清单。
32
- 6. 先输出“事实对齐清单”,再实现组件与挂载。
33
- 7. 改动后执行 lint,并输出映射与验证结论。
34
-
35
- ## 关键硬约束
36
-
37
- - 冲突裁决顺序:`mcp-raw-get-design-context.txt` 优先。
38
- - 禁止猜测设计值;无法裁决必须先提问。
39
- - 禁止使用 Figma 临时远程资产 URL 作为运行时图标。
40
- - 图标优先项目图标系统;无则 `inline svg`。
41
- - 默认按 `border-box` 思维实现;弹层必须锚定触发器。
42
-
43
- ## 固定输出
44
-
45
- 1. 缓存定位结果(命中节点目录)
46
- 2. 事实对齐清单(结构/文案/token/状态/交互)
47
- 3. 变更文件列表
48
- 4. 关键设计值 -> 代码映射
49
- 5. lint/验证结果
50
- 6. 未决问题(如有)
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` 默认**覆盖**同名模板为最新版本(`--force` 可改为保留已有模板并跳过覆盖);并会下发通用低 token 规则 `00-output-token-budget.mdc`;**`AGENT-SETUP-PROMPT.md` 每次 `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: overwrite .cursor templates with latest bootstrap; --force keeps existing templates (skip overwrite)`,
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] # default overwrite; --force keeps existing templates",
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 force = args.includes("--force");
370
- copyCursorBootstrap(force, {
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,202 +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 copyCursorBootstrap(force, deps) {
11
- const {
12
- fs,
13
- path,
14
- ROOT,
15
- CACHE_DIR,
16
- CURSOR_BOOTSTRAP_DIR,
17
- normalizeSlash,
18
- readSelfNpmPackageName,
19
- packageDir,
20
- } = deps;
21
-
22
- const pairs = [
23
- {
24
- from: path.join("rules", "00-output-token-budget.mdc"),
25
- to: path.join(".cursor", "rules", "00-output-token-budget.mdc"),
26
- },
27
- {
28
- from: path.join("rules", "01-figma-cache-core.mdc"),
29
- to: path.join(".cursor", "rules", "01-figma-cache-core.mdc"),
30
- },
31
- {
32
- from: path.join("rules", "02-figma-stack-adapter.mdc"),
33
- to: path.join(".cursor", "rules", "02-figma-stack-adapter.mdc"),
34
- },
35
- {
36
- from: path.join("rules", "03-figma-ui-implementation-hard-constraints.mdc"),
37
- to: path.join(".cursor", "rules", "03-figma-ui-implementation-hard-constraints.mdc"),
38
- },
39
- {
40
- from: path.join("rules", "04-ui-baseline-governance.mdc"),
41
- to: path.join(".cursor", "rules", "04-ui-baseline-governance.mdc"),
42
- },
43
- {
44
- from: path.join("rules", "figma-local-cache-first.mdc"),
45
- to: path.join(".cursor", "rules", "figma-local-cache-first.mdc"),
46
- },
47
- {
48
- from: path.join("skills", "figma-mcp-local-cache", "SKILL.md"),
49
- to: path.join(".cursor", "skills", "figma-mcp-local-cache", "SKILL.md"),
50
- },
51
- {
52
- from: path.join("skills", "ui-baseline-governance", "SKILL.md"),
53
- to: path.join(".cursor", "skills", "ui-baseline-governance", "SKILL.md"),
54
- },
55
- {
56
- from: path.join("skills", "figma-ui-dual-mode-execution", "SKILL.md"),
57
- to: path.join(".cursor", "skills", "figma-ui-dual-mode-execution", "SKILL.md"),
58
- },
59
- ];
60
-
61
- if (!fs.existsSync(CURSOR_BOOTSTRAP_DIR)) {
62
- console.error(
63
- `[figma-cache] cursor-bootstrap not found at ${normalizeSlash(CURSOR_BOOTSTRAP_DIR)} (broken package install?)`
64
- );
65
- process.exit(1);
66
- }
67
-
68
- const overwrite = !force;
69
- let copied = 0;
70
- let skipped = 0;
71
- pairs.forEach(({ from: relFrom, to: relTo }) => {
72
- const absFrom = path.join(CURSOR_BOOTSTRAP_DIR, relFrom);
73
- const absTo = path.join(ROOT, relTo);
74
- if (!fs.existsSync(absFrom)) {
75
- console.error(`[figma-cache] missing template file: ${normalizeSlash(absFrom)}`);
76
- process.exit(1);
77
- }
78
- fs.mkdirSync(path.dirname(absTo), { recursive: true });
79
- if (fs.existsSync(absTo) && !overwrite) {
80
- skipped += 1;
81
- return;
82
- }
83
- fs.copyFileSync(absFrom, absTo);
84
- copied += 1;
85
- });
86
-
87
- const configTemplatePath = path.join(CURSOR_BOOTSTRAP_DIR, "figma-cache.config.example.js");
88
- const projectConfigPath = path.join(ROOT, "figma-cache.config.js");
89
- const legacyExamplePath = path.join(ROOT, "figma-cache.config.example.js");
90
-
91
- if (!fs.existsSync(configTemplatePath)) {
92
- console.error(`[figma-cache] missing template file: ${normalizeSlash(configTemplatePath)}`);
93
- process.exit(1);
94
- }
95
-
96
- const hadProjectConfig = fs.existsSync(projectConfigPath);
97
- const hadLegacyExample = fs.existsSync(legacyExamplePath);
98
- const configTemplateBody = fs.readFileSync(configTemplatePath, "utf8");
99
-
100
- let configAction = "skipped";
101
- let configSource = "existing";
102
- if (hadProjectConfig && !force) {
103
- configAction = "skipped";
104
- configSource = "existing";
105
- } else if (!hadProjectConfig && hadLegacyExample && !force) {
106
- fs.copyFileSync(legacyExamplePath, projectConfigPath);
107
- configAction = "created";
108
- configSource = "legacy-example";
109
- } else {
110
- fs.writeFileSync(projectConfigPath, configTemplateBody, "utf8");
111
- configAction = hadProjectConfig ? "overwritten" : "created";
112
- configSource = "template";
113
- }
114
-
115
- let legacyExampleStatus = "not-found";
116
- if (fs.existsSync(legacyExamplePath)) {
117
- const legacyBody = readUtf8IfExists(fs, legacyExamplePath);
118
- const projectBody = readUtf8IfExists(fs, projectConfigPath);
119
- const sameAsTemplate = legacyBody === configTemplateBody;
120
- const sameAsProject = projectBody && legacyBody === projectBody;
121
- if (sameAsTemplate || sameAsProject) {
122
- fs.unlinkSync(legacyExamplePath);
123
- legacyExampleStatus = "deleted";
124
- } else {
125
- legacyExampleStatus = "kept-customized";
126
- }
127
- }
128
-
129
- const agentSrc = path.join(CURSOR_BOOTSTRAP_DIR, "AGENT-SETUP-PROMPT.md");
130
- const agentDest = path.join(ROOT, "AGENT-SETUP-PROMPT.md");
131
- if (!fs.existsSync(agentSrc)) {
132
- console.error(`[figma-cache] missing ${normalizeSlash(agentSrc)}`);
133
- process.exit(1);
134
- }
135
-
136
- let agentBody = fs.readFileSync(agentSrc, "utf8");
137
- const npmPkg = readSelfNpmPackageName();
138
- agentBody = agentBody.replace(/\{\{NPM_PACKAGE_NAME\}\}/g, npmPkg);
139
- fs.writeFileSync(agentDest, agentBody, "utf8");
140
-
141
- const colleagueSrc = path.join(packageDir, "docs", "colleague-guide-zh.md");
142
- const colleagueDest = path.join(CACHE_DIR, "docs", "colleague-guide-zh.md");
143
- if (!fs.existsSync(colleagueSrc)) {
144
- console.error(`[figma-cache] missing ${normalizeSlash(colleagueSrc)} (broken package install?)`);
145
- process.exit(1);
146
- }
147
- const colleagueSameFile = path.resolve(colleagueSrc) === path.resolve(colleagueDest);
148
- if (!colleagueSameFile) {
149
- fs.mkdirSync(path.dirname(colleagueDest), { recursive: true });
150
- fs.copyFileSync(colleagueSrc, colleagueDest);
151
- }
152
-
153
- console.log(
154
- JSON.stringify(
155
- {
156
- ok: true,
157
- root: normalizeSlash(ROOT),
158
- copied,
159
- skipped,
160
- force: !!force,
161
- overwriteByDefault: overwrite,
162
- hint: skipped
163
- ? "Some template files were skipped (--force means keep existing files)."
164
- : overwrite
165
- ? "Done. Existing .cursor templates were overwritten by latest bootstrap."
166
- : "Done.",
167
- configFile: normalizeSlash(projectConfigPath),
168
- configAction,
169
- configSource,
170
- legacyExampleFile: normalizeSlash(legacyExamplePath),
171
- legacyExampleStatus,
172
- agentPromptFile: normalizeSlash(agentDest),
173
- colleagueGuideFile: normalizeSlash(colleagueDest),
174
- colleagueGuideSynced: !colleagueSameFile,
175
- colleagueGuideNote: colleagueSameFile
176
- ? "colleague-guide-zh.md already at package path (toolchain dev tree); no copy."
177
- : "colleague-guide-zh.md refreshed under FIGMA_CACHE_DIR/docs (default figma-cache/docs/).",
178
- agentPromptNote:
179
- "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).",
180
- npmPackageName: npmPkg,
181
- },
182
- null,
183
- 2
184
- )
185
- );
186
- console.log(
187
- "\n" +
188
- "================================================================\n" +
189
- "下一步(请按顺序):\n" +
190
- "1) 在 Cursor 对话中输入 @AGENT-SETUP-PROMPT.md,并说明「按该文档执行」\n" +
191
- " (每次 cursor init 都会刷新该文件;无需再整篇粘贴。)\n" +
192
- "2) 待 Agent 完成后,在项目根初始化本地缓存索引:\n" +
193
- " npm run figma:cache:init\n" +
194
- " 若尚未补全 npm scripts,请改用:npx figma-cache init\n" +
195
- "================================================================\n"
196
- );
197
- }
198
-
199
- module.exports = {
200
- copyCursorBootstrap,
201
- };
202
-
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
+ };