dsh-config-manager 0.1.71 → 0.1.73

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 (596) hide show
  1. package/README.md +149 -98
  2. package/README.zh-CN.md +245 -88
  3. package/lib/adapters/agent-instructions.js +1 -1
  4. package/lib/adapters/file-collection.js +1 -1
  5. package/lib/adapters/index.d.ts +2 -1
  6. package/lib/adapters/index.js +6 -1
  7. package/lib/adapters/link-report.d.ts +1 -0
  8. package/lib/adapters/link-report.js +27 -3
  9. package/lib/adapters/messages.d.ts +21 -0
  10. package/lib/adapters/messages.js +57 -0
  11. package/lib/adapters/plugin-data.d.ts +114 -0
  12. package/lib/adapters/plugin-data.js +309 -0
  13. package/lib/adapters/plugin-files.js +3 -2
  14. package/lib/adapters/plugins.js +4 -3
  15. package/lib/adapters/prompts.d.ts +1 -0
  16. package/lib/adapters/prompts.js +7 -1
  17. package/lib/adapters/self.d.ts +8 -2
  18. package/lib/adapters/self.js +3 -2
  19. package/lib/adapters/sessions.d.ts +1 -0
  20. package/lib/adapters/sessions.js +4 -2
  21. package/lib/adapters/test-helpers.d.ts +9 -0
  22. package/lib/adapters/test-helpers.js +14 -0
  23. package/lib/adapters/ui.d.ts +2 -2
  24. package/lib/adapters/ui.js +25 -25
  25. package/lib/adapters/workspaces.d.ts +1 -0
  26. package/lib/adapters/workspaces.js +7 -3
  27. package/lib/cli/actions.d.ts +9 -1
  28. package/lib/cli/actions.js +5 -2
  29. package/lib/cli/help.js +23 -10
  30. package/lib/cli/index.d.ts +23 -0
  31. package/lib/cli/index.js +90 -32
  32. package/lib/cli/sessions-inspect.js +3 -1
  33. package/lib/cli/sessions-repair.js +25 -6
  34. package/lib/cli/web/page.d.ts +12 -0
  35. package/lib/cli/web/page.js +21 -12
  36. package/lib/cli/web/routes.js +2 -2
  37. package/lib/cli/web/server.js +4 -4
  38. package/lib/client.d.ts +1442 -494
  39. package/lib/client.js +15326 -8520
  40. package/lib/core/analyzer.d.ts +11 -2
  41. package/lib/core/analyzer.js +31 -8
  42. package/lib/core/backup-plan.d.ts +10 -0
  43. package/lib/core/backup-plan.js +51 -20
  44. package/lib/core/backup-verify.js +24 -23
  45. package/lib/core/backup.d.ts +25 -1
  46. package/lib/core/backup.js +99 -28
  47. package/lib/core/boot-rescue.js +4 -3
  48. package/lib/core/boot-safety.js +2 -1
  49. package/lib/core/command-rollback.d.ts +182 -0
  50. package/lib/core/command-rollback.js +293 -0
  51. package/lib/core/consult-source.js +7 -6
  52. package/lib/core/disk-usage.d.ts +74 -10
  53. package/lib/core/disk-usage.js +67 -4
  54. package/lib/core/engine-locale.d.ts +87 -0
  55. package/lib/core/engine-locale.js +125 -0
  56. package/lib/core/exporter.js +3 -3
  57. package/lib/core/fork-reconcile.d.ts +128 -0
  58. package/lib/core/fork-reconcile.js +150 -0
  59. package/lib/core/journal.js +6 -5
  60. package/lib/core/local-plugin-host.js +3 -2
  61. package/lib/core/local-plugin-pack.js +11 -6
  62. package/lib/core/messages-core.d.ts +294 -0
  63. package/lib/core/messages-core.js +619 -0
  64. package/lib/core/messages.d.ts +61 -2
  65. package/lib/core/messages.js +118 -13
  66. package/lib/core/migration-consult.js +21 -20
  67. package/lib/core/migration-history.js +19 -5
  68. package/lib/core/model-tools.d.ts +0 -22
  69. package/lib/core/model-tools.js +50 -27
  70. package/lib/core/phase3-host.js +30 -5
  71. package/lib/core/plugin-cli.js +18 -19
  72. package/lib/core/plugin-data-registry.d.ts +124 -0
  73. package/lib/core/plugin-data-registry.js +198 -0
  74. package/lib/core/reconcile.d.ts +2 -14
  75. package/lib/core/reconcile.js +87 -17
  76. package/lib/core/recovery-orchestrator.js +19 -18
  77. package/lib/core/reinstall.d.ts +4 -0
  78. package/lib/core/reinstall.js +26 -21
  79. package/lib/core/restore.js +20 -17
  80. package/lib/core/rollback-gate.d.ts +33 -0
  81. package/lib/core/rollback-gate.js +57 -0
  82. package/lib/core/rollback-ignore-rules.d.ts +31 -0
  83. package/lib/core/rollback-ignore-rules.js +140 -0
  84. package/lib/core/rollback-ledger.d.ts +248 -0
  85. package/lib/core/rollback-ledger.js +1282 -0
  86. package/lib/core/rollback-point.d.ts +1391 -0
  87. package/lib/core/rollback-point.js +3503 -0
  88. package/lib/core/rollback.js +6 -4
  89. package/lib/core/run-registry.js +6 -5
  90. package/lib/core/session-health.d.ts +15 -0
  91. package/lib/core/session-meta.d.ts +42 -2
  92. package/lib/core/session-meta.js +140 -1
  93. package/lib/core/session-title.d.ts +28 -0
  94. package/lib/core/session-title.js +185 -0
  95. package/lib/core/startup-barrier.d.ts +24 -0
  96. package/lib/core/startup-barrier.js +22 -0
  97. package/lib/core/transaction-coordinator.js +4 -3
  98. package/lib/core/types.d.ts +37 -1
  99. package/lib/core/validator.js +5 -4
  100. package/lib/core/verify-recovery.js +31 -30
  101. package/lib/foreign/bundle.js +3 -2
  102. package/lib/foreign/continue.js +2 -1
  103. package/lib/foreign/crush.js +2 -1
  104. package/lib/foreign/gemini.js +2 -1
  105. package/lib/foreign/goose.js +2 -1
  106. package/lib/foreign/kilocode.js +2 -1
  107. package/lib/foreign/kimi.js +2 -1
  108. package/lib/foreign/messages.d.ts +15 -0
  109. package/lib/foreign/messages.js +40 -0
  110. package/lib/foreign/mimocode.js +2 -1
  111. package/lib/foreign/openclaw.js +2 -1
  112. package/lib/foreign/opencode.js +2 -1
  113. package/lib/foreign/pi.js +2 -1
  114. package/lib/foreign/qoder.js +2 -1
  115. package/lib/foreign/qwen.js +2 -1
  116. package/lib/foreign/registry.d.ts +1 -1
  117. package/lib/foreign/registry.js +8 -7
  118. package/lib/foreign/teleagent.js +2 -1
  119. package/lib/foreign/workbuddy.js +2 -1
  120. package/lib/foreign/zcode.js +2 -1
  121. package/lib/foreign/zed.js +2 -1
  122. package/lib/index.d.ts +227 -7
  123. package/lib/index.js +799 -54
  124. package/lib/market/git-file-writer.js +20 -19
  125. package/lib/market/github-repos.js +35 -19
  126. package/lib/market/index-parser.js +31 -30
  127. package/lib/market/messages-market.d.ts +138 -0
  128. package/lib/market/messages-market.js +305 -0
  129. package/lib/market/my-repo.d.ts +2 -2
  130. package/lib/market/my-repo.js +32 -29
  131. package/lib/market/prepare.js +18 -15
  132. package/lib/market/security.js +20 -19
  133. package/lib/market/types.js +2 -1
  134. package/lib/market/url.js +2 -1
  135. package/lib/migrations/index.js +6 -5
  136. package/lib/migrations/messages-migrations.d.ts +32 -0
  137. package/lib/migrations/messages-migrations.js +58 -0
  138. package/lib/profiles/dsh-profile-launcher.js +2 -1
  139. package/lib/profiles/dsh-profile-runtime.js +2 -1
  140. package/lib/profiles/messages.d.ts +7 -0
  141. package/lib/profiles/messages.js +27 -0
  142. package/lib/routes/backup.js +18 -2
  143. package/lib/routes/import.js +3 -3
  144. package/lib/routes/index.d.ts +1 -1
  145. package/lib/routes/kit.d.ts +3 -2
  146. package/lib/routes/kit.js +6 -1
  147. package/lib/routes/market.js +1 -1
  148. package/lib/routes/messages.d.ts +43 -0
  149. package/lib/routes/messages.js +102 -0
  150. package/lib/routes/prefs.js +26 -3
  151. package/lib/routes/profiles.js +12 -6
  152. package/lib/routes/recovery.d.ts +21 -0
  153. package/lib/routes/recovery.js +478 -94
  154. package/lib/routes/snapshots.js +51 -4
  155. package/lib/routes/sync.js +79 -17
  156. package/lib/schema/config.d.ts +11 -1
  157. package/lib/schema/config.js +52 -20
  158. package/lib/schema/index.d.ts +8 -6
  159. package/lib/schema/index.js +8 -6
  160. package/lib/schema/manifest.js +19 -18
  161. package/lib/schema/messages.d.ts +47 -0
  162. package/lib/schema/messages.js +110 -0
  163. package/lib/schema/section-registry.d.ts +42 -15
  164. package/lib/schema/section-registry.js +67 -32
  165. package/lib/schema/types.d.ts +1 -1
  166. package/lib/schema/versions.js +6 -5
  167. package/lib/security/encryption.js +16 -15
  168. package/lib/security/integrity.js +8 -7
  169. package/lib/security/messages.d.ts +30 -0
  170. package/lib/security/messages.js +77 -0
  171. package/lib/security/redaction.js +12 -0
  172. package/lib/security/secret-scanner.js +16 -13
  173. package/lib/security/vault.js +2 -1
  174. package/lib/security/zip-security.js +4 -3
  175. package/lib/sync/ancestor.js +2 -1
  176. package/lib/sync/autosync-config.d.ts +11 -0
  177. package/lib/sync/autosync-config.js +12 -0
  178. package/lib/sync/autosync-scheduler.d.ts +11 -1
  179. package/lib/sync/autosync-scheduler.js +115 -76
  180. package/lib/sync/backup-files.js +3 -2
  181. package/lib/sync/backup-scheduler.js +6 -5
  182. package/lib/sync/blob-store.js +2 -1
  183. package/lib/sync/git/git-transport.d.ts +55 -0
  184. package/lib/sync/git/git-transport.js +152 -2
  185. package/lib/sync/github-auth.js +10 -9
  186. package/lib/sync/layout.js +13 -12
  187. package/lib/sync/messages.d.ts +63 -0
  188. package/lib/sync/messages.js +149 -0
  189. package/lib/sync/review-queue.js +6 -5
  190. package/lib/sync/s3/messages.d.ts +7 -0
  191. package/lib/sync/s3/messages.js +16 -0
  192. package/lib/sync/s3/s3-providers.d.ts +4 -1
  193. package/lib/sync/s3/s3-providers.js +5 -5
  194. package/lib/sync/s3/s3-transport.js +1 -1
  195. package/lib/sync/s3/sigv4.js +2 -1
  196. package/lib/sync/snapshot-crypto.js +6 -5
  197. package/lib/sync/snapshot-json.js +3 -2
  198. package/lib/sync/sync-engine.d.ts +58 -22
  199. package/lib/sync/sync-engine.js +119 -48
  200. package/lib/sync/sync-history.js +7 -6
  201. package/lib/sync/sync-selection.d.ts +15 -4
  202. package/lib/sync/sync-selection.js +17 -5
  203. package/lib/sync/ui-prefs.d.ts +22 -0
  204. package/lib/sync/ui-prefs.js +28 -0
  205. package/lib/sync/webdav/webdav-transport.d.ts +1 -0
  206. package/lib/sync/webdav/webdav-transport.js +4 -1
  207. package/lib/ui/artifact-view.js +4 -3
  208. package/lib/ui/commands.d.ts +1 -1
  209. package/lib/ui/commands.js +10 -0
  210. package/lib/ui/diff-view.d.ts +10 -0
  211. package/lib/ui/diff-view.js +17 -0
  212. package/lib/ui/disk-usage-view.d.ts +33 -4
  213. package/lib/ui/disk-usage-view.js +29 -1
  214. package/lib/ui/errors.d.ts +1 -1
  215. package/lib/ui/errors.js +4 -3
  216. package/lib/ui/export-flow.js +26 -20
  217. package/lib/ui/foreign-view.d.ts +5 -1
  218. package/lib/ui/foreign-view.js +26 -2
  219. package/lib/ui/i18n.d.ts +68 -1
  220. package/lib/ui/i18n.js +120 -2
  221. package/lib/ui/import-wizard.d.ts +7 -0
  222. package/lib/ui/import-wizard.js +13 -10
  223. package/lib/ui/progress.d.ts +2 -2
  224. package/lib/ui/progress.js +1 -2
  225. package/lib/ui/report.d.ts +5 -5
  226. package/lib/ui/report.js +6 -6
  227. package/lib/ui/rollback-view.d.ts +815 -0
  228. package/lib/ui/rollback-view.js +738 -0
  229. package/lib/ui/selection-model.d.ts +41 -0
  230. package/lib/ui/selection-model.js +30 -0
  231. package/lib/ui/session-inventory-view.d.ts +97 -3
  232. package/lib/ui/session-inventory-view.js +76 -2
  233. package/lib/ui/session-issue-labels.d.ts +43 -0
  234. package/lib/ui/session-issue-labels.js +48 -0
  235. package/lib/ui/sync-settings-view.d.ts +33 -0
  236. package/lib/ui/sync-settings-view.js +40 -0
  237. package/lib/ui/test-helpers.js +2 -1
  238. package/lib/ui/types.d.ts +8 -3
  239. package/lib/ui/types.js +1 -1
  240. package/lib/utils/atomic-write.js +6 -5
  241. package/lib/utils/bundle-scan.d.ts +11 -1
  242. package/lib/utils/bundle-scan.js +12 -1
  243. package/lib/utils/env-lock.d.ts +10 -0
  244. package/lib/utils/env-lock.js +73 -46
  245. package/lib/utils/json.js +6 -5
  246. package/lib/utils/messages-utils.d.ts +96 -0
  247. package/lib/utils/messages-utils.js +216 -0
  248. package/lib/utils/proxy.js +18 -5
  249. package/lib/utils/recursive-walk.d.ts +22 -0
  250. package/lib/utils/recursive-walk.js +75 -1
  251. package/lib/utils/session-log-repair.js +10 -9
  252. package/lib/utils/zip.js +27 -26
  253. package/package.json +12 -2
  254. package/src/adapters/agent-instructions.ts +1 -1
  255. package/src/adapters/file-collection.test.ts +1 -0
  256. package/src/adapters/file-collection.ts +1 -1
  257. package/src/adapters/files.test.ts +27 -0
  258. package/src/adapters/index.ts +6 -1
  259. package/src/adapters/link-report.test.ts +22 -2
  260. package/src/adapters/link-report.ts +29 -4
  261. package/src/adapters/messages.ts +61 -0
  262. package/src/adapters/plugin-data.test.ts +225 -0
  263. package/src/adapters/plugin-data.ts +351 -0
  264. package/src/adapters/plugin-files.ts +3 -2
  265. package/src/adapters/plugins.ts +4 -3
  266. package/src/adapters/prompts.ts +7 -1
  267. package/src/adapters/self.test.ts +26 -0
  268. package/src/adapters/self.ts +10 -3
  269. package/src/adapters/sessions.ts +4 -2
  270. package/src/adapters/settings.test.ts +38 -1
  271. package/src/adapters/test-helpers.ts +15 -0
  272. package/src/adapters/ui.test.ts +2 -2
  273. package/src/adapters/ui.ts +27 -26
  274. package/src/adapters/workspaces.ts +7 -3
  275. package/src/cli/actions.test.ts +28 -0
  276. package/src/cli/actions.ts +11 -2
  277. package/src/cli/help.ts +23 -10
  278. package/src/cli/index-guards.test.ts +193 -0
  279. package/src/cli/index.ts +106 -31
  280. package/src/cli/sessions-inspect.test.ts +15 -1
  281. package/src/cli/sessions-inspect.ts +3 -1
  282. package/src/cli/sessions-repair.test.ts +84 -0
  283. package/src/cli/sessions-repair.ts +33 -7
  284. package/src/cli/web/console-route-parity.test.ts +115 -0
  285. package/src/cli/web/page.ts +23 -12
  286. package/src/cli/web/routes.ts +2 -1
  287. package/src/cli/web/server.ts +4 -4
  288. package/src/cli/web/web.test.ts +2 -2
  289. package/src/client/ConfigManagerSection.tsx +30 -2
  290. package/src/client/about/AboutPanel.tsx +2 -2
  291. package/src/client/about/PluginUpdateDialog.tsx +1 -1
  292. package/src/client/about/ReleaseNotesDialog.tsx +2 -2
  293. package/src/client/about/about-view.test.ts +13 -3
  294. package/src/client/about/about-view.ts +10 -6
  295. package/src/client/about/release-notes-view.test.ts +14 -4
  296. package/src/client/about/release-notes-view.ts +4 -2
  297. package/src/client/api.ts +18 -6
  298. package/src/client/chat/ChatEntryView.tsx +411 -0
  299. package/src/client/chat/RollbackDiffTab.tsx +108 -0
  300. package/src/client/chat/RollbackFileIcon.tsx +96 -0
  301. package/src/client/chat/RollbackReviewDialog.tsx +607 -0
  302. package/src/client/chat/chat-entry-view.test.ts +1174 -0
  303. package/src/client/chat/chat-entry-view.ts +758 -0
  304. package/src/client/chat/chat-locales.ts +152 -0
  305. package/src/client/chat/chat-node-registration.ts +64 -0
  306. package/src/client/chat/chat-point-window.ts +183 -0
  307. package/src/client/chat/chat-slots.ts +107 -0
  308. package/src/client/chat/rollback-diff-tab.test.ts +105 -0
  309. package/src/client/chat/rollback-diff-tab.ts +174 -0
  310. package/src/client/chat/rollback-entry-view.test.ts +1469 -0
  311. package/src/client/chat/rollback-entry-view.ts +946 -0
  312. package/src/client/chat/sidebar-slots.ts +59 -0
  313. package/src/client/common/ConfirmDialog.tsx +7 -3
  314. package/src/client/common/ContentPicker.tsx +48 -10
  315. package/src/client/common/DiffTable.tsx +133 -0
  316. package/src/client/common/ErrorBanner.tsx +4 -4
  317. package/src/client/common/Icon.tsx +2 -0
  318. package/src/client/common/Modal.tsx +8 -1
  319. package/src/client/common/ProgressBar.tsx +8 -2
  320. package/src/client/common/ReportView.tsx +4 -4
  321. package/src/client/common/RunsCenter.tsx +1 -0
  322. package/src/client/common/client-route-parity.test.ts +84 -0
  323. package/src/client/common/info-hint-guard.test.ts +46 -13
  324. package/src/client/common/picker-lazy-units.test.ts +42 -0
  325. package/src/client/common/plan-text-redaction.test.ts +17 -6
  326. package/src/client/common/progress-view-edge.test.ts +8 -7
  327. package/src/client/common/progress-view.test.ts +9 -9
  328. package/src/client/common/progress-view.ts +2 -2
  329. package/src/client/common/routes.ts +38 -0
  330. package/src/client/common/section-labels.test.ts +1 -0
  331. package/src/client/common/section-labels.ts +2 -0
  332. package/src/client/common/ui.tsx +73 -10
  333. package/src/client/config-manager.module.css +1109 -31
  334. package/src/client/css-scale-guard.test.ts +30 -0
  335. package/src/client/environment/EnvironmentPanel.tsx +11 -4
  336. package/src/client/environment/maintenance/DiskUsageCard.tsx +23 -2
  337. package/src/client/export/ExportView.tsx +13 -8
  338. package/src/client/history/HistoryPanel.tsx +4 -3
  339. package/src/client/history/history-api.ts +2 -2
  340. package/src/client/history/history-locales.ts +5 -1
  341. package/src/client/home/HomePanel.tsx +29 -8
  342. package/src/client/import/ForeignImportView.tsx +4 -5
  343. package/src/client/import/ImportWizardView.tsx +5 -3
  344. package/src/client/import/import-wizard-split.test.ts +3 -1
  345. package/src/client/import/import-wizard-steps.tsx +9 -9
  346. package/src/client/index.ts +232 -3
  347. package/src/client/library/LibraryActions.tsx +32 -7
  348. package/src/client/library/LibraryPanel.tsx +23 -3
  349. package/src/client/library/RestorePlanView.tsx +9 -66
  350. package/src/client/locales.ts +62 -9
  351. package/src/client/lucide-icons.d.ts +1 -0
  352. package/src/client/market/MarketPanel.tsx +13 -2
  353. package/src/client/market/MyConfigsView.tsx +5 -4
  354. package/src/client/market/MyConfigsWizard.tsx +10 -8
  355. package/src/client/market/market-api.test.ts +9 -8
  356. package/src/client/market/market-api.ts +2 -2
  357. package/src/client/market/market-locales.ts +3 -0
  358. package/src/client/market/market-view.test.ts +6 -6
  359. package/src/client/market/market-view.ts +3 -3
  360. package/src/client/market/my-configs-api.ts +2 -2
  361. package/src/client/market/my-configs-view.test.ts +23 -22
  362. package/src/client/market/my-configs-view.ts +8 -8
  363. package/src/client/recovery/IncompleteCopiesSection.tsx +2 -1
  364. package/src/client/recovery/RecoveryPanel.tsx +442 -283
  365. package/src/client/recovery/RollbackCard.tsx +859 -0
  366. package/src/client/recovery/RollbackDiffPane.tsx +69 -0
  367. package/src/client/recovery/RollbackFileChanges.tsx +163 -0
  368. package/src/client/recovery/incident-api.ts +2 -2
  369. package/src/client/recovery/recovery-api.ts +144 -6
  370. package/src/client/recovery/recovery-locales.test.ts +299 -0
  371. package/src/client/recovery/recovery-locales.ts +520 -149
  372. package/src/client/recovery/recovery-panel-layout.test.ts +132 -2
  373. package/src/client/recovery/rollback-enabled.ts +41 -0
  374. package/src/client/recovery/rollback-file-changes.test.ts +114 -0
  375. package/src/client/recovery/session-dialog-mount.test.ts +54 -0
  376. package/src/client/run-store.ts +84 -21
  377. package/src/client/sync/AutosyncCard.tsx +25 -1
  378. package/src/client/sync/ChannelClearConfirmDialog.tsx +6 -3
  379. package/src/client/sync/ChannelConfigDialog.tsx +10 -10
  380. package/src/client/sync/DecryptPasswordCard.tsx +2 -2
  381. package/src/client/sync/SecurityOptionsCard.tsx +27 -17
  382. package/src/client/sync/SyncChannelEntryCard.tsx +14 -2
  383. package/src/client/sync/SyncConfirmView.tsx +46 -8
  384. package/src/client/sync/SyncLogList.tsx +1 -1
  385. package/src/client/sync/SyncPanel.tsx +31 -23
  386. package/src/client/sync/SyncRepositoryPicker.tsx +3 -5
  387. package/src/client/sync/SyncSectionPickerDialog.tsx +11 -2
  388. package/src/client/sync/SyncSettingsView.test.ts +20 -1
  389. package/src/client/sync/UnreadableSnapshotsBanner.tsx +1 -1
  390. package/src/client/sync/WorkDirCard.tsx +112 -0
  391. package/src/client/sync/history-model.test.ts +42 -9
  392. package/src/client/sync/history-model.ts +30 -15
  393. package/src/client/sync/sync-api.test.ts +57 -33
  394. package/src/client/sync/sync-api.ts +80 -6
  395. package/src/client/sync/sync-locales.ts +104 -3
  396. package/src/client/sync/sync-view-v2.test.ts +65 -13
  397. package/src/client/sync/sync-view.test.ts +107 -52
  398. package/src/client/sync/sync-view.ts +124 -41
  399. package/src/core/analyzer.ts +31 -9
  400. package/src/core/backup-plan.test.ts +48 -5
  401. package/src/core/backup-plan.ts +51 -20
  402. package/src/core/backup-verify.ts +24 -23
  403. package/src/core/backup.test.ts +76 -0
  404. package/src/core/backup.ts +105 -29
  405. package/src/core/boot-rescue.ts +4 -3
  406. package/src/core/boot-safety.ts +2 -1
  407. package/src/core/command-rollback.test.ts +536 -0
  408. package/src/core/command-rollback.ts +406 -0
  409. package/src/core/consult-source.ts +7 -6
  410. package/src/core/disk-usage.test.ts +257 -1
  411. package/src/core/disk-usage.ts +134 -14
  412. package/src/core/engine-locale.test.ts +593 -0
  413. package/src/core/engine-locale.ts +175 -0
  414. package/src/core/exporter.ts +3 -3
  415. package/src/core/fork-reconcile.test.ts +279 -0
  416. package/src/core/fork-reconcile.ts +234 -0
  417. package/src/core/journal.ts +6 -5
  418. package/src/core/local-plugin-host.ts +3 -2
  419. package/src/core/local-plugin-pack.ts +11 -6
  420. package/src/core/messages-core.ts +661 -0
  421. package/src/core/messages.ts +125 -17
  422. package/src/core/migration-consult.ts +21 -20
  423. package/src/core/migration-history.ts +19 -5
  424. package/src/core/model-tools.ts +28 -27
  425. package/src/core/phase3-host.ts +21 -5
  426. package/src/core/phase3-p2b-fingerprint.test.ts +22 -0
  427. package/src/core/plugin-cli.ts +18 -19
  428. package/src/core/plugin-data-registry.test.ts +113 -0
  429. package/src/core/plugin-data-registry.ts +261 -0
  430. package/src/core/reconcile.test.ts +117 -0
  431. package/src/core/reconcile.ts +85 -17
  432. package/src/core/recovery-orchestrator.ts +19 -18
  433. package/src/core/reinstall.ts +26 -21
  434. package/src/core/restore.ts +20 -17
  435. package/src/core/rollback-file-diff.test.ts +159 -0
  436. package/src/core/rollback-gate.test.ts +66 -0
  437. package/src/core/rollback-gate.ts +61 -0
  438. package/src/core/rollback-ignore-rules.ts +126 -0
  439. package/src/core/rollback-ledger.test.ts +655 -0
  440. package/src/core/rollback-ledger.ts +1314 -0
  441. package/src/core/rollback-point.test.ts +2853 -0
  442. package/src/core/rollback-point.ts +4340 -0
  443. package/src/core/rollback.ts +5 -3
  444. package/src/core/run-registry.ts +6 -5
  445. package/src/core/session-health.ts +15 -0
  446. package/src/core/session-meta.test.ts +117 -1
  447. package/src/core/session-meta.ts +149 -2
  448. package/src/core/session-title.test.ts +127 -0
  449. package/src/core/session-title.ts +189 -0
  450. package/src/core/startup-barrier.test.ts +69 -0
  451. package/src/core/startup-barrier.ts +27 -0
  452. package/src/core/transaction-coordinator.ts +4 -3
  453. package/src/core/types.ts +37 -1
  454. package/src/core/validator.ts +5 -4
  455. package/src/core/verify-recovery.ts +31 -30
  456. package/src/foreign/bundle.ts +3 -2
  457. package/src/foreign/continue.ts +2 -1
  458. package/src/foreign/crush.ts +2 -1
  459. package/src/foreign/file-budget.test.ts +2 -0
  460. package/src/foreign/gemini.ts +2 -1
  461. package/src/foreign/goose.ts +2 -1
  462. package/src/foreign/kilocode.ts +2 -1
  463. package/src/foreign/kimi.ts +2 -1
  464. package/src/foreign/messages.ts +44 -0
  465. package/src/foreign/mimocode.ts +2 -1
  466. package/src/foreign/openclaw.ts +2 -1
  467. package/src/foreign/opencode.ts +2 -1
  468. package/src/foreign/pi.ts +2 -1
  469. package/src/foreign/qoder.ts +2 -1
  470. package/src/foreign/qwen.ts +2 -1
  471. package/src/foreign/registry.test.ts +1 -1
  472. package/src/foreign/registry.ts +8 -7
  473. package/src/foreign/teleagent.ts +2 -1
  474. package/src/foreign/workbuddy.ts +2 -1
  475. package/src/foreign/zcode.ts +2 -1
  476. package/src/foreign/zed.ts +2 -1
  477. package/src/index.facade.test.ts +340 -1
  478. package/src/index.ts +876 -57
  479. package/src/market/git-file-writer.ts +20 -19
  480. package/src/market/github-repos.test.ts +23 -0
  481. package/src/market/github-repos.ts +37 -19
  482. package/src/market/index-parser.ts +31 -30
  483. package/src/market/messages-market.ts +325 -0
  484. package/src/market/my-repo.ts +32 -29
  485. package/src/market/prepare.ts +18 -15
  486. package/src/market/security.ts +20 -19
  487. package/src/market/types.ts +2 -1
  488. package/src/market/url.ts +2 -1
  489. package/src/migrations/index.ts +6 -5
  490. package/src/migrations/messages-migrations.ts +59 -0
  491. package/src/profiles/dsh-profile-launcher.ts +2 -1
  492. package/src/profiles/dsh-profile-runtime.ts +2 -1
  493. package/src/profiles/messages.ts +31 -0
  494. package/src/routes/backup.ts +18 -2
  495. package/src/routes/import.ts +3 -3
  496. package/src/routes/index.ts +1 -1
  497. package/src/routes/kit.ts +9 -3
  498. package/src/routes/market.ts +1 -1
  499. package/src/routes/messages.ts +106 -0
  500. package/src/routes/prefs.ts +31 -2
  501. package/src/routes/profiles.ts +12 -6
  502. package/src/routes/recovery.test.ts +405 -1
  503. package/src/routes/recovery.ts +477 -94
  504. package/src/routes/snapshots.ts +51 -4
  505. package/src/routes/sync.ts +82 -17
  506. package/src/schema/config.ts +53 -20
  507. package/src/schema/index.ts +7 -5
  508. package/src/schema/manifest-schema.test.ts +4 -4
  509. package/src/schema/manifest.ts +19 -18
  510. package/src/schema/messages.ts +120 -0
  511. package/src/schema/registry.test.ts +28 -7
  512. package/src/schema/section-registry.ts +96 -42
  513. package/src/schema/types.ts +2 -1
  514. package/src/schema/versions.ts +6 -5
  515. package/src/security/encryption.ts +16 -15
  516. package/src/security/integrity.ts +8 -7
  517. package/src/security/messages.ts +87 -0
  518. package/src/security/redaction.test.ts +17 -1
  519. package/src/security/redaction.ts +13 -0
  520. package/src/security/secret-scanner.ts +19 -12
  521. package/src/security/security.test.ts +47 -0
  522. package/src/security/vault.ts +2 -1
  523. package/src/security/zip-security.ts +4 -3
  524. package/src/sync/ancestor.ts +2 -1
  525. package/src/sync/autosync-config.ts +21 -0
  526. package/src/sync/autosync-scheduler.test.ts +63 -7
  527. package/src/sync/autosync-scheduler.ts +118 -78
  528. package/src/sync/backup-files.ts +3 -2
  529. package/src/sync/backup-scheduler.ts +6 -5
  530. package/src/sync/blob-store.ts +2 -1
  531. package/src/sync/git/git-transport.test.ts +170 -8
  532. package/src/sync/git/git-transport.ts +176 -2
  533. package/src/sync/github-auth.ts +10 -9
  534. package/src/sync/layout.ts +13 -12
  535. package/src/sync/messages.ts +153 -0
  536. package/src/sync/review-queue.ts +6 -5
  537. package/src/sync/s3/messages.ts +16 -0
  538. package/src/sync/s3/s3-providers.ts +9 -6
  539. package/src/sync/s3/s3-transport.ts +1 -1
  540. package/src/sync/s3/sigv4.ts +3 -1
  541. package/src/sync/snapshot-crypto.ts +6 -5
  542. package/src/sync/snapshot-json.ts +3 -2
  543. package/src/sync/sync-credentials.test.ts +119 -0
  544. package/src/sync/sync-engine-download-tombstone.test.ts +1 -1
  545. package/src/sync/sync-engine.test.ts +226 -8
  546. package/src/sync/sync-engine.ts +154 -52
  547. package/src/sync/sync-history.ts +7 -6
  548. package/src/sync/sync-selection.test.ts +12 -2
  549. package/src/sync/sync-selection.ts +18 -5
  550. package/src/sync/transport.test.ts +1 -0
  551. package/src/sync/ui-prefs.test.ts +44 -1
  552. package/src/sync/ui-prefs.ts +39 -0
  553. package/src/sync/webdav/webdav-transport.ts +4 -1
  554. package/src/ui/artifact-view.ts +4 -3
  555. package/src/ui/commands.test.ts +1 -0
  556. package/src/ui/commands.ts +11 -1
  557. package/src/ui/diff-view.test.ts +9 -1
  558. package/src/ui/diff-view.ts +22 -0
  559. package/src/ui/disk-usage-view.test.ts +113 -6
  560. package/src/ui/disk-usage-view.ts +63 -7
  561. package/src/ui/errors.ts +4 -3
  562. package/src/ui/export-flow.ts +26 -20
  563. package/src/ui/foreign-view.test.ts +43 -0
  564. package/src/ui/foreign-view.ts +30 -3
  565. package/src/ui/i18n.ts +131 -2
  566. package/src/ui/import-wizard.ts +18 -10
  567. package/src/ui/progress.ts +2 -2
  568. package/src/ui/report.ts +7 -6
  569. package/src/ui/rollback-view.test.ts +836 -0
  570. package/src/ui/rollback-view.ts +1405 -0
  571. package/src/ui/selection-model.test.ts +33 -1
  572. package/src/ui/selection-model.ts +53 -0
  573. package/src/ui/session-inventory-view.test.ts +109 -0
  574. package/src/ui/session-inventory-view.ts +138 -3
  575. package/src/ui/session-issue-labels.test.ts +51 -0
  576. package/src/ui/session-issue-labels.ts +70 -0
  577. package/src/ui/sync-settings-view.test.ts +36 -0
  578. package/src/ui/sync-settings-view.ts +49 -0
  579. package/src/ui/test-helpers.ts +2 -1
  580. package/src/ui/types.ts +10 -4
  581. package/src/utils/atomic-write.ts +6 -5
  582. package/src/utils/bundle-scan.test.ts +2 -2
  583. package/src/utils/bundle-scan.ts +12 -1
  584. package/src/utils/env-lock.ts +83 -49
  585. package/src/utils/json.ts +7 -5
  586. package/src/utils/messages-utils.ts +232 -0
  587. package/src/utils/proxy.test.ts +25 -0
  588. package/src/utils/proxy.ts +19 -5
  589. package/src/utils/recursive-walk.test.ts +43 -0
  590. package/src/utils/recursive-walk.ts +75 -1
  591. package/src/utils/session-log-repair.ts +10 -9
  592. package/src/utils/zip.ts +27 -26
  593. package/lib/core/checkpoint.d.ts +0 -362
  594. package/lib/core/checkpoint.js +0 -1309
  595. package/src/core/checkpoint.test.ts +0 -665
  596. package/src/core/checkpoint.ts +0 -1614
package/lib/utils/zip.js CHANGED
@@ -17,6 +17,7 @@ import path from 'node:path';
17
17
  import zlib from 'node:zlib';
18
18
  import { parseJsonSafe } from './json.js';
19
19
  import { isPathSafe, isSameOrChild } from './paths.js';
20
+ import { utilsMsg } from './messages-utils.js';
20
21
  export const DEFAULT_ZIP_SAFETY_LIMITS = {
21
22
  maxEntries: 10_000,
22
23
  maxTotalBytes: 500 * 1024 * 1024,
@@ -78,7 +79,7 @@ export function assertZipEntryCount(count, limits = {}) {
78
79
  const readSideMax = DEFAULT_ZIP_SAFETY_LIMITS.maxEntries;
79
80
  const max = Math.min(limits.maxEntries ?? readSideMax, readSideMax, ZIP_MAX_WRITABLE_ENTRIES);
80
81
  if (count > max) {
81
- throw new ZipSafetyError(`ZIP 条目数 ${count} 超过上限 ${max}(导出上限与读取上限一致;请缩小导出分区范围后重试)`);
82
+ throw new ZipSafetyError(utilsMsg('utils.zip.entryCountWriteExceeded', { count, max }));
82
83
  }
83
84
  }
84
85
  /* ---------------- 写出侧布局片段(zipToBuffer 与 writeZip 共用,避免两份布局漂移) ----------------
@@ -171,7 +172,7 @@ export function zipToBuffer(entries, limits = {}) {
171
172
  const { time, date } = dosDateTime();
172
173
  for (const entry of entries) {
173
174
  if (!isPathSafe(entry.name)) {
174
- throw new ZipSafetyError(`拒绝写入不安全的条目名: ${entry.name}`);
175
+ throw new ZipSafetyError(utilsMsg('utils.zip.unsafeEntryNameWrite', { name: entry.name }));
175
176
  }
176
177
  const nameBuf = Buffer.from(entry.name, 'utf8');
177
178
  const data = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data);
@@ -206,7 +207,7 @@ export async function writeZip(zipPath, entries, limits = {}) {
206
207
  // 先全量校验条目名:不安全的名字在**落任何字节之前**拒绝(与 zipToBuffer 的拒绝顺序一致)
207
208
  const prepared = entries.map((entry) => {
208
209
  if (!isPathSafe(entry.name))
209
- throw new ZipSafetyError(`拒绝写入不安全的条目名: ${entry.name}`);
210
+ throw new ZipSafetyError(utilsMsg('utils.zip.unsafeEntryNameWrite', { name: entry.name }));
210
211
  return {
211
212
  nameBuf: Buffer.from(entry.name, 'utf8'),
212
213
  data: Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data),
@@ -342,11 +343,11 @@ export class ZipArchive {
342
343
  out = zlib.inflateRawSync(raw, { maxOutputLength: this.limits.maxSingleBytes });
343
344
  }
344
345
  catch (err) {
345
- throw new ZipSafetyError(`条目 "${name}" 解压失败: ${err instanceof Error ? err.message : String(err)}`);
346
+ throw new ZipSafetyError(utilsMsg('utils.zip.entryInflateFailed', { name, reason: err instanceof Error ? err.message : String(err) }));
346
347
  }
347
348
  }
348
349
  else {
349
- throw new ZipSafetyError(`条目 "${name}" 使用未知压缩方法 ${meta.method}`);
350
+ throw new ZipSafetyError(utilsMsg('utils.zip.unknownCompression', { name, method: meta.method }));
350
351
  }
351
352
  return this.accept(name, meta, out);
352
353
  }
@@ -372,11 +373,11 @@ export class ZipArchive {
372
373
  out = await inflateRawAsync(raw, this.limits.maxSingleBytes);
373
374
  }
374
375
  catch (err) {
375
- throw new ZipSafetyError(`条目 "${name}" 解压失败: ${err instanceof Error ? err.message : String(err)}`);
376
+ throw new ZipSafetyError(utilsMsg('utils.zip.entryInflateFailed', { name, reason: err instanceof Error ? err.message : String(err) }));
376
377
  }
377
378
  }
378
379
  else {
379
- throw new ZipSafetyError(`条目 "${name}" 使用未知压缩方法 ${meta.method}`);
380
+ throw new ZipSafetyError(utilsMsg('utils.zip.unknownCompression', { name, method: meta.method }));
380
381
  }
381
382
  return this.accept(name, meta, out);
382
383
  }
@@ -384,7 +385,7 @@ export class ZipArchive {
384
385
  metaOf(name) {
385
386
  const meta = this.metas.find((m) => m.name === name);
386
387
  if (!meta)
387
- throw new ZipSafetyError(`ZIP 中不存在条目: ${name}`);
388
+ throw new ZipSafetyError(utilsMsg('utils.zip.entryMissing', { name }));
388
389
  return meta;
389
390
  }
390
391
  /** 本地文件头校验 + 定位压缩字节区间(越界 → 抛错)。 */
@@ -392,32 +393,32 @@ export class ZipArchive {
392
393
  const lhOffset = meta.localOffset;
393
394
  const lh = this.buf.subarray(lhOffset, lhOffset + 30);
394
395
  if (lh.length < 30 || lh.readUInt32LE(0) !== LOCAL_SIG) {
395
- throw new ZipSafetyError(`条目 "${name}" 的本地文件头损坏`);
396
+ throw new ZipSafetyError(utilsMsg('utils.zip.localHeaderCorrupt', { name }));
396
397
  }
397
398
  const nameLen = lh.readUInt16LE(26);
398
399
  const extraLen = lh.readUInt16LE(28);
399
400
  const dataStart = lhOffset + 30 + nameLen + extraLen;
400
401
  if (dataStart + meta.compressedSize > this.buf.length) {
401
- throw new ZipSafetyError(`条目 "${name}" 数据越界`);
402
+ throw new ZipSafetyError(utilsMsg('utils.zip.dataOutOfRange', { name }));
402
403
  }
403
404
  return this.buf.subarray(dataStart, dataStart + meta.compressedSize);
404
405
  }
405
406
  /** 解压后的验收:尺寸 → CRC32 → 解压总量预算 → 压缩比(zip bomb)。两处解压路径共用同一套判据。 */
406
407
  accept(name, meta, out) {
407
408
  if (out.length !== meta.uncompressedSize) {
408
- throw new ZipSafetyError(`条目 "${name}" 解压尺寸不符(${out.length} ≠ ${meta.uncompressedSize})`);
409
+ throw new ZipSafetyError(utilsMsg('utils.zip.sizeMismatch', { name, actual: out.length, expected: meta.uncompressedSize }));
409
410
  }
410
411
  if (crc32(out) !== meta.crc32) {
411
- throw new ZipSafetyError(`条目 "${name}" CRC32 校验失败(ZIP 已损坏)`);
412
+ throw new ZipSafetyError(utilsMsg('utils.zip.crcMismatch', { name }));
412
413
  }
413
414
  this.totalUncompressed += out.length;
414
415
  if (this.totalUncompressed > this.limits.maxTotalBytes) {
415
- throw new ZipSafetyError('ZIP 解压总字节数超过上限');
416
+ throw new ZipSafetyError(utilsMsg('utils.zip.totalUncompressedExceeded'));
416
417
  }
417
418
  if (meta.compressedSize > 0) {
418
419
  const ratio = out.length / meta.compressedSize;
419
420
  if (ratio > this.limits.maxRatio) {
420
- throw new ZipSafetyError(`条目 "${name}" 压缩比 ${ratio.toFixed(1)} 超过上限(疑似 zip bomb)`);
421
+ throw new ZipSafetyError(utilsMsg('utils.zip.ratioExceeded', { name, ratio: ratio.toFixed(1) }));
421
422
  }
422
423
  }
423
424
  return out;
@@ -440,19 +441,19 @@ export function parseZip(buf, limits = {}) {
440
441
  const merged = { ...DEFAULT_ZIP_SAFETY_LIMITS, ...limits };
441
442
  const b = Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
442
443
  if (b.length < 22)
443
- throw new ZipSafetyError('不是合法的 ZIP 文件(体积过小)');
444
+ throw new ZipSafetyError(utilsMsg('utils.zip.tooSmall'));
444
445
  const eocdIdx = b.lastIndexOf(EOCD_SIG);
445
446
  if (eocdIdx < 0 || eocdIdx + 22 > b.length) {
446
- throw new ZipSafetyError('不是合法的 ZIP 文件(缺少中央目录结束记录)');
447
+ throw new ZipSafetyError(utilsMsg('utils.zip.missingEocd'));
447
448
  }
448
449
  const totalEntries = b.readUInt16LE(eocdIdx + 10);
449
450
  const cdSize = b.readUInt32LE(eocdIdx + 12);
450
451
  const cdOffset = b.readUInt32LE(eocdIdx + 16);
451
452
  if (cdOffset + cdSize > b.length) {
452
- throw new ZipSafetyError('中央目录越界(ZIP 损坏)');
453
+ throw new ZipSafetyError(utilsMsg('utils.zip.centralDirOutOfRange'));
453
454
  }
454
455
  if (totalEntries > merged.maxEntries) {
455
- throw new ZipSafetyError(`ZIP 条目数 ${totalEntries} 超过上限 ${merged.maxEntries}`);
456
+ throw new ZipSafetyError(utilsMsg('utils.zip.entryCountReadExceeded', { count: totalEntries, max: merged.maxEntries }));
456
457
  }
457
458
  const metas = [];
458
459
  /** 已见条目名:重复条目会让「按名读取」产生歧义(读取到哪一个取决于遍历顺序) */
@@ -461,9 +462,9 @@ export function parseZip(buf, limits = {}) {
461
462
  let compressedTotal = 0;
462
463
  for (let i = 0; i < totalEntries; i++) {
463
464
  if (pos + 46 > cdOffset + cdSize)
464
- throw new ZipSafetyError('中央目录条目越界(ZIP 损坏)');
465
+ throw new ZipSafetyError(utilsMsg('utils.zip.centralEntryOutOfRange'));
465
466
  if (b.readUInt32LE(pos) !== CENTRAL_SIG)
466
- throw new ZipSafetyError('中央目录签名损坏');
467
+ throw new ZipSafetyError(utilsMsg('utils.zip.centralSignatureCorrupt'));
467
468
  const method = b.readUInt16LE(pos + 10);
468
469
  const crc = b.readUInt32LE(pos + 16);
469
470
  const compSize = b.readUInt32LE(pos + 20);
@@ -475,21 +476,21 @@ export function parseZip(buf, limits = {}) {
475
476
  const localOffset = b.readUInt32LE(pos + 42);
476
477
  const name = b.subarray(pos + 46, pos + 46 + nameLen).toString('utf8');
477
478
  if (!isPathSafe(name))
478
- throw new ZipSafetyError(`ZIP 条目名不安全: ${name}`);
479
+ throw new ZipSafetyError(utilsMsg('utils.zip.unsafeEntryName', { name }));
479
480
  // —— 以下三项原属 security/zip-security.ts 的 parseZipHardened,现并入默认解析器 ——
480
481
  // (默认值即最严:未注入 parseZipOverride 的调用方不再拿到「弱版」)
481
482
  if (seenNames.has(name))
482
- throw new ZipSafetyError(`ZIP 条目名重复: ${name}`);
483
+ throw new ZipSafetyError(utilsMsg('utils.zip.duplicateEntryName', { name }));
483
484
  seenNames.add(name);
484
485
  if (((externalAttrs >>> 16) & S_IFMT) === S_IFLNK) {
485
- throw new ZipSafetyError(`ZIP 含符号链接条目,已拒绝: ${name}`);
486
+ throw new ZipSafetyError(utilsMsg('utils.zip.symlinkEntryRejected', { name }));
486
487
  }
487
488
  if (localOffset + 30 > b.length) {
488
- throw new ZipSafetyError(`条目 "${name}" 本地文件头越界`);
489
+ throw new ZipSafetyError(utilsMsg('utils.zip.localHeaderOutOfRange', { name }));
489
490
  }
490
491
  compressedTotal += compSize;
491
492
  if (compressedTotal > merged.maxCompressedBytes) {
492
- throw new ZipSafetyError('ZIP 压缩数据总量超过上限');
493
+ throw new ZipSafetyError(utilsMsg('utils.zip.compressedTotalExceeded'));
493
494
  }
494
495
  metas.push({
495
496
  name,
@@ -518,7 +519,7 @@ export async function safeExtract(zipPath, destDir, limits = {}) {
518
519
  continue;
519
520
  const target = path.join(destDir, ...meta.name.split('/'));
520
521
  if (!isSameOrChild(target, destDir)) {
521
- throw new ZipSafetyError(`解压目标越界: ${meta.name}`);
522
+ throw new ZipSafetyError(utilsMsg('utils.zip.extractTargetOutOfRange', { name: meta.name }));
522
523
  }
523
524
  await fs.mkdir(path.dirname(target), { recursive: true });
524
525
  await fs.writeFile(target, archive.readEntry(meta.name));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-config-manager",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "license": "MIT",
5
5
  "description": "Backup, restore, export, import, migrate and sync your DeepSeek Harness (DSH) configuration: settings, plugins, MCP servers, skills, agent presets and workspaces. One-click migration to another machine. DSH 配置一键备份、恢复、导出、导入、迁移与同步插件。",
6
6
  "icon": "./icon.svg",
@@ -99,8 +99,10 @@
99
99
  "@deepseek-ai/dsh-client-connection": ">=0.1.0-rc.6 <0.3.0-0",
100
100
  "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.6 <0.3.0-0",
101
101
  "@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.6 <0.3.0-0",
102
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.0-rc.6 <0.3.0-0",
102
103
  "@deepseek-ai/dsh-client-ui-settings": ">=0.1.0-rc.6 <0.3.0-0",
103
104
  "@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.6 <0.3.0-0",
105
+ "@deepseek-ai/dsh-commands": ">=0.1.0-rc.6 <0.3.0-0",
104
106
  "@deepseek-ai/dsh-credentials": ">=0.1.0-rc.6 <0.3.0-0",
105
107
  "@deepseek-ai/dsh-home-paths": ">=0.1.0-rc.6 <0.3.0-0",
106
108
  "@deepseek-ai/dsh-host-plugin-inventory": ">=0.1.0-rc.6 <0.3.0-0",
@@ -125,12 +127,18 @@
125
127
  "@deepseek-ai/dsh-client-runtime": {
126
128
  "optional": true
127
129
  },
130
+ "@deepseek-ai/dsh-client-ui-primitives": {
131
+ "optional": true
132
+ },
128
133
  "@deepseek-ai/dsh-client-ui-settings": {
129
134
  "optional": true
130
135
  },
131
136
  "@deepseek-ai/dsh-client-ui-slots": {
132
137
  "optional": true
133
138
  },
139
+ "@deepseek-ai/dsh-commands": {
140
+ "optional": true
141
+ },
134
142
  "@deepseek-ai/dsh-credentials": {
135
143
  "optional": true
136
144
  },
@@ -167,8 +175,10 @@
167
175
  "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6",
168
176
  "@deepseek-ai/dsh-client-locale": "^0.2.0-rc.2",
169
177
  "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.6",
170
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6",
178
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.2.0-rc.2",
179
+ "@deepseek-ai/dsh-client-ui-settings": "^0.2.0-rc.2",
171
180
  "@deepseek-ai/dsh-client-ui-slots": "^0.2.0-rc.2",
181
+ "@deepseek-ai/dsh-commands": "^0.2.0-rc.2",
172
182
  "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
173
183
  "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.6",
174
184
  "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.6",
@@ -40,7 +40,7 @@ export class AgentInstructionsAdapter extends FileCollectionAdapter {
40
40
  * (单文件代价可忽略,且 `collect` 之后还要读它)。读不到 → 空清单(与「文件不存在 = 空分区」同语义)。
41
41
  */
42
42
  protected override async listRelPaths(ctx: HostContext): Promise<RecursiveListing> {
43
- const empty: RecursiveListing = { paths: [], skippedLinks: [], followedLinks: 0, unreadableDirs: [] };
43
+ const empty: RecursiveListing = { paths: [], skippedLinks: [], skippedDepDirs: [], followedLinks: 0, unreadableDirs: [] };
44
44
  const rel = AgentInstructionsAdapter.FILE;
45
45
  try {
46
46
  if (ctx.fs.statSize !== undefined) {
@@ -152,6 +152,7 @@ test('字节闸门:单元的成员在遍历结果里不连续时同样整块
152
152
  ctx.fs.listRecursiveDetailed = async () => ({
153
153
  paths: ['skills/a/1.md', 'skills/b/1.md', 'skills/a/2.md'],
154
154
  skippedLinks: [],
155
+ skippedDepDirs: [],
155
156
  followedLinks: 0,
156
157
  unreadableDirs: [],
157
158
  });
@@ -191,7 +191,7 @@ export abstract class FileCollectionAdapter implements ConfigAdapter<FilesSectio
191
191
  // issue #37:用「跟随 junction/符号链接」的遍历,并把跟随/跳过的链接写进告警——
192
192
  // 此前链接目录及其全部内容被静默排除,备份仍报成功。
193
193
  // 枚举走 listRelPaths 钩子(单文件分区覆写它,避免对 home 根整目录递归)。
194
- let listing: RecursiveListing = { paths: [], skippedLinks: [], followedLinks: 0, unreadableDirs: [] };
194
+ let listing: RecursiveListing = { paths: [], skippedLinks: [], skippedDepDirs: [], followedLinks: 0, unreadableDirs: [] };
195
195
  try {
196
196
  listing = await this.listRelPaths(ctx);
197
197
  } catch {
@@ -215,6 +215,7 @@ test('issue #37: skills 导出把「跟随/跳过的链接」写进 warnings(
215
215
  src.fs.listRecursiveDetailed = async () => ({
216
216
  paths: ['skills/coding.md', 'skills/shared/inner.md'],
217
217
  skippedLinks: [{ path: 'skills/broken', reason: 'broken' }],
218
+ skippedDepDirs: [],
218
219
  followedLinks: 1,
219
220
  unreadableDirs: [],
220
221
  });
@@ -225,6 +226,32 @@ test('issue #37: skills 导出把「跟随/跳过的链接」写进 warnings(
225
226
  assert.equal(out.warnings.some((w) => w.includes('skills/broken')), true, '必须点名被跳过的链接');
226
227
  });
227
228
 
229
+ test('issue #76: skills 导出跳过 node_modules 依赖目录,并在导出报告里说明(不静默)', async () => {
230
+ const src = makeContext('win32', 'C:\\Users\\alice');
231
+ await src.fs.writeFile('skills/md2pdf/SKILL.md', Buffer.from('# md2pdf\n', 'utf8'));
232
+ await src.fs.writeFile('skills/md2pdf/package.json', Buffer.from('{"name":"md2pdf"}\n', 'utf8'));
233
+ // 宿主枚举已按 issue #76 排除依赖树,并把它带回来(真实 walk 的形态)
234
+ src.fs.listRecursiveDetailed = async () => ({
235
+ paths: ['skills/md2pdf/SKILL.md', 'skills/md2pdf/package.json'],
236
+ skippedLinks: [],
237
+ skippedDepDirs: [{ path: 'skills/md2pdf/node_modules', files: 11625 }],
238
+ followedLinks: 0,
239
+ unreadableDirs: [],
240
+ });
241
+
242
+ const out = await new SkillsAdapter().export(src, { includeSecrets: false });
243
+ assert.deepEqual(
244
+ out.data.files.map((f) => f.relativePath).sort(),
245
+ ['md2pdf/SKILL.md', 'md2pdf/package.json'],
246
+ '依赖树不得进包,技能本体与 package.json 必须进',
247
+ );
248
+ const line = out.warnings.find((w) => w.includes('运行时依赖目录')) ?? '';
249
+ assert.ok(line.length > 0, '缺依赖目录告警: ' + out.warnings.join(' | '));
250
+ assert.match(line, /11625 个文件/);
251
+ assert.match(line, /未进备份/);
252
+ assert.doesNotMatch(line, /链接/, '依赖目录不是链接问题,措辞不得混淆');
253
+ });
254
+
228
255
  test('agentPresets: 目录 bundle 文件收集与写入(.agent-presets 基准目录)', async () => {
229
256
  const src = makeContext('win32', 'C:\\Users\\alice');
230
257
  await src.fs.writeFile('.agent-presets/work/agent.cordis.yml', Buffer.from('services:\n - name: work\n', 'utf8'));
@@ -22,6 +22,7 @@ import { CredentialsAdapter, type CredentialRefsProvider } from './credentials.t
22
22
  import { PluginFilesAdapter } from './plugin-files.ts';
23
23
  import { SessionsAdapter } from './sessions.ts';
24
24
  import { SelfAdapter } from './self.ts';
25
+ import { PluginDataAdapter } from './plugin-data.ts';
25
26
 
26
27
  export interface AdapterRegistryOptions {
27
28
  /** settings namespace 清单(宿主从 settings.yaml 顶层 key 解析注入;缺省 [] → settings/ui/credentials 为空) */
@@ -64,6 +65,9 @@ export function createAdapters(options: AdapterRegistryOptions = {}): ConfigAdap
64
65
  new WorkspacesAdapter(),
65
66
  new CredentialsAdapter({ namespaces, refs: options.credentialsRefs }),
66
67
  new PluginFilesAdapter(options.pluginFiles, options.pluginFilesDir),
68
+ // 第三方插件数据(两个分区:配置类 / 大资产类;均 defaultIncluded=false,用户显式勾选)
69
+ new PluginDataAdapter('pluginData'),
70
+ new PluginDataAdapter('pluginAssets'),
67
71
  ];
68
72
  // self 分区:插件自身配置(同步/市场/偏好),portable 默认包含;'' = 不挂载
69
73
  if (options.selfDir !== '') {
@@ -77,7 +81,7 @@ export type { NamespaceProvider } from './settings.ts';
77
81
  export type { CredentialRefsProvider } from './credentials.ts';
78
82
 
79
83
  export { SettingsAdapter } from './settings.ts';
80
- export { UiAdapter, isUiNamespace, KNOWN_UI_NAMESPACE_PREFIXES, UI_MIGRATION_NOTES } from './ui.ts';
84
+ export { UiAdapter, isUiNamespace, KNOWN_UI_NAMESPACE_PREFIXES, uiMigrationNotes } from './ui.ts';
81
85
  export { ProvidersAdapter, DEFAULT_PROVIDER_NAMESPACES, type ProviderExportEntry, type ProviderExportSection } from './providers.ts';
82
86
  export { PluginsAdapter, USER_PATCH_FILE } from './plugins.ts';
83
87
  export type { LocalPluginPackHook } from './plugins.ts';
@@ -91,6 +95,7 @@ export { CredentialsAdapter, defaultCredentialRefs } from './credentials.ts';
91
95
  export { PluginFilesAdapter, DEFAULT_PLUGIN_FILE_WHITELIST } from './plugin-files.ts';
92
96
  export { SessionsAdapter } from './sessions.ts';
93
97
  export { SelfAdapter, SELF_CONFIG_FILES } from './self.ts';
98
+ export { PluginDataAdapter, type PluginDataAdapterOptions, type PluginDataEntry } from './plugin-data.ts';
94
99
  export { FileCollectionAdapter } from './file-collection.ts';
95
100
  /* JSON 分区共享校验骨架(本导出是其接入点)。收敛轨迹:
96
101
  * · t31 抽出骨架,settings / ui / providers / plugins / mcp / prompts / credentials /
@@ -8,7 +8,7 @@ import { zhMsg } from '../core/messages.ts';
8
8
  import type { FileSystemFacade } from '../core/types.ts';
9
9
  import type { RecursiveListing } from '../utils/recursive-walk.ts';
10
10
 
11
- const clean: RecursiveListing = { paths: ['skills/a.md'], skippedLinks: [], followedLinks: 0, unreadableDirs: [] };
11
+ const clean: RecursiveListing = { paths: ['skills/a.md'], skippedLinks: [], skippedDepDirs: [], followedLinks: 0, unreadableDirs: [] };
12
12
 
13
13
  test('linkWarnings:无链接 → 零告警(不制造噪音)', () => {
14
14
  assert.deepEqual(linkWarnings(zhMsg, 'Skills', clean), []);
@@ -26,6 +26,7 @@ test('linkWarnings:跳过项按原因归并,给出数量、原因与路径',
26
26
  const out = linkWarnings(zhMsg, 'Skills', {
27
27
  paths: [],
28
28
  followedLinks: 1,
29
+ skippedDepDirs: [],
29
30
  unreadableDirs: [],
30
31
  skippedLinks: [
31
32
  { path: 'skills/self', reason: 'loop' },
@@ -48,7 +49,7 @@ test('linkWarnings:跳过项按原因归并,给出数量、原因与路径',
48
49
 
49
50
  test('linkWarnings:目录读取失败也必须告警(其内容同样未进备份)', () => {
50
51
  const out = linkWarnings(zhMsg, 'Skills', {
51
- paths: [], followedLinks: 0, skippedLinks: [], unreadableDirs: ['skills/locked', 'skills/denied'],
52
+ paths: [], followedLinks: 0, skippedLinks: [], skippedDepDirs: [], unreadableDirs: ['skills/locked', 'skills/denied'],
52
53
  });
53
54
  assert.equal(out.length, 1);
54
55
  assert.match(out[0]!, /2 个目录读取失败/);
@@ -61,5 +62,24 @@ test('listFilesDetailed:宿主未实现 detailed 时回退到 listRecursive(
61
62
  const listing = await listFilesDetailed(fs, 'skills');
62
63
  assert.deepEqual(listing.paths, ['skills/x.md']);
63
64
  assert.deepEqual(listing.skippedLinks, []);
65
+ assert.deepEqual(listing.skippedDepDirs, []);
64
66
  assert.equal(listing.followedLinks, 0);
65
67
  });
68
+
69
+ test('issue #76:跳过的 node_modules 依赖目录必须告警(点名路径 + 文件数 + 可重建说明)', () => {
70
+ const out = linkWarnings(zhMsg, 'Skills', {
71
+ ...clean,
72
+ skippedDepDirs: [
73
+ { path: 'skills/md2pdf/node_modules', files: 11625 },
74
+ { path: 'skills/other/node_modules', files: null },
75
+ ],
76
+ });
77
+ assert.equal(out.length, 1, '汇总成一条,不逐目录刷屏');
78
+ const line = out[0]!;
79
+ assert.match(line, /2 个运行时依赖目录/);
80
+ assert.match(line, /未进备份/);
81
+ assert.match(line, /skills\/md2pdf\/node_modules/);
82
+ assert.match(line, /11625 个文件/);
83
+ assert.match(line, /文件数未统计/, '计数预算耗尽时不得猜一个数(更不得写成 0)');
84
+ assert.match(line, /重新安装依赖/);
85
+ });
@@ -9,7 +9,9 @@
9
9
  */
10
10
  import type { FileSystemFacade } from '../core/types.ts';
11
11
  import type { MsgFunc } from '../core/messages.ts';
12
- import type { RecursiveListing, SkippedLink } from '../utils/recursive-walk.ts';
12
+ // t6:注册 adapters 域追加目录(本模块只消费注入的 msg,故只引它的注册副作用)。
13
+ import './messages.ts';
14
+ import type { RecursiveListing, SkippedDepDir, SkippedLink } from '../utils/recursive-walk.ts';
13
15
 
14
16
  /** 跳过原因 → 消息 key(与 SkippedLink.reason 一一对应,穷尽映射) */
15
17
  const REASON_KEY: Record<SkippedLink['reason'], string> = {
@@ -23,10 +25,27 @@ const REASON_KEY: Record<SkippedLink['reason'], string> = {
23
25
  /** 单条原因下最多列出的路径数(其余折叠为计数,避免把报告撑爆) */
24
26
  const MAX_PATHS_PER_REASON = 5
25
27
 
28
+ /**
29
+ * 被跳过的依赖目录 → 详情片段(路径 + 文件数,issue #76)。
30
+ *
31
+ * 文件数是**量级说明**而非完整性判据:计数预算耗尽时如实写「未统计」,绝不猜一个数
32
+ * (把未知写成 0 会被读成「这个目录是空的」)。
33
+ */
34
+ function depDirDetail(msg: MsgFunc, dirs: SkippedDepDir[]): string {
35
+ const shown = dirs.slice(0, MAX_PATHS_PER_REASON).map((dir) => {
36
+ const files = dir.files === null
37
+ ? msg('adapter.depsDirFilesUnknown')
38
+ : msg('adapter.depsDirFiles', { count: String(dir.files) })
39
+ return msg('adapter.linkDirEntry', { path: dir.path, files })
40
+ })
41
+ const more = dirs.length - shown.length
42
+ return (more > 0 ? [...shown, `(+ ${more})`] : shown).join(', ')
43
+ }
44
+
26
45
  /** 取遍历结果:宿主未实现 listRecursiveDetailed(旧版/测试 mock)时回退,行为与旧版一致。 */
27
46
  export async function listFilesDetailed(fs: FileSystemFacade, dir: string): Promise<RecursiveListing> {
28
47
  if (fs.listRecursiveDetailed !== undefined) return fs.listRecursiveDetailed(dir)
29
- return { paths: await fs.listRecursive(dir), skippedLinks: [], followedLinks: 0, unreadableDirs: [] }
48
+ return { paths: await fs.listRecursive(dir), skippedLinks: [], skippedDepDirs: [], followedLinks: 0, unreadableDirs: [] }
30
49
  }
31
50
 
32
51
  /** 把遍历结果转成告警行(无链接时返回空数组 —— 不制造噪音)。 */
@@ -45,8 +64,8 @@ export function linkWarnings(msg: MsgFunc, type: string, listing: RecursiveListi
45
64
  const detail = [...byReason.entries()].map(([reason, paths]) => {
46
65
  const shown = paths.slice(0, MAX_PATHS_PER_REASON).join(', ')
47
66
  const more = paths.length > MAX_PATHS_PER_REASON ? ` (+ ${paths.length - MAX_PATHS_PER_REASON})` : ''
48
- return `${msg(REASON_KEY[reason])} ${paths.length} 个: ${shown}${more}`
49
- }).join(';')
67
+ return msg('adapter.linkSkipLine', { reason: msg(REASON_KEY[reason]), count: paths.length, paths: shown, more })
68
+ }).join(msg('adapter.listSeparator'))
50
69
  out.push(msg('adapter.linksSkipped', { type, count: String(listing.skippedLinks.length), detail }))
51
70
  }
52
71
  if (listing.unreadableDirs.length > 0) {
@@ -57,5 +76,11 @@ export function linkWarnings(msg: MsgFunc, type: string, listing: RecursiveListi
57
76
  type, count: String(listing.unreadableDirs.length), detail: `${shown}${more}`,
58
77
  }))
59
78
  }
79
+ // issue #76:运行时依赖目录整棵跳过(内容未进备份)——与链接/不可读目录同等对待:必须可见,绝不静默。
80
+ if (listing.skippedDepDirs.length > 0) {
81
+ out.push(msg('adapter.depsDirsSkipped', {
82
+ type, count: String(listing.skippedDepDirs.length), detail: depDirDetail(msg, listing.skippedDepDirs),
83
+ }))
84
+ }
60
85
  return out
61
86
  }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * adapters 域(src/adapters/**)的追加消息目录(zh 源 / en 镜像),归 t6 作用域。
3
+ *
4
+ * 为什么不在 \`src/core/messages.ts\` 追加:该文件不在本作用域的 inScope 内,且既有 372 键有冻结指纹。
5
+ * 本模块经 \`registerMessageCatalog\` 注册**追加目录**:engineMsg / makeMsg 的查找顺序是
6
+ * 「既有目录 → en 下回退既有 zh → 注册目录 → 键名」,所以本域新键只在既有目录未命中时生效,
7
+ * 不可能遮蔽 core 的既有 adapter.* 键。
8
+ *
9
+ * 纪律:zh 值 = 改动前的既有中文文案**逐字原样**;en 为 \`Record<keyof typeof zh, string>\`(缺键即编译错)。
10
+ * **导入本模块即完成注册**:本域消费面是注入的 ctx.msg(MsgFunc)与 engineMsg,两者都查注册目录。
11
+ */
12
+ import { engineMsg as engineMsgOf, registerMessageCatalog } from '../core/engine-locale.ts';
13
+ import type { MsgFunc } from '../core/msg-types.ts';
14
+
15
+ export const zh = {
16
+ // ---------- 链接 / 依赖目录报告(issue #37 / #76)----------
17
+ 'adapter.linkDirEntry': '{path}({files})',
18
+ 'adapter.linkSkipLine': '{reason} {count} 个: {paths}{more}',
19
+ 'adapter.listSeparator': ';',
20
+ // ---------- pluginFiles / tarball ----------
21
+ 'adapter.pluginFilesCollectDirInvalid': 'pluginFiles collectDir 非法(须为相对 ~/.dsh 根的安全路径): {dir}',
22
+ 'adapter.tarballRelPathInvalid': '非法 tarball 相对路径: {path}',
23
+ 'adapter.localTarballUnpackFailed': '本地插件 {name} 的 tarball 解包失败,回退原始 spec:{err}',
24
+ // ---------- prompts 计划项明细 ----------
25
+ 'adapter.promptDiffDetail': '行 {line} current={current} imported={imported}',
26
+ // ---------- 会话连带失败明细 ----------
27
+ 'adapter.sessionUncoupledNote': '{id}({reason})',
28
+ // ---------- 工作区告警拼接 ----------
29
+ 'adapter.workspaceNotesParen': '({notes})',
30
+ // ---------- localStorage 等 Host 无通道的 UI 状态说明 ----------
31
+ 'adapter.uiLocalStorageTaskBoard': '任务看板数据存于浏览器 localStorage,Host 侧无访问通道,需在目标机器重新配置',
32
+ 'adapter.uiLocalStoragePanel': '面板宽度/折叠状态存于浏览器 localStorage,Host 侧无访问通道,需在目标机器重新配置',
33
+ 'adapter.uiLocalStorageGeneric': '浏览器端 UI 状态无法经 Host API 迁移',
34
+ // ---------- pluginData / pluginAssets(第三方插件数据迁移) ----------
35
+ 'adapter.pluginDataEnvOverridden': '{path} 的位置被环境变量 {env} 覆盖,本次已跳过(不猜它指向哪里)',
36
+ 'adapter.pluginDataPathNotAllowed': '路径不在第三方插件数据的允许范围内,已拒绝写入: {path}',
37
+ 'adapter.pluginDataNoOsHome': '第三方插件的数据在系统主目录下,但当前宿主没有提供该目录的文件通道(旧版本宿主):本次不读取也不导入 / third-party plugin data lives under the system home directory, but this host offers no file channel for it (older host): nothing is read or imported this time',
38
+ } as const;
39
+
40
+ export const en: Record<keyof typeof zh, string> = {
41
+ 'adapter.linkDirEntry': '{path} ({files})',
42
+ 'adapter.linkSkipLine': '{reason} {count} item(s): {paths}{more}',
43
+ 'adapter.listSeparator': '; ',
44
+ 'adapter.pluginFilesCollectDirInvalid': 'pluginFiles collectDir is invalid (must be a safe path relative to the ~/.dsh root): {dir}',
45
+ 'adapter.tarballRelPathInvalid': 'Invalid relative tarball path: {path}',
46
+ 'adapter.localTarballUnpackFailed': 'Failed to unpack the tarball of local plugin {name}; falling back to the original spec: {err}',
47
+ 'adapter.promptDiffDetail': 'line {line} current={current} imported={imported}',
48
+ 'adapter.sessionUncoupledNote': '{id} ({reason})',
49
+ 'adapter.workspaceNotesParen': ' ({notes})',
50
+ 'adapter.uiLocalStorageTaskBoard': 'Task-board data lives in the browser localStorage and the host has no access path; reconfigure it on the target machine',
51
+ 'adapter.uiLocalStoragePanel': 'Panel width/collapsed state lives in the browser localStorage and the host has no access path; reconfigure it on the target machine',
52
+ 'adapter.uiLocalStorageGeneric': 'Browser-side UI state cannot be migrated through the host API',
53
+ 'adapter.pluginDataEnvOverridden': "the location of {path} is overridden by the {env} environment variable; skipped this time (the new location is never guessed)",
54
+ 'adapter.pluginDataPathNotAllowed': 'the path is outside the range allowed for third-party plugin data and was refused: {path}',
55
+ 'adapter.pluginDataNoOsHome': 'third-party plugin data lives under the system home directory, but this host offers no file channel for it (older host): nothing is read or imported this time',
56
+ };
57
+
58
+ registerMessageCatalog({ id: 'adapters-domain', zh, en });
59
+
60
+ /** 本域活翻译器(与 core 的 engineMsg 同一实现;导入本模块即完成目录注册)。 */
61
+ export const engineMsg: MsgFunc = engineMsgOf;