@cleocode/core 2026.4.45 → 2026.4.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/internal.js CHANGED
@@ -11471,14 +11471,14 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
11471
11471
  const dbHashes = new Set(dbEntries.map((e) => e.hash));
11472
11472
  const allLocalHashesPresentInDb = localMigrations.every((m2) => dbHashes.has(m2.hash));
11473
11473
  if (allLocalHashesPresentInDb) {
11474
- const log11 = getLogger(logSubsystem);
11475
- log11.debug(
11474
+ const log12 = getLogger(logSubsystem);
11475
+ log12.debug(
11476
11476
  { extra: orphanedEntries.length },
11477
11477
  `Migration journal has ${orphanedEntries.length} entries for migrations not known to this install (DB is ahead). Skipping reconciliation.`
11478
11478
  );
11479
11479
  } else {
11480
- const log11 = getLogger(logSubsystem);
11481
- log11.warn(
11480
+ const log12 = getLogger(logSubsystem);
11481
+ log12.warn(
11482
11482
  { orphaned: orphanedEntries.length },
11483
11483
  `Detected stale migration journal entries from a previous CLEO version. Reconciling.`
11484
11484
  );
@@ -11509,8 +11509,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
11509
11509
  return cols.some((c) => c.name === column);
11510
11510
  });
11511
11511
  if (allColumnsExist) {
11512
- const log11 = getLogger(logSubsystem);
11513
- log11.warn(
11512
+ const log12 = getLogger(logSubsystem);
11513
+ log12.warn(
11514
11514
  { migration: migration.name, columns: alterMatches },
11515
11515
  `Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
11516
11516
  );
@@ -11528,8 +11528,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable, logSubsyst
11528
11528
  for (const entry of unnamedEntries) {
11529
11529
  const migrationName = hashToName.get(entry.hash);
11530
11530
  if (!migrationName) continue;
11531
- const log11 = getLogger(logSubsystem);
11532
- log11.warn(
11531
+ const log12 = getLogger(logSubsystem);
11532
+ log12.warn(
11533
11533
  { id: entry.id, hash: entry.hash, name: migrationName },
11534
11534
  `Backfilling missing name on journal entry id=${entry.id} \u2014 Drizzle v1 beta requires name for applied-migration detection.`
11535
11535
  );
@@ -11573,8 +11573,8 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem) {
11573
11573
  const existingCols = new Set(columns.map((c) => c.name));
11574
11574
  for (const req of requiredColumns) {
11575
11575
  if (!existingCols.has(req.name)) {
11576
- const log11 = getLogger(logSubsystem);
11577
- log11.warn(
11576
+ const log12 = getLogger(logSubsystem);
11577
+ log12.warn(
11578
11578
  { column: req.name },
11579
11579
  `Adding missing column ${tableName}.${req.name} via ALTER TABLE`
11580
11580
  );
@@ -13972,7 +13972,7 @@ function getDbPath(cwd) {
13972
13972
  return join10(getCleoDirAbsolute(cwd), DB_FILENAME2);
13973
13973
  }
13974
13974
  async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
13975
- const log11 = getLogger("sqlite");
13975
+ const log12 = getLogger("sqlite");
13976
13976
  try {
13977
13977
  const countResult = nativeDb.prepare("SELECT COUNT(*) as cnt FROM tasks").get();
13978
13978
  const taskCount = countResult?.cnt ?? 0;
@@ -13993,7 +13993,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
13993
13993
  if (backupTaskCount < MIN_BACKUP_TASK_COUNT) {
13994
13994
  return;
13995
13995
  }
13996
- log11.warn(
13996
+ log12.warn(
13997
13997
  { dbPath, backupPath: newestBackup.path, backupTasks: backupTaskCount },
13998
13998
  `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).`
13999
13999
  );
@@ -14011,7 +14011,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
14011
14011
  const tempPath = dbPath + ".recovery-tmp";
14012
14012
  copyFileSync4(newestBackup.path, tempPath);
14013
14013
  renameSync(tempPath, dbPath);
14014
- log11.info(
14014
+ log12.info(
14015
14015
  { dbPath, backupPath: newestBackup.path, restoredTasks: backupTaskCount },
14016
14016
  "Database auto-recovered from backup successfully."
14017
14017
  );
@@ -14021,7 +14021,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
14021
14021
  runMigrations(restoredNativeDb, restoredDb);
14022
14022
  _db = restoredDb;
14023
14023
  } catch (err) {
14024
- log11.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
14024
+ log12.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
14025
14025
  }
14026
14026
  }
14027
14027
  async function getDb(cwd) {
@@ -14055,7 +14055,7 @@ async function getDb(cwd) {
14055
14055
  const { execFileSync: execFileSync14 } = await import("node:child_process");
14056
14056
  const gitCwd = resolve3(dbPath, "..", "..");
14057
14057
  const filesToCheck = [dbPath, dbPath + "-wal", dbPath + "-shm"];
14058
- const log11 = getLogger("sqlite");
14058
+ const log12 = getLogger("sqlite");
14059
14059
  for (const fileToCheck of filesToCheck) {
14060
14060
  try {
14061
14061
  execFileSync14("git", ["ls-files", "--error-unmatch", fileToCheck], {
@@ -14064,7 +14064,7 @@ async function getDb(cwd) {
14064
14064
  });
14065
14065
  const basename18 = fileToCheck.split(/[\\/]/).pop();
14066
14066
  const relPath = fileToCheck.replace(gitCwd + sep, "");
14067
- log11.warn(
14067
+ log12.warn(
14068
14068
  { path: fileToCheck },
14069
14069
  `${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.`
14070
14070
  );
@@ -15258,11 +15258,18 @@ var init_cross_db_cleanup = __esm({
15258
15258
 
15259
15259
  // packages/core/src/store/db-helpers.ts
15260
15260
  import { eq as eq4, inArray as inArray2 } from "drizzle-orm";
15261
- async function upsertTask(db, row, archiveFields) {
15261
+ async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
15262
15262
  if (row.parentId) {
15263
15263
  const parent = await db.select({ id: tasks.id }).from(tasks).where(eq4(tasks.id, row.parentId)).limit(1).all();
15264
15264
  if (parent.length === 0) {
15265
- row = { ...row, parentId: null };
15265
+ if (allowOrphanParent) {
15266
+ row = { ...row, parentId: null };
15267
+ } else {
15268
+ log2.warn(
15269
+ { taskId: row.id, parentId: row.parentId },
15270
+ "upsertTask: parentId references a non-existent task \u2014 parent relationship may be lost"
15271
+ );
15272
+ }
15266
15273
  }
15267
15274
  }
15268
15275
  const values = archiveFields ? { ...row, ...archiveFields, status: "archived" } : row;
@@ -15406,10 +15413,13 @@ async function loadRelationsForTasks(db, tasks2) {
15406
15413
  }
15407
15414
  }
15408
15415
  }
15416
+ var log2;
15409
15417
  var init_db_helpers = __esm({
15410
15418
  "packages/core/src/store/db-helpers.ts"() {
15411
15419
  "use strict";
15420
+ init_logger();
15412
15421
  init_tasks_schema();
15422
+ log2 = getLogger("db-helpers");
15413
15423
  }
15414
15424
  });
15415
15425
 
@@ -15743,7 +15753,7 @@ async function createSqliteDataAccessor(cwd) {
15743
15753
  archiveReason: taskAny.archiveReason ?? "completed",
15744
15754
  cycleTimeDays: taskAny.cycleTimeDays ?? null
15745
15755
  };
15746
- await upsertTask(db, row, archiveFields);
15756
+ await upsertTask(db, row, archiveFields, true);
15747
15757
  depBatch.push({ taskId: task.id, deps: task.depends ?? [] });
15748
15758
  }
15749
15759
  await batchUpdateDependencies(db, depBatch, validDepIds);
@@ -16756,7 +16766,7 @@ async function ensureSequenceValid(cwd, options) {
16756
16766
  if (!options?.validateSequence) return;
16757
16767
  const check2 = await checkSequence(cwd);
16758
16768
  if (!check2.valid) {
16759
- log2.warn({ counter: check2.counter, maxId: check2.maxIdInData }, "Sequence behind, repairing");
16769
+ log3.warn({ counter: check2.counter, maxId: check2.maxIdInData }, "Sequence behind, repairing");
16760
16770
  const repair = await repairSequence(cwd);
16761
16771
  if (!repair.repaired && options.strict) {
16762
16772
  throw new DataSafetyError(`Sequence repair failed: ${repair.message}`, "SEQUENCE_INVALID", {
@@ -16773,7 +16783,7 @@ async function checkpoint(context, cwd, options) {
16773
16783
  stats.checkpoints++;
16774
16784
  stats.lastCheckpoint = /* @__PURE__ */ new Date();
16775
16785
  } catch (err) {
16776
- log2.warn({ err }, "Checkpoint failed (non-fatal)");
16786
+ log3.warn({ err }, "Checkpoint failed (non-fatal)");
16777
16787
  }
16778
16788
  vacuumIntoBackup({ cwd }).catch(() => {
16779
16789
  });
@@ -16835,7 +16845,7 @@ async function safeAppendLog(accessor, entry, cwd, options) {
16835
16845
  stats.writes++;
16836
16846
  await checkpoint("log entry", cwd, opts);
16837
16847
  }
16838
- var log2, DataSafetyError, DEFAULT_SAFETY, stats;
16848
+ var log3, DataSafetyError, DEFAULT_SAFETY, stats;
16839
16849
  var init_data_safety_central = __esm({
16840
16850
  "packages/core/src/store/data-safety-central.ts"() {
16841
16851
  "use strict";
@@ -16843,7 +16853,7 @@ var init_data_safety_central = __esm({
16843
16853
  init_sequence();
16844
16854
  init_git_checkpoint();
16845
16855
  init_sqlite_backup();
16846
- log2 = getLogger("data-safety");
16856
+ log3 = getLogger("data-safety");
16847
16857
  DataSafetyError = class extends Error {
16848
16858
  constructor(message, code, context) {
16849
16859
  super(message);
@@ -16883,7 +16893,7 @@ function isSafetyDisabled() {
16883
16893
  }
16884
16894
  function wrapWithSafety(accessor, cwd) {
16885
16895
  if (isSafetyDisabled()) {
16886
- log3.warn(
16896
+ log4.warn(
16887
16897
  "Safety disabled - emergency mode (CLEO_DISABLE_SAFETY=true). Data integrity checks bypassed."
16888
16898
  );
16889
16899
  return accessor;
@@ -16904,13 +16914,13 @@ function getSafetyStatus() {
16904
16914
  enabled: true
16905
16915
  };
16906
16916
  }
16907
- var log3, SafetyDataAccessor;
16917
+ var log4, SafetyDataAccessor;
16908
16918
  var init_safety_data_accessor = __esm({
16909
16919
  "packages/core/src/store/safety-data-accessor.ts"() {
16910
16920
  "use strict";
16911
16921
  init_logger();
16912
16922
  init_data_safety_central();
16913
- log3 = getLogger("data-safety");
16923
+ log4 = getLogger("data-safety");
16914
16924
  SafetyDataAccessor = class {
16915
16925
  /** The underlying accessor being wrapped. */
16916
16926
  inner;
@@ -16934,7 +16944,7 @@ var init_safety_data_accessor = __esm({
16934
16944
  ...config2
16935
16945
  };
16936
16946
  if (this.config.verbose) {
16937
- log3.debug({ engine: inner.engine }, "SafetyDataAccessor initialized");
16947
+ log4.debug({ engine: inner.engine }, "SafetyDataAccessor initialized");
16938
16948
  }
16939
16949
  }
16940
16950
  /** The storage engine backing this accessor. */
@@ -16946,7 +16956,7 @@ var init_safety_data_accessor = __esm({
16946
16956
  */
16947
16957
  logVerbose(message) {
16948
16958
  if (this.config.verbose) {
16949
- log3.debug(message);
16959
+ log4.debug(message);
16950
16960
  }
16951
16961
  }
16952
16962
  /**
@@ -21347,16 +21357,16 @@ async function queryAudit(options) {
21347
21357
  error: row.errorMessage ?? void 0
21348
21358
  }));
21349
21359
  } catch (err) {
21350
- log4.warn({ err }, "Failed to query audit entries from SQLite");
21360
+ log5.warn({ err }, "Failed to query audit entries from SQLite");
21351
21361
  return [];
21352
21362
  }
21353
21363
  }
21354
- var log4;
21364
+ var log5;
21355
21365
  var init_audit = __esm({
21356
21366
  "packages/core/src/audit.ts"() {
21357
21367
  "use strict";
21358
21368
  init_logger();
21359
- log4 = getLogger("audit");
21369
+ log5 = getLogger("audit");
21360
21370
  }
21361
21371
  });
21362
21372
 
@@ -43701,13 +43711,16 @@ async function runTierPromotion(projectRoot) {
43701
43711
  try {
43702
43712
  shortToMedium = typedAll(
43703
43713
  nativeDb.prepare(`
43704
- SELECT id, citation_count, quality_score
43714
+ SELECT id, citation_count, quality_score, verified
43705
43715
  FROM ${table}
43706
43716
  WHERE memory_tier = 'short'
43707
43717
  AND invalid_at IS NULL
43708
43718
  AND ${dateCol} < ?
43709
- AND verified = 1
43710
- AND (citation_count >= 3 OR quality_score >= 0.7)
43719
+ AND (
43720
+ citation_count >= 3
43721
+ OR quality_score >= 0.7
43722
+ OR verified = 1
43723
+ )
43711
43724
  `),
43712
43725
  age24h
43713
43726
  );
@@ -43717,13 +43730,15 @@ async function runTierPromotion(projectRoot) {
43717
43730
  for (const row of shortToMedium) {
43718
43731
  try {
43719
43732
  nativeDb.prepare(`UPDATE ${table} SET memory_tier = 'medium', updated_at = ? WHERE id = ?`).run(now2, row.id);
43720
- promoted.push({
43721
- id: row.id,
43722
- table,
43723
- fromTier: "short",
43724
- toTier: "medium",
43725
- reason: row.citation_count >= 3 ? `citationCount=${row.citation_count} >= 3, verified, age > 24h` : `qualityScore=${row.quality_score?.toFixed(2)} >= 0.70, verified, age > 24h`
43726
- });
43733
+ let reason;
43734
+ if (row.citation_count >= 3) {
43735
+ reason = `citationCount=${row.citation_count} >= 3, age > 24h`;
43736
+ } else if ((row.quality_score ?? 0) >= 0.7) {
43737
+ reason = `qualityScore=${row.quality_score?.toFixed(2)} >= 0.70, age > 24h`;
43738
+ } else {
43739
+ reason = `verified=true, age > 24h`;
43740
+ }
43741
+ promoted.push({ id: row.id, table, fromTier: "short", toTier: "medium", reason });
43727
43742
  } catch {
43728
43743
  }
43729
43744
  }
@@ -43731,13 +43746,12 @@ async function runTierPromotion(projectRoot) {
43731
43746
  try {
43732
43747
  mediumToLong = typedAll(
43733
43748
  nativeDb.prepare(`
43734
- SELECT id, citation_count, quality_score
43749
+ SELECT id, citation_count, quality_score, verified
43735
43750
  FROM ${table}
43736
43751
  WHERE memory_tier = 'medium'
43737
43752
  AND invalid_at IS NULL
43738
43753
  AND ${dateCol} < ?
43739
- AND verified = 1
43740
- AND citation_count >= 5
43754
+ AND (citation_count >= 5 OR verified = 1)
43741
43755
  `),
43742
43756
  age7d
43743
43757
  );
@@ -43747,13 +43761,8 @@ async function runTierPromotion(projectRoot) {
43747
43761
  for (const row of mediumToLong) {
43748
43762
  try {
43749
43763
  nativeDb.prepare(`UPDATE ${table} SET memory_tier = 'long', updated_at = ? WHERE id = ?`).run(now2, row.id);
43750
- promoted.push({
43751
- id: row.id,
43752
- table,
43753
- fromTier: "medium",
43754
- toTier: "long",
43755
- reason: `citationCount=${row.citation_count} >= 5, verified, age > 7d`
43756
- });
43764
+ const reason = row.citation_count >= 5 ? `citationCount=${row.citation_count} >= 5, age > 7d` : `verified=true, age > 7d`;
43765
+ promoted.push({ id: row.id, table, fromTier: "medium", toTier: "long", reason });
43757
43766
  } catch {
43758
43767
  }
43759
43768
  }
@@ -54112,9 +54121,7 @@ async function completeTask(options, cwd, accessor) {
54112
54121
  const parent = await acc.loadSingleTask(task.parentId);
54113
54122
  if (parent && parent.type === "epic" && !parent.noAutoComplete) {
54114
54123
  const siblings = await acc.getChildren(parent.id);
54115
- const allDone = siblings.every(
54116
- (c) => c.id === task.id || c.status === "done" || c.status === "cancelled"
54117
- );
54124
+ const allDone = siblings.length > 0 && siblings.every((c) => c.id === task.id || c.status === "done" || c.status === "cancelled");
54118
54125
  if (allDone) {
54119
54126
  parent.status = "done";
54120
54127
  parent.completedAt = now2;
@@ -58253,7 +58260,7 @@ async function validateAndRepairSequence(cwd, config2 = {}) {
58253
58260
  }
58254
58261
  const repair = await repairSequence(cwd);
58255
58262
  if (repair.repaired) {
58256
- log10.warn(
58263
+ log11.warn(
58257
58264
  { oldCounter: repair.oldCounter, newCounter: repair.newCounter },
58258
58265
  "Sequence repaired"
58259
58266
  );
@@ -58282,7 +58289,7 @@ async function triggerCheckpoint(context, cwd, config2 = {}) {
58282
58289
  try {
58283
58290
  await gitCheckpoint("auto", context, cwd);
58284
58291
  } catch (err) {
58285
- log10.warn({ err }, "Checkpoint failed (non-fatal)");
58292
+ log11.warn({ err }, "Checkpoint failed (non-fatal)");
58286
58293
  }
58287
58294
  vacuumIntoBackup({ cwd }).catch(() => {
58288
58295
  });
@@ -58320,16 +58327,16 @@ async function safeDeleteTask(deleteFn, taskId, cwd, config2 = {}) {
58320
58327
  return result;
58321
58328
  }
58322
58329
  async function forceCheckpointBeforeOperation(operation, cwd) {
58323
- log10.info({ operation }, "Forcing checkpoint before operation");
58330
+ log11.info({ operation }, "Forcing checkpoint before operation");
58324
58331
  try {
58325
58332
  await gitCheckpoint("manual", `pre-${operation}`, cwd);
58326
58333
  } catch (err) {
58327
- log10.error({ err }, "Failed to create pre-operation checkpoint");
58334
+ log11.error({ err }, "Failed to create pre-operation checkpoint");
58328
58335
  }
58329
58336
  vacuumIntoBackup({ cwd, force: true }).catch(() => {
58330
58337
  });
58331
58338
  }
58332
- var log10, DEFAULT_CONFIG2, SafetyError;
58339
+ var log11, DEFAULT_CONFIG2, SafetyError;
58333
58340
  var init_data_safety = __esm({
58334
58341
  "packages/core/src/store/data-safety.ts"() {
58335
58342
  "use strict";
@@ -58339,7 +58346,7 @@ var init_data_safety = __esm({
58339
58346
  init_sqlite2();
58340
58347
  init_sqlite_backup();
58341
58348
  init_tasks_schema();
58342
- log10 = getLogger("data-safety");
58349
+ log11 = getLogger("data-safety");
58343
58350
  DEFAULT_CONFIG2 = {
58344
58351
  verifyWrites: true,
58345
58352
  detectCollisions: true,
@@ -63649,11 +63656,11 @@ var require_core = __commonJS({
63649
63656
  Ajv4.ValidationError = validation_error_1.default;
63650
63657
  Ajv4.MissingRefError = ref_error_1.default;
63651
63658
  exports.default = Ajv4;
63652
- function checkOptions(checkOpts, options, msg, log11 = "error") {
63659
+ function checkOptions(checkOpts, options, msg, log12 = "error") {
63653
63660
  for (const key in checkOpts) {
63654
63661
  const opt = key;
63655
63662
  if (opt in options)
63656
- this.logger[log11](`${msg}: option ${key}. ${checkOpts[opt]}`);
63663
+ this.logger[log12](`${msg}: option ${key}. ${checkOpts[opt]}`);
63657
63664
  }
63658
63665
  }
63659
63666
  function getSchEnv(keyRef) {
@@ -71017,7 +71024,7 @@ init_logger();
71017
71024
  init_paths();
71018
71025
  init_tasks_schema();
71019
71026
  import { basename as basename6, relative as relative2 } from "node:path";
71020
- var log5 = getLogger("lifecycle:evidence");
71027
+ var log6 = getLogger("lifecycle:evidence");
71021
71028
  async function recordEvidence(epicId, stage, uri, type, options) {
71022
71029
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
71023
71030
  const stageId = `stage-${epicId}-${stage}`;
@@ -71044,7 +71051,7 @@ async function recordEvidence(epicId, stage, uri, type, options) {
71044
71051
  description: options?.description ?? null
71045
71052
  }).run();
71046
71053
  } catch (err) {
71047
- log5.warn({ err }, "Failed to write evidence to SQLite");
71054
+ log6.warn({ err }, "Failed to write evidence to SQLite");
71048
71055
  }
71049
71056
  return record2;
71050
71057
  }
@@ -76782,7 +76789,7 @@ init_sqlite2();
76782
76789
  init_tasks_schema();
76783
76790
  import { randomUUID as randomUUID5 } from "node:crypto";
76784
76791
  import { and as and8, eq as eq11, sql as sql11 } from "drizzle-orm";
76785
- var log6 = getLogger("link-store");
76792
+ var log7 = getLogger("link-store");
76786
76793
  async function getLinksByProvider(providerId, cwd) {
76787
76794
  const db = await getDb(cwd);
76788
76795
  const rows = await db.select().from(externalTaskLinks).where(eq11(externalTaskLinks.providerId, providerId));
@@ -76837,7 +76844,7 @@ async function ensureExternalTaskLinksTable(cwd) {
76837
76844
  )
76838
76845
  );
76839
76846
  } catch (err) {
76840
- log6.warn({ err }, "Failed to ensure external_task_links table exists");
76847
+ log7.warn({ err }, "Failed to ensure external_task_links table exists");
76841
76848
  throw err;
76842
76849
  }
76843
76850
  }
@@ -76911,7 +76918,7 @@ init_brain_accessor();
76911
76918
  init_brain_sqlite();
76912
76919
  init_data_accessor();
76913
76920
  init_registry3();
76914
- var log7 = getLogger("nexus:transfer");
76921
+ var log8 = getLogger("nexus:transfer");
76915
76922
  async function previewTransfer(params) {
76916
76923
  return executeTransferInternal({ ...params, dryRun: true });
76917
76924
  }
@@ -77052,7 +77059,7 @@ async function executeTransferInternal(params) {
77052
77059
  }
77053
77060
  }
77054
77061
  } catch (err) {
77055
- log7.warn(
77062
+ log8.warn(
77056
77063
  { err, linksCreated },
77057
77064
  "Failed to create external_task_links during transfer \u2014 tasks were transferred successfully but provenance links could not be written"
77058
77065
  );
@@ -77080,7 +77087,7 @@ async function executeTransferInternal(params) {
77080
77087
  })
77081
77088
  });
77082
77089
  } catch (err) {
77083
- log7.warn({ err }, "nexus transfer audit write failed");
77090
+ log8.warn({ err }, "nexus transfer audit write failed");
77084
77091
  }
77085
77092
  if (mode === "move") {
77086
77093
  let archived = 0;
@@ -77093,7 +77100,7 @@ async function executeTransferInternal(params) {
77093
77100
  });
77094
77101
  archived++;
77095
77102
  } catch (err) {
77096
- log7.warn({ err, taskId: entry.sourceId }, "failed to archive source task after transfer");
77103
+ log8.warn({ err, taskId: entry.sourceId }, "failed to archive source task after transfer");
77097
77104
  }
77098
77105
  }
77099
77106
  }
@@ -77131,7 +77138,7 @@ async function executeTransferInternal(params) {
77131
77138
  }
77132
77139
  }
77133
77140
  } catch (err) {
77134
- log7.warn({ err }, "brain observation transfer failed");
77141
+ log8.warn({ err }, "brain observation transfer failed");
77135
77142
  }
77136
77143
  result.brainObservationsTransferred = brainTransferred;
77137
77144
  result.manifest.brainObservationsTransferred = brainTransferred;
@@ -77179,8 +77186,8 @@ async function loadProjectACL(projectPath) {
77179
77186
  async function logAclFailure(projectPath) {
77180
77187
  try {
77181
77188
  const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
77182
- const log11 = getLogger2("nexus.acl");
77183
- log11.warn({ projectPath }, "Failed to load ACL configuration, defaulting to deny-all");
77189
+ const log12 = getLogger2("nexus.acl");
77190
+ log12.warn({ projectPath }, "Failed to load ACL configuration, defaulting to deny-all");
77184
77191
  } catch {
77185
77192
  }
77186
77193
  }
@@ -77335,9 +77342,9 @@ async function executeOperation(operation, taskId, projectPath, accessor, direct
77335
77342
  async function logRouteAudit(directive, projectName, taskId, operation, success2, error48) {
77336
77343
  try {
77337
77344
  const { getLogger: getLogger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
77338
- const log11 = getLogger2("nexus.route");
77345
+ const log12 = getLogger2("nexus.route");
77339
77346
  const level = success2 ? "info" : "warn";
77340
- log11[level](
77347
+ log12[level](
77341
77348
  {
77342
77349
  directive: directive.verb,
77343
77350
  agentId: directive.agentId,
@@ -85909,7 +85916,7 @@ init_data_accessor();
85909
85916
 
85910
85917
  // packages/core/src/stats/workflow-telemetry.ts
85911
85918
  init_logger();
85912
- var log8 = getLogger("workflow-telemetry");
85919
+ var log9 = getLogger("workflow-telemetry");
85913
85920
  async function queryTasks(cwd, since) {
85914
85921
  try {
85915
85922
  const { getDb: getDb4 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
@@ -85931,7 +85938,7 @@ async function queryTasks(cwd, since) {
85931
85938
  }).from(tasks2).where(conditions.length > 0 ? and13(...conditions) : void 0).all();
85932
85939
  return rows;
85933
85940
  } catch (err) {
85934
- log8.warn({ err }, "Failed to query tasks for workflow telemetry");
85941
+ log9.warn({ err }, "Failed to query tasks for workflow telemetry");
85935
85942
  return [];
85936
85943
  }
85937
85944
  }
@@ -85965,7 +85972,7 @@ async function queryCompletionAuditRows(cwd, since) {
85965
85972
  return isComplete;
85966
85973
  });
85967
85974
  } catch (err) {
85968
- log8.warn({ err }, "Failed to query audit log for workflow telemetry");
85975
+ log9.warn({ err }, "Failed to query audit log for workflow telemetry");
85969
85976
  return [];
85970
85977
  }
85971
85978
  }
@@ -87451,11 +87458,11 @@ import { join as join88 } from "node:path";
87451
87458
  import { Readable } from "node:stream";
87452
87459
  import { pipeline } from "node:stream/promises";
87453
87460
  import { createGzip } from "node:zlib";
87454
- var log9 = getLogger("prune");
87461
+ var log10 = getLogger("prune");
87455
87462
  async function pruneAuditLog(cleoDir, config2) {
87456
87463
  try {
87457
87464
  if (!config2.auditRetentionDays || config2.auditRetentionDays <= 0) {
87458
- log9.debug("auditRetentionDays is 0 or unset; skipping audit prune");
87465
+ log10.debug("auditRetentionDays is 0 or unset; skipping audit prune");
87459
87466
  return { rowsArchived: 0, rowsDeleted: 0 };
87460
87467
  }
87461
87468
  const cutoff = new Date(Date.now() - config2.auditRetentionDays * 864e5).toISOString();
@@ -87466,7 +87473,7 @@ async function pruneAuditLog(cleoDir, config2) {
87466
87473
  const db = await getDb4(projectRoot);
87467
87474
  const oldRows = await db.select().from(auditLog2).where(lt4(auditLog2.timestamp, cutoff));
87468
87475
  if (oldRows.length === 0) {
87469
- log9.debug("No audit_log rows older than cutoff; nothing to prune");
87476
+ log10.debug("No audit_log rows older than cutoff; nothing to prune");
87470
87477
  return { rowsArchived: 0, rowsDeleted: 0 };
87471
87478
  }
87472
87479
  let archivePath;
@@ -87484,17 +87491,17 @@ async function pruneAuditLog(cleoDir, config2) {
87484
87491
  const inStream = Readable.from([jsonlContent]);
87485
87492
  await pipeline(inStream, gzip, outStream);
87486
87493
  rowsArchived = oldRows.length;
87487
- log9.info(
87494
+ log10.info(
87488
87495
  { archivePath, rowsArchived },
87489
87496
  `Archived ${rowsArchived} audit rows to ${archivePath}`
87490
87497
  );
87491
87498
  } catch (archiveErr) {
87492
- log9.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
87499
+ log10.warn({ err: archiveErr }, "Failed to archive audit rows; continuing with deletion");
87493
87500
  archivePath = void 0;
87494
87501
  }
87495
87502
  }
87496
87503
  await db.delete(auditLog2).where(lt4(auditLog2.timestamp, cutoff)).run();
87497
- log9.info(
87504
+ log10.info(
87498
87505
  { rowsDeleted: oldRows.length, cutoff },
87499
87506
  `Pruned ${oldRows.length} audit_log rows older than ${cutoff}`
87500
87507
  );
@@ -87504,7 +87511,7 @@ async function pruneAuditLog(cleoDir, config2) {
87504
87511
  archivePath
87505
87512
  };
87506
87513
  } catch (err) {
87507
- log9.warn({ err }, "audit log pruning failed");
87514
+ log10.warn({ err }, "audit log pruning failed");
87508
87515
  return { rowsArchived: 0, rowsDeleted: 0 };
87509
87516
  }
87510
87517
  }
@@ -96585,6 +96592,7 @@ async function runBrainMaintenance(projectRoot, options) {
96585
96592
  skipDecay = false,
96586
96593
  skipConsolidation = false,
96587
96594
  skipReconciliation = false,
96595
+ skipTierPromotion = false,
96588
96596
  skipEmbeddings = false,
96589
96597
  onProgress
96590
96598
  } = options ?? {};
@@ -96596,6 +96604,7 @@ async function runBrainMaintenance(projectRoot, options) {
96596
96604
  observationsFixed: 0,
96597
96605
  linksRemoved: 0
96598
96606
  };
96607
+ const tierPromotionResult = { promoted: 0, evicted: 0 };
96599
96608
  const embeddingsResult = {
96600
96609
  processed: 0,
96601
96610
  skipped: 0,
@@ -96622,6 +96631,13 @@ async function runBrainMaintenance(projectRoot, options) {
96622
96631
  reconciliationResult.linksRemoved = raw.linksRemoved;
96623
96632
  onProgress?.("reconciliation", 1, 1);
96624
96633
  }
96634
+ if (!skipTierPromotion) {
96635
+ onProgress?.("tier-promotion", 0, 1);
96636
+ const raw = await runTierPromotion(projectRoot);
96637
+ tierPromotionResult.promoted = raw.promoted.length;
96638
+ tierPromotionResult.evicted = raw.evicted.length;
96639
+ onProgress?.("tier-promotion", 1, 1);
96640
+ }
96625
96641
  if (!skipEmbeddings) {
96626
96642
  const raw = await populateEmbeddings(projectRoot, {
96627
96643
  onProgress: (current, total) => {
@@ -96636,6 +96652,7 @@ async function runBrainMaintenance(projectRoot, options) {
96636
96652
  decay: decayResult,
96637
96653
  consolidation: consolidationResult,
96638
96654
  reconciliation: reconciliationResult,
96655
+ tierPromotion: tierPromotionResult,
96639
96656
  embeddings: embeddingsResult,
96640
96657
  duration: Date.now() - startTime
96641
96658
  };
@@ -102838,7 +102855,7 @@ var LEGACY_FILES = [
102838
102855
  "nexus-pre-cleo.db.bak"
102839
102856
  ];
102840
102857
  function detectAndRemoveLegacyGlobalFiles(cleoHomeOverride) {
102841
- const log11 = getLogger("cleanup-legacy");
102858
+ const log12 = getLogger("cleanup-legacy");
102842
102859
  const cleoHome = cleoHomeOverride ?? getCleoHome();
102843
102860
  const removed = [];
102844
102861
  const errors = [];
@@ -102848,30 +102865,30 @@ function detectAndRemoveLegacyGlobalFiles(cleoHomeOverride) {
102848
102865
  if (fs5.existsSync(fullPath)) {
102849
102866
  fs5.unlinkSync(fullPath);
102850
102867
  removed.push(fileName);
102851
- log11.info({ file: fullPath }, "Removed legacy global file");
102868
+ log12.info({ file: fullPath }, "Removed legacy global file");
102852
102869
  }
102853
102870
  } catch (err) {
102854
102871
  const message = err instanceof Error ? err.message : String(err);
102855
102872
  errors.push({ file: fileName, error: message });
102856
- log11.warn({ file: fullPath, error: message }, "Failed to remove legacy global file");
102873
+ log12.warn({ file: fullPath, error: message }, "Failed to remove legacy global file");
102857
102874
  }
102858
102875
  }
102859
102876
  return { removed, errors };
102860
102877
  }
102861
102878
  function detectAndRemoveStrayProjectNexus(projectRoot) {
102862
- const log11 = getLogger("cleanup-legacy");
102879
+ const log12 = getLogger("cleanup-legacy");
102863
102880
  const strayPath = path5.join(projectRoot, ".cleo", "nexus.db");
102864
102881
  if (fs5.existsSync(strayPath)) {
102865
102882
  try {
102866
102883
  fs5.unlinkSync(strayPath);
102867
- log11.warn(
102884
+ log12.warn(
102868
102885
  { path: strayPath },
102869
102886
  "Removed stray project-tier nexus.db (violates ADR-036 global-only contract)"
102870
102887
  );
102871
102888
  return { removed: true, path: strayPath };
102872
102889
  } catch (err) {
102873
102890
  const message = err instanceof Error ? err.message : String(err);
102874
- log11.warn(
102891
+ log12.warn(
102875
102892
  { path: strayPath, error: message },
102876
102893
  "Failed to remove stray project-tier nexus.db \u2014 manual deletion may be required"
102877
102894
  );
@@ -102964,7 +102981,7 @@ function brokenTimestamp() {
102964
102981
  return `${now2.getFullYear()}${pad2(now2.getMonth() + 1)}${pad2(now2.getDate())}-${pad2(now2.getHours())}${pad2(now2.getMinutes())}${pad2(now2.getSeconds())}-${pad3(now2.getMilliseconds())}`;
102965
102982
  }
102966
102983
  function migrateSignaldockToConduit(projectRoot) {
102967
- const log11 = getLogger("migrate-signaldock-to-conduit");
102984
+ const log12 = getLogger("migrate-signaldock-to-conduit");
102968
102985
  const legacyPath = join112(projectRoot, ".cleo", "signaldock.db");
102969
102986
  const conduitPath = join112(projectRoot, ".cleo", "conduit.db");
102970
102987
  const globalSignaldockPath = join112(getCleoHome(), "signaldock.db");
@@ -102981,13 +102998,13 @@ function migrateSignaldockToConduit(projectRoot) {
102981
102998
  if (!needsSignaldockToConduitMigration(projectRoot)) {
102982
102999
  return result;
102983
103000
  }
102984
- log11.info({ projectRoot, legacyPath }, "T310 migration: starting signaldock.db \u2192 conduit.db");
103001
+ log12.info({ projectRoot, legacyPath }, "T310 migration: starting signaldock.db \u2192 conduit.db");
102985
103002
  let legacy = null;
102986
103003
  try {
102987
103004
  legacy = new DatabaseSync7(legacyPath, { readOnly: true });
102988
103005
  } catch (err) {
102989
103006
  const message = err instanceof Error ? err.message : String(err);
102990
- log11.error({ legacyPath, error: message }, "T310 migration: cannot open legacy signaldock.db");
103007
+ log12.error({ legacyPath, error: message }, "T310 migration: cannot open legacy signaldock.db");
102991
103008
  result.errors.push({ step: "step-2-open-legacy", error: message });
102992
103009
  result.status = "failed";
102993
103010
  return result;
@@ -102995,7 +103012,7 @@ function migrateSignaldockToConduit(projectRoot) {
102995
103012
  try {
102996
103013
  if (!integrityCheckPasses(legacy)) {
102997
103014
  const msg = "Legacy signaldock.db failed PRAGMA integrity_check. Migration aborted \u2014 no changes written. Recovery: inspect the database with sqlite3 and attempt manual repair before re-running.";
102998
- log11.error({ legacyPath }, msg);
103015
+ log12.error({ legacyPath }, msg);
102999
103016
  result.errors.push({ step: "step-3-legacy-integrity", error: msg });
103000
103017
  result.status = "failed";
103001
103018
  legacy.close();
@@ -103003,7 +103020,7 @@ function migrateSignaldockToConduit(projectRoot) {
103003
103020
  }
103004
103021
  } catch (err) {
103005
103022
  const message = err instanceof Error ? err.message : String(err);
103006
- log11.error({ legacyPath, error: message }, "T310 migration: integrity_check threw on legacy DB");
103023
+ log12.error({ legacyPath, error: message }, "T310 migration: integrity_check threw on legacy DB");
103007
103024
  result.errors.push({ step: "step-3-legacy-integrity", error: message });
103008
103025
  result.status = "failed";
103009
103026
  legacy.close();
@@ -103021,7 +103038,7 @@ function migrateSignaldockToConduit(projectRoot) {
103021
103038
  getGlobalSalt();
103022
103039
  } catch (err) {
103023
103040
  const message = err instanceof Error ? err.message : String(err);
103024
- log11.error({ error: message }, "T310 migration: getGlobalSalt failed \u2014 migration aborted");
103041
+ log12.error({ error: message }, "T310 migration: getGlobalSalt failed \u2014 migration aborted");
103025
103042
  result.errors.push({ step: "step-6-global-salt", error: message });
103026
103043
  result.status = "failed";
103027
103044
  legacy.close();
@@ -103035,7 +103052,7 @@ function migrateSignaldockToConduit(projectRoot) {
103035
103052
  conduit.exec("PRAGMA foreign_keys = OFF");
103036
103053
  } catch (err) {
103037
103054
  const message = err instanceof Error ? err.message : String(err);
103038
- log11.error({ conduitPath, error: message }, "T310 migration: failed to create conduit.db");
103055
+ log12.error({ conduitPath, error: message }, "T310 migration: failed to create conduit.db");
103039
103056
  result.errors.push({ step: "step-7-create-conduit", error: message });
103040
103057
  result.status = "failed";
103041
103058
  legacy.close();
@@ -103081,7 +103098,7 @@ function migrateSignaldockToConduit(projectRoot) {
103081
103098
  result.agentsCopied = agentsCountForConduit;
103082
103099
  } catch (err) {
103083
103100
  const message = err instanceof Error ? err.message : String(err);
103084
- log11.error({ error: message }, "T310 migration: conduit.db write failed \u2014 rolling back");
103101
+ log12.error({ error: message }, "T310 migration: conduit.db write failed \u2014 rolling back");
103085
103102
  result.errors.push({ step: "step-8-conduit-write", error: message });
103086
103103
  result.status = "failed";
103087
103104
  try {
@@ -103102,7 +103119,7 @@ function migrateSignaldockToConduit(projectRoot) {
103102
103119
  try {
103103
103120
  if (!integrityCheckPasses(conduit)) {
103104
103121
  const msg = "conduit.db failed PRAGMA integrity_check after write";
103105
- log11.error({ conduitPath }, msg);
103122
+ log12.error({ conduitPath }, msg);
103106
103123
  result.errors.push({ step: "step-10-conduit-integrity", error: msg });
103107
103124
  result.status = "failed";
103108
103125
  conduit.close();
@@ -103117,7 +103134,7 @@ function migrateSignaldockToConduit(projectRoot) {
103117
103134
  }
103118
103135
  } catch (err) {
103119
103136
  const message = err instanceof Error ? err.message : String(err);
103120
- log11.error({ error: message }, "T310 migration: conduit.db integrity_check threw");
103137
+ log12.error({ error: message }, "T310 migration: conduit.db integrity_check threw");
103121
103138
  result.errors.push({ step: "step-10-conduit-integrity", error: message });
103122
103139
  result.status = "failed";
103123
103140
  if (conduit) {
@@ -103139,7 +103156,7 @@ function migrateSignaldockToConduit(projectRoot) {
103139
103156
  globalDb.exec("PRAGMA foreign_keys = OFF");
103140
103157
  } catch (err) {
103141
103158
  const message = err instanceof Error ? err.message : String(err);
103142
- log11.error(
103159
+ log12.error(
103143
103160
  { globalSignaldockPath, error: message },
103144
103161
  "T310 migration: cannot open global signaldock.db"
103145
103162
  );
@@ -103178,7 +103195,7 @@ function migrateSignaldockToConduit(projectRoot) {
103178
103195
  result.agentsCopied = agentsCopiedToGlobal;
103179
103196
  } catch (err) {
103180
103197
  const message = err instanceof Error ? err.message : String(err);
103181
- log11.error(
103198
+ log12.error(
103182
103199
  { error: message },
103183
103200
  "T310 migration: global signaldock.db write failed \u2014 rolling back"
103184
103201
  );
@@ -103196,7 +103213,7 @@ function migrateSignaldockToConduit(projectRoot) {
103196
103213
  try {
103197
103214
  if (!integrityCheckPasses(globalDb)) {
103198
103215
  const msg = "Global signaldock.db failed PRAGMA integrity_check after write";
103199
- log11.error({ globalSignaldockPath }, msg);
103216
+ log12.error({ globalSignaldockPath }, msg);
103200
103217
  result.errors.push({ step: "step-14-global-integrity", error: msg });
103201
103218
  result.status = "failed";
103202
103219
  globalDb.close();
@@ -103211,7 +103228,7 @@ function migrateSignaldockToConduit(projectRoot) {
103211
103228
  }
103212
103229
  } catch (err) {
103213
103230
  const message = err instanceof Error ? err.message : String(err);
103214
- log11.error({ error: message }, "T310 migration: global signaldock.db integrity_check threw");
103231
+ log12.error({ error: message }, "T310 migration: global signaldock.db integrity_check threw");
103215
103232
  result.errors.push({ step: "step-14-global-integrity", error: message });
103216
103233
  result.status = "failed";
103217
103234
  if (globalDb) {
@@ -103230,21 +103247,21 @@ function migrateSignaldockToConduit(projectRoot) {
103230
103247
  result.bakPath = bakPath;
103231
103248
  } catch (err) {
103232
103249
  const message = err instanceof Error ? err.message : String(err);
103233
- log11.error(
103250
+ log12.error(
103234
103251
  { legacyPath, bakPath, error: message },
103235
103252
  "T310 migration: rename to .pre-t310.bak failed \u2014 legacy file left in place (harmless)"
103236
103253
  );
103237
103254
  result.errors.push({ step: "step-16-rename-bak", error: message });
103238
103255
  }
103239
- log11.info(
103256
+ log12.info(
103240
103257
  { projectRoot, agentsCopied: result.agentsCopied, conduitPath, bakPath: result.bakPath },
103241
103258
  `T310 migration complete: ${result.agentsCopied} agents migrated to global, conduit.db created`
103242
103259
  );
103243
- log11.warn(
103260
+ log12.warn(
103244
103261
  {},
103245
103262
  "T310 migration: API keys have been re-keyed. External systems holding old API keys (CI env vars, remote agent configs) must be updated."
103246
103263
  );
103247
- log11.info(
103264
+ log12.info(
103248
103265
  { legacyPath, bakPath: result.bakPath, conduitPath },
103249
103266
  "T310 migration recovery: if problems occur, rename .pre-t310.bak to signaldock.db and delete conduit.db to re-run migration."
103250
103267
  );
@@ -110531,9 +110548,11 @@ export {
110531
110548
  routing_exports as routing,
110532
110549
  runAllMigrations,
110533
110550
  runBrainMaintenance,
110551
+ runConsolidation,
110534
110552
  runDoctorFixes,
110535
110553
  runMigration,
110536
110554
  runReleaseGates,
110555
+ runTierPromotion,
110537
110556
  runUpgrade,
110538
110557
  safestop,
110539
110558
  sanitizeContent,