dsh-config-manager 0.1.63 → 0.1.65

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 (547) hide show
  1. package/README.md +66 -14
  2. package/README.zh-CN.md +43 -13
  3. package/lib/adapters/agent-instructions.d.ts +3 -3
  4. package/lib/adapters/agent-instructions.js +5 -3
  5. package/lib/adapters/agent-presets.d.ts +3 -3
  6. package/lib/adapters/agent-presets.js +5 -3
  7. package/lib/adapters/credentials.d.ts +3 -3
  8. package/lib/adapters/credentials.js +20 -23
  9. package/lib/adapters/file-collection.d.ts +43 -0
  10. package/lib/adapters/file-collection.js +130 -18
  11. package/lib/adapters/index.d.ts +1 -0
  12. package/lib/adapters/index.js +11 -0
  13. package/lib/adapters/json-section.d.ts +32 -0
  14. package/lib/adapters/json-section.js +61 -0
  15. package/lib/adapters/mcp.d.ts +3 -3
  16. package/lib/adapters/mcp.js +16 -19
  17. package/lib/adapters/plugin-files.d.ts +3 -3
  18. package/lib/adapters/plugin-files.js +11 -14
  19. package/lib/adapters/plugins.d.ts +3 -3
  20. package/lib/adapters/plugins.js +39 -42
  21. package/lib/adapters/prompts.d.ts +3 -3
  22. package/lib/adapters/prompts.js +16 -20
  23. package/lib/adapters/providers.d.ts +3 -3
  24. package/lib/adapters/providers.js +23 -26
  25. package/lib/adapters/sessions.d.ts +97 -1
  26. package/lib/adapters/sessions.js +455 -15
  27. package/lib/adapters/settings.d.ts +3 -3
  28. package/lib/adapters/settings.js +23 -26
  29. package/lib/adapters/skills.d.ts +3 -3
  30. package/lib/adapters/skills.js +5 -3
  31. package/lib/adapters/test-helpers.d.ts +8 -0
  32. package/lib/adapters/test-helpers.js +8 -0
  33. package/lib/adapters/ui.d.ts +3 -3
  34. package/lib/adapters/ui.js +14 -17
  35. package/lib/adapters/workspaces.d.ts +22 -0
  36. package/lib/adapters/workspaces.js +237 -16
  37. package/lib/cli/index.d.ts +46 -4
  38. package/lib/cli/index.js +170 -34
  39. package/lib/cli/sessions-repair.d.ts +28 -0
  40. package/lib/cli/sessions-repair.js +206 -0
  41. package/lib/client.d.ts +464 -173
  42. package/lib/client.js +14414 -8888
  43. package/lib/core/analyzer.d.ts +71 -5
  44. package/lib/core/analyzer.js +409 -112
  45. package/lib/core/backup-plan.d.ts +7 -1
  46. package/lib/core/backup-plan.js +15 -8
  47. package/lib/core/backup.d.ts +53 -2
  48. package/lib/core/backup.js +120 -24
  49. package/lib/core/boot-paths.d.ts +14 -0
  50. package/lib/core/boot-paths.js +28 -0
  51. package/lib/core/boot-rescue.d.ts +21 -0
  52. package/lib/core/boot-rescue.js +57 -1
  53. package/lib/core/boot-safety.d.ts +50 -0
  54. package/lib/core/boot-safety.js +211 -0
  55. package/lib/core/conflict-decisions.d.ts +16 -0
  56. package/lib/core/conflict-decisions.js +21 -0
  57. package/lib/core/crash-report.d.ts +15 -12
  58. package/lib/core/crash-report.js +33 -40
  59. package/lib/core/credential-status.d.ts +15 -0
  60. package/lib/core/credential-status.js +13 -0
  61. package/lib/core/exporter.d.ts +18 -0
  62. package/lib/core/exporter.js +115 -3
  63. package/lib/core/importer.d.ts +15 -2
  64. package/lib/core/importer.js +10 -3
  65. package/lib/core/index.d.ts +2 -0
  66. package/lib/core/index.js +3 -0
  67. package/lib/core/journal.d.ts +74 -5
  68. package/lib/core/journal.js +127 -12
  69. package/lib/core/messages.d.ts +54 -0
  70. package/lib/core/messages.js +110 -0
  71. package/lib/core/migration-consult.js +0 -4
  72. package/lib/core/model-tools.js +6 -9
  73. package/lib/core/path-mapping.d.ts +11 -0
  74. package/lib/core/path-mapping.js +28 -0
  75. package/lib/core/phase3-host.d.ts +79 -6
  76. package/lib/core/phase3-host.js +223 -73
  77. package/lib/core/phase4-crash-child.js +0 -1
  78. package/lib/core/plugin-cli.js +22 -2
  79. package/lib/core/reconcile.d.ts +8 -1
  80. package/lib/core/reconcile.js +12 -4
  81. package/lib/core/recovery-orchestrator.js +1 -1
  82. package/lib/core/restore.js +10 -4
  83. package/lib/core/rollback.js +1 -1
  84. package/lib/core/run-registry.d.ts +63 -3
  85. package/lib/core/run-registry.js +74 -4
  86. package/lib/core/session-meta.d.ts +27 -8
  87. package/lib/core/session-meta.js +59 -32
  88. package/lib/core/session-repair.d.ts +89 -0
  89. package/lib/core/session-repair.js +118 -0
  90. package/lib/core/session-select.d.ts +50 -0
  91. package/lib/core/session-select.js +137 -0
  92. package/lib/core/startup-barrier.d.ts +15 -0
  93. package/lib/core/startup-barrier.js +24 -2
  94. package/lib/core/transaction-coordinator.js +3 -3
  95. package/lib/core/types.d.ts +250 -0
  96. package/lib/core/validator.js +0 -1
  97. package/lib/index.d.ts +368 -6
  98. package/lib/index.js +884 -3365
  99. package/lib/market/index-parser.d.ts +2 -1
  100. package/lib/market/index-parser.js +27 -6
  101. package/lib/market/my-repo.d.ts +0 -1
  102. package/lib/market/my-repo.js +0 -6
  103. package/lib/market/prepare.d.ts +9 -0
  104. package/lib/market/prepare.js +5 -31
  105. package/lib/market/reader.js +0 -1
  106. package/lib/market/security.js +3 -9
  107. package/lib/profiles/dsh-profile-launcher.d.ts +141 -0
  108. package/lib/profiles/dsh-profile-launcher.js +396 -0
  109. package/lib/profiles/dsh-profile-manager.d.ts +49 -15
  110. package/lib/profiles/dsh-profile-manager.js +151 -48
  111. package/lib/profiles/dsh-profile-runtime.d.ts +83 -0
  112. package/lib/profiles/dsh-profile-runtime.js +194 -0
  113. package/lib/profiles/dsh-profile-shared.d.ts +117 -10
  114. package/lib/profiles/dsh-profile-shared.js +12 -0
  115. package/lib/profiles/index.d.ts +10 -3
  116. package/lib/profiles/index.js +10 -3
  117. package/lib/profiles/process-control.d.ts +37 -0
  118. package/lib/profiles/process-control.js +75 -0
  119. package/lib/routes/backup.d.ts +9 -0
  120. package/lib/routes/backup.js +99 -0
  121. package/lib/routes/consult.d.ts +9 -0
  122. package/lib/routes/consult.js +134 -0
  123. package/lib/routes/context.d.ts +9 -0
  124. package/lib/routes/context.js +2 -0
  125. package/lib/routes/history.d.ts +9 -0
  126. package/lib/routes/history.js +53 -0
  127. package/lib/routes/import.d.ts +9 -0
  128. package/lib/routes/import.js +390 -0
  129. package/lib/routes/index.d.ts +10 -0
  130. package/lib/routes/index.js +27 -0
  131. package/lib/routes/kit.d.ts +99 -0
  132. package/lib/routes/kit.js +161 -0
  133. package/lib/routes/market.d.ts +9 -0
  134. package/lib/routes/market.js +256 -0
  135. package/lib/routes/me.d.ts +9 -0
  136. package/lib/routes/me.js +170 -0
  137. package/lib/routes/prefs.d.ts +9 -0
  138. package/lib/routes/prefs.js +103 -0
  139. package/lib/routes/profiles.d.ts +9 -0
  140. package/lib/routes/profiles.js +250 -0
  141. package/lib/routes/recovery.d.ts +9 -0
  142. package/lib/routes/recovery.js +137 -0
  143. package/lib/routes/snapshots.d.ts +9 -0
  144. package/lib/routes/snapshots.js +214 -0
  145. package/lib/routes/sync.d.ts +9 -0
  146. package/lib/routes/sync.js +783 -0
  147. package/lib/schema/config.d.ts +10 -9
  148. package/lib/schema/config.js +78 -96
  149. package/lib/schema/index.d.ts +8 -1
  150. package/lib/schema/index.js +13 -1
  151. package/lib/schema/manifest.d.ts +2 -0
  152. package/lib/schema/manifest.js +1 -0
  153. package/lib/schema/section-registry.d.ts +211 -0
  154. package/lib/schema/section-registry.js +285 -0
  155. package/lib/schema/types.d.ts +13 -3
  156. package/lib/schema/versions.d.ts +11 -6
  157. package/lib/schema/versions.js +27 -1
  158. package/lib/security/secret-scanner.js +1 -1
  159. package/lib/security/zip-security.d.ts +8 -5
  160. package/lib/security/zip-security.js +20 -90
  161. package/lib/sync/ancestor.d.ts +11 -0
  162. package/lib/sync/ancestor.js +20 -0
  163. package/lib/sync/autosync-config.js +9 -18
  164. package/lib/sync/autosync-scheduler.d.ts +7 -2
  165. package/lib/sync/autosync-scheduler.js +35 -17
  166. package/lib/sync/backup-schedule-config.js +0 -1
  167. package/lib/sync/blob-store.d.ts +85 -0
  168. package/lib/sync/blob-store.js +85 -0
  169. package/lib/sync/git/git-transport.d.ts +28 -5
  170. package/lib/sync/git/git-transport.js +170 -24
  171. package/lib/sync/github-auth.d.ts +0 -1
  172. package/lib/sync/github-auth.js +0 -2
  173. package/lib/sync/layout.d.ts +16 -2
  174. package/lib/sync/layout.js +48 -7
  175. package/lib/sync/risk.d.ts +18 -12
  176. package/lib/sync/risk.js +17 -28
  177. package/lib/sync/session-tombstones.d.ts +39 -0
  178. package/lib/sync/session-tombstones.js +125 -0
  179. package/lib/sync/sync-config.d.ts +26 -3
  180. package/lib/sync/sync-config.js +40 -3
  181. package/lib/sync/sync-engine.d.ts +140 -12
  182. package/lib/sync/sync-engine.js +266 -49
  183. package/lib/sync/sync-history.js +0 -1
  184. package/lib/sync/sync-selection.d.ts +18 -0
  185. package/lib/sync/sync-selection.js +50 -24
  186. package/lib/sync/sync-state.d.ts +31 -4
  187. package/lib/sync/sync-state.js +38 -6
  188. package/lib/sync/transport.d.ts +103 -0
  189. package/lib/sync/transport.js +121 -0
  190. package/lib/sync/ui-prefs.d.ts +4 -2
  191. package/lib/sync/ui-prefs.js +6 -4
  192. package/lib/sync/webdav/webdav-transport.d.ts +36 -4
  193. package/lib/sync/webdav/webdav-transport.js +242 -43
  194. package/lib/ui/dsh-profiles-view.d.ts +52 -9
  195. package/lib/ui/dsh-profiles-view.js +80 -13
  196. package/lib/ui/export-flow.d.ts +2 -2
  197. package/lib/ui/export-flow.js +63 -17
  198. package/lib/ui/i18n.d.ts +12 -2
  199. package/lib/ui/i18n.js +25 -4
  200. package/lib/ui/import-log.d.ts +72 -0
  201. package/lib/ui/import-log.js +110 -0
  202. package/lib/ui/import-stepper.d.ts +14 -0
  203. package/lib/ui/import-stepper.js +18 -0
  204. package/lib/ui/import-wizard.d.ts +106 -3
  205. package/lib/ui/import-wizard.js +125 -7
  206. package/lib/ui/mid-ellipsis.d.ts +31 -0
  207. package/lib/ui/mid-ellipsis.js +39 -0
  208. package/lib/ui/my-configs-view.d.ts +136 -0
  209. package/lib/ui/my-configs-view.js +127 -0
  210. package/lib/ui/progress.js +6 -0
  211. package/lib/ui/report.d.ts +26 -0
  212. package/lib/ui/report.js +37 -0
  213. package/lib/ui/runs-view.d.ts +128 -0
  214. package/lib/ui/runs-view.js +123 -0
  215. package/lib/ui/select-model.d.ts +51 -0
  216. package/lib/ui/select-model.js +84 -0
  217. package/lib/ui/selection-model.d.ts +118 -2
  218. package/lib/ui/selection-model.js +291 -4
  219. package/lib/ui/snapshots-view.d.ts +116 -0
  220. package/lib/ui/snapshots-view.js +141 -0
  221. package/lib/ui/sync-settings-view.d.ts +295 -0
  222. package/lib/ui/sync-settings-view.js +280 -0
  223. package/lib/ui/test-helpers.d.ts +7 -1
  224. package/lib/ui/test-helpers.js +4 -1
  225. package/lib/ui/types.d.ts +8 -1
  226. package/lib/utils/env-lock.d.ts +77 -5
  227. package/lib/utils/env-lock.js +171 -57
  228. package/lib/utils/logger.d.ts +17 -13
  229. package/lib/utils/logger.js +79 -41
  230. package/lib/utils/paths.d.ts +1 -1
  231. package/lib/utils/paths.js +2 -2
  232. package/lib/utils/session-log.d.ts +70 -0
  233. package/lib/utils/session-log.js +347 -0
  234. package/lib/utils/zip.d.ts +49 -5
  235. package/lib/utils/zip.js +240 -51
  236. package/lib/utils/zstd-frame.d.ts +44 -0
  237. package/lib/utils/zstd-frame.js +115 -0
  238. package/package.json +4 -2
  239. package/src/adapters/agent-instructions.ts +5 -3
  240. package/src/adapters/agent-presets.ts +5 -3
  241. package/src/adapters/credentials.ts +19 -22
  242. package/src/adapters/file-collection.test.ts +256 -0
  243. package/src/adapters/file-collection.ts +129 -17
  244. package/src/adapters/index.ts +12 -1
  245. package/src/adapters/json-section.ts +73 -0
  246. package/src/adapters/mcp.ts +16 -19
  247. package/src/adapters/plugin-files.ts +11 -14
  248. package/src/adapters/plugins.test.ts +1 -1
  249. package/src/adapters/plugins.ts +39 -42
  250. package/src/adapters/prompts.ts +16 -20
  251. package/src/adapters/providers.ts +22 -25
  252. package/src/adapters/roundtrip.test.ts +44 -0
  253. package/src/adapters/sessions.test.ts +400 -1
  254. package/src/adapters/sessions.ts +435 -16
  255. package/src/adapters/settings.ts +22 -25
  256. package/src/adapters/skills.ts +5 -3
  257. package/src/adapters/test-helpers.ts +8 -0
  258. package/src/adapters/ui.ts +14 -17
  259. package/src/adapters/workspaces.test.ts +226 -2
  260. package/src/adapters/workspaces.ts +247 -16
  261. package/src/cli/index.ts +180 -37
  262. package/src/cli/sessions-repair.ts +229 -0
  263. package/src/client/CLIENT_DEPENDENCIES.md +3 -1
  264. package/src/client/ConfigManagerSection.tsx +50 -46
  265. package/src/client/about/AboutPanel.tsx +22 -8
  266. package/src/client/about/about-view.test.ts +53 -6
  267. package/src/client/about/about-view.ts +26 -2
  268. package/src/client/api.ts +195 -242
  269. package/src/client/client-types.ts +2 -2
  270. package/src/client/common/ConfirmDialog.tsx +3 -2
  271. package/src/client/common/ContentPicker.tsx +53 -24
  272. package/src/client/common/CopyButton.tsx +74 -0
  273. package/src/client/common/ErrorBanner.tsx +3 -2
  274. package/src/client/common/Icon.tsx +116 -0
  275. package/src/client/common/Modal.tsx +29 -8
  276. package/src/client/common/Motion.tsx +70 -0
  277. package/src/client/common/ProgressBar.tsx +18 -9
  278. package/src/client/common/ReportView.tsx +128 -54
  279. package/src/client/common/RunsCenter.tsx +378 -0
  280. package/src/client/common/Select.tsx +223 -0
  281. package/src/client/common/Skeleton.tsx +128 -0
  282. package/src/client/common/client-route-parity.test.ts +171 -0
  283. package/src/client/common/http-usage-guard.test.ts +163 -0
  284. package/src/client/common/http.test.ts +225 -0
  285. package/src/client/common/http.ts +238 -0
  286. package/src/client/common/morph-icons.test.ts +206 -0
  287. package/src/client/common/morph-icons.ts +89 -0
  288. package/src/client/common/plan-text-redaction.test.ts +29 -7
  289. package/src/client/common/progress-view.test.ts +33 -1
  290. package/src/client/common/progress-view.ts +17 -0
  291. package/src/client/common/routes.ts +130 -0
  292. package/src/client/common/runs-center-guard.test.ts +44 -0
  293. package/src/client/common/ui.tsx +48 -5
  294. package/src/client/config-manager.module.css +877 -35
  295. package/src/client/export/ExportView.tsx +27 -3
  296. package/src/client/history/HistoryPanel.tsx +30 -30
  297. package/src/client/history/history-api.ts +34 -61
  298. package/src/client/icon-layer-guard.test.ts +137 -0
  299. package/src/client/import/ImportLogPanel.tsx +136 -0
  300. package/src/client/import/ImportWizardView.tsx +455 -838
  301. package/src/client/import/PathMappingForm.tsx +12 -1
  302. package/src/client/import/import-wizard-split.test.ts +101 -0
  303. package/src/client/import/import-wizard-steps.tsx +352 -0
  304. package/src/client/import/use-import-wizard-controller.ts +476 -0
  305. package/src/client/index.ts +4 -6
  306. package/src/client/locales.ts +258 -123
  307. package/src/client/lucide-icons.d.ts +11 -0
  308. package/src/client/market/MarketPanel.tsx +39 -37
  309. package/src/client/market/MyConfigsInstall.tsx +93 -0
  310. package/src/client/market/MyConfigsList.tsx +121 -0
  311. package/src/client/market/MyConfigsLoginCard.tsx +100 -0
  312. package/src/client/market/MyConfigsView.tsx +148 -476
  313. package/src/client/market/MyConfigsWizard.tsx +252 -0
  314. package/src/client/market/market-api.test.ts +36 -0
  315. package/src/client/market/market-api.ts +13 -70
  316. package/src/client/market/market-view.ts +1 -1
  317. package/src/client/market/my-configs-api.ts +17 -71
  318. package/src/client/market/my-configs-split.test.ts +58 -0
  319. package/src/client/overview/OverviewPanel.tsx +5 -48
  320. package/src/client/profiles/ProfilesPanel.tsx +422 -215
  321. package/src/client/recovery/RecoveryPanel.tsx +121 -5
  322. package/src/client/recovery/incident-api.ts +91 -0
  323. package/src/client/recovery/recovery-api.ts +15 -65
  324. package/src/client/recovery/recovery-locales.ts +56 -0
  325. package/src/client/recovery/recovery-view.ts +71 -0
  326. package/src/client/run-store.test.ts +593 -3
  327. package/src/client/run-store.ts +430 -80
  328. package/src/client/snapshots/BackupScheduleCard.tsx +434 -0
  329. package/src/client/snapshots/RestorePlanView.tsx +8 -5
  330. package/src/client/snapshots/SnapshotsEmptyState.tsx +31 -0
  331. package/src/client/snapshots/SnapshotsListTable.tsx +97 -0
  332. package/src/client/snapshots/SnapshotsPanel.tsx +55 -630
  333. package/src/client/sync/AutosyncCard.tsx +84 -0
  334. package/src/client/sync/ChannelConfigDialog.tsx +266 -0
  335. package/src/client/sync/DecryptPasswordCard.tsx +48 -0
  336. package/src/client/sync/SecurityOptionsCard.tsx +83 -0
  337. package/src/client/sync/SyncChannelEntryCard.tsx +78 -0
  338. package/src/client/sync/SyncConfirmView.tsx +10 -8
  339. package/src/client/sync/SyncHistoryView.tsx +3 -2
  340. package/src/client/sync/SyncSectionPickerDialog.tsx +182 -0
  341. package/src/client/sync/SyncSettingsView.test.ts +85 -0
  342. package/src/client/sync/SyncSettingsView.tsx +247 -667
  343. package/src/client/sync/history-model.ts +4 -10
  344. package/src/client/sync/sync-api.ts +59 -100
  345. package/src/client/sync/sync-locales.ts +16 -2
  346. package/src/client/sync/sync-view-v2.test.ts +30 -4
  347. package/src/client/sync/sync-view.ts +67 -17
  348. package/src/core/analyzer-mapping.test.ts +55 -0
  349. package/src/core/analyzer.ts +458 -111
  350. package/src/core/apply-order.test.ts +182 -0
  351. package/src/core/backup-plan.test.ts +141 -0
  352. package/src/core/backup-plan.ts +16 -8
  353. package/src/core/backup.test.ts +310 -0
  354. package/src/core/backup.ts +174 -23
  355. package/src/core/base-path-rebase.test.ts +97 -0
  356. package/src/core/boot-paths.test.ts +35 -0
  357. package/src/core/boot-paths.ts +29 -0
  358. package/src/core/boot-rescue.test.ts +108 -0
  359. package/src/core/boot-rescue.ts +57 -1
  360. package/src/core/boot-safety.test.ts +138 -0
  361. package/src/core/boot-safety.ts +248 -0
  362. package/src/core/conflict-decisions.ts +34 -0
  363. package/src/core/crash-report.test.ts +25 -41
  364. package/src/core/crash-report.ts +34 -41
  365. package/src/core/credential-status.test.ts +35 -0
  366. package/src/core/credential-status.ts +25 -0
  367. package/src/core/export-coupling.test.ts +255 -0
  368. package/src/core/exporter.ts +110 -3
  369. package/src/core/finalize-order.test.ts +82 -0
  370. package/src/core/import-sessions-visibility.test.ts +93 -0
  371. package/src/core/importer.ts +21 -3
  372. package/src/core/incident-wiring.test.ts +96 -0
  373. package/src/core/index.ts +10 -0
  374. package/src/core/journal.test.ts +59 -2
  375. package/src/core/journal.ts +152 -10
  376. package/src/core/messages.ts +110 -0
  377. package/src/core/migration-consult.ts +0 -5
  378. package/src/core/migration-history.test.ts +3 -5
  379. package/src/core/model-tools.test.ts +0 -14
  380. package/src/core/model-tools.ts +6 -8
  381. package/src/core/path-mapping.ts +33 -0
  382. package/src/core/phase3-consistency.test.ts +1 -1
  383. package/src/core/phase3-host.ts +248 -70
  384. package/src/core/phase3-p2b-fingerprint.test.ts +0 -1
  385. package/src/core/phase3-production-integration.test.ts +1 -1
  386. package/src/core/phase4-crash-child.ts +0 -1
  387. package/src/core/phase4-crash-injection.test.ts +1 -3
  388. package/src/core/plugin-cli.fs.test.ts +54 -2
  389. package/src/core/plugin-cli.ts +21 -2
  390. package/src/core/reconcile.test.ts +62 -0
  391. package/src/core/reconcile.ts +20 -5
  392. package/src/core/recovery-orchestrator.test.ts +13 -1
  393. package/src/core/recovery-orchestrator.ts +1 -1
  394. package/src/core/restore.ts +10 -4
  395. package/src/core/rollback.ts +1 -1
  396. package/src/core/run-registry-runs.test.ts +71 -0
  397. package/src/core/run-registry.test.ts +58 -7
  398. package/src/core/run-registry.ts +96 -5
  399. package/src/core/session-meta.test.ts +59 -1
  400. package/src/core/session-meta.ts +62 -29
  401. package/src/core/session-repair.test.ts +91 -0
  402. package/src/core/session-repair.ts +203 -0
  403. package/src/core/session-select.test.ts +73 -0
  404. package/src/core/session-select.ts +131 -0
  405. package/src/core/smoke.test.ts +5 -3
  406. package/src/core/startup-barrier.ts +29 -2
  407. package/src/core/transaction-coordinator.ts +3 -3
  408. package/src/core/types.ts +253 -0
  409. package/src/core/validator.ts +0 -1
  410. package/src/index.sync.test.ts +8 -0
  411. package/src/index.ts +611 -2922
  412. package/src/market/git-file-writer.test.ts +1 -1
  413. package/src/market/index-parser.ts +29 -6
  414. package/src/market/market.test.ts +146 -1
  415. package/src/market/my-repo.test.ts +57 -4
  416. package/src/market/my-repo.ts +0 -7
  417. package/src/market/prepare.ts +12 -32
  418. package/src/market/reader.ts +0 -1
  419. package/src/market/security.ts +3 -11
  420. package/src/profiles/dsh-profile-launcher.test.ts +359 -0
  421. package/src/profiles/dsh-profile-launcher.ts +473 -0
  422. package/src/profiles/dsh-profile-manager.test.ts +123 -59
  423. package/src/profiles/dsh-profile-manager.ts +148 -51
  424. package/src/profiles/dsh-profile-runtime.test.ts +196 -0
  425. package/src/profiles/dsh-profile-runtime.ts +228 -0
  426. package/src/profiles/dsh-profile-shared.ts +126 -9
  427. package/src/profiles/index.ts +30 -4
  428. package/src/profiles/process-control.ts +99 -0
  429. package/src/routes/backup.ts +103 -0
  430. package/src/routes/consult.ts +139 -0
  431. package/src/routes/context.ts +10 -0
  432. package/src/routes/history.ts +56 -0
  433. package/src/routes/import.ts +399 -0
  434. package/src/routes/index.ts +36 -0
  435. package/src/routes/kit.ts +223 -0
  436. package/src/routes/market.ts +275 -0
  437. package/src/routes/me.ts +168 -0
  438. package/src/routes/prefs.ts +104 -0
  439. package/src/routes/profiles.ts +252 -0
  440. package/src/routes/recovery.ts +113 -0
  441. package/src/routes/snapshots.ts +219 -0
  442. package/src/routes/sync.ts +810 -0
  443. package/src/schema/config.ts +96 -91
  444. package/src/schema/index.ts +33 -1
  445. package/src/schema/manifest.ts +3 -0
  446. package/src/schema/registry.test.ts +293 -0
  447. package/src/schema/section-registry.ts +463 -0
  448. package/src/schema/types.ts +13 -3
  449. package/src/schema/versions.ts +31 -1
  450. package/src/security/secret-scanner.ts +1 -1
  451. package/src/security/security.test.ts +145 -2
  452. package/src/security/zip-security.ts +20 -92
  453. package/src/sync/ancestor.test.ts +0 -1
  454. package/src/sync/ancestor.ts +23 -0
  455. package/src/sync/autosync-config.ts +9 -18
  456. package/src/sync/autosync-scheduler.test.ts +60 -3
  457. package/src/sync/autosync-scheduler.ts +45 -19
  458. package/src/sync/backup-schedule-config.ts +0 -1
  459. package/src/sync/backup-scheduler.test.ts +15 -2
  460. package/src/sync/blob-store.test.ts +191 -0
  461. package/src/sync/blob-store.ts +139 -0
  462. package/src/sync/git/git-transport.test.ts +203 -1
  463. package/src/sync/git/git-transport.ts +173 -24
  464. package/src/sync/github-auth.ts +0 -2
  465. package/src/sync/layout.ts +62 -8
  466. package/src/sync/risk.test.ts +32 -1
  467. package/src/sync/risk.ts +26 -31
  468. package/src/sync/session-tombstones.test.ts +87 -0
  469. package/src/sync/session-tombstones.ts +123 -0
  470. package/src/sync/sync-config.test.ts +132 -0
  471. package/src/sync/sync-config.ts +47 -6
  472. package/src/sync/sync-credentials.test.ts +77 -0
  473. package/src/sync/sync-engine.test.ts +799 -8
  474. package/src/sync/sync-engine.ts +322 -51
  475. package/src/sync/sync-history.ts +0 -1
  476. package/src/sync/sync-selection.test.ts +43 -7
  477. package/src/sync/sync-selection.ts +56 -24
  478. package/src/sync/sync-state.test.ts +83 -0
  479. package/src/sync/sync-state.ts +58 -7
  480. package/src/sync/transport.ts +191 -0
  481. package/src/sync/ui-prefs.ts +10 -6
  482. package/src/sync/webdav/webdav-transport.test.ts +122 -2
  483. package/src/sync/webdav/webdav-transport.ts +256 -37
  484. package/src/ui/dsh-profiles-view.test.ts +87 -12
  485. package/src/ui/dsh-profiles-view.ts +106 -17
  486. package/src/ui/export-flow.ts +65 -18
  487. package/src/ui/i18n.test.ts +147 -0
  488. package/src/ui/i18n.ts +25 -4
  489. package/src/ui/import-log.test.ts +106 -0
  490. package/src/ui/import-log.ts +158 -0
  491. package/src/ui/import-stepper.test.ts +25 -1
  492. package/src/ui/import-stepper.ts +18 -0
  493. package/src/ui/import-wizard.test.ts +168 -2
  494. package/src/ui/import-wizard.ts +175 -8
  495. package/src/ui/market-import.test.ts +0 -1
  496. package/src/ui/mid-ellipsis.test.ts +160 -0
  497. package/src/ui/mid-ellipsis.ts +37 -0
  498. package/src/ui/my-configs-view.test.ts +222 -0
  499. package/src/ui/my-configs-view.ts +206 -0
  500. package/src/ui/progress.ts +6 -0
  501. package/src/ui/report.test.ts +32 -2
  502. package/src/ui/report.ts +52 -0
  503. package/src/ui/runs-view.test.ts +152 -0
  504. package/src/ui/runs-view.ts +207 -0
  505. package/src/ui/select-model.test.ts +75 -0
  506. package/src/ui/select-model.ts +92 -0
  507. package/src/ui/selection-model.test.ts +315 -12
  508. package/src/ui/selection-model.ts +327 -4
  509. package/src/ui/snapshots-view.test.ts +228 -0
  510. package/src/ui/snapshots-view.ts +233 -0
  511. package/src/ui/sync-settings-view.test.ts +348 -0
  512. package/src/ui/sync-settings-view.ts +516 -0
  513. package/src/ui/test-helpers.ts +8 -1
  514. package/src/ui/types.ts +10 -1
  515. package/src/utils/env-lock.test.ts +290 -107
  516. package/src/utils/env-lock.ts +209 -54
  517. package/src/utils/logger.test.ts +178 -1
  518. package/src/utils/logger.ts +81 -44
  519. package/src/utils/paths.ts +2 -2
  520. package/src/utils/session-log.test.ts +136 -0
  521. package/src/utils/session-log.ts +344 -0
  522. package/src/utils/zip.test.ts +284 -0
  523. package/src/utils/zip.ts +226 -52
  524. package/src/utils/zstd-frame.test.ts +80 -0
  525. package/src/utils/zstd-frame.ts +131 -0
  526. package/lib/core/config-lifecycle.d.ts +0 -180
  527. package/lib/core/config-lifecycle.js +0 -481
  528. package/lib/core/config-snapshot.d.ts +0 -135
  529. package/lib/core/config-snapshot.js +0 -424
  530. package/lib/core/config-state.d.ts +0 -70
  531. package/lib/core/config-state.js +0 -177
  532. package/lib/core/undo.d.ts +0 -73
  533. package/lib/core/undo.js +0 -87
  534. package/lib/core/watcher.d.ts +0 -101
  535. package/lib/core/watcher.js +0 -219
  536. package/src/client/lifecycle/LifecyclePanel.tsx +0 -525
  537. package/src/client/lifecycle/lifecycle-api.ts +0 -249
  538. package/src/core/config-lifecycle.test.ts +0 -727
  539. package/src/core/config-lifecycle.ts +0 -573
  540. package/src/core/config-snapshot.test.ts +0 -369
  541. package/src/core/config-snapshot.ts +0 -522
  542. package/src/core/config-state.test.ts +0 -381
  543. package/src/core/config-state.ts +0 -207
  544. package/src/core/phase1-wiring.test.ts +0 -139
  545. package/src/core/undo.ts +0 -116
  546. package/src/core/watcher.test.ts +0 -326
  547. package/src/core/watcher.ts +0 -263
package/README.md CHANGED
@@ -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 do not sync by default; encrypted snapshots can optionally carry encrypted credentials) |
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-item content selection (change summary + in-place high-risk flags) |
82
- | 🗂️ | **Profiles (DSH profiles)** | Manage `$DSH_HOME/profiles/<name>` directly: list / create from a shipped template / rename / hard delete / record which profile the next launch should use |
82
+ | 🗂️ | **Profiles (DSH profiles)** | Manage `$DSH_HOME/profiles/<name>` directly: list / create from a shipped template / rename / hard delete / **launch this profile (independent instance)** / **stop the instance** (the row button flips between Launch and Stop with the running state) |
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
 
@@ -87,17 +87,21 @@ Browse the built-in official market for ready-made configurations (model provide
87
87
 
88
88
  ## 📸 Screenshots
89
89
 
90
+ | Overview | Backups & Snapshots |
91
+ |:---:|:---:|
92
+ | ![Overview](assets/screenshot-overview-en.png) | ![Backups and snapshots](assets/screenshot-backups-en.png) |
93
+
90
94
  | Export | Import Preview |
91
95
  |:---:|:---:|
92
- | ![One-click Export](assets/screenshot-export.png) | ![Import Preview](assets/screenshot-import-preview.png) |
96
+ | ![One-click Export](assets/screenshot-export-en.png) | ![Import Preview](assets/screenshot-import-en.png) |
93
97
 
94
- | Snapshot Restore | Remote Sync |
98
+ | Remote Sync | Configuration Market |
95
99
  |:---:|:---:|
96
- | ![Snapshot Restore](assets/screenshot-snapshots.png) | ![Remote Sync](assets/screenshot-sync.png) |
100
+ | ![Remote Sync](assets/screenshot-sync-en.png) | ![Configuration Market](assets/screenshot-market-en.png) |
97
101
 
98
- | Configuration Market |
102
+ | Profiles (DSH profiles) |
99
103
  |:---:|
100
- | ![Configuration Market](assets/screenshot-market.png) |
104
+ | ![Profiles](assets/screenshot-profiles-en.png) |
101
105
 
102
106
  ---
103
107
 
@@ -272,11 +276,18 @@ launched with `dsh --profile <name>`. This page reads and writes that directory
272
276
  | Create | Writes the standard three files under `$DSH_HOME/profiles/<name>` (equivalent to the shipped `initProfile`); starting templates: base / web / headless / sdk / sdk-minimal / acp |
273
277
  | Rename | Directory move + fixes the manifest name field; the running profile is refused |
274
278
  | Delete | **Hard-deletes the whole directory** (including node_modules); deleting the running profile needs an extra checkbox |
275
- | Next launch | Only records which profile to use next and shows the `dsh --profile <name>` restart command |
276
-
277
- > DSH **cannot switch profiles while running** (the profile comes from the launch flag and bundle layers resolve at boot),
278
- > so this page never touches processes — it records your choice and asks you to restart.
279
- > Third-party plugins must be installed into that profile separately (`dsh plugin --profile <name> add <pkg>`).
279
+ | Launch this profile | The **switch that actually works**: starts an **independent DSH instance** for that profile (free port picked automatically, browser opened automatically); the running instance and its tasks are untouched. Web-shaped profiles only — non-web ones (e.g. the base template) have no browser UI, so the page shows the terminal command instead of failing silently |
280
+ | Stop instance | While that profile has a running instance, the row button flips from Launch to Stop (the Runtime card also offers one); it asks the process to exit first (grace period) and terminates the process tree only after that, reporting which path was used. **Deleting a profile with a running instance is refused** |
281
+ | No duplicate launches | “Which profiles are running” = the ledger of instances this plugin started ∪ **each instance's own heartbeat** (`<dataDir>/running/<profile>.json`, pid/port only — **never the auth token**). So even a profile you started by hand with `dsh web` will not be launched a second time (you get a clear “already running” message); the instance you are using right now offers no Stop button (that would kill your own session — close that window/terminal, or stop it from the instance that launched it) |
282
+
283
+ > **Why there is no "set as next launch"** (button and marker removed in 2026-09): DSH has **no "default / next launch
284
+ > profile" state** — the profile comes only from the launch arguments (`dsh <name>` / `--profile <name>`; `dsh web` is a
285
+ > hard-coded alias), so any "which profile to use next" marker has **no consumer at all**: the `dsh web` you type
286
+ > yourself still boots web after a restart. Only two mechanisms really switch profiles: ① this page's "launch this
287
+ > profile" (an extra instance, no interruption, stoppable at any time), ② pointing your launch command/shortcut at
288
+ > `dsh --profile <name>` (ecosystem tools such as dshm and DSH Launcher all spawn instances from an external launcher).
289
+ > Instances started by this plugin are recorded in `<dataDir>/launches.json` (pid/port/log), which is why they can be
290
+ > stopped; third-party plugins must be installed into that profile separately (`dsh plugin --profile <name> add <pkg>`).
280
291
  > The tab lives at Settings → "Backup & Migration" → **Profiles**.
281
292
 
282
293
  ### 📸 Snapshot restore (undo an import)
@@ -331,6 +342,8 @@ dsh-config-manager verify [--id <file|path>] [--json] # read-only check
331
342
  [--data-dir <dir>]
332
343
  dsh-config-manager backup [--sections <a,b,c>] [--out <path>] # offline file-level backup
333
344
  [--dry-run] [--data-dir <dir>]
345
+ dsh-config-manager sessions repair [--home <dir>] [--fix] # offline session layout repair
346
+ [--keep <dir>] [--map old=new]...
334
347
  ```
335
348
 
336
349
  **`reinstall` — rescue when DSH is broken.** It reinstalls the `@deepseek-ai/dsh` launcher across platforms (uses the right command per OS: PowerShell on Windows, bash on Unix). By default it reinstalls the launcher + clears global caches; interactively it asks which **dangerous** clean-up items to include (settings / plugins / session data & credentials) — those are **not** selected by default, and any destructive choice requires a second confirmation by typing `YES` before anything runs. Before wiping any `~/.dsh` data it makes an emergency backup at `.reinstall-backup` (the `snapshots/` folder is deliberately never touched).
@@ -396,7 +409,7 @@ dsh-config-manager backup --sections skills,self # narrow the scope
396
409
 
397
410
  `--sections` accepts `skills,agentPresets,agentInstructions,self,pluginFiles`. `pluginFiles` is **opt-in** (as in the GUI): it copies third-party plugin files verbatim, and `dsh-ssh.json` holds plaintext host passwords — select it only when you have looked at what is in there.
398
411
 
399
- **A typical rescue flow** when DSH won't start: ① `dsh-config-manager reinstall` to bring the launcher back (plus any clean-up), ② `dsh web` to start DSH again, ③ re-add the plugin from the registry, and ④ pull a snapshot from the remote repo (or run `dsh-config-manager restore`) to bring your config back. The CLI works at every step regardless of DSH's health.
412
+ **A typical rescue flow** when DSH won't start: ① `dsh-config-manager reinstall` to bring the launcher back (plus any clean-up), ② if DSH reports a session-log error (`corrupt session log` / `duplicate JSONL session id`), run `dsh-config-manager sessions repair --fix` first — it repairs the log layout offline, ③ `dsh web` to start DSH again, ③ re-add the plugin from the registry, and ④ pull a snapshot from the remote repo (or run `dsh-config-manager restore`) to bring your config back. The CLI works at every step regardless of DSH's health.
400
413
 
401
414
  **`recover-stale-lock` — when every operation suddenly fails.** Before touching your config, the plugin claims a small environment lock (it records who is operating plus a heartbeat) so that two operations can never write your config at the same time. If a `dsh web` process is **force-killed** (Task Manager, `kill -9`), the lock file survives with a dead owner: the next operation is refused, and it stays refused **no matter how often you retry or restart DSH** — because the plugin deliberately never removes a lock on its own (a wrong guess could evict a live operation).
402
415
 
@@ -413,6 +426,25 @@ Symptoms and the fix:
413
426
  dsh-config-manager recover-stale-lock
414
427
  ```
415
428
 
429
+ **`sessions repair` — when DSH refuses to start over a session log.** DSH validates that each session log sits exactly where its own header says it belongs: `corrupt session log … header id and cwd identify …`, or `duplicate JSONL session id … in multiple project directories`. The plugin cannot help at that point (it only loads *inside* DSH), so this is the one repair path that works while DSH is down. It reads every session's first-frame cwd and moves the session directory under `projectKeyOf(cwd)` — the location DSH expects, derived from the log itself, never guessed.
430
+
431
+ - **Dry run by default** (zero writes); `--fix` performs the moves. Exit code: dry runs always 0, `--fix` returns 1 if anything failed, conflicted or rolled back.
432
+ - **`--map old=new`** (repeatable) is for cross-machine restores: a matching prefix rewrites the first-frame cwd before relocating the directory (every other frame is copied byte for byte). Targets that already exist are never overwritten.
433
+ - **`--keep <dir>`** resolves duplicate ids: the copy you name is kept, the others are moved into `sessions/.cm-repair-quarantine-<timestamp>/` — moved, never deleted. Without `--keep` duplicates are reported only.
434
+
435
+ ```bash
436
+ # see what would move (no writes at all)
437
+ dsh-config-manager sessions repair
438
+ # apply, mapping a source-machine prefix onto this machine
439
+ dsh-config-manager sessions repair --fix --map 'C:/Users/alice=D:/Work'
440
+ ```
441
+
442
+ If the two machines use **different DSH base paths** (e.g. `/opt/dsh/.dsh` vs a Windows drive path), the backup records the source base path and the import **rebases automatically** every path that lives under it (session cwd, workspace path, …) onto your local one — no mapping to type. User mappings still apply afterwards, so you can override anything.
443
+
444
+ In the content picker, selecting sessions also selects the workspaces that own them (and unchecking a workspace unchecks its sessions).
445
+
446
+ Cross-machine restores need no extra step in the GUI: **exporting sessions now carries the workspaces that own them**, and the path mapping you fill in the import wizard rewrites both the workspace paths and the sessions' first-frame cwd (relocating the directories accordingly) before the sessions are attached to those workspaces.
447
+
416
448
  **Plugins installed but the backup doesn't see them?** Check **Settings → DSH Config Manager → About**: it now shows which directory / profile the plugin list was read from, and how many plugins were detected. The list comes from `$DSH_HOME/profiles/<profile>/package.json` → `dependencies` (plus anything declared in `dsh.profile.bundles` that is not a dependency), where `<profile>` is resolved as `config.profile` → `--profile` → `web`. If the shown path is not the profile you installed into (Desktop builds may use a different profile or a different `DSH_HOME`), that is the cause — align `--profile` / `DSH_HOME` with it.
417
449
 
418
450
  ### 🌐 Behind a proxy? (GitHub login / sync)
@@ -515,14 +547,34 @@ Yes. The import wizard asks for the export-time encryption password and verifies
515
547
  5. **Encrypted backups**: a lost password means the `secrets.enc` can't be decrypted (by design — keep your password safe)
516
548
  6. **Snapshot restore is offline and honest**: entries the offline engine can't restore (settings namespaces / patch lines when the snapshot has no whole-file backup, workspace records stored in DSH storages) are reported as skipped with a pointer to online rollback; credential **values** are never auto-written (manual re-entry hint only); old snapshots without a plugin baseline only get a hint to remove added plugins manually
517
549
 
550
+ ## 💬 Feedback
551
+
552
+ Found a bug, a misaligned panel, a button that does nothing — or just have an idea? **All of it is welcome.** UI problems especially: they are the easiest thing to overlook and the part that real usage should decide.
553
+
554
+ | What you want to say | Where |
555
+ |---|---|
556
+ | 🎨 **UI problem**: misaligned layout, broken styling, dark mode, scaling, a control that does nothing | [UI issue form](https://github.com/xiajiajun516/dsh-config-manager/issues/new?template=ui_bug.en.yml) — screenshot + browser version is enough |
557
+ | 🐛 **Something is broken / an error / wrong data** | [Bug report](https://github.com/xiajiajun516/dsh-config-manager/issues/new?template=bug_report.en.yml) |
558
+ | ✨ **New feature idea** | [Feature request](https://github.com/xiajiajun516/dsh-config-manager/issues/new?template=feature_request.en.yml) |
559
+ | 💬 **Not sure whether it is a bug — just asking** | [Discussions](https://github.com/xiajiajun516/dsh-config-manager/discussions) |
560
+ | 🔒 **Security issue / leaked credential** | [Private security advisory](https://github.com/xiajiajun516/dsh-config-manager/security/advisories/new) (please do not open a public issue) |
561
+
562
+ **Report straight from the plugin**: Settings → Backup & Migration → **About** → "Issues"; or hit **Copy environment info** on that page — plugin version / DSH version / platform are included, so you can paste it into the issue instead of typing version numbers.
563
+
564
+ **Every report gets followed up**: a new issue receives an immediate reply and the `needs-triage` label, and progress is visible in the labels (`needs-info` → `confirmed` → `fixed`). Fixed problems end up in [CHANGELOG.md](CHANGELOG.md) under the release that fixed them, tagged with the issue number (e.g. #38 / #43 / #45) — that is where a report finally lands.
565
+
566
+ > ⚠️ Please search for an existing issue first, and **strip every API key / token / password** — including the ones visible in screenshots and logs.
567
+
518
568
  ## 🙏 Contributors
519
569
 
520
570
  - **lux-liang (Jialiang Liang)** — [PR #44](https://github.com/xiajiajun516/dsh-config-manager/pull/44): independently fixed the
521
571
  issue #43 "Back up now" false-success bug. Two details from that patch were more robust than the mainline implementation and
522
572
  have been adopted into `main`: (1) when `failed` comes back with an empty / whitespace-only error text, fall back to the
523
573
  generic message instead of rendering a dangling "Backup failed:"; (2) an unknown `skipReason` is mapped to a localized
524
- message rather than echoing the raw machine token. Because that PR was closed as superseded, **his commits never landed and
525
- he does not appear in GitHub's Contributors graph** — so he is credited here.
574
+ message rather than echoing the raw machine token. In addition, so that GitHub's contributor list records the
575
+ contribution, commit `1248200` was landed on `main` through a **"keep the commit, take the mainline tree"** merge
576
+ (`122317b`) — that merge takes **none** of its code (the resulting tree is byte-identical to the mainline) and exists purely
577
+ to record authorship, so GitHub now counts this contribution instead of leaving it invisible behind a closed PR.
526
578
  - **Bug reports**: `zhyx1996` (#38 sync "Export secrets" did nothing), `IPF-Sinon` (#39 the `.credentials.yaml` `refs:` block
527
579
  was not recognized — they also implemented and machine-tested a fix in their own fork), `zerginlaw` (#43 "Back up now"
528
580
  silently no-oped while toasting success). Each report drove one fix.
package/README.zh-CN.md CHANGED
@@ -13,7 +13,7 @@ DSH Config Manager 是一个 DeepSeek Harness 配置备份与迁移插件:一
13
13
  - Workspace / AGENTS.md
14
14
 
15
15
  > DSH 的 profile(`$DSH_HOME/profiles/<name>`)本身**不随备份迁移**(它是「用哪套插件组合启动」的机器本地选择);
16
- > 本插件的「档案」页可以列表 / 新建 / 重命名 / 删除它们,并记录「下次启动用哪个」。
16
+ > 本插件的「档案」页可以列表 / 新建 / 重命名 / 删除它们,也可以**用某个档案另起一个独立实例并随时停止它**(真正可用的切换)。
17
17
 
18
18
  把当前 DeepSeek Harness 环境导出为可移植备份,在另一台电脑上一键恢复;也支持通过 Git / WebDAV 跨机同步(密钥默认不同步,勾选「导出密钥」并加密后可随加密快照迁移);还能通过内置**配置市场**浏览、一键安装社区分享的现成配置。
19
19
 
@@ -81,7 +81,7 @@ DSH 是你的 AI 助手工作台,里面存着你的各种设置:模型配置
81
81
  | 🔄 | **远程同步** | 通过 **Git 私有仓库或 WebDAV** 推送 / 拉取可移植配置(密钥默认不参与同步;加密快照可选携带密文凭据) |
82
82
  | ⏰ | **定时全量备份** | 按固定周期(6h / 12h / 24h / 7d)自动全量备份,一劳永逸,密钥永不包含 |
83
83
  | 🛒 | **配置市场** | 浏览并一键安装社区分享的配置——供应链警示 + 逐项内容选择(可就地看到改动与高风险分区) |
84
- | 🗂️ | **档案 Profiles(DSH profile)** | 直接管理 `$DSH_HOME/profiles/<name>`:列表 / 新建(官方模板)/ 重命名 / 物理删除 / 记录「下次启动用哪个」 |
84
+ | 🗂️ | **档案 Profiles(DSH profile)** | 直接管理 `$DSH_HOME/profiles/<name>`:列表 / 新建(官方模板)/ 重命名 / 物理删除 / **启动该档案(独立实例)** / **停止实例**(行内按钮按运行状态在「启动 ↔ 停止」间切换) |
85
85
  | 🧩 | **本地插件随备份迁移** | `link:` / `file:` 安装的本地开发插件会被打包进备份,换机不再丢失 |
86
86
  | 🗄️ | **保留策略可配(GFS 分层)** | 「最近 N 份 + 每月留 1 份 + 每年留 1 份」,默认值等价旧行为 |
87
87
  | 🤖 | **Agent 工具** | Agent 会话内直接备份 / 快照 / 恢复 / 同步 |
@@ -90,17 +90,21 @@ DSH 是你的 AI 助手工作台,里面存着你的各种设置:模型配置
90
90
 
91
91
  ## 📸 功能截图
92
92
 
93
+ | 总览 | 备份与快照 |
94
+ |:---:|:---:|
95
+ | ![总览](assets/screenshot-overview-zh.png) | ![备份与快照](assets/screenshot-backups-zh.png) |
96
+
93
97
  | 导出备份 | 导入预览 |
94
98
  |:---:|:---:|
95
- | ![一键导出](assets/screenshot-export.png) | ![导入预览](assets/screenshot-import-preview.png) |
99
+ | ![一键导出](assets/screenshot-export-zh.png) | ![导入预览](assets/screenshot-import-zh.png) |
96
100
 
97
- | 快照恢复 | 远程同步 |
101
+ | 远程同步 | 配置市场 |
98
102
  |:---:|:---:|
99
- | ![快照恢复](assets/screenshot-snapshots.png) | ![远程同步](assets/screenshot-sync.png) |
103
+ | ![远程同步](assets/screenshot-sync-zh.png) | ![配置市场](assets/screenshot-market-zh.png) |
100
104
 
101
- | 配置市场 |
105
+ | 档案 Profiles |
102
106
  |:---:|
103
- | ![配置市场](assets/screenshot-market.png) |
107
+ | ![档案 Profiles](assets/screenshot-profiles-zh.png) |
104
108
 
105
109
  ---
106
110
 
@@ -268,10 +272,17 @@ dsh plugin --profile web add dsh-config-manager@latest
268
272
  | 新建 | 在 `$DSH_HOME/profiles/<name>` 写标准三件套(与官方 `initProfile` 等价);可选起步模板 base / web / headless / sdk / sdk-minimal / acp |
269
273
  | 重命名 | 目录级移动 + 同步修正 `package.json` 的 name;当前运行中的档案拒绝重命名 |
270
274
  | 删除 | **物理删除整个目录**(含 node_modules);当前运行中的档案需额外勾选确认 |
271
- | 下次启动 | 只写「下次启动用哪个」标记 + 给出 `dsh --profile <name>` 重启命令 |
272
-
273
- > DSH **无法在运行中切换 profile**(profile 由启动参数决定,bundle 层在启动时解析),因此本页不做进程操作,
274
- > 只记录选择并提示你手动重启。第三方插件需要在该档案里单独安装(`dsh plugin --profile <name> add <pkg>`)。
275
+ | 启动该档案 | **真正可用的切换**:以该档案另起一个**独立 DSH 实例**(自动挑空闲端口 + 自动打开浏览器),当前实例与正在跑的任务不受影响;只支持 **web 形态**档案:非 web 形态(如 base 模板)没有浏览器界面,点击后给出终端命令而不是静默失败 |
276
+ | 停止实例 | 该档案有实例在跑时,行内「启动」自动变成「停止」(运行状态卡里也有一个);先请它自己退出(优雅期),超时才结束进程树,并如实告诉你是哪种;**实例运行中拒绝物理删除该档案** |
277
+ | 不会重复启动 | 「哪些档案在跑」= 本插件启动的实例台账 ∪ **每个实例自报的心跳**(`<dataDir>/running/<profile>.json`,只含 pid/端口,**不含认证 token**)→ 哪怕某个档案是你手动 `dsh web` 起来的,本页也不会再启动第二个同名实例(明确提示已在运行);**当前这个实例本身**不给停止按钮(停自己会把你自己杀掉——请关窗口/终端,或到启动它的那个实例里停止) |
278
+
279
+ > **为什么没有「设为下次启动」**(2026-09 该按钮与标记一并移除):DSH **没有「默认 / 下次启动 profile」这种状态** ——
280
+ > profile 只由启动参数决定(`dsh <名>` / `--profile <名>`,`dsh web` 是硬编码别名),任何「下次启动用哪个」的标记
281
+ > **都没有消费者**:你自己敲的 `dsh web` 重启后当然还是 web。真正可用的切换只有两种:① 本页的「启动该档案」
282
+ > 另起一个实例(不打断当前会话,随时可停);② 把启动命令/快捷方式换成 `dsh --profile <名>`
283
+ > (生态里的 dshm、DSH Launcher 也都是「外部启动器 spawn 实例」这一条路)。
284
+ > 本插件启动的实例记在 `<dataDir>/launches.json`(pid/端口/日志),所以**关得掉**;
285
+ > 第三方插件需要在该档案里单独安装(`dsh plugin --profile <name> add <pkg>`)。
275
286
 
276
287
  ### 📸 快照恢复(撤销一次导入)
277
288
 
@@ -454,13 +465,32 @@ dsh-config-manager backup --sections skills,self # 收窄范围
454
465
  6. **快照恢复是离线的、诚实的**:离线引擎无法恢复的条目(快照无整文件备份时的 settings namespace / patch 行、存在 DSH storages 里的 workspace 记录)会如实列为跳过并指向在线回滚;凭据**值**绝不自动改写(只提示人工补录);无插件基线的旧快照只提示人工核对新增插件
455
466
  7. **本地源插件(`link:` / `file:`)随备份打包**:导出时执行 `npm pack` 把本地开发中的插件打成 tarball 一并备份,导入时解包到 `$DSH_HOME/dsh-config-manager/local-plugins/` 后按 `file:` 安装。因此:① 备份体积会随本地插件的体积增大(单插件超过 100 MB 会被跳过并告警,建议先发布到 registry / git 再备份);② 插件**源码**会进入备份(与「密钥永不进备份」不冲突——密钥仍被排除,这里进的是代码);③ 打包需要本机有可用的 `npm`,无 npm 时该插件退化为原行为(保留原 spec,换机后仍需手工安装)
456
467
 
468
+ ## 💬 反馈与建议
469
+
470
+ 遇到 Bug、界面错位、按钮点了没反应,或者只是有个想法 —— **都欢迎提出来**。界面问题尤其欢迎:这是最容易被自己忽略、也最该由真实使用场景决定的部分。
471
+
472
+ | 你想说什么 | 去哪儿 |
473
+ |---|---|
474
+ | 🎨 **界面问题**:布局错位、样式异常、深色模式、缩放、按钮无响应 | [UI 问题表单](https://github.com/xiajiajun516/dsh-config-manager/issues/new?template=ui_bug.yml)(只要截图 + 浏览器版本) |
475
+ | 🐛 **功能出错 / 报错 / 数据不对** | [Bug 报告](https://github.com/xiajiajun516/dsh-config-manager/issues/new?template=bug_report.yml) |
476
+ | ✨ **新功能建议** | [功能建议](https://github.com/xiajiajun516/dsh-config-manager/issues/new?template=feature_request.yml) |
477
+ | 💬 **不确定是不是 Bug,想先问问** | [Discussions](https://github.com/xiajiajun516/dsh-config-manager/discussions) |
478
+ | 🔒 **安全问题 / 密钥泄露** | [私密安全公告](https://github.com/xiajiajun516/dsh-config-manager/security/advisories/new)(请不要开公开 issue) |
479
+
480
+ **在插件里就地反馈**:设置 → 备份与迁移 → **关于** → 「反馈问题」;或点「关于」里的**复制环境信息**按钮,插件版本 / DSH 版本 / 平台会自动带上,粘进 issue 即可 —— 不用手抄版本号。
481
+
482
+ **每条都会跟进**:新 issue 会立刻收到一条回复并打上 `needs-triage`,处理进度体现在标签上(`needs-info` → `confirmed` → `fixed`)。修好的问题会出现在 [CHANGELOG.md](CHANGELOG.md) 的对应版本条目里,带 issue 编号(例:#38 / #43 / #45)—— 这就是一条反馈最终的落地记录。
483
+
484
+ > ⚠️ 提交前请先搜一下是否已有同类 issue,并**抹掉任何 API Key / Token / 密码**(截图和日志里也算)。
485
+
457
486
  ## 🙏 贡献者
458
487
 
459
488
  - **lux-liang (Jialiang Liang)** —— [PR #44](https://github.com/xiajiajun516/dsh-config-manager/pull/44):独立修复了 issue #43
460
489
  「立即备份」假报成功的问题。其中两点比主线实现更稳,已采纳进 `main`:① `failed` 且宿主错误文本为空 / 全空白时
461
490
  回退通用文案(否则会渲染出「备份失败:」这种半截提示);② 未知 `skipReason` 归一为本地化说明,不把机器 token
462
- 摆到用户面前。他的提交未合并(该 PR 作为 superseded 关闭),因此**不会出现在 GitHub 的 Contributors 图上** ——
463
- 名单在此登记。
491
+ 摆到用户面前。此外,为了让 GitHub 的 Contributors 列表如实计入这次贡献,其提交 `1248200` 已通过一次
492
+ **「保留其提交、树取主线」**的合并(`122317b`)成为 `main` 的祖先 —— 该合并**不取其代码**(合并后的树与主线
493
+ 逐字节一致),只用于记录署名;因此按 GitHub 的口径这次贡献已被计入(而非 closed 后无痕)。
464
494
  - **问题报告**:`zhyx1996`(#38 同步「导出密钥」未生效)、`IPF-Sinon`(#39 凭据 `refs:` 块未被识别,并在自己的 fork
465
495
  上完成实现与真机验证)、`zerginlaw`(#43「立即备份」空转却提示成功)—— 这三条报告各自驱动了一个修复。
466
496
 
@@ -3,9 +3,9 @@ import type { FilesSection } from '../schema/types.ts';
3
3
  import type { ExportOptions, ExportSection, HostContext } from '../core/types.ts';
4
4
  export declare class AgentInstructionsAdapter extends FileCollectionAdapter {
5
5
  readonly id: 'agentInstructions';
6
- readonly displayName = "Agent Instructions";
7
- readonly defaultIncluded = true;
8
- readonly portability: 'portable';
6
+ readonly displayName: string;
7
+ readonly defaultIncluded: boolean;
8
+ readonly portability: import("../schema/section-registry.ts").SectionPortability;
9
9
  readonly baseDir = "";
10
10
  /** 用户全局指令文件(相对 homeDir;同时是 schema 端该分区唯一的文件) */
11
11
  static readonly FILE = "AGENTS.md";
@@ -11,11 +11,13 @@
11
11
  import { sha256Hex } from '../utils/hashing.js';
12
12
  import { msgOf } from '../core/messages.js';
13
13
  import { FileCollectionAdapter } from './file-collection.js';
14
+ import { sectionMeta } from '../schema/section-registry.js';
14
15
  export class AgentInstructionsAdapter extends FileCollectionAdapter {
15
16
  id = 'agentInstructions';
16
- displayName = 'Agent Instructions';
17
- defaultIncluded = true;
18
- portability = 'portable';
17
+ // 元数据唯一来源 = 注册表(t31):不再与 ui/export-flow.ts 的导出目录各写一份
18
+ displayName = sectionMeta('agentInstructions').displayName;
19
+ defaultIncluded = sectionMeta('agentInstructions').defaultIncluded;
20
+ portability = sectionMeta('agentInstructions').portability;
19
21
  baseDir = '';
20
22
  /** 用户全局指令文件(相对 homeDir;同时是 schema 端该分区唯一的文件) */
21
23
  static FILE = 'AGENTS.md';
@@ -6,8 +6,8 @@
6
6
  import { FileCollectionAdapter } from './file-collection.ts';
7
7
  export declare class AgentPresetsAdapter extends FileCollectionAdapter {
8
8
  readonly id: 'agentPresets';
9
- readonly displayName = "Agent Presets";
10
- readonly defaultIncluded = true;
11
- readonly portability: 'portable';
9
+ readonly displayName: string;
10
+ readonly defaultIncluded: boolean;
11
+ readonly portability: import("../schema/section-registry.ts").SectionPortability;
12
12
  readonly baseDir = ".agent-presets";
13
13
  }
@@ -4,11 +4,13 @@
4
4
  * system 预设(安装目录)只记引用不复制(本 adapter 只读用户目录)。
5
5
  */
6
6
  import { FileCollectionAdapter } from './file-collection.js';
7
+ import { sectionMeta } from '../schema/section-registry.js';
7
8
  export class AgentPresetsAdapter extends FileCollectionAdapter {
8
9
  id = 'agentPresets';
9
- displayName = 'Agent Presets';
10
- defaultIncluded = true;
11
- portability = 'portable';
10
+ // 元数据唯一来源 = 注册表(t31):不再与 ui/export-flow.ts 的导出目录各写一份
11
+ displayName = sectionMeta('agentPresets').displayName;
12
+ defaultIncluded = sectionMeta('agentPresets').defaultIncluded;
13
+ portability = sectionMeta('agentPresets').portability;
12
14
  baseDir = '.agent-presets';
13
15
  }
14
16
  //# sourceMappingURL=agent-presets.js.map
@@ -25,9 +25,9 @@ export interface CredentialsAdapterOptions {
25
25
  }
26
26
  export declare class CredentialsAdapter implements ConfigAdapter<CredentialsSection> {
27
27
  readonly id: 'credentialsStatus';
28
- readonly displayName = "Credentials";
29
- readonly defaultIncluded = true;
30
- readonly portability: 'deviceSpecific';
28
+ readonly displayName: string;
29
+ readonly defaultIncluded: boolean;
30
+ readonly portability: import("../schema/section-registry.ts").SectionPortability;
31
31
  private readonly refs;
32
32
  constructor(options?: CredentialsAdapterOptions);
33
33
  export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<CredentialsSection>>;
@@ -1,5 +1,7 @@
1
1
  import { msgOf, zhMsg } from '../core/messages.js';
2
2
  import { resolveNamespaces } from './settings.js';
3
+ import { sectionMeta } from '../schema/section-registry.js';
4
+ import { validateJsonSection } from './json-section.js';
3
5
  /** 缺省 ref 收集:遍历 settings namespace,收集 llm apiKeyEnv / providers[].apiKeyEnv,
4
6
  * 以及 secrets 标记中「引用类字段」(apiKeyEnv/tokenEnv…)的字段值。
5
7
  * 注意 secrets[].path[0] 是 settings 文档内的字段路径(如 ['apiKey']),本身不是凭据 ref(设计 §4.2),
@@ -47,9 +49,10 @@ export function defaultCredentialRefs(namespaces) {
47
49
  }
48
50
  export class CredentialsAdapter {
49
51
  id = 'credentialsStatus';
50
- displayName = 'Credentials';
51
- defaultIncluded = true;
52
- portability = 'deviceSpecific';
52
+ // 元数据唯一来源 = 注册表(t31):不再与 ui/export-flow.ts 的导出目录各写一份
53
+ displayName = sectionMeta('credentialsStatus').displayName;
54
+ defaultIncluded = sectionMeta('credentialsStatus').defaultIncluded;
55
+ portability = sectionMeta('credentialsStatus').portability;
53
56
  refs;
54
57
  constructor(options = {}) {
55
58
  this.refs = options.refs ?? defaultCredentialRefs(options.namespaces ?? []);
@@ -95,28 +98,22 @@ export class CredentialsAdapter {
95
98
  return { ok: true };
96
99
  }
97
100
  async validate(data, msg = zhMsg) {
98
- const issues = [];
99
- if (data === null || typeof data !== 'object') {
100
- return { valid: false, issues: [{ path: '$', message: msg('adapter.validate.object', { subject: 'credentials' }), severity: 'error' }] };
101
- }
102
- if (data.version !== 1) {
103
- issues.push({ path: 'version', message: msg('adapter.validate.version', { value: String(data.version) }), severity: 'error' });
104
- }
105
- if (!Array.isArray(data.credentials)) {
106
- issues.push({ path: 'credentials', message: msg('adapter.validate.array', { subject: 'credentials' }), severity: 'error' });
107
- }
108
- else {
109
- for (const c of data.credentials) {
110
- if (c === null || typeof c !== 'object' || typeof c.ref !== 'string' || c.ref === '') {
111
- issues.push({ path: 'credentials[]', message: msg('adapter.validate.credentialRef'), severity: 'error' });
112
- }
113
- if (c.hasValue === true) {
114
- // 安全不变量:普通导出恒不携带值;若备份声称有值,视为结构异常
115
- issues.push({ path: `credentials.${c.ref}.hasValue`, message: msg('adapter.validate.hasValueFalse'), severity: 'error' });
101
+ return validateJsonSection('credentialsStatus', data, msg, (section, issues) => {
102
+ if (!Array.isArray(section.credentials)) {
103
+ issues.push({ path: 'credentials', message: msg('adapter.validate.array', { subject: 'credentials' }), severity: 'error' });
104
+ }
105
+ else {
106
+ for (const c of section.credentials) {
107
+ if (c === null || typeof c !== 'object' || typeof c.ref !== 'string' || c.ref === '') {
108
+ issues.push({ path: 'credentials[]', message: msg('adapter.validate.credentialRef'), severity: 'error' });
109
+ }
110
+ if (c.hasValue === true) {
111
+ // 安全不变量:普通导出恒不携带值;若备份声称有值,视为结构异常
112
+ issues.push({ path: `credentials.${c.ref}.hasValue`, message: msg('adapter.validate.hasValueFalse'), severity: 'error' });
113
+ }
116
114
  }
117
115
  }
118
- }
119
- return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
116
+ }, 'credentials');
120
117
  }
121
118
  }
122
119
  //# sourceMappingURL=credentials.js.map
@@ -1,7 +1,29 @@
1
1
  import type { MsgFunc } from '../core/messages.ts';
2
2
  import type { FilesSection, SectionId } from '../schema/types.ts';
3
3
  import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, ExportUnit, HostContext, ImportContext, PlanItem, Portability, ValidationResult } from '../core/types.ts';
4
+ /**
5
+ * 文件类分区导出的**单分区累计字节闸门**:分区内文件内容合计放不下的单元整块剔除(见 export())。
6
+ *
7
+ * 取值依据(不是随手拍的数):
8
+ * 1) **对称性** —— 导入侧对上传的备份包有硬上限 256 MiB(MAX_UPLOAD_BYTES,src/index.ts 与
9
+ * src/routes/kit.ts 的上传路径);导出侧此前**没有任何体积约束**,于是会出现「导出成功、
10
+ * 传不回来」(审计 core-flow F-12 / sync#F-12)。取同一个 256 MiB 作**单分区**上限:
11
+ * 任何单个分区都落在导入侧上传路径能收的范围内。
12
+ * 2) **内存峰值** —— 导出时文件内容以完整 Uint8Array 驻留内存(ZIP 组装前全量在内存里),同步通道
13
+ * 还要再写一份。闸门把「单分区常驻」钳在 256 MiB 以内(峰值 ≈ 上限 + 正在读的那个单元),
14
+ * 不再是「会话附件多大就多吃多少」。
15
+ * 3) **与既有同类上限同量级** —— MAX_MARKET_ZIP_BYTES = 64 MiB、DEFAULT_MAX_JSON_BYTES = 64 MiB、
16
+ * MAX_LOCAL_TARBALL_BYTES = 100 MiB、MAX_PATCH_FILE_BYTES = 2 MiB。文件类分区装的是**用户真实
17
+ * 文件**,所以取「导入侧能收」的 256 MiB,而不是为省内存随意调小(那会平白少带用户数据)。
18
+ * 4) **为什么按分区而不是按整包** —— 整包体积由用户勾选跨分区决定;闸门要能给出「哪些分区、哪些
19
+ * 单元没进去」的可执行信息,落在分区/单元层才可解释。
20
+ *
21
+ * 超限时**绝不静默**:被整块剔除的单元清单进 ExportSection.warnings(导出报告可见)。
22
+ */
23
+ export declare const MAX_FILE_SECTION_BYTES: number;
4
24
  export declare abstract class FileCollectionAdapter implements ConfigAdapter<FilesSection> {
25
+ /** 文件集合:`relativePath` 是身份而非配置 → 永不被导入时的前缀映射改写(见 ConfigAdapter.fileCollection) */
26
+ readonly fileCollection = true;
5
27
  abstract readonly id: SectionId;
6
28
  abstract readonly displayName: string;
7
29
  abstract readonly defaultIncluded: boolean;
@@ -18,6 +40,14 @@ export declare abstract class FileCollectionAdapter implements ConfigAdapter<Fil
18
40
  protected unitIdOf(relativePath: string): string;
19
41
  /** 清单里的路径 → 相对 baseDir 的路径(baseDir 为空表示整目录即根)。 */
20
42
  protected relPathOf(rel: string): string;
43
+ /**
44
+ * 单分区累计字节上限(缺省 MAX_FILE_SECTION_BYTES = 256 MiB,见该常量注释)。
45
+ *
46
+ * 生产代码不覆写;留成受保护方法只为让测试能构造「超限」场景(真实阈值 256 MiB 无法在单测里
47
+ * 造出来而不吃掉 256 MiB 内存)。若要给用户配置入口,应走 ExportOptions(src/core/types.ts),
48
+ * 而不是在子类里飘一个隐式默认值。
49
+ */
50
+ protected sectionByteLimit(): number;
21
51
  /**
22
52
  * 条目级选择(Phase 1):只导出白名单命中的单元。
23
53
  *
@@ -40,5 +70,18 @@ export declare abstract class FileCollectionAdapter implements ConfigAdapter<Fil
40
70
  listUnits(section: ExportSection<FilesSection>): ExportUnit[];
41
71
  analyzeImport(data: FilesSection, ctx: ImportContext): Promise<PlanItem[]>;
42
72
  applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
73
+ /**
74
+ * 结构校验(5 个文件类分区共用:skills / agentPresets / agentInstructions / sessions / self)。
75
+ *
76
+ * **整段样板都接入共享骨架 `validateJsonSection`** —— t7 接入 version 守卫与形状检查收尾,t11 接入
77
+ * object 守卫;dataVersion 由注册表按 `this.id` 派生,等价于此前的字面量 `!== 1`
78
+ * (SECTION_DATA_VERSION = 1)。本类里已无手写样板。
79
+ *
80
+ * object 守卫的**文案**为什么还要参数:文件类分区历史上用的是**专用消息键**
81
+ * `adapter.validate.fileSection`('文件分区数据必须是对象',不含 `{subject}` 占位符),与骨架缺省的
82
+ * `adapter.validate.object` + `{subject}` 是**键**级差异 —— 第 5 参 subject 补不了它。t11 给骨架加了
83
+ * 可选第 6 参 `objectMessageKey`,这里传专用键:5 个分区的用户可见报错文案与改造前**逐字相同**,
84
+ * 同时不放任何手写样板。等价由 src/adapters/file-collection.test.ts 与 outputs/t7-equiv/ 的差分脚本钉住。
85
+ */
43
86
  validate(data: FilesSection, msg?: MsgFunc): Promise<ValidationResult>;
44
87
  }