@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,520 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* TFDS B-End 全自动安装脚本
|
|
4
|
+
*
|
|
5
|
+
* 离线包推荐在业务项目根目录执行:
|
|
6
|
+
* node tfds-npm-distribution/setup.mjs
|
|
7
|
+
*
|
|
8
|
+
* 公共 npm 推荐在业务项目根目录执行:
|
|
9
|
+
* npx -y -p @tfdesign/b-end@latest tfds-setup
|
|
10
|
+
*
|
|
11
|
+
* 兼容旧入口:
|
|
12
|
+
* node tfds-npm-distribution/tfds-b-end/scripts/setup.mjs
|
|
13
|
+
* 或在任意目录执行脚本绝对路径,脚本会优先把 tfds-npm-distribution 的父目录识别为目标项目。
|
|
14
|
+
* 如需手动指定目标项目:
|
|
15
|
+
* node /path/to/tfds-npm-distribution/tfds-b-end/scripts/setup.mjs --target /path/to/app
|
|
16
|
+
*
|
|
17
|
+
* 自动完成(按需判断,已满足则跳过):
|
|
18
|
+
* 1. 检测 package.json,不存在则自动创建最小 Vite + React 项目
|
|
19
|
+
* 2. 检测 tailwindcss + @tailwindcss/vite,缺失则自动安装
|
|
20
|
+
* 3. 检测 vite.config,缺少 tailwindcss() 插件则自动写入
|
|
21
|
+
* 4. 检测入口 CSS,缺少 @import "tailwindcss" 则自动写入(找不到则创建 src/index.css)
|
|
22
|
+
* 5. 安装 @tfdesign/b-end(触发 postinstall:自动复制 Skill + CSS 补丁)
|
|
23
|
+
* 6. 运行接入自检,输出结果
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { execSync } from 'node:child_process';
|
|
27
|
+
import fs from 'node:fs';
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
import { fileURLToPath } from 'node:url';
|
|
30
|
+
|
|
31
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
const pkgRoot = path.resolve(__dirname, '..');
|
|
33
|
+
const cwd = process.cwd();
|
|
34
|
+
const distributionRoot = path.basename(path.dirname(pkgRoot)) === 'tfds-npm-distribution'
|
|
35
|
+
? path.dirname(pkgRoot)
|
|
36
|
+
: null;
|
|
37
|
+
const isOfflineDistribution = Boolean(distributionRoot);
|
|
38
|
+
const publicNpmPackageName = '@tfdesign/b-end';
|
|
39
|
+
const preferredSetupCommand = isOfflineDistribution
|
|
40
|
+
? 'node tfds-npm-distribution/setup.mjs'
|
|
41
|
+
: 'npx -y -p @tfdesign/b-end@latest tfds-setup';
|
|
42
|
+
|
|
43
|
+
function parseTargetArg() {
|
|
44
|
+
const args = process.argv.slice(2);
|
|
45
|
+
const targetIndex = args.findIndex((arg) => arg === '--target' || arg === '-t');
|
|
46
|
+
if (targetIndex >= 0 && args[targetIndex + 1]) return args[targetIndex + 1];
|
|
47
|
+
const inline = args.find((arg) => arg.startsWith('--target='));
|
|
48
|
+
if (inline) return inline.slice('--target='.length);
|
|
49
|
+
return process.env.TFDS_TARGET || '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function hasPackageJson(dir) {
|
|
53
|
+
return fs.existsSync(path.join(dir, 'package.json'));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function readJsonSafe(file) {
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getNodeMajorVersion() {
|
|
65
|
+
return Number.parseInt(String(process.versions.node || '0').split('.')[0], 10) || 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function hasUsableNpm() {
|
|
69
|
+
try {
|
|
70
|
+
execSync('npm --version', { stdio: 'pipe', encoding: 'utf8' });
|
|
71
|
+
return true;
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function printEnvGuide() {
|
|
78
|
+
console.log('\n╔══════════════════════════════════════════════════════╗');
|
|
79
|
+
console.log('║ 现在还不能开始安装 TFDS ║');
|
|
80
|
+
console.log('╚══════════════════════════════════════════════════════╝');
|
|
81
|
+
console.log('\n 开始前请先确认:');
|
|
82
|
+
console.log(' 1. 本机已安装 Node.js 18 或更高版本');
|
|
83
|
+
console.log(' 2. npm 可以在终端中直接使用');
|
|
84
|
+
console.log('\n 你只需要这样处理:');
|
|
85
|
+
console.log(' • 安装或升级到 Node.js LTS(推荐 20+)');
|
|
86
|
+
console.log(' • 安装完成后,重新打开 IDE 或终端,再执行:');
|
|
87
|
+
console.log(` ${preferredSetupCommand}`);
|
|
88
|
+
console.log('');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function ensureRuntimePrerequisites() {
|
|
92
|
+
const nodeMajor = getNodeMajorVersion();
|
|
93
|
+
if (nodeMajor < 18) {
|
|
94
|
+
printEnvGuide();
|
|
95
|
+
console.log(` 你当前安装的 Node.js 版本:${process.versions.node}`);
|
|
96
|
+
console.log(' 继续安装需要 Node.js 18 或更高版本。\n');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!hasUsableNpm()) {
|
|
101
|
+
printEnvGuide();
|
|
102
|
+
console.log(` 你当前安装的 Node.js 版本:${process.versions.node}`);
|
|
103
|
+
console.log(' 目前没有找到可用的 npm。请确认 Node.js 安装完整,或重新安装 Node.js LTS。\n');
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function isTfdsPackageDir(dir) {
|
|
109
|
+
const pkg = readJsonSafe(path.join(dir, 'package.json'));
|
|
110
|
+
return pkg?.name === '@tfdesign/b-end';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isInside(child, parent) {
|
|
114
|
+
const rel = path.relative(parent, child);
|
|
115
|
+
return rel === '' || (!!rel && !rel.startsWith('..') && !path.isAbsolute(rel));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function findNearestBusinessProject(startDir) {
|
|
119
|
+
let cur = path.resolve(startDir);
|
|
120
|
+
while (true) {
|
|
121
|
+
if (hasPackageJson(cur) && !isTfdsPackageDir(cur)) return cur;
|
|
122
|
+
const next = path.dirname(cur);
|
|
123
|
+
if (next === cur) return null;
|
|
124
|
+
cur = next;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function resolveProjectRoot() {
|
|
129
|
+
const explicitTarget = parseTargetArg();
|
|
130
|
+
if (explicitTarget) return path.resolve(cwd, explicitTarget);
|
|
131
|
+
|
|
132
|
+
// 正常情况:IDE 打开的就是业务项目根。
|
|
133
|
+
if (hasPackageJson(cwd) && !isTfdsPackageDir(cwd)) return cwd;
|
|
134
|
+
|
|
135
|
+
// 用户在业务项目里放了 tfds-npm-distribution,但 AI 的 cwd 可能在安装包内部。
|
|
136
|
+
if (distributionRoot) {
|
|
137
|
+
const parent = path.dirname(distributionRoot);
|
|
138
|
+
if (isInside(cwd, distributionRoot) || !hasPackageJson(cwd)) return parent;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 用户把安装包放在当前目录下,但当前目录还没有 package.json(全新空项目)。
|
|
142
|
+
if (fs.existsSync(path.join(cwd, 'tfds-npm-distribution', 'tfds-b-end', 'package.json'))) {
|
|
143
|
+
return cwd;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return findNearestBusinessProject(cwd) || cwd;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const projectRoot = resolveProjectRoot();
|
|
150
|
+
|
|
151
|
+
ensureRuntimePrerequisites();
|
|
152
|
+
|
|
153
|
+
function log(msg) { console.log(`\n[安装向导] ${msg}`); }
|
|
154
|
+
function ok(msg) { console.log(` ✓ ${msg}`); }
|
|
155
|
+
function warn(msg) { console.log(` ⚠ ${msg}`); }
|
|
156
|
+
|
|
157
|
+
function ensureDir(dir) {
|
|
158
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function writeIfMissing(file, content) {
|
|
162
|
+
if (fs.existsSync(file)) return false;
|
|
163
|
+
ensureDir(path.dirname(file));
|
|
164
|
+
fs.writeFileSync(file, content, 'utf8');
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function toPackageName(name) {
|
|
169
|
+
const safe = String(name || 'tfds-app')
|
|
170
|
+
.toLowerCase()
|
|
171
|
+
.replace(/[^a-z0-9._-]+/g, '-')
|
|
172
|
+
.replace(/^-+|-+$/g, '');
|
|
173
|
+
return safe || 'tfds-app';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function createMinimalViteReactProject(root) {
|
|
177
|
+
const appName = toPackageName(path.basename(root));
|
|
178
|
+
writeIfMissing(path.join(root, 'package.json'), `${JSON.stringify({
|
|
179
|
+
name: appName,
|
|
180
|
+
private: true,
|
|
181
|
+
version: '0.0.0',
|
|
182
|
+
type: 'module',
|
|
183
|
+
scripts: {
|
|
184
|
+
dev: 'vite',
|
|
185
|
+
build: 'vite build',
|
|
186
|
+
preview: 'vite preview',
|
|
187
|
+
},
|
|
188
|
+
dependencies: {},
|
|
189
|
+
devDependencies: {},
|
|
190
|
+
}, null, 2)}\n`);
|
|
191
|
+
|
|
192
|
+
writeIfMissing(path.join(root, 'index.html'), `<div id="root"></div>
|
|
193
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
194
|
+
`);
|
|
195
|
+
|
|
196
|
+
writeIfMissing(path.join(root, 'vite.config.js'), `import { defineConfig } from 'vite';
|
|
197
|
+
import react from '@vitejs/plugin-react';
|
|
198
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
199
|
+
|
|
200
|
+
export default defineConfig({
|
|
201
|
+
plugins: [react(), tailwindcss()],
|
|
202
|
+
});
|
|
203
|
+
`);
|
|
204
|
+
|
|
205
|
+
writeIfMissing(path.join(root, 'src', 'main.jsx'), `import React from 'react';
|
|
206
|
+
import { createRoot } from 'react-dom/client';
|
|
207
|
+
import './index.css';
|
|
208
|
+
import App from './App.jsx';
|
|
209
|
+
|
|
210
|
+
createRoot(document.getElementById('root')).render(
|
|
211
|
+
<React.StrictMode>
|
|
212
|
+
<App />
|
|
213
|
+
</React.StrictMode>
|
|
214
|
+
);
|
|
215
|
+
`);
|
|
216
|
+
|
|
217
|
+
writeIfMissing(path.join(root, 'src', 'App.jsx'), `export default function App() {
|
|
218
|
+
return (
|
|
219
|
+
<main style={{ padding: 24, fontFamily: 'system-ui, sans-serif' }}>
|
|
220
|
+
<h1>TFDS Ready</h1>
|
|
221
|
+
<p>项目已初始化,可以开始接入 TFDS 设计规范。</p>
|
|
222
|
+
</main>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
`);
|
|
226
|
+
|
|
227
|
+
writeIfMissing(path.join(root, 'src', 'index.css'), '@import "tailwindcss";\n');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function readProjectPackageJson() {
|
|
231
|
+
return JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function getMergedDeps(pkg) {
|
|
235
|
+
return {
|
|
236
|
+
...pkg.dependencies,
|
|
237
|
+
...pkg.devDependencies,
|
|
238
|
+
...pkg.peerDependencies,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function resolveInstalledPackageDir(pkgName) {
|
|
243
|
+
return path.join(projectRoot, 'node_modules', ...pkgName.split('/'));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function hasInstalledPackage(pkgName) {
|
|
247
|
+
return fs.existsSync(resolveInstalledPackageDir(pkgName));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function getMissingPackages(pkg, pkgNames) {
|
|
251
|
+
const allDeps = getMergedDeps(pkg);
|
|
252
|
+
return pkgNames.filter((name) => !allDeps[name] || !hasInstalledPackage(name));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function formatPackageList(pkgNames) {
|
|
256
|
+
return pkgNames.join(' / ');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function syncInstalledTfdsSkills() {
|
|
260
|
+
const skillSyncScript = path.join(
|
|
261
|
+
projectRoot,
|
|
262
|
+
'node_modules',
|
|
263
|
+
'@tfdesign',
|
|
264
|
+
'b-end',
|
|
265
|
+
'scripts',
|
|
266
|
+
'postinstall-cursor-skill.mjs',
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (!fs.existsSync(skillSyncScript)) {
|
|
270
|
+
warn('没有找到 skill 同步脚本,已跳过自动刷新。后续可重新执行一次 npm install @tfdesign/b-end。');
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
console.log(' 正在刷新本地 skill 描述和规则文件...');
|
|
275
|
+
if (!run(`node "${skillSyncScript}"`, {
|
|
276
|
+
inherit: true,
|
|
277
|
+
env: {
|
|
278
|
+
SKIP_TFDS_CSS_PATCH: '1',
|
|
279
|
+
},
|
|
280
|
+
})) {
|
|
281
|
+
warn('skill 自动刷新未完成。你可以稍后重新执行当前安装脚本,或手动运行:');
|
|
282
|
+
warn('node node_modules/@tfdesign/b-end/scripts/postinstall-cursor-skill.mjs');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
ok('skill 已同步到本地 IDE 目录');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 执行命令,全程静默——进度由调用方用中文打印。
|
|
291
|
+
* 失败时打印错误摘要(stderr 前 20 行)便于排查。
|
|
292
|
+
* @param {string} cmd
|
|
293
|
+
* @param {{ inherit?: boolean, env?: Record<string, string | undefined> }} [opts] inherit=true 时保留原始输出(用于交互式命令)
|
|
294
|
+
*/
|
|
295
|
+
function run(cmd, opts = {}) {
|
|
296
|
+
try {
|
|
297
|
+
execSync(cmd, {
|
|
298
|
+
stdio: opts.inherit ? 'inherit' : 'pipe',
|
|
299
|
+
cwd: projectRoot,
|
|
300
|
+
encoding: 'utf8',
|
|
301
|
+
env: {
|
|
302
|
+
...process.env,
|
|
303
|
+
...opts.env,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
return true;
|
|
307
|
+
} catch (e) {
|
|
308
|
+
if (!opts.inherit) {
|
|
309
|
+
const errLines = (e.stderr || e.stdout || '').split('\n').slice(0, 20).join('\n');
|
|
310
|
+
if (errLines.trim()) {
|
|
311
|
+
console.log(' --- 错误详情(英文)---');
|
|
312
|
+
console.log(errLines);
|
|
313
|
+
console.log(' ----------------------');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
console.log('\n╔══════════════════════════════════════════════════════╗');
|
|
321
|
+
console.log('║ TFDS 页面生成能力安装向导 ║');
|
|
322
|
+
console.log('╚══════════════════════════════════════════════════════╝');
|
|
323
|
+
console.log(`\n 环境检查已通过:Node.js ${process.versions.node},npm 可用`);
|
|
324
|
+
console.log(`\n 安装包位置:${pkgRoot}`);
|
|
325
|
+
console.log(` 准备安装到:${projectRoot}`);
|
|
326
|
+
|
|
327
|
+
// ─────────────────────────────────────────────────────────────────
|
|
328
|
+
// Step 1:确认 package.json 存在
|
|
329
|
+
// ─────────────────────────────────────────────────────────────────
|
|
330
|
+
log('第 1 步 / 6 准备项目基础环境...');
|
|
331
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
332
|
+
const bootstrapDeps = ['react', 'react-dom', 'vite', '@vitejs/plugin-react'];
|
|
333
|
+
let createdProjectShell = false;
|
|
334
|
+
|
|
335
|
+
if (!fs.existsSync(pkgPath)) {
|
|
336
|
+
console.log('\n ⚠ 还没有检测到项目配置,正在为你准备一个可运行的 React 项目...');
|
|
337
|
+
createMinimalViteReactProject(projectRoot);
|
|
338
|
+
createdProjectShell = true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let pkg = readProjectPackageJson();
|
|
342
|
+
if (pkg.name === '@tfdesign/b-end') {
|
|
343
|
+
console.log('\n ✗ 当前打开的是 TFDS 安装包目录,不是你的业务项目目录。');
|
|
344
|
+
console.log(' 请改用 --target 指定你的项目根目录,例如:');
|
|
345
|
+
console.log(` node "${path.join(pkgRoot, 'scripts', 'setup.mjs')}" --target "/path/to/your-app"\n`);
|
|
346
|
+
process.exit(0);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const missingBootstrapDeps = getMissingPackages(pkg, bootstrapDeps);
|
|
350
|
+
if (missingBootstrapDeps.length > 0) {
|
|
351
|
+
if (createdProjectShell) {
|
|
352
|
+
console.log(' 正在安装项目基础依赖,通常需要 10-60 秒...');
|
|
353
|
+
} else {
|
|
354
|
+
warn(`检测到上次安装还没有完成,正在继续补齐项目基础依赖:${formatPackageList(missingBootstrapDeps)}`);
|
|
355
|
+
console.log(' 无需重新开始,脚本会从当前进度继续...');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!run(`npm install ${bootstrapDeps.join(' ')}`, { inherit: true })) {
|
|
359
|
+
warn('项目基础依赖暂未安装完成。这通常和网络或终端权限有关。');
|
|
360
|
+
warn('建议切到系统终端重新执行同一脚本,网络恢复后会从当前进度继续。');
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
pkg = readProjectPackageJson();
|
|
365
|
+
ok('项目基础环境已准备好');
|
|
366
|
+
if (createdProjectShell) {
|
|
367
|
+
console.log(' ✓ 项目已准备完成,继续安装 TFDS 页面生成能力...');
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
ok('项目配置和基础依赖已准备好');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// ─────────────────────────────────────────────────────────────────
|
|
374
|
+
// Step 2:检测并安装 tailwindcss + @tailwindcss/vite
|
|
375
|
+
// ─────────────────────────────────────────────────────────────────
|
|
376
|
+
log('第 2 步 / 6 准备页面样式能力...');
|
|
377
|
+
const tailwindDeps = ['tailwindcss', '@tailwindcss/vite'];
|
|
378
|
+
const missingTailwindDeps = getMissingPackages(pkg, tailwindDeps);
|
|
379
|
+
|
|
380
|
+
if (missingTailwindDeps.length === 0) {
|
|
381
|
+
ok('页面样式依赖已准备好,跳过');
|
|
382
|
+
} else {
|
|
383
|
+
warn(`检测到页面样式能力还未准备完整,正在继续补齐:${formatPackageList(missingTailwindDeps)}`);
|
|
384
|
+
console.log(' 这一步通常也需要一点时间,请稍候...');
|
|
385
|
+
if (!run(`npm install tailwindcss @tailwindcss/vite`, { inherit: true })) {
|
|
386
|
+
warn('页面样式依赖暂未安装完成。建议切到系统终端重新执行同一脚本。');
|
|
387
|
+
warn('如需手动处理,可执行:npm install tailwindcss @tailwindcss/vite');
|
|
388
|
+
} else {
|
|
389
|
+
pkg = readProjectPackageJson();
|
|
390
|
+
ok('页面样式依赖已准备好');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ─────────────────────────────────────────────────────────────────
|
|
395
|
+
// Step 3:检测 vite.config,缺少 tailwindcss() 插件则自动写入
|
|
396
|
+
// ─────────────────────────────────────────────────────────────────
|
|
397
|
+
log('第 3 步 / 6 检查项目配置...');
|
|
398
|
+
const viteConfigCandidates = [
|
|
399
|
+
'vite.config.js', 'vite.config.ts',
|
|
400
|
+
'vite.config.mjs', 'vite.config.mts',
|
|
401
|
+
];
|
|
402
|
+
let viteConfigPath = null;
|
|
403
|
+
for (const f of viteConfigCandidates) {
|
|
404
|
+
const p = path.join(projectRoot, f);
|
|
405
|
+
if (fs.existsSync(p)) { viteConfigPath = p; break; }
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (!viteConfigPath) {
|
|
409
|
+
warn('没有找到项目配置文件,已跳过自动更新。后续请手动在 vite.config 中加入 tailwindcss() 插件。');
|
|
410
|
+
} else {
|
|
411
|
+
let viteContent = fs.readFileSync(viteConfigPath, 'utf8');
|
|
412
|
+
const hasPlugin = /tailwindcss\s*\(\s*\)/.test(viteContent);
|
|
413
|
+
|
|
414
|
+
if (hasPlugin) {
|
|
415
|
+
ok(`${path.basename(viteConfigPath)} 已包含页面样式插件,跳过`);
|
|
416
|
+
} else {
|
|
417
|
+
// 加 import(如果没有)
|
|
418
|
+
if (!/@tailwindcss\/vite/.test(viteContent)) {
|
|
419
|
+
viteContent = `import tailwindcss from '@tailwindcss/vite';\n` + viteContent;
|
|
420
|
+
}
|
|
421
|
+
// 在 plugins 数组里插入 tailwindcss()
|
|
422
|
+
if (/plugins\s*:\s*\[/.test(viteContent)) {
|
|
423
|
+
viteContent = viteContent.replace(
|
|
424
|
+
/plugins\s*:\s*\[/,
|
|
425
|
+
'plugins: [tailwindcss(), '
|
|
426
|
+
);
|
|
427
|
+
} else {
|
|
428
|
+
warn('项目配置文件里没有找到 plugins 数组,后续请手动加入 tailwindcss() 插件。');
|
|
429
|
+
}
|
|
430
|
+
fs.writeFileSync(viteConfigPath, viteContent, 'utf8');
|
|
431
|
+
ok(`${path.basename(viteConfigPath)} 已自动更新`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// ─────────────────────────────────────────────────────────────────
|
|
436
|
+
// Step 4:检测入口 CSS,缺少 @import "tailwindcss" 则自动写入
|
|
437
|
+
// ─────────────────────────────────────────────────────────────────
|
|
438
|
+
log('第 4 步 / 6 检查页面样式入口...');
|
|
439
|
+
const cssCandidates = [
|
|
440
|
+
'src/index.css', 'src/main.css', 'src/styles.css',
|
|
441
|
+
'src/global.css', 'app/globals.css', 'styles/globals.css', 'index.css',
|
|
442
|
+
];
|
|
443
|
+
|
|
444
|
+
let cssHandled = false;
|
|
445
|
+
for (const rel of cssCandidates) {
|
|
446
|
+
const cssPath = path.join(projectRoot, rel);
|
|
447
|
+
if (!fs.existsSync(cssPath)) continue;
|
|
448
|
+
|
|
449
|
+
const content = fs.readFileSync(cssPath, 'utf8');
|
|
450
|
+
if (/@import\s+["']tailwindcss["']/.test(content)) {
|
|
451
|
+
ok(`${rel} 已包含页面样式入口,跳过`);
|
|
452
|
+
cssHandled = true;
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
// 在文件顶部插入
|
|
456
|
+
fs.writeFileSync(cssPath, `@import "tailwindcss";\n` + content, 'utf8');
|
|
457
|
+
ok(`${rel} 已自动补齐页面样式入口`);
|
|
458
|
+
cssHandled = true;
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (!cssHandled) {
|
|
463
|
+
const defaultCss = path.join(projectRoot, 'src', 'index.css');
|
|
464
|
+
fs.mkdirSync(path.dirname(defaultCss), { recursive: true });
|
|
465
|
+
fs.writeFileSync(defaultCss, '@import "tailwindcss";\n', 'utf8');
|
|
466
|
+
ok('已创建 src/index.css 并补齐页面样式入口');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ─────────────────────────────────────────────────────────────────
|
|
470
|
+
// Step 5:安装 @tfdesign/b-end(触发 postinstall)
|
|
471
|
+
// ─────────────────────────────────────────────────────────────────
|
|
472
|
+
log('第 5 步 / 6 安装 TFDS 页面生成能力...');
|
|
473
|
+
const tfdsRelPath = path.relative(projectRoot, pkgRoot).replace(/\\/g, '/');
|
|
474
|
+
const tfdsInstallSource = isOfflineDistribution
|
|
475
|
+
? `"file:${tfdsRelPath}"`
|
|
476
|
+
: publicNpmPackageName;
|
|
477
|
+
const installCmd = `npm install react react-dom lucide-react ${tfdsInstallSource} --save`;
|
|
478
|
+
const tfdsDeps = ['lucide-react', '@tfdesign/b-end'];
|
|
479
|
+
const missingTfdsDeps = getMissingPackages(pkg, tfdsDeps);
|
|
480
|
+
|
|
481
|
+
if (missingTfdsDeps.length === 0) {
|
|
482
|
+
ok('TFDS 页面生成能力已准备好,跳过');
|
|
483
|
+
} else {
|
|
484
|
+
warn(`检测到 TFDS 页面生成能力还未准备完整,正在继续安装:${formatPackageList(missingTfdsDeps)}`);
|
|
485
|
+
console.log(' 正在安装 TFDS 页面生成能力,请稍候(通常需要 10-60 秒)...');
|
|
486
|
+
if (!run(installCmd, { inherit: true })) {
|
|
487
|
+
warn('TFDS 页面生成能力暂未安装完成。建议切到系统终端重新执行同一脚本。');
|
|
488
|
+
warn('网络恢复后,脚本会从当前进度继续。');
|
|
489
|
+
warn(`如需手动执行,可运行:${installCmd}`);
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
pkg = readProjectPackageJson();
|
|
493
|
+
ok('TFDS 页面生成能力已安装完成');
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
syncInstalledTfdsSkills();
|
|
497
|
+
|
|
498
|
+
// ─────────────────────────────────────────────────────────────────
|
|
499
|
+
// Step 6:运行接入自检
|
|
500
|
+
// ─────────────────────────────────────────────────────────────────
|
|
501
|
+
log('第 6 步 / 6 检查是否可以开始使用...\n');
|
|
502
|
+
const checkScript = path.join(
|
|
503
|
+
projectRoot, 'node_modules', '@tfdesign', 'b-end',
|
|
504
|
+
'scripts', 'check-tfds-integration.mjs'
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
if (fs.existsSync(checkScript)) {
|
|
508
|
+
// 自检脚本输出均为中文,使用 inherit 直接展示
|
|
509
|
+
run(`node "${checkScript}"`, { inherit: true });
|
|
510
|
+
} else {
|
|
511
|
+
warn('没有找到自动检查脚本。你可以稍后手动执行:');
|
|
512
|
+
warn('node node_modules/@tfdesign/b-end/scripts/check-tfds-integration.mjs');
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
console.log('\n──────────────────────────────────────────────────────');
|
|
516
|
+
console.log(' 安装已完成!');
|
|
517
|
+
console.log(' 输入 /tfds 即可开始生成页面,如果输入后没有显示具体引用,可以尝试重新打开项目或新开会话。');
|
|
518
|
+
console.log(' 或者输入以下固定提示词开始生成页面:');
|
|
519
|
+
console.log(' 按 TFDS 设计规范生成页面。先读取 node_modules/@tfdesign/b-end/AI_READ_FIRST.md。需求为:……');
|
|
520
|
+
console.log('──────────────────────────────────────────────────────\n');
|