substrate-ai 0.7.0 → 0.8.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.
- package/dist/cli/index.js +21 -8
- package/dist/{health-Dnx-FGva.js → health-C-VRJruD.js} +502 -23
- package/dist/{health-4fyhDU6T.js → health-DMbNP9bw.js} +1 -1
- package/dist/index.d.ts +24 -0
- package/dist/{run-BdqqWU9p.js → run-B40PykZL.js} +2 -2
- package/dist/{run-CfF0-tVP.js → run-ohzPz3r1.js} +550 -189
- package/package.json +1 -2
- package/packs/bmad/prompts/dev-story.md +1 -0
|
@@ -158,6 +158,17 @@ var DoltDatabaseAdapter = class {
|
|
|
158
158
|
//#region src/persistence/memory-adapter.ts
|
|
159
159
|
var InMemoryDatabaseAdapter = class {
|
|
160
160
|
_tables = new Map();
|
|
161
|
+
_indexes = [];
|
|
162
|
+
/** Maps table name → auto-increment column name */
|
|
163
|
+
_autoIncrementCols = new Map();
|
|
164
|
+
/** Maps table name → last assigned auto-increment value */
|
|
165
|
+
_autoIncrementCounters = new Map();
|
|
166
|
+
/** Maps "tableName.colName" → default value expression ('CURRENT_TIMESTAMP' → ISO string, else literal) */
|
|
167
|
+
_columnDefaults = new Map();
|
|
168
|
+
/** Maps table name → array of primary key column names */
|
|
169
|
+
_primaryKeys = new Map();
|
|
170
|
+
/** Maps table name → ordered list of column names (from CREATE TABLE) */
|
|
171
|
+
_tableColumns = new Map();
|
|
161
172
|
async query(sql, params) {
|
|
162
173
|
const rows = this._execute(sql.trim(), params);
|
|
163
174
|
return rows;
|
|
@@ -165,14 +176,23 @@ var InMemoryDatabaseAdapter = class {
|
|
|
165
176
|
async exec(sql) {
|
|
166
177
|
this._execute(sql.trim(), void 0);
|
|
167
178
|
}
|
|
179
|
+
querySync(sql, params) {
|
|
180
|
+
const rows = this._execute(sql.trim(), params);
|
|
181
|
+
return rows;
|
|
182
|
+
}
|
|
183
|
+
execSync(sql) {
|
|
184
|
+
this._execute(sql.trim(), void 0);
|
|
185
|
+
}
|
|
168
186
|
async transaction(fn) {
|
|
169
187
|
const snapshot = new Map();
|
|
170
188
|
for (const [name, rows] of this._tables) snapshot.set(name, rows.map((r) => ({ ...r })));
|
|
189
|
+
const counterSnapshot = new Map(this._autoIncrementCounters);
|
|
171
190
|
try {
|
|
172
191
|
const result = await fn(this);
|
|
173
192
|
return result;
|
|
174
193
|
} catch (err) {
|
|
175
194
|
this._tables = snapshot;
|
|
195
|
+
this._autoIncrementCounters = counterSnapshot;
|
|
176
196
|
throw err;
|
|
177
197
|
}
|
|
178
198
|
}
|
|
@@ -191,11 +211,14 @@ var InMemoryDatabaseAdapter = class {
|
|
|
191
211
|
const upper = resolved.trimStart().toUpperCase();
|
|
192
212
|
if (/^CREATE\s+TABLE/i.test(upper)) return this._createTable(resolved);
|
|
193
213
|
if (/^DROP\s+TABLE/i.test(upper)) return this._dropTable(resolved);
|
|
214
|
+
if (/^CREATE\s+(?:UNIQUE\s+)?INDEX/i.test(upper)) return this._createIndex(resolved);
|
|
215
|
+
if (/^DROP\s+INDEX/i.test(upper)) return this._dropIndex(resolved);
|
|
194
216
|
if (/^CREATE\s+(?:OR\s+REPLACE\s+)?VIEW/i.test(upper)) return [];
|
|
195
217
|
if (/^INSERT\s+(?:IGNORE\s+)?INTO/i.test(upper)) return this._insert(resolved, /^INSERT\s+IGNORE\s+INTO/i.test(upper));
|
|
196
218
|
if (/^SELECT/i.test(upper)) return this._select(resolved);
|
|
197
219
|
if (/^UPDATE/i.test(upper)) return this._update(resolved);
|
|
198
220
|
if (/^DELETE\s+FROM/i.test(upper)) return this._delete(resolved);
|
|
221
|
+
if (/^PRAGMA\s+table_info\s*\(/i.test(upper)) return this._pragmaTableInfo(resolved);
|
|
199
222
|
return [];
|
|
200
223
|
}
|
|
201
224
|
/**
|
|
@@ -217,6 +240,50 @@ var InMemoryDatabaseAdapter = class {
|
|
|
217
240
|
if (m) {
|
|
218
241
|
const name = m[1];
|
|
219
242
|
if (!this._tables.has(name)) this._tables.set(name, []);
|
|
243
|
+
const colDefsM = /\((.+)\)\s*$/is.exec(sql);
|
|
244
|
+
if (colDefsM) {
|
|
245
|
+
const colDefs = colDefsM[1];
|
|
246
|
+
const aiMatch = /^\s*(\w+)\s+\w+.*?(?:AUTO_INCREMENT|AUTOINCREMENT)/im.exec(colDefs);
|
|
247
|
+
if (aiMatch) {
|
|
248
|
+
this._autoIncrementCols.set(name, aiMatch[1]);
|
|
249
|
+
if (!this._autoIncrementCounters.has(name)) this._autoIncrementCounters.set(name, 0);
|
|
250
|
+
}
|
|
251
|
+
const colLines = this._splitTopLevelCommas(colDefs);
|
|
252
|
+
const pkCols = [];
|
|
253
|
+
for (const colLine of colLines) {
|
|
254
|
+
const trimmedLine = colLine.trim();
|
|
255
|
+
const tablePkM = /^PRIMARY\s+KEY\s*\(([^)]+)\)/i.exec(trimmedLine);
|
|
256
|
+
if (tablePkM) {
|
|
257
|
+
const cols = tablePkM[1].split(",").map((c) => c.trim().replace(/^[`"](.+)[`"]$/, "$1"));
|
|
258
|
+
pkCols.push(...cols);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const defaultM = /^\s*(\w+)\s+\S+.*?\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i.exec(trimmedLine);
|
|
262
|
+
if (defaultM) {
|
|
263
|
+
const colName = defaultM[1];
|
|
264
|
+
const defaultVal = defaultM[2].trim();
|
|
265
|
+
this._columnDefaults.set(`${name}.${colName}`, defaultVal);
|
|
266
|
+
}
|
|
267
|
+
const colPkM = /^(\w+)\s+\w+.*?\bPRIMARY\s+KEY\b/i.exec(trimmedLine);
|
|
268
|
+
if (colPkM && !/^PRIMARY\s+KEY\b/i.test(trimmedLine)) pkCols.push(colPkM[1]);
|
|
269
|
+
}
|
|
270
|
+
if (pkCols.length > 0 && !this._primaryKeys.has(name)) this._primaryKeys.set(name, pkCols);
|
|
271
|
+
if (!this._tableColumns.has(name)) {
|
|
272
|
+
const colNames = [];
|
|
273
|
+
for (const colLine of colLines) {
|
|
274
|
+
const trimmedLine = colLine.trim();
|
|
275
|
+
if (/^(?:PRIMARY\s+KEY|UNIQUE|FOREIGN\s+KEY|CHECK)\s*[\s(]/i.test(trimmedLine)) continue;
|
|
276
|
+
const quotedM = /^[`"](\w+)[`"]\s+\S/i.exec(trimmedLine);
|
|
277
|
+
if (quotedM) {
|
|
278
|
+
colNames.push(quotedM[1]);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const bareM = /^(\w+)\s+\S/i.exec(trimmedLine);
|
|
282
|
+
if (bareM) colNames.push(bareM[1]);
|
|
283
|
+
}
|
|
284
|
+
if (colNames.length > 0) this._tableColumns.set(name, colNames);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
220
287
|
}
|
|
221
288
|
return [];
|
|
222
289
|
}
|
|
@@ -225,16 +292,101 @@ var InMemoryDatabaseAdapter = class {
|
|
|
225
292
|
if (m) this._tables.delete(m[1]);
|
|
226
293
|
return [];
|
|
227
294
|
}
|
|
295
|
+
_createIndex(sql) {
|
|
296
|
+
const m = /CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)\s+ON\s+(\w+)/i.exec(sql);
|
|
297
|
+
if (m) {
|
|
298
|
+
const name = m[1];
|
|
299
|
+
const tbl_name = m[2];
|
|
300
|
+
if (!this._indexes.some((idx) => idx.name === name)) this._indexes.push({
|
|
301
|
+
name,
|
|
302
|
+
tbl_name,
|
|
303
|
+
type: "index"
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return [];
|
|
307
|
+
}
|
|
308
|
+
_dropIndex(sql) {
|
|
309
|
+
const m = /DROP\s+INDEX\s+(?:IF\s+EXISTS\s+)?(\w+)/i.exec(sql);
|
|
310
|
+
if (m) {
|
|
311
|
+
const name = m[1];
|
|
312
|
+
this._indexes = this._indexes.filter((idx) => idx.name !== name);
|
|
313
|
+
}
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Emulate PRAGMA table_info(tableName) — returns one row per column with
|
|
318
|
+
* {cid, name, type, notnull, dflt_value, pk} shape.
|
|
319
|
+
* Column names are derived from the CREATE TABLE definition order.
|
|
320
|
+
* This is sufficient for schema compatibility checks.
|
|
321
|
+
*/
|
|
322
|
+
_pragmaTableInfo(sql) {
|
|
323
|
+
const m = /PRAGMA\s+table_info\s*\(\s*[`'"]?(\w+)[`'"]?\s*\)/i.exec(sql);
|
|
324
|
+
if (!m) return [];
|
|
325
|
+
const tableName = m[1];
|
|
326
|
+
const colNames = this._tableColumns.get(tableName);
|
|
327
|
+
if (!colNames || colNames.length === 0) return [];
|
|
328
|
+
const pkCols = this._primaryKeys.get(tableName) ?? [];
|
|
329
|
+
return colNames.map((name, cid) => ({
|
|
330
|
+
cid,
|
|
331
|
+
name,
|
|
332
|
+
type: "TEXT",
|
|
333
|
+
notnull: 0,
|
|
334
|
+
dflt_value: null,
|
|
335
|
+
pk: pkCols.includes(name) ? 1 : 0
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
_selectFromSqliteMaster(sql) {
|
|
339
|
+
const masterRows = [];
|
|
340
|
+
for (const name of this._tables.keys()) masterRows.push({
|
|
341
|
+
type: "table",
|
|
342
|
+
name,
|
|
343
|
+
tbl_name: name,
|
|
344
|
+
rootpage: 0,
|
|
345
|
+
sql: null
|
|
346
|
+
});
|
|
347
|
+
for (const idx of this._indexes) masterRows.push({
|
|
348
|
+
type: "index",
|
|
349
|
+
name: idx.name,
|
|
350
|
+
tbl_name: idx.tbl_name,
|
|
351
|
+
rootpage: 0,
|
|
352
|
+
sql: null
|
|
353
|
+
});
|
|
354
|
+
const whereM = /WHERE\s+(.+?)(?:\s+ORDER\s+BY|\s+LIMIT|\s*$)/is.exec(sql);
|
|
355
|
+
let rows = masterRows;
|
|
356
|
+
if (whereM) rows = rows.filter((row) => this._matchWhere(whereM[1].trim(), row));
|
|
357
|
+
const colsM = /SELECT\s+(.+?)\s+FROM\s+sqlite_master/is.exec(sql);
|
|
358
|
+
if (!colsM) return rows;
|
|
359
|
+
const colsStr = colsM[1].trim();
|
|
360
|
+
if (colsStr === "*") return rows;
|
|
361
|
+
return rows.map((row) => this._projectCols(colsStr, row));
|
|
362
|
+
}
|
|
228
363
|
_insert(sql, _ignoreConflicts = false) {
|
|
229
364
|
const m = /INSERT\s+(?:IGNORE\s+)?INTO\s+(\w+)\s*\(([^)]+)\)\s*VALUES\s*\((.+)\)\s*$/is.exec(sql);
|
|
230
365
|
if (!m) return [];
|
|
231
366
|
const tableName = m[1];
|
|
232
|
-
const cols = m[2].split(",").map((c) => c.trim());
|
|
367
|
+
const cols = m[2].split(",").map((c) => c.trim().replace(/^[`"](.+)[`"]$/, "$1"));
|
|
233
368
|
const valStr = m[3];
|
|
234
369
|
const vals = this._parseValueList(valStr);
|
|
235
370
|
const row = {};
|
|
236
371
|
for (let i = 0; i < cols.length; i++) row[cols[i]] = vals[i] ?? null;
|
|
372
|
+
const aiCol = this._autoIncrementCols.get(tableName);
|
|
373
|
+
if (aiCol && !(aiCol in row)) {
|
|
374
|
+
const next = (this._autoIncrementCounters.get(tableName) ?? 0) + 1;
|
|
375
|
+
this._autoIncrementCounters.set(tableName, next);
|
|
376
|
+
row[aiCol] = next;
|
|
377
|
+
}
|
|
378
|
+
for (const [key, defaultExpr] of this._columnDefaults) {
|
|
379
|
+
const [tbl, col] = key.split(".");
|
|
380
|
+
if (tbl === tableName && !(col in row)) if (/^CURRENT_TIMESTAMP$/i.test(defaultExpr)) row[col] = new Date().toISOString();
|
|
381
|
+
else row[col] = this._evalLiteral(defaultExpr);
|
|
382
|
+
}
|
|
237
383
|
if (!this._tables.has(tableName)) this._tables.set(tableName, []);
|
|
384
|
+
const pkCols = this._primaryKeys.get(tableName);
|
|
385
|
+
if (pkCols && pkCols.length > 0 && !_ignoreConflicts) {
|
|
386
|
+
const table = this._tables.get(tableName);
|
|
387
|
+
const isDuplicate = table.some((existingRow) => pkCols.every((col) => existingRow[col] !== void 0 && String(existingRow[col]) === String(row[col])));
|
|
388
|
+
if (isDuplicate) throw new Error(`UNIQUE constraint failed: ${tableName} (${pkCols.join(", ")})`);
|
|
389
|
+
}
|
|
238
390
|
this._tables.get(tableName).push(row);
|
|
239
391
|
return [];
|
|
240
392
|
}
|
|
@@ -244,7 +396,20 @@ var InMemoryDatabaseAdapter = class {
|
|
|
244
396
|
if (!m$1) return [];
|
|
245
397
|
return [this._evalSelectExprs(m$1[1].trim())];
|
|
246
398
|
}
|
|
247
|
-
|
|
399
|
+
if (/FROM\s+sqlite_master/i.test(sql)) return this._selectFromSqliteMaster(sql);
|
|
400
|
+
let limitValue;
|
|
401
|
+
const limitMatch = /\s+LIMIT\s+(\d+)\s*$/is.exec(sql);
|
|
402
|
+
if (limitMatch) limitValue = parseInt(limitMatch[1], 10);
|
|
403
|
+
let orderByExprs;
|
|
404
|
+
const orderByMatch = /\s+ORDER\s+BY\s+(.+?)(?:\s+LIMIT\s+\d+\s*)?$/is.exec(sql);
|
|
405
|
+
if (orderByMatch) orderByExprs = this._parseOrderBy(orderByMatch[1].trim());
|
|
406
|
+
let stripped = sql.replace(/\s+ORDER\s+BY\s+.+?(?=\s+LIMIT\s|\s*$)/is, "").replace(/\s+LIMIT\s+\d+\s*$/is, "");
|
|
407
|
+
let groupByCols = null;
|
|
408
|
+
const groupByMatch = /\s+GROUP\s+BY\s+(.+?)(?:\s+HAVING\s+.+?)?$/is.exec(stripped);
|
|
409
|
+
if (groupByMatch) {
|
|
410
|
+
groupByCols = groupByMatch[1].split(",").map((c) => c.trim());
|
|
411
|
+
stripped = stripped.replace(/\s+GROUP\s+BY\s+.+$/is, "");
|
|
412
|
+
}
|
|
248
413
|
const m = /SELECT\s+(.+?)\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+))?$/is.exec(stripped);
|
|
249
414
|
if (!m) return [];
|
|
250
415
|
const colsStr = m[1].trim();
|
|
@@ -253,10 +418,201 @@ var InMemoryDatabaseAdapter = class {
|
|
|
253
418
|
const table = this._tables.get(tableName) ?? [];
|
|
254
419
|
let rows = table.map((r) => ({ ...r }));
|
|
255
420
|
if (whereStr) rows = rows.filter((row) => this._matchWhere(whereStr.trim(), row));
|
|
421
|
+
if (groupByCols !== null) {
|
|
422
|
+
const grouped = this._applyGroupBy(colsStr, rows, groupByCols);
|
|
423
|
+
const sorted = orderByExprs ? this._applyOrderBy(grouped, orderByExprs) : grouped;
|
|
424
|
+
return limitValue !== void 0 ? sorted.slice(0, limitValue) : sorted;
|
|
425
|
+
}
|
|
426
|
+
if (orderByExprs) rows = this._applyOrderBy(rows, orderByExprs);
|
|
427
|
+
if (limitValue !== void 0) rows = rows.slice(0, limitValue);
|
|
256
428
|
if (colsStr === "*") return rows;
|
|
257
429
|
if (/\b(?:SUM|COALESCE|COUNT|AVG|MIN|MAX)\s*\(/i.test(colsStr)) return [this._evalAggregate(colsStr, rows)];
|
|
258
430
|
return rows.map((row) => this._projectCols(colsStr, row));
|
|
259
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Apply GROUP BY: bucket rows by the group-by columns, then evaluate
|
|
434
|
+
* aggregate expressions for each bucket. Plain column references in the
|
|
435
|
+
* SELECT list that are also GROUP BY columns return the group value from
|
|
436
|
+
* the first row in the bucket (all rows in a group share the same value).
|
|
437
|
+
*/
|
|
438
|
+
_applyGroupBy(colsStr, rows, groupByCols) {
|
|
439
|
+
const groups = new Map();
|
|
440
|
+
for (const row of rows) {
|
|
441
|
+
const key = groupByCols.map((col) => String(row[col] ?? "")).join("\0");
|
|
442
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
443
|
+
groups.get(key).push(row);
|
|
444
|
+
}
|
|
445
|
+
const result = [];
|
|
446
|
+
for (const [, groupRows] of groups) result.push(this._evalAggregateGroup(colsStr, groupRows));
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Parse ORDER BY expression list into sort keys.
|
|
451
|
+
* Handles: simple columns, COALESCE(col, default) DESC, CASE...END expressions.
|
|
452
|
+
*/
|
|
453
|
+
_parseOrderBy(orderByStr) {
|
|
454
|
+
const parts = this._splitTopLevelCommas(orderByStr);
|
|
455
|
+
return parts.map((part) => {
|
|
456
|
+
const trimmed = part.trim();
|
|
457
|
+
const dirMatch = /^(.*?)\s+(ASC|DESC)\s*$/i.exec(trimmed);
|
|
458
|
+
if (dirMatch) return {
|
|
459
|
+
expr: dirMatch[1].trim(),
|
|
460
|
+
dir: dirMatch[2].toUpperCase()
|
|
461
|
+
};
|
|
462
|
+
return {
|
|
463
|
+
expr: trimmed,
|
|
464
|
+
dir: "ASC"
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Sort rows according to ORDER BY expression list.
|
|
470
|
+
*/
|
|
471
|
+
_applyOrderBy(rows, orderBy) {
|
|
472
|
+
return [...rows].sort((a, b) => {
|
|
473
|
+
for (const { expr, dir } of orderBy) {
|
|
474
|
+
const aVal = this._evalOrderByExpr(expr, a);
|
|
475
|
+
const bVal = this._evalOrderByExpr(expr, b);
|
|
476
|
+
const cmp = this._compareValues(aVal, bVal);
|
|
477
|
+
if (cmp !== 0) return dir === "DESC" ? -cmp : cmp;
|
|
478
|
+
}
|
|
479
|
+
return 0;
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Evaluate an ORDER BY expression for a single row.
|
|
484
|
+
*/
|
|
485
|
+
_evalOrderByExpr(expr, row) {
|
|
486
|
+
const trimmed = expr.trim();
|
|
487
|
+
const simpleCaseM = /^CASE\s+(\w+)\s+(.+?)\s+END$/is.exec(trimmed);
|
|
488
|
+
if (simpleCaseM) {
|
|
489
|
+
const col = simpleCaseM[1];
|
|
490
|
+
const colVal = String(row[col] ?? "");
|
|
491
|
+
const body = simpleCaseM[2].trim();
|
|
492
|
+
const whenMatches = [...body.matchAll(/WHEN\s+'([^']*)'\s+THEN\s+(\S+)/gi)];
|
|
493
|
+
for (const wm of whenMatches) if (colVal === wm[1]) return this._evalLiteral(wm[2]);
|
|
494
|
+
const elseM = /ELSE\s+(\S+)\s*$/i.exec(body);
|
|
495
|
+
if (elseM) return this._evalLiteral(elseM[1]);
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
return this._evalRowExpr(trimmed, row);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Compare two values for sorting (handles null, numbers, strings).
|
|
502
|
+
* Returns negative if a < b, 0 if equal, positive if a > b.
|
|
503
|
+
*/
|
|
504
|
+
_compareValues(a, b) {
|
|
505
|
+
if (a === null || a === void 0) return b === null || b === void 0 ? 0 : 1;
|
|
506
|
+
if (b === null || b === void 0) return -1;
|
|
507
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
508
|
+
return String(a).localeCompare(String(b));
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Evaluate SELECT expressions against a single GROUP BY bucket.
|
|
512
|
+
* Handles both aggregate expressions (SUM, COUNT, COALESCE) and plain
|
|
513
|
+
* column references (for GROUP BY projected columns).
|
|
514
|
+
*/
|
|
515
|
+
_evalAggregateGroup(colsStr, rows) {
|
|
516
|
+
const result = {};
|
|
517
|
+
const cols = this._splitTopLevelCommas(colsStr);
|
|
518
|
+
for (const col of cols) {
|
|
519
|
+
const aliasM = /^(.+?)\s+AS\s+(\w+)$/i.exec(col);
|
|
520
|
+
const expr = aliasM ? aliasM[1].trim() : col.trim();
|
|
521
|
+
const alias = aliasM ? aliasM[2] : col.trim();
|
|
522
|
+
result[alias] = this._evalAggregateExprGrouped(expr, rows);
|
|
523
|
+
}
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Evaluate a single aggregate expression against a GROUP BY bucket.
|
|
528
|
+
* Extends _evalAggregateExpr with:
|
|
529
|
+
* - SUM(expr) where expr may be CASE WHEN ... END
|
|
530
|
+
* - Plain column references (returns first-row value, for GROUP BY cols)
|
|
531
|
+
*/
|
|
532
|
+
_evalAggregateExprGrouped(expr, rows) {
|
|
533
|
+
const trimmed = expr.trim();
|
|
534
|
+
const coalesceM = /^COALESCE\((.+)\)$/i.exec(trimmed);
|
|
535
|
+
if (coalesceM) {
|
|
536
|
+
const args = this._splitTopLevelCommas(coalesceM[1]);
|
|
537
|
+
for (const arg of args) {
|
|
538
|
+
const val = this._evalAggregateExprGrouped(arg.trim(), rows);
|
|
539
|
+
if (val !== null && val !== void 0) return val;
|
|
540
|
+
}
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
const sumM = /^SUM\((.+)\)$/i.exec(trimmed);
|
|
544
|
+
if (sumM) {
|
|
545
|
+
if (rows.length === 0) return null;
|
|
546
|
+
let total = 0;
|
|
547
|
+
for (const row of rows) total += Number(this._evalRowExpr(sumM[1].trim(), row) ?? 0);
|
|
548
|
+
return total;
|
|
549
|
+
}
|
|
550
|
+
if (/^COUNT\(\*\)$/i.test(trimmed)) return rows.length;
|
|
551
|
+
const countColM = /^COUNT\((\w+)\)$/i.exec(trimmed);
|
|
552
|
+
if (countColM) {
|
|
553
|
+
const col = countColM[1];
|
|
554
|
+
return rows.filter((r) => r[col] !== null && r[col] !== void 0).length;
|
|
555
|
+
}
|
|
556
|
+
const maxColM = /^MAX\((\w+)\)$/i.exec(trimmed);
|
|
557
|
+
if (maxColM) {
|
|
558
|
+
const col = maxColM[1];
|
|
559
|
+
const values = rows.map((r) => r[col]).filter((v) => v !== null && v !== void 0);
|
|
560
|
+
if (values.length === 0) return null;
|
|
561
|
+
return values.reduce((a, b) => String(a) >= String(b) ? a : b);
|
|
562
|
+
}
|
|
563
|
+
const minColM = /^MIN\((\w+)\)$/i.exec(trimmed);
|
|
564
|
+
if (minColM) {
|
|
565
|
+
const col = minColM[1];
|
|
566
|
+
const values = rows.map((r) => r[col]).filter((v) => v !== null && v !== void 0);
|
|
567
|
+
if (values.length === 0) return null;
|
|
568
|
+
return values.reduce((a, b) => String(a) <= String(b) ? a : b);
|
|
569
|
+
}
|
|
570
|
+
if (/^\w+$/.test(trimmed) && rows.length > 0 && trimmed in rows[0]) return rows[0][trimmed];
|
|
571
|
+
return this._evalLiteral(trimmed);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Evaluate an expression for a single row.
|
|
575
|
+
* Supports CASE WHEN conditions, COALESCE, column references, and literals.
|
|
576
|
+
* Used by _evalAggregateExprGrouped to evaluate the argument of SUM().
|
|
577
|
+
*/
|
|
578
|
+
_evalRowExpr(expr, row) {
|
|
579
|
+
const trimmed = expr.trim();
|
|
580
|
+
const coalesceM = /^COALESCE\((.+)\)$/i.exec(trimmed);
|
|
581
|
+
if (coalesceM) {
|
|
582
|
+
const args = this._splitTopLevelCommas(coalesceM[1]);
|
|
583
|
+
for (const arg of args) {
|
|
584
|
+
const val = this._evalRowExpr(arg.trim(), row);
|
|
585
|
+
if (val !== null && val !== void 0) return val;
|
|
586
|
+
}
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
const caseM = /^CASE\s+WHEN\s+(.+?)\s+THEN\s+(.+?)\s+ELSE\s+(.+?)\s+END$/is.exec(trimmed);
|
|
590
|
+
if (caseM) {
|
|
591
|
+
const matches = this._evalRowCondition(caseM[1].trim(), row);
|
|
592
|
+
return this._evalRowExpr(matches ? caseM[2].trim() : caseM[3].trim(), row);
|
|
593
|
+
}
|
|
594
|
+
if (/^\w+$/.test(trimmed) && /^[a-zA-Z_]/.test(trimmed)) {
|
|
595
|
+
if (trimmed in row) return row[trimmed];
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
return this._evalLiteral(trimmed);
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Evaluate a simple condition (col = 'str', col = num) for a single row.
|
|
602
|
+
* Returns true if the condition holds.
|
|
603
|
+
*/
|
|
604
|
+
_evalRowCondition(condition, row) {
|
|
605
|
+
const trimmed = condition.trim();
|
|
606
|
+
const strM = /^(\w+)\s*=\s*'(.*)'$/is.exec(trimmed);
|
|
607
|
+
if (strM) {
|
|
608
|
+
const colVal = String(row[strM[1]] ?? "");
|
|
609
|
+
const literal = strM[2].replace(/''/g, "'");
|
|
610
|
+
return colVal === literal;
|
|
611
|
+
}
|
|
612
|
+
const numM = /^(\w+)\s*=\s*(-?\d+(?:\.\d+)?)$/.exec(trimmed);
|
|
613
|
+
if (numM) return Number(row[numM[1]]) === parseFloat(numM[2]);
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
260
616
|
_update(sql) {
|
|
261
617
|
const m = /UPDATE\s+(\w+)\s+SET\s+(.+?)(?:\s+WHERE\s+(.+))?$/is.exec(sql);
|
|
262
618
|
if (!m) return [];
|
|
@@ -265,8 +621,10 @@ var InMemoryDatabaseAdapter = class {
|
|
|
265
621
|
const whereStr = m[3];
|
|
266
622
|
const table = this._tables.get(tableName);
|
|
267
623
|
if (!table) return [];
|
|
268
|
-
const
|
|
269
|
-
|
|
624
|
+
for (const row of table) if (!whereStr || this._matchWhere(whereStr.trim(), row)) {
|
|
625
|
+
const assignments = this._parseAssignmentsForRow(setStr, row);
|
|
626
|
+
for (const [col, val] of assignments) row[col] = val;
|
|
627
|
+
}
|
|
270
628
|
return [];
|
|
271
629
|
}
|
|
272
630
|
_delete(sql) {
|
|
@@ -292,29 +650,65 @@ var InMemoryDatabaseAdapter = class {
|
|
|
292
650
|
const conditions = whereClause.split(/\s+AND\s+/i);
|
|
293
651
|
for (const condition of conditions) {
|
|
294
652
|
const trimmed = condition.trim();
|
|
295
|
-
const strM = /^(\w+)
|
|
653
|
+
const strM = /^[`"]?(\w+)[`"]?\s*=\s*'(.*)'$/is.exec(trimmed);
|
|
296
654
|
if (strM) {
|
|
297
655
|
const colVal = String(row[strM[1]] ?? "");
|
|
298
656
|
const literal = strM[2].replace(/''/g, "'");
|
|
299
657
|
if (colVal !== literal) return false;
|
|
300
658
|
continue;
|
|
301
659
|
}
|
|
302
|
-
const
|
|
660
|
+
const strNeqM = /^[`"]?(\w+)[`"]?\s*!=\s*'(.*)'$/is.exec(trimmed);
|
|
661
|
+
if (strNeqM) {
|
|
662
|
+
const colVal = String(row[strNeqM[1]] ?? "");
|
|
663
|
+
const literal = strNeqM[2].replace(/''/g, "'");
|
|
664
|
+
if (colVal === literal) return false;
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
const numM = /^[`"]?(\w+)[`"]?\s*=\s*(-?\d+(?:\.\d+)?)$/.exec(trimmed);
|
|
303
668
|
if (numM) {
|
|
304
669
|
if (Number(row[numM[1]]) !== parseFloat(numM[2])) return false;
|
|
305
670
|
continue;
|
|
306
671
|
}
|
|
307
|
-
const
|
|
672
|
+
const numNeqM = /^[`"]?(\w+)[`"]?\s*!=\s*(-?\d+(?:\.\d+)?)$/.exec(trimmed);
|
|
673
|
+
if (numNeqM) {
|
|
674
|
+
if (Number(row[numNeqM[1]]) === parseFloat(numNeqM[2])) return false;
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
const strCmpM = /^[`"]?(\w+)[`"]?\s*(>=|<=|>|<)\s*'(.*)'$/s.exec(trimmed);
|
|
678
|
+
if (strCmpM) {
|
|
679
|
+
const colVal = row[strCmpM[1]];
|
|
680
|
+
if (colVal === null || colVal === void 0) return false;
|
|
681
|
+
const lhs = String(colVal);
|
|
682
|
+
const rhs = strCmpM[3].replace(/''/g, "'");
|
|
683
|
+
const op = strCmpM[2];
|
|
684
|
+
if (op === "<" && !(lhs < rhs)) return false;
|
|
685
|
+
if (op === "<=" && !(lhs <= rhs)) return false;
|
|
686
|
+
if (op === ">" && !(lhs > rhs)) return false;
|
|
687
|
+
if (op === ">=" && !(lhs >= rhs)) return false;
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
const numCmpM = /^[`"]?(\w+)[`"]?\s*(>=|<=|>|<)\s*(-?\d+(?:\.\d+)?)$/.exec(trimmed);
|
|
691
|
+
if (numCmpM) {
|
|
692
|
+
const colVal = Number(row[numCmpM[1]] ?? 0);
|
|
693
|
+
const rhs = parseFloat(numCmpM[3]);
|
|
694
|
+
const op = numCmpM[2];
|
|
695
|
+
if (op === "<" && !(colVal < rhs)) return false;
|
|
696
|
+
if (op === "<=" && !(colVal <= rhs)) return false;
|
|
697
|
+
if (op === ">" && !(colVal > rhs)) return false;
|
|
698
|
+
if (op === ">=" && !(colVal >= rhs)) return false;
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const nullM = /^[`"]?(\w+)[`"]?\s+IS\s+NULL$/i.exec(trimmed);
|
|
308
702
|
if (nullM) {
|
|
309
703
|
if (row[nullM[1]] !== null && row[nullM[1]] !== void 0) return false;
|
|
310
704
|
continue;
|
|
311
705
|
}
|
|
312
|
-
const notNullM = /^(\w+)
|
|
706
|
+
const notNullM = /^[`"]?(\w+)[`"]?\s+IS\s+NOT\s+NULL$/i.exec(trimmed);
|
|
313
707
|
if (notNullM) {
|
|
314
708
|
if (row[notNullM[1]] === null || row[notNullM[1]] === void 0) return false;
|
|
315
709
|
continue;
|
|
316
710
|
}
|
|
317
|
-
const likeM = /^(\w+)
|
|
711
|
+
const likeM = /^[`"]?(\w+)[`"]?\s+LIKE\s+'(.*)'$/is.exec(trimmed);
|
|
318
712
|
if (likeM) {
|
|
319
713
|
const colVal = row[likeM[1]];
|
|
320
714
|
if (colVal === null || colVal === void 0) return false;
|
|
@@ -324,6 +718,22 @@ var InMemoryDatabaseAdapter = class {
|
|
|
324
718
|
if (!regex.test(String(colVal))) return false;
|
|
325
719
|
continue;
|
|
326
720
|
}
|
|
721
|
+
const inM = /^[`"]?(\w+)[`"]?\s+IN\s*\((.+)\)$/is.exec(trimmed);
|
|
722
|
+
if (inM) {
|
|
723
|
+
const colVal = row[inM[1]];
|
|
724
|
+
const inValues = this._parseValueList(inM[2]);
|
|
725
|
+
const colStr = colVal === null || colVal === void 0 ? null : typeof colVal === "number" ? colVal : String(colVal);
|
|
726
|
+
if (!inValues.some((v) => v === colStr || String(v) === String(colStr))) return false;
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
const notInM = /^[`"]?(\w+)[`"]?\s+NOT\s+IN\s*\((.+)\)$/is.exec(trimmed);
|
|
730
|
+
if (notInM) {
|
|
731
|
+
const colVal = row[notInM[1]];
|
|
732
|
+
const notInValues = this._parseValueList(notInM[2]);
|
|
733
|
+
const colStr = colVal === null || colVal === void 0 ? null : typeof colVal === "number" ? colVal : String(colVal);
|
|
734
|
+
if (notInValues.some((v) => v === colStr || String(v) === String(colStr))) return false;
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
327
737
|
}
|
|
328
738
|
return true;
|
|
329
739
|
}
|
|
@@ -333,7 +743,7 @@ var InMemoryDatabaseAdapter = class {
|
|
|
333
743
|
for (const col of cols) {
|
|
334
744
|
const aliasM = /^(.+?)\s+AS\s+(\w+)$/i.exec(col);
|
|
335
745
|
if (aliasM) result[aliasM[2]] = this._evalExprAgainstRow(aliasM[1].trim(), row);
|
|
336
|
-
else result[col] = row[col];
|
|
746
|
+
else result[col] = col in row ? row[col] : null;
|
|
337
747
|
}
|
|
338
748
|
return result;
|
|
339
749
|
}
|
|
@@ -413,7 +823,7 @@ var InMemoryDatabaseAdapter = class {
|
|
|
413
823
|
}
|
|
414
824
|
/**
|
|
415
825
|
* Evaluate a single aggregate expression against a set of rows.
|
|
416
|
-
* Supports: SUM(
|
|
826
|
+
* Supports: SUM(expr), COALESCE(expr, default), COUNT(*), MAX(col), MIN(col).
|
|
417
827
|
*/
|
|
418
828
|
_evalAggregateExpr(expr, rows) {
|
|
419
829
|
const trimmed = expr.trim();
|
|
@@ -426,20 +836,39 @@ var InMemoryDatabaseAdapter = class {
|
|
|
426
836
|
}
|
|
427
837
|
return null;
|
|
428
838
|
}
|
|
429
|
-
const sumM = /^SUM\((
|
|
839
|
+
const sumM = /^SUM\((.+)\)$/i.exec(trimmed);
|
|
430
840
|
if (sumM) {
|
|
431
|
-
const col = sumM[1];
|
|
432
841
|
if (rows.length === 0) return null;
|
|
433
842
|
let total = 0;
|
|
434
|
-
for (const row of rows) total += Number(
|
|
843
|
+
for (const row of rows) total += Number(this._evalRowExpr(sumM[1].trim(), row) ?? 0);
|
|
435
844
|
return total;
|
|
436
845
|
}
|
|
437
846
|
if (/^COUNT\(\*\)$/i.test(trimmed)) return rows.length;
|
|
847
|
+
const countDistinctM = /^COUNT\(\s*DISTINCT\s+(\w+)\s*\)$/i.exec(trimmed);
|
|
848
|
+
if (countDistinctM) {
|
|
849
|
+
const col = countDistinctM[1];
|
|
850
|
+
const distinct = new Set(rows.map((r) => r[col]).filter((v) => v !== null && v !== void 0));
|
|
851
|
+
return distinct.size;
|
|
852
|
+
}
|
|
438
853
|
const countM = /^COUNT\((\w+)\)$/i.exec(trimmed);
|
|
439
854
|
if (countM) {
|
|
440
855
|
const col = countM[1];
|
|
441
856
|
return rows.filter((r) => r[col] !== null && r[col] !== void 0).length;
|
|
442
857
|
}
|
|
858
|
+
const maxM = /^MAX\((\w+)\)$/i.exec(trimmed);
|
|
859
|
+
if (maxM) {
|
|
860
|
+
const col = maxM[1];
|
|
861
|
+
const values = rows.map((r) => r[col]).filter((v) => v !== null && v !== void 0);
|
|
862
|
+
if (values.length === 0) return null;
|
|
863
|
+
return values.reduce((a, b) => String(a) >= String(b) ? a : b);
|
|
864
|
+
}
|
|
865
|
+
const minM = /^MIN\((\w+)\)$/i.exec(trimmed);
|
|
866
|
+
if (minM) {
|
|
867
|
+
const col = minM[1];
|
|
868
|
+
const values = rows.map((r) => r[col]).filter((v) => v !== null && v !== void 0);
|
|
869
|
+
if (values.length === 0) return null;
|
|
870
|
+
return values.reduce((a, b) => String(a) <= String(b) ? a : b);
|
|
871
|
+
}
|
|
443
872
|
return this._evalLiteral(trimmed);
|
|
444
873
|
}
|
|
445
874
|
/**
|
|
@@ -473,8 +902,9 @@ var InMemoryDatabaseAdapter = class {
|
|
|
473
902
|
}
|
|
474
903
|
/**
|
|
475
904
|
* Parse `col1 = val1, col2 = val2` assignments into an array of [col, val] pairs.
|
|
905
|
+
* Evaluates each RHS expression against the provided row for arithmetic support.
|
|
476
906
|
*/
|
|
477
|
-
|
|
907
|
+
_parseAssignmentsForRow(setStr, row) {
|
|
478
908
|
const assignments = [];
|
|
479
909
|
const parts = [];
|
|
480
910
|
let current = "";
|
|
@@ -502,10 +932,48 @@ var InMemoryDatabaseAdapter = class {
|
|
|
502
932
|
if (eqIdx === -1) continue;
|
|
503
933
|
const col = part.slice(0, eqIdx).trim();
|
|
504
934
|
const valStr = part.slice(eqIdx + 1).trim();
|
|
505
|
-
assignments.push([col, this.
|
|
935
|
+
assignments.push([col, this._evalAssignmentExpr(valStr, row)]);
|
|
506
936
|
}
|
|
507
937
|
return assignments;
|
|
508
938
|
}
|
|
939
|
+
/**
|
|
940
|
+
* Evaluate a SET assignment RHS expression against the current row.
|
|
941
|
+
* Handles: simple literals, column arithmetic (col +/- val), COALESCE, CURRENT_TIMESTAMP.
|
|
942
|
+
*/
|
|
943
|
+
_evalAssignmentExpr(expr, row) {
|
|
944
|
+
const trimmed = expr.trim();
|
|
945
|
+
if (/^CURRENT_TIMESTAMP$/i.test(trimmed)) return new Date().toISOString();
|
|
946
|
+
const coalesceM = /^COALESCE\((.+)\)$/i.exec(trimmed);
|
|
947
|
+
if (coalesceM) {
|
|
948
|
+
const args = this._splitTopLevelCommas(coalesceM[1]);
|
|
949
|
+
for (const arg of args) {
|
|
950
|
+
const val = this._evalAssignmentExpr(arg.trim(), row);
|
|
951
|
+
if (val !== null && val !== void 0) return val;
|
|
952
|
+
}
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
const arithM = /^(\w+)\s*([+\-*\/])\s*(-?\d+(?:\.\d+)?)$/.exec(trimmed);
|
|
956
|
+
if (arithM) {
|
|
957
|
+
const colName = arithM[1];
|
|
958
|
+
const op = arithM[2];
|
|
959
|
+
const num = parseFloat(arithM[3]);
|
|
960
|
+
const colVal = Number(row[colName] ?? 0);
|
|
961
|
+
switch (op) {
|
|
962
|
+
case "+": return colVal + num;
|
|
963
|
+
case "-": return colVal - num;
|
|
964
|
+
case "*": return colVal * num;
|
|
965
|
+
case "/": return num !== 0 ? colVal / num : null;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return this._evalLiteral(trimmed);
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* @deprecated Use _parseAssignmentsForRow instead.
|
|
972
|
+
* Kept for internal compatibility — evaluates without row context.
|
|
973
|
+
*/
|
|
974
|
+
_parseAssignments(setStr) {
|
|
975
|
+
return this._parseAssignmentsForRow(setStr, {});
|
|
976
|
+
}
|
|
509
977
|
};
|
|
510
978
|
|
|
511
979
|
//#endregion
|
|
@@ -2908,6 +3376,7 @@ function inspectProcessTree(opts) {
|
|
|
2908
3376
|
return parseInt(parts[0], 10) === pid && !parts[2].includes("Z");
|
|
2909
3377
|
});
|
|
2910
3378
|
if (isAlive) result.orchestrator_pid = pid;
|
|
3379
|
+
else result.pid_file_dead = true;
|
|
2911
3380
|
}
|
|
2912
3381
|
} catch {}
|
|
2913
3382
|
if (result.orchestrator_pid === null) {
|
|
@@ -3073,7 +3542,17 @@ async function getAutoHealthData(options) {
|
|
|
3073
3542
|
await initSchema(adapter);
|
|
3074
3543
|
let run;
|
|
3075
3544
|
if (runId !== void 0) run = await getPipelineRunById(adapter, runId);
|
|
3076
|
-
else
|
|
3545
|
+
else {
|
|
3546
|
+
let currentRunId;
|
|
3547
|
+
try {
|
|
3548
|
+
const currentRunIdPath = join(dbRoot, ".substrate", "current-run-id");
|
|
3549
|
+
const content = readFileSync$1(currentRunIdPath, "utf-8").trim();
|
|
3550
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3551
|
+
if (UUID_RE.test(content)) currentRunId = content;
|
|
3552
|
+
} catch {}
|
|
3553
|
+
if (currentRunId !== void 0) run = await getPipelineRunById(adapter, currentRunId);
|
|
3554
|
+
if (run === void 0) run = await getLatestRun(adapter);
|
|
3555
|
+
}
|
|
3077
3556
|
if (run === void 0) {
|
|
3078
3557
|
const substrateDirPath$1 = join(dbRoot, ".substrate");
|
|
3079
3558
|
const fallbackProcessInfo = inspectProcessTree({
|
|
@@ -3121,16 +3600,16 @@ async function getAutoHealthData(options) {
|
|
|
3121
3600
|
}
|
|
3122
3601
|
} catch {}
|
|
3123
3602
|
const substrateDirPath = join(dbRoot, ".substrate");
|
|
3124
|
-
const processInfo = inspectProcessTree({
|
|
3603
|
+
const processInfo = options._processInfoOverride ?? inspectProcessTree({
|
|
3125
3604
|
projectRoot,
|
|
3126
3605
|
substrateDirPath
|
|
3127
3606
|
});
|
|
3128
3607
|
let verdict = "NO_PIPELINE_RUNNING";
|
|
3129
|
-
if (run.status === "running") if (processInfo.
|
|
3130
|
-
else if (processInfo.
|
|
3608
|
+
if (run.status === "running") if (processInfo.orchestrator_pid !== null) verdict = "HEALTHY";
|
|
3609
|
+
else if (processInfo.pid_file_dead === true) verdict = "STALLED";
|
|
3610
|
+
else if (processInfo.zombies.length > 0) verdict = "STALLED";
|
|
3131
3611
|
else if (stalenessSeconds > DEFAULT_STALL_THRESHOLD_SECONDS) verdict = "STALLED";
|
|
3132
|
-
else if (
|
|
3133
|
-
else if (processInfo.orchestrator_pid === null && active > 0) verdict = "STALLED";
|
|
3612
|
+
else if (active > 0) verdict = "STALLED";
|
|
3134
3613
|
else verdict = "HEALTHY";
|
|
3135
3614
|
else if (run.status === "completed" || run.status === "failed" || run.status === "stopped") verdict = "NO_PIPELINE_RUNNING";
|
|
3136
3615
|
const healthOutput = {
|
|
@@ -3244,4 +3723,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
|
|
|
3244
3723
|
|
|
3245
3724
|
//#endregion
|
|
3246
3725
|
export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltClient, DoltMergeConflict, DoltNotInstalled, FileStateStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, buildPipelineStatusOutput, checkDoltInstalled, createDatabaseAdapter, createDoltClient, createStateStore, detectCycles, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, initSchema, initializeDolt, inspectProcessTree, isOrchestratorProcessLine, isSyncAdapter, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runHealthAction, validateStoryKey };
|
|
3247
|
-
//# sourceMappingURL=health-
|
|
3726
|
+
//# sourceMappingURL=health-C-VRJruD.js.map
|