@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,12 @@
1
+ import type { ConfigAdapter, HostContext, RollbackReport, Snapshot, SnapshotStore } from './types.ts';
2
+ export interface RollbackOptions {
3
+ ctx: HostContext;
4
+ snapshot: Snapshot;
5
+ store?: SnapshotStore;
6
+ adapters?: ConfigAdapter[];
7
+ /** 回滚 WAL(Phase 3):每补偿完一条 entry 调用,供 Coordinator 记录 rollback.entryDone;
8
+ * crash during rollback 后 reconcile 从 WAL 判定已补偿/未补偿,避免盲目从头重做。 */
9
+ entryDone?: (entryIndex: number) => Promise<void>;
10
+ }
11
+ /** 回滚:逆序补偿全部条目;返回诚实报告(full / partial) */
12
+ export declare function rollback(opts: RollbackOptions): Promise<RollbackReport>;
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Rollback(规范 §17 / 设计 §8.2):导入失败时逆序执行快照条目的补偿动作。
3
+ *
4
+ * 诚实原则:
5
+ * - 尽力回滚:单项失败不停止其余补偿,最终如实报告 full / partial;
6
+ * - credential 值 DSH 永不回读 → existed=true 的凭据无法自动恢复原值,
7
+ * 如实标记 failed + manualHint(人工补录);
8
+ * - settings 回滚仍走 expectedRevision 乐观锁,避免覆盖导入后用户的新修改。
9
+ */
10
+ import { resolveFileTarget } from './backup.js';
11
+ import { msgOf } from './messages.js';
12
+ /** 逆序补偿单条快照条目;返回 null=成功,否则为失败原因 */
13
+ async function compensateOne(entry, ctx, store) {
14
+ switch (entry.kind) {
15
+ case 'settingsNamespace': {
16
+ try {
17
+ if (!entry.existed) {
18
+ // 原目标不存在该 namespace:若导入已创建它,DSH settings 无删除语义 → 无法恢复「不存在」
19
+ let current = null;
20
+ try {
21
+ current = await ctx.settings.describe(entry.ref);
22
+ }
23
+ catch {
24
+ current = null;
25
+ }
26
+ if (current === null)
27
+ return null; // 本来就没有且未创建 → 无需恢复
28
+ return {
29
+ reason: msgOf(ctx)('rollback.ns.createdNoDelete'),
30
+ manualHint: msgOf(ctx)('rollback.ns.manualHint', { ref: entry.ref }),
31
+ };
32
+ }
33
+ // 用当前 revision 作乐观锁基准:读时即锁,冲突则如实失败(不覆盖并发修改)
34
+ const current = await ctx.settings.describe(entry.ref);
35
+ await ctx.settings.replace(entry.ref, entry.before, current.revision);
36
+ return null;
37
+ }
38
+ catch (err) {
39
+ return { reason: err instanceof Error ? err.message : String(err), manualHint: msgOf(ctx)('rollback.ns.conflictHint', { ref: entry.ref }) };
40
+ }
41
+ }
42
+ case 'credential': {
43
+ if (entry.existed) {
44
+ // 值不可回读:无法自动恢复原值
45
+ return {
46
+ reason: msgOf(ctx)('rollback.cred.noReadback'),
47
+ manualHint: msgOf(ctx)('rollback.cred.manualHint', { ref: entry.ref }),
48
+ };
49
+ }
50
+ try {
51
+ await ctx.credentials.unset(entry.ref);
52
+ return null;
53
+ }
54
+ catch (err) {
55
+ return { reason: err instanceof Error ? err.message : String(err) };
56
+ }
57
+ }
58
+ case 'patchLine': {
59
+ try {
60
+ // 引擎只管理 profile 的 cordis.patch.yml(backup.ts 的 patchLine 快照只记 lineId 作 ref,
61
+ // 不含文件编码)——回滚固定写回该文件;切勿把 lineId 当文件名(否则 patchPath 抛「仅支持管理」)。
62
+ const file = 'cordis.patch.yml';
63
+ const lineId = entry.ref;
64
+ await ctx.patchFile.applyPatchChanges(file, [
65
+ { lineId, raw: entry.before, action: entry.before === null ? 'remove' : 'update' },
66
+ ]);
67
+ return null;
68
+ }
69
+ catch (err) {
70
+ return { reason: err instanceof Error ? err.message : String(err), manualHint: msgOf(ctx)('rollback.patch.manualHint', { ref: entry.ref }) };
71
+ }
72
+ }
73
+ case 'file': {
74
+ try {
75
+ const abs = resolveFileTarget(ctx, entry.adapter, entry.ref);
76
+ if (entry.existed && entry.copiedTo && store) {
77
+ const data = await store.readBlob(entry.snapshotId ?? '', entry.copiedTo);
78
+ await ctx.fs.writeFile(abs, data);
79
+ }
80
+ else if (!entry.existed) {
81
+ // 原文件不存在 → 删除导入写入的文件
82
+ if (await ctx.fs.exists(abs))
83
+ await ctx.fs.remove(abs);
84
+ }
85
+ return null;
86
+ }
87
+ catch (err) {
88
+ return { reason: err instanceof Error ? err.message : String(err), manualHint: msgOf(ctx)('rollback.file.manualHint', { ref: entry.ref }) };
89
+ }
90
+ }
91
+ case 'workspaceRecord': {
92
+ try {
93
+ if (entry.before === null) {
94
+ await ctx.workspace.removeRecord?.(entry.ref);
95
+ }
96
+ else {
97
+ await ctx.workspace.writeRecord(entry.before);
98
+ }
99
+ return null;
100
+ }
101
+ catch (err) {
102
+ return { reason: err instanceof Error ? err.message : String(err), manualHint: msgOf(ctx)('rollback.workspace.manualHint', { ref: entry.ref }) };
103
+ }
104
+ }
105
+ default:
106
+ return { reason: msgOf(ctx)('rollback.unknownEntry', { kind: entry.kind }) };
107
+ }
108
+ }
109
+ /** 回滚:逆序补偿全部条目;返回诚实报告(full / partial) */
110
+ export async function rollback(opts) {
111
+ const { ctx, snapshot, store, adapters, entryDone } = opts;
112
+ const restored = [];
113
+ const failed = [];
114
+ // 逆序遍历;adapter 自带的 rollback? 优先,否则引擎通用补偿
115
+ const entries = [...snapshot.entries].reverse();
116
+ for (let index = 0; index < entries.length; index++) {
117
+ const entry = entries[index];
118
+ const adapter = adapters?.find((a) => a.id === entry.adapter);
119
+ let error = null;
120
+ if (adapter?.rollback) {
121
+ try {
122
+ await adapter.rollback([entry], ctx);
123
+ }
124
+ catch (err) {
125
+ error = { reason: err instanceof Error ? err.message : String(err) };
126
+ }
127
+ }
128
+ else {
129
+ error = await compensateOne(entry, ctx, store);
130
+ }
131
+ // 回滚 WAL:每补偿一项记 entryDone(crash 后可判定进度)
132
+ try {
133
+ await opts.entryDone?.(index);
134
+ }
135
+ catch { /* WAL 写失败不阻断回滚(best-effort) */ }
136
+ if (error === null) {
137
+ restored.push(`${entry.adapter}:${entry.ref}`);
138
+ }
139
+ else {
140
+ failed.push({ item: `${entry.adapter}:${entry.ref}`, reason: error.reason, manualHint: error.manualHint });
141
+ }
142
+ }
143
+ return { full: failed.length === 0, restored, failed };
144
+ }
145
+ //# sourceMappingURL=rollback.js.map
@@ -0,0 +1,85 @@
1
+ import type { MsgFunc } from './messages.ts';
2
+ /** run 类型:导出 / 导入 / 自动同步 / 一键同步逐项应用 / 定时备份 / 快照恢复 / 配置档案切换 / recovery 恢复。 */
3
+ export type RunKind = 'export' | 'import' | 'autosync' | 'sync-apply' | 'backup-schedule' | 'restore' | 'profile-switch' | 'recovery';
4
+ /** run 状态:进行中 / 完成 / 失败。 */
5
+ export type RunStatus = 'running' | 'done' | 'failed';
6
+ /** 单个 run 的实时状态(/progress 返回体;纯 JSON 可序列化)。 */
7
+ export interface RunState {
8
+ /** 不可猜测的 run id(32 hex 字符)。 */
9
+ runId: string;
10
+ kind: RunKind;
11
+ status: RunStatus;
12
+ /** 当前分区(adapter id 或导入阶段名);无则 null。 */
13
+ section: string | null;
14
+ /** 分区总数(导出 = 选中分区数;导入无此语义 = null)。 */
15
+ sectionTotal: number | null;
16
+ /** 已完成的内部计数(导出 = 当前分区序号;导入 = 已处理计划项数)。 */
17
+ item: number | null;
18
+ /** 内部计数总数(导出 = 分区总数;导入 = 计划项总数)。 */
19
+ itemTotal: number | null;
20
+ /** 非敏感进度摘要(当前分区 / 当前计划项 id)。 */
21
+ detail: string | null;
22
+ /** 执行日志行(导入为逐计划项操作 + 子进程命令;append-only,封顶 MAX_RUN_LOG_LINES)。
23
+ * 只存非敏感文本(命令/操作摘要),绝不写入密钥、密码、秘密补录值。 */
24
+ log: string[];
25
+ /** 完成时的业务结果(仅 JSON 可序列化、不含秘密值)。 */
26
+ result?: unknown;
27
+ /** 失败时的错误消息(非敏感)。 */
28
+ error?: string;
29
+ createdAt: number;
30
+ updatedAt: number;
31
+ }
32
+ /** 单个 run 执行日志的行数上限(防无限增长;截断时保留最新行)。 */
33
+ export declare const MAX_RUN_LOG_LINES = 500;
34
+ /** 进行中同 kind 已有 run 时注册被拒(宿主路由 → 409)。 */
35
+ export declare class RunConflictError extends Error {
36
+ /** 已在进行中的 run id(供客户端定位既有任务)。 */
37
+ readonly runId: string;
38
+ constructor(runId: string, kind: RunKind, msg?: MsgFunc);
39
+ }
40
+ /** 完成/失败后的默认保留时长(30 分钟)。 */
41
+ export declare const DEFAULT_RUN_RETENTION_MS: number;
42
+ export interface RunRegistryOptions {
43
+ /** 完成/失败后保留时长(默认 30 分钟);超期 run 在下次访问时清理。 */
44
+ retentionMs?: number;
45
+ /** 时间源(测试注入)。 */
46
+ now?: () => number;
47
+ /** 消息翻译器(缺省 zh;冲突错误文案随应用语言)。 */
48
+ msg?: MsgFunc;
49
+ }
50
+ /**
51
+ * 内存 run 注册表。Node 单线程 + 同步 Map 读写,无并发竞争;
52
+ * 所有公开读方法返回状态副本,防止外部直接篡改内部状态。
53
+ */
54
+ export declare class RunRegistry {
55
+ private readonly runs;
56
+ private readonly retentionMs;
57
+ private readonly now;
58
+ private readonly msg;
59
+ constructor(opts?: RunRegistryOptions);
60
+ /** 注册新 run;同 kind 已有 running 时抛 RunConflictError。 */
61
+ register(kind: RunKind): RunState;
62
+ /** 更新进度;run 不存在返回 undefined;已完成/失败后的晚到更新被忽略(防御异步回调竞态)。 */
63
+ update(runId: string, patch: Partial<Pick<RunState, 'section' | 'sectionTotal' | 'item' | 'itemTotal' | 'detail'>>): RunState | undefined;
64
+ /**
65
+ * 追加一行执行日志(导入逐计划项操作 / 子进程命令);run 不存在返回 undefined,
66
+ * 已完成/失败后的晚到追加被忽略(防御异步回调竞态)。行数封顶 MAX_RUN_LOG_LINES,
67
+ * 超限时截断保留最新行。
68
+ *
69
+ * **不可变写入(性能正确性关键)**:每次 append 生成新数组(push + splice 会原地
70
+ * mutation —— /progress 轮询返回的 RunState.log 与浏览器侧 store 共享同一引用,
71
+ * 行数封顶后长度恒定,React memo 按引用/长度比较将无法感知新行,日志面板冻结)。
72
+ * 调用方(mapRunProgress → ImportLogPanel)据此以「数组引用变化」判断有新输出。
73
+ */
74
+ appendLog(runId: string, line: string): RunState | undefined;
75
+ /** 读单个 run;超过保留期或不存在返回 undefined。 */
76
+ get(runId: string): RunState | undefined;
77
+ /** 列出活跃(running)run(刷新恢复时经 /runs 重订阅用)。 */
78
+ listActive(): RunState[];
79
+ /** 标记完成并写入业务结果;run 不存在返回 undefined。 */
80
+ finish(runId: string, result: unknown): RunState | undefined;
81
+ /** 标记失败并写入错误消息;run 不存在返回 undefined。 */
82
+ fail(runId: string, error: string): RunState | undefined;
83
+ /** 惰性清理:超过保留期的 run(含长期 running 的僵死任务)全部移除。 */
84
+ private prune;
85
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Host 端 run 注册表(m1):记录导出/导入任务的运行状态与真实进度。
3
+ *
4
+ * 浏览器侧通过 `/api/dsh-config-manager/progress?runId=…` 与
5
+ * `/api/dsh-config-manager/runs` 轮询/恢复进度(m2 store 刷新恢复、m3 进度 UI
6
+ * 消费);本模块是 Host 侧的单一事实源,不依赖任何 DSH 运行时服务。
7
+ *
8
+ * 安全纪律:
9
+ * - runId 由 crypto.randomBytes(16) 生成(32 hex 字符),不可猜测;
10
+ * - RunState 只存非敏感摘要(分区/计数/详情文案),绝不写入密钥、密码、
11
+ * 秘密补录值或任何敏感内容;
12
+ * - result 只存可 JSON 序列化的业务结果(导出为 { zipPath, manifest, report },
13
+ * 导入为 ImportResult),不含秘密值。
14
+ *
15
+ * 生命周期:register(running)→ update(进度)→ finish(done+result)/
16
+ * fail(failed+error);超过保留期(默认 30 分钟)的 run 在任意读操作时惰性清理。
17
+ * 并发纪律:同一 kind 已有 running 的 run 时,register 抛 RunConflictError
18
+ * (宿主路由以 409 拒绝新任务,防止重复导出/导入)。
19
+ */
20
+ import { randomBytes } from 'node:crypto';
21
+ import { zhMsg } from './messages.js';
22
+ /** 单个 run 执行日志的行数上限(防无限增长;截断时保留最新行)。 */
23
+ export const MAX_RUN_LOG_LINES = 500;
24
+ /** 进行中同 kind 已有 run 时注册被拒(宿主路由 → 409)。 */
25
+ export class RunConflictError extends Error {
26
+ /** 已在进行中的 run id(供客户端定位既有任务)。 */
27
+ runId;
28
+ constructor(runId, kind, msg = zhMsg) {
29
+ super(kind === 'export'
30
+ ? msg('run.conflict.export', { runId })
31
+ : kind === 'autosync'
32
+ ? '自动同步已在进行中'
33
+ : kind === 'sync-apply'
34
+ ? '一键同步已在进行中'
35
+ : kind === 'backup-schedule'
36
+ ? '定时备份已在进行中'
37
+ : kind === 'restore'
38
+ ? '快照恢复已在进行中(请等待当前恢复完成)'
39
+ : kind === 'recovery'
40
+ ? '恢复/回滚已在进行中(请等待当前恢复完成)'
41
+ : msg('run.conflict.import', { runId }));
42
+ this.name = 'RunConflictError';
43
+ this.runId = runId;
44
+ }
45
+ }
46
+ /** 完成/失败后的默认保留时长(30 分钟)。 */
47
+ export const DEFAULT_RUN_RETENTION_MS = 30 * 60 * 1000;
48
+ /**
49
+ * 内存 run 注册表。Node 单线程 + 同步 Map 读写,无并发竞争;
50
+ * 所有公开读方法返回状态副本,防止外部直接篡改内部状态。
51
+ */
52
+ export class RunRegistry {
53
+ runs = new Map();
54
+ retentionMs;
55
+ now;
56
+ msg;
57
+ constructor(opts = {}) {
58
+ this.retentionMs = opts.retentionMs ?? DEFAULT_RUN_RETENTION_MS;
59
+ this.now = opts.now ?? (() => Date.now());
60
+ this.msg = opts.msg ?? zhMsg;
61
+ }
62
+ /** 注册新 run;同 kind 已有 running 时抛 RunConflictError。 */
63
+ register(kind) {
64
+ this.prune();
65
+ for (const run of this.runs.values()) {
66
+ if (run.kind === kind && run.status === 'running')
67
+ throw new RunConflictError(run.runId, kind, this.msg);
68
+ }
69
+ const now = this.now();
70
+ const state = {
71
+ runId: randomBytes(16).toString('hex'),
72
+ kind,
73
+ status: 'running',
74
+ section: null,
75
+ sectionTotal: null,
76
+ item: null,
77
+ itemTotal: null,
78
+ detail: null,
79
+ log: [],
80
+ createdAt: now,
81
+ updatedAt: now,
82
+ };
83
+ this.runs.set(state.runId, state);
84
+ return { ...state };
85
+ }
86
+ /** 更新进度;run 不存在返回 undefined;已完成/失败后的晚到更新被忽略(防御异步回调竞态)。 */
87
+ update(runId, patch) {
88
+ const run = this.runs.get(runId);
89
+ if (run === undefined)
90
+ return undefined;
91
+ if (run.status !== 'running')
92
+ return { ...run };
93
+ Object.assign(run, patch, { updatedAt: this.now() });
94
+ return { ...run };
95
+ }
96
+ /**
97
+ * 追加一行执行日志(导入逐计划项操作 / 子进程命令);run 不存在返回 undefined,
98
+ * 已完成/失败后的晚到追加被忽略(防御异步回调竞态)。行数封顶 MAX_RUN_LOG_LINES,
99
+ * 超限时截断保留最新行。
100
+ *
101
+ * **不可变写入(性能正确性关键)**:每次 append 生成新数组(push + splice 会原地
102
+ * mutation —— /progress 轮询返回的 RunState.log 与浏览器侧 store 共享同一引用,
103
+ * 行数封顶后长度恒定,React memo 按引用/长度比较将无法感知新行,日志面板冻结)。
104
+ * 调用方(mapRunProgress → ImportLogPanel)据此以「数组引用变化」判断有新输出。
105
+ */
106
+ appendLog(runId, line) {
107
+ const run = this.runs.get(runId);
108
+ if (run === undefined)
109
+ return undefined;
110
+ if (run.status !== 'running')
111
+ return { ...run };
112
+ // 不可变追加:保留最新 MAX_RUN_LOG_LINES 行(slice(-(MAX-1)) 在长度不足时取全量)
113
+ run.log = [...run.log.slice(-(MAX_RUN_LOG_LINES - 1)), line];
114
+ run.updatedAt = this.now();
115
+ return { ...run };
116
+ }
117
+ /** 读单个 run;超过保留期或不存在返回 undefined。 */
118
+ get(runId) {
119
+ this.prune();
120
+ const run = this.runs.get(runId);
121
+ return run === undefined ? undefined : { ...run };
122
+ }
123
+ /** 列出活跃(running)run(刷新恢复时经 /runs 重订阅用)。 */
124
+ listActive() {
125
+ this.prune();
126
+ return [...this.runs.values()].filter((r) => r.status === 'running').map((r) => ({ ...r }));
127
+ }
128
+ /** 标记完成并写入业务结果;run 不存在返回 undefined。 */
129
+ finish(runId, result) {
130
+ const run = this.runs.get(runId);
131
+ if (run === undefined)
132
+ return undefined;
133
+ run.status = 'done';
134
+ run.result = result;
135
+ run.updatedAt = this.now();
136
+ return { ...run };
137
+ }
138
+ /** 标记失败并写入错误消息;run 不存在返回 undefined。 */
139
+ fail(runId, error) {
140
+ const run = this.runs.get(runId);
141
+ if (run === undefined)
142
+ return undefined;
143
+ run.status = 'failed';
144
+ run.error = error;
145
+ run.updatedAt = this.now();
146
+ return { ...run };
147
+ }
148
+ /** 惰性清理:超过保留期的 run(含长期 running 的僵死任务)全部移除。 */
149
+ prune() {
150
+ const cutoff = this.now() - this.retentionMs;
151
+ for (const [id, run] of this.runs) {
152
+ if (run.updatedAt < cutoff)
153
+ this.runs.delete(id);
154
+ }
155
+ }
156
+ }
157
+ //# sourceMappingURL=run-registry.js.map
@@ -0,0 +1,53 @@
1
+ import type { ReconcileProbeHooks, ReconcileEnv, ReconcileOptions } from './reconcile.ts';
2
+ import type { JournalStore } from './journal.ts';
3
+ export type StartupRecoveryState = {
4
+ kind: 'NORMAL';
5
+ } | {
6
+ kind: 'LOCKED_LIVE';
7
+ operationId?: string;
8
+ } | {
9
+ kind: 'RECOVERY_REQUIRED';
10
+ operationId?: string;
11
+ } | {
12
+ kind: 'NEEDS_ATTENTION';
13
+ operationId?: string;
14
+ } | {
15
+ kind: 'UNKNOWN_STATE';
16
+ reason: string;
17
+ };
18
+ export interface StartupClassifier {
19
+ classify(): Promise<{
20
+ state: StartupRecoveryState;
21
+ safeModeRequired: boolean;
22
+ recoveryRequired: boolean;
23
+ }>;
24
+ }
25
+ /** 用 inspectStartup 结果构造分类器。lockState: 'LOCKED'|'STALE_LOCK_DETECTED'|'UNKNOWN_STATE'|'FREE'。 */
26
+ export declare function classifyStartup(opts: {
27
+ store: JournalStore;
28
+ hooks: ReconcileProbeHooks;
29
+ env: ReconcileEnv;
30
+ options?: ReconcileOptions;
31
+ lockState: 'LOCKED' | 'STALE_LOCK_DETECTED' | 'UNKNOWN_STATE' | 'FREE';
32
+ }): StartupClassifier;
33
+ export interface StartupSchedulers {
34
+ start(): void;
35
+ }
36
+ /**
37
+ * StartupRecoveryController:`await run()` 完成后调度器才可启动。
38
+ * `startSchedulersIfAllowed()` 只在 NORMAL 启动(幂等);否则(RECOVERY_REQUIRED/NEEDS_ATTENTION/UNKNOWN/LOCKED_LIVE)
39
+ * 不启动 destructive schedulers(read-only host 仍活,diagnostics/recovery API 可用)。fail-closed:classify 抛错 → RECOVERY_REQUIRED。
40
+ */
41
+ export declare class StartupRecoveryController {
42
+ private state;
43
+ private settled;
44
+ private schedulersStarted;
45
+ private readonly classifier;
46
+ private readonly schedulers;
47
+ constructor(classifier: StartupClassifier, schedulers: StartupSchedulers);
48
+ run(): Promise<StartupRecoveryState>;
49
+ get stateValue(): StartupRecoveryState;
50
+ get isSettled(): boolean;
51
+ /** 仅在 NORMAL 下启动 schedulers(幂等;返回是否已启动)。 */
52
+ startSchedulersIfAllowed(): boolean;
53
+ }
@@ -0,0 +1,77 @@
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.js';
13
+ /** 用 inspectStartup 结果构造分类器。lockState: 'LOCKED'|'STALE_LOCK_DETECTED'|'UNKNOWN_STATE'|'FREE'。 */
14
+ export function classifyStartup(opts) {
15
+ return {
16
+ async classify() {
17
+ const insp = await inspectStartup(opts.store, opts.hooks, opts.env, opts.options ?? {}, opts.lockState);
18
+ let state;
19
+ if (opts.lockState === 'LOCKED') {
20
+ // fresh heartbeat:活锁;若仍有 unresolved journal → 视为 live op(LOCKED_LIVE,不作 recovery/接管)
21
+ state = insp.unresolved.length > 0 ? { kind: 'LOCKED_LIVE', operationId: insp.unresolved[0] } : { kind: 'NORMAL' };
22
+ }
23
+ else if (insp.recoveryRequired) {
24
+ state = { kind: 'RECOVERY_REQUIRED', operationId: insp.unresolved[0] };
25
+ }
26
+ else if (insp.unresolved.length > 0 || insp.safeModeRequired) {
27
+ state = { kind: 'NEEDS_ATTENTION', operationId: insp.unresolved[0] };
28
+ }
29
+ else {
30
+ state = { kind: 'NORMAL' };
31
+ }
32
+ return { state, safeModeRequired: insp.safeModeRequired, recoveryRequired: insp.recoveryRequired };
33
+ },
34
+ };
35
+ }
36
+ /**
37
+ * StartupRecoveryController:`await run()` 完成后调度器才可启动。
38
+ * `startSchedulersIfAllowed()` 只在 NORMAL 启动(幂等);否则(RECOVERY_REQUIRED/NEEDS_ATTENTION/UNKNOWN/LOCKED_LIVE)
39
+ * 不启动 destructive schedulers(read-only host 仍活,diagnostics/recovery API 可用)。fail-closed:classify 抛错 → RECOVERY_REQUIRED。
40
+ */
41
+ export class StartupRecoveryController {
42
+ state = { kind: 'NEEDS_ATTENTION' };
43
+ settled = false;
44
+ schedulersStarted = false;
45
+ classifier;
46
+ schedulers;
47
+ constructor(classifier, schedulers) {
48
+ this.classifier = classifier;
49
+ this.schedulers = schedulers;
50
+ }
51
+ async run() {
52
+ try {
53
+ const r = await this.classifier.classify();
54
+ this.state = r.state;
55
+ }
56
+ catch (err) {
57
+ // fail closed:inspect 抛错 → 不默认 NORMAL
58
+ this.state = { kind: 'RECOVERY_REQUIRED', operationId: undefined };
59
+ }
60
+ finally {
61
+ this.settled = true;
62
+ }
63
+ return this.state;
64
+ }
65
+ get stateValue() { return this.state; }
66
+ get isSettled() { return this.settled; }
67
+ /** 仅在 NORMAL 下启动 schedulers(幂等;返回是否已启动)。 */
68
+ startSchedulersIfAllowed() {
69
+ if (this.state.kind === 'NORMAL' && !this.schedulersStarted) {
70
+ this.schedulers.start();
71
+ this.schedulersStarted = true;
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+ }
77
+ //# sourceMappingURL=startup-barrier.js.map