grf-cli 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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +503 -0
  3. package/README.zh-CN.md +503 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +74 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/add.d.ts +7 -0
  9. package/dist/commands/add.d.ts.map +1 -0
  10. package/dist/commands/add.js +92 -0
  11. package/dist/commands/add.js.map +1 -0
  12. package/dist/commands/clean.d.ts +7 -0
  13. package/dist/commands/clean.d.ts.map +1 -0
  14. package/dist/commands/clean.js +171 -0
  15. package/dist/commands/clean.js.map +1 -0
  16. package/dist/commands/config.d.ts +7 -0
  17. package/dist/commands/config.d.ts.map +1 -0
  18. package/dist/commands/config.js +170 -0
  19. package/dist/commands/config.js.map +1 -0
  20. package/dist/commands/list.d.ts +7 -0
  21. package/dist/commands/list.d.ts.map +1 -0
  22. package/dist/commands/list.js +149 -0
  23. package/dist/commands/list.js.map +1 -0
  24. package/dist/commands/load.d.ts +8 -0
  25. package/dist/commands/load.d.ts.map +1 -0
  26. package/dist/commands/load.js +239 -0
  27. package/dist/commands/load.js.map +1 -0
  28. package/dist/commands/unload.d.ts +7 -0
  29. package/dist/commands/unload.d.ts.map +1 -0
  30. package/dist/commands/unload.js +738 -0
  31. package/dist/commands/unload.js.map +1 -0
  32. package/dist/commands/update.d.ts +7 -0
  33. package/dist/commands/update.d.ts.map +1 -0
  34. package/dist/commands/update.js +471 -0
  35. package/dist/commands/update.js.map +1 -0
  36. package/dist/commands/use.d.ts +8 -0
  37. package/dist/commands/use.d.ts.map +1 -0
  38. package/dist/commands/use.js +224 -0
  39. package/dist/commands/use.js.map +1 -0
  40. package/dist/core/config.d.ts +55 -0
  41. package/dist/core/config.d.ts.map +1 -0
  42. package/dist/core/config.js +179 -0
  43. package/dist/core/config.js.map +1 -0
  44. package/dist/core/filesystem.d.ts +74 -0
  45. package/dist/core/filesystem.d.ts.map +1 -0
  46. package/dist/core/filesystem.js +300 -0
  47. package/dist/core/filesystem.js.map +1 -0
  48. package/dist/core/git.d.ts +75 -0
  49. package/dist/core/git.d.ts.map +1 -0
  50. package/dist/core/git.js +169 -0
  51. package/dist/core/git.js.map +1 -0
  52. package/dist/core/loading.d.ts +85 -0
  53. package/dist/core/loading.d.ts.map +1 -0
  54. package/dist/core/loading.js +224 -0
  55. package/dist/core/loading.js.map +1 -0
  56. package/dist/core/repository.d.ts +120 -0
  57. package/dist/core/repository.d.ts.map +1 -0
  58. package/dist/core/repository.js +374 -0
  59. package/dist/core/repository.js.map +1 -0
  60. package/dist/core/sync.d.ts +72 -0
  61. package/dist/core/sync.d.ts.map +1 -0
  62. package/dist/core/sync.js +226 -0
  63. package/dist/core/sync.js.map +1 -0
  64. package/dist/types/index.d.ts +135 -0
  65. package/dist/types/index.d.ts.map +1 -0
  66. package/dist/types/index.js +63 -0
  67. package/dist/types/index.js.map +1 -0
  68. package/package.json +59 -0
@@ -0,0 +1,374 @@
1
+ "use strict";
2
+ /**
3
+ * Repository 模块
4
+ * 负责仓库的增删改查操作,整合配置、Git 和文件系统模块
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.parseRepoUrl = parseRepoUrl;
44
+ exports.getRepoStoragePath = getRepoStoragePath;
45
+ exports.add = add;
46
+ exports.get = get;
47
+ exports.list = list;
48
+ exports.remove = remove;
49
+ exports.exists = exists;
50
+ exports.resolvePath = resolvePath;
51
+ exports.switchBranch = switchBranch;
52
+ const path_1 = __importDefault(require("path"));
53
+ const index_js_1 = require("../types/index.js");
54
+ const config_js_1 = require("./config.js");
55
+ const git = __importStar(require("./git.js"));
56
+ const fs = __importStar(require("./filesystem.js"));
57
+ /**
58
+ * 解析 Git URL
59
+ * 支持 HTTPS 和 SSH 格式
60
+ * @param url Git 仓库 URL
61
+ * @returns 解析后的 URL 信息
62
+ * @throws GrfError 如果 URL 格式无效
63
+ *
64
+ * @example
65
+ * // HTTPS 格式
66
+ * parseRepoUrl('https://github.com/facebook/react.git')
67
+ * // -> { host: 'github.com', owner: 'facebook', repo: 'react' }
68
+ *
69
+ * // SSH 格式
70
+ * parseRepoUrl('git@github.com:facebook/react.git')
71
+ * // -> { host: 'github.com', owner: 'facebook', repo: 'react' }
72
+ */
73
+ function parseRepoUrl(url) {
74
+ // 去除首尾空白
75
+ url = url.trim();
76
+ // HTTPS 格式: https://github.com/user/repo.git
77
+ const httpsRegex = /^https?:\/\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?$/;
78
+ const httpsMatch = url.match(httpsRegex);
79
+ if (httpsMatch) {
80
+ return {
81
+ host: httpsMatch[1],
82
+ owner: httpsMatch[2],
83
+ repo: httpsMatch[3].replace(/\.git$/, ""),
84
+ };
85
+ }
86
+ // SSH 格式: git@github.com:user/repo.git
87
+ const sshRegex = /^git@([^:]+):([^/]+)\/([^/]+?)(?:\.git)?$/;
88
+ const sshMatch = url.match(sshRegex);
89
+ if (sshMatch) {
90
+ return {
91
+ host: sshMatch[1],
92
+ owner: sshMatch[2],
93
+ repo: sshMatch[3].replace(/\.git$/, ""),
94
+ };
95
+ }
96
+ throw new index_js_1.GrfError(index_js_1.ErrorCode.REPO_INVALID_URL, `无效的 Git URL: ${url}。支持的格式: https://github.com/user/repo.git 或 git@github.com:user/repo.git`);
97
+ }
98
+ /**
99
+ * 根据 URL 生成本地存储路径
100
+ * @param url Git 仓库 URL
101
+ * @returns 本地存储路径
102
+ *
103
+ * @example
104
+ * getRepoStoragePath('https://github.com/facebook/react.git')
105
+ * // -> ~/.gitreference/repos/github.com/facebook/react
106
+ */
107
+ function getRepoStoragePath(url) {
108
+ const { host, owner, repo } = parseRepoUrl(url);
109
+ return path_1.default.join((0, config_js_1.getReposRoot)(), host, owner, repo);
110
+ }
111
+ /**
112
+ * 根据解析后的 URL 信息生成仓库名称
113
+ * @param parsed 解析后的 URL 信息
114
+ * @returns 仓库名称(格式: host/owner/repo)
115
+ */
116
+ function getRepoName(parsed) {
117
+ return `${parsed.host}/${parsed.owner}/${parsed.repo}`;
118
+ }
119
+ /**
120
+ * 添加仓库
121
+ * @param url Git 仓库 URL
122
+ * @param options 添加选项
123
+ * @returns 仓库信息
124
+ */
125
+ async function add(url, options) {
126
+ // 解析 URL
127
+ const parsed = parseRepoUrl(url);
128
+ const repoPath = getRepoStoragePath(url);
129
+ const repoName = options?.name ?? getRepoName(parsed);
130
+ // 检查仓库是否已存在
131
+ if (await exists(repoName)) {
132
+ throw new index_js_1.GrfError(index_js_1.ErrorCode.REPO_ALREADY_EXISTS, `仓库已存在: ${repoName}`);
133
+ }
134
+ // 确保配置目录存在
135
+ await (0, config_js_1.ensureConfigDir)();
136
+ // 确保父目录存在
137
+ await fs.ensureDir(path_1.default.dirname(repoPath));
138
+ // 克隆仓库
139
+ await git.clone(url, repoPath, {
140
+ branch: options?.branch,
141
+ shallow: options?.shallow,
142
+ depth: options?.depth,
143
+ });
144
+ // 获取 commit ID 和分支信息
145
+ const commitId = await git.getCurrentCommit(repoPath);
146
+ const branch = await git.getBranch(repoPath);
147
+ // 创建元信息
148
+ const now = new Date().toISOString();
149
+ const meta = {
150
+ url,
151
+ name: repoName,
152
+ addedAt: now,
153
+ updatedAt: now,
154
+ commitId,
155
+ branch,
156
+ };
157
+ // 保存元信息
158
+ await (0, config_js_1.writeRepoMeta)(repoPath, meta);
159
+ // 更新全局配置
160
+ const config = await (0, config_js_1.readGlobalConfig)();
161
+ config.repos[repoName] = {
162
+ url,
163
+ path: repoPath,
164
+ addedAt: now,
165
+ };
166
+ await (0, config_js_1.writeGlobalConfig)(config);
167
+ return {
168
+ name: repoName,
169
+ url,
170
+ path: repoPath,
171
+ commitId,
172
+ branch,
173
+ addedAt: now,
174
+ updatedAt: now,
175
+ };
176
+ }
177
+ /**
178
+ * 检查仓库名称是否匹配
179
+ * 支持以下匹配方式:
180
+ * - 完整名称:github.com/owner/repo
181
+ * - owner/repo 格式:owner/repo
182
+ * - 仅 repo 名称:repo
183
+ *
184
+ * @param repoName 仓库完整名称(如 github.com/owner/repo)
185
+ * @param searchName 搜索名称
186
+ * @returns 是否匹配
187
+ */
188
+ function matchRepoName(repoName, searchName) {
189
+ // 标准化:将反斜杠转换为正斜杠
190
+ const normalizedRepoName = repoName.replace(/\\/g, "/");
191
+ const normalizedSearchName = searchName.replace(/\\/g, "/");
192
+ // 完整名称匹配
193
+ if (normalizedRepoName === normalizedSearchName) {
194
+ return true;
195
+ }
196
+ // 分割仓库名称为各个部分
197
+ const repoParts = normalizedRepoName.split("/");
198
+ const searchParts = normalizedSearchName.split("/");
199
+ // 如果搜索名称有多个部分,从末尾开始匹配
200
+ if (searchParts.length > 1) {
201
+ // 检查是否匹配末尾的 N 个部分
202
+ if (repoParts.length >= searchParts.length) {
203
+ const repoSuffix = repoParts.slice(-searchParts.length).join("/");
204
+ return repoSuffix === normalizedSearchName;
205
+ }
206
+ return false;
207
+ }
208
+ // 单个名称:只匹配最后一个部分(repo 名称)
209
+ const repoBaseName = repoParts[repoParts.length - 1];
210
+ return repoBaseName === normalizedSearchName;
211
+ }
212
+ /**
213
+ * 根据名称获取仓库信息
214
+ * @param name 仓库名称(完整路径或简短名称)
215
+ * @returns 仓库信息,不存在返回 null
216
+ */
217
+ async function get(name) {
218
+ const config = await (0, config_js_1.readGlobalConfig)();
219
+ // 首先尝试完整名称匹配
220
+ if (config.repos[name]) {
221
+ const entry = config.repos[name];
222
+ const meta = await (0, config_js_1.readRepoMeta)(entry.path);
223
+ if (!meta) {
224
+ return null;
225
+ }
226
+ return {
227
+ name,
228
+ url: entry.url,
229
+ path: entry.path,
230
+ commitId: meta.commitId,
231
+ branch: meta.branch,
232
+ addedAt: meta.addedAt,
233
+ updatedAt: meta.updatedAt,
234
+ };
235
+ }
236
+ // 尝试简短名称匹配(支持 repo 或 owner/repo 格式)
237
+ for (const [repoName, entry] of Object.entries(config.repos)) {
238
+ if (matchRepoName(repoName, name)) {
239
+ const meta = await (0, config_js_1.readRepoMeta)(entry.path);
240
+ if (!meta) {
241
+ continue;
242
+ }
243
+ return {
244
+ name: repoName,
245
+ url: entry.url,
246
+ path: entry.path,
247
+ commitId: meta.commitId,
248
+ branch: meta.branch,
249
+ addedAt: meta.addedAt,
250
+ updatedAt: meta.updatedAt,
251
+ };
252
+ }
253
+ }
254
+ return null;
255
+ }
256
+ /**
257
+ * 列出所有仓库
258
+ * @returns 仓库信息数组
259
+ */
260
+ async function list() {
261
+ const config = await (0, config_js_1.readGlobalConfig)();
262
+ const repos = [];
263
+ for (const [name, entry] of Object.entries(config.repos)) {
264
+ const meta = await (0, config_js_1.readRepoMeta)(entry.path);
265
+ if (meta) {
266
+ repos.push({
267
+ name,
268
+ url: entry.url,
269
+ path: entry.path,
270
+ commitId: meta.commitId,
271
+ branch: meta.branch,
272
+ addedAt: meta.addedAt,
273
+ updatedAt: meta.updatedAt,
274
+ });
275
+ }
276
+ }
277
+ return repos;
278
+ }
279
+ /**
280
+ * 删除仓库
281
+ * @param name 仓库名称
282
+ * @throws GrfError 如果仓库不存在
283
+ */
284
+ async function remove(name) {
285
+ const repoInfo = await get(name);
286
+ if (!repoInfo) {
287
+ throw new index_js_1.GrfError(index_js_1.ErrorCode.REPO_NOT_FOUND, `仓库不存在: ${name}`);
288
+ }
289
+ // 删除仓库目录
290
+ await fs.removeDir(repoInfo.path);
291
+ // 更新全局配置
292
+ const config = await (0, config_js_1.readGlobalConfig)();
293
+ delete config.repos[repoInfo.name];
294
+ await (0, config_js_1.writeGlobalConfig)(config);
295
+ }
296
+ /**
297
+ * 检查仓库是否存在
298
+ * @param name 仓库名称
299
+ * @returns 是否存在
300
+ */
301
+ async function exists(name) {
302
+ const config = await (0, config_js_1.readGlobalConfig)();
303
+ // 首先尝试完整名称匹配
304
+ if (config.repos[name]) {
305
+ const entry = config.repos[name];
306
+ // 检查目录和元信息是否都存在
307
+ const dirExists = await fs.exists(entry.path);
308
+ const meta = await (0, config_js_1.readRepoMeta)(entry.path);
309
+ return dirExists && meta !== null;
310
+ }
311
+ // 尝试简短名称匹配(使用统一的匹配函数)
312
+ for (const [repoName, entry] of Object.entries(config.repos)) {
313
+ if (matchRepoName(repoName, name)) {
314
+ const dirExists = await fs.exists(entry.path);
315
+ const meta = await (0, config_js_1.readRepoMeta)(entry.path);
316
+ return dirExists && meta !== null;
317
+ }
318
+ }
319
+ return false;
320
+ }
321
+ /**
322
+ * 将仓库名称解析为本地路径
323
+ * @param name 仓库名称(完整名称或简短名称)
324
+ * @returns 本地路径
325
+ * @throws GrfError 如果仓库不存在
326
+ */
327
+ async function resolvePath(name) {
328
+ const repoInfo = await get(name);
329
+ if (!repoInfo) {
330
+ throw new index_js_1.GrfError(index_js_1.ErrorCode.REPO_NOT_FOUND, `仓库不存在: ${name}`);
331
+ }
332
+ return repoInfo.path;
333
+ }
334
+ /**
335
+ * 切换仓库分支
336
+ * @param name 仓库名称
337
+ * @param branch 目标分支
338
+ * @returns 更新后的仓库信息
339
+ * @throws GrfError 如果仓库不存在或切换失败
340
+ */
341
+ async function switchBranch(name, branch) {
342
+ // 获取仓库信息
343
+ const repoInfo = await get(name);
344
+ if (!repoInfo) {
345
+ throw new index_js_1.GrfError(index_js_1.ErrorCode.REPO_NOT_FOUND, `仓库不存在: ${name}`);
346
+ }
347
+ // 调用 git.checkout() 切换分支
348
+ await git.checkout(repoInfo.path, branch);
349
+ // 获取新的 commit ID
350
+ const commitId = await git.getCurrentCommit(repoInfo.path);
351
+ const currentBranch = await git.getBranch(repoInfo.path);
352
+ // 更新 meta.json 中的 branch 字段
353
+ const now = new Date().toISOString();
354
+ const meta = {
355
+ url: repoInfo.url,
356
+ name: repoInfo.name,
357
+ addedAt: repoInfo.addedAt,
358
+ updatedAt: now,
359
+ commitId,
360
+ branch: currentBranch,
361
+ };
362
+ await (0, config_js_1.writeRepoMeta)(repoInfo.path, meta);
363
+ // 返回更新后的仓库信息
364
+ return {
365
+ name: repoInfo.name,
366
+ url: repoInfo.url,
367
+ path: repoInfo.path,
368
+ commitId,
369
+ branch: currentBranch,
370
+ addedAt: repoInfo.addedAt,
371
+ updatedAt: now,
372
+ };
373
+ }
374
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/core/repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 同步模块
3
+ * 负责工作目录与全局缓存之间的同步操作
4
+ */
5
+ import type { LoadingEntry } from "../types/index.js";
6
+ /**
7
+ * 同步状态
8
+ */
9
+ export interface SyncStatus {
10
+ /** 条目 ID */
11
+ entryId: string;
12
+ /** 仓库名称 */
13
+ repoName: string;
14
+ /** 目标路径 */
15
+ targetPath: string;
16
+ /** loading.json 中记录的 commitId */
17
+ loadedCommitId: string;
18
+ /** 缓存仓库当前的 commitId */
19
+ cacheCommitId: string;
20
+ /** 是否需要同步 */
21
+ needsSync: boolean;
22
+ /** 缓存仓库是否存在 */
23
+ cacheExists: boolean;
24
+ /** 目标目录是否存在 */
25
+ targetExists: boolean;
26
+ }
27
+ /**
28
+ * 同步结果
29
+ */
30
+ export interface SyncResult {
31
+ /** 条目 ID */
32
+ entryId: string;
33
+ /** 仓库名称 */
34
+ repoName: string;
35
+ /** 是否成功 */
36
+ success: boolean;
37
+ /** 结果消息 */
38
+ message: string;
39
+ /** 旧的 commitId */
40
+ oldCommitId?: string;
41
+ /** 新的 commitId */
42
+ newCommitId?: string;
43
+ }
44
+ /**
45
+ * 获取单个加载条目的同步状态
46
+ * @param entry 加载条目
47
+ * @param projectRoot 项目根目录
48
+ * @returns 同步状态
49
+ */
50
+ export declare function getSyncStatus(entry: LoadingEntry, projectRoot?: string): Promise<SyncStatus>;
51
+ /**
52
+ * 获取所有已加载条目的同步状态
53
+ * @param projectRoot 项目根目录
54
+ * @returns 同步状态列表
55
+ */
56
+ export declare function getAllSyncStatus(projectRoot?: string): Promise<SyncStatus[]>;
57
+ /**
58
+ * 同步单个条目到工作目录
59
+ * @param entry 加载条目
60
+ * @param force 是否强制同步(忽略本地修改)
61
+ * @param projectRoot 项目根目录
62
+ * @returns 同步结果
63
+ */
64
+ export declare function syncEntry(entry: LoadingEntry, force?: boolean, projectRoot?: string): Promise<SyncResult>;
65
+ /**
66
+ * 同步所有需要更新的条目
67
+ * @param force 是否强制同步
68
+ * @param projectRoot 项目根目录
69
+ * @returns 同步结果列表
70
+ */
71
+ export declare function syncAll(force?: boolean, projectRoot?: string): Promise<SyncResult[]>;
72
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/core/sync.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,YAAY;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe;IACf,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,YAAY;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,YAAY,EACnB,WAAW,GAAE,MAAsB,GAClC,OAAO,CAAC,UAAU,CAAC,CA4CrB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,GAAE,MAAsB,GAClC,OAAO,CAAC,UAAU,EAAE,CAAC,CAUvB;AAID;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,YAAY,EACnB,KAAK,GAAE,OAAe,EACtB,WAAW,GAAE,MAAsB,GAClC,OAAO,CAAC,UAAU,CAAC,CA2ErB;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,KAAK,GAAE,OAAe,EACtB,WAAW,GAAE,MAAsB,GAClC,OAAO,CAAC,UAAU,EAAE,CAAC,CAsCvB"}
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ /**
3
+ * 同步模块
4
+ * 负责工作目录与全局缓存之间的同步操作
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.getSyncStatus = getSyncStatus;
41
+ exports.getAllSyncStatus = getAllSyncStatus;
42
+ exports.syncEntry = syncEntry;
43
+ exports.syncAll = syncAll;
44
+ const path = __importStar(require("path"));
45
+ const loading = __importStar(require("./loading.js"));
46
+ const repository = __importStar(require("./repository.js"));
47
+ const filesystem = __importStar(require("./filesystem.js"));
48
+ const git = __importStar(require("./git.js"));
49
+ // ============ 状态检测 ============
50
+ /**
51
+ * 获取单个加载条目的同步状态
52
+ * @param entry 加载条目
53
+ * @param projectRoot 项目根目录
54
+ * @returns 同步状态
55
+ */
56
+ async function getSyncStatus(entry, projectRoot = process.cwd()) {
57
+ const status = {
58
+ entryId: entry.id,
59
+ repoName: entry.repoName,
60
+ targetPath: entry.targetPath,
61
+ loadedCommitId: entry.commitId,
62
+ cacheCommitId: "",
63
+ needsSync: false,
64
+ cacheExists: false,
65
+ targetExists: false,
66
+ };
67
+ // 检查目标目录是否存在
68
+ const targetAbsPath = path.join(projectRoot, entry.targetPath);
69
+ status.targetExists = await filesystem.exists(targetAbsPath);
70
+ // 获取缓存仓库信息
71
+ try {
72
+ const repoInfo = await repository.get(entry.repoName);
73
+ if (repoInfo) {
74
+ status.cacheExists = true;
75
+ // 获取缓存仓库当前的 commitId
76
+ status.cacheCommitId = await git.getCurrentCommit(repoInfo.path);
77
+ // 判断是否需要同步
78
+ // 需要同步的情况:
79
+ // 1. 目标目录不存在
80
+ // 2. commitId 不一致
81
+ if (!status.targetExists) {
82
+ status.needsSync = true;
83
+ }
84
+ else if (status.loadedCommitId !== status.cacheCommitId) {
85
+ status.needsSync = true;
86
+ }
87
+ }
88
+ else {
89
+ status.cacheExists = false;
90
+ status.needsSync = false; // 缓存不存在,无法同步
91
+ }
92
+ }
93
+ catch {
94
+ // 获取仓库信息失败,标记缓存不存在
95
+ status.cacheExists = false;
96
+ status.needsSync = false;
97
+ }
98
+ return status;
99
+ }
100
+ /**
101
+ * 获取所有已加载条目的同步状态
102
+ * @param projectRoot 项目根目录
103
+ * @returns 同步状态列表
104
+ */
105
+ async function getAllSyncStatus(projectRoot = process.cwd()) {
106
+ const entries = await loading.getEntries(projectRoot);
107
+ const statusList = [];
108
+ for (const entry of entries) {
109
+ const status = await getSyncStatus(entry, projectRoot);
110
+ statusList.push(status);
111
+ }
112
+ return statusList;
113
+ }
114
+ // ============ 同步操作 ============
115
+ /**
116
+ * 同步单个条目到工作目录
117
+ * @param entry 加载条目
118
+ * @param force 是否强制同步(忽略本地修改)
119
+ * @param projectRoot 项目根目录
120
+ * @returns 同步结果
121
+ */
122
+ async function syncEntry(entry, force = false, projectRoot = process.cwd()) {
123
+ const result = {
124
+ entryId: entry.id,
125
+ repoName: entry.repoName,
126
+ success: false,
127
+ message: "",
128
+ oldCommitId: entry.commitId,
129
+ };
130
+ try {
131
+ // 获取缓存仓库信息
132
+ const repoInfo = await repository.get(entry.repoName);
133
+ if (!repoInfo) {
134
+ result.message = `缓存仓库不存在: ${entry.repoName}`;
135
+ return result;
136
+ }
137
+ // 获取缓存仓库当前的 commitId
138
+ const cacheCommitId = await git.getCurrentCommit(repoInfo.path);
139
+ result.newCommitId = cacheCommitId;
140
+ // 检查是否需要同步
141
+ const targetAbsPath = path.join(projectRoot, entry.targetPath);
142
+ const targetExists = await filesystem.exists(targetAbsPath);
143
+ if (targetExists && entry.commitId === cacheCommitId && !force) {
144
+ result.success = true;
145
+ result.message = "已是最新版本,无需同步";
146
+ return result;
147
+ }
148
+ // 确定源路径(考虑 subdir)
149
+ let sourcePath = repoInfo.path;
150
+ if (entry.subdir) {
151
+ sourcePath = path.join(repoInfo.path, entry.subdir);
152
+ // 检查子目录是否存在
153
+ if (!(await filesystem.exists(sourcePath))) {
154
+ result.message = `子目录不存在: ${entry.subdir}`;
155
+ return result;
156
+ }
157
+ }
158
+ // 删除旧目录(如果存在)
159
+ if (targetExists) {
160
+ await filesystem.removeDir(targetAbsPath);
161
+ }
162
+ // 确保目标父目录存在
163
+ const targetParentDir = path.dirname(targetAbsPath);
164
+ await filesystem.ensureDir(targetParentDir);
165
+ // 复制新内容(排除 .git 目录)
166
+ await filesystem.copyDir(sourcePath, targetAbsPath, {
167
+ exclude: [".git", ".gitreference-meta.json"],
168
+ overwrite: true,
169
+ });
170
+ // 更新 loading.json 中的 commitId 和 updatedAt
171
+ await loading.updateEntry(entry.id, {
172
+ commitId: cacheCommitId,
173
+ }, projectRoot);
174
+ result.success = true;
175
+ result.message = `同步成功: ${entry.commitId.substring(0, 7)} → ${cacheCommitId.substring(0, 7)}`;
176
+ return result;
177
+ }
178
+ catch (error) {
179
+ const err = error;
180
+ result.message = `同步失败: ${err.message}`;
181
+ return result;
182
+ }
183
+ }
184
+ /**
185
+ * 同步所有需要更新的条目
186
+ * @param force 是否强制同步
187
+ * @param projectRoot 项目根目录
188
+ * @returns 同步结果列表
189
+ */
190
+ async function syncAll(force = false, projectRoot = process.cwd()) {
191
+ const entries = await loading.getEntries(projectRoot);
192
+ const results = [];
193
+ for (const entry of entries) {
194
+ // 获取同步状态
195
+ const status = await getSyncStatus(entry, projectRoot);
196
+ // 只同步需要同步的条目,或者强制同步所有
197
+ if (status.needsSync || force) {
198
+ if (!status.cacheExists) {
199
+ // 缓存不存在,跳过
200
+ results.push({
201
+ entryId: entry.id,
202
+ repoName: entry.repoName,
203
+ success: false,
204
+ message: `缓存仓库不存在: ${entry.repoName}`,
205
+ oldCommitId: entry.commitId,
206
+ });
207
+ continue;
208
+ }
209
+ const result = await syncEntry(entry, force, projectRoot);
210
+ results.push(result);
211
+ }
212
+ else {
213
+ // 不需要同步
214
+ results.push({
215
+ entryId: entry.id,
216
+ repoName: entry.repoName,
217
+ success: true,
218
+ message: "已是最新版本",
219
+ oldCommitId: entry.commitId,
220
+ newCommitId: entry.commitId,
221
+ });
222
+ }
223
+ }
224
+ return results;
225
+ }
226
+ //# sourceMappingURL=sync.js.map