@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,99 @@
1
+ /**
2
+ * P1-B:Startup Recovery Barrier。
3
+ *
4
+ * Rev 3 §8.3/§26 要求「recovery classification MUST complete BEFORE destructive schedulers may start」。
5
+ * 本模块提供:
6
+ * - `StartupRecoveryState`:启动分类的显式结果(NORMAL / LOCKED_LIVE / RECOVERY_REQUIRED / NEEDS_ATTENTION / UNKNOWN_STATE)。
7
+ * - `StartupRecoveryController`:`await run()` 完成分类;`startSchedulersIfAllowed()` 只在 NORMAL 下启动 schedulers(幂等)。
8
+ * `failClosed`:任何 inspect 抛错 → 归为 RECOVERY_REQUIRED/NEEDS_ATTENTION,绝不自动 NORMAL,schedulers 不启动。
9
+ *
10
+ * 不依赖全局 flag「稍后同步」赌时序——调用方必须 `await run()` 再据 state 决定。read-only 服务可继续(diagnostics/recovery UI)。
11
+ */
12
+ import { inspectStartup } from './reconcile.ts';
13
+ import type { ReconcileProbeHooks, ReconcileEnv, ReconcileOptions } from './reconcile.ts';
14
+ import type { JournalStore } from './journal.ts';
15
+
16
+ export type StartupRecoveryState =
17
+ | { kind: 'NORMAL' }
18
+ | { kind: 'LOCKED_LIVE'; operationId?: string }
19
+ | { kind: 'RECOVERY_REQUIRED'; operationId?: string }
20
+ | { kind: 'NEEDS_ATTENTION'; operationId?: string }
21
+ | { kind: 'UNKNOWN_STATE'; reason: string };
22
+
23
+ export interface StartupClassifier {
24
+ classify(): Promise<{ state: StartupRecoveryState; safeModeRequired: boolean; recoveryRequired: boolean }>;
25
+ }
26
+
27
+ /** 用 inspectStartup 结果构造分类器。lockState: 'LOCKED'|'STALE_LOCK_DETECTED'|'UNKNOWN_STATE'|'FREE'。 */
28
+ export function classifyStartup(opts: {
29
+ store: JournalStore;
30
+ hooks: ReconcileProbeHooks;
31
+ env: ReconcileEnv;
32
+ options?: ReconcileOptions;
33
+ lockState: 'LOCKED' | 'STALE_LOCK_DETECTED' | 'UNKNOWN_STATE' | 'FREE';
34
+ }): StartupClassifier {
35
+ return {
36
+ async classify() {
37
+ const insp = await inspectStartup(opts.store, opts.hooks, opts.env, opts.options ?? {}, opts.lockState);
38
+ let state: StartupRecoveryState;
39
+ if (opts.lockState === 'LOCKED') {
40
+ // fresh heartbeat:活锁;若仍有 unresolved journal → 视为 live op(LOCKED_LIVE,不作 recovery/接管)
41
+ state = insp.unresolved.length > 0 ? { kind: 'LOCKED_LIVE', operationId: insp.unresolved[0] } : { kind: 'NORMAL' };
42
+ } else if (insp.recoveryRequired) {
43
+ state = { kind: 'RECOVERY_REQUIRED', operationId: insp.unresolved[0] };
44
+ } else if (insp.unresolved.length > 0 || insp.safeModeRequired) {
45
+ state = { kind: 'NEEDS_ATTENTION', operationId: insp.unresolved[0] };
46
+ } else {
47
+ state = { kind: 'NORMAL' };
48
+ }
49
+ return { state, safeModeRequired: insp.safeModeRequired, recoveryRequired: insp.recoveryRequired };
50
+ },
51
+ };
52
+ }
53
+
54
+ export interface StartupSchedulers {
55
+ start(): void;
56
+ }
57
+
58
+ /**
59
+ * StartupRecoveryController:`await run()` 完成后调度器才可启动。
60
+ * `startSchedulersIfAllowed()` 只在 NORMAL 启动(幂等);否则(RECOVERY_REQUIRED/NEEDS_ATTENTION/UNKNOWN/LOCKED_LIVE)
61
+ * 不启动 destructive schedulers(read-only host 仍活,diagnostics/recovery API 可用)。fail-closed:classify 抛错 → RECOVERY_REQUIRED。
62
+ */
63
+ export class StartupRecoveryController {
64
+ private state: StartupRecoveryState = { kind: 'NEEDS_ATTENTION' };
65
+ private settled = false;
66
+ private schedulersStarted = false;
67
+ private readonly classifier: StartupClassifier;
68
+ private readonly schedulers: StartupSchedulers;
69
+ constructor(classifier: StartupClassifier, schedulers: StartupSchedulers) {
70
+ this.classifier = classifier;
71
+ this.schedulers = schedulers;
72
+ }
73
+
74
+ async run(): Promise<StartupRecoveryState> {
75
+ try {
76
+ const r = await this.classifier.classify();
77
+ this.state = r.state;
78
+ } catch (err) {
79
+ // fail closed:inspect 抛错 → 不默认 NORMAL
80
+ this.state = { kind: 'RECOVERY_REQUIRED', operationId: undefined };
81
+ } finally {
82
+ this.settled = true;
83
+ }
84
+ return this.state;
85
+ }
86
+
87
+ get stateValue(): StartupRecoveryState { return this.state; }
88
+ get isSettled(): boolean { return this.settled; }
89
+
90
+ /** 仅在 NORMAL 下启动 schedulers(幂等;返回是否已启动)。 */
91
+ startSchedulersIfAllowed(): boolean {
92
+ if (this.state.kind === 'NORMAL' && !this.schedulersStarted) {
93
+ this.schedulers.start();
94
+ this.schedulersStarted = true;
95
+ return true;
96
+ }
97
+ return false;
98
+ }
99
+ }
@@ -0,0 +1,542 @@
1
+ /**
2
+ * 核心引擎契约类型(对齐 Docs/design/architecture.md §13.2/§13.3/§13.5)。
3
+ *
4
+ * 关键解耦原则:核心引擎只依赖这里的接口,绝不 import DSH 运行时包。
5
+ * HostContext 是 m3 定义、m5 实现的 DSH Service 门面(研究报告 §3.2 的叶子方法最小集),
6
+ * 测试用内存 mock 即可驱动完整导出→导入往返。
7
+ */
8
+ import type { EncryptionInfo, Manifest, SectionId, WorkspaceRecord } from '../schema/types.ts';
9
+ import type { TombstoneKind } from '../schema/tombstones.ts';
10
+ import type { MutationLockPort } from '../utils/env-lock.ts';
11
+ import type { RecursiveListing } from '../utils/recursive-walk.ts';
12
+ import type { Logger } from '../utils/logger.ts';
13
+ import { zhMsg } from './messages.ts';
14
+ import type { MsgFunc } from './messages.ts';
15
+
16
+ /* ---------------- 导出选项与分区产出 ---------------- */
17
+
18
+ export interface ExportOptions {
19
+ /** 是否包含真实秘密(必须配合 encryption 提供者;缺省 false = 只导状态) */
20
+ includeSecrets: boolean;
21
+ /** 仅导出指定分区(缺省 = 全部默认包含分区) */
22
+ only?: SectionId[];
23
+ /** 导出文件路径(缺省自动生成 dsh-config-<date>.zip) */
24
+ outPath?: string;
25
+ /** 导出备注(P0-④:host 写入 exports/.backup-notes.json,随 self 分区迁移;非敏感) */
26
+ note?: string;
27
+ }
28
+
29
+ /** adapter.export() 的产出:数据 + 文件 + 报告计数 + 告警 */
30
+ export interface ExportSection<T = unknown> {
31
+ sectionId: SectionId;
32
+ data: T;
33
+ /** 文件类分区(skills/agentPresets/pluginFiles/sessions)以真实文件形式进入 ZIP */
34
+ files?: { relativePath: string; data: Uint8Array }[];
35
+ counts: Record<string, number>;
36
+ warnings: string[];
37
+ }
38
+
39
+ export interface ValidationResult {
40
+ valid: boolean;
41
+ issues: { path: string; message: string; severity: 'error' | 'warning' }[];
42
+ }
43
+
44
+ /* ---------------- Secret 扫描(m4 可替换实现) ---------------- */
45
+
46
+ export interface SensitiveHit { path: string; field: string; }
47
+
48
+ export interface SecretScanner {
49
+ /** 递归扫描 + 剥离敏感字段值;返回清洗后的数据与命中清单(不泄值) */
50
+ scanAndRedact(data: unknown): { sanitized: unknown; hits: SensitiveHit[] };
51
+ /** 文本级扫描(文件类分区内容),供强化版使用 */
52
+ scanText?(text: string): SensitiveHit[];
53
+ }
54
+
55
+ /* ---------------- DSH Service 门面(m5 对接真实 ctx) ---------------- */
56
+
57
+ export interface NamespaceInfo {
58
+ value: unknown;
59
+ base?: unknown;
60
+ revision: number;
61
+ applies?: string[];
62
+ secrets: { path: string[]; set: boolean }[];
63
+ }
64
+
65
+ export interface SettingsFacade {
66
+ /** 读某 namespace(redactSecrets 剥离密钥值);返回含乐观锁 revision */
67
+ describe(namespace: string, opts?: { redactSecrets?: boolean }): Promise<NamespaceInfo>;
68
+ /** 整体替换(导入/回滚主通道);expectedRevision 不一致时抛 SETTINGS_CONFLICT 类错误 */
69
+ replace(namespace: string, value: unknown, expectedRevision?: number): Promise<void>;
70
+ /** 部分更新(未来 Merge 策略用) */
71
+ update?(namespace: string, patch: unknown, expectedRevision?: number): Promise<void>;
72
+ }
73
+
74
+ export interface CredentialsFacade {
75
+ /** 只返回状态,永不返回值 */
76
+ describe(ref: string): Promise<{ configured: boolean; source?: string; writable?: boolean }>;
77
+ set(ref: string, value: string): Promise<void>;
78
+ unset(ref: string): Promise<void>;
79
+ }
80
+
81
+ export interface PluginInfo {
82
+ name: string;
83
+ version: string;
84
+ enabled: boolean;
85
+ isBundle?: boolean;
86
+ inBundles?: string[];
87
+ /** 声明依赖 spec(profile package.json dependencies 原样);文件视图来自 readInstalled */
88
+ spec?: string;
89
+ }
90
+
91
+ export interface PluginsFacade {
92
+ listInstalled(): Promise<PluginInfo[]>;
93
+ /** 安装/更新插件;spec 为来源记录的声明依赖 spec(如 github:user/repo),缺省按裸包名装 npm 最新版。
94
+ * signal 可选:中止时宿主应 kill 子进程并清理半装状态(恢复 package.json + 删 node_modules/<pkg>)。 */
95
+ install(pkg: string, spec?: string, signal?: AbortSignal): Promise<{ needsRestart: boolean }>;
96
+ }
97
+
98
+ export interface WorkspaceFacade {
99
+ listRecords(): Promise<WorkspaceRecord[]>;
100
+ writeRecord(record: WorkspaceRecord): Promise<void>;
101
+ removeRecord?(id: string): Promise<void>;
102
+ }
103
+
104
+ export interface PatchChange { lineId: string; raw: unknown; action: 'insert' | 'update' | 'remove'; }
105
+
106
+ export interface PatchFileFacade {
107
+ readPatchLines(file: string): Promise<{ lineId: string; raw: unknown }[]>;
108
+ applyPatchChanges(file: string, changes: PatchChange[]): Promise<void>;
109
+ }
110
+
111
+ export interface FileSystemFacade {
112
+ readFile(relPath: string): Promise<Uint8Array>;
113
+ writeFile(relPath: string, data: Uint8Array): Promise<void>;
114
+ exists(relPath: string): Promise<boolean>;
115
+ copy(from: string, to: string): Promise<void>;
116
+ remove(relPath: string): Promise<void>;
117
+ listRecursive(dir: string): Promise<string[]>;
118
+ /**
119
+ * 与 listRecursive 相同的遍历,但**跟随**目录 junction / 符号链接,并附带被跳过的链接清单
120
+ * (issue #37)。可选:未实现时调用方回退到 listRecursive(行为与旧版一致)。
121
+ */
122
+ listRecursiveDetailed?(dir: string): Promise<RecursiveListing>;
123
+ mkdir(dir: string): Promise<void>;
124
+ }
125
+
126
+ /** DSH 运行时门面:m3 只依赖此接口;m5 用真实 ctx.settings/credentials/… 实现 */
127
+ export interface HostContext {
128
+ platform: string;
129
+ arch: string;
130
+ homeDir: string;
131
+ dshVersion: string;
132
+ log: Logger;
133
+ settings: SettingsFacade;
134
+ credentials: CredentialsFacade;
135
+ plugins: PluginsFacade;
136
+ workspace: WorkspaceFacade;
137
+ patchFile: PatchFileFacade;
138
+ fs: FileSystemFacade;
139
+ /** 当前管理的 DSH profile 名(如 web);引擎用它定位 profiles/<profile>/cordis.patch.yml。宿主不暴露时缺省 */
140
+ profile?: string;
141
+ /**
142
+ * 消息翻译器(zh/en 目录,见 messages.ts)。由宿主按 DSH 应用语言注入;
143
+ * 缺省 zh(改造前行为)。引擎与适配器用它生成所有用户可见动态文案。
144
+ */
145
+ msg?: MsgFunc;
146
+ /**
147
+ * 跨进程环境锁契约(Phase 2,可选注入)。宿主在构造时注入 GLOBAL EXCLUSIVE MUTATION LOCK
148
+ * 的 port;核心 destructive 入口用 runWithMutationLock(ctx.mutationLock, …) 包住 ——
149
+ * 无有效父 token → acquire(被别的进程/操作持有则抛 EnvironmentLockUnavailableError),
150
+ * 有有效父 token(nested rollback 等)→ reuse,不 reacquire。
151
+ * 测试 mock 缺省不注入 → 无锁环境(不锁定、不抛)。绝不用进程级 reentrancy 判断嵌套。
152
+ */
153
+ mutationLock?: MutationLockPort;
154
+ /**
155
+ * Phase 3 SAFE MODE:同步谓词(读内存标志),供 runWithMutationLock/withMutationLock 的
156
+ * isBlocked 注入(env-lock 不识 policy)。true → 阻断 destructive。
157
+ */
158
+ safeModeIsBlocked?: () => boolean;
159
+ /** Phase 3 恢复/事务(JournalStore + reconcile + runJournaled/runExternalIntent)。宿主注入。 */
160
+ phase3Recovery?: import('./phase3-host.ts').Phase3Recovery;
161
+ }
162
+
163
+ /* ---------------- 导入计划(§13.3 十类 + 决策) ---------------- */
164
+
165
+ export type PlanItemKind =
166
+ | 'Create' | 'Update' | 'Skip' | 'Conflict' | 'Install'
167
+ | 'MissingSecret' | 'MissingDependency' | 'PathMapping' | 'Warning' | 'Error';
168
+
169
+ export type ItemResolution = 'keepCurrent' | 'useImported' | 'review';
170
+ export type GlobalConflictStrategy = 'merge' | 'replace' | 'skipExisting';
171
+
172
+ export interface ConflictDecision { itemId: string; resolution: ItemResolution; }
173
+
174
+ export interface PathMapping {
175
+ oldPrefix: string;
176
+ newPrefix: string;
177
+ appliesTo: ('workspaces' | 'mcp' | 'pluginConfig' | 'skills')[];
178
+ }
179
+
180
+ export interface PathIssue {
181
+ kind: 'missing' | 'platformMismatch' | 'homeMismatch';
182
+ value: string;
183
+ mappedTo?: string;
184
+ }
185
+
186
+ export interface SnapshotTarget { adapter: SectionId; ref: string; }
187
+
188
+ export interface PlanItem {
189
+ id: string; // 稳定项 id(plugin:pkg / prompt:name / workspace:<id> …)
190
+ kind: PlanItemKind;
191
+ adapter: SectionId;
192
+ description: string;
193
+ detail?: string;
194
+ severity: 'info' | 'warning' | 'error';
195
+ conflict?: ConflictDecision;
196
+ pathMapping?: PathMapping;
197
+ missingDependency?: string;
198
+ target?: SnapshotTarget; // 该项将修改的目标(快照登记用)
199
+ }
200
+
201
+ /** applyItem 结果。warning=true 表示“未应用但属非致命”(如目标路径不可达/需人工映射),
202
+ * 引擎记为警告、不触发失败回滚(§34.17 单项失败不拖垮整体)。 */
203
+ export interface ApplyResult { ok: boolean; message?: string; needsRestart?: boolean; warning?: boolean; }
204
+
205
+ /* ---------------- 三段式输入输出 ---------------- */
206
+
207
+ export interface ImportAnalysis {
208
+ valid: boolean;
209
+ errors: string[];
210
+ warnings: string[];
211
+ compatibility: 'excellent' | 'good' | 'partial' | 'unsupported';
212
+ sectionsInZip: SectionId[];
213
+ /**
214
+ * 备份 manifest 声明启用、但**本版本不认识**的分区 id(不在 `SECTION_IDS` 中)。
215
+ *
216
+ * 语义(G-01/G-02/G-03):这些分区的数据被跳过、未导入,且**绝不**计入
217
+ * `missingSections` —— 它们并非「备份声明了但文件缺失」,而是「本插件不认识」。
218
+ *
219
+ * 当前用户可见路径是 `warnings` 里的文案键 `import.unsupportedSections`
220
+ * (导入向导直接渲染 `analysis.warnings`);本字段供第三方实现者与
221
+ * 后续 UI 做结构化展示(例如把「未知分区」与「版本过高」分列)。**尚无 UI 消费点。**
222
+ */
223
+ unsupportedSections: string[];
224
+ /**
225
+ * 已知分区、但其数据 `version` **高于**本版本支持的 1 → 该分区已被跳过(G-05)。
226
+ *
227
+ * 与 `unsupportedSections` 的区别:那个是「本插件不认识这个分区」,这个是
228
+ * 「认识这个分区,但它来自更新的格式」。两者都只告警、不阻断整个 bundle。
229
+ *
230
+ * 当前用户可见路径是 `warnings` 里的文案键 `import.unsupportedSectionVersion`;
231
+ * 本字段供第三方实现者与后续 UI 与 `unsupportedSections` 分列展示。**尚无 UI 消费点。**
232
+ */
233
+ unsupportedVersions: { section: SectionId; version: number }[];
234
+ pluginSummary: { installed: number; toInstall: number };
235
+ pathIssues: PathIssue[];
236
+ secretCount: number;
237
+ dependencyIssues: { item: string; dependency: string }[];
238
+ /** 备份是否加密(manifest.security.encrypted):加密备份的凭据必须用解密密码恢复 */
239
+ encrypted: boolean;
240
+ }
241
+
242
+ export interface ImportDecisions {
243
+ strategy: GlobalConflictStrategy;
244
+ resolutions: Record<string, ItemResolution>;
245
+ pathMappings: PathMapping[];
246
+ }
247
+
248
+ export interface ImportPlan {
249
+ items: PlanItem[];
250
+ globalStrategy: GlobalConflictStrategy;
251
+ pathMappings: PathMapping[];
252
+ missingSecrets: { ref: string; required: boolean }[];
253
+ needsRestart: boolean;
254
+ estimatedActions: Record<SectionId, number>;
255
+ /** F4:被删除墓碑(tombstone)过滤掉的计划项(缺省/空数组 = 无过滤;UI 据此提示用户) */
256
+ skippedTombstoned?: SkippedTombstone[];
257
+ }
258
+
259
+ /** F4:被墓碑过滤的计划项记录(条目级:kind+id;分区级:kind='section',id=分区 id) */
260
+ export interface SkippedTombstone {
261
+ kind: TombstoneKind;
262
+ id: string;
263
+ adapter: SectionId;
264
+ }
265
+
266
+ export interface ExecutedItem {
267
+ itemId: string;
268
+ /** warning = 未应用但非致命(目标不可达等),不计入失败、不触发回滚 */
269
+ status: 'ok' | 'skipped' | 'warning' | 'failed';
270
+ message?: string;
271
+ /** 用户主动跳过(导入中点击「跳过当前插件」):status 为 skipped 且此标记为 true。
272
+ * 结果页据此区分「用户跳过」与「引擎跳过」,并提供重试入口。 */
273
+ skippedByUser?: boolean;
274
+ }
275
+
276
+ export interface ImportResult {
277
+ ok: boolean;
278
+ executed: ExecutedItem[];
279
+ needsRestart: boolean;
280
+ missingSecrets: string[];
281
+ warnings: string[];
282
+ rollback: RollbackReport | null;
283
+ snapshotId: string | null;
284
+ /** F4:本次导入被删除墓碑过滤掉的条目(缺省/空 = 无过滤;UI 据此提示用户) */
285
+ skippedTombstoned?: SkippedTombstone[];
286
+ }
287
+
288
+ /* ---------------- 导入上下文(传给 adapter.analyzeImport / applyItem) ---------------- */
289
+
290
+ export interface ImportContext {
291
+ manifest: Manifest;
292
+ targetPlatform: string;
293
+ /** 目标 DSH 门面(adapter 比较目标状态 / 写入 / 读取数据用) */
294
+ target: HostContext;
295
+ /** 已由 PathMapper 处理后的各分区最终数据(adapter.applyItem 从这取写入内容) */
296
+ sections: Map<SectionId, unknown>;
297
+ pathMappings: PathMapping[];
298
+ resolutions: Record<string, ItemResolution>;
299
+ /** 用户补录的秘密值(仅内存,永不落盘/日志) */
300
+ secretInputs: Record<string, string>;
301
+ decryptedCredentials?: Map<string, string>;
302
+ log: Logger;
303
+ /** 消息翻译器(analyzer 注入;适配器用它生成计划项描述/校验/结果消息) */
304
+ msg: MsgFunc;
305
+ /**
306
+ * 执行日志回调(executeImportPlan 注入;适配器在发出子进程命令等动作时调用)。
307
+ * 行文本只允许非敏感内容(命令/操作摘要),绝不写入密钥/密码/补录值;
308
+ * Dry Run / 分析阶段未注入(undefined),调用方可空调用。
309
+ */
310
+ onLog?: (line: string) => void;
311
+ /**
312
+ * 当前计划项的中止信号(executeImportPlan 注入;适配器在启动子进程时传给宿主 install)。
313
+ * 用户点击「跳过当前插件」时宿主 abort 该信号 → 子进程被 kill → 该项标记为 user-skipped。
314
+ * 非插件项 / Dry Run 阶段为 undefined。
315
+ */
316
+ signal?: AbortSignal;
317
+ }
318
+
319
+ /* ---------------- Snapshot / Rollback(§8) ---------------- */
320
+
321
+ export type SnapshotEntryKind = 'settingsNamespace' | 'credential' | 'patchLine' | 'file' | 'workspaceRecord';
322
+
323
+ export interface SnapshotEntry {
324
+ kind: SnapshotEntryKind;
325
+ adapter: SectionId;
326
+ ref: string;
327
+ /** 原值(credential 条目不含值,仅 existed 标志) */
328
+ before: unknown;
329
+ revision?: number;
330
+ /** file 条目:原文件副本在快照存储中的位置 */
331
+ copiedTo?: string;
332
+ /** credential/file 条目:原目标是否存在 */
333
+ existed?: boolean;
334
+ /** 所属快照 id(file 条目回滚读取 blob 时使用) */
335
+ snapshotId?: string;
336
+ }
337
+
338
+ /** 快照生命周期状态(M1 增强;旧快照无此字段,视为未知/兼容) */
339
+ export type SnapshotStatus = 'pending' | 'done' | 'rolled-back';
340
+
341
+ /** 快照 readiness(Phase 4):CREATING = 未完成不可用;READY = 已验证可恢复。旧快照无此字段 → LEGACY。 */
342
+ export type SnapshotReadiness = 'CREATING' | 'READY';
343
+
344
+ /** 快照完整性 manifest(Phase 4,F1):blob hashes + 破坏性内容 hash。 */
345
+ export interface SnapshotManifest {
346
+ schemaVersion: number;
347
+ snapshotId: string;
348
+ entryCount: number;
349
+ /** blobPath → sha256(blob 完整性) */
350
+ blobHashes: Record<string, string>;
351
+ /** 破坏性内容(entries + hostFileBackups + beforePlugins)的 sha256;稳定(不含 readiness/status) */
352
+ metadataHash: string;
353
+ }
354
+
355
+ /** 宿主整文件备份登记(M1):导入前对 $DSH_HOME 关键文件的整文件快照。
356
+ * relPath 相对 $DSH_HOME(如 settings.yaml / cordis.patch.yml / profiles/<p>/cordis.patch.yml),
357
+ * blobPath 为快照内 blob 路径(existed=false 时为空串,表示该文件当时不存在)。 */
358
+ export interface HostFileBackup {
359
+ relPath: string;
360
+ blobPath: string;
361
+ existed: boolean;
362
+ }
363
+
364
+ export interface Snapshot {
365
+ id: string;
366
+ createdAt: string;
367
+ sourceZip: string;
368
+ entries: SnapshotEntry[];
369
+ /** 生命周期状态:pending(已生成,导入未完成)/ done(导入成功)/ rolled-back(失败已回滚)。旧快照缺省 */
370
+ status?: SnapshotStatus;
371
+ /** 导入前已安装插件清单(M2 restore 撤销插件时与当前已装对比)。旧快照缺省 */
372
+ beforePlugins?: PluginInfo[];
373
+ /** 宿主整文件备份(settings.yaml / settings.json / cordis.patch.yml / profiles/<p>/cordis.patch.yml)。旧快照缺省 */
374
+ hostFileBackups?: HostFileBackup[];
375
+ /** 置顶标记(P1-⑧):置顶快照在保留清理(自动删最旧)中豁免,需用户手动删除 */
376
+ pinned?: boolean;
377
+ // ---- Phase 4 新增(F1:operation-bound + integrity + readiness)----
378
+ /** 绑定 upgrade operation(journal.operationId ↔ snapshot.operationId) */
379
+ operationId?: string;
380
+ /** 来源操作类型(import/profile-switch/sync-apply/reinstall) */
381
+ operationType?: string;
382
+ /** 环境绑定(journal.environmentFingerprint ↔ snapshot.environmentFingerprint) */
383
+ environmentFingerprint?: string;
384
+ /** ownership epoch(journal.ownerInstanceId ↔ snapshot.ownerInstanceId) */
385
+ ownerInstanceId?: string;
386
+ /** readiness:CREATING = 未完成不可用;READY = 已验证可恢复。旧快照缺省 → LEGACY */
387
+ readiness?: SnapshotReadiness;
388
+ /** 完整性 manifest(blob hashes + 破坏性内容 hash) */
389
+ manifest?: SnapshotManifest;
390
+ }
391
+
392
+ /** 快照存储(默认文件实现见 core/backup.ts;测试可用内存实现) */
393
+ export interface SnapshotStore {
394
+ save(snapshot: Snapshot, blobs?: Map<string, Uint8Array>): Promise<string>;
395
+ load(id: string): Promise<Snapshot>;
396
+ readBlob(id: string, blobPath: string): Promise<Uint8Array>;
397
+ /** 标记快照生命周期状态(导入成功→done;失败回滚→rolled-back;持久化由实现负责) */
398
+ updateStatus(id: string, status: SnapshotStatus): Promise<void>;
399
+ }
400
+
401
+ /**
402
+ * Phase 4 生产 journal↔snapshot 绑定 context(由宿主注入引擎,引擎在首 destructive side effect 前调用)。
403
+ * 保证「快照 durable+verified 且 journal 已知」先于任何写。结构上兼容 phase3-host 的 JournalRunContext;
404
+ * 这里用最小接口避免 core 引擎依赖 phase3 宿主实现(显式 ctx,无 process-global)。
405
+ */
406
+ /** 逐计划项 WAL step 记录(P2-B,Phase 8):供 reconcile 判精度。 */
407
+ export interface JournalStepRecord {
408
+ /** 稳定 step id(= plan item id;跨进程稳定)。 */
409
+ id: string;
410
+ adapter: string;
411
+ kind: string;
412
+ /** 目标引用(文件类项 = 绝对目标路径,供 reconcile 指纹判定;非文件项可为空串)。 */
413
+ ref: string;
414
+ /** 外部副作用(非文件项,如 settings/plugins/patchLine)→ reconcile 一律保守。 */
415
+ external: boolean;
416
+ status?: 'planned' | 'done' | 'failed' | 'skipped' | 'attention';
417
+ /** side effect 前目标内容指纹(null = 不可指纹)。 */
418
+ beforeFp?: string | null;
419
+ /** side effect 后重读磁盘指纹(null = 不可指纹)。 */
420
+ afterFp?: string | null;
421
+ /** 该项的结论文案(issue #35:安装失败与「用户跳过」必须可区分)。 */
422
+ message?: string | null;
423
+ }
424
+
425
+ export interface TransactionSnapshotContext {
426
+ operationId: string;
427
+ operationType: string;
428
+ environmentFingerprint: string;
429
+ ownerInstanceId: string;
430
+ /** 记录 journal.snapshotId 并推进 SNAPSHOT_CREATED(快照已 durable+verified 后调用)。 */
431
+ bindSnapshot: (snapshotId: string) => Promise<void>;
432
+ /** 首个 destructive side effect 前调用:SNAPSHOT_CREATED→APPLYING。 */
433
+ markApplying: () => Promise<void>;
434
+ /**
435
+ * 逐计划项 WAL(P2-B,可选):记录一个将执行/已执行的 step。
436
+ * 文件类项带 beforeFp/afterFp(可证明);非文件项 external=true(reconcile 维持保守)。
437
+ * 不实现/不传 = 无逐项 journal(opaque intent,保持 Phase 3 行为)。
438
+ */
439
+ recordStep?: (step: JournalStepRecord) => Promise<void>;
440
+ }
441
+
442
+ export interface RollbackReport {
443
+ full: boolean;
444
+ restored: string[];
445
+ failed: { item: string; reason: string; manualHint?: string }[];
446
+ }
447
+
448
+ /* ---------------- 兼容性(§13.3 注释规则) ---------------- */
449
+
450
+ export interface CompatibilityInput {
451
+ sourceDsh: string;
452
+ targetDsh: string;
453
+ sourcePlatform: string;
454
+ targetPlatform: string;
455
+ schemaVersion: number;
456
+ missingSections: SectionId[];
457
+ }
458
+
459
+ export type CompatibilityScore = 'excellent' | 'good' | 'partial' | 'unsupported';
460
+
461
+ /* ---------------- 导出报告(规范 §21) ---------------- */
462
+
463
+ export interface ExportReport {
464
+ included: { section: SectionId; counts: Record<string, number> }[];
465
+ excluded: SectionId[];
466
+ security: {
467
+ secretsExcluded: boolean;
468
+ containsSecrets: boolean;
469
+ encrypted: boolean;
470
+ redactedHits: number;
471
+ /** 本次导出镜像到本机 vault 的敏感文件数(文件级 vault;0 或缺失 = 未镜像) */
472
+ vaultRefreshed?: number;
473
+ };
474
+ file: { name: string; sizeBytes: number };
475
+ warnings: string[];
476
+ }
477
+
478
+ /* ---------------- ConfigAdapter 契约(m5 实现;§13.2) ---------------- */
479
+
480
+ export type Portability = 'portable' | 'deviceSpecific' | 'platformSpecific';
481
+
482
+ export interface ConfigAdapter<TSection = unknown> {
483
+ readonly id: SectionId;
484
+ readonly displayName: string;
485
+ readonly defaultIncluded: boolean;
486
+ readonly portability: Portability;
487
+
488
+ /** 读取当前 DSH 该类别配置 → 导出数据(无秘密值) */
489
+ export(ctx: HostContext, options: ExportOptions): Promise<ExportSection<TSection>>;
490
+
491
+ /** 分析导入数据与目标 DSH 的差异 → 计划项(纯计算,零写入) */
492
+ analyzeImport(data: TSection, ctx: ImportContext): Promise<PlanItem[]>;
493
+
494
+ /** 执行单个计划项(Importer 引擎按阶段调度) */
495
+ applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
496
+
497
+ /** 结构校验 */
498
+ validate(data: TSection, msg?: MsgFunc): Promise<ValidationResult>;
499
+
500
+ /** 可选:导入前快照(缺省用引擎通用快照) */
501
+ snapshot?(targets: SnapshotTarget[], ctx: HostContext): Promise<SnapshotEntry[]>;
502
+
503
+ /** 可选:针对本 adapter 的补偿动作 */
504
+ rollback?(entries: SnapshotEntry[], ctx: HostContext): Promise<void>;
505
+ }
506
+
507
+ /* ---------------- 加密提供者(m4 用 node:crypto 实现) ---------------- */
508
+
509
+ export interface EncryptionProvider {
510
+ encrypt(plaintext: string): Promise<{ blob: Uint8Array; info: EncryptionInfo }>;
511
+ /** authTag 校验失败必须抛错 */
512
+ decrypt(blob: Uint8Array, info: EncryptionInfo, password: string): Promise<string>;
513
+ }
514
+
515
+ /* ---------------- 错误类型 ---------------- */
516
+
517
+ /** 导入被确认前拒绝执行(安全阀) */
518
+ export class ImportNotConfirmedError extends Error {
519
+ constructor(msg?: MsgFunc) {
520
+ super((msg ?? zhMsg)('import.notConfirmed'));
521
+ this.name = 'ImportNotConfirmedError';
522
+ }
523
+ }
524
+
525
+ /** 导入失败:触发回滚后抛出,携带结果供 UI 展示 */
526
+ export class ImportFailedError extends Error {
527
+ readonly result: ImportResult;
528
+ constructor(message: string, result: ImportResult) {
529
+ super(message);
530
+ this.name = 'ImportFailedError';
531
+ this.result = result;
532
+ }
533
+ }
534
+
535
+ /** 当前计划项被用户跳过(导入中点击「跳过当前插件」中止子进程)。
536
+ * 宿主 install 中止时抛出;引擎在 applyOne 捕获并记为 skipped + skippedByUser。 */
537
+ export class ImportUserSkippedError extends Error {
538
+ constructor(msg?: MsgFunc) {
539
+ super((msg ?? zhMsg)('import.userSkipped'));
540
+ this.name = 'ImportUserSkippedError';
541
+ }
542
+ }