openryoko 2026.10.9 → 2026.10.13

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 (669) hide show
  1. package/dist/bin/jimmy.js +51 -1
  2. package/dist/bin/jimmy.js.map +1 -1
  3. package/dist/package.json +2 -1
  4. package/dist/src/backup/archive.d.ts +65 -0
  5. package/dist/src/backup/archive.d.ts.map +1 -0
  6. package/dist/src/backup/archive.js +214 -0
  7. package/dist/src/backup/archive.js.map +1 -0
  8. package/dist/src/backup/catalog.d.ts +64 -0
  9. package/dist/src/backup/catalog.d.ts.map +1 -0
  10. package/dist/src/backup/catalog.js +252 -0
  11. package/dist/src/backup/catalog.js.map +1 -0
  12. package/dist/src/backup/database-restore.d.ts +63 -0
  13. package/dist/src/backup/database-restore.d.ts.map +1 -0
  14. package/dist/src/backup/database-restore.js +236 -0
  15. package/dist/src/backup/database-restore.js.map +1 -0
  16. package/dist/src/backup/database-source.d.ts +70 -0
  17. package/dist/src/backup/database-source.d.ts.map +1 -0
  18. package/dist/src/backup/database-source.js +70 -0
  19. package/dist/src/backup/database-source.js.map +1 -0
  20. package/dist/src/backup/format.d.ts +4 -0
  21. package/dist/src/backup/format.d.ts.map +1 -0
  22. package/dist/src/backup/format.js +15 -0
  23. package/dist/src/backup/format.js.map +1 -0
  24. package/dist/src/backup/gateway-liveness.d.ts +44 -0
  25. package/dist/src/backup/gateway-liveness.d.ts.map +1 -0
  26. package/dist/src/backup/gateway-liveness.js +120 -0
  27. package/dist/src/backup/gateway-liveness.js.map +1 -0
  28. package/dist/src/backup/inspect.d.ts +45 -0
  29. package/dist/src/backup/inspect.d.ts.map +1 -0
  30. package/dist/src/backup/inspect.js +291 -0
  31. package/dist/src/backup/inspect.js.map +1 -0
  32. package/dist/src/backup/layout.d.ts +11 -0
  33. package/dist/src/backup/layout.d.ts.map +1 -0
  34. package/dist/src/backup/layout.js +16 -0
  35. package/dist/src/backup/layout.js.map +1 -0
  36. package/dist/src/backup/limits.d.ts +54 -0
  37. package/dist/src/backup/limits.d.ts.map +1 -0
  38. package/dist/src/backup/limits.js +59 -0
  39. package/dist/src/backup/limits.js.map +1 -0
  40. package/dist/src/backup/manifest.d.ts +45 -0
  41. package/dist/src/backup/manifest.d.ts.map +1 -0
  42. package/dist/src/backup/manifest.js +77 -0
  43. package/dist/src/backup/manifest.js.map +1 -0
  44. package/dist/src/backup/restore.d.ts +73 -0
  45. package/dist/src/backup/restore.d.ts.map +1 -0
  46. package/dist/src/backup/restore.js +685 -0
  47. package/dist/src/backup/restore.js.map +1 -0
  48. package/dist/src/backup/run.d.ts +76 -0
  49. package/dist/src/backup/run.d.ts.map +1 -0
  50. package/dist/src/backup/run.js +181 -0
  51. package/dist/src/backup/run.js.map +1 -0
  52. package/dist/src/backup/scheduler.d.ts +51 -0
  53. package/dist/src/backup/scheduler.d.ts.map +1 -0
  54. package/dist/src/backup/scheduler.js +198 -0
  55. package/dist/src/backup/scheduler.js.map +1 -0
  56. package/dist/src/backup/settings.d.ts +44 -0
  57. package/dist/src/backup/settings.d.ts.map +1 -0
  58. package/dist/src/backup/settings.js +91 -0
  59. package/dist/src/backup/settings.js.map +1 -0
  60. package/dist/src/backup/space.d.ts +22 -0
  61. package/dist/src/backup/space.d.ts.map +1 -0
  62. package/dist/src/backup/space.js +47 -0
  63. package/dist/src/backup/space.js.map +1 -0
  64. package/dist/src/backup/state.d.ts +46 -0
  65. package/dist/src/backup/state.d.ts.map +1 -0
  66. package/dist/src/backup/state.js +137 -0
  67. package/dist/src/backup/state.js.map +1 -0
  68. package/dist/src/backup/tar.d.ts +64 -0
  69. package/dist/src/backup/tar.d.ts.map +1 -0
  70. package/dist/src/backup/tar.js +274 -0
  71. package/dist/src/backup/tar.js.map +1 -0
  72. package/dist/src/backup/targets.d.ts +85 -0
  73. package/dist/src/backup/targets.d.ts.map +1 -0
  74. package/dist/src/backup/targets.js +104 -0
  75. package/dist/src/backup/targets.js.map +1 -0
  76. package/dist/src/backup/walk.d.ts +42 -0
  77. package/dist/src/backup/walk.d.ts.map +1 -0
  78. package/dist/src/backup/walk.js +324 -0
  79. package/dist/src/backup/walk.js.map +1 -0
  80. package/dist/src/cli/backup.d.ts +45 -0
  81. package/dist/src/cli/backup.d.ts.map +1 -0
  82. package/dist/src/cli/backup.js +344 -0
  83. package/dist/src/cli/backup.js.map +1 -0
  84. package/dist/src/cli/bundled-skills.d.ts +7 -1
  85. package/dist/src/cli/bundled-skills.d.ts.map +1 -1
  86. package/dist/src/cli/bundled-skills.js +12 -2
  87. package/dist/src/cli/bundled-skills.js.map +1 -1
  88. package/dist/src/cli/config-failure.d.ts +18 -0
  89. package/dist/src/cli/config-failure.d.ts.map +1 -0
  90. package/dist/src/cli/config-failure.js +39 -0
  91. package/dist/src/cli/config-failure.js.map +1 -0
  92. package/dist/src/cli/gateway-audit.d.ts +3 -0
  93. package/dist/src/cli/gateway-audit.d.ts.map +1 -1
  94. package/dist/src/cli/gateway-audit.js +61 -14
  95. package/dist/src/cli/gateway-audit.js.map +1 -1
  96. package/dist/src/cli/gateway-url-backup.d.ts +21 -0
  97. package/dist/src/cli/gateway-url-backup.d.ts.map +1 -0
  98. package/dist/src/cli/gateway-url-backup.js +87 -0
  99. package/dist/src/cli/gateway-url-backup.js.map +1 -0
  100. package/dist/src/cli/home-copy.d.ts +37 -0
  101. package/dist/src/cli/home-copy.d.ts.map +1 -0
  102. package/dist/src/cli/home-copy.js +155 -0
  103. package/dist/src/cli/home-copy.js.map +1 -0
  104. package/dist/src/cli/interactive-config.d.ts +5 -0
  105. package/dist/src/cli/interactive-config.d.ts.map +1 -1
  106. package/dist/src/cli/interactive-config.js +16 -7
  107. package/dist/src/cli/interactive-config.js.map +1 -1
  108. package/dist/src/cli/migrate.d.ts +16 -0
  109. package/dist/src/cli/migrate.d.ts.map +1 -1
  110. package/dist/src/cli/migrate.js +358 -69
  111. package/dist/src/cli/migrate.js.map +1 -1
  112. package/dist/src/cli/migration-declarations.d.ts +24 -0
  113. package/dist/src/cli/migration-declarations.d.ts.map +1 -0
  114. package/dist/src/cli/migration-declarations.js +54 -0
  115. package/dist/src/cli/migration-declarations.js.map +1 -0
  116. package/dist/src/cli/start.d.ts.map +1 -1
  117. package/dist/src/cli/start.js +40 -1
  118. package/dist/src/cli/start.js.map +1 -1
  119. package/dist/src/connectors/chunked-send.d.ts +27 -0
  120. package/dist/src/connectors/chunked-send.d.ts.map +1 -0
  121. package/dist/src/connectors/chunked-send.js +40 -0
  122. package/dist/src/connectors/chunked-send.js.map +1 -0
  123. package/dist/src/connectors/cron/index.d.ts +10 -0
  124. package/dist/src/connectors/cron/index.d.ts.map +1 -1
  125. package/dist/src/connectors/cron/index.js +26 -3
  126. package/dist/src/connectors/cron/index.js.map +1 -1
  127. package/dist/src/connectors/discord/attachments.d.ts +25 -0
  128. package/dist/src/connectors/discord/attachments.d.ts.map +1 -0
  129. package/dist/src/connectors/discord/attachments.js +33 -0
  130. package/dist/src/connectors/discord/attachments.js.map +1 -0
  131. package/dist/src/connectors/discord/format.d.ts +17 -1
  132. package/dist/src/connectors/discord/format.d.ts.map +1 -1
  133. package/dist/src/connectors/discord/format.js +36 -6
  134. package/dist/src/connectors/discord/format.js.map +1 -1
  135. package/dist/src/connectors/discord/index.d.ts +12 -0
  136. package/dist/src/connectors/discord/index.d.ts.map +1 -1
  137. package/dist/src/connectors/discord/index.js +47 -40
  138. package/dist/src/connectors/discord/index.js.map +1 -1
  139. package/dist/src/connectors/discord/remote.d.ts +45 -1
  140. package/dist/src/connectors/discord/remote.d.ts.map +1 -1
  141. package/dist/src/connectors/discord/remote.js +147 -22
  142. package/dist/src/connectors/discord/remote.js.map +1 -1
  143. package/dist/src/connectors/slack/attachments.d.ts +25 -0
  144. package/dist/src/connectors/slack/attachments.d.ts.map +1 -0
  145. package/dist/src/connectors/slack/attachments.js +32 -0
  146. package/dist/src/connectors/slack/attachments.js.map +1 -0
  147. package/dist/src/connectors/slack/auth-test-cache.d.ts +22 -0
  148. package/dist/src/connectors/slack/auth-test-cache.d.ts.map +1 -0
  149. package/dist/src/connectors/slack/auth-test-cache.js +34 -0
  150. package/dist/src/connectors/slack/auth-test-cache.js.map +1 -0
  151. package/dist/src/connectors/slack/format.d.ts +6 -1
  152. package/dist/src/connectors/slack/format.d.ts.map +1 -1
  153. package/dist/src/connectors/slack/format.js +65 -13
  154. package/dist/src/connectors/slack/format.js.map +1 -1
  155. package/dist/src/connectors/slack/index.d.ts +4 -0
  156. package/dist/src/connectors/slack/index.d.ts.map +1 -1
  157. package/dist/src/connectors/slack/index.js +64 -52
  158. package/dist/src/connectors/slack/index.js.map +1 -1
  159. package/dist/src/connectors/slack/provider-auth-blocks.d.ts +62 -0
  160. package/dist/src/connectors/slack/provider-auth-blocks.d.ts.map +1 -0
  161. package/dist/src/connectors/slack/provider-auth-blocks.js +204 -0
  162. package/dist/src/connectors/slack/provider-auth-blocks.js.map +1 -0
  163. package/dist/src/connectors/slack/provider-auth.d.ts +126 -0
  164. package/dist/src/connectors/slack/provider-auth.d.ts.map +1 -0
  165. package/dist/src/connectors/slack/provider-auth.js +357 -0
  166. package/dist/src/connectors/slack/provider-auth.js.map +1 -0
  167. package/dist/src/connectors/telegram/index.d.ts +5 -0
  168. package/dist/src/connectors/telegram/index.d.ts.map +1 -1
  169. package/dist/src/connectors/telegram/index.js +14 -22
  170. package/dist/src/connectors/telegram/index.js.map +1 -1
  171. package/dist/src/connectors/whatsapp/index.d.ts +3 -0
  172. package/dist/src/connectors/whatsapp/index.d.ts.map +1 -1
  173. package/dist/src/connectors/whatsapp/index.js +33 -14
  174. package/dist/src/connectors/whatsapp/index.js.map +1 -1
  175. package/dist/src/cron/alert-throttle.d.ts +28 -0
  176. package/dist/src/cron/alert-throttle.d.ts.map +1 -0
  177. package/dist/src/cron/alert-throttle.js +106 -0
  178. package/dist/src/cron/alert-throttle.js.map +1 -0
  179. package/dist/src/cron/jobs.d.ts +8 -0
  180. package/dist/src/cron/jobs.d.ts.map +1 -1
  181. package/dist/src/cron/jobs.js +27 -1
  182. package/dist/src/cron/jobs.js.map +1 -1
  183. package/dist/src/cron/run-outcome.d.ts +28 -0
  184. package/dist/src/cron/run-outcome.d.ts.map +1 -0
  185. package/dist/src/cron/run-outcome.js +66 -0
  186. package/dist/src/cron/run-outcome.js.map +1 -0
  187. package/dist/src/cron/runner.d.ts.map +1 -1
  188. package/dist/src/cron/runner.js +68 -5
  189. package/dist/src/cron/runner.js.map +1 -1
  190. package/dist/src/cron/scheduler.d.ts +8 -1
  191. package/dist/src/cron/scheduler.d.ts.map +1 -1
  192. package/dist/src/cron/scheduler.js +11 -4
  193. package/dist/src/cron/scheduler.js.map +1 -1
  194. package/dist/src/cron/waiting-fires.d.ts +18 -0
  195. package/dist/src/cron/waiting-fires.d.ts.map +1 -0
  196. package/dist/src/cron/waiting-fires.js +49 -0
  197. package/dist/src/cron/waiting-fires.js.map +1 -0
  198. package/dist/src/engines/claude-interactive.d.ts +15 -2
  199. package/dist/src/engines/claude-interactive.d.ts.map +1 -1
  200. package/dist/src/engines/claude-interactive.js +32 -11
  201. package/dist/src/engines/claude-interactive.js.map +1 -1
  202. package/dist/src/engines/claude.d.ts.map +1 -1
  203. package/dist/src/engines/claude.js +37 -5
  204. package/dist/src/engines/claude.js.map +1 -1
  205. package/dist/src/engines/codex.d.ts.map +1 -1
  206. package/dist/src/engines/codex.js +1 -0
  207. package/dist/src/engines/codex.js.map +1 -1
  208. package/dist/src/engines/gemini.d.ts.map +1 -1
  209. package/dist/src/engines/gemini.js +1 -0
  210. package/dist/src/engines/gemini.js.map +1 -1
  211. package/dist/src/gateway/api.d.ts.map +1 -1
  212. package/dist/src/gateway/api.js +182 -150
  213. package/dist/src/gateway/api.js.map +1 -1
  214. package/dist/src/gateway/config-redaction.d.ts +32 -0
  215. package/dist/src/gateway/config-redaction.d.ts.map +1 -0
  216. package/dist/src/gateway/config-redaction.js +139 -0
  217. package/dist/src/gateway/config-redaction.js.map +1 -0
  218. package/dist/src/gateway/config-revision.d.ts +46 -0
  219. package/dist/src/gateway/config-revision.d.ts.map +1 -0
  220. package/dist/src/gateway/config-revision.js +63 -0
  221. package/dist/src/gateway/config-revision.js.map +1 -0
  222. package/dist/src/gateway/connector-config.d.ts +21 -0
  223. package/dist/src/gateway/connector-config.d.ts.map +1 -0
  224. package/dist/src/gateway/connector-config.js +24 -0
  225. package/dist/src/gateway/connector-config.js.map +1 -0
  226. package/dist/src/gateway/daemon-entry.js +5 -0
  227. package/dist/src/gateway/daemon-entry.js.map +1 -1
  228. package/dist/src/gateway/engine-health-monitor.d.ts +67 -0
  229. package/dist/src/gateway/engine-health-monitor.d.ts.map +1 -0
  230. package/dist/src/gateway/engine-health-monitor.js +221 -0
  231. package/dist/src/gateway/engine-health-monitor.js.map +1 -0
  232. package/dist/src/gateway/files.d.ts +7 -1
  233. package/dist/src/gateway/files.d.ts.map +1 -1
  234. package/dist/src/gateway/files.js +110 -217
  235. package/dist/src/gateway/files.js.map +1 -1
  236. package/dist/src/gateway/portal-config.d.ts +17 -3
  237. package/dist/src/gateway/portal-config.d.ts.map +1 -1
  238. package/dist/src/gateway/portal-config.js +52 -3
  239. package/dist/src/gateway/portal-config.js.map +1 -1
  240. package/dist/src/gateway/request-origin.d.ts +9 -0
  241. package/dist/src/gateway/request-origin.d.ts.map +1 -1
  242. package/dist/src/gateway/request-origin.js +10 -0
  243. package/dist/src/gateway/request-origin.js.map +1 -1
  244. package/dist/src/gateway/server.d.ts.map +1 -1
  245. package/dist/src/gateway/server.js +76 -59
  246. package/dist/src/gateway/server.js.map +1 -1
  247. package/dist/src/gateway/slack-connect-rollback.d.ts +23 -0
  248. package/dist/src/gateway/slack-connect-rollback.d.ts.map +1 -0
  249. package/dist/src/gateway/slack-connect-rollback.js +53 -0
  250. package/dist/src/gateway/slack-connect-rollback.js.map +1 -0
  251. package/dist/src/gateway/status-reconciler.d.ts +25 -7
  252. package/dist/src/gateway/status-reconciler.d.ts.map +1 -1
  253. package/dist/src/gateway/status-reconciler.js +86 -43
  254. package/dist/src/gateway/status-reconciler.js.map +1 -1
  255. package/dist/src/gateway/watcher.d.ts.map +1 -1
  256. package/dist/src/gateway/watcher.js +44 -3
  257. package/dist/src/gateway/watcher.js.map +1 -1
  258. package/dist/src/mcp/gateway-server.js +21 -3
  259. package/dist/src/mcp/gateway-server.js.map +1 -1
  260. package/dist/src/mcp/resolver.d.ts.map +1 -1
  261. package/dist/src/mcp/resolver.js +51 -1
  262. package/dist/src/mcp/resolver.js.map +1 -1
  263. package/dist/src/models/service.d.ts.map +1 -1
  264. package/dist/src/models/service.js +14 -8
  265. package/dist/src/models/service.js.map +1 -1
  266. package/dist/src/provider-auth/discovery.d.ts +16 -0
  267. package/dist/src/provider-auth/discovery.d.ts.map +1 -0
  268. package/dist/src/provider-auth/discovery.js +66 -0
  269. package/dist/src/provider-auth/discovery.js.map +1 -0
  270. package/dist/src/provider-auth/failure-notices.d.ts +29 -0
  271. package/dist/src/provider-auth/failure-notices.d.ts.map +1 -0
  272. package/dist/src/provider-auth/failure-notices.js +48 -0
  273. package/dist/src/provider-auth/failure-notices.js.map +1 -0
  274. package/dist/src/provider-auth/failure-signal.d.ts +22 -0
  275. package/dist/src/provider-auth/failure-signal.d.ts.map +1 -0
  276. package/dist/src/provider-auth/failure-signal.js +79 -0
  277. package/dist/src/provider-auth/failure-signal.js.map +1 -0
  278. package/dist/src/provider-auth/index.d.ts +26 -0
  279. package/dist/src/provider-auth/index.d.ts.map +1 -0
  280. package/dist/src/provider-auth/index.js +51 -0
  281. package/dist/src/provider-auth/index.js.map +1 -0
  282. package/dist/src/provider-auth/input.d.ts +44 -0
  283. package/dist/src/provider-auth/input.d.ts.map +1 -0
  284. package/dist/src/provider-auth/input.js +86 -0
  285. package/dist/src/provider-auth/input.js.map +1 -0
  286. package/dist/src/provider-auth/providers.d.ts +26 -0
  287. package/dist/src/provider-auth/providers.d.ts.map +1 -0
  288. package/dist/src/provider-auth/providers.js +86 -0
  289. package/dist/src/provider-auth/providers.js.map +1 -0
  290. package/dist/src/provider-auth/runtime.d.ts +21 -0
  291. package/dist/src/provider-auth/runtime.d.ts.map +1 -0
  292. package/dist/src/provider-auth/runtime.js +104 -0
  293. package/dist/src/provider-auth/runtime.js.map +1 -0
  294. package/dist/src/provider-auth/service.d.ts +70 -0
  295. package/dist/src/provider-auth/service.d.ts.map +1 -0
  296. package/dist/src/provider-auth/service.js +349 -0
  297. package/dist/src/provider-auth/service.js.map +1 -0
  298. package/dist/src/provider-auth/terminal.d.ts +21 -0
  299. package/dist/src/provider-auth/terminal.d.ts.map +1 -0
  300. package/dist/src/provider-auth/terminal.js +46 -0
  301. package/dist/src/provider-auth/terminal.js.map +1 -0
  302. package/dist/src/provider-auth/types.d.ts +123 -0
  303. package/dist/src/provider-auth/types.d.ts.map +1 -0
  304. package/dist/src/provider-auth/types.js +10 -0
  305. package/dist/src/provider-auth/types.js.map +1 -0
  306. package/dist/src/sessions/accounting.d.ts +3 -0
  307. package/dist/src/sessions/accounting.d.ts.map +1 -1
  308. package/dist/src/sessions/accounting.js +5 -0
  309. package/dist/src/sessions/accounting.js.map +1 -1
  310. package/dist/src/sessions/backup-integrity.d.ts +45 -0
  311. package/dist/src/sessions/backup-integrity.d.ts.map +1 -0
  312. package/dist/src/sessions/backup-integrity.js +122 -0
  313. package/dist/src/sessions/backup-integrity.js.map +1 -0
  314. package/dist/src/sessions/backup.d.ts +40 -2
  315. package/dist/src/sessions/backup.d.ts.map +1 -1
  316. package/dist/src/sessions/backup.js +88 -12
  317. package/dist/src/sessions/backup.js.map +1 -1
  318. package/dist/src/sessions/callbacks.d.ts +9 -0
  319. package/dist/src/sessions/callbacks.d.ts.map +1 -1
  320. package/dist/src/sessions/callbacks.js +55 -10
  321. package/dist/src/sessions/callbacks.js.map +1 -1
  322. package/dist/src/sessions/completion-batching.d.ts +82 -0
  323. package/dist/src/sessions/completion-batching.d.ts.map +1 -0
  324. package/dist/src/sessions/completion-batching.js +126 -0
  325. package/dist/src/sessions/completion-batching.js.map +1 -0
  326. package/dist/src/sessions/connector-command-guard.d.ts +66 -0
  327. package/dist/src/sessions/connector-command-guard.d.ts.map +1 -0
  328. package/dist/src/sessions/connector-command-guard.js +145 -0
  329. package/dist/src/sessions/connector-command-guard.js.map +1 -0
  330. package/dist/src/sessions/context.js +2 -2
  331. package/dist/src/sessions/engine-fallback.d.ts +43 -1
  332. package/dist/src/sessions/engine-fallback.d.ts.map +1 -1
  333. package/dist/src/sessions/engine-fallback.js +266 -15
  334. package/dist/src/sessions/engine-fallback.js.map +1 -1
  335. package/dist/src/sessions/engine-health-gate.d.ts +83 -0
  336. package/dist/src/sessions/engine-health-gate.d.ts.map +1 -0
  337. package/dist/src/sessions/engine-health-gate.js +186 -0
  338. package/dist/src/sessions/engine-health-gate.js.map +1 -0
  339. package/dist/src/sessions/engine-login.d.ts +58 -0
  340. package/dist/src/sessions/engine-login.d.ts.map +1 -0
  341. package/dist/src/sessions/engine-login.js +107 -0
  342. package/dist/src/sessions/engine-login.js.map +1 -0
  343. package/dist/src/sessions/fork.d.ts.map +1 -1
  344. package/dist/src/sessions/fork.js +2 -1
  345. package/dist/src/sessions/fork.js.map +1 -1
  346. package/dist/src/sessions/goal-execution.d.ts.map +1 -1
  347. package/dist/src/sessions/goal-execution.js +8 -1
  348. package/dist/src/sessions/goal-execution.js.map +1 -1
  349. package/dist/src/sessions/limit-failure-notice.d.ts +41 -0
  350. package/dist/src/sessions/limit-failure-notice.d.ts.map +1 -0
  351. package/dist/src/sessions/limit-failure-notice.js +87 -0
  352. package/dist/src/sessions/limit-failure-notice.js.map +1 -0
  353. package/dist/src/sessions/lost-turn.d.ts +39 -0
  354. package/dist/src/sessions/lost-turn.d.ts.map +1 -0
  355. package/dist/src/sessions/lost-turn.js +32 -0
  356. package/dist/src/sessions/lost-turn.js.map +1 -0
  357. package/dist/src/sessions/manager.d.ts.map +1 -1
  358. package/dist/src/sessions/manager.js +104 -47
  359. package/dist/src/sessions/manager.js.map +1 -1
  360. package/dist/src/sessions/new-session-engine.d.ts +42 -0
  361. package/dist/src/sessions/new-session-engine.d.ts.map +1 -0
  362. package/dist/src/sessions/new-session-engine.js +100 -0
  363. package/dist/src/sessions/new-session-engine.js.map +1 -0
  364. package/dist/src/sessions/origin-delivery.d.ts +50 -4
  365. package/dist/src/sessions/origin-delivery.d.ts.map +1 -1
  366. package/dist/src/sessions/origin-delivery.js +108 -9
  367. package/dist/src/sessions/origin-delivery.js.map +1 -1
  368. package/dist/src/sessions/queue.d.ts +14 -0
  369. package/dist/src/sessions/queue.d.ts.map +1 -1
  370. package/dist/src/sessions/queue.js +38 -2
  371. package/dist/src/sessions/queue.js.map +1 -1
  372. package/dist/src/sessions/registry.d.ts +4 -2
  373. package/dist/src/sessions/registry.d.ts.map +1 -1
  374. package/dist/src/sessions/registry.js +21 -4
  375. package/dist/src/sessions/registry.js.map +1 -1
  376. package/dist/src/sessions/reply-disposition.d.ts +8 -0
  377. package/dist/src/sessions/reply-disposition.d.ts.map +1 -1
  378. package/dist/src/sessions/reply-disposition.js +8 -0
  379. package/dist/src/sessions/reply-disposition.js.map +1 -1
  380. package/dist/src/sessions/restart-resume.d.ts +234 -0
  381. package/dist/src/sessions/restart-resume.d.ts.map +1 -0
  382. package/dist/src/sessions/restart-resume.js +596 -0
  383. package/dist/src/sessions/restart-resume.js.map +1 -0
  384. package/dist/src/sessions/speaker-prefix.d.ts.map +1 -1
  385. package/dist/src/sessions/speaker-prefix.js +3 -1
  386. package/dist/src/sessions/speaker-prefix.js.map +1 -1
  387. package/dist/src/sessions/turn-delivery.d.ts +26 -0
  388. package/dist/src/sessions/turn-delivery.d.ts.map +1 -0
  389. package/dist/src/sessions/turn-delivery.js +34 -0
  390. package/dist/src/sessions/turn-delivery.js.map +1 -0
  391. package/dist/src/sessions/unrequested-stop.d.ts +26 -0
  392. package/dist/src/sessions/unrequested-stop.d.ts.map +1 -0
  393. package/dist/src/sessions/unrequested-stop.js +19 -0
  394. package/dist/src/sessions/unrequested-stop.js.map +1 -0
  395. package/dist/src/sessions/usage-limit-wait.d.ts +14 -0
  396. package/dist/src/sessions/usage-limit-wait.d.ts.map +1 -0
  397. package/dist/src/sessions/usage-limit-wait.js +9 -0
  398. package/dist/src/sessions/usage-limit-wait.js.map +1 -0
  399. package/dist/src/shared/attachment-download.d.ts +41 -0
  400. package/dist/src/shared/attachment-download.d.ts.map +1 -0
  401. package/dist/src/shared/attachment-download.js +110 -0
  402. package/dist/src/shared/attachment-download.js.map +1 -0
  403. package/dist/src/shared/attachment-notice.d.ts +24 -0
  404. package/dist/src/shared/attachment-notice.d.ts.map +1 -0
  405. package/dist/src/shared/attachment-notice.js +37 -0
  406. package/dist/src/shared/attachment-notice.js.map +1 -0
  407. package/dist/src/shared/attachments.d.ts +65 -0
  408. package/dist/src/shared/attachments.d.ts.map +1 -0
  409. package/dist/src/shared/attachments.js +153 -0
  410. package/dist/src/shared/attachments.js.map +1 -0
  411. package/dist/src/shared/childEnv.d.ts +15 -0
  412. package/dist/src/shared/childEnv.d.ts.map +1 -1
  413. package/dist/src/shared/childEnv.js +15 -0
  414. package/dist/src/shared/childEnv.js.map +1 -1
  415. package/dist/src/shared/claude-limit-reset.d.ts +54 -0
  416. package/dist/src/shared/claude-limit-reset.d.ts.map +1 -0
  417. package/dist/src/shared/claude-limit-reset.js +99 -0
  418. package/dist/src/shared/claude-limit-reset.js.map +1 -0
  419. package/dist/src/shared/config-error.d.ts +21 -0
  420. package/dist/src/shared/config-error.d.ts.map +1 -0
  421. package/dist/src/shared/config-error.js +37 -0
  422. package/dist/src/shared/config-error.js.map +1 -0
  423. package/dist/src/shared/config-file.d.ts +57 -0
  424. package/dist/src/shared/config-file.d.ts.map +1 -0
  425. package/dist/src/shared/config-file.js +217 -0
  426. package/dist/src/shared/config-file.js.map +1 -0
  427. package/dist/src/shared/config-yaml-edit.d.ts +20 -0
  428. package/dist/src/shared/config-yaml-edit.d.ts.map +1 -0
  429. package/dist/src/shared/config-yaml-edit.js +468 -0
  430. package/dist/src/shared/config-yaml-edit.js.map +1 -0
  431. package/dist/src/shared/config.d.ts.map +1 -1
  432. package/dist/src/shared/config.js +12 -4
  433. package/dist/src/shared/config.js.map +1 -1
  434. package/dist/src/shared/engine-fallback.d.ts +22 -0
  435. package/dist/src/shared/engine-fallback.d.ts.map +1 -1
  436. package/dist/src/shared/engine-fallback.js +55 -4
  437. package/dist/src/shared/engine-fallback.js.map +1 -1
  438. package/dist/src/shared/engine-health.d.ts +16 -0
  439. package/dist/src/shared/engine-health.d.ts.map +1 -1
  440. package/dist/src/shared/engine-health.js +42 -0
  441. package/dist/src/shared/engine-health.js.map +1 -1
  442. package/dist/src/shared/list-alignment.d.ts +23 -0
  443. package/dist/src/shared/list-alignment.d.ts.map +1 -0
  444. package/dist/src/shared/list-alignment.js +61 -0
  445. package/dist/src/shared/list-alignment.js.map +1 -0
  446. package/dist/src/shared/logger.d.ts.map +1 -1
  447. package/dist/src/shared/logger.js +104 -33
  448. package/dist/src/shared/logger.js.map +1 -1
  449. package/dist/src/shared/map-limited.d.ts +11 -0
  450. package/dist/src/shared/map-limited.d.ts.map +1 -0
  451. package/dist/src/shared/map-limited.js +30 -0
  452. package/dist/src/shared/map-limited.js.map +1 -0
  453. package/dist/src/shared/oneShotCli.d.ts.map +1 -1
  454. package/dist/src/shared/oneShotCli.js +4 -2
  455. package/dist/src/shared/oneShotCli.js.map +1 -1
  456. package/dist/src/shared/partial-delivery.d.ts +24 -0
  457. package/dist/src/shared/partial-delivery.d.ts.map +1 -0
  458. package/dist/src/shared/partial-delivery.js +46 -0
  459. package/dist/src/shared/partial-delivery.js.map +1 -0
  460. package/dist/src/shared/process-safety-net.d.ts +44 -0
  461. package/dist/src/shared/process-safety-net.d.ts.map +1 -0
  462. package/dist/src/shared/process-safety-net.js +88 -0
  463. package/dist/src/shared/process-safety-net.js.map +1 -0
  464. package/dist/src/shared/rateLimit.d.ts +45 -2
  465. package/dist/src/shared/rateLimit.d.ts.map +1 -1
  466. package/dist/src/shared/rateLimit.js +64 -2
  467. package/dist/src/shared/rateLimit.js.map +1 -1
  468. package/dist/src/shared/redact.d.ts.map +1 -1
  469. package/dist/src/shared/redact.js +11 -1
  470. package/dist/src/shared/redact.js.map +1 -1
  471. package/dist/src/shared/safe-file-name.d.ts +9 -0
  472. package/dist/src/shared/safe-file-name.d.ts.map +1 -0
  473. package/dist/src/shared/safe-file-name.js +16 -0
  474. package/dist/src/shared/safe-file-name.js.map +1 -0
  475. package/dist/src/shared/terminal-safe-text.d.ts +2 -0
  476. package/dist/src/shared/terminal-safe-text.d.ts.map +1 -0
  477. package/dist/src/shared/terminal-safe-text.js +21 -0
  478. package/dist/src/shared/terminal-safe-text.js.map +1 -0
  479. package/dist/src/shared/types.d.ts +69 -4
  480. package/dist/src/shared/types.d.ts.map +1 -1
  481. package/dist/src/skills-sync/apply.d.ts +21 -0
  482. package/dist/src/skills-sync/apply.d.ts.map +1 -0
  483. package/dist/src/skills-sync/apply.js +209 -0
  484. package/dist/src/skills-sync/apply.js.map +1 -0
  485. package/dist/src/skills-sync/backup-run.d.ts +47 -0
  486. package/dist/src/skills-sync/backup-run.d.ts.map +1 -0
  487. package/dist/src/skills-sync/backup-run.js +150 -0
  488. package/dist/src/skills-sync/backup-run.js.map +1 -0
  489. package/dist/src/skills-sync/bounded-read.d.ts +32 -0
  490. package/dist/src/skills-sync/bounded-read.d.ts.map +1 -0
  491. package/dist/src/skills-sync/bounded-read.js +104 -0
  492. package/dist/src/skills-sync/bounded-read.js.map +1 -0
  493. package/dist/src/skills-sync/bundled.d.ts +28 -0
  494. package/dist/src/skills-sync/bundled.d.ts.map +1 -0
  495. package/dist/src/skills-sync/bundled.js +84 -0
  496. package/dist/src/skills-sync/bundled.js.map +1 -0
  497. package/dist/src/skills-sync/fingerprint.d.ts +32 -0
  498. package/dist/src/skills-sync/fingerprint.d.ts.map +1 -0
  499. package/dist/src/skills-sync/fingerprint.js +58 -0
  500. package/dist/src/skills-sync/fingerprint.js.map +1 -0
  501. package/dist/src/skills-sync/history.d.ts +44 -0
  502. package/dist/src/skills-sync/history.d.ts.map +1 -0
  503. package/dist/src/skills-sync/history.js +115 -0
  504. package/dist/src/skills-sync/history.js.map +1 -0
  505. package/dist/src/skills-sync/home-skill.d.ts +28 -0
  506. package/dist/src/skills-sync/home-skill.d.ts.map +1 -0
  507. package/dist/src/skills-sync/home-skill.js +67 -0
  508. package/dist/src/skills-sync/home-skill.js.map +1 -0
  509. package/dist/src/skills-sync/instance.d.ts +26 -0
  510. package/dist/src/skills-sync/instance.d.ts.map +1 -0
  511. package/dist/src/skills-sync/instance.js +128 -0
  512. package/dist/src/skills-sync/instance.js.map +1 -0
  513. package/dist/src/skills-sync/names.d.ts +25 -0
  514. package/dist/src/skills-sync/names.d.ts.map +1 -0
  515. package/dist/src/skills-sync/names.js +56 -0
  516. package/dist/src/skills-sync/names.js.map +1 -0
  517. package/dist/src/skills-sync/plan.d.ts +58 -0
  518. package/dist/src/skills-sync/plan.d.ts.map +1 -0
  519. package/dist/src/skills-sync/plan.js +132 -0
  520. package/dist/src/skills-sync/plan.js.map +1 -0
  521. package/dist/src/skills-sync/receipt.d.ts +61 -0
  522. package/dist/src/skills-sync/receipt.d.ts.map +1 -0
  523. package/dist/src/skills-sync/receipt.js +149 -0
  524. package/dist/src/skills-sync/receipt.js.map +1 -0
  525. package/dist/src/skills-sync/staging.d.ts +21 -0
  526. package/dist/src/skills-sync/staging.d.ts.map +1 -0
  527. package/dist/src/skills-sync/staging.js +81 -0
  528. package/dist/src/skills-sync/staging.js.map +1 -0
  529. package/dist/src/skills-sync/sync.d.ts +37 -0
  530. package/dist/src/skills-sync/sync.d.ts.map +1 -0
  531. package/dist/src/skills-sync/sync.js +201 -0
  532. package/dist/src/skills-sync/sync.js.map +1 -0
  533. package/dist/src/skills-sync/types.d.ts +66 -0
  534. package/dist/src/skills-sync/types.d.ts.map +1 -0
  535. package/dist/src/skills-sync/types.js +2 -0
  536. package/dist/src/skills-sync/types.js.map +1 -0
  537. package/dist/src/stt/config.d.ts +5 -0
  538. package/dist/src/stt/config.d.ts.map +1 -0
  539. package/dist/src/stt/config.js +18 -0
  540. package/dist/src/stt/config.js.map +1 -0
  541. package/dist/src/updates/maintenance.d.ts.map +1 -1
  542. package/dist/src/updates/maintenance.js +24 -4
  543. package/dist/src/updates/maintenance.js.map +1 -1
  544. package/dist/src/workflows/repository-mutex.d.ts +1 -1
  545. package/dist/web/404.html +1 -1
  546. package/dist/web/__next.__PAGE__.txt +11 -11
  547. package/dist/web/__next._full.txt +12 -12
  548. package/dist/web/__next._tree.txt +2 -2
  549. package/dist/web/_next/static/chunks/{0g5c5ppr8zmup.js → 20v6mri7epga5.js} +1 -1
  550. package/dist/web/_next/static/chunks/2u0328ngpt-ek.js +1 -0
  551. package/dist/web/_next/static/chunks/3f9i3f9q6v6_j.css +1 -0
  552. package/dist/web/_next/static/chunks/{2iqxlc9wtxzm2.js → 3yy053rafgrzy.js} +1 -1
  553. package/dist/web/_not-found/__next._full.txt +10 -10
  554. package/dist/web/_not-found/__next._not-found.__PAGE__.txt +9 -9
  555. package/dist/web/_not-found/__next._tree.txt +2 -2
  556. package/dist/web/_not-found.html +1 -1
  557. package/dist/web/_not-found.txt +10 -10
  558. package/dist/web/chat/__next._full.txt +12 -12
  559. package/dist/web/chat/__next._tree.txt +2 -2
  560. package/dist/web/chat/__next.chat.__PAGE__.txt +11 -11
  561. package/dist/web/chat.html +1 -1
  562. package/dist/web/chat.txt +12 -12
  563. package/dist/web/cron/__next._full.txt +12 -12
  564. package/dist/web/cron/__next._tree.txt +2 -2
  565. package/dist/web/cron/__next.cron.__PAGE__.txt +11 -11
  566. package/dist/web/cron.html +1 -1
  567. package/dist/web/cron.txt +12 -12
  568. package/dist/web/index.html +1 -1
  569. package/dist/web/index.txt +12 -12
  570. package/dist/web/kanban/__next._full.txt +12 -12
  571. package/dist/web/kanban/__next._tree.txt +2 -2
  572. package/dist/web/kanban/__next.kanban.__PAGE__.txt +11 -11
  573. package/dist/web/kanban.html +1 -1
  574. package/dist/web/kanban.txt +12 -12
  575. package/dist/web/logs/__next._full.txt +12 -12
  576. package/dist/web/logs/__next._tree.txt +2 -2
  577. package/dist/web/logs/__next.logs.__PAGE__.txt +11 -11
  578. package/dist/web/logs.html +1 -1
  579. package/dist/web/logs.txt +12 -12
  580. package/dist/web/models/__next._full.txt +12 -12
  581. package/dist/web/models/__next._tree.txt +2 -2
  582. package/dist/web/models/__next.models.__PAGE__.txt +11 -11
  583. package/dist/web/models.html +1 -1
  584. package/dist/web/models.txt +12 -12
  585. package/dist/web/org/__next._full.txt +12 -12
  586. package/dist/web/org/__next._tree.txt +2 -2
  587. package/dist/web/org/__next.org.__PAGE__.txt +11 -11
  588. package/dist/web/org.html +1 -1
  589. package/dist/web/org.txt +12 -12
  590. package/dist/web/sessions/__next._full.txt +10 -10
  591. package/dist/web/sessions/__next._tree.txt +2 -2
  592. package/dist/web/sessions/__next.sessions.__PAGE__.txt +9 -9
  593. package/dist/web/sessions.html +1 -1
  594. package/dist/web/sessions.txt +10 -10
  595. package/dist/web/settings/__next._full.txt +12 -12
  596. package/dist/web/settings/__next._tree.txt +2 -2
  597. package/dist/web/settings/__next.settings.__PAGE__.txt +11 -11
  598. package/dist/web/settings.html +1 -1
  599. package/dist/web/settings.txt +12 -12
  600. package/dist/web/skills/__next._full.txt +12 -12
  601. package/dist/web/skills/__next._tree.txt +2 -2
  602. package/dist/web/skills/__next.skills.__PAGE__.txt +11 -11
  603. package/dist/web/skills.html +1 -1
  604. package/dist/web/skills.txt +12 -12
  605. package/package.json +2 -1
  606. package/template/bundled-skill-history.json +377 -0
  607. package/template/config.default.yaml +48 -3
  608. package/template/docs/architecture.md +41 -3
  609. package/template/docs/backup.md +142 -0
  610. package/template/docs/connectors.md +192 -16
  611. package/template/docs/cron.md +30 -11
  612. package/template/docs/memory.md +1 -1
  613. package/template/docs/overview.md +6 -2
  614. package/template/docs/self-modification.md +11 -10
  615. package/template/docs/skills.md +77 -4
  616. package/template/migrations/0.3.0/MIGRATION.md +6 -0
  617. package/template/migrations/0.7.3/MIGRATION.md +6 -0
  618. package/template/migrations/0.7.5/MIGRATION.md +1 -1
  619. package/template/migrations/0.9.0/MIGRATION.md +6 -0
  620. package/template/migrations/2026.10.13/MIGRATION.md +76 -0
  621. package/template/migrations/2026.10.13/files/docs/architecture.md +112 -0
  622. package/template/migrations/2026.10.13/files/docs/automations.md +110 -0
  623. package/template/migrations/2026.10.13/files/docs/backup.md +142 -0
  624. package/template/migrations/2026.10.13/files/docs/connectors.md +370 -0
  625. package/template/migrations/2026.10.13/files/docs/cron-commands.md +52 -0
  626. package/template/migrations/2026.10.13/files/docs/cron.md +178 -0
  627. package/template/migrations/2026.10.13/files/docs/mcp.md +108 -0
  628. package/template/migrations/2026.10.13/files/docs/memory.md +47 -0
  629. package/template/migrations/2026.10.13/files/docs/org.md +111 -0
  630. package/template/migrations/2026.10.13/files/docs/overview.md +44 -0
  631. package/template/migrations/2026.10.13/files/docs/self-modification.md +71 -0
  632. package/template/migrations/2026.10.13/files/docs/skills.md +140 -0
  633. package/template/migrations/2026.10.13/files/skills/cron-manager/SKILL.md +107 -0
  634. package/template/migrations/2026.10.13/files/skills/management/SKILL.md +227 -0
  635. package/template/migrations/2026.10.13/files/skills/migrate/SKILL.md +194 -0
  636. package/template/migrations/2026.10.13/files/skills/onboarding/SKILL.md +153 -0
  637. package/template/migrations/2026.10.13/files/skills/openryoko-config/SKILL.md +35 -0
  638. package/template/migrations/2026.10.13/files/skills/openryoko-config/references/engine-fallback.md +98 -0
  639. package/template/migrations/2026.10.13/files/skills/openryoko-config/references/jev.md +89 -0
  640. package/template/migrations/2026.10.13/files/skills/openryoko-config/references/maintenance.md +49 -0
  641. package/template/migrations/2026.10.13/files/skills/openryoko-config/references/platform.md +100 -0
  642. package/template/migrations/2026.10.13/files/skills/self-heal/SKILL.md +187 -0
  643. package/template/migrations/2026.10.9/MIGRATION.md +6 -0
  644. package/template/migrations/2026.10.9/files/docs/memory.md +1 -1
  645. package/template/migrations/2026.10.9/files/skills/migrate/SKILL.md +39 -5
  646. package/template/migrations/2026.5.7/MIGRATION.md +6 -0
  647. package/template/migrations/2026.8.28/MIGRATION.md +6 -0
  648. package/template/migrations/2026.9.11/MIGRATION.md +6 -0
  649. package/template/skills/cron-manager/SKILL.md +10 -0
  650. package/template/skills/management/SKILL.md +5 -4
  651. package/template/skills/migrate/SKILL.md +39 -5
  652. package/template/skills/onboarding/SKILL.md +2 -2
  653. package/template/skills/openryoko-config/SKILL.md +1 -1
  654. package/template/skills/openryoko-config/references/engine-fallback.md +16 -5
  655. package/template/skills/openryoko-config/references/platform.md +23 -4
  656. package/template/skills/self-heal/SKILL.md +117 -44
  657. package/dist/src/engines/mock.d.ts +0 -16
  658. package/dist/src/engines/mock.d.ts.map +0 -1
  659. package/dist/src/engines/mock.js +0 -47
  660. package/dist/src/engines/mock.js.map +0 -1
  661. package/dist/src/shared/test-support/posix-mode.d.ts +0 -17
  662. package/dist/src/shared/test-support/posix-mode.d.ts.map +0 -1
  663. package/dist/src/shared/test-support/posix-mode.js +0 -23
  664. package/dist/src/shared/test-support/posix-mode.js.map +0 -1
  665. package/dist/web/_next/static/chunks/0ic18n-m7ixyw.css +0 -1
  666. package/dist/web/_next/static/chunks/1_jm0szyu2the.js +0 -1
  667. /package/dist/web/_next/static/{peH9RGESLkxB7fw3Cq1GO → ov0mWzyHx0B5oEnTHE_pa}/_buildManifest.js +0 -0
  668. /package/dist/web/_next/static/{peH9RGESLkxB7fw3Cq1GO → ov0mWzyHx0B5oEnTHE_pa}/_clientMiddlewareManifest.js +0 -0
  669. /package/dist/web/_next/static/{peH9RGESLkxB7fw3Cq1GO → ov0mWzyHx0B5oEnTHE_pa}/_ssgManifest.js +0 -0
@@ -0,0 +1,252 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { DATABASE_BACKUP_RETENTION, SQLITE_SIDECAR_SUFFIXES } from "../sessions/backup.js";
4
+ const STAMP = String.raw `(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z`;
5
+ const ARCHIVE_NAME = new RegExp(`^(home|pre-restore)-(${STAMP})(?:-(\\d+))?\\.tar\\.gz$`);
6
+ const DAILY_DATABASE_NAME = /^(sessions|workflows)-\d{4}-\d{2}-\d{2}\.db$/;
7
+ const DATABASE_SNAPSHOT_NAME = new RegExp(`^pre-restore-(${STAMP})(?:-(\\d+))?-(sessions|workflows)\\.db$`);
8
+ /**
9
+ * Temporary names this feature writes under: a leading dot for archives, a bare
10
+ * suffix for database copies and the state file. A database copy is read back
11
+ * before it gets its name, which can leave a -wal and a -shm beside the
12
+ * temporary file; those are temporary too.
13
+ */
14
+ const TEMPORARY_NAME = /^(\.?(home|pre-restore|sessions|workflows)-.+\.tmp-[0-9a-f-]+(-wal|-shm)?|backup-state\.json\.\d+\.[0-9a-f]+\.tmp)$/;
15
+ const STALE_TEMPORARY_MS = 24 * 60 * 60 * 1000;
16
+ /** `20261012T030000Z`: the moment an archive was taken, in a form that sorts as text. */
17
+ export function archiveStamp(when) {
18
+ return `${when.toISOString().slice(0, 19).replace(/[-:]/g, "")}Z`;
19
+ }
20
+ function stampToIso(match, offset) {
21
+ const [year, month, day, hour, minute, second] = match.slice(offset, offset + 6);
22
+ return `${year}-${month}-${day}T${hour}:${minute}:${second}.000Z`;
23
+ }
24
+ /** Recognises a backup by its file name alone, or returns null for anything else. */
25
+ function classify(name) {
26
+ const archive = ARCHIVE_NAME.exec(name);
27
+ if (archive)
28
+ return { kind: "home", preRestore: archive[1] === "pre-restore", createdAt: stampToIso(archive, 3) };
29
+ const snapshot = DATABASE_SNAPSHOT_NAME.exec(name);
30
+ if (snapshot)
31
+ return { kind: snapshot[9], preRestore: true, createdAt: stampToIso(snapshot, 2) };
32
+ const daily = DAILY_DATABASE_NAME.exec(name);
33
+ return daily ? { kind: daily[1], preRestore: false } : null;
34
+ }
35
+ function idOf(name) {
36
+ return name.replace(/\.tar\.gz$|\.db$/, "");
37
+ }
38
+ /** Describes one file as a backup, or returns null when it is not a regular file with a backup's name. */
39
+ function describe(file) {
40
+ const classified = classify(path.basename(file));
41
+ if (!classified)
42
+ return null;
43
+ let stat;
44
+ try {
45
+ stat = fs.lstatSync(file);
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ // A symlink or directory wearing a backup's name is not one, and retention must never act on it.
51
+ if (!stat.isFile())
52
+ return null;
53
+ return {
54
+ id: idOf(path.basename(file)),
55
+ kind: classified.kind,
56
+ preRestore: classified.preRestore,
57
+ file,
58
+ bytes: stat.size,
59
+ createdAt: classified.createdAt ?? stat.mtime.toISOString(),
60
+ };
61
+ }
62
+ function newestFirst(a, b) {
63
+ if (a.createdAt !== b.createdAt)
64
+ return a.createdAt < b.createdAt ? 1 : -1;
65
+ // Same second: a numeric suffix marks the later one.
66
+ return b.id.length - a.id.length || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0);
67
+ }
68
+ /**
69
+ * Far more backups than retention ever leaves behind. Past it the listing stops
70
+ * taking names in: the directory is being flooded, and the next prune removes
71
+ * what it has seen.
72
+ */
73
+ const MAX_LISTED_BACKUPS = 10_000;
74
+ /**
75
+ * The names in `directory` that `wanted` accepts, read one at a time and at
76
+ * most `limit` of them. Never `readdirSync`: the gateway lists this directory
77
+ * after every backup, and a directory somebody has filled with files must not
78
+ * arrive as one array of every name in it.
79
+ */
80
+ function matchingNames(directory, wanted, limit) {
81
+ let listing;
82
+ try {
83
+ listing = fs.opendirSync(directory);
84
+ }
85
+ catch {
86
+ return [];
87
+ }
88
+ const names = [];
89
+ try {
90
+ for (let entry = listing.readSync(); entry && names.length < limit; entry = listing.readSync()) {
91
+ if (wanted(entry.name))
92
+ names.push(entry.name);
93
+ }
94
+ }
95
+ catch {
96
+ // What was read so far is still a true, if partial, picture.
97
+ }
98
+ finally {
99
+ try {
100
+ listing.closeSync();
101
+ }
102
+ catch { /* already closed */ }
103
+ }
104
+ return names;
105
+ }
106
+ /** Every backup in `directory`, newest first. */
107
+ export function listBackups(directory, options = {}) {
108
+ return matchingNames(directory, (name) => classify(name) !== null, options.maxItems ?? MAX_LISTED_BACKUPS)
109
+ .map((name) => describe(path.join(directory, name)))
110
+ .filter((item) => item !== null)
111
+ .sort(newestFirst);
112
+ }
113
+ /**
114
+ * Resolves what the operator typed - an id from `ryoko backup list`, a file
115
+ * name, or a path to an archive kept somewhere else - to one backup.
116
+ */
117
+ export function findBackup(directory, reference) {
118
+ const looksLikePath = path.isAbsolute(reference) || reference.includes("/") || reference.includes(path.sep);
119
+ if (looksLikePath) {
120
+ const file = path.resolve(reference);
121
+ if (!fs.existsSync(file))
122
+ throw new Error(`no backup file at ${file}`);
123
+ const item = describe(file);
124
+ if (!item)
125
+ throw new Error(`${file} is not a backup this command wrote (its file name is not one it recognises)`);
126
+ return item;
127
+ }
128
+ const id = idOf(reference);
129
+ const item = listBackups(directory).find((candidate) => candidate.id === id);
130
+ if (!item)
131
+ throw new Error(`no backup with id "${reference}" in ${directory} (list them with: ryoko backup list)`);
132
+ return item;
133
+ }
134
+ /**
135
+ * A name no backup of this second holds, numbered one past the highest that is
136
+ * there. `build("")` is the first of a second, `build("-2")` the second, and
137
+ * so on; `numbered` matches those names and captures the number.
138
+ *
139
+ * Not the first number that is free. Within a second the number is the order,
140
+ * and one that pruning has freed belonged to a backup older than every one
141
+ * still there: a new backup given it would be named as the oldest of its
142
+ * second, and be the next the rule removes.
143
+ */
144
+ function reserve(directory, numbered, build) {
145
+ let highest = 0;
146
+ for (const name of matchingNames(directory, (candidate) => numbered.test(candidate), MAX_LISTED_BACKUPS)) {
147
+ highest = Math.max(highest, Number(numbered.exec(name)?.[1] ?? 1));
148
+ }
149
+ for (let sequence = highest + 1;; sequence += 1) {
150
+ const name = build(sequence === 1 ? "" : `-${sequence}`);
151
+ // Still asked of each: a directory flooded past what was listed may hold the name after all.
152
+ if (!fs.existsSync(path.join(directory, name)))
153
+ return name;
154
+ }
155
+ }
156
+ /** A name no archive holds yet, so two taken in the same second sit side by side. */
157
+ export function reserveArchiveName(directory, prefix, when) {
158
+ const stem = `${prefix}-${archiveStamp(when)}`;
159
+ const name = reserve(directory, new RegExp(`^${stem}(?:-(\\d+))?\\.tar\\.gz$`), (suffix) => `${stem}${suffix}.tar.gz`);
160
+ return { id: idOf(name), file: path.join(directory, name) };
161
+ }
162
+ /** A name for the copy of a live database taken before a restore replaces it. */
163
+ export function reserveDatabaseSnapshotName(directory, name, when) {
164
+ const stem = `pre-restore-${archiveStamp(when)}`;
165
+ const fileName = reserve(directory, new RegExp(`^${stem}(?:-(\\d+))?-${name}\\.db$`), (suffix) => `${stem}${suffix}-${name}.db`);
166
+ return { id: idOf(fileName), file: path.join(directory, fileName) };
167
+ }
168
+ function removeWithSidecars(file, removed) {
169
+ for (const suffix of ["", ...SQLITE_SIDECAR_SUFFIXES])
170
+ fs.rmSync(`${file}${suffix}`, { force: true });
171
+ removed.push(file);
172
+ }
173
+ function sweepStaleTemporaries(directory, now, removed) {
174
+ for (const name of matchingNames(directory, (candidate) => TEMPORARY_NAME.test(candidate), MAX_LISTED_BACKUPS)) {
175
+ const file = path.join(directory, name);
176
+ try {
177
+ const stat = fs.lstatSync(file);
178
+ if (!stat.isFile() || now.getTime() - stat.mtimeMs < STALE_TEMPORARY_MS)
179
+ continue;
180
+ fs.rmSync(file, { force: true });
181
+ removed.push(file);
182
+ }
183
+ catch { /* gone already, or not ours to touch */ }
184
+ }
185
+ }
186
+ /**
187
+ * How many backups of one kind are kept from a single day. The newest is the
188
+ * day's backup; the two before it are for whoever takes one before each risky
189
+ * change and wants the last few steps back.
190
+ */
191
+ export const SAME_DAY_BACKUPS_KEPT = 3;
192
+ /**
193
+ * The members of one pool that have outlived their keep. `members` is newest
194
+ * first. Kept: the newest `days` days that have a backup at all, and of each of
195
+ * those days its most recent {@link SAME_DAY_BACKUPS_KEPT}.
196
+ *
197
+ * Days, not a count. A count let fourteen backups taken in one afternoon push
198
+ * out fourteen days of history; here a day's worth of them can only ever
199
+ * displace each other. And days that have a backup, not days on the calendar:
200
+ * an instance that was switched off for a month still has its `days` of
201
+ * history when it comes back, rather than none.
202
+ */
203
+ function expired(members, days) {
204
+ const keptPerDay = new Map();
205
+ return members.filter((item) => {
206
+ const day = item.createdAt.slice(0, 10);
207
+ const keptToday = keptPerDay.get(day);
208
+ if (keptToday === undefined && keptPerDay.size >= Math.max(1, days))
209
+ return true;
210
+ if ((keptToday ?? 0) >= SAME_DAY_BACKUPS_KEPT)
211
+ return true;
212
+ keptPerDay.set(day, (keptToday ?? 0) + 1);
213
+ return false;
214
+ });
215
+ }
216
+ /**
217
+ * Trims the backup directory to the days it is meant to hold.
218
+ *
219
+ * Only files this feature names are ever candidates: the directory may be one
220
+ * the operator shares with other things. Daily archives and pre-restore
221
+ * snapshots are counted apart, so a burst of restores cannot push out the
222
+ * daily history. The daily database copies are not touched here - their writer
223
+ * keeps its own seven, one a day - and anything unrecognised is left exactly
224
+ * as it is.
225
+ *
226
+ * `keep` is what the run that is pruning has just written, and none of it is
227
+ * removed whatever the rule says. The rule goes by the time in a file's name.
228
+ * With a clock that has fallen behind the backups already there, the newest
229
+ * backup is by its name the oldest, and a run would report it written and
230
+ * then delete it. It is still judged with the rest, so that on an ordinary
231
+ * day it takes its place and its day keeps to its share.
232
+ */
233
+ export function pruneBackups(directory, options) {
234
+ const removed = [];
235
+ const kept = new Set((options.keep ?? []).map((file) => path.resolve(file)));
236
+ const items = listBackups(directory);
237
+ const pools = [
238
+ { members: items.filter((item) => item.kind === "home" && !item.preRestore), days: options.retention },
239
+ { members: items.filter((item) => item.kind === "home" && item.preRestore), days: options.retention },
240
+ { members: items.filter((item) => item.kind === "sessions" && item.preRestore), days: DATABASE_BACKUP_RETENTION },
241
+ { members: items.filter((item) => item.kind === "workflows" && item.preRestore), days: DATABASE_BACKUP_RETENTION },
242
+ ];
243
+ for (const pool of pools) {
244
+ for (const item of expired(pool.members, pool.days)) {
245
+ if (!kept.has(path.resolve(item.file)))
246
+ removeWithSidecars(item.file, removed);
247
+ }
248
+ }
249
+ sweepStaleTemporaries(directory, options.now, removed);
250
+ return removed;
251
+ }
252
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../src/backup/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type DatabaseBackupName } from "../sessions/backup.js";
2
+ import { type GatewayLiveness } from "./gateway-liveness.js";
3
+ import { type DiskSpaceProbe } from "./space.js";
4
+ export interface DatabaseRestoreOptions {
5
+ /** The backup file to restore from. */
6
+ backup: string;
7
+ name: DatabaseBackupName;
8
+ home: string;
9
+ /** Where the copy of the database being replaced goes. */
10
+ backupDirectory: string;
11
+ now: Date;
12
+ dryRun?: boolean;
13
+ /**
14
+ * The operator's own word that no gateway is running on this home. Required
15
+ * to replace a database, on top of the automatic check - which it never
16
+ * overrides. A dry run replaces nothing and does not need it.
17
+ */
18
+ gatewayStopped?: boolean;
19
+ /** Replaces the check for a running gateway. `destination` is the database about to be replaced. */
20
+ detectGateway?: (home: string, destination: string, now: Date) => GatewayLiveness;
21
+ /** The existing free-space judgement, replaceable in tests. */
22
+ diskSpace?: DiskSpaceProbe;
23
+ }
24
+ export interface DatabaseRestoreResult {
25
+ name: DatabaseBackupName;
26
+ backup: string;
27
+ destination: string;
28
+ dryRun: boolean;
29
+ /** The copy of the database that was replaced. Null on a dry run or when there was none. */
30
+ preRestore: {
31
+ id: string;
32
+ file: string;
33
+ } | null;
34
+ }
35
+ /** What is wrong with a database backup, or an empty list when SQLite finds it sound. */
36
+ export declare function inspectDatabaseBackup(file: string): string[];
37
+ /** The flag that carries the operator's confirmation. Named here because the refusals quote it. */
38
+ export declare const GATEWAY_STOPPED_FLAG = "--gateway-stopped";
39
+ /**
40
+ * Replaces a home's session registry or workflows store with a backup of it.
41
+ *
42
+ * Refused while a gateway is running on the home: its connection would keep
43
+ * writing to a file that is no longer there, and a WAL from the old database
44
+ * would be replayed into the new one.
45
+ *
46
+ * What is opened, and when, is the whole design:
47
+ *
48
+ * - The live database is never opened, in any mode, at any point: not to see
49
+ * whether it is in use, not on a dry run, not to copy it aside (that is a
50
+ * plain file copy, sidecars included), not to replace it (a rename).
51
+ * - The operator's confirmation is checked first, before anything is looked
52
+ * at. Then that the two places this writes - beside the database, and the
53
+ * backup directory when it is in the home - are reached through real
54
+ * directories and not through a symlink leading out of it. Then the signs of
55
+ * a running gateway, which are pid files and file timestamps. A refusal at
56
+ * any of these points has read no database at all.
57
+ * - Only then is the backup opened, read-only: once for SQLite's integrity
58
+ * check (on a dry run too - it is a file in the backup directory, not the
59
+ * one in use), and once as the source of the copy that is written to a new
60
+ * file beside the live database and renamed over it.
61
+ */
62
+ export declare function restoreDatabase(options: DatabaseRestoreOptions): Promise<DatabaseRestoreResult>;
63
+ //# sourceMappingURL=database-restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-restore.d.ts","sourceRoot":"","sources":["../../../src/backup/database-restore.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGzF,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEnF,OAAO,EAAgD,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,sBAAsB;IACrC,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,kBAAkB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oGAAoG;IACpG,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,KAAK,eAAe,CAAC;IAClF,+DAA+D;IAC/D,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,4FAA4F;IAC5F,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACjD;AAoBD,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAW5D;AAwHD,mGAAmG;AACnG,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAwBxD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAyBrG"}
@@ -0,0 +1,236 @@
1
+ import Database from "better-sqlite3";
2
+ import crypto from "node:crypto";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { SQLITE_SIDECAR_SUFFIXES } from "../sessions/backup.js";
6
+ import { reserveDatabaseSnapshotName } from "./catalog.js";
7
+ import { errorMessage } from "./format.js";
8
+ import { detectRunningGateway } from "./gateway-liveness.js";
9
+ import { databasePath } from "./layout.js";
10
+ import { fileBytes, insufficientSpace, sameFilesystem } from "./space.js";
11
+ /**
12
+ * Opens a backup read-only. Reading a WAL-mode file makes SQLite create -wal
13
+ * and -shm beside it and, for a read-only connection, leave them there; the
14
+ * ones that were not there before are removed again on close, so checking a
15
+ * backup does not litter the directory it is kept in.
16
+ */
17
+ function openBackup(file) {
18
+ const absent = SQLITE_SIDECAR_SUFFIXES.filter((suffix) => !fs.existsSync(`${file}${suffix}`));
19
+ const database = new Database(file, { readonly: true, fileMustExist: true });
20
+ return {
21
+ database,
22
+ close: () => {
23
+ database.close();
24
+ for (const suffix of absent)
25
+ fs.rmSync(`${file}${suffix}`, { force: true });
26
+ },
27
+ };
28
+ }
29
+ /** What is wrong with a database backup, or an empty list when SQLite finds it sound. */
30
+ export function inspectDatabaseBackup(file) {
31
+ let opened;
32
+ try {
33
+ opened = openBackup(file);
34
+ const lines = opened.database.pragma("integrity_check").map((row) => row.integrity_check);
35
+ return lines.length === 1 && lines[0] === "ok" ? [] : lines.length > 0 ? lines : ["the integrity check returned nothing"];
36
+ }
37
+ catch (error) {
38
+ return [`the database could not be read: ${errorMessage(error)}`];
39
+ }
40
+ finally {
41
+ opened?.close();
42
+ }
43
+ }
44
+ /** The registry, and the database about to be replaced when that is a different one. */
45
+ function findRunningGateway(home, destination, now) {
46
+ return detectRunningGateway(home, { now, databases: [destination] });
47
+ }
48
+ function lstatOrNull(file) {
49
+ try {
50
+ return fs.lstatSync(file);
51
+ }
52
+ catch (error) {
53
+ if (error.code === "ENOENT")
54
+ return null;
55
+ throw error;
56
+ }
57
+ }
58
+ /**
59
+ * Holds a directory inside the home to being reached through real directories
60
+ * only, all the way down from the home. One that is not there yet is fine: it
61
+ * gets made, as a real directory. A place outside the home is not this
62
+ * function's business - the operator named it, and it is used as it is found.
63
+ */
64
+ function assertRealDirectories(home, directory, consequence) {
65
+ const relative = path.relative(home, directory);
66
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
67
+ return;
68
+ let current = home;
69
+ for (const segment of relative.split(path.sep)) {
70
+ current = path.join(current, segment);
71
+ const stat = lstatOrNull(current);
72
+ if (!stat)
73
+ return;
74
+ const shown = path.relative(home, current).split(path.sep).join("/");
75
+ if (stat.isSymbolicLink())
76
+ throw new Error(`${shown} is a symlink (to ${fs.readlinkSync(current)}). ${consequence} Nothing was changed.`);
77
+ if (!stat.isDirectory())
78
+ throw new Error(`${shown} is not a directory. ${consequence} Nothing was changed.`);
79
+ }
80
+ }
81
+ /**
82
+ * Refuses a restore that would write outside the home by way of a symlink in
83
+ * it. Restoring files never writes through one; this is the same rule for the
84
+ * two things a database restore writes. The new database goes beside the old
85
+ * one, so with `sessions/` swapped for a link it would land wherever that
86
+ * points, and the gateway would go on using it there. And the database being
87
+ * replaced is copied into the backup directory first, which inside the home
88
+ * has to be the directory it looks like.
89
+ */
90
+ function refuseToLeaveTheHome(options, destination) {
91
+ assertRealDirectories(options.home, path.dirname(destination), "A database is restored in place, and through that it would be written outside the home: put the real directory back and run the restore again.");
92
+ assertRealDirectories(options.home, options.backupDirectory, "The database being replaced is copied there first, and through that the copy would leave the home: "
93
+ + "put the real directory back, or name the place itself as backup.directory in config.yaml, and run the restore again.");
94
+ }
95
+ /**
96
+ * Sets the live database aside before it is replaced. The files are copied as
97
+ * they are, sidecars included, rather than through SQLite: a registry being
98
+ * replaced because it is damaged cannot be read that way, and its bytes are
99
+ * still worth keeping.
100
+ */
101
+ function keepCurrentDatabase(options, destination) {
102
+ if (!fs.existsSync(destination))
103
+ return null;
104
+ try {
105
+ fs.mkdirSync(options.backupDirectory, { recursive: true, mode: 0o700 });
106
+ const { id, file } = reserveDatabaseSnapshotName(options.backupDirectory, options.name, options.now);
107
+ for (const suffix of ["", ...SQLITE_SIDECAR_SUFFIXES]) {
108
+ if (!fs.existsSync(`${destination}${suffix}`))
109
+ continue;
110
+ fs.copyFileSync(`${destination}${suffix}`, `${file}${suffix}`, fs.constants.COPYFILE_EXCL);
111
+ try {
112
+ fs.chmodSync(`${file}${suffix}`, 0o600);
113
+ }
114
+ catch { /* Windows has no POSIX modes */ }
115
+ }
116
+ return { id, file };
117
+ }
118
+ catch (error) {
119
+ throw new Error(`the current database could not be saved first, so nothing was restored: ${errorMessage(error)}`);
120
+ }
121
+ }
122
+ async function installDatabase(backup, destination) {
123
+ const directory = path.dirname(destination);
124
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
125
+ const temporary = path.join(directory, `.${path.basename(destination)}.restore-${process.pid}-${crypto.randomBytes(4).toString("hex")}`);
126
+ const source = openBackup(backup);
127
+ try {
128
+ // Through SQLite rather than a file copy: a backup that still has a WAL
129
+ // beside it (a pre-restore copy does) comes out as one complete file.
130
+ await source.database.backup(temporary);
131
+ try {
132
+ fs.chmodSync(temporary, 0o600);
133
+ }
134
+ catch { /* Windows has no POSIX modes */ }
135
+ // A -wal or -shm left beside a replaced database is read as that database's own tail.
136
+ for (const suffix of SQLITE_SIDECAR_SUFFIXES)
137
+ fs.rmSync(`${destination}${suffix}`, { force: true });
138
+ fs.renameSync(temporary, destination);
139
+ }
140
+ catch (error) {
141
+ fs.rmSync(temporary, { force: true });
142
+ throw error;
143
+ }
144
+ finally {
145
+ source.close();
146
+ }
147
+ }
148
+ /**
149
+ * Refuses a restore that would not leave room for the gateway to work once it
150
+ * is back. Two things get written: the copy of the database being replaced,
151
+ * into the backup directory, and the new database beside the old one, which
152
+ * exist together until the rename. Sizes are read from the directory entries;
153
+ * nothing is opened.
154
+ */
155
+ function refuseWithoutRoom(options, destination) {
156
+ const incoming = fileBytes(options.backup) + fileBytes(`${options.backup}-wal`);
157
+ const outgoing = ["", ...SQLITE_SIDECAR_SUFFIXES].reduce((total, suffix) => total + fileBytes(`${destination}${suffix}`), 0);
158
+ const beside = fs.existsSync(path.dirname(destination)) ? path.dirname(destination) : options.home;
159
+ const needs = sameFilesystem(beside, options.backupDirectory)
160
+ ? [[options.backupDirectory, incoming + outgoing]]
161
+ : [[beside, incoming], [options.backupDirectory, outgoing]];
162
+ for (const [directory, bytes] of needs) {
163
+ const reason = insufficientSpace(directory, bytes, options.diskSpace);
164
+ if (reason)
165
+ throw new Error(`${reason}. Nothing was changed.`);
166
+ }
167
+ }
168
+ /** The flag that carries the operator's confirmation. Named here because the refusals quote it. */
169
+ export const GATEWAY_STOPPED_FLAG = "--gateway-stopped";
170
+ /**
171
+ * Why a database is not replaced on the strength of "no gateway was detected".
172
+ *
173
+ * What the detection can read - a live pid, a recent write - is evidence that
174
+ * a gateway is there, never that one is not. The usual deployment keeps the
175
+ * home on the host and bind-mounts it into a container where the gateway runs;
176
+ * a `ryoko` on the host sees the same files, a pid that means nothing in its
177
+ * own pid namespace, and, while the gateway has nothing to write, files that
178
+ * look idle. The one way to know for certain would be to open the database,
179
+ * and opening a database in use from the wrong side of that boundary is what
180
+ * destroys it.
181
+ */
182
+ function confirmationRequired() {
183
+ return new Error(`restoring a database needs ${GATEWAY_STOPPED_FLAG}, your confirmation that no gateway is running on this home. `
184
+ + "This command cannot be sure of it by itself: when the home is bind-mounted into a container, a gateway running inside is "
185
+ + "not reliably visible to a command run on the host, and a database that may be in use is never opened just to find out. "
186
+ + `Run this where the gateway runs (inside the container), stop the gateway first (ryoko stop), then repeat the command with ${GATEWAY_STOPPED_FLAG}. `
187
+ + "Nothing was changed.");
188
+ }
189
+ /**
190
+ * Replaces a home's session registry or workflows store with a backup of it.
191
+ *
192
+ * Refused while a gateway is running on the home: its connection would keep
193
+ * writing to a file that is no longer there, and a WAL from the old database
194
+ * would be replayed into the new one.
195
+ *
196
+ * What is opened, and when, is the whole design:
197
+ *
198
+ * - The live database is never opened, in any mode, at any point: not to see
199
+ * whether it is in use, not on a dry run, not to copy it aside (that is a
200
+ * plain file copy, sidecars included), not to replace it (a rename).
201
+ * - The operator's confirmation is checked first, before anything is looked
202
+ * at. Then that the two places this writes - beside the database, and the
203
+ * backup directory when it is in the home - are reached through real
204
+ * directories and not through a symlink leading out of it. Then the signs of
205
+ * a running gateway, which are pid files and file timestamps. A refusal at
206
+ * any of these points has read no database at all.
207
+ * - Only then is the backup opened, read-only: once for SQLite's integrity
208
+ * check (on a dry run too - it is a file in the backup directory, not the
209
+ * one in use), and once as the source of the copy that is written to a new
210
+ * file beside the live database and renamed over it.
211
+ */
212
+ export async function restoreDatabase(options) {
213
+ const destination = databasePath(options.home, options.name);
214
+ const dryRun = options.dryRun === true;
215
+ if (!dryRun && options.gatewayStopped !== true)
216
+ throw confirmationRequired();
217
+ refuseToLeaveTheHome(options, destination);
218
+ const liveness = (options.detectGateway ?? findRunningGateway)(options.home, destination, options.now);
219
+ if (liveness.running) {
220
+ throw new Error(`a gateway appears to be running on this home (${liveness.reason ?? "it was detected"}). A database cannot be replaced underneath it: `
221
+ + `stop the gateway (ryoko stop), wait a minute, run this command again with ${GATEWAY_STOPPED_FLAG}, then start the gateway. `
222
+ + "Nothing was changed.");
223
+ }
224
+ const problems = inspectDatabaseBackup(options.backup);
225
+ if (problems.length > 0) {
226
+ throw new Error(`refusing to restore a database backup that failed its integrity check - ${problems.slice(0, 3).join("; ")}`);
227
+ }
228
+ refuseWithoutRoom(options, destination);
229
+ const result = { name: options.name, backup: options.backup, destination, dryRun, preRestore: null };
230
+ if (dryRun)
231
+ return result;
232
+ const preRestore = keepCurrentDatabase(options, destination);
233
+ await installDatabase(options.backup, destination);
234
+ return { ...result, preRestore };
235
+ }
236
+ //# sourceMappingURL=database-restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-restore.js","sourceRoot":"","sources":["../../../src/backup/database-restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import Database from "better-sqlite3";
2
+ import type { DatabaseBackupName } from "../sessions/backup.js";
3
+ /**
4
+ * Where a backup run gets a database connection from, and when it gets none.
5
+ *
6
+ * A run opens no database on its own. Every connection is handed to it by a
7
+ * caller that has decided it is safe: the gateway hands over its own, and a
8
+ * command run by hand hands one over only when asked to and only when nothing
9
+ * suggests a gateway is running on the home.
10
+ */
11
+ /** A database to copy, and how to give it back. */
12
+ export interface DatabaseHandle {
13
+ database: Database.Database;
14
+ release(): void;
15
+ }
16
+ /**
17
+ * Why a database was deliberately left unopened.
18
+ * - "not-requested": the run was handed no source for it.
19
+ * - "gateway-running": it was asked for, and a gateway appears to be running on the home.
20
+ */
21
+ export type WithheldReason = "not-requested" | "gateway-running";
22
+ /** A source's refusal: the database is there, and it is not going to be opened. */
23
+ export interface DatabaseWithheld {
24
+ withheld: WithheldReason;
25
+ detail: string;
26
+ }
27
+ /** Hands over a connection, declines to, or returns null when the home has no such database. */
28
+ export type DatabaseSource = () => DatabaseHandle | DatabaseWithheld | null;
29
+ /** The flag that asks `ryoko backup run` for the databases too. Named here because the reports quote it. */
30
+ export declare const INCLUDE_DATABASES_FLAG = "--include-databases";
31
+ /**
32
+ * Opens a database read-only for copying.
33
+ *
34
+ * Read-only is not the same as harmless, and this is only for a caller that
35
+ * knows who else has the file open. What a read-only connection does, traced
36
+ * through the SQLite this ships with and measured:
37
+ *
38
+ * - The main file is opened read-only and cannot be written. The -wal is not
39
+ * written, truncated or deleted either: all of that needs an exclusive lock
40
+ * on the main file, which a read-only descriptor cannot take. So closing it
41
+ * never checkpoints the WAL away, which is what a read-write connection does
42
+ * the moment it believes itself the last one.
43
+ * - The -shm (the WAL's index) is opened read-write regardless. Beside other
44
+ * connections it can see, this one only records where it is reading. When it
45
+ * sees none it takes itself for the first, truncates the -shm to three bytes
46
+ * and rebuilds it from the WAL - and creates an empty -wal and a -shm beside
47
+ * a database that had neither, and leaves them there.
48
+ *
49
+ * On the machine the other connections run on, their locks are seen and this
50
+ * is ordinary SQLite. From the far side of a bind mount into a container they
51
+ * may not be, and a gateway whose index was rebuilt underneath it has not been
52
+ * tested and cannot be from here. Hence the two callers: the gateway, for a
53
+ * database in its own home, and {@link standaloneDatabaseSources}.
54
+ */
55
+ export declare function readOnlyDatabaseSource(file: string): DatabaseSource;
56
+ /**
57
+ * Sources for a command run by hand, outside the gateway.
58
+ *
59
+ * Before the first database would be opened, the home is looked at for signs
60
+ * of a running gateway - pid files and file timestamps, nothing that touches a
61
+ * database - and if there are any, neither database is opened. The answer is
62
+ * settled once for both: this command's own reading leaves a freshly written
63
+ * -shm behind, and asked again it would take that for a gateway.
64
+ *
65
+ * No sign is not proof. A gateway behind a pid this process cannot see, with
66
+ * nothing written for a minute, passes; so this is offered only on request
67
+ * (`--include-databases`), never by default.
68
+ */
69
+ export declare function standaloneDatabaseSources(home: string, now: () => Date): Record<DatabaseBackupName, DatabaseSource>;
70
+ //# sourceMappingURL=database-source.d.ts.map