@logictan/dsh-config-manager 0.1.60

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 (429) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/cordis.patch.yml +21 -0
  4. package/lib/adapters/agent-instructions.d.ts +13 -0
  5. package/lib/adapters/agent-instructions.js +46 -0
  6. package/lib/adapters/agent-presets.d.ts +13 -0
  7. package/lib/adapters/agent-presets.js +14 -0
  8. package/lib/adapters/credentials.d.ts +37 -0
  9. package/lib/adapters/credentials.js +122 -0
  10. package/lib/adapters/file-collection.d.ts +15 -0
  11. package/lib/adapters/file-collection.js +127 -0
  12. package/lib/adapters/index.d.ts +57 -0
  13. package/lib/adapters/index.js +55 -0
  14. package/lib/adapters/link-report.d.ts +16 -0
  15. package/lib/adapters/link-report.js +47 -0
  16. package/lib/adapters/mcp.d.ts +28 -0
  17. package/lib/adapters/mcp.js +178 -0
  18. package/lib/adapters/plugin-files.d.ts +18 -0
  19. package/lib/adapters/plugin-files.js +142 -0
  20. package/lib/adapters/plugins.d.ts +41 -0
  21. package/lib/adapters/plugins.js +603 -0
  22. package/lib/adapters/pnpm-workspace.d.ts +26 -0
  23. package/lib/adapters/pnpm-workspace.js +147 -0
  24. package/lib/adapters/prompts.d.ts +30 -0
  25. package/lib/adapters/prompts.js +231 -0
  26. package/lib/adapters/providers.d.ts +34 -0
  27. package/lib/adapters/providers.js +155 -0
  28. package/lib/adapters/self.d.ts +17 -0
  29. package/lib/adapters/self.js +71 -0
  30. package/lib/adapters/sessions.d.ts +14 -0
  31. package/lib/adapters/sessions.js +15 -0
  32. package/lib/adapters/settings.d.ts +28 -0
  33. package/lib/adapters/settings.js +165 -0
  34. package/lib/adapters/skills.d.ts +13 -0
  35. package/lib/adapters/skills.js +14 -0
  36. package/lib/adapters/test-helpers.d.ts +125 -0
  37. package/lib/adapters/test-helpers.js +236 -0
  38. package/lib/adapters/ui.d.ts +27 -0
  39. package/lib/adapters/ui.js +89 -0
  40. package/lib/adapters/workspaces.d.ts +13 -0
  41. package/lib/adapters/workspaces.js +106 -0
  42. package/lib/client.d.ts +1026 -0
  43. package/lib/client.js +10047 -0
  44. package/lib/core/analyzer.d.ts +99 -0
  45. package/lib/core/analyzer.js +934 -0
  46. package/lib/core/backup.d.ts +138 -0
  47. package/lib/core/backup.js +513 -0
  48. package/lib/core/boot-rescue.d.ts +146 -0
  49. package/lib/core/boot-rescue.js +618 -0
  50. package/lib/core/cache-cleaner.d.ts +31 -0
  51. package/lib/core/cache-cleaner.js +95 -0
  52. package/lib/core/config-lifecycle.d.ts +180 -0
  53. package/lib/core/config-lifecycle.js +481 -0
  54. package/lib/core/config-snapshot.d.ts +135 -0
  55. package/lib/core/config-snapshot.js +424 -0
  56. package/lib/core/config-state.d.ts +70 -0
  57. package/lib/core/config-state.js +177 -0
  58. package/lib/core/consult-source.d.ts +58 -0
  59. package/lib/core/consult-source.js +260 -0
  60. package/lib/core/crash-report.d.ts +84 -0
  61. package/lib/core/crash-report.js +317 -0
  62. package/lib/core/exporter.d.ts +68 -0
  63. package/lib/core/exporter.js +375 -0
  64. package/lib/core/ghost-sweep.d.ts +19 -0
  65. package/lib/core/ghost-sweep.js +52 -0
  66. package/lib/core/importer.d.ts +60 -0
  67. package/lib/core/importer.js +29 -0
  68. package/lib/core/index.d.ts +14 -0
  69. package/lib/core/index.js +14 -0
  70. package/lib/core/journal.d.ts +197 -0
  71. package/lib/core/journal.js +418 -0
  72. package/lib/core/local-plugin-host.d.ts +35 -0
  73. package/lib/core/local-plugin-host.js +120 -0
  74. package/lib/core/local-plugin-pack.d.ts +135 -0
  75. package/lib/core/local-plugin-pack.js +278 -0
  76. package/lib/core/messages.d.ts +310 -0
  77. package/lib/core/messages.js +621 -0
  78. package/lib/core/migration-consult.d.ts +117 -0
  79. package/lib/core/migration-consult.js +363 -0
  80. package/lib/core/migration-history.d.ts +153 -0
  81. package/lib/core/migration-history.js +411 -0
  82. package/lib/core/model-tools.d.ts +50 -0
  83. package/lib/core/model-tools.js +148 -0
  84. package/lib/core/msg-types.d.ts +8 -0
  85. package/lib/core/msg-types.js +6 -0
  86. package/lib/core/phase3-child-crash.d.ts +1 -0
  87. package/lib/core/phase3-child-crash.js +87 -0
  88. package/lib/core/phase3-host.d.ts +138 -0
  89. package/lib/core/phase3-host.js +359 -0
  90. package/lib/core/phase3-prod-child.d.ts +1 -0
  91. package/lib/core/phase3-prod-child.js +35 -0
  92. package/lib/core/phase4-crash-child.d.ts +1 -0
  93. package/lib/core/phase4-crash-child.js +103 -0
  94. package/lib/core/plugin-cli.d.ts +150 -0
  95. package/lib/core/plugin-cli.js +497 -0
  96. package/lib/core/reconcile.d.ts +120 -0
  97. package/lib/core/reconcile.js +389 -0
  98. package/lib/core/recovery-orchestrator.d.ts +94 -0
  99. package/lib/core/recovery-orchestrator.js +327 -0
  100. package/lib/core/restore.d.ts +162 -0
  101. package/lib/core/restore.js +703 -0
  102. package/lib/core/rollback.d.ts +12 -0
  103. package/lib/core/rollback.js +145 -0
  104. package/lib/core/run-registry.d.ts +85 -0
  105. package/lib/core/run-registry.js +157 -0
  106. package/lib/core/startup-barrier.d.ts +53 -0
  107. package/lib/core/startup-barrier.js +77 -0
  108. package/lib/core/types.d.ts +515 -0
  109. package/lib/core/types.js +27 -0
  110. package/lib/core/undo.d.ts +73 -0
  111. package/lib/core/undo.js +87 -0
  112. package/lib/core/validator.d.ts +18 -0
  113. package/lib/core/validator.js +77 -0
  114. package/lib/core/verify-recovery.d.ts +21 -0
  115. package/lib/core/verify-recovery.js +256 -0
  116. package/lib/core/watcher.d.ts +101 -0
  117. package/lib/core/watcher.js +219 -0
  118. package/lib/index.d.ts +238 -0
  119. package/lib/index.js +2764 -0
  120. package/lib/migrations/index.d.ts +29 -0
  121. package/lib/migrations/index.js +56 -0
  122. package/lib/migrations/v1-to-v2.d.ts +9 -0
  123. package/lib/migrations/v1-to-v2.js +10 -0
  124. package/lib/profiles/index.d.ts +4 -0
  125. package/lib/profiles/index.js +5 -0
  126. package/lib/profiles/profile-manager.d.ts +106 -0
  127. package/lib/profiles/profile-manager.js +543 -0
  128. package/lib/schema/config.d.ts +28 -0
  129. package/lib/schema/config.js +165 -0
  130. package/lib/schema/index.d.ts +24 -0
  131. package/lib/schema/index.js +26 -0
  132. package/lib/schema/manifest.d.ts +28 -0
  133. package/lib/schema/manifest.js +109 -0
  134. package/lib/schema/tombstones.d.ts +46 -0
  135. package/lib/schema/tombstones.js +64 -0
  136. package/lib/schema/types.d.ts +232 -0
  137. package/lib/schema/types.js +8 -0
  138. package/lib/schema/versions.d.ts +27 -0
  139. package/lib/schema/versions.js +50 -0
  140. package/lib/security/encryption.d.ts +85 -0
  141. package/lib/security/encryption.js +279 -0
  142. package/lib/security/index.d.ts +16 -0
  143. package/lib/security/index.js +17 -0
  144. package/lib/security/integrity.d.ts +30 -0
  145. package/lib/security/integrity.js +78 -0
  146. package/lib/security/redaction.d.ts +26 -0
  147. package/lib/security/redaction.js +95 -0
  148. package/lib/security/secret-scanner.d.ts +86 -0
  149. package/lib/security/secret-scanner.js +404 -0
  150. package/lib/security/vault.d.ts +59 -0
  151. package/lib/security/vault.js +151 -0
  152. package/lib/security/zip-security.d.ts +27 -0
  153. package/lib/security/zip-security.js +154 -0
  154. package/lib/sync/autosync-config.d.ts +39 -0
  155. package/lib/sync/autosync-config.js +151 -0
  156. package/lib/sync/autosync-scheduler.d.ts +139 -0
  157. package/lib/sync/autosync-scheduler.js +564 -0
  158. package/lib/sync/fs.d.ts +18 -0
  159. package/lib/sync/fs.js +49 -0
  160. package/lib/sync/git/git-transport.d.ts +100 -0
  161. package/lib/sync/git/git-transport.js +437 -0
  162. package/lib/sync/github-auth.d.ts +131 -0
  163. package/lib/sync/github-auth.js +264 -0
  164. package/lib/sync/layout.d.ts +43 -0
  165. package/lib/sync/layout.js +203 -0
  166. package/lib/sync/snapshot-json.d.ts +9 -0
  167. package/lib/sync/snapshot-json.js +107 -0
  168. package/lib/sync/sync-config.d.ts +81 -0
  169. package/lib/sync/sync-config.js +281 -0
  170. package/lib/sync/sync-engine.d.ts +269 -0
  171. package/lib/sync/sync-engine.js +591 -0
  172. package/lib/sync/sync-history.d.ts +42 -0
  173. package/lib/sync/sync-history.js +78 -0
  174. package/lib/sync/sync-selection.d.ts +29 -0
  175. package/lib/sync/sync-selection.js +127 -0
  176. package/lib/sync/sync-session.d.ts +40 -0
  177. package/lib/sync/sync-session.js +54 -0
  178. package/lib/sync/sync-state.d.ts +37 -0
  179. package/lib/sync/sync-state.js +108 -0
  180. package/lib/sync/transport.d.ts +75 -0
  181. package/lib/sync/transport.js +55 -0
  182. package/lib/sync/ui-prefs.d.ts +34 -0
  183. package/lib/sync/ui-prefs.js +109 -0
  184. package/lib/sync/webdav/webdav-transport.d.ts +77 -0
  185. package/lib/sync/webdav/webdav-transport.js +451 -0
  186. package/lib/ui/errors.d.ts +19 -0
  187. package/lib/ui/errors.js +81 -0
  188. package/lib/ui/export-flow.d.ts +82 -0
  189. package/lib/ui/export-flow.js +98 -0
  190. package/lib/ui/i18n.d.ts +289 -0
  191. package/lib/ui/i18n.js +581 -0
  192. package/lib/ui/migration-consult-view.d.ts +91 -0
  193. package/lib/ui/migration-consult-view.js +115 -0
  194. package/lib/ui/progress.d.ts +38 -0
  195. package/lib/ui/progress.js +87 -0
  196. package/lib/ui/report.d.ts +23 -0
  197. package/lib/ui/report.js +153 -0
  198. package/lib/ui/test-helpers.d.ts +69 -0
  199. package/lib/ui/test-helpers.js +154 -0
  200. package/lib/ui/types.d.ts +257 -0
  201. package/lib/ui/types.js +21 -0
  202. package/lib/utils/atomic-write.d.ts +88 -0
  203. package/lib/utils/atomic-write.js +399 -0
  204. package/lib/utils/env-lock.d.ts +393 -0
  205. package/lib/utils/env-lock.js +930 -0
  206. package/lib/utils/hashing.d.ts +17 -0
  207. package/lib/utils/hashing.js +41 -0
  208. package/lib/utils/json.d.ts +24 -0
  209. package/lib/utils/json.js +76 -0
  210. package/lib/utils/logger.d.ts +39 -0
  211. package/lib/utils/logger.js +82 -0
  212. package/lib/utils/paths.d.ts +42 -0
  213. package/lib/utils/paths.js +189 -0
  214. package/lib/utils/proxy.d.ts +69 -0
  215. package/lib/utils/proxy.js +455 -0
  216. package/lib/utils/recursive-walk.d.ts +24 -0
  217. package/lib/utils/recursive-walk.js +134 -0
  218. package/lib/utils/zip.d.ts +54 -0
  219. package/lib/utils/zip.js +285 -0
  220. package/package.json +188 -0
  221. package/src/adapters/agent-instructions.ts +48 -0
  222. package/src/adapters/agent-presets.ts +14 -0
  223. package/src/adapters/credentials.test.ts +90 -0
  224. package/src/adapters/credentials.ts +143 -0
  225. package/src/adapters/file-collection.ts +137 -0
  226. package/src/adapters/files.test.ts +353 -0
  227. package/src/adapters/index.ts +94 -0
  228. package/src/adapters/link-report.test.ts +65 -0
  229. package/src/adapters/link-report.ts +61 -0
  230. package/src/adapters/mcp.test.ts +96 -0
  231. package/src/adapters/mcp.ts +185 -0
  232. package/src/adapters/plugin-files.ts +146 -0
  233. package/src/adapters/plugins.test.ts +326 -0
  234. package/src/adapters/plugins.ts +615 -0
  235. package/src/adapters/pnpm-workspace.test.ts +87 -0
  236. package/src/adapters/pnpm-workspace.ts +150 -0
  237. package/src/adapters/prompts.test.ts +110 -0
  238. package/src/adapters/prompts.ts +230 -0
  239. package/src/adapters/providers.test.ts +126 -0
  240. package/src/adapters/providers.ts +173 -0
  241. package/src/adapters/roundtrip.test.ts +190 -0
  242. package/src/adapters/self.test.ts +92 -0
  243. package/src/adapters/self.ts +75 -0
  244. package/src/adapters/sessions.ts +15 -0
  245. package/src/adapters/settings.test.ts +100 -0
  246. package/src/adapters/settings.ts +187 -0
  247. package/src/adapters/skills.ts +14 -0
  248. package/src/adapters/test-helpers.ts +248 -0
  249. package/src/adapters/ui.test.ts +57 -0
  250. package/src/adapters/ui.ts +108 -0
  251. package/src/adapters/workspaces.test.ts +106 -0
  252. package/src/adapters/workspaces.ts +109 -0
  253. package/src/client/ConfigManagerSection.tsx +90 -0
  254. package/src/client/api.ts +66 -0
  255. package/src/client/client-types.ts +18 -0
  256. package/src/client/common/ErrorBanner.tsx +73 -0
  257. package/src/client/common/Icon.tsx +129 -0
  258. package/src/client/common/Modal.tsx +173 -0
  259. package/src/client/common/ToastViewport.tsx +73 -0
  260. package/src/client/common/toast-store.test.ts +192 -0
  261. package/src/client/common/toast-store.ts +181 -0
  262. package/src/client/common/toast-types.ts +7 -0
  263. package/src/client/common/ui.tsx +342 -0
  264. package/src/client/config-manager.module.css +2971 -0
  265. package/src/client/css-modules.d.ts +8 -0
  266. package/src/client/index.ts +65 -0
  267. package/src/client/locales.ts +56 -0
  268. package/src/client/lucide-icons.d.ts +38 -0
  269. package/src/client/run-store.test.ts +223 -0
  270. package/src/client/run-store.ts +372 -0
  271. package/src/client/sync/SyncConfirmView.tsx +379 -0
  272. package/src/client/sync/SyncHistoryView.test.ts +40 -0
  273. package/src/client/sync/SyncHistoryView.tsx +220 -0
  274. package/src/client/sync/SyncSettingsView.tsx +1535 -0
  275. package/src/client/sync/history-model.test.ts +194 -0
  276. package/src/client/sync/history-model.ts +195 -0
  277. package/src/client/sync/sync-api.test.ts +585 -0
  278. package/src/client/sync/sync-api.ts +543 -0
  279. package/src/client/sync/sync-locales.ts +416 -0
  280. package/src/client/sync/sync-push-preview.test.ts +52 -0
  281. package/src/client/sync/sync-view-v2.test.ts +213 -0
  282. package/src/client/sync/sync-view.test.ts +487 -0
  283. package/src/client/sync/sync-view.ts +759 -0
  284. package/src/core/analyzer.ts +1068 -0
  285. package/src/core/backup.ts +605 -0
  286. package/src/core/boot-rescue.test.ts +847 -0
  287. package/src/core/boot-rescue.ts +737 -0
  288. package/src/core/cache-cleaner.test.ts +169 -0
  289. package/src/core/cache-cleaner.ts +121 -0
  290. package/src/core/config-lifecycle.test.ts +727 -0
  291. package/src/core/config-lifecycle.ts +573 -0
  292. package/src/core/config-snapshot.test.ts +369 -0
  293. package/src/core/config-snapshot.ts +522 -0
  294. package/src/core/config-state.test.ts +381 -0
  295. package/src/core/config-state.ts +207 -0
  296. package/src/core/consult-source.test.ts +199 -0
  297. package/src/core/consult-source.ts +293 -0
  298. package/src/core/crash-report.test.ts +380 -0
  299. package/src/core/crash-report.ts +369 -0
  300. package/src/core/exporter.ts +417 -0
  301. package/src/core/ghost-sweep.test.ts +94 -0
  302. package/src/core/ghost-sweep.ts +67 -0
  303. package/src/core/importer.ts +83 -0
  304. package/src/core/index.ts +56 -0
  305. package/src/core/journal.test.ts +257 -0
  306. package/src/core/journal.ts +518 -0
  307. package/src/core/local-plugin-host.ts +152 -0
  308. package/src/core/local-plugin-pack.test.ts +359 -0
  309. package/src/core/local-plugin-pack.ts +363 -0
  310. package/src/core/messages.test.ts +54 -0
  311. package/src/core/messages.ts +664 -0
  312. package/src/core/migration-consult.test.ts +315 -0
  313. package/src/core/migration-consult.ts +494 -0
  314. package/src/core/migration-history.test.ts +319 -0
  315. package/src/core/migration-history.ts +484 -0
  316. package/src/core/model-tools.test.ts +190 -0
  317. package/src/core/model-tools.ts +208 -0
  318. package/src/core/msg-types.ts +10 -0
  319. package/src/core/phase3-child-crash.ts +95 -0
  320. package/src/core/phase3-host.ts +411 -0
  321. package/src/core/phase3-p1.test.ts +212 -0
  322. package/src/core/phase3-p2b-fingerprint.test.ts +189 -0
  323. package/src/core/phase3-prod-child.ts +36 -0
  324. package/src/core/phase3-production-integration.test.ts +286 -0
  325. package/src/core/phase4-crash-child.ts +101 -0
  326. package/src/core/phase4-crash-injection.test.ts +166 -0
  327. package/src/core/plugin-cli.fs.test.ts +184 -0
  328. package/src/core/plugin-cli.test.ts +137 -0
  329. package/src/core/plugin-cli.ts +563 -0
  330. package/src/core/reconcile.test.ts +392 -0
  331. package/src/core/reconcile.ts +498 -0
  332. package/src/core/recovery-orchestrator.test.ts +145 -0
  333. package/src/core/recovery-orchestrator.ts +366 -0
  334. package/src/core/restore-manage.test.ts +94 -0
  335. package/src/core/restore.ts +849 -0
  336. package/src/core/rollback.ts +151 -0
  337. package/src/core/run-progress.test.ts +237 -0
  338. package/src/core/run-registry.test.ts +232 -0
  339. package/src/core/run-registry.ts +209 -0
  340. package/src/core/smoke.test.ts +842 -0
  341. package/src/core/startup-barrier.ts +99 -0
  342. package/src/core/types.ts +542 -0
  343. package/src/core/undo.ts +116 -0
  344. package/src/core/validator.ts +84 -0
  345. package/src/core/verify-recovery.ts +265 -0
  346. package/src/core/watcher.test.ts +326 -0
  347. package/src/core/watcher.ts +263 -0
  348. package/src/index.facade.test.ts +265 -0
  349. package/src/index.sync.test.ts +217 -0
  350. package/src/index.ts +2975 -0
  351. package/src/migrations/index.ts +71 -0
  352. package/src/migrations/v1-to-v2.ts +17 -0
  353. package/src/profiles/index.ts +8 -0
  354. package/src/profiles/profile-manager.test.ts +282 -0
  355. package/src/profiles/profile-manager.ts +630 -0
  356. package/src/schema/config.ts +165 -0
  357. package/src/schema/index.ts +71 -0
  358. package/src/schema/manifest-schema.test.ts +519 -0
  359. package/src/schema/manifest.ts +124 -0
  360. package/src/schema/tombstones.test.ts +131 -0
  361. package/src/schema/tombstones.ts +89 -0
  362. package/src/schema/types.ts +245 -0
  363. package/src/schema/versions.ts +55 -0
  364. package/src/security/encryption.ts +335 -0
  365. package/src/security/index.ts +16 -0
  366. package/src/security/integrity.ts +102 -0
  367. package/src/security/redaction.ts +101 -0
  368. package/src/security/secret-scanner.ts +445 -0
  369. package/src/security/security.test.ts +1215 -0
  370. package/src/security/vault.test.ts +164 -0
  371. package/src/security/vault.ts +198 -0
  372. package/src/security/zip-security.ts +180 -0
  373. package/src/sync/autosync-config.test.ts +147 -0
  374. package/src/sync/autosync-config.ts +179 -0
  375. package/src/sync/autosync-scheduler.test.ts +490 -0
  376. package/src/sync/autosync-scheduler.ts +646 -0
  377. package/src/sync/fs.ts +48 -0
  378. package/src/sync/git/git-transport.test.ts +673 -0
  379. package/src/sync/git/git-transport.ts +491 -0
  380. package/src/sync/github-auth.test.ts +280 -0
  381. package/src/sync/github-auth.ts +356 -0
  382. package/src/sync/layout.test.ts +270 -0
  383. package/src/sync/layout.ts +222 -0
  384. package/src/sync/snapshot-json.test.ts +119 -0
  385. package/src/sync/snapshot-json.ts +128 -0
  386. package/src/sync/sync-config.test.ts +310 -0
  387. package/src/sync/sync-config.ts +299 -0
  388. package/src/sync/sync-engine.test.ts +1074 -0
  389. package/src/sync/sync-engine.ts +754 -0
  390. package/src/sync/sync-history.test.ts +116 -0
  391. package/src/sync/sync-history.ts +120 -0
  392. package/src/sync/sync-selection.test.ts +186 -0
  393. package/src/sync/sync-selection.ts +143 -0
  394. package/src/sync/sync-session.test.ts +143 -0
  395. package/src/sync/sync-session.ts +77 -0
  396. package/src/sync/sync-state.test.ts +164 -0
  397. package/src/sync/sync-state.ts +131 -0
  398. package/src/sync/transport.test.ts +111 -0
  399. package/src/sync/transport.ts +118 -0
  400. package/src/sync/ui-prefs.test.ts +152 -0
  401. package/src/sync/ui-prefs.ts +135 -0
  402. package/src/sync/webdav/webdav-transport.test.ts +871 -0
  403. package/src/sync/webdav/webdav-transport.ts +535 -0
  404. package/src/ui/errors.test.ts +47 -0
  405. package/src/ui/errors.ts +100 -0
  406. package/src/ui/export-flow.test.ts +87 -0
  407. package/src/ui/export-flow.ts +156 -0
  408. package/src/ui/i18n.ts +590 -0
  409. package/src/ui/migration-consult-view.test.ts +151 -0
  410. package/src/ui/migration-consult-view.ts +178 -0
  411. package/src/ui/progress.test.ts +47 -0
  412. package/src/ui/progress.ts +102 -0
  413. package/src/ui/report.test.ts +101 -0
  414. package/src/ui/report.ts +146 -0
  415. package/src/ui/test-helpers.ts +184 -0
  416. package/src/ui/types.ts +325 -0
  417. package/src/utils/atomic-write.test.ts +312 -0
  418. package/src/utils/atomic-write.ts +422 -0
  419. package/src/utils/env-lock.test.ts +999 -0
  420. package/src/utils/env-lock.ts +1086 -0
  421. package/src/utils/hashing.ts +53 -0
  422. package/src/utils/json.ts +77 -0
  423. package/src/utils/logger.ts +114 -0
  424. package/src/utils/paths.ts +176 -0
  425. package/src/utils/proxy.test.ts +465 -0
  426. package/src/utils/proxy.ts +493 -0
  427. package/src/utils/recursive-walk.test.ts +148 -0
  428. package/src/utils/recursive-walk.ts +145 -0
  429. package/src/utils/zip.ts +332 -0
@@ -0,0 +1,416 @@
1
+ /**
2
+ * 远程同步设置区块(config-manager-sync)表面文案:zh 为源语言,en 镜像每个键。
3
+ * 独立命名空间、独立文件:不触碰共享的 locales.ts(并行会话已改),零冲突。
4
+ * 键集合经 `SyncKey` 类型在 client/index.ts 注册处做编译期校验。
5
+ */
6
+
7
+ export const zh = {
8
+ // 入口
9
+ 'section.label': '远程同步',
10
+ 'section.description': '通过私有 Git / WebDAV 通道在设备间同步 DSH 配置(明文,私有通道自用)',
11
+ // 私有仓库强制提示(常驻警示横幅)
12
+ 'privateRepoHint': '安全要求:同步仓库必须为私有仓库(public 仓库会公开你的配置内容)。认证 token 仅用于仓库访问,绝不写入同步文件、提交内容或日志。',
13
+ // 仓库配置表单
14
+ 'config.title': '仓库配置',
15
+ 'config.repoUrl': '仓库地址',
16
+ 'config.repoUrlHint': 'Git 私有仓库地址(https / ssh / 本地路径)。认证 token 请使用下方凭据字段,不要拼入地址。',
17
+ 'config.token': '认证 token',
18
+ 'config.tokenHint': '将安全写入 DSH credentials(引用名 {ref}),不会写入同步文件或日志。留空表示沿用已保存的凭据。',
19
+ 'config.tokenSaved': '凭据已配置',
20
+ 'config.tokenPlaceholder': 'ghp_…(可选)',
21
+ // 配置保存(自动保存 + 显式保存按钮)
22
+ 'config.save': '保存配置',
23
+ 'config.saving': '保存中…',
24
+ 'config.saveHint': '表单改动会自动保存(密码/token 安全写入 DSH credentials,不会写入同步文件或日志);也可点击按钮立即保存。',
25
+ // 通道选择器
26
+ 'channel.title': '同步通道',
27
+ 'channel.git': 'Git 私有仓库',
28
+ 'channel.webdav': 'WebDAV 服务器',
29
+ 'channel.perChannelHint': 'GitHub 与 WebDAV 通道的自动同步、同步模式与远端快照各自独立配置。',
30
+ // 通道入口卡(弹窗驱动:点按钮 → 弹窗内配置通道)
31
+ 'channel.open': '配置同步通道',
32
+ 'channel.openHint': '远程同步通过「同步通道」进行:Git 私有仓库或 WebDAV 服务器。点击按钮在弹窗中配置或修改。',
33
+ 'channel.configured': '已配置',
34
+ 'channel.notConfigured': '未配置',
35
+ 'channel.currentUrl': '当前地址',
36
+ 'syncStatus.lastSync': '上次同步',
37
+ 'syncStatus.sections': '可同步分区',
38
+ 'syncStatus.state': '配置状态',
39
+ // WebDAV 配置表单
40
+ 'webdav.title': 'WebDAV 配置',
41
+ 'webdav.url': '服务器地址',
42
+ 'webdav.urlHint': 'WebDAV 服务器根地址(https://…)。同步快照与索引存放于该地址的 dsh-config-manager/ 子目录下。请勿在地址中包含用户名/密码。',
43
+ 'webdav.username': '用户名',
44
+ 'webdav.usernameHint': 'HTTP Basic 认证用户名(非敏感,可回显)。',
45
+ 'webdav.password': '密码',
46
+ 'webdav.passwordHint': '将安全写入 DSH credentials(引用名 {ref}),不会写入同步文件或日志。留空表示沿用已保存的凭据。',
47
+ 'webdav.passwordSaved': '凭据已配置',
48
+ 'webdav.passwordPlaceholder': '密码(可选)',
49
+ 'webdav.presetHint': '选择常见 WebDAV 服务器可快速填入地址;含 <占位符> 的模板请替换为你的真实服务器/用户名。',
50
+ // GitHub OAuth 登录(device flow,无需手动输入 token)
51
+ 'github.title': 'GitHub 登录',
52
+ 'github.description': '通过 GitHub OAuth 设备码流程授权:无需手动输入 token,在浏览器中确认授权后,token 自动写入 DSH credentials。',
53
+ 'github.login': '使用 GitHub 登录',
54
+ 'github.retry': '重新登录',
55
+ 'github.cancel': '取消',
56
+ 'github.tokenInvalid': 'GitHub 登录已失效,请重新登录。',
57
+ 'github.userCode': '一次性授权代码',
58
+ 'github.openAuth': '打开 GitHub 授权页面',
59
+ 'github.clientIdHint': '需要插件配置 githubClientId(GitHub OAuth App 的 client_id)才能使用 GitHub 登录。',
60
+ // 状态
61
+ 'status.title': '同步状态',
62
+ 'status.never': '从未同步',
63
+ // 操作
64
+ 'action.push': '推送到远端',
65
+ 'action.pull': '拉取差异预览',
66
+ 'action.pushing': '正在推送…',
67
+ 'action.pulling': '正在拉取…',
68
+ // 报告
69
+ 'push.title': '推送结果',
70
+ 'pull.title': '拉取差异预览',
71
+ 'pull.previewHint': '以上为只读差异预览,不会执行导入。当前版本暂不支持一键导入;如需应用远端配置,请使用「导入恢复」向导手动导入导出的备份。',
72
+ 'pull.needsReview': '包含需要人工决策的项(冲突 / 密钥 / 依赖 / 安装)',
73
+ 'pull.empty': '远端快照与本地一致(无变更)',
74
+ 'change.total': '共 {total} 项变更',
75
+ 'sections.title': '同步分区',
76
+ 'warnings.title': '分区告警',
77
+ // 一键同步(方案 A:拉取 → 逐项确认 → apply-items)
78
+ 'syncflow.title': '一键同步',
79
+ 'syncflow.button': '一键同步',
80
+ 'syncflow.syncing': '正在同步…',
81
+ 'syncflow.syncFailed': '同步失败',
82
+ 'syncflow.snapshotOption': '({date} · {count} 分区)',
83
+ 'syncflow.selectSnapshot': '选择历史快照',
84
+ 'syncflow.refreshSnapshots': '刷新快照列表',
85
+ 'syncflow.refreshingSnapshots': '正在获取…',
86
+ 'syncflow.latestSnapshot': '最新快照',
87
+ 'syncflow.noSnapshots': '远端暂无快照',
88
+ 'syncflow.confirmImport': '确认导入',
89
+ 'syncflow.cancel': '取消',
90
+ 'syncflow.adoptRemote': '采用远端',
91
+ 'syncflow.adoptHint': '勾选 = 导入该项;取消 = 跳过',
92
+ 'syncflow.needsReviewBadge': '需人工决策',
93
+ 'syncflow.empty': '远端快照与本地一致(无变更)',
94
+ 'syncflow.diffCount': '共 {count} 项差异',
95
+ 'syncflow.keepLocalAll': '全部保留当前配置',
96
+ 'syncflow.useRemoteAll': '全部使用备份配置',
97
+ 'syncflow.bulkHint': '批量决策仅作用于冲突项;其余差异默认自动采用。',
98
+ 'syncflow.conflictTitle': '冲突解决',
99
+ 'syncflow.conflictUseLocal': '保留当前',
100
+ 'syncflow.conflictUseRemote': '使用备份',
101
+ 'syncflow.conflictLocalLabel': '当前',
102
+ 'syncflow.conflictRemoteLabel': '备份',
103
+ 'syncflow.conflictAncestorLabel': '共同祖先',
104
+ 'syncflow.conflictUnresolved': '冲突项 {itemId} 尚未选择解决方式(保留当前 / 使用备份)',
105
+ 'syncflow.diff': '差异',
106
+ 'syncflow.importDone': '已导入 {n} 个分区',
107
+ 'syncflow.importFailed': '导入失败(已整体回滚)',
108
+ 'syncflow.importedSections': '已写入',
109
+ 'syncflow.importWarnings': '导入告警',
110
+ 'syncflow.rollback': '回滚到应用前',
111
+ 'syncflow.rollingBack': '正在回滚…',
112
+ 'syncflow.rollbackDone': '已回滚到应用前',
113
+ 'syncflow.needsRestart': '部分改动需要重启 DSH 后生效',
114
+ // P0-②:push 前只读预览确认弹窗
115
+ 'syncflow.pushPreviewTitle': '确认推送',
116
+ 'syncflow.pushPreviewSections': '将推送的分区',
117
+ 'syncflow.pushConfirm': '确认推送',
118
+ 'syncflow.pushing': '正在推送…',
119
+ 'syncflow.pushFirstBaseline': '远端暂无快照:本次将创建首个同步基线',
120
+ // 同步模式(默认快速导出 / 高级自定义导出)
121
+ 'mode.title': '同步模式',
122
+ 'mode.hint': '选择推送时导出哪些分区:默认 = 推荐分区一键推送(快速导出);高级 = 自定义勾选(自定义导出)。',
123
+ 'mode.default': '默认(快速导出)',
124
+ 'mode.defaultHint': '一键推送全部推荐分区(settings、providers、plugins、prompts、skills 等),无需配置。',
125
+ 'mode.advanced': '高级(自定义导出)',
126
+ 'mode.advancedHint': '手动勾选要推送的分区;未勾选任何分区时回退为全部推荐分区。',
127
+ 'mode.sectionsTitle': '同步分区',
128
+ 'mode.sectionsHint': '所有分区都可勾选同步(标「推荐」的默认勾选);快照为明文,仅同步到你自己配置的私有通道。',
129
+ 'mode.atLeastOne': '请至少勾选一个同步分区',
130
+ 'mode.defaultCount': '将同步 {n} 个推荐分区',
131
+ 'mode.sectionRecommended': '推荐',
132
+ 'mode.persistHint': '模式与分区选择已保存到本机:自动同步和手动推送都会使用此配置(重启后仍生效)。',
133
+ // 自动同步(方案 A)
134
+ 'autosync.title': '自动同步',
135
+ 'autosync.description': '开启后,DSH 在后台保持配置一致:本地配置有改动时自动上传,检测到远端有新快照时才自动拉取覆盖;定时器仅作兜底轮询,无变化不重复动作。仅在无冲突且无需人工干预时才自动写入本地。',
136
+ 'autosync.enable': '启用自动同步',
137
+ 'autosync.interval': '兜底轮询间隔',
138
+ 'autosync.intervalHint': '间隔到点 / DSH 启动时检查远端是否有新快照,有才拉取覆盖(不上传本地);本地配置改动会触发上传。',
139
+ 'autosync.interval5m': '5 分钟',
140
+ 'autosync.interval15m': '15 分钟',
141
+ 'autosync.interval30m': '30 分钟',
142
+ 'autosync.interval60m': '60 分钟',
143
+ 'autosync.interval6h': '6 小时',
144
+ 'autosync.interval12h': '12 小时',
145
+ 'autosync.interval24h': '24 小时',
146
+ 'autosync.status': '上次运行:{status}({time})',
147
+ 'autosync.statusNever': '从未运行',
148
+ 'autosync.nextRun': '下次约 {time} 后',
149
+ 'autosync.due': '已到同步时间,即将执行',
150
+ 'autosync.failCount': '连续失败 {n} 次',
151
+ 'autosync.running': '自动同步进行中…',
152
+ 'autosync.success': '成功',
153
+ 'autosync.skipped': '已跳过',
154
+ 'autosync.failed': '失败',
155
+ 'autosync.partial': '部分成功',
156
+ // 同步历史(含自动同步记录)
157
+ 'history.title': '同步历史',
158
+ 'history.empty': '尚无同步历史',
159
+ 'history.emptyHint': '完成首次 push / 一键同步 / 自动同步后,这里会显示记录。',
160
+ 'history.colTime': '时间',
161
+ 'history.colKind': '类型',
162
+ 'history.colDetail': '详情',
163
+ 'history.kindSnapshot': '快照',
164
+ 'history.kindAutosync': '自动同步',
165
+ 'history.sectionCount': '分区',
166
+ 'history.detail': '明细',
167
+ 'history.autosyncDirection': '方向:{direction}',
168
+ 'history.autosyncPull': '下载',
169
+ 'history.autosyncPush': '上传',
170
+ 'history.autosyncBoth': '双向',
171
+ 'history.autosyncSkipReason': '跳过原因:{reason}',
172
+ 'history.autosyncReasonConflict': '冲突',
173
+ 'history.autosyncReasonNoRemote': '无远端快照',
174
+ 'history.autosyncReasonNotConfigured': '未配置仓库',
175
+ 'history.autosyncReasonNetwork': '网络问题',
176
+ 'history.autosyncConflicted': '跳过冲突分区:{sections}',
177
+ 'history.autosyncApplied': '应用分区:{sections}',
178
+ 'history.autosyncError': '错误:{error}',
179
+ 'history.autosyncNotified': '已通知(连续失败 3 次)',
180
+ 'history.column.snapshot': '快照',
181
+ 'history.column.autosync': '自动同步',
182
+ // 触发通道(同步历史「由哪个通道触发」)
183
+ 'history.channelGit': 'GitHub',
184
+ 'history.channelWebdav': 'WebDAV',
185
+ // 列表头部统计摘要(需求 4F)
186
+ 'history.stats.total': '共 {count} 条',
187
+ 'history.stats.snapshots': '快照 {count}',
188
+ 'history.stats.autosync': '自动同步 {count}',
189
+ 'history.stats.failed': '失败 {count}',
190
+ 'history.stats.skipped': '跳过 {count}',
191
+ 'history.stats.summary': '同步历史统计',
192
+ // —— Toast 操作回执(R-20:按动作分文案) ——
193
+ // 原先 10+ 个动作的失败共用同一个 state.error;机械替换成 Toast 后,同 kind+text
194
+ // 会被 store 的去重逻辑合并(互相顶掉),故此处为每个动作单独给出可区分文案。
195
+ 'toast.autosyncLoadFailed': '读取自动同步状态失败',
196
+ 'toast.configSaveFailed': '保存通道配置失败',
197
+ 'toast.configSaved': '通道配置已保存',
198
+ 'toast.configNothingToSave': '请先填写通道地址再保存',
199
+ 'toast.selectionSaveFailed': '同步设置保存失败',
200
+ 'toast.pushPreviewFailed': '推送预览失败',
201
+ 'toast.pushFailed': '推送失败',
202
+ 'toast.pushDone': '推送完成',
203
+ 'toast.pullFailed': '拉取失败',
204
+ 'toast.pullDone': '拉取完成',
205
+ 'toast.syncStartFailed': '一键同步失败',
206
+ 'toast.autosyncUpdateFailed': '自动同步设置更新失败',
207
+ 'toast.autosyncUpdated': '自动同步设置已更新',
208
+ 'toast.snapshotsLoadFailed': '读取远端快照失败',
209
+ 'toast.snapshotsRefreshed': '远端快照列表已刷新',
210
+ // 页面级加载失败(M-16:就地错误态标题;loadError 此前无任何渲染点)
211
+ 'load.failed': '加载同步状态失败',
212
+ // 公共
213
+ 'common.close': '关闭',
214
+ 'common.retry': '重试',
215
+ 'common.loading': '加载中…',
216
+ } as const;
217
+
218
+ export const en: Record<keyof typeof zh, string> = {
219
+ 'section.label': 'Remote Sync',
220
+ 'section.description': 'Sync DSH configuration across devices via a private Git / WebDAV channel (plaintext, for your own private channel)',
221
+ 'privateRepoHint': 'Security requirement: the sync repository MUST be private (a public repo would expose your configuration). The auth token is only used for repository access and is never written into sync files, commit content, or logs.',
222
+ 'config.title': 'Repository',
223
+ 'config.repoUrl': 'Repository URL',
224
+ 'config.repoUrlHint': 'Private Git repository URL (https / ssh / local path). Use the credential field below for the auth token; never embed it in the URL.',
225
+ 'config.token': 'Auth token',
226
+ 'config.tokenHint': 'Securely written into DSH credentials (ref {ref}); never written into sync files or logs. Leave blank to reuse the saved credential.',
227
+ 'config.tokenSaved': 'Credential configured',
228
+ 'config.tokenPlaceholder': 'ghp_… (optional)',
229
+ // Config save (auto-save + explicit save button)
230
+ 'config.save': 'Save config',
231
+ 'config.saving': 'Saving…',
232
+ 'config.saveHint': 'Form changes are saved automatically (password/token written securely into DSH credentials, never into sync files or logs); you can also save explicitly with the button.',
233
+ 'channel.title': 'Sync Channel',
234
+ 'channel.git': 'Git private repo',
235
+ 'channel.webdav': 'WebDAV server',
236
+ 'channel.perChannelHint': 'Auto sync, sync mode and remote snapshots are configured independently for the GitHub and WebDAV channels.',
237
+ // Channel entry card (dialog-driven: click the button → configure the channel in the dialog)
238
+ 'channel.open': 'Configure sync channel',
239
+ 'channel.openHint': 'Remote sync runs through a sync channel: a private Git repository or a WebDAV server. Click the button to configure or change it in the dialog.',
240
+ 'channel.configured': 'Configured',
241
+ 'channel.notConfigured': 'Not configured',
242
+ 'channel.currentUrl': 'Current URL',
243
+ 'syncStatus.lastSync': 'Last sync',
244
+ 'syncStatus.sections': 'Syncable sections',
245
+ 'syncStatus.state': 'State',
246
+ 'webdav.title': 'WebDAV Configuration',
247
+ 'webdav.url': 'Server URL',
248
+ 'webdav.urlHint': 'WebDAV server root URL (https://…). Sync snapshots and the index are stored under a dsh-config-manager/ subdirectory of that URL. Do not include a username/password in the URL.',
249
+ 'webdav.username': 'Username',
250
+ 'webdav.usernameHint': 'HTTP Basic auth username (not sensitive, may be shown).',
251
+ 'webdav.password': 'Password',
252
+ 'webdav.passwordHint': 'Securely written into DSH credentials (ref {ref}); never written into sync files or logs. Leave blank to reuse the saved credential.',
253
+ 'webdav.passwordSaved': 'Credential configured',
254
+ 'webdav.passwordPlaceholder': 'Password (optional)',
255
+ 'webdav.presetHint': 'Pick a common WebDAV server to prefill the URL; templates containing <placeholders> need to be replaced with your real server/username.',
256
+ 'github.title': 'GitHub Sign-in',
257
+ 'github.description': 'Authorize via the GitHub OAuth device flow: no manual token entry — after you approve in the browser, the token is written into DSH credentials automatically.',
258
+ 'github.login': 'Sign in with GitHub',
259
+ 'github.retry': 'Sign in again',
260
+ 'github.cancel': 'Cancel',
261
+ 'github.tokenInvalid': 'GitHub sign-in is no longer valid — please sign in again.',
262
+ 'github.userCode': 'One-time code',
263
+ 'github.openAuth': 'Open GitHub authorization page',
264
+ 'github.clientIdHint': 'Requires the githubClientId plugin config (the client_id of your GitHub OAuth App).',
265
+ 'status.title': 'Sync Status',
266
+ 'status.never': 'Never synced',
267
+ 'action.push': 'Push to remote',
268
+ 'action.pull': 'Pull diff preview',
269
+ 'action.pushing': 'Pushing…',
270
+ 'action.pulling': 'Pulling…',
271
+ 'push.title': 'Push Result',
272
+ 'pull.title': 'Pull Diff Preview',
273
+ 'pull.previewHint': 'Read-only diff preview above; nothing is imported. One-click import is not supported in this version; use the Import wizard to apply a downloaded backup if needed.',
274
+ 'pull.needsReview': 'Contains items that need human decisions (conflicts / secrets / dependencies / installs)',
275
+ 'pull.empty': 'Remote snapshot matches local (no changes)',
276
+ 'change.total': '{total} change(s)',
277
+ 'sections.title': 'Synced Sections',
278
+ 'warnings.title': 'Section Warnings',
279
+ 'syncflow.title': 'One-Click Sync',
280
+ 'syncflow.button': 'One-click sync',
281
+ 'syncflow.syncing': 'Syncing…',
282
+ 'syncflow.syncFailed': 'Sync failed',
283
+ 'syncflow.snapshotOption': '({date} · {count} sections)',
284
+ 'syncflow.selectSnapshot': 'Select snapshot',
285
+ 'syncflow.refreshSnapshots': 'Refresh snapshots',
286
+ 'syncflow.refreshingSnapshots': 'Fetching…',
287
+ 'syncflow.latestSnapshot': 'Latest snapshot',
288
+ 'syncflow.noSnapshots': 'No remote snapshots',
289
+ 'syncflow.confirmImport': 'Confirm import',
290
+ 'syncflow.cancel': 'Cancel',
291
+ 'syncflow.adoptRemote': 'Adopt remote',
292
+ 'syncflow.adoptHint': 'Check = import item; uncheck = skip',
293
+ 'syncflow.needsReviewBadge': 'Needs decision',
294
+ 'syncflow.empty': 'Remote snapshot matches local (no changes)',
295
+ 'syncflow.diffCount': '{count} change(s)',
296
+ 'syncflow.keepLocalAll': 'Keep all current',
297
+ 'syncflow.useRemoteAll': 'Use all backup',
298
+ 'syncflow.bulkHint': 'Bulk decisions only apply to conflict items; other changes are adopted by default.',
299
+ 'syncflow.conflictTitle': 'Resolve conflict',
300
+ 'syncflow.conflictUseLocal': 'Keep current',
301
+ 'syncflow.conflictUseRemote': 'Use backup',
302
+ 'syncflow.conflictLocalLabel': 'Current',
303
+ 'syncflow.conflictRemoteLabel': 'Backup',
304
+ 'syncflow.conflictAncestorLabel': 'Common ancestor',
305
+ 'syncflow.conflictUnresolved': 'Conflict item {itemId} has no resolution yet (keep current / use backup)',
306
+ 'syncflow.diff': 'Diff',
307
+ 'syncflow.importDone': 'Imported {n} section(s)',
308
+ 'syncflow.importFailed': 'Import failed (rolled back)',
309
+ 'syncflow.importedSections': 'Written',
310
+ 'syncflow.importWarnings': 'Import warnings',
311
+ 'syncflow.rollback': 'Rollback',
312
+ 'syncflow.rollingBack': 'Rolling back…',
313
+ 'syncflow.rollbackDone': 'Rolled back',
314
+ 'syncflow.needsRestart': 'Some changes require a DSH restart to take effect',
315
+ // P0-②: push read-only preview confirm dialog
316
+ 'syncflow.pushPreviewTitle': 'Confirm Push',
317
+ 'syncflow.pushPreviewSections': 'Sections to push',
318
+ 'syncflow.pushConfirm': 'Push',
319
+ 'syncflow.pushing': 'Pushing…',
320
+ 'syncflow.pushFirstBaseline': 'No remote snapshots yet: this push creates the first sync baseline',
321
+ // Sync mode (default quick export / advanced custom export)
322
+ 'mode.title': 'Sync Mode',
323
+ 'mode.hint': 'Choose which sections to export when pushing: Default = recommended sections in one click (Quick Export); Advanced = custom selection (Custom Export).',
324
+ 'mode.default': 'Default (Quick Export)',
325
+ 'mode.defaultHint': 'Push all recommended sections (settings, providers, plugins, prompts, skills, etc.) in one click — no configuration needed.',
326
+ 'mode.advanced': 'Advanced (Custom Export)',
327
+ 'mode.advancedHint': 'Manually select the sections to push; with none selected it falls back to all recommended sections.',
328
+ 'mode.sectionsTitle': 'Sync Sections',
329
+ 'mode.sectionsHint': 'Every section can be selected (the ones marked Recommended are on by default); snapshots are plaintext and go only to the private channel you configure.',
330
+ 'mode.atLeastOne': 'Select at least one section to sync',
331
+ 'mode.defaultCount': 'Will sync {n} recommended section(s)',
332
+ 'mode.sectionRecommended': 'Recommended',
333
+ 'mode.persistHint': 'The mode and section selection are saved locally: both auto sync and manual push use this configuration (persists across restarts).',
334
+ // Encryption & secret export (manual push only; auto sync always pushes plain snapshots and skips encrypted ones)
335
+ 'autosync.title': 'Auto Sync',
336
+ 'autosync.description': 'When enabled, DSH keeps config in sync in the background: uploads locally-changed config automatically, pulls and overwrites only when it detects a new remote snapshot; the timer is just a fallback poll and no-ops when nothing changed. Local writes happen only when there are no conflicts or manual-decision items.',
337
+ 'autosync.enable': 'Enable auto sync',
338
+ 'autosync.interval': 'Fallback poll interval',
339
+ 'autosync.intervalHint': 'On interval / DSH startup, checks for a new remote snapshot and pulls+overwrites only if one exists (no upload); local config changes trigger an upload.',
340
+ 'autosync.interval5m': '5 min',
341
+ 'autosync.interval15m': '15 min',
342
+ 'autosync.interval30m': '30 min',
343
+ 'autosync.interval60m': '60 min',
344
+ 'autosync.interval6h': '6 hr',
345
+ 'autosync.interval12h': '12 hr',
346
+ 'autosync.interval24h': '24 hr',
347
+ 'autosync.status': 'Last run: {status} ({time})',
348
+ 'autosync.statusNever': 'Never run',
349
+ 'autosync.nextRun': 'Next in ~{time}',
350
+ 'autosync.due': 'Due — running soon',
351
+ 'autosync.failCount': '{n} consecutive failure(s)',
352
+ 'autosync.running': 'Auto sync running…',
353
+ 'autosync.success': 'Success',
354
+ 'autosync.skipped': 'Skipped',
355
+ 'autosync.failed': 'Failed',
356
+ 'autosync.partial': 'Partial',
357
+ 'history.title': 'Sync History',
358
+ 'history.empty': 'No sync history yet',
359
+ 'history.emptyHint': 'Records appear here after your first push / one-click sync / auto sync.',
360
+ 'history.colTime': 'Time',
361
+ 'history.colKind': 'Kind',
362
+ 'history.colDetail': 'Detail',
363
+ 'history.kindSnapshot': 'Snapshot',
364
+ 'history.kindAutosync': 'Auto Sync',
365
+ 'history.sectionCount': 'sections',
366
+ 'history.detail': 'Detail',
367
+ 'history.autosyncDirection': 'Direction: {direction}',
368
+ 'history.autosyncPull': 'Pull',
369
+ 'history.autosyncPush': 'Push',
370
+ 'history.autosyncBoth': 'Both',
371
+ 'history.autosyncSkipReason': 'Skip reason: {reason}',
372
+ 'history.autosyncReasonConflict': 'Conflict',
373
+ 'history.autosyncReasonNoRemote': 'No remote snapshot',
374
+ 'history.autosyncReasonNotConfigured': 'No repository configured',
375
+ 'history.autosyncReasonNetwork': 'Network issue',
376
+ 'history.autosyncConflicted': 'Skipped conflict sections: {sections}',
377
+ 'history.autosyncApplied': 'Applied sections: {sections}',
378
+ 'history.autosyncError': 'Error: {error}',
379
+ 'history.autosyncNotified': 'Notified (3 consecutive failures)',
380
+ 'history.column.snapshot': 'Snapshot',
381
+ 'history.column.autosync': 'Auto Sync',
382
+ // Trigger channel (which channel triggered this history entry)
383
+ 'history.channelGit': 'GitHub',
384
+ 'history.channelWebdav': 'WebDAV',
385
+ // List header stats summary (requirement 4F)
386
+ 'history.stats.total': '{count} total',
387
+ 'history.stats.snapshots': '{count} snapshots',
388
+ 'history.stats.autosync': '{count} auto sync',
389
+ 'history.stats.failed': '{count} failed',
390
+ 'history.stats.skipped': '{count} skipped',
391
+ 'history.stats.summary': 'Sync history statistics',
392
+ // Toast receipts (R-20: per-action wording; identical kind+text would be de-duplicated)
393
+ 'toast.autosyncLoadFailed': 'Failed to load auto-sync status',
394
+ 'toast.configSaveFailed': 'Failed to save channel config',
395
+ 'toast.configSaved': 'Channel config saved',
396
+ 'toast.configNothingToSave': 'Enter a channel URL before saving',
397
+ 'toast.selectionSaveFailed': 'Failed to save sync settings',
398
+ 'toast.pushPreviewFailed': 'Failed to build push preview',
399
+ 'toast.pushFailed': 'Push failed',
400
+ 'toast.pushDone': 'Push completed',
401
+ 'toast.pullFailed': 'Pull failed',
402
+ 'toast.pullDone': 'Pull completed',
403
+ 'toast.syncStartFailed': 'One-click sync failed',
404
+ 'toast.autosyncUpdateFailed': 'Failed to update auto-sync settings',
405
+ 'toast.autosyncUpdated': 'Auto-sync settings updated',
406
+ 'toast.snapshotsLoadFailed': 'Failed to load remote snapshots',
407
+ 'toast.snapshotsRefreshed': 'Remote snapshot list refreshed',
408
+ // Page-level load failure (M-16: inline error state; loadError had no render point before)
409
+ 'load.failed': 'Failed to load sync status',
410
+ 'common.close': 'Close',
411
+ 'common.retry': 'Retry',
412
+ 'common.loading': 'Loading…',
413
+ };
414
+
415
+ /** 字典键联合(注册处 compile-time 校验) */
416
+ export type SyncKey = keyof typeof zh;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * sync-view push 预览渲染模型测试(P0-②):pushPreviewView 的 ok/error、
3
+ * 分区行(计数 + changed 标记)、changedCount/remoteSnapshotCount 与只读提示。
4
+ */
5
+ import test from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import type { SyncPushPreview } from '../../sync/sync-engine.ts';
8
+ import { zhUiT } from '../../ui/i18n.ts';
9
+ import { pushPreviewView } from './sync-view.ts';
10
+
11
+ const t = zhUiT;
12
+
13
+ function okPreview(partial: Partial<SyncPushPreview> = {}): SyncPushPreview {
14
+ return {
15
+ ok: true,
16
+ sections: [
17
+ { section: 'settings', count: 12, changed: true },
18
+ { section: 'prompts', count: 0, changed: false },
19
+ ],
20
+ remoteSnapshotCount: 3,
21
+ ...partial,
22
+ };
23
+ }
24
+
25
+ test('pushPreviewView: ok 预览 → 分区行 + 变更计数 + 远端快照数(P0-②)', () => {
26
+ const view = pushPreviewView(okPreview(), t);
27
+ assert.ok(view !== null && view.ok);
28
+ assert.equal(view.rows.length, 2);
29
+ assert.deepEqual(view.rows[0], { section: 'settings', count: 12, changed: true });
30
+ assert.deepEqual(view.rows[1], { section: 'prompts', count: 0, changed: false });
31
+ assert.equal(view.changedCount, 1, '只有一个分区有变化');
32
+ assert.equal(view.remoteSnapshotCount, 3);
33
+ assert.equal(view.error, null);
34
+ assert.ok(view.previewHint.length > 0, '恒显示只读预览提示');
35
+ });
36
+
37
+ test('pushPreviewView: 首次推送(远端 0 快照)→ remoteSnapshotCount=0(P0-②)', () => {
38
+ const view = pushPreviewView(okPreview({ remoteSnapshotCount: 0 }), t);
39
+ assert.ok(view !== null);
40
+ assert.equal(view.remoteSnapshotCount, 0);
41
+ });
42
+
43
+ test('pushPreviewView: 失败预览 → error 透传(P0-②)', () => {
44
+ const view = pushPreviewView({ ok: false, sections: [], remoteSnapshotCount: 0, message: 'no sections' }, t);
45
+ assert.ok(view !== null && !view.ok);
46
+ assert.equal(view.error, 'no sections');
47
+ assert.equal(view.rows.length, 0);
48
+ });
49
+
50
+ test('pushPreviewView: null 预览 → null(无弹窗内容)', () => {
51
+ assert.equal(pushPreviewView(null, t), null);
52
+ });