jinzd-ai-cli 0.4.24 → 0.4.25

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,98 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/tools/file-checkpoint.ts
4
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from "fs";
5
+ var MAX_SNAPSHOTS = 200;
6
+ var FileCheckpointStore = class {
7
+ snapshots = [];
8
+ /**
9
+ * 在文件写入前调用,保存当前文件内容。
10
+ * 同一 messageIndex 下同一文件只记录首次快照。
11
+ */
12
+ snapshot(filePath, messageIndex) {
13
+ const exists = this.snapshots.some(
14
+ (s) => s.filePath === filePath && s.messageIndex === messageIndex
15
+ );
16
+ if (exists) return;
17
+ let content = null;
18
+ if (existsSync(filePath)) {
19
+ try {
20
+ content = readFileSync(filePath, "utf-8");
21
+ } catch {
22
+ return;
23
+ }
24
+ }
25
+ this.snapshots.push({
26
+ filePath,
27
+ content,
28
+ messageIndex,
29
+ timestamp: Date.now()
30
+ });
31
+ if (this.snapshots.length > MAX_SNAPSHOTS) {
32
+ this.snapshots = this.snapshots.slice(-MAX_SNAPSHOTS);
33
+ }
34
+ }
35
+ /**
36
+ * 恢复所有在指定消息索引之后被修改的文件到该索引时的状态。
37
+ * @returns 恢复和删除的文件数量
38
+ */
39
+ restoreToMessageIndex(targetIndex) {
40
+ const modifiedAfter = this.snapshots.filter((s) => s.messageIndex > targetIndex);
41
+ const uniqueFiles = [...new Set(modifiedAfter.map((s) => s.filePath))];
42
+ let restored = 0;
43
+ let deleted = 0;
44
+ const files = [];
45
+ for (const filePath of uniqueFiles) {
46
+ const beforeSnapshots = this.snapshots.filter((s) => s.filePath === filePath && s.messageIndex <= targetIndex).sort((a, b) => b.messageIndex - a.messageIndex);
47
+ const restoreTo = beforeSnapshots[0];
48
+ try {
49
+ if (restoreTo) {
50
+ if (restoreTo.content === null) {
51
+ if (existsSync(filePath)) {
52
+ unlinkSync(filePath);
53
+ deleted++;
54
+ files.push(filePath);
55
+ }
56
+ } else {
57
+ writeFileSync(filePath, restoreTo.content, "utf-8");
58
+ restored++;
59
+ files.push(filePath);
60
+ }
61
+ } else {
62
+ const earliest = this.snapshots.filter((s) => s.filePath === filePath).sort((a, b) => a.messageIndex - b.messageIndex)[0];
63
+ if (earliest && earliest.content === null) {
64
+ if (existsSync(filePath)) {
65
+ unlinkSync(filePath);
66
+ deleted++;
67
+ files.push(filePath);
68
+ }
69
+ } else if (earliest) {
70
+ writeFileSync(filePath, earliest.content, "utf-8");
71
+ restored++;
72
+ files.push(filePath);
73
+ }
74
+ }
75
+ } catch {
76
+ }
77
+ }
78
+ this.snapshots = this.snapshots.filter((s) => s.messageIndex <= targetIndex);
79
+ return { restored, deleted, files };
80
+ }
81
+ /** 获取所有快照(供调试/显示) */
82
+ getSnapshots() {
83
+ return this.snapshots;
84
+ }
85
+ /** 获取有快照的消息索引列表(去重排序) */
86
+ getMessageIndices() {
87
+ return [...new Set(this.snapshots.map((s) => s.messageIndex))].sort((a, b) => a - b);
88
+ }
89
+ /** 清空所有快照(新会话/清除时调用) */
90
+ clear() {
91
+ this.snapshots = [];
92
+ }
93
+ };
94
+ var fileCheckpoints = new FileCheckpointStore();
95
+
96
+ export {
97
+ fileCheckpoints
98
+ };