cb554c65b4
Core 层增强:
- 添加 safety.ts: 7点安全检查机制
- 添加 session-tracker.ts: 会话级检查点跟踪
- 添加 lock.ts: 并发控制文件锁
- 添加 lfs.ts: Git LFS 大文件支持
- 添加 path-validator.ts: 路径验证
- 添加 commit-message.ts: 智能提交消息生成
- 增强 manager.ts: 支持三种恢复模式、unrevert 撤销回滚
Server 层:
- 添加 checkpoints.ts: 16个 REST API 端点
- GET/POST /checkpoints: 列表/创建检查点
- GET/DELETE /checkpoints/🆔 获取/删除检查点
- GET /checkpoints/:id/diff: 获取差异
- POST /checkpoints/:id/restore: 恢复到检查点
- POST /checkpoints/unrevert: 撤销回滚
- GET /checkpoints/:id/safety-check: 安全检查
UI 层:
- 添加 CheckpointPanel.tsx: 检查点列表面板
- 添加 CheckpointDiffViewer.tsx: 差异查看器
- 添加 RestoreDialog.tsx: 恢复确认对话框
- 添加 16 个 API 客户端函数
- 添加完整的 TypeScript 类型定义
Web/Desktop 集成:
- 添加 History 按钮到工具栏
- 集成 CheckpointPanel 组件
190 lines
3.7 KiB
TypeScript
190 lines
3.7 KiB
TypeScript
/**
|
||
* Git LFS 大文件支持模块
|
||
* 参考 Cline 的 LFS 模式检测
|
||
*/
|
||
|
||
import * as fs from 'fs/promises';
|
||
import * as path from 'path';
|
||
import { minimatch } from 'minimatch';
|
||
|
||
/**
|
||
* LFS 模式加载器
|
||
* 从 .gitattributes 文件中加载 LFS 模式
|
||
*/
|
||
export class LFSPatternLoader {
|
||
private patterns: string[] = [];
|
||
private loaded = false;
|
||
|
||
/**
|
||
* 从工作目录加载 LFS 模式
|
||
*/
|
||
async loadPatterns(workDir: string): Promise<void> {
|
||
const gitattributesPath = path.join(workDir, '.gitattributes');
|
||
|
||
try {
|
||
const content = await fs.readFile(gitattributesPath, 'utf-8');
|
||
this.patterns = this.parseLfsPatterns(content);
|
||
this.loaded = true;
|
||
} catch {
|
||
// .gitattributes 不存在或无法读取
|
||
this.patterns = [];
|
||
this.loaded = true;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析 .gitattributes 内容,提取 LFS 模式
|
||
*/
|
||
private parseLfsPatterns(content: string): string[] {
|
||
const patterns: string[] = [];
|
||
|
||
for (const line of content.split('\n')) {
|
||
const trimmed = line.trim();
|
||
|
||
// 跳过空行和注释
|
||
if (!trimmed || trimmed.startsWith('#')) {
|
||
continue;
|
||
}
|
||
|
||
// 匹配 LFS 配置行: pattern filter=lfs diff=lfs merge=lfs -text
|
||
// 或简单形式: pattern filter=lfs
|
||
if (trimmed.includes('filter=lfs')) {
|
||
// 提取模式(第一个空白字符前的部分)
|
||
const match = trimmed.match(/^(\S+)/);
|
||
if (match) {
|
||
patterns.push(match[1]);
|
||
}
|
||
}
|
||
}
|
||
|
||
return patterns;
|
||
}
|
||
|
||
/**
|
||
* 检查文件是否为 LFS 管理的文件
|
||
*/
|
||
isLfsFile(filePath: string): boolean {
|
||
if (!this.loaded) {
|
||
return false;
|
||
}
|
||
|
||
// 规范化路径(使用正斜杠)
|
||
const normalizedPath = filePath.replace(/\\/g, '/');
|
||
|
||
return this.patterns.some((pattern) =>
|
||
minimatch(normalizedPath, pattern, { matchBase: true })
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 获取所有 LFS 模式
|
||
*/
|
||
getPatterns(): string[] {
|
||
return [...this.patterns];
|
||
}
|
||
|
||
/**
|
||
* 获取排除模式(用于 .gitignore)
|
||
*/
|
||
getExcludePatterns(): string[] {
|
||
return this.patterns.map((p) => {
|
||
// 确保模式以 / 开头(相对于仓库根目录)
|
||
if (!p.startsWith('/') && !p.startsWith('*')) {
|
||
return `/${p}`;
|
||
}
|
||
return p;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 检查是否已加载
|
||
*/
|
||
isLoaded(): boolean {
|
||
return this.loaded;
|
||
}
|
||
|
||
/**
|
||
* 重置(清除已加载的模式)
|
||
*/
|
||
reset(): void {
|
||
this.patterns = [];
|
||
this.loaded = false;
|
||
}
|
||
|
||
/**
|
||
* 过滤文件列表,排除 LFS 文件
|
||
*/
|
||
filterNonLfsFiles(files: string[]): string[] {
|
||
return files.filter((file) => !this.isLfsFile(file));
|
||
}
|
||
|
||
/**
|
||
* 获取 LFS 文件列表
|
||
*/
|
||
filterLfsFiles(files: string[]): string[] {
|
||
return files.filter((file) => this.isLfsFile(file));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 常见的大文件扩展名(作为 LFS 候选)
|
||
*/
|
||
export const COMMON_LARGE_FILE_EXTENSIONS = [
|
||
// 图片
|
||
'.psd',
|
||
'.ai',
|
||
'.eps',
|
||
'.tiff',
|
||
'.raw',
|
||
'.cr2',
|
||
'.nef',
|
||
// 视频
|
||
'.mp4',
|
||
'.mov',
|
||
'.avi',
|
||
'.mkv',
|
||
'.wmv',
|
||
'.flv',
|
||
// 音频
|
||
'.mp3',
|
||
'.wav',
|
||
'.flac',
|
||
'.aac',
|
||
'.ogg',
|
||
// 压缩文件
|
||
'.zip',
|
||
'.tar',
|
||
'.gz',
|
||
'.rar',
|
||
'.7z',
|
||
// 二进制
|
||
'.exe',
|
||
'.dll',
|
||
'.so',
|
||
'.dylib',
|
||
// 数据文件
|
||
'.db',
|
||
'.sqlite',
|
||
'.mdb',
|
||
// 其他
|
||
'.pdf',
|
||
'.docx',
|
||
'.xlsx',
|
||
'.pptx',
|
||
];
|
||
|
||
/**
|
||
* 检查文件扩展名是否为常见大文件类型
|
||
*/
|
||
export function isCommonLargeFile(filePath: string): boolean {
|
||
const ext = path.extname(filePath).toLowerCase();
|
||
return COMMON_LARGE_FILE_EXTENSIONS.includes(ext);
|
||
}
|
||
|
||
/**
|
||
* 创建 LFS 模式加载器实例
|
||
*/
|
||
export function createLFSPatternLoader(): LFSPatternLoader {
|
||
return new LFSPatternLoader();
|
||
}
|