@cleocode/core 2026.6.18 → 2026.7.1

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.
Files changed (70) hide show
  1. package/dist/docs/export-document.js +1173 -334
  2. package/dist/docs/export-document.js.map +3 -3
  3. package/dist/lifecycle/effective-stage.js +3 -3
  4. package/dist/lifecycle/rollup.js +3 -3
  5. package/dist/llm/plugin-facade.js +1218 -383
  6. package/dist/llm/plugin-facade.js.map +3 -3
  7. package/dist/memory/brain-writer-handlers.d.ts.map +1 -1
  8. package/dist/memory/brain-writer-handlers.js +39 -0
  9. package/dist/memory/brain-writer-handlers.js.map +1 -1
  10. package/dist/orchestrate/admission.d.ts +65 -0
  11. package/dist/orchestrate/admission.d.ts.map +1 -0
  12. package/dist/orchestrate/admission.js +54 -0
  13. package/dist/orchestrate/admission.js.map +1 -0
  14. package/dist/orchestrate/lifecycle-ops.d.ts.map +1 -1
  15. package/dist/orchestrate/lifecycle-ops.js +10 -0
  16. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  17. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  18. package/dist/orchestrate/query-ops.js +37 -8
  19. package/dist/orchestrate/query-ops.js.map +1 -1
  20. package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
  21. package/dist/orchestrate/spawn-ops.js +24 -0
  22. package/dist/orchestrate/spawn-ops.js.map +1 -1
  23. package/dist/release/pr-evidence.d.ts +14 -3
  24. package/dist/release/pr-evidence.d.ts.map +1 -1
  25. package/dist/release/pr-evidence.js +44 -4
  26. package/dist/release/pr-evidence.js.map +1 -1
  27. package/dist/resources/governor.d.ts +133 -0
  28. package/dist/resources/governor.d.ts.map +1 -0
  29. package/dist/resources/governor.js +377 -0
  30. package/dist/resources/governor.js.map +1 -0
  31. package/dist/resources/supervisor-admit.d.ts +42 -0
  32. package/dist/resources/supervisor-admit.d.ts.map +1 -0
  33. package/dist/resources/supervisor-admit.js +136 -0
  34. package/dist/resources/supervisor-admit.js.map +1 -0
  35. package/dist/selfimprove/fix-gen.js +1216 -381
  36. package/dist/selfimprove/fix-gen.js.map +3 -3
  37. package/dist/sentient/tick.d.ts.map +1 -1
  38. package/dist/sentient/tick.js +29 -0
  39. package/dist/sentient/tick.js.map +1 -1
  40. package/dist/store/agent-registry-store.d.ts.map +1 -1
  41. package/dist/store/agent-registry-store.js +17 -2
  42. package/dist/store/agent-registry-store.js.map +1 -1
  43. package/dist/store/dual-scope-db.d.ts.map +1 -1
  44. package/dist/store/dual-scope-db.js +35 -0
  45. package/dist/store/dual-scope-db.js.map +1 -1
  46. package/dist/store/sqlite.d.ts.map +1 -1
  47. package/dist/store/sqlite.js +15 -0
  48. package/dist/store/sqlite.js.map +1 -1
  49. package/dist/store/tasks-schema.d.ts +2 -0
  50. package/dist/store/tasks-schema.d.ts.map +1 -1
  51. package/dist/store/tasks-schema.js +17 -0
  52. package/dist/store/tasks-schema.js.map +1 -1
  53. package/dist/store/validation-schemas.d.ts +98 -98
  54. package/dist/tasks/compute-task-view.js +2 -2
  55. package/dist/tasks/evidence.d.ts +19 -0
  56. package/dist/tasks/evidence.d.ts.map +1 -1
  57. package/dist/tasks/evidence.js +32 -2
  58. package/dist/tasks/evidence.js.map +1 -1
  59. package/dist/tasks/tool-semaphore.d.ts +25 -0
  60. package/dist/tasks/tool-semaphore.d.ts.map +1 -1
  61. package/dist/tasks/tool-semaphore.js +68 -1
  62. package/dist/tasks/tool-semaphore.js.map +1 -1
  63. package/dist/tasks/update.d.ts +2 -0
  64. package/dist/tasks/update.d.ts.map +1 -1
  65. package/dist/tasks/update.js +1 -0
  66. package/dist/tasks/update.js.map +1 -1
  67. package/dist/validation/engine-ops.d.ts.map +1 -1
  68. package/dist/validation/engine-ops.js +33 -7
  69. package/dist/validation/engine-ops.js.map +1 -1
  70. package/package.json +12 -12
@@ -1890,6 +1890,7 @@ var init_tasks = __esm({
1890
1890
  severity: { type: "string", enum: ["P0", "P1", "P2", "P3"] },
1891
1891
  reason: { type: "string" },
1892
1892
  dependsWaiver: { type: "string" },
1893
+ blockedBy: { type: "string" },
1893
1894
  clearBlockedBy: { type: "boolean" },
1894
1895
  relates: {
1895
1896
  type: "array",
@@ -4589,6 +4590,12 @@ var init_operations_registry = __esm({
4589
4590
  required: false,
4590
4591
  description: "Justification to waive the critical-priority --depends requirement"
4591
4592
  },
4593
+ {
4594
+ name: "blockedBy",
4595
+ type: "string",
4596
+ required: false,
4597
+ description: "Set the free-text blockedBy reason (gh#1106)"
4598
+ },
4592
4599
  {
4593
4600
  name: "clearBlockedBy",
4594
4601
  type: "boolean",
@@ -12412,7 +12419,7 @@ var init_lafs = __esm({
12412
12419
 
12413
12420
  // packages/contracts/src/lease-ipc/messages.ts
12414
12421
  import { z as z11 } from "zod";
12415
- var LeaseScopeSchema, LeaseLaneSchema, LeaseAcquireRequestSchema, LeaseReleaseRequestSchema, LeaseRenewRequestSchema, RateCheckRequestSchema, ToolGrantRequestSchema, QueuePriorityClassSchema, QueueAdmitRequestSchema, WorkerHeartbeatRequestSchema, LeaseIpcRequestSchema, LeaseGrantedResponseSchema, LeaseQueuedResponseSchema, LeaseDeniedResponseSchema, RateResultResponseSchema, ToolGrantedResponseSchema, LeaseRevokedResponseSchema, ChildKilledUnresponsiveResponseSchema, QueueAdmitDispositionSchema, QueueAdmitResultResponseSchema, HeartbeatAckResponseSchema, LeaseErrorResponseSchema, LeaseIpcResponseSchema, LeaseIpcRequestEnvelopeSchema, LeaseIpcResponseEnvelopeSchema, LeaseIpcEnvelopeSchema, LEASE_IPC_REQUEST_KINDS, LEASE_IPC_RESPONSE_KINDS, LEASE_IPC_MESSAGE_KINDS;
12422
+ var LeaseScopeSchema, LeaseLaneSchema, LeaseAcquireRequestSchema, LeaseReleaseRequestSchema, LeaseRenewRequestSchema, RateCheckRequestSchema, ToolGrantRequestSchema, QueuePriorityClassSchema, QueueAdmitRequestSchema, WorkerHeartbeatRequestSchema, ResourceAdmitRequestSchema, ResourceReleaseRequestSchema, LeaseIpcRequestSchema, LeaseGrantedResponseSchema, LeaseQueuedResponseSchema, LeaseDeniedResponseSchema, RateResultResponseSchema, ToolGrantedResponseSchema, LeaseRevokedResponseSchema, ChildKilledUnresponsiveResponseSchema, QueueAdmitDispositionSchema, QueueAdmitResultResponseSchema, HeartbeatAckResponseSchema, ResourceAdmitDispositionSchema, ResourceAdmitResultResponseSchema, ResourceReleaseResultResponseSchema, LeaseErrorResponseSchema, LeaseIpcResponseSchema, LeaseIpcRequestEnvelopeSchema, LeaseIpcResponseEnvelopeSchema, LeaseIpcEnvelopeSchema, LEASE_IPC_REQUEST_KINDS, LEASE_IPC_RESPONSE_KINDS, LEASE_IPC_MESSAGE_KINDS;
12416
12423
  var init_messages2 = __esm({
12417
12424
  "packages/contracts/src/lease-ipc/messages.ts"() {
12418
12425
  "use strict";
@@ -12497,6 +12504,24 @@ var init_messages2 = __esm({
12497
12504
  /** The worker's own view of whether it is currently inside an LLM call. */
12498
12505
  in_flight_llm: z11.boolean()
12499
12506
  }).strict();
12507
+ ResourceAdmitRequestSchema = z11.object({
12508
+ /** Tag discriminating this request variant. */
12509
+ kind: z11.literal("resource_admit"),
12510
+ /** The resource class (e.g. `"db-heavy"`, `"full-build"`, `"test-run"`). */
12511
+ class: z11.string().min(1),
12512
+ /** The caller holding the slot — process/worktree-unique; the release key. */
12513
+ holder_id: z11.string().min(1),
12514
+ /** The client-computed budget: the max concurrent holders for this class. */
12515
+ budget: z11.number().int().nonnegative()
12516
+ }).strict();
12517
+ ResourceReleaseRequestSchema = z11.object({
12518
+ /** Tag discriminating this request variant. */
12519
+ kind: z11.literal("resource_release"),
12520
+ /** The resource class the slot belongs to. */
12521
+ class: z11.string().min(1),
12522
+ /** The holder that was admitted (matches the admit `holder_id`). */
12523
+ holder_id: z11.string().min(1)
12524
+ }).strict();
12500
12525
  LeaseIpcRequestSchema = z11.discriminatedUnion("kind", [
12501
12526
  LeaseAcquireRequestSchema,
12502
12527
  LeaseReleaseRequestSchema,
@@ -12504,7 +12529,9 @@ var init_messages2 = __esm({
12504
12529
  RateCheckRequestSchema,
12505
12530
  ToolGrantRequestSchema,
12506
12531
  QueueAdmitRequestSchema,
12507
- WorkerHeartbeatRequestSchema
12532
+ WorkerHeartbeatRequestSchema,
12533
+ ResourceAdmitRequestSchema,
12534
+ ResourceReleaseRequestSchema
12508
12535
  ]);
12509
12536
  LeaseGrantedResponseSchema = z11.object({
12510
12537
  /** Tag discriminating this response variant. */
@@ -12605,6 +12632,25 @@ var init_messages2 = __esm({
12605
12632
  /** Tag discriminating this response variant. */
12606
12633
  kind: z11.literal("heartbeat_ack")
12607
12634
  }).strict();
12635
+ ResourceAdmitDispositionSchema = z11.enum(["admitted", "deferred"]);
12636
+ ResourceAdmitResultResponseSchema = z11.object({
12637
+ /** Tag discriminating this response variant. */
12638
+ kind: z11.literal("resource_admit_result"),
12639
+ /** Whether the heavy op was admitted or deferred. */
12640
+ disposition: ResourceAdmitDispositionSchema,
12641
+ /** Back-off in ms before re-requesting (0 when admitted). */
12642
+ retry_after_ms: z11.number().int().nonnegative(),
12643
+ /** Remaining slots for the class after this decision. */
12644
+ slots_remaining: z11.number().int().nonnegative()
12645
+ }).strict();
12646
+ ResourceReleaseResultResponseSchema = z11.object({
12647
+ /** Tag discriminating this response variant. */
12648
+ kind: z11.literal("resource_release_result"),
12649
+ /** Whether a held slot was actually released (false = no such holder). */
12650
+ released: z11.boolean(),
12651
+ /** Remaining in-flight holders for the class after the release. */
12652
+ slots_remaining: z11.number().int().nonnegative()
12653
+ }).strict();
12608
12654
  LeaseErrorResponseSchema = z11.object({
12609
12655
  /** Tag discriminating this response variant. */
12610
12656
  kind: z11.literal("error"),
@@ -12623,6 +12669,8 @@ var init_messages2 = __esm({
12623
12669
  ChildKilledUnresponsiveResponseSchema,
12624
12670
  QueueAdmitResultResponseSchema,
12625
12671
  HeartbeatAckResponseSchema,
12672
+ ResourceAdmitResultResponseSchema,
12673
+ ResourceReleaseResultResponseSchema,
12626
12674
  LeaseErrorResponseSchema
12627
12675
  ]);
12628
12676
  LeaseIpcRequestEnvelopeSchema = z11.object({
@@ -12656,7 +12704,9 @@ var init_messages2 = __esm({
12656
12704
  "rate_check",
12657
12705
  "tool_grant",
12658
12706
  "queue_admit",
12659
- "worker_heartbeat"
12707
+ "worker_heartbeat",
12708
+ "resource_admit",
12709
+ "resource_release"
12660
12710
  ];
12661
12711
  LEASE_IPC_RESPONSE_KINDS = [
12662
12712
  "lease_granted",
@@ -12668,6 +12718,8 @@ var init_messages2 = __esm({
12668
12718
  "child_killed_unresponsive",
12669
12719
  "queue_admit_result",
12670
12720
  "heartbeat_ack",
12721
+ "resource_admit_result",
12722
+ "resource_release_result",
12671
12723
  "error"
12672
12724
  ];
12673
12725
  LEASE_IPC_MESSAGE_KINDS = [
@@ -12678,9 +12730,11 @@ var init_messages2 = __esm({
12678
12730
  });
12679
12731
 
12680
12732
  // packages/contracts/src/lease-ipc/version.ts
12733
+ var LEASE_IPC_PROTOCOL_VERSION;
12681
12734
  var init_version2 = __esm({
12682
12735
  "packages/contracts/src/lease-ipc/version.ts"() {
12683
12736
  "use strict";
12737
+ LEASE_IPC_PROTOCOL_VERSION = "1.2.0";
12684
12738
  }
12685
12739
  });
12686
12740
 
@@ -13884,6 +13938,25 @@ var init_render = __esm({
13884
13938
  }
13885
13939
  });
13886
13940
 
13941
+ // packages/contracts/src/resource-governor.ts
13942
+ var RESOURCE_CLASSES, DEFAULT_RESOURCE_RETRY_AFTER_MS;
13943
+ var init_resource_governor = __esm({
13944
+ "packages/contracts/src/resource-governor.ts"() {
13945
+ "use strict";
13946
+ RESOURCE_CLASSES = Object.freeze([
13947
+ "interactive-cli",
13948
+ "agent-session",
13949
+ "llm-call",
13950
+ "test-run",
13951
+ "scoped-build",
13952
+ "full-build",
13953
+ "db-heavy",
13954
+ "background-autonomous"
13955
+ ]);
13956
+ DEFAULT_RESOURCE_RETRY_AFTER_MS = 2e3;
13957
+ }
13958
+ });
13959
+
13887
13960
  // packages/contracts/src/session.ts
13888
13961
  var init_session2 = __esm({
13889
13962
  "packages/contracts/src/session.ts"() {
@@ -15635,6 +15708,7 @@ var init_src = __esm({
15635
15708
  init_evidence_atoms();
15636
15709
  init_plan();
15637
15710
  init_render();
15711
+ init_resource_governor();
15638
15712
  init_session2();
15639
15713
  init_session_journal();
15640
15714
  init_status_registry();
@@ -17548,7 +17622,7 @@ var init_sql = __esm({
17548
17622
  return new SQL([new StringChunk(str)]);
17549
17623
  }
17550
17624
  _sql.raw = raw;
17551
- function join23(chunks, separator) {
17625
+ function join25(chunks, separator) {
17552
17626
  const result = [];
17553
17627
  for (const [i, chunk] of chunks.entries()) {
17554
17628
  if (i > 0 && separator !== void 0) result.push(separator);
@@ -17556,7 +17630,7 @@ var init_sql = __esm({
17556
17630
  }
17557
17631
  return new SQL(result);
17558
17632
  }
17559
- _sql.join = join23;
17633
+ _sql.join = join25;
17560
17634
  function identifier(value) {
17561
17635
  return new Name(value);
17562
17636
  }
@@ -19943,7 +20017,7 @@ var init_select2 = __esm({
19943
20017
  const baseTableName = this.tableName;
19944
20018
  const tableName = getTableLikeName(table);
19945
20019
  for (const item of extractUsedTable(table)) this.usedTables.add(item);
19946
- if (typeof tableName === "string" && this.config.joins?.some((join23) => join23.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
20020
+ if (typeof tableName === "string" && this.config.joins?.some((join25) => join25.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
19947
20021
  if (!this.isPartialSelect) {
19948
20022
  if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
19949
20023
  if (typeof tableName === "string" && !is(table, SQL)) {
@@ -23753,7 +23827,7 @@ var init_dialect = __esm({
23753
23827
  if (!joins2) return;
23754
23828
  const withEntries = Object.entries(joins2).filter(([_, v]) => v);
23755
23829
  if (!withEntries.length) return;
23756
- return sql.join(withEntries.map(([k, join23]) => {
23830
+ return sql.join(withEntries.map(([k, join25]) => {
23757
23831
  const relation = tableConfig.relations[k];
23758
23832
  const isSingle2 = is(relation, One);
23759
23833
  const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
@@ -23764,7 +23838,7 @@ var init_dialect = __esm({
23764
23838
  table: targetTable,
23765
23839
  mode: isSingle2 ? "first" : "many",
23766
23840
  schema,
23767
- queryConfig: join23,
23841
+ queryConfig: join25,
23768
23842
  tableConfig: schema[relation.targetTableName],
23769
23843
  relationWhere: filter,
23770
23844
  isNested: true,
@@ -23778,7 +23852,7 @@ var init_dialect = __esm({
23778
23852
  key: k,
23779
23853
  selection: innerQuery.selection,
23780
23854
  isArray: !isSingle2,
23781
- isOptional: (relation.optional ?? false) || join23 !== true && !!join23.where
23855
+ isOptional: (relation.optional ?? false) || join25 !== true && !!join25.where
23782
23856
  });
23783
23857
  const jsonColumns = sql.join(innerQuery.selection.map((s) => {
23784
23858
  return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb3}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
@@ -24599,7 +24673,7 @@ var init_update = __esm({
24599
24673
  createJoin(joinType) {
24600
24674
  return ((table, on) => {
24601
24675
  const tableName = getTableLikeName(table);
24602
- if (typeof tableName === "string" && this.config.joins.some((join23) => join23.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
24676
+ if (typeof tableName === "string" && this.config.joins.some((join25) => join25.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
24603
24677
  if (typeof on === "function") {
24604
24678
  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;
24605
24679
  on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
@@ -25751,8 +25825,8 @@ function probeAndMarkApplied(nativeDb, migration, logSubsystem, eliminatedTables
25751
25825
  });
25752
25826
  if (allAltersPresent && allTablesPresent && allIndexesPresent && allTriggersPresent) {
25753
25827
  insertJournalEntry(nativeDb, migration.hash, migration.folderMillis, migration.name ?? "");
25754
- const log11 = getLogger(logSubsystem);
25755
- log11.debug(
25828
+ const log12 = getLogger(logSubsystem);
25829
+ log12.debug(
25756
25830
  {
25757
25831
  migration: migration.name,
25758
25832
  alters: alterTargets.length,
@@ -25821,14 +25895,14 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
25821
25895
  if (hasOrphanedEntries) {
25822
25896
  const dbHashes = new Set(dbEntries.map((e) => e.hash));
25823
25897
  const allLocalHashesPresentInDb = localMigrations.every((m) => dbHashes.has(m.hash));
25824
- const log11 = getLogger(logSubsystem);
25898
+ const log12 = getLogger(logSubsystem);
25825
25899
  if (allLocalHashesPresentInDb) {
25826
- log11.debug(
25900
+ log12.debug(
25827
25901
  { extra: orphanedEntries.length },
25828
25902
  `Migration journal has ${orphanedEntries.length} entries for migrations not known to this install (DB is ahead). Skipping reconciliation.`
25829
25903
  );
25830
25904
  } else {
25831
- log11.warn(
25905
+ log12.warn(
25832
25906
  { orphaned: orphanedEntries.length },
25833
25907
  `Detected ${orphanedEntries.length} true-orphan journal entries from a previous CLEO lineage. Reconciling via DDL probe.`
25834
25908
  );
@@ -25864,8 +25938,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
25864
25938
  if (alterMatches.length === 0) {
25865
25939
  const stripped = stripSqlComments(fullSql).trim();
25866
25940
  if (stripped === "") {
25867
- const log11 = getLogger(logSubsystem);
25868
- log11.debug(
25941
+ const log12 = getLogger(logSubsystem);
25942
+ log12.debug(
25869
25943
  { migration: migration.name },
25870
25944
  `Migration ${migration.name} is a comment-only baseline marker \u2014 marking applied on existing DB.`
25871
25945
  );
@@ -25904,8 +25978,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
25904
25978
  }
25905
25979
  }
25906
25980
  if (missingColumns.length === 0) {
25907
- const log11 = getLogger(logSubsystem);
25908
- log11.warn(
25981
+ const log12 = getLogger(logSubsystem);
25982
+ log12.warn(
25909
25983
  { migration: migration.name, columns: alterMatches },
25910
25984
  `Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
25911
25985
  );
@@ -25913,8 +25987,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
25913
25987
  continue;
25914
25988
  }
25915
25989
  if (existingColumns.length > 0 && missingColumns.length > 0) {
25916
- const log11 = getLogger(logSubsystem);
25917
- log11.warn(
25990
+ const log12 = getLogger(logSubsystem);
25991
+ log12.warn(
25918
25992
  {
25919
25993
  migration: migration.name,
25920
25994
  existingColumns: existingColumns.map((c) => `${c.table}.${c.column}`),
@@ -25926,12 +26000,12 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
25926
26000
  if (!tableExists(nativeDb, table)) continue;
25927
26001
  try {
25928
26002
  nativeDb.exec(`ALTER TABLE ${table} ADD COLUMN ${column}${ddl ? ` ${ddl}` : ""}`);
25929
- log11.warn(
26003
+ log12.warn(
25930
26004
  { migration: migration.name, table, column },
25931
26005
  `T920: Added missing column ${table}.${column} to complete partial migration.`
25932
26006
  );
25933
26007
  } catch {
25934
- log11.warn(
26008
+ log12.warn(
25935
26009
  { migration: migration.name, table, column },
25936
26010
  `T920: Could not add missing column ${table}.${column} \u2014 will let Drizzle migrate() handle it.`
25937
26011
  );
@@ -25951,8 +26025,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
25951
26025
  for (const entry of unnamedEntries) {
25952
26026
  const migrationName = hashToName.get(entry.hash);
25953
26027
  if (!migrationName) continue;
25954
- const log11 = getLogger(logSubsystem);
25955
- log11.debug(
26028
+ const log12 = getLogger(logSubsystem);
26029
+ log12.debug(
25956
26030
  { id: entry.id, hash: entry.hash, name: migrationName },
25957
26031
  `Backfilling missing name on journal entry id=${entry.id} (Drizzle v1 beta legacy compat).`
25958
26032
  );
@@ -26102,13 +26176,13 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem, conte
26102
26176
  const existingCols = new Set(columns.map((c) => c.name));
26103
26177
  for (const req of requiredColumns) {
26104
26178
  if (!existingCols.has(req.name)) {
26105
- const log11 = getLogger(logSubsystem);
26179
+ const log12 = getLogger(logSubsystem);
26106
26180
  const message = `Adding missing column ${tableName}.${req.name} via ALTER TABLE`;
26107
26181
  const fields = { column: req.name, context };
26108
26182
  if (context === "fresh") {
26109
- log11.error(fields, `${message} \u2014 MIGRATION DEFECT (fresh DB should not need repair)`);
26183
+ log12.error(fields, `${message} \u2014 MIGRATION DEFECT (fresh DB should not need repair)`);
26110
26184
  } else {
26111
- log11.warn(fields, message);
26185
+ log12.warn(fields, message);
26112
26186
  }
26113
26187
  nativeDb.exec(`ALTER TABLE ${tableName} ADD COLUMN ${req.name} ${req.ddl}`);
26114
26188
  }
@@ -35301,11 +35375,750 @@ var init_cleo_global = __esm({
35301
35375
  }
35302
35376
  });
35303
35377
 
35304
- // packages/core/src/store/lock.ts
35378
+ // packages/core/src/resources/linux-backend.ts
35379
+ import { readFile as readFile2, stat } from "node:fs/promises";
35380
+ function parsePressureLine(line2) {
35381
+ const avg10Match = /avg10=([\d.]+)/.exec(line2);
35382
+ const avg60Match = /avg60=([\d.]+)/.exec(line2);
35383
+ const avg300Match = /avg300=([\d.]+)/.exec(line2);
35384
+ const totalMatch = /total=(\d+)/.exec(line2);
35385
+ if (!avg10Match?.[1] || !avg60Match?.[1] || !avg300Match?.[1] || !totalMatch?.[1]) {
35386
+ return null;
35387
+ }
35388
+ return {
35389
+ avg10: parseFloat(avg10Match[1]),
35390
+ avg60: parseFloat(avg60Match[1]),
35391
+ avg300: parseFloat(avg300Match[1]),
35392
+ totalUs: parseInt(totalMatch[1], 10)
35393
+ };
35394
+ }
35395
+ function parsePsiFile(content) {
35396
+ const lines = content.split("\n").map((l) => l.trim()).filter(Boolean);
35397
+ let some = null;
35398
+ let full = null;
35399
+ for (const line2 of lines) {
35400
+ if (line2.startsWith("some ")) {
35401
+ some = parsePressureLine(line2);
35402
+ } else if (line2.startsWith("full ")) {
35403
+ full = parsePressureLine(line2);
35404
+ }
35405
+ }
35406
+ if (!some) {
35407
+ return null;
35408
+ }
35409
+ return { some, full };
35410
+ }
35411
+ function parseMemAvailable(content) {
35412
+ for (const line2 of content.split("\n")) {
35413
+ if (line2.startsWith("MemAvailable:")) {
35414
+ const match = /MemAvailable:\s+(\d+)\s+kB/.exec(line2);
35415
+ if (match?.[1]) {
35416
+ return parseInt(match[1], 10) * 1024;
35417
+ }
35418
+ }
35419
+ }
35420
+ return null;
35421
+ }
35422
+ function parseSmapsRollup(content) {
35423
+ let rssKb = null;
35424
+ let pssKb = null;
35425
+ for (const line2 of content.split("\n")) {
35426
+ if (line2.startsWith("Rss:")) {
35427
+ const m = /Rss:\s+(\d+)\s+kB/.exec(line2);
35428
+ if (m?.[1]) rssKb = parseInt(m[1], 10);
35429
+ } else if (line2.startsWith("Pss:")) {
35430
+ const m = /Pss:\s+(\d+)\s+kB/.exec(line2);
35431
+ if (m?.[1]) pssKb = parseInt(m[1], 10);
35432
+ }
35433
+ }
35434
+ if (rssKb === null || pssKb === null) return null;
35435
+ return { rssBytes: rssKb * 1024, pssBytes: pssKb * 1024 };
35436
+ }
35437
+ var defaultReadFile, defaultStat, LinuxResourceBackend;
35438
+ var init_linux_backend = __esm({
35439
+ "packages/core/src/resources/linux-backend.ts"() {
35440
+ "use strict";
35441
+ defaultReadFile = (path2, encoding) => readFile2(path2, encoding);
35442
+ defaultStat = async (path2) => {
35443
+ try {
35444
+ const s = await stat(path2);
35445
+ return { size: s.size };
35446
+ } catch {
35447
+ return null;
35448
+ }
35449
+ };
35450
+ LinuxResourceBackend = class {
35451
+ globalPressurePath;
35452
+ cgroupSlicePressurePath;
35453
+ walPaths;
35454
+ readFileFn;
35455
+ statFileFn;
35456
+ constructor(opts = {}) {
35457
+ this.globalPressurePath = opts.globalPressurePath ?? "/proc/pressure/memory";
35458
+ this.cgroupSlicePressurePath = opts.cgroupSlicePressurePath ?? null;
35459
+ this.walPaths = opts.walPaths ?? [];
35460
+ this.readFileFn = opts.readFileFn ?? defaultReadFile;
35461
+ this.statFileFn = opts.statFileFn ?? defaultStat;
35462
+ }
35463
+ /**
35464
+ * Take a bounded point-in-time resource sample.
35465
+ *
35466
+ * Read-count (bounded by Amendment 1):
35467
+ * - 1 read: `/proc/pressure/memory`
35468
+ * - 0–1 reads: slice `memory.pressure` (if configured)
35469
+ * - 1 read: `/proc/meminfo`
35470
+ * - N stat calls: one per WAL path in `walPaths`
35471
+ *
35472
+ * Never spawns a child process.
35473
+ */
35474
+ async sample() {
35475
+ const sampledAtMs = Date.now();
35476
+ const globalPressure = await this._readPsi(this.globalPressurePath);
35477
+ const pressureAvailable = globalPressure !== null;
35478
+ let slicePressure = null;
35479
+ if (this.cgroupSlicePressurePath) {
35480
+ slicePressure = await this._readPsi(this.cgroupSlicePressurePath);
35481
+ }
35482
+ const memAvailableBytes = await this._readMemAvailable();
35483
+ const walObservations = await this._readWalObservations();
35484
+ return {
35485
+ sampledAtMs,
35486
+ pressureAvailable,
35487
+ memAvailableBytes,
35488
+ globalPressure,
35489
+ slicePressure,
35490
+ walObservations
35491
+ };
35492
+ }
35493
+ /**
35494
+ * Sweep per-child RSS via `/proc/<pid>/smaps_rollup`.
35495
+ *
35496
+ * **STRUCTURALLY SEPARATED from sample()** — smaps_rollup reads are
35497
+ * ms-scale per multi-GB process and must never appear in the hot path.
35498
+ * Call on a separate low-frequency cadence (e.g. every 60s or on
35499
+ * backoff→hold state transition).
35500
+ *
35501
+ * @param pids - PIDs to sweep. Dead/unknown PIDs are silently skipped.
35502
+ */
35503
+ async sweepChildRss(pids) {
35504
+ const sampledAtMs = Date.now();
35505
+ const entries = [];
35506
+ for (const pid of pids) {
35507
+ try {
35508
+ const content = await this.readFileFn(`/proc/${pid}/smaps_rollup`, "utf-8");
35509
+ const parsed = parseSmapsRollup(content);
35510
+ if (parsed) {
35511
+ entries.push({ pid, ...parsed });
35512
+ }
35513
+ } catch {
35514
+ }
35515
+ }
35516
+ return { sampledAtMs, entries };
35517
+ }
35518
+ // -------------------------------------------------------------------------
35519
+ // Private helpers
35520
+ // -------------------------------------------------------------------------
35521
+ async _readPsi(path2) {
35522
+ try {
35523
+ const content = await this.readFileFn(path2, "utf-8");
35524
+ return parsePsiFile(content);
35525
+ } catch {
35526
+ return null;
35527
+ }
35528
+ }
35529
+ async _readMemAvailable() {
35530
+ try {
35531
+ const content = await this.readFileFn("/proc/meminfo", "utf-8");
35532
+ return parseMemAvailable(content);
35533
+ } catch {
35534
+ return null;
35535
+ }
35536
+ }
35537
+ async _readWalObservations() {
35538
+ const results = [];
35539
+ for (const walPath of this.walPaths) {
35540
+ const info = await this.statFileFn(walPath);
35541
+ results.push({ walPath, sizeBytes: info?.size ?? null });
35542
+ }
35543
+ return results;
35544
+ }
35545
+ };
35546
+ }
35547
+ });
35548
+
35549
+ // packages/core/src/resources/monitor.ts
35550
+ import { EventEmitter as EventEmitter2 } from "node:events";
35551
+ function resolveThresholds(cfg) {
35552
+ return {
35553
+ holdSomeAvg10: cfg.psi?.holdSomeAvg10 ?? DEFAULTS.holdSomeAvg10,
35554
+ backoffSomeAvg10: cfg.psi?.backoffSomeAvg10 ?? DEFAULTS.backoffSomeAvg10,
35555
+ holdFullAvg10: cfg.psi?.holdFullAvg10 ?? DEFAULTS.holdFullAvg10,
35556
+ backoffFullAvg10: cfg.psi?.backoffFullAvg10 ?? DEFAULTS.backoffFullAvg10,
35557
+ hysteresisPoints: cfg.hysteresisPoints ?? DEFAULTS.hysteresisPoints,
35558
+ headroomBytes: cfg.headroomBytes ?? DEFAULTS.headroomBytes,
35559
+ walWarnThresholdBytes: cfg.walWarnThresholdBytes ?? DEFAULTS.walWarnThresholdBytes,
35560
+ pollIntervalMs: cfg.pollIntervalMs ?? DEFAULTS.pollIntervalMs
35561
+ };
35562
+ }
35563
+ function evaluateState(sample, thresholds, currentState) {
35564
+ if (!sample.pressureAvailable) {
35565
+ if (sample.memAvailableBytes !== null && sample.memAvailableBytes < thresholds.headroomBytes) {
35566
+ return { state: "hold", reason: "degraded: memAvailable below headroom" };
35567
+ }
35568
+ return { state: "ok", reason: "degraded: PSI unavailable, memAvailable sufficient" };
35569
+ }
35570
+ const somePressure = sample.globalPressure?.some ?? sample.slicePressure?.some;
35571
+ const fullPressure = sample.globalPressure?.full ?? sample.slicePressure?.full;
35572
+ const someAvg102 = somePressure?.avg10 ?? 0;
35573
+ const fullAvg10 = fullPressure?.avg10 ?? 0;
35574
+ if (someAvg102 > thresholds.backoffSomeAvg10 || fullAvg10 > thresholds.backoffFullAvg10) {
35575
+ return {
35576
+ state: "backoff",
35577
+ reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 above backoff threshold`
35578
+ };
35579
+ }
35580
+ if (someAvg102 > thresholds.holdSomeAvg10 || fullAvg10 > thresholds.holdFullAvg10) {
35581
+ return {
35582
+ state: "hold",
35583
+ reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 above hold threshold`
35584
+ };
35585
+ }
35586
+ if (currentState !== "ok") {
35587
+ const hysteresisFloor = thresholds.holdSomeAvg10 - thresholds.hysteresisPoints;
35588
+ const fullHysteresisFloor = thresholds.holdFullAvg10 - thresholds.hysteresisPoints;
35589
+ if (someAvg102 > hysteresisFloor || fullAvg10 > fullHysteresisFloor) {
35590
+ const clamped = currentState === "backoff" ? "hold" : currentState;
35591
+ return {
35592
+ state: clamped,
35593
+ reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 hysteresis hold (floor: some ${hysteresisFloor}, full ${fullHysteresisFloor})`
35594
+ };
35595
+ }
35596
+ }
35597
+ return {
35598
+ state: "ok",
35599
+ reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 below thresholds`
35600
+ };
35601
+ }
35602
+ var DEFAULTS, ResourceMonitor;
35603
+ var init_monitor = __esm({
35604
+ "packages/core/src/resources/monitor.ts"() {
35605
+ "use strict";
35606
+ init_linux_backend();
35607
+ DEFAULTS = {
35608
+ holdSomeAvg10: 10,
35609
+ backoffSomeAvg10: 20,
35610
+ holdFullAvg10: 5,
35611
+ backoffFullAvg10: 10,
35612
+ hysteresisPoints: 3,
35613
+ headroomBytes: 256 * 1024 * 1024,
35614
+ walWarnThresholdBytes: 256 * 1024 * 1024,
35615
+ pollIntervalMs: 1500
35616
+ };
35617
+ ResourceMonitor = class extends EventEmitter2 {
35618
+ thresholds;
35619
+ backend;
35620
+ _state = "ok";
35621
+ _timer = null;
35622
+ _running = false;
35623
+ constructor(cfg = {}) {
35624
+ super();
35625
+ this.thresholds = resolveThresholds(cfg);
35626
+ this.backend = cfg.backend ?? new LinuxResourceBackend();
35627
+ }
35628
+ // -------------------------------------------------------------------------
35629
+ // Public API
35630
+ // -------------------------------------------------------------------------
35631
+ /**
35632
+ * Current pressure state (only meaningful after at least one sample).
35633
+ */
35634
+ get state() {
35635
+ return this._state;
35636
+ }
35637
+ /**
35638
+ * `true` while the continuous loop is running.
35639
+ */
35640
+ get running() {
35641
+ return this._running;
35642
+ }
35643
+ /**
35644
+ * Take a single point-in-time resource sample.
35645
+ *
35646
+ * Safe to call with the daemon off (no child processes, bounded reads).
35647
+ * Does NOT update `this.state` — use {@link startContinuous} for that.
35648
+ */
35649
+ async sample() {
35650
+ return this.backend.sample();
35651
+ }
35652
+ /**
35653
+ * Start the continuous polling loop.
35654
+ *
35655
+ * Returns a `stop()` function. Calling `stop()` is idempotent.
35656
+ *
35657
+ * Emits:
35658
+ * - `'sample'` on every poll (even if state did not change)
35659
+ * - `'transition'` when `PressureState` changes
35660
+ * - `'error'` if the backend throws (loop continues regardless)
35661
+ */
35662
+ startContinuous() {
35663
+ if (this._running) {
35664
+ return () => this._stopLoop();
35665
+ }
35666
+ this._running = true;
35667
+ this._scheduleNext();
35668
+ return () => this._stopLoop();
35669
+ }
35670
+ /**
35671
+ * Stop the continuous polling loop. Idempotent.
35672
+ */
35673
+ stop() {
35674
+ this._stopLoop();
35675
+ }
35676
+ // -------------------------------------------------------------------------
35677
+ // Private loop machinery
35678
+ // -------------------------------------------------------------------------
35679
+ _scheduleNext() {
35680
+ this._timer = setTimeout(() => {
35681
+ void this._tick();
35682
+ }, this.thresholds.pollIntervalMs);
35683
+ if (typeof this._timer.unref === "function") {
35684
+ this._timer.unref();
35685
+ }
35686
+ }
35687
+ async _tick() {
35688
+ if (!this._running) return;
35689
+ try {
35690
+ const sample = await this.backend.sample();
35691
+ this.emit("sample", sample);
35692
+ const { state: newState, reason } = evaluateState(sample, this.thresholds, this._state);
35693
+ if (newState !== this._state) {
35694
+ const transition = {
35695
+ from: this._state,
35696
+ to: newState,
35697
+ sample,
35698
+ reason
35699
+ };
35700
+ this._state = newState;
35701
+ this.emit("transition", transition);
35702
+ }
35703
+ } catch (err) {
35704
+ this.emit("error", err instanceof Error ? err : new Error(String(err)));
35705
+ }
35706
+ if (this._running) {
35707
+ this._scheduleNext();
35708
+ }
35709
+ }
35710
+ _stopLoop() {
35711
+ this._running = false;
35712
+ if (this._timer !== null) {
35713
+ clearTimeout(this._timer);
35714
+ this._timer = null;
35715
+ }
35716
+ }
35717
+ };
35718
+ }
35719
+ });
35720
+
35721
+ // packages/core/src/resources/supervisor-admit.ts
35722
+ import { connect } from "node:net";
35723
+ import { join as join5 } from "node:path";
35724
+ import { getCleoHome as getCleoHome2 } from "@cleocode/paths";
35725
+ function resolveSupervisorSocketPath() {
35726
+ return process.env.CLEO_SUPERVISOR_SOCKET ?? join5(getCleoHome2(), SUPERVISOR_SOCKET_NAME);
35727
+ }
35728
+ async function sendResourceAdmit(socketPath, cls, holderId, budget) {
35729
+ const result = await sendLeaseRequest(
35730
+ socketPath,
35731
+ { kind: "resource_admit", class: cls, holder_id: holderId, budget },
35732
+ "resource_admit_result"
35733
+ );
35734
+ if ("unavailable" in result) return result;
35735
+ if (result.kind === "resource_admit_result") return result;
35736
+ return { unavailable: true, reason: `unexpected response kind: ${result.kind}` };
35737
+ }
35738
+ async function sendResourceRelease(socketPath, cls, holderId) {
35739
+ const result = await sendLeaseRequest(
35740
+ socketPath,
35741
+ { kind: "resource_release", class: cls, holder_id: holderId },
35742
+ "resource_release_result"
35743
+ );
35744
+ if ("unavailable" in result) return result;
35745
+ if (result.kind === "resource_release_result") return result;
35746
+ return { unavailable: true, reason: `unexpected response kind: ${result.kind}` };
35747
+ }
35748
+ function sendLeaseRequest(socketPath, request, expectedKind) {
35749
+ return new Promise((resolve6) => {
35750
+ const id = `ra-${process.pid}-${request.kind}`;
35751
+ const envelope = LeaseIpcRequestEnvelopeSchema.parse({
35752
+ protocol_version: LEASE_IPC_PROTOCOL_VERSION,
35753
+ id,
35754
+ direction: "request",
35755
+ request
35756
+ });
35757
+ const line2 = `${JSON.stringify(envelope)}
35758
+ `;
35759
+ let settled = false;
35760
+ let buffer = "";
35761
+ const socket = connect(socketPath);
35762
+ const done = (value) => {
35763
+ if (settled) return;
35764
+ settled = true;
35765
+ socket.removeAllListeners();
35766
+ socket.destroy();
35767
+ resolve6(value);
35768
+ };
35769
+ const degrade = (reason) => done({ unavailable: true, reason });
35770
+ socket.setTimeout(REQUEST_TIMEOUT_MS);
35771
+ const connectTimer = setTimeout(
35772
+ () => degrade("supervisor connect timeout"),
35773
+ CONNECT_TIMEOUT_MS
35774
+ );
35775
+ socket.on("connect", () => {
35776
+ clearTimeout(connectTimer);
35777
+ socket.write(line2);
35778
+ });
35779
+ socket.on("timeout", () => degrade("supervisor request timeout"));
35780
+ socket.on("error", (err) => {
35781
+ clearTimeout(connectTimer);
35782
+ degrade(err.message);
35783
+ });
35784
+ socket.on("close", () => {
35785
+ if (!settled) degrade("supervisor closed the connection before responding");
35786
+ });
35787
+ socket.on("data", (chunk) => {
35788
+ buffer += chunk.toString("utf8");
35789
+ const nl = buffer.indexOf("\n");
35790
+ if (nl < 0) return;
35791
+ let json2;
35792
+ try {
35793
+ json2 = JSON.parse(buffer.slice(0, nl));
35794
+ } catch (cause) {
35795
+ degrade(`malformed lease-ipc frame: ${cause instanceof Error ? cause.message : cause}`);
35796
+ return;
35797
+ }
35798
+ const parsed = LeaseIpcResponseEnvelopeSchema.safeParse(json2);
35799
+ if (!parsed.success) {
35800
+ degrade(`off-contract lease-ipc response: ${parsed.error.message}`);
35801
+ return;
35802
+ }
35803
+ const { response } = parsed.data;
35804
+ if (response.kind === expectedKind) {
35805
+ done(response);
35806
+ return;
35807
+ }
35808
+ if (response.kind === "error") {
35809
+ degrade(`${response.code}: ${response.message}`);
35810
+ return;
35811
+ }
35812
+ degrade(`unexpected lease-ipc response kind for ${request.kind}: ${response.kind}`);
35813
+ });
35814
+ });
35815
+ }
35816
+ var SUPERVISOR_SOCKET_NAME, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS;
35817
+ var init_supervisor_admit = __esm({
35818
+ "packages/core/src/resources/supervisor-admit.ts"() {
35819
+ "use strict";
35820
+ init_src();
35821
+ SUPERVISOR_SOCKET_NAME = "cleo-supervisor.sock";
35822
+ CONNECT_TIMEOUT_MS = 250;
35823
+ REQUEST_TIMEOUT_MS = 2e3;
35824
+ }
35825
+ });
35826
+
35827
+ // packages/core/src/resources/governor.ts
35828
+ var governor_exports = {};
35829
+ __export(governor_exports, {
35830
+ ResourceGovernor: () => ResourceGovernor,
35831
+ _resetGovernorStateForTest: () => _resetGovernorStateForTest,
35832
+ computeClassBudget: () => computeClassBudget,
35833
+ governor: () => governor,
35834
+ governorSlotDir: () => governorSlotDir,
35835
+ resolveGovernorMode: () => resolveGovernorMode,
35836
+ slotFileCount: () => slotFileCount
35837
+ });
35838
+ import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, writeFileSync } from "node:fs";
35839
+ import { availableParallelism, totalmem } from "node:os";
35840
+ import { join as join6 } from "node:path";
35305
35841
  import lockfile from "proper-lockfile";
35842
+ function log2() {
35843
+ if (_log2 === null) _log2 = getLogger("resource-governor");
35844
+ return _log2;
35845
+ }
35846
+ function resolveGovernorMode() {
35847
+ if (_cachedMode2 !== null) return _cachedMode2;
35848
+ const raw = process.env.CLEO_RESOURCES_MODE;
35849
+ _cachedMode2 = raw === "supervisor" || raw === "local" || raw === "off" ? raw : "local";
35850
+ return _cachedMode2;
35851
+ }
35852
+ function logSupervisorDegradeOnce(reason) {
35853
+ if (_supervisorDegradeLogged) return;
35854
+ _supervisorDegradeLogged = true;
35855
+ log2().info(
35856
+ `CLEO_RESOURCES_MODE=supervisor but the arbiter is unreachable (${reason}); degrading to local-mode admission for the process lifetime.`
35857
+ );
35858
+ }
35859
+ function _resetGovernorStateForTest() {
35860
+ _cachedMode2 = null;
35861
+ _supervisorDegradeLogged = false;
35862
+ }
35863
+ function someAvg10(sample) {
35864
+ const some = sample.globalPressure?.some ?? sample.slicePressure?.some;
35865
+ return some?.avg10 ?? 0;
35866
+ }
35867
+ function computeClassBudget(cls, sample, opts = {}) {
35868
+ if (cls === "interactive-cli") return Number.POSITIVE_INFINITY;
35869
+ const cpus = Math.max(1, opts.cpuCount ?? availableParallelism());
35870
+ const totalBytes = opts.totalMemBytes ?? totalmem();
35871
+ const headroomBytes = (opts.headroomMb ?? 2048) * MB;
35872
+ const hold = opts.holdSomeAvg10 ?? 10;
35873
+ const floor = opts.floorSomeAvg10 ?? 25;
35874
+ const some = someAvg10(sample);
35875
+ const availBytes = sample.memAvailableBytes ?? totalBytes;
35876
+ const fullStall = sample.globalPressure?.full?.avg10 ?? sample.slicePressure?.full?.avg10 ?? 0;
35877
+ const backoff = some > floor || fullStall > 10;
35878
+ switch (cls) {
35879
+ case "full-build":
35880
+ return 1;
35881
+ case "agent-session": {
35882
+ const estRamBytes = (opts.agentEstRamMb ?? 4096) * MB;
35883
+ const byMem = Math.floor((availBytes - headroomBytes) / estRamBytes);
35884
+ return clamp(1, byMem, Math.max(1, cpus - 2));
35885
+ }
35886
+ case "llm-call":
35887
+ return Math.max(1, cpus - 2);
35888
+ case "test-run":
35889
+ case "scoped-build": {
35890
+ const base = Math.max(1, Math.floor(cpus / 4));
35891
+ if (some > floor) return 1;
35892
+ if (some > hold) return Math.max(1, Math.floor(base / 2));
35893
+ return base;
35894
+ }
35895
+ case "db-heavy":
35896
+ return backoff ? 0 : 1;
35897
+ case "background-autonomous":
35898
+ return some > hold || fullStall > 5 ? 0 : 1;
35899
+ default:
35900
+ return 1;
35901
+ }
35902
+ }
35903
+ function clamp(lo, v, hi) {
35904
+ return Math.max(lo, Math.min(v, hi));
35905
+ }
35906
+ function governorSlotDir(cls) {
35907
+ return join6(getCleoHome(), "locks", `resource-${cls}`);
35908
+ }
35909
+ function ensureSlotFiles(dir, count) {
35910
+ if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
35911
+ const paths = [];
35912
+ for (let i = 0; i < count; i++) {
35913
+ const p = join6(dir, `slot-${i}.lock`);
35914
+ if (!existsSync3(p)) writeFileSync(p, "", { flag: "a" });
35915
+ paths.push(p);
35916
+ }
35917
+ return paths;
35918
+ }
35919
+ function sleep2(ms) {
35920
+ return new Promise((r) => setTimeout(r, ms));
35921
+ }
35922
+ function passThroughGrant(cls) {
35923
+ return {
35924
+ deferred: false,
35925
+ class: cls,
35926
+ slot: -1,
35927
+ acquiredAtMs: Date.now(),
35928
+ release: async () => {
35929
+ }
35930
+ };
35931
+ }
35932
+ function deferral(cls, reason, retryAfterMs) {
35933
+ return { deferred: true, class: cls, retryAfterMs, reason };
35934
+ }
35935
+ function supervisorHolderId(cls) {
35936
+ _supervisorHolderSeq += 1;
35937
+ return `${process.pid}:${cls}:${_supervisorHolderSeq}`;
35938
+ }
35939
+ function shuffledIndices(n) {
35940
+ const order = Array.from({ length: n }, (_, i) => i);
35941
+ for (let i = order.length - 1; i > 0; i--) {
35942
+ const j = Math.floor(Math.random() * (i + 1));
35943
+ const a = order[i];
35944
+ const b = order[j];
35945
+ if (a !== void 0 && b !== void 0) {
35946
+ order[i] = b;
35947
+ order[j] = a;
35948
+ }
35949
+ }
35950
+ return order;
35951
+ }
35952
+ async function countHeldSlots(cls, budget) {
35953
+ const dir = governorSlotDir(cls);
35954
+ if (!existsSync3(dir)) return 0;
35955
+ const slots = ensureSlotFiles(dir, budget);
35956
+ let held = 0;
35957
+ for (const path2 of slots) {
35958
+ try {
35959
+ const release = await lockfile.lock(path2, { retries: 0, stale: STALE_MS, realpath: false });
35960
+ await release();
35961
+ } catch {
35962
+ held++;
35963
+ }
35964
+ }
35965
+ return held;
35966
+ }
35967
+ function slotFileCount(cls) {
35968
+ const dir = governorSlotDir(cls);
35969
+ if (!existsSync3(dir)) return 0;
35970
+ return readdirSync2(dir).filter((f) => f.startsWith("slot-") && f.endsWith(".lock")).length;
35971
+ }
35972
+ var _log2, _cachedMode2, _supervisorDegradeLogged, MB, STALE_MS, _supervisorHolderSeq, ResourceGovernor, governor;
35973
+ var init_governor = __esm({
35974
+ "packages/core/src/resources/governor.ts"() {
35975
+ "use strict";
35976
+ init_src();
35977
+ init_logger2();
35978
+ init_paths();
35979
+ init_monitor();
35980
+ init_supervisor_admit();
35981
+ _log2 = null;
35982
+ _cachedMode2 = null;
35983
+ _supervisorDegradeLogged = false;
35984
+ MB = 1024 * 1024;
35985
+ STALE_MS = 6e5;
35986
+ _supervisorHolderSeq = 0;
35987
+ ResourceGovernor = class {
35988
+ /**
35989
+ * Acquire one slot of `cls`. Returns a {@link ResourceGrant} on success or a
35990
+ * {@link ResourceDeferral} on denial. Never throws for admission control;
35991
+ * only genuinely unexpected I/O errors propagate.
35992
+ */
35993
+ async acquire(cls, opts = {}) {
35994
+ const mode = resolveGovernorMode();
35995
+ if (mode === "off" || cls === "interactive-cli") {
35996
+ return passThroughGrant(cls);
35997
+ }
35998
+ const sample = opts.sample ?? await (opts.monitor ?? new ResourceMonitor()).sample();
35999
+ const budget = computeClassBudget(cls, sample, opts);
36000
+ if (!Number.isFinite(budget)) return passThroughGrant(cls);
36001
+ if (budget <= 0) {
36002
+ return deferral(
36003
+ cls,
36004
+ `class '${cls}' budget is 0 under current pressure (some avg10=${someAvg10(sample).toFixed(1)})`,
36005
+ DEFAULT_RESOURCE_RETRY_AFTER_MS
36006
+ );
36007
+ }
36008
+ if (mode === "supervisor") {
36009
+ const viaSupervisor = await this.acquireViaSupervisor(cls, Math.floor(budget));
36010
+ if (viaSupervisor !== null) return viaSupervisor;
36011
+ }
36012
+ const dir = governorSlotDir(cls);
36013
+ const slots = ensureSlotFiles(dir, budget);
36014
+ const blocking = opts.blocking ?? true;
36015
+ const timeoutMs = opts.timeoutMs ?? 36e5;
36016
+ const pollMs = opts.pollMs ?? 200;
36017
+ const startedAt = Date.now();
36018
+ do {
36019
+ const order = shuffledIndices(slots.length);
36020
+ for (const idx of order) {
36021
+ const path2 = slots[idx];
36022
+ if (!path2) continue;
36023
+ try {
36024
+ const release = await lockfile.lock(path2, {
36025
+ retries: 0,
36026
+ stale: STALE_MS,
36027
+ realpath: false
36028
+ });
36029
+ let released = false;
36030
+ return {
36031
+ deferred: false,
36032
+ class: cls,
36033
+ slot: idx,
36034
+ acquiredAtMs: Date.now(),
36035
+ release: async () => {
36036
+ if (released) return;
36037
+ released = true;
36038
+ try {
36039
+ await release();
36040
+ } catch {
36041
+ }
36042
+ }
36043
+ };
36044
+ } catch {
36045
+ }
36046
+ }
36047
+ if (!blocking) break;
36048
+ await sleep2(pollMs);
36049
+ } while (Date.now() - startedAt < timeoutMs);
36050
+ return deferral(
36051
+ cls,
36052
+ `class '${cls}' is at capacity (${budget} slot(s)); ` + (blocking ? `timed out after ${timeoutMs}ms` : "no slot free"),
36053
+ Math.min(pollMs * 4, DEFAULT_RESOURCE_RETRY_AFTER_MS)
36054
+ );
36055
+ }
36056
+ /**
36057
+ * Route an admission through the supervisor's central `resource_admit` verb.
36058
+ * Returns a grant (whose `release` calls `resource_release`) or a deferral, or
36059
+ * `null` when the supervisor is unreachable so the caller degrades to the
36060
+ * local slot engine. Never throws — a dead arbiter never deadlocks work.
36061
+ *
36062
+ * @task T12001
36063
+ */
36064
+ async acquireViaSupervisor(cls, budget) {
36065
+ const socketPath = resolveSupervisorSocketPath();
36066
+ const holderId = supervisorHolderId(cls);
36067
+ const reply = await sendResourceAdmit(socketPath, cls, holderId, budget);
36068
+ if ("unavailable" in reply) {
36069
+ logSupervisorDegradeOnce(reply.reason);
36070
+ return null;
36071
+ }
36072
+ if (reply.disposition === "deferred") {
36073
+ return deferral(
36074
+ cls,
36075
+ `class '${cls}' deferred by supervisor (budget ${budget})`,
36076
+ reply.retry_after_ms || DEFAULT_RESOURCE_RETRY_AFTER_MS
36077
+ );
36078
+ }
36079
+ let released = false;
36080
+ return {
36081
+ deferred: false,
36082
+ class: cls,
36083
+ slot: 0,
36084
+ acquiredAtMs: Date.now(),
36085
+ release: async () => {
36086
+ if (released) return;
36087
+ released = true;
36088
+ await sendResourceRelease(socketPath, cls, holderId).catch(() => {
36089
+ });
36090
+ }
36091
+ };
36092
+ }
36093
+ /** Non-blocking single-pass acquire (admission semantics). */
36094
+ async tryAcquire(cls, opts = {}) {
36095
+ return this.acquire(cls, { ...opts, blocking: false });
36096
+ }
36097
+ /**
36098
+ * Currently-grantable slot count for `cls` = budget − held. Held is the count
36099
+ * of slot files currently locked. `Infinity` for ungated classes.
36100
+ */
36101
+ async available(cls, opts = {}) {
36102
+ if (resolveGovernorMode() === "off" || cls === "interactive-cli") {
36103
+ return Number.POSITIVE_INFINITY;
36104
+ }
36105
+ const sample = opts.sample ?? await (opts.monitor ?? new ResourceMonitor()).sample();
36106
+ const budget = computeClassBudget(cls, sample, opts);
36107
+ if (!Number.isFinite(budget)) return Number.POSITIVE_INFINITY;
36108
+ if (budget <= 0) return 0;
36109
+ const held = await countHeldSlots(cls, budget);
36110
+ return Math.max(0, budget - held);
36111
+ }
36112
+ };
36113
+ governor = new ResourceGovernor();
36114
+ }
36115
+ });
36116
+
36117
+ // packages/core/src/store/lock.ts
36118
+ import lockfile2 from "proper-lockfile";
35306
36119
  async function acquireLock(filePath, options) {
35307
36120
  try {
35308
- const release = await lockfile.lock(filePath, {
36121
+ const release = await lockfile2.lock(filePath, {
35309
36122
  ...DEFAULT_LOCK_OPTIONS,
35310
36123
  ...options?.stale !== void 0 && { stale: options.stale },
35311
36124
  ...options?.retries !== void 0 && {
@@ -35351,7 +36164,7 @@ var init_lock = __esm({
35351
36164
  });
35352
36165
 
35353
36166
  // packages/core/src/store/atomic.ts
35354
- import { mkdir, readFile as readFile2, rename, unlink } from "node:fs/promises";
36167
+ import { mkdir, readFile as readFile3, rename, unlink } from "node:fs/promises";
35355
36168
  import { dirname as dirname3 } from "node:path";
35356
36169
  import writeFileAtomic from "write-file-atomic";
35357
36170
  async function atomicWrite(filePath, data, options) {
@@ -35367,7 +36180,7 @@ async function atomicWrite(filePath, data, options) {
35367
36180
  }
35368
36181
  async function safeReadFile(filePath) {
35369
36182
  try {
35370
- return await readFile2(filePath, "utf8");
36183
+ return await readFile3(filePath, "utf8");
35371
36184
  } catch (err) {
35372
36185
  if (err instanceof Error && "code" in err && err.code === "ENOENT") {
35373
36186
  return null;
@@ -35388,34 +36201,34 @@ var init_atomic = __esm({
35388
36201
  });
35389
36202
 
35390
36203
  // packages/core/src/store/backup.ts
35391
- import { copyFile, rename as fsRename, mkdir as mkdir2, readdir, stat, unlink as unlink2 } from "node:fs/promises";
35392
- import { basename, join as join5 } from "node:path";
36204
+ import { copyFile, rename as fsRename, mkdir as mkdir2, readdir, stat as stat2, unlink as unlink2 } from "node:fs/promises";
36205
+ import { basename, join as join7 } from "node:path";
35393
36206
  async function createBackup(filePath, backupDir, maxBackups = DEFAULT_MAX_BACKUPS) {
35394
36207
  try {
35395
36208
  await mkdir2(backupDir, { recursive: true });
35396
36209
  const fileName = basename(filePath);
35397
36210
  try {
35398
- await stat(filePath);
36211
+ await stat2(filePath);
35399
36212
  } catch {
35400
36213
  throw new CleoError(3 /* FILE_ERROR */, `Cannot backup: source file not found: ${filePath}`);
35401
36214
  }
35402
36215
  for (let i = maxBackups; i >= 1; i--) {
35403
- const current = join5(backupDir, `${fileName}.${i}`);
36216
+ const current = join7(backupDir, `${fileName}.${i}`);
35404
36217
  if (i === maxBackups) {
35405
36218
  try {
35406
36219
  await unlink2(current);
35407
36220
  } catch {
35408
36221
  }
35409
36222
  } else {
35410
- const next = join5(backupDir, `${fileName}.${i + 1}`);
36223
+ const next = join7(backupDir, `${fileName}.${i + 1}`);
35411
36224
  try {
35412
- await stat(current);
36225
+ await stat2(current);
35413
36226
  await fsRename(current, next);
35414
36227
  } catch {
35415
36228
  }
35416
36229
  }
35417
36230
  }
35418
- const backupPath = join5(backupDir, `${fileName}.1`);
36231
+ const backupPath = join7(backupDir, `${fileName}.1`);
35419
36232
  await copyFile(filePath, backupPath);
35420
36233
  return backupPath;
35421
36234
  } catch (err) {
@@ -35694,8 +36507,8 @@ var init_json2 = __esm({
35694
36507
  });
35695
36508
 
35696
36509
  // packages/core/src/scaffold/ensure-config.ts
35697
- import { existsSync as existsSync3, readFileSync } from "node:fs";
35698
- import { basename as basename2, dirname as dirname4, join as join6, resolve as resolve2 } from "node:path";
36510
+ import { existsSync as existsSync4, readFileSync } from "node:fs";
36511
+ import { basename as basename2, dirname as dirname4, join as join8, resolve as resolve2 } from "node:path";
35699
36512
  import { fileURLToPath as fileURLToPath2 } from "node:url";
35700
36513
  function getPackageRoot() {
35701
36514
  const thisFile = fileURLToPath2(import.meta.url);
@@ -35703,7 +36516,7 @@ function getPackageRoot() {
35703
36516
  }
35704
36517
  function getCleoVersion() {
35705
36518
  try {
35706
- const pkgPath = join6(getPackageRoot(), "package.json");
36519
+ const pkgPath = join8(getPackageRoot(), "package.json");
35707
36520
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
35708
36521
  return pkg.version ?? "0.0.0";
35709
36522
  } catch {
@@ -35722,25 +36535,25 @@ var init_ensure_config = __esm({
35722
36535
  // packages/core/src/store/exodus/archive.ts
35723
36536
  import {
35724
36537
  copyFileSync as copyFileSync2,
35725
- existsSync as existsSync4,
35726
- mkdirSync,
36538
+ existsSync as existsSync5,
36539
+ mkdirSync as mkdirSync2,
35727
36540
  renameSync,
35728
36541
  unlinkSync,
35729
- writeFileSync
36542
+ writeFileSync as writeFileSync2
35730
36543
  } from "node:fs";
35731
- import { basename as basename3, join as join7 } from "node:path";
36544
+ import { basename as basename3, join as join9 } from "node:path";
35732
36545
  function scopeBaseDir(scope, cwd) {
35733
36546
  return scope === "project" ? resolveCleoDir(cwd) : getCleoHome();
35734
36547
  }
35735
36548
  function exodusArchiveDir(scope, cwd) {
35736
- return join7(scopeBaseDir(scope, cwd), ARCHIVE_DIR_NAME);
36549
+ return join9(scopeBaseDir(scope, cwd), ARCHIVE_DIR_NAME);
35737
36550
  }
35738
36551
  function exodusMarkerPath(scope, cwd) {
35739
- return join7(scopeBaseDir(scope, cwd), MARKER_FILENAME_BY_SCOPE[scope]);
36552
+ return join9(scopeBaseDir(scope, cwd), MARKER_FILENAME_BY_SCOPE[scope]);
35740
36553
  }
35741
36554
  function hasExodusCompleteMarker(scope, cwd) {
35742
36555
  try {
35743
- return existsSync4(exodusMarkerPath(scope, cwd));
36556
+ return existsSync5(exodusMarkerPath(scope, cwd));
35744
36557
  } catch {
35745
36558
  return false;
35746
36559
  }
@@ -35748,7 +36561,7 @@ function hasExodusCompleteMarker(scope, cwd) {
35748
36561
  function writeExodusCompleteMarker(scope, archivedSources, cwd) {
35749
36562
  const markerPath = exodusMarkerPath(scope, cwd);
35750
36563
  const baseDir = scopeBaseDir(scope, cwd);
35751
- mkdirSync(baseDir, { recursive: true });
36564
+ mkdirSync2(baseDir, { recursive: true });
35752
36565
  const marker = {
35753
36566
  version: 1,
35754
36567
  scope,
@@ -35757,17 +36570,17 @@ function writeExodusCompleteMarker(scope, archivedSources, cwd) {
35757
36570
  archivedSources: [...archivedSources]
35758
36571
  };
35759
36572
  const tmpPath = `${markerPath}.tmp`;
35760
- writeFileSync(tmpPath, JSON.stringify(marker, null, 2) + "\n", "utf8");
36573
+ writeFileSync2(tmpPath, JSON.stringify(marker, null, 2) + "\n", "utf8");
35761
36574
  renameSync(tmpPath, markerPath);
35762
- log2.info({ scope, markerPath, archivedSources }, "exodus: wrote completion marker");
36575
+ log3.info({ scope, markerPath, archivedSources }, "exodus: wrote completion marker");
35763
36576
  return markerPath;
35764
36577
  }
35765
36578
  function moveFileInto(srcPath, destDir) {
35766
- mkdirSync(destDir, { recursive: true });
35767
- let dest = join7(destDir, basename3(srcPath));
35768
- if (existsSync4(dest)) {
36579
+ mkdirSync2(destDir, { recursive: true });
36580
+ let dest = join9(destDir, basename3(srcPath));
36581
+ if (existsSync5(dest)) {
35769
36582
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
35770
- dest = join7(destDir, `${basename3(srcPath)}.${stamp}`);
36583
+ dest = join9(destDir, `${basename3(srcPath)}.${stamp}`);
35771
36584
  }
35772
36585
  try {
35773
36586
  renameSync(srcPath, dest);
@@ -35778,25 +36591,25 @@ function moveFileInto(srcPath, destDir) {
35778
36591
  return dest;
35779
36592
  }
35780
36593
  function archiveSourceDb(source, cwd) {
35781
- if (!existsSync4(source.path)) {
36594
+ if (!existsSync5(source.path)) {
35782
36595
  return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
35783
36596
  }
35784
36597
  const destDir = exodusArchiveDir(source.targetScope, cwd);
35785
36598
  const archivedTo = moveFileInto(source.path, destDir);
35786
36599
  for (const suffix of SIDECAR_SUFFIXES) {
35787
36600
  const sidecar = `${source.path}${suffix}`;
35788
- if (existsSync4(sidecar)) {
36601
+ if (existsSync5(sidecar)) {
35789
36602
  try {
35790
36603
  moveFileInto(sidecar, destDir);
35791
36604
  } catch (err) {
35792
- log2.warn(
36605
+ log3.warn(
35793
36606
  { err, sidecar, sourceName: source.name },
35794
36607
  "exodus-archive: failed to archive sidecar (non-fatal)"
35795
36608
  );
35796
36609
  }
35797
36610
  }
35798
36611
  }
35799
- log2.info(
36612
+ log3.info(
35800
36613
  { sourceName: source.name, sourcePath: source.path, archivedTo, scope: source.targetScope },
35801
36614
  "exodus-archive: archived legacy source DB"
35802
36615
  );
@@ -35831,7 +36644,7 @@ function detectStrandedResidue(sources, cwd) {
35831
36644
  const stranded = [];
35832
36645
  for (const source of sources) {
35833
36646
  if (!markedScopes.has(source.targetScope)) continue;
35834
- if (existsSync4(source.path)) {
36647
+ if (existsSync5(source.path)) {
35835
36648
  stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
35836
36649
  }
35837
36650
  }
@@ -35847,14 +36660,14 @@ function archiveStrandedResidue(stranded, sources, cwd) {
35847
36660
  }
35848
36661
  return results;
35849
36662
  }
35850
- var log2, ARCHIVE_DIR_NAME, MARKER_FILENAME_BY_SCOPE, SIDECAR_SUFFIXES;
36663
+ var log3, ARCHIVE_DIR_NAME, MARKER_FILENAME_BY_SCOPE, SIDECAR_SUFFIXES;
35851
36664
  var init_archive2 = __esm({
35852
36665
  "packages/core/src/store/exodus/archive.ts"() {
35853
36666
  "use strict";
35854
36667
  init_logger2();
35855
36668
  init_paths();
35856
36669
  init_ensure_config();
35857
- log2 = getLogger("exodus-archive");
36670
+ log3 = getLogger("exodus-archive");
35858
36671
  ARCHIVE_DIR_NAME = "_archive";
35859
36672
  MARKER_FILENAME_BY_SCOPE = {
35860
36673
  project: "exodus-complete",
@@ -35865,13 +36678,13 @@ var init_archive2 = __esm({
35865
36678
  });
35866
36679
 
35867
36680
  // packages/core/src/project-info.ts
35868
- import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
35869
- import { join as join8 } from "node:path";
36681
+ import { existsSync as existsSync6, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
36682
+ import { join as join10 } from "node:path";
35870
36683
  function getProjectInfoSync(cwd) {
35871
36684
  const projectRoot = resolveOrCwd(cwd);
35872
36685
  const cleoDir = getCleoDirAbsolute(projectRoot);
35873
- const infoPath = join8(cleoDir, "project-info.json");
35874
- if (!existsSync5(infoPath)) return null;
36686
+ const infoPath = join10(cleoDir, "project-info.json");
36687
+ if (!existsSync6(infoPath)) return null;
35875
36688
  try {
35876
36689
  const raw = readFileSync2(infoPath, "utf-8");
35877
36690
  const data = JSON.parse(raw);
@@ -35898,8 +36711,8 @@ var init_project_info = __esm({
35898
36711
  });
35899
36712
 
35900
36713
  // packages/core/src/store/worktree-isolation-guard.ts
35901
- import { existsSync as existsSync6, statSync } from "node:fs";
35902
- import { dirname as dirname5, join as join9 } from "node:path";
36714
+ import { existsSync as existsSync7, statSync } from "node:fs";
36715
+ import { dirname as dirname5, join as join11 } from "node:path";
35903
36716
  function assertDbPathIsNotWorktreeResident(role, cwd) {
35904
36717
  let cleoDir;
35905
36718
  try {
@@ -35908,10 +36721,10 @@ function assertDbPathIsNotWorktreeResident(role, cwd) {
35908
36721
  return;
35909
36722
  }
35910
36723
  const projectRoot = dirname5(cleoDir);
35911
- const projectGit = join9(projectRoot, ".git");
36724
+ const projectGit = join11(projectRoot, ".git");
35912
36725
  let isWorktreeGitlink = false;
35913
36726
  try {
35914
- isWorktreeGitlink = existsSync6(projectGit) && statSync(projectGit).isFile();
36727
+ isWorktreeGitlink = existsSync7(projectGit) && statSync(projectGit).isFile();
35915
36728
  } catch {
35916
36729
  }
35917
36730
  if (!isWorktreeGitlink) {
@@ -36376,7 +37189,7 @@ var init_table_name_map = __esm({
36376
37189
  });
36377
37190
 
36378
37191
  // packages/core/src/store/exodus/count-parity.ts
36379
- import { existsSync as existsSync7 } from "node:fs";
37192
+ import { existsSync as existsSync8 } from "node:fs";
36380
37193
  function listTables(db) {
36381
37194
  return db.prepare(
36382
37195
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
@@ -36397,14 +37210,14 @@ function rowCount(db, tableName) {
36397
37210
  function computeCountParity(sources, projectDbPath, globalDbPath) {
36398
37211
  const entries = [];
36399
37212
  let skipped = 0;
36400
- if (!existsSync7(projectDbPath) || !existsSync7(globalDbPath)) {
37213
+ if (!existsSync8(projectDbPath) || !existsSync8(globalDbPath)) {
36401
37214
  return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
36402
37215
  }
36403
37216
  const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
36404
37217
  const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
36405
37218
  try {
36406
37219
  for (const src of sources) {
36407
- if (!existsSync7(src.path)) continue;
37220
+ if (!existsSync8(src.path)) continue;
36408
37221
  const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
36409
37222
  try {
36410
37223
  for (const legacyTable of listTables(srcSnap.db)) {
@@ -36443,27 +37256,27 @@ function computeCountParity(sources, projectDbPath, globalDbPath) {
36443
37256
  }
36444
37257
  const deficits = entries.filter((e) => e.deficit > 0);
36445
37258
  if (deficits.length > 0) {
36446
- log3.warn(
37259
+ log4.warn(
36447
37260
  { deficitCount: deficits.length, sample: deficits.slice(0, 5) },
36448
37261
  `exodus count-parity: ${deficits.length} table(s) have FEWER rows in the consolidated target than the legacy source`
36449
37262
  );
36450
37263
  }
36451
37264
  return { ok: deficits.length === 0, entries, deficits, checked: entries.length, skipped };
36452
37265
  }
36453
- var log3;
37266
+ var log4;
36454
37267
  var init_count_parity = __esm({
36455
37268
  "packages/core/src/store/exodus/count-parity.ts"() {
36456
37269
  "use strict";
36457
37270
  init_logger2();
36458
37271
  init_open_cleo_db();
36459
37272
  init_table_name_map();
36460
- log3 = getLogger("exodus-count-parity");
37273
+ log4 = getLogger("exodus-count-parity");
36461
37274
  }
36462
37275
  });
36463
37276
 
36464
37277
  // packages/core/src/store/exodus/plan.ts
36465
- import { existsSync as existsSync8, readdirSync as readdirSync2, statfsSync, statSync as statSync2 } from "node:fs";
36466
- import { join as join10 } from "node:path";
37278
+ import { existsSync as existsSync9, readdirSync as readdirSync3, statfsSync, statSync as statSync2 } from "node:fs";
37279
+ import { join as join12 } from "node:path";
36467
37280
  function computeRequiredBytes(totalSourceBytes, largestSourceBytes) {
36468
37281
  return Math.ceil(STAGING_HEADROOM_FACTOR * largestSourceBytes) + totalSourceBytes;
36469
37282
  }
@@ -36474,33 +37287,33 @@ function buildSourceDescriptors(cwd) {
36474
37287
  // Project-tier — go into consolidated project-scope cleo.db
36475
37288
  {
36476
37289
  name: "tasks",
36477
- path: join10(cleoDir, "tasks.db"),
37290
+ path: join12(cleoDir, "tasks.db"),
36478
37291
  targetScope: "project"
36479
37292
  },
36480
37293
  {
36481
37294
  name: "brain (project)",
36482
- path: join10(cleoDir, "brain.db"),
37295
+ path: join12(cleoDir, "brain.db"),
36483
37296
  targetScope: "project"
36484
37297
  },
36485
37298
  {
36486
37299
  name: "conduit",
36487
- path: join10(cleoDir, "conduit.db"),
37300
+ path: join12(cleoDir, "conduit.db"),
36488
37301
  targetScope: "project"
36489
37302
  },
36490
37303
  // Global-tier — go into consolidated global-scope cleo.db
36491
37304
  {
36492
37305
  name: "nexus",
36493
- path: join10(cleoHome, "nexus.db"),
37306
+ path: join12(cleoHome, "nexus.db"),
36494
37307
  targetScope: "global"
36495
37308
  },
36496
37309
  {
36497
37310
  name: "signaldock",
36498
- path: join10(cleoHome, "signaldock.db"),
37311
+ path: join12(cleoHome, "signaldock.db"),
36499
37312
  targetScope: "global"
36500
37313
  },
36501
37314
  {
36502
37315
  name: "skills",
36503
- path: join10(cleoHome, "skills.db"),
37316
+ path: join12(cleoHome, "skills.db"),
36504
37317
  targetScope: "global"
36505
37318
  }
36506
37319
  ];
@@ -36526,10 +37339,10 @@ function deriveStagingDirName() {
36526
37339
  }
36527
37340
  function findExistingStaging(cleoDir) {
36528
37341
  try {
36529
- const entries = readdirSync2(cleoDir, { withFileTypes: true });
37342
+ const entries = readdirSync3(cleoDir, { withFileTypes: true });
36530
37343
  const stagingDirs = entries.filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => e.name).sort().reverse();
36531
37344
  if (stagingDirs.length > 0) {
36532
- return join10(cleoDir, stagingDirs[0]);
37345
+ return join12(cleoDir, stagingDirs[0]);
36533
37346
  }
36534
37347
  } catch {
36535
37348
  }
@@ -36545,7 +37358,7 @@ function buildExodusPlan(cwd) {
36545
37358
  const availableBytes = getAvailableBytes(cleoDir);
36546
37359
  const diskPreflight = totalSourceBytes === 0 || availableBytes >= requiredBytes;
36547
37360
  const existingStaging = findExistingStaging(cleoDir);
36548
- const stagingDir = existingStaging ?? join10(cleoDir, deriveStagingDirName());
37361
+ const stagingDir = existingStaging ?? join12(cleoDir, deriveStagingDirName());
36549
37362
  const resumeFromStaging = existingStaging !== null;
36550
37363
  const projectDbPath = resolveDualScopeDbPath("project", cwd);
36551
37364
  const globalDbPath = resolveDualScopeDbPath("global");
@@ -36564,7 +37377,7 @@ function buildExodusPlan(cwd) {
36564
37377
  };
36565
37378
  }
36566
37379
  function sourcesPresent(sources) {
36567
- return sources.some((s) => existsSync8(s.path));
37380
+ return sources.some((s) => existsSync9(s.path));
36568
37381
  }
36569
37382
  var STAGING_HEADROOM_FACTOR, STAGING_COPY_SKIP_THRESHOLD_BYTES;
36570
37383
  var init_plan2 = __esm({
@@ -36578,18 +37391,18 @@ var init_plan2 = __esm({
36578
37391
  });
36579
37392
 
36580
37393
  // packages/core/src/store/exodus/health.ts
36581
- import { existsSync as existsSync9, statSync as statSync3 } from "node:fs";
37394
+ import { existsSync as existsSync10, statSync as statSync3 } from "node:fs";
36582
37395
  function buildExodusHealth(cwd) {
36583
37396
  const plan = buildExodusPlan(cwd);
36584
- const anyLegacyPresent = plan.sources.some((s) => existsSync9(s.path));
37397
+ const anyLegacyPresent = plan.sources.some((s) => existsSync10(s.path));
36585
37398
  const parity = anyLegacyPresent ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath) : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
36586
37399
  const consolidatedExistsByScope = {
36587
- project: existsSync9(plan.projectDbPath),
36588
- global: existsSync9(plan.globalDbPath)
37400
+ project: existsSync10(plan.projectDbPath),
37401
+ global: existsSync10(plan.globalDbPath)
36589
37402
  };
36590
37403
  const buildScope = (scope) => {
36591
37404
  const sources = plan.sources.filter((s) => s.targetScope === scope).map((s) => {
36592
- const present = existsSync9(s.path);
37405
+ const present = existsSync10(s.path);
36593
37406
  let bytes = 0;
36594
37407
  if (present) {
36595
37408
  try {
@@ -36856,15 +37669,15 @@ var init_types = __esm({
36856
37669
  // packages/core/src/store/exodus/migrate.ts
36857
37670
  import {
36858
37671
  copyFileSync as copyFileSync3,
36859
- existsSync as existsSync10,
36860
- mkdirSync as mkdirSync2,
37672
+ existsSync as existsSync11,
37673
+ mkdirSync as mkdirSync3,
36861
37674
  readFileSync as readFileSync3,
36862
37675
  renameSync as renameSync2,
36863
37676
  statSync as statSync4,
36864
37677
  unlinkSync as unlinkSync2,
36865
- writeFileSync as writeFileSync3
37678
+ writeFileSync as writeFileSync4
36866
37679
  } from "node:fs";
36867
- import { join as join11 } from "node:path";
37680
+ import { join as join13 } from "node:path";
36868
37681
  function getSqliteVersion(db) {
36869
37682
  try {
36870
37683
  const row = db.prepare("SELECT sqlite_version() AS v").get();
@@ -36880,14 +37693,14 @@ function listTables2(db) {
36880
37693
  return rows.map((r) => r.name);
36881
37694
  }
36882
37695
  function writeJournal(stagingDir, journal) {
36883
- const journalPath = join11(stagingDir, JOURNAL_FILENAME);
37696
+ const journalPath = join13(stagingDir, JOURNAL_FILENAME);
36884
37697
  const tmpPath = `${journalPath}.tmp`;
36885
- writeFileSync3(tmpPath, JSON.stringify(journal, null, 2) + "\n", "utf8");
37698
+ writeFileSync4(tmpPath, JSON.stringify(journal, null, 2) + "\n", "utf8");
36886
37699
  renameSync2(tmpPath, journalPath);
36887
37700
  }
36888
37701
  function readJournal(stagingDir) {
36889
- const journalPath = join11(stagingDir, JOURNAL_FILENAME);
36890
- if (!existsSync10(journalPath)) return null;
37702
+ const journalPath = join13(stagingDir, JOURNAL_FILENAME);
37703
+ if (!existsSync11(journalPath)) return null;
36891
37704
  try {
36892
37705
  return JSON.parse(readFileSync3(journalPath, "utf8"));
36893
37706
  } catch {
@@ -36895,17 +37708,17 @@ function readJournal(stagingDir) {
36895
37708
  }
36896
37709
  }
36897
37710
  function clearExodusJournal(stagingDir) {
36898
- const journalPath = join11(stagingDir, JOURNAL_FILENAME);
37711
+ const journalPath = join13(stagingDir, JOURNAL_FILENAME);
36899
37712
  try {
36900
- if (!existsSync10(journalPath)) return false;
37713
+ if (!existsSync11(journalPath)) return false;
36901
37714
  unlinkSync2(journalPath);
36902
- log4.info(
37715
+ log5.info(
36903
37716
  { stagingDir },
36904
37717
  "exodus: cleared migrate journal after abort/rollback \u2014 a retry will RE-COPY all tables"
36905
37718
  );
36906
37719
  return true;
36907
37720
  } catch (err) {
36908
- log4.warn(
37721
+ log5.warn(
36909
37722
  { err, stagingDir },
36910
37723
  'exodus: failed to clear migrate journal after rollback (a retry may skip already-"done" tables)'
36911
37724
  );
@@ -36930,7 +37743,7 @@ function lockPath(dbPath) {
36930
37743
  }
36931
37744
  function acquireAdvisoryLock(dbPath) {
36932
37745
  const lp = lockPath(dbPath);
36933
- writeFileSync3(lp, JSON.stringify({ pid: process.pid, ts: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
37746
+ writeFileSync4(lp, JSON.stringify({ pid: process.pid, ts: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
36934
37747
  }
36935
37748
  function releaseAdvisoryLock(dbPath) {
36936
37749
  try {
@@ -36993,7 +37806,7 @@ function buildSelectExpr(attachAlias, legacyTable, targetTableName, col, srcType
36993
37806
  function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyTableName, sourceName, targetSchema = "main") {
36994
37807
  const resolution = resolveConsolidatedTableName(sourceName, legacyTableName);
36995
37808
  if (resolution.kind === "skip") {
36996
- log4.warn(
37809
+ log5.warn(
36997
37810
  { legacyTableName, sourceName, reason: resolution.reason },
36998
37811
  `Exodus: explicitly skipping table \u2014 ${resolution.reason}`
36999
37812
  );
@@ -37012,7 +37825,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37012
37825
  ).get();
37013
37826
  if (!existsRow) {
37014
37827
  const reason = `consolidated target '${targetTableName}' not found (mapped from legacy '${legacyTableName}')`;
37015
- log4.warn(
37828
+ log5.warn(
37016
37829
  { legacyTableName, targetTableName, sourceName, attachAlias, targetSchema },
37017
37830
  `Exodus: ${reason}`
37018
37831
  );
@@ -37023,13 +37836,13 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37023
37836
  const sharedColumns = srcPragma.map((r) => r.name).filter((col) => tgtColMap.has(col));
37024
37837
  if (sharedColumns.length === 0) {
37025
37838
  const reason = `no overlapping columns between source '${legacyTableName}' and target '${targetTableName}'`;
37026
- log4.warn({ legacyTableName, targetTableName, sourceName }, `Exodus: ${reason}`);
37839
+ log5.warn({ legacyTableName, targetTableName, sourceName }, `Exodus: ${reason}`);
37027
37840
  return { rowsCopied: 0, skipped: true, reason };
37028
37841
  }
37029
37842
  const srcOnlyColumns = srcPragma.map((r) => r.name).filter((c) => !tgtColMap.has(c));
37030
37843
  const tgtOnlyColumns = tgtPragma.map((r) => r.name).filter((c) => !srcColumns.has(c));
37031
37844
  if (srcOnlyColumns.length > 0 || tgtOnlyColumns.length > 0) {
37032
- log4.info(
37845
+ log5.info(
37033
37846
  { legacyTableName, targetTableName, sourceName, srcOnlyColumns, tgtOnlyColumns },
37034
37847
  "Exodus: column drift detected \u2014 copying intersection, dropping src-only cols, using defaults for tgt-only cols"
37035
37848
  );
@@ -37044,7 +37857,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37044
37857
  return isoGlobCols.has(col) && (upper.includes("INT") || upper === "" || upper === "NUMERIC");
37045
37858
  });
37046
37859
  if (coercedCols.length > 0) {
37047
- log4.info(
37860
+ log5.info(
37048
37861
  {
37049
37862
  legacyTableName,
37050
37863
  targetTableName,
@@ -37060,7 +37873,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37060
37873
  (col) => ENUM_NORMALIZATIONS.has(`${targetTableName}.${col}`)
37061
37874
  );
37062
37875
  if (normalizedCols.length > 0) {
37063
- log4.info(
37876
+ log5.info(
37064
37877
  { legacyTableName, targetTableName, sourceName, normalizedCols },
37065
37878
  `Exodus: applying enum-value normalization for ${normalizedCols.length} column(s) (T11547)`
37066
37879
  );
@@ -37069,7 +37882,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37069
37882
  (col) => NUMERIC_CLAMPS.has(`${targetTableName}.${col}`)
37070
37883
  );
37071
37884
  if (clampedCols.length > 0) {
37072
- log4.info(
37885
+ log5.info(
37073
37886
  { legacyTableName, targetTableName, sourceName, clampedCols },
37074
37887
  `Exodus: applying non-finite numeric clamp for ${clampedCols.length} column(s) (T11782)`
37075
37888
  );
@@ -37111,7 +37924,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37111
37924
  if (rowsCopied < sourceCount) {
37112
37925
  const presentAccountedFor = existingBefore + rowsCopied;
37113
37926
  if (presentAccountedFor >= sourceCount) {
37114
- log4.info(
37927
+ log5.info(
37115
37928
  { legacyTableName, targetTableName, sourceName, sourceCount, rowsCopied, existingBefore },
37116
37929
  `Exodus: '${legacyTableName}'\u2192'${targetTableName}' \u2014 ${sourceCount - rowsCopied} of ${sourceCount} row(s) already present in target (idempotent PK dedup), ${rowsCopied} newly copied; no loss`
37117
37930
  );
@@ -37119,7 +37932,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
37119
37932
  }
37120
37933
  const missing = sourceCount - presentAccountedFor;
37121
37934
  const reason = `INSERT OR IGNORE lost ${missing} of ${sourceCount} rows from '${legacyTableName}'\u2192'${targetTableName}' (rowsCopied=${rowsCopied}, existingBefore=${existingBefore}) \u2014 a CHECK/NOT NULL/type/enum constraint rejected them (NOT PK dedup); inspect epoch coercion + enum normalization. verify will confirm.`;
37122
- log4.error(
37935
+ log5.error(
37123
37936
  {
37124
37937
  legacyTableName,
37125
37938
  targetTableName,
@@ -37139,10 +37952,10 @@ function checkSchemaVersion(journal, forceCrossVersion) {
37139
37952
  if (journal.targetSchemaVersion !== EXODUS_TARGET_SCHEMA_VERSION) {
37140
37953
  const msg = `Schema version mismatch: journal=${journal.targetSchemaVersion}, expected=${EXODUS_TARGET_SCHEMA_VERSION}`;
37141
37954
  if (forceCrossVersion) {
37142
- log4.warn(msg + " (--force-cross-version: continuing anyway)");
37955
+ log5.warn(msg + " (--force-cross-version: continuing anyway)");
37143
37956
  return true;
37144
37957
  }
37145
- log4.error(msg + " \u2014 pass --force-cross-version to override");
37958
+ log5.error(msg + " \u2014 pass --force-cross-version to override");
37146
37959
  return false;
37147
37960
  }
37148
37961
  return true;
@@ -37159,10 +37972,10 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
37159
37972
  error: `Insufficient disk space for exodus: need \u2265${plan.requiredBytes} bytes (\u2248${STAGING_HEADROOM_FACTOR}\xD7 largest source ${plan.largestSourceBytes} + consolidated estimate ${plan.totalSourceBytes}), but only ${plan.availableBytes} bytes are free on the target filesystem \u2014 ${shortfall} bytes short. Free up at least ${shortfall} bytes (e.g. \`cleo backup prune\`, clear caches), or move the .cleo/ directory to a larger volume, then retry.`
37160
37973
  };
37161
37974
  }
37162
- mkdirSync2(stagingDir, { recursive: true });
37975
+ mkdirSync3(stagingDir, { recursive: true });
37163
37976
  let sqliteVersion = "unknown";
37164
37977
  for (const src of sources) {
37165
- if (existsSync10(src.path)) {
37978
+ if (existsSync11(src.path)) {
37166
37979
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
37167
37980
  sqliteVersion = getSqliteVersion(snap.db);
37168
37981
  snap.close();
@@ -37203,15 +38016,15 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
37203
38016
  };
37204
38017
  var extractNativeDb = extractNativeDb2;
37205
38018
  for (const src of sources) {
37206
- if (!existsSync10(src.path)) continue;
37207
- const backupDest = join11(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
38019
+ if (!existsSync11(src.path)) continue;
38020
+ const backupDest = join13(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
37208
38021
  const srcBytes = safeStatBytes(src.path);
37209
38022
  const skipStagingCopy = srcBytes > plan.stagingCopyThresholdBytes;
37210
38023
  if (skipStagingCopy) {
37211
38024
  onProgress?.(
37212
38025
  `Skipping full staging copy of ${src.name} (${srcBytes} bytes > ${plan.stagingCopyThresholdBytes} threshold) \u2014 source is archived, not deleted, on success.`
37213
38026
  );
37214
- } else if (!existsSync10(backupDest)) {
38027
+ } else if (!existsSync11(backupDest)) {
37215
38028
  onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
37216
38029
  copyFileSync3(src.path, backupDest);
37217
38030
  backupPaths.push(backupDest);
@@ -37229,8 +38042,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
37229
38042
  });
37230
38043
  const projectNative = extractNativeDb2(projectHandle);
37231
38044
  const globalNative = extractNativeDb2(globalHandle);
37232
- const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync10(s.path));
37233
- const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync10(s.path));
38045
+ const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync11(s.path));
38046
+ const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync11(s.path));
37234
38047
  await migrateScope(
37235
38048
  "project",
37236
38049
  projectSources,
@@ -37255,7 +38068,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
37255
38068
  return { ok: true, tables: allTableResults, stagingDir, backupPaths };
37256
38069
  } catch (err) {
37257
38070
  const error = err instanceof Error ? err.message : String(err);
37258
- log4.error({ err }, "Exodus migration failed");
38071
+ log5.error({ err }, "Exodus migration failed");
37259
38072
  return { ok: false, tables: allTableResults, stagingDir, backupPaths, error };
37260
38073
  } finally {
37261
38074
  try {
@@ -37275,7 +38088,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
37275
38088
  if (sources.length === 0) return;
37276
38089
  onProgress?.(`Migrating ${scope}-scope sources\u2026`);
37277
38090
  targetNativeDb.exec("PRAGMA foreign_keys = OFF");
37278
- log4.info({ scope }, "Exodus: foreign_keys=OFF for bulk copy (T11533 FK-defer)");
38091
+ log5.info({ scope }, "Exodus: foreign_keys=OFF for bulk copy (T11533 FK-defer)");
37279
38092
  try {
37280
38093
  for (let i = 0; i < sources.length; i++) {
37281
38094
  const src = sources[i];
@@ -37342,7 +38155,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
37342
38155
  }
37343
38156
  } catch (err) {
37344
38157
  const msg = err instanceof Error ? err.message : String(err);
37345
- log4.warn({ tableName, sourceDb: src.name, err }, "Table copy failed \u2014 skipping");
38158
+ log5.warn({ tableName, sourceDb: src.name, err }, "Table copy failed \u2014 skipping");
37346
38159
  status = "skipped";
37347
38160
  errorMsg = msg;
37348
38161
  skipped = true;
@@ -37390,7 +38203,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
37390
38203
  targetNativeDb.exec(`DETACH DATABASE "${attachAlias}"`);
37391
38204
  onProgress?.(` [${src.name}] Detached "${attachAlias}"`);
37392
38205
  } catch (detachErr) {
37393
- log4.warn(
38206
+ log5.warn(
37394
38207
  { attachAlias, sourceDb: src.name, err: detachErr },
37395
38208
  "DETACH failed \u2014 alias will be released on DB close"
37396
38209
  );
@@ -37400,7 +38213,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
37400
38213
  targetNativeDb.exec(`DETACH DATABASE "${crossAlias}"`);
37401
38214
  onProgress?.(` [${src.name}] Cross-scope target detached "${crossAlias}"`);
37402
38215
  } catch (detachErr) {
37403
- log4.warn(
38216
+ log5.warn(
37404
38217
  { crossAlias, sourceDb: src.name, err: detachErr },
37405
38218
  "Cross-scope DETACH failed \u2014 alias will be released on DB close"
37406
38219
  );
@@ -37412,28 +38225,28 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
37412
38225
  try {
37413
38226
  const orphans = targetNativeDb.prepare("PRAGMA foreign_key_check").all();
37414
38227
  if (orphans.length > 0) {
37415
- log4.warn(
38228
+ log5.warn(
37416
38229
  { scope, orphanCount: orphans.length, sample: orphans.slice(0, 5) },
37417
38230
  `Exodus: PRAGMA foreign_key_check found ${orphans.length} orphan row(s) after bulk copy \u2014 these are genuine data orphans (not ordering artifacts)`
37418
38231
  );
37419
38232
  } else {
37420
- log4.info({ scope }, "Exodus: PRAGMA foreign_key_check PASSED \u2014 no orphan rows");
38233
+ log5.info({ scope }, "Exodus: PRAGMA foreign_key_check PASSED \u2014 no orphan rows");
37421
38234
  }
37422
38235
  } catch (checkErr) {
37423
- log4.warn(
38236
+ log5.warn(
37424
38237
  { scope, err: checkErr },
37425
38238
  "Exodus: PRAGMA foreign_key_check failed (non-fatal) \u2014 target schema may not have FK constraints enabled"
37426
38239
  );
37427
38240
  }
37428
38241
  try {
37429
38242
  targetNativeDb.exec("PRAGMA foreign_keys = ON");
37430
- log4.info({ scope }, "Exodus: foreign_keys=ON restored after bulk copy");
38243
+ log5.info({ scope }, "Exodus: foreign_keys=ON restored after bulk copy");
37431
38244
  } catch (fkErr) {
37432
- log4.warn({ scope, err: fkErr }, "Exodus: could not restore foreign_keys=ON (non-fatal)");
38245
+ log5.warn({ scope, err: fkErr }, "Exodus: could not restore foreign_keys=ON (non-fatal)");
37433
38246
  }
37434
38247
  }
37435
38248
  }
37436
- var log4, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, SOURCE_EPOCH_UNITS;
38249
+ var log5, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, SOURCE_EPOCH_UNITS;
37437
38250
  var init_migrate = __esm({
37438
38251
  "packages/core/src/store/exodus/migrate.ts"() {
37439
38252
  "use strict";
@@ -37445,7 +38258,7 @@ var init_migrate = __esm({
37445
38258
  init_plan2();
37446
38259
  init_table_name_map();
37447
38260
  init_types();
37448
- log4 = getLogger("exodus-migrate");
38261
+ log5 = getLogger("exodus-migrate");
37449
38262
  LOCK_SENTINEL_SUFFIX = ".exodus-lock";
37450
38263
  JOURNAL_FILENAME = "exodus-journal.json";
37451
38264
  SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
@@ -37469,7 +38282,7 @@ function sealExodus(plan, scopeArg, cwd) {
37469
38282
  const parity = computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath);
37470
38283
  if (!parity.ok) {
37471
38284
  const refusedReason = `Refusing to seal: ${parity.deficits.length} table(s) have FEWER rows in the consolidated cleo.db than the legacy source \u2014 the data is NOT fully migrated. Run \`cleo exodus migrate\` first. Deficits: ${parity.deficits.map((d) => `${d.targetTable}(${d.sourceCount}\u2192${d.targetCount})`).join(", ")}`;
37472
- log5.error({ deficits: parity.deficits.length }, `exodus seal refused \u2014 ${refusedReason}`);
38285
+ log6.error({ deficits: parity.deficits.length }, `exodus seal refused \u2014 ${refusedReason}`);
37473
38286
  return { ok: false, refusedReason, parity, scopes: [] };
37474
38287
  }
37475
38288
  const outcomes = [];
@@ -37485,7 +38298,7 @@ function sealExodus(plan, scopeArg, cwd) {
37485
38298
  scopeSources.map((s) => s.name),
37486
38299
  cwd
37487
38300
  );
37488
- log5.info(
38301
+ log6.info(
37489
38302
  { scope, alreadySealed, archived: archived.filter((a) => a.action === "archived").length },
37490
38303
  `exodus seal: scope '${scope}' certified (count-parity verified, ${parity.checked} tables)`
37491
38304
  );
@@ -37493,23 +38306,23 @@ function sealExodus(plan, scopeArg, cwd) {
37493
38306
  }
37494
38307
  return { ok: true, parity, scopes: outcomes };
37495
38308
  }
37496
- var log5;
38309
+ var log6;
37497
38310
  var init_seal = __esm({
37498
38311
  "packages/core/src/store/exodus/seal.ts"() {
37499
38312
  "use strict";
37500
38313
  init_logger2();
37501
38314
  init_archive2();
37502
38315
  init_count_parity();
37503
- log5 = getLogger("exodus-seal");
38316
+ log6 = getLogger("exodus-seal");
37504
38317
  }
37505
38318
  });
37506
38319
 
37507
38320
  // packages/core/src/store/exodus/status.ts
37508
- import { existsSync as existsSync11, readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync5 } from "node:fs";
37509
- import { join as join12 } from "node:path";
38321
+ import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync5 } from "node:fs";
38322
+ import { join as join14 } from "node:path";
37510
38323
  function readJournal2(stagingDir) {
37511
- const p = join12(stagingDir, JOURNAL_FILENAME2);
37512
- if (!existsSync11(p)) return null;
38324
+ const p = join14(stagingDir, JOURNAL_FILENAME2);
38325
+ if (!existsSync12(p)) return null;
37513
38326
  try {
37514
38327
  return JSON.parse(readFileSync4(p, "utf8"));
37515
38328
  } catch {
@@ -37518,7 +38331,7 @@ function readJournal2(stagingDir) {
37518
38331
  }
37519
38332
  function findStagingDirs(cleoDir) {
37520
38333
  try {
37521
- return readdirSync3(cleoDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => join12(cleoDir, e.name)).sort().reverse();
38334
+ return readdirSync4(cleoDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => join14(cleoDir, e.name)).sort().reverse();
37522
38335
  } catch {
37523
38336
  return [];
37524
38337
  }
@@ -37541,15 +38354,15 @@ function runExodusStatus(cwd) {
37541
38354
  const sourcesInfo = plan.sources.map((s) => ({
37542
38355
  name: s.name,
37543
38356
  path: s.path,
37544
- exists: existsSync11(s.path),
38357
+ exists: existsSync12(s.path),
37545
38358
  bytes: safeBytes(s.path)
37546
38359
  }));
37547
38360
  return {
37548
38361
  hasStaging: latestStaging !== null,
37549
38362
  stagingDir: latestStaging,
37550
38363
  journal,
37551
- projectDbExists: existsSync11(projectDbPath),
37552
- globalDbExists: existsSync11(globalDbPath),
38364
+ projectDbExists: existsSync12(projectDbPath),
38365
+ globalDbExists: existsSync12(globalDbPath),
37553
38366
  sourcesPresent: sourcesInfo.some((s) => s.exists),
37554
38367
  sources: sourcesInfo
37555
38368
  };
@@ -37566,7 +38379,7 @@ var init_status = __esm({
37566
38379
  });
37567
38380
 
37568
38381
  // packages/core/src/store/exodus/verify-migration.ts
37569
- import { existsSync as existsSync12 } from "node:fs";
38382
+ import { existsSync as existsSync13 } from "node:fs";
37570
38383
  import { createRequire as createRequire3 } from "node:module";
37571
38384
  function orderByClause(db, tableName) {
37572
38385
  try {
@@ -37586,7 +38399,7 @@ function computeTableDigest(db, tableName, columns, transform) {
37586
38399
  count = Number(row?.c ?? 0);
37587
38400
  } catch (err) {
37588
38401
  const msg = err instanceof Error ? err.message : String(err);
37589
- log6.warn(
38402
+ log7.warn(
37590
38403
  { tableName, err: msg },
37591
38404
  "computeTableDigest: COUNT(*) failed (possibly a virtual/FTS table) \u2014 treating as 0 rows"
37592
38405
  );
@@ -37621,7 +38434,7 @@ function computeTableDigest(db, tableName, columns, transform) {
37621
38434
  }
37622
38435
  } catch (err) {
37623
38436
  const msg = err instanceof Error ? err.message : String(err);
37624
- log6.warn(
38437
+ log7.warn(
37625
38438
  { tableName, err: msg },
37626
38439
  "computeTableDigest: streamed SELECT failed (possibly a virtual/FTS table) \u2014 digest skipped (COUNT(*) parity still enforced)"
37627
38440
  );
@@ -37747,7 +38560,7 @@ function foreignKeyCheck(db, scope) {
37747
38560
  try {
37748
38561
  const rows = db.prepare("PRAGMA foreign_key_check").all();
37749
38562
  if (rows.length > 0) {
37750
- log6.warn(
38563
+ log7.warn(
37751
38564
  { scope, count: rows.length, sample: rows.slice(0, 5) },
37752
38565
  `verifyMigration: PRAGMA foreign_key_check found ${rows.length} orphan row(s)`
37753
38566
  );
@@ -37759,7 +38572,7 @@ function foreignKeyCheck(db, scope) {
37759
38572
  fkid: r.fkid
37760
38573
  }));
37761
38574
  } catch (err) {
37762
- log6.warn({ scope, err }, "verifyMigration: PRAGMA foreign_key_check failed (non-fatal)");
38575
+ log7.warn({ scope, err }, "verifyMigration: PRAGMA foreign_key_check failed (non-fatal)");
37763
38576
  return [];
37764
38577
  }
37765
38578
  }
@@ -37796,13 +38609,13 @@ function sourceOrphanSignatures(db, sourceName, scope) {
37796
38609
  const rows = db.prepare("PRAGMA foreign_key_check").all();
37797
38610
  for (const r of rows) sigs.add(orphanSignature(db, r, sourceName));
37798
38611
  if (rows.length > 0) {
37799
- log6.warn(
38612
+ log7.warn(
37800
38613
  { scope, count: rows.length, sample: rows.slice(0, 5) },
37801
38614
  `verifyMigration: source already has ${rows.length} pre-existing FK orphan(s) \u2014 these are tolerated (carried forward losslessly, flagged for data-hygiene)`
37802
38615
  );
37803
38616
  }
37804
38617
  } catch (err) {
37805
- log6.warn({ scope, err }, "verifyMigration: source PRAGMA foreign_key_check failed (non-fatal)");
38618
+ log7.warn({ scope, err }, "verifyMigration: source PRAGMA foreign_key_check failed (non-fatal)");
37806
38619
  }
37807
38620
  return sigs;
37808
38621
  }
@@ -37814,7 +38627,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
37814
38627
  const preExistingForeignKeyViolations = [];
37815
38628
  const failureLines = [];
37816
38629
  const sourceOrphanSigs = /* @__PURE__ */ new Set();
37817
- if (!existsSync12(projectDbPath)) {
38630
+ if (!existsSync13(projectDbPath)) {
37818
38631
  return {
37819
38632
  ok: false,
37820
38633
  tables: [],
@@ -37825,7 +38638,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
37825
38638
  error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
37826
38639
  };
37827
38640
  }
37828
- if (!existsSync12(globalDbPath)) {
38641
+ if (!existsSync13(globalDbPath)) {
37829
38642
  return {
37830
38643
  ok: false,
37831
38644
  tables: [],
@@ -37840,7 +38653,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
37840
38653
  const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
37841
38654
  try {
37842
38655
  for (const src of sources) {
37843
- if (!existsSync12(src.path)) {
38656
+ if (!existsSync13(src.path)) {
37844
38657
  onProgress?.(`Skipping ${src.name} (not present)`);
37845
38658
  continue;
37846
38659
  }
@@ -37925,7 +38738,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
37925
38738
  `[${scope}] ${src.name}.${legacyTableName} \u2192 ${targetTableName}: DEFICIT \u2014 source=${srcDigest.count} rows, target=${tgtDigest.count} rows (${srcDigest.count - tgtDigest.count} missing), hashMatch=${hashMatch}`
37926
38739
  );
37927
38740
  } else if (tgtDigest.count > srcDigest.count) {
37928
- log6.warn(
38741
+ log7.warn(
37929
38742
  {
37930
38743
  scope,
37931
38744
  source: src.name,
@@ -37975,7 +38788,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
37975
38788
  }
37976
38789
  }
37977
38790
  if (preExistingForeignKeyViolations.length > 0) {
37978
- log6.warn(
38791
+ log7.warn(
37979
38792
  {
37980
38793
  count: preExistingForeignKeyViolations.length,
37981
38794
  sample: preExistingForeignKeyViolations.slice(0, 5)
@@ -37985,7 +38798,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
37985
38798
  }
37986
38799
  } catch (err) {
37987
38800
  const error = err instanceof Error ? err.message : String(err);
37988
- log6.error({ err }, "verifyMigration failed");
38801
+ log7.error({ err }, "verifyMigration failed");
37989
38802
  return {
37990
38803
  ok: false,
37991
38804
  tables,
@@ -38002,7 +38815,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
38002
38815
  if (failureLines.length > 0) {
38003
38816
  const error = `verifyMigration FAILED: ${failureLines.length} issue(s):
38004
38817
  ${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
38005
- log6.error({ failureCount: failureLines.length }, error);
38818
+ log7.error({ failureCount: failureLines.length }, error);
38006
38819
  return {
38007
38820
  ok: false,
38008
38821
  tables,
@@ -38022,7 +38835,7 @@ ${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
38022
38835
  enumDrift
38023
38836
  };
38024
38837
  }
38025
- var log6, _require, CHECK_ENUM_REGEX;
38838
+ var log7, _require, CHECK_ENUM_REGEX;
38026
38839
  var init_verify_migration = __esm({
38027
38840
  "packages/core/src/store/exodus/verify-migration.ts"() {
38028
38841
  "use strict";
@@ -38031,7 +38844,7 @@ var init_verify_migration = __esm({
38031
38844
  init_open_cleo_db();
38032
38845
  init_column_transforms();
38033
38846
  init_table_name_map();
38034
- log6 = getLogger("verify-migration");
38847
+ log7 = getLogger("verify-migration");
38035
38848
  _require = createRequire3(import.meta.url);
38036
38849
  CHECK_ENUM_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+(?:IS\s+NULL\s+OR\s+"[^"]+"\s+)?IN\s*\(([^)]*)\)\s*\)/gi;
38037
38850
  }
@@ -38123,7 +38936,7 @@ __export(on_open_exports, {
38123
38936
  isDataContinuityOk: () => isDataContinuityOk,
38124
38937
  maybeRunExodusOnOpen: () => maybeRunExodusOnOpen
38125
38938
  });
38126
- import { existsSync as existsSync13 } from "node:fs";
38939
+ import { existsSync as existsSync14 } from "node:fs";
38127
38940
  function isDisabledByEnv() {
38128
38941
  const v = process.env.CLEO_DISABLE_EXODUS_ON_OPEN;
38129
38942
  return v === "1" || v === "true";
@@ -38149,7 +38962,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
38149
38962
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%'"
38150
38963
  ).all().map((r) => r.name);
38151
38964
  } catch (err) {
38152
- log7.error({ err, scope }, "exodus-on-open: failed to enumerate tables for rollback");
38965
+ log8.error({ err, scope }, "exodus-on-open: failed to enumerate tables for rollback");
38153
38966
  return;
38154
38967
  }
38155
38968
  try {
@@ -38159,7 +38972,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
38159
38972
  try {
38160
38973
  nativeDb.exec(`DELETE FROM "${table}"`);
38161
38974
  } catch (err) {
38162
- log7.warn({ err, table, scope }, "exodus-on-open: failed to clear table during rollback");
38975
+ log8.warn({ err, table, scope }, "exodus-on-open: failed to clear table during rollback");
38163
38976
  }
38164
38977
  }
38165
38978
  nativeDb.exec("COMMIT");
@@ -38168,7 +38981,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
38168
38981
  nativeDb.exec("ROLLBACK");
38169
38982
  } catch {
38170
38983
  }
38171
- log7.error({ err, scope }, "exodus-on-open: rollback transaction failed");
38984
+ log8.error({ err, scope }, "exodus-on-open: rollback transaction failed");
38172
38985
  } finally {
38173
38986
  try {
38174
38987
  nativeDb.exec("PRAGMA foreign_keys = ON");
@@ -38188,7 +39001,7 @@ async function rollbackBothScopes(scope, projectDbPath, globalDbPath) {
38188
39001
  rollbackConsolidatedToEmpty(native, s);
38189
39002
  }
38190
39003
  } catch (err) {
38191
- log7.warn(
39004
+ log8.warn(
38192
39005
  { err, scope: s, openingScope: scope },
38193
39006
  "exodus-on-open: could not roll back scope (best-effort)"
38194
39007
  );
@@ -38204,7 +39017,7 @@ function isDataContinuityOk(result) {
38204
39017
  const deficits = result.tables.filter((t) => t.targetCount < t.sourceCount);
38205
39018
  const surpluses = result.tables.filter((t) => t.targetCount > t.sourceCount);
38206
39019
  if (surpluses.length > 0) {
38207
- log7.warn(
39020
+ log8.warn(
38208
39021
  {
38209
39022
  surpluses: surpluses.map((t) => ({
38210
39023
  table: t.targetTable,
@@ -38238,7 +39051,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38238
39051
  const { buildExodusPlan: buildExodusPlan2, runExodusMigrate: runExodusMigrate2, verifyMigration: verifyMigration2, clearExodusJournal: clearExodusJournal2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
38239
39052
  const plan = buildExodusPlan2(cwd);
38240
39053
  const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
38241
- if (!scopeSources.some((s) => existsSync13(s.path))) {
39054
+ if (!scopeSources.some((s) => existsSync14(s.path))) {
38242
39055
  return {
38243
39056
  outcome: "skipped",
38244
39057
  reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
@@ -38251,11 +39064,11 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38251
39064
  if (!consolidatedIsEmpty(nativeDb, scope)) {
38252
39065
  return { outcome: "skipped", reason: "migrated by a concurrent process (lock winner)" };
38253
39066
  }
38254
- log7.info(
39067
+ log8.info(
38255
39068
  {
38256
39069
  scope,
38257
39070
  dbPath,
38258
- sources: plan.sources.filter((s) => existsSync13(s.path)).map((s) => s.name)
39071
+ sources: plan.sources.filter((s) => existsSync14(s.path)).map((s) => s.name)
38259
39072
  },
38260
39073
  "exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
38261
39074
  );
@@ -38264,23 +39077,23 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38264
39077
  const migrateResult = await runExodusMigrate2(
38265
39078
  plan,
38266
39079
  false,
38267
- (msg) => log7.debug({ scope }, `exodus-on-open: ${msg}`)
39080
+ (msg) => log8.debug({ scope }, `exodus-on-open: ${msg}`)
38268
39081
  );
38269
39082
  if (!migrateResult.ok) {
38270
39083
  await rollbackBothScopes(scope, plan.projectDbPath, plan.globalDbPath);
38271
39084
  clearExodusJournal2(migrateResult.stagingDir);
38272
39085
  const reason = `migration failed: ${migrateResult.error ?? "unknown error"} \u2014 legacy DBs kept as source`;
38273
- log7.error({ scope, error: migrateResult.error }, `exodus-on-open: ${reason}`);
39086
+ log8.error({ scope, error: migrateResult.error }, `exodus-on-open: ${reason}`);
38274
39087
  return { outcome: "aborted", reason };
38275
39088
  }
38276
39089
  const verifyResult = verifyMigration2(
38277
39090
  plan.sources,
38278
39091
  plan.projectDbPath,
38279
39092
  plan.globalDbPath,
38280
- (msg) => log7.debug({ scope }, `exodus-on-open verify: ${msg}`)
39093
+ (msg) => log8.debug({ scope }, `exodus-on-open verify: ${msg}`)
38281
39094
  );
38282
39095
  if (!verifyResult.ok) {
38283
- log7.warn(
39096
+ log8.warn(
38284
39097
  {
38285
39098
  scope,
38286
39099
  enumDrift: verifyResult.enumDrift.length,
@@ -38294,7 +39107,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38294
39107
  clearExodusJournal2(plan.stagingDir);
38295
39108
  const deficits = verifyResult.tables.filter((t) => t.targetCount < t.sourceCount).map((t) => `${t.targetTable}(${t.sourceCount}\u2192${t.targetCount})`);
38296
39109
  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();
38297
- log7.error(
39110
+ log8.error(
38298
39111
  {
38299
39112
  scope,
38300
39113
  countDeficits: deficits,
@@ -38306,14 +39119,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38306
39119
  return { outcome: "aborted", reason };
38307
39120
  }
38308
39121
  const rowsCopied = migrateResult.tables.filter((t) => !t.skipped).reduce((n, t) => n + t.rowsCopied, 0);
38309
- log7.info(
39122
+ log8.info(
38310
39123
  { scope, rowsCopied, tables: migrateResult.tables.length },
38311
39124
  "exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
38312
39125
  );
38313
39126
  try {
38314
- const consumed = plan.sources.filter((s) => existsSync13(s.path));
39127
+ const consumed = plan.sources.filter((s) => existsSync14(s.path));
38315
39128
  const archiveResult = archiveMigratedSources(consumed, cwd);
38316
- log7.info(
39129
+ log8.info(
38317
39130
  {
38318
39131
  scope,
38319
39132
  archived: archiveResult.sources.filter((s) => s.action === "archived").length,
@@ -38322,7 +39135,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38322
39135
  "exodus-on-open: archived legacy sources + sealed completion marker(s)"
38323
39136
  );
38324
39137
  } catch (err) {
38325
- log7.error(
39138
+ log8.error(
38326
39139
  { err, scope },
38327
39140
  "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`)"
38328
39141
  );
@@ -38344,14 +39157,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
38344
39157
  function _isExodusInProgress() {
38345
39158
  return _exodusInProgress;
38346
39159
  }
38347
- var log7, _exodusInProgress;
39160
+ var log8, _exodusInProgress;
38348
39161
  var init_on_open = __esm({
38349
39162
  "packages/core/src/store/exodus/on-open.ts"() {
38350
39163
  "use strict";
38351
39164
  init_logger2();
38352
39165
  init_lock();
38353
39166
  init_archive2();
38354
- log7 = getLogger("exodus-on-open");
39167
+ log8 = getLogger("exodus-on-open");
38355
39168
  _exodusInProgress = false;
38356
39169
  }
38357
39170
  });
@@ -38368,9 +39181,9 @@ __export(dual_scope_db_exports, {
38368
39181
  resolveDualScopeDbPath: () => resolveDualScopeDbPath,
38369
39182
  upsertIdempotent: () => upsertIdempotent
38370
39183
  });
38371
- import { existsSync as existsSync14, mkdirSync as mkdirSync3 } from "node:fs";
39184
+ import { existsSync as existsSync15, mkdirSync as mkdirSync4 } from "node:fs";
38372
39185
  import { createRequire as createRequire4 } from "node:module";
38373
- import { dirname as dirname6, join as join13 } from "node:path";
39186
+ import { dirname as dirname6, join as join15 } from "node:path";
38374
39187
  function assertWriteDurable(handle) {
38375
39188
  if (handle.exodusAbort) {
38376
39189
  throw new ExodusAbortWriteUnsafeError(handle.exodusAbort);
@@ -38387,9 +39200,9 @@ function cacheKey(scope, dbPath) {
38387
39200
  }
38388
39201
  function resolveDualScopeDbPath(scope, cwd) {
38389
39202
  if (scope === "project") {
38390
- return join13(resolveCleoDir(cwd), "cleo.db");
39203
+ return join15(resolveCleoDir(cwd), "cleo.db");
38391
39204
  }
38392
- return join13(getCleoHome(), "cleo.db");
39205
+ return join15(getCleoHome(), "cleo.db");
38393
39206
  }
38394
39207
  function migrationsSetName(scope) {
38395
39208
  return scope === "project" ? "drizzle-cleo-project" : "drizzle-cleo-global";
@@ -38432,11 +39245,11 @@ async function openDualScopeDb(scope, cwd) {
38432
39245
  const dbPath = resolveDualScopeDbPath(scope, cwd);
38433
39246
  return scope === "project" ? openDualScopeDbAtPath("project", dbPath, cwd) : openDualScopeDbAtPath("global", dbPath, cwd);
38434
39247
  }
38435
- async function openDedicatedDualScopeDb(scope, dbPath, log11) {
38436
- log11.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
39248
+ async function openDedicatedDualScopeDb(scope, dbPath, log12) {
39249
+ log12.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
38437
39250
  const dir = dirname6(dbPath);
38438
- if (!existsSync14(dir)) {
38439
- mkdirSync3(dir, { recursive: true });
39251
+ if (!existsSync15(dir)) {
39252
+ mkdirSync4(dir, { recursive: true });
38440
39253
  }
38441
39254
  const DatabaseSyncCtor = getDatabaseSyncCtor();
38442
39255
  const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
@@ -38459,7 +39272,7 @@ async function openDedicatedDualScopeDb(scope, dbPath, log11) {
38459
39272
  existenceTable(scope),
38460
39273
  `dual-scope-db[${scope}]`
38461
39274
  );
38462
- log11.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
39275
+ log12.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
38463
39276
  return {
38464
39277
  db,
38465
39278
  scope,
@@ -38484,15 +39297,15 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
38484
39297
  return existing.handle;
38485
39298
  }
38486
39299
  }
38487
- const log11 = getLogger("dual-scope-db");
39300
+ const log12 = getLogger("dual-scope-db");
38488
39301
  if (dedicated) {
38489
- return openDedicatedDualScopeDb(scope, dbPath, log11);
39302
+ return openDedicatedDualScopeDb(scope, dbPath, log12);
38490
39303
  }
38491
39304
  const initPromise = (async () => {
38492
- log11.debug({ scope, dbPath }, "opening dual-scope cleo.db");
39305
+ log12.debug({ scope, dbPath }, "opening dual-scope cleo.db");
38493
39306
  const dir = dirname6(dbPath);
38494
- if (!existsSync14(dir)) {
38495
- mkdirSync3(dir, { recursive: true });
39307
+ if (!existsSync15(dir)) {
39308
+ mkdirSync4(dir, { recursive: true });
38496
39309
  }
38497
39310
  const DatabaseSyncCtor = getDatabaseSyncCtor();
38498
39311
  const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
@@ -38519,7 +39332,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
38519
39332
  existenceTable(scope),
38520
39333
  `dual-scope-db[${scope}]`
38521
39334
  );
38522
- log11.debug({ scope, dbPath }, "dual-scope cleo.db ready");
39335
+ log12.debug({ scope, dbPath }, "dual-scope cleo.db ready");
38523
39336
  const built = {
38524
39337
  db,
38525
39338
  scope,
@@ -38545,6 +39358,25 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
38545
39358
  { dbPath }
38546
39359
  );
38547
39360
  if (exodusCwd !== void 0 && dbPath === resolveDualScopeDbPath(scope, exodusCwd)) {
39361
+ let releaseDbHeavy = null;
39362
+ let dbHeavyDeferred = false;
39363
+ try {
39364
+ const { governor: governor2 } = await Promise.resolve().then(() => (init_governor(), governor_exports));
39365
+ const admit = await governor2.tryAcquire("db-heavy");
39366
+ if (admit.deferred) {
39367
+ dbHeavyDeferred = true;
39368
+ } else {
39369
+ releaseDbHeavy = admit.release;
39370
+ }
39371
+ } catch {
39372
+ }
39373
+ if (dbHeavyDeferred) {
39374
+ log12.debug(
39375
+ { scope, dbPath },
39376
+ "exodus-on-open skipped this open \u2014 db-heavy deferred under memory pressure (re-runs idempotently on a calmer open)"
39377
+ );
39378
+ return handle;
39379
+ }
38548
39380
  try {
38549
39381
  const { maybeRunExodusOnOpen: maybeRunExodusOnOpen2 } = await Promise.resolve().then(() => (init_on_open(), on_open_exports));
38550
39382
  const result = await maybeRunExodusOnOpen2(scope, dbPath, nativeDb, exodusCwd);
@@ -38557,7 +39389,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
38557
39389
  reason: result.reason,
38558
39390
  at: Date.now()
38559
39391
  };
38560
- log11.warn(
39392
+ log12.warn(
38561
39393
  { scope, reason: result.reason },
38562
39394
  "exodus-on-open aborted; consolidated cleo.db left empty, legacy kept as source \u2014 mutating callers must check handle.exodusAbort / call assertWriteDurable (T11828)"
38563
39395
  );
@@ -38570,11 +39402,14 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
38570
39402
  return reopened;
38571
39403
  }
38572
39404
  } catch (err) {
38573
- log11.warn(
39405
+ log12.warn(
38574
39406
  { err, scope },
38575
39407
  "exodus-on-open hook failed (non-fatal); re-opening consolidated handle"
38576
39408
  );
38577
39409
  return scope === "project" ? openDualScopeDbAtPath("project", dbPath) : openDualScopeDbAtPath("global", dbPath);
39410
+ } finally {
39411
+ if (releaseDbHeavy) await releaseDbHeavy().catch(() => {
39412
+ });
38578
39413
  }
38579
39414
  }
38580
39415
  return handle;
@@ -39197,8 +40032,8 @@ __export(nexus_sqlite_exports, {
39197
40032
  resetNexusDbState: () => resetNexusDbState,
39198
40033
  resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
39199
40034
  });
39200
- import { copyFileSync as copyFileSync4, existsSync as existsSync15 } from "node:fs";
39201
- import { join as join14 } from "node:path";
40035
+ import { copyFileSync as copyFileSync4, existsSync as existsSync16 } from "node:fs";
40036
+ import { join as join16 } from "node:path";
39202
40037
  function getNexusDbPath(cwd) {
39203
40038
  return resolveDualScopeDbPath("project", cwd);
39204
40039
  }
@@ -39230,7 +40065,7 @@ function resolveNexusMigrationsFolder() {
39230
40065
  return resolveCorePackageMigrationsFolder("drizzle-nexus");
39231
40066
  }
39232
40067
  function getNestedNexusSentinelPath() {
39233
- return join14(getCleoHome(), "nexus", NESTED_NEXUS_SENTINEL);
40068
+ return join16(getCleoHome(), "nexus", NESTED_NEXUS_SENTINEL);
39234
40069
  }
39235
40070
  function detectAndWarnOnNestedNexus() {
39236
40071
  let nestedPath;
@@ -39239,12 +40074,12 @@ function detectAndWarnOnNestedNexus() {
39239
40074
  } catch {
39240
40075
  return false;
39241
40076
  }
39242
- if (!existsSync15(nestedPath)) return false;
40077
+ if (!existsSync16(nestedPath)) return false;
39243
40078
  if (_warnedNestedPaths.has(nestedPath)) return false;
39244
40079
  _warnedNestedPaths.add(nestedPath);
39245
40080
  const canonicalPath = getNexusDbPath();
39246
- const log11 = getLogger("nexus-sqlite");
39247
- log11.warn(
40081
+ const log12 = getLogger("nexus-sqlite");
40082
+ log12.warn(
39248
40083
  {
39249
40084
  nestedPath,
39250
40085
  canonicalPath,
@@ -39398,7 +40233,7 @@ function runNexusMigrations(nativeDb, db) {
39398
40233
  const migrationsFolder = resolveNexusMigrationsFolder();
39399
40234
  if (tableExists4(nativeDb, "nexus_nodes") && _nexusDbPath) {
39400
40235
  const backupPath = _nexusDbPath.replace(/\.db$/, "-pre-cleo.db.bak");
39401
- if (!existsSync15(backupPath)) {
40236
+ if (!existsSync16(backupPath)) {
39402
40237
  try {
39403
40238
  copyFileSync4(_nexusDbPath, backupPath);
39404
40239
  } catch {
@@ -39536,10 +40371,10 @@ var init_nexus_sqlite = __esm({
39536
40371
 
39537
40372
  // packages/core/src/paths.ts
39538
40373
  import { AsyncLocalStorage } from "node:async_hooks";
39539
- import { existsSync as existsSync16, readFileSync as readFileSync5, statSync as statSync6 } from "node:fs";
40374
+ import { existsSync as existsSync17, readFileSync as readFileSync5, statSync as statSync6 } from "node:fs";
39540
40375
  import { createRequire as createRequire5 } from "node:module";
39541
40376
  import { homedir } from "node:os";
39542
- import { basename as basename4, dirname as dirname7, join as join15, resolve as resolve3 } from "node:path";
40377
+ import { basename as basename4, dirname as dirname7, join as join17, resolve as resolve3 } from "node:path";
39543
40378
  import {
39544
40379
  computeCanonicalProjectId as _computeCanonicalProjectId,
39545
40380
  getCanonicalTemplatesTildePath as _getCanonicalTemplatesTildePath,
@@ -39629,8 +40464,8 @@ function getCleoDirAbsolute(cwd, opts) {
39629
40464
  function _resolveProjectByCwdFromNexus(cwd) {
39630
40465
  try {
39631
40466
  const cleoHome = getCleoHome();
39632
- const globalDbPath = join15(cleoHome, "cleo.db");
39633
- if (!existsSync16(globalDbPath)) return null;
40467
+ const globalDbPath = join17(cleoHome, "cleo.db");
40468
+ if (!existsSync17(globalDbPath)) return null;
39634
40469
  const start = resolve3(cwd ?? process.cwd());
39635
40470
  let current = start;
39636
40471
  const DatabaseSync3 = _getDatabaseSyncCtor();
@@ -39669,7 +40504,7 @@ function _findCleoDirRoot(cwd) {
39669
40504
  const isDangerousRoot = current === homeRoot || current === "/" || current === "";
39670
40505
  if (!isDangerousRoot) {
39671
40506
  try {
39672
- if (statSync6(join15(current, ".cleo")).isDirectory()) {
40507
+ if (statSync6(join17(current, ".cleo")).isDirectory()) {
39673
40508
  return current;
39674
40509
  }
39675
40510
  } catch {
@@ -39684,7 +40519,7 @@ function _findCleoDirRoot(cwd) {
39684
40519
  function resolveCleoDir(cwd) {
39685
40520
  const scope = worktreeScope.getStore();
39686
40521
  if (scope !== void 0) {
39687
- return join15(scope.worktreeRoot, ".cleo");
40522
+ return join17(scope.worktreeRoot, ".cleo");
39688
40523
  }
39689
40524
  const override = _cleoDirEnvOverride();
39690
40525
  if (override !== null) {
@@ -39692,14 +40527,14 @@ function resolveCleoDir(cwd) {
39692
40527
  }
39693
40528
  const root = _findCleoDirRoot(cwd);
39694
40529
  if (root !== null) {
39695
- return join15(root, ".cleo");
40530
+ return join17(root, ".cleo");
39696
40531
  }
39697
40532
  const start = resolve3(cwd ?? process.cwd());
39698
40533
  let current = start;
39699
40534
  while (true) {
39700
40535
  const mainRepo = _resolveMainRepoFromGitlink(current);
39701
40536
  if (mainRepo !== null) {
39702
- return join15(mainRepo, ".cleo");
40537
+ return join17(mainRepo, ".cleo");
39703
40538
  }
39704
40539
  const parent = dirname7(current);
39705
40540
  if (parent === current) {
@@ -39741,9 +40576,9 @@ function _cwdHasGitAncestor(cwd) {
39741
40576
  const start = resolve3(cwd ?? process.cwd());
39742
40577
  let current = start;
39743
40578
  while (true) {
39744
- const gitMarker = join15(current, ".git");
40579
+ const gitMarker = join17(current, ".git");
39745
40580
  try {
39746
- if (existsSync16(gitMarker)) {
40581
+ if (existsSync17(gitMarker)) {
39747
40582
  return true;
39748
40583
  }
39749
40584
  } catch {
@@ -39755,16 +40590,16 @@ function _cwdHasGitAncestor(cwd) {
39755
40590
  }
39756
40591
  function _resolveMainRepoFromGitlink(gitlinkDir) {
39757
40592
  try {
39758
- const gitLinkPath = join15(gitlinkDir, ".git");
39759
- if (!existsSync16(gitLinkPath)) return null;
39760
- const stat2 = statSync6(gitLinkPath);
39761
- if (!stat2.isFile()) return null;
40593
+ const gitLinkPath = join17(gitlinkDir, ".git");
40594
+ if (!existsSync17(gitLinkPath)) return null;
40595
+ const stat3 = statSync6(gitLinkPath);
40596
+ if (!stat3.isFile()) return null;
39762
40597
  const gitLinkContent = readFileSync5(gitLinkPath, "utf-8").trim();
39763
40598
  const match = gitLinkContent.match(/^gitdir:\s*(.+)$/m);
39764
40599
  if (!match) return null;
39765
40600
  const gitdir = match[1].trim();
39766
40601
  const mainRepo = dirname7(dirname7(dirname7(gitdir)));
39767
- if (existsSync16(join15(mainRepo, ".cleo")) && validateProjectRoot(mainRepo)) {
40602
+ if (existsSync17(join17(mainRepo, ".cleo")) && validateProjectRoot(mainRepo)) {
39768
40603
  return mainRepo;
39769
40604
  }
39770
40605
  } catch {
@@ -39772,18 +40607,18 @@ function _resolveMainRepoFromGitlink(gitlinkDir) {
39772
40607
  return null;
39773
40608
  }
39774
40609
  function validateProjectRoot(candidate) {
39775
- const cleoDir = join15(candidate, ".cleo");
39776
- if (!existsSync16(cleoDir)) {
40610
+ const cleoDir = join17(candidate, ".cleo");
40611
+ if (!existsSync17(cleoDir)) {
39777
40612
  return false;
39778
40613
  }
39779
- const projectInfoPath = join15(cleoDir, "project-info.json");
39780
- if (existsSync16(projectInfoPath)) {
40614
+ const projectInfoPath = join17(cleoDir, "project-info.json");
40615
+ if (existsSync17(projectInfoPath)) {
39781
40616
  try {
39782
40617
  const raw = readFileSync5(projectInfoPath, "utf-8");
39783
40618
  const parsed = JSON.parse(raw);
39784
40619
  if (typeof parsed === "object" && parsed !== null && "projectId" in parsed && typeof parsed["projectId"] === "string" && parsed["projectId"] !== "") {
39785
- const gitMarker = join15(candidate, ".git");
39786
- if (existsSync16(gitMarker)) {
40620
+ const gitMarker = join17(candidate, ".git");
40621
+ if (existsSync17(gitMarker)) {
39787
40622
  try {
39788
40623
  if (!statSync6(gitMarker).isDirectory()) {
39789
40624
  return false;
@@ -39797,12 +40632,12 @@ function validateProjectRoot(candidate) {
39797
40632
  } catch {
39798
40633
  }
39799
40634
  }
39800
- const gitDir = join15(candidate, ".git");
39801
- if (existsSync16(gitDir)) {
40635
+ const gitDir = join17(candidate, ".git");
40636
+ if (existsSync17(gitDir)) {
39802
40637
  let isRealGitDir = false;
39803
40638
  try {
39804
- const stat2 = statSync6(gitDir);
39805
- isRealGitDir = stat2.isDirectory();
40639
+ const stat3 = statSync6(gitDir);
40640
+ isRealGitDir = stat3.isDirectory();
39806
40641
  } catch {
39807
40642
  isRealGitDir = false;
39808
40643
  }
@@ -39845,16 +40680,16 @@ function getProjectRoot(cwd) {
39845
40680
  const homeRoot = homedir();
39846
40681
  const skippedCleoDirs = [];
39847
40682
  while (true) {
39848
- const cleoDir = join15(current, ".cleo");
39849
- const gitDir = join15(current, ".git");
40683
+ const cleoDir = join17(current, ".cleo");
40684
+ const gitDir = join17(current, ".git");
39850
40685
  const isDangerousRoot = current === homeRoot || current === "/" || current === "";
39851
- if (existsSync16(cleoDir) && !isDangerousRoot) {
40686
+ if (existsSync17(cleoDir) && !isDangerousRoot) {
39852
40687
  if (validateProjectRoot(current)) {
39853
40688
  return current;
39854
40689
  }
39855
40690
  skippedCleoDirs.push(current);
39856
40691
  }
39857
- if (existsSync16(gitDir) && !isDangerousRoot) {
40692
+ if (existsSync17(gitDir) && !isDangerousRoot) {
39858
40693
  let isRealGitDir = false;
39859
40694
  try {
39860
40695
  isRealGitDir = statSync6(gitDir).isDirectory();
@@ -39899,18 +40734,18 @@ function resolveOrCwd(maybeRoot) {
39899
40734
  return getProjectRoot();
39900
40735
  }
39901
40736
  function getConfigPath(cwd) {
39902
- return join15(_resolveCleoDir(cwd), "config.json");
40737
+ return join17(_resolveCleoDir(cwd), "config.json");
39903
40738
  }
39904
40739
  function getGlobalConfigPath() {
39905
- return join15(getCleoHome(), "config.json");
40740
+ return join17(getCleoHome(), "config.json");
39906
40741
  }
39907
40742
  function isAbsolutePath(path2) {
39908
40743
  return _isAbsolutePath(path2);
39909
40744
  }
39910
40745
  function _readProjectNameFromInfo(projectRoot) {
39911
40746
  try {
39912
- const infoPath = join15(projectRoot, ".cleo", "project-info.json");
39913
- if (!existsSync16(infoPath)) return void 0;
40747
+ const infoPath = join17(projectRoot, ".cleo", "project-info.json");
40748
+ if (!existsSync17(infoPath)) return void 0;
39914
40749
  const raw = readFileSync5(infoPath, "utf-8");
39915
40750
  const data = JSON.parse(raw);
39916
40751
  return typeof data.name === "string" && data.name.length > 0 ? data.name : void 0;
@@ -39936,8 +40771,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
39936
40771
  if (existingRows.length > 0) {
39937
40772
  const existingPath = existingRows[0].projectPath;
39938
40773
  if (existingPath !== resolvedPath) {
39939
- const newBrainDbPath = join15(resolvedPath, ".cleo", "brain.db");
39940
- const newTasksDbPath = join15(resolvedPath, ".cleo", "tasks.db");
40774
+ const newBrainDbPath = join17(resolvedPath, ".cleo", "brain.db");
40775
+ const newTasksDbPath = join17(resolvedPath, ".cleo", "tasks.db");
39941
40776
  await db.update(projectRegistry2).set({
39942
40777
  projectPath: resolvedPath,
39943
40778
  projectHash: generateProjectHash2(resolvedPath),
@@ -39968,8 +40803,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
39968
40803
  lastSync: now,
39969
40804
  taskCount: 0,
39970
40805
  labelsJson: "[]",
39971
- brainDbPath: join15(resolvedPath, ".cleo", "brain.db"),
39972
- tasksDbPath: join15(resolvedPath, ".cleo", "tasks.db"),
40806
+ brainDbPath: join17(resolvedPath, ".cleo", "brain.db"),
40807
+ tasksDbPath: join17(resolvedPath, ".cleo", "tasks.db"),
39973
40808
  statsJson: "{}"
39974
40809
  }).onConflictDoNothing();
39975
40810
  const aliases = canonicalResult.legacyAliases ?? [];
@@ -40186,7 +41021,7 @@ __export(config_exports, {
40186
41021
  parseConfigValue: () => parseConfigValue,
40187
41022
  setConfigValue: () => setConfigValue
40188
41023
  });
40189
- import { existsSync as existsSync17 } from "node:fs";
41024
+ import { existsSync as existsSync18 } from "node:fs";
40190
41025
  function getNestedValue(obj, path2) {
40191
41026
  const parts = path2.split(".");
40192
41027
  let current = obj;
@@ -40234,7 +41069,7 @@ function parseEnvValue(value) {
40234
41069
  return value;
40235
41070
  }
40236
41071
  async function loadConfig(cwd) {
40237
- let merged = JSON.parse(JSON.stringify(DEFAULTS));
41072
+ let merged = JSON.parse(JSON.stringify(DEFAULTS2));
40238
41073
  const globalConfig = await readJson(getGlobalConfigPath());
40239
41074
  if (globalConfig) {
40240
41075
  merged = deepMerge(merged, globalConfig);
@@ -40280,7 +41115,7 @@ async function getConfigValue(path2, cwd) {
40280
41115
  return { value: val, source: "global" };
40281
41116
  }
40282
41117
  }
40283
- const defaultVal = getNestedValue({ ...DEFAULTS }, path2);
41118
+ const defaultVal = getNestedValue({ ...DEFAULTS2 }, path2);
40284
41119
  return { value: defaultVal, source: "default" };
40285
41120
  }
40286
41121
  async function getRawConfigValue(key, cwd) {
@@ -40308,7 +41143,7 @@ function parseConfigValue(value) {
40308
41143
  }
40309
41144
  async function setConfigValue(key, value, cwd, opts) {
40310
41145
  const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
40311
- if (!existsSync17(configPath)) {
41146
+ if (!existsSync18(configPath)) {
40312
41147
  await atomicWriteJson(configPath, {});
40313
41148
  }
40314
41149
  const config = await readJson(configPath) ?? {};
@@ -40320,7 +41155,7 @@ async function setConfigValue(key, value, cwd, opts) {
40320
41155
  async function applyStrictnessPreset(preset, cwd, opts) {
40321
41156
  const definition = STRICTNESS_PRESETS[preset];
40322
41157
  const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
40323
- if (!existsSync17(configPath)) {
41158
+ if (!existsSync18(configPath)) {
40324
41159
  await atomicWriteJson(configPath, {});
40325
41160
  }
40326
41161
  const config = await readJson(configPath) ?? {};
@@ -40344,7 +41179,7 @@ function listStrictnessPresets() {
40344
41179
  })
40345
41180
  );
40346
41181
  }
40347
- var DEFAULTS, ENV_MAP, STRICTNESS_PRESETS;
41182
+ var DEFAULTS2, ENV_MAP, STRICTNESS_PRESETS;
40348
41183
  var init_config = __esm({
40349
41184
  "packages/core/src/config.ts"() {
40350
41185
  "use strict";
@@ -40352,7 +41187,7 @@ var init_config = __esm({
40352
41187
  init_paths();
40353
41188
  init_atomic();
40354
41189
  init_json2();
40355
- DEFAULTS = {
41190
+ DEFAULTS2 = {
40356
41191
  version: "2.10.0",
40357
41192
  output: {
40358
41193
  defaultFormat: "json",
@@ -40671,7 +41506,7 @@ function brainTablesAreConsolidatedShape(nativeDb) {
40671
41506
  return createdAt !== void 0 && createdAt.type.toUpperCase() !== "INTEGER";
40672
41507
  }
40673
41508
  function establishLegacyBrainSchema(nativeDb, db) {
40674
- const log11 = getLogger("brain-schema");
41509
+ const log12 = getLogger("brain-schema");
40675
41510
  if (brainTablesAreConsolidatedShape(nativeDb)) {
40676
41511
  const fkRow = nativeDb.prepare("PRAGMA foreign_keys").get();
40677
41512
  const fkWasOn = fkRow?.foreign_keys === 1;
@@ -40681,7 +41516,7 @@ function establishLegacyBrainSchema(nativeDb, db) {
40681
41516
  try {
40682
41517
  nativeDb.exec(`DROP TABLE IF EXISTS \`${table}\``);
40683
41518
  } catch (err) {
40684
- log11.warn(
41519
+ log12.warn(
40685
41520
  { table, err },
40686
41521
  "Failed to drop consolidated brain table during legacy rebuild."
40687
41522
  );
@@ -40690,7 +41525,7 @@ function establishLegacyBrainSchema(nativeDb, db) {
40690
41525
  } finally {
40691
41526
  nativeDb.exec(`PRAGMA foreign_keys=${fkWasOn ? "ON" : "OFF"}`);
40692
41527
  }
40693
- log11.debug(
41528
+ log12.debug(
40694
41529
  { count: CONSOLIDATED_BRAIN_TABLES.length },
40695
41530
  "Dropped consolidated (exodus-target) brain tables \u2014 rebuilding in legacy runtime shape."
40696
41531
  );
@@ -40701,7 +41536,7 @@ function establishLegacyBrainSchema(nativeDb, db) {
40701
41536
  nativeDb,
40702
41537
  migrationsFolder
40703
41538
  );
40704
- log11.debug(
41539
+ log12.debug(
40705
41540
  { marked, applied },
40706
41541
  "brain consolidated cleo.db reconcile (T11647) \u2014 marked already-present migrations applied + executed the missing unprefixed-table migrations directly."
40707
41542
  );
@@ -41199,11 +42034,11 @@ __export(tasks_schema_exports, {
41199
42034
  isValidStatus: () => isValidStatus,
41200
42035
  jsonb: () => jsonb2,
41201
42036
  jsonbText: () => jsonbText,
41202
- lifecycleEvidence: () => lifecycleEvidence,
41203
- lifecycleGateResults: () => lifecycleGateResults,
41204
- lifecyclePipelines: () => lifecyclePipelines,
41205
- lifecycleStages: () => lifecycleStages,
41206
- lifecycleTransitions: () => lifecycleTransitions,
42037
+ lifecycleEvidence: () => tasksLifecycleEvidence,
42038
+ lifecycleGateResults: () => tasksLifecycleGateResults,
42039
+ lifecyclePipelines: () => tasksLifecyclePipelines,
42040
+ lifecycleStages: () => tasksLifecycleStages,
42041
+ lifecycleTransitions: () => tasksLifecycleTransitions,
41207
42042
  makeSchemaMetaTable: () => makeSchemaMetaTable,
41208
42043
  manifestEntries: () => manifestEntries,
41209
42044
  pipelineManifest: () => pipelineManifest,
@@ -41237,6 +42072,7 @@ var init_tasks_schema = __esm({
41237
42072
  "use strict";
41238
42073
  init_agent_schema();
41239
42074
  init_chain_schema();
42075
+ init_lifecycle3();
41240
42076
  init_provenance_commits();
41241
42077
  init_provenance_orphans();
41242
42078
  init_provenance_rest();
@@ -41256,7 +42092,7 @@ async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
41256
42092
  if (allowOrphanParent) {
41257
42093
  row = { ...row, parentId: null };
41258
42094
  } else {
41259
- log8.warn(
42095
+ log9.warn(
41260
42096
  { taskId: row.id, parentId: row.parentId },
41261
42097
  "upsertTask: parentId references a non-existent task \u2014 parent relationship may be lost"
41262
42098
  );
@@ -41441,13 +42277,13 @@ async function loadRelationsForTasks(db, tasks2) {
41441
42277
  task.relates = relations && relations.length > 0 ? relations : [];
41442
42278
  }
41443
42279
  }
41444
- var log8;
42280
+ var log9;
41445
42281
  var init_db_helpers = __esm({
41446
42282
  "packages/core/src/store/db-helpers.ts"() {
41447
42283
  "use strict";
41448
42284
  init_logger2();
41449
42285
  init_tasks_schema();
41450
- log8 = getLogger("db-helpers");
42286
+ log9 = getLogger("db-helpers");
41451
42287
  }
41452
42288
  });
41453
42289
 
@@ -41548,10 +42384,10 @@ var init_telemetry_schema = __esm({
41548
42384
  });
41549
42385
 
41550
42386
  // packages/core/src/telemetry/sqlite.ts
41551
- import { mkdirSync as mkdirSync4 } from "node:fs";
41552
- import { dirname as dirname8, join as join16 } from "node:path";
42387
+ import { mkdirSync as mkdirSync5 } from "node:fs";
42388
+ import { dirname as dirname8, join as join18 } from "node:path";
41553
42389
  function getTelemetryDbPath() {
41554
- return join16(getCleoHome(), DB_FILENAME);
42390
+ return join18(getCleoHome(), DB_FILENAME);
41555
42391
  }
41556
42392
  function resolveTelemetryMigrationsFolder() {
41557
42393
  return resolveCorePackageMigrationsFolder("drizzle-telemetry");
@@ -41599,7 +42435,7 @@ async function getTelemetryDb() {
41599
42435
  _initPromise2 = (async () => {
41600
42436
  const dbPath = requestedPath;
41601
42437
  _dbPath2 = dbPath;
41602
- mkdirSync4(dirname8(dbPath), { recursive: true });
42438
+ mkdirSync5(dirname8(dbPath), { recursive: true });
41603
42439
  const nativeDb = openNativeDatabase(dbPath);
41604
42440
  _nativeDb2 = nativeDb;
41605
42441
  const db = drizzle({ client: nativeDb, schema: telemetry_schema_exports });
@@ -41632,11 +42468,11 @@ var init_sqlite2 = __esm({
41632
42468
  });
41633
42469
 
41634
42470
  // packages/core/src/store/agent-registry-store.ts
41635
- import { existsSync as existsSync18 } from "node:fs";
41636
- import { join as join17 } from "node:path";
42471
+ import { existsSync as existsSync19 } from "node:fs";
42472
+ import { join as join19 } from "node:path";
41637
42473
  function getGlobalAgentRegistryDbPath() {
41638
42474
  const cleoHome = getCleoHome();
41639
- const dbPath = join17(cleoHome, "cleo.db");
42475
+ const dbPath = join19(cleoHome, "cleo.db");
41640
42476
  if (!dbPath.startsWith(cleoHome)) {
41641
42477
  throw new Error(
41642
42478
  `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.`
@@ -41683,8 +42519,8 @@ function writeAgentRegistrySchemaVersionSentinel(db) {
41683
42519
  }
41684
42520
  async function ensureGlobalAgentRegistryDb() {
41685
42521
  const dbPath = getGlobalAgentRegistryDbPath();
41686
- const alreadyExists = existsSync18(dbPath);
41687
- const dualHandle = await openDualScopeDb("global");
42522
+ const alreadyExists = existsSync19(dbPath);
42523
+ const dualHandle = await openDualScopeDbAtPath("global", dbPath);
41688
42524
  const nativeDb = dualHandle.db.$client ?? null;
41689
42525
  if (!nativeDb) {
41690
42526
  throw new Error(
@@ -41732,7 +42568,7 @@ var init_agent_registry_store = __esm({
41732
42568
  });
41733
42569
 
41734
42570
  // packages/core/src/store/conduit-sqlite.ts
41735
- import { existsSync as existsSync19 } from "node:fs";
42571
+ import { existsSync as existsSync20 } from "node:fs";
41736
42572
  import { createRequire as createRequire7 } from "node:module";
41737
42573
  function _getDrizzle2() {
41738
42574
  if (_drizzle3 === null) {
@@ -41769,7 +42605,7 @@ async function ensureConduitDb(projectRoot) {
41769
42605
  }
41770
42606
  if (_initPromise3) return _initPromise3;
41771
42607
  _initPromise3 = (async () => {
41772
- const alreadyExists = existsSync19(dbPath);
42608
+ const alreadyExists = existsSync20(dbPath);
41773
42609
  const dualHandle = await openDualScopeDb("project", projectRoot);
41774
42610
  const nativeDb = dualHandle.db.$client ?? null;
41775
42611
  if (!nativeDb) {
@@ -41989,11 +42825,11 @@ var init_skills_schema = __esm({
41989
42825
  });
41990
42826
 
41991
42827
  // packages/core/src/store/skills-db.ts
41992
- import { join as join18 } from "node:path";
42828
+ import { join as join20 } from "node:path";
41993
42829
  import { and as and3, eq as eq4 } from "drizzle-orm";
41994
42830
  function getDefaultSkillsDbPath() {
41995
42831
  const cleoHome = getCleoHome();
41996
- const dbPath = join18(cleoHome, "cleo.db");
42832
+ const dbPath = join20(cleoHome, "cleo.db");
41997
42833
  if (!dbPath.startsWith(cleoHome)) {
41998
42834
  throw new Error(
41999
42835
  `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.`
@@ -42063,13 +42899,13 @@ var init_skills_db = __esm({
42063
42899
  import {
42064
42900
  chmodSync,
42065
42901
  copyFileSync as copyFileSync5,
42066
- existsSync as existsSync20,
42067
- mkdirSync as mkdirSync5,
42068
- readdirSync as readdirSync4,
42902
+ existsSync as existsSync21,
42903
+ mkdirSync as mkdirSync6,
42904
+ readdirSync as readdirSync5,
42069
42905
  statSync as statSync7,
42070
42906
  unlinkSync as unlinkSync3
42071
42907
  } from "node:fs";
42072
- import { join as join19 } from "node:path";
42908
+ import { join as join21 } from "node:path";
42073
42909
  function resolveInventoryPath(entry, cwd) {
42074
42910
  try {
42075
42911
  if (entry.tier === "global") {
@@ -42104,8 +42940,8 @@ async function openAgentRegistryDbForSnapshot() {
42104
42940
  }
42105
42941
  async function openTelemetryDbForSnapshot() {
42106
42942
  try {
42107
- const path2 = join19(getCleoHome(), "telemetry.db");
42108
- if (!existsSync20(path2)) return null;
42943
+ const path2 = join21(getCleoHome(), "telemetry.db");
42944
+ if (!existsSync21(path2)) return null;
42109
42945
  } catch {
42110
42946
  return null;
42111
42947
  }
@@ -42120,7 +42956,7 @@ function buildRawFileVacuumOpener(entry) {
42120
42956
  return async (cwd) => {
42121
42957
  const path2 = resolveInventoryPath(entry, cwd);
42122
42958
  if (!path2) return null;
42123
- if (!existsSync20(path2)) return null;
42959
+ if (!existsSync21(path2)) return null;
42124
42960
  try {
42125
42961
  const { DatabaseSync: DatabaseSync3 } = await import("node:sqlite");
42126
42962
  return new DatabaseSync3(path2, { readOnly: true });
@@ -42208,10 +43044,10 @@ function snapshotPattern(prefix) {
42208
43044
  function rotateSnapshots(backupDir, prefix) {
42209
43045
  try {
42210
43046
  const pattern = snapshotPattern(prefix);
42211
- const files = readdirSync4(backupDir).filter((f) => pattern.test(f)).map((f) => ({
43047
+ const files = readdirSync5(backupDir).filter((f) => pattern.test(f)).map((f) => ({
42212
43048
  name: f,
42213
- path: join19(backupDir, f),
42214
- mtimeMs: statSync7(join19(backupDir, f)).mtimeMs
43049
+ path: join21(backupDir, f),
43050
+ mtimeMs: statSync7(join21(backupDir, f)).mtimeMs
42215
43051
  })).sort((a, b) => a.mtimeMs - b.mtimeMs);
42216
43052
  while (files.length >= MAX_SNAPSHOTS) {
42217
43053
  const oldest = files.shift();
@@ -42236,7 +43072,7 @@ async function snapshotOne(target, backupDir, now, cwd) {
42236
43072
  if (!db) return;
42237
43073
  opened = db;
42238
43074
  }
42239
- const dest = join19(backupDir, `${target.prefix}-${formatTimestamp(now)}.db`);
43075
+ const dest = join21(backupDir, `${target.prefix}-${formatTimestamp(now)}.db`);
42240
43076
  try {
42241
43077
  db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
42242
43078
  rotateSnapshots(backupDir, target.prefix);
@@ -42257,8 +43093,8 @@ async function vacuumIntoBackup(opts = {}) {
42257
43093
  }
42258
43094
  try {
42259
43095
  const cleoDir = getCleoDir(opts.cwd);
42260
- const backupDir = join19(cleoDir, "backups", "sqlite");
42261
- mkdirSync5(backupDir, { recursive: true });
43096
+ const backupDir = join21(cleoDir, "backups", "sqlite");
43097
+ mkdirSync6(backupDir, { recursive: true });
42262
43098
  const target = SNAPSHOT_TARGETS.find((t) => t.prefix === prefix);
42263
43099
  if (!target) return;
42264
43100
  await snapshotOne(target, backupDir, /* @__PURE__ */ new Date(), opts.cwd);
@@ -42269,13 +43105,13 @@ async function vacuumIntoBackup(opts = {}) {
42269
43105
  function listSqliteBackupsForPrefix(prefix, cwd) {
42270
43106
  try {
42271
43107
  const cleoDir = getCleoDir(cwd);
42272
- const backupDir = join19(cleoDir, "backups", "sqlite");
42273
- if (!existsSync20(backupDir)) return [];
43108
+ const backupDir = join21(cleoDir, "backups", "sqlite");
43109
+ if (!existsSync21(backupDir)) return [];
42274
43110
  const pattern = snapshotPattern(prefix);
42275
- return readdirSync4(backupDir).filter((f) => pattern.test(f)).map((f) => ({
43111
+ return readdirSync5(backupDir).filter((f) => pattern.test(f)).map((f) => ({
42276
43112
  name: f,
42277
- path: join19(backupDir, f),
42278
- mtimeMs: statSync7(join19(backupDir, f)).mtimeMs
43113
+ path: join21(backupDir, f),
43114
+ mtimeMs: statSync7(join21(backupDir, f)).mtimeMs
42279
43115
  })).sort((a, b) => b.mtimeMs - a.mtimeMs);
42280
43116
  } catch {
42281
43117
  return [];
@@ -42331,7 +43167,7 @@ __export(sqlite_native_exports, {
42331
43167
  import { realpathSync } from "node:fs";
42332
43168
  import { createRequire as createRequire8 } from "node:module";
42333
43169
  import { tmpdir } from "node:os";
42334
- import { delimiter, dirname as dirname9, isAbsolute, join as join20, resolve as resolve4, sep } from "node:path";
43170
+ import { delimiter, dirname as dirname9, isAbsolute, join as join22, resolve as resolve4, sep } from "node:path";
42335
43171
  function getDbSyncConstructor() {
42336
43172
  if (_ctor === null) {
42337
43173
  const mod = _require5("node:sqlite");
@@ -42352,7 +43188,7 @@ function resolveAbsoluteSafe(p) {
42352
43188
  missingParts.unshift(cursor.slice(parent.length + (parent.endsWith(sep) ? 0 : 1)));
42353
43189
  cursor = parent;
42354
43190
  try {
42355
- return join20(realpathSync(cursor), ...missingParts);
43191
+ return join22(realpathSync(cursor), ...missingParts);
42356
43192
  } catch {
42357
43193
  }
42358
43194
  }
@@ -42458,7 +43294,7 @@ __export(sqlite_exports, {
42458
43294
  resolveMigrationsFolder: () => resolveMigrationsFolder,
42459
43295
  schema: () => tasks_schema_exports
42460
43296
  });
42461
- import { copyFileSync as copyFileSync6, existsSync as existsSync21, renameSync as renameSync3, unlinkSync as unlinkSync4 } from "node:fs";
43297
+ import { copyFileSync as copyFileSync6, existsSync as existsSync22, renameSync as renameSync3, unlinkSync as unlinkSync4 } from "node:fs";
42462
43298
  import { createRequire as createRequire9 } from "node:module";
42463
43299
  import { eq as eq5 } from "drizzle-orm";
42464
43300
  function _getDrizzle3() {
@@ -42500,7 +43336,7 @@ function countBackupTasks(backupDb) {
42500
43336
  }
42501
43337
  async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
42502
43338
  const { openNativeDatabase: openNativeDatabase2 } = await Promise.resolve().then(() => (init_sqlite_native(), sqlite_native_exports));
42503
- const log11 = getLogger("sqlite");
43339
+ const log12 = getLogger("sqlite");
42504
43340
  try {
42505
43341
  const countResult = nativeDb.prepare("SELECT COUNT(*) as cnt FROM tasks_tasks").get();
42506
43342
  const taskCount = countResult?.cnt ?? 0;
@@ -42526,13 +43362,13 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
42526
43362
  async () => {
42527
43363
  const currentTaskCount = await recountTasksFromDisk(dbPath);
42528
43364
  if (currentTaskCount > 0) {
42529
- log11.info(
43365
+ log12.info(
42530
43366
  { dbPath, currentTaskCount },
42531
43367
  "Auto-recovery skipped: database was populated by a concurrent process while acquiring the first-open lock (T11662 double-checked re-query)."
42532
43368
  );
42533
43369
  return;
42534
43370
  }
42535
- log11.warn(
43371
+ log12.warn(
42536
43372
  { dbPath, backupPath: newestBackup.path, backupTasks: backupTaskCount },
42537
43373
  `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).`
42538
43374
  );
@@ -42552,7 +43388,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
42552
43388
  const tempPath = dbPath + ".recovery-tmp";
42553
43389
  copyFileSync6(newestBackup.path, tempPath);
42554
43390
  renameSync3(tempPath, dbPath);
42555
- log11.info(
43391
+ log12.info(
42556
43392
  { dbPath, backupPath: newestBackup.path, restoredTasks: backupTaskCount },
42557
43393
  "Database auto-recovered from backup successfully."
42558
43394
  );
@@ -42569,7 +43405,7 @@ async function autoRecoverFromBackup(nativeDb, dbPath, cwd) {
42569
43405
  { stale: 6e5, retries: 30 }
42570
43406
  );
42571
43407
  } catch (err) {
42572
- log11.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
43408
+ log12.error({ err, dbPath }, "Auto-recovery from backup failed. Continuing with empty database.");
42573
43409
  }
42574
43410
  }
42575
43411
  async function getDb(cwd) {
@@ -42578,6 +43414,9 @@ async function getDb(cwd) {
42578
43414
  if (_db3 && _dbPath3 !== requestedPath) {
42579
43415
  resetDbState();
42580
43416
  }
43417
+ if (_db3 && (_nativeDb3 === null || !_nativeDb3.isOpen)) {
43418
+ resetDbState();
43419
+ }
42581
43420
  if (_db3) return _db3;
42582
43421
  if (_initPromise4) return _initPromise4;
42583
43422
  _initPromise4 = (async () => {
@@ -42675,7 +43514,7 @@ async function getSchemaVersion(cwd) {
42675
43514
  return result[0]?.value ?? null;
42676
43515
  }
42677
43516
  function dbExists(cwd) {
42678
- return existsSync21(resolveDualScopeDbPath("project", cwd));
43517
+ return existsSync22(resolveDualScopeDbPath("project", cwd));
42679
43518
  }
42680
43519
  function getNativeDb() {
42681
43520
  return _nativeDb3;
@@ -43905,13 +44744,13 @@ var init_sqlite_data_accessor = __esm({
43905
44744
  });
43906
44745
 
43907
44746
  // packages/core/src/sequence/index.ts
43908
- import { existsSync as existsSync22, readFileSync as readFileSync6, renameSync as renameSync4 } from "node:fs";
43909
- import { join as join21 } from "node:path";
44747
+ import { existsSync as existsSync23, readFileSync as readFileSync6, renameSync as renameSync4 } from "node:fs";
44748
+ import { join as join23 } from "node:path";
43910
44749
  function getLegacySequenceJsonPath(cwd) {
43911
- return join21(resolveOrCwd(cwd), ".cleo", ".sequence.json");
44750
+ return join23(resolveOrCwd(cwd), ".cleo", ".sequence.json");
43912
44751
  }
43913
44752
  function getLegacySequencePath(cwd) {
43914
- return join21(resolveOrCwd(cwd), ".cleo", ".sequence");
44753
+ return join23(resolveOrCwd(cwd), ".cleo", ".sequence");
43915
44754
  }
43916
44755
  function isValidSequenceState(value) {
43917
44756
  if (!value || typeof value !== "object") return false;
@@ -43922,7 +44761,7 @@ function isSeedSequence(value) {
43922
44761
  return value.counter === 0 && value.lastId === "T000" && value.checksum === "seed";
43923
44762
  }
43924
44763
  function readLegacySequenceFile(path2) {
43925
- if (!existsSync22(path2)) return null;
44764
+ if (!existsSync23(path2)) return null;
43926
44765
  try {
43927
44766
  const parsed = JSON.parse(readFileSync6(path2, "utf-8"));
43928
44767
  return isValidSequenceState(parsed) ? parsed : null;
@@ -43931,10 +44770,10 @@ function readLegacySequenceFile(path2) {
43931
44770
  }
43932
44771
  }
43933
44772
  function renameLegacyFile(path2) {
43934
- if (!existsSync22(path2)) return;
44773
+ if (!existsSync23(path2)) return;
43935
44774
  const migratedPath = `${path2}.migrated`;
43936
44775
  try {
43937
- if (!existsSync22(migratedPath)) {
44776
+ if (!existsSync23(migratedPath)) {
43938
44777
  renameSync4(path2, migratedPath);
43939
44778
  return;
43940
44779
  }
@@ -44097,15 +44936,15 @@ var init_sequence = __esm({
44097
44936
 
44098
44937
  // packages/core/src/store/git-checkpoint.ts
44099
44938
  import { execFile as execFile2 } from "node:child_process";
44100
- import { existsSync as existsSync23 } from "node:fs";
44101
- import { readFile as readFile3, writeFile } from "node:fs/promises";
44102
- import { join as join22, resolve as resolve5 } from "node:path";
44939
+ import { existsSync as existsSync24 } from "node:fs";
44940
+ import { readFile as readFile4, writeFile } from "node:fs/promises";
44941
+ import { join as join24, resolve as resolve5 } from "node:path";
44103
44942
  import { promisify as promisify2 } from "node:util";
44104
44943
  function makeCleoGitEnv(cleoDir) {
44105
44944
  const abs = resolve5(cleoDir);
44106
44945
  return {
44107
44946
  ...process.env,
44108
- GIT_DIR: join22(abs, ".git"),
44947
+ GIT_DIR: join24(abs, ".git"),
44109
44948
  GIT_WORK_TREE: abs
44110
44949
  };
44111
44950
  }
@@ -44123,7 +44962,7 @@ async function cleoGitCommand(args, cleoDir) {
44123
44962
  }
44124
44963
  }
44125
44964
  function isCleoGitInitialized(cleoDir) {
44126
- return existsSync23(join22(cleoDir, ".git", "HEAD"));
44965
+ return existsSync24(join24(cleoDir, ".git", "HEAD"));
44127
44966
  }
44128
44967
  async function loadStateFileAllowlist(cwd) {
44129
44968
  try {
@@ -44167,26 +45006,26 @@ async function isCleoGitRepo(cleoDir) {
44167
45006
  return result.success && (result.stdout === "true" || isCleoGitInitialized(cleoDir));
44168
45007
  }
44169
45008
  function isMergeInProgress(cleoDir) {
44170
- return existsSync23(join22(cleoDir, ".git", "MERGE_HEAD"));
45009
+ return existsSync24(join24(cleoDir, ".git", "MERGE_HEAD"));
44171
45010
  }
44172
45011
  async function isDetachedHead(cleoDir) {
44173
45012
  const result = await cleoGitCommand(["symbolic-ref", "HEAD"], cleoDir);
44174
45013
  return !result.success;
44175
45014
  }
44176
45015
  function isRebaseInProgress(cleoDir) {
44177
- return existsSync23(join22(cleoDir, ".git", "rebase-merge")) || existsSync23(join22(cleoDir, ".git", "rebase-apply"));
45016
+ return existsSync24(join24(cleoDir, ".git", "rebase-merge")) || existsSync24(join24(cleoDir, ".git", "rebase-apply"));
44178
45017
  }
44179
45018
  async function recordCheckpointTime(cleoDir) {
44180
45019
  try {
44181
- const stateFile = join22(cleoDir, CHECKPOINT_STATE_FILE);
45020
+ const stateFile = join24(cleoDir, CHECKPOINT_STATE_FILE);
44182
45021
  await writeFile(stateFile, String(Math.floor(Date.now() / 1e3)));
44183
45022
  } catch {
44184
45023
  }
44185
45024
  }
44186
45025
  async function getLastCheckpointTime(cleoDir) {
44187
45026
  try {
44188
- const stateFile = join22(cleoDir, CHECKPOINT_STATE_FILE);
44189
- const content = await readFile3(stateFile, "utf-8");
45027
+ const stateFile = join24(cleoDir, CHECKPOINT_STATE_FILE);
45028
+ const content = await readFile4(stateFile, "utf-8");
44190
45029
  const epoch = parseInt(content.trim(), 10);
44191
45030
  return Number.isNaN(epoch) ? 0 : epoch;
44192
45031
  } catch {
@@ -44197,8 +45036,8 @@ async function getChangedStateFiles(cleoDir, cwd) {
44197
45036
  const changed = [];
44198
45037
  const allStateFiles = await getAllStateFiles(cwd);
44199
45038
  for (const stateFile of allStateFiles) {
44200
- const fullPath = join22(cleoDir, stateFile);
44201
- if (!existsSync23(fullPath)) continue;
45039
+ const fullPath = join24(cleoDir, stateFile);
45040
+ if (!existsSync24(fullPath)) continue;
44202
45041
  const diffResult = await cleoGitCommand(["diff", "--quiet", "--", stateFile], cleoDir);
44203
45042
  const cachedResult = await cleoGitCommand(
44204
45043
  ["diff", "--cached", "--quiet", "--", stateFile],
@@ -44225,7 +45064,7 @@ async function shouldCheckpoint(options) {
44225
45064
  const config = await loadCheckpointConfig(cwd);
44226
45065
  if (!config.enabled) return false;
44227
45066
  const cleoDir = getCleoDir(cwd);
44228
- if (!existsSync23(cleoDir)) return false;
45067
+ if (!existsSync24(cleoDir)) return false;
44229
45068
  if (!isCleoGitInitialized(cleoDir)) return false;
44230
45069
  if (!await isCleoGitRepo(cleoDir)) return false;
44231
45070
  if (isMergeInProgress(cleoDir)) return false;
@@ -44303,7 +45142,7 @@ async function ensureSequenceValid(cwd, options) {
44303
45142
  if (!options?.validateSequence) return;
44304
45143
  const check = await checkSequence(cwd);
44305
45144
  if (!check.valid) {
44306
- log9.warn({ counter: check.counter, maxId: check.maxIdInData }, "Sequence behind, repairing");
45145
+ log10.warn({ counter: check.counter, maxId: check.maxIdInData }, "Sequence behind, repairing");
44307
45146
  const repair = await repairSequence(cwd);
44308
45147
  if (!repair.repaired && options.strict) {
44309
45148
  throw new DataSafetyError(`Sequence repair failed: ${repair.message}`, "SEQUENCE_INVALID", {
@@ -44320,7 +45159,7 @@ async function checkpoint(context, cwd, options) {
44320
45159
  stats.checkpoints++;
44321
45160
  stats.lastCheckpoint = /* @__PURE__ */ new Date();
44322
45161
  } catch (err) {
44323
- log9.warn({ err }, "Checkpoint failed (non-fatal)");
45162
+ log10.warn({ err }, "Checkpoint failed (non-fatal)");
44324
45163
  }
44325
45164
  vacuumIntoBackup({ cwd }).catch(() => {
44326
45165
  });
@@ -44382,7 +45221,7 @@ async function safeAppendLog(accessor, entry, cwd, options) {
44382
45221
  stats.writes++;
44383
45222
  await checkpoint("log entry", cwd, opts);
44384
45223
  }
44385
- var log9, DataSafetyError, DEFAULT_SAFETY, stats;
45224
+ var log10, DataSafetyError, DEFAULT_SAFETY, stats;
44386
45225
  var init_data_safety_central = __esm({
44387
45226
  "packages/core/src/store/data-safety-central.ts"() {
44388
45227
  "use strict";
@@ -44392,7 +45231,7 @@ var init_data_safety_central = __esm({
44392
45231
  init_sqlite3();
44393
45232
  init_sqlite_backup();
44394
45233
  init_tasks_schema();
44395
- log9 = getLogger("data-safety");
45234
+ log10 = getLogger("data-safety");
44396
45235
  DataSafetyError = class extends Error {
44397
45236
  constructor(message, code, context) {
44398
45237
  super(message);
@@ -44432,7 +45271,7 @@ function isSafetyDisabled() {
44432
45271
  }
44433
45272
  function wrapWithSafety(accessor, cwd) {
44434
45273
  if (isSafetyDisabled()) {
44435
- log10.warn(
45274
+ log11.warn(
44436
45275
  "Safety disabled - emergency mode (CLEO_DISABLE_SAFETY=true). Data integrity checks bypassed."
44437
45276
  );
44438
45277
  return accessor;
@@ -44453,13 +45292,13 @@ function getSafetyStatus() {
44453
45292
  enabled: true
44454
45293
  };
44455
45294
  }
44456
- var log10, SafetyDataAccessor;
45295
+ var log11, SafetyDataAccessor;
44457
45296
  var init_safety_data_accessor = __esm({
44458
45297
  "packages/core/src/store/safety-data-accessor.ts"() {
44459
45298
  "use strict";
44460
45299
  init_logger2();
44461
45300
  init_data_safety_central();
44462
- log10 = getLogger("data-safety");
45301
+ log11 = getLogger("data-safety");
44463
45302
  SafetyDataAccessor = class {
44464
45303
  /** The underlying accessor being wrapped. */
44465
45304
  inner;
@@ -44483,7 +45322,7 @@ var init_safety_data_accessor = __esm({
44483
45322
  ...config
44484
45323
  };
44485
45324
  if (this.config.verbose) {
44486
- log10.debug({ engine: inner.engine }, "SafetyDataAccessor initialized");
45325
+ log11.debug({ engine: inner.engine }, "SafetyDataAccessor initialized");
44487
45326
  }
44488
45327
  }
44489
45328
  /** The storage engine backing this accessor. */
@@ -44495,7 +45334,7 @@ var init_safety_data_accessor = __esm({
44495
45334
  */
44496
45335
  logVerbose(message) {
44497
45336
  if (this.config.verbose) {
44498
- log10.debug(message);
45337
+ log11.debug(message);
44499
45338
  }
44500
45339
  }
44501
45340
  /**