steroids-cli 0.6.5 → 0.7.0

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 (41) hide show
  1. package/dist/commands/completion.js +5 -1
  2. package/dist/commands/completion.js.map +1 -1
  3. package/dist/commands/health-stuck.d.ts +5 -0
  4. package/dist/commands/health-stuck.d.ts.map +1 -0
  5. package/dist/commands/health-stuck.js +312 -0
  6. package/dist/commands/health-stuck.js.map +1 -0
  7. package/dist/commands/health.d.ts.map +1 -1
  8. package/dist/commands/health.js +14 -1
  9. package/dist/commands/health.js.map +1 -1
  10. package/dist/config/loader.d.ts +8 -0
  11. package/dist/config/loader.d.ts.map +1 -1
  12. package/dist/config/loader.js +14 -0
  13. package/dist/config/loader.js.map +1 -1
  14. package/dist/config/schema.d.ts.map +1 -1
  15. package/dist/config/schema.js +40 -0
  16. package/dist/config/schema.js.map +1 -1
  17. package/dist/database/queries.d.ts +2 -0
  18. package/dist/database/queries.d.ts.map +1 -1
  19. package/dist/database/queries.js.map +1 -1
  20. package/dist/database/schema.d.ts +2 -2
  21. package/dist/database/schema.d.ts.map +1 -1
  22. package/dist/database/schema.js +21 -0
  23. package/dist/database/schema.js.map +1 -1
  24. package/dist/health/stuck-task-detector.d.ts +131 -0
  25. package/dist/health/stuck-task-detector.d.ts.map +1 -0
  26. package/dist/health/stuck-task-detector.js +238 -0
  27. package/dist/health/stuck-task-detector.js.map +1 -0
  28. package/dist/health/stuck-task-recovery.d.ts +45 -0
  29. package/dist/health/stuck-task-recovery.d.ts.map +1 -0
  30. package/dist/health/stuck-task-recovery.js +312 -0
  31. package/dist/health/stuck-task-recovery.js.map +1 -0
  32. package/dist/migrations/manifest.d.ts.map +1 -1
  33. package/dist/migrations/manifest.js +2 -1
  34. package/dist/migrations/manifest.js.map +1 -1
  35. package/dist/runners/wakeup.d.ts +2 -0
  36. package/dist/runners/wakeup.d.ts.map +1 -1
  37. package/dist/runners/wakeup.js +144 -93
  38. package/dist/runners/wakeup.js.map +1 -1
  39. package/migrations/009_add_incidents_and_failure_tracking.sql +35 -0
  40. package/migrations/manifest.json +9 -1
  41. package/package.json +1 -1
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ /**
3
+ * Core stuck-task detection logic (detection only, no recovery).
4
+ *
5
+ * This implementation intentionally uses the project's current schemas:
6
+ * - Project DB: tasks, audit, task_invocations
7
+ * - Global DB: runners
8
+ *
9
+ * The design doc (docs/stuck-task-detection.md) describes additional fields/tables
10
+ * (incidents, invocation started/completed timestamps, last_tool_execution, etc.).
11
+ * Those are not present in the current repo schema, so we derive signals from
12
+ * existing timestamps (tasks.updated_at, task_invocations.created_at, runners.heartbeat_at).
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.parseSqliteDateTimeUtc = parseSqliteDateTimeUtc;
16
+ exports.formatSqliteDateTimeUtc = formatSqliteDateTimeUtc;
17
+ exports.detectStuckTasks = detectStuckTasks;
18
+ const DEFAULTS = {
19
+ orphanedTaskTimeoutSec: 600,
20
+ maxCoderDurationSec: 1800,
21
+ maxReviewerDurationSec: 900,
22
+ runnerHeartbeatTimeoutSec: 300,
23
+ invocationStalenessSec: 600,
24
+ dbInconsistencyRecentUpdateSec: 60,
25
+ };
26
+ function isProcessAliveBestEffort(pid) {
27
+ try {
28
+ // Signal 0: existence check only.
29
+ process.kill(pid, 0);
30
+ return true;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ /**
37
+ * Parse SQLite datetime('now') strings (YYYY-MM-DD HH:MM:SS) as UTC.
38
+ * Node's Date parser can treat "YYYY-MM-DD HH:MM:SS" as local time depending on runtime,
39
+ * so we normalize to ISO 8601 Zulu.
40
+ */
41
+ function parseSqliteDateTimeUtc(value) {
42
+ // Already ISO? (e.g., 2026-02-10T13:45:00.000Z)
43
+ if (value.includes('T'))
44
+ return new Date(value);
45
+ // SQLite "YYYY-MM-DD HH:MM:SS" (UTC) => "YYYY-MM-DDTHH:MM:SSZ"
46
+ return new Date(value.replace(' ', 'T') + 'Z');
47
+ }
48
+ /**
49
+ * Format a Date as SQLite datetime('now')-compatible UTC string: YYYY-MM-DD HH:MM:SS
50
+ * This keeps comparisons lexicographically safe against stored SQLite timestamps.
51
+ */
52
+ function formatSqliteDateTimeUtc(date) {
53
+ // Date#toISOString is always UTC; trim milliseconds and replace T with space.
54
+ return date.toISOString().slice(0, 19).replace('T', ' ');
55
+ }
56
+ function secondsBetween(a, b) {
57
+ return Math.max(0, Math.floor((a.getTime() - b.getTime()) / 1000));
58
+ }
59
+ function mergeConfig(config) {
60
+ return { ...DEFAULTS, ...(config ?? {}) };
61
+ }
62
+ function detectStuckTasks(options) {
63
+ const now = options.now ?? new Date();
64
+ const cfg = mergeConfig(options.config);
65
+ const isPidAlive = options.isPidAlive ?? isProcessAliveBestEffort;
66
+ const zombieRunners = detectZombieRunnersInternal(options.globalDb, options.projectPath, cfg, now, isPidAlive);
67
+ const deadRunners = detectDeadRunnersInternal(options.globalDb, options.projectPath, cfg, now, isPidAlive);
68
+ const { orphanedTasks, hangingInvocations, dbInconsistencies } = detectTaskSignalsInternal(options.projectDb, options.globalDb, options.projectPath, cfg, now, isPidAlive);
69
+ return {
70
+ timestamp: now,
71
+ orphanedTasks,
72
+ hangingInvocations,
73
+ zombieRunners,
74
+ deadRunners,
75
+ dbInconsistencies,
76
+ };
77
+ }
78
+ function detectZombieRunnersInternal(globalDb, projectPath, cfg, now, isPidAlive) {
79
+ const cutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.runnerHeartbeatTimeoutSec * 1000));
80
+ const rows = globalDb.prepare(`SELECT id, status, pid, project_path, current_task_id, heartbeat_at
81
+ FROM runners
82
+ WHERE status = 'running'
83
+ AND project_path = ?
84
+ AND heartbeat_at < ?`).all(projectPath, cutoff);
85
+ const result = [];
86
+ for (const row of rows) {
87
+ if (row.pid !== null && isPidAlive(row.pid)) {
88
+ const hb = parseSqliteDateTimeUtc(row.heartbeat_at);
89
+ result.push({
90
+ failureMode: 'zombie_runner',
91
+ runnerId: row.id,
92
+ pid: row.pid,
93
+ status: row.status,
94
+ projectPath: row.project_path,
95
+ currentTaskId: row.current_task_id,
96
+ heartbeatAt: hb,
97
+ secondsSinceHeartbeat: secondsBetween(now, hb),
98
+ });
99
+ }
100
+ }
101
+ return result;
102
+ }
103
+ function detectDeadRunnersInternal(globalDb, projectPath, cfg, now, isPidAlive) {
104
+ const rows = globalDb.prepare(`SELECT id, status, pid, project_path, current_task_id, heartbeat_at
105
+ FROM runners
106
+ WHERE status = 'running'
107
+ AND project_path = ?`).all(projectPath);
108
+ const result = [];
109
+ for (const row of rows) {
110
+ const alive = row.pid !== null && isPidAlive(row.pid);
111
+ if (!alive) {
112
+ const hb = parseSqliteDateTimeUtc(row.heartbeat_at);
113
+ result.push({
114
+ failureMode: 'dead_runner',
115
+ runnerId: row.id,
116
+ pid: row.pid,
117
+ status: row.status,
118
+ projectPath: row.project_path,
119
+ currentTaskId: row.current_task_id,
120
+ heartbeatAt: hb,
121
+ secondsSinceHeartbeat: secondsBetween(now, hb),
122
+ });
123
+ }
124
+ }
125
+ return result;
126
+ }
127
+ function detectTaskSignalsInternal(projectDb, globalDb, projectPath, cfg, now, isPidAlive) {
128
+ const orphanedTasks = [];
129
+ const hangingInvocations = [];
130
+ const dbInconsistencies = [];
131
+ // DB inconsistency (transient): in_progress, no invocations, very recently updated.
132
+ {
133
+ const cutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.dbInconsistencyRecentUpdateSec * 1000));
134
+ const rows = projectDb.prepare(`SELECT t.id, t.title, t.status, t.updated_at
135
+ FROM tasks t
136
+ LEFT JOIN task_invocations i ON i.task_id = t.id AND i.role = 'coder'
137
+ WHERE t.status = 'in_progress'
138
+ GROUP BY t.id
139
+ HAVING COUNT(i.id) = 0
140
+ AND t.updated_at >= ?`).all(cutoff);
141
+ for (const row of rows) {
142
+ const updatedAt = parseSqliteDateTimeUtc(row.updated_at);
143
+ dbInconsistencies.push({
144
+ failureMode: 'db_inconsistency',
145
+ taskId: row.id,
146
+ title: row.title,
147
+ status: 'in_progress',
148
+ updatedAt,
149
+ secondsSinceUpdate: secondsBetween(now, updatedAt),
150
+ invocationCount: 0,
151
+ });
152
+ }
153
+ }
154
+ // Orphaned tasks: in_progress, stale updated_at, and no recent invocations, and no active runner assigned.
155
+ {
156
+ const taskCutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.orphanedTaskTimeoutSec * 1000));
157
+ const invocationCutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.invocationStalenessSec * 1000));
158
+ const rows = projectDb.prepare(`SELECT
159
+ t.id,
160
+ t.title,
161
+ t.status,
162
+ t.updated_at,
163
+ COUNT(i.id) as invocation_count,
164
+ MAX(i.created_at) as last_invocation_at
165
+ FROM tasks t
166
+ LEFT JOIN task_invocations i ON i.task_id = t.id AND i.role = 'coder'
167
+ WHERE t.status = 'in_progress'
168
+ AND t.updated_at < ?
169
+ GROUP BY t.id
170
+ HAVING COUNT(i.id) = 0
171
+ OR MAX(i.created_at) < ?`).all(taskCutoff, invocationCutoff);
172
+ for (const row of rows) {
173
+ const updatedAt = parseSqliteDateTimeUtc(row.updated_at);
174
+ const lastInvocationAt = row.last_invocation_at ? parseSqliteDateTimeUtc(row.last_invocation_at) : null;
175
+ const activeRunner = getActiveRunnerForTask(globalDb, projectPath, row.id, cfg, now, isPidAlive);
176
+ if (!activeRunner) {
177
+ orphanedTasks.push({
178
+ failureMode: 'orphaned_task',
179
+ taskId: row.id,
180
+ title: row.title,
181
+ status: 'in_progress',
182
+ updatedAt,
183
+ secondsSinceUpdate: secondsBetween(now, updatedAt),
184
+ invocationCount: row.invocation_count,
185
+ lastInvocationAt,
186
+ hasActiveRunner: false,
187
+ });
188
+ }
189
+ }
190
+ }
191
+ // Hanging invocations: in_progress/review for too long with an active runner currently executing the task.
192
+ // Approximates "invocation started but not completed" using task age + runner current_task_id.
193
+ {
194
+ const coderCutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.maxCoderDurationSec * 1000));
195
+ const reviewerCutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.maxReviewerDurationSec * 1000));
196
+ const rows = projectDb.prepare(`SELECT t.id, t.title, t.status, t.updated_at
197
+ FROM tasks t
198
+ WHERE (t.status = 'in_progress' AND t.updated_at < ?)
199
+ OR (t.status = 'review' AND t.updated_at < ?)`).all(coderCutoff, reviewerCutoff);
200
+ for (const row of rows) {
201
+ const activeRunner = getActiveRunnerForTask(globalDb, projectPath, row.id, cfg, now, isPidAlive);
202
+ if (!activeRunner)
203
+ continue;
204
+ const updatedAt = parseSqliteDateTimeUtc(row.updated_at);
205
+ const hbAt = parseSqliteDateTimeUtc(activeRunner.heartbeat_at);
206
+ hangingInvocations.push({
207
+ failureMode: 'hanging_invocation',
208
+ phase: row.status === 'review' ? 'reviewer' : 'coder',
209
+ taskId: row.id,
210
+ title: row.title,
211
+ status: row.status,
212
+ updatedAt,
213
+ secondsSinceUpdate: secondsBetween(now, updatedAt),
214
+ runnerId: activeRunner.id,
215
+ runnerPid: activeRunner.pid,
216
+ runnerHeartbeatAt: hbAt,
217
+ });
218
+ }
219
+ }
220
+ return { orphanedTasks, hangingInvocations, dbInconsistencies };
221
+ }
222
+ function getActiveRunnerForTask(globalDb, projectPath, taskId, cfg, now, isPidAlive) {
223
+ const cutoff = formatSqliteDateTimeUtc(new Date(now.getTime() - cfg.runnerHeartbeatTimeoutSec * 1000));
224
+ const row = globalDb.prepare(`SELECT id, pid, heartbeat_at
225
+ FROM runners
226
+ WHERE project_path = ?
227
+ AND current_task_id = ?
228
+ AND status = 'running'
229
+ AND heartbeat_at >= ?
230
+ ORDER BY heartbeat_at DESC
231
+ LIMIT 1`).get(projectPath, taskId, cutoff);
232
+ if (!row)
233
+ return null;
234
+ if (row.pid !== null && !isPidAlive(row.pid))
235
+ return null;
236
+ return row;
237
+ }
238
+ //# sourceMappingURL=stuck-task-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stuck-task-detector.js","sourceRoot":"","sources":["../../src/health/stuck-task-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Automatic recovery actions for stuck tasks.
3
+ *
4
+ * This builds on detectStuckTasks() and applies a conservative set of actions:
5
+ * - orphaned_task: reset task to pending, release any task lock, increment failure_count, log incident
6
+ * - hanging_invocation: kill runner process, remove runner row, reset task (or skip after repeated failures)
7
+ * - zombie_runner/dead_runner: stop runner (best-effort) and reset its current_task_id (if any)
8
+ *
9
+ * Note: The repo intentionally approximates "invocation started/completed" using tasks.updated_at,
10
+ * task_invocations.created_at, and runners.heartbeat_at. Recovery follows those same signals.
11
+ */
12
+ import type Database from 'better-sqlite3';
13
+ import type { SteroidsConfig } from '../config/loader.js';
14
+ import { type StuckTaskDetectionConfig, type StuckTaskDetectionReport } from './stuck-task-detector.js';
15
+ export interface StuckTaskRecoveryConfig extends StuckTaskDetectionConfig {
16
+ autoRecover?: boolean;
17
+ maxRecoveryAttempts?: number;
18
+ maxIncidentsPerHour?: number;
19
+ killGraceMs?: number;
20
+ }
21
+ export type RecoveryResolution = 'auto_restart' | 'skipped' | 'escalated' | 'none';
22
+ export interface RecoveryAction {
23
+ kind: 'task' | 'runner';
24
+ targetId: string;
25
+ failureMode: string;
26
+ resolution: RecoveryResolution;
27
+ reason: string;
28
+ }
29
+ export interface RecoverStuckTasksOptions {
30
+ projectPath: string;
31
+ projectDb: Database.Database;
32
+ globalDb: Database.Database;
33
+ config?: SteroidsConfig;
34
+ now?: Date;
35
+ dryRun?: boolean;
36
+ isPidAlive?: (pid: number) => boolean;
37
+ killPid?: (pid: number, graceMs: number) => Promise<boolean>;
38
+ }
39
+ export interface RecoverStuckTasksResult {
40
+ report: StuckTaskDetectionReport;
41
+ actions: RecoveryAction[];
42
+ skippedDueToSafetyLimit: boolean;
43
+ }
44
+ export declare function recoverStuckTasks(options: RecoverStuckTasksOptions): Promise<RecoverStuckTasksResult>;
45
+ //# sourceMappingURL=stuck-task-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stuck-task-recovery.d.ts","sourceRoot":"","sources":["../../src/health/stuck-task-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAK9B,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,uBAAwB,SAAQ,wBAAwB;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC5B,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,wBAAwB,CAAC;IACjC,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAuTD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAqD3G"}
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ /**
3
+ * Automatic recovery actions for stuck tasks.
4
+ *
5
+ * This builds on detectStuckTasks() and applies a conservative set of actions:
6
+ * - orphaned_task: reset task to pending, release any task lock, increment failure_count, log incident
7
+ * - hanging_invocation: kill runner process, remove runner row, reset task (or skip after repeated failures)
8
+ * - zombie_runner/dead_runner: stop runner (best-effort) and reset its current_task_id (if any)
9
+ *
10
+ * Note: The repo intentionally approximates "invocation started/completed" using tasks.updated_at,
11
+ * task_invocations.created_at, and runners.heartbeat_at. Recovery follows those same signals.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.recoverStuckTasks = recoverStuckTasks;
15
+ const uuid_1 = require("uuid");
16
+ const queries_js_1 = require("../database/queries.js");
17
+ const queries_js_2 = require("../locking/queries.js");
18
+ const stuck_task_detector_js_1 = require("./stuck-task-detector.js");
19
+ const DEFAULTS = {
20
+ autoRecover: true,
21
+ maxRecoveryAttempts: 3,
22
+ maxIncidentsPerHour: 10,
23
+ killGraceMs: 10_000,
24
+ };
25
+ function delay(ms) {
26
+ return new Promise((resolve) => setTimeout(resolve, ms));
27
+ }
28
+ function isPidAliveBestEffort(pid) {
29
+ try {
30
+ process.kill(pid, 0);
31
+ return true;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ async function killPidBestEffort(pid, graceMs, isAlive) {
38
+ try {
39
+ process.kill(pid, 'SIGTERM');
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ const start = Date.now();
45
+ while (Date.now() - start < graceMs) {
46
+ if (!isAlive(pid))
47
+ return true;
48
+ await delay(250);
49
+ }
50
+ try {
51
+ process.kill(pid, 'SIGKILL');
52
+ }
53
+ catch {
54
+ // ignore
55
+ }
56
+ return !isAlive(pid);
57
+ }
58
+ function readRecoveryConfig(config) {
59
+ const h = config?.health ?? {};
60
+ return {
61
+ orphanedTaskTimeoutSec: h.orphanedTaskTimeout ?? 600,
62
+ maxCoderDurationSec: h.maxCoderDuration ?? 1800,
63
+ maxReviewerDurationSec: h.maxReviewerDuration ?? 900,
64
+ runnerHeartbeatTimeoutSec: h.runnerHeartbeatTimeout ?? 300,
65
+ invocationStalenessSec: h.invocationStaleness ?? 600,
66
+ dbInconsistencyRecentUpdateSec: 60,
67
+ autoRecover: h.autoRecover ?? DEFAULTS.autoRecover,
68
+ maxRecoveryAttempts: h.maxRecoveryAttempts ?? DEFAULTS.maxRecoveryAttempts,
69
+ maxIncidentsPerHour: h.maxIncidentsPerHour ?? DEFAULTS.maxIncidentsPerHour,
70
+ killGraceMs: DEFAULTS.killGraceMs,
71
+ };
72
+ }
73
+ function incidentsInLastHour(projectDb) {
74
+ try {
75
+ const row = projectDb
76
+ .prepare(`SELECT COUNT(*) as count FROM incidents WHERE detected_at >= datetime('now', '-1 hour')`)
77
+ .get();
78
+ return row?.count ?? 0;
79
+ }
80
+ catch {
81
+ return 0;
82
+ }
83
+ }
84
+ function insertIncident(projectDb, args) {
85
+ try {
86
+ const id = (0, uuid_1.v4)();
87
+ const details = args.details === undefined ? null : JSON.stringify(args.details);
88
+ projectDb
89
+ .prepare(`INSERT INTO incidents (id, task_id, runner_id, failure_mode, detected_at, resolved_at, resolution, details)
90
+ VALUES (?, ?, ?, ?, datetime('now'), datetime('now'), ?, ?)`)
91
+ .run(id, args.taskId ?? null, args.runnerId ?? null, args.failureMode, args.resolution, details);
92
+ }
93
+ catch {
94
+ // Best-effort: incidents table may not exist if migrations are disabled.
95
+ }
96
+ }
97
+ function getFailureCount(projectDb, taskId) {
98
+ try {
99
+ const row = projectDb.prepare('SELECT failure_count as c FROM tasks WHERE id = ?').get(taskId);
100
+ return row?.c ?? 0;
101
+ }
102
+ catch {
103
+ return 0;
104
+ }
105
+ }
106
+ function bumpFailureCount(projectDb, taskId) {
107
+ try {
108
+ projectDb
109
+ .prepare(`UPDATE tasks
110
+ SET failure_count = COALESCE(failure_count, 0) + 1,
111
+ last_failure_at = datetime('now')
112
+ WHERE id = ?`)
113
+ .run(taskId);
114
+ }
115
+ catch {
116
+ // ignore
117
+ }
118
+ }
119
+ function deleteRunnerRow(globalDb, runnerId) {
120
+ try {
121
+ globalDb.prepare('DELETE FROM runners WHERE id = ?').run(runnerId);
122
+ }
123
+ catch {
124
+ // ignore
125
+ }
126
+ }
127
+ function recoverOrphanedTask(projectDb, signal, cfg, dryRun) {
128
+ const currentFailures = getFailureCount(projectDb, signal.taskId);
129
+ const nextFailures = currentFailures + 1;
130
+ const shouldEscalate = nextFailures >= cfg.maxRecoveryAttempts;
131
+ const resolution = shouldEscalate ? 'skipped' : 'auto_restart';
132
+ const newStatus = shouldEscalate ? 'skipped' : 'pending';
133
+ if (!dryRun) {
134
+ const tx = projectDb.transaction(() => {
135
+ (0, queries_js_2.forceReleaseTaskLock)(projectDb, signal.taskId);
136
+ (0, queries_js_1.updateTaskStatus)(projectDb, signal.taskId, newStatus, 'system:stuck-task-recovery', shouldEscalate
137
+ ? `Auto-recovery escalated after ${nextFailures} failure(s): orphaned task`
138
+ : `Auto-recovery: orphaned task reset to pending`);
139
+ bumpFailureCount(projectDb, signal.taskId);
140
+ insertIncident(projectDb, {
141
+ taskId: signal.taskId,
142
+ failureMode: 'orphaned_task',
143
+ resolution,
144
+ details: {
145
+ secondsSinceUpdate: signal.secondsSinceUpdate,
146
+ invocationCount: signal.invocationCount,
147
+ lastInvocationAt: signal.lastInvocationAt?.toISOString() ?? null,
148
+ },
149
+ });
150
+ });
151
+ tx();
152
+ }
153
+ return {
154
+ kind: 'task',
155
+ targetId: signal.taskId,
156
+ failureMode: 'orphaned_task',
157
+ resolution,
158
+ reason: shouldEscalate
159
+ ? `orphaned task escalated (failure_count ${nextFailures})`
160
+ : `orphaned task reset to pending (failure_count ${nextFailures})`,
161
+ };
162
+ }
163
+ async function recoverHangingInvocation(projectDb, globalDb, signal, cfg, dryRun, killPid) {
164
+ const currentFailures = getFailureCount(projectDb, signal.taskId);
165
+ const nextFailures = currentFailures + 1;
166
+ const shouldEscalate = nextFailures >= cfg.maxRecoveryAttempts;
167
+ const resolution = shouldEscalate ? 'skipped' : 'auto_restart';
168
+ const newStatus = shouldEscalate ? 'skipped' : 'pending';
169
+ if (!dryRun) {
170
+ // Stop the runner first (best-effort), then reset the task.
171
+ if (signal.runnerPid !== null) {
172
+ await killPid(signal.runnerPid, cfg.killGraceMs ?? DEFAULTS.killGraceMs);
173
+ }
174
+ deleteRunnerRow(globalDb, signal.runnerId);
175
+ const tx = projectDb.transaction(() => {
176
+ (0, queries_js_2.forceReleaseTaskLock)(projectDb, signal.taskId);
177
+ (0, queries_js_1.updateTaskStatus)(projectDb, signal.taskId, newStatus, 'system:stuck-task-recovery', shouldEscalate
178
+ ? `Auto-recovery escalated after ${nextFailures} failure(s): hanging ${signal.phase}`
179
+ : `Auto-recovery: killed hanging ${signal.phase}, reset to pending`);
180
+ bumpFailureCount(projectDb, signal.taskId);
181
+ insertIncident(projectDb, {
182
+ taskId: signal.taskId,
183
+ runnerId: signal.runnerId,
184
+ failureMode: 'hanging_invocation',
185
+ resolution,
186
+ details: {
187
+ phase: signal.phase,
188
+ secondsSinceUpdate: signal.secondsSinceUpdate,
189
+ runnerPid: signal.runnerPid,
190
+ runnerHeartbeatAt: signal.runnerHeartbeatAt.toISOString(),
191
+ },
192
+ });
193
+ });
194
+ tx();
195
+ }
196
+ return {
197
+ kind: 'task',
198
+ targetId: signal.taskId,
199
+ failureMode: 'hanging_invocation',
200
+ resolution,
201
+ reason: shouldEscalate
202
+ ? `hanging ${signal.phase} escalated (failure_count ${nextFailures})`
203
+ : `killed hanging ${signal.phase}, reset to pending (failure_count ${nextFailures})`,
204
+ };
205
+ }
206
+ async function recoverZombieOrDeadRunner(projectDb, globalDb, signal, dryRun, killPid) {
207
+ if (!dryRun) {
208
+ if (signal.failureMode === 'zombie_runner' && signal.pid !== null) {
209
+ await killPid(signal.pid, DEFAULTS.killGraceMs);
210
+ }
211
+ // Reset the runner's current task (if any) so the project can continue.
212
+ if (signal.currentTaskId) {
213
+ const taskExists = (() => {
214
+ try {
215
+ const row = projectDb.prepare('SELECT 1 FROM tasks WHERE id = ?').get(signal.currentTaskId);
216
+ return row !== undefined;
217
+ }
218
+ catch {
219
+ return false;
220
+ }
221
+ })();
222
+ const tx = projectDb.transaction(() => {
223
+ (0, queries_js_2.forceReleaseTaskLock)(projectDb, signal.currentTaskId);
224
+ if (taskExists) {
225
+ (0, queries_js_1.updateTaskStatus)(projectDb, signal.currentTaskId, 'pending', 'system:stuck-task-recovery', `Auto-recovery: ${signal.failureMode} cleared runner and reset task to pending`);
226
+ bumpFailureCount(projectDb, signal.currentTaskId);
227
+ }
228
+ insertIncident(projectDb, {
229
+ taskId: signal.currentTaskId,
230
+ runnerId: signal.runnerId,
231
+ failureMode: signal.failureMode,
232
+ resolution: 'auto_restart',
233
+ details: {
234
+ runnerPid: signal.pid,
235
+ secondsSinceHeartbeat: signal.secondsSinceHeartbeat,
236
+ taskExists,
237
+ },
238
+ });
239
+ });
240
+ tx();
241
+ }
242
+ else {
243
+ insertIncident(projectDb, {
244
+ runnerId: signal.runnerId,
245
+ failureMode: signal.failureMode,
246
+ resolution: 'auto_restart',
247
+ details: {
248
+ runnerPid: signal.pid,
249
+ secondsSinceHeartbeat: signal.secondsSinceHeartbeat,
250
+ },
251
+ });
252
+ }
253
+ deleteRunnerRow(globalDb, signal.runnerId);
254
+ }
255
+ return {
256
+ kind: 'runner',
257
+ targetId: signal.runnerId,
258
+ failureMode: signal.failureMode,
259
+ resolution: 'auto_restart',
260
+ reason: `${signal.failureMode} runner removed`,
261
+ };
262
+ }
263
+ async function recoverStuckTasks(options) {
264
+ const cfg = readRecoveryConfig(options.config);
265
+ const now = options.now ?? new Date();
266
+ const dryRun = options.dryRun ?? false;
267
+ const isPidAlive = options.isPidAlive ?? isPidAliveBestEffort;
268
+ const killPid = options.killPid ??
269
+ ((pid, graceMs) => killPidBestEffort(pid, graceMs, isPidAlive));
270
+ const report = (0, stuck_task_detector_js_1.detectStuckTasks)({
271
+ projectPath: options.projectPath,
272
+ projectDb: options.projectDb,
273
+ globalDb: options.globalDb,
274
+ now,
275
+ isPidAlive,
276
+ config: cfg,
277
+ });
278
+ const actions = [];
279
+ const handledTaskIds = new Set();
280
+ // Safety limit: too many incidents per hour => stop auto-recovery.
281
+ const recentIncidents = incidentsInLastHour(options.projectDb);
282
+ if ((cfg.maxIncidentsPerHour ?? DEFAULTS.maxIncidentsPerHour) > 0 && recentIncidents >= (cfg.maxIncidentsPerHour ?? DEFAULTS.maxIncidentsPerHour)) {
283
+ return { report, actions, skippedDueToSafetyLimit: true };
284
+ }
285
+ if (!cfg.autoRecover) {
286
+ return { report, actions, skippedDueToSafetyLimit: false };
287
+ }
288
+ // Runner-level recovery first, to avoid repeatedly detecting "hanging" with a zombie/dead runner.
289
+ for (const r of report.zombieRunners) {
290
+ actions.push(await recoverZombieOrDeadRunner(options.projectDb, options.globalDb, r, dryRun, killPid));
291
+ if (r.currentTaskId)
292
+ handledTaskIds.add(r.currentTaskId);
293
+ }
294
+ for (const r of report.deadRunners) {
295
+ actions.push(await recoverZombieOrDeadRunner(options.projectDb, options.globalDb, r, dryRun, killPid));
296
+ if (r.currentTaskId)
297
+ handledTaskIds.add(r.currentTaskId);
298
+ }
299
+ // Task-level recovery.
300
+ for (const t of report.orphanedTasks) {
301
+ if (handledTaskIds.has(t.taskId))
302
+ continue;
303
+ actions.push(recoverOrphanedTask(options.projectDb, t, cfg, dryRun));
304
+ }
305
+ for (const h of report.hangingInvocations) {
306
+ if (handledTaskIds.has(h.taskId))
307
+ continue;
308
+ actions.push(await recoverHangingInvocation(options.projectDb, options.globalDb, h, cfg, dryRun, killPid));
309
+ }
310
+ return { report, actions, skippedDueToSafetyLimit: false };
311
+ }
312
+ //# sourceMappingURL=stuck-task-recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stuck-task-recovery.js","sourceRoot":"","sources":["../../src/health/stuck-task-recovery.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAwWH,8CAqDC;AA1ZD,+BAAoC;AAEpC,uDAA0D;AAC1D,sDAA6D;AAC7D,qEAQkC;AAoClC,MAAM,QAAQ,GAA2H;IACvI,WAAW,EAAE,IAAI;IACjB,mBAAmB,EAAE,CAAC;IACtB,mBAAmB,EAAE,EAAE;IACvB,WAAW,EAAE,MAAM;CACpB,CAAC;AAEF,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAW;IACvC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,OAAe,EAAE,OAAiC;IAC9F,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAuB;IACjD,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC;IAC/B,OAAO;QACL,sBAAsB,EAAE,CAAC,CAAC,mBAAmB,IAAI,GAAG;QACpD,mBAAmB,EAAE,CAAC,CAAC,gBAAgB,IAAI,IAAI;QAC/C,sBAAsB,EAAE,CAAC,CAAC,mBAAmB,IAAI,GAAG;QACpD,yBAAyB,EAAE,CAAC,CAAC,sBAAsB,IAAI,GAAG;QAC1D,sBAAsB,EAAE,CAAC,CAAC,mBAAmB,IAAI,GAAG;QACpD,8BAA8B,EAAE,EAAE;QAClC,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW;QAClD,mBAAmB,EAAE,CAAC,CAAC,mBAAmB,IAAI,QAAQ,CAAC,mBAAmB;QAC1E,mBAAmB,EAAE,CAAC,CAAC,mBAAmB,IAAI,QAAQ,CAAC,mBAAmB;QAC1E,WAAW,EAAE,QAAQ,CAAC,WAAW;KAClC,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,SAA4B;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS;aAClB,OAAO,CAAC,yFAAyF,CAAC;aAClG,GAAG,EAAmC,CAAC;QAC1C,OAAO,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CACrB,SAA4B,EAC5B,IAMC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,IAAA,SAAM,GAAE,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjF,SAAS;aACN,OAAO,CACN;qEAC6D,CAC9D;aACA,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACrG,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,SAA4B,EAAE,MAAc;IACnE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,CAAC,MAAM,CAA8B,CAAC;QAC5H,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,SAA4B,EAAE,MAAc;IACpE,IAAI,CAAC;QACH,SAAS;aACN,OAAO,CACN;;;sBAGc,CACf;aACA,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,QAA2B,EAAE,QAAgB;IACpE,IAAI,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAC1B,SAA4B,EAC5B,MAA0B,EAC1B,GAAsC,EACtC,MAAe;IAEf,MAAM,eAAe,GAAG,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,eAAe,GAAG,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,YAAY,IAAI,GAAG,CAAC,mBAAmB,CAAC;IAE/D,MAAM,UAAU,GAAuB,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC;IACnF,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE;YACpC,IAAA,iCAAoB,EAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAA,6BAAgB,EACd,SAAS,EACT,MAAM,CAAC,MAAM,EACb,SAAS,EACT,4BAA4B,EAC5B,cAAc;gBACZ,CAAC,CAAC,iCAAiC,YAAY,4BAA4B;gBAC3E,CAAC,CAAC,+CAA+C,CACpD,CAAC;YACF,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3C,cAAc,CAAC,SAAS,EAAE;gBACxB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,WAAW,EAAE,eAAe;gBAC5B,UAAU;gBACV,OAAO,EAAE;oBACP,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;oBAC7C,eAAe,EAAE,MAAM,CAAC,eAAe;oBACvC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,WAAW,EAAE,IAAI,IAAI;iBACjE;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,EAAE,EAAE,CAAC;IACP,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,MAAM,CAAC,MAAM;QACvB,WAAW,EAAE,eAAe;QAC5B,UAAU;QACV,MAAM,EAAE,cAAc;YACpB,CAAC,CAAC,0CAA0C,YAAY,GAAG;YAC3D,CAAC,CAAC,iDAAiD,YAAY,GAAG;KACrE,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,SAA4B,EAC5B,QAA2B,EAC3B,MAAyB,EACzB,GAAsC,EACtC,MAAe,EACf,OAA2D;IAE3D,MAAM,eAAe,GAAG,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,eAAe,GAAG,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,YAAY,IAAI,GAAG,CAAC,mBAAmB,CAAC;IAE/D,MAAM,UAAU,GAAuB,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC;IACnF,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,4DAA4D;QAC5D,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC9B,MAAM,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC3E,CAAC;QACD,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAE3C,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE;YACpC,IAAA,iCAAoB,EAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAA,6BAAgB,EACd,SAAS,EACT,MAAM,CAAC,MAAM,EACb,SAAS,EACT,4BAA4B,EAC5B,cAAc;gBACZ,CAAC,CAAC,iCAAiC,YAAY,wBAAwB,MAAM,CAAC,KAAK,EAAE;gBACrF,CAAC,CAAC,iCAAiC,MAAM,CAAC,KAAK,oBAAoB,CACtE,CAAC;YACF,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3C,cAAc,CAAC,SAAS,EAAE;gBACxB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,WAAW,EAAE,oBAAoB;gBACjC,UAAU;gBACV,OAAO,EAAE;oBACP,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;oBAC7C,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,CAAC,WAAW,EAAE;iBAC1D;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,EAAE,EAAE,CAAC;IACP,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,MAAM,CAAC,MAAM;QACvB,WAAW,EAAE,oBAAoB;QACjC,UAAU;QACV,MAAM,EAAE,cAAc;YACpB,CAAC,CAAC,WAAW,MAAM,CAAC,KAAK,6BAA6B,YAAY,GAAG;YACrE,CAAC,CAAC,kBAAkB,MAAM,CAAC,KAAK,qCAAqC,YAAY,GAAG;KACvF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,yBAAyB,CACtC,SAA4B,EAC5B,QAA2B,EAC3B,MAA6C,EAC7C,MAAe,EACf,OAA2D;IAE3D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,MAAM,CAAC,WAAW,KAAK,eAAe,IAAI,MAAM,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;YAClE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;QAClD,CAAC;QAED,wEAAwE;QACxE,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE;gBACvB,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAA8B,CAAC;oBACzH,OAAO,GAAG,KAAK,SAAS,CAAC;gBAC3B,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;YAEL,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE;gBACpC,IAAA,iCAAoB,EAAC,SAAS,EAAE,MAAM,CAAC,aAAuB,CAAC,CAAC;gBAChE,IAAI,UAAU,EAAE,CAAC;oBACf,IAAA,6BAAgB,EACd,SAAS,EACT,MAAM,CAAC,aAAuB,EAC9B,SAAS,EACT,4BAA4B,EAC5B,kBAAkB,MAAM,CAAC,WAAW,2CAA2C,CAChF,CAAC;oBACF,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,aAAuB,CAAC,CAAC;gBAC9D,CAAC;gBACD,cAAc,CAAC,SAAS,EAAE;oBACxB,MAAM,EAAE,MAAM,CAAC,aAAuB;oBACtC,QAAQ,EAAE,MAAM,CAAC,QAAQ;oBACzB,WAAW,EAAE,MAAM,CAAC,WAAW;oBAC/B,UAAU,EAAE,cAAc;oBAC1B,OAAO,EAAE;wBACP,SAAS,EAAE,MAAM,CAAC,GAAG;wBACrB,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;wBACnD,UAAU;qBACX;iBACF,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YACH,EAAE,EAAE,CAAC;QACP,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,SAAS,EAAE;gBACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,UAAU,EAAE,cAAc;gBAC1B,OAAO,EAAE;oBACP,SAAS,EAAE,MAAM,CAAC,GAAG;oBACrB,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;iBACpD;aACF,CAAC,CAAC;QACL,CAAC;QAED,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,cAAc;QAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,iBAAiB;KAC/C,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IAEvC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,oBAAoB,CAAC;IAC9D,MAAM,OAAO,GACX,OAAO,CAAC,OAAO;QACf,CAAC,CAAC,GAAW,EAAE,OAAe,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IAElF,MAAM,MAAM,GAAG,IAAA,yCAAgB,EAAC;QAC9B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG;QACH,UAAU;QACV,MAAM,EAAE,GAAG;KACZ,CAAC,CAAC;IAEH,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IAEzC,mEAAmE;IACnE,MAAM,eAAe,GAAG,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/D,IAAI,CAAC,GAAG,CAAC,mBAAmB,IAAI,QAAQ,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,eAAe,IAAI,CAAC,GAAG,CAAC,mBAAmB,IAAI,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAClJ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC;IAC7D,CAAC;IAED,kGAAkG;IAClG,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,MAAM,yBAAyB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QACvG,IAAI,CAAC,CAAC,aAAa;YAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAC3D,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,MAAM,yBAAyB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QACvG,IAAI,CAAC,CAAC,aAAa;YAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED,uBAAuB;IACvB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACrC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,SAAS;QAC3C,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC1C,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,SAAS;QAC3C,OAAO,CAAC,IAAI,CAAC,MAAM,wBAAwB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7G,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC;AAC7D,CAAC"}
@@ -1 +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"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/migrations/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA8EH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,iBAAiB,CASvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,iBAAiB,GAAG,IAAI,CAkB7D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAc/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAIhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAmClE;AA6BD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAQjF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,iBAAiB,EAC3B,iBAAiB,EAAE,gBAAgB,EAAE,GACpC,cAAc,EAAE,CAGlB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,EAC3B,iBAAiB,EAAE,gBAAgB,EAAE,GACpC,gBAAgB,EAAE,CAGpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE/F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CASjG"}
@@ -42,7 +42,8 @@ function getPackageRoot() {
42
42
  }
43
43
  }
44
44
  // Strategy 2: Check require.main.filename if available
45
- if (require.main?.filename) {
45
+ // In ESM, `require` is not defined, so guard with typeof.
46
+ if (typeof require !== 'undefined' && require.main?.filename) {
46
47
  let dir = (0, node_path_1.dirname)(require.main.filename);
47
48
  for (let i = 0; i < 5; i++) {
48
49
  candidates.push(dir);