@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,146 @@
1
+ /**
2
+ * 报告渲染(规范 §21 导出报告 / §22 导入报告 / §17 回滚报告,m6-ui)。
3
+ *
4
+ * 纯文本渲染:输出用户可读的多行文本(未来 React 客户端可直接替换为组件渲染)。
5
+ * 导入报告按分区统计:从 ExecutedItem.itemId 前缀推断所属分区(与 adapters 的 id 规则一致)。
6
+ */
7
+ import type { SectionId } from '../schema/types.ts';
8
+ import type {
9
+ ExecutedItem, ExportReport, ImportResult, RollbackReport,
10
+ } from '../core/types.ts';
11
+ import type { ImportResultAction, ImportSectionStat } from './types.ts';
12
+ import { zhUiT, type UiT } from './i18n.ts';
13
+
14
+ /* ---------------- §21 导出报告 ---------------- */
15
+
16
+ export function renderExportReport(report: ExportReport, t: UiT = zhUiT): string {
17
+ const lines: string[] = [t('report.backupCreated'), ''];
18
+ lines.push(t('report.included'));
19
+ for (const { section, counts } of report.included) {
20
+ const detail = Object.entries(counts)
21
+ .map(([k, v]) => `${v} ${k}`)
22
+ .join(', ');
23
+ lines.push(` ✓ ${section}${detail !== '' ? ` (${detail})` : ''}`);
24
+ }
25
+ lines.push('');
26
+ if (report.excluded.length > 0) {
27
+ lines.push(t('report.excluded'));
28
+ for (const s of report.excluded) lines.push(` ○ ${s}`);
29
+ lines.push('');
30
+ }
31
+ lines.push(t('report.security'));
32
+ lines.push(` ✓ ${t('report.apiKeysExcluded')} ${report.security.secretsExcluded ? t('report.yes') : t('report.no')}`);
33
+ lines.push(` ✓ ${t('report.containsSecrets')} ${report.security.containsSecrets ? t('report.yesEncrypted') : t('report.no')}`);
34
+ lines.push(` ✓ ${t('report.encrypted')} ${report.security.encrypted ? t('report.yes') : t('report.no')}`);
35
+ if (report.security.redactedHits > 0) lines.push(` ⚠ ${t('report.redacted', { count: String(report.security.redactedHits) })}`);
36
+ lines.push('');
37
+ lines.push(`${t('report.file')} ${report.file.name} (${formatBytes(report.file.sizeBytes)})`);
38
+ for (const w of report.warnings) lines.push(` ⚠ ${w}`);
39
+ return lines.join('\n');
40
+ }
41
+
42
+ /* ---------------- §22 导入报告 ---------------- */
43
+
44
+ /** 从 itemId 前缀推断所属分区(与 adapters id 规则对齐;未知归 'other') */
45
+ export function sectionFromItemId(itemId: string): SectionId | 'other' {
46
+ if (itemId.startsWith('settings:')) return 'settings';
47
+ if (itemId.startsWith('ui:')) return 'ui';
48
+ if (itemId.startsWith('provider:')) return 'providers';
49
+ if (itemId.startsWith('plugin:') || itemId.startsWith('patch:')) return 'plugins';
50
+ if (itemId.startsWith('mcp:')) return 'mcp';
51
+ if (itemId.startsWith('prompt:')) return 'prompts';
52
+ if (itemId.startsWith('workspace:')) return 'workspaces';
53
+ if (itemId.startsWith('secret:')) return 'credentialsStatus';
54
+ if (itemId.startsWith('skills:')) return 'skills';
55
+ if (itemId.startsWith('agentPresets:')) return 'agentPresets';
56
+ if (itemId.startsWith('agentInstructions:')) return 'agentInstructions';
57
+ if (itemId.startsWith('pluginFiles:')) return 'pluginFiles';
58
+ if (itemId.startsWith('sessions:')) return 'sessions';
59
+ return 'other';
60
+ }
61
+
62
+ /** 按分区聚合执行结果(统计 + 明细) */
63
+ export function importSectionStats(executed: readonly ExecutedItem[]): ImportSectionStat[] {
64
+ const bySection = new Map<string, ImportSectionStat>();
65
+ for (const e of executed) {
66
+ const section = sectionFromItemId(e.itemId);
67
+ let stat = bySection.get(section);
68
+ if (!stat) {
69
+ stat = { section: section as SectionId, ok: 0, skipped: 0, warned: 0, failed: 0, items: [] };
70
+ bySection.set(section, stat);
71
+ }
72
+ if (e.status === 'ok') stat.ok += 1;
73
+ else if (e.status === 'skipped') stat.skipped += 1;
74
+ else if (e.status === 'warning') stat.warned += 1;
75
+ else stat.failed += 1;
76
+ stat.items.push(e);
77
+ }
78
+ return [...bySection.values()];
79
+ }
80
+
81
+ /** 导入报告渲染(含回滚状态;§22 动作按钮由 suggestedActions 给出) */
82
+ export function renderImportReport(result: ImportResult, t: UiT = zhUiT): string {
83
+ const lines: string[] = [result.ok ? t('report.importComplete') : t('report.importFailed'), ''];
84
+ // F4:被删除墓碑过滤的条目提示(用户明确删过、不复活)
85
+ if ((result.skippedTombstoned?.length ?? 0) > 0) {
86
+ lines.push(t('report.tombstonedSkipped', { count: String(result.skippedTombstoned!.length) }));
87
+ lines.push('');
88
+ }
89
+ const stats = importSectionStats(result.executed);
90
+ for (const s of stats) {
91
+ const parts: string[] = [];
92
+ if (s.ok > 0) parts.push(`✓ ${s.ok} ${t('report.importedRestored')}`);
93
+ if (s.skipped > 0) parts.push(`- ${s.skipped} ${t('report.skipped')}`);
94
+ if (s.warned > 0) parts.push(`⚠ ${s.warned} ${t('report.needAttention')}`);
95
+ if (s.failed > 0) parts.push(`✗ ${s.failed} ${t('report.failed')}`);
96
+ lines.push(`${s.section}: ${parts.join(' ') || t('report.noChanges')}`);
97
+ // 失败/警告项给出可操作原因(§23)
98
+ for (const it of s.items) {
99
+ if (it.status === 'failed' || it.status === 'warning') {
100
+ lines.push(` ${it.status === 'failed' ? t('report.reason') : t('report.note')}: ${it.message ?? t('report.unknownReason')}`);
101
+ }
102
+ }
103
+ }
104
+ if (result.missingSecrets.length > 0) {
105
+ lines.push(`${t('report.secrets')} ⚠ ${t('report.credentialsNeedEntry', { count: String(result.missingSecrets.length) })}`);
106
+ }
107
+ if (result.needsRestart) {
108
+ lines.push(t('report.restartPluginsMcp'));
109
+ }
110
+ for (const w of result.warnings) lines.push(`⚠ ${w}`);
111
+ if (result.rollback) {
112
+ lines.push('');
113
+ lines.push(renderRollbackReport(result.rollback, t));
114
+ }
115
+ return lines.join('\n');
116
+ }
117
+
118
+ /** 结果页动作按钮(§22)。报告已内联展示全部失败/警告项的原因与回滚详情(§23),
119
+ * 不再提供空操作的 Fix Issues / View Details 按钮——仅保留「完成」。 */
120
+ export function suggestedActions(_result: ImportResult): ImportResultAction[] {
121
+ return ['done'];
122
+ }
123
+
124
+ /* ---------------- §17 回滚报告 ---------------- */
125
+
126
+ /** 回滚报告渲染(full / partial + 人工恢复清单) */
127
+ export function renderRollbackReport(rr: RollbackReport, t: UiT = zhUiT): string {
128
+ if (rr.full) {
129
+ return t('report.rollbackFull');
130
+ }
131
+ const lines = [t('report.rollbackPartial')];
132
+ lines.push(t('report.rollbackManual'));
133
+ for (const f of rr.failed) {
134
+ lines.push(` - ${f.item}: ${f.reason}${f.manualHint ? ` (${f.manualHint})` : ''}`);
135
+ }
136
+ if (rr.restored.length > 0) lines.push(t('report.restored', { count: String(rr.restored.length) }));
137
+ return lines.join('\n');
138
+ }
139
+
140
+ /* ---------------- 工具 ---------------- */
141
+
142
+ export function formatBytes(n: number): string {
143
+ if (n < 1024) return `${n} B`;
144
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
145
+ return `${(n / (1024 * 1024)).toFixed(1)} MB`;
146
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * UI 层测试辅助(m6-ui):mock core 调用与样本数据。
3
+ * 仅供 src/ui/*.test.ts 使用,不参与生产构建语义。
4
+ */
5
+ import type { Manifest } from '../schema/types.ts';
6
+ import type {
7
+ ExportReport, ImportAnalysis, ImportDecisions, ImportPlan, ImportResult,
8
+ PlanItem, RollbackReport,
9
+ } from '../core/types.ts';
10
+ import type { ExportPort } from './export-flow.ts';
11
+ import type { ImportPort } from './types.ts';
12
+
13
+ /** 样本 manifest(UI 测试不关心真实字段,仅类型占位) */
14
+ export function makeManifest(): Manifest {
15
+ return {
16
+ schemaVersion: 1,
17
+ exporter: { name: 'dsh-config-manager-test', version: '0.0.0' },
18
+ source: { dshVersion: '0.1.0-rc.6', platform: 'win32', arch: 'x64' },
19
+ exportedAt: '2026-08-14T12:00:00.000Z',
20
+ sections: {
21
+ settings: true, ui: false, providers: false, plugins: false, mcp: false, prompts: false,
22
+ skills: false, agentPresets: false, agentInstructions: false, workspaces: false, pluginFiles: false,
23
+ credentialsStatus: false, secrets: false, sessions: false, self: false,
24
+ },
25
+ security: { containsSecrets: false, encrypted: false, encryption: null },
26
+ };
27
+ }
28
+
29
+ export function makeExportReport(overrides: Partial<ExportReport> = {}): ExportReport {
30
+ return {
31
+ included: [
32
+ { section: 'settings', counts: { namespaces: 3 } },
33
+ { section: 'plugins', counts: { plugins: 8 } },
34
+ ],
35
+ excluded: ['sessions', 'pluginFiles'],
36
+ security: { secretsExcluded: true, containsSecrets: false, encrypted: false, redactedHits: 2 },
37
+ file: { name: 'dsh-config-2026-08-14.zip', sizeBytes: 20480 },
38
+ warnings: [],
39
+ ...overrides,
40
+ };
41
+ }
42
+
43
+ /** 内存 ExportPort mock:记录调用参数,返回固定结果 */
44
+ export class MockExportPort implements ExportPort {
45
+ calls: { includeSecrets: boolean; only?: string[] }[] = [];
46
+ result: { zipPath: string; manifest: Manifest; report: ExportReport };
47
+ constructor(report: ExportReport = makeExportReport()) {
48
+ this.result = {
49
+ zipPath: report.file.name,
50
+ manifest: makeManifest(),
51
+ report,
52
+ };
53
+ }
54
+ async export(opts: { includeSecrets: boolean; only?: string[] }): Promise<{ zipPath: string; manifest: Manifest; report: ExportReport }> {
55
+ this.calls.push({ includeSecrets: opts.includeSecrets, only: opts.only });
56
+ return this.result;
57
+ }
58
+ }
59
+
60
+ /* ---------------- Import mock ---------------- */
61
+
62
+ export function makeAnalysis(overrides: Partial<ImportAnalysis> = {}): ImportAnalysis {
63
+ return {
64
+ valid: true,
65
+ errors: [],
66
+ warnings: [],
67
+ compatibility: 'good',
68
+ sectionsInZip: ['settings', 'plugins', 'mcp', 'prompts'],
69
+ unsupportedSections: [],
70
+ unsupportedVersions: [],
71
+ pluginSummary: { installed: 6, toInstall: 2 },
72
+ pathIssues: [],
73
+ secretCount: 3,
74
+ dependencyIssues: [],
75
+ encrypted: false,
76
+ ...overrides,
77
+ };
78
+ }
79
+
80
+ export function makePlanItem(overrides: Partial<PlanItem> = {}): PlanItem {
81
+ return {
82
+ id: 'settings:general',
83
+ kind: 'Create',
84
+ adapter: 'settings',
85
+ description: '创建设置 general',
86
+ severity: 'info',
87
+ ...overrides,
88
+ };
89
+ }
90
+
91
+ export function makePlan(overrides: Partial<ImportPlan> = {}): ImportPlan {
92
+ return {
93
+ items: [
94
+ makePlanItem({ id: 'settings:a', kind: 'Update', description: '更新设置 a' }),
95
+ makePlanItem({ id: 'settings:b', kind: 'Create', description: '创建设置 b' }),
96
+ makePlanItem({ id: 'plugin:x', kind: 'Install', adapter: 'plugins', description: '安装插件 x' }),
97
+ makePlanItem({ id: 'plugin:y', kind: 'Skip', adapter: 'plugins', description: '插件 y 已一致' }),
98
+ makePlanItem({ id: 'prompt:p', kind: 'Create', adapter: 'prompts', description: '创建提示 p' }),
99
+ makePlanItem({ id: 'mcp:m', kind: 'Create', adapter: 'mcp', description: '创建 MCP m' }),
100
+ makePlanItem({ id: 'secret:K1', kind: 'MissingSecret', adapter: 'credentialsStatus', description: '凭据 K1 需要补录' }),
101
+ ],
102
+ globalStrategy: 'merge',
103
+ pathMappings: [],
104
+ missingSecrets: [{ ref: 'K1', required: true }],
105
+ needsRestart: true,
106
+ estimatedActions: {
107
+ settings: 2, ui: 0, providers: 0, plugins: 1, mcp: 1, prompts: 1,
108
+ skills: 0, agentPresets: 0, agentInstructions: 0, workspaces: 0, pluginFiles: 0,
109
+ credentialsStatus: 0, secrets: 0, sessions: 0, self: 0,
110
+ },
111
+ ...overrides,
112
+ };
113
+ }
114
+
115
+ export function makeRollbackReport(overrides: Partial<RollbackReport> = {}): RollbackReport {
116
+ return {
117
+ full: false,
118
+ restored: ['settings:a'],
119
+ failed: [{ item: 'plugin:x', reason: '安装失败', manualHint: '请手动安装' }],
120
+ ...overrides,
121
+ };
122
+ }
123
+
124
+ export function makeImportResult(overrides: Partial<ImportResult> = {}): ImportResult {
125
+ return {
126
+ ok: true,
127
+ executed: [
128
+ { itemId: 'settings:a', status: 'ok' },
129
+ { itemId: 'settings:b', status: 'ok' },
130
+ { itemId: 'plugin:x', status: 'ok', message: '需要重启生效' },
131
+ { itemId: 'plugin:y', status: 'skipped' },
132
+ { itemId: 'prompt:p', status: 'ok' },
133
+ { itemId: 'mcp:m', status: 'ok' },
134
+ { itemId: 'secret:K1', status: 'skipped', message: '凭据未提供' },
135
+ ],
136
+ needsRestart: true,
137
+ missingSecrets: ['K1'],
138
+ warnings: [],
139
+ rollback: null,
140
+ snapshotId: 'snap-1',
141
+ ...overrides,
142
+ };
143
+ }
144
+
145
+ /** 内存 ImportPort mock:可编排各阶段返回与调用记录 */
146
+ export class MockImportPort implements ImportPort {
147
+ analysis: ImportAnalysis;
148
+ plan: ImportPlan;
149
+ result: ImportResult;
150
+ analyzeCalls = 0;
151
+ planCalls: ImportDecisions[] = [];
152
+ executeCalls: { confirm: boolean; secretInputs?: Record<string, string>; rollbackOnError: boolean; decryptPassword?: string; plan?: ImportPlan }[] = [];
153
+
154
+ constructor(opts: {
155
+ analysis?: ImportAnalysis;
156
+ plan?: ImportPlan;
157
+ result?: ImportResult;
158
+ } = {}) {
159
+ this.analysis = opts.analysis ?? makeAnalysis();
160
+ this.plan = opts.plan ?? makePlan();
161
+ this.result = opts.result ?? makeImportResult();
162
+ }
163
+
164
+ async analyzeImport(): Promise<ImportAnalysis> {
165
+ this.analyzeCalls += 1;
166
+ return this.analysis;
167
+ }
168
+ async createImportPlan(_zip: string, decisions: ImportDecisions): Promise<ImportPlan> {
169
+ this.planCalls.push(decisions);
170
+ return this.plan;
171
+ }
172
+ async decryptArchive(zipPath: string): Promise<{ zipPath: string; refs: string[] }> {
173
+ // 测试用:把传入路径视为已解锁的明文 ZIP(不真正解密),无内部凭据
174
+ return { zipPath, refs: [] };
175
+ }
176
+ async executeImportPlan(
177
+ _zip: string,
178
+ plan: ImportPlan,
179
+ opts: { confirm: boolean; secretInputs?: Record<string, string>; rollbackOnError: boolean; decryptPassword?: string },
180
+ ): Promise<ImportResult> {
181
+ this.executeCalls.push({ ...opts, plan });
182
+ return this.result;
183
+ }
184
+ }
@@ -0,0 +1,325 @@
1
+ /**
2
+ * UI 层共享类型(m6-ui,框架无关)。
3
+ *
4
+ * 设计原则(对齐 Docs/design/architecture.md §12.2 与规范 §28/§29):
5
+ * - 本模块为纯 TypeScript 逻辑层,不引入 React / 打包器 / 任何运行时依赖;
6
+ * - 未来 React 客户端(src/client/)直接消费本层的控制器输出(渲染文本 / 状态快照);
7
+ * - UI 层不直接 import core 的类实现,只依赖 core/types.ts 的纯类型 + 注入的「端口」
8
+ * (ExportPort / ImportPort,宿主在 settings.section 挂载时把真实 Exporter/Importer 接入)。
9
+ */
10
+ import type { SectionId } from '../schema/types.ts';
11
+ import type {
12
+ CompatibilityScore, ImportAnalysis, ImportDecisions, ImportPlan, ImportResult,
13
+ ItemResolution, PathIssue, PlanItem, Portability, RollbackReport,
14
+ } from '../core/types.ts';
15
+
16
+ /* ---------------- 导出(规范 §1 / §21) ---------------- */
17
+
18
+ export type ExportMode = 'quick' | 'custom';
19
+
20
+ /** Custom Export 分组(规范 §1 分类;automation 组在 DSH 中无对应分区,UI 标注说明) */
21
+ export type ExportGroup =
22
+ | 'general' | 'ai' | 'extensions' | 'mcp' | 'customization'
23
+ | 'automation' | 'workspace' | 'ui' | 'optional';
24
+
25
+ /** 分类树节点(与 adapters 的 displayName/defaultIncluded/portability 对齐;宿主可注入覆盖) */
26
+ export interface ExportCategory {
27
+ id: SectionId;
28
+ label: string;
29
+ description: string;
30
+ defaultIncluded: boolean;
31
+ portability: Portability;
32
+ group: ExportGroup;
33
+ /** 涉及秘密状态(如 credentialsStatus):UI 需展示安全提示但绝不显示值 */
34
+ sensitive?: boolean;
35
+ }
36
+
37
+ export interface ExportGroupDef {
38
+ id: ExportGroup;
39
+ label: string;
40
+ /** automation 组在 DSH 无对应配置时的说明 */
41
+ note?: string;
42
+ }
43
+
44
+ /** Custom Export 分组目录(规范 §1;automation 组 DSH 无对应分区,仅说明) */
45
+ export const EXPORT_GROUPS: readonly ExportGroupDef[] = [
46
+ { id: 'general', label: 'General' },
47
+ { id: 'ai', label: 'AI' },
48
+ { id: 'extensions', label: 'Extensions' },
49
+ { id: 'mcp', label: 'MCP / Tools' },
50
+ { id: 'customization', label: 'Customization' },
51
+ { id: 'automation', label: 'Automation', note: 'DSH 当前无 Workflows / Commands 配置文件(运行时注册),无迁移内容' },
52
+ { id: 'workspace', label: 'Workspace' },
53
+ { id: 'ui', label: 'UI' },
54
+ { id: 'optional', label: 'Optional Data' },
55
+ ] as const;
56
+
57
+ /** Quick Export 推荐项 = defaultIncluded 且非 deviceSpecific(设计 §11.1) */
58
+ export function isQuickRecommended(c: ExportCategory): boolean {
59
+ return c.defaultIncluded && c.portability !== 'deviceSpecific';
60
+ }
61
+
62
+ /* ---------------- 进度事件(规范 §29) ---------------- */
63
+
64
+ export interface ProgressEvent {
65
+ /** 阶段 id(见 progress.ts 的 STAGE_TEXTS) */
66
+ stage: string;
67
+ detail?: string;
68
+ /** 阶段序号(从 1 起,供 UI 显示 n/m) */
69
+ step?: number;
70
+ /** 阶段总数 */
71
+ total?: number;
72
+ }
73
+
74
+ export type ProgressListener = (event: ProgressEvent) => void;
75
+
76
+ /* ---------------- 导入向导(规范 §9 / §10 / §28) ---------------- */
77
+
78
+ export type ImportStep =
79
+ | 'select' // 选 ZIP
80
+ | 'analyzing' // Analyzing...
81
+ | 'compatibility' // Compatibility
82
+ | 'preview' // Import Preview(Dry Run 摘要)
83
+ | 'conflicts' // Resolve Conflicts(§11)
84
+ | 'path-mapping' // Path Mapping(§12)
85
+ | 'secrets' // Secrets 补录(§7)
86
+ | 'importing' // Importing(含快照/回滚阶段)
87
+ | 'result'; // Result(§22)
88
+
89
+ /** Preview 摘要(规范 §10 示例的数值化版本) */
90
+ export interface ImportPreviewSummary {
91
+ /** 将更新的配置项数(Create+Update+Install 合计) */
92
+ willChange: number;
93
+ /** 已存在且一致的项(Skip) */
94
+ unchanged: number;
95
+ settingsUpdates: number;
96
+ pluginsInstalled: number;
97
+ pluginsToInstall: number;
98
+ mcpAdds: number;
99
+ prompts: number;
100
+ pathMappingsNeeded: number;
101
+ secretsNeeded: number;
102
+ conflicts: number;
103
+ needsRestart: boolean;
104
+ }
105
+
106
+ /** 向导状态快照(React 客户端可直接绑定渲染) */
107
+ export interface WizardSnapshot {
108
+ step: ImportStep;
109
+ zipPath: string | null;
110
+ analysis: ImportAnalysis | null;
111
+ plan: ImportPlan | null;
112
+ result: ImportResult | null;
113
+ /** 导入执行的回滚策略(场景 E:默认 true 整体回滚) */
114
+ rollbackOnError: boolean;
115
+ errors: string[];
116
+ }
117
+
118
+ /* ---------------- 冲突视图(规范 §11) ---------------- */
119
+
120
+ /** 单个冲突项的视图数据:当前值 vs 导入值摘要 + 用户决策 */
121
+ export interface ConflictViewItem {
122
+ item: PlanItem;
123
+ currentSummary?: string;
124
+ importedSummary?: string;
125
+ resolution: ItemResolution | null;
126
+ }
127
+
128
+ /* ---------------- 路径映射(规范 §12) ---------------- */
129
+
130
+ /** 路径映射编辑器的单条记录(旧前缀 → 新前缀;未解析时 newPrefix 为空串) */
131
+ export interface PathMappingDraft {
132
+ /** 关联的原始路径问题值(一条 issue 一条 draft;批量映射用 oldPrefix 聚合) */
133
+ oldPrefix: string;
134
+ newPrefix: string;
135
+ issue?: PathIssue;
136
+ /** 应用范围(缺省 [] = 全部相关分区,与 core applyMappingsToSections 语义一致) */
137
+ appliesTo: PathMappingAppliesTo[];
138
+ }
139
+
140
+ /** 与 core PathMapping.appliesTo 对齐的取值(留空数组 = 全应用) */
141
+ export type PathMappingAppliesTo = 'workspaces' | 'mcp' | 'pluginConfig' | 'skills';
142
+
143
+ /* ---------------- 兼容性(规范 §30) ---------------- */
144
+
145
+ export interface CompatibilityView {
146
+ score: CompatibilityScore;
147
+ sourceDsh: string;
148
+ targetDsh: string;
149
+ description: string;
150
+ }
151
+
152
+ /* ---------------- 报告(规范 §21 / §22 / §17) ---------------- */
153
+
154
+ /** 导入结果按分区的统计(report.ts 用) */
155
+ export interface ImportSectionStat {
156
+ section: SectionId;
157
+ ok: number;
158
+ skipped: number;
159
+ warned: number;
160
+ failed: number;
161
+ items: { itemId: string; status: 'ok' | 'skipped' | 'warning' | 'failed'; message?: string }[];
162
+ }
163
+
164
+ export type ImportResultAction = 'fixIssues' | 'viewDetails' | 'done';
165
+
166
+ export interface RollbackView {
167
+ report: RollbackReport | null;
168
+ /** 是否有可展示的人工恢复清单(partial 回滚时) */
169
+ hasManualRecovery: boolean;
170
+ }
171
+
172
+ /* ---------------- 控制器公共依赖注入 ---------------- */
173
+
174
+ /** UI 层与 core 的导入端口(宿主注入真实 Importer;测试注入内存 mock) */
175
+ export interface ImportPort {
176
+ analyzeImport(zipPath: string): Promise<ImportAnalysis>;
177
+ createImportPlan(zipPath: string, decisions: ImportDecisions): Promise<ImportPlan>;
178
+ /**
179
+ * 解锁整体加密备份(只读,零写入):用备份密码解密上传的加密容器,得到明文 ZIP
180
+ * 写入受控临时目录并返回新的 zipPath,供 analyze/plan/execute 引用。
181
+ * 顺带返回解密覆盖的凭据 ref 名(非值)——导出时容器密码与内部 secrets.enc
182
+ * 密码同源,解锁即完成凭据解密验证,无需第二次密码校验。
183
+ * 密码仅内存,绝不落盘/落日志;解密后的明文 ZIP 亦为临时文件,导入结束后清理。
184
+ */
185
+ decryptArchive(zipPath: string, password: string): Promise<{ zipPath: string; refs: string[] }>;
186
+ executeImportPlan(
187
+ zipPath: string,
188
+ plan: ImportPlan,
189
+ opts: {
190
+ /** 用户确认(安全阀,非 true 拒绝执行) */
191
+ confirm: boolean;
192
+ secretInputs?: Record<string, string>;
193
+ /** 显式回滚策略:true=任一项失败整体回滚(场景 E);false=单项失败继续(§34.17) */
194
+ rollbackOnError: boolean;
195
+ /** 加密备份的解密密码(仅内存;core 拒绝加密备份无密码执行) */
196
+ decryptPassword?: string;
197
+ },
198
+ ): Promise<ImportResult>;
199
+ }
200
+
201
+ /** 选项构造辅助:从 PlanItem 提取稳定决策键(与 core analyzer.applyItemResolution 的 id 语义一致) */
202
+ export function itemDecisionKey(item: PlanItem): string {
203
+ return item.id;
204
+ }
205
+
206
+ /* ---------------- Recovery(Phase 5:引导式恢复工作流) ---------------- */
207
+
208
+ /** recovery 决策(§5.2):rollback-recommended=恢复到 trusted snapshot;rollback-continue=续跑中断回滚;needs-attention=需人工调查。 */
209
+ export type RecoveryDecision = 'rollback-recommended' | 'rollback-continue' | 'needs-attention';
210
+
211
+ /** post-recovery verification verdict(§6.3)。 */
212
+ export type RecoveryVerdict = 'MATCH' | 'PARTIAL_MATCH' | 'MISMATCH' | 'VERIFICATION_ERROR';
213
+
214
+ /** GET /recovery/status 的单个 incident(未解决 operation)。 */
215
+ export interface RecoveryIncident {
216
+ operationId: string;
217
+ operationType: string;
218
+ state: string;
219
+ decision: RecoveryDecision;
220
+ snapshotId: string | null;
221
+ /** 已 redact 的原因文本。 */
222
+ reason: string;
223
+ createdAt: string;
224
+ }
225
+
226
+ /** GET /recovery/status 响应。 */
227
+ export interface RecoveryStatus {
228
+ incidents: RecoveryIncident[];
229
+ running: { runId: string; status: string }[];
230
+ /**
231
+ * 环境锁状态摘要(issue #31)。纯残留锁**不是** journal:进程在 op 期间被杀时
232
+ * `journalId: null`、`transactions/active/` 为空,incidents 恒为 [],而 423 文案却
233
+ * 让用户去「事故恢复」处理 → 面板恒空、GUI 无出路。本字段让面板能显示可执行的锁事项。
234
+ * 旧宿主不返回 → undefined(面板按「无锁事项」处理,不误报)。
235
+ */
236
+ lock?: RecoveryLockStatus;
237
+ }
238
+
239
+ /** 环境锁状态摘要:**只暴露分类**(owner pid/op/hostname 属内部诊断,不进 UI/响应体)。 */
240
+ export interface RecoveryLockStatus {
241
+ /** LockState:STALE_LOCK_DETECTED / UNKNOWN_STATE / LOCKED / FREE / LOCK_IO_ERROR / PERMISSION_ERROR */
242
+ state: string;
243
+ /** 是否需用户显式处理(残留锁/无法判定)。LOCKED 活锁为 false —— 它会自行释放,不该催用户回收。 */
244
+ attention: boolean;
245
+ }
246
+
247
+ /** POST /recovery/lock/recover 响应(显式回收 stale 残留锁;拒绝时 ok=false)。 */
248
+ export interface RecoveryLockRecoverResult {
249
+ ok: boolean;
250
+ removed: boolean;
251
+ state: string;
252
+ }
253
+
254
+ /** GET /recovery/:operationId/preview 响应(只读,零写入)。 */
255
+ export interface RecoveryPreview {
256
+ operationId: string;
257
+ operationType: string;
258
+ state: string;
259
+ decision: RecoveryDecision;
260
+ snapshotId: string | null;
261
+ snapshotVerdict: string | null;
262
+ snapshotMeta: { id: string; createdAt: string; operationType?: string } | null;
263
+ environmentFingerprint: string;
264
+ environmentCompatible: boolean;
265
+ reason: string;
266
+ createdAt: string;
267
+ }
268
+
269
+ /** POST /recovery/:operationId/verify 响应。 */
270
+ export interface RecoveryVerifyResult {
271
+ ok: boolean;
272
+ operationId: string;
273
+ verdict: RecoveryVerdict;
274
+ terminal: string;
275
+ /** 每项检查结果(已 redact)。 */
276
+ details: string[];
277
+ /** 需人工处理项(已 redact)。 */
278
+ manualHints: string[];
279
+ }
280
+
281
+ /** POST /recovery/:operationId/execute|retry 响应。 */
282
+ export interface RecoveryExecuteResult {
283
+ ok: boolean;
284
+ operationId: string;
285
+ decision: RecoveryDecision;
286
+ state: string;
287
+ runId: string;
288
+ }
289
+
290
+ /** POST /recovery/:operationId/confirm 响应。 */
291
+ export interface RecoveryConfirmResult {
292
+ ok: boolean;
293
+ operationId: string;
294
+ snapshotId: string;
295
+ verdict: string;
296
+ }
297
+
298
+ /** POST /recovery/:operationId/dismiss 响应。 */
299
+ export interface RecoveryDismissResult {
300
+ ok: boolean;
301
+ operationId: string;
302
+ dismissed: boolean;
303
+ }
304
+
305
+ /**
306
+ * Recovery 端口契约(§10.3):recovery 无现有 port(ExportPort/ImportPort 只服务控制器)。
307
+ * `recovery-api.ts` 实现之;`recovery-view.ts` 是纯渲染模型(非控制器),消费本端口返回的渲染数据。
308
+ * 安全:所有 destructive 动作(confirm/execute/retry/dismiss)必须显式传 userConfirmed=true,
309
+ * 由 Host 侧双重校验(请求体 + journal 状态机)。
310
+ */
311
+ export interface RecoveryPort {
312
+ status(): Promise<RecoveryStatus>;
313
+ preview(operationId: string): Promise<RecoveryPreview>;
314
+ confirm(operationId: string, userConfirmed: boolean): Promise<RecoveryConfirmResult>;
315
+ execute(operationId: string, userConfirmed: boolean): Promise<RecoveryExecuteResult>;
316
+ verify(operationId: string): Promise<RecoveryVerifyResult>;
317
+ retry(operationId: string, userConfirmed: boolean): Promise<RecoveryExecuteResult>;
318
+ dismiss(operationId: string, userConfirmed: boolean): Promise<RecoveryDismissResult>;
319
+ /**
320
+ * POST /recovery/lock/recover(issue #31):显式回收 stale 残留配置锁。
321
+ * 不带 operationId(残留锁没有 journal);宿主侧会重新证明确属 stale 才回收,
322
+ * 无法证明(活锁/判定不确定/二次验证失败)→ 返回 ok=false 且不做任何改动。
323
+ */
324
+ recoverStaleLock(userConfirmed: boolean): Promise<RecoveryLockRecoverResult>;
325
+ }