feat(skill-addresses): 新增技能地址修改记录,支持单次记录回退

后端:
- 每次「应用」写一份 {id}.manifest.json(记录本次 from→to 替换明细/文件数/处数),
  放在备份目录的同级,避免被回退误恢复或计入文件数
- GET /backups 返回每条记录的 replaced_total + replacements;POST /rollback/{id} 回退单条

前端:
- 把「撤销上次」升级为「修改记录」面板:每条显示时间/改了哪些地址/文件数,
  带「回退此次」(二次确认);应用后自动展开
- BackupEntry 类型扩展 replacedTotal + replacements

同步更新前后端 CLAUDE.md。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
吉鑫升andClaude Opus 4.8 committed 2026-06-22 18:05:05 +08:00
1 parent 7487395e44
commit 06b169d7a1
5 files changed
+245 -28

No files matched your search

@@ -80,10 +80,18 @@ export interface ApplyResult {
warnings: string[];
}
export interface BackupReplacement {
from: string;
to: string;
kind: AddressKind;
}
export interface BackupEntry {
backupId: string;
files: number;
createdAt: string;
replacedTotal: number;
replacements: BackupReplacement[];
}
/** 扫描进度(逐技能)。 */
@@ -249,7 +257,13 @@ export async function applyReplacementsStream(
export async function listBackups(): Promise<BackupEntry[]> {
const res = await apiFetch(`${BASE()}/backups`, { method: "GET" });
const data = await readJson<{ backups: any[] }>(res, "读取备份");
return (data.backups ?? []).map((b) => ({ backupId: b.backup_id, files: b.files ?? 0, createdAt: b.created_at ?? "" }));
return (data.backups ?? []).map((b) => ({
backupId: b.backup_id,
files: b.files ?? 0,
createdAt: b.created_at ?? "",
replacedTotal: b.replaced_total ?? 0,
replacements: (b.replacements ?? []).map((r: any) => ({ from: r.from, to: r.to, kind: r.kind })),
}));
}
export async function rollbackBackup(backupId: string): Promise<{ restored: number }> {