steroids-cli 0.4.47

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 (395) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +640 -0
  3. package/dist/cli/colors.d.ts +110 -0
  4. package/dist/cli/colors.d.ts.map +1 -0
  5. package/dist/cli/colors.js +228 -0
  6. package/dist/cli/colors.js.map +1 -0
  7. package/dist/cli/env.d.ts +159 -0
  8. package/dist/cli/env.d.ts.map +1 -0
  9. package/dist/cli/env.js +227 -0
  10. package/dist/cli/env.js.map +1 -0
  11. package/dist/cli/errors.d.ts +166 -0
  12. package/dist/cli/errors.d.ts.map +1 -0
  13. package/dist/cli/errors.js +244 -0
  14. package/dist/cli/errors.js.map +1 -0
  15. package/dist/cli/flags.d.ts +75 -0
  16. package/dist/cli/flags.d.ts.map +1 -0
  17. package/dist/cli/flags.js +232 -0
  18. package/dist/cli/flags.js.map +1 -0
  19. package/dist/cli/help.d.ts +97 -0
  20. package/dist/cli/help.d.ts.map +1 -0
  21. package/dist/cli/help.js +275 -0
  22. package/dist/cli/help.js.map +1 -0
  23. package/dist/cli/index.d.ts +13 -0
  24. package/dist/cli/index.d.ts.map +1 -0
  25. package/dist/cli/index.js +29 -0
  26. package/dist/cli/index.js.map +1 -0
  27. package/dist/cli/interactive.d.ts +58 -0
  28. package/dist/cli/interactive.d.ts.map +1 -0
  29. package/dist/cli/interactive.js +127 -0
  30. package/dist/cli/interactive.js.map +1 -0
  31. package/dist/cli/output.d.ts +116 -0
  32. package/dist/cli/output.d.ts.map +1 -0
  33. package/dist/cli/output.js +178 -0
  34. package/dist/cli/output.js.map +1 -0
  35. package/dist/commands/about.d.ts +7 -0
  36. package/dist/commands/about.d.ts.map +1 -0
  37. package/dist/commands/about.js +259 -0
  38. package/dist/commands/about.js.map +1 -0
  39. package/dist/commands/ai.d.ts +6 -0
  40. package/dist/commands/ai.d.ts.map +1 -0
  41. package/dist/commands/ai.js +382 -0
  42. package/dist/commands/ai.js.map +1 -0
  43. package/dist/commands/backup.d.ts +3 -0
  44. package/dist/commands/backup.d.ts.map +1 -0
  45. package/dist/commands/backup.js +528 -0
  46. package/dist/commands/backup.js.map +1 -0
  47. package/dist/commands/completion.d.ts +3 -0
  48. package/dist/commands/completion.d.ts.map +1 -0
  49. package/dist/commands/completion.js +405 -0
  50. package/dist/commands/completion.js.map +1 -0
  51. package/dist/commands/config.d.ts +3 -0
  52. package/dist/commands/config.d.ts.map +1 -0
  53. package/dist/commands/config.js +665 -0
  54. package/dist/commands/config.js.map +1 -0
  55. package/dist/commands/disputes.d.ts +3 -0
  56. package/dist/commands/disputes.d.ts.map +1 -0
  57. package/dist/commands/disputes.js +499 -0
  58. package/dist/commands/disputes.js.map +1 -0
  59. package/dist/commands/gc.d.ts +3 -0
  60. package/dist/commands/gc.d.ts.map +1 -0
  61. package/dist/commands/gc.js +300 -0
  62. package/dist/commands/gc.js.map +1 -0
  63. package/dist/commands/git.d.ts +3 -0
  64. package/dist/commands/git.d.ts.map +1 -0
  65. package/dist/commands/git.js +458 -0
  66. package/dist/commands/git.js.map +1 -0
  67. package/dist/commands/health.d.ts +3 -0
  68. package/dist/commands/health.d.ts.map +1 -0
  69. package/dist/commands/health.js +604 -0
  70. package/dist/commands/health.js.map +1 -0
  71. package/dist/commands/hooks.d.ts +6 -0
  72. package/dist/commands/hooks.d.ts.map +1 -0
  73. package/dist/commands/hooks.js +529 -0
  74. package/dist/commands/hooks.js.map +1 -0
  75. package/dist/commands/init.d.ts +6 -0
  76. package/dist/commands/init.d.ts.map +1 -0
  77. package/dist/commands/init.js +200 -0
  78. package/dist/commands/init.js.map +1 -0
  79. package/dist/commands/llm.d.ts +7 -0
  80. package/dist/commands/llm.d.ts.map +1 -0
  81. package/dist/commands/llm.js +285 -0
  82. package/dist/commands/llm.js.map +1 -0
  83. package/dist/commands/locks.d.ts +3 -0
  84. package/dist/commands/locks.d.ts.map +1 -0
  85. package/dist/commands/locks.js +431 -0
  86. package/dist/commands/locks.js.map +1 -0
  87. package/dist/commands/logs.d.ts +3 -0
  88. package/dist/commands/logs.d.ts.map +1 -0
  89. package/dist/commands/logs.js +487 -0
  90. package/dist/commands/logs.js.map +1 -0
  91. package/dist/commands/loop-phases.d.ts +11 -0
  92. package/dist/commands/loop-phases.d.ts.map +1 -0
  93. package/dist/commands/loop-phases.js +204 -0
  94. package/dist/commands/loop-phases.js.map +1 -0
  95. package/dist/commands/loop.d.ts +3 -0
  96. package/dist/commands/loop.d.ts.map +1 -0
  97. package/dist/commands/loop.js +396 -0
  98. package/dist/commands/loop.js.map +1 -0
  99. package/dist/commands/projects.d.ts +6 -0
  100. package/dist/commands/projects.d.ts.map +1 -0
  101. package/dist/commands/projects.js +362 -0
  102. package/dist/commands/projects.js.map +1 -0
  103. package/dist/commands/purge.d.ts +3 -0
  104. package/dist/commands/purge.d.ts.map +1 -0
  105. package/dist/commands/purge.js +516 -0
  106. package/dist/commands/purge.js.map +1 -0
  107. package/dist/commands/runners.d.ts +3 -0
  108. package/dist/commands/runners.d.ts.map +1 -0
  109. package/dist/commands/runners.js +1076 -0
  110. package/dist/commands/runners.js.map +1 -0
  111. package/dist/commands/scan.d.ts +3 -0
  112. package/dist/commands/scan.d.ts.map +1 -0
  113. package/dist/commands/scan.js +291 -0
  114. package/dist/commands/scan.js.map +1 -0
  115. package/dist/commands/sections-commands.d.ts +9 -0
  116. package/dist/commands/sections-commands.d.ts.map +1 -0
  117. package/dist/commands/sections-commands.js +282 -0
  118. package/dist/commands/sections-commands.js.map +1 -0
  119. package/dist/commands/sections-graph.d.ts +25 -0
  120. package/dist/commands/sections-graph.d.ts.map +1 -0
  121. package/dist/commands/sections-graph.js +180 -0
  122. package/dist/commands/sections-graph.js.map +1 -0
  123. package/dist/commands/sections.d.ts +3 -0
  124. package/dist/commands/sections.d.ts.map +1 -0
  125. package/dist/commands/sections.js +376 -0
  126. package/dist/commands/sections.js.map +1 -0
  127. package/dist/commands/stats.d.ts +6 -0
  128. package/dist/commands/stats.d.ts.map +1 -0
  129. package/dist/commands/stats.js +324 -0
  130. package/dist/commands/stats.js.map +1 -0
  131. package/dist/commands/tasks.d.ts +3 -0
  132. package/dist/commands/tasks.d.ts.map +1 -0
  133. package/dist/commands/tasks.js +1115 -0
  134. package/dist/commands/tasks.js.map +1 -0
  135. package/dist/commands/web.d.ts +7 -0
  136. package/dist/commands/web.d.ts.map +1 -0
  137. package/dist/commands/web.js +204 -0
  138. package/dist/commands/web.js.map +1 -0
  139. package/dist/config/ai-setup.d.ts +27 -0
  140. package/dist/config/ai-setup.d.ts.map +1 -0
  141. package/dist/config/ai-setup.js +432 -0
  142. package/dist/config/ai-setup.js.map +1 -0
  143. package/dist/config/browser.d.ts +9 -0
  144. package/dist/config/browser.d.ts.map +1 -0
  145. package/dist/config/browser.js +200 -0
  146. package/dist/config/browser.js.map +1 -0
  147. package/dist/config/json-schema.d.ts +28 -0
  148. package/dist/config/json-schema.d.ts.map +1 -0
  149. package/dist/config/json-schema.js +84 -0
  150. package/dist/config/json-schema.js.map +1 -0
  151. package/dist/config/loader.d.ts +152 -0
  152. package/dist/config/loader.d.ts.map +1 -0
  153. package/dist/config/loader.js +270 -0
  154. package/dist/config/loader.js.map +1 -0
  155. package/dist/config/schema.d.ts +34 -0
  156. package/dist/config/schema.d.ts.map +1 -0
  157. package/dist/config/schema.js +437 -0
  158. package/dist/config/schema.js.map +1 -0
  159. package/dist/config/validator.d.ts +32 -0
  160. package/dist/config/validator.d.ts.map +1 -0
  161. package/dist/config/validator.js +187 -0
  162. package/dist/config/validator.js.map +1 -0
  163. package/dist/database/connection.d.ts +35 -0
  164. package/dist/database/connection.d.ts.map +1 -0
  165. package/dist/database/connection.js +208 -0
  166. package/dist/database/connection.js.map +1 -0
  167. package/dist/database/queries.d.ts +218 -0
  168. package/dist/database/queries.d.ts.map +1 -0
  169. package/dist/database/queries.js +613 -0
  170. package/dist/database/queries.js.map +1 -0
  171. package/dist/database/schema.d.ts +8 -0
  172. package/dist/database/schema.d.ts.map +1 -0
  173. package/dist/database/schema.js +160 -0
  174. package/dist/database/schema.js.map +1 -0
  175. package/dist/disputes/behavior.d.ts +106 -0
  176. package/dist/disputes/behavior.d.ts.map +1 -0
  177. package/dist/disputes/behavior.js +150 -0
  178. package/dist/disputes/behavior.js.map +1 -0
  179. package/dist/disputes/create.d.ts +59 -0
  180. package/dist/disputes/create.d.ts.map +1 -0
  181. package/dist/disputes/create.js +222 -0
  182. package/dist/disputes/create.js.map +1 -0
  183. package/dist/disputes/index.d.ts +21 -0
  184. package/dist/disputes/index.d.ts.map +1 -0
  185. package/dist/disputes/index.js +76 -0
  186. package/dist/disputes/index.js.map +1 -0
  187. package/dist/disputes/markdown.d.ts +41 -0
  188. package/dist/disputes/markdown.d.ts.map +1 -0
  189. package/dist/disputes/markdown.js +261 -0
  190. package/dist/disputes/markdown.js.map +1 -0
  191. package/dist/disputes/queries.d.ts +83 -0
  192. package/dist/disputes/queries.d.ts.map +1 -0
  193. package/dist/disputes/queries.js +180 -0
  194. package/dist/disputes/queries.js.map +1 -0
  195. package/dist/disputes/resolve.d.ts +57 -0
  196. package/dist/disputes/resolve.d.ts.map +1 -0
  197. package/dist/disputes/resolve.js +171 -0
  198. package/dist/disputes/resolve.js.map +1 -0
  199. package/dist/disputes/stale.d.ts +98 -0
  200. package/dist/disputes/stale.d.ts.map +1 -0
  201. package/dist/disputes/stale.js +205 -0
  202. package/dist/disputes/stale.js.map +1 -0
  203. package/dist/disputes/types.d.ts +92 -0
  204. package/dist/disputes/types.d.ts.map +1 -0
  205. package/dist/disputes/types.js +100 -0
  206. package/dist/disputes/types.js.map +1 -0
  207. package/dist/git/push.d.ts +26 -0
  208. package/dist/git/push.d.ts.map +1 -0
  209. package/dist/git/push.js +97 -0
  210. package/dist/git/push.js.map +1 -0
  211. package/dist/git/status.d.ts +61 -0
  212. package/dist/git/status.d.ts.map +1 -0
  213. package/dist/git/status.js +251 -0
  214. package/dist/git/status.js.map +1 -0
  215. package/dist/hooks/events.d.ts +72 -0
  216. package/dist/hooks/events.d.ts.map +1 -0
  217. package/dist/hooks/events.js +120 -0
  218. package/dist/hooks/events.js.map +1 -0
  219. package/dist/hooks/index.d.ts +19 -0
  220. package/dist/hooks/index.d.ts.map +1 -0
  221. package/dist/hooks/index.js +48 -0
  222. package/dist/hooks/index.js.map +1 -0
  223. package/dist/hooks/integration.d.ts +69 -0
  224. package/dist/hooks/integration.d.ts.map +1 -0
  225. package/dist/hooks/integration.js +179 -0
  226. package/dist/hooks/integration.js.map +1 -0
  227. package/dist/hooks/merge.d.ts +115 -0
  228. package/dist/hooks/merge.d.ts.map +1 -0
  229. package/dist/hooks/merge.js +161 -0
  230. package/dist/hooks/merge.js.map +1 -0
  231. package/dist/hooks/orchestrator.d.ts +115 -0
  232. package/dist/hooks/orchestrator.d.ts.map +1 -0
  233. package/dist/hooks/orchestrator.js +226 -0
  234. package/dist/hooks/orchestrator.js.map +1 -0
  235. package/dist/hooks/payload.d.ts +294 -0
  236. package/dist/hooks/payload.d.ts.map +1 -0
  237. package/dist/hooks/payload.js +267 -0
  238. package/dist/hooks/payload.js.map +1 -0
  239. package/dist/hooks/script-runner.d.ts +63 -0
  240. package/dist/hooks/script-runner.d.ts.map +1 -0
  241. package/dist/hooks/script-runner.js +221 -0
  242. package/dist/hooks/script-runner.js.map +1 -0
  243. package/dist/hooks/templates.d.ts +104 -0
  244. package/dist/hooks/templates.d.ts.map +1 -0
  245. package/dist/hooks/templates.js +327 -0
  246. package/dist/hooks/templates.js.map +1 -0
  247. package/dist/hooks/webhook-runner.d.ts +69 -0
  248. package/dist/hooks/webhook-runner.d.ts.map +1 -0
  249. package/dist/hooks/webhook-runner.js +208 -0
  250. package/dist/hooks/webhook-runner.js.map +1 -0
  251. package/dist/index.d.ts +7 -0
  252. package/dist/index.d.ts.map +1 -0
  253. package/dist/index.js +281 -0
  254. package/dist/index.js.map +1 -0
  255. package/dist/locking/cleanup.d.ts +70 -0
  256. package/dist/locking/cleanup.d.ts.map +1 -0
  257. package/dist/locking/cleanup.js +157 -0
  258. package/dist/locking/cleanup.js.map +1 -0
  259. package/dist/locking/queries.d.ts +116 -0
  260. package/dist/locking/queries.d.ts.map +1 -0
  261. package/dist/locking/queries.js +255 -0
  262. package/dist/locking/queries.js.map +1 -0
  263. package/dist/locking/section-lock.d.ts +74 -0
  264. package/dist/locking/section-lock.d.ts.map +1 -0
  265. package/dist/locking/section-lock.js +207 -0
  266. package/dist/locking/section-lock.js.map +1 -0
  267. package/dist/locking/task-lock.d.ts +92 -0
  268. package/dist/locking/task-lock.d.ts.map +1 -0
  269. package/dist/locking/task-lock.js +246 -0
  270. package/dist/locking/task-lock.js.map +1 -0
  271. package/dist/migrations/index.d.ts +7 -0
  272. package/dist/migrations/index.d.ts.map +1 -0
  273. package/dist/migrations/index.js +37 -0
  274. package/dist/migrations/index.js.map +1 -0
  275. package/dist/migrations/manifest.d.ts +92 -0
  276. package/dist/migrations/manifest.d.ts.map +1 -0
  277. package/dist/migrations/manifest.js +270 -0
  278. package/dist/migrations/manifest.js.map +1 -0
  279. package/dist/migrations/runner.d.ts +84 -0
  280. package/dist/migrations/runner.d.ts.map +1 -0
  281. package/dist/migrations/runner.js +351 -0
  282. package/dist/migrations/runner.js.map +1 -0
  283. package/dist/orchestrator/coder.d.ts +32 -0
  284. package/dist/orchestrator/coder.d.ts.map +1 -0
  285. package/dist/orchestrator/coder.js +174 -0
  286. package/dist/orchestrator/coder.js.map +1 -0
  287. package/dist/orchestrator/coordinator.d.ts +28 -0
  288. package/dist/orchestrator/coordinator.d.ts.map +1 -0
  289. package/dist/orchestrator/coordinator.js +256 -0
  290. package/dist/orchestrator/coordinator.js.map +1 -0
  291. package/dist/orchestrator/reviewer.d.ts +35 -0
  292. package/dist/orchestrator/reviewer.d.ts.map +1 -0
  293. package/dist/orchestrator/reviewer.js +241 -0
  294. package/dist/orchestrator/reviewer.js.map +1 -0
  295. package/dist/orchestrator/task-selector.d.ts +102 -0
  296. package/dist/orchestrator/task-selector.d.ts.map +1 -0
  297. package/dist/orchestrator/task-selector.js +341 -0
  298. package/dist/orchestrator/task-selector.js.map +1 -0
  299. package/dist/prompts/coder.d.ts +36 -0
  300. package/dist/prompts/coder.d.ts.map +1 -0
  301. package/dist/prompts/coder.js +315 -0
  302. package/dist/prompts/coder.js.map +1 -0
  303. package/dist/prompts/prompt-helpers.d.ts +51 -0
  304. package/dist/prompts/prompt-helpers.d.ts.map +1 -0
  305. package/dist/prompts/prompt-helpers.js +312 -0
  306. package/dist/prompts/prompt-helpers.js.map +1 -0
  307. package/dist/prompts/reviewer.d.ts +40 -0
  308. package/dist/prompts/reviewer.d.ts.map +1 -0
  309. package/dist/prompts/reviewer.js +438 -0
  310. package/dist/prompts/reviewer.js.map +1 -0
  311. package/dist/providers/api-models.d.ts +65 -0
  312. package/dist/providers/api-models.d.ts.map +1 -0
  313. package/dist/providers/api-models.js +323 -0
  314. package/dist/providers/api-models.js.map +1 -0
  315. package/dist/providers/claude.d.ts +53 -0
  316. package/dist/providers/claude.d.ts.map +1 -0
  317. package/dist/providers/claude.js +229 -0
  318. package/dist/providers/claude.js.map +1 -0
  319. package/dist/providers/codex.d.ts +53 -0
  320. package/dist/providers/codex.d.ts.map +1 -0
  321. package/dist/providers/codex.js +214 -0
  322. package/dist/providers/codex.js.map +1 -0
  323. package/dist/providers/gemini.d.ts +58 -0
  324. package/dist/providers/gemini.d.ts.map +1 -0
  325. package/dist/providers/gemini.js +242 -0
  326. package/dist/providers/gemini.js.map +1 -0
  327. package/dist/providers/index.d.ts +13 -0
  328. package/dist/providers/index.d.ts.map +1 -0
  329. package/dist/providers/index.js +49 -0
  330. package/dist/providers/index.js.map +1 -0
  331. package/dist/providers/interface.d.ts +173 -0
  332. package/dist/providers/interface.d.ts.map +1 -0
  333. package/dist/providers/interface.js +96 -0
  334. package/dist/providers/interface.js.map +1 -0
  335. package/dist/providers/invocation-logger.d.ts +114 -0
  336. package/dist/providers/invocation-logger.d.ts.map +1 -0
  337. package/dist/providers/invocation-logger.js +298 -0
  338. package/dist/providers/invocation-logger.js.map +1 -0
  339. package/dist/providers/openai.d.ts +53 -0
  340. package/dist/providers/openai.d.ts.map +1 -0
  341. package/dist/providers/openai.js +232 -0
  342. package/dist/providers/openai.js.map +1 -0
  343. package/dist/providers/registry.d.ts +100 -0
  344. package/dist/providers/registry.d.ts.map +1 -0
  345. package/dist/providers/registry.js +178 -0
  346. package/dist/providers/registry.js.map +1 -0
  347. package/dist/runners/activity-log.d.ts +65 -0
  348. package/dist/runners/activity-log.d.ts.map +1 -0
  349. package/dist/runners/activity-log.js +148 -0
  350. package/dist/runners/activity-log.js.map +1 -0
  351. package/dist/runners/cron.d.ts +26 -0
  352. package/dist/runners/cron.d.ts.map +1 -0
  353. package/dist/runners/cron.js +176 -0
  354. package/dist/runners/cron.js.map +1 -0
  355. package/dist/runners/daemon.d.ts +71 -0
  356. package/dist/runners/daemon.d.ts.map +1 -0
  357. package/dist/runners/daemon.js +245 -0
  358. package/dist/runners/daemon.js.map +1 -0
  359. package/dist/runners/global-db.d.ts +31 -0
  360. package/dist/runners/global-db.d.ts.map +1 -0
  361. package/dist/runners/global-db.js +230 -0
  362. package/dist/runners/global-db.js.map +1 -0
  363. package/dist/runners/hang-detector.d.ts +38 -0
  364. package/dist/runners/hang-detector.d.ts.map +1 -0
  365. package/dist/runners/hang-detector.js +136 -0
  366. package/dist/runners/hang-detector.js.map +1 -0
  367. package/dist/runners/heartbeat.d.ts +39 -0
  368. package/dist/runners/heartbeat.d.ts.map +1 -0
  369. package/dist/runners/heartbeat.js +79 -0
  370. package/dist/runners/heartbeat.js.map +1 -0
  371. package/dist/runners/lock.d.ts +47 -0
  372. package/dist/runners/lock.d.ts.map +1 -0
  373. package/dist/runners/lock.js +150 -0
  374. package/dist/runners/lock.js.map +1 -0
  375. package/dist/runners/orchestrator-loop.d.ts +20 -0
  376. package/dist/runners/orchestrator-loop.d.ts.map +1 -0
  377. package/dist/runners/orchestrator-loop.js +285 -0
  378. package/dist/runners/orchestrator-loop.js.map +1 -0
  379. package/dist/runners/projects.d.ts +96 -0
  380. package/dist/runners/projects.d.ts.map +1 -0
  381. package/dist/runners/projects.js +255 -0
  382. package/dist/runners/projects.js.map +1 -0
  383. package/dist/runners/wakeup.d.ts +34 -0
  384. package/dist/runners/wakeup.d.ts.map +1 -0
  385. package/dist/runners/wakeup.js +291 -0
  386. package/dist/runners/wakeup.js.map +1 -0
  387. package/migrations/001_initial_schema.sql +106 -0
  388. package/migrations/002_add_commit_sha.sql +12 -0
  389. package/migrations/003_add_section_priority.sql +13 -0
  390. package/migrations/004_add_section_dependencies.sql +18 -0
  391. package/migrations/005_add_audit_actor_model.sql +10 -0
  392. package/migrations/006_add_task_invocations.sql +33 -0
  393. package/migrations/007_add_file_anchor.sql +14 -0
  394. package/migrations/manifest.json +62 -0
  395. package/package.json +49 -0
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ /**
3
+ * Database queries for task and section lock management
4
+ * All lock operations are atomic using SQLite transactions
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.getTaskLock = getTaskLock;
8
+ exports.isTaskLockExpired = isTaskLockExpired;
9
+ exports.getTaskLockInfo = getTaskLockInfo;
10
+ exports.tryInsertTaskLock = tryInsertTaskLock;
11
+ exports.claimExpiredTaskLock = claimExpiredTaskLock;
12
+ exports.releaseTaskLock = releaseTaskLock;
13
+ exports.forceReleaseTaskLock = forceReleaseTaskLock;
14
+ exports.updateTaskLockHeartbeat = updateTaskLockHeartbeat;
15
+ exports.extendTaskLock = extendTaskLock;
16
+ exports.listTaskLocks = listTaskLocks;
17
+ exports.findExpiredTaskLocks = findExpiredTaskLocks;
18
+ exports.cleanupExpiredTaskLocks = cleanupExpiredTaskLocks;
19
+ exports.getSectionLock = getSectionLock;
20
+ exports.isSectionLockExpired = isSectionLockExpired;
21
+ exports.tryInsertSectionLock = tryInsertSectionLock;
22
+ exports.claimExpiredSectionLock = claimExpiredSectionLock;
23
+ exports.releaseSectionLock = releaseSectionLock;
24
+ exports.forceReleaseSectionLock = forceReleaseSectionLock;
25
+ exports.listSectionLocks = listSectionLocks;
26
+ exports.findExpiredSectionLocks = findExpiredSectionLocks;
27
+ exports.cleanupExpiredSectionLocks = cleanupExpiredSectionLocks;
28
+ // ============ Task Lock Queries ============
29
+ /**
30
+ * Get task lock by task ID
31
+ */
32
+ function getTaskLock(db, taskId) {
33
+ return db
34
+ .prepare('SELECT * FROM task_locks WHERE task_id = ?')
35
+ .get(taskId);
36
+ }
37
+ /**
38
+ * Check if a task lock is expired
39
+ */
40
+ function isTaskLockExpired(lock) {
41
+ const expiresAt = new Date(lock.expires_at).getTime();
42
+ return Date.now() > expiresAt;
43
+ }
44
+ /**
45
+ * Get task lock info with ownership and expiry status
46
+ */
47
+ function getTaskLockInfo(db, taskId, runnerId) {
48
+ const lock = getTaskLock(db, taskId);
49
+ if (!lock) {
50
+ return {
51
+ isLocked: false,
52
+ lock: null,
53
+ isExpired: false,
54
+ isOwnedByUs: false,
55
+ };
56
+ }
57
+ const isExpired = isTaskLockExpired(lock);
58
+ const isOwnedByUs = lock.runner_id === runnerId;
59
+ return {
60
+ isLocked: !isExpired,
61
+ lock,
62
+ isExpired,
63
+ isOwnedByUs,
64
+ };
65
+ }
66
+ /**
67
+ * Try to insert a new task lock (atomic)
68
+ * Returns true if lock was acquired, false if already exists
69
+ */
70
+ function tryInsertTaskLock(db, taskId, runnerId, timeoutMinutes) {
71
+ const expiresAt = new Date(Date.now() + timeoutMinutes * 60 * 1000).toISOString();
72
+ try {
73
+ db.prepare(`INSERT INTO task_locks (task_id, runner_id, expires_at)
74
+ VALUES (?, ?, ?)`).run(taskId, runnerId, expiresAt);
75
+ return true;
76
+ }
77
+ catch (err) {
78
+ // IntegrityError means lock already exists
79
+ if (err instanceof Error && err.message.includes('UNIQUE constraint')) {
80
+ return false;
81
+ }
82
+ throw err;
83
+ }
84
+ }
85
+ /**
86
+ * Claim an expired lock atomically
87
+ * Only succeeds if the lock is actually expired at execution time
88
+ */
89
+ function claimExpiredTaskLock(db, taskId, runnerId, timeoutMinutes) {
90
+ const expiresAt = new Date(Date.now() + timeoutMinutes * 60 * 1000).toISOString();
91
+ const result = db.prepare(`UPDATE task_locks
92
+ SET runner_id = ?,
93
+ acquired_at = datetime('now'),
94
+ expires_at = ?,
95
+ heartbeat_at = datetime('now')
96
+ WHERE task_id = ?
97
+ AND expires_at < datetime('now')`).run(runnerId, expiresAt, taskId);
98
+ return result.changes > 0;
99
+ }
100
+ /**
101
+ * Release a task lock (only if owned by the specified runner)
102
+ * Returns true if lock was released, false if not owned
103
+ */
104
+ function releaseTaskLock(db, taskId, runnerId) {
105
+ const result = db.prepare(`DELETE FROM task_locks
106
+ WHERE task_id = ?
107
+ AND runner_id = ?`).run(taskId, runnerId);
108
+ return result.changes > 0;
109
+ }
110
+ /**
111
+ * Force release a task lock (admin operation)
112
+ * Returns true if lock was released
113
+ */
114
+ function forceReleaseTaskLock(db, taskId) {
115
+ const result = db.prepare(`DELETE FROM task_locks WHERE task_id = ?`).run(taskId);
116
+ return result.changes > 0;
117
+ }
118
+ /**
119
+ * Update heartbeat for a task lock
120
+ * Returns true if heartbeat was updated, false if lock not found or not owned
121
+ */
122
+ function updateTaskLockHeartbeat(db, taskId, runnerId) {
123
+ const result = db.prepare(`UPDATE task_locks
124
+ SET heartbeat_at = datetime('now')
125
+ WHERE task_id = ?
126
+ AND runner_id = ?`).run(taskId, runnerId);
127
+ return result.changes > 0;
128
+ }
129
+ /**
130
+ * Extend a task lock's expiry time
131
+ * Returns true if extended, false if lock not found or not owned
132
+ */
133
+ function extendTaskLock(db, taskId, runnerId, additionalMinutes) {
134
+ const newExpiresAt = new Date(Date.now() + additionalMinutes * 60 * 1000).toISOString();
135
+ const result = db.prepare(`UPDATE task_locks
136
+ SET expires_at = ?,
137
+ heartbeat_at = datetime('now')
138
+ WHERE task_id = ?
139
+ AND runner_id = ?`).run(newExpiresAt, taskId, runnerId);
140
+ return result.changes > 0;
141
+ }
142
+ /**
143
+ * List all task locks
144
+ */
145
+ function listTaskLocks(db) {
146
+ return db
147
+ .prepare('SELECT * FROM task_locks ORDER BY acquired_at DESC')
148
+ .all();
149
+ }
150
+ /**
151
+ * Find all expired task locks
152
+ */
153
+ function findExpiredTaskLocks(db) {
154
+ return db
155
+ .prepare(`SELECT * FROM task_locks
156
+ WHERE expires_at < datetime('now')
157
+ ORDER BY expires_at ASC`)
158
+ .all();
159
+ }
160
+ /**
161
+ * Delete all expired task locks
162
+ * Returns the number of locks deleted
163
+ */
164
+ function cleanupExpiredTaskLocks(db) {
165
+ const result = db.prepare(`DELETE FROM task_locks WHERE expires_at < datetime('now')`).run();
166
+ return result.changes;
167
+ }
168
+ // ============ Section Lock Queries ============
169
+ /**
170
+ * Get section lock by section ID
171
+ */
172
+ function getSectionLock(db, sectionId) {
173
+ return db
174
+ .prepare('SELECT * FROM section_locks WHERE section_id = ?')
175
+ .get(sectionId);
176
+ }
177
+ /**
178
+ * Check if a section lock is expired
179
+ */
180
+ function isSectionLockExpired(lock) {
181
+ const expiresAt = new Date(lock.expires_at).getTime();
182
+ return Date.now() > expiresAt;
183
+ }
184
+ /**
185
+ * Try to insert a new section lock (atomic)
186
+ */
187
+ function tryInsertSectionLock(db, sectionId, runnerId, timeoutMinutes) {
188
+ const expiresAt = new Date(Date.now() + timeoutMinutes * 60 * 1000).toISOString();
189
+ try {
190
+ db.prepare(`INSERT INTO section_locks (section_id, runner_id, expires_at)
191
+ VALUES (?, ?, ?)`).run(sectionId, runnerId, expiresAt);
192
+ return true;
193
+ }
194
+ catch (err) {
195
+ if (err instanceof Error && err.message.includes('UNIQUE constraint')) {
196
+ return false;
197
+ }
198
+ throw err;
199
+ }
200
+ }
201
+ /**
202
+ * Claim an expired section lock atomically
203
+ */
204
+ function claimExpiredSectionLock(db, sectionId, runnerId, timeoutMinutes) {
205
+ const expiresAt = new Date(Date.now() + timeoutMinutes * 60 * 1000).toISOString();
206
+ const result = db.prepare(`UPDATE section_locks
207
+ SET runner_id = ?,
208
+ acquired_at = datetime('now'),
209
+ expires_at = ?
210
+ WHERE section_id = ?
211
+ AND expires_at < datetime('now')`).run(runnerId, expiresAt, sectionId);
212
+ return result.changes > 0;
213
+ }
214
+ /**
215
+ * Release a section lock
216
+ */
217
+ function releaseSectionLock(db, sectionId, runnerId) {
218
+ const result = db.prepare(`DELETE FROM section_locks
219
+ WHERE section_id = ?
220
+ AND runner_id = ?`).run(sectionId, runnerId);
221
+ return result.changes > 0;
222
+ }
223
+ /**
224
+ * Force release a section lock
225
+ */
226
+ function forceReleaseSectionLock(db, sectionId) {
227
+ const result = db.prepare(`DELETE FROM section_locks WHERE section_id = ?`).run(sectionId);
228
+ return result.changes > 0;
229
+ }
230
+ /**
231
+ * List all section locks
232
+ */
233
+ function listSectionLocks(db) {
234
+ return db
235
+ .prepare('SELECT * FROM section_locks ORDER BY acquired_at DESC')
236
+ .all();
237
+ }
238
+ /**
239
+ * Find all expired section locks
240
+ */
241
+ function findExpiredSectionLocks(db) {
242
+ return db
243
+ .prepare(`SELECT * FROM section_locks
244
+ WHERE expires_at < datetime('now')
245
+ ORDER BY expires_at ASC`)
246
+ .all();
247
+ }
248
+ /**
249
+ * Delete all expired section locks
250
+ */
251
+ function cleanupExpiredSectionLocks(db) {
252
+ const result = db.prepare(`DELETE FROM section_locks WHERE expires_at < datetime('now')`).run();
253
+ return result.changes;
254
+ }
255
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/locking/queries.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Section locking for parallel work prevention
3
+ * Prevents multiple runners from working on tasks in the same section
4
+ */
5
+ import type Database from 'better-sqlite3';
6
+ import { type SectionLock } from './queries.js';
7
+ export interface SectionLockAcquisitionResult {
8
+ acquired: boolean;
9
+ lock?: SectionLock;
10
+ reason?: 'already_owned' | 'acquired_new' | 'claimed_expired';
11
+ error?: SectionLockError;
12
+ }
13
+ export interface SectionLockError {
14
+ code: 'SECTION_LOCKED' | 'LOCK_NOT_FOUND' | 'PERMISSION_DENIED';
15
+ message: string;
16
+ details?: {
17
+ sectionId: string;
18
+ runnerId?: string;
19
+ expiresAt?: string;
20
+ };
21
+ }
22
+ export interface SectionLockReleaseResult {
23
+ released: boolean;
24
+ error?: SectionLockError;
25
+ }
26
+ export interface SectionLockManager {
27
+ acquire: () => SectionLockAcquisitionResult;
28
+ release: () => SectionLockReleaseResult;
29
+ isHeld: () => boolean;
30
+ }
31
+ /**
32
+ * Acquire a section lock with atomic operations
33
+ *
34
+ * Flow:
35
+ * 1. Try INSERT (fails if lock exists)
36
+ * 2. If exists, check if we own it
37
+ * 3. If owned by another, check if expired
38
+ * 4. If expired, claim atomically
39
+ * 5. If not expired, return failure
40
+ */
41
+ export declare function acquireSectionLock(db: Database.Database, sectionId: string, runnerId: string, timeoutMinutes?: number): SectionLockAcquisitionResult;
42
+ /**
43
+ * Release a section lock (only by owner)
44
+ */
45
+ export declare function releaseSectionLock(db: Database.Database, sectionId: string, runnerId: string): SectionLockReleaseResult;
46
+ /**
47
+ * Force release a section lock (admin operation)
48
+ */
49
+ export declare function forceRelease(db: Database.Database, sectionId: string): SectionLockReleaseResult;
50
+ /**
51
+ * Create a section lock manager for a specific section
52
+ */
53
+ export declare function createSectionLockManager(db: Database.Database, sectionId: string, runnerId: string, timeoutMinutes?: number): SectionLockManager;
54
+ /**
55
+ * Check if a section is locked
56
+ */
57
+ export declare function isSectionLocked(db: Database.Database, sectionId: string): boolean;
58
+ /**
59
+ * Check if a section is locked by a specific runner
60
+ */
61
+ export declare function isSectionLockedBy(db: Database.Database, sectionId: string, runnerId: string): boolean;
62
+ /**
63
+ * Get time until section lock expires (in milliseconds)
64
+ */
65
+ export declare function getTimeUntilExpiry(db: Database.Database, sectionId: string): number | null;
66
+ /**
67
+ * Check if any tasks in the section are in progress by another runner
68
+ * This can be used before acquiring a section lock
69
+ */
70
+ export declare function getSectionLockHolder(db: Database.Database, sectionId: string): SectionLock | null;
71
+ export declare const SECTION_LOCK_CONSTANTS: {
72
+ readonly DEFAULT_TIMEOUT_MINUTES: 120;
73
+ };
74
+ //# sourceMappingURL=section-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-lock.d.ts","sourceRoot":"","sources":["../../src/locking/section-lock.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAOtB,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,GAAG,cAAc,GAAG,iBAAiB,CAAC;IAC9D,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,4BAA4B,CAAC;IAC5C,OAAO,EAAE,MAAM,wBAAwB,CAAC;IACxC,MAAM,EAAE,MAAM,OAAO,CAAC;CACvB;AAID;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,MAAwC,GACvD,4BAA4B,CAqD9B;AAyBD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,wBAAwB,CA+B1B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,GAChB,wBAAwB,CAe1B;AAID;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,MAAwC,GACvD,kBAAkB,CASpB;AAID;;GAEG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAIT;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAOf;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,GAChB,WAAW,GAAG,IAAI,CAMpB;AAID,eAAO,MAAM,sBAAsB;;CAEzB,CAAC"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ /**
3
+ * Section locking for parallel work prevention
4
+ * Prevents multiple runners from working on tasks in the same section
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SECTION_LOCK_CONSTANTS = void 0;
8
+ exports.acquireSectionLock = acquireSectionLock;
9
+ exports.releaseSectionLock = releaseSectionLock;
10
+ exports.forceRelease = forceRelease;
11
+ exports.createSectionLockManager = createSectionLockManager;
12
+ exports.isSectionLocked = isSectionLocked;
13
+ exports.isSectionLockedBy = isSectionLockedBy;
14
+ exports.getTimeUntilExpiry = getTimeUntilExpiry;
15
+ exports.getSectionLockHolder = getSectionLockHolder;
16
+ const queries_js_1 = require("./queries.js");
17
+ // Default section lock timeout in minutes
18
+ const DEFAULT_SECTION_TIMEOUT_MINUTES = 120;
19
+ // ============ Lock Acquisition ============
20
+ /**
21
+ * Acquire a section lock with atomic operations
22
+ *
23
+ * Flow:
24
+ * 1. Try INSERT (fails if lock exists)
25
+ * 2. If exists, check if we own it
26
+ * 3. If owned by another, check if expired
27
+ * 4. If expired, claim atomically
28
+ * 5. If not expired, return failure
29
+ */
30
+ function acquireSectionLock(db, sectionId, runnerId, timeoutMinutes = DEFAULT_SECTION_TIMEOUT_MINUTES) {
31
+ // Step 1: Try to insert new lock
32
+ if ((0, queries_js_1.tryInsertSectionLock)(db, sectionId, runnerId, timeoutMinutes)) {
33
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
34
+ return {
35
+ acquired: true,
36
+ lock: lock ?? undefined,
37
+ reason: 'acquired_new',
38
+ };
39
+ }
40
+ // Step 2: Lock exists, get current state
41
+ const existingLock = (0, queries_js_1.getSectionLock)(db, sectionId);
42
+ if (!existingLock) {
43
+ // Race condition: lock was deleted between insert attempt and now
44
+ if ((0, queries_js_1.tryInsertSectionLock)(db, sectionId, runnerId, timeoutMinutes)) {
45
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
46
+ return {
47
+ acquired: true,
48
+ lock: lock ?? undefined,
49
+ reason: 'acquired_new',
50
+ };
51
+ }
52
+ const currentLock = (0, queries_js_1.getSectionLock)(db, sectionId);
53
+ return createLockedError(sectionId, currentLock);
54
+ }
55
+ // Step 3: Check if we already own the lock
56
+ if (existingLock.runner_id === runnerId) {
57
+ return {
58
+ acquired: true,
59
+ lock: existingLock,
60
+ reason: 'already_owned',
61
+ };
62
+ }
63
+ // Step 4: Check if lock is expired
64
+ if ((0, queries_js_1.isSectionLockExpired)(existingLock)) {
65
+ if ((0, queries_js_1.claimExpiredSectionLock)(db, sectionId, runnerId, timeoutMinutes)) {
66
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
67
+ return {
68
+ acquired: true,
69
+ lock: lock ?? undefined,
70
+ reason: 'claimed_expired',
71
+ };
72
+ }
73
+ // Another runner claimed it first
74
+ const currentLock = (0, queries_js_1.getSectionLock)(db, sectionId);
75
+ return createLockedError(sectionId, currentLock);
76
+ }
77
+ // Step 5: Lock is held by another runner and not expired
78
+ return createLockedError(sectionId, existingLock);
79
+ }
80
+ /**
81
+ * Create a SECTION_LOCKED error response
82
+ */
83
+ function createLockedError(sectionId, lock) {
84
+ return {
85
+ acquired: false,
86
+ error: {
87
+ code: 'SECTION_LOCKED',
88
+ message: 'Section is locked by another runner',
89
+ details: {
90
+ sectionId,
91
+ runnerId: lock?.runner_id,
92
+ expiresAt: lock?.expires_at,
93
+ },
94
+ },
95
+ };
96
+ }
97
+ // ============ Lock Release ============
98
+ /**
99
+ * Release a section lock (only by owner)
100
+ */
101
+ function releaseSectionLock(db, sectionId, runnerId) {
102
+ const existingLock = (0, queries_js_1.getSectionLock)(db, sectionId);
103
+ if (!existingLock) {
104
+ return {
105
+ released: false,
106
+ error: {
107
+ code: 'LOCK_NOT_FOUND',
108
+ message: 'Lock does not exist',
109
+ details: { sectionId },
110
+ },
111
+ };
112
+ }
113
+ if (existingLock.runner_id !== runnerId) {
114
+ return {
115
+ released: false,
116
+ error: {
117
+ code: 'PERMISSION_DENIED',
118
+ message: 'Cannot release lock owned by another runner',
119
+ details: {
120
+ sectionId,
121
+ runnerId: existingLock.runner_id,
122
+ expiresAt: existingLock.expires_at,
123
+ },
124
+ },
125
+ };
126
+ }
127
+ (0, queries_js_1.releaseSectionLock)(db, sectionId, runnerId);
128
+ return { released: true };
129
+ }
130
+ /**
131
+ * Force release a section lock (admin operation)
132
+ */
133
+ function forceRelease(db, sectionId) {
134
+ const existed = (0, queries_js_1.forceReleaseSectionLock)(db, sectionId);
135
+ if (!existed) {
136
+ return {
137
+ released: false,
138
+ error: {
139
+ code: 'LOCK_NOT_FOUND',
140
+ message: 'Lock does not exist',
141
+ details: { sectionId },
142
+ },
143
+ };
144
+ }
145
+ return { released: true };
146
+ }
147
+ // ============ Lock Manager ============
148
+ /**
149
+ * Create a section lock manager for a specific section
150
+ */
151
+ function createSectionLockManager(db, sectionId, runnerId, timeoutMinutes = DEFAULT_SECTION_TIMEOUT_MINUTES) {
152
+ return {
153
+ acquire: () => acquireSectionLock(db, sectionId, runnerId, timeoutMinutes),
154
+ release: () => releaseSectionLock(db, sectionId, runnerId),
155
+ isHeld: () => {
156
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
157
+ return lock !== null && lock.runner_id === runnerId && !(0, queries_js_1.isSectionLockExpired)(lock);
158
+ },
159
+ };
160
+ }
161
+ // ============ Lock Status Check ============
162
+ /**
163
+ * Check if a section is locked
164
+ */
165
+ function isSectionLocked(db, sectionId) {
166
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
167
+ if (!lock)
168
+ return false;
169
+ return !(0, queries_js_1.isSectionLockExpired)(lock);
170
+ }
171
+ /**
172
+ * Check if a section is locked by a specific runner
173
+ */
174
+ function isSectionLockedBy(db, sectionId, runnerId) {
175
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
176
+ if (!lock)
177
+ return false;
178
+ return lock.runner_id === runnerId && !(0, queries_js_1.isSectionLockExpired)(lock);
179
+ }
180
+ /**
181
+ * Get time until section lock expires (in milliseconds)
182
+ */
183
+ function getTimeUntilExpiry(db, sectionId) {
184
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
185
+ if (!lock)
186
+ return null;
187
+ const expiresAt = new Date(lock.expires_at).getTime();
188
+ const remaining = expiresAt - Date.now();
189
+ return Math.max(0, remaining);
190
+ }
191
+ // ============ Helper Functions ============
192
+ /**
193
+ * Check if any tasks in the section are in progress by another runner
194
+ * This can be used before acquiring a section lock
195
+ */
196
+ function getSectionLockHolder(db, sectionId) {
197
+ const lock = (0, queries_js_1.getSectionLock)(db, sectionId);
198
+ if (!lock || (0, queries_js_1.isSectionLockExpired)(lock)) {
199
+ return null;
200
+ }
201
+ return lock;
202
+ }
203
+ // ============ Constants Export ============
204
+ exports.SECTION_LOCK_CONSTANTS = {
205
+ DEFAULT_TIMEOUT_MINUTES: DEFAULT_SECTION_TIMEOUT_MINUTES,
206
+ };
207
+ //# sourceMappingURL=section-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-lock.js","sourceRoot":"","sources":["../../src/locking/section-lock.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA0DH,gDA0DC;AA4BD,gDAmCC;AAKD,oCAkBC;AAOD,4DAcC;AAOD,0CAOC;AAKD,8CAQC;AAKD,gDAUC;AAQD,oDASC;AAvRD,6CAQsB;AAEtB,0CAA0C;AAC1C,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAgC5C,6CAA6C;AAE7C;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAChC,EAAqB,EACrB,SAAiB,EACjB,QAAgB,EAChB,iBAAyB,+BAA+B;IAExD,iCAAiC;IACjC,IAAI,IAAA,iCAAoB,EAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAC3C,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,IAAI,IAAI,SAAS;YACvB,MAAM,EAAE,cAAc;SACvB,CAAC;IACJ,CAAC;IAED,yCAAyC;IACzC,MAAM,YAAY,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,kEAAkE;QAClE,IAAI,IAAA,iCAAoB,EAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YAC3C,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,IAAI,IAAI,SAAS;gBACvB,MAAM,EAAE,cAAc;aACvB,CAAC;QACJ,CAAC;QACD,MAAM,WAAW,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAClD,OAAO,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;IAED,2CAA2C;IAC3C,IAAI,YAAY,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,eAAe;SACxB,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,IAAI,IAAA,iCAAoB,EAAC,YAAY,CAAC,EAAE,CAAC;QACvC,IAAI,IAAA,oCAAuB,EAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YAC3C,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,IAAI,EAAE,IAAI,IAAI,SAAS;gBACvB,MAAM,EAAE,iBAAiB;aAC1B,CAAC;QACJ,CAAC;QACD,kCAAkC;QAClC,MAAM,WAAW,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAClD,OAAO,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;IAED,yDAAyD;IACzD,OAAO,iBAAiB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CACxB,SAAiB,EACjB,IAAwB;IAExB,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE;YACL,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,qCAAqC;YAC9C,OAAO,EAAE;gBACP,SAAS;gBACT,QAAQ,EAAE,IAAI,EAAE,SAAS;gBACzB,SAAS,EAAE,IAAI,EAAE,UAAU;aAC5B;SACF;KACF,CAAC;AACJ,CAAC;AAED,yCAAyC;AAEzC;;GAEG;AACH,SAAgB,kBAAkB,CAChC,EAAqB,EACrB,SAAiB,EACjB,QAAgB;IAEhB,MAAM,YAAY,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAEnD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE;gBACL,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAE,qBAAqB;gBAC9B,OAAO,EAAE,EAAE,SAAS,EAAE;aACvB;SACF,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE;gBACL,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,6CAA6C;gBACtD,OAAO,EAAE;oBACP,SAAS;oBACT,QAAQ,EAAE,YAAY,CAAC,SAAS;oBAChC,SAAS,EAAE,YAAY,CAAC,UAAU;iBACnC;aACF;SACF,CAAC;IACJ,CAAC;IAED,IAAA,+BAAuB,EAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACjD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAC1B,EAAqB,EACrB,SAAiB;IAEjB,MAAM,OAAO,GAAG,IAAA,oCAAuB,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAEvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE;gBACL,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAE,qBAAqB;gBAC9B,OAAO,EAAE,EAAE,SAAS,EAAE;aACvB;SACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,yCAAyC;AAEzC;;GAEG;AACH,SAAgB,wBAAwB,CACtC,EAAqB,EACrB,SAAiB,EACjB,QAAgB,EAChB,iBAAyB,+BAA+B;IAExD,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC;QAC1E,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC;QAC1D,MAAM,EAAE,GAAG,EAAE;YACX,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YAC3C,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,IAAA,iCAAoB,EAAC,IAAI,CAAC,CAAC;QACrF,CAAC;KACF,CAAC;AACJ,CAAC;AAED,8CAA8C;AAE9C;;GAEG;AACH,SAAgB,eAAe,CAC7B,EAAqB,EACrB,SAAiB;IAEjB,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,CAAC,IAAA,iCAAoB,EAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAC/B,EAAqB,EACrB,SAAiB,EACjB,QAAgB;IAEhB,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,IAAA,iCAAoB,EAAC,IAAI,CAAC,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAChC,EAAqB,EACrB,SAAiB;IAEjB,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAChC,CAAC;AAED,6CAA6C;AAE7C;;;GAGG;AACH,SAAgB,oBAAoB,CAClC,EAAqB,EACrB,SAAiB;IAEjB,MAAM,IAAI,GAAG,IAAA,2BAAc,EAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,IAAI,IAAA,iCAAoB,EAAC,IAAI,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6CAA6C;AAEhC,QAAA,sBAAsB,GAAG;IACpC,uBAAuB,EAAE,+BAA+B;CAChD,CAAC"}
@@ -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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"}