steroids-api 0.2.7

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 (328) hide show
  1. package/dist/API/src/index.d.ts +10 -0
  2. package/dist/API/src/index.d.ts.map +1 -0
  3. package/dist/API/src/index.js +130 -0
  4. package/dist/API/src/index.js.map +1 -0
  5. package/dist/API/src/routes/activity.d.ts +7 -0
  6. package/dist/API/src/routes/activity.d.ts.map +1 -0
  7. package/dist/API/src/routes/activity.js +252 -0
  8. package/dist/API/src/routes/activity.js.map +1 -0
  9. package/dist/API/src/routes/config.d.ts +7 -0
  10. package/dist/API/src/routes/config.d.ts.map +1 -0
  11. package/dist/API/src/routes/config.js +521 -0
  12. package/dist/API/src/routes/config.js.map +1 -0
  13. package/dist/API/src/routes/health.d.ts +7 -0
  14. package/dist/API/src/routes/health.d.ts.map +1 -0
  15. package/dist/API/src/routes/health.js +172 -0
  16. package/dist/API/src/routes/health.js.map +1 -0
  17. package/dist/API/src/routes/incidents.d.ts +7 -0
  18. package/dist/API/src/routes/incidents.d.ts.map +1 -0
  19. package/dist/API/src/routes/incidents.js +117 -0
  20. package/dist/API/src/routes/incidents.js.map +1 -0
  21. package/dist/API/src/routes/projects.d.ts +7 -0
  22. package/dist/API/src/routes/projects.d.ts.map +1 -0
  23. package/dist/API/src/routes/projects.js +398 -0
  24. package/dist/API/src/routes/projects.js.map +1 -0
  25. package/dist/API/src/routes/runners.d.ts +7 -0
  26. package/dist/API/src/routes/runners.d.ts.map +1 -0
  27. package/dist/API/src/routes/runners.js +242 -0
  28. package/dist/API/src/routes/runners.js.map +1 -0
  29. package/dist/API/src/routes/tasks.d.ts +7 -0
  30. package/dist/API/src/routes/tasks.d.ts.map +1 -0
  31. package/dist/API/src/routes/tasks.js +1007 -0
  32. package/dist/API/src/routes/tasks.js.map +1 -0
  33. package/dist/API/src/utils/validation.d.ts +22 -0
  34. package/dist/API/src/utils/validation.d.ts.map +1 -0
  35. package/dist/API/src/utils/validation.js +50 -0
  36. package/dist/API/src/utils/validation.js.map +1 -0
  37. package/dist/index.d.ts +10 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +184 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/routes/activity.d.ts +7 -0
  42. package/dist/routes/activity.d.ts.map +1 -0
  43. package/dist/routes/activity.js +252 -0
  44. package/dist/routes/activity.js.map +1 -0
  45. package/dist/routes/config.d.ts +7 -0
  46. package/dist/routes/config.d.ts.map +1 -0
  47. package/dist/routes/config.js +647 -0
  48. package/dist/routes/config.js.map +1 -0
  49. package/dist/routes/credit-alerts.d.ts +2 -0
  50. package/dist/routes/credit-alerts.d.ts.map +1 -0
  51. package/dist/routes/credit-alerts.js +97 -0
  52. package/dist/routes/credit-alerts.js.map +1 -0
  53. package/dist/routes/health.d.ts +7 -0
  54. package/dist/routes/health.d.ts.map +1 -0
  55. package/dist/routes/health.js +200 -0
  56. package/dist/routes/health.js.map +1 -0
  57. package/dist/routes/incidents.d.ts +7 -0
  58. package/dist/routes/incidents.d.ts.map +1 -0
  59. package/dist/routes/incidents.js +117 -0
  60. package/dist/routes/incidents.js.map +1 -0
  61. package/dist/routes/projects.d.ts +7 -0
  62. package/dist/routes/projects.d.ts.map +1 -0
  63. package/dist/routes/projects.js +643 -0
  64. package/dist/routes/projects.js.map +1 -0
  65. package/dist/routes/runners.d.ts +7 -0
  66. package/dist/routes/runners.d.ts.map +1 -0
  67. package/dist/routes/runners.js +299 -0
  68. package/dist/routes/runners.js.map +1 -0
  69. package/dist/routes/skills.d.ts +3 -0
  70. package/dist/routes/skills.d.ts.map +1 -0
  71. package/dist/routes/skills.js +109 -0
  72. package/dist/routes/skills.js.map +1 -0
  73. package/dist/routes/storage.d.ts +7 -0
  74. package/dist/routes/storage.d.ts.map +1 -0
  75. package/dist/routes/storage.js +93 -0
  76. package/dist/routes/storage.js.map +1 -0
  77. package/dist/routes/tasks.d.ts +7 -0
  78. package/dist/routes/tasks.d.ts.map +1 -0
  79. package/dist/routes/tasks.js +1145 -0
  80. package/dist/routes/tasks.js.map +1 -0
  81. package/dist/src/cleanup/invocation-logs.d.ts +30 -0
  82. package/dist/src/cleanup/invocation-logs.d.ts.map +1 -0
  83. package/dist/src/cleanup/invocation-logs.js +66 -0
  84. package/dist/src/cleanup/invocation-logs.js.map +1 -0
  85. package/dist/src/commands/loop-phases.d.ts +11 -0
  86. package/dist/src/commands/loop-phases.d.ts.map +1 -0
  87. package/dist/src/commands/loop-phases.js +304 -0
  88. package/dist/src/commands/loop-phases.js.map +1 -0
  89. package/dist/src/config/loader.d.ts +160 -0
  90. package/dist/src/config/loader.d.ts.map +1 -0
  91. package/dist/src/config/loader.js +276 -0
  92. package/dist/src/config/loader.js.map +1 -0
  93. package/dist/src/database/connection.d.ts +35 -0
  94. package/dist/src/database/connection.d.ts.map +1 -0
  95. package/dist/src/database/connection.js +197 -0
  96. package/dist/src/database/connection.js.map +1 -0
  97. package/dist/src/database/queries.d.ts +220 -0
  98. package/dist/src/database/queries.d.ts.map +1 -0
  99. package/dist/src/database/queries.js +589 -0
  100. package/dist/src/database/queries.js.map +1 -0
  101. package/dist/src/database/schema.d.ts +8 -0
  102. package/dist/src/database/schema.d.ts.map +1 -0
  103. package/dist/src/database/schema.js +184 -0
  104. package/dist/src/database/schema.js.map +1 -0
  105. package/dist/src/git/push.d.ts +26 -0
  106. package/dist/src/git/push.d.ts.map +1 -0
  107. package/dist/src/git/push.js +91 -0
  108. package/dist/src/git/push.js.map +1 -0
  109. package/dist/src/git/status.d.ts +83 -0
  110. package/dist/src/git/status.d.ts.map +1 -0
  111. package/dist/src/git/status.js +315 -0
  112. package/dist/src/git/status.js.map +1 -0
  113. package/dist/src/health/stuck-task-detector.d.ts +131 -0
  114. package/dist/src/health/stuck-task-detector.d.ts.map +1 -0
  115. package/dist/src/health/stuck-task-detector.js +233 -0
  116. package/dist/src/health/stuck-task-detector.js.map +1 -0
  117. package/dist/src/health/stuck-task-recovery.d.ts +45 -0
  118. package/dist/src/health/stuck-task-recovery.d.ts.map +1 -0
  119. package/dist/src/health/stuck-task-recovery.js +309 -0
  120. package/dist/src/health/stuck-task-recovery.js.map +1 -0
  121. package/dist/src/index.d.ts +10 -0
  122. package/dist/src/index.d.ts.map +1 -0
  123. package/dist/src/index.js +130 -0
  124. package/dist/src/index.js.map +1 -0
  125. package/dist/src/locking/queries.d.ts +116 -0
  126. package/dist/src/locking/queries.d.ts.map +1 -0
  127. package/dist/src/locking/queries.js +232 -0
  128. package/dist/src/locking/queries.js.map +1 -0
  129. package/dist/src/locking/section-lock.d.ts +74 -0
  130. package/dist/src/locking/section-lock.d.ts.map +1 -0
  131. package/dist/src/locking/section-lock.js +196 -0
  132. package/dist/src/locking/section-lock.js.map +1 -0
  133. package/dist/src/locking/task-lock.d.ts +92 -0
  134. package/dist/src/locking/task-lock.d.ts.map +1 -0
  135. package/dist/src/locking/task-lock.js +233 -0
  136. package/dist/src/locking/task-lock.js.map +1 -0
  137. package/dist/src/migrations/index.d.ts +7 -0
  138. package/dist/src/migrations/index.d.ts.map +1 -0
  139. package/dist/src/migrations/index.js +9 -0
  140. package/dist/src/migrations/index.js.map +1 -0
  141. package/dist/src/migrations/manifest.d.ts +92 -0
  142. package/dist/src/migrations/manifest.d.ts.map +1 -0
  143. package/dist/src/migrations/manifest.js +255 -0
  144. package/dist/src/migrations/manifest.js.map +1 -0
  145. package/dist/src/migrations/runner.d.ts +84 -0
  146. package/dist/src/migrations/runner.d.ts.map +1 -0
  147. package/dist/src/migrations/runner.js +338 -0
  148. package/dist/src/migrations/runner.js.map +1 -0
  149. package/dist/src/orchestrator/coder.d.ts +32 -0
  150. package/dist/src/orchestrator/coder.d.ts.map +1 -0
  151. package/dist/src/orchestrator/coder.js +170 -0
  152. package/dist/src/orchestrator/coder.js.map +1 -0
  153. package/dist/src/orchestrator/coordinator.d.ts +28 -0
  154. package/dist/src/orchestrator/coordinator.d.ts.map +1 -0
  155. package/dist/src/orchestrator/coordinator.js +252 -0
  156. package/dist/src/orchestrator/coordinator.js.map +1 -0
  157. package/dist/src/orchestrator/fallback-handler.d.ts +24 -0
  158. package/dist/src/orchestrator/fallback-handler.d.ts.map +1 -0
  159. package/dist/src/orchestrator/fallback-handler.js +280 -0
  160. package/dist/src/orchestrator/fallback-handler.js.map +1 -0
  161. package/dist/src/orchestrator/invoke.d.ts +14 -0
  162. package/dist/src/orchestrator/invoke.d.ts.map +1 -0
  163. package/dist/src/orchestrator/invoke.js +76 -0
  164. package/dist/src/orchestrator/invoke.js.map +1 -0
  165. package/dist/src/orchestrator/post-coder.d.ts +10 -0
  166. package/dist/src/orchestrator/post-coder.d.ts.map +1 -0
  167. package/dist/src/orchestrator/post-coder.js +198 -0
  168. package/dist/src/orchestrator/post-coder.js.map +1 -0
  169. package/dist/src/orchestrator/post-reviewer.d.ts +10 -0
  170. package/dist/src/orchestrator/post-reviewer.d.ts.map +1 -0
  171. package/dist/src/orchestrator/post-reviewer.js +199 -0
  172. package/dist/src/orchestrator/post-reviewer.js.map +1 -0
  173. package/dist/src/orchestrator/reviewer.d.ts +35 -0
  174. package/dist/src/orchestrator/reviewer.d.ts.map +1 -0
  175. package/dist/src/orchestrator/reviewer.js +237 -0
  176. package/dist/src/orchestrator/reviewer.js.map +1 -0
  177. package/dist/src/orchestrator/schemas.d.ts +10 -0
  178. package/dist/src/orchestrator/schemas.d.ts.map +1 -0
  179. package/dist/src/orchestrator/schemas.js +81 -0
  180. package/dist/src/orchestrator/schemas.js.map +1 -0
  181. package/dist/src/orchestrator/task-selector.d.ts +102 -0
  182. package/dist/src/orchestrator/task-selector.d.ts.map +1 -0
  183. package/dist/src/orchestrator/task-selector.js +326 -0
  184. package/dist/src/orchestrator/task-selector.js.map +1 -0
  185. package/dist/src/orchestrator/types.d.ts +74 -0
  186. package/dist/src/orchestrator/types.d.ts.map +1 -0
  187. package/dist/src/orchestrator/types.js +5 -0
  188. package/dist/src/orchestrator/types.js.map +1 -0
  189. package/dist/src/prompts/coder.d.ts +36 -0
  190. package/dist/src/prompts/coder.d.ts.map +1 -0
  191. package/dist/src/prompts/coder.js +303 -0
  192. package/dist/src/prompts/coder.js.map +1 -0
  193. package/dist/src/prompts/prompt-helpers.d.ts +51 -0
  194. package/dist/src/prompts/prompt-helpers.d.ts.map +1 -0
  195. package/dist/src/prompts/prompt-helpers.js +299 -0
  196. package/dist/src/prompts/prompt-helpers.js.map +1 -0
  197. package/dist/src/prompts/reviewer.d.ts +40 -0
  198. package/dist/src/prompts/reviewer.d.ts.map +1 -0
  199. package/dist/src/prompts/reviewer.js +416 -0
  200. package/dist/src/prompts/reviewer.js.map +1 -0
  201. package/dist/src/providers/claude.d.ts +53 -0
  202. package/dist/src/providers/claude.d.ts.map +1 -0
  203. package/dist/src/providers/claude.js +227 -0
  204. package/dist/src/providers/claude.js.map +1 -0
  205. package/dist/src/providers/codex.d.ts +53 -0
  206. package/dist/src/providers/codex.d.ts.map +1 -0
  207. package/dist/src/providers/codex.js +253 -0
  208. package/dist/src/providers/codex.js.map +1 -0
  209. package/dist/src/providers/gemini.d.ts +58 -0
  210. package/dist/src/providers/gemini.d.ts.map +1 -0
  211. package/dist/src/providers/gemini.js +240 -0
  212. package/dist/src/providers/gemini.js.map +1 -0
  213. package/dist/src/providers/interface.d.ts +185 -0
  214. package/dist/src/providers/interface.d.ts.map +1 -0
  215. package/dist/src/providers/interface.js +92 -0
  216. package/dist/src/providers/interface.js.map +1 -0
  217. package/dist/src/providers/invocation-logger.d.ts +97 -0
  218. package/dist/src/providers/invocation-logger.d.ts.map +1 -0
  219. package/dist/src/providers/invocation-logger.js +378 -0
  220. package/dist/src/providers/invocation-logger.js.map +1 -0
  221. package/dist/src/providers/openai.d.ts +53 -0
  222. package/dist/src/providers/openai.d.ts.map +1 -0
  223. package/dist/src/providers/openai.js +230 -0
  224. package/dist/src/providers/openai.js.map +1 -0
  225. package/dist/src/providers/registry.d.ts +100 -0
  226. package/dist/src/providers/registry.d.ts.map +1 -0
  227. package/dist/src/providers/registry.js +170 -0
  228. package/dist/src/providers/registry.js.map +1 -0
  229. package/dist/src/routes/activity.d.ts +7 -0
  230. package/dist/src/routes/activity.d.ts.map +1 -0
  231. package/dist/src/routes/activity.js +252 -0
  232. package/dist/src/routes/activity.js.map +1 -0
  233. package/dist/src/routes/config.d.ts +7 -0
  234. package/dist/src/routes/config.d.ts.map +1 -0
  235. package/dist/src/routes/config.js +521 -0
  236. package/dist/src/routes/config.js.map +1 -0
  237. package/dist/src/routes/health.d.ts +7 -0
  238. package/dist/src/routes/health.d.ts.map +1 -0
  239. package/dist/src/routes/health.js +172 -0
  240. package/dist/src/routes/health.js.map +1 -0
  241. package/dist/src/routes/incidents.d.ts +7 -0
  242. package/dist/src/routes/incidents.d.ts.map +1 -0
  243. package/dist/src/routes/incidents.js +117 -0
  244. package/dist/src/routes/incidents.js.map +1 -0
  245. package/dist/src/routes/projects.d.ts +7 -0
  246. package/dist/src/routes/projects.d.ts.map +1 -0
  247. package/dist/src/routes/projects.js +398 -0
  248. package/dist/src/routes/projects.js.map +1 -0
  249. package/dist/src/routes/runners.d.ts +7 -0
  250. package/dist/src/routes/runners.d.ts.map +1 -0
  251. package/dist/src/routes/runners.js +242 -0
  252. package/dist/src/routes/runners.js.map +1 -0
  253. package/dist/src/routes/tasks.d.ts +7 -0
  254. package/dist/src/routes/tasks.d.ts.map +1 -0
  255. package/dist/src/routes/tasks.js +1007 -0
  256. package/dist/src/routes/tasks.js.map +1 -0
  257. package/dist/src/runners/activity-log.d.ts +65 -0
  258. package/dist/src/runners/activity-log.d.ts.map +1 -0
  259. package/dist/src/runners/activity-log.js +140 -0
  260. package/dist/src/runners/activity-log.js.map +1 -0
  261. package/dist/src/runners/cron.d.ts +30 -0
  262. package/dist/src/runners/cron.d.ts.map +1 -0
  263. package/dist/src/runners/cron.js +333 -0
  264. package/dist/src/runners/cron.js.map +1 -0
  265. package/dist/src/runners/daemon.d.ts +71 -0
  266. package/dist/src/runners/daemon.d.ts.map +1 -0
  267. package/dist/src/runners/daemon.js +233 -0
  268. package/dist/src/runners/daemon.js.map +1 -0
  269. package/dist/src/runners/global-db.d.ts +31 -0
  270. package/dist/src/runners/global-db.d.ts.map +1 -0
  271. package/dist/src/runners/global-db.js +220 -0
  272. package/dist/src/runners/global-db.js.map +1 -0
  273. package/dist/src/runners/hang-detector.d.ts +38 -0
  274. package/dist/src/runners/hang-detector.d.ts.map +1 -0
  275. package/dist/src/runners/hang-detector.js +130 -0
  276. package/dist/src/runners/hang-detector.js.map +1 -0
  277. package/dist/src/runners/heartbeat.d.ts +39 -0
  278. package/dist/src/runners/heartbeat.d.ts.map +1 -0
  279. package/dist/src/runners/heartbeat.js +71 -0
  280. package/dist/src/runners/heartbeat.js.map +1 -0
  281. package/dist/src/runners/lock.d.ts +47 -0
  282. package/dist/src/runners/lock.d.ts.map +1 -0
  283. package/dist/src/runners/lock.js +140 -0
  284. package/dist/src/runners/lock.js.map +1 -0
  285. package/dist/src/runners/orchestrator-loop.d.ts +20 -0
  286. package/dist/src/runners/orchestrator-loop.d.ts.map +1 -0
  287. package/dist/src/runners/orchestrator-loop.js +208 -0
  288. package/dist/src/runners/orchestrator-loop.js.map +1 -0
  289. package/dist/src/runners/projects.d.ts +96 -0
  290. package/dist/src/runners/projects.d.ts.map +1 -0
  291. package/dist/src/runners/projects.js +243 -0
  292. package/dist/src/runners/projects.js.map +1 -0
  293. package/dist/src/runners/wakeup.d.ts +37 -0
  294. package/dist/src/runners/wakeup.d.ts.map +1 -0
  295. package/dist/src/runners/wakeup.js +355 -0
  296. package/dist/src/runners/wakeup.js.map +1 -0
  297. package/dist/src/utils/validation.d.ts +22 -0
  298. package/dist/src/utils/validation.d.ts.map +1 -0
  299. package/dist/src/utils/validation.js +50 -0
  300. package/dist/src/utils/validation.js.map +1 -0
  301. package/dist/utils/sqlite.d.ts +17 -0
  302. package/dist/utils/sqlite.d.ts.map +1 -0
  303. package/dist/utils/sqlite.js +27 -0
  304. package/dist/utils/sqlite.js.map +1 -0
  305. package/dist/utils/storage-cache.d.ts +33 -0
  306. package/dist/utils/storage-cache.d.ts.map +1 -0
  307. package/dist/utils/storage-cache.js +81 -0
  308. package/dist/utils/storage-cache.js.map +1 -0
  309. package/dist/utils/validation.d.ts +22 -0
  310. package/dist/utils/validation.d.ts.map +1 -0
  311. package/dist/utils/validation.js +51 -0
  312. package/dist/utils/validation.js.map +1 -0
  313. package/package.json +39 -0
  314. package/src/index.ts +199 -0
  315. package/src/routes/activity.ts +302 -0
  316. package/src/routes/config.ts +723 -0
  317. package/src/routes/credit-alerts.ts +73 -0
  318. package/src/routes/health.ts +219 -0
  319. package/src/routes/incidents.ts +131 -0
  320. package/src/routes/projects.ts +854 -0
  321. package/src/routes/runners.ts +357 -0
  322. package/src/routes/skills.ts +127 -0
  323. package/src/routes/storage.ts +108 -0
  324. package/src/routes/tasks.ts +1372 -0
  325. package/src/utils/sqlite.ts +36 -0
  326. package/src/utils/storage-cache.ts +107 -0
  327. package/src/utils/validation.ts +61 -0
  328. package/tsconfig.json +20 -0
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Section locking for parallel work prevention
3
+ * Prevents multiple runners from working on tasks in the same section
4
+ */
5
+ import { getSectionLock, isSectionLockExpired, tryInsertSectionLock, claimExpiredSectionLock, releaseSectionLock as releaseSectionLockQuery, forceReleaseSectionLock, } from './queries.js';
6
+ // Default section lock timeout in minutes
7
+ const DEFAULT_SECTION_TIMEOUT_MINUTES = 120;
8
+ // ============ Lock Acquisition ============
9
+ /**
10
+ * Acquire a section lock with atomic operations
11
+ *
12
+ * Flow:
13
+ * 1. Try INSERT (fails if lock exists)
14
+ * 2. If exists, check if we own it
15
+ * 3. If owned by another, check if expired
16
+ * 4. If expired, claim atomically
17
+ * 5. If not expired, return failure
18
+ */
19
+ export function acquireSectionLock(db, sectionId, runnerId, timeoutMinutes = DEFAULT_SECTION_TIMEOUT_MINUTES) {
20
+ // Step 1: Try to insert new lock
21
+ if (tryInsertSectionLock(db, sectionId, runnerId, timeoutMinutes)) {
22
+ const lock = getSectionLock(db, sectionId);
23
+ return {
24
+ acquired: true,
25
+ lock: lock ?? undefined,
26
+ reason: 'acquired_new',
27
+ };
28
+ }
29
+ // Step 2: Lock exists, get current state
30
+ const existingLock = getSectionLock(db, sectionId);
31
+ if (!existingLock) {
32
+ // Race condition: lock was deleted between insert attempt and now
33
+ if (tryInsertSectionLock(db, sectionId, runnerId, timeoutMinutes)) {
34
+ const lock = getSectionLock(db, sectionId);
35
+ return {
36
+ acquired: true,
37
+ lock: lock ?? undefined,
38
+ reason: 'acquired_new',
39
+ };
40
+ }
41
+ const currentLock = getSectionLock(db, sectionId);
42
+ return createLockedError(sectionId, currentLock);
43
+ }
44
+ // Step 3: Check if we already own the lock
45
+ if (existingLock.runner_id === runnerId) {
46
+ return {
47
+ acquired: true,
48
+ lock: existingLock,
49
+ reason: 'already_owned',
50
+ };
51
+ }
52
+ // Step 4: Check if lock is expired
53
+ if (isSectionLockExpired(existingLock)) {
54
+ if (claimExpiredSectionLock(db, sectionId, runnerId, timeoutMinutes)) {
55
+ const lock = getSectionLock(db, sectionId);
56
+ return {
57
+ acquired: true,
58
+ lock: lock ?? undefined,
59
+ reason: 'claimed_expired',
60
+ };
61
+ }
62
+ // Another runner claimed it first
63
+ const currentLock = getSectionLock(db, sectionId);
64
+ return createLockedError(sectionId, currentLock);
65
+ }
66
+ // Step 5: Lock is held by another runner and not expired
67
+ return createLockedError(sectionId, existingLock);
68
+ }
69
+ /**
70
+ * Create a SECTION_LOCKED error response
71
+ */
72
+ function createLockedError(sectionId, lock) {
73
+ return {
74
+ acquired: false,
75
+ error: {
76
+ code: 'SECTION_LOCKED',
77
+ message: 'Section is locked by another runner',
78
+ details: {
79
+ sectionId,
80
+ runnerId: lock?.runner_id,
81
+ expiresAt: lock?.expires_at,
82
+ },
83
+ },
84
+ };
85
+ }
86
+ // ============ Lock Release ============
87
+ /**
88
+ * Release a section lock (only by owner)
89
+ */
90
+ export function releaseSectionLock(db, sectionId, runnerId) {
91
+ const existingLock = getSectionLock(db, sectionId);
92
+ if (!existingLock) {
93
+ return {
94
+ released: false,
95
+ error: {
96
+ code: 'LOCK_NOT_FOUND',
97
+ message: 'Lock does not exist',
98
+ details: { sectionId },
99
+ },
100
+ };
101
+ }
102
+ if (existingLock.runner_id !== runnerId) {
103
+ return {
104
+ released: false,
105
+ error: {
106
+ code: 'PERMISSION_DENIED',
107
+ message: 'Cannot release lock owned by another runner',
108
+ details: {
109
+ sectionId,
110
+ runnerId: existingLock.runner_id,
111
+ expiresAt: existingLock.expires_at,
112
+ },
113
+ },
114
+ };
115
+ }
116
+ releaseSectionLockQuery(db, sectionId, runnerId);
117
+ return { released: true };
118
+ }
119
+ /**
120
+ * Force release a section lock (admin operation)
121
+ */
122
+ export function forceRelease(db, sectionId) {
123
+ const existed = forceReleaseSectionLock(db, sectionId);
124
+ if (!existed) {
125
+ return {
126
+ released: false,
127
+ error: {
128
+ code: 'LOCK_NOT_FOUND',
129
+ message: 'Lock does not exist',
130
+ details: { sectionId },
131
+ },
132
+ };
133
+ }
134
+ return { released: true };
135
+ }
136
+ // ============ Lock Manager ============
137
+ /**
138
+ * Create a section lock manager for a specific section
139
+ */
140
+ export function createSectionLockManager(db, sectionId, runnerId, timeoutMinutes = DEFAULT_SECTION_TIMEOUT_MINUTES) {
141
+ return {
142
+ acquire: () => acquireSectionLock(db, sectionId, runnerId, timeoutMinutes),
143
+ release: () => releaseSectionLock(db, sectionId, runnerId),
144
+ isHeld: () => {
145
+ const lock = getSectionLock(db, sectionId);
146
+ return lock !== null && lock.runner_id === runnerId && !isSectionLockExpired(lock);
147
+ },
148
+ };
149
+ }
150
+ // ============ Lock Status Check ============
151
+ /**
152
+ * Check if a section is locked
153
+ */
154
+ export function isSectionLocked(db, sectionId) {
155
+ const lock = getSectionLock(db, sectionId);
156
+ if (!lock)
157
+ return false;
158
+ return !isSectionLockExpired(lock);
159
+ }
160
+ /**
161
+ * Check if a section is locked by a specific runner
162
+ */
163
+ export function isSectionLockedBy(db, sectionId, runnerId) {
164
+ const lock = getSectionLock(db, sectionId);
165
+ if (!lock)
166
+ return false;
167
+ return lock.runner_id === runnerId && !isSectionLockExpired(lock);
168
+ }
169
+ /**
170
+ * Get time until section lock expires (in milliseconds)
171
+ */
172
+ export function getTimeUntilExpiry(db, sectionId) {
173
+ const lock = getSectionLock(db, sectionId);
174
+ if (!lock)
175
+ return null;
176
+ const expiresAt = new Date(lock.expires_at).getTime();
177
+ const remaining = expiresAt - Date.now();
178
+ return Math.max(0, remaining);
179
+ }
180
+ // ============ Helper Functions ============
181
+ /**
182
+ * Check if any tasks in the section are in progress by another runner
183
+ * This can be used before acquiring a section lock
184
+ */
185
+ export function getSectionLockHolder(db, sectionId) {
186
+ const lock = getSectionLock(db, sectionId);
187
+ if (!lock || isSectionLockExpired(lock)) {
188
+ return null;
189
+ }
190
+ return lock;
191
+ }
192
+ // ============ Constants Export ============
193
+ export const SECTION_LOCK_CONSTANTS = {
194
+ DEFAULT_TIMEOUT_MINUTES: DEFAULT_SECTION_TIMEOUT_MINUTES,
195
+ };
196
+ //# sourceMappingURL=section-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-lock.js","sourceRoot":"","sources":["../../../../src/locking/section-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Task locking with atomic operations
3
+ * Prevents multiple runners from working on the same task
4
+ */
5
+ import type Database from 'better-sqlite3';
6
+ import { type TaskLock } from './queries.js';
7
+ export interface LockAcquisitionResult {
8
+ acquired: boolean;
9
+ lock?: TaskLock;
10
+ reason?: 'already_owned' | 'acquired_new' | 'claimed_expired';
11
+ error?: LockError;
12
+ }
13
+ export interface LockError {
14
+ code: 'TASK_LOCKED' | 'LOCK_NOT_FOUND' | 'PERMISSION_DENIED';
15
+ message: string;
16
+ details?: {
17
+ taskId: string;
18
+ runnerId?: string;
19
+ expiresAt?: string;
20
+ };
21
+ }
22
+ export interface LockReleaseResult {
23
+ released: boolean;
24
+ error?: LockError;
25
+ }
26
+ export interface TaskLockManager {
27
+ acquire: () => LockAcquisitionResult;
28
+ release: () => LockReleaseResult;
29
+ heartbeat: () => boolean;
30
+ extend: (additionalMinutes?: number) => boolean;
31
+ isHeld: () => boolean;
32
+ }
33
+ /**
34
+ * Acquire a task lock with atomic operations
35
+ *
36
+ * Flow:
37
+ * 1. Try INSERT (fails if lock exists)
38
+ * 2. If exists, check if we own it
39
+ * 3. If owned by another, check if expired
40
+ * 4. If expired, claim atomically
41
+ * 5. If not expired, return failure
42
+ */
43
+ export declare function acquireTaskLock(db: Database.Database, taskId: string, runnerId: string, timeoutMinutes?: number): LockAcquisitionResult;
44
+ /**
45
+ * Release a task lock (only by owner)
46
+ */
47
+ export declare function releaseTaskLock(db: Database.Database, taskId: string, runnerId: string): LockReleaseResult;
48
+ /**
49
+ * Force release a task lock (admin operation, ignores owner)
50
+ */
51
+ export declare function forceRelease(db: Database.Database, taskId: string): LockReleaseResult;
52
+ /**
53
+ * Update heartbeat for a task lock
54
+ * Should be called periodically while holding the lock
55
+ */
56
+ export declare function heartbeat(db: Database.Database, taskId: string, runnerId: string): boolean;
57
+ /**
58
+ * Extend a task lock's expiry time
59
+ */
60
+ export declare function extend(db: Database.Database, taskId: string, runnerId: string, additionalMinutes?: number): boolean;
61
+ /**
62
+ * Create a task lock manager for a specific task
63
+ * Provides a convenient interface for managing a single lock
64
+ */
65
+ export declare function createTaskLockManager(db: Database.Database, taskId: string, runnerId: string, timeoutMinutes?: number): TaskLockManager;
66
+ export interface HeartbeatHandle {
67
+ start: () => void;
68
+ stop: () => void;
69
+ }
70
+ /**
71
+ * Create an automatic heartbeat manager that updates
72
+ * the lock heartbeat at regular intervals
73
+ */
74
+ export declare function createHeartbeatLoop(db: Database.Database, taskId: string, runnerId: string, intervalMs?: number): HeartbeatHandle;
75
+ /**
76
+ * Check if a task is locked
77
+ */
78
+ export declare function isTaskLocked(db: Database.Database, taskId: string): boolean;
79
+ /**
80
+ * Check if a task is locked by a specific runner
81
+ */
82
+ export declare function isTaskLockedBy(db: Database.Database, taskId: string, runnerId: string): boolean;
83
+ /**
84
+ * Get time until lock expires (in milliseconds)
85
+ * Returns null if not locked, 0 if already expired
86
+ */
87
+ export declare function getTimeUntilExpiry(db: Database.Database, taskId: string): number | null;
88
+ export declare const LOCK_CONSTANTS: {
89
+ readonly DEFAULT_TIMEOUT_MINUTES: 60;
90
+ readonly HEARTBEAT_INTERVAL_MS: number;
91
+ };
92
+ //# sourceMappingURL=task-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-lock.d.ts","sourceRoot":"","sources":["../../../../src/locking/task-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Task locking with atomic operations
3
+ * Prevents multiple runners from working on the same task
4
+ */
5
+ import { getTaskLock, isTaskLockExpired, tryInsertTaskLock, claimExpiredTaskLock, releaseTaskLock as releaseTaskLockQuery, forceReleaseTaskLock, updateTaskLockHeartbeat, extendTaskLock, } from './queries.js';
6
+ // Default lock timeout in minutes
7
+ const DEFAULT_LOCK_TIMEOUT_MINUTES = 60;
8
+ const HEARTBEAT_INTERVAL_MS = 30 * 1000; // 30 seconds
9
+ // ============ Lock Acquisition ============
10
+ /**
11
+ * Acquire a task lock with atomic operations
12
+ *
13
+ * Flow:
14
+ * 1. Try INSERT (fails if lock exists)
15
+ * 2. If exists, check if we own it
16
+ * 3. If owned by another, check if expired
17
+ * 4. If expired, claim atomically
18
+ * 5. If not expired, return failure
19
+ */
20
+ export function acquireTaskLock(db, taskId, runnerId, timeoutMinutes = DEFAULT_LOCK_TIMEOUT_MINUTES) {
21
+ // Step 1: Try to insert new lock
22
+ if (tryInsertTaskLock(db, taskId, runnerId, timeoutMinutes)) {
23
+ const lock = getTaskLock(db, taskId);
24
+ return {
25
+ acquired: true,
26
+ lock: lock ?? undefined,
27
+ reason: 'acquired_new',
28
+ };
29
+ }
30
+ // Step 2: Lock exists, get current state
31
+ const existingLock = getTaskLock(db, taskId);
32
+ if (!existingLock) {
33
+ // Race condition: lock was deleted between insert attempt and now
34
+ // Try to acquire again
35
+ if (tryInsertTaskLock(db, taskId, runnerId, timeoutMinutes)) {
36
+ const lock = getTaskLock(db, taskId);
37
+ return {
38
+ acquired: true,
39
+ lock: lock ?? undefined,
40
+ reason: 'acquired_new',
41
+ };
42
+ }
43
+ // Still failed, get the current lock
44
+ const currentLock = getTaskLock(db, taskId);
45
+ return createLockedError(taskId, currentLock);
46
+ }
47
+ // Step 3: Check if we already own the lock
48
+ if (existingLock.runner_id === runnerId) {
49
+ // Refresh the lock expiry
50
+ extendTaskLock(db, taskId, runnerId, timeoutMinutes);
51
+ const updatedLock = getTaskLock(db, taskId);
52
+ return {
53
+ acquired: true,
54
+ lock: updatedLock ?? undefined,
55
+ reason: 'already_owned',
56
+ };
57
+ }
58
+ // Step 4: Check if lock is expired
59
+ if (isTaskLockExpired(existingLock)) {
60
+ // Try to claim the expired lock atomically
61
+ if (claimExpiredTaskLock(db, taskId, runnerId, timeoutMinutes)) {
62
+ const lock = getTaskLock(db, taskId);
63
+ return {
64
+ acquired: true,
65
+ lock: lock ?? undefined,
66
+ reason: 'claimed_expired',
67
+ };
68
+ }
69
+ // Another runner claimed it first
70
+ const currentLock = getTaskLock(db, taskId);
71
+ return createLockedError(taskId, currentLock);
72
+ }
73
+ // Step 5: Lock is held by another runner and not expired
74
+ return createLockedError(taskId, existingLock);
75
+ }
76
+ /**
77
+ * Create a TASK_LOCKED error response
78
+ */
79
+ function createLockedError(taskId, lock) {
80
+ return {
81
+ acquired: false,
82
+ error: {
83
+ code: 'TASK_LOCKED',
84
+ message: 'Task is locked by another runner',
85
+ details: {
86
+ taskId,
87
+ runnerId: lock?.runner_id,
88
+ expiresAt: lock?.expires_at,
89
+ },
90
+ },
91
+ };
92
+ }
93
+ // ============ Lock Release ============
94
+ /**
95
+ * Release a task lock (only by owner)
96
+ */
97
+ export function releaseTaskLock(db, taskId, runnerId) {
98
+ const existingLock = getTaskLock(db, taskId);
99
+ if (!existingLock) {
100
+ return {
101
+ released: false,
102
+ error: {
103
+ code: 'LOCK_NOT_FOUND',
104
+ message: 'Lock does not exist',
105
+ details: { taskId },
106
+ },
107
+ };
108
+ }
109
+ if (existingLock.runner_id !== runnerId) {
110
+ return {
111
+ released: false,
112
+ error: {
113
+ code: 'PERMISSION_DENIED',
114
+ message: 'Cannot release lock owned by another runner',
115
+ details: {
116
+ taskId,
117
+ runnerId: existingLock.runner_id,
118
+ expiresAt: existingLock.expires_at,
119
+ },
120
+ },
121
+ };
122
+ }
123
+ releaseTaskLockQuery(db, taskId, runnerId);
124
+ return { released: true };
125
+ }
126
+ /**
127
+ * Force release a task lock (admin operation, ignores owner)
128
+ */
129
+ export function forceRelease(db, taskId) {
130
+ const existed = forceReleaseTaskLock(db, taskId);
131
+ if (!existed) {
132
+ return {
133
+ released: false,
134
+ error: {
135
+ code: 'LOCK_NOT_FOUND',
136
+ message: 'Lock does not exist',
137
+ details: { taskId },
138
+ },
139
+ };
140
+ }
141
+ return { released: true };
142
+ }
143
+ // ============ Lock Heartbeat ============
144
+ /**
145
+ * Update heartbeat for a task lock
146
+ * Should be called periodically while holding the lock
147
+ */
148
+ export function heartbeat(db, taskId, runnerId) {
149
+ return updateTaskLockHeartbeat(db, taskId, runnerId);
150
+ }
151
+ /**
152
+ * Extend a task lock's expiry time
153
+ */
154
+ export function extend(db, taskId, runnerId, additionalMinutes = DEFAULT_LOCK_TIMEOUT_MINUTES) {
155
+ return extendTaskLock(db, taskId, runnerId, additionalMinutes);
156
+ }
157
+ // ============ Lock Manager ============
158
+ /**
159
+ * Create a task lock manager for a specific task
160
+ * Provides a convenient interface for managing a single lock
161
+ */
162
+ export function createTaskLockManager(db, taskId, runnerId, timeoutMinutes = DEFAULT_LOCK_TIMEOUT_MINUTES) {
163
+ return {
164
+ acquire: () => acquireTaskLock(db, taskId, runnerId, timeoutMinutes),
165
+ release: () => releaseTaskLock(db, taskId, runnerId),
166
+ heartbeat: () => updateTaskLockHeartbeat(db, taskId, runnerId),
167
+ extend: (additionalMinutes = timeoutMinutes) => extendTaskLock(db, taskId, runnerId, additionalMinutes),
168
+ isHeld: () => {
169
+ const lock = getTaskLock(db, taskId);
170
+ return lock !== null && lock.runner_id === runnerId && !isTaskLockExpired(lock);
171
+ },
172
+ };
173
+ }
174
+ /**
175
+ * Create an automatic heartbeat manager that updates
176
+ * the lock heartbeat at regular intervals
177
+ */
178
+ export function createHeartbeatLoop(db, taskId, runnerId, intervalMs = HEARTBEAT_INTERVAL_MS) {
179
+ let intervalId = null;
180
+ const beat = () => {
181
+ updateTaskLockHeartbeat(db, taskId, runnerId);
182
+ };
183
+ const start = () => {
184
+ if (intervalId)
185
+ return; // Already running
186
+ beat(); // Immediate first beat
187
+ intervalId = setInterval(beat, intervalMs);
188
+ };
189
+ const stop = () => {
190
+ if (intervalId) {
191
+ clearInterval(intervalId);
192
+ intervalId = null;
193
+ }
194
+ };
195
+ return { start, stop };
196
+ }
197
+ // ============ Lock Status Check ============
198
+ /**
199
+ * Check if a task is locked
200
+ */
201
+ export function isTaskLocked(db, taskId) {
202
+ const lock = getTaskLock(db, taskId);
203
+ if (!lock)
204
+ return false;
205
+ return !isTaskLockExpired(lock);
206
+ }
207
+ /**
208
+ * Check if a task is locked by a specific runner
209
+ */
210
+ export function isTaskLockedBy(db, taskId, runnerId) {
211
+ const lock = getTaskLock(db, taskId);
212
+ if (!lock)
213
+ return false;
214
+ return lock.runner_id === runnerId && !isTaskLockExpired(lock);
215
+ }
216
+ /**
217
+ * Get time until lock expires (in milliseconds)
218
+ * Returns null if not locked, 0 if already expired
219
+ */
220
+ export function getTimeUntilExpiry(db, taskId) {
221
+ const lock = getTaskLock(db, taskId);
222
+ if (!lock)
223
+ return null;
224
+ const expiresAt = new Date(lock.expires_at).getTime();
225
+ const remaining = expiresAt - Date.now();
226
+ return Math.max(0, remaining);
227
+ }
228
+ // ============ Constants Export ============
229
+ export const LOCK_CONSTANTS = {
230
+ DEFAULT_TIMEOUT_MINUTES: DEFAULT_LOCK_TIMEOUT_MINUTES,
231
+ HEARTBEAT_INTERVAL_MS,
232
+ };
233
+ //# sourceMappingURL=task-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-lock.js","sourceRoot":"","sources":["../../../../src/locking/task-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Migration system exports
3
+ * Re-exports all migration-related functionality
4
+ */
5
+ export { MigrationEntry, MigrationManifest, AppliedMigration, getBundledManifestPath, getMigrationFilePath, getCachedManifestPath, readBundledManifest, readCachedManifest, cacheManifest, parseManifest, validateManifest, calculateChecksum, verifyChecksum, findPendingMigrations, findOrphanedMigrations, getMigrationById, getCliSupportedVersions, } from './manifest.js';
6
+ export { MigrationResult, MigrationStatus, parseMigrationFile, readMigrationFile, getAppliedMigrations, getDatabaseVersion, createBackup, applyMigration, rollbackMigration, runMigrations, rollbackToVersion, getMigrationStatus, autoMigrate, } from './runner.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,GACZ,MAAM,aAAa,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Migration system exports
3
+ * Re-exports all migration-related functionality
4
+ */
5
+ // Manifest management
6
+ export { getBundledManifestPath, getMigrationFilePath, getCachedManifestPath, readBundledManifest, readCachedManifest, cacheManifest, parseManifest, validateManifest, calculateChecksum, verifyChecksum, findPendingMigrations, findOrphanedMigrations, getMigrationById, getCliSupportedVersions, } from './manifest.js';
7
+ // Migration runner
8
+ export { parseMigrationFile, readMigrationFile, getAppliedMigrations, getDatabaseVersion, createBackup, applyMigration, rollbackMigration, runMigrations, rollbackToVersion, getMigrationStatus, autoMigrate, } from './runner.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sBAAsB;AACtB,OAAO,EAIL,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAEvB,mBAAmB;AACnB,OAAO,EAGL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,GACZ,MAAM,aAAa,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Migration manifest management
3
+ * Handles reading, parsing, and validating the migration manifest
4
+ */
5
+ /**
6
+ * Single migration entry in the manifest
7
+ */
8
+ export interface MigrationEntry {
9
+ id: number;
10
+ name: string;
11
+ file: string;
12
+ description: string;
13
+ checksum: string;
14
+ cliVersion: string;
15
+ }
16
+ /**
17
+ * Migration manifest structure
18
+ */
19
+ export interface MigrationManifest {
20
+ version: string;
21
+ latestDbVersion: number;
22
+ migrations: MigrationEntry[];
23
+ }
24
+ /**
25
+ * Applied migration record from database
26
+ */
27
+ export interface AppliedMigration {
28
+ id: number;
29
+ name: string;
30
+ checksum: string;
31
+ applied_at: string;
32
+ }
33
+ /**
34
+ * Get the path to the bundled manifest (in the package)
35
+ */
36
+ export declare function getBundledManifestPath(): string;
37
+ /**
38
+ * Get the path to a migration file (in the package)
39
+ */
40
+ export declare function getMigrationFilePath(filename: string): string;
41
+ /**
42
+ * Get the path to the cached manifest
43
+ */
44
+ export declare function getCachedManifestPath(): string;
45
+ /**
46
+ * Read the bundled manifest from the package
47
+ */
48
+ export declare function readBundledManifest(): MigrationManifest;
49
+ /**
50
+ * Read the cached manifest if it exists and is valid
51
+ */
52
+ export declare function readCachedManifest(): MigrationManifest | null;
53
+ /**
54
+ * Save manifest to cache
55
+ */
56
+ export declare function cacheManifest(manifest: MigrationManifest): void;
57
+ /**
58
+ * Parse and validate manifest content
59
+ */
60
+ export declare function parseManifest(content: string): MigrationManifest;
61
+ /**
62
+ * Validate manifest structure
63
+ */
64
+ export declare function validateManifest(manifest: MigrationManifest): void;
65
+ /**
66
+ * Calculate SHA256 checksum for migration file content
67
+ */
68
+ export declare function calculateChecksum(content: string): string;
69
+ /**
70
+ * Verify checksum matches
71
+ */
72
+ export declare function verifyChecksum(content: string, expectedChecksum: string): boolean;
73
+ /**
74
+ * Find pending migrations that need to be applied
75
+ */
76
+ export declare function findPendingMigrations(manifest: MigrationManifest, appliedMigrations: AppliedMigration[]): MigrationEntry[];
77
+ /**
78
+ * Find migrations to rollback (applied but not in manifest)
79
+ */
80
+ export declare function findOrphanedMigrations(manifest: MigrationManifest, appliedMigrations: AppliedMigration[]): AppliedMigration[];
81
+ /**
82
+ * Get migration entry by ID
83
+ */
84
+ export declare function getMigrationById(manifest: MigrationManifest, id: number): MigrationEntry | null;
85
+ /**
86
+ * Get the current supported database version range for this CLI
87
+ */
88
+ export declare function getCliSupportedVersions(manifest: MigrationManifest): {
89
+ min: number;
90
+ max: number;
91
+ };
92
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../src/migrations/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA8EH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,iBAAiB,CASvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,iBAAiB,GAAG,IAAI,CAkB7D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAc/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAIhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAmClE;AA6BD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAQjF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,iBAAiB,EAC3B,iBAAiB,EAAE,gBAAgB,EAAE,GACpC,cAAc,EAAE,CAGlB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,EAC3B,iBAAiB,EAAE,gBAAgB,EAAE,GACpC,gBAAgB,EAAE,CAGpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE/F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CASjG"}