@cleocode/core 2026.4.45 → 2026.4.46
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/index.js +65 -57
- package/dist/index.js.map +3 -3
- package/dist/internal.js +97 -89
- package/dist/internal.js.map +3 -3
- package/dist/store/db-helpers.d.ts +8 -3
- package/dist/store/db-helpers.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/store/__tests__/db-helpers.test.ts +46 -6
- package/src/store/db-helpers.ts +25 -4
- package/src/store/sqlite-data-accessor.ts +2 -1
- package/src/tasks/__tests__/epic-auto-complete.test.ts +331 -0
- package/src/tasks/complete.ts +7 -4
package/dist/index.js
CHANGED
|
@@ -11448,14 +11448,14 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
|
|
|
11448
11448
|
const dbHashes = new Set(dbEntries.map((e) => e.hash));
|
|
11449
11449
|
const allLocalHashesPresentInDb = localMigrations.every((m) => dbHashes.has(m.hash));
|
|
11450
11450
|
if (allLocalHashesPresentInDb) {
|
|
11451
|
-
const
|
|
11452
|
-
|
|
11451
|
+
const log11 = getLogger(logSubsystem);
|
|
11452
|
+
log11.debug(
|
|
11453
11453
|
{ extra: orphanedEntries.length },
|
|
11454
11454
|
`Migration journal has ${orphanedEntries.length} entries for migrations not known to this install (DB is ahead). Skipping reconciliation.`
|
|
11455
11455
|
);
|
|
11456
11456
|
} else {
|
|
11457
|
-
const
|
|
11458
|
-
|
|
11457
|
+
const log11 = getLogger(logSubsystem);
|
|
11458
|
+
log11.warn(
|
|
11459
11459
|
{ orphaned: orphanedEntries.length },
|
|
11460
11460
|
`Detected stale migration journal entries from a previous CLEO version. Reconciling.`
|
|
11461
11461
|
);
|
|
@@ -11486,8 +11486,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
|
|
|
11486
11486
|
return cols.some((c) => c.name === column);
|
|
11487
11487
|
});
|
|
11488
11488
|
if (allColumnsExist) {
|
|
11489
|
-
const
|
|
11490
|
-
|
|
11489
|
+
const log11 = getLogger(logSubsystem);
|
|
11490
|
+
log11.warn(
|
|
11491
11491
|
{ migration: migration.name, columns: alterMatches },
|
|
11492
11492
|
`Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
|
|
11493
11493
|
);
|
|
@@ -11505,8 +11505,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
|
|
|
11505
11505
|
for (const entry of unnamedEntries) {
|
|
11506
11506
|
const migrationName = hashToName.get(entry.hash);
|
|
11507
11507
|
if (!migrationName) continue;
|
|
11508
|
-
const
|
|
11509
|
-
|
|
11508
|
+
const log11 = getLogger(logSubsystem);
|
|
11509
|
+
log11.warn(
|
|
11510
11510
|
{ id: entry.id, hash: entry.hash, name: migrationName },
|
|
11511
11511
|
`Backfilling missing name on journal entry id=${entry.id} \u2014 Drizzle v1 beta requires name for applied-migration detection.`
|
|
11512
11512
|
);
|
|
@@ -11550,8 +11550,8 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem) {
|
|
|
11550
11550
|
const existingCols = new Set(columns.map((c) => c.name));
|
|
11551
11551
|
for (const req of requiredColumns) {
|
|
11552
11552
|
if (!existingCols.has(req.name)) {
|
|
11553
|
-
const
|
|
11554
|
-
|
|
11553
|
+
const log11 = getLogger(logSubsystem);
|
|
11554
|
+
log11.warn(
|
|
11555
11555
|
{ column: req.name },
|
|
11556
11556
|
`Adding missing column ${tableName}.${req.name} via ALTER TABLE`
|
|
11557
11557
|
);
|
|
@@ -13511,7 +13511,7 @@ function getDbPath(cwd) {
|
|
|
13511
13511
|
return join9(getCleoDirAbsolute(cwd), DB_FILENAME2);
|
|
13512
13512
|
}
|
|
13513
13513
|
async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
13514
|
-
const
|
|
13514
|
+
const log11 = getLogger("sqlite");
|
|
13515
13515
|
try {
|
|
13516
13516
|
const countResult = nativeDb.prepare("SELECT COUNT(*) as cnt FROM tasks").get();
|
|
13517
13517
|
const taskCount = countResult?.cnt ?? 0;
|
|
@@ -13532,7 +13532,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
13532
13532
|
if (backupTaskCount < MIN_BACKUP_TASK_COUNT) {
|
|
13533
13533
|
return;
|
|
13534
13534
|
}
|
|
13535
|
-
|
|
13535
|
+
log11.warn(
|
|
13536
13536
|
{ dbPath, backupPath: newestBackup.path, backupTasks: backupTaskCount },
|
|
13537
13537
|
`Empty database detected with ${backupTaskCount}-task backup available. Auto-recovering from backup. This likely happened because git-tracked WAL/SHM files were overwritten during a branch switch (T5188).`
|
|
13538
13538
|
);
|
|
@@ -13550,7 +13550,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
13550
13550
|
const tempPath = dbPath + ".recovery-tmp";
|
|
13551
13551
|
copyFileSync4(newestBackup.path, tempPath);
|
|
13552
13552
|
renameSync(tempPath, dbPath);
|
|
13553
|
-
|
|
13553
|
+
log11.info(
|
|
13554
13554
|
{ dbPath, backupPath: newestBackup.path, restoredTasks: backupTaskCount },
|
|
13555
13555
|
"Database auto-recovered from backup successfully."
|
|
13556
13556
|
);
|
|
@@ -13560,7 +13560,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
13560
13560
|
runMigrations(restoredNativeDb, restoredDb);
|
|
13561
13561
|
_db = restoredDb;
|
|
13562
13562
|
} catch (err) {
|
|
13563
|
-
|
|
13563
|
+
log11.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
|
|
13564
13564
|
}
|
|
13565
13565
|
}
|
|
13566
13566
|
async function getDb(cwd) {
|
|
@@ -13594,7 +13594,7 @@ async function getDb(cwd) {
|
|
|
13594
13594
|
const { execFileSync: execFileSync12 } = await import("node:child_process");
|
|
13595
13595
|
const gitCwd = resolve3(dbPath, "..", "..");
|
|
13596
13596
|
const filesToCheck = [dbPath, dbPath + "-wal", dbPath + "-shm"];
|
|
13597
|
-
const
|
|
13597
|
+
const log11 = getLogger("sqlite");
|
|
13598
13598
|
for (const fileToCheck of filesToCheck) {
|
|
13599
13599
|
try {
|
|
13600
13600
|
execFileSync12("git", ["ls-files", "--error-unmatch", fileToCheck], {
|
|
@@ -13603,7 +13603,7 @@ async function getDb(cwd) {
|
|
|
13603
13603
|
});
|
|
13604
13604
|
const basename18 = fileToCheck.split(/[\\/]/).pop();
|
|
13605
13605
|
const relPath = fileToCheck.replace(gitCwd + sep, "");
|
|
13606
|
-
|
|
13606
|
+
log11.warn(
|
|
13607
13607
|
{ path: fileToCheck },
|
|
13608
13608
|
`${basename18} is tracked by project git \u2014 this risks data loss on branch switch. Resolution (ADR-013 \xA79): \`git rm --cached ${relPath}\` and rely on \`.cleo/backups/sqlite/\` snapshots + \`cleo backup add\` for recovery.`
|
|
13609
13609
|
);
|
|
@@ -14589,11 +14589,18 @@ var init_cross_db_cleanup = __esm({
|
|
|
14589
14589
|
|
|
14590
14590
|
// packages/core/src/store/db-helpers.ts
|
|
14591
14591
|
import { eq as eq4, inArray as inArray2 } from "drizzle-orm";
|
|
14592
|
-
async function upsertTask(db, row, archiveFields) {
|
|
14592
|
+
async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
|
|
14593
14593
|
if (row.parentId) {
|
|
14594
14594
|
const parent = await db.select({ id: tasks.id }).from(tasks).where(eq4(tasks.id, row.parentId)).limit(1).all();
|
|
14595
14595
|
if (parent.length === 0) {
|
|
14596
|
-
|
|
14596
|
+
if (allowOrphanParent) {
|
|
14597
|
+
row = { ...row, parentId: null };
|
|
14598
|
+
} else {
|
|
14599
|
+
log2.warn(
|
|
14600
|
+
{ taskId: row.id, parentId: row.parentId },
|
|
14601
|
+
"upsertTask: parentId references a non-existent task \u2014 parent relationship may be lost"
|
|
14602
|
+
);
|
|
14603
|
+
}
|
|
14597
14604
|
}
|
|
14598
14605
|
}
|
|
14599
14606
|
const values = archiveFields ? { ...row, ...archiveFields, status: "archived" } : row;
|
|
@@ -14737,10 +14744,13 @@ async function loadRelationsForTasks(db, tasks2) {
|
|
|
14737
14744
|
}
|
|
14738
14745
|
}
|
|
14739
14746
|
}
|
|
14747
|
+
var log2;
|
|
14740
14748
|
var init_db_helpers = __esm({
|
|
14741
14749
|
"packages/core/src/store/db-helpers.ts"() {
|
|
14742
14750
|
"use strict";
|
|
14751
|
+
init_logger();
|
|
14743
14752
|
init_tasks_schema();
|
|
14753
|
+
log2 = getLogger("db-helpers");
|
|
14744
14754
|
}
|
|
14745
14755
|
});
|
|
14746
14756
|
|
|
@@ -15074,7 +15084,7 @@ async function createSqliteDataAccessor(cwd) {
|
|
|
15074
15084
|
archiveReason: taskAny.archiveReason ?? "completed",
|
|
15075
15085
|
cycleTimeDays: taskAny.cycleTimeDays ?? null
|
|
15076
15086
|
};
|
|
15077
|
-
await upsertTask(db, row, archiveFields);
|
|
15087
|
+
await upsertTask(db, row, archiveFields, true);
|
|
15078
15088
|
depBatch.push({ taskId: task.id, deps: task.depends ?? [] });
|
|
15079
15089
|
}
|
|
15080
15090
|
await batchUpdateDependencies(db, depBatch, validDepIds);
|
|
@@ -16061,7 +16071,7 @@ async function ensureSequenceValid(cwd, options) {
|
|
|
16061
16071
|
if (!options?.validateSequence) return;
|
|
16062
16072
|
const check2 = await checkSequence(cwd);
|
|
16063
16073
|
if (!check2.valid) {
|
|
16064
|
-
|
|
16074
|
+
log3.warn({ counter: check2.counter, maxId: check2.maxIdInData }, "Sequence behind, repairing");
|
|
16065
16075
|
const repair = await repairSequence(cwd);
|
|
16066
16076
|
if (!repair.repaired && options.strict) {
|
|
16067
16077
|
throw new DataSafetyError(`Sequence repair failed: ${repair.message}`, "SEQUENCE_INVALID", {
|
|
@@ -16078,7 +16088,7 @@ async function checkpoint(context, cwd, options) {
|
|
|
16078
16088
|
stats.checkpoints++;
|
|
16079
16089
|
stats.lastCheckpoint = /* @__PURE__ */ new Date();
|
|
16080
16090
|
} catch (err) {
|
|
16081
|
-
|
|
16091
|
+
log3.warn({ err }, "Checkpoint failed (non-fatal)");
|
|
16082
16092
|
}
|
|
16083
16093
|
vacuumIntoBackup({ cwd }).catch(() => {
|
|
16084
16094
|
});
|
|
@@ -16140,7 +16150,7 @@ async function safeAppendLog(accessor, entry, cwd, options) {
|
|
|
16140
16150
|
stats.writes++;
|
|
16141
16151
|
await checkpoint("log entry", cwd, opts);
|
|
16142
16152
|
}
|
|
16143
|
-
var
|
|
16153
|
+
var log3, DataSafetyError, DEFAULT_SAFETY, stats;
|
|
16144
16154
|
var init_data_safety_central = __esm({
|
|
16145
16155
|
"packages/core/src/store/data-safety-central.ts"() {
|
|
16146
16156
|
"use strict";
|
|
@@ -16148,7 +16158,7 @@ var init_data_safety_central = __esm({
|
|
|
16148
16158
|
init_sequence();
|
|
16149
16159
|
init_git_checkpoint();
|
|
16150
16160
|
init_sqlite_backup();
|
|
16151
|
-
|
|
16161
|
+
log3 = getLogger("data-safety");
|
|
16152
16162
|
DataSafetyError = class extends Error {
|
|
16153
16163
|
constructor(message, code, context) {
|
|
16154
16164
|
super(message);
|
|
@@ -16188,7 +16198,7 @@ function isSafetyDisabled() {
|
|
|
16188
16198
|
}
|
|
16189
16199
|
function wrapWithSafety(accessor, cwd) {
|
|
16190
16200
|
if (isSafetyDisabled()) {
|
|
16191
|
-
|
|
16201
|
+
log4.warn(
|
|
16192
16202
|
"Safety disabled - emergency mode (CLEO_DISABLE_SAFETY=true). Data integrity checks bypassed."
|
|
16193
16203
|
);
|
|
16194
16204
|
return accessor;
|
|
@@ -16209,13 +16219,13 @@ function getSafetyStatus() {
|
|
|
16209
16219
|
enabled: true
|
|
16210
16220
|
};
|
|
16211
16221
|
}
|
|
16212
|
-
var
|
|
16222
|
+
var log4, SafetyDataAccessor;
|
|
16213
16223
|
var init_safety_data_accessor = __esm({
|
|
16214
16224
|
"packages/core/src/store/safety-data-accessor.ts"() {
|
|
16215
16225
|
"use strict";
|
|
16216
16226
|
init_logger();
|
|
16217
16227
|
init_data_safety_central();
|
|
16218
|
-
|
|
16228
|
+
log4 = getLogger("data-safety");
|
|
16219
16229
|
SafetyDataAccessor = class {
|
|
16220
16230
|
/** The underlying accessor being wrapped. */
|
|
16221
16231
|
inner;
|
|
@@ -16239,7 +16249,7 @@ var init_safety_data_accessor = __esm({
|
|
|
16239
16249
|
...config2
|
|
16240
16250
|
};
|
|
16241
16251
|
if (this.config.verbose) {
|
|
16242
|
-
|
|
16252
|
+
log4.debug({ engine: inner.engine }, "SafetyDataAccessor initialized");
|
|
16243
16253
|
}
|
|
16244
16254
|
}
|
|
16245
16255
|
/** The storage engine backing this accessor. */
|
|
@@ -16251,7 +16261,7 @@ var init_safety_data_accessor = __esm({
|
|
|
16251
16261
|
*/
|
|
16252
16262
|
logVerbose(message) {
|
|
16253
16263
|
if (this.config.verbose) {
|
|
16254
|
-
|
|
16264
|
+
log4.debug(message);
|
|
16255
16265
|
}
|
|
16256
16266
|
}
|
|
16257
16267
|
/**
|
|
@@ -20611,16 +20621,16 @@ async function queryAudit(options) {
|
|
|
20611
20621
|
error: row.errorMessage ?? void 0
|
|
20612
20622
|
}));
|
|
20613
20623
|
} catch (err) {
|
|
20614
|
-
|
|
20624
|
+
log5.warn({ err }, "Failed to query audit entries from SQLite");
|
|
20615
20625
|
return [];
|
|
20616
20626
|
}
|
|
20617
20627
|
}
|
|
20618
|
-
var
|
|
20628
|
+
var log5;
|
|
20619
20629
|
var init_audit = __esm({
|
|
20620
20630
|
"packages/core/src/audit.ts"() {
|
|
20621
20631
|
"use strict";
|
|
20622
20632
|
init_logger();
|
|
20623
|
-
|
|
20633
|
+
log5 = getLogger("audit");
|
|
20624
20634
|
}
|
|
20625
20635
|
});
|
|
20626
20636
|
|
|
@@ -52550,9 +52560,7 @@ async function completeTask(options, cwd, accessor) {
|
|
|
52550
52560
|
const parent = await acc.loadSingleTask(task.parentId);
|
|
52551
52561
|
if (parent && parent.type === "epic" && !parent.noAutoComplete) {
|
|
52552
52562
|
const siblings = await acc.getChildren(parent.id);
|
|
52553
|
-
const allDone = siblings.every(
|
|
52554
|
-
(c) => c.id === task.id || c.status === "done" || c.status === "cancelled"
|
|
52555
|
-
);
|
|
52563
|
+
const allDone = siblings.length > 0 && siblings.every((c) => c.id === task.id || c.status === "done" || c.status === "cancelled");
|
|
52556
52564
|
if (allDone) {
|
|
52557
52565
|
parent.status = "done";
|
|
52558
52566
|
parent.completedAt = now;
|
|
@@ -59571,7 +59579,7 @@ init_logger();
|
|
|
59571
59579
|
init_paths();
|
|
59572
59580
|
init_tasks_schema();
|
|
59573
59581
|
import { basename as basename6, relative as relative2 } from "node:path";
|
|
59574
|
-
var
|
|
59582
|
+
var log6 = getLogger("lifecycle:evidence");
|
|
59575
59583
|
async function recordEvidence(epicId, stage, uri, type, options) {
|
|
59576
59584
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
59577
59585
|
const stageId = `stage-${epicId}-${stage}`;
|
|
@@ -59598,7 +59606,7 @@ async function recordEvidence(epicId, stage, uri, type, options) {
|
|
|
59598
59606
|
description: options?.description ?? null
|
|
59599
59607
|
}).run();
|
|
59600
59608
|
} catch (err) {
|
|
59601
|
-
|
|
59609
|
+
log6.warn({ err }, "Failed to write evidence to SQLite");
|
|
59602
59610
|
}
|
|
59603
59611
|
return record2;
|
|
59604
59612
|
}
|
|
@@ -65897,7 +65905,7 @@ init_sqlite2();
|
|
|
65897
65905
|
init_tasks_schema();
|
|
65898
65906
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
65899
65907
|
import { and as and8, eq as eq11, sql as sql11 } from "drizzle-orm";
|
|
65900
|
-
var
|
|
65908
|
+
var log7 = getLogger("link-store");
|
|
65901
65909
|
async function getLinksByProvider(providerId, cwd) {
|
|
65902
65910
|
const db = await getDb(cwd);
|
|
65903
65911
|
const rows = await db.select().from(externalTaskLinks).where(eq11(externalTaskLinks.providerId, providerId));
|
|
@@ -65952,7 +65960,7 @@ async function ensureExternalTaskLinksTable(cwd) {
|
|
|
65952
65960
|
)
|
|
65953
65961
|
);
|
|
65954
65962
|
} catch (err) {
|
|
65955
|
-
|
|
65963
|
+
log7.warn({ err }, "Failed to ensure external_task_links table exists");
|
|
65956
65964
|
throw err;
|
|
65957
65965
|
}
|
|
65958
65966
|
}
|
|
@@ -66026,7 +66034,7 @@ init_brain_accessor();
|
|
|
66026
66034
|
init_brain_sqlite();
|
|
66027
66035
|
init_data_accessor();
|
|
66028
66036
|
init_registry3();
|
|
66029
|
-
var
|
|
66037
|
+
var log8 = getLogger("nexus:transfer");
|
|
66030
66038
|
async function previewTransfer(params) {
|
|
66031
66039
|
return executeTransferInternal({ ...params, dryRun: true });
|
|
66032
66040
|
}
|
|
@@ -66167,7 +66175,7 @@ async function executeTransferInternal(params) {
|
|
|
66167
66175
|
}
|
|
66168
66176
|
}
|
|
66169
66177
|
} catch (err) {
|
|
66170
|
-
|
|
66178
|
+
log8.warn(
|
|
66171
66179
|
{ err, linksCreated },
|
|
66172
66180
|
"Failed to create external_task_links during transfer \u2014 tasks were transferred successfully but provenance links could not be written"
|
|
66173
66181
|
);
|
|
@@ -66195,7 +66203,7 @@ async function executeTransferInternal(params) {
|
|
|
66195
66203
|
})
|
|
66196
66204
|
});
|
|
66197
66205
|
} catch (err) {
|
|
66198
|
-
|
|
66206
|
+
log8.warn({ err }, "nexus transfer audit write failed");
|
|
66199
66207
|
}
|
|
66200
66208
|
if (mode === "move") {
|
|
66201
66209
|
let archived = 0;
|
|
@@ -66208,7 +66216,7 @@ async function executeTransferInternal(params) {
|
|
|
66208
66216
|
});
|
|
66209
66217
|
archived++;
|
|
66210
66218
|
} catch (err) {
|
|
66211
|
-
|
|
66219
|
+
log8.warn({ err, taskId: entry.sourceId }, "failed to archive source task after transfer");
|
|
66212
66220
|
}
|
|
66213
66221
|
}
|
|
66214
66222
|
}
|
|
@@ -66246,7 +66254,7 @@ async function executeTransferInternal(params) {
|
|
|
66246
66254
|
}
|
|
66247
66255
|
}
|
|
66248
66256
|
} catch (err) {
|
|
66249
|
-
|
|
66257
|
+
log8.warn({ err }, "brain observation transfer failed");
|
|
66250
66258
|
}
|
|
66251
66259
|
result.brainObservationsTransferred = brainTransferred;
|
|
66252
66260
|
result.manifest.brainObservationsTransferred = brainTransferred;
|
|
@@ -66294,8 +66302,8 @@ async function loadProjectACL(projectPath) {
|
|
|
66294
66302
|
async function logAclFailure(projectPath) {
|
|
66295
66303
|
try {
|
|
66296
66304
|
const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
66297
|
-
const
|
|
66298
|
-
|
|
66305
|
+
const log11 = getLogger2("nexus.acl");
|
|
66306
|
+
log11.warn({ projectPath }, "Failed to load ACL configuration, defaulting to deny-all");
|
|
66299
66307
|
} catch {
|
|
66300
66308
|
}
|
|
66301
66309
|
}
|
|
@@ -66450,9 +66458,9 @@ async function executeOperation(operation, taskId, projectPath, accessor, direct
|
|
|
66450
66458
|
async function logRouteAudit(directive, projectName, taskId, operation, success2, error48) {
|
|
66451
66459
|
try {
|
|
66452
66460
|
const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
66453
|
-
const
|
|
66461
|
+
const log11 = getLogger2("nexus.route");
|
|
66454
66462
|
const level = success2 ? "info" : "warn";
|
|
66455
|
-
|
|
66463
|
+
log11[level](
|
|
66456
66464
|
{
|
|
66457
66465
|
directive: directive.verb,
|
|
66458
66466
|
agentId: directive.agentId,
|
|
@@ -75028,7 +75036,7 @@ init_data_accessor();
|
|
|
75028
75036
|
|
|
75029
75037
|
// packages/core/src/stats/workflow-telemetry.ts
|
|
75030
75038
|
init_logger();
|
|
75031
|
-
var
|
|
75039
|
+
var log9 = getLogger("workflow-telemetry");
|
|
75032
75040
|
async function queryTasks(cwd, since) {
|
|
75033
75041
|
try {
|
|
75034
75042
|
const { getDb: getDb3 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
|
|
@@ -75050,7 +75058,7 @@ async function queryTasks(cwd, since) {
|
|
|
75050
75058
|
}).from(tasks2).where(conditions.length > 0 ? and10(...conditions) : void 0).all();
|
|
75051
75059
|
return rows;
|
|
75052
75060
|
} catch (err) {
|
|
75053
|
-
|
|
75061
|
+
log9.warn({ err }, "Failed to query tasks for workflow telemetry");
|
|
75054
75062
|
return [];
|
|
75055
75063
|
}
|
|
75056
75064
|
}
|
|
@@ -75084,7 +75092,7 @@ async function queryCompletionAuditRows(cwd, since) {
|
|
|
75084
75092
|
return isComplete;
|
|
75085
75093
|
});
|
|
75086
75094
|
} catch (err) {
|
|
75087
|
-
|
|
75095
|
+
log9.warn({ err }, "Failed to query audit log for workflow telemetry");
|
|
75088
75096
|
return [];
|
|
75089
75097
|
}
|
|
75090
75098
|
}
|
|
@@ -76540,11 +76548,11 @@ import { join as join87 } from "node:path";
|
|
|
76540
76548
|
import { Readable } from "node:stream";
|
|
76541
76549
|
import { pipeline } from "node:stream/promises";
|
|
76542
76550
|
import { createGzip } from "node:zlib";
|
|
76543
|
-
var
|
|
76551
|
+
var log10 = getLogger("prune");
|
|
76544
76552
|
async function pruneAuditLog(cleoDir, config2) {
|
|
76545
76553
|
try {
|
|
76546
76554
|
if (!config2.auditRetentionDays || config2.auditRetentionDays <= 0) {
|
|
76547
|
-
|
|
76555
|
+
log10.debug("auditRetentionDays is 0 or unset; skipping audit prune");
|
|
76548
76556
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
76549
76557
|
}
|
|
76550
76558
|
const cutoff = new Date(Date.now() - config2.auditRetentionDays * 864e5).toISOString();
|
|
@@ -76555,7 +76563,7 @@ async function pruneAuditLog(cleoDir, config2) {
|
|
|
76555
76563
|
const db = await getDb3(projectRoot);
|
|
76556
76564
|
const oldRows = await db.select().from(auditLog2).where(lt3(auditLog2.timestamp, cutoff));
|
|
76557
76565
|
if (oldRows.length === 0) {
|
|
76558
|
-
|
|
76566
|
+
log10.debug("No audit_log rows older than cutoff; nothing to prune");
|
|
76559
76567
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
76560
76568
|
}
|
|
76561
76569
|
let archivePath;
|
|
@@ -76573,17 +76581,17 @@ async function pruneAuditLog(cleoDir, config2) {
|
|
|
76573
76581
|
const inStream = Readable.from([jsonlContent]);
|
|
76574
76582
|
await pipeline(inStream, gzip, outStream);
|
|
76575
76583
|
rowsArchived = oldRows.length;
|
|
76576
|
-
|
|
76584
|
+
log10.info(
|
|
76577
76585
|
{ archivePath, rowsArchived },
|
|
76578
76586
|
`Archived ${rowsArchived} audit rows to ${archivePath}`
|
|
76579
76587
|
);
|
|
76580
76588
|
} catch (archiveErr) {
|
|
76581
|
-
|
|
76589
|
+
log10.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
|
|
76582
76590
|
archivePath = void 0;
|
|
76583
76591
|
}
|
|
76584
76592
|
}
|
|
76585
76593
|
await db.delete(auditLog2).where(lt3(auditLog2.timestamp, cutoff)).run();
|
|
76586
|
-
|
|
76594
|
+
log10.info(
|
|
76587
76595
|
{ rowsDeleted: oldRows.length, cutoff },
|
|
76588
76596
|
`Pruned ${oldRows.length} audit_log rows older than ${cutoff}`
|
|
76589
76597
|
);
|
|
@@ -76593,7 +76601,7 @@ async function pruneAuditLog(cleoDir, config2) {
|
|
|
76593
76601
|
archivePath
|
|
76594
76602
|
};
|
|
76595
76603
|
} catch (err) {
|
|
76596
|
-
|
|
76604
|
+
log10.warn({ err }, "audit log pruning failed");
|
|
76597
76605
|
return { rowsArchived: 0, rowsDeleted: 0 };
|
|
76598
76606
|
}
|
|
76599
76607
|
}
|