dsh-config-manager 0.1.52 → 0.1.54

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 (100) hide show
  1. package/README.md +26 -4
  2. package/lib/adapters/self.js +3 -0
  3. package/lib/adapters/self.js.map +1 -1
  4. package/lib/client.d.ts +240 -5
  5. package/lib/client.js +2619 -322
  6. package/lib/client.js.map +1 -1
  7. package/lib/core/backup.d.ts +3 -1
  8. package/lib/core/backup.js +5 -1
  9. package/lib/core/backup.js.map +1 -1
  10. package/lib/core/restore.d.ts +10 -0
  11. package/lib/core/restore.js +41 -0
  12. package/lib/core/restore.js.map +1 -1
  13. package/lib/core/run-registry.d.ts +2 -2
  14. package/lib/core/types.d.ts +4 -0
  15. package/lib/core/types.js.map +1 -1
  16. package/lib/index.js +415 -14
  17. package/lib/index.js.map +1 -1
  18. package/lib/market/types.d.ts +2 -0
  19. package/lib/sync/backup-files.d.ts +25 -4
  20. package/lib/sync/backup-files.js +82 -3
  21. package/lib/sync/backup-files.js.map +1 -1
  22. package/lib/sync/backup-schedule-config.d.ts +29 -3
  23. package/lib/sync/backup-schedule-config.js +50 -2
  24. package/lib/sync/backup-schedule-config.js.map +1 -1
  25. package/lib/sync/backup-scheduler.js +11 -3
  26. package/lib/sync/backup-scheduler.js.map +1 -1
  27. package/lib/sync/sync-engine.d.ts +30 -1
  28. package/lib/sync/sync-engine.js +63 -0
  29. package/lib/sync/sync-engine.js.map +1 -1
  30. package/lib/ui/backup-inspect.d.ts +53 -0
  31. package/lib/ui/backup-inspect.js +54 -0
  32. package/lib/ui/backup-inspect.js.map +1 -0
  33. package/lib/ui/backup-schedule.d.ts +14 -3
  34. package/lib/ui/backup-schedule.js +39 -4
  35. package/lib/ui/backup-schedule.js.map +1 -1
  36. package/lib/ui/conflict-view.d.ts +4 -0
  37. package/lib/ui/conflict-view.js +11 -0
  38. package/lib/ui/conflict-view.js.map +1 -1
  39. package/lib/ui/export-flow.d.ts +16 -0
  40. package/lib/ui/export-flow.js +15 -0
  41. package/lib/ui/export-flow.js.map +1 -1
  42. package/lib/ui/i18n.d.ts +3 -0
  43. package/lib/ui/i18n.js +6 -0
  44. package/lib/ui/i18n.js.map +1 -1
  45. package/lib/ui/next-steps.d.ts +56 -0
  46. package/lib/ui/next-steps.js +29 -0
  47. package/lib/ui/next-steps.js.map +1 -0
  48. package/lib/ui/profiles-view.d.ts +26 -0
  49. package/lib/ui/profiles-view.js +38 -0
  50. package/lib/ui/profiles-view.js.map +1 -0
  51. package/package.json +1 -1
  52. package/src/adapters/self.ts +3 -0
  53. package/src/client/ConfigManagerSection.tsx +61 -28
  54. package/src/client/about/AboutPanel.tsx +19 -1
  55. package/src/client/about/about-view.ts +21 -1
  56. package/src/client/api.ts +150 -1
  57. package/src/client/config-manager.module.css +209 -3
  58. package/src/client/export/ExportView.tsx +99 -4
  59. package/src/client/import/ConflictList.tsx +4 -3
  60. package/src/client/import/ImportWizardView.tsx +58 -1
  61. package/src/client/locales.ts +194 -0
  62. package/src/client/market/MarketPanel.tsx +46 -4
  63. package/src/client/market/MyConfigsView.tsx +15 -13
  64. package/src/client/market/market-locales.ts +16 -0
  65. package/src/client/market/market-view.test.ts +60 -4
  66. package/src/client/market/market-view.ts +73 -2
  67. package/src/client/profiles/ProfilesPanel.tsx +570 -0
  68. package/src/client/run-store.ts +74 -5
  69. package/src/client/snapshots/SnapshotsPanel.tsx +453 -49
  70. package/src/client/sync/SyncSettingsView.tsx +126 -16
  71. package/src/client/sync/sync-api.ts +6 -1
  72. package/src/client/sync/sync-locales.ts +12 -0
  73. package/src/client/sync/sync-push-preview.test.ts +68 -0
  74. package/src/client/sync/sync-view.ts +45 -1
  75. package/src/core/backup.ts +4 -1
  76. package/src/core/restore-manage.test.ts +94 -0
  77. package/src/core/restore.ts +46 -0
  78. package/src/core/run-registry.ts +2 -2
  79. package/src/core/types.ts +4 -0
  80. package/src/index.ts +396 -18
  81. package/src/market/types.ts +2 -0
  82. package/src/sync/backup-files.test.ts +64 -0
  83. package/src/sync/backup-files.ts +84 -6
  84. package/src/sync/backup-schedule-config.ts +66 -5
  85. package/src/sync/backup-scheduler.test.ts +49 -1
  86. package/src/sync/backup-scheduler.ts +11 -3
  87. package/src/sync/sync-engine.ts +86 -1
  88. package/src/ui/backup-inspect.test.ts +142 -0
  89. package/src/ui/backup-inspect.ts +100 -0
  90. package/src/ui/backup-schedule.test.ts +51 -0
  91. package/src/ui/backup-schedule.ts +49 -7
  92. package/src/ui/conflict-view.test.ts +24 -2
  93. package/src/ui/conflict-view.ts +12 -0
  94. package/src/ui/export-flow.test.ts +10 -1
  95. package/src/ui/export-flow.ts +24 -1
  96. package/src/ui/i18n.ts +6 -0
  97. package/src/ui/next-steps.test.ts +117 -0
  98. package/src/ui/next-steps.ts +62 -0
  99. package/src/ui/profiles-view.test.ts +77 -0
  100. package/src/ui/profiles-view.ts +55 -0
package/README.md CHANGED
@@ -7,7 +7,7 @@ Backup, restore, export, import, migrate and sync your complete DeepSeek Harness
7
7
  - 🔄 **Backup & Restore** DeepSeek Harness configuration
8
8
  - 📦 **Export / Import** complete DSH configuration
9
9
  - 🚚 **Migrate** DSH to another machine
10
- - ⏰ **Scheduled full backups** — automatic, on your own cadence (6h / 12h / 24h / 7d), secrets never included
10
+ - ⏰ **Scheduled full backups** — automatic, on your own cadence (6h / 12h / 24h / 7d / custom weekly), secrets never included
11
11
  - 🔌 Backup installed **plugins** and plugin configuration
12
12
  - 🧩 Backup **MCP servers** and **Skills**
13
13
  - 🔐 Encrypted backups with optional credentials
@@ -56,7 +56,7 @@ Keep portable configuration synchronized between machines through a private Git
56
56
 
57
57
  ### Schedule automatic full backups
58
58
 
59
- Turn on scheduled backups (6h / 12h / 24h / 7d) and DSH quietly keeps a fresh full backup of your configuration in the background — secrets are never included, so it stays safe on disk without a password.
59
+ Turn on scheduled backups (6h / 12h / 24h / 7d — or a **custom weekly weekday & time**) and DSH quietly keeps a fresh full backup of your configuration in the background — secrets are never included, so it stays safe on disk without a password. Consecutive failures are highlighted in red in the settings card.
60
60
 
61
61
  ### Discover & install configurations from the marketplace
62
62
 
@@ -79,7 +79,7 @@ Browse the built-in official market for ready-made configurations (model provide
79
79
  | 🔄 | **Remote Sync** | Push/pull portable config via **Git private repo or WebDAV** (secrets never sync) |
80
80
  | ⏰ | **Scheduled backups** | Full backup on a fixed cadence (6h / 12h / 24h / 7d) — set-and-forget, secrets never included |
81
81
  | 🛒 | **Config Marketplace** | Browse & one-click install community configs — supply-chain warnings + per-section approval |
82
- | 🗂️ | **Profiles** | Save multiple setups (Work / Personal) and switch anytime |
82
+ | 🗂️ | **Profiles** | Save multiple setups (Work / Personal) and switch anytime — preview + auto-backup + rollback |
83
83
  | 🌐 | **Bilingual UI** | Interface, reports and error details follow the DSH app language (中文 / English) |
84
84
  | 🤖 | **Agent tools** | Backup / snapshot / restore / sync right from an agent session |
85
85
 
@@ -186,11 +186,16 @@ Copy the ZIP to Machine B (import)
186
186
 
187
187
  > Output: `dsh-config-<date>.zip` with manifest + per-category data + SHA-256 checksums.
188
188
 
189
+ **Export extras:**
190
+ - **Preview before export** — see what will be packaged (section count + estimated size, no secrets) before anything is written
191
+ - **Custom file name & note** — name the ZIP yourself (auto-naming is the default) and attach an optional note that shows in the **Backup Files** list (the note travels with the self section when you sync/backup the config)
192
+
189
193
  ### 📥 Import (safe flow)
190
194
 
191
195
  - **Nothing is written before confirmation** — analyze & preview are zero-write
192
196
  - **Backup before applying** — the target config is snapshotted automatically
193
197
  - **Automatic rollback on failure** — full rollback or skip-and-continue, your choice
198
+ - **Next-steps checklist after import** — the result page lists what needs a DSH restart (per plugin/MCP), credentials to re-enter, and failed/skipped items you can retry
194
199
 
195
200
  ### 👀 Import Preview (dry run)
196
201
 
@@ -242,13 +247,15 @@ Push / pull your portable config between machines through **either of two channe
242
247
  - **Switching channels starts fresh**: Git and WebDAV do **not** share snapshots or a common ancestor. When you switch transport, sync begins again from the new remote's empty baseline — push a fresh snapshot first.
243
248
  - **WebDAV auth** uses HTTP Basic: the `username` is stored in the config and may be echoed back into the UI, while the `password` is read live from the DSH credentials slot `DSH_CONFIG_MANAGER_SYNC_WEBDAV_PASSWORD` — it never appears in any sync file or log.
244
249
  - **Plugins auto-install**: when pulling diffs, plugins that are new in the backup are **installed automatically** on confirm — no manual per-item ticking in the diff list. Only **version-conflict** plugins still ask you to pick "Keep Current / Use Imported".
250
+ - **Push preview before uploading** — the Push button first shows a read-only preview of what will be sent (sections + per-section counts + changed-vs-baseline markers, first-baseline notice) and only writes the remote after you confirm.
245
251
 
246
252
  ### 🛒 Configuration Marketplace
247
253
 
248
254
  Browse and install ready-made configurations (model providers, plugins, MCP servers, skills, agent presets…) shared by the community:
249
255
 
250
256
  - **Built-in official market** — read-only, bound to the official public repo (official badge shown, not editable); first open auto-refreshes, manual refresh also available
251
- - **Search & filter** — keyword search, category filter, source filter (Official / Community), sorting (recently updated / most starred / name A–Z), and a ⭐ badge showing the **source repo's** star count (queried anonymously, no token involved)
257
+ - **Search & filter** — keyword search (matches name / description / author / **categories**), category filter, **section filter** (items already downloaded list their sections; others are excluded with a hint), source filter (Official / Community), sorting (recently updated / most starred / name A–Z), and a ⭐ badge showing the **source repo's** star count (queried anonymously, no token involved)
258
+ - **Impact preview** — the detail view shows "what installing this will change" (items updated / identical / conflicts / secrets to re-enter / DSH restart needed) before you approve anything
252
259
  - **Supply-chain warnings always shown** — source repo URL, "not officially reviewed", download time; **per-section approval** — high-risk sections (sessions / arbitrary files) are banned from listing outright, and every remaining section must be explicitly approved before the import is confirmed
253
260
  - **Install reuses the safe import pipeline** — analyze → preview → auto-backup → apply → rollback; nothing is written before you confirm
254
261
  - **"My Configs"** — sign in with GitHub (device flow), upload a config to **your own public repo** in one click, and an **auto listing PR** is opened against the official market repo; manage your listings (status badges: not listed / PR pending / listed), update in one click, install back locally, or delist (auto de-listing PR)
@@ -257,6 +264,11 @@ Browse and install ready-made configurations (model providers, plugins, MCP serv
257
264
 
258
265
  Save multiple configurations (Work / Personal) and switch anytime; switching includes preview + auto-backup + rollback.
259
266
 
267
+ - **Save current config** — pick a name and store the current DSH configuration (settings / providers / plugins / skills / agent presets…; no secrets, file sections embedded)
268
+ - **Switch with safety** — preview first (zero writes) → confirm → automatic snapshot → staged apply; any failure rolls back fully
269
+ - **Manage** — rename / delete (confirmed) / import an exported profile.json
270
+ - Library is an independent tab: Settings → "Backup & Migration" → **Profiles**
271
+
260
272
  ### 📸 Snapshot restore (undo an import)
261
273
 
262
274
  Every import creates a **safety snapshot** first. If something feels off afterwards, restore the target back to its pre-import state:
@@ -270,6 +282,16 @@ Every import creates a **safety snapshot** first. If something feels off afterwa
270
282
 
271
283
  **GUI**: Settings → "Backup & Migration" → **Snapshots & Restore** tab → pick a snapshot → preview the plan (dry-run, zero writes) → confirm.
272
284
 
285
+ **Snapshot management:**
286
+ - **Retention is visible** — up to **10** snapshots are kept automatically (oldest pruned); the hint is shown in the list
287
+ - **Pin important snapshots** — a pinned snapshot is exempt from auto-pruning and can only be deleted manually
288
+ - **Manual delete** — remove any snapshot (danger, confirmed) when you no longer need that rollback point
289
+
290
+ **Backup Files management** (same tab → "Backup Files"):
291
+ - List every export ZIP (manual + scheduled) with source badge, size, time and your custom **note**
292
+ - **Search** by file name or note
293
+ - **Inspect / Compare** — read-only preview of what the backup contains (sections + per-section counts) and the diff against your current config (zero writes) before deciding to import
294
+
273
295
  ---
274
296
 
275
297
  ### 🚨 CLI — the first line of defense when DSH is broken
@@ -33,6 +33,9 @@ export const SELF_CONFIG_FILES = [
33
33
  'sync/ui-prefs.json',
34
34
  'sync/backup-schedule.json',
35
35
  'market/market-config.json',
36
+ // P0-④:导出产物备注清单(exports/.backup-notes.json)——随 self 分区迁移,
37
+ // 换机器后备份列表仍能看到手动导出时填写的备注
38
+ 'exports/.backup-notes.json',
36
39
  ];
37
40
  export class SelfAdapter extends FileCollectionAdapter {
38
41
  id = 'self';
@@ -1 +1 @@
1
- {"version":3,"file":"self.js","sourceRoot":"","sources":["../../src/adapters/self.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAG5C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,gEAAgE;AAChE,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,uBAAuB;IACvB,yBAAyB;IACzB,0BAA0B;IAC1B,oBAAoB;IACpB,2BAA2B;IAC3B,2BAA2B;CAC5B,CAAC;AAEF,MAAM,OAAO,WAAY,SAAQ,qBAAqB;IAC3C,EAAE,GAAG,MAAe,CAAC;IACrB,WAAW,GAAG,oBAAoB,CAAC;IACnC,eAAe,GAAG,IAAI,CAAC;IACvB,WAAW,GAAG,UAAmB,CAAC;IAC3C,kEAAkE;IACzD,OAAO,CAAS;IAEzB,YAAY,OAAO,GAAG,oBAAoB;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;iGAC6F;IACpF,KAAK,CAAC,MAAM,CAAC,GAAgB,EAAE,QAAuB;QAC7D,MAAM,KAAK,GAA0B,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;YACpC,oEAAoE;YACpE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACnF,IAAI,IAAI,KAAK,IAAI;gBAAE,SAAS,CAAC,0BAA0B;YACvD,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,EAAE;YAClB,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE;YAC3B,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE;YAC/B,QAAQ;SACT,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"self.js","sourceRoot":"","sources":["../../src/adapters/self.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAG5C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,gEAAgE;AAChE,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,uBAAuB;IACvB,yBAAyB;IACzB,0BAA0B;IAC1B,oBAAoB;IACpB,2BAA2B;IAC3B,2BAA2B;IAC3B,0DAA0D;IAC1D,yBAAyB;IACzB,4BAA4B;CAC7B,CAAC;AAEF,MAAM,OAAO,WAAY,SAAQ,qBAAqB;IAC3C,EAAE,GAAG,MAAe,CAAC;IACrB,WAAW,GAAG,oBAAoB,CAAC;IACnC,eAAe,GAAG,IAAI,CAAC;IACvB,WAAW,GAAG,UAAmB,CAAC;IAC3C,kEAAkE;IACzD,OAAO,CAAS;IAEzB,YAAY,OAAO,GAAG,oBAAoB;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;iGAC6F;IACpF,KAAK,CAAC,MAAM,CAAC,GAAgB,EAAE,QAAuB;QAC7D,MAAM,KAAK,GAA0B,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;YACpC,oEAAoE;YACpE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACnF,IAAI,IAAI,KAAK,IAAI;gBAAE,SAAS,CAAC,0BAA0B;YACvD,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,EAAE;YAClB,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE;YAC3B,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE;YAC/B,QAAQ;SACT,CAAC;IACJ,CAAC;CACF"}
package/lib/client.d.ts CHANGED
@@ -83,6 +83,8 @@ interface ExportOptions {
83
83
  only?: SectionId[];
84
84
  /** 导出文件路径(缺省自动生成 dsh-config-<date>.zip) */
85
85
  outPath?: string;
86
+ /** 导出备注(P0-④:host 写入 exports/.backup-notes.json,随 self 分区迁移;非敏感) */
87
+ note?: string;
86
88
  }
87
89
  type PlanItemKind = 'Create' | 'Update' | 'Skip' | 'Conflict' | 'Install' | 'MissingSecret' | 'MissingDependency' | 'PathMapping' | 'Warning' | 'Error';
88
90
  type ItemResolution = 'keepCurrent' | 'useImported' | 'review';
@@ -278,11 +280,40 @@ interface SnapshotMeta {
278
280
  entryCount: number;
279
281
  hostFileBackupCount: number;
280
282
  beforePluginCount: number;
283
+ /** 置顶标记(P1-⑧):置顶快照不参与自动保留清理(最多保留 N 个时的淘汰豁免) */
284
+ pinned?: boolean;
285
+ }
286
+ //#endregion
287
+ //#region src/profiles/profile-manager.d.ts
288
+ interface ProfileMeta {
289
+ name: string;
290
+ createdAt: string;
291
+ updatedAt: string;
292
+ sections: SectionId[];
293
+ fileCount: number;
294
+ }
295
+ interface SwitchPreview {
296
+ items: PlanItem[];
297
+ missingSecrets: {
298
+ ref: string;
299
+ required: boolean;
300
+ }[];
301
+ needsRestart: boolean;
302
+ sectionsInProfile: SectionId[];
303
+ }
304
+ interface ProfileSwitchResult {
305
+ ok: boolean;
306
+ executed: ExecutedItem[];
307
+ needsRestart: boolean;
308
+ missingSecrets: string[];
309
+ warnings: string[];
310
+ rollback: RollbackReport | null;
311
+ snapshotId: string | null;
281
312
  }
282
313
  //#endregion
283
314
  //#region src/core/run-registry.d.ts
284
- /** run 类型:导出 / 导入 / 自动同步 / 一键同步逐项应用 / 定时备份 / 快照恢复。 */
285
- type RunKind = 'export' | 'import' | 'autosync' | 'sync-apply' | 'backup-schedule' | 'restore';
315
+ /** run 类型:导出 / 导入 / 自动同步 / 一键同步逐项应用 / 定时备份 / 快照恢复 / 配置档案切换。 */
316
+ type RunKind = 'export' | 'import' | 'autosync' | 'sync-apply' | 'backup-schedule' | 'restore' | 'profile-switch';
286
317
  /** run 状态:进行中 / 完成 / 失败。 */
287
318
  type RunStatus = 'running' | 'done' | 'failed';
288
319
  /** 单个 run 的实时状态(/progress 返回体;纯 JSON 可序列化)。 */
@@ -313,8 +344,22 @@ interface RunState {
313
344
  }
314
345
  //#endregion
315
346
  //#region src/sync/backup-schedule-config.d.ts
316
- /** 定时备份间隔档位(全量备份无需太频繁;默认 24h) */
317
- type BackupInterval = '6h' | '12h' | '24h' | '7d';
347
+ /** 定时备份间隔档位(全量备份无需太频繁;默认 24h)。
348
+ * - '6h' | '12h' | '24h' | '7d':固定间隔;
349
+ * - 'custom':每周固定时刻(见 customSchedule)。 */
350
+ type BackupInterval = '6h' | '12h' | '24h' | '7d' | 'custom';
351
+ /**
352
+ * 自定义(每周固定时刻)档配置:
353
+ * - dayOfWeek:0-6(0 = 周日,1 = 周一 … 6 = 周六);
354
+ * - hour:0-23;
355
+ * - minute:0-59。
356
+ * 语义 = 每周该时刻触发一次全量备份(错过的时间点不补跑——下次排期自然对齐)。
357
+ */
358
+ interface BackupWeeklySchedule {
359
+ dayOfWeek: number;
360
+ hour: number;
361
+ minute: number;
362
+ }
318
363
  /** 最近一次定时备份执行状态 */
319
364
  type BackupRunStatus = 'success' | 'skipped' | 'failed';
320
365
  //#endregion
@@ -330,15 +375,18 @@ interface BackupRunResult {
330
375
  }
331
376
  //#endregion
332
377
  //#region src/ui/backup-schedule.d.ts
333
- /** 设置草稿(表单编辑态:总开关 + 间隔档位)。 */
378
+ /** 设置草稿(表单编辑态:总开关 + 间隔档位 + 自定义周档)。 */
334
379
  interface BackupScheduleDraft {
335
380
  enabled: boolean;
336
381
  interval: BackupInterval;
382
+ /** custom 档的每周固定时刻(仅 interval='custom' 时校验;其他档位忽略) */
383
+ customSchedule?: BackupWeeklySchedule;
337
384
  }
338
385
  /** 定时备份配置的浏览器侧视图(与 sync/backup-schedule-config.ts 的持久化面一致;无敏感字段)。 */
339
386
  interface BackupScheduleStatus {
340
387
  enabled: boolean;
341
388
  interval: BackupInterval;
389
+ customSchedule?: BackupWeeklySchedule;
342
390
  startupMinIntervalMs: number;
343
391
  consecutiveFailures: number;
344
392
  lastRunAt?: string;
@@ -361,6 +409,8 @@ interface BackupFileMeta {
361
409
  mtimeMs: number;
362
410
  /** 来源:auto = 定时备份;manual = 手动导出 */
363
411
  source: BackupFileSource;
412
+ /** 用户备注(手动导出时可选填写;null = 无备注) */
413
+ note?: string | null;
364
414
  }
365
415
  //#endregion
366
416
  //#region src/ui/i18n.d.ts
@@ -513,6 +563,9 @@ declare const uiZh: {
513
563
  readonly 'sync.neverSyncedShort': "从未同步";
514
564
  readonly 'sync.pushFailed': "推送失败";
515
565
  readonly 'sync.pushOk': "推送成功(快照 {id})";
566
+ readonly 'sync.pushPreviewHeadline': "将推送 {total} 个分区({changed} 个有变化)";
567
+ readonly 'sync.pushPreviewHint': "以上为只读预览,不会写入远端。确认后点击「推送」才真正上传。";
568
+ readonly 'sync.pushPreviewEncrypted': "加密快照:载荷将整体加密,各分区相对基线的变化不可比对。";
516
569
  readonly 'sync.pullFailed': "拉取失败";
517
570
  readonly 'sync.pullOk': "远端快照 {id} 差异预览:共 {count} 项变更";
518
571
  readonly 'sync.pullEmpty': "远端快照与本地一致(无变更)";
@@ -649,6 +702,23 @@ interface UploadResponse {
649
702
  /** zip=普通备份;encrypted=整体加密备份容器(需先 decryptArchive 解锁才能按 ZIP 解析) */
650
703
  containerType: 'zip' | 'encrypted';
651
704
  }
705
+ /** P1-⑦/P2-⑬:备份内容查看 / 差异对比结果(只读;复用 analyze + plan 链路,零写入) */
706
+ interface BackupInspectResult {
707
+ analysis: ImportAnalysis;
708
+ plan: ImportPlan;
709
+ }
710
+ /** P2-⑫:导出前预览响应(不落盘 ZIP;各分区 counts + 估算大小) */
711
+ interface ExportPreviewResponse {
712
+ ok: boolean;
713
+ sections: {
714
+ section: SectionId;
715
+ count: number;
716
+ sizeBytes: number;
717
+ }[];
718
+ totalSections: number;
719
+ totalSizeBytes: number;
720
+ sectionsFailed: number;
721
+ }
652
722
  /** decrypt-archive 端点响应:解锁整体加密容器后返回明文 ZIP 路径 + 解密覆盖的凭据 ref 名(非值) */
653
723
  interface DecryptArchiveResponse {
654
724
  zipPath: string;
@@ -721,6 +791,8 @@ declare class ConfigManagerApi {
721
791
  status(): Promise<ServiceStatus>;
722
792
  /** Star 引导弹窗状态(进入页面时判定是否展示 / 是否补记首次使用时间)。 */
723
793
  starPromptStatus(): Promise<StarPromptStatus>;
794
+ /** P2-⑫:导出前只读预览(不落盘 ZIP)——「将打包 X 分区 / Y 条目 / 约 Z 大小」。 */
795
+ exportPreview(only?: SectionId[]): Promise<ExportPreviewResponse>;
724
796
  /** 保存 Star 引导弹窗状态(局部更新:firstSeenAt / dismissed / clicked)。
725
797
  * 纯偏好无 secret;失败由调用方静默降级(本次不弹/不记,下次再判)。 */
726
798
  saveStarPrompt(patch: StarPromptPatch): Promise<StarPromptSaveResponse>;
@@ -765,6 +837,34 @@ declare class ConfigManagerApi {
765
837
  snapshots(): Promise<SnapshotMeta[]>;
766
838
  /** 快照恢复:dryRun=true 只取动作计划(零写入);false 执行并返回诚实报告 */
767
839
  restoreSnapshot(snapshotId: string, dryRun: boolean): Promise<RestoreResponse>;
840
+ /** P1-⑧:手动删除单个快照(危险操作:该导入前回滚点不可恢复;`removed` 为是否实际删除)。 */
841
+ deleteSnapshot(snapshotId: string): Promise<{
842
+ removed: boolean;
843
+ }>;
844
+ /** P1-⑧:置顶/取消置顶快照(置顶快照豁免自动保留清理,只能手动删除)。 */
845
+ setSnapshotPinned(snapshotId: string, pinned: boolean): Promise<{
846
+ pinned: boolean;
847
+ }>;
848
+ /** 列出全部 Profile(name/createdAt/updatedAt/sections/fileCount)。 */
849
+ profilesList(): Promise<ProfileMeta[]>;
850
+ /** 保存当前 DSH 配置为新 Profile(天然不含秘密值)。 */
851
+ profileSave(name: string, sections?: SectionId[]): Promise<ProfileMeta>;
852
+ /** 删除 Profile(危险操作:该组配置快照不可恢复)。 */
853
+ profileDelete(name: string): Promise<void>;
854
+ /** 重命名 Profile(目录级移动)。 */
855
+ profileRename(name: string, newName: string): Promise<ProfileMeta>;
856
+ /** 切换前预览(只读,零写入):分析切换到该 Profile 会产生的计划项。 */
857
+ profileAnalyzeSwitch(name: string): Promise<SwitchPreview>;
858
+ /** 执行切换(confirm=true 安全阀;走快照 + 分阶段 apply + 失败回滚;响应含 runId)。 */
859
+ profileExecuteSwitch(name: string, opts: {
860
+ strategy?: 'merge' | 'replace' | 'skipExisting';
861
+ secretInputs?: Record<string, string>;
862
+ rollbackOnError?: boolean;
863
+ }): Promise<ProfileSwitchResult & {
864
+ runId: string;
865
+ }>;
866
+ /** 导入 Profile(content = profile.json 字符串;asName 可选覆盖目标名)。 */
867
+ profileImport(content: string, asName?: string): Promise<ProfileMeta>;
768
868
  /** 读取定时备份配置(enabled / interval / 上次运行状态;无敏感字段)。 */
769
869
  backupSchedule(): Promise<BackupScheduleStatus>;
770
870
  /** 保存定时备份设置(enabled + interval);Host 校验后原子写 + 重排调度器。 */
@@ -780,6 +880,9 @@ declare class ConfigManagerApi {
780
880
  deleteBackupFile(name: string): Promise<{
781
881
  removed: boolean;
782
882
  }>;
883
+ /** 「查看备份内容」:对 exports 目录内的备份文件做只读分析(reuse /analyze,零写入)。
884
+ * 返回分析 + 与当前配置的差异计划摘要("装/导这个备份会动你什么")。 */
885
+ inspectBackup(zipPath: string): Promise<BackupInspectResult>;
783
886
  }
784
887
  //#endregion
785
888
  //#region src/sync/sync-engine.d.ts
@@ -809,6 +912,26 @@ interface SyncPullReport {
809
912
  needsReview: boolean;
810
913
  message?: string;
811
914
  }
915
+ /** P0-②:push 前只读预览 ——「将推送什么」的单分区摘要(不写远端、不落盘)。 */
916
+ interface SyncPushPreviewSection {
917
+ /** 分区 id(将进入快照的 portable 分区) */
918
+ section: SectionId;
919
+ /** 分区内条目计数(adapter.export 的 counts 聚合;无计数时为 0) */
920
+ count: number;
921
+ /** 相对上次基线(sync-state)是否变化:true = 本次会更新该分区;false = 与基线一致 */
922
+ changed: boolean;
923
+ }
924
+ /** P0-②:push 前预览结果(零写入)。 */
925
+ interface SyncPushPreview {
926
+ ok: boolean;
927
+ /** 将推送的分区清单(含计数与变化标记) */
928
+ sections: SyncPushPreviewSection[];
929
+ /** 远端现有快照数(0 = 首次推送将创建首个基线) */
930
+ remoteSnapshotCount: number;
931
+ /** 加密快照:载荷将整体加密(分区计数与基线比较不可得) */
932
+ encrypted: boolean;
933
+ message?: string;
934
+ }
812
935
  //#endregion
813
936
  //#region src/client/sync/sync-api.d.ts
814
937
  /** 远程同步通道类型:git(默认)或 webdav */
@@ -1126,6 +1249,8 @@ declare class SyncApi {
1126
1249
  status(): Promise<SyncStatusResponse>;
1127
1250
  /** 推送:导出 portable 分区 → 提交到私有 Git 仓库 → 更新 sync-state */
1128
1251
  push(payload: SyncPushPayload): Promise<SyncPushReport>;
1252
+ /** P0-②:push 前只读预览(「将推送什么」,零写入远端)——body.preview=true 触发 */
1253
+ pushPreview(payload: SyncPushPayload): Promise<SyncPushPreview>;
1129
1254
  /** 拉取差异预览:拉取远端最新快照 → 只读分析(绝不执行导入) */
1130
1255
  pull(payload: SyncPullPayload): Promise<SyncPullReport>;
1131
1256
  /** GitHub OAuth device flow:发起登录,返回一次性用户码 + 授权页 URL + flowId */
@@ -1241,6 +1366,8 @@ interface MarketListItem {
1241
1366
  stars?: number;
1242
1367
  /** 本地缓存状态:cached | fresh | none(UI 徽章) */
1243
1368
  cacheState: 'cached' | 'fresh' | 'none';
1369
+ /** 分区清单(P2-⑭:已缓存条目从 L2 manifest 合并;未缓存条目缺省 = 未知,列表分区筛选时排除) */
1370
+ sections?: SectionId[];
1244
1371
  }
1245
1372
  /** POST /market/download 响应:条目详情 + 校验结果(dry-run 预览) */
1246
1373
  interface MarketItemDetail {
@@ -1527,12 +1654,14 @@ interface ConfigManagerSectionInjected {
1527
1654
  declare const zh$2: {
1528
1655
  readonly 'section.label': "备份与迁移";
1529
1656
  readonly 'section.description': "导出 / 导入 / 迁移 DSH 配置(备份不含密钥,加密备份可选)";
1657
+ readonly 'view.transfer': "导出与导入";
1530
1658
  readonly 'view.export': "导出备份";
1531
1659
  readonly 'view.import': "导入恢复";
1532
1660
  readonly 'view.snapshots': "备份与快照";
1533
1661
  readonly 'view.sync': "远程同步";
1534
1662
  readonly 'view.market': "配置市场";
1535
1663
  readonly 'view.about': "关于";
1664
+ readonly 'view.profiles': "配置文件";
1536
1665
  readonly 'common.close': "关闭";
1537
1666
  readonly 'common.cancel': "取消";
1538
1667
  readonly 'common.back': "上一步";
@@ -1558,6 +1687,10 @@ declare const zh$2: {
1558
1687
  readonly 'export.includeSecrets': "导出密钥";
1559
1688
  readonly 'export.includeSecretsHint': "把真实密钥(凭据值)写入备份。密钥必须以加密形式保存:勾选时会自动选中「加密备份」;取消「加密备份」会同时取消「导出密钥」。";
1560
1689
  readonly 'export.run': "开始导出";
1690
+ readonly 'export.preview': "预览将导出内容";
1691
+ readonly 'export.previewing': "正在统计…";
1692
+ readonly 'export.previewSummary': "将打包 {sections} 个分区,约 {size}(不含密钥)";
1693
+ readonly 'export.previewSkipped': "{count} 个分区导出失败已跳过";
1561
1694
  readonly 'export.running': "正在导出…";
1562
1695
  readonly 'export.download': "下载备份文件";
1563
1696
  readonly 'export.saved': "已保存到下载目录:{name}";
@@ -1565,6 +1698,13 @@ declare const zh$2: {
1565
1698
  readonly 'export.group.unknown': "其他";
1566
1699
  readonly 'export.included': "已包含";
1567
1700
  readonly 'export.excluded': "未包含";
1701
+ readonly 'export.naming': "文件名与备注(可选)";
1702
+ readonly 'export.fileName': "自定义文件名";
1703
+ readonly 'export.fileNameHint': "留空自动命名(dsh-config-<日期>.zip);无需手动输入 .zip 后缀,保存时自动补全。仅允许字母数字、空格、- _ .。";
1704
+ readonly 'export.fileNameInvalid': "文件名不合法:仅允许字母数字、空格、- _ .,不能包含路径分隔符。";
1705
+ readonly 'export.note': "备注";
1706
+ readonly 'export.notePlaceholder': "例如:迁移前的完整备份 / 2026-08 存档";
1707
+ readonly 'export.noteHint': "备注保存在本机备份列表中(随配置备份迁移),便于区分多个导出产物。";
1568
1708
  readonly 'import.select.title': "选择备份文件";
1569
1709
  readonly 'import.select.hint': "选择本机导出的 dsh-config-*.zip 备份文件开始导入。分析阶段只读,不会修改任何配置。";
1570
1710
  readonly 'import.select.browse': "选择 ZIP 文件";
@@ -1634,11 +1774,19 @@ declare const zh$2: {
1634
1774
  readonly 'snapshots.status': "状态";
1635
1775
  readonly 'snapshots.entries': "条目";
1636
1776
  readonly 'snapshots.plugins': "插件";
1777
+ readonly 'snapshots.actions': "操作";
1778
+ readonly 'snapshots.retentionHint': "最多自动保留 {count} 个快照(超出清理最旧的);置顶的快照不参与自动清理,只能手动删除。";
1779
+ readonly 'snapshots.pin': "置顶";
1780
+ readonly 'snapshots.unpin': "取消置顶";
1781
+ readonly 'snapshots.delete': "删除";
1782
+ readonly 'snapshots.deleteConfirmTitle': "删除快照";
1783
+ readonly 'snapshots.deleteConfirm': "确认删除 {time} 创建的快照?该导入前回滚点将被永久删除,不可恢复。";
1637
1784
  readonly 'snapshots.status.pending': "进行中";
1638
1785
  readonly 'snapshots.status.done': "已完成";
1639
1786
  readonly 'snapshots.status.rolled-back': "已回滚";
1640
1787
  readonly 'snapshots.status.unknown': "未知";
1641
1788
  readonly 'snapshots.planTitle': "恢复计划预览";
1789
+ readonly 'snapshots.viewPlan': "查看恢复计划";
1642
1790
  readonly 'snapshots.noActions': "该快照无可用恢复动作(或全部跳过)。";
1643
1791
  readonly 'snapshots.execute': "执行恢复";
1644
1792
  readonly 'snapshots.executing': "恢复执行中…";
@@ -1659,6 +1807,15 @@ declare const zh$2: {
1659
1807
  readonly 'backupSchedule.interval.12h': "每 12 小时";
1660
1808
  readonly 'backupSchedule.interval.24h': "每 24 小时";
1661
1809
  readonly 'backupSchedule.interval.7d': "每 7 天";
1810
+ readonly 'backupSchedule.interval.custom': "自定义(每周固定时刻)";
1811
+ readonly 'backupSchedule.customHint': "每周在选定星期与时刻各执行一次全量备份(错过的时间点不补跑)";
1812
+ readonly 'backupSchedule.weekday.sunday': "周日";
1813
+ readonly 'backupSchedule.weekday.monday': "周一";
1814
+ readonly 'backupSchedule.weekday.tuesday': "周二";
1815
+ readonly 'backupSchedule.weekday.wednesday': "周三";
1816
+ readonly 'backupSchedule.weekday.thursday': "周四";
1817
+ readonly 'backupSchedule.weekday.friday': "周五";
1818
+ readonly 'backupSchedule.weekday.saturday': "周六";
1662
1819
  readonly 'backupSchedule.save': "保存设置";
1663
1820
  readonly 'backupSchedule.saved': "设置已保存";
1664
1821
  readonly 'backupSchedule.runNow': "立即备份";
@@ -1668,6 +1825,7 @@ declare const zh$2: {
1668
1825
  readonly 'backupSchedule.status.success': "成功";
1669
1826
  readonly 'backupSchedule.status.skipped': "已跳过";
1670
1827
  readonly 'backupSchedule.status.failed': "失败";
1828
+ readonly 'backupSchedule.consecutiveFailures': "定时备份连续失败 {count} 次,请检查配置(磁盘空间 / 权限 / 分区导出错误)";
1671
1829
  readonly 'backupSchedule.loading': "加载定时备份设置…";
1672
1830
  readonly 'backupSchedule.error': "定时备份设置加载失败";
1673
1831
  readonly 'backupFiles.title': "备份文件";
@@ -1682,6 +1840,19 @@ declare const zh$2: {
1682
1840
  readonly 'backupFiles.delete': "删除";
1683
1841
  readonly 'backupFiles.deleteConfirmTitle': "删除备份文件";
1684
1842
  readonly 'backupFiles.deleteConfirm': "确认删除备份文件「{name}」?此操作不可恢复。";
1843
+ readonly 'backupFiles.searchPlaceholder': "按文件名或备注搜索…";
1844
+ readonly 'backupFiles.searchEmpty': "没有匹配的备份文件";
1845
+ readonly 'backupFiles.inspect': "查看 / 对比";
1846
+ readonly 'backupFiles.inspectLoading': "正在分析备份内容…";
1847
+ readonly 'backupFiles.inspectEmpty': "该备份无法分析(文件损坏或格式不支持)";
1848
+ readonly 'backupFiles.inspectSections': "包含的分区";
1849
+ readonly 'backupFiles.inspectDiff': "与此备份的差异(只读预览)";
1850
+ readonly 'backupFiles.inspectItems': "变更明细";
1851
+ readonly 'backupFiles.inspectGroup.conflicts': "冲突(需决策)";
1852
+ readonly 'backupFiles.inspectGroup.changes': "变更(将写入)";
1853
+ readonly 'backupFiles.inspectGroup.paths': "路径映射(需处理)";
1854
+ readonly 'backupFiles.inspectGroup.skipped': "已一致(无需处理)";
1855
+ readonly 'backupFiles.inspectGroup.others': "其他";
1685
1856
  readonly 'report.export.title': "导出完成";
1686
1857
  readonly 'report.import.title': "导入结果";
1687
1858
  readonly 'report.rollback.title': "回滚报告";
@@ -1689,6 +1860,14 @@ declare const zh$2: {
1689
1860
  readonly 'report.action.viewDetails': "查看详情";
1690
1861
  readonly 'report.action.done': "完成";
1691
1862
  readonly 'report.needsRestart': "插件 / MCP 变更将在重启 DSH 后生效。";
1863
+ readonly 'nextSteps.title': "接下来需要处理";
1864
+ readonly 'nextSteps.done': "全部完成,无需额外处理";
1865
+ readonly 'nextSteps.restart.title': "重启 DSH 后生效({count})";
1866
+ readonly 'nextSteps.restart.hint': "以下变更需要重启 DSH 才会生效:";
1867
+ readonly 'nextSteps.secrets.title': "补录凭据({count})";
1868
+ readonly 'nextSteps.secrets.hint': "以下凭据未随备份导出,需在本机手动补录:";
1869
+ readonly 'nextSteps.unresolved.title': "失败 / 已跳过({count})";
1870
+ readonly 'nextSteps.unresolved.hint': "以下项未成功应用,可在结果页点击「重试」:";
1692
1871
  readonly 'error.title': "操作失败";
1693
1872
  readonly 'error.hint': "错误消息已自动脱敏,不会泄露任何密钥信息。";
1694
1873
  readonly 'starPrompt.title': "喜欢 Config Manager 吗?";
@@ -1708,6 +1887,49 @@ declare const zh$2: {
1708
1887
  readonly 'about.authorLabel': "作者";
1709
1888
  readonly 'about.loading': "正在获取版本信息…";
1710
1889
  readonly 'about.retryStatus': "重新获取";
1890
+ readonly 'about.cli.title': "CLI 救援工具";
1891
+ readonly 'about.cli.hint': "GUI 运行在 DSH 内部——DSH 无法启动时,独立安装的 CLI(dsh-config-manager)是第一救援手段:列快照 / 离线恢复 / 一键重装 DSH,全程无需 DSH 运行。安装一次即可在任何机器上用:";
1892
+ readonly 'about.cli.docs': "CLI 使用文档";
1893
+ readonly 'profiles.title': "配置档案";
1894
+ readonly 'profiles.subtitle': "把当前 DSH 配置保存为多套档案(Work / Personal / …),随时切换;切换含预览 + 自动快照 + 失败回滚。";
1895
+ readonly 'profiles.save.title': "保存当前配置为档案";
1896
+ readonly 'profiles.save.hint': "输入档案名并保存:内容复用导出管道(不含密钥),文件类分区(技能/预设)一并内嵌。";
1897
+ readonly 'profiles.save.placeholder': "例如 Work / Personal / Minimal";
1898
+ readonly 'profiles.save.action': "保存档案";
1899
+ readonly 'profiles.save.saving': "保存中…";
1900
+ readonly 'profiles.nameInvalid': "档案名不合法:仅允许字母数字与常见字符,禁止路径分隔符(/ \\)与 ..";
1901
+ readonly 'profiles.name': "档案名";
1902
+ readonly 'profiles.sections': "分区";
1903
+ readonly 'profiles.updatedAt': "更新时间";
1904
+ readonly 'profiles.loading': "加载档案中…";
1905
+ readonly 'profiles.empty': "暂无档案。先保存一份当前配置即可开始。";
1906
+ readonly 'profiles.switch': "切换";
1907
+ readonly 'profiles.previewHint': "点击查看切换预览(只读)";
1908
+ readonly 'profiles.rename': "重命名";
1909
+ readonly 'profiles.delete': "删除";
1910
+ readonly 'profiles.renameTitle': "重命名档案";
1911
+ readonly 'profiles.renameMessage': "将档案「{name}」重命名为:";
1912
+ readonly 'profiles.deleteTitle': "删除档案";
1913
+ readonly 'profiles.deleteMessage': "确认删除档案「{name}」?该组配置快照将被永久删除,不可恢复。";
1914
+ readonly 'profiles.import.title': "导入档案";
1915
+ readonly 'profiles.import.hint': "导入导出的 profile.json 文件(本机或他机导出的档案,含文件类分区内嵌数据)。";
1916
+ readonly 'profiles.import.choose': "选择 JSON 文件";
1917
+ readonly 'profiles.switchPreviewTitle': "切换预览:{name}";
1918
+ readonly 'profiles.previewing': "正在分析切换计划…";
1919
+ readonly 'profiles.previewSummary': "切换影响";
1920
+ readonly 'profiles.previewWillChange': "将变更 {count} 项";
1921
+ readonly 'profiles.previewUnchanged': "已一致 {count} 项";
1922
+ readonly 'profiles.previewConflicts': "冲突 {count}";
1923
+ readonly 'profiles.previewSecrets': "需补录密钥 {count}";
1924
+ readonly 'profiles.previewRestart': "需重启 DSH 生效";
1925
+ readonly 'profiles.previewNote': "以上为只读预览(零写入)。确认后会自动创建快照并执行,失败时整体回滚。";
1926
+ readonly 'profiles.previewSections': "档案包含的分区";
1927
+ readonly 'profiles.previewItems': "变更明细";
1928
+ readonly 'profiles.switchConfirm': "确认切换";
1929
+ readonly 'profiles.switching': "切换中…(自动快照 + 分阶段应用)";
1930
+ readonly 'profiles.switchDone': "切换完成:{count} 项已应用";
1931
+ readonly 'profiles.switchFailed': "切换失败(部分项未应用)";
1932
+ readonly 'profiles.switchRolledBack': "切换失败,已整体回滚";
1711
1933
  };
1712
1934
  /** 字典键联合(注册处 compile-time 校验) */
1713
1935
  type ConfigManagerKey = keyof typeof zh$2;
@@ -1808,6 +2030,11 @@ declare const zh$1: {
1808
2030
  readonly 'syncflow.rollingBack': "正在回滚…";
1809
2031
  readonly 'syncflow.rollbackDone': "已回滚到应用前";
1810
2032
  readonly 'syncflow.needsRestart': "部分改动需要重启 DSH 后生效";
2033
+ readonly 'syncflow.pushPreviewTitle': "确认推送";
2034
+ readonly 'syncflow.pushPreviewSections': "将推送的分区";
2035
+ readonly 'syncflow.pushConfirm': "确认推送";
2036
+ readonly 'syncflow.pushing': "正在推送…";
2037
+ readonly 'syncflow.pushFirstBaseline': "远端暂无快照:本次将创建首个同步基线";
1811
2038
  readonly 'mode.title': "同步模式";
1812
2039
  readonly 'mode.hint': "选择推送时导出哪些分区:默认 = 推荐分区一键推送(快速导出);高级 = 自定义勾选(自定义导出)。";
1813
2040
  readonly 'mode.default': "默认(快速导出)";
@@ -1913,6 +2140,8 @@ declare const zh: {
1913
2140
  readonly 'list.noItems': "该市场暂无条目。";
1914
2141
  readonly 'list.searchPlaceholder': "搜索名称 / 作者 / 描述…";
1915
2142
  readonly 'list.categoriesAll': "全部类别";
2143
+ readonly 'list.sectionsAll': "全部分区";
2144
+ readonly 'list.sectionsUnknown': "另有 {count} 个条目未下载,无法按分区匹配";
1916
2145
  readonly 'list.sourceAll': "全部来源";
1917
2146
  readonly 'list.sourceOfficial': "官方配置";
1918
2147
  readonly 'list.sourcePersonal': "个人配置";
@@ -1935,6 +2164,12 @@ declare const zh: {
1935
2164
  readonly 'detail.emptySections': "该条目未包含任何可导入分区";
1936
2165
  readonly 'detail.needReview': "需要人工确认";
1937
2166
  readonly 'detail.previewHint': "以下为只读 dry-run 预览(零写入)。确认导入将复用现有安全管道(快照 + 校验 + 失败回滚)。";
2167
+ readonly 'detail.impact.willChange': "将变更 {count} 项";
2168
+ readonly 'detail.impact.unchanged': "已一致 {count} 项";
2169
+ readonly 'detail.impact.conflicts': "冲突 {count}";
2170
+ readonly 'detail.impact.secrets': "需补录密钥 {count}";
2171
+ readonly 'detail.impact.paths': "路径映射 {count}";
2172
+ readonly 'detail.impact.restart': "需重启 DSH 生效";
1938
2173
  readonly 'detail.import': "确认导入";
1939
2174
  readonly 'detail.back': "返回列表";
1940
2175
  readonly 'detail.approval.title': "逐分区批准导入";