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
@@ -0,0 +1,69 @@
1
+ /**
2
+ * 单文件前后对照面板 —— DSH 右侧栏标签页与预览弹窗的降级内嵌**共用同一个**渲染。
3
+ *
4
+ * 数据面只有一种形状(`RollbackFileDiffResult`):界面按「能不能逐行对照」分派四态
5
+ * (结构原因 / 一致 / 有差异 / 读失败),**不猜、不撒谎**:
6
+ * · `reason` 有值 ⇒ 说「看不了」并给原因(绝不显示成「没有差异」);
7
+ * · `identical` ⇒ 才说「一致」。
8
+ * 安全:单元格正文是磁盘原文 ⇒ 展示前必过 redact()(由 DiffTable 的 sanitize 承接)。
9
+ */
10
+ import type { TranslateNS } from '../client-types.ts'
11
+ import type { RollbackFileDiffResult } from '../../ui/rollback-view.ts'
12
+ import { rollbackFileDiffComparable, rollbackFileDiffReasonKey } from '../../ui/rollback-view.ts'
13
+ import { redact } from '../../security/redaction.ts'
14
+ import { Banner, Spinner } from '../common/ui.tsx'
15
+ import { DiffTable } from '../common/DiffTable.tsx'
16
+ import css from '../config-manager.module.css'
17
+
18
+ type RKey = Parameters<TranslateNS<'config-manager-recovery'>>[0]
19
+ const rk = (key: string): RKey => key as RKey
20
+
21
+ /** 面板状态(加载 / 就绪 / 读失败)。 */
22
+ export type RollbackDiffState =
23
+ | { status: 'loading' }
24
+ | { status: 'ready'; diff: RollbackFileDiffResult }
25
+ | { status: 'error'; message: string | null }
26
+
27
+ export interface RollbackDiffPaneProps {
28
+ state: RollbackDiffState
29
+ rt: TranslateNS<'config-manager-recovery'>
30
+ /**
31
+ * 文件头(可选)= 该文件路径:给了就在差异上方画一行「路径 + +A/−R」(编辑器式)。
32
+ * 调用方**已在别处写过这份路径**(聊天预览/设置页的就地展示原本各画一行)时**不要传** —— 同一路径不画两遍。
33
+ */
34
+ title?: string
35
+ /**
36
+ * 撑满宿主给的高度(**只有侧栏标签页该给**):正文是那一屏的唯一内容时,
37
+ * 表格自己吃掉剩余高度、滚动只发生在表格里;弹窗 / 计划列表里的就地差异不给(那些容器有别的约束)。
38
+ */
39
+ fill?: boolean
40
+ }
41
+
42
+ export function RollbackDiffPane({ state, rt, title, fill }: RollbackDiffPaneProps) {
43
+ if (state.status === 'loading') return <Spinner label={rt('rollback.diff.loading')} />
44
+ if (state.status === 'error') return <Banner kind="error">{state.message === null ? rt('rollback.diff.failed') : redact(state.message)}</Banner>
45
+ const diff = state.diff
46
+ if (diff.ok !== true) {
47
+ // 宿主结构化拒绝(未命中记录 / 存储栈不可用 …):给可读文案 + 真实 code(不裸渲染机器码,但也不藏)
48
+ const code = diff.code === undefined || diff.code === '' ? '' : ' — ' + diff.code
49
+ return <Banner kind="error">{rt('rollback.diff.failed') + code}</Banner>
50
+ }
51
+ if (!rollbackFileDiffComparable(diff)) {
52
+ const key = rollbackFileDiffReasonKey(diff.reason)
53
+ return <div className={css.hint}>{key === null ? rt('rollback.diff.reason.unknown') : rt(rk(key))}</div>
54
+ }
55
+ if (diff.identical) return <div className={css.hint}>{rt('rollback.diff.identical')}</div>
56
+ return (
57
+ <div className={fill === true ? css.diffPane + ' ' + css.diffPaneFill : css.diffPane}>
58
+ {diff.degraded && <div className={css.hint}>{rt('rollback.diff.degraded')}</div>}
59
+ <DiffTable
60
+ hunks={diff.hunks}
61
+ title={title}
62
+ beforeLabel={rt('rollback.diff.before')}
63
+ afterLabel={rt('rollback.diff.after')}
64
+ truncatedNotice={(shown, total) => rt('rollback.diff.truncated', { shown: String(shown), total: String(total) })}
65
+ sanitize={redact}
66
+ />
67
+ </div>
68
+ )
69
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * 回退预览的文件清单 —— **一份实现,两处调用**:
3
+ * · 聊天里用户消息旁的回退预览(`src/client/chat/RollbackReviewDialog.tsx`);
4
+ * · 设置页「环境 → 工作区 + 会话回滚」回滚卡的预览弹窗(`src/client/recovery/RollbackCard.tsx`)。
5
+ *
6
+ * 为什么抽成一个文件(2026-10-12 用户要求「设置页的回退预览也要一眼看清被改动的文件」):
7
+ * 两处必须**逐字同版式** —— 图标 | 目录(弱化)+ 基名(主色)| 右对齐统计;删除行写「删除」;
8
+ * 行数不可信写「行数未统计」。版式散在两处就会漂移,所以渲染只有这一份。
9
+ * 数据面与判定面照旧各自只有一份:行数据来自 `readRollbackPreviewFiles` /
10
+ * `readRollbackPreviewRemovals`(引擎 `preview.workspace` 的同一份数据),统计口径来自
11
+ * `rollbackPreviewScope`(只累加两侧都可信的行数)。
12
+ *
13
+ * 诚实边界(不假装):
14
+ * · **删除行不是按钮**:这类路径不在该回滚点的记录里,引擎的 file-diff 也读不出它 ⇒ 点了也没有
15
+ * 差异可看。「点文件名看差异」只对**能看**的行成立(调用方给了 `view` 才把路径画成按钮)。
16
+ * · 行数可能是 `null`(超限 / 非文本 / 内容副本读不出)⇒ 那一格写「行数未统计」,**绝不写 0**:
17
+ * 「0 行」是一个会被证伪的具体断言,而「不知道」不是。
18
+ * · 形状读不出(`status` 不在取值域)⇒ 不画语义色条(宁可不画,也不按猜测上色)。
19
+ */
20
+ import type { TranslateNS } from '../client-types.ts'
21
+ import { rollbackPreviewFileLabel, splitRollbackPath } from '../../ui/rollback-view.ts'
22
+ import { RollbackFileIcon, type RollbackFileIconRenderer } from '../chat/RollbackFileIcon.tsx'
23
+ import {
24
+ previewFileStatusKnown,
25
+ rollbackPreviewFileKey,
26
+ type ChatPreviewFileRow,
27
+ } from '../chat/rollback-entry-view.ts'
28
+ import css from '../config-manager.module.css'
29
+
30
+ type RKey = Parameters<TranslateNS<'config-manager-recovery'>>[0]
31
+ const rk = (key: string): RKey => key as RKey
32
+
33
+ /** 一个文件的「查看差异」入口(调用方给的已插值文案 + 点击回调)。 */
34
+ export interface RollbackFileViewEntry {
35
+ /** 该行的无障碍名 / 悬停提示(把 {path} 插好的完整句)。 */
36
+ hint: (path: string) => string
37
+ /** 忙态或还没有可写目标时禁用 —— 入口仍占位(不消失)。 */
38
+ disabled: boolean
39
+ onView: (path: string) => void
40
+ }
41
+
42
+ export interface RollbackFileChangesProps {
43
+ /** 会被**改动**的文件(`readRollbackPreviewFiles(preview.workspace)` 的产物)。 */
44
+ files: readonly ChatPreviewFileRow[]
45
+ /** 会被整文件**删除**的路径(`readRollbackPreviewRemovals(preview.workspace)` 的产物)。 */
46
+ removals: readonly string[]
47
+ /** recovery 字典翻译器(±行数 / 「删除」/「行数未统计」的词汇单一所有)。 */
48
+ rt: TranslateNS<'config-manager-recovery'>
49
+ /** 逐行「查看差异」;不给 = 该表面没有差异通道(那时路径只是文字,不给假入口)。 */
50
+ view?: RollbackFileViewEntry
51
+ /** 文件类型图标的外部来源(装了 dsh-better-sidebar 时由装配点注入)。 */
52
+ renderFileIcon?: RollbackFileIconRenderer
53
+ }
54
+
55
+ /**
56
+ * 一行文件统计:`+N` / `−M`;任一侧是 null ⇒ 「行数未统计」整句替换(绝不打 0)。
57
+ * 两侧都可信时**两个数字都给**(新增与删除是两件事,用户两个都要看)。
58
+ *
59
+ * 例外:**整文件删除写「删除」**,不写 `+0 −N`。判据只看引擎给的 `status === 'delete'`
60
+ * (取值域在 src/ui/rollback-view.ts,契约里已有),**绝不**从 `added === 0` 反推删除 ——
61
+ * 一个文件被清空成 0 行同样是 `+0 −N`,那是另一件事。
62
+ */
63
+ function FileStat({ status, added, removed, unknown, deleted, rt }: {
64
+ status: string
65
+ added: number | null
66
+ removed: number | null
67
+ unknown: string
68
+ /** 「删除」这一句(调用点传已翻译文本,本组件不碰字典键)。 */
69
+ deleted: string
70
+ rt: TranslateNS<'config-manager-recovery'>
71
+ }) {
72
+ if (status === 'delete') return <span className={css.rollbackDeleted}>{deleted}</span>
73
+ if (added === null || removed === null) return <span className={css.hint}>{unknown}</span>
74
+ return (
75
+ <>
76
+ <span className={css.rollbackAdded}>{rt(rk('rollback.preview.file.added'), { n: String(added) })}</span>
77
+ <span className={css.rollbackRemoved}>{rt(rk('rollback.preview.file.removed'), { n: String(removed) })}</span>
78
+ </>
79
+ )
80
+ }
81
+
82
+ /** 文件清单(改动行 + 删除行)。两处调用共用这一份渲染。 */
83
+ export function RollbackFileChanges({ files, removals, rt, view, renderFileIcon }: RollbackFileChangesProps) {
84
+ return (
85
+ <div className={css.rollbackFileList} role="list">
86
+ {files.map((file, index) => {
87
+ // 目录弱化 + 基名主色:只画基名时 `.git/index` 读不出「在哪」。
88
+ const { dir, base } = splitRollbackPath(file.path)
89
+ const label = (
90
+ <>
91
+ {dir !== '' && <span className={css.rollbackFileDir}>{dir}</span>}
92
+ {base}
93
+ </>
94
+ )
95
+ return (
96
+ <div
97
+ key={rollbackPreviewFileKey(file.path, file.added, file.removed, index)}
98
+ className={css.rollbackFileRow}
99
+ role="listitem"
100
+ data-kind={previewFileStatusKnown(file.status) ? file.status : undefined}
101
+ >
102
+ {/* 文件类型图标(DSH 文件树同一颗)。装饰性:行内文件名就是它的可访问名。 */}
103
+ <span className={css.rollbackFileIcon} aria-hidden="true">
104
+ <RollbackFileIcon path={file.path} size={14} render={renderFileIcon} />
105
+ </span>
106
+ {/* 主标签 = 目录(弱化)+ 文件名(主色)。给了 `view` 时**它本身就是那颗按钮**
107
+ (2026-10-12 用户要求:不要尾部的独立「查看」按钮,点文件名直接跳)。
108
+ 为什么按钮不是整行:整行做热区会把右侧 `+N −M` 也变成可点区域,鼠标停在统计上
109
+ 像是要点它;这里只有名字/目录可点,统计永远点不到。完整路径仍在 title 里。 */}
110
+ {view === undefined ? (
111
+ <span className={`${css.rollbackFilePath} ${css.mono}`} title={file.path}>{label}</span>
112
+ ) : (
113
+ <button
114
+ type="button"
115
+ className={`${css.rollbackFilePath} ${css.mono}`}
116
+ title={file.path}
117
+ aria-label={view.hint(file.path)}
118
+ disabled={view.disabled}
119
+ onClick={() => { view.onView(file.path) }}
120
+ >
121
+ {label}
122
+ </button>
123
+ )}
124
+ {/* ±行数紧跟文件名(统计列右对齐、列宽固定):三种取值的右缘对齐成一条竖线。 */}
125
+ <span className={css.rollbackFileStat}>
126
+ <FileStat
127
+ status={file.status}
128
+ added={file.added}
129
+ removed={file.removed}
130
+ unknown={rt('rollback.preview.file.unknown')}
131
+ deleted={rt(rk('rollback.preview.file.deleted'))}
132
+ rt={rt}
133
+ />
134
+ </span>
135
+ </div>
136
+ )
137
+ })}
138
+ {removals.map((path, index) => {
139
+ const { dir, base } = splitRollbackPath(path)
140
+ return (
141
+ <div
142
+ key={'remove:' + rollbackPreviewFileKey(path, null, null, index)}
143
+ className={css.rollbackFileRow}
144
+ role="listitem"
145
+ data-kind="delete"
146
+ >
147
+ <span className={css.rollbackFileIcon} aria-hidden="true">
148
+ <RollbackFileIcon path={path} size={14} render={renderFileIcon} />
149
+ </span>
150
+ {/* 删除行**不是按钮**(纯文本):见文件头「诚实边界」第 1 条。 */}
151
+ <span className={`${css.rollbackFilePath} ${css.mono}`} title={path}>
152
+ {dir !== '' && <span className={css.rollbackFileDir}>{dir}</span>}
153
+ {base || rollbackPreviewFileLabel(path)}
154
+ </span>
155
+ <span className={css.rollbackFileStat}>
156
+ <span className={css.rollbackDeleted}>{rt(rk('rollback.preview.file.deleted'))}</span>
157
+ </span>
158
+ </div>
159
+ )
160
+ })}
161
+ </div>
162
+ )
163
+ }
@@ -13,7 +13,7 @@
13
13
  * 安全约束:错误文本由 Host 侧脱敏;进入救援模式是高风险写盘动作,confirm 必须由调用方在
14
14
  * 显式确认弹窗后传入 —— 本层绝不代填。本文件不 import 任何 node 模块(纯浏览器 bundle)。
15
15
  */
16
- import { zhUiT, type UiT } from '../../ui/i18n.ts'
16
+ import type { UiT } from '../../ui/i18n.ts'
17
17
  import { getJson, LONG_REQUEST_TIMEOUT_MS, postJson, type RequestOptions } from '../common/http.ts'
18
18
  import { INCIDENT_API } from '../common/routes.ts'
19
19
 
@@ -62,7 +62,7 @@ export interface RescueActionResult {
62
62
  /** 事故恢复(崩溃归因 + 救援模式)浏览器半数据入口。 */
63
63
  export class IncidentApi {
64
64
  readonly t: UiT
65
- constructor(t: UiT = zhUiT) {
65
+ constructor(t: UiT) {
66
66
  this.t = t
67
67
  }
68
68
 
@@ -16,6 +16,12 @@
16
16
  * POST /api/dsh-config-manager/recovery/lock/recover → RecoveryLockRecoverResult
17
17
  * POST /api/dsh-config-manager/recovery/safe-mode/clear → RecoverySafeModeClearResult
18
18
  * POST /api/dsh-config-manager/recovery/sessions/layout → SessionLayoutPlanView | SessionLayoutApplyView
19
+ * GET /api/dsh-config-manager/recovery/rollback-points → RollbackListResult
20
+ * GET /api/dsh-config-manager/recovery/rollback-points/storage → RollbackStorageStatus
21
+ * GET /api/dsh-config-manager/recovery/rollback-points/<id> → RollbackDetailResult
22
+ * GET /api/dsh-config-manager/recovery/rollback-points/<id>/preview → RollbackPreviewResult
23
+ * POST /api/dsh-config-manager/recovery/rollback-points/<id>/rewind → RollbackRewindResult
24
+ * POST /api/dsh-config-manager/recovery/rollback-points/<id>/delete → RollbackRemoveResult
19
25
  * ```
20
26
  *
21
27
  * 安全约束(§9.4 / §11):
@@ -35,9 +41,22 @@ import type {
35
41
  SessionRepairResult,
36
42
  SessionRepairRollbackResult,
37
43
  } from '../../ui/session-inventory-view.ts';
38
- import type { SessionLayoutResponse } from '../../ui/session-layout-view.ts';
44
+ import type { SessionLayoutResponse } from '../../ui/session-layout-view.ts'
45
+ import type {
46
+ RollbackDetailResult,
47
+ RollbackFileDiffResult,
48
+ RollbackListResult,
49
+ RollbackPointPort,
50
+ RollbackPreviewResult,
51
+ RollbackRemoveResult,
52
+ RollbackRewindOptions,
53
+ RollbackRewindResult,
54
+ RollbackPrefsResult,
55
+ RollbackPurgeResult,
56
+ RollbackStorageStatus,
57
+ } from '../../ui/rollback-view.ts';
39
58
  import { ConfigManagerApiError, getJson, LONG_REQUEST_TIMEOUT_MS, postJson, type RequestOptions } from '../common/http.ts';
40
- import { zhUiT, type UiT } from '../../ui/i18n.ts';
59
+ import type { UiT } from '../../ui/i18n.ts';
41
60
  import { RECOVERY_API } from '../common/routes.ts';
42
61
 
43
62
  /** recovery 端点常量:**唯一来源** = `common/routes.ts`(W4 单点化),此处重导出保持导入面。 */
@@ -49,7 +68,25 @@ const RECOVERY_OPTS: RequestOptions = { timeoutMs: LONG_REQUEST_TIMEOUT_MS, time
49
68
  /* 请求封装(readJson / getJson / postJson:统一超时 + 取消 + 错误映射)见 common/http.ts。 */
50
69
 
51
70
  /** operationId 严格 UUID 校验(与 Host 侧 isValidOperationId 一致;防路径穿越)。 */
52
- const OPERATION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
71
+ const OPERATION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
72
+
73
+ /**
74
+ * rollback-point 台账 id → 子路径。
75
+ *
76
+ * 只接受 `[A-Za-z0-9._-]{1,128}`:id 是宿主生成的,这里**只做形态收窄**(与 operationId 的
77
+ * UUID 校验同一条理由 —— 防路径穿越);不合形态的 id 直接抛,**绝不回显原始 id**、绝不拼进 URL
78
+ * 让宿主去兜。路径由 `RECOVERY_API.rollbackPoints` **派生**(路由常量是唯一来源;源码级守卫
79
+ * `http-usage-guard` 也只允许 `common/routes.ts` 出现 `/api/dsh-config-manager…` 字面量)。
80
+ */
81
+ const ROLLBACK_POINT_ID_RE = /^[A-Za-z0-9._-]{1,128}$/
82
+ function rollbackPointUrl(id: string): string {
83
+ if (!ROLLBACK_POINT_ID_RE.test(id)) throw new Error('rollback point id invalid')
84
+ return RECOVERY_API.rollbackPoints + '/' + id
85
+ }
86
+
87
+ function rollbackPointPath(id: string, sub: string): string {
88
+ return rollbackPointUrl(id) + '/' + sub
89
+ }
53
90
 
54
91
  /**
55
92
  * E2:`POST /recovery/sessions/layout`(布局归位 / 重复 id 隔离)。
@@ -67,10 +104,10 @@ function operationPath(operationId: string, action: string): string {
67
104
  return `${RECOVERY_API.base}/${operationId}/${action}`;
68
105
  }
69
106
 
70
- /** Recovery 浏览器半数据入口(实现 RecoveryPort 契约)。 */
71
- export class RecoveryApi implements RecoveryPort {
107
+ /** Recovery 浏览器半数据入口(实现 RecoveryPort 契约 + rollback-points 族)。 */
108
+ export class RecoveryApi implements RecoveryPort, RollbackPointPort {
72
109
  readonly t: UiT
73
- constructor(t: UiT = zhUiT) {
110
+ constructor(t: UiT) {
74
111
  this.t = t
75
112
  }
76
113
 
@@ -106,6 +143,107 @@ export class RecoveryApi implements RecoveryPort {
106
143
  return postJson<SessionRepairResult>(RECOVERY_API.sessionsRepair, body, this.t, RECOVERY_OPTS)
107
144
  }
108
145
 
146
+ /* ------------------------------------------------- S7 rollback-points(工作区 + 会话回滚,两态) */
147
+
148
+ /**
149
+ * GET /recovery/rollback-points:台账列表(按时间倒序)+ 存储栈状态 + 留存上限。
150
+ *
151
+ * 列表本身**只读**:SAFE MODE 下也能看(宿主侧只有 rewind / delete 被 423 拦下),
152
+ * 因此界面必须能「看得见、但按钮说明为什么点不了」。
153
+ * 存储栈不可用时宿主回 **503 + 同体**(`storage.available=false` + guidance);`getJson` 对非 2xx
154
+ * 抛 `ConfigManagerApiError`(`status`=503,`code` 取响应体 code),调用方按 status 区分「读不出来」
155
+ * 与「本来就没有」。
156
+ */
157
+ async rollbackPoints(): Promise<RollbackListResult> {
158
+ return getJson<RollbackListResult>(RECOVERY_API.rollbackPoints, this.t, RECOVERY_OPTS)
159
+ }
160
+
161
+ /** GET /recovery/rollback-points/storage:存储栈探针(不可用 → 503 + guidance,同上)。 */
162
+ async rollbackPointStorage(): Promise<RollbackStorageStatus> {
163
+ return getJson<RollbackStorageStatus>(RECOVERY_API.rollbackPointsStorage, this.t, RECOVERY_OPTS)
164
+ }
165
+
166
+ /** GET /recovery/rollback-points/<id>:单条详情(不存在 → 404 `record-not-found`)。 */
167
+ async rollbackPoint(id: string): Promise<RollbackDetailResult> {
168
+ return getJson<RollbackDetailResult>(rollbackPointUrl(id), this.t, RECOVERY_OPTS)
169
+ }
170
+
171
+ /**
172
+ * GET /recovery/rollback-points/<id>/preview:**只读预览(零写入)**。
173
+ *
174
+ * 回传两态将覆盖多少项、其中多少项内容不同、多少项当前已不存在、多少项是该点**未记录**的
175
+ * (`removals` = 会被删除的、`createdSkipped` = 按安全判据拒删的;两者都只是**读回来的清单**,
176
+ * 本方法零写入),以及会话边界(from → to)与回合号;`canRestore` / `canRemove`
177
+ * 是宿主给出的权威判定,界面据此决定按钮可用性(展示判定见 `src/ui/rollback-view.ts`)。
178
+ */
179
+ async rollbackPointPreview(id: string): Promise<RollbackPreviewResult> {
180
+ return getJson<RollbackPreviewResult>(rollbackPointPath(id, 'preview'), this.t, RECOVERY_OPTS)
181
+ }
182
+
183
+ /**
184
+ * GET /recovery/rollback-points/<id>/file-diff?path=...:**单个记录在案文件**的前后逐行对照。
185
+ *
186
+ * 只读、零写入;路径以 query 传递(宿主内再收窄一次:未命中该点记录一律 `file-not-recorded`,
187
+ * 一个字节都不读)。非 2xx(存储栈 503 / 参数 400)由 getJson 抛 ConfigManagerApiError,
188
+ * 由调用方按 status + code 出文案。
189
+ */
190
+ async rollbackPointFileDiff(id: string, path: string): Promise<RollbackFileDiffResult> {
191
+ const query = '?path=' + encodeURIComponent(path)
192
+ return getJson<RollbackFileDiffResult>(rollbackPointPath(id, 'file-diff') + query, this.t, RECOVERY_OPTS)
193
+ }
194
+
195
+ /**
196
+ * POST /recovery/rollback-points/<id>/rewind:回退(工作区文件覆盖 + 会话 fork 子会话)。
197
+ *
198
+ * **确认门是 fail-closed**:`userConfirmed` 必须**恰好** true(宿主缺省 / 假值一律
199
+ * 409 `confirmation-required` + 零写入)。本方法绝不自动置 true —— 由确认弹窗的 onClick 传进来。
200
+ * 409(confirmation-required / protected-point / record-incomplete)与 423(mutation-locked)
201
+ * 都以 `ConfigManagerApiError` 抛出,`status` / `code` 保留,界面按 code 出文案(不靠状态码猜原因)。
202
+ * 会话回退 **不改写原会话日志**:结果里回传 `childSessionId`(新子会话),原会话只读。
203
+ */
204
+ async restoreRollbackPoint(id: string, opts: RollbackRewindOptions): Promise<RollbackRewindResult> {
205
+ const body: Record<string, unknown> = { userConfirmed: opts.userConfirmed === true }
206
+ if (opts.mode !== undefined) body['mode'] = opts.mode
207
+ if (opts.segments !== undefined && opts.segments.length > 0) body['segments'] = [...opts.segments]
208
+ if (opts.allowPartial === true) body['allowPartial'] = true
209
+ if (opts.preRewindGuard !== undefined) body['preRewindGuard'] = opts.preRewindGuard
210
+ return postJson<RollbackRewindResult>(rollbackPointPath(id, 'rewind'), body, this.t, RECOVERY_OPTS)
211
+ }
212
+
213
+ /**
214
+ * POST /recovery/rollback-points/<id>/delete:删除一个回滚点(保护点由宿主拒绝)。
215
+ * body 必须 `userConfirmed: true`(未确认 → 409 `confirmation-required`);本方法不自动置 true。
216
+ */
217
+ async removeRollbackPoint(id: string, userConfirmed: boolean): Promise<RollbackRemoveResult> {
218
+ return postJson<RollbackRemoveResult>(rollbackPointPath(id, 'delete'), { userConfirmed: userConfirmed === true }, this.t, RECOVERY_OPTS)
219
+ }
220
+
221
+ /**
222
+ * GET /recovery/rollback-points/prefs(issue #88):读开关。
223
+ * `rollbackEnabled` = 磁盘偏好(用户意图,随 self 分区进备份);
224
+ * `rollbackActive` = 本进程此刻是否真的在留点(关闭后订阅已解绑)。两者正常一致。
225
+ */
226
+ async rollbackPrefs(): Promise<RollbackPrefsResult> {
227
+ return getJson<RollbackPrefsResult>(RECOVERY_API.rollbackPointsPrefs, this.t, RECOVERY_OPTS)
228
+ }
229
+
230
+ /**
231
+ * POST /recovery/rollback-points/prefs(issue #88):写开关。
232
+ * 宿主写盘成功后才切进程 gate —— 写失败却把功能打开,等于「界面说开着、实际不留点」。
233
+ */
234
+ async setRollbackEnabled(enabled: boolean): Promise<RollbackPrefsResult> {
235
+ return postJson<RollbackPrefsResult>(RECOVERY_API.rollbackPointsPrefs, { rollbackEnabled: enabled === true }, this.t, RECOVERY_OPTS)
236
+ }
237
+
238
+ /**
239
+ * POST /recovery/rollback-points/cleanup(issue #89):清理台账占用。
240
+ * **只删自动点**;`includeGuards` 为 true 时连救援点也删(protected 永不删)。
241
+ * 返回逐类删除计数与释放字节,界面照实说「删了多少 / 还剩多少」。
242
+ */
243
+ async purgeRollbackPoints(opts: { includeGuards: boolean }): Promise<RollbackPurgeResult> {
244
+ return postJson<RollbackPurgeResult>(RECOVERY_API.rollbackPointsCleanup, { userConfirmed: true, includeGuards: opts.includeGuards === true }, this.t, RECOVERY_OPTS)
245
+ }
246
+
109
247
  /** POST /recovery/sessions/rollback(T8):按台账 repairId 回滚(客户端不传路径)。 */
110
248
  async rollbackSessionRepair(repairId: string): Promise<SessionRepairRollbackResult> {
111
249
  return postJson<SessionRepairRollbackResult>(RECOVERY_API.sessionsRollback, { repairId }, this.t, RECOVERY_OPTS)