bmall-mcp 1.0.0

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.
@@ -0,0 +1,287 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { execSync } from "child_process";
4
+ import { fileURLToPath } from "url";
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const HOME = process.env.HOME || process.env.USERPROFILE || "";
8
+ const CWD = process.cwd();
9
+ // Git 仓库配置
10
+ const GIT_REPO = "git@coding.jd.com:IBKFXHJDBM/RulesManager.git";
11
+ const GIT_BRANCH = "develop";
12
+ const RULES_CACHE_DIR = path.join(HOME, ".bmall-mcp/rules-cache");
13
+ // IDE 的 Rules 目录映射(项目级别)
14
+ const IDE_PATHS = {
15
+ kiro: {
16
+ ios: path.join(CWD, ".kiro/steering/bmall-rules"),
17
+ android: path.join(CWD, ".kiro/steering/bmall-rules"),
18
+ web: path.join(CWD, ".kiro/steering/bmall-rules"),
19
+ flutter: path.join(CWD, ".kiro/steering/bmall-rules"),
20
+ unknown: path.join(CWD, ".kiro/steering/bmall-rules"),
21
+ },
22
+ cursor: {
23
+ ios: path.join(CWD, ".cursor/rules/bmall"),
24
+ android: path.join(CWD, ".cursor/rules/bmall"),
25
+ web: path.join(CWD, ".cursor/rules/bmall"),
26
+ flutter: path.join(CWD, ".cursor/rules/bmall"),
27
+ unknown: path.join(CWD, ".cursor/rules/bmall"),
28
+ },
29
+ windsurf: {
30
+ ios: path.join(CWD, ".windsurfrules"),
31
+ android: path.join(CWD, ".windsurfrules"),
32
+ web: path.join(CWD, ".windsurfrules"),
33
+ flutter: path.join(CWD, ".windsurfrules"),
34
+ unknown: path.join(CWD, ".windsurfrules"),
35
+ },
36
+ };
37
+ function log(message) {
38
+ console.error(`[bmall-mcp] ${message}`);
39
+ }
40
+ /**
41
+ * 检测项目类型
42
+ */
43
+ function detectProjectType() {
44
+ // 检查特征文件/目录
45
+ const checks = [
46
+ // iOS 特征
47
+ ["ios/Podfile", "ios"],
48
+ ["*.xcodeproj", "ios"],
49
+ ["Podfile", "ios"],
50
+ // Android 特征
51
+ ["android/build.gradle", "android"],
52
+ ["build.gradle", "android"],
53
+ ["AndroidManifest.xml", "android"],
54
+ // Web 特征
55
+ ["package.json", "web"],
56
+ ["webpack.config.js", "web"],
57
+ ["tsconfig.json", "web"],
58
+ ["vite.config.ts", "web"],
59
+ // Flutter 特征
60
+ ["pubspec.yaml", "flutter"],
61
+ ["flutter.yaml", "flutter"],
62
+ ];
63
+ for (const [pattern, type] of checks) {
64
+ try {
65
+ if (pattern.includes("*")) {
66
+ // 通配符匹配
67
+ const files = fs.readdirSync(CWD);
68
+ if (files.some(f => f.match(pattern.replace("*", ".*")))) {
69
+ log(`检测到 ${type} 项目特征: ${pattern}`);
70
+ return type;
71
+ }
72
+ }
73
+ else {
74
+ // 直接路径检查
75
+ const fullPath = path.join(CWD, pattern);
76
+ if (fs.existsSync(fullPath)) {
77
+ log(`检测到 ${type} 项目特征: ${pattern}`);
78
+ return type;
79
+ }
80
+ }
81
+ }
82
+ catch (e) {
83
+ // 继续检查下一个
84
+ }
85
+ }
86
+ log(`未检测到项目类型,使用默认值: iOS`);
87
+ return "ios";
88
+ }
89
+ /**
90
+ * 规范化用户输入的 Rules 类型
91
+ */
92
+ function normalizeRulesType(input) {
93
+ const normalized = input.toLowerCase().trim();
94
+ // iOS 的多种表达
95
+ if (["ios", "i", "iphone", "objective-c", "objc", "oc"].includes(normalized)) {
96
+ return "ios";
97
+ }
98
+ // Android 的多种表达
99
+ if (["android", "a", "kotlin", "java"].includes(normalized)) {
100
+ return "android";
101
+ }
102
+ // Web 的多种表达
103
+ if (["web", "w", "javascript", "js", "typescript", "ts", "react", "vue", "angular"].includes(normalized)) {
104
+ return "web";
105
+ }
106
+ // Flutter 的多种表达
107
+ if (["flutter", "f", "dart"].includes(normalized)) {
108
+ return "flutter";
109
+ }
110
+ // 默认返回 unknown,让调用者处理
111
+ return "unknown";
112
+ }
113
+ /**
114
+ * 获取 Git 仓库中对应项目类型的目录
115
+ */
116
+ function getGitRulesDir(projectType) {
117
+ const dirMap = {
118
+ ios: "iOS",
119
+ android: "Android",
120
+ web: "Web",
121
+ flutter: "Flutter",
122
+ unknown: "iOS",
123
+ };
124
+ return dirMap[projectType];
125
+ }
126
+ /**
127
+ * 检测当前 IDE
128
+ */
129
+ function detectCurrentIDE() {
130
+ // 检查环境变量
131
+ if (process.env.KIRO_HOME)
132
+ return "kiro";
133
+ if (process.env.CURSOR_HOME)
134
+ return "cursor";
135
+ if (process.env.WINDSURF_HOME)
136
+ return "windsurf";
137
+ // 检查目录是否存在
138
+ if (fs.existsSync(path.join(HOME, ".kiro")))
139
+ return "kiro";
140
+ if (fs.existsSync(path.join(HOME, ".cursor")))
141
+ return "cursor";
142
+ if (fs.existsSync(path.join(HOME, ".codeium/windsurf")))
143
+ return "windsurf";
144
+ // 默认返回 kiro
145
+ return "kiro";
146
+ }
147
+ /**
148
+ * 从 Git 克隆或更新 Rules(使用 sparse-checkout)
149
+ */
150
+ async function fetchRulesFromGit(projectType) {
151
+ try {
152
+ const rulesDir = getGitRulesDir(projectType);
153
+ log(`Git 仓库: ${GIT_REPO}`);
154
+ log(`分支: ${GIT_BRANCH}`);
155
+ log(`项目类型: ${projectType}`);
156
+ log(`Rules 目录: ${rulesDir}`);
157
+ log(`缓存目录: ${RULES_CACHE_DIR}`);
158
+ log(`当前工作目录: ${CWD}`);
159
+ // 创建缓存目录
160
+ if (!fs.existsSync(RULES_CACHE_DIR)) {
161
+ log(`创建缓存目录: ${RULES_CACHE_DIR}`);
162
+ fs.mkdirSync(RULES_CACHE_DIR, { recursive: true });
163
+ log(`初始化 Git 仓库...`);
164
+ execSync(`git init ${RULES_CACHE_DIR}`, { stdio: "inherit" });
165
+ log(`配置 sparse-checkout...`);
166
+ execSync(`git -C ${RULES_CACHE_DIR} config core.sparseCheckout true`, {
167
+ stdio: "inherit",
168
+ });
169
+ log(`添加远程: ${GIT_REPO}`);
170
+ execSync(`git -C ${RULES_CACHE_DIR} remote add origin ${GIT_REPO}`, { stdio: "inherit" });
171
+ log(`设置只克隆 ${rulesDir} 目录...`);
172
+ const sparseCheckoutFile = path.join(RULES_CACHE_DIR, ".git/info/sparse-checkout");
173
+ fs.writeFileSync(sparseCheckoutFile, `${rulesDir}/\n`);
174
+ log(`sparse-checkout 文件: ${sparseCheckoutFile}`);
175
+ log(`拉取分支 ${GIT_BRANCH}...`);
176
+ execSync(`git -C ${RULES_CACHE_DIR} fetch origin ${GIT_BRANCH}`, {
177
+ stdio: "inherit",
178
+ });
179
+ log(`检出分支 ${GIT_BRANCH}...`);
180
+ execSync(`git -C ${RULES_CACHE_DIR} checkout ${GIT_BRANCH}`, {
181
+ stdio: "inherit",
182
+ });
183
+ }
184
+ else {
185
+ log(`缓存目录已存在,更新中...`);
186
+ // 更新 sparse-checkout 配置
187
+ const sparseCheckoutFile = path.join(RULES_CACHE_DIR, ".git/info/sparse-checkout");
188
+ fs.writeFileSync(sparseCheckoutFile, `${rulesDir}/\n`);
189
+ log(`拉取最新更改...`);
190
+ execSync(`git -C ${RULES_CACHE_DIR} fetch origin ${GIT_BRANCH}`, {
191
+ stdio: "inherit",
192
+ });
193
+ log(`检出分支 ${GIT_BRANCH}...`);
194
+ execSync(`git -C ${RULES_CACHE_DIR} checkout ${GIT_BRANCH}`, {
195
+ stdio: "inherit",
196
+ });
197
+ log(`合并最新更改...`);
198
+ execSync(`git -C ${RULES_CACHE_DIR} pull origin ${GIT_BRANCH}`, {
199
+ stdio: "inherit",
200
+ });
201
+ }
202
+ // 返回对应项目类型的目录路径
203
+ const projectRulesDir = path.join(RULES_CACHE_DIR, rulesDir);
204
+ if (!fs.existsSync(projectRulesDir)) {
205
+ throw new Error(`${rulesDir} 目录不存在: ${projectRulesDir}`);
206
+ }
207
+ log(`${rulesDir} 目录: ${projectRulesDir}`);
208
+ return projectRulesDir;
209
+ }
210
+ catch (error) {
211
+ const errorMsg = error instanceof Error ? error.message : String(error);
212
+ throw new Error(`从 Git 获取 Rules 失败: ${errorMsg}`);
213
+ }
214
+ }
215
+ /**
216
+ * 递归复制目录中的 Markdown 文件
217
+ */
218
+ function copyMarkdownFiles(src, dest) {
219
+ if (!fs.existsSync(dest)) {
220
+ fs.mkdirSync(dest, { recursive: true });
221
+ }
222
+ let count = 0;
223
+ const files = fs.readdirSync(src);
224
+ for (const file of files) {
225
+ // 跳过隐藏文件、node_modules 和 .git
226
+ if (file.startsWith(".") || file === "node_modules") {
227
+ continue;
228
+ }
229
+ const srcPath = path.join(src, file);
230
+ const destPath = path.join(dest, file);
231
+ const stat = fs.statSync(srcPath);
232
+ if (stat.isDirectory()) {
233
+ count += copyMarkdownFiles(srcPath, destPath);
234
+ }
235
+ else if (file.endsWith(".md")) {
236
+ fs.copyFileSync(srcPath, destPath);
237
+ count++;
238
+ }
239
+ }
240
+ return count;
241
+ }
242
+ export async function syncRules(ide, rulesType) {
243
+ try {
244
+ // 确定 Rules 类型:优先使用用户指定,否则自动检测
245
+ let projectType;
246
+ if (rulesType) {
247
+ // 用户指定了 Rules 类型,规范化输入
248
+ const normalized = normalizeRulesType(rulesType);
249
+ if (normalized === "unknown") {
250
+ return `❌ 不支持的 Rules 类型: ${rulesType}\n支持的类型: iOS/Android/Web/Flutter (或其他别名)`;
251
+ }
252
+ projectType = normalized;
253
+ log(`使用用户指定的 Rules 类型: ${projectType}`);
254
+ }
255
+ else {
256
+ // 自动检测项目类型
257
+ projectType = detectProjectType();
258
+ }
259
+ // 如果没有指定 IDE,自动检测
260
+ const targetIDE = ide || detectCurrentIDE();
261
+ const idePathMap = IDE_PATHS[targetIDE];
262
+ if (!idePathMap) {
263
+ return `❌ 不支持的 IDE: ${targetIDE}\n支持的 IDE: kiro, cursor, windsurf`;
264
+ }
265
+ const targetPath = idePathMap[projectType];
266
+ // 从 Git 获取对应项目类型的 Rules
267
+ console.error("[bmall-mcp] Fetching rules from git...");
268
+ const rulesSourceDir = await fetchRulesFromGit(projectType);
269
+ // 复制文件
270
+ console.error(`[bmall-mcp] Copying files to ${targetPath}...`);
271
+ const copiedCount = copyMarkdownFiles(rulesSourceDir, targetPath);
272
+ if (copiedCount === 0) {
273
+ return `⚠️ 未找到任何 Markdown 文件\n源目录: ${rulesSourceDir}`;
274
+ }
275
+ return `✅ 同步完成!
276
+ Rules 类型: ${projectType}
277
+ IDE: ${targetIDE}
278
+ 目标目录: ${targetPath}
279
+ 复制文件数: ${copiedCount}
280
+ 缓存目录: ${RULES_CACHE_DIR}`;
281
+ }
282
+ catch (error) {
283
+ const errorMsg = error instanceof Error ? error.message : String(error);
284
+ return `❌ 同步失败: ${errorMsg}`;
285
+ }
286
+ }
287
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/tools/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export declare const HOME: string;
2
+ export declare const CWD: string;
3
+ export declare const GIT_REPO = "git@coding.jd.com:IBKFXHJDBM/RulesManager.git";
4
+ export declare const GIT_BRANCH = "develop";
5
+ export declare const RULES_CACHE_DIR: string;
6
+ export type ProjectType = "ios" | "android" | "web" | "flutter" | "unknown";
7
+ export declare const IDE_PATHS: Record<string, string>;
8
+ export declare function log(message: string): void;
9
+ export declare function detectProjectType(): ProjectType;
10
+ export declare function detectProjectName(): string;
11
+ export declare function sanitizeProjectName(name: string): string;
12
+ export declare function normalizeRulesType(input: string): ProjectType;
13
+ export declare function validateAndGetRulesType(rulesType?: string): {
14
+ type: ProjectType;
15
+ error?: string;
16
+ };
17
+ export declare function validateAndGetIDE(ide?: string): {
18
+ ide: string;
19
+ path: string;
20
+ error?: string;
21
+ };
22
+ export declare function getGitRulesDir(projectType: ProjectType): string;
23
+ export declare function detectCurrentIDE(): string;
24
+ export declare function initializeGitCache(): void;
25
+ export declare function setupSparseCheckout(rulesDir: string): void;
26
+ export declare function checkoutOrCreateBranch(branchName: string, baseBranch?: string): void;
27
+ export declare function fetchRulesFromGit(projectType: ProjectType): Promise<string>;
28
+ export declare function copyMarkdownFiles(src: string, dest: string, options?: {
29
+ backup?: boolean;
30
+ }): {
31
+ count: number;
32
+ backups: string[];
33
+ };
34
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/tools/utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,QAAoD,CAAC;AACtE,eAAO,MAAM,GAAG,QAAgB,CAAC;AAGjC,eAAO,MAAM,QAAQ,kDAAkD,CAAC;AACxE,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,eAAe,QAA4C,CAAC;AAGzE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;AAG5E,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5C,CAAC;AAEF,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,QAElC;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAsC/C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAwD1C;AAGD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAiB7D;AAED,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAejG;AAED,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAa7F;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAS/D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAUzC;AAGD,wBAAgB,kBAAkB,IAAI,IAAI,CAyBzC;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAY1D;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,GAAE,MAAmB,GAAG,IAAI,CAmChG;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCjF;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAqB,GAC/C;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAsCtC"}
@@ -0,0 +1,324 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { execSync } from "child_process";
4
+ export const HOME = process.env.HOME || process.env.USERPROFILE || "";
5
+ export const CWD = process.cwd();
6
+ // Git 仓库配置
7
+ export const GIT_REPO = "git@coding.jd.com:IBKFXHJDBM/RulesManager.git";
8
+ export const GIT_BRANCH = "develop";
9
+ export const RULES_CACHE_DIR = path.join(HOME, ".bmall-mcp/rules-cache");
10
+ // IDE 的 Rules 目录映射(项目级别)
11
+ export const IDE_PATHS = {
12
+ kiro: path.join(CWD, ".kiro/steering/bmall"),
13
+ cursor: path.join(CWD, ".cursor/rules/bmall"),
14
+ windsurf: path.join(CWD, ".windsurfrules"),
15
+ };
16
+ export function log(message) {
17
+ console.error(`[bmall-mcp] ${message}`);
18
+ }
19
+ export function detectProjectType() {
20
+ const checks = [
21
+ ["ios/Podfile", "ios"],
22
+ ["*.xcodeproj", "ios"],
23
+ ["Podfile", "ios"],
24
+ ["android/build.gradle", "android"],
25
+ ["build.gradle", "android"],
26
+ ["AndroidManifest.xml", "android"],
27
+ ["package.json", "web"],
28
+ ["webpack.config.js", "web"],
29
+ ["tsconfig.json", "web"],
30
+ ["vite.config.ts", "web"],
31
+ ["pubspec.yaml", "flutter"],
32
+ ["flutter.yaml", "flutter"],
33
+ ];
34
+ for (const [pattern, type] of checks) {
35
+ try {
36
+ if (pattern.includes("*")) {
37
+ const files = fs.readdirSync(CWD);
38
+ if (files.some(f => f.match(pattern.replace("*", ".*")))) {
39
+ log(`检测到 ${type} 项目特征: ${pattern}`);
40
+ return type;
41
+ }
42
+ }
43
+ else {
44
+ const fullPath = path.join(CWD, pattern);
45
+ if (fs.existsSync(fullPath)) {
46
+ log(`检测到 ${type} 项目特征: ${pattern}`);
47
+ return type;
48
+ }
49
+ }
50
+ }
51
+ catch (e) {
52
+ // 继续
53
+ }
54
+ }
55
+ log(`未检测到项目类型,使用默认值: iOS`);
56
+ return "ios";
57
+ }
58
+ export function detectProjectName() {
59
+ // 优先级:package.json > Podfile > pubspec.yaml > 目录名
60
+ // 1. 检查 package.json
61
+ const packageJsonPath = path.join(CWD, "package.json");
62
+ if (fs.existsSync(packageJsonPath)) {
63
+ try {
64
+ const content = fs.readFileSync(packageJsonPath, "utf-8");
65
+ const json = JSON.parse(content);
66
+ if (json.name) {
67
+ const name = sanitizeProjectName(json.name);
68
+ log(`从 package.json 检测到项目名: ${name}`);
69
+ return name;
70
+ }
71
+ }
72
+ catch (e) {
73
+ // 继续
74
+ }
75
+ }
76
+ // 2. 检查 Podfile
77
+ const podfilePath = path.join(CWD, "Podfile");
78
+ if (fs.existsSync(podfilePath)) {
79
+ try {
80
+ const content = fs.readFileSync(podfilePath, "utf-8");
81
+ const match = content.match(/platform\s*:\s*:ios.*?target\s+['"](.*?)['"]/s);
82
+ if (match && match[1]) {
83
+ const name = sanitizeProjectName(match[1]);
84
+ log(`从 Podfile 检测到项目名: ${name}`);
85
+ return name;
86
+ }
87
+ }
88
+ catch (e) {
89
+ // 继续
90
+ }
91
+ }
92
+ // 3. 检查 pubspec.yaml
93
+ const pubspecPath = path.join(CWD, "pubspec.yaml");
94
+ if (fs.existsSync(pubspecPath)) {
95
+ try {
96
+ const content = fs.readFileSync(pubspecPath, "utf-8");
97
+ const match = content.match(/^name:\s*(.+?)$/m);
98
+ if (match && match[1]) {
99
+ const name = sanitizeProjectName(match[1]);
100
+ log(`从 pubspec.yaml 检测到项目名: ${name}`);
101
+ return name;
102
+ }
103
+ }
104
+ catch (e) {
105
+ // 继续
106
+ }
107
+ }
108
+ // 4. 使用目录名
109
+ const dirName = path.basename(CWD);
110
+ const name = sanitizeProjectName(dirName);
111
+ log(`使用目录名作为项目名: ${name}`);
112
+ return name;
113
+ }
114
+ // 清理项目名,确保可以用作分支名
115
+ export function sanitizeProjectName(name) {
116
+ return name
117
+ .toLowerCase()
118
+ .replace(/[^a-z0-9-_]/g, "-") // 非法字符替换为 -
119
+ .replace(/-+/g, "-") // 多个 - 合并
120
+ .replace(/^-|-$/g, ""); // 去掉首尾 -
121
+ }
122
+ export function normalizeRulesType(input) {
123
+ const normalized = input.toLowerCase().trim();
124
+ if (["ios", "i", "iphone", "objective-c", "objc", "oc"].includes(normalized)) {
125
+ return "ios";
126
+ }
127
+ if (["android", "a", "kotlin", "java"].includes(normalized)) {
128
+ return "android";
129
+ }
130
+ if (["web", "w", "javascript", "js", "typescript", "ts", "react", "vue", "angular"].includes(normalized)) {
131
+ return "web";
132
+ }
133
+ if (["flutter", "f", "dart"].includes(normalized)) {
134
+ return "flutter";
135
+ }
136
+ return "unknown";
137
+ }
138
+ export function validateAndGetRulesType(rulesType) {
139
+ if (rulesType) {
140
+ const normalized = normalizeRulesType(rulesType);
141
+ if (normalized === "unknown") {
142
+ return {
143
+ type: "ios",
144
+ error: `❌ 不支持的 Rules 类型: ${rulesType}\n支持的类型: iOS/Android/Web/Flutter (或其他别名)`,
145
+ };
146
+ }
147
+ log(`使用用户指定的 Rules 类型: ${normalized}`);
148
+ return { type: normalized };
149
+ }
150
+ const projectType = detectProjectType();
151
+ return { type: projectType };
152
+ }
153
+ export function validateAndGetIDE(ide) {
154
+ const targetIDE = ide || detectCurrentIDE();
155
+ const idePath = IDE_PATHS[targetIDE];
156
+ if (!idePath) {
157
+ return {
158
+ ide: targetIDE,
159
+ path: "",
160
+ error: `❌ 不支持的 IDE: ${targetIDE}\n支持的 IDE: kiro, cursor, windsurf`,
161
+ };
162
+ }
163
+ return { ide: targetIDE, path: idePath };
164
+ }
165
+ export function getGitRulesDir(projectType) {
166
+ const dirMap = {
167
+ ios: "iOS",
168
+ android: "Android",
169
+ web: "Web",
170
+ flutter: "Flutter",
171
+ unknown: "iOS",
172
+ };
173
+ return dirMap[projectType];
174
+ }
175
+ export function detectCurrentIDE() {
176
+ if (process.env.KIRO_HOME)
177
+ return "kiro";
178
+ if (process.env.CURSOR_HOME)
179
+ return "cursor";
180
+ if (process.env.WINDSURF_HOME)
181
+ return "windsurf";
182
+ if (fs.existsSync(path.join(HOME, ".kiro")))
183
+ return "kiro";
184
+ if (fs.existsSync(path.join(HOME, ".cursor")))
185
+ return "cursor";
186
+ if (fs.existsSync(path.join(HOME, ".codeium/windsurf")))
187
+ return "windsurf";
188
+ return "kiro";
189
+ }
190
+ // Git 操作公共函数
191
+ export function initializeGitCache() {
192
+ const gitDir = path.join(RULES_CACHE_DIR, ".git");
193
+ // 检查 .git 目录是否存在且有效
194
+ if (fs.existsSync(gitDir)) {
195
+ try {
196
+ execSync(`git -C ${RULES_CACHE_DIR} status`, { stdio: "pipe" });
197
+ return; // Git 仓库有效
198
+ }
199
+ catch (e) {
200
+ log(`Git 仓库损坏,重新初始化...`);
201
+ fs.rmSync(RULES_CACHE_DIR, { recursive: true, force: true });
202
+ }
203
+ }
204
+ log(`创建缓存目录: ${RULES_CACHE_DIR}`);
205
+ fs.mkdirSync(RULES_CACHE_DIR, { recursive: true });
206
+ log(`初始化 Git 仓库...`);
207
+ execSync(`git init ${RULES_CACHE_DIR}`, { stdio: "inherit" });
208
+ log(`添加远程: ${GIT_REPO}`);
209
+ execSync(`git -C ${RULES_CACHE_DIR} remote add origin ${GIT_REPO}`, { stdio: "inherit" });
210
+ }
211
+ export function setupSparseCheckout(rulesDir) {
212
+ log(`配置 sparse-checkout...`);
213
+ execSync(`git -C ${RULES_CACHE_DIR} config core.sparseCheckout true`, {
214
+ stdio: "inherit",
215
+ });
216
+ const sparseCheckoutFile = path.join(RULES_CACHE_DIR, ".git/info/sparse-checkout");
217
+ fs.writeFileSync(sparseCheckoutFile, `${rulesDir}/\n`);
218
+ log(`设置只克隆 ${rulesDir} 目录...`);
219
+ }
220
+ export function checkoutOrCreateBranch(branchName, baseBranch = GIT_BRANCH) {
221
+ log(`检出或创建分支 ${branchName}...`);
222
+ // 先尝试检出远程分支(如果存在)
223
+ try {
224
+ execSync(`git -C ${RULES_CACHE_DIR} fetch origin ${branchName}`, {
225
+ stdio: "pipe",
226
+ });
227
+ // 远程分支存在,检出并跟踪
228
+ execSync(`git -C ${RULES_CACHE_DIR} checkout -B ${branchName} origin/${branchName}`, {
229
+ stdio: "inherit",
230
+ });
231
+ log(`检出远程分支: ${branchName}`);
232
+ return;
233
+ }
234
+ catch (e) {
235
+ // 远程分支不存在,继续创建新分支
236
+ }
237
+ // 基于主分支创建新分支
238
+ log(`远程分支不存在,基于 ${baseBranch} 创建...`);
239
+ try {
240
+ execSync(`git -C ${RULES_CACHE_DIR} checkout -B ${baseBranch} origin/${baseBranch}`, {
241
+ stdio: "inherit",
242
+ });
243
+ execSync(`git -C ${RULES_CACHE_DIR} checkout -b ${branchName}`, {
244
+ stdio: "inherit",
245
+ });
246
+ log(`创建新分支: ${branchName}`);
247
+ }
248
+ catch (e2) {
249
+ log(`主分支不存在,创建孤立分支...`);
250
+ execSync(`git -C ${RULES_CACHE_DIR} checkout --orphan ${branchName}`, {
251
+ stdio: "inherit",
252
+ });
253
+ log(`创建孤立分支: ${branchName}`);
254
+ }
255
+ }
256
+ export async function fetchRulesFromGit(projectType) {
257
+ const rulesDir = getGitRulesDir(projectType);
258
+ log(`Git 仓库: ${GIT_REPO}`);
259
+ log(`分支: ${GIT_BRANCH}`);
260
+ log(`Rules 目录: ${rulesDir}`);
261
+ // 初始化缓存仓库
262
+ initializeGitCache();
263
+ // 设置 sparse-checkout
264
+ setupSparseCheckout(rulesDir);
265
+ // 拉取远程分支
266
+ log(`拉取分支 ${GIT_BRANCH}...`);
267
+ execSync(`git -C ${RULES_CACHE_DIR} fetch origin ${GIT_BRANCH}`, {
268
+ stdio: "inherit",
269
+ });
270
+ // 检出到 origin/develop(避免本地分支不存在的问题)
271
+ log(`检出 origin/${GIT_BRANCH}...`);
272
+ try {
273
+ execSync(`git -C ${RULES_CACHE_DIR} checkout -B ${GIT_BRANCH} origin/${GIT_BRANCH}`, {
274
+ stdio: "inherit",
275
+ });
276
+ }
277
+ catch (e) {
278
+ // 如果失败,尝试直接检出 FETCH_HEAD
279
+ execSync(`git -C ${RULES_CACHE_DIR} checkout FETCH_HEAD`, {
280
+ stdio: "inherit",
281
+ });
282
+ }
283
+ const projectRulesDir = path.join(RULES_CACHE_DIR, rulesDir);
284
+ if (!fs.existsSync(projectRulesDir)) {
285
+ throw new Error(`${rulesDir} 目录不存在: ${projectRulesDir}`);
286
+ }
287
+ log(`${rulesDir} 目录: ${projectRulesDir}`);
288
+ return projectRulesDir;
289
+ }
290
+ export function copyMarkdownFiles(src, dest, options = { backup: true }) {
291
+ if (!fs.existsSync(dest)) {
292
+ fs.mkdirSync(dest, { recursive: true });
293
+ }
294
+ let count = 0;
295
+ const backups = [];
296
+ const files = fs.readdirSync(src);
297
+ for (const file of files) {
298
+ if (file.startsWith(".") || file === "node_modules") {
299
+ continue;
300
+ }
301
+ const srcPath = path.join(src, file);
302
+ const destPath = path.join(dest, file);
303
+ const stat = fs.statSync(srcPath);
304
+ if (stat.isDirectory()) {
305
+ const result = copyMarkdownFiles(srcPath, destPath, options);
306
+ count += result.count;
307
+ backups.push(...result.backups);
308
+ }
309
+ else if (file.endsWith(".md")) {
310
+ // 如果目标文件已存在且需要备份
311
+ if (options.backup && fs.existsSync(destPath)) {
312
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
313
+ const backupPath = `${destPath}.backup.${timestamp}`;
314
+ fs.copyFileSync(destPath, backupPath);
315
+ backups.push(backupPath);
316
+ log(`备份文件: ${destPath} → ${backupPath}`);
317
+ }
318
+ fs.copyFileSync(srcPath, destPath);
319
+ count++;
320
+ }
321
+ }
322
+ return { count, backups };
323
+ }
324
+ //# sourceMappingURL=utils.js.map