@cleocode/cleo 2026.4.7 → 2026.4.10

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 CHANGED
@@ -9932,52 +9932,97 @@ var init_migration_manager = __esm({
9932
9932
  });
9933
9933
 
9934
9934
  // packages/core/src/store/sqlite-backup.ts
9935
+ var sqlite_backup_exports = {};
9936
+ __export(sqlite_backup_exports, {
9937
+ listBrainBackups: () => listBrainBackups,
9938
+ listSqliteBackups: () => listSqliteBackups,
9939
+ listSqliteBackupsAll: () => listSqliteBackupsAll,
9940
+ vacuumIntoBackup: () => vacuumIntoBackup,
9941
+ vacuumIntoBackupAll: () => vacuumIntoBackupAll
9942
+ });
9935
9943
  import { existsSync as existsSync6, mkdirSync, readdirSync as readdirSync3, statSync, unlinkSync } from "node:fs";
9936
9944
  import { join as join6 } from "node:path";
9937
9945
  function formatTimestamp(d) {
9938
9946
  const pad = (n, len = 2) => String(n).padStart(len, "0");
9939
9947
  return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
9940
9948
  }
9941
- function rotateSnapshots(backupDir) {
9949
+ function snapshotPattern(prefix) {
9950
+ const safe = prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9951
+ return new RegExp(`^${safe}-\\d{8}-\\d{6}\\.db$`);
9952
+ }
9953
+ function rotateSnapshots(backupDir, prefix) {
9942
9954
  try {
9943
- const files = readdirSync3(backupDir).filter((f) => f.match(/^tasks-\d{8}-\d{6}\.db$/)).map((f) => ({
9955
+ const pattern = snapshotPattern(prefix);
9956
+ const files = readdirSync3(backupDir).filter((f) => pattern.test(f)).map((f) => ({
9944
9957
  name: f,
9945
9958
  path: join6(backupDir, f),
9946
9959
  mtimeMs: statSync(join6(backupDir, f)).mtimeMs
9947
9960
  })).sort((a, b) => a.mtimeMs - b.mtimeMs);
9948
9961
  while (files.length >= MAX_SNAPSHOTS) {
9949
9962
  const oldest = files.shift();
9963
+ if (!oldest) break;
9950
9964
  unlinkSync(oldest.path);
9951
9965
  }
9952
9966
  } catch {
9953
9967
  }
9954
9968
  }
9969
+ function snapshotOne(target, backupDir, now2) {
9970
+ const db = target.getDb();
9971
+ if (!db) return;
9972
+ const dest = join6(backupDir, `${target.prefix}-${formatTimestamp(now2)}.db`);
9973
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
9974
+ rotateSnapshots(backupDir, target.prefix);
9975
+ const safeDest = dest.replace(/'/g, "''");
9976
+ db.exec(`VACUUM INTO '${safeDest}'`);
9977
+ }
9955
9978
  async function vacuumIntoBackup(opts = {}) {
9956
9979
  const now2 = Date.now();
9957
- if (!opts.force && now2 - _lastBackupEpoch < DEBOUNCE_MS) {
9980
+ const prefix = "tasks";
9981
+ const last = _lastBackupEpoch[prefix] ?? 0;
9982
+ if (!opts.force && now2 - last < DEBOUNCE_MS) {
9958
9983
  return;
9959
9984
  }
9960
9985
  try {
9961
9986
  const cleoDir = getCleoDir(opts.cwd);
9962
9987
  const backupDir = join6(cleoDir, "backups", "sqlite");
9963
9988
  mkdirSync(backupDir, { recursive: true });
9964
- const db = getNativeDb();
9965
- if (!db) return;
9966
- const dest = join6(backupDir, `tasks-${formatTimestamp(/* @__PURE__ */ new Date())}.db`);
9967
- db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
9968
- rotateSnapshots(backupDir);
9969
- const safeDest = dest.replace(/'/g, "''");
9970
- db.exec(`VACUUM INTO '${safeDest}'`);
9971
- _lastBackupEpoch = Date.now();
9989
+ const target = SNAPSHOT_TARGETS.find((t) => t.prefix === prefix);
9990
+ if (!target) return;
9991
+ snapshotOne(target, backupDir, /* @__PURE__ */ new Date());
9992
+ _lastBackupEpoch[prefix] = Date.now();
9972
9993
  } catch {
9973
9994
  }
9974
9995
  }
9975
- function listSqliteBackups(cwd) {
9996
+ async function vacuumIntoBackupAll(opts = {}) {
9997
+ const nowMs = Date.now();
9998
+ const now2 = /* @__PURE__ */ new Date();
9999
+ let backupDir;
10000
+ try {
10001
+ const cleoDir = getCleoDir(opts.cwd);
10002
+ backupDir = join6(cleoDir, "backups", "sqlite");
10003
+ mkdirSync(backupDir, { recursive: true });
10004
+ } catch {
10005
+ return;
10006
+ }
10007
+ for (const target of SNAPSHOT_TARGETS) {
10008
+ const last = _lastBackupEpoch[target.prefix] ?? 0;
10009
+ if (!opts.force && nowMs - last < DEBOUNCE_MS) {
10010
+ continue;
10011
+ }
10012
+ try {
10013
+ snapshotOne(target, backupDir, now2);
10014
+ _lastBackupEpoch[target.prefix] = Date.now();
10015
+ } catch {
10016
+ }
10017
+ }
10018
+ }
10019
+ function listSqliteBackupsForPrefix(prefix, cwd) {
9976
10020
  try {
9977
10021
  const cleoDir = getCleoDir(cwd);
9978
10022
  const backupDir = join6(cleoDir, "backups", "sqlite");
9979
10023
  if (!existsSync6(backupDir)) return [];
9980
- return readdirSync3(backupDir).filter((f) => f.match(/^tasks-\d{8}-\d{6}\.db$/)).map((f) => ({
10024
+ const pattern = snapshotPattern(prefix);
10025
+ return readdirSync3(backupDir).filter((f) => pattern.test(f)).map((f) => ({
9981
10026
  name: f,
9982
10027
  path: join6(backupDir, f),
9983
10028
  mtimeMs: statSync(join6(backupDir, f)).mtimeMs
@@ -9986,15 +10031,33 @@ function listSqliteBackups(cwd) {
9986
10031
  return [];
9987
10032
  }
9988
10033
  }
9989
- var MAX_SNAPSHOTS, DEBOUNCE_MS, _lastBackupEpoch;
10034
+ function listSqliteBackups(cwd) {
10035
+ return listSqliteBackupsForPrefix("tasks", cwd);
10036
+ }
10037
+ function listBrainBackups(cwd) {
10038
+ return listSqliteBackupsForPrefix("brain", cwd);
10039
+ }
10040
+ function listSqliteBackupsAll(cwd) {
10041
+ const out = {};
10042
+ for (const target of SNAPSHOT_TARGETS) {
10043
+ out[target.prefix] = listSqliteBackupsForPrefix(target.prefix, cwd);
10044
+ }
10045
+ return out;
10046
+ }
10047
+ var MAX_SNAPSHOTS, DEBOUNCE_MS, _lastBackupEpoch, SNAPSHOT_TARGETS;
9990
10048
  var init_sqlite_backup = __esm({
9991
10049
  "packages/core/src/store/sqlite-backup.ts"() {
9992
10050
  "use strict";
9993
10051
  init_paths();
10052
+ init_brain_sqlite();
9994
10053
  init_sqlite2();
9995
10054
  MAX_SNAPSHOTS = 10;
9996
10055
  DEBOUNCE_MS = 3e4;
9997
- _lastBackupEpoch = 0;
10056
+ _lastBackupEpoch = {};
10057
+ SNAPSHOT_TARGETS = [
10058
+ { prefix: "tasks", getDb: getNativeDb },
10059
+ { prefix: "brain", getDb: getBrainNativeDb }
10060
+ ];
9998
10061
  }
9999
10062
  });
10000
10063
 
@@ -11134,9 +11197,10 @@ async function getDb(cwd) {
11134
11197
  stdio: "pipe"
11135
11198
  });
11136
11199
  const basename19 = fileToCheck.split(/[\\/]/).pop();
11200
+ const relPath = fileToCheck.replace(gitCwd + sep, "");
11137
11201
  log11.warn(
11138
11202
  { path: fileToCheck },
11139
- `${basename19} is tracked by project git \u2014 this risks data loss on branch switch. Run: git rm --cached ${fileToCheck.replace(gitCwd + sep, "")} (see ADR-013, T5188)`
11203
+ `${basename19} 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.`
11140
11204
  );
11141
11205
  } catch {
11142
11206
  }
@@ -21847,6 +21911,13 @@ Tasks completed: ${payload.tasksCompleted.join(", ") || "none"}`,
21847
21911
  }
21848
21912
  await maybeRefreshMemoryBridge(projectRoot);
21849
21913
  }
21914
+ async function handleSessionEndBackup(projectRoot, _payload) {
21915
+ try {
21916
+ const { vacuumIntoBackupAll: vacuumIntoBackupAll2 } = await Promise.resolve().then(() => (init_sqlite_backup(), sqlite_backup_exports));
21917
+ await vacuumIntoBackupAll2({ cwd: projectRoot, force: true });
21918
+ } catch {
21919
+ }
21920
+ }
21850
21921
  var init_session_hooks = __esm({
21851
21922
  "packages/core/src/hooks/handlers/session-hooks.ts"() {
21852
21923
  "use strict";
@@ -21865,6 +21936,12 @@ var init_session_hooks = __esm({
21865
21936
  handler: handleSessionEnd,
21866
21937
  priority: 100
21867
21938
  });
21939
+ hooks.register({
21940
+ id: "backup-session-end",
21941
+ event: "SessionEnd",
21942
+ handler: handleSessionEndBackup,
21943
+ priority: 10
21944
+ });
21868
21945
  }
21869
21946
  });
21870
21947
 
@@ -41954,15 +42031,19 @@ var init_scaffold = __esm({
41954
42031
  ];
41955
42032
  CLEO_GITIGNORE_FALLBACK = `# .cleo/.gitignore \u2014 Deny-by-default for CLEO project data
41956
42033
  # Ignore everything, then explicitly allow only tracked files.
42034
+ #
42035
+ # ADR-013 \xA79 (2026-04-07, T5158): config.json + project-info.json are
42036
+ # runtime snapshots regenerated by \`cleo init\`, not tracked in git.
42037
+ # Recovery for all four runtime files (tasks.db, brain.db, config.json,
42038
+ # project-info.json) is provided by \`cleo backup add\` snapshots under
42039
+ # .cleo/backups/. See .cleo/adrs/ADR-013 for the full recovery story.
41957
42040
 
41958
42041
  # Step 1: Ignore everything
41959
42042
  *
41960
42043
 
41961
42044
  # Allow list
41962
42045
  !.gitignore
41963
- !config.json
41964
42046
  !project-context.json
41965
- !project-info.json
41966
42047
  !setup-otel.sh
41967
42048
  !DATA-SAFETY-IMPLEMENTATION-SUMMARY.md
41968
42049
  !adrs/
@@ -41977,6 +42058,8 @@ var init_scaffold = __esm({
41977
42058
  *.db-shm
41978
42059
  *.db-wal
41979
42060
  *.db-journal
42061
+ config.json
42062
+ project-info.json
41980
42063
  log.json
41981
42064
  bypass-log.json
41982
42065
  qa-log.json
@@ -62372,9 +62455,39 @@ var init_audit2 = __esm({
62372
62455
  });
62373
62456
 
62374
62457
  // packages/core/src/system/backup.ts
62375
- import { existsSync as existsSync85, mkdirSync as mkdirSync19, readdirSync as readdirSync28, readFileSync as readFileSync60, writeFileSync as writeFileSync12 } from "node:fs";
62376
- import { join as join86 } from "node:path";
62377
- function createBackup2(projectRoot, opts) {
62458
+ import {
62459
+ copyFileSync as copyFileSync7,
62460
+ existsSync as existsSync85,
62461
+ mkdirSync as mkdirSync19,
62462
+ readdirSync as readdirSync28,
62463
+ readFileSync as readFileSync60,
62464
+ renameSync as renameSync6,
62465
+ unlinkSync as unlinkSync5,
62466
+ writeFileSync as writeFileSync12
62467
+ } from "node:fs";
62468
+ import { dirname as dirname17, join as join86 } from "node:path";
62469
+ function safeSqliteSnapshot(db, destPath) {
62470
+ if (!db) return false;
62471
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
62472
+ const safeDest = destPath.replace(/'/g, "''");
62473
+ db.exec(`VACUUM INTO '${safeDest}'`);
62474
+ return true;
62475
+ }
62476
+ function atomicWriteSync(destPath, data) {
62477
+ mkdirSync19(dirname17(destPath), { recursive: true });
62478
+ const tmp = `${destPath}.${process.pid}.${Date.now()}.tmp`;
62479
+ try {
62480
+ writeFileSync12(tmp, data);
62481
+ renameSync6(tmp, destPath);
62482
+ } catch (err) {
62483
+ try {
62484
+ unlinkSync5(tmp);
62485
+ } catch {
62486
+ }
62487
+ throw err;
62488
+ }
62489
+ }
62490
+ async function createBackup2(projectRoot, opts) {
62378
62491
  const cleoDir = join86(projectRoot, ".cleo");
62379
62492
  const btype = opts?.type || "snapshot";
62380
62493
  const timestamp2 = (/* @__PURE__ */ new Date()).toISOString();
@@ -62383,23 +62496,48 @@ function createBackup2(projectRoot, opts) {
62383
62496
  if (!existsSync85(backupDir)) {
62384
62497
  mkdirSync19(backupDir, { recursive: true });
62385
62498
  }
62386
- const filesToBackup = ["tasks.db", "brain.db", "config.json", "project-info.json"];
62499
+ try {
62500
+ const { getDb: getDb4 } = await Promise.resolve().then(() => (init_sqlite2(), sqlite_exports));
62501
+ await getDb4(projectRoot);
62502
+ } catch {
62503
+ }
62504
+ try {
62505
+ const { getBrainDb: getBrainDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
62506
+ await getBrainDb2(projectRoot);
62507
+ } catch {
62508
+ }
62509
+ const sqliteTargets = [
62510
+ { file: "tasks.db", getDb: getNativeDb },
62511
+ { file: "brain.db", getDb: getBrainNativeDb }
62512
+ ];
62513
+ const jsonTargets = ["config.json", "project-info.json"];
62387
62514
  const backedUp = [];
62388
- for (const file2 of filesToBackup) {
62389
- const src = join86(cleoDir, file2);
62390
- if (existsSync85(src)) {
62391
- const dest = join86(backupDir, `${file2}.${backupId}`);
62392
- try {
62393
- const content = readFileSync60(src);
62394
- writeFileSync12(dest, content);
62395
- backedUp.push(file2);
62396
- } catch {
62515
+ for (const target of sqliteTargets) {
62516
+ const src = join86(cleoDir, target.file);
62517
+ if (!existsSync85(src)) continue;
62518
+ const dest = join86(backupDir, `${target.file}.${backupId}`);
62519
+ try {
62520
+ const ok = safeSqliteSnapshot(target.getDb(), dest);
62521
+ if (ok) {
62522
+ backedUp.push(target.file);
62397
62523
  }
62524
+ } catch {
62525
+ }
62526
+ }
62527
+ for (const file2 of jsonTargets) {
62528
+ const src = join86(cleoDir, file2);
62529
+ if (!existsSync85(src)) continue;
62530
+ const dest = join86(backupDir, `${file2}.${backupId}`);
62531
+ try {
62532
+ const content = readFileSync60(src);
62533
+ atomicWriteSync(dest, content);
62534
+ backedUp.push(file2);
62535
+ } catch {
62398
62536
  }
62399
62537
  }
62400
62538
  const metaPath = join86(backupDir, `${backupId}.meta.json`);
62401
62539
  try {
62402
- writeFileSync12(
62540
+ atomicWriteSync(
62403
62541
  metaPath,
62404
62542
  JSON.stringify(
62405
62543
  {
@@ -62411,8 +62549,7 @@ function createBackup2(projectRoot, opts) {
62411
62549
  },
62412
62550
  null,
62413
62551
  2
62414
- ),
62415
- "utf-8"
62552
+ )
62416
62553
  );
62417
62554
  } catch {
62418
62555
  }
@@ -62476,13 +62613,17 @@ function restoreBackup(projectRoot, params) {
62476
62613
  const restored = [];
62477
62614
  for (const file2 of meta.files ?? []) {
62478
62615
  const backupFile = join86(backupDir, `${file2}.${params.backupId}`);
62479
- if (existsSync85(backupFile)) {
62480
- try {
62616
+ if (!existsSync85(backupFile)) continue;
62617
+ const destPath = join86(cleoDir, file2);
62618
+ try {
62619
+ if (file2.endsWith(".db")) {
62620
+ copyFileSync7(backupFile, destPath);
62621
+ } else {
62481
62622
  const content = readFileSync60(backupFile);
62482
- writeFileSync12(join86(cleoDir, file2), content);
62483
- restored.push(file2);
62484
- } catch {
62623
+ atomicWriteSync(destPath, content);
62485
62624
  }
62625
+ restored.push(file2);
62626
+ } catch {
62486
62627
  }
62487
62628
  }
62488
62629
  return {
@@ -62497,6 +62638,8 @@ var init_backup2 = __esm({
62497
62638
  "use strict";
62498
62639
  init_src();
62499
62640
  init_errors3();
62641
+ init_brain_sqlite();
62642
+ init_sqlite2();
62500
62643
  }
62501
62644
  });
62502
62645
 
@@ -62572,7 +62715,7 @@ var init_audit_prune = __esm({
62572
62715
  });
62573
62716
 
62574
62717
  // packages/core/src/system/cleanup.ts
62575
- import { existsSync as existsSync86, readdirSync as readdirSync29, readFileSync as readFileSync61, unlinkSync as unlinkSync5, writeFileSync as writeFileSync13 } from "node:fs";
62718
+ import { existsSync as existsSync86, readdirSync as readdirSync29, readFileSync as readFileSync61, unlinkSync as unlinkSync6, writeFileSync as writeFileSync13 } from "node:fs";
62576
62719
  import { join as join88 } from "node:path";
62577
62720
  async function cleanupSystem(projectRoot, params) {
62578
62721
  if (!params.target) {
@@ -62631,11 +62774,11 @@ async function cleanupSystem(projectRoot, params) {
62631
62774
  if (params.olderThan && meta.timestamp < params.olderThan) {
62632
62775
  items.push(file2.replace(".meta.json", ""));
62633
62776
  if (!dryRun) {
62634
- unlinkSync5(metaFilePath);
62777
+ unlinkSync6(metaFilePath);
62635
62778
  for (const bf of readdirSync29(fullDir)) {
62636
62779
  if (bf.includes(meta.backupId)) {
62637
62780
  try {
62638
- unlinkSync5(join88(fullDir, bf));
62781
+ unlinkSync6(join88(fullDir, bf));
62639
62782
  } catch {
62640
62783
  }
62641
62784
  }
@@ -62667,7 +62810,7 @@ async function cleanupSystem(projectRoot, params) {
62667
62810
  items.push(file2);
62668
62811
  if (!dryRun) {
62669
62812
  try {
62670
- unlinkSync5(join88(cleoDir, file2));
62813
+ unlinkSync6(join88(cleoDir, file2));
62671
62814
  } catch {
62672
62815
  }
62673
62816
  }
@@ -62824,14 +62967,14 @@ import {
62824
62967
  mkdirSync as mkdirSync21,
62825
62968
  readdirSync as readdirSync30,
62826
62969
  readFileSync as readFileSync62,
62827
- renameSync as renameSync6,
62828
- unlinkSync as unlinkSync6,
62970
+ renameSync as renameSync7,
62971
+ unlinkSync as unlinkSync7,
62829
62972
  writeFileSync as writeFileSync14
62830
62973
  } from "node:fs";
62831
- import { basename as basename14, dirname as dirname17, join as join90 } from "node:path";
62974
+ import { basename as basename14, dirname as dirname18, join as join90 } from "node:path";
62832
62975
  import * as lockfile2 from "proper-lockfile";
62833
62976
  function rotateBackup(filePath) {
62834
- const dir = dirname17(filePath);
62977
+ const dir = dirname18(filePath);
62835
62978
  const name2 = basename14(filePath);
62836
62979
  const backupDir = join90(dir, ".backups");
62837
62980
  if (!existsSync88(backupDir)) {
@@ -62841,13 +62984,13 @@ function rotateBackup(filePath) {
62841
62984
  const current = join90(backupDir, `${name2}.${i}`);
62842
62985
  if (i === MAX_BACKUPS) {
62843
62986
  try {
62844
- unlinkSync6(current);
62987
+ unlinkSync7(current);
62845
62988
  } catch {
62846
62989
  }
62847
62990
  } else {
62848
62991
  const next = join90(backupDir, `${name2}.${i + 1}`);
62849
62992
  try {
62850
- if (existsSync88(current)) renameSync6(current, next);
62993
+ if (existsSync88(current)) renameSync7(current, next);
62851
62994
  } catch {
62852
62995
  }
62853
62996
  }
@@ -62859,7 +63002,7 @@ function rotateBackup(filePath) {
62859
63002
  }
62860
63003
  }
62861
63004
  function writeJsonFileAtomic(filePath, data, indent = 2) {
62862
- const dir = dirname17(filePath);
63005
+ const dir = dirname18(filePath);
62863
63006
  const tempPath = join90(dir, `.${basename14(filePath)}.${randomBytes12(6).toString("hex")}.tmp`);
62864
63007
  const content = JSON.stringify(data, null, indent) + "\n";
62865
63008
  writeFileSync14(tempPath, content, "utf-8");
@@ -62867,10 +63010,10 @@ function writeJsonFileAtomic(filePath, data, indent = 2) {
62867
63010
  if (existsSync88(filePath)) {
62868
63011
  rotateBackup(filePath);
62869
63012
  }
62870
- renameSync6(tempPath, filePath);
63013
+ renameSync7(tempPath, filePath);
62871
63014
  } catch (error40) {
62872
63015
  try {
62873
- unlinkSync6(tempPath);
63016
+ unlinkSync7(tempPath);
62874
63017
  } catch {
62875
63018
  }
62876
63019
  throw error40;
@@ -67442,8 +67585,8 @@ var init_docs_sync = __esm({
67442
67585
 
67443
67586
  // packages/core/src/validation/doctor/project-cache.ts
67444
67587
  import { createHash as createHash11 } from "node:crypto";
67445
- import { existsSync as existsSync101, mkdirSync as mkdirSync22, readFileSync as readFileSync73, unlinkSync as unlinkSync7, writeFileSync as writeFileSync18 } from "node:fs";
67446
- import { dirname as dirname18, join as join102 } from "node:path";
67588
+ import { existsSync as existsSync101, mkdirSync as mkdirSync22, readFileSync as readFileSync73, unlinkSync as unlinkSync8, writeFileSync as writeFileSync18 } from "node:fs";
67589
+ import { dirname as dirname19, join as join102 } from "node:path";
67447
67590
  function getCacheFilePath(cleoHome) {
67448
67591
  const home = cleoHome ?? getCleoHome();
67449
67592
  return join102(home, CACHE_FILE2);
@@ -67454,7 +67597,7 @@ function initCacheFile(cacheFile) {
67454
67597
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
67455
67598
  projects: {}
67456
67599
  };
67457
- const dir = dirname18(cacheFile);
67600
+ const dir = dirname19(cacheFile);
67458
67601
  if (!existsSync101(dir)) {
67459
67602
  mkdirSync22(dir, { recursive: true });
67460
67603
  }
@@ -67530,7 +67673,7 @@ function clearProjectCache(projectHash, cacheFile) {
67530
67673
  function clearEntireCache(cacheFile) {
67531
67674
  const cachePath = cacheFile ?? getCacheFilePath();
67532
67675
  if (existsSync101(cachePath)) {
67533
- unlinkSync7(cachePath);
67676
+ unlinkSync8(cachePath);
67534
67677
  }
67535
67678
  initCacheFile(cachePath);
67536
67679
  }
@@ -68538,7 +68681,7 @@ var init_gap_check = __esm({
68538
68681
  // packages/core/src/validation/manifest.ts
68539
68682
  import { existsSync as existsSync102 } from "node:fs";
68540
68683
  import { appendFile as appendFile3, mkdir as mkdir15, readFile as readFile16 } from "node:fs/promises";
68541
- import { dirname as dirname19 } from "node:path";
68684
+ import { dirname as dirname20 } from "node:path";
68542
68685
  async function findManifestEntry(taskId, manifestPath) {
68543
68686
  if (!manifestPath) {
68544
68687
  try {
@@ -68659,7 +68802,7 @@ async function validateManifestEntry(taskId, manifestEntry, manifestPath = DEFAU
68659
68802
  };
68660
68803
  }
68661
68804
  async function logRealCompliance(taskId, validationResult, agentType = "unknown", compliancePath = DEFAULT_COMPLIANCE_PATH) {
68662
- const metricsDir = dirname19(compliancePath);
68805
+ const metricsDir = dirname20(compliancePath);
68663
68806
  await mkdir15(metricsDir, { recursive: true });
68664
68807
  const { score, pass, violations } = validationResult;
68665
68808
  const violationCount = violations.length;
@@ -69826,13 +69969,13 @@ __export(init_exports, {
69826
69969
  import { existsSync as existsSync105, readdirSync as readdirSync36, readFileSync as readFileSync75 } from "node:fs";
69827
69970
  import { copyFile as copyFile4, lstat, mkdir as mkdir16, readFile as readFile17, symlink, unlink as unlink4, writeFile as writeFile11 } from "node:fs/promises";
69828
69971
  import { platform as platform4 } from "node:os";
69829
- import { basename as basename17, dirname as dirname20, join as join104 } from "node:path";
69972
+ import { basename as basename17, dirname as dirname21, join as join104 } from "node:path";
69830
69973
  async function resolveSeedAgentsDir() {
69831
69974
  try {
69832
69975
  const { createRequire: createRequire9 } = await import("node:module");
69833
69976
  const req = createRequire9(import.meta.url);
69834
69977
  const agentsPkgMain = req.resolve("@cleocode/agents/package.json");
69835
- const agentsPkgRoot = dirname20(agentsPkgMain);
69978
+ const agentsPkgRoot = dirname21(agentsPkgMain);
69836
69979
  const candidate = join104(agentsPkgRoot, "seed-agents");
69837
69980
  if (existsSync105(candidate)) {
69838
69981
  return candidate;
@@ -69860,7 +70003,7 @@ async function initAgentDefinition(created, warnings) {
69860
70003
  const { createRequire: createRequire9 } = await import("node:module");
69861
70004
  const req = createRequire9(import.meta.url);
69862
70005
  const agentsPkgMain = req.resolve("@cleocode/agents/package.json");
69863
- const agentsPkgRoot = dirname20(agentsPkgMain);
70006
+ const agentsPkgRoot = dirname21(agentsPkgMain);
69864
70007
  const candidate = join104(agentsPkgRoot, "cleo-subagent");
69865
70008
  if (existsSync105(candidate)) {
69866
70009
  agentSourceDir = candidate;
@@ -69879,7 +70022,7 @@ async function initAgentDefinition(created, warnings) {
69879
70022
  return;
69880
70023
  }
69881
70024
  const globalAgentsDir = join104(getAgentsHome(), "agents", "cleo-subagent");
69882
- await mkdir16(dirname20(globalAgentsDir), { recursive: true });
70025
+ await mkdir16(dirname21(globalAgentsDir), { recursive: true });
69883
70026
  try {
69884
70027
  try {
69885
70028
  const stat4 = await lstat(globalAgentsDir);
@@ -69927,7 +70070,7 @@ async function initCoreSkills(created, warnings) {
69927
70070
  const { createRequire: createRequire9 } = await import("node:module");
69928
70071
  const req = createRequire9(import.meta.url);
69929
70072
  const skillsPkgMain = req.resolve("@cleocode/skills/package.json");
69930
- const skillsPkgRoot = dirname20(skillsPkgMain);
70073
+ const skillsPkgRoot = dirname21(skillsPkgMain);
69931
70074
  if (existsSync105(join104(skillsPkgRoot, "skills.json"))) {
69932
70075
  ctSkillsRoot = skillsPkgRoot;
69933
70076
  }
@@ -69962,7 +70105,7 @@ async function initCoreSkills(created, warnings) {
69962
70105
  const coreSkills = skills.filter((s) => s.tier <= 2);
69963
70106
  const installed = [];
69964
70107
  for (const skill of coreSkills) {
69965
- const skillSourceDir = dirname20(join104(ctSkillsRoot, skill.path));
70108
+ const skillSourceDir = dirname21(join104(ctSkillsRoot, skill.path));
69966
70109
  if (!existsSync105(skillSourceDir)) {
69967
70110
  continue;
69968
70111
  }
@@ -70640,8 +70783,8 @@ async function bootstrapGlobalCleo(options) {
70640
70783
  }
70641
70784
  async function writeTemplateTo(content, destPath, isDryRun) {
70642
70785
  if (isDryRun) return false;
70643
- const { dirname: dirname28 } = await import("node:path");
70644
- await mkdir17(dirname28(destPath), { recursive: true });
70786
+ const { dirname: dirname29 } = await import("node:path");
70787
+ await mkdir17(dirname29(destPath), { recursive: true });
70645
70788
  await writeFile12(destPath, content);
70646
70789
  return true;
70647
70790
  }
@@ -75470,7 +75613,7 @@ var init_engine_compat = __esm({
75470
75613
 
75471
75614
  // packages/core/src/memory/pipeline-manifest-sqlite.ts
75472
75615
  import { createHash as createHash12 } from "node:crypto";
75473
- import { existsSync as existsSync110, readFileSync as readFileSync79, renameSync as renameSync7 } from "node:fs";
75616
+ import { existsSync as existsSync110, readFileSync as readFileSync79, renameSync as renameSync8 } from "node:fs";
75474
75617
  import { join as join108 } from "node:path";
75475
75618
  import { and as and10, count as count2, desc as desc5, eq as eq13, gte as gte3, isNull as isNull3, like as like3, lte as lte2, or as or5 } from "drizzle-orm";
75476
75619
  async function getDb3(cwd) {
@@ -78495,6 +78638,7 @@ var init_store3 = __esm({
78495
78638
  init_lock();
78496
78639
  init_provider();
78497
78640
  init_safety_data_accessor();
78641
+ init_sqlite_backup();
78498
78642
  }
78499
78643
  });
78500
78644
 
@@ -78507,7 +78651,7 @@ __export(migration_sqlite_exports, {
78507
78651
  migrateJsonToSqliteAtomic: () => migrateJsonToSqliteAtomic
78508
78652
  });
78509
78653
  import { existsSync as existsSync114, mkdirSync as mkdirSync23, readFileSync as readFileSync83 } from "node:fs";
78510
- import { dirname as dirname21, join as join111 } from "node:path";
78654
+ import { dirname as dirname22, join as join111 } from "node:path";
78511
78655
  function topoSortTasks(tasks2) {
78512
78656
  const taskMap = new Map(tasks2.map((t) => [t.id, t]));
78513
78657
  const sorted = [];
@@ -78585,7 +78729,7 @@ async function migrateJsonToSqliteAtomic(cwd, tempDbPath, logger) {
78585
78729
  closeDb2();
78586
78730
  try {
78587
78731
  logger?.info("import", "init", "Initializing node:sqlite for migration");
78588
- mkdirSync23(dirname21(tempDbPath), { recursive: true });
78732
+ mkdirSync23(dirname22(tempDbPath), { recursive: true });
78589
78733
  const nativeDb = openNativeDatabase(tempDbPath, { enableWal: true });
78590
78734
  const db = drizzle({ client: nativeDb, schema: tasks_schema_exports });
78591
78735
  logger?.info("import", "create-tables", "Running drizzle migrations to create tables");
@@ -79180,7 +79324,7 @@ var init_repair = __esm({
79180
79324
 
79181
79325
  // packages/core/src/upgrade.ts
79182
79326
  import {
79183
- copyFileSync as copyFileSync7,
79327
+ copyFileSync as copyFileSync8,
79184
79328
  existsSync as existsSync115,
79185
79329
  mkdirSync as mkdirSync24,
79186
79330
  readdirSync as readdirSync39,
@@ -79273,7 +79417,7 @@ async function runUpgrade(options = {}) {
79273
79417
  if (!existsSync115(backupDir)) {
79274
79418
  mkdirSync24(backupDir, { recursive: true });
79275
79419
  }
79276
- copyFileSync7(dbPath2, dbBackupPath);
79420
+ copyFileSync8(dbPath2, dbBackupPath);
79277
79421
  const { createHash: createHash14 } = await import("node:crypto");
79278
79422
  const origChecksum = createHash14("sha256").update(readFileSync84(dbPath2)).digest("hex");
79279
79423
  const backupChecksum = createHash14("sha256").update(readFileSync84(dbBackupPath)).digest("hex");
@@ -79294,8 +79438,8 @@ async function runUpgrade(options = {}) {
79294
79438
  });
79295
79439
  }
79296
79440
  if (existsSync115(dbTempPath)) {
79297
- const { unlinkSync: unlinkSync8 } = await import("node:fs");
79298
- unlinkSync8(dbTempPath);
79441
+ const { unlinkSync: unlinkSync9 } = await import("node:fs");
79442
+ unlinkSync9(dbTempPath);
79299
79443
  }
79300
79444
  const configPath = join112(cleoDir2, "config.json");
79301
79445
  let configBackup = null;
@@ -79329,7 +79473,7 @@ async function runUpgrade(options = {}) {
79329
79473
  if (result.success) {
79330
79474
  const totalImported = result.tasksImported + result.archivedImported;
79331
79475
  if (totalImported === 0 && existsSync115(dbBackupPath)) {
79332
- copyFileSync7(dbBackupPath, dbPath2);
79476
+ copyFileSync8(dbBackupPath, dbPath2);
79333
79477
  if (configBackup) {
79334
79478
  writeFileSync21(configPath, configBackup);
79335
79479
  }
@@ -79371,7 +79515,7 @@ async function runUpgrade(options = {}) {
79371
79515
  }
79372
79516
  } else {
79373
79517
  if (existsSync115(dbBackupPath)) {
79374
- copyFileSync7(dbBackupPath, dbPath2);
79518
+ copyFileSync8(dbBackupPath, dbPath2);
79375
79519
  }
79376
79520
  if (configBackup) {
79377
79521
  writeFileSync21(configPath, configBackup);
@@ -79398,7 +79542,7 @@ async function runUpgrade(options = {}) {
79398
79542
  if (existsSync115(safetyDir)) {
79399
79543
  const backups = readdirSync39(safetyDir).filter((f) => f.startsWith("tasks.db.pre-migration.")).sort().reverse();
79400
79544
  if (backups.length > 0 && !existsSync115(dbPath2)) {
79401
- copyFileSync7(join112(safetyDir, backups[0]), dbPath2);
79545
+ copyFileSync8(join112(safetyDir, backups[0]), dbPath2);
79402
79546
  }
79403
79547
  }
79404
79548
  } catch {
@@ -79496,11 +79640,11 @@ async function runUpgrade(options = {}) {
79496
79640
  mkdirSync24(backupDir, { recursive: true });
79497
79641
  for (const f of foundStale) {
79498
79642
  const src = join112(cleoDir, f);
79499
- copyFileSync7(src, join112(backupDir, f));
79643
+ copyFileSync8(src, join112(backupDir, f));
79500
79644
  }
79501
- const { unlinkSync: unlinkSync8 } = await import("node:fs");
79645
+ const { unlinkSync: unlinkSync9 } = await import("node:fs");
79502
79646
  for (const f of foundStale) {
79503
- unlinkSync8(join112(cleoDir, f));
79647
+ unlinkSync9(join112(cleoDir, f));
79504
79648
  }
79505
79649
  actions.push({
79506
79650
  action: "stale_json_cleanup",
@@ -81695,7 +81839,7 @@ var init_schema_validator = __esm({
81695
81839
  // packages/core/src/validation/validate-ops.ts
81696
81840
  import { execFileSync as execFileSync12 } from "node:child_process";
81697
81841
  import { appendFileSync as appendFileSync10, existsSync as existsSync119, mkdirSync as mkdirSync25, readFileSync as readFileSync89 } from "node:fs";
81698
- import { dirname as dirname22, join as join113, resolve as resolve12 } from "node:path";
81842
+ import { dirname as dirname23, join as join113, resolve as resolve12 } from "node:path";
81699
81843
  function readJsonFile2(filePath) {
81700
81844
  try {
81701
81845
  const raw = readFileSync89(filePath, "utf-8");
@@ -82003,7 +82147,7 @@ function coreComplianceRecord(taskId, result, protocol, violations, projectRoot)
82003
82147
  throw new Error(`Invalid result: ${result}. Valid: ${validResults.join(", ")}`);
82004
82148
  }
82005
82149
  const compliancePath = join113(projectRoot, ".cleo", "metrics", "COMPLIANCE.jsonl");
82006
- const dir = dirname22(compliancePath);
82150
+ const dir = dirname23(compliancePath);
82007
82151
  if (!existsSync119(dir)) {
82008
82152
  mkdirSync25(dir, { recursive: true });
82009
82153
  }
@@ -82808,7 +82952,7 @@ var init_plan = __esm({
82808
82952
  import { execFileSync as execFileSync13 } from "node:child_process";
82809
82953
  import { createCipheriv, createDecipheriv, createHmac, randomBytes as randomBytes15 } from "node:crypto";
82810
82954
  import { chmod as chmod2, mkdir as mkdir18, readFile as readFile20, stat as stat2, writeFile as writeFile13 } from "node:fs/promises";
82811
- import { dirname as dirname23, join as join115 } from "node:path";
82955
+ import { dirname as dirname24, join as join115 } from "node:path";
82812
82956
  function getMachineKeyPath() {
82813
82957
  if (process.platform === "win32") {
82814
82958
  const appData = process.env["LOCALAPPDATA"] ?? process.env["APPDATA"];
@@ -82859,7 +83003,7 @@ async function getMachineKey() {
82859
83003
  } catch (err) {
82860
83004
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
82861
83005
  const key = randomBytes15(KEY_LENGTH);
82862
- await mkdir18(dirname23(keyPath), { recursive: true });
83006
+ await mkdir18(dirname24(keyPath), { recursive: true });
82863
83007
  await writeFile13(keyPath, key, { mode: 384 });
82864
83008
  if (process.platform === "win32") {
82865
83009
  try {
@@ -83688,6 +83832,7 @@ __export(internal_exports, {
83688
83832
  listAdrs: () => listAdrs,
83689
83833
  listAgentInstances: () => listAgentInstances,
83690
83834
  listBackups: () => listBackups,
83835
+ listBrainBackups: () => listBrainBackups,
83691
83836
  listChains: () => listChains,
83692
83837
  listEpicsWithLifecycle: () => listEpicsWithLifecycle,
83693
83838
  listLabels: () => listLabels,
@@ -83695,6 +83840,8 @@ __export(internal_exports, {
83695
83840
  listPhases: () => listPhases2,
83696
83841
  listRemotes: () => listRemotes,
83697
83842
  listSessions: () => listSessions,
83843
+ listSqliteBackups: () => listSqliteBackups,
83844
+ listSqliteBackupsAll: () => listSqliteBackupsAll,
83698
83845
  listStickies: () => listStickies,
83699
83846
  listStrictnessPresets: () => listStrictnessPresets,
83700
83847
  listSystemBackups: () => listSystemBackups,
@@ -83931,6 +84078,8 @@ __export(internal_exports, {
83931
84078
  updatePatternStats: () => updatePatternStats,
83932
84079
  updateProjectName: () => updateProjectName,
83933
84080
  updateTask: () => updateTask,
84081
+ vacuumIntoBackup: () => vacuumIntoBackup,
84082
+ vacuumIntoBackupAll: () => vacuumIntoBackupAll,
83934
84083
  validateAgainstSchema: () => validateAgainstSchema,
83935
84084
  validateAllAdrs: () => validateAllAdrs,
83936
84085
  validateArchitectureDecisionTask: () => validateArchitectureDecisionTask,
@@ -84060,6 +84209,7 @@ var init_internal = __esm({
84060
84209
  init_session_store();
84061
84210
  init_signaldock_sqlite();
84062
84211
  init_sqlite2();
84212
+ init_sqlite_backup();
84063
84213
  init_task_store();
84064
84214
  init_tasks_schema();
84065
84215
  init_validation_schemas();
@@ -91086,9 +91236,9 @@ async function systemHealth(projectRoot, params) {
91086
91236
  return engineError("E_GENERAL", err.message);
91087
91237
  }
91088
91238
  }
91089
- function systemBackup(projectRoot, params) {
91239
+ async function systemBackup(projectRoot, params) {
91090
91240
  try {
91091
- const result = createBackup2(projectRoot, params);
91241
+ const result = await createBackup2(projectRoot, params);
91092
91242
  return { success: true, data: result };
91093
91243
  } catch (err) {
91094
91244
  return engineError("E_GENERAL", err.message);
@@ -93388,7 +93538,7 @@ var init_admin2 = __esm({
93388
93538
  });
93389
93539
  return wrapResult(result2, "mutate", "admin", operation, startTime);
93390
93540
  }
93391
- const result = systemBackup(
93541
+ const result = await systemBackup(
93392
93542
  projectRoot,
93393
93543
  params
93394
93544
  );
@@ -99763,7 +99913,7 @@ var init_cli = __esm({
99763
99913
 
99764
99914
  // packages/cleo/src/cli/index.ts
99765
99915
  import { readFileSync as readFileSync98 } from "node:fs";
99766
- import { dirname as dirname27, join as join125 } from "node:path";
99916
+ import { dirname as dirname28, join as join125 } from "node:path";
99767
99917
  import { fileURLToPath as fileURLToPath5 } from "node:url";
99768
99918
 
99769
99919
  // node_modules/.pnpm/citty@0.2.1/node_modules/citty/dist/_chunks/libs/scule.mjs
@@ -101925,7 +102075,7 @@ function registerBugCommand(program) {
101925
102075
  // packages/cleo/src/cli/commands/cant.ts
101926
102076
  init_renderers();
101927
102077
  import { existsSync as existsSync123, mkdirSync as mkdirSync26, readFileSync as readFileSync94, writeFileSync as writeFileSync22 } from "node:fs";
101928
- import { dirname as dirname24, isAbsolute as isAbsolute3, join as join119, resolve as resolve14 } from "node:path";
102078
+ import { dirname as dirname25, isAbsolute as isAbsolute3, join as join119, resolve as resolve14 } from "node:path";
101929
102079
  function registerCantCommand(program) {
101930
102080
  const cant = program.command("cant").description("CANT DSL tooling");
101931
102081
  cant.command("parse <file>").description("Parse a .cant file and emit the AST").action(async (file2) => {
@@ -102017,7 +102167,7 @@ function registerCantCommand(program) {
102017
102167
  let written = 0;
102018
102168
  for (const outputFile of result.outputFiles) {
102019
102169
  const outputPath = isAbsolute3(outputFile.path) ? outputFile.path : join119(projectRoot, outputFile.path);
102020
- mkdirSync26(dirname24(outputPath), { recursive: true });
102170
+ mkdirSync26(dirname25(outputPath), { recursive: true });
102021
102171
  writeFileSync22(outputPath, outputFile.content, "utf-8");
102022
102172
  written++;
102023
102173
  if (isVerbose) {
@@ -102757,14 +102907,14 @@ function registerDetectCommand(program) {
102757
102907
  init_src();
102758
102908
  init_renderers();
102759
102909
  import { existsSync as existsSync124, readdirSync as readdirSync41, readFileSync as readFileSync95 } from "node:fs";
102760
- import { dirname as dirname25, join as join120 } from "node:path";
102910
+ import { dirname as dirname26, join as join120 } from "node:path";
102761
102911
  function findProjectRoot() {
102762
102912
  let currentDir = process.cwd();
102763
102913
  while (currentDir !== "/") {
102764
102914
  if (existsSync124(join120(currentDir, "package.json"))) {
102765
102915
  return currentDir;
102766
102916
  }
102767
- const parent = dirname25(currentDir);
102917
+ const parent = dirname26(currentDir);
102768
102918
  if (parent === currentDir) break;
102769
102919
  currentDir = parent;
102770
102920
  }
@@ -103678,7 +103828,7 @@ init_src2();
103678
103828
  init_renderers();
103679
103829
  import { execFileSync as execFileSync16 } from "node:child_process";
103680
103830
  import { existsSync as existsSync125, mkdirSync as mkdirSync27, readFileSync as readFileSync96, writeFileSync as writeFileSync23 } from "node:fs";
103681
- import { dirname as dirname26, join as join122 } from "node:path";
103831
+ import { dirname as dirname27, join as join122 } from "node:path";
103682
103832
  function getChangelogSource(cwd) {
103683
103833
  const configPath = getConfigPath(cwd);
103684
103834
  try {
@@ -103830,7 +103980,7 @@ function registerGenerateChangelogCommand(program) {
103830
103980
  const content = generateForPlatform(targetPlatform, sourceContent, repoSlug, limit);
103831
103981
  if (!dryRun) {
103832
103982
  const fullPath = join122(getProjectRoot(), outputPath);
103833
- mkdirSync27(dirname26(fullPath), { recursive: true });
103983
+ mkdirSync27(dirname27(fullPath), { recursive: true });
103834
103984
  writeFileSync23(fullPath, content, "utf-8");
103835
103985
  }
103836
103986
  results.push({ platform: targetPlatform, path: outputPath, written: !dryRun });
@@ -103851,7 +104001,7 @@ function registerGenerateChangelogCommand(program) {
103851
104001
  );
103852
104002
  if (!dryRun) {
103853
104003
  const fullPath = join122(getProjectRoot(), platformConfig.path);
103854
- mkdirSync27(dirname26(fullPath), { recursive: true });
104004
+ mkdirSync27(dirname27(fullPath), { recursive: true });
103855
104005
  writeFileSync23(fullPath, content, "utf-8");
103856
104006
  }
103857
104007
  results.push({
@@ -107339,7 +107489,7 @@ var codeCommand = defineCommand({
107339
107489
 
107340
107490
  // packages/cleo/src/cli/index.ts
107341
107491
  function getPackageVersion() {
107342
- const pkgPath = join125(dirname27(fileURLToPath5(import.meta.url)), "../../package.json");
107492
+ const pkgPath = join125(dirname28(fileURLToPath5(import.meta.url)), "../../package.json");
107343
107493
  const pkg = JSON.parse(readFileSync98(pkgPath, "utf-8"));
107344
107494
  return pkg.version;
107345
107495
  }