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.
- package/LICENSE +21 -0
- package/README.md +640 -0
- package/dist/cli/colors.d.ts +110 -0
- package/dist/cli/colors.d.ts.map +1 -0
- package/dist/cli/colors.js +228 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/env.d.ts +159 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +227 -0
- package/dist/cli/env.js.map +1 -0
- package/dist/cli/errors.d.ts +166 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +244 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/flags.d.ts +75 -0
- package/dist/cli/flags.d.ts.map +1 -0
- package/dist/cli/flags.js +232 -0
- package/dist/cli/flags.js.map +1 -0
- package/dist/cli/help.d.ts +97 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +275 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/interactive.d.ts +58 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +127 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/output.d.ts +116 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +178 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/commands/about.d.ts +7 -0
- package/dist/commands/about.d.ts.map +1 -0
- package/dist/commands/about.js +259 -0
- package/dist/commands/about.js.map +1 -0
- package/dist/commands/ai.d.ts +6 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +382 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/backup.d.ts +3 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +528 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/completion.d.ts +3 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +405 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +665 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/disputes.d.ts +3 -0
- package/dist/commands/disputes.d.ts.map +1 -0
- package/dist/commands/disputes.js +499 -0
- package/dist/commands/disputes.js.map +1 -0
- package/dist/commands/gc.d.ts +3 -0
- package/dist/commands/gc.d.ts.map +1 -0
- package/dist/commands/gc.js +300 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/git.d.ts +3 -0
- package/dist/commands/git.d.ts.map +1 -0
- package/dist/commands/git.js +458 -0
- package/dist/commands/git.js.map +1 -0
- package/dist/commands/health.d.ts +3 -0
- package/dist/commands/health.d.ts.map +1 -0
- package/dist/commands/health.js +604 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/hooks.d.ts +6 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +529 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +200 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/llm.d.ts +7 -0
- package/dist/commands/llm.d.ts.map +1 -0
- package/dist/commands/llm.js +285 -0
- package/dist/commands/llm.js.map +1 -0
- package/dist/commands/locks.d.ts +3 -0
- package/dist/commands/locks.d.ts.map +1 -0
- package/dist/commands/locks.js +431 -0
- package/dist/commands/locks.js.map +1 -0
- package/dist/commands/logs.d.ts +3 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +487 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/loop-phases.d.ts +11 -0
- package/dist/commands/loop-phases.d.ts.map +1 -0
- package/dist/commands/loop-phases.js +204 -0
- package/dist/commands/loop-phases.js.map +1 -0
- package/dist/commands/loop.d.ts +3 -0
- package/dist/commands/loop.d.ts.map +1 -0
- package/dist/commands/loop.js +396 -0
- package/dist/commands/loop.js.map +1 -0
- package/dist/commands/projects.d.ts +6 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +362 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/purge.d.ts +3 -0
- package/dist/commands/purge.d.ts.map +1 -0
- package/dist/commands/purge.js +516 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/runners.d.ts +3 -0
- package/dist/commands/runners.d.ts.map +1 -0
- package/dist/commands/runners.js +1076 -0
- package/dist/commands/runners.js.map +1 -0
- package/dist/commands/scan.d.ts +3 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +291 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sections-commands.d.ts +9 -0
- package/dist/commands/sections-commands.d.ts.map +1 -0
- package/dist/commands/sections-commands.js +282 -0
- package/dist/commands/sections-commands.js.map +1 -0
- package/dist/commands/sections-graph.d.ts +25 -0
- package/dist/commands/sections-graph.d.ts.map +1 -0
- package/dist/commands/sections-graph.js +180 -0
- package/dist/commands/sections-graph.js.map +1 -0
- package/dist/commands/sections.d.ts +3 -0
- package/dist/commands/sections.d.ts.map +1 -0
- package/dist/commands/sections.js +376 -0
- package/dist/commands/sections.js.map +1 -0
- package/dist/commands/stats.d.ts +6 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +324 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/tasks.d.ts +3 -0
- package/dist/commands/tasks.d.ts.map +1 -0
- package/dist/commands/tasks.js +1115 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/commands/web.d.ts +7 -0
- package/dist/commands/web.d.ts.map +1 -0
- package/dist/commands/web.js +204 -0
- package/dist/commands/web.js.map +1 -0
- package/dist/config/ai-setup.d.ts +27 -0
- package/dist/config/ai-setup.d.ts.map +1 -0
- package/dist/config/ai-setup.js +432 -0
- package/dist/config/ai-setup.js.map +1 -0
- package/dist/config/browser.d.ts +9 -0
- package/dist/config/browser.d.ts.map +1 -0
- package/dist/config/browser.js +200 -0
- package/dist/config/browser.js.map +1 -0
- package/dist/config/json-schema.d.ts +28 -0
- package/dist/config/json-schema.d.ts.map +1 -0
- package/dist/config/json-schema.js +84 -0
- package/dist/config/json-schema.js.map +1 -0
- package/dist/config/loader.d.ts +152 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +270 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +34 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +437 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/validator.d.ts +32 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +187 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/database/connection.d.ts +35 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +208 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/database/queries.d.ts +218 -0
- package/dist/database/queries.d.ts.map +1 -0
- package/dist/database/queries.js +613 -0
- package/dist/database/queries.js.map +1 -0
- package/dist/database/schema.d.ts +8 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +160 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/disputes/behavior.d.ts +106 -0
- package/dist/disputes/behavior.d.ts.map +1 -0
- package/dist/disputes/behavior.js +150 -0
- package/dist/disputes/behavior.js.map +1 -0
- package/dist/disputes/create.d.ts +59 -0
- package/dist/disputes/create.d.ts.map +1 -0
- package/dist/disputes/create.js +222 -0
- package/dist/disputes/create.js.map +1 -0
- package/dist/disputes/index.d.ts +21 -0
- package/dist/disputes/index.d.ts.map +1 -0
- package/dist/disputes/index.js +76 -0
- package/dist/disputes/index.js.map +1 -0
- package/dist/disputes/markdown.d.ts +41 -0
- package/dist/disputes/markdown.d.ts.map +1 -0
- package/dist/disputes/markdown.js +261 -0
- package/dist/disputes/markdown.js.map +1 -0
- package/dist/disputes/queries.d.ts +83 -0
- package/dist/disputes/queries.d.ts.map +1 -0
- package/dist/disputes/queries.js +180 -0
- package/dist/disputes/queries.js.map +1 -0
- package/dist/disputes/resolve.d.ts +57 -0
- package/dist/disputes/resolve.d.ts.map +1 -0
- package/dist/disputes/resolve.js +171 -0
- package/dist/disputes/resolve.js.map +1 -0
- package/dist/disputes/stale.d.ts +98 -0
- package/dist/disputes/stale.d.ts.map +1 -0
- package/dist/disputes/stale.js +205 -0
- package/dist/disputes/stale.js.map +1 -0
- package/dist/disputes/types.d.ts +92 -0
- package/dist/disputes/types.d.ts.map +1 -0
- package/dist/disputes/types.js +100 -0
- package/dist/disputes/types.js.map +1 -0
- package/dist/git/push.d.ts +26 -0
- package/dist/git/push.d.ts.map +1 -0
- package/dist/git/push.js +97 -0
- package/dist/git/push.js.map +1 -0
- package/dist/git/status.d.ts +61 -0
- package/dist/git/status.d.ts.map +1 -0
- package/dist/git/status.js +251 -0
- package/dist/git/status.js.map +1 -0
- package/dist/hooks/events.d.ts +72 -0
- package/dist/hooks/events.d.ts.map +1 -0
- package/dist/hooks/events.js +120 -0
- package/dist/hooks/events.js.map +1 -0
- package/dist/hooks/index.d.ts +19 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +48 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/integration.d.ts +69 -0
- package/dist/hooks/integration.d.ts.map +1 -0
- package/dist/hooks/integration.js +179 -0
- package/dist/hooks/integration.js.map +1 -0
- package/dist/hooks/merge.d.ts +115 -0
- package/dist/hooks/merge.d.ts.map +1 -0
- package/dist/hooks/merge.js +161 -0
- package/dist/hooks/merge.js.map +1 -0
- package/dist/hooks/orchestrator.d.ts +115 -0
- package/dist/hooks/orchestrator.d.ts.map +1 -0
- package/dist/hooks/orchestrator.js +226 -0
- package/dist/hooks/orchestrator.js.map +1 -0
- package/dist/hooks/payload.d.ts +294 -0
- package/dist/hooks/payload.d.ts.map +1 -0
- package/dist/hooks/payload.js +267 -0
- package/dist/hooks/payload.js.map +1 -0
- package/dist/hooks/script-runner.d.ts +63 -0
- package/dist/hooks/script-runner.d.ts.map +1 -0
- package/dist/hooks/script-runner.js +221 -0
- package/dist/hooks/script-runner.js.map +1 -0
- package/dist/hooks/templates.d.ts +104 -0
- package/dist/hooks/templates.d.ts.map +1 -0
- package/dist/hooks/templates.js +327 -0
- package/dist/hooks/templates.js.map +1 -0
- package/dist/hooks/webhook-runner.d.ts +69 -0
- package/dist/hooks/webhook-runner.d.ts.map +1 -0
- package/dist/hooks/webhook-runner.js +208 -0
- package/dist/hooks/webhook-runner.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +281 -0
- package/dist/index.js.map +1 -0
- package/dist/locking/cleanup.d.ts +70 -0
- package/dist/locking/cleanup.d.ts.map +1 -0
- package/dist/locking/cleanup.js +157 -0
- package/dist/locking/cleanup.js.map +1 -0
- package/dist/locking/queries.d.ts +116 -0
- package/dist/locking/queries.d.ts.map +1 -0
- package/dist/locking/queries.js +255 -0
- package/dist/locking/queries.js.map +1 -0
- package/dist/locking/section-lock.d.ts +74 -0
- package/dist/locking/section-lock.d.ts.map +1 -0
- package/dist/locking/section-lock.js +207 -0
- package/dist/locking/section-lock.js.map +1 -0
- package/dist/locking/task-lock.d.ts +92 -0
- package/dist/locking/task-lock.d.ts.map +1 -0
- package/dist/locking/task-lock.js +246 -0
- package/dist/locking/task-lock.js.map +1 -0
- package/dist/migrations/index.d.ts +7 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +37 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/manifest.d.ts +92 -0
- package/dist/migrations/manifest.d.ts.map +1 -0
- package/dist/migrations/manifest.js +270 -0
- package/dist/migrations/manifest.js.map +1 -0
- package/dist/migrations/runner.d.ts +84 -0
- package/dist/migrations/runner.d.ts.map +1 -0
- package/dist/migrations/runner.js +351 -0
- package/dist/migrations/runner.js.map +1 -0
- package/dist/orchestrator/coder.d.ts +32 -0
- package/dist/orchestrator/coder.d.ts.map +1 -0
- package/dist/orchestrator/coder.js +174 -0
- package/dist/orchestrator/coder.js.map +1 -0
- package/dist/orchestrator/coordinator.d.ts +28 -0
- package/dist/orchestrator/coordinator.d.ts.map +1 -0
- package/dist/orchestrator/coordinator.js +256 -0
- package/dist/orchestrator/coordinator.js.map +1 -0
- package/dist/orchestrator/reviewer.d.ts +35 -0
- package/dist/orchestrator/reviewer.d.ts.map +1 -0
- package/dist/orchestrator/reviewer.js +241 -0
- package/dist/orchestrator/reviewer.js.map +1 -0
- package/dist/orchestrator/task-selector.d.ts +102 -0
- package/dist/orchestrator/task-selector.d.ts.map +1 -0
- package/dist/orchestrator/task-selector.js +341 -0
- package/dist/orchestrator/task-selector.js.map +1 -0
- package/dist/prompts/coder.d.ts +36 -0
- package/dist/prompts/coder.d.ts.map +1 -0
- package/dist/prompts/coder.js +315 -0
- package/dist/prompts/coder.js.map +1 -0
- package/dist/prompts/prompt-helpers.d.ts +51 -0
- package/dist/prompts/prompt-helpers.d.ts.map +1 -0
- package/dist/prompts/prompt-helpers.js +312 -0
- package/dist/prompts/prompt-helpers.js.map +1 -0
- package/dist/prompts/reviewer.d.ts +40 -0
- package/dist/prompts/reviewer.d.ts.map +1 -0
- package/dist/prompts/reviewer.js +438 -0
- package/dist/prompts/reviewer.js.map +1 -0
- package/dist/providers/api-models.d.ts +65 -0
- package/dist/providers/api-models.d.ts.map +1 -0
- package/dist/providers/api-models.js +323 -0
- package/dist/providers/api-models.js.map +1 -0
- package/dist/providers/claude.d.ts +53 -0
- package/dist/providers/claude.d.ts.map +1 -0
- package/dist/providers/claude.js +229 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/codex.d.ts +53 -0
- package/dist/providers/codex.d.ts.map +1 -0
- package/dist/providers/codex.js +214 -0
- package/dist/providers/codex.js.map +1 -0
- package/dist/providers/gemini.d.ts +58 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +242 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +49 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/interface.d.ts +173 -0
- package/dist/providers/interface.d.ts.map +1 -0
- package/dist/providers/interface.js +96 -0
- package/dist/providers/interface.js.map +1 -0
- package/dist/providers/invocation-logger.d.ts +114 -0
- package/dist/providers/invocation-logger.d.ts.map +1 -0
- package/dist/providers/invocation-logger.js +298 -0
- package/dist/providers/invocation-logger.js.map +1 -0
- package/dist/providers/openai.d.ts +53 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +232 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/registry.d.ts +100 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +178 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/runners/activity-log.d.ts +65 -0
- package/dist/runners/activity-log.d.ts.map +1 -0
- package/dist/runners/activity-log.js +148 -0
- package/dist/runners/activity-log.js.map +1 -0
- package/dist/runners/cron.d.ts +26 -0
- package/dist/runners/cron.d.ts.map +1 -0
- package/dist/runners/cron.js +176 -0
- package/dist/runners/cron.js.map +1 -0
- package/dist/runners/daemon.d.ts +71 -0
- package/dist/runners/daemon.d.ts.map +1 -0
- package/dist/runners/daemon.js +245 -0
- package/dist/runners/daemon.js.map +1 -0
- package/dist/runners/global-db.d.ts +31 -0
- package/dist/runners/global-db.d.ts.map +1 -0
- package/dist/runners/global-db.js +230 -0
- package/dist/runners/global-db.js.map +1 -0
- package/dist/runners/hang-detector.d.ts +38 -0
- package/dist/runners/hang-detector.d.ts.map +1 -0
- package/dist/runners/hang-detector.js +136 -0
- package/dist/runners/hang-detector.js.map +1 -0
- package/dist/runners/heartbeat.d.ts +39 -0
- package/dist/runners/heartbeat.d.ts.map +1 -0
- package/dist/runners/heartbeat.js +79 -0
- package/dist/runners/heartbeat.js.map +1 -0
- package/dist/runners/lock.d.ts +47 -0
- package/dist/runners/lock.d.ts.map +1 -0
- package/dist/runners/lock.js +150 -0
- package/dist/runners/lock.js.map +1 -0
- package/dist/runners/orchestrator-loop.d.ts +20 -0
- package/dist/runners/orchestrator-loop.d.ts.map +1 -0
- package/dist/runners/orchestrator-loop.js +285 -0
- package/dist/runners/orchestrator-loop.js.map +1 -0
- package/dist/runners/projects.d.ts +96 -0
- package/dist/runners/projects.d.ts.map +1 -0
- package/dist/runners/projects.js +255 -0
- package/dist/runners/projects.js.map +1 -0
- package/dist/runners/wakeup.d.ts +34 -0
- package/dist/runners/wakeup.d.ts.map +1 -0
- package/dist/runners/wakeup.js +291 -0
- package/dist/runners/wakeup.js.map +1 -0
- package/migrations/001_initial_schema.sql +106 -0
- package/migrations/002_add_commit_sha.sql +12 -0
- package/migrations/003_add_section_priority.sql +13 -0
- package/migrations/004_add_section_dependencies.sql +18 -0
- package/migrations/005_add_audit_actor_model.sql +10 -0
- package/migrations/006_add_task_invocations.sql +33 -0
- package/migrations/007_add_file_anchor.sql +14 -0
- package/migrations/manifest.json +62 -0
- package/package.json +49 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Task locking with atomic operations
|
|
4
|
+
* Prevents multiple runners from working on the same task
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.LOCK_CONSTANTS = void 0;
|
|
8
|
+
exports.acquireTaskLock = acquireTaskLock;
|
|
9
|
+
exports.releaseTaskLock = releaseTaskLock;
|
|
10
|
+
exports.forceRelease = forceRelease;
|
|
11
|
+
exports.heartbeat = heartbeat;
|
|
12
|
+
exports.extend = extend;
|
|
13
|
+
exports.createTaskLockManager = createTaskLockManager;
|
|
14
|
+
exports.createHeartbeatLoop = createHeartbeatLoop;
|
|
15
|
+
exports.isTaskLocked = isTaskLocked;
|
|
16
|
+
exports.isTaskLockedBy = isTaskLockedBy;
|
|
17
|
+
exports.getTimeUntilExpiry = getTimeUntilExpiry;
|
|
18
|
+
const queries_js_1 = require("./queries.js");
|
|
19
|
+
// Default lock timeout in minutes
|
|
20
|
+
const DEFAULT_LOCK_TIMEOUT_MINUTES = 60;
|
|
21
|
+
const HEARTBEAT_INTERVAL_MS = 30 * 1000; // 30 seconds
|
|
22
|
+
// ============ Lock Acquisition ============
|
|
23
|
+
/**
|
|
24
|
+
* Acquire a task lock with atomic operations
|
|
25
|
+
*
|
|
26
|
+
* Flow:
|
|
27
|
+
* 1. Try INSERT (fails if lock exists)
|
|
28
|
+
* 2. If exists, check if we own it
|
|
29
|
+
* 3. If owned by another, check if expired
|
|
30
|
+
* 4. If expired, claim atomically
|
|
31
|
+
* 5. If not expired, return failure
|
|
32
|
+
*/
|
|
33
|
+
function acquireTaskLock(db, taskId, runnerId, timeoutMinutes = DEFAULT_LOCK_TIMEOUT_MINUTES) {
|
|
34
|
+
// Step 1: Try to insert new lock
|
|
35
|
+
if ((0, queries_js_1.tryInsertTaskLock)(db, taskId, runnerId, timeoutMinutes)) {
|
|
36
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
37
|
+
return {
|
|
38
|
+
acquired: true,
|
|
39
|
+
lock: lock ?? undefined,
|
|
40
|
+
reason: 'acquired_new',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Step 2: Lock exists, get current state
|
|
44
|
+
const existingLock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
45
|
+
if (!existingLock) {
|
|
46
|
+
// Race condition: lock was deleted between insert attempt and now
|
|
47
|
+
// Try to acquire again
|
|
48
|
+
if ((0, queries_js_1.tryInsertTaskLock)(db, taskId, runnerId, timeoutMinutes)) {
|
|
49
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
50
|
+
return {
|
|
51
|
+
acquired: true,
|
|
52
|
+
lock: lock ?? undefined,
|
|
53
|
+
reason: 'acquired_new',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Still failed, get the current lock
|
|
57
|
+
const currentLock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
58
|
+
return createLockedError(taskId, currentLock);
|
|
59
|
+
}
|
|
60
|
+
// Step 3: Check if we already own the lock
|
|
61
|
+
if (existingLock.runner_id === runnerId) {
|
|
62
|
+
// Refresh the lock expiry
|
|
63
|
+
(0, queries_js_1.extendTaskLock)(db, taskId, runnerId, timeoutMinutes);
|
|
64
|
+
const updatedLock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
65
|
+
return {
|
|
66
|
+
acquired: true,
|
|
67
|
+
lock: updatedLock ?? undefined,
|
|
68
|
+
reason: 'already_owned',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Step 4: Check if lock is expired
|
|
72
|
+
if ((0, queries_js_1.isTaskLockExpired)(existingLock)) {
|
|
73
|
+
// Try to claim the expired lock atomically
|
|
74
|
+
if ((0, queries_js_1.claimExpiredTaskLock)(db, taskId, runnerId, timeoutMinutes)) {
|
|
75
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
76
|
+
return {
|
|
77
|
+
acquired: true,
|
|
78
|
+
lock: lock ?? undefined,
|
|
79
|
+
reason: 'claimed_expired',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// Another runner claimed it first
|
|
83
|
+
const currentLock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
84
|
+
return createLockedError(taskId, currentLock);
|
|
85
|
+
}
|
|
86
|
+
// Step 5: Lock is held by another runner and not expired
|
|
87
|
+
return createLockedError(taskId, existingLock);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Create a TASK_LOCKED error response
|
|
91
|
+
*/
|
|
92
|
+
function createLockedError(taskId, lock) {
|
|
93
|
+
return {
|
|
94
|
+
acquired: false,
|
|
95
|
+
error: {
|
|
96
|
+
code: 'TASK_LOCKED',
|
|
97
|
+
message: 'Task is locked by another runner',
|
|
98
|
+
details: {
|
|
99
|
+
taskId,
|
|
100
|
+
runnerId: lock?.runner_id,
|
|
101
|
+
expiresAt: lock?.expires_at,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// ============ Lock Release ============
|
|
107
|
+
/**
|
|
108
|
+
* Release a task lock (only by owner)
|
|
109
|
+
*/
|
|
110
|
+
function releaseTaskLock(db, taskId, runnerId) {
|
|
111
|
+
const existingLock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
112
|
+
if (!existingLock) {
|
|
113
|
+
return {
|
|
114
|
+
released: false,
|
|
115
|
+
error: {
|
|
116
|
+
code: 'LOCK_NOT_FOUND',
|
|
117
|
+
message: 'Lock does not exist',
|
|
118
|
+
details: { taskId },
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (existingLock.runner_id !== runnerId) {
|
|
123
|
+
return {
|
|
124
|
+
released: false,
|
|
125
|
+
error: {
|
|
126
|
+
code: 'PERMISSION_DENIED',
|
|
127
|
+
message: 'Cannot release lock owned by another runner',
|
|
128
|
+
details: {
|
|
129
|
+
taskId,
|
|
130
|
+
runnerId: existingLock.runner_id,
|
|
131
|
+
expiresAt: existingLock.expires_at,
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
(0, queries_js_1.releaseTaskLock)(db, taskId, runnerId);
|
|
137
|
+
return { released: true };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Force release a task lock (admin operation, ignores owner)
|
|
141
|
+
*/
|
|
142
|
+
function forceRelease(db, taskId) {
|
|
143
|
+
const existed = (0, queries_js_1.forceReleaseTaskLock)(db, taskId);
|
|
144
|
+
if (!existed) {
|
|
145
|
+
return {
|
|
146
|
+
released: false,
|
|
147
|
+
error: {
|
|
148
|
+
code: 'LOCK_NOT_FOUND',
|
|
149
|
+
message: 'Lock does not exist',
|
|
150
|
+
details: { taskId },
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return { released: true };
|
|
155
|
+
}
|
|
156
|
+
// ============ Lock Heartbeat ============
|
|
157
|
+
/**
|
|
158
|
+
* Update heartbeat for a task lock
|
|
159
|
+
* Should be called periodically while holding the lock
|
|
160
|
+
*/
|
|
161
|
+
function heartbeat(db, taskId, runnerId) {
|
|
162
|
+
return (0, queries_js_1.updateTaskLockHeartbeat)(db, taskId, runnerId);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Extend a task lock's expiry time
|
|
166
|
+
*/
|
|
167
|
+
function extend(db, taskId, runnerId, additionalMinutes = DEFAULT_LOCK_TIMEOUT_MINUTES) {
|
|
168
|
+
return (0, queries_js_1.extendTaskLock)(db, taskId, runnerId, additionalMinutes);
|
|
169
|
+
}
|
|
170
|
+
// ============ Lock Manager ============
|
|
171
|
+
/**
|
|
172
|
+
* Create a task lock manager for a specific task
|
|
173
|
+
* Provides a convenient interface for managing a single lock
|
|
174
|
+
*/
|
|
175
|
+
function createTaskLockManager(db, taskId, runnerId, timeoutMinutes = DEFAULT_LOCK_TIMEOUT_MINUTES) {
|
|
176
|
+
return {
|
|
177
|
+
acquire: () => acquireTaskLock(db, taskId, runnerId, timeoutMinutes),
|
|
178
|
+
release: () => releaseTaskLock(db, taskId, runnerId),
|
|
179
|
+
heartbeat: () => (0, queries_js_1.updateTaskLockHeartbeat)(db, taskId, runnerId),
|
|
180
|
+
extend: (additionalMinutes = timeoutMinutes) => (0, queries_js_1.extendTaskLock)(db, taskId, runnerId, additionalMinutes),
|
|
181
|
+
isHeld: () => {
|
|
182
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
183
|
+
return lock !== null && lock.runner_id === runnerId && !(0, queries_js_1.isTaskLockExpired)(lock);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Create an automatic heartbeat manager that updates
|
|
189
|
+
* the lock heartbeat at regular intervals
|
|
190
|
+
*/
|
|
191
|
+
function createHeartbeatLoop(db, taskId, runnerId, intervalMs = HEARTBEAT_INTERVAL_MS) {
|
|
192
|
+
let intervalId = null;
|
|
193
|
+
const beat = () => {
|
|
194
|
+
(0, queries_js_1.updateTaskLockHeartbeat)(db, taskId, runnerId);
|
|
195
|
+
};
|
|
196
|
+
const start = () => {
|
|
197
|
+
if (intervalId)
|
|
198
|
+
return; // Already running
|
|
199
|
+
beat(); // Immediate first beat
|
|
200
|
+
intervalId = setInterval(beat, intervalMs);
|
|
201
|
+
};
|
|
202
|
+
const stop = () => {
|
|
203
|
+
if (intervalId) {
|
|
204
|
+
clearInterval(intervalId);
|
|
205
|
+
intervalId = null;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
return { start, stop };
|
|
209
|
+
}
|
|
210
|
+
// ============ Lock Status Check ============
|
|
211
|
+
/**
|
|
212
|
+
* Check if a task is locked
|
|
213
|
+
*/
|
|
214
|
+
function isTaskLocked(db, taskId) {
|
|
215
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
216
|
+
if (!lock)
|
|
217
|
+
return false;
|
|
218
|
+
return !(0, queries_js_1.isTaskLockExpired)(lock);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Check if a task is locked by a specific runner
|
|
222
|
+
*/
|
|
223
|
+
function isTaskLockedBy(db, taskId, runnerId) {
|
|
224
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
225
|
+
if (!lock)
|
|
226
|
+
return false;
|
|
227
|
+
return lock.runner_id === runnerId && !(0, queries_js_1.isTaskLockExpired)(lock);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get time until lock expires (in milliseconds)
|
|
231
|
+
* Returns null if not locked, 0 if already expired
|
|
232
|
+
*/
|
|
233
|
+
function getTimeUntilExpiry(db, taskId) {
|
|
234
|
+
const lock = (0, queries_js_1.getTaskLock)(db, taskId);
|
|
235
|
+
if (!lock)
|
|
236
|
+
return null;
|
|
237
|
+
const expiresAt = new Date(lock.expires_at).getTime();
|
|
238
|
+
const remaining = expiresAt - Date.now();
|
|
239
|
+
return Math.max(0, remaining);
|
|
240
|
+
}
|
|
241
|
+
// ============ Constants Export ============
|
|
242
|
+
exports.LOCK_CONSTANTS = {
|
|
243
|
+
DEFAULT_TIMEOUT_MINUTES: DEFAULT_LOCK_TIMEOUT_MINUTES,
|
|
244
|
+
HEARTBEAT_INTERVAL_MS,
|
|
245
|
+
};
|
|
246
|
+
//# 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,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Migration system exports
|
|
4
|
+
* Re-exports all migration-related functionality
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.autoMigrate = exports.getMigrationStatus = exports.rollbackToVersion = exports.runMigrations = exports.rollbackMigration = exports.applyMigration = exports.createBackup = exports.getDatabaseVersion = exports.getAppliedMigrations = exports.readMigrationFile = exports.parseMigrationFile = exports.getCliSupportedVersions = exports.getMigrationById = exports.findOrphanedMigrations = exports.findPendingMigrations = exports.verifyChecksum = exports.calculateChecksum = exports.validateManifest = exports.parseManifest = exports.cacheManifest = exports.readCachedManifest = exports.readBundledManifest = exports.getCachedManifestPath = exports.getMigrationFilePath = exports.getBundledManifestPath = void 0;
|
|
8
|
+
// Manifest management
|
|
9
|
+
var manifest_js_1 = require("./manifest.js");
|
|
10
|
+
Object.defineProperty(exports, "getBundledManifestPath", { enumerable: true, get: function () { return manifest_js_1.getBundledManifestPath; } });
|
|
11
|
+
Object.defineProperty(exports, "getMigrationFilePath", { enumerable: true, get: function () { return manifest_js_1.getMigrationFilePath; } });
|
|
12
|
+
Object.defineProperty(exports, "getCachedManifestPath", { enumerable: true, get: function () { return manifest_js_1.getCachedManifestPath; } });
|
|
13
|
+
Object.defineProperty(exports, "readBundledManifest", { enumerable: true, get: function () { return manifest_js_1.readBundledManifest; } });
|
|
14
|
+
Object.defineProperty(exports, "readCachedManifest", { enumerable: true, get: function () { return manifest_js_1.readCachedManifest; } });
|
|
15
|
+
Object.defineProperty(exports, "cacheManifest", { enumerable: true, get: function () { return manifest_js_1.cacheManifest; } });
|
|
16
|
+
Object.defineProperty(exports, "parseManifest", { enumerable: true, get: function () { return manifest_js_1.parseManifest; } });
|
|
17
|
+
Object.defineProperty(exports, "validateManifest", { enumerable: true, get: function () { return manifest_js_1.validateManifest; } });
|
|
18
|
+
Object.defineProperty(exports, "calculateChecksum", { enumerable: true, get: function () { return manifest_js_1.calculateChecksum; } });
|
|
19
|
+
Object.defineProperty(exports, "verifyChecksum", { enumerable: true, get: function () { return manifest_js_1.verifyChecksum; } });
|
|
20
|
+
Object.defineProperty(exports, "findPendingMigrations", { enumerable: true, get: function () { return manifest_js_1.findPendingMigrations; } });
|
|
21
|
+
Object.defineProperty(exports, "findOrphanedMigrations", { enumerable: true, get: function () { return manifest_js_1.findOrphanedMigrations; } });
|
|
22
|
+
Object.defineProperty(exports, "getMigrationById", { enumerable: true, get: function () { return manifest_js_1.getMigrationById; } });
|
|
23
|
+
Object.defineProperty(exports, "getCliSupportedVersions", { enumerable: true, get: function () { return manifest_js_1.getCliSupportedVersions; } });
|
|
24
|
+
// Migration runner
|
|
25
|
+
var runner_js_1 = require("./runner.js");
|
|
26
|
+
Object.defineProperty(exports, "parseMigrationFile", { enumerable: true, get: function () { return runner_js_1.parseMigrationFile; } });
|
|
27
|
+
Object.defineProperty(exports, "readMigrationFile", { enumerable: true, get: function () { return runner_js_1.readMigrationFile; } });
|
|
28
|
+
Object.defineProperty(exports, "getAppliedMigrations", { enumerable: true, get: function () { return runner_js_1.getAppliedMigrations; } });
|
|
29
|
+
Object.defineProperty(exports, "getDatabaseVersion", { enumerable: true, get: function () { return runner_js_1.getDatabaseVersion; } });
|
|
30
|
+
Object.defineProperty(exports, "createBackup", { enumerable: true, get: function () { return runner_js_1.createBackup; } });
|
|
31
|
+
Object.defineProperty(exports, "applyMigration", { enumerable: true, get: function () { return runner_js_1.applyMigration; } });
|
|
32
|
+
Object.defineProperty(exports, "rollbackMigration", { enumerable: true, get: function () { return runner_js_1.rollbackMigration; } });
|
|
33
|
+
Object.defineProperty(exports, "runMigrations", { enumerable: true, get: function () { return runner_js_1.runMigrations; } });
|
|
34
|
+
Object.defineProperty(exports, "rollbackToVersion", { enumerable: true, get: function () { return runner_js_1.rollbackToVersion; } });
|
|
35
|
+
Object.defineProperty(exports, "getMigrationStatus", { enumerable: true, get: function () { return runner_js_1.getMigrationStatus; } });
|
|
36
|
+
Object.defineProperty(exports, "autoMigrate", { enumerable: true, get: function () { return runner_js_1.autoMigrate; } });
|
|
37
|
+
//# 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,6CAkBuB;AAdrB,qHAAA,sBAAsB,OAAA;AACtB,mHAAA,oBAAoB,OAAA;AACpB,oHAAA,qBAAqB,OAAA;AACrB,kHAAA,mBAAmB,OAAA;AACnB,iHAAA,kBAAkB,OAAA;AAClB,4GAAA,aAAa,OAAA;AACb,4GAAA,aAAa,OAAA;AACb,+GAAA,gBAAgB,OAAA;AAChB,gHAAA,iBAAiB,OAAA;AACjB,6GAAA,cAAc,OAAA;AACd,oHAAA,qBAAqB,OAAA;AACrB,qHAAA,sBAAsB,OAAA;AACtB,+GAAA,gBAAgB,OAAA;AAChB,sHAAA,uBAAuB,OAAA;AAGzB,mBAAmB;AACnB,yCAcqB;AAXnB,+GAAA,kBAAkB,OAAA;AAClB,8GAAA,iBAAiB,OAAA;AACjB,iHAAA,oBAAoB,OAAA;AACpB,+GAAA,kBAAkB,OAAA;AAClB,yGAAA,YAAY,OAAA;AACZ,2GAAA,cAAc,OAAA;AACd,8GAAA,iBAAiB,OAAA;AACjB,0GAAA,aAAa,OAAA;AACb,8GAAA,iBAAiB,OAAA;AACjB,+GAAA,kBAAkB,OAAA;AAClB,wGAAA,WAAW,OAAA"}
|
|
@@ -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;AA6EH;;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"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Migration manifest management
|
|
4
|
+
* Handles reading, parsing, and validating the migration manifest
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getBundledManifestPath = getBundledManifestPath;
|
|
8
|
+
exports.getMigrationFilePath = getMigrationFilePath;
|
|
9
|
+
exports.getCachedManifestPath = getCachedManifestPath;
|
|
10
|
+
exports.readBundledManifest = readBundledManifest;
|
|
11
|
+
exports.readCachedManifest = readCachedManifest;
|
|
12
|
+
exports.cacheManifest = cacheManifest;
|
|
13
|
+
exports.parseManifest = parseManifest;
|
|
14
|
+
exports.validateManifest = validateManifest;
|
|
15
|
+
exports.calculateChecksum = calculateChecksum;
|
|
16
|
+
exports.verifyChecksum = verifyChecksum;
|
|
17
|
+
exports.findPendingMigrations = findPendingMigrations;
|
|
18
|
+
exports.findOrphanedMigrations = findOrphanedMigrations;
|
|
19
|
+
exports.getMigrationById = getMigrationById;
|
|
20
|
+
exports.getCliSupportedVersions = getCliSupportedVersions;
|
|
21
|
+
const node_fs_1 = require("node:fs");
|
|
22
|
+
const node_path_1 = require("node:path");
|
|
23
|
+
const node_crypto_1 = require("node:crypto");
|
|
24
|
+
const node_os_1 = require("node:os");
|
|
25
|
+
// Cache for package root to avoid repeated filesystem operations
|
|
26
|
+
let _packageRoot = null;
|
|
27
|
+
/**
|
|
28
|
+
* Get the CLI package root directory
|
|
29
|
+
* Works whether running from src/ or dist/
|
|
30
|
+
*/
|
|
31
|
+
function getPackageRoot() {
|
|
32
|
+
if (_packageRoot)
|
|
33
|
+
return _packageRoot;
|
|
34
|
+
// Try multiple strategies to find the package root
|
|
35
|
+
const candidates = [];
|
|
36
|
+
// Strategy 1: Check process.argv[1] - this is the executed script path
|
|
37
|
+
if (process.argv[1]) {
|
|
38
|
+
let dir = (0, node_path_1.dirname)(process.argv[1]);
|
|
39
|
+
for (let i = 0; i < 5; i++) {
|
|
40
|
+
candidates.push(dir);
|
|
41
|
+
dir = (0, node_path_1.dirname)(dir);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Strategy 2: Check require.main.filename if available
|
|
45
|
+
if (require.main?.filename) {
|
|
46
|
+
let dir = (0, node_path_1.dirname)(require.main.filename);
|
|
47
|
+
for (let i = 0; i < 5; i++) {
|
|
48
|
+
candidates.push(dir);
|
|
49
|
+
dir = (0, node_path_1.dirname)(dir);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Strategy 3: Check __dirname of this module (works in CommonJS)
|
|
53
|
+
// In compiled output this will be dist/migrations/
|
|
54
|
+
if (typeof __dirname !== 'undefined') {
|
|
55
|
+
let dir = __dirname;
|
|
56
|
+
for (let i = 0; i < 5; i++) {
|
|
57
|
+
candidates.push(dir);
|
|
58
|
+
dir = (0, node_path_1.dirname)(dir);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Find the first candidate that contains package.json with name 'steroids-cli'
|
|
62
|
+
for (const dir of candidates) {
|
|
63
|
+
const pkgPath = (0, node_path_1.join)(dir, 'package.json');
|
|
64
|
+
if ((0, node_fs_1.existsSync)(pkgPath)) {
|
|
65
|
+
try {
|
|
66
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
67
|
+
if (pkg.name === 'steroids-cli') {
|
|
68
|
+
_packageRoot = dir;
|
|
69
|
+
return dir;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch { /* ignore */ }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Last resort: try cwd (useful during development)
|
|
76
|
+
const cwdPkg = (0, node_path_1.join)(process.cwd(), 'package.json');
|
|
77
|
+
if ((0, node_fs_1.existsSync)(cwdPkg)) {
|
|
78
|
+
try {
|
|
79
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(cwdPkg, 'utf-8'));
|
|
80
|
+
if (pkg.name === 'steroids-cli') {
|
|
81
|
+
_packageRoot = process.cwd();
|
|
82
|
+
return process.cwd();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch { /* ignore */ }
|
|
86
|
+
}
|
|
87
|
+
throw new Error('Could not locate steroids-cli package root');
|
|
88
|
+
}
|
|
89
|
+
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
|
|
90
|
+
const GLOBAL_STEROIDS_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), '.steroids');
|
|
91
|
+
const CACHE_DIR = (0, node_path_1.join)(GLOBAL_STEROIDS_DIR, 'migrations');
|
|
92
|
+
const CACHE_FILE = (0, node_path_1.join)(CACHE_DIR, 'manifest-cache.json');
|
|
93
|
+
/**
|
|
94
|
+
* Get the path to the bundled manifest (in the package)
|
|
95
|
+
*/
|
|
96
|
+
function getBundledManifestPath() {
|
|
97
|
+
// Resolve relative to CLI package root, not cwd
|
|
98
|
+
return (0, node_path_1.join)(getPackageRoot(), 'migrations', 'manifest.json');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get the path to a migration file (in the package)
|
|
102
|
+
*/
|
|
103
|
+
function getMigrationFilePath(filename) {
|
|
104
|
+
return (0, node_path_1.join)(getPackageRoot(), 'migrations', filename);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the path to the cached manifest
|
|
108
|
+
*/
|
|
109
|
+
function getCachedManifestPath() {
|
|
110
|
+
return (0, node_path_1.join)(CACHE_DIR, 'manifest.json');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Read the bundled manifest from the package
|
|
114
|
+
*/
|
|
115
|
+
function readBundledManifest() {
|
|
116
|
+
const manifestPath = getBundledManifestPath();
|
|
117
|
+
if (!(0, node_fs_1.existsSync)(manifestPath)) {
|
|
118
|
+
throw new Error(`Bundled manifest not found at: ${manifestPath}`);
|
|
119
|
+
}
|
|
120
|
+
const content = (0, node_fs_1.readFileSync)(manifestPath, 'utf-8');
|
|
121
|
+
return parseManifest(content);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Read the cached manifest if it exists and is valid
|
|
125
|
+
*/
|
|
126
|
+
function readCachedManifest() {
|
|
127
|
+
if (!(0, node_fs_1.existsSync)(CACHE_FILE)) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const cacheContent = (0, node_fs_1.readFileSync)(CACHE_FILE, 'utf-8');
|
|
132
|
+
const cache = JSON.parse(cacheContent);
|
|
133
|
+
// Check if cache is still valid
|
|
134
|
+
if (Date.now() - cache.fetchedAt > CACHE_TTL) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
return cache.manifest;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Save manifest to cache
|
|
145
|
+
*/
|
|
146
|
+
function cacheManifest(manifest) {
|
|
147
|
+
if (!(0, node_fs_1.existsSync)(CACHE_DIR)) {
|
|
148
|
+
(0, node_fs_1.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
149
|
+
}
|
|
150
|
+
const cache = {
|
|
151
|
+
fetchedAt: Date.now(),
|
|
152
|
+
manifest,
|
|
153
|
+
};
|
|
154
|
+
(0, node_fs_1.writeFileSync)(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
155
|
+
// Also save the manifest itself for offline access
|
|
156
|
+
(0, node_fs_1.writeFileSync)(getCachedManifestPath(), JSON.stringify(manifest, null, 2));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Parse and validate manifest content
|
|
160
|
+
*/
|
|
161
|
+
function parseManifest(content) {
|
|
162
|
+
const manifest = JSON.parse(content);
|
|
163
|
+
validateManifest(manifest);
|
|
164
|
+
return manifest;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Validate manifest structure
|
|
168
|
+
*/
|
|
169
|
+
function validateManifest(manifest) {
|
|
170
|
+
if (!manifest.version) {
|
|
171
|
+
throw new Error('Manifest missing version field');
|
|
172
|
+
}
|
|
173
|
+
if (typeof manifest.latestDbVersion !== 'number' || manifest.latestDbVersion < 1) {
|
|
174
|
+
throw new Error('Manifest missing or invalid latestDbVersion field');
|
|
175
|
+
}
|
|
176
|
+
if (!Array.isArray(manifest.migrations)) {
|
|
177
|
+
throw new Error('Manifest missing migrations array');
|
|
178
|
+
}
|
|
179
|
+
// Validate each migration entry
|
|
180
|
+
for (const migration of manifest.migrations) {
|
|
181
|
+
validateMigrationEntry(migration);
|
|
182
|
+
}
|
|
183
|
+
// Validate migrations are in order
|
|
184
|
+
const ids = manifest.migrations.map(m => m.id);
|
|
185
|
+
for (let i = 1; i < ids.length; i++) {
|
|
186
|
+
if (ids[i] <= ids[i - 1]) {
|
|
187
|
+
throw new Error(`Migrations not in order: ${ids[i - 1]} followed by ${ids[i]}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Validate latestDbVersion matches
|
|
191
|
+
if (manifest.migrations.length > 0) {
|
|
192
|
+
const maxId = Math.max(...ids);
|
|
193
|
+
if (maxId !== manifest.latestDbVersion) {
|
|
194
|
+
throw new Error(`latestDbVersion (${manifest.latestDbVersion}) does not match highest migration id (${maxId})`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Validate a single migration entry
|
|
200
|
+
*/
|
|
201
|
+
function validateMigrationEntry(entry) {
|
|
202
|
+
if (typeof entry.id !== 'number' || entry.id < 1) {
|
|
203
|
+
throw new Error(`Invalid migration id: ${entry.id}`);
|
|
204
|
+
}
|
|
205
|
+
if (!entry.name || typeof entry.name !== 'string') {
|
|
206
|
+
throw new Error(`Migration ${entry.id} missing name`);
|
|
207
|
+
}
|
|
208
|
+
if (!entry.file || typeof entry.file !== 'string') {
|
|
209
|
+
throw new Error(`Migration ${entry.id} missing file`);
|
|
210
|
+
}
|
|
211
|
+
if (!entry.description || typeof entry.description !== 'string') {
|
|
212
|
+
throw new Error(`Migration ${entry.id} missing description`);
|
|
213
|
+
}
|
|
214
|
+
if (!entry.cliVersion || typeof entry.cliVersion !== 'string') {
|
|
215
|
+
throw new Error(`Migration ${entry.id} missing cliVersion`);
|
|
216
|
+
}
|
|
217
|
+
// Checksum can be empty for new migrations
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Calculate SHA256 checksum for migration file content
|
|
221
|
+
*/
|
|
222
|
+
function calculateChecksum(content) {
|
|
223
|
+
const hash = (0, node_crypto_1.createHash)('sha256');
|
|
224
|
+
hash.update(content);
|
|
225
|
+
return `sha256:${hash.digest('hex')}`;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Verify checksum matches
|
|
229
|
+
*/
|
|
230
|
+
function verifyChecksum(content, expectedChecksum) {
|
|
231
|
+
if (!expectedChecksum) {
|
|
232
|
+
// No checksum to verify
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
const actual = calculateChecksum(content);
|
|
236
|
+
return actual === expectedChecksum;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Find pending migrations that need to be applied
|
|
240
|
+
*/
|
|
241
|
+
function findPendingMigrations(manifest, appliedMigrations) {
|
|
242
|
+
const appliedIds = new Set(appliedMigrations.map(m => m.id));
|
|
243
|
+
return manifest.migrations.filter(m => !appliedIds.has(m.id));
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Find migrations to rollback (applied but not in manifest)
|
|
247
|
+
*/
|
|
248
|
+
function findOrphanedMigrations(manifest, appliedMigrations) {
|
|
249
|
+
const manifestIds = new Set(manifest.migrations.map(m => m.id));
|
|
250
|
+
return appliedMigrations.filter(m => !manifestIds.has(m.id));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get migration entry by ID
|
|
254
|
+
*/
|
|
255
|
+
function getMigrationById(manifest, id) {
|
|
256
|
+
return manifest.migrations.find(m => m.id === id) ?? null;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get the current supported database version range for this CLI
|
|
260
|
+
*/
|
|
261
|
+
function getCliSupportedVersions(manifest) {
|
|
262
|
+
if (manifest.migrations.length === 0) {
|
|
263
|
+
return { min: 0, max: 0 };
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
min: 1, // Always support from version 1
|
|
267
|
+
max: manifest.latestDbVersion,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=manifest.js.map
|