dsh-config-manager 0.1.0

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 (253) hide show
  1. package/README.md +216 -0
  2. package/README.zh-CN.md +218 -0
  3. package/cordis.patch.yml +45 -0
  4. package/dsh.bundle.patch +21 -0
  5. package/dsh.client +39 -0
  6. package/lib/adapters/agent-presets.d.ts +13 -0
  7. package/lib/adapters/agent-presets.js +14 -0
  8. package/lib/adapters/agent-presets.js.map +1 -0
  9. package/lib/adapters/credentials.d.ts +36 -0
  10. package/lib/adapters/credentials.js +121 -0
  11. package/lib/adapters/credentials.js.map +1 -0
  12. package/lib/adapters/file-collection.d.ts +14 -0
  13. package/lib/adapters/file-collection.js +102 -0
  14. package/lib/adapters/file-collection.js.map +1 -0
  15. package/lib/adapters/index.d.ts +38 -0
  16. package/lib/adapters/index.js +46 -0
  17. package/lib/adapters/index.js.map +1 -0
  18. package/lib/adapters/mcp.d.ts +27 -0
  19. package/lib/adapters/mcp.js +175 -0
  20. package/lib/adapters/mcp.js.map +1 -0
  21. package/lib/adapters/plugin-files.d.ts +15 -0
  22. package/lib/adapters/plugin-files.js +91 -0
  23. package/lib/adapters/plugin-files.js.map +1 -0
  24. package/lib/adapters/plugins.d.ts +13 -0
  25. package/lib/adapters/plugins.js +177 -0
  26. package/lib/adapters/plugins.js.map +1 -0
  27. package/lib/adapters/prompts.d.ts +29 -0
  28. package/lib/adapters/prompts.js +228 -0
  29. package/lib/adapters/prompts.js.map +1 -0
  30. package/lib/adapters/providers.d.ts +33 -0
  31. package/lib/adapters/providers.js +143 -0
  32. package/lib/adapters/providers.js.map +1 -0
  33. package/lib/adapters/sessions.d.ts +14 -0
  34. package/lib/adapters/sessions.js +15 -0
  35. package/lib/adapters/sessions.js.map +1 -0
  36. package/lib/adapters/settings.d.ts +23 -0
  37. package/lib/adapters/settings.js +142 -0
  38. package/lib/adapters/settings.js.map +1 -0
  39. package/lib/adapters/skills.d.ts +13 -0
  40. package/lib/adapters/skills.js +14 -0
  41. package/lib/adapters/skills.js.map +1 -0
  42. package/lib/adapters/test-helpers.d.ts +99 -0
  43. package/lib/adapters/test-helpers.js +192 -0
  44. package/lib/adapters/test-helpers.js.map +1 -0
  45. package/lib/adapters/ui.d.ts +26 -0
  46. package/lib/adapters/ui.js +88 -0
  47. package/lib/adapters/ui.js.map +1 -0
  48. package/lib/adapters/workspaces.d.ts +12 -0
  49. package/lib/adapters/workspaces.js +92 -0
  50. package/lib/adapters/workspaces.js.map +1 -0
  51. package/lib/client.d.ts +377 -0
  52. package/lib/client.js +2598 -0
  53. package/lib/client.js.map +1 -0
  54. package/lib/core/analyzer.d.ts +35 -0
  55. package/lib/core/analyzer.js +563 -0
  56. package/lib/core/analyzer.js.map +1 -0
  57. package/lib/core/backup.d.ts +29 -0
  58. package/lib/core/backup.js +184 -0
  59. package/lib/core/backup.js.map +1 -0
  60. package/lib/core/exporter.d.ts +37 -0
  61. package/lib/core/exporter.js +222 -0
  62. package/lib/core/exporter.js.map +1 -0
  63. package/lib/core/importer.d.ts +42 -0
  64. package/lib/core/importer.js +25 -0
  65. package/lib/core/importer.js.map +1 -0
  66. package/lib/core/index.d.ts +12 -0
  67. package/lib/core/index.js +11 -0
  68. package/lib/core/index.js.map +1 -0
  69. package/lib/core/rollback.d.ts +9 -0
  70. package/lib/core/rollback.js +136 -0
  71. package/lib/core/rollback.js.map +1 -0
  72. package/lib/core/types.d.ts +331 -0
  73. package/lib/core/types.js +18 -0
  74. package/lib/core/types.js.map +1 -0
  75. package/lib/core/validator.d.ts +18 -0
  76. package/lib/core/validator.js +77 -0
  77. package/lib/core/validator.js.map +1 -0
  78. package/lib/index.d.ts +51 -0
  79. package/lib/index.js +875 -0
  80. package/lib/index.js.map +1 -0
  81. package/lib/migrations/index.d.ts +29 -0
  82. package/lib/migrations/index.js +56 -0
  83. package/lib/migrations/index.js.map +1 -0
  84. package/lib/migrations/v1-to-v2.d.ts +9 -0
  85. package/lib/migrations/v1-to-v2.js +10 -0
  86. package/lib/migrations/v1-to-v2.js.map +1 -0
  87. package/lib/profiles/index.d.ts +4 -0
  88. package/lib/profiles/index.js +5 -0
  89. package/lib/profiles/index.js.map +1 -0
  90. package/lib/profiles/profile-manager.d.ts +102 -0
  91. package/lib/profiles/profile-manager.js +522 -0
  92. package/lib/profiles/profile-manager.js.map +1 -0
  93. package/lib/schema/config.d.ts +28 -0
  94. package/lib/schema/config.js +136 -0
  95. package/lib/schema/config.js.map +1 -0
  96. package/lib/schema/manifest.d.ts +28 -0
  97. package/lib/schema/manifest.js +109 -0
  98. package/lib/schema/manifest.js.map +1 -0
  99. package/lib/schema/types.d.ts +169 -0
  100. package/lib/schema/types.js +8 -0
  101. package/lib/schema/types.js.map +1 -0
  102. package/lib/schema/versions.d.ts +27 -0
  103. package/lib/schema/versions.js +50 -0
  104. package/lib/schema/versions.js.map +1 -0
  105. package/lib/security/encryption.d.ts +41 -0
  106. package/lib/security/encryption.js +152 -0
  107. package/lib/security/encryption.js.map +1 -0
  108. package/lib/security/index.d.ts +16 -0
  109. package/lib/security/index.js +17 -0
  110. package/lib/security/index.js.map +1 -0
  111. package/lib/security/integrity.d.ts +30 -0
  112. package/lib/security/integrity.js +78 -0
  113. package/lib/security/integrity.js.map +1 -0
  114. package/lib/security/redaction.d.ts +26 -0
  115. package/lib/security/redaction.js +95 -0
  116. package/lib/security/redaction.js.map +1 -0
  117. package/lib/security/secret-scanner.d.ts +48 -0
  118. package/lib/security/secret-scanner.js +253 -0
  119. package/lib/security/secret-scanner.js.map +1 -0
  120. package/lib/security/zip-security.d.ts +27 -0
  121. package/lib/security/zip-security.js +154 -0
  122. package/lib/security/zip-security.js.map +1 -0
  123. package/lib/ui/conflict-view.d.ts +28 -0
  124. package/lib/ui/conflict-view.js +49 -0
  125. package/lib/ui/conflict-view.js.map +1 -0
  126. package/lib/ui/errors.d.ts +17 -0
  127. package/lib/ui/errors.js +76 -0
  128. package/lib/ui/errors.js.map +1 -0
  129. package/lib/ui/export-flow.d.ts +62 -0
  130. package/lib/ui/export-flow.js +79 -0
  131. package/lib/ui/export-flow.js.map +1 -0
  132. package/lib/ui/import-wizard.d.ts +67 -0
  133. package/lib/ui/import-wizard.js +169 -0
  134. package/lib/ui/import-wizard.js.map +1 -0
  135. package/lib/ui/path-mapping.d.ts +38 -0
  136. package/lib/ui/path-mapping.js +75 -0
  137. package/lib/ui/path-mapping.js.map +1 -0
  138. package/lib/ui/progress.d.ts +27 -0
  139. package/lib/ui/progress.js +76 -0
  140. package/lib/ui/progress.js.map +1 -0
  141. package/lib/ui/report.d.ts +21 -0
  142. package/lib/ui/report.js +146 -0
  143. package/lib/ui/report.js.map +1 -0
  144. package/lib/ui/test-helpers.d.ts +62 -0
  145. package/lib/ui/test-helpers.js +147 -0
  146. package/lib/ui/test-helpers.js.map +1 -0
  147. package/lib/ui/types.d.ts +129 -0
  148. package/lib/ui/types.js +21 -0
  149. package/lib/ui/types.js.map +1 -0
  150. package/lib/utils/hashing.d.ts +17 -0
  151. package/lib/utils/hashing.js +41 -0
  152. package/lib/utils/hashing.js.map +1 -0
  153. package/lib/utils/json.d.ts +24 -0
  154. package/lib/utils/json.js +76 -0
  155. package/lib/utils/json.js.map +1 -0
  156. package/lib/utils/logger.d.ts +39 -0
  157. package/lib/utils/logger.js +82 -0
  158. package/lib/utils/logger.js.map +1 -0
  159. package/lib/utils/paths.d.ts +31 -0
  160. package/lib/utils/paths.js +132 -0
  161. package/lib/utils/paths.js.map +1 -0
  162. package/lib/utils/zip.d.ts +54 -0
  163. package/lib/utils/zip.js +285 -0
  164. package/lib/utils/zip.js.map +1 -0
  165. package/package.json +109 -0
  166. package/src/adapters/agent-presets.ts +14 -0
  167. package/src/adapters/credentials.test.ts +90 -0
  168. package/src/adapters/credentials.ts +141 -0
  169. package/src/adapters/file-collection.ts +110 -0
  170. package/src/adapters/files.test.ts +113 -0
  171. package/src/adapters/index.ts +69 -0
  172. package/src/adapters/mcp.test.ts +96 -0
  173. package/src/adapters/mcp.ts +181 -0
  174. package/src/adapters/plugin-files.ts +96 -0
  175. package/src/adapters/plugins.test.ts +72 -0
  176. package/src/adapters/plugins.ts +176 -0
  177. package/src/adapters/prompts.test.ts +110 -0
  178. package/src/adapters/prompts.ts +226 -0
  179. package/src/adapters/providers.test.ts +125 -0
  180. package/src/adapters/providers.ts +161 -0
  181. package/src/adapters/roundtrip.test.ts +188 -0
  182. package/src/adapters/sessions.ts +15 -0
  183. package/src/adapters/settings.test.ts +93 -0
  184. package/src/adapters/settings.ts +165 -0
  185. package/src/adapters/skills.ts +14 -0
  186. package/src/adapters/test-helpers.ts +207 -0
  187. package/src/adapters/ui.test.ts +56 -0
  188. package/src/adapters/ui.ts +106 -0
  189. package/src/adapters/workspaces.test.ts +79 -0
  190. package/src/adapters/workspaces.ts +95 -0
  191. package/src/client/CLIENT_DEPENDENCIES.md +101 -0
  192. package/src/client/ConfigManagerSection.tsx +60 -0
  193. package/src/client/api.ts +270 -0
  194. package/src/client/client-types.ts +27 -0
  195. package/src/client/common/ErrorBanner.tsx +68 -0
  196. package/src/client/common/ProgressBar.tsx +49 -0
  197. package/src/client/common/ReportView.tsx +117 -0
  198. package/src/client/common/ui.tsx +165 -0
  199. package/src/client/config-manager.module.css +759 -0
  200. package/src/client/css-modules.d.ts +8 -0
  201. package/src/client/export/ExportView.tsx +222 -0
  202. package/src/client/import/ConflictList.tsx +72 -0
  203. package/src/client/import/ImportWizardView.tsx +406 -0
  204. package/src/client/import/PathMappingForm.tsx +77 -0
  205. package/src/client/index.ts +65 -0
  206. package/src/client/locales.ts +182 -0
  207. package/src/core/analyzer.ts +631 -0
  208. package/src/core/backup.ts +212 -0
  209. package/src/core/exporter.ts +246 -0
  210. package/src/core/importer.ts +66 -0
  211. package/src/core/index.ts +39 -0
  212. package/src/core/rollback.ts +140 -0
  213. package/src/core/smoke.test.ts +717 -0
  214. package/src/core/types.ts +343 -0
  215. package/src/core/validator.ts +84 -0
  216. package/src/index.ts +942 -0
  217. package/src/migrations/index.ts +71 -0
  218. package/src/migrations/v1-to-v2.ts +17 -0
  219. package/src/profiles/index.ts +8 -0
  220. package/src/profiles/profile-manager.test.ts +280 -0
  221. package/src/profiles/profile-manager.ts +606 -0
  222. package/src/schema/config.ts +137 -0
  223. package/src/schema/manifest.ts +124 -0
  224. package/src/schema/types.ts +179 -0
  225. package/src/schema/versions.ts +55 -0
  226. package/src/security/encryption.ts +180 -0
  227. package/src/security/index.ts +16 -0
  228. package/src/security/integrity.ts +102 -0
  229. package/src/security/redaction.ts +101 -0
  230. package/src/security/secret-scanner.ts +275 -0
  231. package/src/security/security.test.ts +796 -0
  232. package/src/security/zip-security.ts +180 -0
  233. package/src/ui/conflict-view.test.ts +62 -0
  234. package/src/ui/conflict-view.ts +65 -0
  235. package/src/ui/errors.test.ts +44 -0
  236. package/src/ui/errors.ts +95 -0
  237. package/src/ui/export-flow.test.ts +75 -0
  238. package/src/ui/export-flow.ts +128 -0
  239. package/src/ui/import-wizard.test.ts +128 -0
  240. package/src/ui/import-wizard.ts +208 -0
  241. package/src/ui/path-mapping.test.ts +67 -0
  242. package/src/ui/path-mapping.ts +103 -0
  243. package/src/ui/progress.test.ts +42 -0
  244. package/src/ui/progress.ts +90 -0
  245. package/src/ui/report.test.ts +93 -0
  246. package/src/ui/report.ts +140 -0
  247. package/src/ui/test-helpers.ts +177 -0
  248. package/src/ui/types.ts +193 -0
  249. package/src/utils/hashing.ts +53 -0
  250. package/src/utils/json.ts +77 -0
  251. package/src/utils/logger.ts +114 -0
  252. package/src/utils/paths.ts +122 -0
  253. package/src/utils/zip.ts +332 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Export 控制器(规范 §1 / §21,m6-ui)。
3
+ *
4
+ * 职责:
5
+ * - Quick Export:推荐项 = defaultIncluded 且非 deviceSpecific 的分区(设计 §11.1);
6
+ * - Custom Export:按 §1 分组目录逐项勾选(含默认关闭的可选分区 pluginFiles/sessions);
7
+ * - 进度事件:调用 core 前后按 §29 阶段文案发出(UI 不冻结);
8
+ * - 结果:返回 ExportReport 并渲染 §21 文本报告。
9
+ *
10
+ * 依赖注入:ExportPort 由宿主在挂载时接入真实 Exporter(core/exporter.ts),
11
+ * 测试注入内存 mock —— 本层零依赖 core 实现。
12
+ */
13
+ import type { Manifest, SectionId } from '../schema/types.ts';
14
+ import type { ExportOptions, ExportReport } from '../core/types.ts';
15
+ import { type ExportCategory, type ExportGroup, type ProgressListener } from './types.ts';
16
+ /** UI → core 的导出端口(宿主注入 Exporter.export;测试注入 mock) */
17
+ export interface ExportPort {
18
+ export(options: ExportOptions): Promise<{
19
+ zipPath: string;
20
+ manifest: Manifest;
21
+ report: ExportReport;
22
+ }>;
23
+ }
24
+ export interface ExportFlowOptions {
25
+ port: ExportPort;
26
+ /** 分类目录(缺省用内置目录,与 adapters 的 displayName/defaultIncluded/portability 对齐) */
27
+ categories?: ExportCategory[];
28
+ onProgress?: ProgressListener;
29
+ }
30
+ export interface ExportRunResult {
31
+ zipPath: string;
32
+ manifest: Manifest;
33
+ report: ExportReport;
34
+ /** §21 渲染文本(report.ts) */
35
+ text: string;
36
+ }
37
+ /** 内置分类目录(与 src/adapters/* 的 displayName/defaultIncluded/portability 对齐,研究报告 §2.2) */
38
+ export declare const DEFAULT_CATEGORIES: readonly ExportCategory[];
39
+ export declare class ExportFlow {
40
+ readonly categories: readonly ExportCategory[];
41
+ private readonly port;
42
+ private readonly onProgress;
43
+ constructor(opts: ExportFlowOptions);
44
+ /** Quick Export 推荐分区(defaultIncluded 且非 deviceSpecific) */
45
+ quickSelection(): SectionId[];
46
+ /** 按 §1 分组返回分类目录(Custom Export 树) */
47
+ groupedCatalog(): {
48
+ group: ExportGroup;
49
+ label: string;
50
+ note?: string;
51
+ categories: ExportCategory[];
52
+ }[];
53
+ /** 校验 Custom 勾选:未知分区 = invalid;deviceSpecific 分区给提示警告(仍可继续) */
54
+ validateSelection(selection: readonly SectionId[]): {
55
+ valid: boolean;
56
+ warnings: string[];
57
+ };
58
+ /** 执行导出:发进度事件 → 调 core → 渲染 §21 报告 */
59
+ run(mode: 'quick' | 'custom', selection: readonly SectionId[], opts?: {
60
+ includeSecrets?: boolean;
61
+ }): Promise<ExportRunResult>;
62
+ }
@@ -0,0 +1,79 @@
1
+ import { EXPORT_GROUPS, isQuickRecommended, } from "./types.js";
2
+ import { EXPORT_STAGES, ProgressTracker } from "./progress.js";
3
+ import { renderExportReport } from "./report.js";
4
+ /** 内置分类目录(与 src/adapters/* 的 displayName/defaultIncluded/portability 对齐,研究报告 §2.2) */
5
+ export const DEFAULT_CATEGORIES = [
6
+ { id: 'settings', label: 'Settings', description: 'DSH 全局设置(namespace 分区,redacted)', defaultIncluded: true, portability: 'portable', group: 'general' },
7
+ { id: 'providers', label: 'Providers & Models', description: 'LLM Provider / Model / 默认模型 / BaseURL', defaultIncluded: true, portability: 'portable', group: 'ai' },
8
+ { id: 'plugins', label: 'Plugins', description: '已安装插件清单与启用状态(不含二进制)', defaultIncluded: true, portability: 'portable', group: 'extensions' },
9
+ { id: 'pluginFiles', label: 'Plugin Files', description: '插件自有配置文件(dsh-ssh.json 等,白名单)', defaultIncluded: false, portability: 'deviceSpecific', group: 'extensions' },
10
+ { id: 'mcp', label: 'MCP Servers', description: 'MCP 服务器组合配置(需重启生效)', defaultIncluded: true, portability: 'platformSpecific', group: 'mcp' },
11
+ { id: 'prompts', label: 'Prompts', description: 'System Prompt / Plan Mode 提示', defaultIncluded: true, portability: 'portable', group: 'customization' },
12
+ { id: 'skills', label: 'Skills', description: '用户技能文件(~/.dsh/skills)', defaultIncluded: true, portability: 'portable', group: 'customization' },
13
+ { id: 'agentPresets', label: 'Agent Presets', description: 'Agent 预设(~/.dsh/.agent-presets)', defaultIncluded: true, portability: 'portable', group: 'customization' },
14
+ { id: 'workspaces', label: 'Workspaces', description: '工作区记录(含绝对路径,需路径映射)', defaultIncluded: true, portability: 'platformSpecific', group: 'workspace' },
15
+ { id: 'ui', label: 'UI Preferences', description: 'UI 类 settings namespace(localStorage 项仅说明)', defaultIncluded: true, portability: 'portable', group: 'ui' },
16
+ { id: 'credentialsStatus', label: 'Credentials Status', description: '凭据状态(configured 标记,永不导出值)', defaultIncluded: true, portability: 'deviceSpecific', group: 'optional', sensitive: true },
17
+ { id: 'sessions', label: 'Sessions', description: '历史会话(默认关闭,含敏感内容)', defaultIncluded: false, portability: 'deviceSpecific', group: 'optional' },
18
+ ];
19
+ export class ExportFlow {
20
+ categories;
21
+ port;
22
+ onProgress;
23
+ constructor(opts) {
24
+ this.port = opts.port;
25
+ this.categories = opts.categories ?? DEFAULT_CATEGORIES;
26
+ this.onProgress = opts.onProgress;
27
+ }
28
+ /** Quick Export 推荐分区(defaultIncluded 且非 deviceSpecific) */
29
+ quickSelection() {
30
+ return this.categories.filter(isQuickRecommended).map((c) => c.id);
31
+ }
32
+ /** 按 §1 分组返回分类目录(Custom Export 树) */
33
+ groupedCatalog() {
34
+ return EXPORT_GROUPS.map((g) => ({
35
+ group: g.id,
36
+ label: g.label,
37
+ note: g.note,
38
+ categories: this.categories.filter((c) => c.group === g.id),
39
+ }));
40
+ }
41
+ /** 校验 Custom 勾选:未知分区 = invalid;deviceSpecific 分区给提示警告(仍可继续) */
42
+ validateSelection(selection) {
43
+ const warnings = [];
44
+ let valid = true;
45
+ const known = new Set(this.categories.map((c) => c.id));
46
+ for (const id of selection) {
47
+ if (!known.has(id)) {
48
+ warnings.push(`未知分区:${id}`);
49
+ valid = false;
50
+ }
51
+ }
52
+ for (const c of this.categories) {
53
+ if (selection.includes(c.id) && c.portability === 'deviceSpecific') {
54
+ warnings.push(`${c.label} 为设备相关数据(${c.portability}),跨设备导入时可能不适用`);
55
+ }
56
+ }
57
+ return { valid, warnings };
58
+ }
59
+ /** 执行导出:发进度事件 → 调 core → 渲染 §21 报告 */
60
+ async run(mode, selection, opts = {}) {
61
+ const tracker = new ProgressTracker(EXPORT_STAGES, this.onProgress);
62
+ const only = mode === 'quick' ? this.quickSelection() : [...selection];
63
+ if (mode === 'quick' && opts.includeSecrets === undefined)
64
+ opts = { ...opts, includeSecrets: false };
65
+ tracker.emit('analyzing');
66
+ tracker.emit('exporting-settings');
67
+ tracker.emit('scanning-secrets');
68
+ tracker.emit('exporting-plugins');
69
+ tracker.emit('creating-archive');
70
+ tracker.emit('calculating-checksums');
71
+ const result = await this.port.export({
72
+ includeSecrets: opts.includeSecrets ?? false,
73
+ only,
74
+ });
75
+ tracker.emit('done');
76
+ return { ...result, text: renderExportReport(result.report) };
77
+ }
78
+ }
79
+ //# sourceMappingURL=export-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-flow.js","sourceRoot":"","sources":["../../src/ui/export-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Import 向导状态机(规范 §9/§10/§28,m6-ui)。
3
+ *
4
+ * 步骤:Select ZIP → Analyzing → Compatibility → Import Preview → Resolve Conflicts
5
+ * → Path Mapping → Secrets → Importing → Result。
6
+ *
7
+ * 关键安全/正确性约束:
8
+ * - analyzeImport / createImportPlan 零写入(Dry Run 复用,规范 §10);
9
+ * - executeImportPlan 必须 confirm=true(core 安全阀),UI 在用户点「确认导入」后传入;
10
+ * - **显式传 rollbackOnError**:场景 E(§36)要求导入中途失败整体回滚,
11
+ * 本向导默认 rollbackOnError=true,UI 可在执行前让用户选择(true=整体回滚 / false=单项失败继续 §34.17);
12
+ * - 秘密补录值仅内存(secretInputs),绝不落日志/落盘。
13
+ */
14
+ import type { GlobalConflictStrategy, ImportAnalysis, ImportPlan, ImportResult, PathMapping, PlanItem } from '../core/types.ts';
15
+ import type { ImportPort, ImportPreviewSummary, ImportStep, ProgressListener, WizardSnapshot } from './types.ts';
16
+ export interface ImportWizardOptions {
17
+ port: ImportPort;
18
+ onProgress?: ProgressListener;
19
+ /** 默认回滚策略(场景 E:true=整体回滚;UI 可在执行前覆盖) */
20
+ defaultRollbackOnError?: boolean;
21
+ }
22
+ export declare class ImportWizard {
23
+ private readonly port;
24
+ private readonly onProgress;
25
+ private readonly tracker;
26
+ private step;
27
+ private zipPath;
28
+ private analysis;
29
+ private plan;
30
+ private result;
31
+ private rollbackOnError;
32
+ private errors;
33
+ private decisions;
34
+ private secretInputs;
35
+ constructor(opts: ImportWizardOptions);
36
+ /** 当前状态快照(React 绑定 / 测试断言用) */
37
+ snapshot(): WizardSnapshot;
38
+ get currentStep(): ImportStep;
39
+ /** 步骤 1-2:选 ZIP → Analyzing → Compatibility(analyzeImport 零写入) */
40
+ selectZip(path: string): Promise<ImportAnalysis>;
41
+ /** 步骤 3→4:用户确认兼容性后进入 Preview(Dry Run:用当前决策生成计划摘要,零写入) */
42
+ confirmCompatibility(): Promise<ImportPlan>;
43
+ /** 更新全局冲突策略(merge/replace/skipExisting,规范 §11) */
44
+ setStrategy(strategy: GlobalConflictStrategy): void;
45
+ /** 设置逐项冲突决策(keepCurrent/useImported/review) */
46
+ setResolutions(resolutions: Record<string, 'keepCurrent' | 'useImported' | 'review'>): void;
47
+ /** 设置路径映射(§12) */
48
+ setPathMappings(mappings: PathMapping[]): void;
49
+ /** 设置秘密补录值(仅内存,绝不持久化) */
50
+ setSecretInputs(inputs: Record<string, string>): void;
51
+ /** Preview 摘要(规范 §10 数值化;基于当前 plan 与 analysis) */
52
+ previewSummary(): ImportPreviewSummary;
53
+ /** 冲突项(供 ConflictCollector 使用) */
54
+ conflictItems(): PlanItem[];
55
+ /** 设置回滚策略(场景 E 选择;执行前调用) */
56
+ setRollbackOnError(enable: boolean): void;
57
+ /**
58
+ * 步骤 10-14:确认导入 → 快照 → 执行 → 校验 → 结果。
59
+ * 用最终决策重建计划(与预览一致),显式传 rollbackOnError。
60
+ */
61
+ execute(opts: {
62
+ confirm: boolean;
63
+ rollbackOnError?: boolean;
64
+ }): Promise<ImportResult>;
65
+ /** 重置向导(可复用实例开始新导入) */
66
+ reset(): void;
67
+ }
@@ -0,0 +1,169 @@
1
+ import { IMPORT_STAGES, ProgressTracker } from "./progress.js";
2
+ import { formatActionableError, toActionableError } from "./errors.js";
3
+ export class ImportWizard {
4
+ port;
5
+ onProgress;
6
+ tracker;
7
+ step = 'select';
8
+ zipPath = null;
9
+ analysis = null;
10
+ plan = null;
11
+ result = null;
12
+ rollbackOnError;
13
+ errors = [];
14
+ decisions = {
15
+ strategy: 'merge',
16
+ resolutions: {},
17
+ pathMappings: [],
18
+ };
19
+ secretInputs = {};
20
+ constructor(opts) {
21
+ this.port = opts.port;
22
+ this.onProgress = opts.onProgress;
23
+ this.tracker = new ProgressTracker(IMPORT_STAGES, this.onProgress);
24
+ this.rollbackOnError = opts.defaultRollbackOnError ?? true;
25
+ }
26
+ /** 当前状态快照(React 绑定 / 测试断言用) */
27
+ snapshot() {
28
+ return {
29
+ step: this.step,
30
+ zipPath: this.zipPath,
31
+ analysis: this.analysis,
32
+ plan: this.plan,
33
+ result: this.result,
34
+ rollbackOnError: this.rollbackOnError,
35
+ errors: [...this.errors],
36
+ };
37
+ }
38
+ get currentStep() {
39
+ return this.step;
40
+ }
41
+ /** 步骤 1-2:选 ZIP → Analyzing → Compatibility(analyzeImport 零写入) */
42
+ async selectZip(path) {
43
+ this.zipPath = path;
44
+ this.step = 'analyzing';
45
+ this.tracker.emit('validating');
46
+ this.errors = [];
47
+ try {
48
+ this.analysis = await this.port.analyzeImport(path);
49
+ this.tracker.emit('checking-compatibility');
50
+ if (!this.analysis.valid) {
51
+ // 分析失败(完整性/schema/兼容性):错误进 errors,UI 停在失败态
52
+ this.errors.push(...this.analysis.errors.map((e) => formatActionableError(toActionableError(new Error(e)))));
53
+ throw new Error(this.analysis.errors.join('; ') || '备份分析失败');
54
+ }
55
+ this.step = 'compatibility';
56
+ return this.analysis;
57
+ }
58
+ catch (err) {
59
+ // 仅当尚未记录分析错误时才追加(避免重复)
60
+ if (this.errors.length === 0) {
61
+ this.errors.push(formatActionableError(toActionableError(err)));
62
+ }
63
+ throw err;
64
+ }
65
+ }
66
+ /** 步骤 3→4:用户确认兼容性后进入 Preview(Dry Run:用当前决策生成计划摘要,零写入) */
67
+ async confirmCompatibility() {
68
+ if (this.analysis === null || this.zipPath === null) {
69
+ throw new Error('尚未完成分析,请先选择备份文件');
70
+ }
71
+ this.plan = await this.port.createImportPlan(this.zipPath, this.decisions);
72
+ this.step = 'preview';
73
+ return this.plan;
74
+ }
75
+ /** 更新全局冲突策略(merge/replace/skipExisting,规范 §11) */
76
+ setStrategy(strategy) {
77
+ this.decisions = { ...this.decisions, strategy };
78
+ }
79
+ /** 设置逐项冲突决策(keepCurrent/useImported/review) */
80
+ setResolutions(resolutions) {
81
+ this.decisions = { ...this.decisions, resolutions };
82
+ }
83
+ /** 设置路径映射(§12) */
84
+ setPathMappings(mappings) {
85
+ this.decisions = { ...this.decisions, pathMappings: mappings };
86
+ }
87
+ /** 设置秘密补录值(仅内存,绝不持久化) */
88
+ setSecretInputs(inputs) {
89
+ this.secretInputs = inputs;
90
+ }
91
+ /** Preview 摘要(规范 §10 数值化;基于当前 plan 与 analysis) */
92
+ previewSummary() {
93
+ const items = this.plan?.items ?? [];
94
+ const analysis = this.analysis;
95
+ const count = (kinds) => items.filter((i) => kinds.includes(i.kind)).length;
96
+ return {
97
+ willChange: count(['Create', 'Update', 'Install', 'Conflict']),
98
+ unchanged: count(['Skip']),
99
+ settingsUpdates: count(['Create', 'Update']),
100
+ pluginsInstalled: analysis?.pluginSummary.installed ?? 0,
101
+ pluginsToInstall: count(['Install']),
102
+ mcpAdds: items.filter((i) => i.adapter === 'mcp' && i.kind === 'Create').length,
103
+ prompts: items.filter((i) => i.adapter === 'prompts' && i.kind !== 'Skip').length,
104
+ pathMappingsNeeded: analysis?.pathIssues.length ?? 0,
105
+ secretsNeeded: this.plan?.missingSecrets.length ?? analysis?.secretCount ?? 0,
106
+ conflicts: count(['Conflict']),
107
+ needsRestart: this.plan?.needsRestart ?? false,
108
+ };
109
+ }
110
+ /** 冲突项(供 ConflictCollector 使用) */
111
+ conflictItems() {
112
+ return (this.plan?.items ?? []).filter((i) => i.kind === 'Conflict');
113
+ }
114
+ /** 设置回滚策略(场景 E 选择;执行前调用) */
115
+ setRollbackOnError(enable) {
116
+ this.rollbackOnError = enable;
117
+ }
118
+ /**
119
+ * 步骤 10-14:确认导入 → 快照 → 执行 → 校验 → 结果。
120
+ * 用最终决策重建计划(与预览一致),显式传 rollbackOnError。
121
+ */
122
+ async execute(opts) {
123
+ if (this.zipPath === null || this.analysis === null) {
124
+ throw new Error('尚未完成分析,请先选择备份文件');
125
+ }
126
+ if (opts.confirm !== true) {
127
+ throw new Error('导入未确认:必须确认后才允许修改任何数据');
128
+ }
129
+ const rollbackOnError = opts.rollbackOnError ?? this.rollbackOnError;
130
+ this.step = 'importing';
131
+ this.tracker.emit('creating-snapshot');
132
+ try {
133
+ // 用最终决策重建计划(与预览逻辑一致,保证 Dry Run 与真实导入一致)
134
+ this.plan = await this.port.createImportPlan(this.zipPath, this.decisions);
135
+ this.tracker.emit('restoring-settings');
136
+ this.tracker.emit('restoring-plugins');
137
+ this.tracker.emit('restoring-mcp');
138
+ this.tracker.emit('validating-config');
139
+ this.result = await this.port.executeImportPlan(this.zipPath, this.plan, {
140
+ confirm: true,
141
+ secretInputs: this.secretInputs,
142
+ rollbackOnError,
143
+ });
144
+ // 失败且已整体回滚(场景 E)→ 报告回滚阶段
145
+ if (!this.result.ok && this.result.rollback) {
146
+ this.tracker.emit('rolling-back');
147
+ }
148
+ this.tracker.emit('done');
149
+ this.step = 'result';
150
+ return this.result;
151
+ }
152
+ catch (err) {
153
+ this.errors.push(formatActionableError(toActionableError(err)));
154
+ throw err;
155
+ }
156
+ }
157
+ /** 重置向导(可复用实例开始新导入) */
158
+ reset() {
159
+ this.step = 'select';
160
+ this.zipPath = null;
161
+ this.analysis = null;
162
+ this.plan = null;
163
+ this.result = null;
164
+ this.errors = [];
165
+ this.decisions = { strategy: 'merge', resolutions: {}, pathMappings: [] };
166
+ this.secretInputs = {};
167
+ }
168
+ }
169
+ //# sourceMappingURL=import-wizard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-wizard.js","sourceRoot":"","sources":["../../src/ui/import-wizard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * 路径映射编辑器(规范 §12,m6-ui)。
3
+ *
4
+ * 两种形态(§12 批量映射优先):
5
+ * - 单项映射:某条具体 PathIssue(如 workspace 绝对路径)→ 新路径;
6
+ * - 批量前缀映射:oldPrefix → newPrefix,一次替换全部相关路径。
7
+ *
8
+ * 输出 core PathMapping[]:newPrefix 非空的映射才进入执行计划
9
+ * (core mergePathMappings 只保留已解析映射;未解析项保留在 plan.items 供 UI 提示)。
10
+ * 应用范围 appliesTo 缺省 [](全部相关分区),与 core applyMappingsToSections 语义一致。
11
+ */
12
+ import type { PathIssue, PathMapping } from '../core/types.ts';
13
+ import type { PathMappingAppliesTo, PathMappingDraft } from './types.ts';
14
+ export interface PathMappingEditorOptions {
15
+ /** 从分析结果得到的路径问题 */
16
+ issues?: PathIssue[];
17
+ /** 预置映射(如上次导入可复用的映射) */
18
+ existing?: PathMapping[];
19
+ }
20
+ export declare class PathMappingEditor {
21
+ private readonly issues;
22
+ private drafts;
23
+ constructor(opts?: PathMappingEditorOptions);
24
+ /** 全部草稿(含未解析) */
25
+ get all(): PathMappingDraft[];
26
+ /** 已解析(newPrefix 非空)的草稿 */
27
+ get resolved(): PathMappingDraft[];
28
+ /** 未解析的问题(UI 需提示用户选择文件夹;按「是否被已解析映射覆盖」判断,批量前缀映射一次覆盖多条) */
29
+ get unresolved(): PathIssue[];
30
+ /** 单项/批量设置映射(oldPrefix 已存在则更新;否则新建批量映射) */
31
+ setMapping(oldPrefix: string, newPrefix: string, appliesTo?: PathMappingAppliesTo[]): void;
32
+ /** 对某个具体值应用当前映射,返回替换结果(预览用;无映射则原样返回) */
33
+ preview(value: string): string;
34
+ /** 未解析项是否可进入执行(false = 有路径问题未解决) */
35
+ get isComplete(): boolean;
36
+ /** 输出 core PathMapping[](仅已解析项) */
37
+ toPathMappings(): PathMapping[];
38
+ }
@@ -0,0 +1,75 @@
1
+ import { applyPrefixMappings } from "../utils/paths.js";
2
+ export class PathMappingEditor {
3
+ issues;
4
+ drafts = new Map();
5
+ constructor(opts = {}) {
6
+ this.issues = opts.issues ?? [];
7
+ for (const issue of this.issues) {
8
+ this.drafts.set(issue.value, {
9
+ oldPrefix: issue.value,
10
+ newPrefix: issue.mappedTo ?? '',
11
+ issue,
12
+ appliesTo: [],
13
+ });
14
+ }
15
+ // 批量映射按 oldPrefix 聚合(一个 oldPrefix 一条 draft)
16
+ for (const m of opts.existing ?? []) {
17
+ const prev = this.drafts.get(m.oldPrefix);
18
+ this.drafts.set(m.oldPrefix, {
19
+ oldPrefix: m.oldPrefix,
20
+ newPrefix: m.newPrefix,
21
+ appliesTo: [...m.appliesTo],
22
+ });
23
+ void prev;
24
+ }
25
+ }
26
+ /** 全部草稿(含未解析) */
27
+ get all() {
28
+ return [...this.drafts.values()];
29
+ }
30
+ /** 已解析(newPrefix 非空)的草稿 */
31
+ get resolved() {
32
+ return this.all.filter((d) => d.newPrefix !== '');
33
+ }
34
+ /** 未解析的问题(UI 需提示用户选择文件夹;按「是否被已解析映射覆盖」判断,批量前缀映射一次覆盖多条) */
35
+ get unresolved() {
36
+ const mappings = this.toPathMappings();
37
+ return (this.issues ?? []).filter((issue) => {
38
+ const mapped = applyPrefixMappings(issue.value, mappings);
39
+ return mapped === issue.value;
40
+ });
41
+ }
42
+ /** 单项/批量设置映射(oldPrefix 已存在则更新;否则新建批量映射) */
43
+ setMapping(oldPrefix, newPrefix, appliesTo = []) {
44
+ const existing = this.drafts.get(oldPrefix);
45
+ this.drafts.set(oldPrefix, {
46
+ oldPrefix,
47
+ newPrefix,
48
+ appliesTo,
49
+ issue: existing?.issue,
50
+ });
51
+ }
52
+ /** 对某个具体值应用当前映射,返回替换结果(预览用;无映射则原样返回) */
53
+ preview(value) {
54
+ const resolved = this.resolved.map((d) => ({
55
+ oldPrefix: d.oldPrefix,
56
+ newPrefix: d.newPrefix,
57
+ appliesTo: d.appliesTo,
58
+ }));
59
+ const mapped = applyPrefixMappings(value, resolved);
60
+ return typeof mapped === 'string' ? mapped : value;
61
+ }
62
+ /** 未解析项是否可进入执行(false = 有路径问题未解决) */
63
+ get isComplete() {
64
+ return this.unresolved.length === 0;
65
+ }
66
+ /** 输出 core PathMapping[](仅已解析项) */
67
+ toPathMappings() {
68
+ return this.resolved.map((d) => ({
69
+ oldPrefix: d.oldPrefix,
70
+ newPrefix: d.newPrefix,
71
+ appliesTo: d.appliesTo,
72
+ }));
73
+ }
74
+ }
75
+ //# sourceMappingURL=path-mapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-mapping.js","sourceRoot":"","sources":["../../src/ui/path-mapping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 进度阶段文案与进度追踪(规范 §29,m6-ui)。
3
+ *
4
+ * 纯文本层:每个阶段 id 有默认文案;未知阶段回退显示 id 本身。
5
+ * ProgressTracker 供导出/导入控制器在调用 core 前后发出阶段事件(UI 不冻结)。
6
+ */
7
+ import type { ProgressListener } from './types.ts';
8
+ /** 导出阶段文案(规范 §29 Export 示例) */
9
+ export declare const EXPORT_STAGES: readonly string[];
10
+ /** 导入阶段文案(规范 §29 Import 示例 + 快照/回滚阶段) */
11
+ export declare const IMPORT_STAGES: readonly string[];
12
+ /** 阶段 id → 用户可读文案(未知阶段回退 id) */
13
+ export declare function stageText(stage: string): string;
14
+ /**
15
+ * 进度追踪器:按给定阶段序列在回调时附带 step/total 序号。
16
+ * 控制器调用 core 前后 emit(),UI 侧渲染进度条/阶段文字。
17
+ */
18
+ export declare class ProgressTracker {
19
+ private readonly listener;
20
+ private readonly stages;
21
+ private readonly emitted;
22
+ constructor(stages: readonly string[], listener?: ProgressListener);
23
+ /** 发出某阶段事件(可携带 detail);未在序列中的阶段 step/total 缺省 */
24
+ emit(stage: string, detail?: string): void;
25
+ /** 已发出阶段的快照(测试与日志用) */
26
+ get events(): readonly string[];
27
+ }
@@ -0,0 +1,76 @@
1
+ /** 导出阶段文案(规范 §29 Export 示例) */
2
+ export const EXPORT_STAGES = [
3
+ 'analyzing', // Analyzing configuration...
4
+ 'exporting-settings', // Exporting settings...
5
+ 'scanning-secrets', // Scanning secrets...
6
+ 'exporting-plugins', // Exporting plugins...
7
+ 'creating-archive', // Creating archive...
8
+ 'calculating-checksums', // Calculating checksums...
9
+ 'done',
10
+ ];
11
+ /** 导入阶段文案(规范 §29 Import 示例 + 快照/回滚阶段) */
12
+ export const IMPORT_STAGES = [
13
+ 'validating', // Validating backup...
14
+ 'checking-compatibility', // Checking compatibility...
15
+ 'creating-snapshot', // Creating safety snapshot...
16
+ 'restoring-settings', // Restoring settings...
17
+ 'restoring-plugins', // Restoring plugins...
18
+ 'restoring-mcp', // Restoring MCP...
19
+ 'validating-config', // Validating configuration...
20
+ 'rolling-back', // Rolling back...(仅失败回滚时)
21
+ 'done',
22
+ ];
23
+ const STAGE_TEXTS = {
24
+ // export
25
+ 'analyzing': 'Analyzing configuration...',
26
+ 'exporting-settings': 'Exporting settings...',
27
+ 'scanning-secrets': 'Scanning secrets...',
28
+ 'exporting-plugins': 'Exporting plugins...',
29
+ 'creating-archive': 'Creating archive...',
30
+ 'calculating-checksums': 'Calculating checksums...',
31
+ // import
32
+ 'validating': 'Validating backup...',
33
+ 'checking-compatibility': 'Checking compatibility...',
34
+ 'creating-snapshot': 'Creating safety snapshot...',
35
+ 'restoring-settings': 'Restoring settings...',
36
+ 'restoring-plugins': 'Restoring plugins...',
37
+ 'restoring-mcp': 'Restoring MCP...',
38
+ 'validating-config': 'Validating configuration...',
39
+ 'rolling-back': 'Rolling back...',
40
+ // common
41
+ 'done': 'Done',
42
+ };
43
+ /** 阶段 id → 用户可读文案(未知阶段回退 id) */
44
+ export function stageText(stage) {
45
+ return STAGE_TEXTS[stage] ?? stage;
46
+ }
47
+ /**
48
+ * 进度追踪器:按给定阶段序列在回调时附带 step/total 序号。
49
+ * 控制器调用 core 前后 emit(),UI 侧渲染进度条/阶段文字。
50
+ */
51
+ export class ProgressTracker {
52
+ listener;
53
+ stages;
54
+ emitted = [];
55
+ constructor(stages, listener) {
56
+ this.stages = stages;
57
+ this.listener = listener;
58
+ }
59
+ /** 发出某阶段事件(可携带 detail);未在序列中的阶段 step/total 缺省 */
60
+ emit(stage, detail) {
61
+ const idx = this.stages.indexOf(stage);
62
+ const event = {
63
+ stage,
64
+ detail,
65
+ step: idx >= 0 ? idx + 1 : undefined,
66
+ total: idx >= 0 ? this.stages.length : undefined,
67
+ };
68
+ this.emitted.push(stage);
69
+ this.listener?.(event);
70
+ }
71
+ /** 已发出阶段的快照(测试与日志用) */
72
+ get events() {
73
+ return [...this.emitted];
74
+ }
75
+ }
76
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../src/ui/progress.ts"],"names":[],"mappings":"AAQA,+BAA+B;AAC/B,MAAM,CAAC,MAAM,aAAa,GAAsB;IAC9C,WAAW,EAAY,6BAA6B;IACpD,oBAAoB,EAAG,wBAAwB;IAC/C,kBAAkB,EAAK,sBAAsB;IAC7C,mBAAmB,EAAI,uBAAuB;IAC9C,kBAAkB,EAAK,sBAAsB;IAC7C,uBAAuB,EAAE,2BAA2B;IACpD,MAAM;CACE,CAAC;AAEX,yCAAyC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAsB;IAC9C,YAAY,EAAW,uBAAuB;IAC9C,wBAAwB,EAAE,4BAA4B;IACtD,mBAAmB,EAAI,8BAA8B;IACrD,oBAAoB,EAAG,wBAAwB;IAC/C,mBAAmB,EAAI,uBAAuB;IAC9C,eAAe,EAAQ,mBAAmB;IAC1C,mBAAmB,EAAI,8BAA8B;IACrD,cAAc,EAAS,0BAA0B;IACjD,MAAM;CACE,CAAC;AAEX,MAAM,WAAW,GAA2B;IAC1C,SAAS;IACT,WAAW,EAAE,4BAA4B;IACzC,oBAAoB,EAAE,uBAAuB;IAC7C,kBAAkB,EAAE,qBAAqB;IACzC,mBAAmB,EAAE,sBAAsB;IAC3C,kBAAkB,EAAE,qBAAqB;IACzC,uBAAuB,EAAE,0BAA0B;IACnD,SAAS;IACT,YAAY,EAAE,sBAAsB;IACpC,wBAAwB,EAAE,2BAA2B;IACrD,mBAAmB,EAAE,6BAA6B;IAClD,oBAAoB,EAAE,uBAAuB;IAC7C,mBAAmB,EAAE,sBAAsB;IAC3C,eAAe,EAAE,kBAAkB;IACnC,mBAAmB,EAAE,6BAA6B;IAClD,cAAc,EAAE,iBAAiB;IACjC,SAAS;IACT,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,gCAAgC;AAChC,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,eAAe;IACT,QAAQ,CAA+B;IACvC,MAAM,CAAoB;IAC1B,OAAO,GAAa,EAAE,CAAC;IAExC,YAAY,MAAyB,EAAE,QAA2B;QAChE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,iDAAiD;IACjD,IAAI,CAAC,KAAa,EAAE,MAAe;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,KAAK,GAAkB;YAC3B,KAAK;YACL,MAAM;YACN,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;YACpC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACjD,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,uBAAuB;IACvB,IAAI,MAAM;QACR,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;CACF"}