@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,317 @@
1
+ /**
2
+ * 崩溃检测 / 归因 / 「最后正常快照」选择(Phase 1 P0-5)。
3
+ *
4
+ * 背景:宿主启动时先读 `<dir>/boot-state.json`(本模块的 BootState),据此判断
5
+ * 「上次启动是否走到过确认成功」:
6
+ * - 首次启动(无 boot-state)→ 不判崩溃;
7
+ * - `prev.ok !== true` → 上次没走到确认成功(进程被杀 / 启动即崩 / dispose 前未标记)→
8
+ * 判崩溃,并按日志尾部签名归因(session 日志损坏 / bundle 声明缺失 / 插件树注册冲突);
9
+ * - `prev.ok === true` → 上次正常。
10
+ * 崩溃时给出「建议动作」枚举(advice)与「最近确认正常时刻」(lastGoodAt),宿主据此选择
11
+ * 恢复目标:`selectLastGoodSnapshot()` 在快照列表中挑出 `createdAt <= lastGoodAt` 的最新一个
12
+ * (跳过 `pre-restore` 双保险快照),再由既有恢复通道执行。
13
+ *
14
+ * 生命周期(宿主接线,本模块只提供纯函数与 IO 原语):
15
+ * 读 prev = readBootState(dir) → alert = computeBootAlert(prev, readCrashLogTail(...))
16
+ * → writeBootState(dir, beginBoot(pid, prev)) → 30 秒后 / dispose 时
17
+ * writeBootState(dir, markBootOk(state))。
18
+ *
19
+ * 与竞品 `boot-state.json` 机制的对应关系:同一份持久化字段、同一套日志签名、同样的
20
+ * 「未确认成功即视为崩溃」判定;差别只在本模块**不产出任何用户可见文案**——全部返回
21
+ * 枚举码(crashReason / advice),由宿主按应用语言映射到 `messages.ts`(建议键名形如
22
+ * `crash.advice.restoreLastGood` / `crash.advice.repairSession` / `crash.advice.checkBundles`
23
+ * / `crash.advice.checkPatchTree`,`advice === 'none'` 时无提示)。
24
+ *
25
+ * 纪律:
26
+ * - 只读读取绝不抛:缺失 / 损坏 / 结构非法一律返回 null;
27
+ * - 写入 best-effort:失败不抛(boot-state 只是诊断数据,绝不能反过来阻断启动);
28
+ * - 写入经 Phase 1 `atomicWriteFile`(目标文件任意时刻要么旧完整、要么新完整);
29
+ * - 本模块不执行恢复动作、不改 DSH 配置、不解析快照目录(避免与 restore.ts 循环依赖);
30
+ * - 零 DSH 运行时依赖(仅 node 内置 + `../utils`),CLI 离线引擎可复用。
31
+ *
32
+ * 语义决策(两处刻意的「清理」行为,宿主若需展示历史崩溃原因请自行留存 alert):
33
+ * - `computeBootAlert`:`crashed === false` 时 `crashReason` 恒为 null —— 健康启动不做崩溃
34
+ * 归因(否则会把正常日志尾部误判成崩溃原因),`lastGoodAt` 另行原样带出;
35
+ * - `markBootOk`:确认成功时清空 `crashReason`,避免陈旧原因跨成功启动延续、
36
+ * 在「成功 → 崩溃」序列里误传染下一次崩溃的归因。
37
+ */
38
+ import fs from 'node:fs/promises';
39
+ import path from 'node:path';
40
+ import { atomicWriteFile } from '../utils/atomic-write.js';
41
+ import { parseJsonSafe } from '../utils/json.js';
42
+ // ---------- 常量 ----------
43
+ /** boot-state 文件名(位于 <dir> 之下)。 */
44
+ const BOOT_STATE_FILE = 'boot-state.json';
45
+ /** 日志尾部默认读取字节数(256 KiB)。 */
46
+ const DEFAULT_LOG_TAIL_BYTES = 262144;
47
+ /** 候选日志所在子目录(<homeDir>/logs/*.log)。 */
48
+ const LOGS_DIR_NAME = 'logs';
49
+ /** 主日志文件名(<homeDir>/dsh.log)。 */
50
+ const MAIN_LOG_FILE = 'dsh.log';
51
+ /** 日志文件后缀(大小写不敏感)。 */
52
+ const LOG_SUFFIX = '.log';
53
+ /** 快照 kind:恢复前的双保险快照,不作为「最后正常」候选。 */
54
+ const PRE_RESTORE_KIND = 'pre-restore';
55
+ /** 合法崩溃原因(读盘校验用;与 CrashKind 联合类型保持一一对应)。 */
56
+ const CRASH_KINDS = ['session-corrupt', 'bundle-check', 'patch-tree', 'unknown'];
57
+ /** 崩溃原因 → 建议动作(crashed=false 时恒为 'none',不经此表)。 */
58
+ const ADVICE_BY_KIND = {
59
+ 'session-corrupt': 'repair-session',
60
+ 'bundle-check': 'check-bundles',
61
+ 'patch-tree': 'check-patch-tree',
62
+ 'unknown': 'restore-last-good',
63
+ };
64
+ // ---------- 日志签名(与竞品 boot-state.json 机制逐字对齐) ----------
65
+ /** 会话日志损坏:Zstandard 压缩的 session 日志读不出来(写入被中断)。 */
66
+ const SESSION_CORRUPT_RE = /corrupt Zstandard session log/i;
67
+ /** bundle 检查失败:profile 未声明 dsh.bundle / bundle 无法解析(插件包元数据被改坏)。 */
68
+ const BUNDLE_CHECK_RE = /declares no dsh\.bundle|cannot resolve profile bundle/i;
69
+ /** patch 树加载失败:重复注册 / loader 条目重复 / 插件加载失败 / 依赖缺失。 */
70
+ const PATCH_TREE_RE = /already registered|duplicate loader entry|failed to load plugin|cannot find (module|package)/i;
71
+ // ---------- 崩溃归因 ----------
72
+ /** 按日志尾部签名分类崩溃原因;无匹配返回 'unknown'。 */
73
+ export function classifyCrashLog(text) {
74
+ if (SESSION_CORRUPT_RE.test(text))
75
+ return 'session-corrupt';
76
+ if (BUNDLE_CHECK_RE.test(text))
77
+ return 'bundle-check';
78
+ if (PATCH_TREE_RE.test(text))
79
+ return 'patch-tree';
80
+ return 'unknown';
81
+ }
82
+ /**
83
+ * advice 由 crashReason 决定:session-corrupt→repair-session, bundle-check→check-bundles,
84
+ * patch-tree→check-patch-tree, unknown→restore-last-good(crashReason 为 null 时同样
85
+ * 回退 restore-last-good:崩溃但无归因证据,只有「回到最后正常」这一条稳妥动作)。
86
+ * crashed=false 时 advice='none'。
87
+ */
88
+ export function adviceFor(kind, crashed) {
89
+ if (!crashed)
90
+ return 'none';
91
+ if (kind === null)
92
+ return 'restore-last-good';
93
+ // 防御:磁盘上的值理论上已校验,运行时仍可能越界 → 保守回退「恢复最后正常快照」
94
+ return ADVICE_BY_KIND[kind] ?? 'restore-last-good';
95
+ }
96
+ // ---------- boot-state 读写 ----------
97
+ /** 普通对象判定(数组 / null / 原始值均不算)。 */
98
+ function isRecord(value) {
99
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
100
+ }
101
+ /** crashReason 是否为合法枚举值。 */
102
+ function isCrashKind(value) {
103
+ return typeof value === 'string' && CRASH_KINDS.includes(value);
104
+ }
105
+ /** 可空字符串字段校验(null 合法;缺失/其它类型非法)。 */
106
+ function isNullableString(value) {
107
+ return value === null || typeof value === 'string';
108
+ }
109
+ /**
110
+ * 结构校验:只有完整且类型正确的对象才算 BootState(不做字段值语义校验 —— 时间戳是否
111
+ * 可解析由消费方决定,避免把「格式怪但可用」的旧数据判死)。
112
+ */
113
+ function parseBootState(value) {
114
+ if (!isRecord(value))
115
+ return null;
116
+ const { startedAt, pid, ok, okAt, lastGoodAt, crashReason } = value;
117
+ if (typeof startedAt !== 'string')
118
+ return null;
119
+ if (typeof pid !== 'number' || !Number.isFinite(pid))
120
+ return null;
121
+ if (typeof ok !== 'boolean')
122
+ return null;
123
+ if (!isNullableString(okAt))
124
+ return null;
125
+ if (!isNullableString(lastGoodAt))
126
+ return null;
127
+ if (crashReason !== null && !isCrashKind(crashReason))
128
+ return null;
129
+ return { startedAt, pid, ok, okAt, lastGoodAt, crashReason };
130
+ }
131
+ /** 只读读取 boot-state;缺失/损坏/非法一律返回 null(绝不抛)。 */
132
+ export async function readBootState(dir) {
133
+ try {
134
+ const text = await fs.readFile(path.join(dir, BOOT_STATE_FILE), 'utf8');
135
+ return parseBootState(parseJsonSafe(text));
136
+ }
137
+ catch {
138
+ // 文件缺失 / 非法 JSON / 读权限 → 与「无 boot-state」同义:不判崩溃
139
+ return null;
140
+ }
141
+ }
142
+ /**
143
+ * 原子写入 boot-state(用 ../utils/atomic-write.ts 的 atomicWriteFile)。失败不抛。
144
+ * 只落盘 BootState 的六个已知字段(避免调用方对象上的额外字段进入持久化文件)。
145
+ */
146
+ export async function writeBootState(dir, state) {
147
+ const persisted = {
148
+ startedAt: state.startedAt,
149
+ pid: state.pid,
150
+ ok: state.ok,
151
+ okAt: state.okAt,
152
+ lastGoodAt: state.lastGoodAt,
153
+ crashReason: state.crashReason,
154
+ };
155
+ try {
156
+ await atomicWriteFile(path.join(dir, BOOT_STATE_FILE), `${JSON.stringify(persisted, null, 2)}\n`);
157
+ }
158
+ catch {
159
+ // boot-state 只是诊断数据:写入失败绝不影响启动/恢复主流程
160
+ }
161
+ }
162
+ // ---------- boot alert ----------
163
+ /**
164
+ * 计算本次启动的 boot alert。
165
+ * - prev 为 null(首次启动)→ crashed=false,lastGoodAt=null,crashReason=null,advice='none';
166
+ * - prev.ok !== true → crashed=true(上次没走到「确认成功」);
167
+ * - crashReason 优先沿用 prev.crashReason(上次已算过),否则若给了 logTail 就用 classifyCrashLog;
168
+ * - crashed=false 时 crashReason 恒为 null(健康启动不做归因,见文件头「语义决策」)。
169
+ */
170
+ export function computeBootAlert(prev, logTail) {
171
+ if (prev === null) {
172
+ return { crashed: false, lastGoodAt: null, crashReason: null, advice: 'none' };
173
+ }
174
+ const crashed = prev.ok !== true;
175
+ const lastGoodAt = prev.lastGoodAt ?? null;
176
+ if (!crashed) {
177
+ return { crashed: false, lastGoodAt, crashReason: null, advice: 'none' };
178
+ }
179
+ const hasLog = logTail !== null && logTail.trim() !== '';
180
+ const crashReason = prev.crashReason ?? (hasLog ? classifyCrashLog(logTail) : null);
181
+ return { crashed: true, lastGoodAt, crashReason, advice: adviceFor(crashReason, true) };
182
+ }
183
+ // ---------- 候选日志与尾部读取 ----------
184
+ /** 读单个文件尾部(最多 maxBytes);不可读/为空返回 null。 */
185
+ async function readFileTail(file, maxBytes) {
186
+ let handle = null;
187
+ try {
188
+ handle = await fs.open(file, 'r');
189
+ const { size } = await handle.stat();
190
+ if (size <= 0)
191
+ return null;
192
+ const start = Math.max(0, size - maxBytes);
193
+ const length = size - start;
194
+ const buf = Buffer.alloc(length);
195
+ await handle.read(buf, 0, length, start);
196
+ const text = buf.toString('utf8');
197
+ return text.length > 0 ? text : null;
198
+ }
199
+ catch {
200
+ // 不存在 / 无权限 / 是目录 / 读取竞态 → 该候选不可用,由调用方试下一个
201
+ return null;
202
+ }
203
+ finally {
204
+ if (handle !== null) {
205
+ try {
206
+ await handle.close();
207
+ }
208
+ catch { /* 关闭失败无需处理 */ }
209
+ }
210
+ }
211
+ }
212
+ /**
213
+ * 从候选日志文件里读尾部(最多 maxBytes,默认 262144),返回第一个非空日志的文本;
214
+ * 无则 null。单个候选不可读(不存在/无权限/是目录)不抛,直接跳到下一个。
215
+ */
216
+ export async function readCrashLogTail(candidates, maxBytes = DEFAULT_LOG_TAIL_BYTES) {
217
+ const limit = Math.floor(maxBytes);
218
+ if (!Number.isFinite(limit) || limit <= 0)
219
+ return null;
220
+ for (const candidate of candidates) {
221
+ const text = await readFileTail(candidate, limit);
222
+ if (text !== null)
223
+ return text;
224
+ }
225
+ return null;
226
+ }
227
+ /** 路径是否为可读常规文件(跟随 symlink;不存在/是目录 → false)。 */
228
+ async function isFile(p) {
229
+ try {
230
+ return (await fs.stat(p)).isFile();
231
+ }
232
+ catch {
233
+ return false;
234
+ }
235
+ }
236
+ /**
237
+ * 列出候选日志路径:`<homeDir>/logs/*.log`(按文件名字典序,稳定可测)与
238
+ * `<homeDir>/dsh.log`(存在才纳入)。`logs` 目录不存在/不可读时返回空数组
239
+ * —— 与「无候选日志」同义(不抛)。
240
+ */
241
+ export async function listCandidateLogs(homeDir) {
242
+ const out = [];
243
+ const logsDir = path.join(homeDir, LOGS_DIR_NAME);
244
+ let names;
245
+ try {
246
+ const entries = await fs.readdir(logsDir, { withFileTypes: true });
247
+ names = entries
248
+ .filter((e) => (e.isFile() || e.isSymbolicLink()) && e.name.toLowerCase().endsWith(LOG_SUFFIX))
249
+ .map((e) => e.name)
250
+ .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
251
+ }
252
+ catch {
253
+ return [];
254
+ }
255
+ for (const name of names)
256
+ out.push(path.join(logsDir, name));
257
+ const main = path.join(homeDir, MAIN_LOG_FILE);
258
+ if (await isFile(main))
259
+ out.push(main);
260
+ return out;
261
+ }
262
+ // ---------- 最后正常快照 ----------
263
+ /** 时间戳解析(非字符串/空串/不可解析 → null)。 */
264
+ function parseTime(value) {
265
+ if (typeof value !== 'string' || value === '')
266
+ return null;
267
+ const ms = Date.parse(value);
268
+ return Number.isNaN(ms) ? null : ms;
269
+ }
270
+ /**
271
+ * 选「最后正常快照」:在 snapshots 中找 createdAt <= lastGoodAt 的**最新**一个,
272
+ * 跳过 kind==='pre-restore'(恢复前双保险快照,不代表「正常状态」)。
273
+ * lastGoodAt 为 null / 非法 → null;无符合项(含 createdAt 不可解析者)→ null。
274
+ * createdAt 相同时保留数组中靠前者。入参为最小结构类型,刻意不 import restore.ts
275
+ * (快照元信息 → 恢复执行 的依赖方向必须单向,避免循环依赖)。
276
+ */
277
+ export function selectLastGoodSnapshot(snapshots, lastGoodAt) {
278
+ const boundary = parseTime(lastGoodAt);
279
+ if (boundary === null)
280
+ return null;
281
+ let best = null;
282
+ let bestTime = Number.NEGATIVE_INFINITY;
283
+ for (const snapshot of snapshots) {
284
+ if (snapshot.kind === PRE_RESTORE_KIND)
285
+ continue;
286
+ const at = parseTime(snapshot.createdAt);
287
+ if (at === null || at > boundary)
288
+ continue;
289
+ if (best === null || at > bestTime) {
290
+ best = snapshot;
291
+ bestTime = at;
292
+ }
293
+ }
294
+ return best;
295
+ }
296
+ // ---------- 启动生命周期辅助 ----------
297
+ /** 启动生命周期辅助:apply 时调用一次,写「正在启动」(ok:false)。 */
298
+ export function beginBoot(pid, prev, now = () => new Date()) {
299
+ return {
300
+ startedAt: now().toISOString(),
301
+ pid,
302
+ ok: false,
303
+ okAt: null,
304
+ // 未确认成功前,「最近正常」与「上次崩溃归因」都从上一次状态延续
305
+ lastGoodAt: prev?.lastGoodAt ?? null,
306
+ crashReason: prev?.crashReason ?? null,
307
+ };
308
+ }
309
+ /**
310
+ * 30 秒后 / dispose 时调用:标记成功并推进 lastGoodAt(ok:true、okAt=lastGoodAt=now)。
311
+ * 同时清空 crashReason:本次启动已确认正常,陈旧归因不得延续到下一次崩溃判定。
312
+ */
313
+ export function markBootOk(state, now = () => new Date()) {
314
+ const iso = now().toISOString();
315
+ return { ...state, ok: true, okAt: iso, lastGoodAt: iso, crashReason: null };
316
+ }
317
+ //# sourceMappingURL=crash-report.js.map
@@ -0,0 +1,68 @@
1
+ import type { MsgFunc } from './messages.ts';
2
+ import type { Manifest } from '../schema/types.ts';
3
+ import type { ConfigAdapter, EncryptionProvider, ExportOptions, ExportReport, HostContext, SecretScanner } from './types.ts';
4
+ /** m1:每导出一个分区前的进度回调信息(Host 侧 run 状态更新用;section = adapter id) */
5
+ export interface SectionProgress {
6
+ section: string;
7
+ /** 当前分区序号(1 起) */
8
+ index: number;
9
+ /** 选中分区总数 */
10
+ total: number;
11
+ }
12
+ export interface ExporterOptions {
13
+ ctx: HostContext;
14
+ adapters: ConfigAdapter[];
15
+ /** Secret 扫描器;缺省用字段名黑名单剥离(m4 可注入强化版) */
16
+ scanner?: SecretScanner;
17
+ /** 加密提供者(m4 用 node:crypto 实现);includeSecrets 时必填;提供时备份标记 encrypted=true */
18
+ encryption?: EncryptionProvider | null;
19
+ /** 插件自身版本(manifest.exporter.version) */
20
+ exporterVersion?: string;
21
+ now?: () => Date;
22
+ /** 消息翻译器(缺省 ctx.msg ?? zh) */
23
+ msg?: MsgFunc;
24
+ /** m1:每导出一个分区前调用(真实进度埋点;不传则无埋点) */
25
+ onSection?: (info: SectionProgress) => void;
26
+ /**
27
+ * 插件数据目录(文件级 vault 位于 <vaultDataDir>/vault,缺省 <homeDir>/dsh-config-manager)。
28
+ * includeSecrets=false 时导出会自动刷新 vault;宿主自定义 dataDir 时应注入实际值
29
+ * (HostContext 不携带 dataDir,故经选项注入)。
30
+ */
31
+ vaultDataDir?: string;
32
+ }
33
+ /** 缺省 SecretScanner:递归黑名单字段剥离(字段名大小写不敏感;二进制/Uint8Array 原样跳过) */
34
+ export declare function defaultSecretScanner(): SecretScanner;
35
+ /**
36
+ * 单文件扫描字节上限(1 MiB)。超大文件只扫描前 1 MiB:
37
+ * 凭据通常出现在配置/脚本的头部;超过上限的剩余部分放弃扫描,避免单个巨型文件拖垮导出。
38
+ */
39
+ export declare const FILE_SECTION_SCAN_MAX_BYTES: number;
40
+ /** 一次导出中所有文件类分区的累计扫描字节上限(16 MiB),防「成千上万小文件」拖慢导出 */
41
+ export declare const FILE_SECTION_SCAN_TOTAL_BUDGET_BYTES: number;
42
+ /** 每个分区最多告警的**不同文件**数(不是 hit 条数);命中仍全量计入 redactedHits(报告统计通道),超出部分由一条汇总告警兜底,避免「真有凭据的文件被静默淹没」或「截断即静默丢失」 */
43
+ export declare const MAX_FILE_SECTION_WARNINGS_PER_SECTION = 5;
44
+ export declare class Exporter {
45
+ private readonly ctx;
46
+ private readonly adapters;
47
+ private readonly scanner;
48
+ private readonly encryption;
49
+ private readonly exporterVersion;
50
+ private readonly now;
51
+ private readonly msg;
52
+ private readonly onSection;
53
+ private readonly vaultDataDir;
54
+ constructor(opts: ExporterOptions);
55
+ /**
56
+ * 导出:收集 → 过滤 → checksum → manifest → ZIP。
57
+ * 返回 zipPath(含文件名)、manifest、报告。
58
+ */
59
+ export(options: ExportOptions): Promise<{
60
+ zipPath: string;
61
+ manifest: Manifest;
62
+ report: ExportReport;
63
+ }>;
64
+ }
65
+ /** 供报告使用:导出器身份(避免与 manifest 常量重复维护) */
66
+ export declare const EXPORTER_INFO: {
67
+ name: string;
68
+ };