dsh-config-manager 0.1.71 → 0.1.72

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 (548) hide show
  1. package/README.md +111 -96
  2. package/README.zh-CN.md +207 -86
  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 +1 -1
  6. package/lib/adapters/index.js +1 -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 +18 -0
  10. package/lib/adapters/messages.js +50 -0
  11. package/lib/adapters/plugin-files.js +3 -2
  12. package/lib/adapters/plugins.js +4 -3
  13. package/lib/adapters/prompts.d.ts +1 -0
  14. package/lib/adapters/prompts.js +7 -1
  15. package/lib/adapters/self.d.ts +7 -1
  16. package/lib/adapters/self.js +1 -1
  17. package/lib/adapters/sessions.d.ts +1 -0
  18. package/lib/adapters/sessions.js +4 -2
  19. package/lib/adapters/ui.d.ts +2 -2
  20. package/lib/adapters/ui.js +25 -25
  21. package/lib/adapters/workspaces.d.ts +1 -0
  22. package/lib/adapters/workspaces.js +7 -3
  23. package/lib/cli/actions.d.ts +9 -1
  24. package/lib/cli/actions.js +5 -2
  25. package/lib/cli/help.js +23 -10
  26. package/lib/cli/index.d.ts +23 -0
  27. package/lib/cli/index.js +90 -32
  28. package/lib/cli/sessions-inspect.js +3 -1
  29. package/lib/cli/sessions-repair.js +25 -6
  30. package/lib/cli/web/page.d.ts +12 -0
  31. package/lib/cli/web/page.js +21 -12
  32. package/lib/cli/web/routes.js +2 -2
  33. package/lib/cli/web/server.js +4 -4
  34. package/lib/client.d.ts +1349 -490
  35. package/lib/client.js +43047 -36738
  36. package/lib/core/backup-plan.js +30 -17
  37. package/lib/core/backup-verify.js +24 -23
  38. package/lib/core/backup.d.ts +5 -0
  39. package/lib/core/backup.js +51 -25
  40. package/lib/core/boot-rescue.js +4 -3
  41. package/lib/core/boot-safety.js +2 -1
  42. package/lib/core/command-rollback.d.ts +178 -0
  43. package/lib/core/command-rollback.js +289 -0
  44. package/lib/core/consult-source.js +7 -6
  45. package/lib/core/disk-usage.d.ts +74 -10
  46. package/lib/core/disk-usage.js +67 -4
  47. package/lib/core/engine-locale.d.ts +87 -0
  48. package/lib/core/engine-locale.js +125 -0
  49. package/lib/core/exporter.js +3 -3
  50. package/lib/core/fork-reconcile.d.ts +128 -0
  51. package/lib/core/fork-reconcile.js +150 -0
  52. package/lib/core/journal.js +6 -5
  53. package/lib/core/local-plugin-host.js +3 -2
  54. package/lib/core/local-plugin-pack.js +11 -6
  55. package/lib/core/messages-core.d.ts +292 -0
  56. package/lib/core/messages-core.js +615 -0
  57. package/lib/core/messages.d.ts +60 -2
  58. package/lib/core/messages.js +116 -13
  59. package/lib/core/migration-consult.js +21 -20
  60. package/lib/core/migration-history.js +19 -5
  61. package/lib/core/model-tools.d.ts +0 -22
  62. package/lib/core/model-tools.js +50 -27
  63. package/lib/core/phase3-host.js +30 -5
  64. package/lib/core/plugin-cli.js +18 -19
  65. package/lib/core/reconcile.d.ts +2 -14
  66. package/lib/core/reconcile.js +87 -17
  67. package/lib/core/recovery-orchestrator.js +19 -18
  68. package/lib/core/reinstall.d.ts +4 -0
  69. package/lib/core/reinstall.js +26 -21
  70. package/lib/core/restore.js +20 -17
  71. package/lib/core/rollback-ignore-rules.d.ts +31 -0
  72. package/lib/core/rollback-ignore-rules.js +140 -0
  73. package/lib/core/rollback-point.d.ts +1208 -0
  74. package/lib/core/rollback-point.js +2993 -0
  75. package/lib/core/run-registry.js +6 -5
  76. package/lib/core/session-health.d.ts +15 -0
  77. package/lib/core/session-meta.d.ts +42 -2
  78. package/lib/core/session-meta.js +140 -1
  79. package/lib/core/session-title.d.ts +28 -0
  80. package/lib/core/session-title.js +185 -0
  81. package/lib/core/startup-barrier.d.ts +24 -0
  82. package/lib/core/startup-barrier.js +22 -0
  83. package/lib/core/transaction-coordinator.js +4 -3
  84. package/lib/core/types.d.ts +18 -1
  85. package/lib/core/validator.js +5 -4
  86. package/lib/core/verify-recovery.js +31 -30
  87. package/lib/foreign/bundle.js +3 -2
  88. package/lib/foreign/continue.js +2 -1
  89. package/lib/foreign/crush.js +2 -1
  90. package/lib/foreign/gemini.js +2 -1
  91. package/lib/foreign/goose.js +2 -1
  92. package/lib/foreign/kilocode.js +2 -1
  93. package/lib/foreign/kimi.js +2 -1
  94. package/lib/foreign/messages.d.ts +15 -0
  95. package/lib/foreign/messages.js +40 -0
  96. package/lib/foreign/mimocode.js +2 -1
  97. package/lib/foreign/openclaw.js +2 -1
  98. package/lib/foreign/opencode.js +2 -1
  99. package/lib/foreign/pi.js +2 -1
  100. package/lib/foreign/qoder.js +2 -1
  101. package/lib/foreign/qwen.js +2 -1
  102. package/lib/foreign/registry.js +7 -6
  103. package/lib/foreign/teleagent.js +2 -1
  104. package/lib/foreign/workbuddy.js +2 -1
  105. package/lib/foreign/zcode.js +2 -1
  106. package/lib/foreign/zed.js +2 -1
  107. package/lib/index.d.ts +223 -7
  108. package/lib/index.js +729 -54
  109. package/lib/market/git-file-writer.js +20 -19
  110. package/lib/market/github-repos.js +35 -19
  111. package/lib/market/index-parser.js +31 -30
  112. package/lib/market/messages-market.d.ts +138 -0
  113. package/lib/market/messages-market.js +305 -0
  114. package/lib/market/my-repo.d.ts +2 -2
  115. package/lib/market/my-repo.js +32 -29
  116. package/lib/market/prepare.js +18 -15
  117. package/lib/market/security.js +20 -19
  118. package/lib/market/types.js +2 -1
  119. package/lib/market/url.js +2 -1
  120. package/lib/migrations/index.js +6 -5
  121. package/lib/migrations/messages-migrations.d.ts +32 -0
  122. package/lib/migrations/messages-migrations.js +58 -0
  123. package/lib/profiles/dsh-profile-launcher.js +2 -1
  124. package/lib/profiles/dsh-profile-runtime.js +2 -1
  125. package/lib/profiles/messages.d.ts +7 -0
  126. package/lib/profiles/messages.js +27 -0
  127. package/lib/routes/backup.js +18 -2
  128. package/lib/routes/import.js +3 -3
  129. package/lib/routes/index.d.ts +1 -1
  130. package/lib/routes/kit.d.ts +3 -2
  131. package/lib/routes/kit.js +6 -1
  132. package/lib/routes/market.js +1 -1
  133. package/lib/routes/messages.d.ts +42 -0
  134. package/lib/routes/messages.js +100 -0
  135. package/lib/routes/profiles.js +12 -6
  136. package/lib/routes/recovery.js +378 -114
  137. package/lib/routes/snapshots.js +51 -4
  138. package/lib/routes/sync.js +68 -16
  139. package/lib/schema/config.d.ts +11 -1
  140. package/lib/schema/config.js +52 -20
  141. package/lib/schema/index.d.ts +8 -6
  142. package/lib/schema/index.js +8 -6
  143. package/lib/schema/manifest.js +19 -18
  144. package/lib/schema/messages.d.ts +47 -0
  145. package/lib/schema/messages.js +110 -0
  146. package/lib/schema/section-registry.d.ts +41 -14
  147. package/lib/schema/section-registry.js +35 -29
  148. package/lib/schema/versions.js +6 -5
  149. package/lib/security/encryption.js +16 -15
  150. package/lib/security/integrity.js +8 -7
  151. package/lib/security/messages.d.ts +30 -0
  152. package/lib/security/messages.js +77 -0
  153. package/lib/security/redaction.js +12 -0
  154. package/lib/security/secret-scanner.js +16 -13
  155. package/lib/security/vault.js +2 -1
  156. package/lib/security/zip-security.js +4 -3
  157. package/lib/sync/ancestor.js +2 -1
  158. package/lib/sync/autosync-config.d.ts +11 -0
  159. package/lib/sync/autosync-config.js +12 -0
  160. package/lib/sync/autosync-scheduler.d.ts +11 -1
  161. package/lib/sync/autosync-scheduler.js +115 -76
  162. package/lib/sync/backup-files.js +3 -2
  163. package/lib/sync/backup-scheduler.js +6 -5
  164. package/lib/sync/blob-store.js +2 -1
  165. package/lib/sync/git/git-transport.d.ts +55 -0
  166. package/lib/sync/git/git-transport.js +152 -2
  167. package/lib/sync/github-auth.js +10 -9
  168. package/lib/sync/layout.js +13 -12
  169. package/lib/sync/messages.d.ts +63 -0
  170. package/lib/sync/messages.js +149 -0
  171. package/lib/sync/review-queue.js +6 -5
  172. package/lib/sync/s3/messages.d.ts +7 -0
  173. package/lib/sync/s3/messages.js +16 -0
  174. package/lib/sync/s3/s3-providers.d.ts +4 -1
  175. package/lib/sync/s3/s3-providers.js +5 -5
  176. package/lib/sync/s3/s3-transport.js +1 -1
  177. package/lib/sync/s3/sigv4.js +2 -1
  178. package/lib/sync/snapshot-crypto.js +6 -5
  179. package/lib/sync/snapshot-json.js +3 -2
  180. package/lib/sync/sync-engine.d.ts +37 -15
  181. package/lib/sync/sync-engine.js +67 -37
  182. package/lib/sync/sync-history.js +7 -6
  183. package/lib/sync/sync-selection.d.ts +15 -4
  184. package/lib/sync/sync-selection.js +17 -5
  185. package/lib/sync/webdav/webdav-transport.d.ts +1 -0
  186. package/lib/sync/webdav/webdav-transport.js +4 -1
  187. package/lib/ui/artifact-view.js +4 -3
  188. package/lib/ui/commands.d.ts +1 -1
  189. package/lib/ui/commands.js +10 -0
  190. package/lib/ui/disk-usage-view.d.ts +33 -4
  191. package/lib/ui/disk-usage-view.js +29 -1
  192. package/lib/ui/errors.d.ts +1 -1
  193. package/lib/ui/errors.js +4 -3
  194. package/lib/ui/export-flow.js +24 -20
  195. package/lib/ui/foreign-view.d.ts +5 -1
  196. package/lib/ui/foreign-view.js +26 -2
  197. package/lib/ui/i18n.d.ts +65 -0
  198. package/lib/ui/i18n.js +114 -0
  199. package/lib/ui/import-wizard.d.ts +7 -0
  200. package/lib/ui/import-wizard.js +13 -10
  201. package/lib/ui/progress.d.ts +2 -2
  202. package/lib/ui/progress.js +1 -2
  203. package/lib/ui/report.d.ts +5 -5
  204. package/lib/ui/report.js +6 -6
  205. package/lib/ui/rollback-view.d.ts +756 -0
  206. package/lib/ui/rollback-view.js +724 -0
  207. package/lib/ui/selection-model.d.ts +41 -0
  208. package/lib/ui/selection-model.js +30 -0
  209. package/lib/ui/session-inventory-view.d.ts +97 -3
  210. package/lib/ui/session-inventory-view.js +76 -2
  211. package/lib/ui/session-issue-labels.d.ts +43 -0
  212. package/lib/ui/session-issue-labels.js +48 -0
  213. package/lib/ui/sync-settings-view.d.ts +33 -0
  214. package/lib/ui/sync-settings-view.js +40 -0
  215. package/lib/ui/types.d.ts +8 -3
  216. package/lib/ui/types.js +1 -1
  217. package/lib/utils/atomic-write.js +6 -5
  218. package/lib/utils/bundle-scan.d.ts +11 -1
  219. package/lib/utils/bundle-scan.js +12 -1
  220. package/lib/utils/env-lock.d.ts +10 -0
  221. package/lib/utils/env-lock.js +73 -46
  222. package/lib/utils/json.js +6 -5
  223. package/lib/utils/messages-utils.d.ts +96 -0
  224. package/lib/utils/messages-utils.js +216 -0
  225. package/lib/utils/proxy.js +18 -5
  226. package/lib/utils/recursive-walk.d.ts +22 -0
  227. package/lib/utils/recursive-walk.js +75 -1
  228. package/lib/utils/session-log-repair.js +10 -9
  229. package/lib/utils/zip.js +27 -26
  230. package/package.json +12 -2
  231. package/src/adapters/agent-instructions.ts +1 -1
  232. package/src/adapters/file-collection.test.ts +1 -0
  233. package/src/adapters/file-collection.ts +1 -1
  234. package/src/adapters/files.test.ts +27 -0
  235. package/src/adapters/index.ts +1 -1
  236. package/src/adapters/link-report.test.ts +22 -2
  237. package/src/adapters/link-report.ts +29 -4
  238. package/src/adapters/messages.ts +54 -0
  239. package/src/adapters/plugin-files.ts +3 -2
  240. package/src/adapters/plugins.ts +4 -3
  241. package/src/adapters/prompts.ts +7 -1
  242. package/src/adapters/self.test.ts +26 -0
  243. package/src/adapters/self.ts +8 -2
  244. package/src/adapters/sessions.ts +4 -2
  245. package/src/adapters/settings.test.ts +38 -1
  246. package/src/adapters/ui.test.ts +2 -2
  247. package/src/adapters/ui.ts +27 -26
  248. package/src/adapters/workspaces.ts +7 -3
  249. package/src/cli/actions.test.ts +28 -0
  250. package/src/cli/actions.ts +11 -2
  251. package/src/cli/help.ts +23 -10
  252. package/src/cli/index-guards.test.ts +193 -0
  253. package/src/cli/index.ts +106 -31
  254. package/src/cli/sessions-inspect.test.ts +15 -1
  255. package/src/cli/sessions-inspect.ts +3 -1
  256. package/src/cli/sessions-repair.test.ts +84 -0
  257. package/src/cli/sessions-repair.ts +33 -7
  258. package/src/cli/web/console-route-parity.test.ts +115 -0
  259. package/src/cli/web/page.ts +23 -12
  260. package/src/cli/web/routes.ts +2 -1
  261. package/src/cli/web/server.ts +4 -4
  262. package/src/cli/web/web.test.ts +2 -2
  263. package/src/client/ConfigManagerSection.tsx +30 -2
  264. package/src/client/about/AboutPanel.tsx +2 -2
  265. package/src/client/about/PluginUpdateDialog.tsx +1 -1
  266. package/src/client/about/ReleaseNotesDialog.tsx +2 -2
  267. package/src/client/about/about-view.test.ts +13 -3
  268. package/src/client/about/about-view.ts +10 -6
  269. package/src/client/about/release-notes-view.test.ts +14 -4
  270. package/src/client/about/release-notes-view.ts +4 -2
  271. package/src/client/api.ts +18 -6
  272. package/src/client/chat/ChatEntryView.tsx +391 -0
  273. package/src/client/chat/RollbackDiffTab.tsx +61 -0
  274. package/src/client/chat/RollbackFileIcon.tsx +96 -0
  275. package/src/client/chat/RollbackReviewDialog.tsx +591 -0
  276. package/src/client/chat/chat-entry-view.test.ts +1174 -0
  277. package/src/client/chat/chat-entry-view.ts +758 -0
  278. package/src/client/chat/chat-locales.ts +152 -0
  279. package/src/client/chat/chat-node-registration.ts +64 -0
  280. package/src/client/chat/chat-point-window.ts +173 -0
  281. package/src/client/chat/chat-slots.ts +107 -0
  282. package/src/client/chat/rollback-diff-tab.test.ts +105 -0
  283. package/src/client/chat/rollback-diff-tab.ts +164 -0
  284. package/src/client/chat/rollback-entry-view.test.ts +1469 -0
  285. package/src/client/chat/rollback-entry-view.ts +941 -0
  286. package/src/client/chat/sidebar-slots.ts +37 -0
  287. package/src/client/common/ConfirmDialog.tsx +7 -3
  288. package/src/client/common/ContentPicker.tsx +48 -10
  289. package/src/client/common/DiffTable.tsx +97 -0
  290. package/src/client/common/ErrorBanner.tsx +4 -4
  291. package/src/client/common/Icon.tsx +2 -0
  292. package/src/client/common/Modal.tsx +8 -1
  293. package/src/client/common/ProgressBar.tsx +8 -2
  294. package/src/client/common/ReportView.tsx +4 -4
  295. package/src/client/common/RunsCenter.tsx +1 -0
  296. package/src/client/common/client-route-parity.test.ts +78 -0
  297. package/src/client/common/info-hint-guard.test.ts +46 -13
  298. package/src/client/common/picker-lazy-units.test.ts +42 -0
  299. package/src/client/common/plan-text-redaction.test.ts +17 -6
  300. package/src/client/common/progress-view-edge.test.ts +8 -7
  301. package/src/client/common/progress-view.test.ts +9 -9
  302. package/src/client/common/progress-view.ts +2 -2
  303. package/src/client/common/routes.ts +28 -0
  304. package/src/client/common/ui.tsx +73 -10
  305. package/src/client/config-manager.module.css +996 -21
  306. package/src/client/css-scale-guard.test.ts +30 -0
  307. package/src/client/environment/EnvironmentPanel.tsx +11 -4
  308. package/src/client/environment/maintenance/DiskUsageCard.tsx +23 -2
  309. package/src/client/export/ExportView.tsx +13 -8
  310. package/src/client/history/HistoryPanel.tsx +4 -3
  311. package/src/client/history/history-api.ts +2 -2
  312. package/src/client/history/history-locales.ts +5 -1
  313. package/src/client/home/HomePanel.tsx +29 -8
  314. package/src/client/import/ForeignImportView.tsx +4 -5
  315. package/src/client/import/ImportWizardView.tsx +5 -3
  316. package/src/client/import/import-wizard-split.test.ts +3 -1
  317. package/src/client/import/import-wizard-steps.tsx +9 -9
  318. package/src/client/index.ts +186 -3
  319. package/src/client/library/LibraryActions.tsx +32 -7
  320. package/src/client/library/LibraryPanel.tsx +23 -3
  321. package/src/client/library/RestorePlanView.tsx +9 -66
  322. package/src/client/locales.ts +54 -5
  323. package/src/client/lucide-icons.d.ts +1 -0
  324. package/src/client/market/MarketPanel.tsx +13 -2
  325. package/src/client/market/MyConfigsView.tsx +5 -4
  326. package/src/client/market/MyConfigsWizard.tsx +10 -8
  327. package/src/client/market/market-api.test.ts +9 -8
  328. package/src/client/market/market-api.ts +2 -2
  329. package/src/client/market/market-locales.ts +3 -0
  330. package/src/client/market/market-view.test.ts +6 -6
  331. package/src/client/market/market-view.ts +3 -3
  332. package/src/client/market/my-configs-api.ts +2 -2
  333. package/src/client/market/my-configs-view.test.ts +23 -22
  334. package/src/client/market/my-configs-view.ts +8 -8
  335. package/src/client/recovery/IncompleteCopiesSection.tsx +2 -1
  336. package/src/client/recovery/RecoveryPanel.tsx +442 -283
  337. package/src/client/recovery/RollbackCard.tsx +665 -0
  338. package/src/client/recovery/RollbackDiffPane.tsx +58 -0
  339. package/src/client/recovery/RollbackFileChanges.tsx +163 -0
  340. package/src/client/recovery/incident-api.ts +2 -2
  341. package/src/client/recovery/recovery-api.ts +116 -6
  342. package/src/client/recovery/recovery-locales.test.ts +299 -0
  343. package/src/client/recovery/recovery-locales.ts +488 -149
  344. package/src/client/recovery/recovery-panel-layout.test.ts +132 -2
  345. package/src/client/recovery/rollback-file-changes.test.ts +73 -0
  346. package/src/client/recovery/session-dialog-mount.test.ts +54 -0
  347. package/src/client/run-store.ts +84 -21
  348. package/src/client/sync/AutosyncCard.tsx +25 -1
  349. package/src/client/sync/ChannelClearConfirmDialog.tsx +6 -3
  350. package/src/client/sync/ChannelConfigDialog.tsx +10 -10
  351. package/src/client/sync/DecryptPasswordCard.tsx +2 -2
  352. package/src/client/sync/SecurityOptionsCard.tsx +27 -17
  353. package/src/client/sync/SyncChannelEntryCard.tsx +14 -2
  354. package/src/client/sync/SyncConfirmView.tsx +46 -8
  355. package/src/client/sync/SyncLogList.tsx +1 -1
  356. package/src/client/sync/SyncPanel.tsx +31 -23
  357. package/src/client/sync/SyncRepositoryPicker.tsx +3 -5
  358. package/src/client/sync/SyncSectionPickerDialog.tsx +11 -2
  359. package/src/client/sync/SyncSettingsView.test.ts +20 -1
  360. package/src/client/sync/UnreadableSnapshotsBanner.tsx +1 -1
  361. package/src/client/sync/WorkDirCard.tsx +112 -0
  362. package/src/client/sync/history-model.test.ts +42 -9
  363. package/src/client/sync/history-model.ts +30 -15
  364. package/src/client/sync/sync-api.test.ts +57 -33
  365. package/src/client/sync/sync-api.ts +80 -6
  366. package/src/client/sync/sync-locales.ts +104 -3
  367. package/src/client/sync/sync-view-v2.test.ts +65 -13
  368. package/src/client/sync/sync-view.test.ts +107 -52
  369. package/src/client/sync/sync-view.ts +124 -41
  370. package/src/core/backup-plan.test.ts +28 -0
  371. package/src/core/backup-plan.ts +29 -17
  372. package/src/core/backup-verify.ts +24 -23
  373. package/src/core/backup.test.ts +76 -0
  374. package/src/core/backup.ts +55 -25
  375. package/src/core/boot-rescue.ts +4 -3
  376. package/src/core/boot-safety.ts +2 -1
  377. package/src/core/command-rollback.test.ts +536 -0
  378. package/src/core/command-rollback.ts +402 -0
  379. package/src/core/consult-source.ts +7 -6
  380. package/src/core/disk-usage.test.ts +257 -1
  381. package/src/core/disk-usage.ts +134 -14
  382. package/src/core/engine-locale.test.ts +593 -0
  383. package/src/core/engine-locale.ts +175 -0
  384. package/src/core/exporter.ts +3 -3
  385. package/src/core/fork-reconcile.test.ts +279 -0
  386. package/src/core/fork-reconcile.ts +234 -0
  387. package/src/core/journal.ts +6 -5
  388. package/src/core/local-plugin-host.ts +3 -2
  389. package/src/core/local-plugin-pack.ts +11 -6
  390. package/src/core/messages-core.ts +657 -0
  391. package/src/core/messages.ts +123 -17
  392. package/src/core/migration-consult.ts +21 -20
  393. package/src/core/migration-history.ts +19 -5
  394. package/src/core/model-tools.ts +28 -27
  395. package/src/core/phase3-host.ts +21 -5
  396. package/src/core/phase3-p2b-fingerprint.test.ts +22 -0
  397. package/src/core/plugin-cli.ts +18 -19
  398. package/src/core/reconcile.test.ts +117 -0
  399. package/src/core/reconcile.ts +85 -17
  400. package/src/core/recovery-orchestrator.ts +19 -18
  401. package/src/core/reinstall.ts +26 -21
  402. package/src/core/restore.ts +20 -17
  403. package/src/core/rollback-file-diff.test.ts +159 -0
  404. package/src/core/rollback-ignore-rules.ts +126 -0
  405. package/src/core/rollback-point.test.ts +2603 -0
  406. package/src/core/rollback-point.ts +3755 -0
  407. package/src/core/run-registry.ts +6 -5
  408. package/src/core/session-health.ts +15 -0
  409. package/src/core/session-meta.test.ts +117 -1
  410. package/src/core/session-meta.ts +149 -2
  411. package/src/core/session-title.test.ts +127 -0
  412. package/src/core/session-title.ts +189 -0
  413. package/src/core/startup-barrier.test.ts +69 -0
  414. package/src/core/startup-barrier.ts +27 -0
  415. package/src/core/transaction-coordinator.ts +4 -3
  416. package/src/core/types.ts +18 -1
  417. package/src/core/validator.ts +5 -4
  418. package/src/core/verify-recovery.ts +31 -30
  419. package/src/foreign/bundle.ts +3 -2
  420. package/src/foreign/continue.ts +2 -1
  421. package/src/foreign/crush.ts +2 -1
  422. package/src/foreign/file-budget.test.ts +2 -0
  423. package/src/foreign/gemini.ts +2 -1
  424. package/src/foreign/goose.ts +2 -1
  425. package/src/foreign/kilocode.ts +2 -1
  426. package/src/foreign/kimi.ts +2 -1
  427. package/src/foreign/messages.ts +44 -0
  428. package/src/foreign/mimocode.ts +2 -1
  429. package/src/foreign/openclaw.ts +2 -1
  430. package/src/foreign/opencode.ts +2 -1
  431. package/src/foreign/pi.ts +2 -1
  432. package/src/foreign/qoder.ts +2 -1
  433. package/src/foreign/qwen.ts +2 -1
  434. package/src/foreign/registry.ts +7 -6
  435. package/src/foreign/teleagent.ts +2 -1
  436. package/src/foreign/workbuddy.ts +2 -1
  437. package/src/foreign/zcode.ts +2 -1
  438. package/src/foreign/zed.ts +2 -1
  439. package/src/index.facade.test.ts +340 -1
  440. package/src/index.ts +813 -57
  441. package/src/market/git-file-writer.ts +20 -19
  442. package/src/market/github-repos.test.ts +23 -0
  443. package/src/market/github-repos.ts +37 -19
  444. package/src/market/index-parser.ts +31 -30
  445. package/src/market/messages-market.ts +325 -0
  446. package/src/market/my-repo.ts +32 -29
  447. package/src/market/prepare.ts +18 -15
  448. package/src/market/security.ts +20 -19
  449. package/src/market/types.ts +2 -1
  450. package/src/market/url.ts +2 -1
  451. package/src/migrations/index.ts +6 -5
  452. package/src/migrations/messages-migrations.ts +59 -0
  453. package/src/profiles/dsh-profile-launcher.ts +2 -1
  454. package/src/profiles/dsh-profile-runtime.ts +2 -1
  455. package/src/profiles/messages.ts +31 -0
  456. package/src/routes/backup.ts +18 -2
  457. package/src/routes/import.ts +3 -3
  458. package/src/routes/index.ts +1 -1
  459. package/src/routes/kit.ts +9 -3
  460. package/src/routes/market.ts +1 -1
  461. package/src/routes/messages.ts +104 -0
  462. package/src/routes/profiles.ts +12 -6
  463. package/src/routes/recovery.test.ts +405 -1
  464. package/src/routes/recovery.ts +377 -109
  465. package/src/routes/snapshots.ts +51 -4
  466. package/src/routes/sync.ts +67 -16
  467. package/src/schema/config.ts +53 -20
  468. package/src/schema/index.ts +7 -5
  469. package/src/schema/manifest.ts +19 -18
  470. package/src/schema/messages.ts +120 -0
  471. package/src/schema/registry.test.ts +19 -5
  472. package/src/schema/section-registry.ts +64 -39
  473. package/src/schema/versions.ts +6 -5
  474. package/src/security/encryption.ts +16 -15
  475. package/src/security/integrity.ts +8 -7
  476. package/src/security/messages.ts +87 -0
  477. package/src/security/redaction.test.ts +17 -1
  478. package/src/security/redaction.ts +13 -0
  479. package/src/security/secret-scanner.ts +19 -12
  480. package/src/security/security.test.ts +47 -0
  481. package/src/security/vault.ts +2 -1
  482. package/src/security/zip-security.ts +4 -3
  483. package/src/sync/ancestor.ts +2 -1
  484. package/src/sync/autosync-config.ts +21 -0
  485. package/src/sync/autosync-scheduler.test.ts +63 -7
  486. package/src/sync/autosync-scheduler.ts +118 -78
  487. package/src/sync/backup-files.ts +3 -2
  488. package/src/sync/backup-scheduler.ts +6 -5
  489. package/src/sync/blob-store.ts +2 -1
  490. package/src/sync/git/git-transport.test.ts +170 -8
  491. package/src/sync/git/git-transport.ts +176 -2
  492. package/src/sync/github-auth.ts +10 -9
  493. package/src/sync/layout.ts +13 -12
  494. package/src/sync/messages.ts +153 -0
  495. package/src/sync/review-queue.ts +6 -5
  496. package/src/sync/s3/messages.ts +16 -0
  497. package/src/sync/s3/s3-providers.ts +9 -6
  498. package/src/sync/s3/s3-transport.ts +1 -1
  499. package/src/sync/s3/sigv4.ts +3 -1
  500. package/src/sync/snapshot-crypto.ts +6 -5
  501. package/src/sync/snapshot-json.ts +3 -2
  502. package/src/sync/sync-engine-download-tombstone.test.ts +1 -1
  503. package/src/sync/sync-engine.test.ts +226 -8
  504. package/src/sync/sync-engine.ts +103 -41
  505. package/src/sync/sync-history.ts +7 -6
  506. package/src/sync/sync-selection.test.ts +12 -2
  507. package/src/sync/sync-selection.ts +18 -5
  508. package/src/sync/webdav/webdav-transport.ts +4 -1
  509. package/src/ui/artifact-view.ts +4 -3
  510. package/src/ui/commands.test.ts +1 -0
  511. package/src/ui/commands.ts +11 -1
  512. package/src/ui/disk-usage-view.test.ts +113 -6
  513. package/src/ui/disk-usage-view.ts +63 -7
  514. package/src/ui/errors.ts +4 -3
  515. package/src/ui/export-flow.ts +24 -20
  516. package/src/ui/foreign-view.test.ts +43 -0
  517. package/src/ui/foreign-view.ts +30 -3
  518. package/src/ui/i18n.ts +125 -0
  519. package/src/ui/import-wizard.ts +18 -10
  520. package/src/ui/progress.ts +2 -2
  521. package/src/ui/report.ts +7 -6
  522. package/src/ui/rollback-view.test.ts +819 -0
  523. package/src/ui/rollback-view.ts +1339 -0
  524. package/src/ui/selection-model.test.ts +33 -1
  525. package/src/ui/selection-model.ts +53 -0
  526. package/src/ui/session-inventory-view.test.ts +109 -0
  527. package/src/ui/session-inventory-view.ts +138 -3
  528. package/src/ui/session-issue-labels.test.ts +51 -0
  529. package/src/ui/session-issue-labels.ts +70 -0
  530. package/src/ui/sync-settings-view.test.ts +36 -0
  531. package/src/ui/sync-settings-view.ts +49 -0
  532. package/src/ui/types.ts +10 -4
  533. package/src/utils/atomic-write.ts +6 -5
  534. package/src/utils/bundle-scan.test.ts +2 -2
  535. package/src/utils/bundle-scan.ts +12 -1
  536. package/src/utils/env-lock.ts +83 -49
  537. package/src/utils/json.ts +7 -5
  538. package/src/utils/messages-utils.ts +232 -0
  539. package/src/utils/proxy.test.ts +25 -0
  540. package/src/utils/proxy.ts +19 -5
  541. package/src/utils/recursive-walk.test.ts +43 -0
  542. package/src/utils/recursive-walk.ts +75 -1
  543. package/src/utils/session-log-repair.ts +10 -9
  544. package/src/utils/zip.ts +27 -26
  545. package/lib/core/checkpoint.d.ts +0 -362
  546. package/lib/core/checkpoint.js +0 -1309
  547. package/src/core/checkpoint.test.ts +0 -665
  548. package/src/core/checkpoint.ts +0 -1614
@@ -9,12 +9,38 @@
9
9
  * ② 对「可回收」子区按各自保留期算出**已超期**的字节数与条目数(与 host 侧清理逻辑同口径,
10
10
  * 保留期由调用方注入 —— 本模块不读配置、不猜默认值)。
11
11
  *
12
- * 硬约束:**只读**。任何子路径缺失/不可读都不抛错,如实降级为该子区 0 字节;
13
- * 扫描期间出现的竞态删除(readdir/stat 失败)只终止那一支,不影响其余统计。
12
+ * 硬约束:**只读**。任何子路径缺失/不可读都不抛错,如实降级为该子区 0 字节、并把
13
+ * `unreadable` 置真(界面显示「未统计」而不是 0);扫描期间出现的竞态删除(readdir/stat
14
+ * 失败)只终止那一支,不影响其余统计。
15
+ *
16
+ * 已补齐两块此前不可见的占用(都**只报告、绝不提供清理**):
17
+ * - 回滚点库 `dataDir/rollback-points`:并进 `DISK_USAGE_AREAS`,`policy: 'protected'`;
18
+ * - 「遗留数据」`LEGACY_DATA_DIRS`(当前一条:旧检查点库 `dataDir/checkpoints`):
19
+ * 插件**已不再读取**该目录,也**不代删**(删除不可逆,需用户单独授权)。
20
+ * 本模块与清理动作完全解耦:`IMMEDIATE_CLEAN_CATEGORIES` 只有可重建区,
21
+ * `POST /disk-usage/cleanup` 的候选白名单也只有 'tmp' | 'expired-exports'。
14
22
  */
15
23
  import fs from 'node:fs/promises';
16
24
  import path from 'node:path';
17
- /** 体检子区(顺序即界面展示顺序:先备份产物,再缓存/暂存) */
25
+ /**
26
+ * 回滚点库目录名(`dataDir/rollback-points`)。
27
+ *
28
+ * 为什么不直接 import 引擎的 `ROLLBACK_POINTS_DIR_NAME`:本模块是**只读体检**,也是离线
29
+ * 救急台(`dcm web` 的磁盘页)的依赖 —— 不该把整个回滚引擎(crypto / zlib / atomic-write /
30
+ * 会话索引…)拉进它的运行时依赖图;引擎文件一旦有问题,救急台恰恰是最不该跟着挂的那个页面。
31
+ * 「单一事实源」在这里靠**源码级守卫**而不是 import:`disk-usage.test.ts` 直接读
32
+ * `src/core/rollback-point.ts` 的声明并与本常量逐字比对(改了那边、或改了这边,测试即红)
33
+ * —— 与 `tests/packaging-contract.test.ts` 的 V-1(源码级读 `PLUGIN_VERSION`,不 import 宿主入口)
34
+ * 同一种姿势。
35
+ */
36
+ const ROLLBACK_POINTS_DIR = 'rollback-points';
37
+ /**
38
+ * 只报告、**不提供清理**的子区(当前一条:回滚点库 = `dataDir/rollback-points`)。
39
+ * 它只是「口径清单」:报告/展示一律用完备的 `DISK_USAGE_AREAS`,清理候选另有白名单
40
+ * (`IMMEDIATE_CLEAN_CATEGORIES` / 清理入口 categories),两者不得混用。
41
+ */
42
+ export const DISK_USAGE_EXTRA_AREAS = ['rollback-points'];
43
+ /** 体检子区(顺序即报告/展示顺序:先备份产物,再缓存/暂存,末位为只读保护的附加区) */
18
44
  export const DISK_USAGE_AREAS = [
19
45
  'exports',
20
46
  'snapshots',
@@ -28,10 +54,22 @@ export const DISK_USAGE_AREAS = [
28
54
  'transactions',
29
55
  'locks',
30
56
  'vault',
57
+ ...DISK_USAGE_EXTRA_AREAS,
58
+ ];
59
+ /**
60
+ * 遗留数据目录清单(当前一条:旧检查点库)。
61
+ *
62
+ * `checkpoints/` 是回滚点库改名(`rollback-points/`)之前的旧目录:新代码**不再读取**它,
63
+ * 本插件也**不去删**它(删除是不可逆动作,需用户单独授权)。
64
+ */
65
+ export const LEGACY_DATA_DIRS = [
66
+ { id: 'legacy-checkpoints', relPath: 'checkpoints' },
31
67
  ];
32
68
  /** 可立即整块清理的子区(转成磁盘使用分区 id;供清理路由映射回结果) */
33
69
  export const IMMEDIATE_CLEAN_CATEGORIES = ['tmp', 'marketCache', 'marketWork'];
34
- /** 子区 → 物理目录(单一映射点;展示与统计都不再重复挑目录) */
70
+ /** 子区 → 物理目录(单一映射点;展示与统计都不再重复挑目录)。
71
+ * 回滚点库不在 `DiskUsageDirs` 里显式传:它的位置 = `dataDir` + `ROLLBACK_POINTS_DIR`
72
+ * (与引擎常量逐字一致,有源码级守卫),宿主路由与离线 CLI 两条构造路径因此不可能漂移。 */
35
73
  export function diskUsageDirOf(dirs, area) {
36
74
  switch (area) {
37
75
  case 'exports': return dirs.exportsDir;
@@ -46,6 +84,7 @@ export function diskUsageDirOf(dirs, area) {
46
84
  case 'transactions': return dirs.transactionsDir;
47
85
  case 'locks': return dirs.locksDir;
48
86
  case 'vault': return dirs.vaultDir;
87
+ case 'rollback-points': return path.join(dirs.dataDir, ROLLBACK_POINTS_DIR);
49
88
  }
50
89
  }
51
90
  /**
@@ -184,6 +223,8 @@ export async function scanDiskUsage(options) {
184
223
  transactions: null,
185
224
  locks: null,
186
225
  vault: null,
226
+ // 回滚点库没有「保留期」:只报告,绝不自动清理(工作区 + 会话两态的恢复入口)
227
+ 'rollback-points': null,
187
228
  };
188
229
  const policyOf = {
189
230
  exports: 'retained',
@@ -198,6 +239,8 @@ export async function scanDiskUsage(options) {
198
239
  transactions: 'protected',
199
240
  locks: 'protected',
200
241
  vault: 'protected',
242
+ // 与 snapshots/sync 同语义:用户数据/恢复入口 —— 只报告,绝不提供清理
243
+ 'rollback-points': 'protected',
201
244
  };
202
245
  const areas = {};
203
246
  let totalBytes = 0;
@@ -233,6 +276,25 @@ export async function scanDiskUsage(options) {
233
276
  if (entry.policy === 'regenerable')
234
277
  reclaimableBytes += walk.sizeBytes;
235
278
  }
279
+ /**
280
+ * 遗留数据:与子区**同一套**遍历口径(只读、不跟随符号链接、读不到即 unreadable),
281
+ * 但**不计入 totalBytes**(与 areas 分列),且 policy 恒为 protected —— 本模块不提供
282
+ * 任何删除动作,也不把它们的路径交给清理入口。
283
+ */
284
+ const legacy = [];
285
+ for (const item of LEGACY_DATA_DIRS) {
286
+ const dir = path.join(dirs.dataDir, item.relPath);
287
+ const walk = await walkDirectory(dir, null, nowMs);
288
+ legacy.push({
289
+ id: item.id,
290
+ relPath: item.relPath,
291
+ path: dir,
292
+ sizeBytes: walk.sizeBytes,
293
+ fileCount: walk.fileCount,
294
+ unreadable: walk.unreadable,
295
+ policy: 'protected',
296
+ });
297
+ }
236
298
  return {
237
299
  dataDir: dirs.dataDir,
238
300
  totalBytes,
@@ -240,6 +302,7 @@ export async function scanDiskUsage(options) {
240
302
  reclaimableBytes,
241
303
  expiredBytes,
242
304
  areas,
305
+ legacy,
243
306
  backupRetention: { keepLast: options.backupKeepLast ?? 10, latestBackupBytes: 0, latestBackupAt: null },
244
307
  };
245
308
  }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * 引擎语言运行时(宿主 / 引擎半)——「英文界面零中文」的引擎侧根因修复。
3
+ *
4
+ * 语义(唯一要记住的一句话):**语言必须在「取文案的那一刻」解析,而不是在「装配的那一刻」**。
5
+ * 改造前的写法是 this.msg = makeMsg(resolveAppLanguage(ctx)):apply() 只在插件加载时执行一次,
6
+ * 于是宿主产出的报告 / 计划 / 错误文本被冻结成加载时那门语言(用户切到 English 后仍是中文)。
7
+ *
8
+ * 本模块提供三件事:
9
+ * 1. 语言运行时:setEngineLocale / setEngineLanguageSource / getEngineLocale /
10
+ * invalidateEngineLocale(函数源按 LANGUAGE_TTL_MS 兜底缓存;取文案时才解析);
11
+ * 2. 消息目录注册:registerMessageCatalog(领域模块追加自己的目录,**仅在既有目录未命中时生效**);
12
+ * 基础目录(src/core/messages.ts 的 zh/en)由该模块经 registerBaseMessageCatalog 反向注册;
13
+ * 3. engineMsg:宿主 / 引擎半的活翻译器(MsgFunc 形状),未知键回退 zh → 键名,绝不抛错。
14
+ *
15
+ * 纪律:
16
+ * - 未设定语言时行为等于 zh(与改造前的缺省逐字一致);
17
+ * - 本模块**不 import src/core/messages.ts**(否则形成循环依赖):基础目录由 messages.ts 反向注册;
18
+ * - 目录查找每次调用现查(目录是常量,成本可忽略);语言只按 LANGUAGE_TTL_MS 缓存。
19
+ */
20
+ import type { MsgParams } from './msg-types.ts';
21
+ /** 应用语言(与 DSH settings 的 locale preference 同口径)。 */
22
+ export type LanguageId = 'zh' | 'en';
23
+ /**
24
+ * 语言源允许的缓存上界(毫秒)。
25
+ *
26
+ * 只给**非请求路径**(调度器、后台任务)兜底:请求入口应调用 invalidateEngineLocale()
27
+ * 让每个请求都拿到最新语言(见 routes/kit.ts 的注册点)。
28
+ */
29
+ export declare const LANGUAGE_TTL_MS = 1000;
30
+ /** 目录(zh 源 / en 镜像;两本都可选,缺的那本不参与查找)。 */
31
+ export interface MessageCatalog {
32
+ /** 目录标识(诊断用)。 */
33
+ readonly id?: string;
34
+ readonly zh?: Readonly<Record<string, string>>;
35
+ readonly en?: Readonly<Record<string, string>>;
36
+ }
37
+ /** 语言源:固定值,或「调用期解析」的活源。 */
38
+ export type LanguageSource = LanguageId | (() => LanguageId);
39
+ /** 设定引擎语言(固定值):构造宿主时按 resolveAppLanguage(ctx) 初始化。 */
40
+ export declare function setEngineLocale(locale: LanguageSource): void;
41
+ /**
42
+ * 注册「调用期解析」的语言活源(宿主用 () => resolveAppLanguage(ctx))。
43
+ *
44
+ * 与 setEngineLocale 同源:后者给构造期的初值,本函数让**之后**每次取文案都能跟随用户切语言。
45
+ */
46
+ export declare function setEngineLanguageSource(resolve: () => LanguageId): void;
47
+ /** 强制失效:下一次 getEngineLocale() 必须重新解析(路由入口 / 测试用)。 */
48
+ export declare function invalidateEngineLocale(): void;
49
+ /**
50
+ * 当前引擎语言(调用期解析)。
51
+ *
52
+ * 函数源的结果按 LANGUAGE_TTL_MS 缓存;固定值源缓存无副作用。解析失败一律回落 zh(绝不抛错)。
53
+ * now 可注入(单测用假时钟验证 TTL 上界)。
54
+ */
55
+ export declare function getEngineLocale(now?: number): LanguageId;
56
+ /**
57
+ * 注册基础目录(zh 源 / en 镜像)。
58
+ *
59
+ * 由 src/core/messages.ts 在模块初始化时调用一次 —— 这样本模块不必 import 它(避免循环依赖)。
60
+ * 直接 import engine-locale 而不 import messages.ts 的模块,engineMsg 只能拿到注册目录 + 键名。
61
+ */
62
+ export declare function registerBaseMessageCatalog(catalogs: {
63
+ readonly zh: Readonly<Record<string, string>>;
64
+ readonly en: Readonly<Record<string, string>>;
65
+ }): void;
66
+ /**
67
+ * 注册一本追加目录(领域模块的键并入既有目录)。
68
+ *
69
+ * **只在既有目录未命中时生效**(makeMsg / engineMsg 的查找顺序:既有目录 → 注册目录 → 键名);
70
+ * 同一键先注册者优先。en 语言下注册目录未命中时再回退注册目录的 zh(与既有 en → zh 同口径)。
71
+ */
72
+ export declare function registerMessageCatalog(catalog: MessageCatalog): void;
73
+ /** 已注册的追加目录(只读快照,诊断用)。 */
74
+ export declare function registeredMessageCatalogs(): readonly MessageCatalog[];
75
+ /** 清空追加目录(测试 / 装配隔离用)。 */
76
+ export declare function resetMessageCatalogs(): void;
77
+ /** 注册目录里查一条(未命中 → undefined)。 */
78
+ export declare function registeredMessage(lang: LanguageId, key: string): string | undefined;
79
+ /** 插值:{param} → 形参值;缺参原样保留(便于排查)。与改造前的 messages.ts 逐字同口径。 */
80
+ export declare function interpolate(template: string, params?: MsgParams): string;
81
+ /**
82
+ * 活翻译器(宿主 / 引擎半的 MsgFunc):每次调用按 getEngineLocale() 选目录。
83
+ *
84
+ * 查找顺序:既有目录(当前语言)→ en 语言下回退既有 zh → 注册目录(同语言 → zh)→ 键名。
85
+ * 未设定语言时 = zh 目录,行为与改造前逐字一致;未知键回退键名,绝不抛错。
86
+ */
87
+ export declare function engineMsg(key: string, params?: MsgParams): string;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * 语言源允许的缓存上界(毫秒)。
3
+ *
4
+ * 只给**非请求路径**(调度器、后台任务)兜底:请求入口应调用 invalidateEngineLocale()
5
+ * 让每个请求都拿到最新语言(见 routes/kit.ts 的注册点)。
6
+ */
7
+ export const LANGUAGE_TTL_MS = 1000;
8
+ const DEFAULT_LANGUAGE = 'zh';
9
+ let source = DEFAULT_LANGUAGE;
10
+ let cachedLanguage = DEFAULT_LANGUAGE;
11
+ let cachedAt = 0;
12
+ let cachedValid = false;
13
+ function normalize(value) {
14
+ return value === 'en' ? 'en' : 'zh';
15
+ }
16
+ /** 设定引擎语言(固定值):构造宿主时按 resolveAppLanguage(ctx) 初始化。 */
17
+ export function setEngineLocale(locale) {
18
+ source = locale;
19
+ invalidateEngineLocale();
20
+ }
21
+ /**
22
+ * 注册「调用期解析」的语言活源(宿主用 () => resolveAppLanguage(ctx))。
23
+ *
24
+ * 与 setEngineLocale 同源:后者给构造期的初值,本函数让**之后**每次取文案都能跟随用户切语言。
25
+ */
26
+ export function setEngineLanguageSource(resolve) {
27
+ setEngineLocale(resolve);
28
+ }
29
+ /** 强制失效:下一次 getEngineLocale() 必须重新解析(路由入口 / 测试用)。 */
30
+ export function invalidateEngineLocale() {
31
+ cachedValid = false;
32
+ cachedAt = 0;
33
+ }
34
+ /**
35
+ * 当前引擎语言(调用期解析)。
36
+ *
37
+ * 函数源的结果按 LANGUAGE_TTL_MS 缓存;固定值源缓存无副作用。解析失败一律回落 zh(绝不抛错)。
38
+ * now 可注入(单测用假时钟验证 TTL 上界)。
39
+ */
40
+ export function getEngineLocale(now = Date.now()) {
41
+ if (cachedValid && now - cachedAt < LANGUAGE_TTL_MS)
42
+ return cachedLanguage;
43
+ let next = DEFAULT_LANGUAGE;
44
+ try {
45
+ next = normalize(typeof source === 'function' ? source() : source);
46
+ }
47
+ catch {
48
+ next = cachedValid ? cachedLanguage : DEFAULT_LANGUAGE;
49
+ }
50
+ cachedLanguage = next;
51
+ cachedAt = now;
52
+ cachedValid = true;
53
+ return next;
54
+ }
55
+ /* ------------------------------------------------------------- 目录注册 */
56
+ const registry = [];
57
+ let baseZh;
58
+ let baseEn;
59
+ /**
60
+ * 注册基础目录(zh 源 / en 镜像)。
61
+ *
62
+ * 由 src/core/messages.ts 在模块初始化时调用一次 —— 这样本模块不必 import 它(避免循环依赖)。
63
+ * 直接 import engine-locale 而不 import messages.ts 的模块,engineMsg 只能拿到注册目录 + 键名。
64
+ */
65
+ export function registerBaseMessageCatalog(catalogs) {
66
+ baseZh = catalogs.zh;
67
+ baseEn = catalogs.en;
68
+ }
69
+ /**
70
+ * 注册一本追加目录(领域模块的键并入既有目录)。
71
+ *
72
+ * **只在既有目录未命中时生效**(makeMsg / engineMsg 的查找顺序:既有目录 → 注册目录 → 键名);
73
+ * 同一键先注册者优先。en 语言下注册目录未命中时再回退注册目录的 zh(与既有 en → zh 同口径)。
74
+ */
75
+ export function registerMessageCatalog(catalog) {
76
+ registry.push(catalog);
77
+ }
78
+ /** 已注册的追加目录(只读快照,诊断用)。 */
79
+ export function registeredMessageCatalogs() {
80
+ return registry;
81
+ }
82
+ /** 清空追加目录(测试 / 装配隔离用)。 */
83
+ export function resetMessageCatalogs() {
84
+ registry.length = 0;
85
+ }
86
+ /** 注册目录里查一条(未命中 → undefined)。 */
87
+ export function registeredMessage(lang, key) {
88
+ for (const catalog of registry) {
89
+ const hit = catalog[lang]?.[key];
90
+ if (hit !== undefined)
91
+ return hit;
92
+ }
93
+ if (lang === 'en') {
94
+ for (const catalog of registry) {
95
+ const hit = catalog.zh?.[key];
96
+ if (hit !== undefined)
97
+ return hit;
98
+ }
99
+ }
100
+ return undefined;
101
+ }
102
+ /* --------------------------------------------------------------- 翻译器 */
103
+ /** 插值:{param} → 形参值;缺参原样保留(便于排查)。与改造前的 messages.ts 逐字同口径。 */
104
+ export function interpolate(template, params) {
105
+ if (params === undefined)
106
+ return template;
107
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
108
+ const value = params[key];
109
+ return value === undefined ? match : String(value);
110
+ });
111
+ }
112
+ /**
113
+ * 活翻译器(宿主 / 引擎半的 MsgFunc):每次调用按 getEngineLocale() 选目录。
114
+ *
115
+ * 查找顺序:既有目录(当前语言)→ en 语言下回退既有 zh → 注册目录(同语言 → zh)→ 键名。
116
+ * 未设定语言时 = zh 目录,行为与改造前逐字一致;未知键回退键名,绝不抛错。
117
+ */
118
+ export function engineMsg(key, params) {
119
+ const lang = getEngineLocale();
120
+ const dict = lang === 'en' ? baseEn : baseZh;
121
+ const fallback = lang === 'en' ? baseZh : undefined;
122
+ const template = dict?.[key] ?? fallback?.[key] ?? registeredMessage(lang, key) ?? key;
123
+ return interpolate(template, params);
124
+ }
125
+ //# sourceMappingURL=engine-locale.js.map
@@ -18,6 +18,7 @@ import { SECTION_JSON_PATHS, SECTION_FILE_PREFIXES, isFileSection } from '../sch
18
18
  import { DEFAULT_SENSITIVE_RELS, refreshVault } from '../security/vault.js';
19
19
  import { writeZip } from '../utils/zip.js';
20
20
  import { msgOf } from './messages.js';
21
+ import { engineMsg } from './messages-core.js';
21
22
  import { declareBundledSessionsInWorkspaces, normalizeSessionLimit, sessionIdKey } from './session-select.js';
22
23
  // issue #45 连带匹配的第二判据:工作区 path 的 cwd 目录键(DSH 的 sessionIds 覆盖率很低,见 coupleSessionWorkspaces)
23
24
  import { projectKeyOf } from './session-meta.js';
@@ -340,11 +341,10 @@ export class Exporter {
340
341
  warnings.push(this.msg('export.fileSectionSecrets', { section: adapter.id, path: hitPath }));
341
342
  }
342
343
  // 被截断的文件数必须**显式**汇总告警,否则截断本身又变成静默丢失。
343
- // 说明:此处未新增消息键(如 export.fileSectionSecretsTruncated)是为避免与并行任务冲突
344
- // (src/core/messages.ts 属他人改动范围);故复用 export.fileSectionSecrets,仅 path 传汇总文案。
344
+ // 文案在 t4 域目录(src/core/messages-core.ts):不再借用 export.fileSectionSecrets 传中文 path 值。
345
345
  const truncatedCount = hitPaths.length - warnedPaths.length;
346
346
  if (truncatedCount > 0) {
347
- warnings.push(this.msg('export.fileSectionSecrets', { section: adapter.id, path: `(另有 ${truncatedCount} 个文件命中,详见报告)` }));
347
+ warnings.push(engineMsg('core.exporter.fileSectionSecretsTruncated', { section: adapter.id, count: truncatedCount }));
348
348
  }
349
349
  }
350
350
  }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * 历史 fork 归位(t17)—— 把「有父会话、但**账内不含它**」的旧子会话收回到它该在的工作区。
3
+ *
4
+ * 背景(t10 真机复核):本机 887 条有父会话的子会话里 58 条是回退 fork,其中能解析到已注册工作区的
5
+ * 是 **58/58**,但只有 3 条在账内 —— 其余全部停在侧栏「未分组」。t10 的修复只管**新建** fork,
6
+ * 历史遗留不会自动回收;本模块提供一次**显式触发**的归位动作(不是后台自动跑)。
7
+ *
8
+ * 三条纪律(逐条对应验收):
9
+ * ① **判据只有一份**:cwd 解析 / 成员判定 / attach / 复核全部由宿主注入的 seam 提供 ——
10
+ * 就是 t10 已落地的 `DshSessionStoreFacade.attachChildToParentWorkspace`(成员 / 血缘 / cwd 同目录三档
11
+ * + 写后 `list()` 复核)。core **不 import 宿主入口**(架构守卫),也不另写第二套 attach:
12
+ * 第二套判据迟早与第一套漂移。
13
+ * ② **只读盘点 + 逐个归位 + 逐个复核**,逐条回执(attached / already / refused + **具体**理由);
14
+ * 任何一条失败都不静默 —— 异常也收成一条 refused(reason=`unexpected-error`)。
15
+ * ③ **绝不猜、绝不删、绝不动会话日志字节**:本模块自己不碰文件系统(IO 全在 seam 里),
16
+ * 候选只认「有 `parentSession` 的子会话」;能不能归位由 seam 按 cwd/成员事实判定。
17
+ *
18
+ * 为什么收成「一次动作」而不是后台自动跑:归位是**写**(改工作区成员),必须由用户显式触发;
19
+ * 而且它只影响侧栏分组观感,不该在后台悄悄改用户数据。
20
+ */
21
+ /** 一个候选子会话(只读事实;cwd 不在这里 —— 它属于 seam 的判定面)。 */
22
+ export interface ForkReconcileChild {
23
+ sessionId: string;
24
+ parentSessionId: string;
25
+ /**
26
+ * 该会话自己是不是**子代理会话**(`header.origin === 'subagent'`;宿主经
27
+ * `sessions.parentRelations()` 的 `SessionParentRelation.subagent` 给)。
28
+ *
29
+ * ⚠️ **它不能用来区分「回退 fork 子会话」**(t17 真机实测,务必别顺手加过滤):
30
+ * 本机 887 条有父会话的子会话里 58 条是回退 fork(`isSeeded:true`),而这 58 条里
31
+ * **50 条同样带 `origin='subagent'`**(DSH 的 fork 就是用 `agents.create` 造的,标记就是 subagent)。
32
+ * 所以「跳过 subagent」会把**目标本身**(50/58)一起跳掉 ⇒ 该口径默认**关闭**,
33
+ * 只在调用方显式传 {@link ForkReconcileOptions.skipSubagentSessions} 时才生效。
34
+ */
35
+ subagent?: boolean;
36
+ }
37
+ /** 归位动作的可选口径(默认 = 合同字面:**全部**有父会话的子会话)。 */
38
+ export interface ForkReconcileOptions {
39
+ /**
40
+ * 跳过 `origin='subagent'` 的子会话(默认 false)。
41
+ *
42
+ * 为什么默认**关**:真机上 50/58 条回退 fork 自己就带这个标记(见 {@link ForkReconcileChild.subagent}),
43
+ * 开了它等于把要修的东西跳掉。给这个开关只为让「窄化」这一选择可被显式表达与复核,
44
+ * 不是默认行为。跳过条数一律记进 {@link ForkReconcileResult.skipped}(不静默)。
45
+ */
46
+ skipSubagentSessions?: boolean;
47
+ }
48
+ /** 逐条回执的状态(三态,互斥)。 */
49
+ export type ForkReconcileStatus =
50
+ /** 本次真的写成功且复核通过(seam 给的 `attached`)。 */
51
+ 'attached'
52
+ /** 已经在账内(seam 给的 `already-attached`)——**幂等:不重复写**。 */
53
+ | 'already'
54
+ /** 没能归位;`reason` 是具体理由码(见 seam 的 WorkspaceAttachFailureReason 同名同义)。 */
55
+ | 'refused';
56
+ /** seam 对**一条**子会话的归位结果(与 index.ts 的 `WorkspaceAttachOutcome` 同形同义)。 */
57
+ export type ForkReconcileOutcome = {
58
+ ok: true;
59
+ status: 'attached' | 'already';
60
+ workspaceId?: string;
61
+ } | {
62
+ ok: false;
63
+ reason: string;
64
+ detail?: string;
65
+ };
66
+ /** 归位动作的注入面(全部只读或由宿主实现;core 只编排)。 */
67
+ export interface ForkReconcileDeps {
68
+ /**
69
+ * 只读:本机**有父会话的子会话**清单。宿主用 `sessions.parentRelations()`(DSH 存储列举,
70
+ * 解析成本在 DSH 侧已付);**读不到必须抛错**,绝不用空表冒充「本机没有子会话」。
71
+ */
72
+ childSessions: () => Promise<readonly ForkReconcileChild[]>;
73
+ /** 一条子会话的归位动作(t10 的同一份实现;逐条调用,互不影响)。 */
74
+ reconcileOne: (child: ForkReconcileChild) => Promise<ForkReconcileOutcome>;
75
+ /** 逐条留痕(可选;失败必须能被日志看到)。 */
76
+ log?: (line: string) => void;
77
+ }
78
+ /** 一条回执。 */
79
+ export interface ForkReconcileReceipt {
80
+ sessionId: string;
81
+ parentSessionId: string;
82
+ status: ForkReconcileStatus;
83
+ /** 机器码:attached/already 时是 seam 的 reason;refused 时是**具体**失败理由。 */
84
+ reason: string;
85
+ /** 归位到的工作区 id(拿不到就是 null;只作诊断,不参与判定)。 */
86
+ workspaceId: string | null;
87
+ /** 技术细节(errno / 路径 / 形状码)——不是用户文案。 */
88
+ detail?: string;
89
+ }
90
+ /** 归位动作的结果(计数恒为**精确值**;回执列表有界,截断时如实标记)。 */
91
+ export interface ForkReconcileResult {
92
+ ok: boolean;
93
+ /** 扫描到的父子关系条数(含无父/空 id 的噪声项,只作诊断)。 */
94
+ scanned: number;
95
+ /** 真正尝试归位的候选数(有父会话的子会话,去重后)。 */
96
+ candidates: number;
97
+ attached: number;
98
+ already: number;
99
+ refused: number;
100
+ /** 失败理由分布(只统计 refused;键 = 理由码)。 */
101
+ reasonCounts: Record<string, number>;
102
+ /**
103
+ * **有意跳过**的条数(不是失败,也不是静默丢弃):只统计「显式窄化」跳过的子代理会话。
104
+ * 默认口径({@link ForkReconcileOptions.skipSubagentSessions} 未开)下恒为 0。
105
+ */
106
+ skipped: {
107
+ subagent: number;
108
+ };
109
+ receipts: ForkReconcileReceipt[];
110
+ /** 回执被上限截断(计数仍精确)。 */
111
+ receiptsTruncated: boolean;
112
+ /** 盘点阶段就失败(读不到父子关系)时的具体原因;此时 candidates=0 且**不是**「本机没有子会话」。 */
113
+ error?: string;
114
+ }
115
+ /**
116
+ * 回执列表上限。
117
+ *
118
+ * 为什么有界:候选是「本机全部有父会话的子会话」(真机 887 条),逐条回执全量回传会让响应体
119
+ * 无谓地大;计数(attached/already/refused 与理由分布)**恒为精确值**,截断只影响明细列表。
120
+ */
121
+ export declare const FORK_RECONCILE_RECEIPT_LIMIT = 500;
122
+ /**
123
+ * 一次历史 fork 归位:只读盘点 → 逐个归位 → 逐个复核(复核在 seam 内,写后重读 `list()`)。
124
+ *
125
+ * **顺序执行**(不并发):归位是写动作,且逐条失败理由要能按顺序对上号;候选规模(真机数百条)
126
+ * 与每条的成本(一次 registry 读 + 一次 attach + 一次复核读)都不值得为并发牺牲可读性。
127
+ */
128
+ export declare function reconcileForkSessions(deps: ForkReconcileDeps, options?: ForkReconcileOptions): Promise<ForkReconcileResult>;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * 历史 fork 归位(t17)—— 把「有父会话、但**账内不含它**」的旧子会话收回到它该在的工作区。
3
+ *
4
+ * 背景(t10 真机复核):本机 887 条有父会话的子会话里 58 条是回退 fork,其中能解析到已注册工作区的
5
+ * 是 **58/58**,但只有 3 条在账内 —— 其余全部停在侧栏「未分组」。t10 的修复只管**新建** fork,
6
+ * 历史遗留不会自动回收;本模块提供一次**显式触发**的归位动作(不是后台自动跑)。
7
+ *
8
+ * 三条纪律(逐条对应验收):
9
+ * ① **判据只有一份**:cwd 解析 / 成员判定 / attach / 复核全部由宿主注入的 seam 提供 ——
10
+ * 就是 t10 已落地的 `DshSessionStoreFacade.attachChildToParentWorkspace`(成员 / 血缘 / cwd 同目录三档
11
+ * + 写后 `list()` 复核)。core **不 import 宿主入口**(架构守卫),也不另写第二套 attach:
12
+ * 第二套判据迟早与第一套漂移。
13
+ * ② **只读盘点 + 逐个归位 + 逐个复核**,逐条回执(attached / already / refused + **具体**理由);
14
+ * 任何一条失败都不静默 —— 异常也收成一条 refused(reason=`unexpected-error`)。
15
+ * ③ **绝不猜、绝不删、绝不动会话日志字节**:本模块自己不碰文件系统(IO 全在 seam 里),
16
+ * 候选只认「有 `parentSession` 的子会话」;能不能归位由 seam 按 cwd/成员事实判定。
17
+ *
18
+ * 为什么收成「一次动作」而不是后台自动跑:归位是**写**(改工作区成员),必须由用户显式触发;
19
+ * 而且它只影响侧栏分组观感,不该在后台悄悄改用户数据。
20
+ */
21
+ /**
22
+ * 回执列表上限。
23
+ *
24
+ * 为什么有界:候选是「本机全部有父会话的子会话」(真机 887 条),逐条回执全量回传会让响应体
25
+ * 无谓地大;计数(attached/already/refused 与理由分布)**恒为精确值**,截断只影响明细列表。
26
+ */
27
+ export const FORK_RECONCILE_RECEIPT_LIMIT = 500;
28
+ /** 一条候选 → 回执(分类只认 seam 给的事实,绝不从「看起来成功」推断)。 */
29
+ function receiptOf(child, outcome) {
30
+ if (outcome.ok) {
31
+ return {
32
+ sessionId: child.sessionId,
33
+ parentSessionId: child.parentSessionId,
34
+ status: outcome.status === 'already' ? 'already' : 'attached',
35
+ reason: outcome.status === 'already' ? 'already-attached' : 'attached',
36
+ workspaceId: outcome.workspaceId ?? null,
37
+ };
38
+ }
39
+ const receipt = {
40
+ sessionId: child.sessionId,
41
+ parentSessionId: child.parentSessionId,
42
+ status: 'refused',
43
+ reason: outcome.reason,
44
+ workspaceId: null,
45
+ };
46
+ if (outcome.detail !== undefined)
47
+ receipt.detail = outcome.detail;
48
+ return receipt;
49
+ }
50
+ /**
51
+ * 一次历史 fork 归位:只读盘点 → 逐个归位 → 逐个复核(复核在 seam 内,写后重读 `list()`)。
52
+ *
53
+ * **顺序执行**(不并发):归位是写动作,且逐条失败理由要能按顺序对上号;候选规模(真机数百条)
54
+ * 与每条的成本(一次 registry 读 + 一次 attach + 一次复核读)都不值得为并发牺牲可读性。
55
+ */
56
+ export async function reconcileForkSessions(deps, options = {}) {
57
+ const empty = {
58
+ ok: false,
59
+ scanned: 0,
60
+ candidates: 0,
61
+ attached: 0,
62
+ already: 0,
63
+ refused: 0,
64
+ reasonCounts: {},
65
+ skipped: { subagent: 0 },
66
+ receipts: [],
67
+ receiptsTruncated: false,
68
+ };
69
+ let listed;
70
+ try {
71
+ listed = await deps.childSessions();
72
+ }
73
+ catch (error) {
74
+ const detail = error instanceof Error ? error.message : String(error);
75
+ deps.log?.('fork-reconcile: childSessions failed: ' + detail);
76
+ return { ...empty, error: 'child-sessions-unavailable: ' + detail };
77
+ }
78
+ // 候选 = 有父会话的子会话(去重;形状不符的噪声项只计入 scanned)
79
+ const candidates = [];
80
+ const seen = new Set();
81
+ let skippedSubagent = 0;
82
+ for (const item of listed) {
83
+ const sessionId = item?.sessionId;
84
+ const parentSessionId = item?.parentSessionId;
85
+ if (typeof sessionId !== 'string' || sessionId === '')
86
+ continue;
87
+ if (typeof parentSessionId !== 'string' || parentSessionId === '')
88
+ continue;
89
+ if (sessionId === parentSessionId)
90
+ continue;
91
+ if (seen.has(sessionId))
92
+ continue;
93
+ seen.add(sessionId);
94
+ candidates.push(item.subagent === true
95
+ ? { sessionId, parentSessionId, subagent: true }
96
+ : { sessionId, parentSessionId });
97
+ }
98
+ const attempted = options.skipSubagentSessions === true
99
+ ? candidates.filter((child) => child.subagent !== true)
100
+ : candidates;
101
+ skippedSubagent = candidates.length - attempted.length;
102
+ if (skippedSubagent > 0) {
103
+ deps.log?.('fork-reconcile: skipped ' + String(skippedSubagent) + ' subagent sessions (explicit narrowing)');
104
+ }
105
+ const receipts = [];
106
+ const reasonCounts = {};
107
+ let attached = 0;
108
+ let already = 0;
109
+ let refused = 0;
110
+ let truncated = false;
111
+ for (const child of attempted) {
112
+ let outcome;
113
+ try {
114
+ outcome = await deps.reconcileOne(child);
115
+ }
116
+ catch (error) {
117
+ // 一条失败绝不影响其余(逐条互不影响),且**如实记一条 refused**
118
+ const detail = error instanceof Error ? error.message : String(error);
119
+ deps.log?.('fork-reconcile: ' + child.sessionId + ' threw: ' + detail);
120
+ outcome = { ok: false, reason: 'unexpected-error', detail };
121
+ }
122
+ const receipt = receiptOf(child, outcome);
123
+ if (receipt.status === 'attached')
124
+ attached += 1;
125
+ else if (receipt.status === 'already')
126
+ already += 1;
127
+ else {
128
+ refused += 1;
129
+ reasonCounts[receipt.reason] = (reasonCounts[receipt.reason] ?? 0) + 1;
130
+ deps.log?.('fork-reconcile: ' + child.sessionId + ' refused: ' + receipt.reason + (receipt.detail !== undefined ? ' ' + receipt.detail : ''));
131
+ }
132
+ if (receipts.length < FORK_RECONCILE_RECEIPT_LIMIT)
133
+ receipts.push(receipt);
134
+ else
135
+ truncated = true;
136
+ }
137
+ return {
138
+ ok: true,
139
+ scanned: listed.length,
140
+ candidates: attempted.length,
141
+ attached,
142
+ already,
143
+ refused,
144
+ reasonCounts,
145
+ skipped: { subagent: skippedSubagent },
146
+ receipts,
147
+ receiptsTruncated: truncated,
148
+ };
149
+ }
150
+ //# sourceMappingURL=fork-reconcile.js.map