@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,543 @@
1
+ /**
2
+ * 远程同步浏览器半 —— `/api/dsh-config-manager/sync/*` 的类型化 fetch 封装。
3
+ *
4
+ * 独立于 `../api.ts`(ConfigManagerApi 为并行会话已改文件,禁碰):本文件自持
5
+ * 端点常量与 readJson/postJson 小工具(与 api.ts 同款模式),只新增不修改。
6
+ *
7
+ * 端点契约(Host 半 src/index.ts 的 makeRoutes 按此实现):
8
+ * ```
9
+ * GET /api/dsh-config-manager/sync/status → SyncStatusResponse (配置/凭据/上次同步)
10
+ * POST /api/dsh-config-manager/sync/push → SyncPushReport (body: { repoUrl, token?, snapshotId? })
11
+ * POST /api/dsh-config-manager/sync/pull → SyncPullReport (body: { repoUrl, token?, strategy?, snapshotId? })
12
+ * POST /api/dsh-config-manager/sync/github/start → GithubDeviceFlowStartResponse(GitHub OAuth 设备码)
13
+ * POST /api/dsh-config-manager/sync/github/poll → GithubPollResponse(凭 flowId 轮询;成功时 token 已由 Host 写入 credentials)
14
+ * POST /api/dsh-config-manager/sync/github/cancel → { ok: true }
15
+ * ```
16
+ *
17
+ * 安全约束:
18
+ * - token 只存在于请求体内(同源 loopback,与导入 secretInputs 同策略),由 Host 写入
19
+ * DSH credentials(credentialRef),绝不落同步文件/日志/URL;响应永不回传 token;
20
+ * - GitHub device flow:浏览器只持有 flowId(随机 id)+ user_code + 授权页 URL;
21
+ * device_code 与 access token 只存在于宿主(内存 / DSH credentials),永不回传;
22
+ * - 错误消息由 Host 侧已脱敏(GitTransport 统一 [REDACTED]),UI 侧再经 ErrorBanner redact 兜底;
23
+ * - 本文件不 import 任何 node 模块(纯浏览器 bundle;sync-engine 仅作 type-only 引用)。
24
+ */
25
+ import type { SyncPullReport, SyncPushPreview, SyncPushReport } from '../../sync/sync-engine.ts';
26
+ import type { PlanItemKind } from '../../core/types.ts';
27
+ import type { SectionId } from '../../schema/types.ts';
28
+ import { ConfigManagerApiError } from '../api.ts';
29
+ import { zhUiT, type UiT } from '../../ui/i18n.ts';
30
+
31
+ /** 同步端点常量(与 Host 半 src/index.ts API 常量保持一致) */
32
+ export const SYNC_API = {
33
+ base: '/api/dsh-config-manager/sync',
34
+ status: '/api/dsh-config-manager/sync/status',
35
+ push: '/api/dsh-config-manager/sync/push',
36
+ pull: '/api/dsh-config-manager/sync/pull',
37
+ githubStart: '/api/dsh-config-manager/sync/github/start',
38
+ githubPoll: '/api/dsh-config-manager/sync/github/poll',
39
+ githubCancel: '/api/dsh-config-manager/sync/github/cancel',
40
+ githubValidate: '/api/dsh-config-manager/sync/github/validate',
41
+ history: '/api/dsh-config-manager/sync/history',
42
+ snapshotsList: '/api/dsh-config-manager/sync/snapshots-list',
43
+ sync: '/api/dsh-config-manager/sync/sync',
44
+ applyItems: '/api/dsh-config-manager/sync/apply-items',
45
+ cancel: '/api/dsh-config-manager/sync/cancel',
46
+ autosync: '/api/dsh-config-manager/sync/autosync',
47
+ selection: '/api/dsh-config-manager/sync/selection',
48
+ config: '/api/dsh-config-manager/sync/config',
49
+ uiPrefs: '/api/dsh-config-manager/sync/ui-prefs',
50
+ rollback: '/api/dsh-config-manager/sync/rollback',
51
+ } as const;
52
+
53
+ /** DSH credentials 中的同步 token 引用名(Host 半同值;仅供提示文案使用,值由 Host 读写) */
54
+ export const SYNC_CREDENTIAL_REF = 'DSH_CONFIG_MANAGER_SYNC_TOKEN';
55
+
56
+ /** WebDAV 通道密码在 DSH credentials 中的引用名(Host 半同值;仅供提示文案使用,值由 Host 读写) */
57
+ export const SYNC_WEBDAV_CREDENTIAL_REF = 'DSH_CONFIG_MANAGER_SYNC_WEBDAV_PASSWORD';
58
+
59
+ /** 远程同步通道类型:git(默认)或 webdav */
60
+ export type SyncTransportType = 'git' | 'webdav';
61
+
62
+ /** GET /sync/status 响应:配置/凭据/上次同步的只读事实(无任何 secret 值) */
63
+ export interface SyncStatusResponse {
64
+ ok: boolean;
65
+ /** 是否已保存过仓库/通道配置(sync-config.json;任一通道配置过即为 true) */
66
+ configured: boolean;
67
+ /** git 通道:已配置的仓库地址(不含 token,可回显;与当前通道无关,配置过即返回) */
68
+ repoUrl?: string;
69
+ /** git 通道:DSH credentials 中是否已存在 token(describe 只报状态,值永不返回) */
70
+ credentialConfigured: boolean;
71
+ credentialWritable: boolean;
72
+ /** webdav 通道:配置状态(url 可回显,username 非敏感;password 值永不返回;
73
+ * 与当前通道无关,配置过即返回,供 git ↔ webdav 切换时回填表单) */
74
+ webdav?: WebDavStatusResponse;
75
+ /** sync-state.lastSyncAt;'' = 从未同步 */
76
+ lastSyncAt?: string;
77
+ /** sync-state.sections 条目数 */
78
+ sectionCount: number;
79
+ transport?: { type: string; ref: string };
80
+ /** 上次选择的同步通道(磁盘 ui-prefs.json;UI 回填优先于此,localStorage 仅兜底) */
81
+ lastSyncChannel?: 'git' | 'webdav';
82
+ /** 可同步分区目录(自定义同步勾选列表;host adapters 唯一事实源) */
83
+ syncSections?: SyncSectionInfo[];
84
+ /** 当前分区选择(当前激活通道;UI 回填用,自动同步与手动 push 共用) */
85
+ syncSelection?: SyncSelectionPayload;
86
+ /** 全部通道的分区选择(git/webdav 各自独立;UI 按当前 tab 取对应通道) */
87
+ syncSelectionByChannel?: Record<SyncTransportType, SyncSelectionPayload>;
88
+ /** 自动同步当前状态(当前激活通道;供 UI 顶部开关回填;§3.9) */
89
+ autosync?: AutosyncStatusResponse;
90
+ /** 全部通道的自动同步状态(git/webdav 各自独立;UI 按当前 tab 取对应通道) */
91
+ autosyncByChannel?: Record<SyncTransportType, AutosyncStatusResponse>;
92
+ }
93
+
94
+ /** 同步分区选择(POST /sync/selection 请求体 + status.syncSelection 响应;持久化于 Host)。
95
+ * git/webdav 通道各自独立(transport 缺省 git)。 */
96
+ export interface SyncSelectionPayload {
97
+ /** 目标通道(git/webdav 各自独立的模式与勾选;缺省 git) */
98
+ transport?: SyncTransportType;
99
+ mode: 'default' | 'advanced';
100
+ /** 高级模式勾选分区;default 模式可为空数组 */
101
+ sections: SectionId[];
102
+ }
103
+
104
+ /** webdav 通道状态字段(无任何 secret 值;password 只报 passwordConfigured 布尔) */
105
+ export interface WebDavStatusResponse {
106
+ /** 上次使用的服务器地址(可回显;不含 userinfo) */
107
+ url?: string;
108
+ /** 上次使用的用户名(非敏感,可回显;供表单回填) */
109
+ username?: string;
110
+ /** 是否已填过用户名(布尔;便于 UI 提示徽章) */
111
+ usernameConfigured: boolean;
112
+ /** DSH credentials 中是否已存在密码(值永不返回) */
113
+ passwordConfigured: boolean;
114
+ }
115
+
116
+ /** POST /sync/config 响应:保存成功后的轻量凭据状态(无 secret 值;UI 直接合并刷新徽章)。 */
117
+ export interface SyncConfigSaveResponse {
118
+ ok: boolean;
119
+ configured: boolean;
120
+ transport: SyncTransportType;
121
+ /** git 通道:token 是否已配置(值永不返回) */
122
+ credentialConfigured: boolean;
123
+ /** webdav 通道:username/password 是否已配置(值永不返回;git 通道为 undefined) */
124
+ webdav?: {
125
+ usernameConfigured: boolean;
126
+ passwordConfigured: boolean;
127
+ };
128
+ }
129
+
130
+ /** 可同步分区条目(status.syncSections 项)。 */
131
+ export interface SyncSectionInfo {
132
+ id: SectionId;
133
+ /** 展示名(host adapter displayName) */
134
+ displayName: string;
135
+ defaultIncluded: boolean;
136
+ }
137
+
138
+ /** push 请求体(token 可选:非空则 Host 先写入 DSH credentials 再使用)。
139
+ * 扁平形状与 Host parseSyncBody 一致:git 携带 repoUrl/token;
140
+ * webdav 携带 url/username/password(顶层,不嵌套 webdav 对象)。
141
+ * git 可执行文件固定使用系统 PATH 中的 git,不再接受自定义路径。
142
+ * sections 可选(自定义同步模式):只推送勾选分区;缺省 = 全部推荐分区。
143
+ * 快照恒为明文:勾选即同步,不加密、不脱敏。 */
144
+ export interface SyncPushPayload {
145
+ /** 通道类型;缺省 'git' */
146
+ transport?: SyncTransportType;
147
+ repoUrl?: string;
148
+ token?: string;
149
+ /** webdav 通道字段(transport='webdav' 时使用;扁平顶层) */
150
+ url?: string;
151
+ username?: string;
152
+ password?: string;
153
+ /** 仅同步指定分区(缺省 = 全部推荐分区) */
154
+ sections?: SectionId[];
155
+ }
156
+
157
+ /** pull 请求体(strategy 缺省 replace:远端值覆盖本地;snapshotId 缺省 = 最新)。 */
158
+ export interface SyncPullPayload extends SyncPushPayload {
159
+ strategy?: 'merge' | 'replace' | 'skipExisting';
160
+ snapshotId?: string;
161
+ }
162
+
163
+ /* ---------------------------------------------------------------- 一键同步(方案 A) */
164
+
165
+ /** GET /sync/snapshots-list 响应:远端历史快照列表(按 createdAt 倒序)。 */
166
+ export interface SyncSnapshotsListResponse {
167
+ ok: boolean;
168
+ /** 按 createdAt 倒序(最新在前) */
169
+ snapshots: SyncSnapshotLite[];
170
+ /** 当前本地祖先指针(sync-state.lastSnapshotId),用于高亮当前基线 */
171
+ currentSnapshotId?: string;
172
+ }
173
+
174
+ /** 远端快照摘要(「选择历史快照」下拉项)。 */
175
+ export interface SyncSnapshotLite {
176
+ id: string;
177
+ createdAt: string;
178
+ sectionCount: number;
179
+ platform: string;
180
+ dshVersion: string;
181
+ }
182
+
183
+ /** POST /sync/sync 请求体(一键同步第一步:拉取 → 差异确认会话)。 */
184
+ export interface SyncStartPayload extends SyncPushPayload {
185
+ /** 缺省 = 最新快照;传入则对该历史快照拉取 */
186
+ snapshotId?: string;
187
+ }
188
+
189
+ /** POST /sync/sync 响应:差异确认会话(items 供 UI 逐项确认)。 */
190
+ export interface SyncStartResponse {
191
+ ok: boolean;
192
+ /** 差异确认会话 id:后续 apply-items / cancel 引用 */
193
+ syncSessionId: string;
194
+ /** 被拉取的远端快照 id */
195
+ snapshotId: string;
196
+ items: SyncConfirmItem[];
197
+ /** 是否包含任何需人工决策项 */
198
+ needsReview: boolean;
199
+ compatibility: 'excellent' | 'good' | 'partial' | 'unsupported';
200
+ message?: string;
201
+ }
202
+
203
+ /** 单条可确认的差异项(由 ImportPlan.item 投影 + 冲突详情)。 */
204
+ export interface SyncConfirmItem {
205
+ itemId: string;
206
+ adapter: SectionId;
207
+ kind: PlanItemKind;
208
+ description: string;
209
+ /** 变更详情(如插件「当前 1.1 vs 导入 1.6」),与导入恢复向导展示一致 */
210
+ detail?: string;
211
+ severity: 'info' | 'warning' | 'error';
212
+ /** 默认采纳方向;Conflict/MissingSecret 等人工项默认 false */
213
+ defaultAdopt: boolean;
214
+ /** 用户最终决策(缺省 = defaultAdopt) */
215
+ adopt: boolean;
216
+ /** 冲突项内联解决所需详情(仅 Conflict 项非空) */
217
+ conflict?: SyncConflictDetail;
218
+ /** 该项若采用将写入的目标摘要 */
219
+ target?: { adapter: SectionId; ref: string };
220
+ }
221
+
222
+ /** 冲突项内联解决详情(来源 MergeConflict + 可读 diff)。 */
223
+ export interface SyncConflictDetail {
224
+ path: string;
225
+ kind: 'key' | 'file' | 'section';
226
+ local?: unknown;
227
+ remote?: unknown;
228
+ ancestor?: unknown;
229
+ diff?: string;
230
+ }
231
+
232
+ /** POST /sync/apply-items 请求体(一键同步第二步:按逐项决策执行导入)。 */
233
+ export interface ApplyItemsPayload {
234
+ syncSessionId: string;
235
+ /** 每项的最终采纳决策(未列出项视为 adopt=false) */
236
+ adoptions: SyncItemAdoption[];
237
+ }
238
+
239
+ /** 单条采纳决策。 */
240
+ export interface SyncItemAdoption {
241
+ itemId: string;
242
+ adopt: boolean;
243
+ /** 冲突项解决方案(仅当该项是 Conflict 且 adopt=true 时必须)。
244
+ * 与导入恢复向导一致:keepLocal=保留当前 / useRemote=使用导入;跳过 = adopt=false。 */
245
+ resolution?: 'useRemote' | 'keepLocal';
246
+ }
247
+
248
+ /** POST /sync/apply-items 响应。 */
249
+ export interface ApplyItemsResponse {
250
+ ok: boolean;
251
+ applied: string[];
252
+ skipped: string[];
253
+ needsRestart: boolean;
254
+ warnings: string[];
255
+ /** 应用前快照 id(UI 一键回滚用) */
256
+ restoreId: string;
257
+ /** 任一失败是否整体回滚 */
258
+ rolledBack: boolean;
259
+ failed: { itemId: string; message?: string }[];
260
+ result: unknown;
261
+ }
262
+
263
+ /* ---------------------------------------------------------------- 自动同步 */
264
+
265
+ /** 统一间隔类型。 */
266
+ export type AutosyncInterval = '5m' | '15m' | '30m' | '60m' | '6h' | '12h' | '24h';
267
+
268
+ /** 最近一次自动同步执行状态。 */
269
+ export type AutosyncRunStatus = 'success' | 'skipped' | 'failed' | 'partial';
270
+
271
+ /** GET/POST /sync/autosync 响应:自动同步状态。 */
272
+ export interface AutosyncStatusResponse {
273
+ enabled: boolean;
274
+ interval: AutosyncInterval;
275
+ lastRunAt?: string;
276
+ lastRunStatus?: AutosyncRunStatus;
277
+ lastRunMessage?: string;
278
+ consecutiveFailures: number;
279
+ /** 距上次自动同步已过 ms(host 计算,供 UI 倒计时/立即触发判断) */
280
+ elapsedMs: number;
281
+ lastRunHistoryId?: string;
282
+ }
283
+
284
+ /** POST /sync/autosync 请求体(transport 指定目标通道;git/webdav 各自独立)。 */
285
+ export interface AutosyncUpdatePayload {
286
+ /** 目标通道(git/webdav 各自独立的开关/间隔/状态;缺省 git) */
287
+ transport?: SyncTransportType;
288
+ enabled: boolean;
289
+ interval?: AutosyncInterval;
290
+ startupMinIntervalMs?: number;
291
+ }
292
+
293
+ /* ---------------------------------------------------------------- 同步历史 */
294
+
295
+ /** 自动同步执行记录(§3.7 AutosyncHistoryEntry)。 */
296
+ export interface AutosyncHistoryEntry {
297
+ /** 触发该次运行的同步通道(git / webdav;旧记录缺省 undefined) */
298
+ transport?: SyncTransportType;
299
+ direction: 'pull' | 'push' | 'both';
300
+ status: 'success' | 'skipped' | 'failed' | 'partial';
301
+ /** 跳过原因(冲突项 / 缺失依赖 / Install / 错误 / 无远端 / 网络) */
302
+ skipReason?: string;
303
+ /** 被跳过的冲突分区 id(冲突跳过时列出) */
304
+ conflictedSections?: string[];
305
+ /** 本次自动合并实际写入的分区 */
306
+ appliedSections?: string[];
307
+ /** 本次 push 产生的快照 id */
308
+ pushedSnapshotId?: string;
309
+ /** 本次 pull 来源快照 id */
310
+ pulledSnapshotId?: string;
311
+ error?: string;
312
+ notifiedAt?: string;
313
+ /** 本次触发时的连续失败计数 */
314
+ failureCountAtRun: number;
315
+ createdAt: string;
316
+ }
317
+
318
+ /** 同步历史条目(Host 端返回;kind='autosync' 时 autosync 非空)。 */
319
+ export interface SyncHistoryEntry {
320
+ id: string;
321
+ createdAt: string;
322
+ kind: 'push' | 'pull' | 'apply' | 'autosync' | 'rollback';
323
+ sectionCount?: number;
324
+ reviewCount?: number;
325
+ /** 快照类条目的触发通道(git / webdav;旧快照缺省 undefined) */
326
+ transport?: string;
327
+ autosync?: AutosyncHistoryEntry;
328
+ }
329
+
330
+ /** GET /sync/history 响应:{ entries }。 */
331
+ export interface SyncHistoryResponse {
332
+ entries: SyncHistoryEntry[];
333
+ }
334
+
335
+ /* ---------------------------------------------------------------- GitHub OAuth device flow */
336
+
337
+ /** POST /sync/github/start 响应:UI 展示用(device_code 只存宿主,绝不回传) */
338
+ export interface GithubDeviceFlowStartResponse {
339
+ /** 随机 flowId:后续 poll/cancel 凭它引用宿主侧登记的 device_code */
340
+ flowId: string;
341
+ /** 一次性用户码(用户在 GitHub 授权页输入) */
342
+ userCode: string;
343
+ /** GitHub 授权页 URL(用户浏览器打开) */
344
+ verificationUri: string;
345
+ /** 设备码过期秒数 */
346
+ expiresIn: number;
347
+ /** GitHub 建议轮询间隔秒数 */
348
+ interval: number;
349
+ }
350
+
351
+ /** POST /sync/github/poll 响应状态 */
352
+ export type GithubPollStatus = 'pending' | 'success' | 'denied' | 'expired' | 'error';
353
+
354
+ /** POST /sync/github/poll 响应:成功时 token 已由 Host 写入 DSH credentials(值永不回传) */
355
+ export interface GithubPollResponse {
356
+ status: GithubPollStatus;
357
+ /** pending:下次轮询前应等待的毫秒数 */
358
+ pollDelayMs?: number;
359
+ /** 终止态错误码(GitHub error code) */
360
+ errorCode?: string;
361
+ /** 终止态可展示消息(来自 GitHub error_description / 宿主文案,不含秘密) */
362
+ message?: string;
363
+ /** success 时恒 true(凭据已配置);便于 UI 直接刷新状态 */
364
+ credentialConfigured?: boolean;
365
+ }
366
+
367
+ /** POST /sync/github/validate 响应:token 是否已配置 + 是否有效(GET /user;
368
+ * 401 → 无效)。只回布尔 + 登录名(非敏感),token 值永不回传浏览器。 */
369
+ export interface GithubValidateResponse {
370
+ ok: boolean;
371
+ /** token 是否存在于 DSH credentials */
372
+ configured: boolean;
373
+ /** token 是否有效(GitHub GET /user 成功;configured=false 时恒 false) */
374
+ valid: boolean;
375
+ /** GitHub 登录名(valid=true 时;非敏感展示位) */
376
+ login?: string;
377
+ }
378
+
379
+ /** 同步请求超时(ms):与 Host 半 ROUTE_TIMEOUT_MS 对齐(git 网络操作可能较慢) */
380
+ const SYNC_TIMEOUT_MS = 5 * 60 * 1000;
381
+
382
+ /** 解析 JSON 响应;非 2xx 时抛出带路由 error 消息的 ConfigManagerApiError(与 api.ts 同款) */
383
+ async function readJson<T>(response: Response, t: UiT): Promise<T> {
384
+ const notMountedMessage = t('error.notMounted');
385
+ let body: unknown;
386
+ try {
387
+ body = await response.json();
388
+ } catch {
389
+ if (response.status === 404) throw new ConfigManagerApiError(notMountedMessage);
390
+ throw new ConfigManagerApiError(t('error.httpInvalidJson', { status: String(response.status) }));
391
+ }
392
+ if (!response.ok) {
393
+ const message =
394
+ typeof body === 'object' && body !== null && typeof (body as { error?: unknown }).error === 'string'
395
+ ? (body as { error: string }).error
396
+ : response.status === 404
397
+ ? notMountedMessage
398
+ : `HTTP ${response.status}`;
399
+ throw new ConfigManagerApiError(message);
400
+ }
401
+ return body as T;
402
+ }
403
+
404
+ /** POST JSON 请求(带超时:宿主卡死时 UI 拿到明确错误而不是永远转圈) */
405
+ async function postJson<T>(path: string, body: unknown, t: UiT): Promise<T> {
406
+ const controller = new AbortController();
407
+ const timer = setTimeout(() => controller.abort(), SYNC_TIMEOUT_MS);
408
+ try {
409
+ const response = await fetch(path, {
410
+ method: 'POST',
411
+ headers: { 'content-type': 'application/json' },
412
+ body: JSON.stringify(body),
413
+ signal: controller.signal,
414
+ });
415
+ return await readJson<T>(response, t);
416
+ } catch (err) {
417
+ if (controller.signal.aborted) {
418
+ throw new ConfigManagerApiError(
419
+ t('error.syncTimeout', { minutes: String(Math.round(SYNC_TIMEOUT_MS / 60000)) }),
420
+ );
421
+ }
422
+ throw err;
423
+ } finally {
424
+ clearTimeout(timer);
425
+ }
426
+ }
427
+
428
+ /** 远程同步浏览器半数据入口(备份与迁移页第 4 个 tab 的注入业务面) */
429
+ export class SyncApi {
430
+ readonly t: UiT
431
+ constructor(t: UiT = zhUiT) {
432
+ this.t = t
433
+ }
434
+
435
+ /** 读取同步状态(配置 / 凭据 / 上次同步时间 / 分区数) */
436
+ async status(): Promise<SyncStatusResponse> {
437
+ const response = await fetch(SYNC_API.status);
438
+ return readJson<SyncStatusResponse>(response, this.t);
439
+ }
440
+
441
+ /** 推送:导出勾选分区 → 提交到私有 Git 仓库 → 更新 sync-state */
442
+ async push(payload: SyncPushPayload): Promise<SyncPushReport> {
443
+ return postJson<SyncPushReport>(SYNC_API.push, payload, this.t);
444
+ }
445
+
446
+ /** P0-②:push 前只读预览(「将推送什么」,零写入远端)——body.preview=true 触发 */
447
+ async pushPreview(payload: SyncPushPayload): Promise<SyncPushPreview> {
448
+ return postJson<SyncPushPreview>(SYNC_API.push, { ...payload, preview: true }, this.t);
449
+ }
450
+
451
+ /** 拉取差异预览:拉取远端最新快照 → 只读分析(绝不执行导入) */
452
+ async pull(payload: SyncPullPayload): Promise<SyncPullReport> {
453
+ return postJson<SyncPullReport>(SYNC_API.pull, payload, this.t);
454
+ }
455
+
456
+ /** GitHub OAuth device flow:发起登录,返回一次性用户码 + 授权页 URL + flowId */
457
+ async githubStart(): Promise<GithubDeviceFlowStartResponse> {
458
+ return postJson<GithubDeviceFlowStartResponse>(SYNC_API.githubStart, {}, this.t);
459
+ }
460
+
461
+ /** GitHub OAuth device flow:凭 flowId 轮询授权结果(成功时 token 已由 Host 写入 credentials) */
462
+ async githubPoll(flowId: string): Promise<GithubPollResponse> {
463
+ return postJson<GithubPollResponse>(SYNC_API.githubPoll, { flowId }, this.t);
464
+ }
465
+
466
+ /** GitHub OAuth device flow:取消(丢弃宿主侧登记,零副作用) */
467
+ async githubCancel(flowId: string): Promise<{ ok: boolean }> {
468
+ return postJson<{ ok: boolean }>(SYNC_API.githubCancel, { flowId }, this.t);
469
+ }
470
+
471
+ /** GitHub token 有效性校验(判定「是否已登录」:token 存在且 GitHub API 接受;
472
+ * 401 → valid:false 引导重新登录;非 401 错误向上抛,UI 兜底不误判登出) */
473
+ async githubValidate(): Promise<GithubValidateResponse> {
474
+ return postJson<GithubValidateResponse>(SYNC_API.githubValidate, {}, this.t);
475
+ }
476
+
477
+ /** 同步历史:列出本地祖先快照 + 自动同步执行记录(按 createdAt 倒序合并)。 */
478
+ async history(): Promise<SyncHistoryResponse> {
479
+ const response = await fetch(SYNC_API.history);
480
+ return readJson<SyncHistoryResponse>(response, this.t);
481
+ }
482
+
483
+ /** 远端历史快照列表(供「选择历史快照」下拉)。 */
484
+ async snapshotsList(payload: SyncPushPayload): Promise<SyncSnapshotsListResponse> {
485
+ return postJson<SyncSnapshotsListResponse>(SYNC_API.snapshotsList, payload, this.t);
486
+ }
487
+
488
+ /** 一键同步第一步:拉取 → 差异确认会话(items 逐项确认,暂不导入)。 */
489
+ async sync(payload: SyncStartPayload): Promise<SyncStartResponse> {
490
+ return postJson<SyncStartResponse>(SYNC_API.sync, payload, this.t);
491
+ }
492
+
493
+ /** 一键同步第二步:按用户对差异项的逐项决策执行导入。 */
494
+ async applyItems(payload: ApplyItemsPayload): Promise<ApplyItemsResponse> {
495
+ return postJson<ApplyItemsResponse>(SYNC_API.applyItems, payload, this.t);
496
+ }
497
+
498
+ /** 取消/清理差异确认会话(丢弃临时 ZIP,零副作用)。 */
499
+ async cancel(syncSessionId: string): Promise<{ ok: boolean }> {
500
+ return postJson<{ ok: boolean }>(SYNC_API.cancel, { syncSessionId }, this.t);
501
+ }
502
+
503
+ /** 自动同步状态(GET /sync/autosync 返回全部通道的 { git, webdav },各自独立)。 */
504
+ async autosyncStatusAll(): Promise<Record<SyncTransportType, AutosyncStatusResponse>> {
505
+ const response = await fetch(SYNC_API.autosync);
506
+ return readJson<Record<SyncTransportType, AutosyncStatusResponse>>(response, this.t);
507
+ }
508
+
509
+ /** 自动同步状态(指定通道;从全部通道状态中取)。 */
510
+ async autosyncStatus(transport: SyncTransportType = 'git'): Promise<AutosyncStatusResponse> {
511
+ const all = await this.autosyncStatusAll();
512
+ return all[transport];
513
+ }
514
+
515
+ /** 自动同步配置更新(POST /sync/autosync;payload.transport 指定目标通道)。 */
516
+ async autosyncUpdate(payload: AutosyncUpdatePayload): Promise<AutosyncStatusResponse> {
517
+ return postJson<AutosyncStatusResponse>(SYNC_API.autosync, payload, this.t);
518
+ }
519
+
520
+ /** 保存同步分区选择(POST /sync/selection):模式 + 勾选分区持久化到 Host。
521
+ * 自动同步调度器与手动 push 共用此配置(刷新/重启后仍然生效)。 */
522
+ async saveSelection(payload: SyncSelectionPayload): Promise<SyncSelectionPayload> {
523
+ return postJson<SyncSelectionPayload>(SYNC_API.selection, payload, this.t);
524
+ }
525
+
526
+ /** 保存同步通道配置(POST /sync/config):url/username/password(git: repoUrl/token)持久化。
527
+ * password/token 经 Host 写入 DSH credentials(值永不回传);返回凭据布尔供 UI 刷新徽章。 */
528
+ async saveConfig(payload: SyncPushPayload): Promise<SyncConfigSaveResponse> {
529
+ return postJson<SyncConfigSaveResponse>(SYNC_API.config, payload, this.t);
530
+ }
531
+
532
+ /** 保存插件 UI 偏好(POST /sync/ui-prefs):当前为上次选择的同步通道(ui-prefs.json,
533
+ * 随 self 分区进导出备份)。纯偏好无 secret;失败由调用方静默降级(localStorage 兜底)。 */
534
+ async saveUiPrefs(payload: { lastSyncChannel?: 'git' | 'webdav' }): Promise<{ ok: boolean; lastSyncChannel?: 'git' | 'webdav' }> {
535
+ return postJson<{ ok: boolean; lastSyncChannel?: 'git' | 'webdav' }>(SYNC_API.uiPrefs, payload, this.t);
536
+ }
537
+
538
+ /** 一键回滚:按 restoreId 调用 backup→rollback */
539
+ async rollback(payload: { restoreId: string }): Promise<{ ok: boolean; full: boolean }> {
540
+ return postJson<{ ok: boolean; full: boolean }>(SYNC_API.rollback, payload, this.t);
541
+ }
542
+
543
+ }