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,406 @@
1
+ /**
2
+ * 宿主斜杠命令 /rollback(别名 /rw)—— 不打开设置面板也能回退(对齐 dsh-rewind 的 /rewind、/undo)。
3
+ *
4
+ * 语义(用户 2026-10-12 确认方案 A):
5
+ * /rollback → 当前**会话**的可回退点列表(回合号 / 时间 / 类型 / 状态 / 可回退性)
6
+ * /rollback <id> → 回退到该点,走**与 HTTP 路由同源**的那道写入门:
7
+ * runWithMutationLock(= SAFE MODE 门 + 跨进程/跨 kind 环境锁)
8
+ * → 引擎 preview(零写入)→ 引擎 rewind(userConfirmed=true)
9
+ * 引擎回的 confirmation-required / protected-point / record-incomplete 一律翻成可读错误结果,
10
+ * **绝不绕过**(命令入口没有「确认按钮」,用户敲下 id 就是那次确认;其余门照旧全量生效)。
11
+ *
12
+ * 纪律(与 src/core/model-tools.ts 的 registerModelTools 同口径):
13
+ * · 命令服务**惰取**:一律 ctx.get('commands'),绝不属性访问 ctx.commands、绝不放进 inject ——
14
+ * 未组合该服务的部署必须照常启动(命令是可选能力,不是硬依赖);
15
+ * **读的时机是装配期一次**(见 registerRollbackCommand):Cordis 的 ctx.get 在 apply 期只能拿到
16
+ * **已 apply** 的服务,所以 `commands` 行晚于本插件时 `/rollback` 不会注册(只 warn 一行、无重试入口)。
17
+ * DSH 内置插件与本插件的实际 apply 顺序**未坐实**(asar 不可直接读、本机 profile 无相关行);
18
+ * 要彻底消除这个窗口需要 `ctx.inject(['commands'])` 式的「服务就绪再注册」回调 —— 未做,如实记在这里。
19
+ * · 注册失败只 warn:命令挂不上不得影响其它装配(宿主启动 = blocker);
20
+ * · 用户可见文案一律走宿主字典 engineMsg(key: command.rollback.*),**取文案那一刻**解析语言;
21
+ * · 本模块不 import @deepseek-ai/dsh-commands 的运行时值(只做结构化窄化),core 保持与 DSH 解耦。
22
+ */
23
+
24
+ import { engineMsg } from './engine-locale.ts'
25
+ import { EnvironmentLockUnavailableError } from '../utils/env-lock.ts'
26
+ import type { MutationLockPort } from '../utils/env-lock.ts'
27
+ import type {
28
+ RollbackPointSummary,
29
+ RollbackRewindResult,
30
+ RollbackSegmentResult,
31
+ } from './rollback-point.ts'
32
+
33
+ /**
34
+ * 命令结果(与 @deepseek-ai/dsh-commands 的 `CommandResult` **逐字同形**)。
35
+ *
36
+ * 为什么在这里自己声明而不是 import 那门包的类型:`src/core/**` 的架构边界(tests/architecture-boundaries.test.ts
37
+ * 的 core allow 表)只允许 node 内置 / core 内部 / schema / utils / security / migrations / js-yaml ——
38
+ * `@deepseek-ai/*` 仅允许出现在 `src/index.ts` 与 `src/client/`。core 必须保持与 DSH 解耦,
39
+ * 所以这里做**结构化窄化**;两边一旦漂移,`command-rollback.test.ts` 的编译期断言会红。
40
+ */
41
+ export type CommandResult =
42
+ | { readonly kind: 'success'; readonly text?: string; readonly sourceEventSeq?: number }
43
+ | { readonly kind: 'error'; readonly text: string }
44
+
45
+ /** 命令名(无前导斜杠)与别名。 */
46
+ export const ROLLBACK_COMMAND_NAME = 'rollback'
47
+ export const ROLLBACK_COMMAND_ALIAS = 'rw'
48
+
49
+ /**
50
+ * 命令定义 id:/rw 别名是**第二条定义** —— 同一个 definitionId(客户端按 definitionId 做身份化行为,
51
+ * 别名与主名必须被视作同一条命令)。
52
+ */
53
+ export const ROLLBACK_COMMAND_DEFINITION_ID = 'dsh-config-manager/rollback'
54
+
55
+ /** 命令服务惰取回调(调用期读 ctx.get('commands');未组合返回 undefined)。 */
56
+ export type CommandServiceReader = () => CommandServiceLike | undefined | null
57
+
58
+ /** 一条已注册命令的最小形状(避免把 DSH 类型变成本插件的硬依赖)。 */
59
+ export interface CommandDefinitionLike {
60
+ readonly name: string
61
+ readonly description: string
62
+ readonly definitionId?: string
63
+ readonly input?: { readonly hint: string; readonly attachments?: boolean }
64
+ readonly handler: (invocation: CommandInvocationLike) => CommandResult | Promise<CommandResult>
65
+ }
66
+
67
+ /** 一次命令调用的最小形状(只读用到的字段)。 */
68
+ export interface CommandInvocationLike {
69
+ readonly agent: unknown
70
+ /** 命令名之后的原文(含分隔空白)。 */
71
+ readonly rawInput: string
72
+ /** 派发 UI 持有的取消信号(透传给回退执行)。 */
73
+ readonly signal?: AbortSignal
74
+ }
75
+
76
+ /** 命令服务的最小形状(ctx.get('commands') 的结构化窄化)。 */
77
+ export interface CommandServiceLike {
78
+ register(definition: CommandDefinitionLike): unknown
79
+ }
80
+
81
+ /** 宿主提供的回退能力(由 src/index.ts 装配;测试用假的实现即可)。 */
82
+ export interface RollbackCommandHost {
83
+ /** 当前 agent 所属会话(拿不准则 ok:false —— 绝不猜)。 */
84
+ agentSession(agent: unknown): AgentSessionFacts
85
+ /** 列出该会话的回退点(含存储栈状态;只读)。 */
86
+ list(sessionId: string): Promise<RollbackCommandListResult>
87
+ /**
88
+ * 执行回退:runWithMutationLock → SAFE MODE → 引擎 preview → 引擎 rewind。
89
+ *
90
+ * 被 SAFE MODE / 环境锁挡住时**抛 EnvironmentLockUnavailableError**(与 HTTP 路由同口径),
91
+ * 由本模块翻成可读错误结果。
92
+ */
93
+ rewind(input: RollbackRewindExecution): Promise<RollbackRewindResult>
94
+ }
95
+
96
+ /**
97
+ * 回退执行入参。
98
+ *
99
+ * 只带 id + 取消信号:引擎 `rewind({ id, userConfirmed: true })` 的**写入面**已经由该点的记录
100
+ * 决定(不是调用方临时指定路径),多传会话/分块只会制造「两处口径」;会话事实只供只读列表过滤用。
101
+ */
102
+ export interface RollbackRewindExecution {
103
+ readonly id: string
104
+ readonly signal?: AbortSignal
105
+ }
106
+
107
+ /** 列表结果(引擎 RollbackListResult 的可测子集)。 */
108
+ export interface RollbackCommandListResult {
109
+ ok: boolean
110
+ storage: { available: boolean; root: string; detail?: string }
111
+ points: readonly RollbackPointSummary[]
112
+ error?: string
113
+ }
114
+
115
+ /** 当前 agent 的会话事实(宽进严出:形状不符即 ok:false)。 */
116
+ export type AgentSessionFacts =
117
+ | { ok: true; sessionId: string; chunks: readonly string[] }
118
+ | { ok: false; detail: string }
119
+
120
+ /** 绝对路径判定(win32 盘符 + POSIX 前缀 + UNC;纯函数,不引 node:path)。 */
121
+ export function isAbsolutePath(value: string): boolean {
122
+ if (value.startsWith('/') || value.startsWith('\\')) return true
123
+ return /^[A-Za-z]:[\\/]/.test(value)
124
+ }
125
+
126
+ /**
127
+ * 从 agent 窄化会话事实。
128
+ *
129
+ * **不猜**:agent.session.id 读不出来就退回 agent.id(DSH 的 Agent.id 就是会话 id);
130
+ * 两者都读不出 → ok:false(命令如实报「拿不到当前会话」,而不是列全网的点)。
131
+ * 工作区分块只认**绝对路径**的 cwd(与 rollbackSessionBindingOf 同一口径)。
132
+ */
133
+ export function agentSessionFactsOf(agent: unknown): AgentSessionFacts {
134
+ if (agent === null || typeof agent !== 'object') return { ok: false, detail: 'agent-not-object' }
135
+ const rec = agent as { id?: unknown; session?: unknown }
136
+ let sessionId: string | undefined
137
+ let cwd: string | undefined
138
+ const session = rec.session
139
+ if (session !== null && typeof session === 'object') {
140
+ const s = session as { id?: unknown; header?: unknown }
141
+ if (typeof s.id === 'string' && s.id !== '') sessionId = s.id
142
+ const header = s.header
143
+ if (header !== null && typeof header === 'object') {
144
+ const value = (header as { cwd?: unknown }).cwd
145
+ if (typeof value === 'string' && value !== '') cwd = value
146
+ }
147
+ }
148
+ if (sessionId === undefined && typeof rec.id === 'string' && rec.id !== '') sessionId = rec.id
149
+ if (sessionId === undefined) return { ok: false, detail: 'session-id-missing' }
150
+ const chunks = cwd !== undefined && isAbsolutePath(cwd) ? [cwd] : []
151
+ return { ok: true, sessionId, chunks }
152
+ }
153
+
154
+ /** 解析结果:空输入 = 只读列表;单个 token = 目标点 id;其余 = invalid。 */
155
+ export type RollbackCommandInput =
156
+ | { kind: 'list' }
157
+ | { kind: 'rewind'; id: string }
158
+ | { kind: 'invalid'; detail: string }
159
+
160
+ /**
161
+ * 解析 rawInput(命令名之后的原文,含分隔空白)。
162
+ * 语法只有两种:空 = 列表;单个非空 token = 目标 id。多 token 一律 invalid。
163
+ */
164
+ export function parseRollbackCommand(rawInput: string): RollbackCommandInput {
165
+ const trimmed = (rawInput ?? '').trim()
166
+ if (trimmed === '') return { kind: 'list' }
167
+ const parts = trimmed.split(/\s+/)
168
+ if (parts.length !== 1) return { kind: 'invalid', detail: 'too-many-arguments' }
169
+ return { kind: 'rewind', id: parts[0] ?? '' }
170
+ }
171
+
172
+ /* ------------------------------------------------------------------ 渲染 */
173
+
174
+ function isoOf(createdAt: number): string {
175
+ if (!Number.isFinite(createdAt)) return '?'
176
+ try {
177
+ return new Date(createdAt).toISOString()
178
+ } catch {
179
+ return '?'
180
+ }
181
+ }
182
+
183
+ /** 点状态:受保护 / 捕获不完整 / 正常(三者互斥,按引擎字段的优先级分派)。 */
184
+ function stateLabel(point: RollbackPointSummary): string {
185
+ if (point.protected) return engineMsg('command.rollback.stateProtected')
186
+ if (point.incomplete) return engineMsg('command.rollback.stateIncomplete')
187
+ return engineMsg('command.rollback.stateNormal')
188
+ }
189
+
190
+ /** 该点两态各自的「可回退 / 不可回退」摘要(诚实:按段逐项说,再给总判)。 */
191
+ function restorableLabel(point: RollbackPointSummary): string {
192
+ const segments = point.segments ?? []
193
+ const parts: string[] = []
194
+ for (const segment of segments) {
195
+ const label = segment.restorable ? engineMsg('command.rollback.restorableYes') : engineMsg('command.rollback.restorableNo')
196
+ parts.push(
197
+ engineMsg('command.rollback.segmentLabel', {
198
+ state: engineMsg(segment.state === 'workspace' ? 'command.rollback.segmentWorkspace' : 'command.rollback.segmentSession'),
199
+ label,
200
+ }),
201
+ )
202
+ }
203
+ if (parts.length === 0) return engineMsg('command.rollback.restorableNo')
204
+ const any = segments.some((segment) => segment.restorable)
205
+ return engineMsg('command.rollback.restorableSummary', {
206
+ parts: parts.join(engineMsg('command.rollback.listSeparator')),
207
+ verdict: any ? engineMsg('command.rollback.restorableYes') : engineMsg('command.rollback.restorableNo'),
208
+ })
209
+ }
210
+
211
+ function turnLabel(point: RollbackPointSummary): string {
212
+ return point.turn === null ? engineMsg('command.rollback.turnUnknown') : String(point.turn)
213
+ }
214
+
215
+ function kindLabel(point: RollbackPointSummary): string {
216
+ return engineMsg(point.kind === 'guard' ? 'command.rollback.kindGuard' : 'command.rollback.kindAuto')
217
+ }
218
+
219
+ /** 渲染只读列表(本会话没有点时给「本会话没有」,绝不冒充「全库为空」)。 */
220
+ export function renderRollbackList(result: RollbackCommandListResult, sessionId: string): CommandResult {
221
+ if (!result.storage.available) {
222
+ return {
223
+ kind: 'error',
224
+ text: engineMsg('command.rollback.storageUnavailable', { detail: result.storage.detail ?? result.storage.root }),
225
+ }
226
+ }
227
+ if (result.error !== undefined && result.error !== '') {
228
+ return { kind: 'error', text: engineMsg('command.rollback.listFailed', { detail: result.error }) }
229
+ }
230
+ const points = (result.points ?? []).filter((point) => point.sessionId === sessionId)
231
+ if (points.length === 0) return { kind: 'error', text: engineMsg('command.rollback.empty') }
232
+ const lines = points.map((point, index) =>
233
+ engineMsg('command.rollback.listRow', {
234
+ index: String(index + 1),
235
+ id: point.id,
236
+ turn: turnLabel(point),
237
+ createdAt: isoOf(point.createdAt),
238
+ kind: kindLabel(point),
239
+ state: stateLabel(point),
240
+ restorable: restorableLabel(point),
241
+ }),
242
+ )
243
+ return { kind: 'success', text: [engineMsg('command.rollback.listTitle'), ...lines].join('\n') }
244
+ }
245
+
246
+ /** 段结果的一行技术事实(定位失败用;**不是**文案分派的语义依据)。 */
247
+ function segmentFacts(segments: readonly RollbackSegmentResult[] | undefined): string {
248
+ if (segments === undefined || segments.length === 0) return ''
249
+ return segments
250
+ .map((segment) => segment.state + '/' + segment.status + (segment.reasonCode !== undefined ? '(' + segment.reasonCode + ')' : ''))
251
+ .join(',')
252
+ }
253
+
254
+ /** 把引擎结果翻成命令结果(失败一律带机器码 + 技术细节;processed 的段事实不隐藏)。 */
255
+ export function renderRewindResult(result: RollbackRewindResult, id: string): CommandResult {
256
+ const detail = result.detail ?? ''
257
+ if (result.ok && result.outcome === 'restored') {
258
+ return { kind: 'success', text: engineMsg('command.rollback.rewindRestored', { id, detail }) }
259
+ }
260
+ if (result.outcome === 'partial') {
261
+ // 「部分恢复」既不是成功也不是泛化失败:逐段事实必须上屏(含被跳过的段)。
262
+ return {
263
+ kind: 'error',
264
+ text: engineMsg('command.rollback.rewindPartial', {
265
+ id,
266
+ segments: engineMsg('command.rollback.segmentFacts', { facts: segmentFacts(result.segments) }),
267
+ detail,
268
+ }),
269
+ }
270
+ }
271
+ return {
272
+ kind: 'error',
273
+ text: engineMsg('command.rollback.rewindFailed', { id, code: String(result.code), detail }),
274
+ }
275
+ }
276
+
277
+ /* ------------------------------------------------------------------ 执行 */
278
+
279
+ /** 命令依赖(index.ts 装配;测试直接构造)。 */
280
+ export interface RollbackCommandDeps {
281
+ readonly host: RollbackCommandHost
282
+ /** mutation lock 端口(index.ts 传 host.mutationLock;测试可传 undefined 或假端口)。 */
283
+ readonly mutationLock?: MutationLockPort
284
+ /** SAFE MODE 同步谓词(与 HTTP 路由同一份 host.safeModeIsBlocked)。 */
285
+ readonly isBlocked?: () => boolean
286
+ }
287
+
288
+ /**
289
+ * 构造命令处理器(**纯编排**:不注册、不读 ctx)。
290
+ *
291
+ * 带参数时:parser → agentSession(只用于「这次是不是列表」的会话判定)→ host.rewind。
292
+ * host.rewind 内部才是那道门:runWithMutationLock → SAFE MODE → 引擎 preview → 引擎 rewind
293
+ * EnvironmentLockUnavailableError(SAFE MODE / 环境锁被挡)在此翻成可读错误结果。
294
+ * 任何未预期异常也翻成错误结果 —— 命令处理器抛异常会让整条命令生命周期报泛化失败,
295
+ * UI 只看到一句「失败」;这里如实把原因说清楚。
296
+ */
297
+ export function makeRollbackCommandHandler(
298
+ deps: RollbackCommandDeps,
299
+ ): (invocation: CommandInvocationLike) => Promise<CommandResult> {
300
+ return async (invocation) => {
301
+ const parsed = parseRollbackCommand(invocation.rawInput)
302
+ if (parsed.kind === 'invalid') {
303
+ return { kind: 'error', text: engineMsg('command.rollback.usageInvalid', { detail: parsed.detail }) }
304
+ }
305
+ const facts = deps.host.agentSession(invocation.agent)
306
+ if (!facts.ok) {
307
+ return { kind: 'error', text: engineMsg('command.rollback.sessionUnavailable', { detail: facts.detail }) }
308
+ }
309
+ if (parsed.kind === 'list') {
310
+ try {
311
+ return renderRollbackList(await deps.host.list(facts.sessionId), facts.sessionId)
312
+ } catch (error) {
313
+ return { kind: 'error', text: engineMsg('command.rollback.listFailed', { detail: errorText(error) }) }
314
+ }
315
+ }
316
+ try {
317
+ const execution: RollbackRewindExecution = {
318
+ id: parsed.id,
319
+ ...(invocation.signal !== undefined ? { signal: invocation.signal } : {}),
320
+ }
321
+ return renderRewindResult(await deps.host.rewind(execution), parsed.id)
322
+ } catch (error) {
323
+ if (error instanceof EnvironmentLockUnavailableError) {
324
+ return {
325
+ kind: 'error',
326
+ text: engineMsg('command.rollback.mutationLocked', { reason: error.reason, id: parsed.id }),
327
+ }
328
+ }
329
+ return {
330
+ kind: 'error',
331
+ text: engineMsg('command.rollback.rewindFailed', { id: parsed.id, code: 'exception', detail: errorText(error) }),
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ function errorText(error: unknown): string {
338
+ return error instanceof Error ? error.message : String(error)
339
+ }
340
+
341
+ /* ------------------------------------------------------------------ 注册 */
342
+
343
+ /** 注册所需的依赖面(命令服务惰取回调 + 宿主日志 + 命令依赖)。 */
344
+ export interface RollbackCommandRegistrationOptions {
345
+ /** 惰取命令服务:实现必须是「调用期」的 ctx.get('commands')(绝不属性访问、绝不进 inject)。 */
346
+ readonly readCommands: CommandServiceReader
347
+ readonly deps: RollbackCommandDeps
348
+ /** 只 warn:注册失败/服务缺失不得影响其它装配。 */
349
+ readonly log?: { warn(message: string, meta?: unknown): void }
350
+ }
351
+
352
+ /**
353
+ * 注册 /rollback 与 /rw(两条定义 = 同一 definitionId)。
354
+ *
355
+ * 服务缺失 → warn 后**安静返回**(未组合 commands 的部署照常启动、不抛错);
356
+ * 服务存在但 register 抛错 → warn(其余装配不受影响)。
357
+ * @returns 反注册函数(重复调用安全)。
358
+ */
359
+ export function registerRollbackCommand(options: RollbackCommandRegistrationOptions): () => void {
360
+ const disposers: (() => void)[] = []
361
+ let service: CommandServiceLike | undefined
362
+ try {
363
+ service = options.readCommands() ?? undefined
364
+ } catch (error) {
365
+ options.log?.warn(engineMsg('command.rollback.serviceUnavailable', { detail: errorText(error) }))
366
+ return () => {}
367
+ }
368
+ if (service === undefined || typeof service.register !== 'function') {
369
+ options.log?.warn(engineMsg('command.rollback.serviceUnavailable', { detail: 'commands-service-missing' }))
370
+ return () => {}
371
+ }
372
+ const handler = makeRollbackCommandHandler(options.deps)
373
+ const definitions: readonly CommandDefinitionLike[] = [
374
+ {
375
+ name: ROLLBACK_COMMAND_NAME,
376
+ definitionId: ROLLBACK_COMMAND_DEFINITION_ID,
377
+ description: engineMsg('command.rollback.commandDesc'),
378
+ input: { hint: engineMsg('command.rollback.commandInputHint') },
379
+ handler,
380
+ },
381
+ {
382
+ name: ROLLBACK_COMMAND_ALIAS,
383
+ definitionId: ROLLBACK_COMMAND_DEFINITION_ID,
384
+ description: engineMsg('command.rollback.commandDescAlias'),
385
+ input: { hint: engineMsg('command.rollback.commandInputHint') },
386
+ handler,
387
+ },
388
+ ]
389
+ for (const definition of definitions) {
390
+ try {
391
+ const disposer = service.register(definition)
392
+ if (typeof disposer === 'function') disposers.push(disposer as () => void)
393
+ } catch (error) {
394
+ options.log?.warn(engineMsg('command.rollback.registerFailed', { name: definition.name, detail: errorText(error) }))
395
+ }
396
+ }
397
+ return () => {
398
+ for (const dispose of disposers.splice(0)) {
399
+ try {
400
+ dispose()
401
+ } catch (error) {
402
+ options.log?.warn(engineMsg('command.rollback.registerFailed', { name: 'dispose', detail: errorText(error) }))
403
+ }
404
+ }
405
+ }
406
+ }
@@ -19,6 +19,7 @@ import { SECTION_JSON_PATHS, SECTION_FILE_PREFIXES, isFileSection } from '../sch
19
19
  import { scanAndRedact, scanText } from '../security/secret-scanner.ts';
20
20
  import type { Manifest, SectionId } from '../schema/types.ts';
21
21
  import type { ConsultSourceData, ConsultSourceRef, MigratabilityResult } from './migration-consult.ts';
22
+ import { engineMsg } from './messages-core.ts';
22
23
 
23
24
  export interface ConsultSourceReaderOptions {
24
25
  /** 计算可迁移性(宿主注入;缺省 null = 不评估) */
@@ -75,11 +76,11 @@ export async function readExportZipSource(
75
76
  const parsed = JSON.parse(archive.readEntryText(MANIFEST_FILE));
76
77
  manifestIssues = validateManifest(parsed);
77
78
  } catch {
78
- manifestIssues = [{ path: '$', message: 'manifest 无法解析', severity: 'error' }];
79
+ manifestIssues = [{ path: '$', message: engineMsg('core.consult.manifestUnparsable'), severity: 'error' }];
79
80
  }
80
81
  }
81
82
  } else {
82
- manifestIssues = [{ path: '$', message: 'manifest 缺失', severity: 'error' }];
83
+ manifestIssues = [{ path: '$', message: engineMsg('core.consult.manifestMissing'), severity: 'error' }];
83
84
  }
84
85
 
85
86
  // 3. checksums(捕获不匹配,不抛错)
@@ -94,8 +95,8 @@ export async function readExportZipSource(
94
95
  }
95
96
  const result = verifyChecksumsJson(entries, archive.readEntryText(CHECKSUMS_FILE));
96
97
  checksums = result.ok ? {} : null;
97
- for (const m of result.mismatches) checksumIssues.push(`"${m}" (hash 不符)`);
98
- for (const m of result.missing) checksumIssues.push(`"${m}" (缺失)`);
98
+ for (const m of result.mismatches) checksumIssues.push(engineMsg('core.consult.hashMismatch', { name: m }));
99
+ for (const m of result.missing) checksumIssues.push(engineMsg('core.consult.entryMissing', { name: m }));
99
100
  } catch (err) {
100
101
  checksumIssues.push(err instanceof Error ? err.message : String(err));
101
102
  }
@@ -205,8 +206,8 @@ export function buildLocalSnapshotSource(
205
206
  sections: sectionFlags,
206
207
  security: { containsSecrets: false, encrypted: false, encryption: null },
207
208
  };
208
- const manifestIssues = input.verify.ok ? [] : [{ path: '$', message: input.verify.reason ?? '快照完整性校验失败', severity: 'error' as const }];
209
- const checksumIssues = input.verify.ok ? [] : [input.verify.reason ?? '快照完整性校验失败'];
209
+ const manifestIssues = input.verify.ok ? [] : [{ path: '$', message: input.verify.reason ?? engineMsg('core.consult.snapshotIntegrityFailed'), severity: 'error' as const }];
210
+ const checksumIssues = input.verify.ok ? [] : [input.verify.reason ?? engineMsg('core.consult.snapshotIntegrityFailed')];
210
211
  const migratability: MigratabilityResult = {
211
212
  ok: input.restorePlan.errors.length === 0,
212
213
  itemCount: input.restorePlan.itemCount,