@tfdesign/b-end 1.0.4
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/AI_READ_FIRST.md +131 -0
- package/LICENSE +21 -0
- package/README.md +353 -0
- package/package.json +67 -0
- package/scripts/check-tfds-contract.mjs +334 -0
- package/scripts/check-tfds-integration.mjs +263 -0
- package/scripts/postinstall-cursor-skill.mjs +382 -0
- package/scripts/setup.mjs +520 -0
- package/skills/tfds/CHECKLIST.md +205 -0
- package/skills/tfds/COMMON_FAILURES.md +238 -0
- package/skills/tfds/DESIGN_PRINCIPLES.md +477 -0
- package/skills/tfds/GLOBAL_DESIGN_RULES.md +636 -0
- package/skills/tfds/LAYOUT_RECIPES.md +140 -0
- package/skills/tfds/LAYOUT_RULES.md +1355 -0
- package/skills/tfds/PAGE_ARCHETYPES.md +201 -0
- package/skills/tfds/SKILL.md +188 -0
- package/skills/tfds/components.index.json +7305 -0
- package/skills/tfds/components.summary.json +1809 -0
- package/src/_b_end_runtime/components/AiSuggestionShared.jsx +166 -0
- package/src/_b_end_runtime/components/Avatar.jsx +325 -0
- package/src/_b_end_runtime/components/Avatar.tokens.js +76 -0
- package/src/_b_end_runtime/components/AvatarGridPreview.jsx +56 -0
- package/src/_b_end_runtime/components/AvatarGroup.jsx +80 -0
- package/src/_b_end_runtime/components/AvatarGroup.tokens.js +28 -0
- package/src/_b_end_runtime/components/Button.jsx +144 -0
- package/src/_b_end_runtime/components/Button.tokens.js +90 -0
- package/src/_b_end_runtime/components/Card.jsx +460 -0
- package/src/_b_end_runtime/components/Card.tokens.js +124 -0
- package/src/_b_end_runtime/components/CardPreview.jsx +51 -0
- package/src/_b_end_runtime/components/ChatBubble.jsx +384 -0
- package/src/_b_end_runtime/components/ChatBubble.tokens.js +60 -0
- package/src/_b_end_runtime/components/ChatBubblePreview.jsx +129 -0
- package/src/_b_end_runtime/components/ChatInput.jsx +1399 -0
- package/src/_b_end_runtime/components/ChatInput.tokens.js +75 -0
- package/src/_b_end_runtime/components/ChatMessage.jsx +2215 -0
- package/src/_b_end_runtime/components/ChatMessage.tokens.js +257 -0
- package/src/_b_end_runtime/components/ChatMessagePreview.jsx +388 -0
- package/src/_b_end_runtime/components/Checkbox.jsx +317 -0
- package/src/_b_end_runtime/components/Checkbox.tokens.js +59 -0
- package/src/_b_end_runtime/components/ConversationList.jsx +1264 -0
- package/src/_b_end_runtime/components/ConversationList.tokens.js +135 -0
- package/src/_b_end_runtime/components/ConversationListPreview.jsx +108 -0
- package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.jsx +324 -0
- package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.tokens.js +69 -0
- package/src/_b_end_runtime/components/DatePicker.jsx +739 -0
- package/src/_b_end_runtime/components/DatePicker.tokens.js +99 -0
- package/src/_b_end_runtime/components/Empty.jsx +141 -0
- package/src/_b_end_runtime/components/Empty.tokens.js +40 -0
- package/src/_b_end_runtime/components/Form.jsx +609 -0
- package/src/_b_end_runtime/components/Form.tokens.js +77 -0
- package/src/_b_end_runtime/components/FormFieldStack.jsx +123 -0
- package/src/_b_end_runtime/components/FormFieldStack.tokens.js +12 -0
- package/src/_b_end_runtime/components/FormTitle.jsx +119 -0
- package/src/_b_end_runtime/components/FormTitle.tokens.js +87 -0
- package/src/_b_end_runtime/components/FullScreenPage.jsx +97 -0
- package/src/_b_end_runtime/components/FullScreenPage.tokens.js +19 -0
- package/src/_b_end_runtime/components/Icon.jsx +172 -0
- package/src/_b_end_runtime/components/Icon.tokens.js +26 -0
- package/src/_b_end_runtime/components/IconGridPreview.jsx +277 -0
- package/src/_b_end_runtime/components/InfoDisplayPanel.jsx +620 -0
- package/src/_b_end_runtime/components/InfoDisplayPanel.tokens.js +71 -0
- package/src/_b_end_runtime/components/InfoDisplayPanelPreview.jsx +133 -0
- package/src/_b_end_runtime/components/Input.jsx +258 -0
- package/src/_b_end_runtime/components/Input.tokens.js +68 -0
- package/src/_b_end_runtime/components/InputNumber.jsx +242 -0
- package/src/_b_end_runtime/components/InputNumber.tokens.js +55 -0
- package/src/_b_end_runtime/components/Modal.jsx +155 -0
- package/src/_b_end_runtime/components/Modal.tokens.js +73 -0
- package/src/_b_end_runtime/components/NavBar.jsx +842 -0
- package/src/_b_end_runtime/components/NavBar.tokens.js +97 -0
- package/src/_b_end_runtime/components/NavBarPreview.jsx +11 -0
- package/src/_b_end_runtime/components/Radio.jsx +227 -0
- package/src/_b_end_runtime/components/Radio.tokens.js +59 -0
- package/src/_b_end_runtime/components/Select.jsx +766 -0
- package/src/_b_end_runtime/components/Select.tokens.js +99 -0
- package/src/_b_end_runtime/components/Sheet.jsx +132 -0
- package/src/_b_end_runtime/components/Sheet.tokens.js +61 -0
- package/src/_b_end_runtime/components/Slider.jsx +346 -0
- package/src/_b_end_runtime/components/Slider.tokens.js +47 -0
- package/src/_b_end_runtime/components/Switch.jsx +124 -0
- package/src/_b_end_runtime/components/Switch.tokens.js +38 -0
- package/src/_b_end_runtime/components/Table.jsx +1338 -0
- package/src/_b_end_runtime/components/Table.tokens.js +147 -0
- package/src/_b_end_runtime/components/TablePreview.jsx +599 -0
- package/src/_b_end_runtime/components/Tabs.jsx +149 -0
- package/src/_b_end_runtime/components/Tabs.tokens.js +102 -0
- package/src/_b_end_runtime/components/Tag.jsx +199 -0
- package/src/_b_end_runtime/components/Tag.tokens.js +171 -0
- package/src/_b_end_runtime/components/TagBar.jsx +1134 -0
- package/src/_b_end_runtime/components/TagBar.tokens.js +75 -0
- package/src/_b_end_runtime/components/TagGridPreview.jsx +23 -0
- package/src/_b_end_runtime/components/TagInput.jsx +382 -0
- package/src/_b_end_runtime/components/TagInput.tokens.js +52 -0
- package/src/_b_end_runtime/components/TextArea.jsx +363 -0
- package/src/_b_end_runtime/components/TextArea.tokens.js +65 -0
- package/src/_b_end_runtime/components/TimePicker.jsx +444 -0
- package/src/_b_end_runtime/components/TimePicker.tokens.js +77 -0
- package/src/_b_end_runtime/components/Toast.jsx +120 -0
- package/src/_b_end_runtime/components/Toast.tokens.js +146 -0
- package/src/_b_end_runtime/components/Tooltip.jsx +282 -0
- package/src/_b_end_runtime/components/Tooltip.tokens.js +48 -0
- package/src/_b_end_runtime/components/TooltipPreview.jsx +50 -0
- package/src/_b_end_runtime/components/Upload.jsx +455 -0
- package/src/_b_end_runtime/components/Upload.tokens.js +47 -0
- package/src/_b_end_runtime/components/avatar-assets/avatar-default.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-1.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-2.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-3.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-4.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-5.png +0 -0
- package/src/_b_end_runtime/components/empty-assets/administrator-1.svg +40 -0
- package/src/_b_end_runtime/components/empty-assets/administrator-2.svg +33 -0
- package/src/_b_end_runtime/components/empty-assets/construction.svg +33 -0
- package/src/_b_end_runtime/components/empty-assets/failure.svg +49 -0
- package/src/_b_end_runtime/components/empty-assets/idle.svg +34 -0
- package/src/_b_end_runtime/components/empty-assets/no-access.svg +36 -0
- package/src/_b_end_runtime/components/empty-assets/no-content.svg +77 -0
- package/src/_b_end_runtime/components/empty-assets/no-result.svg +61 -0
- package/src/_b_end_runtime/components/empty-assets/not-found.svg +46 -0
- package/src/_b_end_runtime/components/empty-assets/success.svg +38 -0
- package/src/_b_end_runtime/components/file-type-assets/batch-report.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/catcat.svg +21 -0
- package/src/_b_end_runtime/components/file-type-assets/code.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/conversation.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/document.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu-card.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu-sheet.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/image.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/index.js +105 -0
- package/src/_b_end_runtime/components/file-type-assets/knowledge.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/pdf.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/pe.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/strategy.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/table.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/webpage.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/xmind.png +0 -0
- package/src/_b_end_runtime/components/icons/icon-data.js +12496 -0
- package/src/_b_end_runtime/components/nav-bar-assets/bytehi-logo-mark.svg +21 -0
- package/src/_b_end_runtime/components/table-assets/avatar.png +0 -0
- package/src/_b_end_runtime/components/table-assets/button.png +0 -0
- package/src/_b_end_runtime/components/table-assets/icon-chevron-down.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/avatar.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/button.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/checkbox.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/icon-chevron-right.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/icon.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/semi-icons-handle.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/semi-icons-tree-triangle-right.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/switch.png +0 -0
- package/src/_b_end_runtime/components/tagShared.js +3 -0
- package/src/_b_end_runtime/components/team-avatar-assets/chengcheng-murphy.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/duan-ran.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/guo-zhezhi.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/li-siru.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/liu-delin.png +0 -0
- package/src/_b_end_runtime/components.js +3499 -0
- package/src/_b_end_runtime/index.js +9 -0
- package/src/_b_end_runtime/page-patterns/BasePageFramePattern.jsx +395 -0
- package/src/_b_end_runtime/page-patterns/ChatConversationPattern.jsx +989 -0
- package/src/_b_end_runtime/page-patterns/ChatHomePagePattern.jsx +281 -0
- package/src/_b_end_runtime/page-patterns/CopilotPagePattern.jsx +380 -0
- package/src/_b_end_runtime/page-patterns/CustomerServiceWorkspaceFramePattern.jsx +392 -0
- package/src/_b_end_runtime/page-patterns/IMConversationPattern.jsx +590 -0
- package/src/_b_end_runtime/page-patterns/McpManagementPage.jsx +237 -0
- package/src/_b_end_runtime/page-patterns/StrategyListPage.jsx +189 -0
- package/src/_b_end_runtime/page-patterns/TabTopBarListPage.jsx +594 -0
- package/src/_b_end_runtime/page-patterns/VariableManagementPage.jsx +87 -0
- package/src/_b_end_runtime/page-patterns/pageListShared.jsx +177 -0
- package/src/_b_end_runtime/patterns.js +428 -0
- package/src/_b_end_runtime/preview-registry.jsx +4719 -0
- package/src/_b_end_runtime/teamMembers.js +56 -0
- package/src/_b_end_runtime/tokens.js +500 -0
- package/src/index.d.ts +1073 -0
- package/src/index.js +52 -0
- package/theme.css +350 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
// 安装 @tfdesign/b-end 后自动执行三件事:
|
|
2
|
+
//
|
|
3
|
+
// 1. IDE Skill 自动写入(仅 opt-in 通道,不写 always-on)
|
|
4
|
+
// → .cursor/skills/tfds/ (Cursor → /tfds 唤起)
|
|
5
|
+
// → .claude/skills/tfds/ (Claude Code → /tfds 唤起)
|
|
6
|
+
// → .codex/skills/tfds/ (Codex → 项目内参考)
|
|
7
|
+
// → ~/.codex/skills/tfds/ (Codex → 用户级 /tfds Skill,需新开/重启 Codex 会话)
|
|
8
|
+
// → .agents/skills/tfds/ (通用 agent 兜底,与 .codex 并存)
|
|
9
|
+
// ⚠️ 不再自动写 .trae/rules/tfds.md:Trae rules 是 always-on 全局规则,
|
|
10
|
+
// 与 TFDS"显式调用才生效"原则冲突。Trae 用户请把 skills/tfds/ 手动加入项目知识库。
|
|
11
|
+
// 跳过:SKIP_TFDS_CURSOR_SKILL=1;目标已存在且完整时不覆盖,旧版/缺文件时自动同步
|
|
12
|
+
//
|
|
13
|
+
// 2. 入口 CSS 自动补丁(最关键步骤,消除手动操作)
|
|
14
|
+
// 在 @import "tailwindcss" 之后自动插入:
|
|
15
|
+
// @import "@tfdesign/b-end/theme.css";
|
|
16
|
+
// @source "./**/*.{js,jsx,ts,tsx}";
|
|
17
|
+
// @source "<relPath>/node_modules/@tfdesign/b-end/**/*.{js,jsx}";
|
|
18
|
+
// 候选文件:src/index.css、src/main.css、src/styles.css、
|
|
19
|
+
// src/global.css、app/globals.css、styles/globals.css、index.css
|
|
20
|
+
// 已有 theme.css import → 跳过;未找到 @import "tailwindcss" → 不改写,终端提示
|
|
21
|
+
// 跳过:SKIP_TFDS_CSS_PATCH=1
|
|
22
|
+
//
|
|
23
|
+
// 3. 终端安装报告(已做了什么、还差什么、如何唤起规范)
|
|
24
|
+
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
import os from 'node:os';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import { fileURLToPath } from 'node:url';
|
|
29
|
+
|
|
30
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
31
|
+
const __dirname = path.dirname(__filename);
|
|
32
|
+
const pkgRoot = path.resolve(__dirname, '..');
|
|
33
|
+
|
|
34
|
+
const projectRoot = process.env.INIT_CWD || process.cwd();
|
|
35
|
+
|
|
36
|
+
// ─────────────────────────────────────────────────────────────────
|
|
37
|
+
// 前置检查:确认运行在正确的业务项目根(有自己的 package.json,且不是 tfds-b-end 自身)
|
|
38
|
+
// ─────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function readJson(p) {
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const projectPkg = readJson(path.join(projectRoot, 'package.json'));
|
|
49
|
+
const isSelfPkg = projectPkg?.name === '@tfdesign/b-end';
|
|
50
|
+
const hasNoPkg = !projectPkg;
|
|
51
|
+
|
|
52
|
+
if (hasNoPkg || isSelfPkg) {
|
|
53
|
+
console.log('\n╔══════════════════════════════════════════════════════╗');
|
|
54
|
+
console.log('║ @tfdesign/b-end ⚠ 安装位置需要调整 ║');
|
|
55
|
+
console.log('╚══════════════════════════════════════════════════════╝\n');
|
|
56
|
+
|
|
57
|
+
if (hasNoPkg) {
|
|
58
|
+
console.log(' 当前目录没有业务项目的 package.json。');
|
|
59
|
+
} else {
|
|
60
|
+
console.log(' 当前目录是 tfds-b-end 包自身,不是业务项目根。');
|
|
61
|
+
}
|
|
62
|
+
console.log(' 不需要手动新建项目或手动猜 file: 路径,请改用离线包根目录的一键安装脚本。\n');
|
|
63
|
+
|
|
64
|
+
console.log(' ── 推荐做法:把 tfds-npm-distribution/ 放进目标文件夹后执行 ──\n');
|
|
65
|
+
console.log(' node tfds-npm-distribution/setup.mjs\n');
|
|
66
|
+
console.log(' 脚本会自动判断:');
|
|
67
|
+
console.log(' • 已有项目:复用现有 package.json / vite.config / 入口 CSS,缺什么补什么');
|
|
68
|
+
console.log(' • 全新空文件夹:自动创建最小 Vite + React 项目,然后继续安装 TFDS\n');
|
|
69
|
+
console.log(' 如果安装包不在目标项目根,请显式指定目标:');
|
|
70
|
+
console.log(' node "/绝对路径/.../tfds-npm-distribution/setup.mjs" --target "/绝对路径/.../业务项目根"\n');
|
|
71
|
+
console.log(' 仅旧包没有 setup.mjs 时,才在业务项目根手动执行:');
|
|
72
|
+
console.log(` npm i "file:${pkgRoot}" --save\n`);
|
|
73
|
+
console.log(' 详见:README.md → "全新项目?从这里开始"\n');
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ─────────────────────────────────────────────────────────────────
|
|
78
|
+
// Step 1: Cursor / Agents Skill 复制
|
|
79
|
+
// ─────────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
const skillSrcLower = path.join(pkgRoot, 'skills', 'tfds');
|
|
82
|
+
const skillSrcLegacy = path.join(pkgRoot, 'skills', 'TFDS');
|
|
83
|
+
const skillSrc = fs.existsSync(skillSrcLower)
|
|
84
|
+
? skillSrcLower
|
|
85
|
+
: fs.existsSync(skillSrcLegacy)
|
|
86
|
+
? skillSrcLegacy
|
|
87
|
+
: null;
|
|
88
|
+
|
|
89
|
+
const REQUIRED_TFDS_SKILL_FILES = [
|
|
90
|
+
'SKILL.md',
|
|
91
|
+
'DESIGN_PRINCIPLES.md',
|
|
92
|
+
'PAGE_ARCHETYPES.md',
|
|
93
|
+
'components.summary.json',
|
|
94
|
+
'components.index.json',
|
|
95
|
+
'LAYOUT_RULES.md',
|
|
96
|
+
'GLOBAL_DESIGN_RULES.md',
|
|
97
|
+
'CHECKLIST.md',
|
|
98
|
+
'COMMON_FAILURES.md',
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
function readText(p) {
|
|
102
|
+
try {
|
|
103
|
+
return fs.readFileSync(p, 'utf8');
|
|
104
|
+
} catch {
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasSourceSkillDiff(dest) {
|
|
110
|
+
return REQUIRED_TFDS_SKILL_FILES.some((file) => {
|
|
111
|
+
const sourceFile = path.join(skillSrc, file);
|
|
112
|
+
const destFile = path.join(dest, file);
|
|
113
|
+
return readText(sourceFile) !== readText(destFile);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function needsSkillRefresh(dest) {
|
|
118
|
+
const missingRequiredFile = REQUIRED_TFDS_SKILL_FILES.some((file) => !fs.existsSync(path.join(dest, file)));
|
|
119
|
+
if (missingRequiredFile) return true;
|
|
120
|
+
|
|
121
|
+
return hasSourceSkillDiff(dest);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function copySkillDir(dest) {
|
|
125
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
126
|
+
fs.cpSync(skillSrc, dest, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** @type {string[]} postinstall 步骤摘要,最后汇总打印 */
|
|
130
|
+
const done = [];
|
|
131
|
+
/** @type {string[]} 需用户手动处理的提示 */
|
|
132
|
+
const todo = [];
|
|
133
|
+
|
|
134
|
+
// ⚠️ SKILL_DIR_TARGETS 必须在 installSkillDir() 定义与调用之前声明,避免 const TDZ 错误
|
|
135
|
+
const SKILL_DIR_TARGETS = {
|
|
136
|
+
cursor: { base: path.join(projectRoot, '.cursor', 'skills'), label: 'Cursor Skill → .cursor/skills/tfds/ (唤起:/tfds)' },
|
|
137
|
+
claude: { base: path.join(projectRoot, '.claude', 'skills'), label: 'Claude Code Skill → .claude/skills/tfds/ (唤起:/tfds)' },
|
|
138
|
+
codex: { base: path.join(projectRoot, '.codex', 'skills'), label: 'Codex 参考文件 → .codex/skills/tfds/ (若 /tfds 不出现,请用下方手动提示词)' },
|
|
139
|
+
agents: { base: path.join(projectRoot, '.agents', 'skills'), label: 'Agents Skill → .agents/skills/tfds/ (通用 agent 兜底)' },
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 复制整个 skill 目录到指定 IDE 的 skills 路径。
|
|
144
|
+
* @param {'cursor'|'claude'|'codex'|'agents'} which
|
|
145
|
+
*/
|
|
146
|
+
function installSkillDir(which) {
|
|
147
|
+
const target = SKILL_DIR_TARGETS[which];
|
|
148
|
+
const dest = path.join(target.base, 'tfds');
|
|
149
|
+
|
|
150
|
+
// 迁移旧版大写路径(仅 Cursor)
|
|
151
|
+
if (which === 'cursor') {
|
|
152
|
+
const legacy = path.join(projectRoot, '.cursor', 'skills', 'TFDS');
|
|
153
|
+
if (!fs.existsSync(dest) && fs.existsSync(legacy)) {
|
|
154
|
+
try {
|
|
155
|
+
fs.renameSync(legacy, dest);
|
|
156
|
+
done.push('Cursor Skill 大写路径已迁移 → .cursor/skills/tfds/ (/tfds)');
|
|
157
|
+
} catch (e) {
|
|
158
|
+
todo.push(`Skill 迁移失败(${e?.message}),请手动重命名 .cursor/skills/TFDS → tfds`);
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (fs.existsSync(dest)) {
|
|
165
|
+
if (needsSkillRefresh(dest)) {
|
|
166
|
+
try {
|
|
167
|
+
copySkillDir(dest);
|
|
168
|
+
done.push(`Skill 已存在且已同步新版(${which}):${path.relative(projectRoot, dest)}`);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
todo.push(`Skill 同步失败(${which}):${e?.message || e}。请删除 ${path.relative(projectRoot, dest)} 后重新执行 npm i。`);
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
done.push(`Skill 已存在且完整,跳过(${which}):${path.relative(projectRoot, dest)}`);
|
|
174
|
+
}
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
copySkillDir(dest);
|
|
180
|
+
done.push(target.label);
|
|
181
|
+
} catch (e) {
|
|
182
|
+
todo.push(`Skill 复制失败(${which}):${e?.message || e}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function resolveCodexHome() {
|
|
187
|
+
if (process.env.CODEX_HOME) return path.resolve(process.env.CODEX_HOME);
|
|
188
|
+
const home = os.homedir();
|
|
189
|
+
return home ? path.join(home, '.codex') : null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function installCodexUserSkill() {
|
|
193
|
+
const codexHome = resolveCodexHome();
|
|
194
|
+
if (!codexHome) {
|
|
195
|
+
todo.push('Codex 用户级 Skill 未写入:无法解析 home 目录。');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const dest = path.join(codexHome, 'skills', 'tfds');
|
|
200
|
+
if (fs.existsSync(dest)) {
|
|
201
|
+
if (needsSkillRefresh(dest)) {
|
|
202
|
+
try {
|
|
203
|
+
copySkillDir(dest);
|
|
204
|
+
done.push(`Codex 用户级 Skill 已存在且已同步新版:${dest}`);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
todo.push(`Codex 用户级 Skill 同步失败:${e?.message || e}。请删除 ${dest} 后重新执行 npm i。`);
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
done.push(`Codex 用户级 Skill 已存在且完整,跳过:${dest}`);
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
copySkillDir(dest);
|
|
216
|
+
done.push(`Codex 用户级 Skill → ${dest} (新开/重启 Codex 后 /tfds)`);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
todo.push(`Codex 用户级 Skill 写入失败:${e?.message || e}。可手动复制 skills/tfds 到 ${dest}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (process.env.SKIP_TFDS_CURSOR_SKILL === '1') {
|
|
223
|
+
done.push('Skill 复制已跳过(SKIP_TFDS_CURSOR_SKILL=1)');
|
|
224
|
+
} else if (!skillSrc) {
|
|
225
|
+
todo.push('包内未找到 skills/tfds 目录,Skill 未复制(可能是 files 裁剪的极简包)');
|
|
226
|
+
} else {
|
|
227
|
+
installSkillDir('cursor'); // Cursor → .cursor/skills/tfds/
|
|
228
|
+
installSkillDir('claude'); // Claude Code → .claude/skills/tfds/
|
|
229
|
+
installSkillDir('codex'); // Codex → .codex/skills/tfds/
|
|
230
|
+
installSkillDir('agents'); // 通用兜底 → .agents/skills/tfds/
|
|
231
|
+
if (process.env.SKIP_TFDS_CODEX_GLOBAL === '1') {
|
|
232
|
+
done.push('Codex 用户级 Skill 复制已跳过(SKIP_TFDS_CODEX_GLOBAL=1)');
|
|
233
|
+
} else {
|
|
234
|
+
installCodexUserSkill();
|
|
235
|
+
}
|
|
236
|
+
// Trae:故意不自动写 .trae/rules/(避免 always-on 污染所有对话)
|
|
237
|
+
todo.push(
|
|
238
|
+
'Trae 用户请手动操作:把 node_modules/@tfdesign/b-end/skills/tfds/ 加入 Trae 项目知识库(命名 tfds),之后 @tfds 引用。',
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ─────────────────────────────────────────────────────────────────
|
|
243
|
+
// Step 2: 入口 CSS 自动补丁
|
|
244
|
+
// ─────────────────────────────────────────────────────────────────
|
|
245
|
+
|
|
246
|
+
if (process.env.SKIP_TFDS_CSS_PATCH === '1') {
|
|
247
|
+
todo.push(
|
|
248
|
+
'CSS 补丁已跳过(SKIP_TFDS_CSS_PATCH=1),请手动在入口 CSS 添加 theme.css import 与 @source 扫描',
|
|
249
|
+
);
|
|
250
|
+
} else {
|
|
251
|
+
patchEntryCss();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function candidateCssFiles() {
|
|
255
|
+
const rels = [
|
|
256
|
+
'src/index.css',
|
|
257
|
+
'src/main.css',
|
|
258
|
+
'src/styles.css',
|
|
259
|
+
'src/global.css',
|
|
260
|
+
'app/globals.css',
|
|
261
|
+
'styles/globals.css',
|
|
262
|
+
'index.css',
|
|
263
|
+
];
|
|
264
|
+
return rels.map((r) => path.join(projectRoot, r)).filter((p) => fs.existsSync(p));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function patchEntryCss() {
|
|
268
|
+
const cssFiles = candidateCssFiles();
|
|
269
|
+
|
|
270
|
+
if (cssFiles.length === 0) {
|
|
271
|
+
todo.push(
|
|
272
|
+
'未在常见路径找到入口 CSS,请手动在入口 CSS 添加(src/index.css 为例):\n' +
|
|
273
|
+
' @import "tailwindcss";\n' +
|
|
274
|
+
' @import "@tfdesign/b-end/theme.css";\n' +
|
|
275
|
+
' @source "./**/*.{js,jsx,ts,tsx}";\n' +
|
|
276
|
+
' @source "../node_modules/@tfdesign/b-end/**/*.{js,jsx}";',
|
|
277
|
+
);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
for (const cssPath of cssFiles) {
|
|
282
|
+
let content;
|
|
283
|
+
try {
|
|
284
|
+
content = fs.readFileSync(cssPath, 'utf8');
|
|
285
|
+
} catch {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const rel = path.relative(projectRoot, cssPath);
|
|
290
|
+
|
|
291
|
+
// 已有 theme.css → 无需操作
|
|
292
|
+
if (/@tfdesign\/b-end\/theme\.css/.test(content)) {
|
|
293
|
+
done.push(`CSS 已配置,无需更改:${rel}`);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// 没有 @import "tailwindcss" → 不改写,提示手动
|
|
298
|
+
if (!/@import\s+["']tailwindcss["']/.test(content)) {
|
|
299
|
+
continue; // 尝试下一个候选
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 计算 CSS 文件到 node_modules 的相对路径
|
|
303
|
+
const cssDir = path.dirname(cssPath);
|
|
304
|
+
const nmRel = path.relative(cssDir, path.join(projectRoot, 'node_modules')).replace(/\\/g, '/') || '.';
|
|
305
|
+
|
|
306
|
+
const hasSource = /@source[^;]*@tfdesign\/b-end/i.test(content);
|
|
307
|
+
|
|
308
|
+
// 在 @import "tailwindcss"; 行后插入
|
|
309
|
+
const insertion =
|
|
310
|
+
`\n@import "@tfdesign/b-end/theme.css";` +
|
|
311
|
+
(hasSource ? '' : `\n@source "./**/*.{js,jsx,ts,tsx}";\n@source "${nmRel}/@tfdesign/b-end/**/*.{js,jsx}";`);
|
|
312
|
+
|
|
313
|
+
const patched = content.replace(
|
|
314
|
+
/(@import\s+["']tailwindcss["'];[^\n]*)/,
|
|
315
|
+
`$1${insertion}`,
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
fs.writeFileSync(cssPath, patched, 'utf8');
|
|
320
|
+
done.push(`CSS 已自动配置:${rel}`);
|
|
321
|
+
done.push(` + @import "@tfdesign/b-end/theme.css"`);
|
|
322
|
+
if (!hasSource) {
|
|
323
|
+
done.push(` + @source "./**/*.{js,jsx,ts,tsx}"`);
|
|
324
|
+
done.push(` + @source "${nmRel}/@tfdesign/b-end/**/*.{js,jsx}"`);
|
|
325
|
+
}
|
|
326
|
+
} catch (e) {
|
|
327
|
+
todo.push(
|
|
328
|
+
`CSS 自动补丁写入失败(${rel}):${e?.message},请手动在 @import "tailwindcss" 后追加:\n` +
|
|
329
|
+
` @import "@tfdesign/b-end/theme.css";\n` +
|
|
330
|
+
` @source "${nmRel}/@tfdesign/b-end/**/*.{js,jsx}";`,
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
return; // 只补丁第一个匹配的 CSS 文件
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// 所有候选 CSS 都没有 @import "tailwindcss"
|
|
337
|
+
const firstCss = path.relative(projectRoot, cssFiles[0]);
|
|
338
|
+
todo.push(
|
|
339
|
+
`在 ${firstCss} 中未找到 @import "tailwindcss",CSS 未自动修改。\n` +
|
|
340
|
+
' 请在入口 CSS 的 @import "tailwindcss" 之后手动追加:\n' +
|
|
341
|
+
' @import "@tfdesign/b-end/theme.css";\n' +
|
|
342
|
+
' @source "../node_modules/@tfdesign/b-end/**/*.{js,jsx}";',
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ─────────────────────────────────────────────────────────────────
|
|
347
|
+
// Step 3: 终端安装报告
|
|
348
|
+
// ─────────────────────────────────────────────────────────────────
|
|
349
|
+
|
|
350
|
+
console.log('\n╔══════════════════════════════════════════════════════╗');
|
|
351
|
+
console.log('║ @tfdesign/b-end 安装完成 ║');
|
|
352
|
+
console.log('╚══════════════════════════════════════════════════════╝\n');
|
|
353
|
+
|
|
354
|
+
if (done.length) {
|
|
355
|
+
console.log('✓ 已完成:');
|
|
356
|
+
done.forEach((l) => console.log(` ${l}`));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (todo.length) {
|
|
360
|
+
console.log('\n⚠ 还需手动处理:');
|
|
361
|
+
todo.forEach((l) => console.log(` ! ${l}`));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
console.log('\n──────────────────────────────────────────────────────');
|
|
365
|
+
console.log(' 规范仅在你主动调用时生效(opt-in,不影响其他对话):');
|
|
366
|
+
console.log(' Cursor → 重新打开项目 / 新开 Agent 会话后输入 /tfds');
|
|
367
|
+
console.log(' Claude Code → 重启当前 Claude Code 会话后输入 /tfds');
|
|
368
|
+
console.log(' Codex → 新开/重启 Codex 会话后输入 /tfds(当前会话通常不会热加载)');
|
|
369
|
+
console.log(' Trae → 不会自动出现 /tfds;把 skills/tfds/ 手动加入项目知识库 → @tfds');
|
|
370
|
+
console.log('');
|
|
371
|
+
console.log(' ⚠ 勿把 TFDS 规范写入 AGENTS.md / .trae/rules/(全局通道会污染所有对话)');
|
|
372
|
+
console.log(' ⚠ 输入 / 后没看到 tfds?这通常是 IDE 尚未重新扫描 Skill 目录;请重启 IDE / 重新打开项目 / 新开会话。');
|
|
373
|
+
console.log('──────────────────────────────────────────────────────');
|
|
374
|
+
console.log(
|
|
375
|
+
' 自检(只读):node node_modules/@tfdesign/b-end/scripts/check-tfds-integration.mjs',
|
|
376
|
+
);
|
|
377
|
+
console.log(
|
|
378
|
+
' 跳过 CSS 补丁:SKIP_TFDS_CSS_PATCH=1 npm i | 跳过 Skill:SKIP_TFDS_CURSOR_SKILL=1 npm i | 跳过 Codex 全局 Skill:SKIP_TFDS_CODEX_GLOBAL=1 npm i',
|
|
379
|
+
);
|
|
380
|
+
console.log('');
|
|
381
|
+
|
|
382
|
+
process.exit(0);
|