@cleocode/core 2026.6.3 → 2026.6.4
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/docs/export-document.js +626 -310
- package/dist/docs/export-document.js.map +3 -3
- package/dist/llm/catalog-cache.d.ts +3 -0
- package/dist/llm/catalog-cache.d.ts.map +1 -1
- package/dist/llm/catalog-cache.js.map +1 -1
- package/dist/llm/catalog-model-resolver.d.ts +89 -0
- package/dist/llm/catalog-model-resolver.d.ts.map +1 -0
- package/dist/llm/catalog-model-resolver.js +158 -0
- package/dist/llm/catalog-model-resolver.js.map +1 -0
- package/dist/llm/cli-ops.d.ts +14 -0
- package/dist/llm/cli-ops.d.ts.map +1 -1
- package/dist/llm/cli-ops.js +35 -0
- package/dist/llm/cli-ops.js.map +1 -1
- package/dist/llm/index.d.ts +3 -0
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +3 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/oauth/pkce.js +27 -5
- package/dist/llm/oauth/pkce.js.map +1 -1
- package/dist/llm/plugin-facade.js +613 -325
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/provider-registry/builtin/openai.d.ts +11 -2
- package/dist/llm/provider-registry/builtin/openai.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/openai.js +15 -3
- package/dist/llm/provider-registry/builtin/openai.js.map +1 -1
- package/dist/llm/system-resolver.d.ts +94 -0
- package/dist/llm/system-resolver.d.ts.map +1 -0
- package/dist/llm/system-resolver.js +165 -0
- package/dist/llm/system-resolver.js.map +1 -0
- package/dist/store/dual-scope-db.d.ts +20 -2
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +74 -7
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/exodus/archive.d.ts +216 -0
- package/dist/store/exodus/archive.d.ts.map +1 -0
- package/dist/store/exodus/archive.js +314 -0
- package/dist/store/exodus/archive.js.map +1 -0
- package/dist/store/exodus/index.d.ts +1 -0
- package/dist/store/exodus/index.d.ts.map +1 -1
- package/dist/store/exodus/index.js +1 -0
- package/dist/store/exodus/index.js.map +1 -1
- package/dist/store/exodus/migrate.d.ts.map +1 -1
- package/dist/store/exodus/migrate.js +118 -24
- package/dist/store/exodus/migrate.js.map +1 -1
- package/dist/store/exodus/on-open.d.ts.map +1 -1
- package/dist/store/exodus/on-open.js +95 -34
- package/dist/store/exodus/on-open.js.map +1 -1
- package/dist/store/exodus/types.d.ts +10 -1
- package/dist/store/exodus/types.d.ts.map +1 -1
- package/dist/store/exodus/types.js.map +1 -1
- package/dist/store/exodus/verify-migration.d.ts.map +1 -1
- package/dist/store/exodus/verify-migration.js +12 -1
- package/dist/store/exodus/verify-migration.js.map +1 -1
- package/dist/store/sqlite.d.ts +16 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +160 -39
- package/dist/store/sqlite.js.map +1 -1
- package/dist/validation/doctor/checks.d.ts +22 -0
- package/dist/validation/doctor/checks.d.ts.map +1 -1
- package/dist/validation/doctor/checks.js +67 -0
- package/dist/validation/doctor/checks.js.map +1 -1
- package/dist/validation/doctor/index.d.ts +1 -1
- package/dist/validation/doctor/index.d.ts.map +1 -1
- package/dist/validation/doctor/index.js +1 -1
- package/dist/validation/doctor/index.js.map +1 -1
- package/package.json +12 -12
|
@@ -10555,6 +10555,13 @@ var init_plugin_llm = __esm({
|
|
|
10555
10555
|
}
|
|
10556
10556
|
});
|
|
10557
10557
|
|
|
10558
|
+
// packages/contracts/src/llm/system-resolver.ts
|
|
10559
|
+
var init_system_resolver = __esm({
|
|
10560
|
+
"packages/contracts/src/llm/system-resolver.ts"() {
|
|
10561
|
+
"use strict";
|
|
10562
|
+
}
|
|
10563
|
+
});
|
|
10564
|
+
|
|
10558
10565
|
// packages/contracts/src/memory/observe.ts
|
|
10559
10566
|
var BRAIN_OBSERVATION_SOURCE_TYPES;
|
|
10560
10567
|
var init_observe = __esm({
|
|
@@ -12497,6 +12504,7 @@ var init_src = __esm({
|
|
|
12497
12504
|
init_invariants();
|
|
12498
12505
|
init_lafs();
|
|
12499
12506
|
init_plugin_llm();
|
|
12507
|
+
init_system_resolver();
|
|
12500
12508
|
init_observe();
|
|
12501
12509
|
init_migration_parity();
|
|
12502
12510
|
init_mvi();
|
|
@@ -14422,7 +14430,7 @@ var init_sql = __esm({
|
|
|
14422
14430
|
return new SQL([new StringChunk(str)]);
|
|
14423
14431
|
}
|
|
14424
14432
|
_sql.raw = raw;
|
|
14425
|
-
function
|
|
14433
|
+
function join22(chunks, separator) {
|
|
14426
14434
|
const result = [];
|
|
14427
14435
|
for (const [i, chunk] of chunks.entries()) {
|
|
14428
14436
|
if (i > 0 && separator !== void 0) result.push(separator);
|
|
@@ -14430,7 +14438,7 @@ var init_sql = __esm({
|
|
|
14430
14438
|
}
|
|
14431
14439
|
return new SQL(result);
|
|
14432
14440
|
}
|
|
14433
|
-
_sql.join =
|
|
14441
|
+
_sql.join = join22;
|
|
14434
14442
|
function identifier(value) {
|
|
14435
14443
|
return new Name(value);
|
|
14436
14444
|
}
|
|
@@ -16817,7 +16825,7 @@ var init_select2 = __esm({
|
|
|
16817
16825
|
const baseTableName = this.tableName;
|
|
16818
16826
|
const tableName = getTableLikeName(table);
|
|
16819
16827
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
16820
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
16828
|
+
if (typeof tableName === "string" && this.config.joins?.some((join22) => join22.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
16821
16829
|
if (!this.isPartialSelect) {
|
|
16822
16830
|
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
|
|
16823
16831
|
if (typeof tableName === "string" && !is(table, SQL)) {
|
|
@@ -20627,7 +20635,7 @@ var init_dialect = __esm({
|
|
|
20627
20635
|
if (!joins2) return;
|
|
20628
20636
|
const withEntries = Object.entries(joins2).filter(([_, v]) => v);
|
|
20629
20637
|
if (!withEntries.length) return;
|
|
20630
|
-
return sql.join(withEntries.map(([k,
|
|
20638
|
+
return sql.join(withEntries.map(([k, join22]) => {
|
|
20631
20639
|
const relation = tableConfig.relations[k];
|
|
20632
20640
|
const isSingle2 = is(relation, One);
|
|
20633
20641
|
const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
|
|
@@ -20638,7 +20646,7 @@ var init_dialect = __esm({
|
|
|
20638
20646
|
table: targetTable,
|
|
20639
20647
|
mode: isSingle2 ? "first" : "many",
|
|
20640
20648
|
schema,
|
|
20641
|
-
queryConfig:
|
|
20649
|
+
queryConfig: join22,
|
|
20642
20650
|
tableConfig: schema[relation.targetTableName],
|
|
20643
20651
|
relationWhere: filter,
|
|
20644
20652
|
isNested: true,
|
|
@@ -20652,7 +20660,7 @@ var init_dialect = __esm({
|
|
|
20652
20660
|
key: k,
|
|
20653
20661
|
selection: innerQuery.selection,
|
|
20654
20662
|
isArray: !isSingle2,
|
|
20655
|
-
isOptional: (relation.optional ?? false) ||
|
|
20663
|
+
isOptional: (relation.optional ?? false) || join22 !== true && !!join22.where
|
|
20656
20664
|
});
|
|
20657
20665
|
const jsonColumns = sql.join(innerQuery.selection.map((s) => {
|
|
20658
20666
|
return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb3}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
|
|
@@ -21473,7 +21481,7 @@ var init_update = __esm({
|
|
|
21473
21481
|
createJoin(joinType) {
|
|
21474
21482
|
return ((table, on) => {
|
|
21475
21483
|
const tableName = getTableLikeName(table);
|
|
21476
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
21484
|
+
if (typeof tableName === "string" && this.config.joins.some((join22) => join22.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
21477
21485
|
if (typeof on === "function") {
|
|
21478
21486
|
const from = this.config.from ? is(table, SQLiteTable) ? table[Table.Symbol.Columns] : is(table, Subquery) ? table._.selectedFields : is(table, SQLiteViewBase) ? table[ViewBaseConfig].selectedFields : void 0 : void 0;
|
|
21479
21487
|
on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
|
|
@@ -22506,8 +22514,8 @@ function probeAndMarkApplied(nativeDb, migration, logSubsystem) {
|
|
|
22506
22514
|
});
|
|
22507
22515
|
if (allAltersPresent && allTablesPresent && allIndexesPresent && allTriggersPresent) {
|
|
22508
22516
|
insertJournalEntry(nativeDb, migration.hash, migration.folderMillis, migration.name ?? "");
|
|
22509
|
-
const
|
|
22510
|
-
|
|
22517
|
+
const log8 = getLogger(logSubsystem);
|
|
22518
|
+
log8.debug(
|
|
22511
22519
|
{
|
|
22512
22520
|
migration: migration.name,
|
|
22513
22521
|
alters: alterTargets.length,
|
|
@@ -22547,14 +22555,14 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
22547
22555
|
if (hasOrphanedEntries) {
|
|
22548
22556
|
const dbHashes = new Set(dbEntries.map((e) => e.hash));
|
|
22549
22557
|
const allLocalHashesPresentInDb = localMigrations.every((m) => dbHashes.has(m.hash));
|
|
22550
|
-
const
|
|
22558
|
+
const log8 = getLogger(logSubsystem);
|
|
22551
22559
|
if (allLocalHashesPresentInDb) {
|
|
22552
|
-
|
|
22560
|
+
log8.debug(
|
|
22553
22561
|
{ extra: orphanedEntries.length },
|
|
22554
22562
|
`Migration journal has ${orphanedEntries.length} entries for migrations not known to this install (DB is ahead). Skipping reconciliation.`
|
|
22555
22563
|
);
|
|
22556
22564
|
} else {
|
|
22557
|
-
|
|
22565
|
+
log8.warn(
|
|
22558
22566
|
{ orphaned: orphanedEntries.length },
|
|
22559
22567
|
`Detected ${orphanedEntries.length} true-orphan journal entries from a previous CLEO lineage. Reconciling via DDL probe.`
|
|
22560
22568
|
);
|
|
@@ -22590,8 +22598,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
22590
22598
|
if (alterMatches.length === 0) {
|
|
22591
22599
|
const stripped = fullSql.replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "").trim();
|
|
22592
22600
|
if (stripped === "") {
|
|
22593
|
-
const
|
|
22594
|
-
|
|
22601
|
+
const log8 = getLogger(logSubsystem);
|
|
22602
|
+
log8.debug(
|
|
22595
22603
|
{ migration: migration.name },
|
|
22596
22604
|
`Migration ${migration.name} is a comment-only baseline marker \u2014 marking applied on existing DB.`
|
|
22597
22605
|
);
|
|
@@ -22628,8 +22636,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
22628
22636
|
}
|
|
22629
22637
|
}
|
|
22630
22638
|
if (missingColumns.length === 0) {
|
|
22631
|
-
const
|
|
22632
|
-
|
|
22639
|
+
const log8 = getLogger(logSubsystem);
|
|
22640
|
+
log8.warn(
|
|
22633
22641
|
{ migration: migration.name, columns: alterMatches },
|
|
22634
22642
|
`Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
|
|
22635
22643
|
);
|
|
@@ -22637,8 +22645,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
22637
22645
|
continue;
|
|
22638
22646
|
}
|
|
22639
22647
|
if (existingColumns.length > 0 && missingColumns.length > 0) {
|
|
22640
|
-
const
|
|
22641
|
-
|
|
22648
|
+
const log8 = getLogger(logSubsystem);
|
|
22649
|
+
log8.warn(
|
|
22642
22650
|
{
|
|
22643
22651
|
migration: migration.name,
|
|
22644
22652
|
existingColumns: existingColumns.map((c) => `${c.table}.${c.column}`),
|
|
@@ -22650,12 +22658,12 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
22650
22658
|
if (!tableExists(nativeDb, table)) continue;
|
|
22651
22659
|
try {
|
|
22652
22660
|
nativeDb.exec(`ALTER TABLE ${table} ADD COLUMN ${column}${ddl ? ` ${ddl}` : ""}`);
|
|
22653
|
-
|
|
22661
|
+
log8.warn(
|
|
22654
22662
|
{ migration: migration.name, table, column },
|
|
22655
22663
|
`T920: Added missing column ${table}.${column} to complete partial migration.`
|
|
22656
22664
|
);
|
|
22657
22665
|
} catch {
|
|
22658
|
-
|
|
22666
|
+
log8.warn(
|
|
22659
22667
|
{ migration: migration.name, table, column },
|
|
22660
22668
|
`T920: Could not add missing column ${table}.${column} \u2014 will let Drizzle migrate() handle it.`
|
|
22661
22669
|
);
|
|
@@ -22675,8 +22683,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
22675
22683
|
for (const entry of unnamedEntries) {
|
|
22676
22684
|
const migrationName = hashToName.get(entry.hash);
|
|
22677
22685
|
if (!migrationName) continue;
|
|
22678
|
-
const
|
|
22679
|
-
|
|
22686
|
+
const log8 = getLogger(logSubsystem);
|
|
22687
|
+
log8.debug(
|
|
22680
22688
|
{ id: entry.id, hash: entry.hash, name: migrationName },
|
|
22681
22689
|
`Backfilling missing name on journal entry id=${entry.id} (Drizzle v1 beta legacy compat).`
|
|
22682
22690
|
);
|
|
@@ -22817,13 +22825,13 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem, conte
|
|
|
22817
22825
|
const existingCols = new Set(columns.map((c) => c.name));
|
|
22818
22826
|
for (const req of requiredColumns) {
|
|
22819
22827
|
if (!existingCols.has(req.name)) {
|
|
22820
|
-
const
|
|
22828
|
+
const log8 = getLogger(logSubsystem);
|
|
22821
22829
|
const message = `Adding missing column ${tableName}.${req.name} via ALTER TABLE`;
|
|
22822
22830
|
const fields = { column: req.name, context };
|
|
22823
22831
|
if (context === "fresh") {
|
|
22824
|
-
|
|
22832
|
+
log8.error(fields, `${message} \u2014 MIGRATION DEFECT (fresh DB should not need repair)`);
|
|
22825
22833
|
} else {
|
|
22826
|
-
|
|
22834
|
+
log8.warn(fields, message);
|
|
22827
22835
|
}
|
|
22828
22836
|
nativeDb.exec(`ALTER TABLE ${tableName} ADD COLUMN ${req.name} ${req.ddl}`);
|
|
22829
22837
|
}
|
|
@@ -31359,14 +31367,159 @@ var init_ensure_config = __esm({
|
|
|
31359
31367
|
}
|
|
31360
31368
|
});
|
|
31361
31369
|
|
|
31370
|
+
// packages/core/src/store/exodus/archive.ts
|
|
31371
|
+
import {
|
|
31372
|
+
copyFileSync as copyFileSync2,
|
|
31373
|
+
existsSync as existsSync4,
|
|
31374
|
+
mkdirSync,
|
|
31375
|
+
renameSync,
|
|
31376
|
+
unlinkSync,
|
|
31377
|
+
writeFileSync
|
|
31378
|
+
} from "node:fs";
|
|
31379
|
+
import { basename as basename3, join as join6 } from "node:path";
|
|
31380
|
+
function scopeBaseDir(scope, cwd) {
|
|
31381
|
+
return scope === "project" ? resolveCleoDir(cwd) : getCleoHome();
|
|
31382
|
+
}
|
|
31383
|
+
function exodusArchiveDir(scope, cwd) {
|
|
31384
|
+
return join6(scopeBaseDir(scope, cwd), ARCHIVE_DIR_NAME);
|
|
31385
|
+
}
|
|
31386
|
+
function exodusMarkerPath(scope, cwd) {
|
|
31387
|
+
return join6(scopeBaseDir(scope, cwd), MARKER_FILENAME_BY_SCOPE[scope]);
|
|
31388
|
+
}
|
|
31389
|
+
function hasExodusCompleteMarker(scope, cwd) {
|
|
31390
|
+
try {
|
|
31391
|
+
return existsSync4(exodusMarkerPath(scope, cwd));
|
|
31392
|
+
} catch {
|
|
31393
|
+
return false;
|
|
31394
|
+
}
|
|
31395
|
+
}
|
|
31396
|
+
function writeExodusCompleteMarker(scope, archivedSources, cwd) {
|
|
31397
|
+
const markerPath = exodusMarkerPath(scope, cwd);
|
|
31398
|
+
const baseDir = scopeBaseDir(scope, cwd);
|
|
31399
|
+
mkdirSync(baseDir, { recursive: true });
|
|
31400
|
+
const marker = {
|
|
31401
|
+
version: 1,
|
|
31402
|
+
scope,
|
|
31403
|
+
cleoVersion: getCleoVersion(),
|
|
31404
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
31405
|
+
archivedSources: [...archivedSources]
|
|
31406
|
+
};
|
|
31407
|
+
const tmpPath = `${markerPath}.tmp`;
|
|
31408
|
+
writeFileSync(tmpPath, JSON.stringify(marker, null, 2) + "\n", "utf8");
|
|
31409
|
+
renameSync(tmpPath, markerPath);
|
|
31410
|
+
log.info({ scope, markerPath, archivedSources }, "exodus: wrote completion marker");
|
|
31411
|
+
return markerPath;
|
|
31412
|
+
}
|
|
31413
|
+
function moveFileInto(srcPath, destDir) {
|
|
31414
|
+
mkdirSync(destDir, { recursive: true });
|
|
31415
|
+
let dest = join6(destDir, basename3(srcPath));
|
|
31416
|
+
if (existsSync4(dest)) {
|
|
31417
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
|
|
31418
|
+
dest = join6(destDir, `${basename3(srcPath)}.${stamp}`);
|
|
31419
|
+
}
|
|
31420
|
+
try {
|
|
31421
|
+
renameSync(srcPath, dest);
|
|
31422
|
+
} catch {
|
|
31423
|
+
copyFileSync2(srcPath, dest);
|
|
31424
|
+
unlinkSync(srcPath);
|
|
31425
|
+
}
|
|
31426
|
+
return dest;
|
|
31427
|
+
}
|
|
31428
|
+
function archiveSourceDb(source, cwd) {
|
|
31429
|
+
if (!existsSync4(source.path)) {
|
|
31430
|
+
return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
|
|
31431
|
+
}
|
|
31432
|
+
const destDir = exodusArchiveDir(source.targetScope, cwd);
|
|
31433
|
+
const archivedTo = moveFileInto(source.path, destDir);
|
|
31434
|
+
for (const suffix of SIDECAR_SUFFIXES) {
|
|
31435
|
+
const sidecar = `${source.path}${suffix}`;
|
|
31436
|
+
if (existsSync4(sidecar)) {
|
|
31437
|
+
try {
|
|
31438
|
+
moveFileInto(sidecar, destDir);
|
|
31439
|
+
} catch (err) {
|
|
31440
|
+
log.warn(
|
|
31441
|
+
{ err, sidecar, sourceName: source.name },
|
|
31442
|
+
"exodus-archive: failed to archive sidecar (non-fatal)"
|
|
31443
|
+
);
|
|
31444
|
+
}
|
|
31445
|
+
}
|
|
31446
|
+
}
|
|
31447
|
+
log.info(
|
|
31448
|
+
{ sourceName: source.name, sourcePath: source.path, archivedTo, scope: source.targetScope },
|
|
31449
|
+
"exodus-archive: archived legacy source DB"
|
|
31450
|
+
);
|
|
31451
|
+
return {
|
|
31452
|
+
name: source.name,
|
|
31453
|
+
sourcePath: source.path,
|
|
31454
|
+
archivedTo,
|
|
31455
|
+
action: "archived"
|
|
31456
|
+
};
|
|
31457
|
+
}
|
|
31458
|
+
function archiveMigratedSources(consumed, cwd) {
|
|
31459
|
+
const results = [];
|
|
31460
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
31461
|
+
for (const source of consumed) {
|
|
31462
|
+
scopes.add(source.targetScope);
|
|
31463
|
+
results.push(archiveSourceDb(source, cwd));
|
|
31464
|
+
}
|
|
31465
|
+
const markersWritten = [];
|
|
31466
|
+
for (const scope of scopes) {
|
|
31467
|
+
const archivedForScope = consumed.filter((s) => s.targetScope === scope).map((s) => s.name);
|
|
31468
|
+
writeExodusCompleteMarker(scope, archivedForScope, cwd);
|
|
31469
|
+
markersWritten.push(scope);
|
|
31470
|
+
}
|
|
31471
|
+
return { sources: results, markersWritten };
|
|
31472
|
+
}
|
|
31473
|
+
function detectStrandedResidue(sources, cwd) {
|
|
31474
|
+
const markedScopes = /* @__PURE__ */ new Set();
|
|
31475
|
+
for (const scope of ["project", "global"]) {
|
|
31476
|
+
if (hasExodusCompleteMarker(scope, cwd)) markedScopes.add(scope);
|
|
31477
|
+
}
|
|
31478
|
+
if (markedScopes.size === 0) return [];
|
|
31479
|
+
const stranded = [];
|
|
31480
|
+
for (const source of sources) {
|
|
31481
|
+
if (!markedScopes.has(source.targetScope)) continue;
|
|
31482
|
+
if (existsSync4(source.path)) {
|
|
31483
|
+
stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
|
|
31484
|
+
}
|
|
31485
|
+
}
|
|
31486
|
+
return stranded;
|
|
31487
|
+
}
|
|
31488
|
+
function archiveStrandedResidue(stranded, sources, cwd) {
|
|
31489
|
+
const byName = new Map(sources.map((s) => [s.name, s]));
|
|
31490
|
+
const results = [];
|
|
31491
|
+
for (const entry of stranded) {
|
|
31492
|
+
const descriptor = byName.get(entry.name);
|
|
31493
|
+
if (descriptor === void 0) continue;
|
|
31494
|
+
results.push(archiveSourceDb(descriptor, cwd));
|
|
31495
|
+
}
|
|
31496
|
+
return results;
|
|
31497
|
+
}
|
|
31498
|
+
var log, ARCHIVE_DIR_NAME, MARKER_FILENAME_BY_SCOPE, SIDECAR_SUFFIXES;
|
|
31499
|
+
var init_archive2 = __esm({
|
|
31500
|
+
"packages/core/src/store/exodus/archive.ts"() {
|
|
31501
|
+
"use strict";
|
|
31502
|
+
init_logger2();
|
|
31503
|
+
init_paths();
|
|
31504
|
+
init_ensure_config();
|
|
31505
|
+
log = getLogger("exodus-archive");
|
|
31506
|
+
ARCHIVE_DIR_NAME = "_archive";
|
|
31507
|
+
MARKER_FILENAME_BY_SCOPE = {
|
|
31508
|
+
project: "exodus-complete",
|
|
31509
|
+
global: "exodus-complete"
|
|
31510
|
+
};
|
|
31511
|
+
SIDECAR_SUFFIXES = ["-wal", "-shm"];
|
|
31512
|
+
}
|
|
31513
|
+
});
|
|
31514
|
+
|
|
31362
31515
|
// packages/core/src/project-info.ts
|
|
31363
|
-
import { existsSync as
|
|
31364
|
-
import { join as
|
|
31516
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
31517
|
+
import { join as join7 } from "node:path";
|
|
31365
31518
|
function getProjectInfoSync(cwd) {
|
|
31366
31519
|
const projectRoot = resolveOrCwd(cwd);
|
|
31367
31520
|
const cleoDir = getCleoDirAbsolute(projectRoot);
|
|
31368
|
-
const infoPath =
|
|
31369
|
-
if (!
|
|
31521
|
+
const infoPath = join7(cleoDir, "project-info.json");
|
|
31522
|
+
if (!existsSync5(infoPath)) return null;
|
|
31370
31523
|
try {
|
|
31371
31524
|
const raw = readFileSync2(infoPath, "utf-8");
|
|
31372
31525
|
const data = JSON.parse(raw);
|
|
@@ -31393,8 +31546,8 @@ var init_project_info = __esm({
|
|
|
31393
31546
|
});
|
|
31394
31547
|
|
|
31395
31548
|
// packages/core/src/store/worktree-isolation-guard.ts
|
|
31396
|
-
import { existsSync as
|
|
31397
|
-
import { dirname as dirname4, join as
|
|
31549
|
+
import { existsSync as existsSync6, statSync } from "node:fs";
|
|
31550
|
+
import { dirname as dirname4, join as join8 } from "node:path";
|
|
31398
31551
|
function assertDbPathIsNotWorktreeResident(role, cwd) {
|
|
31399
31552
|
let cleoDir;
|
|
31400
31553
|
try {
|
|
@@ -31403,10 +31556,10 @@ function assertDbPathIsNotWorktreeResident(role, cwd) {
|
|
|
31403
31556
|
return;
|
|
31404
31557
|
}
|
|
31405
31558
|
const projectRoot = dirname4(cleoDir);
|
|
31406
|
-
const projectGit =
|
|
31559
|
+
const projectGit = join8(projectRoot, ".git");
|
|
31407
31560
|
let isWorktreeGitlink = false;
|
|
31408
31561
|
try {
|
|
31409
|
-
isWorktreeGitlink =
|
|
31562
|
+
isWorktreeGitlink = existsSync6(projectGit) && statSync(projectGit).isFile();
|
|
31410
31563
|
} catch {
|
|
31411
31564
|
}
|
|
31412
31565
|
if (!isWorktreeGitlink) {
|
|
@@ -31881,15 +32034,15 @@ var init_types = __esm({
|
|
|
31881
32034
|
|
|
31882
32035
|
// packages/core/src/store/exodus/migrate.ts
|
|
31883
32036
|
import {
|
|
31884
|
-
copyFileSync as
|
|
31885
|
-
existsSync as
|
|
31886
|
-
mkdirSync,
|
|
32037
|
+
copyFileSync as copyFileSync3,
|
|
32038
|
+
existsSync as existsSync7,
|
|
32039
|
+
mkdirSync as mkdirSync2,
|
|
31887
32040
|
readFileSync as readFileSync3,
|
|
31888
|
-
renameSync,
|
|
31889
|
-
unlinkSync,
|
|
31890
|
-
writeFileSync as
|
|
32041
|
+
renameSync as renameSync2,
|
|
32042
|
+
unlinkSync as unlinkSync2,
|
|
32043
|
+
writeFileSync as writeFileSync3
|
|
31891
32044
|
} from "node:fs";
|
|
31892
|
-
import { join as
|
|
32045
|
+
import { join as join9 } from "node:path";
|
|
31893
32046
|
function getSqliteVersion(db) {
|
|
31894
32047
|
try {
|
|
31895
32048
|
const row = db.prepare("SELECT sqlite_version() AS v").get();
|
|
@@ -31905,14 +32058,14 @@ function listTables(db) {
|
|
|
31905
32058
|
return rows.map((r) => r.name);
|
|
31906
32059
|
}
|
|
31907
32060
|
function writeJournal(stagingDir, journal) {
|
|
31908
|
-
const journalPath =
|
|
32061
|
+
const journalPath = join9(stagingDir, JOURNAL_FILENAME);
|
|
31909
32062
|
const tmpPath = `${journalPath}.tmp`;
|
|
31910
|
-
|
|
31911
|
-
|
|
32063
|
+
writeFileSync3(tmpPath, JSON.stringify(journal, null, 2) + "\n", "utf8");
|
|
32064
|
+
renameSync2(tmpPath, journalPath);
|
|
31912
32065
|
}
|
|
31913
32066
|
function readJournal(stagingDir) {
|
|
31914
|
-
const journalPath =
|
|
31915
|
-
if (!
|
|
32067
|
+
const journalPath = join9(stagingDir, JOURNAL_FILENAME);
|
|
32068
|
+
if (!existsSync7(journalPath)) return null;
|
|
31916
32069
|
try {
|
|
31917
32070
|
return JSON.parse(readFileSync3(journalPath, "utf8"));
|
|
31918
32071
|
} catch {
|
|
@@ -31920,17 +32073,17 @@ function readJournal(stagingDir) {
|
|
|
31920
32073
|
}
|
|
31921
32074
|
}
|
|
31922
32075
|
function clearExodusJournal(stagingDir) {
|
|
31923
|
-
const journalPath =
|
|
32076
|
+
const journalPath = join9(stagingDir, JOURNAL_FILENAME);
|
|
31924
32077
|
try {
|
|
31925
|
-
if (!
|
|
31926
|
-
|
|
31927
|
-
|
|
32078
|
+
if (!existsSync7(journalPath)) return false;
|
|
32079
|
+
unlinkSync2(journalPath);
|
|
32080
|
+
log2.info(
|
|
31928
32081
|
{ stagingDir },
|
|
31929
32082
|
"exodus: cleared migrate journal after abort/rollback \u2014 a retry will RE-COPY all tables"
|
|
31930
32083
|
);
|
|
31931
32084
|
return true;
|
|
31932
32085
|
} catch (err) {
|
|
31933
|
-
|
|
32086
|
+
log2.warn(
|
|
31934
32087
|
{ err, stagingDir },
|
|
31935
32088
|
'exodus: failed to clear migrate journal after rollback (a retry may skip already-"done" tables)'
|
|
31936
32089
|
);
|
|
@@ -31955,11 +32108,11 @@ function lockPath(dbPath) {
|
|
|
31955
32108
|
}
|
|
31956
32109
|
function acquireAdvisoryLock(dbPath) {
|
|
31957
32110
|
const lp = lockPath(dbPath);
|
|
31958
|
-
|
|
32111
|
+
writeFileSync3(lp, JSON.stringify({ pid: process.pid, ts: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
|
|
31959
32112
|
}
|
|
31960
32113
|
function releaseAdvisoryLock(dbPath) {
|
|
31961
32114
|
try {
|
|
31962
|
-
|
|
32115
|
+
unlinkSync2(lockPath(dbPath));
|
|
31963
32116
|
} catch {
|
|
31964
32117
|
}
|
|
31965
32118
|
}
|
|
@@ -31979,6 +32132,11 @@ function enumNormExpr(targetTableName, col, srcRef) {
|
|
|
31979
32132
|
const fn = ENUM_NORMALIZATIONS.get(key);
|
|
31980
32133
|
return fn ? fn(srcRef) : null;
|
|
31981
32134
|
}
|
|
32135
|
+
function numericClampExpr(targetTableName, col, srcRef) {
|
|
32136
|
+
const key = `${targetTableName}.${col}`;
|
|
32137
|
+
const fn = NUMERIC_CLAMPS.get(key);
|
|
32138
|
+
return fn ? fn(srcRef) : null;
|
|
32139
|
+
}
|
|
31982
32140
|
function epochUnitForSource(sourceName) {
|
|
31983
32141
|
const key = sourceName.toLowerCase();
|
|
31984
32142
|
for (const [pattern, unit] of SOURCE_EPOCH_UNITS) {
|
|
@@ -32014,6 +32172,14 @@ function buildSelectExpr(attachAlias, legacyTable, targetTableName, col, srcType
|
|
|
32014
32172
|
}
|
|
32015
32173
|
return `${isoExpr} AS "${col}"`;
|
|
32016
32174
|
}
|
|
32175
|
+
const clampExpr = numericClampExpr(targetTableName, col, srcRef);
|
|
32176
|
+
if (clampExpr !== null) {
|
|
32177
|
+
if (isNotNullWithoutDefault) {
|
|
32178
|
+
const defLiteral = typeDefaultLiteral(tgtInfo.type);
|
|
32179
|
+
return `COALESCE(${clampExpr}, ${defLiteral}) AS "${col}"`;
|
|
32180
|
+
}
|
|
32181
|
+
return `${clampExpr} AS "${col}"`;
|
|
32182
|
+
}
|
|
32017
32183
|
const normExpr = enumNormExpr(targetTableName, col, srcRef);
|
|
32018
32184
|
if (normExpr !== null) {
|
|
32019
32185
|
if (isNotNullWithoutDefault) {
|
|
@@ -32031,7 +32197,7 @@ function buildSelectExpr(attachAlias, legacyTable, targetTableName, col, srcType
|
|
|
32031
32197
|
function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyTableName, sourceName, targetSchema = "main") {
|
|
32032
32198
|
const resolution = resolveConsolidatedTableName(sourceName, legacyTableName);
|
|
32033
32199
|
if (resolution.kind === "skip") {
|
|
32034
|
-
|
|
32200
|
+
log2.warn(
|
|
32035
32201
|
{ legacyTableName, sourceName, reason: resolution.reason },
|
|
32036
32202
|
`Exodus: explicitly skipping table \u2014 ${resolution.reason}`
|
|
32037
32203
|
);
|
|
@@ -32050,7 +32216,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
32050
32216
|
).get();
|
|
32051
32217
|
if (!existsRow) {
|
|
32052
32218
|
const reason = `consolidated target '${targetTableName}' not found (mapped from legacy '${legacyTableName}')`;
|
|
32053
|
-
|
|
32219
|
+
log2.warn(
|
|
32054
32220
|
{ legacyTableName, targetTableName, sourceName, attachAlias, targetSchema },
|
|
32055
32221
|
`Exodus: ${reason}`
|
|
32056
32222
|
);
|
|
@@ -32061,13 +32227,13 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
32061
32227
|
const sharedColumns = srcPragma.map((r) => r.name).filter((col) => tgtColMap.has(col));
|
|
32062
32228
|
if (sharedColumns.length === 0) {
|
|
32063
32229
|
const reason = `no overlapping columns between source '${legacyTableName}' and target '${targetTableName}'`;
|
|
32064
|
-
|
|
32230
|
+
log2.warn({ legacyTableName, targetTableName, sourceName }, `Exodus: ${reason}`);
|
|
32065
32231
|
return { rowsCopied: 0, skipped: true, reason };
|
|
32066
32232
|
}
|
|
32067
32233
|
const srcOnlyColumns = srcPragma.map((r) => r.name).filter((c) => !tgtColMap.has(c));
|
|
32068
32234
|
const tgtOnlyColumns = tgtPragma.map((r) => r.name).filter((c) => !srcColumns.has(c));
|
|
32069
32235
|
if (srcOnlyColumns.length > 0 || tgtOnlyColumns.length > 0) {
|
|
32070
|
-
|
|
32236
|
+
log2.info(
|
|
32071
32237
|
{ legacyTableName, targetTableName, sourceName, srcOnlyColumns, tgtOnlyColumns },
|
|
32072
32238
|
"Exodus: column drift detected \u2014 copying intersection, dropping src-only cols, using defaults for tgt-only cols"
|
|
32073
32239
|
);
|
|
@@ -32082,7 +32248,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
32082
32248
|
return isoGlobCols.has(col) && (upper.includes("INT") || upper === "" || upper === "NUMERIC");
|
|
32083
32249
|
});
|
|
32084
32250
|
if (coercedCols.length > 0) {
|
|
32085
|
-
|
|
32251
|
+
log2.info(
|
|
32086
32252
|
{
|
|
32087
32253
|
legacyTableName,
|
|
32088
32254
|
targetTableName,
|
|
@@ -32098,11 +32264,20 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
32098
32264
|
(col) => ENUM_NORMALIZATIONS.has(`${targetTableName}.${col}`)
|
|
32099
32265
|
);
|
|
32100
32266
|
if (normalizedCols.length > 0) {
|
|
32101
|
-
|
|
32267
|
+
log2.info(
|
|
32102
32268
|
{ legacyTableName, targetTableName, sourceName, normalizedCols },
|
|
32103
32269
|
`Exodus: applying enum-value normalization for ${normalizedCols.length} column(s) (T11547)`
|
|
32104
32270
|
);
|
|
32105
32271
|
}
|
|
32272
|
+
const clampedCols = sharedColumns.filter(
|
|
32273
|
+
(col) => NUMERIC_CLAMPS.has(`${targetTableName}.${col}`)
|
|
32274
|
+
);
|
|
32275
|
+
if (clampedCols.length > 0) {
|
|
32276
|
+
log2.info(
|
|
32277
|
+
{ legacyTableName, targetTableName, sourceName, clampedCols },
|
|
32278
|
+
`Exodus: applying non-finite numeric clamp for ${clampedCols.length} column(s) (T11782)`
|
|
32279
|
+
);
|
|
32280
|
+
}
|
|
32106
32281
|
const selectExprs = sharedColumns.map((col) => {
|
|
32107
32282
|
const srcType = srcTypeMap.get(col) ?? "";
|
|
32108
32283
|
const tgtInfo = tgtColMap.get(col);
|
|
@@ -32139,13 +32314,13 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
32139
32314
|
const dropped = sourceCount - rowsCopied;
|
|
32140
32315
|
if (rowsCopied === 0) {
|
|
32141
32316
|
const reason = `INSERT OR IGNORE dropped ALL ${sourceCount} rows from '${legacyTableName}'\u2192'${targetTableName}' (rowsCopied=0, sourceCount=${sourceCount}). Likely a CHECK/type constraint violation \u2014 check epoch coercion or enum values.`;
|
|
32142
|
-
|
|
32317
|
+
log2.error(
|
|
32143
32318
|
{ legacyTableName, targetTableName, sourceName, sourceCount, rowsCopied },
|
|
32144
32319
|
`Exodus: ${reason}`
|
|
32145
32320
|
);
|
|
32146
32321
|
return { rowsCopied: 0, skipped: false, reason };
|
|
32147
32322
|
}
|
|
32148
|
-
|
|
32323
|
+
log2.warn(
|
|
32149
32324
|
{ legacyTableName, targetTableName, sourceName, sourceCount, rowsCopied, dropped },
|
|
32150
32325
|
`Exodus: INSERT OR IGNORE dropped ${dropped}/${sourceCount} rows from '${legacyTableName}'\u2192'${targetTableName}' \u2014 may be idempotent-resume dedup or a constraint violation; verify will confirm`
|
|
32151
32326
|
);
|
|
@@ -32156,16 +32331,16 @@ function checkSchemaVersion(journal, forceCrossVersion) {
|
|
|
32156
32331
|
if (journal.targetSchemaVersion !== EXODUS_TARGET_SCHEMA_VERSION) {
|
|
32157
32332
|
const msg = `Schema version mismatch: journal=${journal.targetSchemaVersion}, expected=${EXODUS_TARGET_SCHEMA_VERSION}`;
|
|
32158
32333
|
if (forceCrossVersion) {
|
|
32159
|
-
|
|
32334
|
+
log2.warn(msg + " (--force-cross-version: continuing anyway)");
|
|
32160
32335
|
return true;
|
|
32161
32336
|
}
|
|
32162
|
-
|
|
32337
|
+
log2.error(msg + " \u2014 pass --force-cross-version to override");
|
|
32163
32338
|
return false;
|
|
32164
32339
|
}
|
|
32165
32340
|
return true;
|
|
32166
32341
|
}
|
|
32167
32342
|
async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
32168
|
-
const { sources, stagingDir, diskPreflight, projectDbPath } = plan;
|
|
32343
|
+
const { sources, stagingDir, diskPreflight, projectDbPath, globalDbPath } = plan;
|
|
32169
32344
|
if (!diskPreflight) {
|
|
32170
32345
|
return {
|
|
32171
32346
|
ok: false,
|
|
@@ -32175,10 +32350,10 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
32175
32350
|
error: `Insufficient disk space: need \u22653\xD7 source size (${plan.totalSourceBytes} bytes source, ${plan.availableBytes} bytes available). Free up space or use a different storage location.`
|
|
32176
32351
|
};
|
|
32177
32352
|
}
|
|
32178
|
-
|
|
32353
|
+
mkdirSync2(stagingDir, { recursive: true });
|
|
32179
32354
|
let sqliteVersion = "unknown";
|
|
32180
32355
|
for (const src of sources) {
|
|
32181
|
-
if (
|
|
32356
|
+
if (existsSync7(src.path)) {
|
|
32182
32357
|
const snap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
32183
32358
|
sqliteVersion = getSqliteVersion(snap.db);
|
|
32184
32359
|
snap.close();
|
|
@@ -32203,6 +32378,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
32203
32378
|
const backupPaths = [];
|
|
32204
32379
|
const allTableResults = [];
|
|
32205
32380
|
const lockedPaths = [];
|
|
32381
|
+
let projectHandle = null;
|
|
32382
|
+
let globalHandle = null;
|
|
32206
32383
|
try {
|
|
32207
32384
|
let extractNativeDb2 = function(handle) {
|
|
32208
32385
|
const drizzleHandle = handle.db;
|
|
@@ -32217,24 +32394,28 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
32217
32394
|
};
|
|
32218
32395
|
var extractNativeDb = extractNativeDb2;
|
|
32219
32396
|
for (const src of sources) {
|
|
32220
|
-
if (!
|
|
32221
|
-
const backupDest =
|
|
32222
|
-
if (!
|
|
32397
|
+
if (!existsSync7(src.path)) continue;
|
|
32398
|
+
const backupDest = join9(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
|
|
32399
|
+
if (!existsSync7(backupDest)) {
|
|
32223
32400
|
onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
|
|
32224
|
-
|
|
32401
|
+
copyFileSync3(src.path, backupDest);
|
|
32225
32402
|
backupPaths.push(backupDest);
|
|
32226
32403
|
}
|
|
32227
32404
|
acquireAdvisoryLock(src.path);
|
|
32228
32405
|
lockedPaths.push(src.path);
|
|
32229
32406
|
}
|
|
32230
|
-
onProgress?.("Opening
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
|
|
32407
|
+
onProgress?.("Opening DEDICATED project-scope cleo.db connection (running migrations)\u2026");
|
|
32408
|
+
projectHandle = await openDualScopeDbAtPath("project", projectDbPath, void 0, {
|
|
32409
|
+
dedicated: true
|
|
32410
|
+
});
|
|
32411
|
+
onProgress?.("Opening DEDICATED global-scope cleo.db connection (running migrations)\u2026");
|
|
32412
|
+
globalHandle = await openDualScopeDbAtPath("global", globalDbPath, void 0, {
|
|
32413
|
+
dedicated: true
|
|
32414
|
+
});
|
|
32234
32415
|
const projectNative = extractNativeDb2(projectHandle);
|
|
32235
32416
|
const globalNative = extractNativeDb2(globalHandle);
|
|
32236
|
-
const projectSources = sources.filter((s) => s.targetScope === "project" &&
|
|
32237
|
-
const globalSources = sources.filter((s) => s.targetScope === "global" &&
|
|
32417
|
+
const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync7(s.path));
|
|
32418
|
+
const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync7(s.path));
|
|
32238
32419
|
await migrateScope(
|
|
32239
32420
|
"project",
|
|
32240
32421
|
projectSources,
|
|
@@ -32256,14 +32437,20 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
32256
32437
|
);
|
|
32257
32438
|
journal.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
32258
32439
|
writeJournal(stagingDir, journal);
|
|
32259
|
-
projectHandle.close();
|
|
32260
|
-
globalHandle.close();
|
|
32261
32440
|
return { ok: true, tables: allTableResults, stagingDir, backupPaths };
|
|
32262
32441
|
} catch (err) {
|
|
32263
32442
|
const error = err instanceof Error ? err.message : String(err);
|
|
32264
|
-
|
|
32443
|
+
log2.error({ err }, "Exodus migration failed");
|
|
32265
32444
|
return { ok: false, tables: allTableResults, stagingDir, backupPaths, error };
|
|
32266
32445
|
} finally {
|
|
32446
|
+
try {
|
|
32447
|
+
projectHandle?.close();
|
|
32448
|
+
} catch {
|
|
32449
|
+
}
|
|
32450
|
+
try {
|
|
32451
|
+
globalHandle?.close();
|
|
32452
|
+
} catch {
|
|
32453
|
+
}
|
|
32267
32454
|
for (const p of lockedPaths) {
|
|
32268
32455
|
releaseAdvisoryLock(p);
|
|
32269
32456
|
}
|
|
@@ -32273,7 +32460,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
32273
32460
|
if (sources.length === 0) return;
|
|
32274
32461
|
onProgress?.(`Migrating ${scope}-scope sources\u2026`);
|
|
32275
32462
|
targetNativeDb.exec("PRAGMA foreign_keys = OFF");
|
|
32276
|
-
|
|
32463
|
+
log2.info({ scope }, "Exodus: foreign_keys=OFF for bulk copy (T11533 FK-defer)");
|
|
32277
32464
|
try {
|
|
32278
32465
|
for (let i = 0; i < sources.length; i++) {
|
|
32279
32466
|
const src = sources[i];
|
|
@@ -32335,12 +32522,12 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
32335
32522
|
errorMsg = copyResult.reason;
|
|
32336
32523
|
skipped = true;
|
|
32337
32524
|
} else if (copyResult.reason) {
|
|
32338
|
-
status = "
|
|
32525
|
+
status = "partial";
|
|
32339
32526
|
errorMsg = copyResult.reason;
|
|
32340
32527
|
}
|
|
32341
32528
|
} catch (err) {
|
|
32342
32529
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32343
|
-
|
|
32530
|
+
log2.warn({ tableName, sourceDb: src.name, err }, "Table copy failed \u2014 skipping");
|
|
32344
32531
|
status = "skipped";
|
|
32345
32532
|
errorMsg = msg;
|
|
32346
32533
|
skipped = true;
|
|
@@ -32388,7 +32575,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
32388
32575
|
targetNativeDb.exec(`DETACH DATABASE "${attachAlias}"`);
|
|
32389
32576
|
onProgress?.(` [${src.name}] Detached "${attachAlias}"`);
|
|
32390
32577
|
} catch (detachErr) {
|
|
32391
|
-
|
|
32578
|
+
log2.warn(
|
|
32392
32579
|
{ attachAlias, sourceDb: src.name, err: detachErr },
|
|
32393
32580
|
"DETACH failed \u2014 alias will be released on DB close"
|
|
32394
32581
|
);
|
|
@@ -32398,7 +32585,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
32398
32585
|
targetNativeDb.exec(`DETACH DATABASE "${crossAlias}"`);
|
|
32399
32586
|
onProgress?.(` [${src.name}] Cross-scope target detached "${crossAlias}"`);
|
|
32400
32587
|
} catch (detachErr) {
|
|
32401
|
-
|
|
32588
|
+
log2.warn(
|
|
32402
32589
|
{ crossAlias, sourceDb: src.name, err: detachErr },
|
|
32403
32590
|
"Cross-scope DETACH failed \u2014 alias will be released on DB close"
|
|
32404
32591
|
);
|
|
@@ -32410,28 +32597,28 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
32410
32597
|
try {
|
|
32411
32598
|
const orphans = targetNativeDb.prepare("PRAGMA foreign_key_check").all();
|
|
32412
32599
|
if (orphans.length > 0) {
|
|
32413
|
-
|
|
32600
|
+
log2.warn(
|
|
32414
32601
|
{ scope, orphanCount: orphans.length, sample: orphans.slice(0, 5) },
|
|
32415
32602
|
`Exodus: PRAGMA foreign_key_check found ${orphans.length} orphan row(s) after bulk copy \u2014 these are genuine data orphans (not ordering artifacts)`
|
|
32416
32603
|
);
|
|
32417
32604
|
} else {
|
|
32418
|
-
|
|
32605
|
+
log2.info({ scope }, "Exodus: PRAGMA foreign_key_check PASSED \u2014 no orphan rows");
|
|
32419
32606
|
}
|
|
32420
32607
|
} catch (checkErr) {
|
|
32421
|
-
|
|
32608
|
+
log2.warn(
|
|
32422
32609
|
{ scope, err: checkErr },
|
|
32423
32610
|
"Exodus: PRAGMA foreign_key_check failed (non-fatal) \u2014 target schema may not have FK constraints enabled"
|
|
32424
32611
|
);
|
|
32425
32612
|
}
|
|
32426
32613
|
try {
|
|
32427
32614
|
targetNativeDb.exec("PRAGMA foreign_keys = ON");
|
|
32428
|
-
|
|
32615
|
+
log2.info({ scope }, "Exodus: foreign_keys=ON restored after bulk copy");
|
|
32429
32616
|
} catch (fkErr) {
|
|
32430
|
-
|
|
32617
|
+
log2.warn({ scope, err: fkErr }, "Exodus: could not restore foreign_keys=ON (non-fatal)");
|
|
32431
32618
|
}
|
|
32432
32619
|
}
|
|
32433
32620
|
}
|
|
32434
|
-
var
|
|
32621
|
+
var log2, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, ENUM_NORMALIZATIONS, NUMERIC_CLAMPS, ISO_CHECK_REGEX, SOURCE_EPOCH_UNITS, EPOCH_SECONDS_THRESHOLD;
|
|
32435
32622
|
var init_migrate = __esm({
|
|
32436
32623
|
"packages/core/src/store/exodus/migrate.ts"() {
|
|
32437
32624
|
"use strict";
|
|
@@ -32441,7 +32628,7 @@ var init_migrate = __esm({
|
|
|
32441
32628
|
init_open_cleo_db();
|
|
32442
32629
|
init_table_name_map();
|
|
32443
32630
|
init_types();
|
|
32444
|
-
|
|
32631
|
+
log2 = getLogger("exodus-migrate");
|
|
32445
32632
|
LOCK_SENTINEL_SUFFIX = ".exodus-lock";
|
|
32446
32633
|
JOURNAL_FILENAME = "exodus-journal.json";
|
|
32447
32634
|
ENUM_NORMALIZATIONS = /* @__PURE__ */ new Map([
|
|
@@ -32533,6 +32720,15 @@ var init_migrate = __esm({
|
|
|
32533
32720
|
// brain target = runtime shape with no CHECK; legacy values like 'accepted',
|
|
32534
32721
|
// 'rejected', 'prime' now survive VERBATIM instead of being coerced.)
|
|
32535
32722
|
]);
|
|
32723
|
+
NUMERIC_CLAMPS = /* @__PURE__ */ new Map([
|
|
32724
|
+
// --- brain_weight_history.delta_weight (T11782) -------------------------
|
|
32725
|
+
// +Inf → 1.0 (max canonical reinforcement), -Inf → -1.0 (max canonical
|
|
32726
|
+
// depression), NaN → 0.0 (no-op delta). Finite values pass through.
|
|
32727
|
+
[
|
|
32728
|
+
"brain_weight_history.delta_weight",
|
|
32729
|
+
(src) => `CASE WHEN ${src} = 9e999 THEN 1.0 WHEN ${src} = -9e999 THEN -1.0 WHEN ${src} != ${src} THEN 0.0 ELSE ${src} END`
|
|
32730
|
+
]
|
|
32731
|
+
]);
|
|
32536
32732
|
ISO_CHECK_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+IS\s+NULL\s+OR\s+"[^"]+"\s+GLOB\s+'\[0-9/gi;
|
|
32537
32733
|
SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
|
|
32538
32734
|
["conduit", "seconds"],
|
|
@@ -32549,8 +32745,8 @@ var init_migrate = __esm({
|
|
|
32549
32745
|
});
|
|
32550
32746
|
|
|
32551
32747
|
// packages/core/src/store/exodus/plan.ts
|
|
32552
|
-
import { existsSync as
|
|
32553
|
-
import { join as
|
|
32748
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2, statfsSync, statSync as statSync2 } from "node:fs";
|
|
32749
|
+
import { join as join10 } from "node:path";
|
|
32554
32750
|
function buildSourceDescriptors(cwd) {
|
|
32555
32751
|
const cleoDir = resolveCleoDir(cwd);
|
|
32556
32752
|
const cleoHome = getCleoHome();
|
|
@@ -32558,33 +32754,33 @@ function buildSourceDescriptors(cwd) {
|
|
|
32558
32754
|
// Project-tier — go into consolidated project-scope cleo.db
|
|
32559
32755
|
{
|
|
32560
32756
|
name: "tasks",
|
|
32561
|
-
path:
|
|
32757
|
+
path: join10(cleoDir, "tasks.db"),
|
|
32562
32758
|
targetScope: "project"
|
|
32563
32759
|
},
|
|
32564
32760
|
{
|
|
32565
32761
|
name: "brain (project)",
|
|
32566
|
-
path:
|
|
32762
|
+
path: join10(cleoDir, "brain.db"),
|
|
32567
32763
|
targetScope: "project"
|
|
32568
32764
|
},
|
|
32569
32765
|
{
|
|
32570
32766
|
name: "conduit",
|
|
32571
|
-
path:
|
|
32767
|
+
path: join10(cleoDir, "conduit.db"),
|
|
32572
32768
|
targetScope: "project"
|
|
32573
32769
|
},
|
|
32574
32770
|
// Global-tier — go into consolidated global-scope cleo.db
|
|
32575
32771
|
{
|
|
32576
32772
|
name: "nexus",
|
|
32577
|
-
path:
|
|
32773
|
+
path: join10(cleoHome, "nexus.db"),
|
|
32578
32774
|
targetScope: "global"
|
|
32579
32775
|
},
|
|
32580
32776
|
{
|
|
32581
32777
|
name: "signaldock",
|
|
32582
|
-
path:
|
|
32778
|
+
path: join10(cleoHome, "signaldock.db"),
|
|
32583
32779
|
targetScope: "global"
|
|
32584
32780
|
},
|
|
32585
32781
|
{
|
|
32586
32782
|
name: "skills",
|
|
32587
|
-
path:
|
|
32783
|
+
path: join10(cleoHome, "skills.db"),
|
|
32588
32784
|
targetScope: "global"
|
|
32589
32785
|
}
|
|
32590
32786
|
];
|
|
@@ -32613,7 +32809,7 @@ function findExistingStaging(cleoDir) {
|
|
|
32613
32809
|
const entries = readdirSync2(cleoDir, { withFileTypes: true });
|
|
32614
32810
|
const stagingDirs = entries.filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => e.name).sort().reverse();
|
|
32615
32811
|
if (stagingDirs.length > 0) {
|
|
32616
|
-
return
|
|
32812
|
+
return join10(cleoDir, stagingDirs[0]);
|
|
32617
32813
|
}
|
|
32618
32814
|
} catch {
|
|
32619
32815
|
}
|
|
@@ -32626,7 +32822,7 @@ function buildExodusPlan(cwd) {
|
|
|
32626
32822
|
const availableBytes = getAvailableBytes(cleoDir);
|
|
32627
32823
|
const diskPreflight = totalSourceBytes === 0 || availableBytes >= 3 * totalSourceBytes;
|
|
32628
32824
|
const existingStaging = findExistingStaging(cleoDir);
|
|
32629
|
-
const stagingDir = existingStaging ??
|
|
32825
|
+
const stagingDir = existingStaging ?? join10(cleoDir, deriveStagingDirName());
|
|
32630
32826
|
const resumeFromStaging = existingStaging !== null;
|
|
32631
32827
|
const projectDbPath = resolveDualScopeDbPath("project", cwd);
|
|
32632
32828
|
const globalDbPath = resolveDualScopeDbPath("global");
|
|
@@ -32642,7 +32838,7 @@ function buildExodusPlan(cwd) {
|
|
|
32642
32838
|
};
|
|
32643
32839
|
}
|
|
32644
32840
|
function sourcesPresent(sources) {
|
|
32645
|
-
return sources.some((s) =>
|
|
32841
|
+
return sources.some((s) => existsSync8(s.path));
|
|
32646
32842
|
}
|
|
32647
32843
|
var init_plan2 = __esm({
|
|
32648
32844
|
"packages/core/src/store/exodus/plan.ts"() {
|
|
@@ -32653,11 +32849,11 @@ var init_plan2 = __esm({
|
|
|
32653
32849
|
});
|
|
32654
32850
|
|
|
32655
32851
|
// packages/core/src/store/exodus/status.ts
|
|
32656
|
-
import { existsSync as
|
|
32657
|
-
import { join as
|
|
32852
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
|
|
32853
|
+
import { join as join11 } from "node:path";
|
|
32658
32854
|
function readJournal2(stagingDir) {
|
|
32659
|
-
const p =
|
|
32660
|
-
if (!
|
|
32855
|
+
const p = join11(stagingDir, JOURNAL_FILENAME2);
|
|
32856
|
+
if (!existsSync9(p)) return null;
|
|
32661
32857
|
try {
|
|
32662
32858
|
return JSON.parse(readFileSync4(p, "utf8"));
|
|
32663
32859
|
} catch {
|
|
@@ -32666,7 +32862,7 @@ function readJournal2(stagingDir) {
|
|
|
32666
32862
|
}
|
|
32667
32863
|
function findStagingDirs(cleoDir) {
|
|
32668
32864
|
try {
|
|
32669
|
-
return readdirSync3(cleoDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) =>
|
|
32865
|
+
return readdirSync3(cleoDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => join11(cleoDir, e.name)).sort().reverse();
|
|
32670
32866
|
} catch {
|
|
32671
32867
|
return [];
|
|
32672
32868
|
}
|
|
@@ -32689,15 +32885,15 @@ function runExodusStatus(cwd) {
|
|
|
32689
32885
|
const sourcesInfo = plan.sources.map((s) => ({
|
|
32690
32886
|
name: s.name,
|
|
32691
32887
|
path: s.path,
|
|
32692
|
-
exists:
|
|
32888
|
+
exists: existsSync9(s.path),
|
|
32693
32889
|
bytes: safeBytes(s.path)
|
|
32694
32890
|
}));
|
|
32695
32891
|
return {
|
|
32696
32892
|
hasStaging: latestStaging !== null,
|
|
32697
32893
|
stagingDir: latestStaging,
|
|
32698
32894
|
journal,
|
|
32699
|
-
projectDbExists:
|
|
32700
|
-
globalDbExists:
|
|
32895
|
+
projectDbExists: existsSync9(projectDbPath),
|
|
32896
|
+
globalDbExists: existsSync9(globalDbPath),
|
|
32701
32897
|
sourcesPresent: sourcesInfo.some((s) => s.exists),
|
|
32702
32898
|
sources: sourcesInfo
|
|
32703
32899
|
};
|
|
@@ -32714,7 +32910,7 @@ var init_status = __esm({
|
|
|
32714
32910
|
});
|
|
32715
32911
|
|
|
32716
32912
|
// packages/core/src/store/exodus/verify-migration.ts
|
|
32717
|
-
import { existsSync as
|
|
32913
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
32718
32914
|
import { createRequire as createRequire3 } from "node:module";
|
|
32719
32915
|
function orderByClause(db, tableName) {
|
|
32720
32916
|
try {
|
|
@@ -32737,14 +32933,15 @@ function computeTableDigest(db, tableName, columns) {
|
|
|
32737
32933
|
rows = db.prepare(`SELECT ${selectClause} FROM "${tableName}" ORDER BY ${orderBy}`).all();
|
|
32738
32934
|
} catch (err) {
|
|
32739
32935
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32740
|
-
|
|
32936
|
+
log3.warn(
|
|
32741
32937
|
{ tableName, err: msg },
|
|
32742
32938
|
"computeTableDigest: SELECT failed (possibly a virtual/FTS table) \u2014 treating as 0 rows"
|
|
32743
32939
|
);
|
|
32744
32940
|
return { count: 0, hash: "" };
|
|
32745
32941
|
}
|
|
32746
32942
|
for (const row of rows) {
|
|
32747
|
-
|
|
32943
|
+
const rowObj = row;
|
|
32944
|
+
hasher.update(JSON.stringify(rowObj, Object.keys(rowObj).sort()));
|
|
32748
32945
|
}
|
|
32749
32946
|
return {
|
|
32750
32947
|
count: rows.length,
|
|
@@ -32849,7 +33046,7 @@ function foreignKeyCheck(db, scope) {
|
|
|
32849
33046
|
try {
|
|
32850
33047
|
const rows = db.prepare("PRAGMA foreign_key_check").all();
|
|
32851
33048
|
if (rows.length > 0) {
|
|
32852
|
-
|
|
33049
|
+
log3.warn(
|
|
32853
33050
|
{ scope, count: rows.length, sample: rows.slice(0, 5) },
|
|
32854
33051
|
`verifyMigration: PRAGMA foreign_key_check found ${rows.length} orphan row(s)`
|
|
32855
33052
|
);
|
|
@@ -32861,7 +33058,7 @@ function foreignKeyCheck(db, scope) {
|
|
|
32861
33058
|
fkid: r.fkid
|
|
32862
33059
|
}));
|
|
32863
33060
|
} catch (err) {
|
|
32864
|
-
|
|
33061
|
+
log3.warn({ scope, err }, "verifyMigration: PRAGMA foreign_key_check failed (non-fatal)");
|
|
32865
33062
|
return [];
|
|
32866
33063
|
}
|
|
32867
33064
|
}
|
|
@@ -32898,13 +33095,13 @@ function sourceOrphanSignatures(db, sourceName, scope) {
|
|
|
32898
33095
|
const rows = db.prepare("PRAGMA foreign_key_check").all();
|
|
32899
33096
|
for (const r of rows) sigs.add(orphanSignature(db, r, sourceName));
|
|
32900
33097
|
if (rows.length > 0) {
|
|
32901
|
-
|
|
33098
|
+
log3.warn(
|
|
32902
33099
|
{ scope, count: rows.length, sample: rows.slice(0, 5) },
|
|
32903
33100
|
`verifyMigration: source already has ${rows.length} pre-existing FK orphan(s) \u2014 these are tolerated (carried forward losslessly, flagged for data-hygiene)`
|
|
32904
33101
|
);
|
|
32905
33102
|
}
|
|
32906
33103
|
} catch (err) {
|
|
32907
|
-
|
|
33104
|
+
log3.warn({ scope, err }, "verifyMigration: source PRAGMA foreign_key_check failed (non-fatal)");
|
|
32908
33105
|
}
|
|
32909
33106
|
return sigs;
|
|
32910
33107
|
}
|
|
@@ -32916,7 +33113,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
32916
33113
|
const preExistingForeignKeyViolations = [];
|
|
32917
33114
|
const failureLines = [];
|
|
32918
33115
|
const sourceOrphanSigs = /* @__PURE__ */ new Set();
|
|
32919
|
-
if (!
|
|
33116
|
+
if (!existsSync10(projectDbPath)) {
|
|
32920
33117
|
return {
|
|
32921
33118
|
ok: false,
|
|
32922
33119
|
tables: [],
|
|
@@ -32927,7 +33124,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
32927
33124
|
error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
|
|
32928
33125
|
};
|
|
32929
33126
|
}
|
|
32930
|
-
if (!
|
|
33127
|
+
if (!existsSync10(globalDbPath)) {
|
|
32931
33128
|
return {
|
|
32932
33129
|
ok: false,
|
|
32933
33130
|
tables: [],
|
|
@@ -32942,7 +33139,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
32942
33139
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
32943
33140
|
try {
|
|
32944
33141
|
for (const src of sources) {
|
|
32945
|
-
if (!
|
|
33142
|
+
if (!existsSync10(src.path)) {
|
|
32946
33143
|
onProgress?.(`Skipping ${src.name} (not present)`);
|
|
32947
33144
|
continue;
|
|
32948
33145
|
}
|
|
@@ -33021,7 +33218,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
33021
33218
|
`[${scope}] ${src.name}.${legacyTableName} \u2192 ${targetTableName}: DEFICIT \u2014 source=${srcDigest.count} rows, target=${tgtDigest.count} rows (${srcDigest.count - tgtDigest.count} missing), hashMatch=${hashMatch}`
|
|
33022
33219
|
);
|
|
33023
33220
|
} else if (tgtDigest.count > srcDigest.count) {
|
|
33024
|
-
|
|
33221
|
+
log3.warn(
|
|
33025
33222
|
{
|
|
33026
33223
|
scope,
|
|
33027
33224
|
source: src.name,
|
|
@@ -33071,7 +33268,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
33071
33268
|
}
|
|
33072
33269
|
}
|
|
33073
33270
|
if (preExistingForeignKeyViolations.length > 0) {
|
|
33074
|
-
|
|
33271
|
+
log3.warn(
|
|
33075
33272
|
{
|
|
33076
33273
|
count: preExistingForeignKeyViolations.length,
|
|
33077
33274
|
sample: preExistingForeignKeyViolations.slice(0, 5)
|
|
@@ -33081,7 +33278,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
33081
33278
|
}
|
|
33082
33279
|
} catch (err) {
|
|
33083
33280
|
const error = err instanceof Error ? err.message : String(err);
|
|
33084
|
-
|
|
33281
|
+
log3.error({ err }, "verifyMigration failed");
|
|
33085
33282
|
return {
|
|
33086
33283
|
ok: false,
|
|
33087
33284
|
tables,
|
|
@@ -33098,7 +33295,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
33098
33295
|
if (failureLines.length > 0) {
|
|
33099
33296
|
const error = `verifyMigration FAILED: ${failureLines.length} issue(s):
|
|
33100
33297
|
${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
|
|
33101
|
-
|
|
33298
|
+
log3.error({ failureCount: failureLines.length }, error);
|
|
33102
33299
|
return {
|
|
33103
33300
|
ok: false,
|
|
33104
33301
|
tables,
|
|
@@ -33118,7 +33315,7 @@ ${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
|
|
|
33118
33315
|
enumDrift
|
|
33119
33316
|
};
|
|
33120
33317
|
}
|
|
33121
|
-
var
|
|
33318
|
+
var log3, _require, CHECK_ENUM_REGEX;
|
|
33122
33319
|
var init_verify_migration = __esm({
|
|
33123
33320
|
"packages/core/src/store/exodus/verify-migration.ts"() {
|
|
33124
33321
|
"use strict";
|
|
@@ -33126,7 +33323,7 @@ var init_verify_migration = __esm({
|
|
|
33126
33323
|
init_logger2();
|
|
33127
33324
|
init_open_cleo_db();
|
|
33128
33325
|
init_table_name_map();
|
|
33129
|
-
|
|
33326
|
+
log3 = getLogger("verify-migration");
|
|
33130
33327
|
_require = createRequire3(import.meta.url);
|
|
33131
33328
|
CHECK_ENUM_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+(?:IS\s+NULL\s+OR\s+"[^"]+"\s+)?IN\s*\(([^)]*)\)\s*\)/gi;
|
|
33132
33329
|
}
|
|
@@ -33166,9 +33363,16 @@ var init_verify = __esm({
|
|
|
33166
33363
|
var exodus_exports = {};
|
|
33167
33364
|
__export(exodus_exports, {
|
|
33168
33365
|
EXODUS_TARGET_SCHEMA_VERSION: () => EXODUS_TARGET_SCHEMA_VERSION,
|
|
33366
|
+
archiveMigratedSources: () => archiveMigratedSources,
|
|
33367
|
+
archiveSourceDb: () => archiveSourceDb,
|
|
33368
|
+
archiveStrandedResidue: () => archiveStrandedResidue,
|
|
33169
33369
|
buildExodusPlan: () => buildExodusPlan,
|
|
33170
33370
|
clearExodusJournal: () => clearExodusJournal,
|
|
33171
33371
|
deriveStagingDirName: () => deriveStagingDirName,
|
|
33372
|
+
detectStrandedResidue: () => detectStrandedResidue,
|
|
33373
|
+
exodusArchiveDir: () => exodusArchiveDir,
|
|
33374
|
+
exodusMarkerPath: () => exodusMarkerPath,
|
|
33375
|
+
hasExodusCompleteMarker: () => hasExodusCompleteMarker,
|
|
33172
33376
|
isDerivedOrInternalTable: () => isDerivedOrInternalTable,
|
|
33173
33377
|
resolveConsolidatedTableName: () => resolveConsolidatedTableName,
|
|
33174
33378
|
reverseLookup: () => reverseLookup,
|
|
@@ -33176,11 +33380,13 @@ __export(exodus_exports, {
|
|
|
33176
33380
|
runExodusStatus: () => runExodusStatus,
|
|
33177
33381
|
runExodusVerify: () => runExodusVerify,
|
|
33178
33382
|
sourcesPresent: () => sourcesPresent,
|
|
33179
|
-
verifyMigration: () => verifyMigration
|
|
33383
|
+
verifyMigration: () => verifyMigration,
|
|
33384
|
+
writeExodusCompleteMarker: () => writeExodusCompleteMarker
|
|
33180
33385
|
});
|
|
33181
33386
|
var init_exodus = __esm({
|
|
33182
33387
|
"packages/core/src/store/exodus/index.ts"() {
|
|
33183
33388
|
"use strict";
|
|
33389
|
+
init_archive2();
|
|
33184
33390
|
init_migrate();
|
|
33185
33391
|
init_plan2();
|
|
33186
33392
|
init_status();
|
|
@@ -33198,7 +33404,7 @@ __export(on_open_exports, {
|
|
|
33198
33404
|
isDataContinuityOk: () => isDataContinuityOk,
|
|
33199
33405
|
maybeRunExodusOnOpen: () => maybeRunExodusOnOpen
|
|
33200
33406
|
});
|
|
33201
|
-
import { existsSync as
|
|
33407
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
33202
33408
|
function isDisabledByEnv() {
|
|
33203
33409
|
const v = process.env.CLEO_DISABLE_EXODUS_ON_OPEN;
|
|
33204
33410
|
return v === "1" || v === "true";
|
|
@@ -33224,7 +33430,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
33224
33430
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%'"
|
|
33225
33431
|
).all().map((r) => r.name);
|
|
33226
33432
|
} catch (err) {
|
|
33227
|
-
|
|
33433
|
+
log4.error({ err, scope }, "exodus-on-open: failed to enumerate tables for rollback");
|
|
33228
33434
|
return;
|
|
33229
33435
|
}
|
|
33230
33436
|
try {
|
|
@@ -33234,7 +33440,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
33234
33440
|
try {
|
|
33235
33441
|
nativeDb.exec(`DELETE FROM "${table}"`);
|
|
33236
33442
|
} catch (err) {
|
|
33237
|
-
|
|
33443
|
+
log4.warn({ err, table, scope }, "exodus-on-open: failed to clear table during rollback");
|
|
33238
33444
|
}
|
|
33239
33445
|
}
|
|
33240
33446
|
nativeDb.exec("COMMIT");
|
|
@@ -33243,7 +33449,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
33243
33449
|
nativeDb.exec("ROLLBACK");
|
|
33244
33450
|
} catch {
|
|
33245
33451
|
}
|
|
33246
|
-
|
|
33452
|
+
log4.error({ err, scope }, "exodus-on-open: rollback transaction failed");
|
|
33247
33453
|
} finally {
|
|
33248
33454
|
try {
|
|
33249
33455
|
nativeDb.exec("PRAGMA foreign_keys = ON");
|
|
@@ -33251,20 +33457,27 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
33251
33457
|
}
|
|
33252
33458
|
}
|
|
33253
33459
|
}
|
|
33254
|
-
async function rollbackBothScopes(scope) {
|
|
33255
|
-
const {
|
|
33460
|
+
async function rollbackBothScopes(scope, projectDbPath, globalDbPath) {
|
|
33461
|
+
const { openDualScopeDbAtPath: openDualScopeDbAtPath2 } = await Promise.resolve().then(() => (init_dual_scope_db(), dual_scope_db_exports));
|
|
33256
33462
|
for (const s of ["project", "global"]) {
|
|
33463
|
+
const path2 = s === "project" ? projectDbPath : globalDbPath;
|
|
33464
|
+
let handle = null;
|
|
33257
33465
|
try {
|
|
33258
|
-
|
|
33466
|
+
handle = s === "project" ? await openDualScopeDbAtPath2("project", path2, void 0, { dedicated: true }) : await openDualScopeDbAtPath2("global", path2, void 0, { dedicated: true });
|
|
33259
33467
|
const native = handle.db.$client;
|
|
33260
33468
|
if (native) {
|
|
33261
33469
|
rollbackConsolidatedToEmpty(native, s);
|
|
33262
33470
|
}
|
|
33263
33471
|
} catch (err) {
|
|
33264
|
-
|
|
33472
|
+
log4.warn(
|
|
33265
33473
|
{ err, scope: s, openingScope: scope },
|
|
33266
33474
|
"exodus-on-open: could not roll back scope (best-effort)"
|
|
33267
33475
|
);
|
|
33476
|
+
} finally {
|
|
33477
|
+
try {
|
|
33478
|
+
handle?.close();
|
|
33479
|
+
} catch {
|
|
33480
|
+
}
|
|
33268
33481
|
}
|
|
33269
33482
|
}
|
|
33270
33483
|
}
|
|
@@ -33272,7 +33485,7 @@ function isDataContinuityOk(result) {
|
|
|
33272
33485
|
const deficits = result.tables.filter((t) => t.targetCount < t.sourceCount);
|
|
33273
33486
|
const surpluses = result.tables.filter((t) => t.targetCount > t.sourceCount);
|
|
33274
33487
|
if (surpluses.length > 0) {
|
|
33275
|
-
|
|
33488
|
+
log4.warn(
|
|
33276
33489
|
{
|
|
33277
33490
|
surpluses: surpluses.map((t) => ({
|
|
33278
33491
|
table: t.targetTable,
|
|
@@ -33294,13 +33507,19 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
33294
33507
|
if (isDisabledByEnv()) {
|
|
33295
33508
|
return { outcome: "skipped", reason: "CLEO_DISABLE_EXODUS_ON_OPEN set" };
|
|
33296
33509
|
}
|
|
33510
|
+
if (hasExodusCompleteMarker(scope, cwd)) {
|
|
33511
|
+
return {
|
|
33512
|
+
outcome: "skipped",
|
|
33513
|
+
reason: "exodus completion marker present \u2014 scope already migrated (cutover sealed)"
|
|
33514
|
+
};
|
|
33515
|
+
}
|
|
33297
33516
|
if (!consolidatedIsEmpty(nativeDb, scope)) {
|
|
33298
33517
|
return { outcome: "skipped", reason: "consolidated cleo.db already populated" };
|
|
33299
33518
|
}
|
|
33300
33519
|
const { buildExodusPlan: buildExodusPlan2, runExodusMigrate: runExodusMigrate2, verifyMigration: verifyMigration2, clearExodusJournal: clearExodusJournal2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
|
|
33301
33520
|
const plan = buildExodusPlan2(cwd);
|
|
33302
33521
|
const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
|
|
33303
|
-
if (!scopeSources.some((s) =>
|
|
33522
|
+
if (!scopeSources.some((s) => existsSync11(s.path))) {
|
|
33304
33523
|
return {
|
|
33305
33524
|
outcome: "skipped",
|
|
33306
33525
|
reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
|
|
@@ -33313,11 +33532,11 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
33313
33532
|
if (!consolidatedIsEmpty(nativeDb, scope)) {
|
|
33314
33533
|
return { outcome: "skipped", reason: "migrated by a concurrent process (lock winner)" };
|
|
33315
33534
|
}
|
|
33316
|
-
|
|
33535
|
+
log4.info(
|
|
33317
33536
|
{
|
|
33318
33537
|
scope,
|
|
33319
33538
|
dbPath,
|
|
33320
|
-
sources: plan.sources.filter((s) =>
|
|
33539
|
+
sources: plan.sources.filter((s) => existsSync11(s.path)).map((s) => s.name)
|
|
33321
33540
|
},
|
|
33322
33541
|
"exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
|
|
33323
33542
|
);
|
|
@@ -33326,23 +33545,23 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
33326
33545
|
const migrateResult = await runExodusMigrate2(
|
|
33327
33546
|
plan,
|
|
33328
33547
|
false,
|
|
33329
|
-
(msg) =>
|
|
33548
|
+
(msg) => log4.debug({ scope }, `exodus-on-open: ${msg}`)
|
|
33330
33549
|
);
|
|
33331
33550
|
if (!migrateResult.ok) {
|
|
33332
|
-
await rollbackBothScopes(scope);
|
|
33551
|
+
await rollbackBothScopes(scope, plan.projectDbPath, plan.globalDbPath);
|
|
33333
33552
|
clearExodusJournal2(migrateResult.stagingDir);
|
|
33334
33553
|
const reason = `migration failed: ${migrateResult.error ?? "unknown error"} \u2014 legacy DBs kept as source`;
|
|
33335
|
-
|
|
33554
|
+
log4.error({ scope, error: migrateResult.error }, `exodus-on-open: ${reason}`);
|
|
33336
33555
|
return { outcome: "aborted", reason };
|
|
33337
33556
|
}
|
|
33338
33557
|
const verifyResult = verifyMigration2(
|
|
33339
33558
|
plan.sources,
|
|
33340
33559
|
plan.projectDbPath,
|
|
33341
33560
|
plan.globalDbPath,
|
|
33342
|
-
(msg) =>
|
|
33561
|
+
(msg) => log4.debug({ scope }, `exodus-on-open verify: ${msg}`)
|
|
33343
33562
|
);
|
|
33344
33563
|
if (!verifyResult.ok) {
|
|
33345
|
-
|
|
33564
|
+
log4.warn(
|
|
33346
33565
|
{
|
|
33347
33566
|
scope,
|
|
33348
33567
|
enumDrift: verifyResult.enumDrift.length,
|
|
@@ -33352,11 +33571,11 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
33352
33571
|
);
|
|
33353
33572
|
}
|
|
33354
33573
|
if (!isDataContinuityOk(verifyResult)) {
|
|
33355
|
-
await rollbackBothScopes(scope);
|
|
33574
|
+
await rollbackBothScopes(scope, plan.projectDbPath, plan.globalDbPath);
|
|
33356
33575
|
clearExodusJournal2(plan.stagingDir);
|
|
33357
33576
|
const deficits = verifyResult.tables.filter((t) => t.targetCount < t.sourceCount).map((t) => `${t.targetTable}(${t.sourceCount}\u2192${t.targetCount})`);
|
|
33358
33577
|
const reason = `parity verification failed \u2014 cutover aborted, legacy DBs kept as source. count deficits: [${deficits.join(", ")}]; INTRODUCED fk orphans: ${verifyResult.introducedForeignKeyViolations.length} (pre-existing source orphans tolerated: ${verifyResult.preExistingForeignKeyViolations.length}). ` + `${verifyResult.error ?? ""}`.trim();
|
|
33359
|
-
|
|
33578
|
+
log4.error(
|
|
33360
33579
|
{
|
|
33361
33580
|
scope,
|
|
33362
33581
|
countDeficits: deficits,
|
|
@@ -33368,10 +33587,27 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
33368
33587
|
return { outcome: "aborted", reason };
|
|
33369
33588
|
}
|
|
33370
33589
|
const rowsCopied = migrateResult.tables.filter((t) => !t.skipped).reduce((n, t) => n + t.rowsCopied, 0);
|
|
33371
|
-
|
|
33590
|
+
log4.info(
|
|
33372
33591
|
{ scope, rowsCopied, tables: migrateResult.tables.length },
|
|
33373
33592
|
"exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
|
|
33374
33593
|
);
|
|
33594
|
+
try {
|
|
33595
|
+
const consumed = plan.sources.filter((s) => existsSync11(s.path));
|
|
33596
|
+
const archiveResult = archiveMigratedSources(consumed, cwd);
|
|
33597
|
+
log4.info(
|
|
33598
|
+
{
|
|
33599
|
+
scope,
|
|
33600
|
+
archived: archiveResult.sources.filter((s) => s.action === "archived").length,
|
|
33601
|
+
markersWritten: archiveResult.markersWritten
|
|
33602
|
+
},
|
|
33603
|
+
"exodus-on-open: archived legacy sources + sealed completion marker(s)"
|
|
33604
|
+
);
|
|
33605
|
+
} catch (err) {
|
|
33606
|
+
log4.error(
|
|
33607
|
+
{ err, scope },
|
|
33608
|
+
"exodus-on-open: post-migration archive/marker step failed (migration itself succeeded \u2014 legacy DBs left in place, will be re-checked by `cleo doctor exodus-residue`)"
|
|
33609
|
+
);
|
|
33610
|
+
}
|
|
33375
33611
|
return {
|
|
33376
33612
|
outcome: "migrated",
|
|
33377
33613
|
reason: `migrated ${rowsCopied} rows across ${migrateResult.tables.length} tables; parity verified`,
|
|
@@ -33389,13 +33625,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
33389
33625
|
function _isExodusInProgress() {
|
|
33390
33626
|
return _exodusInProgress;
|
|
33391
33627
|
}
|
|
33392
|
-
var
|
|
33628
|
+
var log4, _exodusInProgress;
|
|
33393
33629
|
var init_on_open = __esm({
|
|
33394
33630
|
"packages/core/src/store/exodus/on-open.ts"() {
|
|
33395
33631
|
"use strict";
|
|
33396
33632
|
init_logger2();
|
|
33397
33633
|
init_lock();
|
|
33398
|
-
|
|
33634
|
+
init_archive2();
|
|
33635
|
+
log4 = getLogger("exodus-on-open");
|
|
33399
33636
|
_exodusInProgress = false;
|
|
33400
33637
|
}
|
|
33401
33638
|
});
|
|
@@ -33410,17 +33647,17 @@ __export(dual_scope_db_exports, {
|
|
|
33410
33647
|
resolveDualScopeDbPath: () => resolveDualScopeDbPath,
|
|
33411
33648
|
upsertIdempotent: () => upsertIdempotent
|
|
33412
33649
|
});
|
|
33413
|
-
import { existsSync as
|
|
33650
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync3 } from "node:fs";
|
|
33414
33651
|
import { createRequire as createRequire4 } from "node:module";
|
|
33415
|
-
import { dirname as dirname5, join as
|
|
33652
|
+
import { dirname as dirname5, join as join12 } from "node:path";
|
|
33416
33653
|
function cacheKey(scope, dbPath) {
|
|
33417
33654
|
return `${scope}::${dbPath}`;
|
|
33418
33655
|
}
|
|
33419
33656
|
function resolveDualScopeDbPath(scope, cwd) {
|
|
33420
33657
|
if (scope === "project") {
|
|
33421
|
-
return
|
|
33658
|
+
return join12(resolveCleoDir(cwd), "cleo.db");
|
|
33422
33659
|
}
|
|
33423
|
-
return
|
|
33660
|
+
return join12(getCleoHome(), "cleo.db");
|
|
33424
33661
|
}
|
|
33425
33662
|
function migrationsSetName(scope) {
|
|
33426
33663
|
return scope === "project" ? "drizzle-cleo-project" : "drizzle-cleo-global";
|
|
@@ -33458,21 +33695,61 @@ async function openDualScopeDb(scope, cwd) {
|
|
|
33458
33695
|
const dbPath = resolveDualScopeDbPath(scope, cwd);
|
|
33459
33696
|
return scope === "project" ? openDualScopeDbAtPath("project", dbPath, cwd) : openDualScopeDbAtPath("global", dbPath, cwd);
|
|
33460
33697
|
}
|
|
33461
|
-
async function
|
|
33698
|
+
async function openDedicatedDualScopeDb(scope, dbPath, log8) {
|
|
33699
|
+
log8.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
|
|
33700
|
+
const dir = dirname5(dbPath);
|
|
33701
|
+
if (!existsSync12(dir)) {
|
|
33702
|
+
mkdirSync3(dir, { recursive: true });
|
|
33703
|
+
}
|
|
33704
|
+
const DatabaseSyncCtor = getDatabaseSyncCtor();
|
|
33705
|
+
const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
|
|
33706
|
+
applyPerfPragmas(nativeDb);
|
|
33707
|
+
const schema = scope === "project" ? await loadProjectSchema() : await loadGlobalSchema();
|
|
33708
|
+
const drizzle2 = getDrizzle();
|
|
33709
|
+
const db = drizzle2({ client: nativeDb, schema });
|
|
33710
|
+
const migrationsFolder = resolveCorePackageMigrationsFolder(migrationsSetName(scope));
|
|
33711
|
+
reconcileJournal(nativeDb, migrationsFolder, existenceTable(scope), `dual-scope-db[${scope}]`);
|
|
33712
|
+
migrateWithRetry(
|
|
33713
|
+
db,
|
|
33714
|
+
migrationsFolder,
|
|
33715
|
+
nativeDb,
|
|
33716
|
+
existenceTable(scope),
|
|
33717
|
+
`dual-scope-db[${scope}]`
|
|
33718
|
+
);
|
|
33719
|
+
log8.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
|
|
33720
|
+
return {
|
|
33721
|
+
db,
|
|
33722
|
+
scope,
|
|
33723
|
+
dbPath,
|
|
33724
|
+
close() {
|
|
33725
|
+
try {
|
|
33726
|
+
nativeDb.close();
|
|
33727
|
+
} catch {
|
|
33728
|
+
}
|
|
33729
|
+
}
|
|
33730
|
+
};
|
|
33731
|
+
}
|
|
33732
|
+
async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
33733
|
+
const dedicated = options?.dedicated === true;
|
|
33462
33734
|
const key = cacheKey(scope, dbPath);
|
|
33463
|
-
|
|
33464
|
-
|
|
33465
|
-
if (existing
|
|
33466
|
-
|
|
33735
|
+
if (!dedicated) {
|
|
33736
|
+
const existing = _cache.get(key);
|
|
33737
|
+
if (existing) {
|
|
33738
|
+
if (existing.initPromise) {
|
|
33739
|
+
return existing.initPromise;
|
|
33740
|
+
}
|
|
33741
|
+
return existing.handle;
|
|
33467
33742
|
}
|
|
33468
|
-
return existing.handle;
|
|
33469
33743
|
}
|
|
33470
|
-
const
|
|
33744
|
+
const log8 = getLogger("dual-scope-db");
|
|
33745
|
+
if (dedicated) {
|
|
33746
|
+
return openDedicatedDualScopeDb(scope, dbPath, log8);
|
|
33747
|
+
}
|
|
33471
33748
|
const initPromise = (async () => {
|
|
33472
|
-
|
|
33749
|
+
log8.debug({ scope, dbPath }, "opening dual-scope cleo.db");
|
|
33473
33750
|
const dir = dirname5(dbPath);
|
|
33474
|
-
if (!
|
|
33475
|
-
|
|
33751
|
+
if (!existsSync12(dir)) {
|
|
33752
|
+
mkdirSync3(dir, { recursive: true });
|
|
33476
33753
|
}
|
|
33477
33754
|
const DatabaseSyncCtor = getDatabaseSyncCtor();
|
|
33478
33755
|
const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
|
|
@@ -33489,7 +33766,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd) {
|
|
|
33489
33766
|
existenceTable(scope),
|
|
33490
33767
|
`dual-scope-db[${scope}]`
|
|
33491
33768
|
);
|
|
33492
|
-
|
|
33769
|
+
log8.debug({ scope, dbPath }, "dual-scope cleo.db ready");
|
|
33493
33770
|
const handle = {
|
|
33494
33771
|
db,
|
|
33495
33772
|
scope,
|
|
@@ -33513,7 +33790,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd) {
|
|
|
33513
33790
|
const result = await maybeRunExodusOnOpen2(scope, dbPath, nativeDb, exodusCwd);
|
|
33514
33791
|
if (result.outcome === "migrated" || result.outcome === "aborted") {
|
|
33515
33792
|
if (result.outcome === "aborted") {
|
|
33516
|
-
|
|
33793
|
+
log8.warn(
|
|
33517
33794
|
{ scope, reason: result.reason },
|
|
33518
33795
|
"exodus-on-open aborted; consolidated cleo.db left empty, legacy kept as source"
|
|
33519
33796
|
);
|
|
@@ -33521,7 +33798,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd) {
|
|
|
33521
33798
|
return scope === "project" ? openDualScopeDbAtPath("project", dbPath) : openDualScopeDbAtPath("global", dbPath);
|
|
33522
33799
|
}
|
|
33523
33800
|
} catch (err) {
|
|
33524
|
-
|
|
33801
|
+
log8.warn(
|
|
33525
33802
|
{ err, scope },
|
|
33526
33803
|
"exodus-on-open hook failed (non-fatal); re-opening consolidated handle"
|
|
33527
33804
|
);
|
|
@@ -34105,8 +34382,8 @@ __export(nexus_sqlite_exports, {
|
|
|
34105
34382
|
resetNexusDbState: () => resetNexusDbState,
|
|
34106
34383
|
resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
|
|
34107
34384
|
});
|
|
34108
|
-
import { copyFileSync as
|
|
34109
|
-
import { join as
|
|
34385
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync13 } from "node:fs";
|
|
34386
|
+
import { join as join13 } from "node:path";
|
|
34110
34387
|
function getNexusDbPath(cwd) {
|
|
34111
34388
|
return resolveDualScopeDbPath("project", cwd);
|
|
34112
34389
|
}
|
|
@@ -34138,7 +34415,7 @@ function resolveNexusMigrationsFolder() {
|
|
|
34138
34415
|
return resolveCorePackageMigrationsFolder("drizzle-nexus");
|
|
34139
34416
|
}
|
|
34140
34417
|
function getNestedNexusSentinelPath() {
|
|
34141
|
-
return
|
|
34418
|
+
return join13(getCleoHome(), "nexus", NESTED_NEXUS_SENTINEL);
|
|
34142
34419
|
}
|
|
34143
34420
|
function detectAndWarnOnNestedNexus() {
|
|
34144
34421
|
let nestedPath;
|
|
@@ -34147,12 +34424,12 @@ function detectAndWarnOnNestedNexus() {
|
|
|
34147
34424
|
} catch {
|
|
34148
34425
|
return false;
|
|
34149
34426
|
}
|
|
34150
|
-
if (!
|
|
34427
|
+
if (!existsSync13(nestedPath)) return false;
|
|
34151
34428
|
if (_warnedNestedPaths.has(nestedPath)) return false;
|
|
34152
34429
|
_warnedNestedPaths.add(nestedPath);
|
|
34153
34430
|
const canonicalPath = getNexusDbPath();
|
|
34154
|
-
const
|
|
34155
|
-
|
|
34431
|
+
const log8 = getLogger("nexus-sqlite");
|
|
34432
|
+
log8.warn(
|
|
34156
34433
|
{
|
|
34157
34434
|
nestedPath,
|
|
34158
34435
|
canonicalPath,
|
|
@@ -34306,9 +34583,9 @@ function runNexusMigrations(nativeDb, db) {
|
|
|
34306
34583
|
const migrationsFolder = resolveNexusMigrationsFolder();
|
|
34307
34584
|
if (tableExists3(nativeDb, "nexus_nodes") && _nexusDbPath) {
|
|
34308
34585
|
const backupPath = _nexusDbPath.replace(/\.db$/, "-pre-cleo.db.bak");
|
|
34309
|
-
if (!
|
|
34586
|
+
if (!existsSync13(backupPath)) {
|
|
34310
34587
|
try {
|
|
34311
|
-
|
|
34588
|
+
copyFileSync4(_nexusDbPath, backupPath);
|
|
34312
34589
|
} catch {
|
|
34313
34590
|
}
|
|
34314
34591
|
}
|
|
@@ -34438,10 +34715,10 @@ var init_nexus_sqlite = __esm({
|
|
|
34438
34715
|
|
|
34439
34716
|
// packages/core/src/paths.ts
|
|
34440
34717
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
34441
|
-
import { existsSync as
|
|
34718
|
+
import { existsSync as existsSync14, readFileSync as readFileSync5, statSync as statSync4 } from "node:fs";
|
|
34442
34719
|
import { createRequire as createRequire5 } from "node:module";
|
|
34443
34720
|
import { homedir } from "node:os";
|
|
34444
|
-
import { basename as
|
|
34721
|
+
import { basename as basename4, dirname as dirname6, join as join14, resolve as resolve3 } from "node:path";
|
|
34445
34722
|
import {
|
|
34446
34723
|
computeCanonicalProjectId as _computeCanonicalProjectId,
|
|
34447
34724
|
getCanonicalTemplatesTildePath as _getCanonicalTemplatesTildePath,
|
|
@@ -34531,8 +34808,8 @@ function getCleoDirAbsolute(cwd, opts) {
|
|
|
34531
34808
|
function _resolveProjectByCwdFromNexus(cwd) {
|
|
34532
34809
|
try {
|
|
34533
34810
|
const cleoHome = getCleoHome();
|
|
34534
|
-
const globalDbPath =
|
|
34535
|
-
if (!
|
|
34811
|
+
const globalDbPath = join14(cleoHome, "cleo.db");
|
|
34812
|
+
if (!existsSync14(globalDbPath)) return null;
|
|
34536
34813
|
const start = resolve3(cwd ?? process.cwd());
|
|
34537
34814
|
let current = start;
|
|
34538
34815
|
const DatabaseSync3 = _getDatabaseSyncCtor();
|
|
@@ -34571,7 +34848,7 @@ function _findCleoDirRoot(cwd) {
|
|
|
34571
34848
|
const isDangerousRoot = current === homeRoot || current === "/" || current === "";
|
|
34572
34849
|
if (!isDangerousRoot) {
|
|
34573
34850
|
try {
|
|
34574
|
-
if (statSync4(
|
|
34851
|
+
if (statSync4(join14(current, ".cleo")).isDirectory()) {
|
|
34575
34852
|
return current;
|
|
34576
34853
|
}
|
|
34577
34854
|
} catch {
|
|
@@ -34586,7 +34863,7 @@ function _findCleoDirRoot(cwd) {
|
|
|
34586
34863
|
function resolveCleoDir(cwd) {
|
|
34587
34864
|
const scope = worktreeScope.getStore();
|
|
34588
34865
|
if (scope !== void 0) {
|
|
34589
|
-
return
|
|
34866
|
+
return join14(scope.worktreeRoot, ".cleo");
|
|
34590
34867
|
}
|
|
34591
34868
|
const override = _cleoDirEnvOverride();
|
|
34592
34869
|
if (override !== null) {
|
|
@@ -34594,14 +34871,14 @@ function resolveCleoDir(cwd) {
|
|
|
34594
34871
|
}
|
|
34595
34872
|
const root = _findCleoDirRoot(cwd);
|
|
34596
34873
|
if (root !== null) {
|
|
34597
|
-
return
|
|
34874
|
+
return join14(root, ".cleo");
|
|
34598
34875
|
}
|
|
34599
34876
|
const start = resolve3(cwd ?? process.cwd());
|
|
34600
34877
|
let current = start;
|
|
34601
34878
|
while (true) {
|
|
34602
34879
|
const mainRepo = _resolveMainRepoFromGitlink(current);
|
|
34603
34880
|
if (mainRepo !== null) {
|
|
34604
|
-
return
|
|
34881
|
+
return join14(mainRepo, ".cleo");
|
|
34605
34882
|
}
|
|
34606
34883
|
const parent = dirname6(current);
|
|
34607
34884
|
if (parent === current) {
|
|
@@ -34643,9 +34920,9 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
34643
34920
|
const start = resolve3(cwd ?? process.cwd());
|
|
34644
34921
|
let current = start;
|
|
34645
34922
|
while (true) {
|
|
34646
|
-
const gitMarker =
|
|
34923
|
+
const gitMarker = join14(current, ".git");
|
|
34647
34924
|
try {
|
|
34648
|
-
if (
|
|
34925
|
+
if (existsSync14(gitMarker)) {
|
|
34649
34926
|
return true;
|
|
34650
34927
|
}
|
|
34651
34928
|
} catch {
|
|
@@ -34657,8 +34934,8 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
34657
34934
|
}
|
|
34658
34935
|
function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
34659
34936
|
try {
|
|
34660
|
-
const gitLinkPath =
|
|
34661
|
-
if (!
|
|
34937
|
+
const gitLinkPath = join14(gitlinkDir, ".git");
|
|
34938
|
+
if (!existsSync14(gitLinkPath)) return null;
|
|
34662
34939
|
const stat2 = statSync4(gitLinkPath);
|
|
34663
34940
|
if (!stat2.isFile()) return null;
|
|
34664
34941
|
const gitLinkContent = readFileSync5(gitLinkPath, "utf-8").trim();
|
|
@@ -34666,7 +34943,7 @@ function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
|
34666
34943
|
if (!match) return null;
|
|
34667
34944
|
const gitdir = match[1].trim();
|
|
34668
34945
|
const mainRepo = dirname6(dirname6(dirname6(gitdir)));
|
|
34669
|
-
if (
|
|
34946
|
+
if (existsSync14(join14(mainRepo, ".cleo")) && validateProjectRoot(mainRepo)) {
|
|
34670
34947
|
return mainRepo;
|
|
34671
34948
|
}
|
|
34672
34949
|
} catch {
|
|
@@ -34674,18 +34951,18 @@ function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
|
34674
34951
|
return null;
|
|
34675
34952
|
}
|
|
34676
34953
|
function validateProjectRoot(candidate) {
|
|
34677
|
-
const cleoDir =
|
|
34678
|
-
if (!
|
|
34954
|
+
const cleoDir = join14(candidate, ".cleo");
|
|
34955
|
+
if (!existsSync14(cleoDir)) {
|
|
34679
34956
|
return false;
|
|
34680
34957
|
}
|
|
34681
|
-
const projectInfoPath =
|
|
34682
|
-
if (
|
|
34958
|
+
const projectInfoPath = join14(cleoDir, "project-info.json");
|
|
34959
|
+
if (existsSync14(projectInfoPath)) {
|
|
34683
34960
|
try {
|
|
34684
34961
|
const raw = readFileSync5(projectInfoPath, "utf-8");
|
|
34685
34962
|
const parsed = JSON.parse(raw);
|
|
34686
34963
|
if (typeof parsed === "object" && parsed !== null && "projectId" in parsed && typeof parsed["projectId"] === "string" && parsed["projectId"] !== "") {
|
|
34687
|
-
const gitMarker =
|
|
34688
|
-
if (
|
|
34964
|
+
const gitMarker = join14(candidate, ".git");
|
|
34965
|
+
if (existsSync14(gitMarker)) {
|
|
34689
34966
|
try {
|
|
34690
34967
|
if (!statSync4(gitMarker).isDirectory()) {
|
|
34691
34968
|
return false;
|
|
@@ -34699,8 +34976,8 @@ function validateProjectRoot(candidate) {
|
|
|
34699
34976
|
} catch {
|
|
34700
34977
|
}
|
|
34701
34978
|
}
|
|
34702
|
-
const gitDir =
|
|
34703
|
-
if (
|
|
34979
|
+
const gitDir = join14(candidate, ".git");
|
|
34980
|
+
if (existsSync14(gitDir)) {
|
|
34704
34981
|
let isRealGitDir = false;
|
|
34705
34982
|
try {
|
|
34706
34983
|
const stat2 = statSync4(gitDir);
|
|
@@ -34747,16 +35024,16 @@ function getProjectRoot(cwd) {
|
|
|
34747
35024
|
const homeRoot = homedir();
|
|
34748
35025
|
const skippedCleoDirs = [];
|
|
34749
35026
|
while (true) {
|
|
34750
|
-
const cleoDir =
|
|
34751
|
-
const gitDir =
|
|
35027
|
+
const cleoDir = join14(current, ".cleo");
|
|
35028
|
+
const gitDir = join14(current, ".git");
|
|
34752
35029
|
const isDangerousRoot = current === homeRoot || current === "/" || current === "";
|
|
34753
|
-
if (
|
|
35030
|
+
if (existsSync14(cleoDir) && !isDangerousRoot) {
|
|
34754
35031
|
if (validateProjectRoot(current)) {
|
|
34755
35032
|
return current;
|
|
34756
35033
|
}
|
|
34757
35034
|
skippedCleoDirs.push(current);
|
|
34758
35035
|
}
|
|
34759
|
-
if (
|
|
35036
|
+
if (existsSync14(gitDir) && !isDangerousRoot) {
|
|
34760
35037
|
let isRealGitDir = false;
|
|
34761
35038
|
try {
|
|
34762
35039
|
isRealGitDir = statSync4(gitDir).isDirectory();
|
|
@@ -34801,18 +35078,18 @@ function resolveOrCwd(maybeRoot) {
|
|
|
34801
35078
|
return getProjectRoot();
|
|
34802
35079
|
}
|
|
34803
35080
|
function getConfigPath(cwd) {
|
|
34804
|
-
return
|
|
35081
|
+
return join14(_resolveCleoDir(cwd), "config.json");
|
|
34805
35082
|
}
|
|
34806
35083
|
function getGlobalConfigPath() {
|
|
34807
|
-
return
|
|
35084
|
+
return join14(getCleoHome(), "config.json");
|
|
34808
35085
|
}
|
|
34809
35086
|
function isAbsolutePath(path2) {
|
|
34810
35087
|
return _isAbsolutePath(path2);
|
|
34811
35088
|
}
|
|
34812
35089
|
function _readProjectNameFromInfo(projectRoot) {
|
|
34813
35090
|
try {
|
|
34814
|
-
const infoPath =
|
|
34815
|
-
if (!
|
|
35091
|
+
const infoPath = join14(projectRoot, ".cleo", "project-info.json");
|
|
35092
|
+
if (!existsSync14(infoPath)) return void 0;
|
|
34816
35093
|
const raw = readFileSync5(infoPath, "utf-8");
|
|
34817
35094
|
const data = JSON.parse(raw);
|
|
34818
35095
|
return typeof data.name === "string" && data.name.length > 0 ? data.name : void 0;
|
|
@@ -34834,12 +35111,12 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
|
|
|
34834
35111
|
const existingRows = await db.select().from(projectRegistry2).where(eq10(projectRegistry2.projectId, immutableId)).limit(1);
|
|
34835
35112
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34836
35113
|
const resolvedPath = resolve3(projectRoot);
|
|
34837
|
-
const projectName = _readProjectNameFromInfo(resolvedPath) ||
|
|
35114
|
+
const projectName = _readProjectNameFromInfo(resolvedPath) || basename4(projectRoot) || "unnamed";
|
|
34838
35115
|
if (existingRows.length > 0) {
|
|
34839
35116
|
const existingPath = existingRows[0].projectPath;
|
|
34840
35117
|
if (existingPath !== resolvedPath) {
|
|
34841
|
-
const newBrainDbPath =
|
|
34842
|
-
const newTasksDbPath =
|
|
35118
|
+
const newBrainDbPath = join14(resolvedPath, ".cleo", "brain.db");
|
|
35119
|
+
const newTasksDbPath = join14(resolvedPath, ".cleo", "tasks.db");
|
|
34843
35120
|
await db.update(projectRegistry2).set({
|
|
34844
35121
|
projectPath: resolvedPath,
|
|
34845
35122
|
projectHash: generateProjectHash2(resolvedPath),
|
|
@@ -34870,8 +35147,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
|
|
|
34870
35147
|
lastSync: now,
|
|
34871
35148
|
taskCount: 0,
|
|
34872
35149
|
labelsJson: "[]",
|
|
34873
|
-
brainDbPath:
|
|
34874
|
-
tasksDbPath:
|
|
35150
|
+
brainDbPath: join14(resolvedPath, ".cleo", "brain.db"),
|
|
35151
|
+
tasksDbPath: join14(resolvedPath, ".cleo", "tasks.db"),
|
|
34875
35152
|
statsJson: "{}"
|
|
34876
35153
|
}).onConflictDoNothing();
|
|
34877
35154
|
const aliases = canonicalResult.legacyAliases ?? [];
|
|
@@ -35086,7 +35363,7 @@ __export(config_exports, {
|
|
|
35086
35363
|
parseConfigValue: () => parseConfigValue,
|
|
35087
35364
|
setConfigValue: () => setConfigValue
|
|
35088
35365
|
});
|
|
35089
|
-
import { existsSync as
|
|
35366
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
35090
35367
|
import { mkdir as mkdir3, writeFile } from "node:fs/promises";
|
|
35091
35368
|
import { dirname as dirname7 } from "node:path";
|
|
35092
35369
|
function getNestedValue(obj, path2) {
|
|
@@ -35210,7 +35487,7 @@ function parseConfigValue(value) {
|
|
|
35210
35487
|
}
|
|
35211
35488
|
async function setConfigValue(key, value, cwd, opts) {
|
|
35212
35489
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
35213
|
-
if (!
|
|
35490
|
+
if (!existsSync15(configPath)) {
|
|
35214
35491
|
const dir = dirname7(configPath);
|
|
35215
35492
|
await mkdir3(dir, { recursive: true });
|
|
35216
35493
|
await writeFile(configPath, "{}", "utf-8");
|
|
@@ -35224,7 +35501,7 @@ async function setConfigValue(key, value, cwd, opts) {
|
|
|
35224
35501
|
async function applyStrictnessPreset(preset, cwd, opts) {
|
|
35225
35502
|
const definition = STRICTNESS_PRESETS[preset];
|
|
35226
35503
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
35227
|
-
if (!
|
|
35504
|
+
if (!existsSync15(configPath)) {
|
|
35228
35505
|
const dir = dirname7(configPath);
|
|
35229
35506
|
await mkdir3(dir, { recursive: true });
|
|
35230
35507
|
await writeFile(configPath, "{}", "utf-8");
|
|
@@ -35570,7 +35847,7 @@ function brainTablesAreConsolidatedShape(nativeDb) {
|
|
|
35570
35847
|
return createdAt !== void 0 && createdAt.type.toUpperCase() !== "INTEGER";
|
|
35571
35848
|
}
|
|
35572
35849
|
function establishLegacyBrainSchema(nativeDb, db) {
|
|
35573
|
-
const
|
|
35850
|
+
const log8 = getLogger("brain-schema");
|
|
35574
35851
|
if (brainTablesAreConsolidatedShape(nativeDb)) {
|
|
35575
35852
|
const fkRow = nativeDb.prepare("PRAGMA foreign_keys").get();
|
|
35576
35853
|
const fkWasOn = fkRow?.foreign_keys === 1;
|
|
@@ -35580,7 +35857,7 @@ function establishLegacyBrainSchema(nativeDb, db) {
|
|
|
35580
35857
|
try {
|
|
35581
35858
|
nativeDb.exec(`DROP TABLE IF EXISTS \`${table}\``);
|
|
35582
35859
|
} catch (err) {
|
|
35583
|
-
|
|
35860
|
+
log8.warn(
|
|
35584
35861
|
{ table, err },
|
|
35585
35862
|
"Failed to drop consolidated brain table during legacy rebuild."
|
|
35586
35863
|
);
|
|
@@ -35589,7 +35866,7 @@ function establishLegacyBrainSchema(nativeDb, db) {
|
|
|
35589
35866
|
} finally {
|
|
35590
35867
|
nativeDb.exec(`PRAGMA foreign_keys=${fkWasOn ? "ON" : "OFF"}`);
|
|
35591
35868
|
}
|
|
35592
|
-
|
|
35869
|
+
log8.debug(
|
|
35593
35870
|
{ count: CONSOLIDATED_BRAIN_TABLES.length },
|
|
35594
35871
|
"Dropped consolidated (exodus-target) brain tables \u2014 rebuilding in legacy runtime shape."
|
|
35595
35872
|
);
|
|
@@ -35600,7 +35877,7 @@ function establishLegacyBrainSchema(nativeDb, db) {
|
|
|
35600
35877
|
nativeDb,
|
|
35601
35878
|
migrationsFolder
|
|
35602
35879
|
);
|
|
35603
|
-
|
|
35880
|
+
log8.debug(
|
|
35604
35881
|
{ marked, applied },
|
|
35605
35882
|
"brain consolidated cleo.db reconcile (T11647) \u2014 marked already-present migrations applied + executed the missing unprefixed-table migrations directly."
|
|
35606
35883
|
);
|
|
@@ -36150,7 +36427,7 @@ async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
|
|
|
36150
36427
|
if (allowOrphanParent) {
|
|
36151
36428
|
row = { ...row, parentId: null };
|
|
36152
36429
|
} else {
|
|
36153
|
-
|
|
36430
|
+
log5.warn(
|
|
36154
36431
|
{ taskId: row.id, parentId: row.parentId },
|
|
36155
36432
|
"upsertTask: parentId references a non-existent task \u2014 parent relationship may be lost"
|
|
36156
36433
|
);
|
|
@@ -36333,13 +36610,13 @@ async function loadRelationsForTasks(db, tasks2) {
|
|
|
36333
36610
|
task.relates = relations && relations.length > 0 ? relations : [];
|
|
36334
36611
|
}
|
|
36335
36612
|
}
|
|
36336
|
-
var
|
|
36613
|
+
var log5;
|
|
36337
36614
|
var init_db_helpers = __esm({
|
|
36338
36615
|
"packages/core/src/store/db-helpers.ts"() {
|
|
36339
36616
|
"use strict";
|
|
36340
36617
|
init_logger2();
|
|
36341
36618
|
init_tasks_schema();
|
|
36342
|
-
|
|
36619
|
+
log5 = getLogger("db-helpers");
|
|
36343
36620
|
}
|
|
36344
36621
|
});
|
|
36345
36622
|
|
|
@@ -36397,10 +36674,10 @@ var init_telemetry_schema = __esm({
|
|
|
36397
36674
|
});
|
|
36398
36675
|
|
|
36399
36676
|
// packages/core/src/telemetry/sqlite.ts
|
|
36400
|
-
import { mkdirSync as
|
|
36401
|
-
import { dirname as dirname8, join as
|
|
36677
|
+
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
36678
|
+
import { dirname as dirname8, join as join15 } from "node:path";
|
|
36402
36679
|
function getTelemetryDbPath() {
|
|
36403
|
-
return
|
|
36680
|
+
return join15(getCleoHome(), DB_FILENAME);
|
|
36404
36681
|
}
|
|
36405
36682
|
function resolveTelemetryMigrationsFolder() {
|
|
36406
36683
|
return resolveCorePackageMigrationsFolder("drizzle-telemetry");
|
|
@@ -36448,7 +36725,7 @@ async function getTelemetryDb() {
|
|
|
36448
36725
|
_initPromise2 = (async () => {
|
|
36449
36726
|
const dbPath = requestedPath;
|
|
36450
36727
|
_dbPath2 = dbPath;
|
|
36451
|
-
|
|
36728
|
+
mkdirSync4(dirname8(dbPath), { recursive: true });
|
|
36452
36729
|
const nativeDb = openNativeDatabase(dbPath);
|
|
36453
36730
|
_nativeDb2 = nativeDb;
|
|
36454
36731
|
const db = drizzle({ client: nativeDb, schema: telemetry_schema_exports });
|
|
@@ -36481,11 +36758,11 @@ var init_sqlite2 = __esm({
|
|
|
36481
36758
|
});
|
|
36482
36759
|
|
|
36483
36760
|
// packages/core/src/store/agent-registry-store.ts
|
|
36484
|
-
import { existsSync as
|
|
36485
|
-
import { join as
|
|
36761
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
36762
|
+
import { join as join16 } from "node:path";
|
|
36486
36763
|
function getGlobalAgentRegistryDbPath() {
|
|
36487
36764
|
const cleoHome = getCleoHome();
|
|
36488
|
-
const dbPath =
|
|
36765
|
+
const dbPath = join16(cleoHome, "cleo.db");
|
|
36489
36766
|
if (!dbPath.startsWith(cleoHome)) {
|
|
36490
36767
|
throw new Error(
|
|
36491
36768
|
`BUG: getGlobalAgentRegistryDbPath() resolved to "${dbPath}" which is NOT under getCleoHome() ("${cleoHome}"). The Agent Registry is global-only per ADR-037. This indicates a code path that bypasses path resolution \u2014 fix the caller, do not suppress this error.`
|
|
@@ -36526,7 +36803,7 @@ function writeAgentRegistrySchemaVersionSentinel(db) {
|
|
|
36526
36803
|
}
|
|
36527
36804
|
async function ensureGlobalAgentRegistryDb() {
|
|
36528
36805
|
const dbPath = getGlobalAgentRegistryDbPath();
|
|
36529
|
-
const alreadyExists =
|
|
36806
|
+
const alreadyExists = existsSync16(dbPath);
|
|
36530
36807
|
const dualHandle = await openDualScopeDb("global");
|
|
36531
36808
|
const nativeDb = dualHandle.db.$client ?? null;
|
|
36532
36809
|
if (!nativeDb) {
|
|
@@ -36575,7 +36852,7 @@ var init_agent_registry_store = __esm({
|
|
|
36575
36852
|
});
|
|
36576
36853
|
|
|
36577
36854
|
// packages/core/src/store/conduit-sqlite.ts
|
|
36578
|
-
import { existsSync as
|
|
36855
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
36579
36856
|
import { createRequire as createRequire7 } from "node:module";
|
|
36580
36857
|
function _getDrizzle2() {
|
|
36581
36858
|
if (_drizzle3 === null) {
|
|
@@ -36606,7 +36883,7 @@ async function ensureConduitDb(projectRoot) {
|
|
|
36606
36883
|
}
|
|
36607
36884
|
if (_initPromise3) return _initPromise3;
|
|
36608
36885
|
_initPromise3 = (async () => {
|
|
36609
|
-
const alreadyExists =
|
|
36886
|
+
const alreadyExists = existsSync17(dbPath);
|
|
36610
36887
|
const dualHandle = await openDualScopeDb("project", projectRoot);
|
|
36611
36888
|
const nativeDb = dualHandle.db.$client ?? null;
|
|
36612
36889
|
if (!nativeDb) {
|
|
@@ -36826,11 +37103,11 @@ var init_skills_schema = __esm({
|
|
|
36826
37103
|
});
|
|
36827
37104
|
|
|
36828
37105
|
// packages/core/src/store/skills-db.ts
|
|
36829
|
-
import { join as
|
|
37106
|
+
import { join as join17 } from "node:path";
|
|
36830
37107
|
import { and as and3, eq as eq4 } from "drizzle-orm";
|
|
36831
37108
|
function getDefaultSkillsDbPath() {
|
|
36832
37109
|
const cleoHome = getCleoHome();
|
|
36833
|
-
const dbPath =
|
|
37110
|
+
const dbPath = join17(cleoHome, "cleo.db");
|
|
36834
37111
|
if (!dbPath.startsWith(cleoHome)) {
|
|
36835
37112
|
throw new Error(
|
|
36836
37113
|
`BUG: getDefaultSkillsDbPath() resolved to "${dbPath}" which is NOT under getCleoHome() ("${cleoHome}"). The skills registry is global-only per SG-CLEO-SKILLS-architecture-v3.md \xA74. Fix the caller, do not suppress.`
|
|
@@ -36899,14 +37176,14 @@ var init_skills_db = __esm({
|
|
|
36899
37176
|
// packages/core/src/store/sqlite-backup.ts
|
|
36900
37177
|
import {
|
|
36901
37178
|
chmodSync,
|
|
36902
|
-
copyFileSync as
|
|
36903
|
-
existsSync as
|
|
36904
|
-
mkdirSync as
|
|
37179
|
+
copyFileSync as copyFileSync5,
|
|
37180
|
+
existsSync as existsSync18,
|
|
37181
|
+
mkdirSync as mkdirSync5,
|
|
36905
37182
|
readdirSync as readdirSync4,
|
|
36906
37183
|
statSync as statSync5,
|
|
36907
|
-
unlinkSync as
|
|
37184
|
+
unlinkSync as unlinkSync3
|
|
36908
37185
|
} from "node:fs";
|
|
36909
|
-
import { join as
|
|
37186
|
+
import { join as join18 } from "node:path";
|
|
36910
37187
|
function resolveInventoryPath(entry, cwd) {
|
|
36911
37188
|
try {
|
|
36912
37189
|
if (entry.tier === "global") {
|
|
@@ -36941,8 +37218,8 @@ async function openAgentRegistryDbForSnapshot() {
|
|
|
36941
37218
|
}
|
|
36942
37219
|
async function openTelemetryDbForSnapshot() {
|
|
36943
37220
|
try {
|
|
36944
|
-
const path2 =
|
|
36945
|
-
if (!
|
|
37221
|
+
const path2 = join18(getCleoHome(), "telemetry.db");
|
|
37222
|
+
if (!existsSync18(path2)) return null;
|
|
36946
37223
|
} catch {
|
|
36947
37224
|
return null;
|
|
36948
37225
|
}
|
|
@@ -36957,7 +37234,7 @@ function buildRawFileVacuumOpener(entry) {
|
|
|
36957
37234
|
return async (cwd) => {
|
|
36958
37235
|
const path2 = resolveInventoryPath(entry, cwd);
|
|
36959
37236
|
if (!path2) return null;
|
|
36960
|
-
if (!
|
|
37237
|
+
if (!existsSync18(path2)) return null;
|
|
36961
37238
|
try {
|
|
36962
37239
|
const { DatabaseSync: DatabaseSync3 } = await import("node:sqlite");
|
|
36963
37240
|
return new DatabaseSync3(path2, { readOnly: true });
|
|
@@ -37047,13 +37324,13 @@ function rotateSnapshots(backupDir, prefix) {
|
|
|
37047
37324
|
const pattern = snapshotPattern(prefix);
|
|
37048
37325
|
const files = readdirSync4(backupDir).filter((f) => pattern.test(f)).map((f) => ({
|
|
37049
37326
|
name: f,
|
|
37050
|
-
path:
|
|
37051
|
-
mtimeMs: statSync5(
|
|
37327
|
+
path: join18(backupDir, f),
|
|
37328
|
+
mtimeMs: statSync5(join18(backupDir, f)).mtimeMs
|
|
37052
37329
|
})).sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
37053
37330
|
while (files.length >= MAX_SNAPSHOTS) {
|
|
37054
37331
|
const oldest = files.shift();
|
|
37055
37332
|
if (!oldest) break;
|
|
37056
|
-
|
|
37333
|
+
unlinkSync3(oldest.path);
|
|
37057
37334
|
}
|
|
37058
37335
|
} catch {
|
|
37059
37336
|
}
|
|
@@ -37073,7 +37350,7 @@ async function snapshotOne(target, backupDir, now, cwd) {
|
|
|
37073
37350
|
if (!db) return;
|
|
37074
37351
|
opened = db;
|
|
37075
37352
|
}
|
|
37076
|
-
const dest =
|
|
37353
|
+
const dest = join18(backupDir, `${target.prefix}-${formatTimestamp(now)}.db`);
|
|
37077
37354
|
try {
|
|
37078
37355
|
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
37079
37356
|
rotateSnapshots(backupDir, target.prefix);
|
|
@@ -37094,8 +37371,8 @@ async function vacuumIntoBackup(opts = {}) {
|
|
|
37094
37371
|
}
|
|
37095
37372
|
try {
|
|
37096
37373
|
const cleoDir = getCleoDir(opts.cwd);
|
|
37097
|
-
const backupDir =
|
|
37098
|
-
|
|
37374
|
+
const backupDir = join18(cleoDir, "backups", "sqlite");
|
|
37375
|
+
mkdirSync5(backupDir, { recursive: true });
|
|
37099
37376
|
const target = SNAPSHOT_TARGETS.find((t) => t.prefix === prefix);
|
|
37100
37377
|
if (!target) return;
|
|
37101
37378
|
await snapshotOne(target, backupDir, /* @__PURE__ */ new Date(), opts.cwd);
|
|
@@ -37106,13 +37383,13 @@ async function vacuumIntoBackup(opts = {}) {
|
|
|
37106
37383
|
function listSqliteBackupsForPrefix(prefix, cwd) {
|
|
37107
37384
|
try {
|
|
37108
37385
|
const cleoDir = getCleoDir(cwd);
|
|
37109
|
-
const backupDir =
|
|
37110
|
-
if (!
|
|
37386
|
+
const backupDir = join18(cleoDir, "backups", "sqlite");
|
|
37387
|
+
if (!existsSync18(backupDir)) return [];
|
|
37111
37388
|
const pattern = snapshotPattern(prefix);
|
|
37112
37389
|
return readdirSync4(backupDir).filter((f) => pattern.test(f)).map((f) => ({
|
|
37113
37390
|
name: f,
|
|
37114
|
-
path:
|
|
37115
|
-
mtimeMs: statSync5(
|
|
37391
|
+
path: join18(backupDir, f),
|
|
37392
|
+
mtimeMs: statSync5(join18(backupDir, f)).mtimeMs
|
|
37116
37393
|
})).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
37117
37394
|
} catch {
|
|
37118
37395
|
return [];
|
|
@@ -37168,7 +37445,7 @@ __export(sqlite_native_exports, {
|
|
|
37168
37445
|
import { realpathSync } from "node:fs";
|
|
37169
37446
|
import { createRequire as createRequire8 } from "node:module";
|
|
37170
37447
|
import { tmpdir } from "node:os";
|
|
37171
|
-
import { delimiter, dirname as dirname9, isAbsolute, join as
|
|
37448
|
+
import { delimiter, dirname as dirname9, isAbsolute, join as join19, resolve as resolve4, sep } from "node:path";
|
|
37172
37449
|
function getDbSyncConstructor() {
|
|
37173
37450
|
if (_ctor === null) {
|
|
37174
37451
|
const mod = _require5("node:sqlite");
|
|
@@ -37189,7 +37466,7 @@ function resolveAbsoluteSafe(p) {
|
|
|
37189
37466
|
missingParts.unshift(cursor.slice(parent.length + (parent.endsWith(sep) ? 0 : 1)));
|
|
37190
37467
|
cursor = parent;
|
|
37191
37468
|
try {
|
|
37192
|
-
return
|
|
37469
|
+
return join19(realpathSync(cursor), ...missingParts);
|
|
37193
37470
|
} catch {
|
|
37194
37471
|
}
|
|
37195
37472
|
}
|
|
@@ -37280,6 +37557,7 @@ var init_sqlite_native = __esm({
|
|
|
37280
37557
|
var sqlite_exports = {};
|
|
37281
37558
|
__export(sqlite_exports, {
|
|
37282
37559
|
SQLITE_SCHEMA_VERSION: () => SQLITE_SCHEMA_VERSION,
|
|
37560
|
+
autoRecoverFromBackup: () => autoRecoverFromBackup,
|
|
37283
37561
|
closeAllDatabases: () => closeAllDatabases,
|
|
37284
37562
|
closeDb: () => closeDb,
|
|
37285
37563
|
dbExists: () => dbExists,
|
|
@@ -37294,7 +37572,7 @@ __export(sqlite_exports, {
|
|
|
37294
37572
|
resolveMigrationsFolder: () => resolveMigrationsFolder,
|
|
37295
37573
|
schema: () => tasks_schema_exports
|
|
37296
37574
|
});
|
|
37297
|
-
import { copyFileSync as
|
|
37575
|
+
import { copyFileSync as copyFileSync6, existsSync as existsSync19, renameSync as renameSync3, unlinkSync as unlinkSync4 } from "node:fs";
|
|
37298
37576
|
import { createRequire as createRequire9 } from "node:module";
|
|
37299
37577
|
import { eq as eq5 } from "drizzle-orm";
|
|
37300
37578
|
function _getDrizzle3() {
|
|
@@ -37308,6 +37586,22 @@ function _getDrizzle3() {
|
|
|
37308
37586
|
function getDbPath(cwd) {
|
|
37309
37587
|
return resolveDualScopeDbPath("project", cwd);
|
|
37310
37588
|
}
|
|
37589
|
+
async function recountTasksFromDisk(dbPath) {
|
|
37590
|
+
const { openNativeDatabase: openNativeDatabase2 } = await Promise.resolve().then(() => (init_sqlite_native(), sqlite_native_exports));
|
|
37591
|
+
let probe = null;
|
|
37592
|
+
try {
|
|
37593
|
+
probe = openNativeDatabase2(dbPath, { readonly: true, enableWal: false });
|
|
37594
|
+
const row = probe.prepare("SELECT COUNT(*) as cnt FROM tasks_tasks").get();
|
|
37595
|
+
return row?.cnt ?? 0;
|
|
37596
|
+
} catch {
|
|
37597
|
+
return 0;
|
|
37598
|
+
} finally {
|
|
37599
|
+
try {
|
|
37600
|
+
probe?.close();
|
|
37601
|
+
} catch {
|
|
37602
|
+
}
|
|
37603
|
+
}
|
|
37604
|
+
}
|
|
37311
37605
|
function countBackupTasks(backupDb) {
|
|
37312
37606
|
for (const table of ["tasks_tasks", "tasks"]) {
|
|
37313
37607
|
try {
|
|
@@ -37320,7 +37614,7 @@ function countBackupTasks(backupDb) {
|
|
|
37320
37614
|
}
|
|
37321
37615
|
async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
37322
37616
|
const { openNativeDatabase: openNativeDatabase2 } = await Promise.resolve().then(() => (init_sqlite_native(), sqlite_native_exports));
|
|
37323
|
-
const
|
|
37617
|
+
const log8 = getLogger("sqlite");
|
|
37324
37618
|
try {
|
|
37325
37619
|
const countResult = nativeDb.prepare("SELECT COUNT(*) as cnt FROM tasks_tasks").get();
|
|
37326
37620
|
const taskCount = countResult?.cnt ?? 0;
|
|
@@ -37340,36 +37634,56 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
|
|
|
37340
37634
|
if (backupTaskCount < MIN_BACKUP_TASK_COUNT) {
|
|
37341
37635
|
return;
|
|
37342
37636
|
}
|
|
37343
|
-
|
|
37344
|
-
|
|
37345
|
-
|
|
37346
|
-
|
|
37347
|
-
|
|
37348
|
-
|
|
37349
|
-
|
|
37350
|
-
|
|
37351
|
-
|
|
37352
|
-
|
|
37353
|
-
|
|
37354
|
-
|
|
37355
|
-
|
|
37356
|
-
|
|
37357
|
-
|
|
37358
|
-
|
|
37359
|
-
|
|
37360
|
-
|
|
37361
|
-
|
|
37362
|
-
|
|
37363
|
-
|
|
37637
|
+
const lockPath2 = dbPath + FIRST_OPEN_LOCK_SUFFIX;
|
|
37638
|
+
await withLock(
|
|
37639
|
+
lockPath2,
|
|
37640
|
+
async () => {
|
|
37641
|
+
const currentTaskCount = await recountTasksFromDisk(dbPath);
|
|
37642
|
+
if (currentTaskCount > 0) {
|
|
37643
|
+
log8.info(
|
|
37644
|
+
{ dbPath, currentTaskCount },
|
|
37645
|
+
"Auto-recovery skipped: database was populated by a concurrent process while acquiring the first-open lock (T11662 double-checked re-query)."
|
|
37646
|
+
);
|
|
37647
|
+
return;
|
|
37648
|
+
}
|
|
37649
|
+
log8.warn(
|
|
37650
|
+
{ dbPath, backupPath: newestBackup.path, backupTasks: backupTaskCount },
|
|
37651
|
+
`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).`
|
|
37652
|
+
);
|
|
37653
|
+
if (nativeDb.isOpen) {
|
|
37654
|
+
nativeDb.close();
|
|
37655
|
+
}
|
|
37656
|
+
const walPath = dbPath + "-wal";
|
|
37657
|
+
const shmPath = dbPath + "-shm";
|
|
37658
|
+
try {
|
|
37659
|
+
unlinkSync4(walPath);
|
|
37660
|
+
} catch {
|
|
37661
|
+
}
|
|
37662
|
+
try {
|
|
37663
|
+
unlinkSync4(shmPath);
|
|
37664
|
+
} catch {
|
|
37665
|
+
}
|
|
37666
|
+
const tempPath = dbPath + ".recovery-tmp";
|
|
37667
|
+
copyFileSync6(newestBackup.path, tempPath);
|
|
37668
|
+
renameSync3(tempPath, dbPath);
|
|
37669
|
+
log8.info(
|
|
37670
|
+
{ dbPath, backupPath: newestBackup.path, restoredTasks: backupTaskCount },
|
|
37671
|
+
"Database auto-recovered from backup successfully."
|
|
37672
|
+
);
|
|
37673
|
+
_resetDualScopeDbCache();
|
|
37674
|
+
const restoredNativeDb = openNativeDatabase2(dbPath);
|
|
37675
|
+
_nativeDb3 = restoredNativeDb;
|
|
37676
|
+
const restoredDb = _getDrizzle3()({ client: restoredNativeDb, schema: tasks_schema_exports });
|
|
37677
|
+
runMigrations(restoredNativeDb, restoredDb);
|
|
37678
|
+
_db3 = restoredDb;
|
|
37679
|
+
},
|
|
37680
|
+
// Allow a generous stale window + retries: an exodus migration holding this
|
|
37681
|
+
// lock can take a while on a large fleet (matches on-open.ts), so a blocked
|
|
37682
|
+
// auto-recovery must wait rather than time out and race.
|
|
37683
|
+
{ stale: 6e5, retries: 30 }
|
|
37364
37684
|
);
|
|
37365
|
-
_resetDualScopeDbCache();
|
|
37366
|
-
const restoredNativeDb = openNativeDatabase2(dbPath);
|
|
37367
|
-
_nativeDb3 = restoredNativeDb;
|
|
37368
|
-
const restoredDb = _getDrizzle3()({ client: restoredNativeDb, schema: tasks_schema_exports });
|
|
37369
|
-
runMigrations(restoredNativeDb, restoredDb);
|
|
37370
|
-
_db3 = restoredDb;
|
|
37371
37685
|
} catch (err) {
|
|
37372
|
-
|
|
37686
|
+
log8.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
|
|
37373
37687
|
}
|
|
37374
37688
|
}
|
|
37375
37689
|
async function getDb(cwd) {
|
|
@@ -37469,7 +37783,7 @@ async function getSchemaVersion(cwd) {
|
|
|
37469
37783
|
return result[0]?.value ?? null;
|
|
37470
37784
|
}
|
|
37471
37785
|
function dbExists(cwd) {
|
|
37472
|
-
return
|
|
37786
|
+
return existsSync19(resolveDualScopeDbPath("project", cwd));
|
|
37473
37787
|
}
|
|
37474
37788
|
function getNativeDb() {
|
|
37475
37789
|
return _nativeDb3;
|
|
@@ -37490,12 +37804,13 @@ async function closeAllDatabases() {
|
|
|
37490
37804
|
} catch {
|
|
37491
37805
|
}
|
|
37492
37806
|
}
|
|
37493
|
-
var _drizzle4, SQLITE_SCHEMA_VERSION, SCHEMA_VERSION, _db3, _nativeDb3, _dbPath3, _initPromise4, MIN_BACKUP_TASK_COUNT, REQUIRED_TASK_COLUMNS, REQUIRED_SESSION_COLUMNS;
|
|
37807
|
+
var _drizzle4, SQLITE_SCHEMA_VERSION, SCHEMA_VERSION, _db3, _nativeDb3, _dbPath3, _initPromise4, MIN_BACKUP_TASK_COUNT, FIRST_OPEN_LOCK_SUFFIX, REQUIRED_TASK_COLUMNS, REQUIRED_SESSION_COLUMNS;
|
|
37494
37808
|
var init_sqlite3 = __esm({
|
|
37495
37809
|
"packages/core/src/store/sqlite.ts"() {
|
|
37496
37810
|
"use strict";
|
|
37497
37811
|
init_logger2();
|
|
37498
37812
|
init_dual_scope_db();
|
|
37813
|
+
init_lock();
|
|
37499
37814
|
init_migration_manager();
|
|
37500
37815
|
init_resolve_migrations_folder();
|
|
37501
37816
|
init_sqlite_backup();
|
|
@@ -37511,6 +37826,7 @@ var init_sqlite3 = __esm({
|
|
|
37511
37826
|
_dbPath3 = null;
|
|
37512
37827
|
_initPromise4 = null;
|
|
37513
37828
|
MIN_BACKUP_TASK_COUNT = 10;
|
|
37829
|
+
FIRST_OPEN_LOCK_SUFFIX = ".exodus-on-open.lock";
|
|
37514
37830
|
REQUIRED_TASK_COLUMNS = [
|
|
37515
37831
|
{ name: "pipeline_stage", ddl: "text" },
|
|
37516
37832
|
{ name: "assignee", ddl: "text" }
|
|
@@ -38655,13 +38971,13 @@ var init_sqlite_data_accessor = __esm({
|
|
|
38655
38971
|
});
|
|
38656
38972
|
|
|
38657
38973
|
// packages/core/src/sequence/index.ts
|
|
38658
|
-
import { existsSync as
|
|
38659
|
-
import { join as
|
|
38974
|
+
import { existsSync as existsSync20, readFileSync as readFileSync6, renameSync as renameSync4 } from "node:fs";
|
|
38975
|
+
import { join as join20 } from "node:path";
|
|
38660
38976
|
function getLegacySequenceJsonPath(cwd) {
|
|
38661
|
-
return
|
|
38977
|
+
return join20(resolveOrCwd(cwd), ".cleo", ".sequence.json");
|
|
38662
38978
|
}
|
|
38663
38979
|
function getLegacySequencePath(cwd) {
|
|
38664
|
-
return
|
|
38980
|
+
return join20(resolveOrCwd(cwd), ".cleo", ".sequence");
|
|
38665
38981
|
}
|
|
38666
38982
|
function isValidSequenceState(value) {
|
|
38667
38983
|
if (!value || typeof value !== "object") return false;
|
|
@@ -38672,7 +38988,7 @@ function isSeedSequence(value) {
|
|
|
38672
38988
|
return value.counter === 0 && value.lastId === "T000" && value.checksum === "seed";
|
|
38673
38989
|
}
|
|
38674
38990
|
function readLegacySequenceFile(path2) {
|
|
38675
|
-
if (!
|
|
38991
|
+
if (!existsSync20(path2)) return null;
|
|
38676
38992
|
try {
|
|
38677
38993
|
const parsed = JSON.parse(readFileSync6(path2, "utf-8"));
|
|
38678
38994
|
return isValidSequenceState(parsed) ? parsed : null;
|
|
@@ -38681,14 +38997,14 @@ function readLegacySequenceFile(path2) {
|
|
|
38681
38997
|
}
|
|
38682
38998
|
}
|
|
38683
38999
|
function renameLegacyFile(path2) {
|
|
38684
|
-
if (!
|
|
39000
|
+
if (!existsSync20(path2)) return;
|
|
38685
39001
|
const migratedPath = `${path2}.migrated`;
|
|
38686
39002
|
try {
|
|
38687
|
-
if (!
|
|
38688
|
-
|
|
39003
|
+
if (!existsSync20(migratedPath)) {
|
|
39004
|
+
renameSync4(path2, migratedPath);
|
|
38689
39005
|
return;
|
|
38690
39006
|
}
|
|
38691
|
-
|
|
39007
|
+
renameSync4(path2, `${migratedPath}.${Date.now()}`);
|
|
38692
39008
|
} catch {
|
|
38693
39009
|
}
|
|
38694
39010
|
}
|
|
@@ -38847,15 +39163,15 @@ var init_sequence = __esm({
|
|
|
38847
39163
|
|
|
38848
39164
|
// packages/core/src/store/git-checkpoint.ts
|
|
38849
39165
|
import { execFile as execFile2 } from "node:child_process";
|
|
38850
|
-
import { existsSync as
|
|
39166
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
38851
39167
|
import { readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
38852
|
-
import { join as
|
|
39168
|
+
import { join as join21, resolve as resolve5 } from "node:path";
|
|
38853
39169
|
import { promisify as promisify2 } from "node:util";
|
|
38854
39170
|
function makeCleoGitEnv(cleoDir) {
|
|
38855
39171
|
const abs = resolve5(cleoDir);
|
|
38856
39172
|
return {
|
|
38857
39173
|
...process.env,
|
|
38858
|
-
GIT_DIR:
|
|
39174
|
+
GIT_DIR: join21(abs, ".git"),
|
|
38859
39175
|
GIT_WORK_TREE: abs
|
|
38860
39176
|
};
|
|
38861
39177
|
}
|
|
@@ -38873,7 +39189,7 @@ async function cleoGitCommand(args, cleoDir) {
|
|
|
38873
39189
|
}
|
|
38874
39190
|
}
|
|
38875
39191
|
function isCleoGitInitialized(cleoDir) {
|
|
38876
|
-
return
|
|
39192
|
+
return existsSync21(join21(cleoDir, ".git", "HEAD"));
|
|
38877
39193
|
}
|
|
38878
39194
|
async function loadStateFileAllowlist(cwd) {
|
|
38879
39195
|
try {
|
|
@@ -38917,25 +39233,25 @@ async function isCleoGitRepo(cleoDir) {
|
|
|
38917
39233
|
return result.success && (result.stdout === "true" || isCleoGitInitialized(cleoDir));
|
|
38918
39234
|
}
|
|
38919
39235
|
function isMergeInProgress(cleoDir) {
|
|
38920
|
-
return
|
|
39236
|
+
return existsSync21(join21(cleoDir, ".git", "MERGE_HEAD"));
|
|
38921
39237
|
}
|
|
38922
39238
|
async function isDetachedHead(cleoDir) {
|
|
38923
39239
|
const result = await cleoGitCommand(["symbolic-ref", "HEAD"], cleoDir);
|
|
38924
39240
|
return !result.success;
|
|
38925
39241
|
}
|
|
38926
39242
|
function isRebaseInProgress(cleoDir) {
|
|
38927
|
-
return
|
|
39243
|
+
return existsSync21(join21(cleoDir, ".git", "rebase-merge")) || existsSync21(join21(cleoDir, ".git", "rebase-apply"));
|
|
38928
39244
|
}
|
|
38929
39245
|
async function recordCheckpointTime(cleoDir) {
|
|
38930
39246
|
try {
|
|
38931
|
-
const stateFile =
|
|
39247
|
+
const stateFile = join21(cleoDir, CHECKPOINT_STATE_FILE);
|
|
38932
39248
|
await writeFile2(stateFile, String(Math.floor(Date.now() / 1e3)));
|
|
38933
39249
|
} catch {
|
|
38934
39250
|
}
|
|
38935
39251
|
}
|
|
38936
39252
|
async function getLastCheckpointTime(cleoDir) {
|
|
38937
39253
|
try {
|
|
38938
|
-
const stateFile =
|
|
39254
|
+
const stateFile = join21(cleoDir, CHECKPOINT_STATE_FILE);
|
|
38939
39255
|
const content = await readFile3(stateFile, "utf-8");
|
|
38940
39256
|
const epoch = parseInt(content.trim(), 10);
|
|
38941
39257
|
return Number.isNaN(epoch) ? 0 : epoch;
|
|
@@ -38947,8 +39263,8 @@ async function getChangedStateFiles(cleoDir, cwd) {
|
|
|
38947
39263
|
const changed = [];
|
|
38948
39264
|
const allStateFiles = await getAllStateFiles(cwd);
|
|
38949
39265
|
for (const stateFile of allStateFiles) {
|
|
38950
|
-
const fullPath =
|
|
38951
|
-
if (!
|
|
39266
|
+
const fullPath = join21(cleoDir, stateFile);
|
|
39267
|
+
if (!existsSync21(fullPath)) continue;
|
|
38952
39268
|
const diffResult = await cleoGitCommand(["diff", "--quiet", "--", stateFile], cleoDir);
|
|
38953
39269
|
const cachedResult = await cleoGitCommand(
|
|
38954
39270
|
["diff", "--cached", "--quiet", "--", stateFile],
|
|
@@ -38975,7 +39291,7 @@ async function shouldCheckpoint(options) {
|
|
|
38975
39291
|
const config = await loadCheckpointConfig(cwd);
|
|
38976
39292
|
if (!config.enabled) return false;
|
|
38977
39293
|
const cleoDir = getCleoDir(cwd);
|
|
38978
|
-
if (!
|
|
39294
|
+
if (!existsSync21(cleoDir)) return false;
|
|
38979
39295
|
if (!isCleoGitInitialized(cleoDir)) return false;
|
|
38980
39296
|
if (!await isCleoGitRepo(cleoDir)) return false;
|
|
38981
39297
|
if (isMergeInProgress(cleoDir)) return false;
|
|
@@ -39053,7 +39369,7 @@ async function ensureSequenceValid(cwd, options) {
|
|
|
39053
39369
|
if (!options?.validateSequence) return;
|
|
39054
39370
|
const check = await checkSequence(cwd);
|
|
39055
39371
|
if (!check.valid) {
|
|
39056
|
-
|
|
39372
|
+
log6.warn({ counter: check.counter, maxId: check.maxIdInData }, "Sequence behind, repairing");
|
|
39057
39373
|
const repair = await repairSequence(cwd);
|
|
39058
39374
|
if (!repair.repaired && options.strict) {
|
|
39059
39375
|
throw new DataSafetyError(`Sequence repair failed: ${repair.message}`, "SEQUENCE_INVALID", {
|
|
@@ -39070,7 +39386,7 @@ async function checkpoint(context, cwd, options) {
|
|
|
39070
39386
|
stats.checkpoints++;
|
|
39071
39387
|
stats.lastCheckpoint = /* @__PURE__ */ new Date();
|
|
39072
39388
|
} catch (err) {
|
|
39073
|
-
|
|
39389
|
+
log6.warn({ err }, "Checkpoint failed (non-fatal)");
|
|
39074
39390
|
}
|
|
39075
39391
|
vacuumIntoBackup({ cwd }).catch(() => {
|
|
39076
39392
|
});
|
|
@@ -39132,7 +39448,7 @@ async function safeAppendLog(accessor, entry, cwd, options) {
|
|
|
39132
39448
|
stats.writes++;
|
|
39133
39449
|
await checkpoint("log entry", cwd, opts);
|
|
39134
39450
|
}
|
|
39135
|
-
var
|
|
39451
|
+
var log6, DataSafetyError, DEFAULT_SAFETY, stats;
|
|
39136
39452
|
var init_data_safety_central = __esm({
|
|
39137
39453
|
"packages/core/src/store/data-safety-central.ts"() {
|
|
39138
39454
|
"use strict";
|
|
@@ -39142,7 +39458,7 @@ var init_data_safety_central = __esm({
|
|
|
39142
39458
|
init_sqlite3();
|
|
39143
39459
|
init_sqlite_backup();
|
|
39144
39460
|
init_tasks_schema();
|
|
39145
|
-
|
|
39461
|
+
log6 = getLogger("data-safety");
|
|
39146
39462
|
DataSafetyError = class extends Error {
|
|
39147
39463
|
constructor(message, code, context) {
|
|
39148
39464
|
super(message);
|
|
@@ -39182,7 +39498,7 @@ function isSafetyDisabled() {
|
|
|
39182
39498
|
}
|
|
39183
39499
|
function wrapWithSafety(accessor, cwd) {
|
|
39184
39500
|
if (isSafetyDisabled()) {
|
|
39185
|
-
|
|
39501
|
+
log7.warn(
|
|
39186
39502
|
"Safety disabled - emergency mode (CLEO_DISABLE_SAFETY=true). Data integrity checks bypassed."
|
|
39187
39503
|
);
|
|
39188
39504
|
return accessor;
|
|
@@ -39203,13 +39519,13 @@ function getSafetyStatus() {
|
|
|
39203
39519
|
enabled: true
|
|
39204
39520
|
};
|
|
39205
39521
|
}
|
|
39206
|
-
var
|
|
39522
|
+
var log7, SafetyDataAccessor;
|
|
39207
39523
|
var init_safety_data_accessor = __esm({
|
|
39208
39524
|
"packages/core/src/store/safety-data-accessor.ts"() {
|
|
39209
39525
|
"use strict";
|
|
39210
39526
|
init_logger2();
|
|
39211
39527
|
init_data_safety_central();
|
|
39212
|
-
|
|
39528
|
+
log7 = getLogger("data-safety");
|
|
39213
39529
|
SafetyDataAccessor = class {
|
|
39214
39530
|
/** The underlying accessor being wrapped. */
|
|
39215
39531
|
inner;
|
|
@@ -39233,7 +39549,7 @@ var init_safety_data_accessor = __esm({
|
|
|
39233
39549
|
...config
|
|
39234
39550
|
};
|
|
39235
39551
|
if (this.config.verbose) {
|
|
39236
|
-
|
|
39552
|
+
log7.debug({ engine: inner.engine }, "SafetyDataAccessor initialized");
|
|
39237
39553
|
}
|
|
39238
39554
|
}
|
|
39239
39555
|
/** The storage engine backing this accessor. */
|
|
@@ -39245,7 +39561,7 @@ var init_safety_data_accessor = __esm({
|
|
|
39245
39561
|
*/
|
|
39246
39562
|
logVerbose(message) {
|
|
39247
39563
|
if (this.config.verbose) {
|
|
39248
|
-
|
|
39564
|
+
log7.debug(message);
|
|
39249
39565
|
}
|
|
39250
39566
|
}
|
|
39251
39567
|
/**
|