@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,169 @@
1
+ /**
2
+ * cache-cleaner 测试:缓存自动清理的保留期 / 白名单边界 / 容错。
3
+ * 使用真实临时目录(node:os tmpdir)+ node:fs 真实读写(与 plugin-cli.fs.test.ts 同模式)。
4
+ * 覆盖:
5
+ * - tmp:过期 .zip 删、新 .zip 留、非 zip 文件留、dsh-sync-pull-* 目录超期删
6
+ * - exports:过期导出 zip 删、新导出 zip 留、非 zip 文件留
7
+ * - 保留期边界(恰好等于保留期 → 不删)、目录不存在 → 不抛错
8
+ */
9
+ import test from 'node:test';
10
+ import assert from 'node:assert/strict';
11
+ import fs from 'node:fs/promises';
12
+ import os from 'node:os';
13
+ import path from 'node:path';
14
+
15
+ import {
16
+ cleanupCaches,
17
+ TMP_RETENTION_DEFAULT_MS,
18
+ EXPORTS_RETENTION_DEFAULT_MS,
19
+ } from './cache-cleaner.ts';
20
+
21
+ /** 建独立临时数据目录,返回 { root, tmpDir, exportsDir, cleanup } */
22
+ async function makeDataDir(): Promise<{
23
+ root: string;
24
+ tmpDir: string;
25
+ exportsDir: string;
26
+ cleanup: () => Promise<void>;
27
+ }> {
28
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'dsh-cm-cache-'));
29
+ const tmpDir = path.join(root, 'tmp');
30
+ const exportsDir = path.join(root, 'exports');
31
+ await fs.mkdir(tmpDir, { recursive: true });
32
+ await fs.mkdir(exportsDir, { recursive: true });
33
+ return {
34
+ root,
35
+ tmpDir,
36
+ exportsDir,
37
+ cleanup: () => fs.rm(root, { recursive: true, force: true }),
38
+ };
39
+ }
40
+
41
+ /** 把目标 mtime 拨到指定毫秒(Windows 精度足够,测试用秒级偏移) */
42
+ async function touch(p: string, mtimeMs: number): Promise<void> {
43
+ const st = await fs.stat(p);
44
+ await fs.utimes(p, st.atimeMs ? new Date(st.atimeMs) : new Date(), new Date(mtimeMs));
45
+ }
46
+
47
+ test('tmp:过期 .zip 删、新 .zip 留、非 zip 文件留', async () => {
48
+ const d = await makeDataDir();
49
+ try {
50
+ const now = Date.now();
51
+ const oldZip = path.join(d.tmpDir, 'upload-old.zip');
52
+ const newZip = path.join(d.tmpDir, 'upload-new.zip');
53
+ const txt = path.join(d.tmpDir, 'notes.txt');
54
+ await fs.writeFile(oldZip, Buffer.alloc(10));
55
+ await fs.writeFile(newZip, Buffer.alloc(20));
56
+ await fs.writeFile(txt, 'keep me');
57
+ await touch(oldZip, now - TMP_RETENTION_DEFAULT_MS - 1000); // 超期 1s
58
+ await touch(newZip, now - 1000); // 新
59
+
60
+ const report = await cleanupCaches({
61
+ tmpDir: d.tmpDir,
62
+ exportsDir: d.exportsDir,
63
+ now: () => now,
64
+ });
65
+
66
+ assert.equal(report.removed, 1, '只删超期 zip');
67
+ assert.equal(report.freedBytes, 10, '释放字节 = 被删文件 size');
68
+ assert.equal(await fs.readFile(newZip).then((b) => b.length), 20, '新 zip 保留');
69
+ assert.equal(await fs.readFile(txt, 'utf8'), 'keep me', '非 zip 文件保留');
70
+ await assert.rejects(() => fs.stat(oldZip), '超期 zip 已删');
71
+ assert.ok(report.detail.some((s) => s.includes('upload-old.zip')), 'detail 含删除记录');
72
+ } finally {
73
+ await d.cleanup();
74
+ }
75
+ });
76
+
77
+ test('tmp:dsh-sync-pull-* 临时目录超期删、新目录留', async () => {
78
+ const d = await makeDataDir();
79
+ try {
80
+ const now = Date.now();
81
+ const oldDir = path.join(d.tmpDir, 'dsh-sync-pull-abc');
82
+ const newDir = path.join(d.tmpDir, 'dsh-sync-pull-def');
83
+ const otherDir = path.join(d.tmpDir, 'keep-dir');
84
+ await fs.mkdir(path.join(oldDir, 'inner'), { recursive: true });
85
+ await fs.mkdir(path.join(newDir, 'inner'), { recursive: true });
86
+ await fs.mkdir(otherDir, { recursive: true });
87
+ await fs.writeFile(path.join(oldDir, 'inner', 'snapshot.zip'), Buffer.alloc(5));
88
+ await touch(oldDir, now - TMP_RETENTION_DEFAULT_MS - 5000);
89
+ await touch(newDir, now - 1000);
90
+
91
+ const report = await cleanupCaches({
92
+ tmpDir: d.tmpDir,
93
+ exportsDir: d.exportsDir,
94
+ now: () => now,
95
+ });
96
+
97
+ assert.equal(report.removed, 1, '只删超期 sync 临时目录');
98
+ await assert.rejects(() => fs.stat(oldDir), '超期 sync 目录整棵已删');
99
+ assert.ok(await fs.stat(newDir), '新 sync 目录保留');
100
+ assert.ok(await fs.stat(otherDir), '无关目录保留');
101
+ } finally {
102
+ await d.cleanup();
103
+ }
104
+ });
105
+
106
+ test('exports:过期导出 zip 删、新导出 zip 留、非 zip 文件留', async () => {
107
+ const d = await makeDataDir();
108
+ try {
109
+ const now = Date.now();
110
+ const oldExport = path.join(d.exportsDir, 'dsh-config-old.zip');
111
+ const newExport = path.join(d.exportsDir, 'dsh-config-new.zip');
112
+ const readme = path.join(d.exportsDir, 'readme.txt');
113
+ await fs.writeFile(oldExport, Buffer.alloc(15));
114
+ await fs.writeFile(newExport, Buffer.alloc(25));
115
+ await fs.writeFile(readme, 'keep');
116
+ await touch(oldExport, now - EXPORTS_RETENTION_DEFAULT_MS - 1000); // 超期 1s
117
+ await touch(newExport, now - 1000); // 新
118
+
119
+ const report = await cleanupCaches({
120
+ tmpDir: d.tmpDir,
121
+ exportsDir: d.exportsDir,
122
+ now: () => now,
123
+ });
124
+
125
+ assert.equal(report.removed, 1, '只删超期导出 zip');
126
+ assert.equal(report.freedBytes, 15, '释放字节 = 被删文件 size');
127
+ await assert.rejects(() => fs.stat(oldExport), '超期导出 zip 已删');
128
+ assert.ok(await fs.stat(newExport), '新导出 zip 保留');
129
+ assert.equal(await fs.readFile(readme, 'utf8'), 'keep', '非 zip 文件保留');
130
+ assert.ok(report.detail.some((s) => s.includes('exports/')), 'detail 含 exports 删除记录');
131
+ } finally {
132
+ await d.cleanup();
133
+ }
134
+ });
135
+
136
+ test('保留期边界:恰好等于保留期 → 不删(超期判定为严格大于)', async () => {
137
+ const d = await makeDataDir();
138
+ try {
139
+ const now = Date.now();
140
+ const zip = path.join(d.tmpDir, 'upload-boundary.zip');
141
+ await fs.writeFile(zip, Buffer.alloc(3));
142
+ await touch(zip, now - TMP_RETENTION_DEFAULT_MS); // 恰好 = 保留期
143
+
144
+ const report = await cleanupCaches({
145
+ tmpDir: d.tmpDir,
146
+ exportsDir: d.exportsDir,
147
+ now: () => now,
148
+ });
149
+
150
+ assert.equal(report.removed, 0, '边界文件不删');
151
+ assert.ok(await fs.stat(zip), '边界 zip 保留');
152
+ } finally {
153
+ await d.cleanup();
154
+ }
155
+ });
156
+
157
+ test('容错:目录不存在 → 不抛错、removed=0', async () => {
158
+ const d = await makeDataDir();
159
+ try {
160
+ const report = await cleanupCaches({
161
+ tmpDir: path.join(d.root, 'no-such-tmp'),
162
+ exportsDir: path.join(d.root, 'no-such-exports'),
163
+ });
164
+ assert.equal(report.removed, 0);
165
+ assert.equal(report.errors, 2, '两个缺失目录各记一次尽力而为跳过');
166
+ } finally {
167
+ await d.cleanup();
168
+ }
169
+ });
@@ -0,0 +1,121 @@
1
+ /**
2
+ * 缓存自动清理:只清「可重建 / 一次性」的临时文件与导出副本。
3
+ *
4
+ * 清理面(保留期内一律不删):
5
+ * - `tmp/`:过期 `.zip` 暂存 + SyncEngine 遗留的 `dsh-sync-pull-*` 目录;
6
+ * - `exports/`:过期的导出产物 ZIP(导出时用户已下载/另存到本地)。
7
+ *
8
+ * **不清理**:`snapshots/`(回滚安全网)与 `sync/`(同步状态/快照)—— 它们是用户数据。
9
+ *
10
+ * 失败语义:任何单项失败只计入 `errors`,不影响主流程(调用方仅记日志)。
11
+ */
12
+ import fs from 'node:fs/promises'
13
+ import path from 'node:path'
14
+
15
+ /** 临时文件缺省保留期:24h(供刷新恢复等窗口继续消费) */
16
+ export const TMP_RETENTION_DEFAULT_MS = 24 * 60 * 60 * 1000
17
+
18
+ /** 导出产物缺省保留期:7 天(导出时用户已通过浏览器下载/另存到本地,host 端副本按周回收) */
19
+ export const EXPORTS_RETENTION_DEFAULT_MS = 7 * 24 * 60 * 60 * 1000
20
+
21
+ /** SyncEngine 在 zipDir(即 tmpDir)下 mkdtemp 的目录前缀(用完即删,崩溃残留由清理兜底) */
22
+ const SYNC_TMP_DIR_PREFIX = 'dsh-sync-pull-'
23
+
24
+ export interface CacheCleanupOptions {
25
+ /** 临时目录($DSH_HOME/dsh-config-manager/tmp) */
26
+ tmpDir: string
27
+ /** 导出产物目录($DSH_HOME/dsh-config-manager/exports) */
28
+ exportsDir: string
29
+ /** 临时文件保留期(缺省 24h) */
30
+ tmpRetentionMs?: number
31
+ /** 导出产物保留期(缺省 7 天) */
32
+ exportsRetentionMs?: number
33
+ /** 时间源(测试注入;缺省 Date.now) */
34
+ now?: () => number
35
+ }
36
+
37
+ export interface CacheCleanupResult {
38
+ /** 删除条目数(文件 + 目录) */
39
+ removed: number
40
+ /** 释放字节数(仅被删文件的 size 累计;目录删除统计为 0) */
41
+ freedBytes: number
42
+ /** 单项失败数(不影响主流程) */
43
+ errors: number
44
+ /** 每条删除记录(相对 dataDir 的描述 + 字节数),供日志/审计 */
45
+ detail: string[]
46
+ }
47
+
48
+ /** 目录是否超期(stat 失败保守视为未超期 → 不删) */
49
+ async function isExpired(target: string, retentionMs: number, nowMs: number): Promise<boolean> {
50
+ try {
51
+ const st = await fs.stat(target)
52
+ return nowMs - st.mtimeMs > retentionMs
53
+ } catch {
54
+ return false
55
+ }
56
+ }
57
+
58
+ /** 删除一个文件/目录并计入报告;目录的 freedBytes 统计为 0(递归统计不划算,用途仅是日志) */
59
+ async function removeEntry(target: string, label: string, result: CacheCleanupResult): Promise<void> {
60
+ try {
61
+ let size = 0
62
+ try {
63
+ const st = await fs.stat(target)
64
+ size = st.isFile() ? st.size : 0
65
+ } catch {
66
+ /* stat 失败仍尝试删除(rm 自己会兜底不存在) */
67
+ }
68
+ await fs.rm(target, { recursive: true, force: true })
69
+ result.removed += 1
70
+ result.freedBytes += size
71
+ result.detail.push(`${label} (${size} bytes)`)
72
+ } catch {
73
+ result.errors += 1
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 执行一次缓存清理(幂等;可重复调用)。
79
+ * 只清理超期(超过保留期)的缓存/临时条目,其余一律保留。
80
+ */
81
+ export async function cleanupCaches(opts: CacheCleanupOptions): Promise<CacheCleanupResult> {
82
+ const nowMs = (opts.now ?? Date.now)()
83
+ const tmpRetentionMs = opts.tmpRetentionMs ?? TMP_RETENTION_DEFAULT_MS
84
+ const exportsRetentionMs = opts.exportsRetentionMs ?? EXPORTS_RETENTION_DEFAULT_MS
85
+ const result: CacheCleanupResult = { removed: 0, freedBytes: 0, errors: 0, detail: [] }
86
+
87
+ // 1) tmpDir:过期 .zip(同步/解密暂存)与 SyncEngine 遗留的 dsh-sync-pull-* 目录
88
+ try {
89
+ const entries = await fs.readdir(opts.tmpDir, { withFileTypes: true })
90
+ for (const entry of entries) {
91
+ const target = path.join(opts.tmpDir, entry.name)
92
+ const isTmpish =
93
+ (entry.isFile() && entry.name.endsWith('.zip')) ||
94
+ (entry.isDirectory() && entry.name.startsWith(SYNC_TMP_DIR_PREFIX))
95
+ if (!isTmpish) continue
96
+ if (await isExpired(target, tmpRetentionMs, nowMs)) {
97
+ await removeEntry(target, `tmp/${entry.name}`, result)
98
+ }
99
+ }
100
+ } catch {
101
+ // tmpDir 不存在/不可读 → 跳过(尽力而为)
102
+ result.errors += 1
103
+ }
104
+
105
+ // 2) exportsDir:过期的导出产物 .zip(导出时已下载/另存到本地,host 端副本按保留期回收)
106
+ try {
107
+ const entries = await fs.readdir(opts.exportsDir, { withFileTypes: true })
108
+ for (const entry of entries) {
109
+ if (!entry.isFile() || !entry.name.endsWith('.zip')) continue
110
+ const target = path.join(opts.exportsDir, entry.name)
111
+ if (await isExpired(target, exportsRetentionMs, nowMs)) {
112
+ await removeEntry(target, `exports/${entry.name}`, result)
113
+ }
114
+ }
115
+ } catch {
116
+ // exportsDir 不存在/不可读 → 跳过
117
+ result.errors += 1
118
+ }
119
+
120
+ return result
121
+ }