feat(checkpoint): 添加 Checkpoint 可视化管理功能

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 组件
This commit is contained in:
2025-12-12 22:52:27 +08:00
parent a225e66ad7
commit cb554c65b4
23 changed files with 4970 additions and 116 deletions
+216
View File
@@ -28,6 +28,16 @@ import type {
AgentDetail,
AgentInput,
AgentDefaults,
CheckpointListItem,
CheckpointDetail,
CheckpointStats,
DiffInfo,
FileDiffDetail,
RestoreOptions,
RestoreResult,
SafetyCheckResult,
UnrevertStatus,
UnrevertResult,
} from './types.js';
// Re-export types
@@ -71,6 +81,21 @@ export type {
AgentDetail,
AgentInput,
AgentDefaults,
// Checkpoint types
CheckpointTrigger,
FileChangeType,
CheckpointListItem,
CheckpointDetail,
FileChange,
DiffInfo,
FileDiffDetail,
RestoreMode,
RestoreOptions,
RestoreResult,
SafetyCheckResult,
CheckpointStats,
UnrevertStatus,
UnrevertResult,
} from './types.js';
// API Configuration
@@ -588,3 +613,194 @@ export async function updateAgentDefaults(defaults: AgentDefaults): Promise<{
}> {
return request('PUT', '/agents/defaults', defaults);
}
// ============ Checkpoints API ============
/**
* 获取所有检查点列表
*/
export async function listCheckpoints(): Promise<{
success: boolean;
data: CheckpointListItem[];
error?: string;
}> {
return request('GET', '/checkpoints');
}
/**
* 获取检查点统计信息
*/
export async function getCheckpointStats(): Promise<{
success: boolean;
data: CheckpointStats;
error?: string;
}> {
return request('GET', '/checkpoints/stats');
}
/**
* 获取最新检查点
*/
export async function getLatestCheckpoint(): Promise<{
success: boolean;
data: CheckpointDetail | null;
error?: string;
}> {
return request('GET', '/checkpoints/latest');
}
/**
* 获取单个检查点详情
*/
export async function getCheckpoint(id: string): Promise<{
success: boolean;
data?: CheckpointDetail;
error?: string;
}> {
return request('GET', `/checkpoints/${encodeURIComponent(id)}`);
}
/**
* 创建手动检查点
*/
export async function createCheckpoint(options?: {
name?: string;
description?: string;
}): Promise<{
success: boolean;
data?: CheckpointDetail;
error?: string;
}> {
return request('POST', '/checkpoints', options || {});
}
/**
* 删除检查点
*/
export async function deleteCheckpoint(id: string): Promise<{
success: boolean;
data?: { deleted: boolean };
error?: string;
}> {
return request('DELETE', `/checkpoints/${encodeURIComponent(id)}`);
}
/**
* 获取检查点与当前工作区的差异
*/
export async function getCheckpointDiff(id: string): Promise<{
success: boolean;
data?: DiffInfo;
error?: string;
}> {
return request('GET', `/checkpoints/${encodeURIComponent(id)}/diff`);
}
/**
* 获取单个文件的详细差异
*/
export async function getFileDiff(checkpointId: string, filePath: string): Promise<{
success: boolean;
data?: FileDiffDetail;
error?: string;
}> {
const params = new URLSearchParams({ path: filePath });
return request('GET', `/checkpoints/${encodeURIComponent(checkpointId)}/file-diff?${params}`);
}
/**
* 回滚到检查点
*/
export async function restoreCheckpoint(
id: string,
options?: RestoreOptions
): Promise<{
success: boolean;
data?: RestoreResult;
error?: string;
}> {
return request('POST', `/checkpoints/${encodeURIComponent(id)}/restore`, options || {});
}
/**
* 预览回滚(dry run
*/
export async function previewRestore(
id: string,
options?: { mode?: RestoreOptions['mode']; files?: string[] }
): Promise<{
success: boolean;
data?: RestoreResult;
error?: string;
}> {
const params = new URLSearchParams();
if (options?.mode) params.set('mode', options.mode);
if (options?.files) params.set('files', options.files.join(','));
return request('GET', `/checkpoints/${encodeURIComponent(id)}/restore/preview?${params}`);
}
/**
* 撤销最近一次回滚
*/
export async function unrevert(): Promise<{
success: boolean;
data?: UnrevertResult;
error?: string;
}> {
return request('POST', '/checkpoints/unrevert');
}
/**
* 检查是否可撤销回滚
*/
export async function getUnrevertStatus(): Promise<{
success: boolean;
data?: UnrevertStatus;
error?: string;
}> {
return request('GET', '/checkpoints/unrevert/status');
}
/**
* 执行安全检查
*/
export async function checkSafety(id: string): Promise<{
success: boolean;
data?: SafetyCheckResult;
error?: string;
}> {
return request('GET', `/checkpoints/${encodeURIComponent(id)}/safety-check`);
}
/**
* 清理过期检查点
*/
export async function cleanupCheckpoints(): Promise<{
success: boolean;
data?: { deleted: number };
error?: string;
}> {
return request('POST', '/checkpoints/cleanup');
}
/**
* 获取会话的所有检查点
*/
export async function getSessionCheckpoints(sessionId: string): Promise<{
success: boolean;
data: CheckpointListItem[];
error?: string;
}> {
return request('GET', `/checkpoints/sessions/${encodeURIComponent(sessionId)}`);
}
/**
* 获取消息关联的检查点
*/
export async function getMessageCheckpoints(messageId: string): Promise<{
success: boolean;
data: CheckpointListItem[];
error?: string;
}> {
return request('GET', `/checkpoints/messages/${encodeURIComponent(messageId)}`);
}