dsh-config-manager 0.2.4 → 0.3.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 (129) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/lib/adapters/self.d.ts +44 -4
  4. package/lib/adapters/self.js +63 -3
  5. package/lib/client.d.ts +11 -6
  6. package/lib/client.js +1263 -1192
  7. package/lib/core/analyzer.d.ts +3 -0
  8. package/lib/core/analyzer.js +32 -56
  9. package/lib/core/backup.d.ts +36 -0
  10. package/lib/core/backup.js +125 -3
  11. package/lib/core/import-defaults.d.ts +13 -0
  12. package/lib/core/import-defaults.js +14 -0
  13. package/lib/core/importer.d.ts +10 -1
  14. package/lib/core/importer.js +7 -1
  15. package/lib/core/messages.d.ts +4 -0
  16. package/lib/core/messages.js +8 -0
  17. package/lib/core/model-tools.js +19 -3
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js +12 -22
  20. package/lib/routes/import.js +3 -1
  21. package/lib/routes/recovery.js +226 -2
  22. package/lib/routes/sync.js +26 -7
  23. package/lib/security/integrity.d.ts +24 -0
  24. package/lib/security/integrity.js +30 -0
  25. package/lib/security/unverified-file-blocks.d.ts +73 -0
  26. package/lib/security/unverified-file-blocks.js +151 -0
  27. package/lib/sync/autosync-config.d.ts +8 -4
  28. package/lib/sync/autosync-config.js +2 -2
  29. package/lib/sync/autosync-scheduler.d.ts +61 -3
  30. package/lib/sync/autosync-scheduler.js +87 -10
  31. package/lib/sync/config-issue-reporting.d.ts +32 -0
  32. package/lib/sync/config-issue-reporting.js +63 -0
  33. package/lib/sync/gc-skip.d.ts +42 -0
  34. package/lib/sync/gc-skip.js +57 -0
  35. package/lib/sync/git/git-transport.d.ts +10 -0
  36. package/lib/sync/git/git-transport.js +72 -14
  37. package/lib/sync/merge-preview-text.d.ts +11 -0
  38. package/lib/sync/merge-preview-text.js +38 -0
  39. package/lib/sync/s3/s3-transport.d.ts +8 -1
  40. package/lib/sync/s3/s3-transport.js +19 -5
  41. package/lib/sync/session-tombstones.d.ts +53 -0
  42. package/lib/sync/session-tombstones.js +52 -0
  43. package/lib/sync/sync-config.d.ts +55 -5
  44. package/lib/sync/sync-config.js +188 -15
  45. package/lib/sync/sync-engine.d.ts +21 -7
  46. package/lib/sync/sync-engine.js +63 -85
  47. package/lib/sync/webdav/webdav-transport.d.ts +11 -1
  48. package/lib/sync/webdav/webdav-transport.js +22 -6
  49. package/lib/ui/i18n.js +56 -36
  50. package/lib/ui/import-wizard.d.ts +1 -1
  51. package/lib/ui/import-wizard.js +2 -1
  52. package/lib/ui/overview-view.d.ts +6 -2
  53. package/lib/ui/overview-view.js +8 -1
  54. package/lib/ui/report.js +2 -1
  55. package/package.json +2 -2
  56. package/src/adapters/self.test.ts +126 -85
  57. package/src/adapters/self.ts +73 -6
  58. package/src/client/ConfigManagerSection.tsx +0 -3
  59. package/src/client/common/Icon.tsx +3 -0
  60. package/src/client/common/SectionComposition.tsx +6 -1
  61. package/src/client/common/info-hint-guard.test.ts +7 -5
  62. package/src/client/config-manager.module.css +254 -13
  63. package/src/client/environment/EnvironmentPanel.tsx +57 -47
  64. package/src/client/environment/maintenance/DiskUsageCard.tsx +3 -1
  65. package/src/client/export/ExportView.tsx +3 -1
  66. package/src/client/home/HomePanel.tsx +25 -5
  67. package/src/client/import/ImportWizardView.tsx +1 -3
  68. package/src/client/import/import-wizard-steps.tsx +1 -17
  69. package/src/client/library/ArtifactRow.tsx +13 -2
  70. package/src/client/library/LibraryPanel.tsx +12 -2
  71. package/src/client/locales.ts +53 -34
  72. package/src/client/lucide-icons.d.ts +2 -0
  73. package/src/client/market/MarketPanel.tsx +12 -11
  74. package/src/client/market/market-locales.ts +16 -16
  75. package/src/client/recovery/RollbackCard.tsx +4 -2
  76. package/src/client/recovery/recovery-locales.test.ts +4 -2
  77. package/src/client/recovery/recovery-locales.ts +23 -23
  78. package/src/client/sync/AutosyncCard.tsx +36 -10
  79. package/src/client/sync/SyncChannelEntryCard.tsx +18 -19
  80. package/src/client/sync/SyncPanel.tsx +32 -33
  81. package/src/client/sync/SyncProbeRow.tsx +23 -6
  82. package/src/client/sync/SyncSectionPickerDialog.tsx +2 -2
  83. package/src/client/sync/sync-locales.ts +24 -24
  84. package/src/core/analyzer.ts +37 -56
  85. package/src/core/backup.test.ts +139 -1
  86. package/src/core/backup.ts +145 -4
  87. package/src/core/import-defaults.ts +13 -0
  88. package/src/core/importer.ts +12 -2
  89. package/src/core/integrity-extra-entries.test.ts +205 -0
  90. package/src/core/messages.test.ts +3 -1
  91. package/src/core/messages.ts +8 -0
  92. package/src/core/model-tools.test.ts +33 -0
  93. package/src/core/model-tools.ts +20 -4
  94. package/src/index.ts +12 -21
  95. package/src/routes/import.ts +4 -1
  96. package/src/routes/recovery.test.ts +198 -1
  97. package/src/routes/recovery.ts +194 -1
  98. package/src/routes/sync.ts +27 -8
  99. package/src/security/integrity.ts +37 -0
  100. package/src/security/unverified-file-blocks.ts +192 -0
  101. package/src/sync/autosync-config.ts +9 -5
  102. package/src/sync/autosync-scheduler.test.ts +133 -6
  103. package/src/sync/autosync-scheduler.ts +118 -14
  104. package/src/sync/config-issue-reporting.test.ts +148 -0
  105. package/src/sync/config-issue-reporting.ts +75 -0
  106. package/src/sync/gc-skip.test.ts +66 -0
  107. package/src/sync/gc-skip.ts +64 -0
  108. package/src/sync/git/git-probe.test.ts +3 -2
  109. package/src/sync/git/git-transport.test.ts +168 -7
  110. package/src/sync/git/git-transport.ts +70 -14
  111. package/src/sync/merge-preview-text.ts +37 -0
  112. package/src/sync/s3/s3-delete-index-404.test.ts +26 -1
  113. package/src/sync/s3/s3-transport.ts +23 -4
  114. package/src/sync/session-tombstones.ts +90 -0
  115. package/src/sync/sync-config.test.ts +170 -1
  116. package/src/sync/sync-config.ts +184 -14
  117. package/src/sync/sync-engine.test.ts +238 -0
  118. package/src/sync/sync-engine.ts +79 -83
  119. package/src/sync/webdav/webdav-delete-index-404.test.ts +29 -1
  120. package/src/sync/webdav/webdav-transport.ts +26 -5
  121. package/src/ui/disk-usage-view.test.ts +2 -1
  122. package/src/ui/i18n.test.ts +47 -0
  123. package/src/ui/i18n.ts +58 -38
  124. package/src/ui/import-wizard.test.ts +18 -1
  125. package/src/ui/import-wizard.ts +3 -2
  126. package/src/ui/overview-view.test.ts +9 -0
  127. package/src/ui/overview-view.ts +9 -2
  128. package/src/ui/report.test.ts +4 -3
  129. package/src/ui/report.ts +2 -1
package/README.md CHANGED
@@ -342,7 +342,7 @@ You do not have to rebuild another agent's setup by hand.
342
342
  - **What travels** — MCP servers, skills, global instructions (as `AGENTS.md`), and **chat history together with the workspaces those conversations belong to** (29 sources; conversations are re-encoded into DSH's session-log format and placed by their recorded `cwd`).
343
343
  - **What does not** — secret **values** are never read: only the key names are recorded so the plan can ask you to re-enter them. Structures DSH has no equivalent for (Claude Code hooks, slash commands, …) are reported as explicit codes rather than silently dropped.
344
344
  - **Honest skips** — a conversation with no recorded `cwd` cannot be placed and is reported as skipped (never guessed into some other project); known lossy items are listed **before** the import runs.
345
- - **Entry points** — Home toolbar → "Import" → **"Import from another agent"** (Home also has a direct entry), the ⌘K command, or the CLI: `dcm import --from <source> [--dry-run] [--out <path>]`.
345
+ - **Entry points** — the **"Import from another agent"** button on the home toolbar, the ⌘K command, or the CLI: `dcm import --from <source> [--dry-run] [--out <path>]`.
346
346
 
347
347
  ### 🔒 Secrets
348
348
 
package/README.zh-CN.md CHANGED
@@ -343,7 +343,7 @@ allowBuilds:
343
343
  - **会带走什么** —— MCP Servers、技能、全局指令(落成 `AGENTS.md`),以及**历史会话连同这些对话所属的工作区**(29 个来源;会话会重新编码成 DSH 的会话日志格式,并按它记录的 `cwd` 归位)。
344
344
  - **不会带走什么** —— 密钥**值**一律不读:只记录键名,由导入计划提示补录。DSH 没有对等结构的东西(Claude Code 的 hooks、斜杠命令等)会**报出明确的码**,不会静默丢掉。
345
345
  - **如实跳过** —— 没记录 `cwd` 的对话无处归位,会列为跳过(绝不猜进别的项目);已知的有损项在导入**之前**就摆明。
346
- - **入口** —— 首页工具栏「导入」→ 面板里的**「从其它 agent 导入」**(首页另有直达入口)、⌘K 的「从其它 agent 导入」,或 CLI:`dcm import --from <来源> [--dry-run] [--out <路径>]`。
346
+ - **入口** —— 首页工具栏的**「从其它 agent 导入」**按钮、⌘K 的「从其它 agent 导入」,或 CLI:`dcm import --from <来源> [--dry-run] [--out <路径>]`。
347
347
 
348
348
  ### 🔒 密钥处理
349
349
 
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * self 分区 adapter(插件自身配置,设计「self 分区」):
3
3
  * 数据源 = $DSH_HOME/dsh-config-manager/ 下的插件自身配置文件(白名单收集,非递归):
4
- * - sync/sync-config.json 同步通道配置(git repoUrl / webdav url+username;凭据值走 credentials 槽位,不含 secret)
5
- * - sync/sync-autosync.json 自动同步调度配置
6
4
  * - sync/sync-selection.json 同步分区选择(默认/高级模式 + 勾选分区)
7
5
  * - sync/ui-prefs.json 插件 UI 偏好(如上次选择的同步通道;从 localStorage 迁入)
6
+ * - sync/backup-schedule.json 备份调度配置
8
7
  * - market/market-config.json 配置市场配置
8
+ * - exports/.backup-notes.json 导出产物备注清单
9
+ *
10
+ * **可信边界(SEC-01)**:`sync/sync-config.json` 与 `sync/sync-autosync.json` 是「同步目标」本身,
11
+ * 永不可由**包**决定 —— 一个把 repoUrl 指向攻击者仓库的包,导入完用户下一次同步就把家目录配置
12
+ * 推过去。它们不在白名单里(不导出),导入侧另由 `SELF_IMPORT_BLOCKED_RELS` 显式挡下并留 warning。
9
13
  *
10
14
  * 排除项:sync/sync-history.json(执行记录,属数据非配置)、market/cache/(缓存)、
11
15
  * snapshots/(快照)、tmp/ exports/(临时/导出产物)、rollback-points/(回滚点库——磁盘体检
@@ -44,13 +48,34 @@
44
48
  * 安全不变量:配置文件本身不含凭据值(同步凭据走 DSH credentials 槽位引用),
45
49
  * 且文件类分区不进 SecretScanner(与 pluginFiles/skills 同语义)。
46
50
  */
47
- import type { HostContext } from '../core/types.ts';
51
+ import type { ApplyResult, HostContext, ImportContext, PlanItem } from '../core/types.ts';
52
+ import type { FilesSection } from '../schema/types.ts';
48
53
  import type { AutosyncConfig } from '../sync/autosync-config.ts';
49
54
  import type { BackupScheduleConfig } from '../sync/backup-schedule-config.ts';
50
55
  import type { RecursiveListing } from '../utils/recursive-walk.ts';
51
56
  import { FileCollectionAdapter } from './file-collection.ts';
52
- /** self 分区白名单文件(相对 baseDir,即 $DSH_HOME/dsh-config-manager/)。 */
57
+ /**
58
+ * self 分区白名单文件(相对 baseDir,即 $DSH_HOME/dsh-config-manager/)。
59
+ *
60
+ * `sync/sync-config.json` 与 `sync/sync-autosync.json` **不在其中**(SEC-01):同步目标与自动同步开关
61
+ * 属于「目标机自己的决定」,跨机搬运等于让包决定把本机配置推到哪里。白名单只管导出侧;
62
+ * 导入侧的包内容不受白名单约束,所以另有 `SELF_IMPORT_BLOCKED_RELS` 显式挡下。
63
+ */
53
64
  export declare const SELF_CONFIG_FILES: readonly string[];
65
+ /**
66
+ * 导入侧**一律不写盘**的 rel(SEC-01)。
67
+ *
68
+ * 与白名单的关系:白名单管「导出带什么」,本清单管「包里有也绝不落地」。两者故意不共用一份
69
+ * 数组 —— 白名单将来若因别的理由重新收进某个文件,也不该连带解除导入侧的保护。
70
+ */
71
+ export declare const SELF_IMPORT_BLOCKED_RELS: readonly string[];
72
+ /**
73
+ * 拦截报告项里的**稳定机器码**前缀(`self-import-blocked:<rel>`)。
74
+ *
75
+ * 为什么要有码而不是只给文案:文案随语言/措辞变,调用方(报告、日志、将来的自动判定)需要
76
+ * 一个能逐字比对的判据。
77
+ */
78
+ export declare const SELF_IMPORT_BLOCKED_CODE = "self-import-blocked";
54
79
  /**
55
80
  * 调度配置里「运行态字段」的**命名口径**:调度器每轮收尾都会改写的字段名形状
56
81
  * (`lastRun*` 一族 + `consecutiveFailures`)。剔除表必须覆盖两个调度配置的并集,
@@ -120,5 +145,20 @@ export declare class SelfAdapter extends FileCollectionAdapter {
120
145
  * 解析不出 JSON 时原样返回 —— 「判不出来」按整文件哈希处理,绝不猜。
121
146
  */
122
147
  protected comparableContent(relativePath: string, data: Uint8Array): Uint8Array;
148
+ /**
149
+ * 导入侧拦截(SEC-01):包里带 `sync/sync-config.json` / `sync/sync-autosync.json` → 改判 Warning。
150
+ *
151
+ * 为什么必须在**计划阶段**改判而不是只在 applyItem 里拒绝:这两份文件是「同步目标」本身,
152
+ * 一个把 repoUrl 指向攻击者仓库的包,导入完用户下一次同步就会把本机配置推过去 —— 而用户
153
+ * 从来没被问过「要不要换同步目标」。去掉 `target` 后引擎不会为它登记快照、也不会调 applyItem;
154
+ * 同时留下一项 report 级 warning(带稳定码 `self-import-blocked:<rel>`),让用户看得见
155
+ * 「包里有这个文件、我没写」,绝不静默。
156
+ */
157
+ analyzeImport(data: FilesSection, ctx: ImportContext): Promise<PlanItem[]>;
158
+ /**
159
+ * 纵深防御(SEC-01):即使有人绕过引擎直接把被拦项喂进 applyItem,也一字节都不写。
160
+ * 报 warning=true(非致命、不触发整体回滚),与计划阶段的判定同源。
161
+ */
162
+ applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
123
163
  }
124
164
  export {};
@@ -1,9 +1,13 @@
1
1
  import { sectionMeta } from '../schema/section-registry.js';
2
2
  import { FileCollectionAdapter } from './file-collection.js';
3
- /** self 分区白名单文件(相对 baseDir,即 $DSH_HOME/dsh-config-manager/)。 */
3
+ /**
4
+ * self 分区白名单文件(相对 baseDir,即 $DSH_HOME/dsh-config-manager/)。
5
+ *
6
+ * `sync/sync-config.json` 与 `sync/sync-autosync.json` **不在其中**(SEC-01):同步目标与自动同步开关
7
+ * 属于「目标机自己的决定」,跨机搬运等于让包决定把本机配置推到哪里。白名单只管导出侧;
8
+ * 导入侧的包内容不受白名单约束,所以另有 `SELF_IMPORT_BLOCKED_RELS` 显式挡下。
9
+ */
4
10
  export const SELF_CONFIG_FILES = [
5
- 'sync/sync-config.json',
6
- 'sync/sync-autosync.json',
7
11
  'sync/sync-selection.json',
8
12
  'sync/ui-prefs.json',
9
13
  'sync/backup-schedule.json',
@@ -12,6 +16,23 @@ export const SELF_CONFIG_FILES = [
12
16
  // 换机器后备份列表仍能看到手动导出时填写的备注
13
17
  'exports/.backup-notes.json',
14
18
  ];
19
+ /**
20
+ * 导入侧**一律不写盘**的 rel(SEC-01)。
21
+ *
22
+ * 与白名单的关系:白名单管「导出带什么」,本清单管「包里有也绝不落地」。两者故意不共用一份
23
+ * 数组 —— 白名单将来若因别的理由重新收进某个文件,也不该连带解除导入侧的保护。
24
+ */
25
+ export const SELF_IMPORT_BLOCKED_RELS = [
26
+ 'sync/sync-config.json',
27
+ 'sync/sync-autosync.json',
28
+ ];
29
+ /**
30
+ * 拦截报告项里的**稳定机器码**前缀(`self-import-blocked:<rel>`)。
31
+ *
32
+ * 为什么要有码而不是只给文案:文案随语言/措辞变,调用方(报告、日志、将来的自动判定)需要
33
+ * 一个能逐字比对的判据。
34
+ */
35
+ export const SELF_IMPORT_BLOCKED_CODE = "self-import-blocked";
15
36
  /**
16
37
  * 调度配置里的**运行态字段**:每次执行收尾都会被调度器改写,不属于「配置身份」。
17
38
  * 仅比对时剔除(见 comparableContent);写盘仍写完整文件。
@@ -149,5 +170,44 @@ export class SelfAdapter extends FileCollectionAdapter {
149
170
  // 回落原引用(解析失败 / 非对象):走整文件哈希,且不额外重算包内哈希
150
171
  return canonicalizeWithoutRunState(data) ?? data;
151
172
  }
173
+ /**
174
+ * 导入侧拦截(SEC-01):包里带 `sync/sync-config.json` / `sync/sync-autosync.json` → 改判 Warning。
175
+ *
176
+ * 为什么必须在**计划阶段**改判而不是只在 applyItem 里拒绝:这两份文件是「同步目标」本身,
177
+ * 一个把 repoUrl 指向攻击者仓库的包,导入完用户下一次同步就会把本机配置推过去 —— 而用户
178
+ * 从来没被问过「要不要换同步目标」。去掉 `target` 后引擎不会为它登记快照、也不会调 applyItem;
179
+ * 同时留下一项 report 级 warning(带稳定码 `self-import-blocked:<rel>`),让用户看得见
180
+ * 「包里有这个文件、我没写」,绝不静默。
181
+ */
182
+ async analyzeImport(data, ctx) {
183
+ const items = await super.analyzeImport(data, ctx);
184
+ return items.map((item) => {
185
+ const rel = item.target?.ref;
186
+ if (rel === undefined || !SELF_IMPORT_BLOCKED_RELS.includes(rel))
187
+ return item;
188
+ const blocked = {
189
+ id: item.id,
190
+ kind: 'Warning',
191
+ adapter: this.id,
192
+ description: ctx.msg('adapter.selfImportBlocked', { path: rel }),
193
+ detail: `${SELF_IMPORT_BLOCKED_CODE}:${rel}`,
194
+ severity: 'warning',
195
+ };
196
+ if (item.unitId !== undefined)
197
+ blocked.unitId = item.unitId;
198
+ return blocked;
199
+ });
200
+ }
201
+ /**
202
+ * 纵深防御(SEC-01):即使有人绕过引擎直接把被拦项喂进 applyItem,也一字节都不写。
203
+ * 报 warning=true(非致命、不触发整体回滚),与计划阶段的判定同源。
204
+ */
205
+ async applyItem(item, ctx) {
206
+ const ref = item.target?.ref;
207
+ if (ref !== undefined && SELF_IMPORT_BLOCKED_RELS.includes(ref)) {
208
+ return { ok: false, message: ctx.msg('adapter.selfImportBlocked', { path: ref }), warning: true };
209
+ }
210
+ return super.applyItem(item, ctx);
211
+ }
152
212
  }
153
213
  //# sourceMappingURL=self.js.map
package/lib/client.d.ts CHANGED
@@ -5019,6 +5019,7 @@ declare const zh$4: {
5019
5019
  readonly 'overview.health.noBackup': '尚无任何备份';
5020
5020
  readonly 'overview.health.scheduleFailed': '上次定时备份失败,建议检查备份设置';
5021
5021
  readonly 'overview.health.recovery': '存在未解决的恢复事项,需要处理';
5022
+ readonly 'overview.health.autoBackupOff': '自动备份已关闭,目前只有手动备份';
5022
5023
  readonly 'overview.health.recoveryAction': '前往「事故恢复」处理';
5023
5024
  readonly 'overview.metric.backups': '备份文件';
5024
5025
  readonly 'overview.metric.snapshots': '安全快照';
@@ -5048,6 +5049,10 @@ declare const zh$4: {
5048
5049
  readonly 'overview.quick.backupSkippedOther': '已跳过:备份服务当前无法执行(详情见宿主日志)';
5049
5050
  readonly 'overview.quick.backupFailed': '备份失败:{message}';
5050
5051
  readonly 'overview.activity.title': '最近活动';
5052
+ readonly 'overview.activity.colTime': '时间';
5053
+ readonly 'overview.activity.colEvent': '动作';
5054
+ readonly 'overview.activity.colDetail': '详情';
5055
+ readonly 'overview.activity.colResult': '结果';
5051
5056
  readonly 'overview.activity.empty': '暂无操作记录';
5052
5057
  readonly 'overview.activity.unavailable': '活动记录读取失败(这不是「没有记录」)';
5053
5058
  readonly 'overview.loadFailed': '有 {count} 项数据读取失败:{message} —— 下面的指标可能不完整';
@@ -5417,6 +5422,7 @@ declare const zh$4: {
5417
5422
  readonly 'profiles.running.port': '端口 {port}';
5418
5423
  readonly 'profiles.running.open': '打开';
5419
5424
  readonly 'profiles.running.badge': ':{port} 运行中';
5425
+ readonly 'profiles.running.portBadge': ':{port}';
5420
5426
  readonly 'profiles.running.originCurrent': '当前实例';
5421
5427
  readonly 'profiles.running.originOwned': '本插件启动';
5422
5428
  readonly 'profiles.running.originExternal': '其他实例';
@@ -5712,6 +5718,7 @@ declare const zh$4: {
5712
5718
  readonly 'library.remoteDeleteBaseline': '注意:这是当前的同步基线(本机上次同步到的那份)。删除不会改动本机配置,但下次同步会重新比对远端最新快照。';
5713
5719
  readonly 'library.remoteDeleted': '已删除远端快照';
5714
5720
  readonly 'library.summary.count': '共 {count} 个';
5721
+ readonly 'library.summary.filtered': '{shown} / {total} 个';
5715
5722
  readonly 'library.new.export': '手动导出';
5716
5723
  readonly 'library.new.import': '从文件导入';
5717
5724
  readonly 'library.new.market': '逛市场';
@@ -5830,7 +5837,7 @@ declare const zh$3: {
5830
5837
  readonly 'channel.s3': '对象存储(S3 兼容)';
5831
5838
  readonly 'channel.gist': 'GitHub Gist';
5832
5839
  readonly 'channel.perChannelHint': '每条通道(Git / WebDAV / 对象存储 / Gist)的自动同步、同步模式、加密与远端快照各自独立配置。';
5833
- readonly 'channel.open': '配置…';
5840
+ readonly 'channel.open': '配置';
5834
5841
  readonly 'channel.openHint': '远程同步通过「同步通道」进行:Git 私有仓库或 WebDAV 服务器。';
5835
5842
  readonly 'channel.expand': '展开通道详情';
5836
5843
  readonly 'channel.collapse': '收起通道详情';
@@ -5897,7 +5904,7 @@ declare const zh$3: {
5897
5904
  readonly 'repoPicker.empty': '没有可用的私有仓库';
5898
5905
  readonly 'repoPicker.loadFailed': '仓库列表加载失败,可重试或直接手填地址。';
5899
5906
  readonly 'repoPicker.updatedAt': '更新于 {time}';
5900
- readonly 'repoPicker.create': '+ 新建私有仓库…';
5907
+ readonly 'repoPicker.create': '+ 新建私有仓库';
5901
5908
  readonly 'repoPicker.createTitle': '新建私有仓库';
5902
5909
  readonly 'repoPicker.name': '仓库名';
5903
5910
  readonly 'repoPicker.namePlaceholder': '如 dsh-configs';
@@ -5959,7 +5966,7 @@ declare const zh$3: {
5959
5966
  readonly 'syncflow.remoteEmptyGuide': '远端还没有任何快照:这是首次同步,先点「推送到远端」把本机配置推上去(推送会创建第一个快照),之后才能拉取。';
5960
5967
  readonly 'mode.title': '同步分区';
5961
5968
  readonly 'mode.hint': '同步范围 = 勾选的分区集合(默认已勾选推荐分区,可随时改)。';
5962
- readonly 'mode.selectedCount': '已勾选 {n} 个';
5969
+ readonly 'mode.selectedCount': '已勾选 {n} / {total}';
5963
5970
  readonly 'mode.sectionsHint': '默认可同步的是可移植分区;平台相关分区(MCP 服务器)与设备相关分区(插件文件、凭据状态、历史会话)只有你在这里主动勾选才参与同步。';
5964
5971
  readonly 'mode.atLeastOne': '请至少勾选一个同步分区';
5965
5972
  readonly 'mode.sectionPortable': '可移植';
@@ -5977,7 +5984,7 @@ declare const zh$3: {
5977
5984
  readonly 'mode.sessionsWorkspaceWarn': '已勾选历史对话,但没有勾选「工作区」分区:目标机上这些对话可能归属不到任何工作区而显示不出来。建议一并勾选「工作区」。';
5978
5985
  readonly 'mode.gistSessionsWarn': '当前通道是 GitHub Gist,且勾选了「历史会话」:gist 会一次取回全部文件内容、单文件超限即截断、文件数还有上限,大分区同步可能失败或内容被截断。建议改用 Git / WebDAV / 对象存储通道同步历史会话,或取消勾选该分区。';
5979
5986
  readonly 'mode.persistHint': '分区选择已保存到本机:自动同步和手动推送都会使用此配置(重启后仍生效)。';
5980
- readonly 'mode.choose': '选择…';
5987
+ readonly 'mode.choose': '选择';
5981
5988
  readonly 'mode.pickerTitle': '选择同步分区';
5982
5989
  readonly 'mode.pickerHint': '改动即时生效并保存(关闭弹窗即完成)。';
5983
5990
  readonly 'mode.pickerBack': '返回分区列表';
@@ -7052,8 +7059,6 @@ interface ExportViewProps {
7052
7059
  interface ImportWizardViewProps {
7053
7060
  api: ConfigManagerApi;
7054
7061
  t: TranslateNS<'config-manager'>;
7055
- uiT?: UiT;
7056
- onOpenForeignImport?: () => void;
7057
7062
  }
7058
7063
  interface SyncPanelProps {
7059
7064
  api: SyncApi;