dsh-config-manager 0.1.19 → 0.1.21

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 (82) hide show
  1. package/lib/client.d.ts +319 -2
  2. package/lib/client.js +1271 -109
  3. package/lib/client.js.map +1 -1
  4. package/lib/core/run-registry.d.ts +2 -2
  5. package/lib/core/run-registry.js +5 -1
  6. package/lib/core/run-registry.js.map +1 -1
  7. package/lib/index.js +408 -2
  8. package/lib/index.js.map +1 -1
  9. package/lib/sync/ancestor.d.ts +17 -0
  10. package/lib/sync/ancestor.js +64 -0
  11. package/lib/sync/ancestor.js.map +1 -0
  12. package/lib/sync/autosync-config.d.ts +34 -0
  13. package/lib/sync/autosync-config.js +116 -0
  14. package/lib/sync/autosync-config.js.map +1 -0
  15. package/lib/sync/autosync-scheduler.d.ts +95 -0
  16. package/lib/sync/autosync-scheduler.js +379 -0
  17. package/lib/sync/autosync-scheduler.js.map +1 -0
  18. package/lib/sync/merge.d.ts +42 -0
  19. package/lib/sync/merge.js +325 -0
  20. package/lib/sync/merge.js.map +1 -0
  21. package/lib/sync/review-queue.d.ts +51 -0
  22. package/lib/sync/review-queue.js +119 -0
  23. package/lib/sync/review-queue.js.map +1 -0
  24. package/lib/sync/risk.d.ts +59 -0
  25. package/lib/sync/risk.js +76 -0
  26. package/lib/sync/risk.js.map +1 -0
  27. package/lib/sync/sync-config.d.ts +7 -2
  28. package/lib/sync/sync-config.js +24 -4
  29. package/lib/sync/sync-config.js.map +1 -1
  30. package/lib/sync/sync-engine.d.ts +88 -2
  31. package/lib/sync/sync-engine.js +333 -8
  32. package/lib/sync/sync-engine.js.map +1 -1
  33. package/lib/sync/sync-history.d.ts +39 -0
  34. package/lib/sync/sync-history.js +88 -0
  35. package/lib/sync/sync-history.js.map +1 -0
  36. package/lib/sync/sync-session.d.ts +39 -0
  37. package/lib/sync/sync-session.js +54 -0
  38. package/lib/sync/sync-session.js.map +1 -0
  39. package/lib/sync/sync-state.d.ts +7 -2
  40. package/lib/sync/sync-state.js +9 -5
  41. package/lib/sync/sync-state.js.map +1 -1
  42. package/lib/ui/i18n.d.ts +63 -0
  43. package/lib/ui/i18n.js +130 -1
  44. package/lib/ui/i18n.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/client/config-manager.module.css +18 -0
  47. package/src/client/sync/SyncConfirmView.tsx +301 -0
  48. package/src/client/sync/SyncHistoryView.test.ts +40 -0
  49. package/src/client/sync/SyncHistoryView.tsx +155 -0
  50. package/src/client/sync/SyncSettingsView.tsx +241 -12
  51. package/src/client/sync/history-model.test.ts +82 -0
  52. package/src/client/sync/history-model.ts +112 -0
  53. package/src/client/sync/sync-api.test.ts +155 -0
  54. package/src/client/sync/sync-api.ts +219 -0
  55. package/src/client/sync/sync-locales.ts +162 -1
  56. package/src/client/sync/sync-view-v2.test.ts +131 -0
  57. package/src/client/sync/sync-view.ts +151 -4
  58. package/src/core/run-registry.ts +7 -3
  59. package/src/index.ts +420 -3
  60. package/src/sync/ancestor.test.ts +152 -0
  61. package/src/sync/ancestor.ts +81 -0
  62. package/src/sync/autosync-config.test.ts +93 -0
  63. package/src/sync/autosync-config.ts +137 -0
  64. package/src/sync/autosync-scheduler.test.ts +191 -0
  65. package/src/sync/autosync-scheduler.ts +443 -0
  66. package/src/sync/merge.test.ts +204 -0
  67. package/src/sync/merge.ts +360 -0
  68. package/src/sync/review-queue.test.ts +120 -0
  69. package/src/sync/review-queue.ts +167 -0
  70. package/src/sync/risk.test.ts +131 -0
  71. package/src/sync/risk.ts +122 -0
  72. package/src/sync/sync-config.test.ts +106 -0
  73. package/src/sync/sync-config.ts +23 -4
  74. package/src/sync/sync-engine.test.ts +392 -3
  75. package/src/sync/sync-engine.ts +383 -10
  76. package/src/sync/sync-history.test.ts +85 -0
  77. package/src/sync/sync-history.ts +126 -0
  78. package/src/sync/sync-session.test.ts +137 -0
  79. package/src/sync/sync-session.ts +76 -0
  80. package/src/sync/sync-state.test.ts +48 -2
  81. package/src/sync/sync-state.ts +11 -5
  82. package/src/ui/i18n.ts +132 -3
@@ -0,0 +1,325 @@
1
+ import { hashSection } from "./sync-state.js";
2
+ /** 收集 local/remote/ancestor 三个快照中出现过的所有分区 id。 */
3
+ function unionSectionIds(local, remote, ancestor) {
4
+ const ids = new Set();
5
+ for (const id of Object.keys(local))
6
+ ids.add(id);
7
+ for (const id of Object.keys(remote))
8
+ ids.add(id);
9
+ if (ancestor)
10
+ for (const id of Object.keys(ancestor))
11
+ ids.add(id);
12
+ return [...ids];
13
+ }
14
+ function computeHashes(local, remote, ancestor, ids) {
15
+ const m = new Map();
16
+ for (const id of ids) {
17
+ const lh = local[id] !== undefined ? hashSection(local[id]) : undefined;
18
+ const rh = remote[id] !== undefined ? hashSection(remote[id]) : undefined;
19
+ const ah = ancestor && ancestor[id] !== undefined ? hashSection(ancestor[id]) : undefined;
20
+ m.set(id, { local: lh, remote: rh, ancestor: ah });
21
+ }
22
+ return m;
23
+ }
24
+ /** 顶层 JSON 分区对象:键序无关判等(深度递归,深层数组也判等)。 */
25
+ function deepEqual(a, b) {
26
+ if (a === b)
27
+ return true;
28
+ if (a === null || b === null)
29
+ return a === b;
30
+ if (typeof a !== typeof b)
31
+ return false;
32
+ if (typeof a !== 'object')
33
+ return a === b;
34
+ if (Array.isArray(a) !== Array.isArray(b))
35
+ return false;
36
+ if (Array.isArray(a)) {
37
+ const aa = a;
38
+ const bb = b;
39
+ if (aa.length !== bb.length)
40
+ return false;
41
+ for (let i = 0; i < aa.length; i++)
42
+ if (!deepEqual(aa[i], bb[i]))
43
+ return false;
44
+ return true;
45
+ }
46
+ const ao = a;
47
+ const bo = b;
48
+ const ak = Object.keys(ao).sort();
49
+ const bk = Object.keys(bo).sort();
50
+ if (ak.length !== bk.length)
51
+ return false;
52
+ for (let i = 0; i < ak.length; i++)
53
+ if (ak[i] !== bk[i])
54
+ return false;
55
+ for (const k of ak)
56
+ if (!deepEqual(ao[k], bo[k]))
57
+ return false;
58
+ return true;
59
+ }
60
+ /** JSON 分区精细合并:按 top-level key 走三方合并。
61
+ * - 双侧均未改 → 跳过
62
+ * - 仅一侧改 → 采纳该侧
63
+ * - 双侧均改 → 若 deepEqual 自动合并;否则留为冲突 */
64
+ function mergeJsonSectionGranular(local, remote, ancestor) {
65
+ const merged = {};
66
+ const conflicts = [];
67
+ const keys = new Set([...Object.keys(local), ...Object.keys(remote), ...(ancestor ? Object.keys(ancestor) : [])]);
68
+ for (const k of keys) {
69
+ const lHas = Object.prototype.hasOwnProperty.call(local, k);
70
+ const rHas = Object.prototype.hasOwnProperty.call(remote, k);
71
+ const aHas = ancestor ? Object.prototype.hasOwnProperty.call(ancestor, k) : false;
72
+ const lv = lHas ? local[k] : undefined;
73
+ const rv = rHas ? remote[k] : undefined;
74
+ const av = aHas ? ancestor[k] : undefined;
75
+ if (lHas && rHas) {
76
+ if (deepEqual(lv, rv)) {
77
+ merged[k] = lv;
78
+ continue;
79
+ }
80
+ // 双侧都有该 key 但值不同 → 看是否都改过
81
+ const lChanged = !aHas || !deepEqual(lv, av);
82
+ const rChanged = !aHas || !deepEqual(rv, av);
83
+ if (lChanged && rChanged) {
84
+ if (deepEqual(lv, rv)) {
85
+ merged[k] = lv; // 两侧改后恰好相同
86
+ }
87
+ else {
88
+ conflicts.push({ path: k, kind: 'key', local: lv, remote: rv, ancestor: av });
89
+ }
90
+ }
91
+ else if (lChanged) {
92
+ merged[k] = lv;
93
+ }
94
+ else if (rChanged) {
95
+ merged[k] = rv;
96
+ }
97
+ else {
98
+ merged[k] = lv; // 双侧都未相对祖先改但 deepEqual 已失败——保持一致
99
+ }
100
+ }
101
+ else if (lHas && !rHas) {
102
+ // 仅本地有:删/改/增?
103
+ const lChanged = !aHas || !deepEqual(lv, av);
104
+ if (lChanged) {
105
+ // 本地增/改,远程删 → 冲突
106
+ conflicts.push({ path: k, kind: 'key', local: lv, remote: undefined, ancestor: av });
107
+ }
108
+ else {
109
+ // 本地等于祖先、远程缺:远程删 → 跟随删除
110
+ }
111
+ }
112
+ else if (!lHas && rHas) {
113
+ const rChanged = !aHas || !deepEqual(rv, av);
114
+ if (rChanged) {
115
+ // 本地删、远程增 → 冲突
116
+ conflicts.push({ path: k, kind: 'key', local: undefined, remote: rv, ancestor: av });
117
+ }
118
+ else {
119
+ // 远程等于祖先、本地缺:本地删 → 跟随删除
120
+ }
121
+ }
122
+ else {
123
+ // 仅祖先有:双侧都删 → 跟随删除
124
+ }
125
+ }
126
+ return { merged, conflicts };
127
+ }
128
+ /** FilesSection 精细合并:按 relativePath 走三方合并(按文件字节 deepEqual)。 */
129
+ function mergeFilesSectionGranular(local, remote, ancestor) {
130
+ const lMap = new Map();
131
+ for (const f of local.files)
132
+ lMap.set(f.relativePath, f.data);
133
+ const rMap = new Map();
134
+ for (const f of remote.files)
135
+ rMap.set(f.relativePath, f.data);
136
+ const aMap = new Map();
137
+ if (ancestor)
138
+ for (const f of ancestor.files)
139
+ aMap.set(f.relativePath, f.data);
140
+ const paths = new Set([...lMap.keys(), ...rMap.keys(), ...aMap.keys()]);
141
+ const mergedFiles = [];
142
+ const conflicts = [];
143
+ for (const p of paths) {
144
+ const l = lMap.get(p);
145
+ const r = rMap.get(p);
146
+ const a = aMap.get(p);
147
+ const eq = (x, y) => {
148
+ if (x === undefined || y === undefined)
149
+ return x === y;
150
+ if (x.length !== y.length)
151
+ return false;
152
+ for (let i = 0; i < x.length; i++)
153
+ if (x[i] !== y[i])
154
+ return false;
155
+ return true;
156
+ };
157
+ if (l && r) {
158
+ if (eq(l, r)) {
159
+ mergedFiles.push({ relativePath: p, data: l, contentHash: '' });
160
+ continue;
161
+ }
162
+ const lChanged = !a || !eq(l, a);
163
+ const rChanged = !a || !eq(r, a);
164
+ if (lChanged && rChanged) {
165
+ conflicts.push({ path: p, kind: 'file', local: l, remote: r, ancestor: a });
166
+ }
167
+ else if (lChanged) {
168
+ mergedFiles.push({ relativePath: p, data: l, contentHash: '' });
169
+ }
170
+ else if (rChanged) {
171
+ mergedFiles.push({ relativePath: p, data: r, contentHash: '' });
172
+ }
173
+ else {
174
+ mergedFiles.push({ relativePath: p, data: l, contentHash: '' });
175
+ }
176
+ }
177
+ else if (l && !r) {
178
+ const aExists = a !== undefined;
179
+ const lChanged = aExists ? !eq(l, a) : true;
180
+ if (lChanged) {
181
+ if (!aExists) {
182
+ // 纯本地新增(祖先里也没有)→ keepLocal
183
+ mergedFiles.push({ relativePath: p, data: l, contentHash: '' });
184
+ }
185
+ else {
186
+ // 本地改/增 vs 远程删 → 冲突
187
+ conflicts.push({ path: p, kind: 'file', local: l, remote: undefined, ancestor: a });
188
+ }
189
+ }
190
+ }
191
+ else if (!l && r) {
192
+ const aExists = a !== undefined;
193
+ const rChanged = aExists ? !eq(r, a) : true;
194
+ if (rChanged) {
195
+ if (!aExists) {
196
+ // 纯远程新增(祖先里也没有)→ useRemote
197
+ mergedFiles.push({ relativePath: p, data: r, contentHash: '' });
198
+ }
199
+ else {
200
+ // 本地删 vs 远程改/增 → 冲突
201
+ conflicts.push({ path: p, kind: 'file', local: undefined, remote: r, ancestor: a });
202
+ }
203
+ }
204
+ }
205
+ }
206
+ return { merged: { version: 1, files: mergedFiles }, conflicts };
207
+ }
208
+ /** 识别 JSON 分区的「键级合并」键值映射(如 settings/ui 的 namespaces、providers 的 providers)。
209
+ * 返回 undefined → 该分区无法做键级合并,调用方应退化为整分区冲突。 */
210
+ function keyMapOf(data) {
211
+ const obj = data;
212
+ if (obj && typeof obj === 'object' && obj['version'] === 1) {
213
+ const ns = obj['namespaces'];
214
+ if (ns && typeof ns === 'object' && !Array.isArray(ns))
215
+ return ns;
216
+ const prov = obj['providers'];
217
+ if (prov && typeof prov === 'object' && !Array.isArray(prov))
218
+ return prov;
219
+ }
220
+ return undefined;
221
+ }
222
+ /** 主入口:三方合并。纯函数,无副作用。 */
223
+ export function merge(local, remote, ancestor) {
224
+ const l = local;
225
+ const r = remote;
226
+ const a = ancestor;
227
+ const ids = unionSectionIds(l, r, a);
228
+ const hashes = computeHashes(l, r, a, ids);
229
+ const results = [];
230
+ for (const id of ids) {
231
+ const h = hashes.get(id);
232
+ const lData = l[id];
233
+ const rData = r[id];
234
+ const aData = a ? a[id] : undefined;
235
+ // 远端无 → skip(不在本轮考虑;本地有但远端没有 = 远端"删了",视作 useRemote=删除)
236
+ // 本实现按远端视角:远端缺 + 本地存在 + 本地未改祖先 → skip(无变化);否则冲突。
237
+ if (rData === undefined && lData !== undefined) {
238
+ const lChanged = h.ancestor === undefined || h.local !== h.ancestor;
239
+ if (!lChanged) {
240
+ results.push({ id, decision: 'skip', conflicts: [] });
241
+ continue;
242
+ }
243
+ results.push({ id, decision: 'conflict', conflicts: [{ path: '$', kind: 'key', local: lData, remote: undefined, ancestor: aData }] });
244
+ continue;
245
+ }
246
+ // 本地无、远端有:远端新增;本地删除过(=等于祖先空)+祖先空→skip;否则按 useRemote。
247
+ if (lData === undefined && rData !== undefined) {
248
+ const rChanged = h.ancestor === undefined || h.remote !== h.ancestor;
249
+ if (!rChanged) {
250
+ results.push({ id, decision: 'skip', conflicts: [] });
251
+ continue;
252
+ }
253
+ results.push({ id, decision: 'useRemote', merged: rData, conflicts: [] });
254
+ continue;
255
+ }
256
+ // 双方都没有 → skip
257
+ if (lData === undefined && rData === undefined) {
258
+ results.push({ id, decision: 'skip', conflicts: [] });
259
+ continue;
260
+ }
261
+ // 双方都有
262
+ if (h.local === h.remote) {
263
+ results.push({ id, decision: 'skip', conflicts: [] });
264
+ continue;
265
+ }
266
+ if (h.ancestor === undefined) {
267
+ // 无祖先 → 两方差异视为整分区冲突(不猜测)
268
+ results.push({ id, decision: 'conflict', conflicts: [{ path: '$', kind: 'key', local: lData, remote: rData, ancestor: undefined }] });
269
+ continue;
270
+ }
271
+ if (h.local === h.ancestor) {
272
+ results.push({ id, decision: 'useRemote', merged: rData, conflicts: [] });
273
+ continue;
274
+ }
275
+ if (h.remote === h.ancestor) {
276
+ results.push({ id, decision: 'keepLocal', merged: lData, conflicts: [] });
277
+ continue;
278
+ }
279
+ // 双侧相对祖先都改 → 进入精细合并
280
+ if (isFilesSectionData(lData)) {
281
+ const { merged, conflicts } = mergeFilesSectionGranular(lData, rData, aData);
282
+ if (conflicts.length === 0) {
283
+ results.push({ id, decision: 'useRemote', merged: merged, conflicts: [] });
284
+ }
285
+ else {
286
+ results.push({ id, decision: 'conflict', conflicts, merged: undefined });
287
+ }
288
+ continue;
289
+ }
290
+ // JSON 分区:识别可键级合并的子映射(namespaces / providers)
291
+ const lKeyMap = keyMapOf(lData);
292
+ const rKeyMap = keyMapOf(rData);
293
+ const aKeyMap = aData ? keyMapOf(aData) : undefined;
294
+ if (lKeyMap && rKeyMap) {
295
+ const { merged: mergedKeys, conflicts } = mergeJsonSectionGranular(lKeyMap, rKeyMap, aKeyMap);
296
+ // 重组 SectionData:用 l/r 中较新者保留非键级合并字段(version 等),键级合并字段用 mergedKeys
297
+ const lObj = lData;
298
+ const rObj = rData;
299
+ const base = { ...lObj, ...rObj };
300
+ // 找到键级合并字段在 base 中的键名
301
+ const keyFieldName = lKeyMap === lObj['namespaces'] ? 'namespaces'
302
+ : lKeyMap === lObj['providers'] ? 'providers' : undefined;
303
+ if (keyFieldName)
304
+ base[keyFieldName] = mergedKeys;
305
+ if (conflicts.length === 0) {
306
+ results.push({ id, decision: 'useRemote', merged: base, conflicts: [] });
307
+ }
308
+ else {
309
+ results.push({ id, decision: 'conflict', conflicts, merged: undefined });
310
+ }
311
+ continue;
312
+ }
313
+ // 非键级合并 JSON 分区(plugins/mcp/prompts/workspaces 等):退化为整分区冲突
314
+ results.push({ id, decision: 'conflict', conflicts: [{ path: '$', kind: 'key', local: lData, remote: rData, ancestor: aData }] });
315
+ }
316
+ return { sections: results };
317
+ }
318
+ /** 分区是否为文件类(FilesSection)—— 鸭子类型,复用 sync-state 的判定以保持一致。 */
319
+ function isFilesSectionData(data) {
320
+ if (data === null || typeof data !== 'object')
321
+ return false;
322
+ const obj = data;
323
+ return obj.version === 1 && Array.isArray(obj.files);
324
+ }
325
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/sync/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * m-sync-flow:待审队列持久化(独立文件 sync-review-queue.json)。
3
+ *
4
+ * 与 sync-state.json 分文件存放:sync-state 是机器可读同步元数据,
5
+ * 待审队列是用户可见/可决策的工作队列;混在一起会让同步引擎误读。
6
+ *
7
+ * 设计:
8
+ * - 只存差异摘要(items 数组),不存全量 payload——避免双写;
9
+ * UI 需要完整数据时回拉远端或复用运行时 MergePlan。
10
+ * - 写入用 writeFile + rename 原子提交:半成品文件不会污染读侧。
11
+ * - 损坏 JSON 严格拒绝(不静默降级到空队列)。
12
+ */
13
+ import fs from 'node:fs/promises';
14
+ export declare const REVIEW_QUEUE_FILE = "sync-review-queue.json";
15
+ /** 单条待审项(决策前 description/local/remote/ancestor 必填;decision 可选) */
16
+ export interface ReviewQueueItem {
17
+ id: string;
18
+ /** 分区 id(settings / providers / workspaces / plugins / mcp 等) */
19
+ sectionId: string;
20
+ /** 'key' | 'file' | 'section':冲突粒度(来自 MergeConflict.kind 或整分区冲突) */
21
+ kind: 'key' | 'file' | 'section';
22
+ description: string;
23
+ local?: unknown;
24
+ remote?: unknown;
25
+ ancestor?: unknown;
26
+ /** 用户决策(resolve 后写入) */
27
+ decision?: 'useRemote' | 'keepLocal' | 'skip';
28
+ decidedAt?: string;
29
+ /** 关联的远端快照 id(追溯来源) */
30
+ snapshotId?: string;
31
+ }
32
+ export interface ReviewQueue {
33
+ items: ReviewQueueItem[];
34
+ updatedAt: string;
35
+ }
36
+ export declare const EMPTY_REVIEW_QUEUE: ReviewQueue;
37
+ /** 读取待审队列;文件不存在 → 返回空队列;损坏 JSON 抛错。 */
38
+ export declare function readReviewQueue(stateDir: string, fsx?: Pick<typeof fs, 'readFile' | 'writeFile' | 'rename' | 'stat' | 'mkdir'>): Promise<ReviewQueue>;
39
+ /**
40
+ * 原子写入:先写临时文件 + rename 到目标文件(POSIX/Windows 均支持 rename 原子替换)。
41
+ * 同一 stateDir 下并发调用不会产生半成品文件(写完临时再 rename)。
42
+ */
43
+ export declare function writeReviewQueue(stateDir: string, queue: ReviewQueue, fsx?: Pick<typeof fs, 'readFile' | 'writeFile' | 'rename' | 'stat' | 'mkdir'>): Promise<void>;
44
+ /** 把多 item 追加到队列(同 id 视为同一项,不重复追加) */
45
+ export declare function enqueueItems(stateDir: string, items: Omit<ReviewQueueItem, 'id' | 'decidedAt' | 'decision'>[], now?: () => Date, fsx?: Pick<typeof fs, 'readFile' | 'writeFile' | 'rename' | 'stat' | 'mkdir'>): Promise<ReviewQueue>;
46
+ /** 把整组合并后的 autoApply 项(失败回滚后)入队 */
47
+ export declare function enqueueAutoAppliedOnFailure(stateDir: string, items: Omit<ReviewQueueItem, 'id' | 'decidedAt' | 'decision'>[], fsx?: Pick<typeof fs, 'readFile' | 'writeFile' | 'rename' | 'stat' | 'mkdir'>): Promise<ReviewQueue>;
48
+ /** 用户对某条 item 做了决策(keepLocal / useRemote / skip);未找到抛错。 */
49
+ export declare function resolveItem(stateDir: string, itemId: string, decision: 'useRemote' | 'keepLocal' | 'skip', now?: () => Date, fsx?: Pick<typeof fs, 'readFile' | 'writeFile' | 'rename' | 'stat' | 'mkdir'>): Promise<ReviewQueue>;
50
+ /** 工具:在临时目录构造 stateDir 的便捷工厂(测试用) */
51
+ export declare function tmpStateDir(prefix: string): Promise<string>;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * m-sync-flow:待审队列持久化(独立文件 sync-review-queue.json)。
3
+ *
4
+ * 与 sync-state.json 分文件存放:sync-state 是机器可读同步元数据,
5
+ * 待审队列是用户可见/可决策的工作队列;混在一起会让同步引擎误读。
6
+ *
7
+ * 设计:
8
+ * - 只存差异摘要(items 数组),不存全量 payload——避免双写;
9
+ * UI 需要完整数据时回拉远端或复用运行时 MergePlan。
10
+ * - 写入用 writeFile + rename 原子提交:半成品文件不会污染读侧。
11
+ * - 损坏 JSON 严格拒绝(不静默降级到空队列)。
12
+ */
13
+ import fs from 'node:fs/promises';
14
+ import os from 'node:os';
15
+ import path from 'node:path';
16
+ import crypto from 'node:crypto';
17
+ import { parseJsonSafe, stringifyJsonSafe } from "../utils/json.js";
18
+ export const REVIEW_QUEUE_FILE = 'sync-review-queue.json';
19
+ export const EMPTY_REVIEW_QUEUE = { items: [], updatedAt: '' };
20
+ /** 读取待审队列;文件不存在 → 返回空队列;损坏 JSON 抛错。 */
21
+ export async function readReviewQueue(stateDir, fsx = fs) {
22
+ const file = path.join(stateDir, REVIEW_QUEUE_FILE);
23
+ try {
24
+ const raw = await fsx.readFile(file, 'utf8');
25
+ const parsed = parseJsonSafe(raw);
26
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
27
+ throw new Error('sync-review-queue.json 损坏:必须是对象');
28
+ }
29
+ const obj = parsed;
30
+ if (!Array.isArray(obj['items'])) {
31
+ throw new Error('sync-review-queue.json 损坏:items 必须是数组');
32
+ }
33
+ const items = [];
34
+ for (const it of obj['items']) {
35
+ if (it === null || typeof it !== 'object' || Array.isArray(it)) {
36
+ throw new Error('sync-review-queue.json 损坏:每个 item 必须是对象');
37
+ }
38
+ const i = it;
39
+ if (typeof i['id'] !== 'string' || typeof i['sectionId'] !== 'string'
40
+ || typeof i['kind'] !== 'string' || typeof i['description'] !== 'string') {
41
+ throw new Error('sync-review-queue.json 损坏:item 必须含字符串 id/sectionId/kind/description');
42
+ }
43
+ items.push(i);
44
+ }
45
+ return {
46
+ items,
47
+ updatedAt: typeof obj['updatedAt'] === 'string' ? obj['updatedAt'] : '',
48
+ };
49
+ }
50
+ catch (err) {
51
+ if (err.code === 'ENOENT')
52
+ return { ...EMPTY_REVIEW_QUEUE };
53
+ throw err;
54
+ }
55
+ }
56
+ /**
57
+ * 原子写入:先写临时文件 + rename 到目标文件(POSIX/Windows 均支持 rename 原子替换)。
58
+ * 同一 stateDir 下并发调用不会产生半成品文件(写完临时再 rename)。
59
+ */
60
+ export async function writeReviewQueue(stateDir, queue, fsx = fs) {
61
+ await fsx.mkdir(stateDir, { recursive: true });
62
+ const target = path.join(stateDir, REVIEW_QUEUE_FILE);
63
+ const tmp = path.join(stateDir, `.${REVIEW_QUEUE_FILE}.${process.pid}.${crypto.randomBytes(4).toString('hex')}.tmp`);
64
+ const data = stringifyJsonSafe(queue, { space: 2 });
65
+ try {
66
+ await fsx.writeFile(tmp, data, 'utf8');
67
+ await fsx.rename(tmp, target);
68
+ }
69
+ catch (err) {
70
+ // 清理可能残留的临时文件
71
+ try {
72
+ await fsx.stat(tmp);
73
+ await fsx.rename(tmp, target);
74
+ }
75
+ catch { /* ignore */ }
76
+ throw err;
77
+ }
78
+ }
79
+ /** 生成稳定 id(基于内容的 hex;同 description → 同 id,便于去重) */
80
+ function hashItemId(sectionId, kind, description, path) {
81
+ const h = crypto.createHash('sha256');
82
+ h.update(`${sectionId}\u0000${kind}\u0000${path ?? ''}\u0000${description}`);
83
+ return h.digest('hex').slice(0, 16);
84
+ }
85
+ /** 把多 item 追加到队列(同 id 视为同一项,不重复追加) */
86
+ export async function enqueueItems(stateDir, items, now = () => new Date(), fsx = fs) {
87
+ const current = await readReviewQueue(stateDir, fsx);
88
+ const seen = new Set(current.items.map((i) => i.id));
89
+ for (const it of items) {
90
+ const id = hashItemId(it.sectionId, it.kind, it.description);
91
+ if (seen.has(id))
92
+ continue;
93
+ current.items.push({ ...it, id });
94
+ seen.add(id);
95
+ }
96
+ current.updatedAt = now().toISOString();
97
+ await writeReviewQueue(stateDir, current, fsx);
98
+ return current;
99
+ }
100
+ /** 把整组合并后的 autoApply 项(失败回滚后)入队 */
101
+ export async function enqueueAutoAppliedOnFailure(stateDir, items, fsx = fs) {
102
+ return enqueueItems(stateDir, items, undefined, fsx);
103
+ }
104
+ /** 用户对某条 item 做了决策(keepLocal / useRemote / skip);未找到抛错。 */
105
+ export async function resolveItem(stateDir, itemId, decision, now = () => new Date(), fsx = fs) {
106
+ const current = await readReviewQueue(stateDir, fsx);
107
+ const idx = current.items.findIndex((i) => i.id === itemId);
108
+ if (idx === -1)
109
+ throw new Error(`resolveItem: 未找到 itemId ${itemId}`);
110
+ current.items[idx] = { ...current.items[idx], decision, decidedAt: now().toISOString() };
111
+ current.updatedAt = now().toISOString();
112
+ await writeReviewQueue(stateDir, current, fsx);
113
+ return current;
114
+ }
115
+ /** 工具:在临时目录构造 stateDir 的便捷工厂(测试用) */
116
+ export function tmpStateDir(prefix) {
117
+ return fs.mkdtemp(path.join(os.tmpdir(), prefix));
118
+ }
119
+ //# sourceMappingURL=review-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-queue.js","sourceRoot":"","sources":["../../src/sync/review-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * m-sync-flow:分级自动应用策略 + 首次强制预览(纯函数)。
3
+ *
4
+ * 数据源:P2a 的 MergePlan(每分区 decision + conflicts)。
5
+ * 产出:SyncApplyPlan 三组(autoApply / review / skipped),供 SyncEngine.applyMergePlan 与 UI 使用。
6
+ *
7
+ * 规则:
8
+ * - SECTION_RISK_TIER 把每个 SectionId 静态归类到 low / medium / high;
9
+ * - 双向 conflict 分区永远进 review(无论风险与 firstSync 与否);
10
+ * - firstSync=true 时所有非 skip 项一律进 review(安全第一:人工确认后才开启自动);
11
+ * - firstSync=false 时按风险等级分流:低风险且 useRemote/keepLocal 进 autoApply;
12
+ * 中风险、high、双向冲突 → review;skip 或无变化 → skipped。
13
+ */
14
+ import type { MergePlan, MergeSectionResult } from './merge.ts';
15
+ import type { SectionId } from '../schema/types.ts';
16
+ /** 分区风险等级(驱动自动应用 vs 待审) */
17
+ export type RiskTier = 'low' | 'medium' | 'high';
18
+ /**
19
+ * 分区风险映射(v1 静态表;可后续接入适配器声明的 risk 字段动态化)。
20
+ * - low :低风险——自动应用(无冲突时)
21
+ * settings / ui / providers / prompts
22
+ * - medium :中风险——待审队列(路径映射、安装、变更)
23
+ * workspaces / plugins / mcp
24
+ * - high :高风险——永不自动(含双向冲突、设备专属、凭据/秘密)
25
+ * credentialsStatus / secrets / sessions / pluginFiles / workspaces? 不,
26
+ * 按规划表 workspaces 归 medium(中风险),credentialsStatus/secrets 归 high;
27
+ * agentPresets / skills 暂归 low(受 sync 通道的 portable 过滤实际不会携带 skills)。
28
+ */
29
+ export declare const SECTION_RISK_TIER: Readonly<Record<SectionId, RiskTier>>;
30
+ export interface ClassifyOptions {
31
+ /**
32
+ * true = 首次同步:所有非 skip 项一律进 review(无论风险等级);
33
+ * false(默认)= 按风险等级分流。
34
+ * 调用方在 SyncEngine 中维护 firstSyncCompleted 标志。
35
+ */
36
+ firstSync: boolean;
37
+ }
38
+ /** 自动应用三组结果(互斥:同一 sectionId 只出现在一组) */
39
+ export interface SyncApplyPlan {
40
+ autoApply: MergeSectionResult[];
41
+ review: MergeSectionResult[];
42
+ skipped: MergeSectionResult[];
43
+ }
44
+ /**
45
+ * 按风险等级 + firstSync 标志将 MergePlan 分流到三组。
46
+ * 纯函数:相同输入 → 相同输出;不读 fs、不发网络。
47
+ */
48
+ export declare function classifyMergePlan(plan: MergePlan, opts: ClassifyOptions): SyncApplyPlan;
49
+ /**
50
+ * 分流摘要计数(供 UI 徽章显示)。
51
+ * 同一函数复用:纯函数无副作用。
52
+ */
53
+ export interface SyncApplySummary {
54
+ autoApplyCount: number;
55
+ reviewCount: number;
56
+ skippedCount: number;
57
+ totalCount: number;
58
+ }
59
+ export declare function summarizeApplyPlan(apply: SyncApplyPlan): SyncApplySummary;