@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,299 @@
1
+ /**
2
+ * m-sync-ui:同步通道配置的持久化(sync-config.json,schemaVersion v2)。
3
+ *
4
+ * 与 sync-state.json 的分工:sync-state 记录「同步了哪些分区、何时同步」(t4 拥有),
5
+ * 本文件只记录「上一次使用的同步通道配置」,供 UI 打开设置页时回填表单。
6
+ *
7
+ * schema v2(统一接口契约,captain 冻结):
8
+ * - 顶层形状:
9
+ * { "schemaVersion": 2, "transport": "git"|"webdav",
10
+ * "git": { "repoUrl": "..." }, // transport=git 时
11
+ * "webdav": { "url": "...", "username": "..." } } // transport=webdav 时
12
+ * - 顶层 transport 选择 + git/webdav 命名空间对象(嵌套,非扁平,避免歧义)。
13
+ * git 命名空间不再含 gitBin(git 可执行文件固定使用系统 PATH 中的 git)。
14
+ * - webdav.url 不含任何凭据、拒绝 userinfo;username 可回显;
15
+ * password 绝不入文件(走 DSH credentials ref `DSH_CONFIG_MANAGER_SYNC_WEBDAV_PASSWORD`)。
16
+ * - 代码内为可辨识联合 SyncConfig + isGitConfig()/isWebDavConfig() 守卫。
17
+ * - 兼容旧 v1 文件({schemaVersion:1, repoUrl, gitBin?} 或缺 schemaVersion 视为 v1)
18
+ * → 读取时归一为 v2 git 形态(旧 gitBin 字段被忽略/下一次保存时丢弃)。
19
+ *
20
+ * 安全不变量:
21
+ * - 配置文件绝不出现密码/token(webdav 仅存 url/可选 username;口令走 DSH credentials)。
22
+ * - url 校验:拒绝空白、非 http(s)、含 userinfo(username:password@)——仿 validateRepoUrl。
23
+ */
24
+ import fs from 'node:fs/promises';
25
+ import path from 'node:path';
26
+
27
+ import { zhMsg } from '../core/messages.ts';
28
+ import type { MsgFunc } from '../core/messages.ts';
29
+ import { parseJsonSafe, stringifyJsonSafe } from '../utils/json.ts';
30
+ import { atomicWriteFile } from '../utils/atomic-write.ts';
31
+
32
+ export const SYNC_CONFIG_FILE = 'sync-config.json';
33
+
34
+ /** 同步通道类型(git / webdav;host 侧统一引用,autosync-config / sync-selection 复用)。 */
35
+ export type SyncTransportType = 'git' | 'webdav';
36
+
37
+ /** 当前 sync-config.json schema 版本号(v3:双命名空间共存,切换通道不丢失另一通道配置)。 */
38
+ export const SYNC_CONFIG_SCHEMA_VERSION = 3;
39
+ /** 历史可读取版本:v1、v2、v3。 */
40
+ export const SYNC_CONFIG_SUPPORTED_VERSIONS: readonly number[] = [1, 2, 3];
41
+
42
+ /** git 通道配置(不含任何凭据;git 可执行文件固定使用系统 PATH 中的 git) */
43
+ export interface GitConfig {
44
+ repoUrl: string;
45
+ }
46
+
47
+ /** webdav 通道配置(不含 password;password 走 DSH credentials) */
48
+ export interface WebDavConfig {
49
+ /** WebDAV 端点地址(不含凭据;拒绝 userinfo) */
50
+ url: string;
51
+ /** 可选用户名(可回显) */
52
+ username?: string;
53
+ }
54
+
55
+ /**
56
+ * 完整双命名空间配置视图(v3 文件直接读取,供 status 路由回填另一通道的 repoUrl/url)。
57
+ * 与可辨识联合 SyncConfig 不同:git 和 webdav 命名空间同时存在,可能缺失。
58
+ */
59
+ export interface FullSyncConfig {
60
+ transport: 'git' | 'webdav';
61
+ git?: GitConfig;
62
+ webdav?: WebDavConfig;
63
+ }
64
+
65
+ /** 持久化的同步通道配置:可辨识联合(schemaVersion 恒 2) */
66
+ export type SyncConfig =
67
+ | { schemaVersion: 2; transport: 'git'; git: GitConfig }
68
+ | { schemaVersion: 2; transport: 'webdav'; webdav: WebDavConfig };
69
+
70
+ /** git 通道守卫 */
71
+ export function isGitConfig(cfg: SyncConfig): cfg is Extract<SyncConfig, { transport: 'git' }> {
72
+ return cfg.transport === 'git';
73
+ }
74
+
75
+ /** webdav 通道守卫 */
76
+ export function isWebDavConfig(cfg: SyncConfig): cfg is Extract<SyncConfig, { transport: 'webdav' }> {
77
+ return cfg.transport === 'webdav';
78
+ }
79
+
80
+ /** 从 v1 扁平形态解析 git 配置;缺 repoUrl → null(gitBin 已废弃:始终使用系统 PATH 中的 git) */
81
+ function parseV1Git(obj: Record<string, unknown>): GitConfig | null {
82
+ if (typeof obj['repoUrl'] !== 'string' || obj['repoUrl'] === '') return null;
83
+ return { repoUrl: obj['repoUrl'] };
84
+ }
85
+
86
+ /** 从 v2 git 命名空间解析;缺有效 repoUrl → null */
87
+ function parseV2GitNamespace(ns: unknown): GitConfig | null {
88
+ if (ns === null || typeof ns !== 'object' || Array.isArray(ns)) return null;
89
+ return parseV1Git(ns as Record<string, unknown>);
90
+ }
91
+
92
+ /** 从 v2 webdav 命名空间解析;缺有效 url → null */
93
+ function parseV2WebDavNamespace(ns: unknown): WebDavConfig | null {
94
+ if (ns === null || typeof ns !== 'object' || Array.isArray(ns)) return null;
95
+ const o = ns as Record<string, unknown>;
96
+ if (typeof o['url'] !== 'string' || o['url'] === '') return null;
97
+ const webdav: WebDavConfig = { url: o['url'] };
98
+ if (typeof o['username'] === 'string' && o['username'] !== '') webdav.username = o['username'];
99
+ return webdav;
100
+ }
101
+
102
+ /**
103
+ * 读取同步通道配置;文件不存在/损坏/不支持 schema → null(视为未配置,UI 显示空表单)。
104
+ * 兼容旧文件:缺 schemaVersion 字段视为 v1(git 通道)。
105
+ * 恒返回 schemaVersion=2 的规范形态(v1 读取时归一为 git)。
106
+ */
107
+ export async function readSyncConfig(dir: string): Promise<SyncConfig | null> {
108
+ const file = path.join(dir, SYNC_CONFIG_FILE);
109
+ let raw: string;
110
+ try {
111
+ raw = await fs.readFile(file, 'utf8');
112
+ } catch {
113
+ return null;
114
+ }
115
+ let parsed: unknown;
116
+ try {
117
+ parsed = parseJsonSafe(raw);
118
+ } catch {
119
+ // 损坏 JSON / 体积超限 / 嵌套过深 → 视为未配置(不抛错)
120
+ return null;
121
+ }
122
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
123
+ const obj = parsed as Record<string, unknown>;
124
+ // schemaVersion:缺省视为 v1(兼容旧文件);非缺省但不在支持列表 → 拒绝
125
+ if (obj['schemaVersion'] !== undefined && typeof obj['schemaVersion'] !== 'number') {
126
+ return null;
127
+ }
128
+ const ver = typeof obj['schemaVersion'] === 'number' ? obj['schemaVersion'] : 1;
129
+ if (!SYNC_CONFIG_SUPPORTED_VERSIONS.includes(ver)) return null;
130
+
131
+ if (ver === 1) {
132
+ const git = parseV1Git(obj);
133
+ if (git === null) return null;
134
+ return { schemaVersion: 2, transport: 'git', git };
135
+ }
136
+
137
+ // v2 / v3:顶层 transport 选择(v3 双命名空间并存,按 transport 返回对应通道)
138
+ const transport = obj['transport'];
139
+ if (transport !== 'git' && transport !== 'webdav') return null;
140
+ if (transport === 'git') {
141
+ const git = parseV2GitNamespace(obj['git']);
142
+ if (git === null) return null;
143
+ return { schemaVersion: 2, transport: 'git', git };
144
+ }
145
+ const webdav = parseV2WebDavNamespace(obj['webdav']);
146
+ if (webdav === null) return null;
147
+ return { schemaVersion: 2, transport: 'webdav', webdav };
148
+ }
149
+
150
+ /**
151
+ * 读取 sync-config.json 原始内容,提取 git/webdav 两个命名空间(不存在/无效 → undefined)。
152
+ * 供 writeSyncConfig 合并保留另一通道配置用:切换通道保存时不得丢弃另一通道的 repoUrl/url。
153
+ */
154
+ function readBothNamespaces(file: string): Promise<{ git?: GitConfig; webdav?: WebDavConfig }> {
155
+ return (async () => {
156
+ let raw: string
157
+ try {
158
+ raw = await fs.readFile(file, 'utf8')
159
+ } catch {
160
+ return {} // 文件不存在:无历史配置
161
+ }
162
+ let parsed: unknown
163
+ try {
164
+ parsed = parseJsonSafe(raw)
165
+ } catch {
166
+ return {} // 损坏 JSON:按无历史配置处理(不阻塞保存)
167
+ }
168
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return {}
169
+ const o = parsed as Record<string, unknown>
170
+ const out: { git?: GitConfig; webdav?: WebDavConfig } = {}
171
+ const git = parseV2GitNamespace(o['git'])
172
+ if (git !== null) out.git = git
173
+ const webdav = parseV2WebDavNamespace(o['webdav'])
174
+ if (webdav !== null) out.webdav = webdav
175
+ // v1 旧文件(无命名空间):git 读扁平 repoUrl
176
+ if (out.git === undefined && out.webdav === undefined) {
177
+ const v1 = parseV1Git(o)
178
+ if (v1 !== null) out.git = v1
179
+ }
180
+ return out
181
+ })()
182
+ }
183
+
184
+ /**
185
+ * 读取完整的双命名空间配置(供 status 路由回填另一通道的 repoUrl/url)。
186
+ * 文件不存在/损坏/无任何通道配置 → null(视为未配置)。
187
+ */
188
+ export async function readFullSyncConfig(dir: string): Promise<FullSyncConfig | null> {
189
+ const file = path.join(dir, SYNC_CONFIG_FILE)
190
+ const both = await readBothNamespaces(file)
191
+ if (both.git === undefined && both.webdav === undefined) return null
192
+ // 从原始文件读取当前活动 transport 字段
193
+ let transport: 'git' | 'webdav' = 'git'
194
+ try {
195
+ const raw = await fs.readFile(file, 'utf8')
196
+ const parsed = parseJsonSafe(raw)
197
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
198
+ const o = parsed as Record<string, unknown>
199
+ if (o['transport'] === 'webdav') transport = 'webdav'
200
+ }
201
+ } catch { /* 默认 git */ }
202
+ return { transport, git: both.git, webdav: both.webdav }
203
+ }
204
+
205
+ /**
206
+ * 读取指定通道的同步通道配置(供自动同步调度器按通道运行)。
207
+ * 从完整双命名空间配置取对应通道构造可辨识联合 SyncConfig;该通道未配置 → null。
208
+ */
209
+ export async function readSyncConfigFor(dir: string, channel: SyncTransportType): Promise<SyncConfig | null> {
210
+ const full = await readFullSyncConfig(dir);
211
+ if (full === null) return null;
212
+ if (channel === 'webdav') {
213
+ if (full.webdav === undefined) return null;
214
+ return { schemaVersion: 2, transport: 'webdav', webdav: full.webdav };
215
+ }
216
+ if (full.git === undefined) return null;
217
+ return { schemaVersion: 2, transport: 'git', git: full.git };
218
+ }
219
+
220
+ /**
221
+ * 保存同步通道配置(自动创建目录;恒写 schemaVersion=3 双命名空间)。
222
+ * - 写入当前通道的命名空间(git/webdav);
223
+ * - 另一通道之前配置过 → 一并保留(切换通道不丢失另一通道的 repoUrl/url);
224
+ * - 覆盖旧值;未配置过的字段不写入。
225
+ */
226
+ export async function writeSyncConfig(dir: string, cfg: SyncConfig): Promise<void> {
227
+ await fs.mkdir(dir, { recursive: true });
228
+ const file = path.join(dir, SYNC_CONFIG_FILE)
229
+ const existing = await readBothNamespaces(file)
230
+ const payload: Record<string, unknown> = {
231
+ schemaVersion: SYNC_CONFIG_SCHEMA_VERSION,
232
+ transport: cfg.transport,
233
+ }
234
+ if (isGitConfig(cfg)) {
235
+ payload.git = cfg.git
236
+ // 保留另一通道的 webdav 配置(存在时)
237
+ if (existing.webdav !== undefined) payload.webdav = existing.webdav
238
+ } else {
239
+ payload.webdav = cfg.webdav
240
+ // 保留另一通道的 git 配置(存在时)
241
+ if (existing.git !== undefined) payload.git = existing.git
242
+ }
243
+ await atomicWriteFile(file, stringifyJsonSafe(payload, { space: 2 }), { mode: 0o600 });
244
+ }
245
+
246
+ /**
247
+ * 仓库地址合法性校验(返回错误消息;null = 合法)。
248
+ * 安全约束:token 永不拼入 repoUrl —— http(s) 地址带 userinfo(username[:password]@)直接拒绝,
249
+ * 引导用户把 token 放凭据字段(DSH credentials),避免 token 经 URL 泄漏进 git 历史/日志。
250
+ */
251
+ export function validateRepoUrl(repoUrl: string, msg: MsgFunc = zhMsg): string | null {
252
+ if (typeof repoUrl !== 'string' || repoUrl.trim() === '') {
253
+ return 'repoUrl is required';
254
+ }
255
+ const url = repoUrl.trim();
256
+ if (/\s/.test(url)) {
257
+ return msg('sync.configWhitespace');
258
+ }
259
+ if (/^https?:\/\//i.test(url)) {
260
+ let parsed: URL;
261
+ try {
262
+ parsed = new URL(url);
263
+ } catch {
264
+ return msg('sync.configUnparseable', { url });
265
+ }
266
+ if (parsed.username !== '' || parsed.password !== '') {
267
+ return msg('sync.configUserinfo');
268
+ }
269
+ }
270
+ return null;
271
+ }
272
+
273
+ /**
274
+ * WebDAV 端点地址合法性校验(返回错误消息;null = 合法)。
275
+ * 安全约束:口令/密码永不拼入 url —— 仅接受 http(s),且拒绝带 userinfo
276
+ * (username[:password]@)的地址,引导用户把口令放 DSH credentials,避免凭据经 URL 泄漏进出入口/日志。
277
+ */
278
+ export function validateWebDavUrl(url: string, msg: MsgFunc = zhMsg): string | null {
279
+ if (typeof url !== 'string' || url.trim() === '') {
280
+ return 'url is required';
281
+ }
282
+ const cleaned = url.trim();
283
+ if (/\s/.test(cleaned)) {
284
+ return msg('sync.configWhitespace');
285
+ }
286
+ if (!/^https?:\/\//i.test(cleaned)) {
287
+ return msg('sync.configUnparseable', { url: cleaned });
288
+ }
289
+ let parsed: URL;
290
+ try {
291
+ parsed = new URL(cleaned);
292
+ } catch {
293
+ return msg('sync.configUnparseable', { url: cleaned });
294
+ }
295
+ if (parsed.username !== '' || parsed.password !== '') {
296
+ return msg('sync.configUserinfo');
297
+ }
298
+ return null;
299
+ }