@cleocode/core 2026.9.25 → 2026.9.26

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 (208) hide show
  1. package/dist/admin/import-tasks.d.ts.map +1 -1
  2. package/dist/admin/import-tasks.js +5 -2
  3. package/dist/admin/import-tasks.js.map +1 -1
  4. package/dist/admin/import.d.ts.map +1 -1
  5. package/dist/admin/import.js +7 -2
  6. package/dist/admin/import.js.map +1 -1
  7. package/dist/build-provenance.json +2 -2
  8. package/dist/cloud/index.d.ts +1 -0
  9. package/dist/cloud/index.d.ts.map +1 -1
  10. package/dist/cloud/index.js +1 -0
  11. package/dist/cloud/index.js.map +1 -1
  12. package/dist/cloud/nexus-auth.d.ts +26 -1
  13. package/dist/cloud/nexus-auth.d.ts.map +1 -1
  14. package/dist/cloud/nexus-auth.js +61 -32
  15. package/dist/cloud/nexus-auth.js.map +1 -1
  16. package/dist/cloud/nexus-credentials.js +2 -2
  17. package/dist/cloud/nexus-credentials.js.map +1 -1
  18. package/dist/cloud/nexus-device.d.ts +809 -0
  19. package/dist/cloud/nexus-device.d.ts.map +1 -0
  20. package/dist/cloud/nexus-device.js +1680 -0
  21. package/dist/cloud/nexus-device.js.map +1 -0
  22. package/dist/cloud/nexus-enrol.d.ts +210 -0
  23. package/dist/cloud/nexus-enrol.d.ts.map +1 -0
  24. package/dist/cloud/nexus-enrol.js +1023 -0
  25. package/dist/cloud/nexus-enrol.js.map +1 -0
  26. package/dist/cloud/nexus-link.d.ts +3 -0
  27. package/dist/cloud/nexus-link.d.ts.map +1 -1
  28. package/dist/cloud/nexus-link.js +38 -4
  29. package/dist/cloud/nexus-link.js.map +1 -1
  30. package/dist/cloud/signing.d.ts +20 -0
  31. package/dist/cloud/signing.d.ts.map +1 -1
  32. package/dist/cloud/signing.js +14 -0
  33. package/dist/cloud/signing.js.map +1 -1
  34. package/dist/crypto/credentials.d.ts +61 -0
  35. package/dist/crypto/credentials.d.ts.map +1 -1
  36. package/dist/crypto/credentials.js +154 -58
  37. package/dist/crypto/credentials.js.map +1 -1
  38. package/dist/docs/export-document.js +830 -190
  39. package/dist/docs/export-document.js.map +3 -3
  40. package/dist/doctor/dependency-cycles.d.ts +41 -0
  41. package/dist/doctor/dependency-cycles.d.ts.map +1 -0
  42. package/dist/doctor/dependency-cycles.js +39 -0
  43. package/dist/doctor/dependency-cycles.js.map +1 -0
  44. package/dist/doctor/index.d.ts +2 -0
  45. package/dist/doctor/index.d.ts.map +1 -1
  46. package/dist/doctor/index.js +1 -0
  47. package/dist/doctor/index.js.map +1 -1
  48. package/dist/doctor/row-identity.d.ts +11 -0
  49. package/dist/doctor/row-identity.d.ts.map +1 -1
  50. package/dist/doctor/row-identity.js +67 -9
  51. package/dist/doctor/row-identity.js.map +1 -1
  52. package/dist/error-catalog.d.ts.map +1 -1
  53. package/dist/error-catalog.js +4 -0
  54. package/dist/error-catalog.js.map +1 -1
  55. package/dist/error-registry.d.ts.map +1 -1
  56. package/dist/error-registry.js +8 -0
  57. package/dist/error-registry.js.map +1 -1
  58. package/dist/llm/plugin-facade.js +857 -217
  59. package/dist/llm/plugin-facade.js.map +3 -3
  60. package/dist/nexus/workspace.d.ts.map +1 -1
  61. package/dist/nexus/workspace.js +54 -4
  62. package/dist/nexus/workspace.js.map +1 -1
  63. package/dist/orchestrate/lifecycle-ops.js +1 -1
  64. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  65. package/dist/orchestrate/pivot.d.ts.map +1 -1
  66. package/dist/orchestrate/pivot.js +4 -2
  67. package/dist/orchestrate/pivot.js.map +1 -1
  68. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  69. package/dist/orchestrate/query-ops.js +3 -3
  70. package/dist/orchestrate/query-ops.js.map +1 -1
  71. package/dist/orchestrate/spawn-ops.js +1 -1
  72. package/dist/orchestrate/spawn-ops.js.map +1 -1
  73. package/dist/orchestration/index.js +1 -1
  74. package/dist/orchestration/index.js.map +1 -1
  75. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  76. package/dist/orchestration/lead-rollup.js +3 -3
  77. package/dist/orchestration/lead-rollup.js.map +1 -1
  78. package/dist/orchestration/parallel.js +1 -1
  79. package/dist/orchestration/parallel.js.map +1 -1
  80. package/dist/orchestration/wave-topic.d.ts +4 -2
  81. package/dist/orchestration/wave-topic.d.ts.map +1 -1
  82. package/dist/orchestration/wave-topic.js +6 -4
  83. package/dist/orchestration/wave-topic.js.map +1 -1
  84. package/dist/orchestration/waves.d.ts +2 -1
  85. package/dist/orchestration/waves.d.ts.map +1 -1
  86. package/dist/orchestration/waves.js +4 -3
  87. package/dist/orchestration/waves.js.map +1 -1
  88. package/dist/phases/index.d.ts.map +1 -1
  89. package/dist/phases/index.js +4 -2
  90. package/dist/phases/index.js.map +1 -1
  91. package/dist/selfimprove/fix-gen.js +856 -216
  92. package/dist/selfimprove/fix-gen.js.map +3 -3
  93. package/dist/session/engine-ops.d.ts.map +1 -1
  94. package/dist/session/engine-ops.js +77 -49
  95. package/dist/session/engine-ops.js.map +1 -1
  96. package/dist/sessions/focus-state-store.d.ts +69 -23
  97. package/dist/sessions/focus-state-store.d.ts.map +1 -1
  98. package/dist/sessions/focus-state-store.js +113 -27
  99. package/dist/sessions/focus-state-store.js.map +1 -1
  100. package/dist/sessions/handoff.js +1 -1
  101. package/dist/sessions/handoff.js.map +1 -1
  102. package/dist/sessions/index.d.ts.map +1 -1
  103. package/dist/sessions/index.js +24 -13
  104. package/dist/sessions/index.js.map +1 -1
  105. package/dist/sessions/terminal-identity.d.ts +165 -17
  106. package/dist/sessions/terminal-identity.d.ts.map +1 -1
  107. package/dist/sessions/terminal-identity.js +341 -32
  108. package/dist/sessions/terminal-identity.js.map +1 -1
  109. package/dist/skills/orchestrator/startup.js +2 -2
  110. package/dist/skills/orchestrator/startup.js.map +1 -1
  111. package/dist/snapshot/index.d.ts +4 -0
  112. package/dist/snapshot/index.d.ts.map +1 -1
  113. package/dist/snapshot/index.js +50 -3
  114. package/dist/snapshot/index.js.map +1 -1
  115. package/dist/store/db-helpers.d.ts +15 -2
  116. package/dist/store/db-helpers.d.ts.map +1 -1
  117. package/dist/store/db-helpers.js +84 -3
  118. package/dist/store/db-helpers.js.map +1 -1
  119. package/dist/store/dependency-cycles.d.ts +164 -0
  120. package/dist/store/dependency-cycles.d.ts.map +1 -0
  121. package/dist/store/dependency-cycles.js +360 -0
  122. package/dist/store/dependency-cycles.js.map +1 -0
  123. package/dist/store/display-id-alias.d.ts +93 -37
  124. package/dist/store/display-id-alias.d.ts.map +1 -1
  125. package/dist/store/display-id-alias.js +590 -115
  126. package/dist/store/display-id-alias.js.map +1 -1
  127. package/dist/store/dual-scope-db.d.ts.map +1 -1
  128. package/dist/store/dual-scope-db.js +34 -7
  129. package/dist/store/dual-scope-db.js.map +1 -1
  130. package/dist/store/exodus/migrate.d.ts.map +1 -1
  131. package/dist/store/exodus/migrate.js +8 -1
  132. package/dist/store/exodus/migrate.js.map +1 -1
  133. package/dist/store/global-salt.d.ts +35 -0
  134. package/dist/store/global-salt.d.ts.map +1 -1
  135. package/dist/store/global-salt.js +136 -16
  136. package/dist/store/global-salt.js.map +1 -1
  137. package/dist/store/migration-sqlite.d.ts.map +1 -1
  138. package/dist/store/migration-sqlite.js +19 -11
  139. package/dist/store/migration-sqlite.js.map +1 -1
  140. package/dist/store/portable-bundle-scan.d.ts.map +1 -1
  141. package/dist/store/portable-bundle-scan.js +6 -0
  142. package/dist/store/portable-bundle-scan.js.map +1 -1
  143. package/dist/store/row-identity-registry.d.ts.map +1 -1
  144. package/dist/store/row-identity-registry.js +11 -3
  145. package/dist/store/row-identity-registry.js.map +1 -1
  146. package/dist/store/row-identity.d.ts +91 -1
  147. package/dist/store/row-identity.d.ts.map +1 -1
  148. package/dist/store/row-identity.js +276 -7
  149. package/dist/store/row-identity.js.map +1 -1
  150. package/dist/store/safety-data-accessor.d.ts +3 -2
  151. package/dist/store/safety-data-accessor.d.ts.map +1 -1
  152. package/dist/store/safety-data-accessor.js +5 -2
  153. package/dist/store/safety-data-accessor.js.map +1 -1
  154. package/dist/store/session-store.d.ts +63 -3
  155. package/dist/store/session-store.d.ts.map +1 -1
  156. package/dist/store/session-store.js +121 -8
  157. package/dist/store/session-store.js.map +1 -1
  158. package/dist/store/split-brain-import.d.ts.map +1 -1
  159. package/dist/store/split-brain-import.js +36 -0
  160. package/dist/store/split-brain-import.js.map +1 -1
  161. package/dist/store/sqlite-data-accessor.d.ts +50 -3
  162. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  163. package/dist/store/sqlite-data-accessor.js +246 -13
  164. package/dist/store/sqlite-data-accessor.js.map +1 -1
  165. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  166. package/dist/store/tasks-sqlite.js +14 -2
  167. package/dist/store/tasks-sqlite.js.map +1 -1
  168. package/dist/store/umbrella-data-accessor.d.ts +3 -2
  169. package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
  170. package/dist/store/umbrella-data-accessor.js +5 -2
  171. package/dist/store/umbrella-data-accessor.js.map +1 -1
  172. package/dist/system/health.d.ts +2 -0
  173. package/dist/system/health.d.ts.map +1 -1
  174. package/dist/system/health.js +54 -0
  175. package/dist/system/health.js.map +1 -1
  176. package/dist/task-work/index.d.ts.map +1 -1
  177. package/dist/task-work/index.js +9 -6
  178. package/dist/task-work/index.js.map +1 -1
  179. package/dist/tasks/analyze.d.ts.map +1 -1
  180. package/dist/tasks/analyze.js +3 -2
  181. package/dist/tasks/analyze.js.map +1 -1
  182. package/dist/tasks/evidence.d.ts +19 -1
  183. package/dist/tasks/evidence.d.ts.map +1 -1
  184. package/dist/tasks/evidence.js +79 -18
  185. package/dist/tasks/evidence.js.map +1 -1
  186. package/dist/tasks/infer-add-params.js +1 -1
  187. package/dist/tasks/infer-add-params.js.map +1 -1
  188. package/dist/tasks/task-context.d.ts.map +1 -1
  189. package/dist/tasks/task-context.js +3 -1
  190. package/dist/tasks/task-context.js.map +1 -1
  191. package/dist/tasks/task-import.d.ts.map +1 -1
  192. package/dist/tasks/task-import.js +11 -3
  193. package/dist/tasks/task-import.js.map +1 -1
  194. package/dist/tasks/task-next.d.ts +5 -1
  195. package/dist/tasks/task-next.d.ts.map +1 -1
  196. package/dist/tasks/task-next.js +7 -2
  197. package/dist/tasks/task-next.js.map +1 -1
  198. package/dist/validation/engine-ops.d.ts.map +1 -1
  199. package/dist/validation/engine-ops.js +3 -2
  200. package/dist/validation/engine-ops.js.map +1 -1
  201. package/dist/workgraph/scaffold-apply.d.ts.map +1 -1
  202. package/dist/workgraph/scaffold-apply.js +14 -5
  203. package/dist/workgraph/scaffold-apply.js.map +1 -1
  204. package/migrations/drizzle-cleo-project/20260930160000_t12886-dependency-cycle-guard/migration.sql +76 -0
  205. package/migrations/drizzle-cleo-project/20260930160000_t12886-dependency-cycle-guard/revert.sql +7 -0
  206. package/package.json +13 -13
  207. package/templates/CLEO-INJECTION.md +2 -2
  208. package/templates/CLEO-REFERENCE.md +1 -1
@@ -1850,7 +1850,7 @@ var init_output_contracts_data = __esm({
1850
1850
  // T12503: the optimistic-concurrency version agents pass to --if-match.
1851
1851
  updatedAt: {
1852
1852
  type: ["string", "null"],
1853
- description: "Task version for optimistic concurrency: pass it to `cleo update|complete --if-match`."
1853
+ description: "Task version for optimistic concurrency: pass it to `cleo update|complete --if-match`. A stale version fails with E_CONFLICT (23); E_TASK_RENAMED (26) when sync re-numbered the task you read (details.expected is its new id)."
1854
1854
  },
1855
1855
  // T12502: the human assignee and the agent claim lease are separate.
1856
1856
  assignee: {
@@ -13111,6 +13111,7 @@ var init_exit_codes = __esm({
13111
13111
  ExitCode2[ExitCode2["VERSION_CONFLICT"] = 23] = "VERSION_CONFLICT";
13112
13112
  ExitCode2[ExitCode2["SESSION_UNBOUND"] = 24] = "SESSION_UNBOUND";
13113
13113
  ExitCode2[ExitCode2["WORKTREE_LOCKED"] = 25] = "WORKTREE_LOCKED";
13114
+ ExitCode2[ExitCode2["TASK_RENAMED"] = 26] = "TASK_RENAMED";
13114
13115
  ExitCode2[ExitCode2["SESSION_EXISTS"] = 30] = "SESSION_EXISTS";
13115
13116
  ExitCode2[ExitCode2["SESSION_NOT_FOUND"] = 31] = "SESSION_NOT_FOUND";
13116
13117
  ExitCode2[ExitCode2["SCOPE_CONFLICT"] = 32] = "SCOPE_CONFLICT";
@@ -17771,6 +17772,19 @@ var init_error_catalog = __esm({
17771
17772
  `Bind a session: run 'cleo session start --scope global --name "<name>"', 'cleo session resume <id>', or set CLEO_SESSION_ID=<id>.`
17772
17773
  )
17773
17774
  ],
17775
+ [
17776
+ 26 /* TASK_RENAMED */,
17777
+ def(
17778
+ 26 /* TASK_RENAMED */,
17779
+ "TASK_RENAMED",
17780
+ "CONFLICT",
17781
+ "Task was re-numbered by sync",
17782
+ 409,
17783
+ true,
17784
+ "E_TASK_RENAMED",
17785
+ "The task you addressed now has another id (a display-id collision re-numbered it). Re-read it with 'cleo show <new id>' and retry against that id."
17786
+ )
17787
+ ],
17774
17788
  [
17775
17789
  25 /* WORKTREE_LOCKED */,
17776
17790
  def(
@@ -19718,10 +19732,10 @@ var init_table2 = __esm({
19718
19732
  [IsDrizzleTable] = true;
19719
19733
  /** @internal */
19720
19734
  [ExtraConfigBuilder] = void 0;
19721
- constructor(name2, schema, baseName) {
19735
+ constructor(name2, schema, baseName2) {
19722
19736
  this[TableName] = this[OriginalName] = name2;
19723
19737
  this[TableSchema] = schema;
19724
- this[BaseName] = baseName;
19738
+ this[BaseName] = baseName2;
19725
19739
  }
19726
19740
  };
19727
19741
  }
@@ -21651,9 +21665,9 @@ var init_casing = __esm({
21651
21665
  });
21652
21666
 
21653
21667
  // node_modules/.pnpm/drizzle-orm@1.0.0-rc.4_@opentelemetry+api@1.9.0_@sinclair+typebox@0.34.49_@types+mssql@_b4e81f2ea693a7363d3e5dc2205249c6/node_modules/drizzle-orm/sqlite-core/table.js
21654
- function sqliteTableBase(name2, columns, extraConfig, schema, casing, baseName = name2) {
21668
+ function sqliteTableBase(name2, columns, extraConfig, schema, casing, baseName2 = name2) {
21655
21669
  const casingFn = getCasingFn(casing);
21656
- const rawTable = new SQLiteTable(name2, schema, baseName);
21670
+ const rawTable = new SQLiteTable(name2, schema, baseName2);
21657
21671
  const parsedColumns = typeof columns === "function" ? columns(getSQLiteColumnBuilders()) : columns;
21658
21672
  const builtColumns = Object.fromEntries(Object.entries(parsedColumns).map(([name3, colBuilderBase]) => {
21659
21673
  const colBuilder = colBuilderBase;
@@ -25450,6 +25464,10 @@ function decisionFor(dbPath) {
25450
25464
  if (!decisions.has(key)) decisions.set(key, schemaWriteRefusal(key));
25451
25465
  return decisions.get(key) ?? null;
25452
25466
  }
25467
+ function schemaWritesAllowed(nativeDb) {
25468
+ const dbPath = nativeDb.location();
25469
+ return !dbPath || decisionFor(dbPath) === null;
25470
+ }
25453
25471
  function isWorktreeBuildSchemaError(error) {
25454
25472
  return error instanceof Error && error.message.includes(E_WORKTREE_BUILD_SCHEMA);
25455
25473
  }
@@ -26488,7 +26506,10 @@ var init_row_identity_registry = __esm({
26488
26506
  key: ["id"],
26489
26507
  birth: "recorded_at",
26490
26508
  content: ["ac_id", "previous_text", "reason"],
26491
- birthFacts: ["ac_id", "previous_text", "reason", "@refFp:ac_uid"],
26509
+ // v2 (T12802): no @refFp: the criterion's fingerprint is unknowable when
26510
+ // it was gone before this row got its identity, so it made the value
26511
+ // depend on fill timing. ac_id is always known.
26512
+ birthFacts: ["ac_id", "previous_text", "reason"],
26492
26513
  storedRefUids: [{ column: "ac_uid", from: "ac_id", table: ACS }],
26493
26514
  task: "T12341"
26494
26515
  },
@@ -26497,7 +26518,10 @@ var init_row_identity_registry = __esm({
26497
26518
  kind: "minted",
26498
26519
  key: ["id"],
26499
26520
  birth: "created_at",
26500
- birthFacts: ["evidence_atom_id", "binding_type", "ac_text_hash", "@refFp:ac_uid"],
26521
+ // v2 (T12802): ac_id in place of @refFp:ac_uid and ac_text_hash. Both
26522
+ // were filled from the criterion, so a backfilled binding whose
26523
+ // criterion was already gone got a different value (see AC history).
26524
+ birthFacts: ["evidence_atom_id", "binding_type", "ac_id"],
26501
26525
  storedRefUids: [
26502
26526
  { column: "ac_uid", from: "ac_id", table: ACS },
26503
26527
  { column: "ac_text_hash", from: "ac_id", table: ACS, source: "text_hash" }
@@ -26539,7 +26563,9 @@ var init_row_identity_registry = __esm({
26539
26563
  // The uid IS the primary key: display-id-alias.ts computes it on write.
26540
26564
  table: "tasks_display_id_aliases",
26541
26565
  kind: "natural",
26542
- key: ["entity_table", "display_id", "entity_uid"],
26566
+ // T12800: the reason is part of the key (collision-remint and
26567
+ // remint-assigned of one id and row are distinct facts).
26568
+ key: ["entity_table", "display_id", "entity_uid", "reason"],
26543
26569
  task: "T12341"
26544
26570
  },
26545
26571
  {
@@ -27121,6 +27147,20 @@ function installRowUidTriggers(db, scope) {
27121
27147
  );
27122
27148
  }
27123
27149
  }
27150
+ function v1ReleaseBirthFp(db, table, row) {
27151
+ const col = (c) => row[c] ?? null;
27152
+ const facts = table === "tasks_task_acceptance_criteria_history" ? [col("ac_id"), col("previous_text"), col("reason")] : table === "tasks_evidence_ac_bindings" ? [col("evidence_atom_id"), col("binding_type"), col("ac_text_hash")] : [];
27153
+ if (facts.length === 0) return null;
27154
+ const acUid = col("ac_uid");
27155
+ let ref = "ref:none";
27156
+ if (acUid !== null) {
27157
+ const ac = db.prepare("SELECT birth_fp AS fp FROM main.tasks_task_acceptance_criteria WHERE uid = ?").get(acUid);
27158
+ ref = ac === void 0 ? "ref:missing" : ac.fp;
27159
+ if (ref === null) return null;
27160
+ }
27161
+ const spec = rowIdentitySpec("project", table);
27162
+ return birthFingerprint(table, spec?.birth ? col(spec.birth) : null, [...facts, ref]);
27163
+ }
27124
27164
  function hasObject(db, type, name2) {
27125
27165
  return db.prepare("SELECT 1 FROM main.sqlite_master WHERE type = ? AND name = ?").get(type, name2) !== void 0;
27126
27166
  }
@@ -27204,24 +27244,41 @@ function preReleaseBirthFp(db, table, row) {
27204
27244
  function resetStaleIdentity(db, scope, writers) {
27205
27245
  if (scope !== "project" || !hasTable(db, ROW_IDENTITY_META_TABLE)) return "none";
27206
27246
  if (readMeta(db, ROW_IDENTITY_RECIPE_KEY) === ROW_IDENTITY_RECIPE) return "none";
27207
- const minted = ROW_IDENTITY.project.filter(
27208
- (spec) => spec.kind === "minted" && hasTable(db, spec.table) && columnsOf(db, spec.table).has(BIRTH_FP_COLUMN)
27247
+ const minted = fingerprintOrder("project", ROW_IDENTITY.project).filter(
27248
+ (spec) => hasTable(db, spec.table) && columnsOf(db, spec.table).has(BIRTH_FP_COLUMN)
27209
27249
  );
27210
27250
  const stale = [];
27251
+ const cleared = /* @__PURE__ */ new Map();
27252
+ const mark = (table, column, value) => {
27253
+ if (value === null || value === void 0) return;
27254
+ const key = `${table}.${column}`;
27255
+ const set = cleared.get(key) ?? /* @__PURE__ */ new Set();
27256
+ set.add(String(value));
27257
+ cleared.set(key, set);
27258
+ };
27211
27259
  for (const spec of minted) {
27260
+ const deps = (spec.birthFacts ?? []).map((fact) => fingerprintRef("project", spec, fact)).filter((d) => d !== null);
27261
+ const keyColumn = targetKey("project", spec.table);
27212
27262
  const rows = db.prepare(
27213
27263
  `SELECT rowid AS _rowid, * FROM main.${q(spec.table)} WHERE ${q(BIRTH_FP_COLUMN)} IS NOT NULL`
27214
27264
  ).all();
27215
27265
  for (const row of rows) {
27216
- if (row[BIRTH_FP_COLUMN] === preReleaseBirthFp(db, spec.table, row)) {
27266
+ const derivedFromStale = deps.some(
27267
+ (d) => cleared.get(`${d.table}.${d.key}`)?.has(String(row[d.column] ?? ""))
27268
+ );
27269
+ if (derivedFromStale || row[BIRTH_FP_COLUMN] === preReleaseBirthFp(db, spec.table, row) || row[BIRTH_FP_COLUMN] === v1ReleaseBirthFp(db, spec.table, row)) {
27217
27270
  stale.push({ table: spec.table, rowid: row._rowid });
27271
+ mark(spec.table, keyColumn, row[keyColumn]);
27272
+ mark(spec.table, UID_COLUMN, row[UID_COLUMN]);
27218
27273
  }
27219
27274
  }
27220
27275
  }
27221
- if (stale.length === 0) return "none";
27276
+ const graveyardRows = scope === "project" && hasTable(db, AC_UID_GRAVEYARD) ? db.prepare(`SELECT count(*) AS n FROM main.${AC_UID_GRAVEYARD}`).get().n : 0;
27277
+ if (stale.length === 0 && graveyardRows === 0) return "none";
27222
27278
  if (readMeta(db, ROW_IDENTITY_SYNCED_KEY) !== void 0) return "refused";
27223
27279
  db.exec("SAVEPOINT row_identity_reset");
27224
27280
  try {
27281
+ if (graveyardRows > 0) writers.clearAcUidGraveyardNative(db);
27225
27282
  for (const { table, rowid } of stale) {
27226
27283
  writers.clearBirthFpNative(db, table, rowid);
27227
27284
  }
@@ -27237,6 +27294,106 @@ function writeRecipeMarker(db, writers = requireWriters()) {
27237
27294
  if (!hasTable(db, ROW_IDENTITY_META_TABLE)) return;
27238
27295
  writers.writeRowIdentityMetaNative(db, ROW_IDENTITY_RECIPE_KEY, ROW_IDENTITY_RECIPE);
27239
27296
  }
27297
+ function rowIdentityShared(db) {
27298
+ return readMeta(db, ROW_IDENTITY_SYNCED_KEY) !== void 0;
27299
+ }
27300
+ function healRowIdentitySchema(db, scope, writers = registeredWriters) {
27301
+ const log15 = getLogger("row-identity");
27302
+ if (ROW_IDENTITY[scope].length === 0) {
27303
+ return [];
27304
+ }
27305
+ if (!schemaWritesAllowed(db)) {
27306
+ log15.debug({ scope }, "row identity schema heal skipped: schema writes refused for this build");
27307
+ return [];
27308
+ }
27309
+ try {
27310
+ db.exec("SAVEPOINT row_identity_heal");
27311
+ try {
27312
+ const healed = [
27313
+ ...scope === "project" ? ensureIdentityTables(db) : [],
27314
+ ...ensureRowIdentitySchema(db, scope)
27315
+ ];
27316
+ if (healed.length > 0) recordHealReceipt(db, scope, healed, writers);
27317
+ db.exec("RELEASE SAVEPOINT row_identity_heal");
27318
+ if (healed.length > 0)
27319
+ log15.info({ scope, healed: healed.length }, "row identity schema healed");
27320
+ return healed;
27321
+ } catch (error) {
27322
+ db.exec("ROLLBACK TO SAVEPOINT row_identity_heal");
27323
+ db.exec("RELEASE SAVEPOINT row_identity_heal");
27324
+ throw error;
27325
+ }
27326
+ } catch (error) {
27327
+ log15.error({ scope, error }, "row identity schema heal failed");
27328
+ return [];
27329
+ }
27330
+ }
27331
+ function recordHealReceipt(db, scope, healed, writers) {
27332
+ const table = HEAL_RECEIPT_TABLE[scope];
27333
+ const log15 = getLogger("row-identity");
27334
+ if (table === null || !hasTable(db, table) || !writers) {
27335
+ log15.warn({ scope, healed: healed.length }, "row identity schema healed; no receipt table");
27336
+ return;
27337
+ }
27338
+ const objects = healed.map((stmt) => {
27339
+ const col = /ALTER TABLE main\.("?)(\w+)\1 ADD COLUMN ("?)(\w+)\3/.exec(stmt);
27340
+ if (col) return `${col[2]}.${col[4]}`;
27341
+ const obj = /(TABLE|INDEX|TRIGGER) IF NOT EXISTS main\.("?)(\w+)\2/.exec(stmt);
27342
+ return obj ? `${obj[1].toLowerCase()} ${obj[3]}` : stmt.slice(0, 60);
27343
+ });
27344
+ const receipt2 = {
27345
+ at: (/* @__PURE__ */ new Date()).toISOString(),
27346
+ scope,
27347
+ statements: healed.length,
27348
+ objects
27349
+ };
27350
+ const history = [...readRowIdentityHealHistory(db), receipt2].slice(-HEAL_RECEIPTS_KEPT);
27351
+ writers.writeRowIdentityMetaNative(db, ROW_IDENTITY_HEAL_KEY, JSON.stringify(history));
27352
+ }
27353
+ function readRowIdentityHealHistory(db) {
27354
+ const raw = readMeta(db, ROW_IDENTITY_HEAL_KEY);
27355
+ if (raw === void 0) return [];
27356
+ try {
27357
+ const parsed = JSON.parse(raw);
27358
+ return Array.isArray(parsed) ? parsed : [parsed];
27359
+ } catch {
27360
+ return [];
27361
+ }
27362
+ }
27363
+ function missingRowIdentitySchema(db) {
27364
+ if (!hasTable(db, "tasks_task_acceptance_criteria")) return [];
27365
+ const missing = [];
27366
+ for (const table of Object.keys(IDENTITY_TABLE_DDL)) {
27367
+ if (!hasTable(db, table)) missing.push(`table ${table}`);
27368
+ }
27369
+ for (const [table, column] of [
27370
+ ["tasks_display_id_aliases", "displaced_hlc"],
27371
+ ["tasks_display_id_aliases", "entity_birth_fp"],
27372
+ [AC_UID_GRAVEYARD, "birth_fp"]
27373
+ ]) {
27374
+ if (hasTable(db, table) && !columnsOf(db, table).has(column)) {
27375
+ missing.push(`column ${table}.${column}`);
27376
+ }
27377
+ }
27378
+ if (!hasObject(db, "trigger", "trg_tasks_ac_uid_graveyard")) {
27379
+ missing.push("trigger trg_tasks_ac_uid_graveyard");
27380
+ }
27381
+ for (const spec of ROW_IDENTITY.project) {
27382
+ if (!hasTable(db, spec.table)) continue;
27383
+ const cols = columnsOf(db, spec.table);
27384
+ for (const column of rowIdentityColumns("project", spec.table)) {
27385
+ if (!cols.has(column)) missing.push(`column ${spec.table}.${column}`);
27386
+ }
27387
+ if (!uidIsPrimaryKey(db, spec.table) && !hasObject(db, "index", `uq_${spec.table}_uid`)) {
27388
+ missing.push(`index uq_${spec.table}_uid`);
27389
+ }
27390
+ for (const ref of spec.storedRefUids ?? []) {
27391
+ const index2 = `idx_${spec.table}_${ref.column}`;
27392
+ if (!hasObject(db, "index", index2)) missing.push(`index ${index2}`);
27393
+ }
27394
+ }
27395
+ return missing;
27396
+ }
27240
27397
  function prepareRowIdentity(db, scope, options = {}) {
27241
27398
  if (ROW_IDENTITY[scope].length === 0) return null;
27242
27399
  if (!rowUidFillEnabled()) return null;
@@ -27275,7 +27432,7 @@ function prepareRowIdentity(db, scope, options = {}) {
27275
27432
  return null;
27276
27433
  }
27277
27434
  }
27278
- var ROW_UID_DOMAIN, ROW_BIRTH_DOMAIN, ROW_UID_SQL_FUNCTION, ROW_BIRTH_FP_SQL_FUNCTION, ROW_RANDOM_UID_SQL_FUNCTION, AC_TEXT_HASH_SQL_FUNCTION, AC_UID_GRAVEYARD, registeredWriters, STORE_TIMESTAMP, MAX_UUID_MS, ROW_IDENTITY_RECIPE, ROW_IDENTITY_META_TABLE, ROW_IDENTITY_RECIPE_KEY, ROW_IDENTITY_SYNCED_KEY, IDENTITY_TABLE_DDL, AC_UID_GRAVEYARD_TRIGGER;
27435
+ var ROW_UID_DOMAIN, ROW_BIRTH_DOMAIN, ROW_UID_SQL_FUNCTION, ROW_BIRTH_FP_SQL_FUNCTION, ROW_RANDOM_UID_SQL_FUNCTION, AC_TEXT_HASH_SQL_FUNCTION, AC_UID_GRAVEYARD, registeredWriters, STORE_TIMESTAMP, MAX_UUID_MS, ROW_IDENTITY_RECIPE, ROW_IDENTITY_META_TABLE, ROW_IDENTITY_RECIPE_KEY, ROW_IDENTITY_SYNCED_KEY, IDENTITY_TABLE_DDL, AC_UID_GRAVEYARD_TRIGGER, ROW_IDENTITY_HEAL_KEY, HEAL_RECEIPT_TABLE, HEAL_RECEIPTS_KEPT;
27279
27436
  var init_row_identity = __esm({
27280
27437
  "packages/core/src/store/row-identity.ts"() {
27281
27438
  "use strict";
@@ -27284,6 +27441,7 @@ var init_row_identity = __esm({
27284
27441
  init_ac_table();
27285
27442
  init_row_identity_flag();
27286
27443
  init_row_identity_registry();
27444
+ init_worktree_build_guard();
27287
27445
  ROW_UID_DOMAIN = "cleo/row-uid/v1";
27288
27446
  ROW_BIRTH_DOMAIN = "cleo/row-birth/v1";
27289
27447
  ROW_UID_SQL_FUNCTION = "cleo_row_uid";
@@ -27293,7 +27451,7 @@ var init_row_identity = __esm({
27293
27451
  AC_UID_GRAVEYARD = "tasks_ac_uid_graveyard";
27294
27452
  STORE_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?)?(Z|[+-]\d{2}:?\d{2})?$/;
27295
27453
  MAX_UUID_MS = 2 ** 48 - 1;
27296
- ROW_IDENTITY_RECIPE = "cleo/row-identity/v1";
27454
+ ROW_IDENTITY_RECIPE = "cleo/row-identity/v2";
27297
27455
  ROW_IDENTITY_META_TABLE = "tasks_row_identity_meta";
27298
27456
  ROW_IDENTITY_RECIPE_KEY = "row_identity_recipe";
27299
27457
  ROW_IDENTITY_SYNCED_KEY = "row_identity_synced";
@@ -27338,6 +27496,15 @@ BEGIN
27338
27496
  INSERT INTO ${AC_UID_GRAVEYARD} (ac_id, uid, task_id, ordinal, text, birth_fp, deleted_at)
27339
27497
  VALUES (OLD.id, OLD.uid, OLD.task_id, OLD.ordinal, OLD.text, OLD.birth_fp, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
27340
27498
  END`;
27499
+ ROW_IDENTITY_HEAL_KEY = "row_identity_schema_healed";
27500
+ HEAL_RECEIPT_TABLE = {
27501
+ project: ROW_IDENTITY_META_TABLE,
27502
+ // The global store declares no identity table yet (ROW_IDENTITY.global is
27503
+ // empty, so its heal never runs); the change that declares one adds its
27504
+ // meta table here.
27505
+ global: null
27506
+ };
27507
+ HEAL_RECEIPTS_KEPT = 20;
27341
27508
  }
27342
27509
  });
27343
27510
 
@@ -40898,12 +41065,12 @@ var init_safety_data_accessor = __esm({
40898
41065
  this.getSafetyOptions()
40899
41066
  );
40900
41067
  }
40901
- async insertNewTask(task) {
41068
+ async insertNewTask(task, identity) {
40902
41069
  this.logVerbose(`Inserting new task ${task.id}`);
40903
41070
  await safeSingleTaskWrite(
40904
41071
  this.inner,
40905
41072
  task.id,
40906
- () => this.inner.insertNewTask(task),
41073
+ () => this.inner.insertNewTask(task, identity),
40907
41074
  this.cwd,
40908
41075
  this.getSafetyOptions()
40909
41076
  );
@@ -40951,6 +41118,9 @@ var init_safety_data_accessor = __esm({
40951
41118
  return this.inner.findOrphanAcBindings();
40952
41119
  }
40953
41120
  // ---- Metadata (pass-through to inner) ----
41121
+ async getTaskIdentities(taskIds) {
41122
+ return await this.inner.getTaskIdentities?.(taskIds) ?? [];
41123
+ }
40954
41124
  async getMetaValue(key) {
40955
41125
  return this.inner.getMetaValue(key);
40956
41126
  }
@@ -41324,13 +41494,147 @@ var init_cross_db_cleanup = __esm({
41324
41494
  }
41325
41495
  });
41326
41496
 
41497
+ // packages/core/src/store/dependency-cycles.ts
41498
+ function formatDependencyCycle(cycle) {
41499
+ return cycle.join(" \u2192 ");
41500
+ }
41501
+ function buildAdjacency(edges) {
41502
+ const adjacency = /* @__PURE__ */ new Map();
41503
+ for (const { taskId, dependsOn } of edges) {
41504
+ const next = adjacency.get(taskId);
41505
+ if (next) next.push(dependsOn);
41506
+ else adjacency.set(taskId, [dependsOn]);
41507
+ }
41508
+ for (const next of adjacency.values()) next.sort();
41509
+ return adjacency;
41510
+ }
41511
+ function shortestPath(adjacency, from, to) {
41512
+ if (from === to) return [from];
41513
+ const previous = /* @__PURE__ */ new Map([[from, from]]);
41514
+ const queue = [from];
41515
+ for (let head = 0; head < queue.length; head++) {
41516
+ const id = queue[head];
41517
+ for (const next of adjacency.get(id) ?? []) {
41518
+ if (previous.has(next)) continue;
41519
+ previous.set(next, id);
41520
+ if (next === to) {
41521
+ const path2 = [to];
41522
+ let cursor = id;
41523
+ while (cursor !== from) {
41524
+ path2.push(cursor);
41525
+ cursor = previous.get(cursor);
41526
+ }
41527
+ path2.push(from);
41528
+ return path2.reverse();
41529
+ }
41530
+ queue.push(next);
41531
+ }
41532
+ }
41533
+ return null;
41534
+ }
41535
+ function findClosedCycle(existing, edge) {
41536
+ if (edge.taskId === edge.dependsOn) return [edge.taskId, edge.taskId];
41537
+ const path2 = shortestPath(buildAdjacency(existing), edge.dependsOn, edge.taskId);
41538
+ return path2 ? [edge.taskId, ...path2] : null;
41539
+ }
41540
+ function dependencyCycleError(edge, cycle) {
41541
+ const self = edge.taskId === edge.dependsOn;
41542
+ const message = self ? `${DEPENDENCY_CYCLE_CODE}: task ${edge.taskId} cannot depend on itself` : `${DEPENDENCY_CYCLE_CODE}: ${edge.taskId} depends on ${edge.dependsOn} would close a dependency cycle: ${formatDependencyCycle(cycle)}`;
41543
+ const closing = cycle.length >= 3 ? cycle[cycle.length - 2] : void 0;
41544
+ const fix = self ? `Drop ${edge.taskId} from its own --depends list` : `Drop this dependency, or first remove another edge of the cycle, e.g. cleo update ${closing} --remove-depends ${edge.taskId}`;
41545
+ return new CleoError(14 /* CIRCULAR_REFERENCE */, message, {
41546
+ fix,
41547
+ details: {
41548
+ field: "depends",
41549
+ actual: edge.dependsOn,
41550
+ taskId: edge.taskId,
41551
+ cycle: [...cycle]
41552
+ }
41553
+ });
41554
+ }
41555
+ function isDependencyCycleAbort(err) {
41556
+ for (let e = err, depth = 0; e instanceof Error && depth < 8; depth++) {
41557
+ if (e.message.includes(DEPENDENCY_CYCLE_CODE)) return true;
41558
+ e = e.cause;
41559
+ }
41560
+ return false;
41561
+ }
41562
+ function readDependencyEdges(db) {
41563
+ return db.select({
41564
+ taskId: tasksTaskDependencies.taskId,
41565
+ dependsOn: tasksTaskDependencies.dependsOn
41566
+ }).from(tasksTaskDependencies).all();
41567
+ }
41568
+ function rethrowDependencyCycle(db, err, attempted) {
41569
+ if (!isDependencyCycleAbort(err)) throw err;
41570
+ const edges = readDependencyEdges(db);
41571
+ for (const edge of attempted) {
41572
+ const cycle = findClosedCycle(edges, edge);
41573
+ if (cycle) throw dependencyCycleError(edge, cycle);
41574
+ edges.push(edge);
41575
+ }
41576
+ throw err;
41577
+ }
41578
+ var DEPENDENCY_CYCLE_CODE;
41579
+ var init_dependency_cycles = __esm({
41580
+ "packages/core/src/store/dependency-cycles.ts"() {
41581
+ "use strict";
41582
+ init_src();
41583
+ init_errors2();
41584
+ init_tasks_schema();
41585
+ DEPENDENCY_CYCLE_CODE = "E_TASK_DEPENDENCY_CYCLE";
41586
+ }
41587
+ });
41588
+
41327
41589
  // packages/core/src/store/db-helpers.ts
41328
41590
  import { and as and5, eq as eq7, inArray as inArray3, sql as sql27 } from "drizzle-orm";
41329
41591
  async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
41330
41592
  await writeTaskRow(db, row, archiveFields, allowOrphanParent, false);
41331
41593
  }
41332
- async function insertNewTask(db, row) {
41333
- await writeTaskRow(db, row, void 0, false, true);
41594
+ async function insertNewTask(db, row, identity = { origin: "new" }) {
41595
+ await writeTaskRow(
41596
+ db,
41597
+ { ...row, ...await importedIdentity(db, identity, row) },
41598
+ void 0,
41599
+ false,
41600
+ true
41601
+ );
41602
+ }
41603
+ async function tableExists2(db, table) {
41604
+ const rows = await db.all(
41605
+ sql27`SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ${table}`
41606
+ );
41607
+ return rows.length > 0;
41608
+ }
41609
+ async function importedIdentity(db, identity, row) {
41610
+ if (identity.origin === "new" || !rowUidFillEnabled()) return {};
41611
+ const fp = identity.birthFp ?? null;
41612
+ const carried2 = identity.uid ?? null;
41613
+ if (carried2 !== null && fp !== null) {
41614
+ let uid = carried2;
41615
+ if (await tableExists2(db, "tasks_uid_aliases")) {
41616
+ for (let hop = 0; hop < 32; hop++) {
41617
+ const found = await db.all(
41618
+ sql27`SELECT new_uid AS uid FROM tasks_uid_aliases
41619
+ WHERE entity_table = 'tasks_tasks' AND old_uid = ${uid} AND old_birth_fp = ${fp}`
41620
+ );
41621
+ const next = found[0];
41622
+ if (!next) break;
41623
+ uid = next.uid;
41624
+ }
41625
+ }
41626
+ const [holder] = await db.select({ id: tasksTasks.id, birthFp: tasksTasks.birthFp }).from(tasksTasks).where(eq7(tasksTasks.uid, uid)).limit(1).all();
41627
+ if (holder && holder.birthFp === fp) throw new SameRowPresentError(row.id, holder.id);
41628
+ if (await tableExists2(db, "tasks_identity_quarantine")) {
41629
+ const [held] = await db.all(
41630
+ sql27`SELECT 1 AS x FROM tasks_identity_quarantine
41631
+ WHERE entity_table = 'tasks_tasks' AND uid = ${uid} AND birth_fp = ${fp}`
41632
+ );
41633
+ if (held) throw new SameRowPresentError(row.id, "held");
41634
+ }
41635
+ if (!holder) return { uid, birthFp: fp };
41636
+ }
41637
+ return { uid: null, birthFp: null };
41334
41638
  }
41335
41639
  async function writeTaskRow(db, row, archiveFields, allowOrphanParent, insertOnly) {
41336
41640
  if (row.parentId && row.parentId === row.id) {
@@ -41481,7 +41785,11 @@ async function batchUpdateDependencies(db, tasks2, validIds) {
41481
41785
  for (const depId of want) if (!have.has(depId)) added.push({ taskId, dependsOn: depId });
41482
41786
  }
41483
41787
  if (added.length > 0) {
41484
- await db.insert(tasksTaskDependencies).values(added).onConflictDoNothing().run();
41788
+ try {
41789
+ await db.insert(tasksTaskDependencies).values(added).onConflictDoNothing().run();
41790
+ } catch (err) {
41791
+ rethrowDependencyCycle(db, err, added);
41792
+ }
41485
41793
  }
41486
41794
  }
41487
41795
  async function loadDependenciesForTasks(db, tasks2, _validationIds) {
@@ -41526,15 +41834,29 @@ async function loadRelationsForTasks(db, tasks2) {
41526
41834
  task.relates = relations && relations.length > 0 ? relations : [];
41527
41835
  }
41528
41836
  }
41529
- var log6;
41837
+ var log6, SameRowPresentError;
41530
41838
  var init_db_helpers = __esm({
41531
41839
  "packages/core/src/store/db-helpers.ts"() {
41532
41840
  "use strict";
41533
41841
  init_src();
41534
41842
  init_errors2();
41535
41843
  init_logger2();
41844
+ init_dependency_cycles();
41845
+ init_row_identity_flag();
41536
41846
  init_tasks_schema();
41537
41847
  log6 = getLogger("db-helpers");
41848
+ SameRowPresentError = class extends CleoError {
41849
+ /** Where the row already is: its display id, or `held` when quarantined. */
41850
+ presentAs;
41851
+ constructor(taskId, presentAs) {
41852
+ super(
41853
+ 22 /* ID_COLLISION */,
41854
+ `Task ${taskId} is already in this store (${presentAs === "held" ? "held for sync" : `as ${presentAs}`}): same uid and birth fingerprint; not written again`,
41855
+ { details: { field: "taskId", actual: taskId, expected: presentAs } }
41856
+ );
41857
+ this.presentAs = presentAs;
41858
+ }
41859
+ };
41538
41860
  }
41539
41861
  });
41540
41862
 
@@ -41619,46 +41941,133 @@ function readProcessEntry(pid) {
41619
41941
  return null;
41620
41942
  }
41621
41943
  }
41622
- function resolvePpidKey(ppid, lookupProcess) {
41944
+ function readProcessArgs(pid) {
41945
+ if (process.platform === "win32" || !Number.isInteger(pid) || pid <= 1) return null;
41946
+ try {
41947
+ const out = execFileSync("ps", ["-o", "args=", "-p", String(pid)], {
41948
+ encoding: "utf8",
41949
+ timeout: 1e3,
41950
+ stdio: ["ignore", "pipe", "ignore"],
41951
+ env: { ...process.env, ...PS_STABLE_ENV }
41952
+ }).trim();
41953
+ return out === "" ? null : out;
41954
+ } catch {
41955
+ return null;
41956
+ }
41957
+ }
41958
+ function baseName(token) {
41959
+ return token.slice(token.lastIndexOf("/") + 1).replace(/^-/, "");
41960
+ }
41961
+ function programName(commandLine) {
41962
+ const tokens = commandLine.trim().split(/\s+/);
41963
+ const head = baseName(tokens[0] ?? "");
41964
+ if (!RUNTIME_PATTERN.test(head)) return head;
41965
+ for (let i = 1; i < tokens.length; i++) {
41966
+ const token = tokens[i] ?? "";
41967
+ if (token === "-m") return (tokens[i + 1] ?? head).split(".")[0] ?? head;
41968
+ if (token.startsWith("-")) continue;
41969
+ return baseName(token).replace(/\.(c|m)?(js|ts)$|\.py$/, "");
41970
+ }
41971
+ return head;
41972
+ }
41973
+ function isCommandStringShell(args) {
41974
+ const tokens = args.trim().split(/\s+/);
41975
+ const shell = programName(args);
41976
+ let first = 1;
41977
+ if (RUNTIME_PATTERN.test(baseName(tokens[0] ?? ""))) {
41978
+ while (first < tokens.length && (tokens[first] ?? "").startsWith("-")) first++;
41979
+ first++;
41980
+ }
41981
+ const rest = tokens.slice(first);
41982
+ if (shell === "pwsh" || shell === "powershell") {
41983
+ return rest.some((t) => PWSH_COMMAND_SWITCHES.has(t.toLowerCase()));
41984
+ }
41985
+ for (let i = 0; i < rest.length; i++) {
41986
+ const token = rest[i] ?? "";
41987
+ if (token === "--") return false;
41988
+ if (token === "--command" || token === "--commands") return true;
41989
+ if (SHELL_OPTIONS_WITH_ARGUMENT.has(token)) {
41990
+ i++;
41991
+ continue;
41992
+ }
41993
+ if (token.startsWith("--")) continue;
41994
+ if (!/^[-+][A-Za-z]+$/.test(token)) return false;
41995
+ if (token.startsWith("-") && token.slice(1).includes("c")) return true;
41996
+ }
41997
+ return false;
41998
+ }
41999
+ function resolveAncestor(ppid, lookupProcess, lookupArgs, agentId = null) {
41623
42000
  let pid = ppid;
41624
- for (let depth = 0; depth < PPID_CHAIN_MAX_DEPTH && pid > 1; depth++) {
42001
+ for (let depth = 0; depth < PPID_CHAIN_MAX_DEPTH; depth++) {
42002
+ if (pid <= 1) return null;
41625
42003
  const entry = lookupProcess(pid);
41626
- if (!entry) return null;
41627
- if (!PPID_CHAIN_LAUNCHERS.has(entry.command)) {
41628
- return { key: `ppid:${entry.pid}@${entry.startedAt}`, source: "ppid", kind: "ppid" };
42004
+ if (!entry || entry.pid <= 1) return null;
42005
+ const args = lookupArgs(entry.pid);
42006
+ const program = programName(args ?? entry.command);
42007
+ if (INIT_PROCESSES.has(program) || INIT_PROCESSES.has(entry.command)) return null;
42008
+ if (OWNER_PROCESS_SHELLS.has(program)) {
42009
+ if (args === null) return null;
42010
+ if (!isCommandStringShell(args)) return { entry, program, type: "shell" };
42011
+ } else if (!ANCESTOR_WRAPPERS.has(program)) {
42012
+ if (KNOWN_HARNESSES.has(program)) return { entry, program, type: "harness" };
42013
+ return agentId ? { entry, program, type: "host" } : null;
41629
42014
  }
41630
42015
  pid = entry.ppid;
41631
42016
  }
41632
42017
  return null;
41633
42018
  }
42019
+ function anchorKey(anchor, agentId, under) {
42020
+ const proc = `${anchor.entry.pid}@${anchor.entry.startedAt}`;
42021
+ if (anchor.type === "shell" && !agentId) {
42022
+ return { key: `proc:${proc}`, source: "process", kind: "process" };
42023
+ }
42024
+ const agent = agentId ? `#agent=${agentId}` : "";
42025
+ const scope = under ? `|${under.key}` : "";
42026
+ return {
42027
+ key: `harness:${anchor.program}:${proc}${agent}${scope}`,
42028
+ source: "process",
42029
+ kind: "harness"
42030
+ };
42031
+ }
41634
42032
  function resolveTerminalKeys(options = {}) {
41635
42033
  const env = options.env ?? process.env;
41636
42034
  const keys = [];
41637
42035
  for (const source of TERMINAL_KEY_SOURCES) {
41638
42036
  const value = envValue(env, source.envVar);
41639
42037
  if (value === null) continue;
41640
- const qualifier = envValue(env, source.qualifierEnvVar);
42038
+ const qualifiers = [source.qualifierEnvVar, ...source.extraQualifierEnvVars ?? []].map((name2) => envValue(env, name2)).filter((q2) => q2 !== null);
41641
42039
  keys.push({
41642
- key: `env:${source.envVar}=${qualifier === null ? value : `${qualifier}|${value}`}`,
42040
+ key: `env:${source.envVar}=${[...qualifiers, value].join("|")}`,
41643
42041
  source: source.envVar,
41644
42042
  kind: source.kind
41645
42043
  });
41646
42044
  }
41647
- if (keys.length > 0) return keys;
41648
- const live = options.ppid === void 0 && options.lookupProcess === void 0;
41649
- let ppidKey;
42045
+ if (keys.some((k) => k.kind === "provider")) return keys;
42046
+ const agentId = envValue(env, "CLEO_AGENT_ID");
42047
+ const live = options.ppid === void 0 && options.lookupProcess === void 0 && options.lookupArgs === void 0;
42048
+ let anchor;
41650
42049
  if (live) {
41651
- if (livePpidKey === void 0) livePpidKey = resolvePpidKey(process.ppid, readProcessEntry);
41652
- ppidKey = livePpidKey;
42050
+ const memoKey2 = agentId ?? "";
42051
+ if (!liveAnchors.has(memoKey2))
42052
+ liveAnchors.set(
42053
+ memoKey2,
42054
+ resolveAncestor(process.ppid, readProcessEntry, readProcessArgs, agentId)
42055
+ );
42056
+ anchor = liveAnchors.get(memoKey2) ?? null;
41653
42057
  } else {
41654
- ppidKey = resolvePpidKey(
42058
+ anchor = resolveAncestor(
41655
42059
  options.ppid ?? process.ppid,
41656
- options.lookupProcess ?? readProcessEntry
42060
+ options.lookupProcess ?? readProcessEntry,
42061
+ options.lookupArgs ?? readProcessArgs,
42062
+ agentId
41657
42063
  );
41658
42064
  }
41659
- return ppidKey ? [ppidKey] : [];
42065
+ if (!anchor) return keys;
42066
+ if (keys.length === 0) return [anchorKey(anchor, agentId, void 0)];
42067
+ if (anchor.type === "shell" && !agentId) return keys;
42068
+ return [...keys, anchorKey(anchor, agentId, keys[0])];
41660
42069
  }
41661
- var TERMINAL_KEY_SOURCES, PPID_CHAIN_LAUNCHERS, PPID_CHAIN_MAX_DEPTH, livePpidKey;
42070
+ var TERMINAL_KEY_SOURCES, PPID_CHAIN_MAX_DEPTH, KNOWN_HARNESSES, RUNTIME_PATTERN, ANCESTOR_WRAPPERS, INIT_PROCESSES, SHELL_OPTIONS_WITH_ARGUMENT, PWSH_COMMAND_SWITCHES, OWNER_PROCESS_SHELLS, liveAnchors;
41662
42071
  var init_terminal_identity = __esm({
41663
42072
  "packages/core/src/sessions/terminal-identity.ts"() {
41664
42073
  "use strict";
@@ -41690,24 +42099,100 @@ var init_terminal_identity = __esm({
41690
42099
  kind: "terminal",
41691
42100
  origin: "konsole",
41692
42101
  qualifierEnvVar: "KONSOLE_DBUS_SERVICE"
42102
+ },
42103
+ // T12864 — non-terminal callers whose platform exports a per-job / per-login id.
42104
+ // GitHub Actions: GITHUB_RUN_ID is per run and shared by its jobs, so it is
42105
+ // qualified by GITHUB_RUN_ATTEMPT and GITHUB_JOB ("Variables reference",
42106
+ // docs.github.com/en/actions/reference/workflows-and-actions/variables).
42107
+ // Every step of one job shares the key; the steps run sequentially.
42108
+ {
42109
+ envVar: "GITHUB_RUN_ID",
42110
+ kind: "terminal",
42111
+ origin: "github-actions",
42112
+ qualifierEnvVar: "GITHUB_RUN_ATTEMPT",
42113
+ extraQualifierEnvVars: ["GITHUB_JOB"]
42114
+ },
42115
+ // GitLab CI: CI_JOB_ID is unique per job across the instance ("Predefined
42116
+ // CI/CD variables reference", docs.gitlab.com/ci/variables/predefined_variables).
42117
+ { envVar: "CI_JOB_ID", kind: "terminal", origin: "gitlab-ci" },
42118
+ // OpenSSH login with a tty: SSH_TTY names the login's tty and is set only
42119
+ // when one was allocated; SSH_CONNECTION ("client-ip client-port server-ip
42120
+ // server-port", ssh(1) ENVIRONMENT) disambiguates it across connections. A
42121
+ // one-shot `ssh host 'cmd'` has no tty and falls through to the ancestor walk.
42122
+ {
42123
+ envVar: "SSH_TTY",
42124
+ kind: "terminal",
42125
+ origin: "openssh",
42126
+ qualifierEnvVar: "SSH_CONNECTION"
41693
42127
  }
41694
42128
  ];
41695
- PPID_CHAIN_LAUNCHERS = /* @__PURE__ */ new Set([
41696
- "node",
42129
+ PPID_CHAIN_MAX_DEPTH = 12;
42130
+ KNOWN_HARNESSES = /* @__PURE__ */ new Set([
42131
+ "claude",
42132
+ "codex",
42133
+ "aider",
42134
+ "gemini",
42135
+ "kimi",
42136
+ "cursor-agent",
42137
+ "amp"
42138
+ ]);
42139
+ RUNTIME_PATTERN = /^(node|nodejs|bun|deno|python[0-9.]*|pypy[0-9.]*|ruby|java|php|perl)$/;
42140
+ ANCESTOR_WRAPPERS = /* @__PURE__ */ new Set([
42141
+ "env",
42142
+ "timeout",
42143
+ "gtimeout",
42144
+ "nohup",
42145
+ "nice",
42146
+ "time",
42147
+ "xargs",
42148
+ "stdbuf",
42149
+ "sudo",
42150
+ "doas",
41697
42151
  "npm",
42152
+ "npm-cli",
41698
42153
  "npx",
42154
+ "npx-cli",
41699
42155
  "pnpm",
41700
42156
  "pnpx",
41701
42157
  "yarn",
41702
- "bun",
41703
42158
  "bunx",
41704
- "tsx",
41705
42159
  "corepack",
41706
42160
  "mise",
41707
- "env",
41708
42161
  "cleo"
41709
42162
  ]);
41710
- PPID_CHAIN_MAX_DEPTH = 4;
42163
+ INIT_PROCESSES = /* @__PURE__ */ new Set(["launchd", "systemd", "init"]);
42164
+ SHELL_OPTIONS_WITH_ARGUMENT = /* @__PURE__ */ new Set([
42165
+ "-o",
42166
+ "+o",
42167
+ "-O",
42168
+ "+O",
42169
+ "--rcfile",
42170
+ "--init-file"
42171
+ ]);
42172
+ PWSH_COMMAND_SWITCHES = /* @__PURE__ */ new Set([
42173
+ "-c",
42174
+ "-command",
42175
+ "-commandwithargs",
42176
+ "-cwa",
42177
+ "-e",
42178
+ "-ec",
42179
+ "-encodedcommand"
42180
+ ]);
42181
+ OWNER_PROCESS_SHELLS = /* @__PURE__ */ new Set([
42182
+ "sh",
42183
+ "bash",
42184
+ "zsh",
42185
+ "dash",
42186
+ "fish",
42187
+ "ksh",
42188
+ "tcsh",
42189
+ "csh",
42190
+ "pwsh",
42191
+ "powershell",
42192
+ "nu",
42193
+ "xonsh"
42194
+ ]);
42195
+ liveAnchors = /* @__PURE__ */ new Map();
41711
42196
  }
41712
42197
  });
41713
42198
 
@@ -41747,7 +42232,8 @@ var init_session_binding_schema = __esm({
41747
42232
  });
41748
42233
 
41749
42234
  // packages/core/src/store/session-store.ts
41750
- import { and as and6, desc as desc2, eq as eq8, isNull as isNull3, lte as lte2, or as or4 } from "drizzle-orm";
42235
+ import { existsSync as existsSync19 } from "node:fs";
42236
+ import { and as and6, desc as desc2, eq as eq8, inArray as inArray4, isNull as isNull3, lte as lte2, or as or4 } from "drizzle-orm";
41751
42237
  async function getSession(sessionId, cwd) {
41752
42238
  const scope = captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
41753
42239
  return worktreeScope.run(scope, async () => {
@@ -41769,8 +42255,9 @@ async function getActiveSession(cwd) {
41769
42255
  function splitTerminalKeys(keys) {
41770
42256
  return {
41771
42257
  provider: keys.find((k) => k.kind === "provider"),
41772
- pane: keys.find((k) => k.kind === "multiplexer"),
41773
- tab: keys.find((k) => k.kind === "terminal" || k.kind === "ppid")
42258
+ // A harness / CLEO_AGENT_ID agent (T12864) is more specific than a pane.
42259
+ pane: keys.find((k) => k.kind === "harness") ?? keys.find((k) => k.kind === "multiplexer"),
42260
+ tab: keys.find((k) => k.kind === "terminal" || k.kind === "process" || k.kind === "ppid")
41774
42261
  };
41775
42262
  }
41776
42263
  async function readBinding(db, key) {
@@ -41850,6 +42337,7 @@ async function resolveCurrentSession(cwd) {
41850
42337
  async function resolveBoundSession(cwd) {
41851
42338
  const scope = captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
41852
42339
  return worktreeScope.run(scope, async () => {
42340
+ if (!existsSync19(getDbPath(scope.worktreeRoot))) return null;
41853
42341
  const connId = getCurrentConnectionSessionId();
41854
42342
  if (connId) {
41855
42343
  const byConn = await getSession(connId, scope.worktreeRoot);
@@ -42001,7 +42489,7 @@ __export(registry_exports2, {
42001
42489
  updateAgentStatus: () => updateAgentStatus
42002
42490
  });
42003
42491
  import { randomBytes as randomBytes2 } from "node:crypto";
42004
- import { and as and7, eq as eq9, inArray as inArray4, lt as lt2, sql as sql29 } from "drizzle-orm";
42492
+ import { and as and7, eq as eq9, inArray as inArray5, lt as lt2, sql as sql29 } from "drizzle-orm";
42005
42493
  function generateAgentId() {
42006
42494
  const now = /* @__PURE__ */ new Date();
42007
42495
  const ts = now.toISOString().replace(/[-:T]/g, "").substring(0, 14);
@@ -42090,11 +42578,11 @@ async function listAgentInstances(filters, cwd) {
42090
42578
  const conditions = [];
42091
42579
  if (filters?.status) {
42092
42580
  const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
42093
- conditions.push(inArray4(agentInstances.status, statuses));
42581
+ conditions.push(inArray5(agentInstances.status, statuses));
42094
42582
  }
42095
42583
  if (filters?.agentType) {
42096
42584
  const types = Array.isArray(filters.agentType) ? filters.agentType : [filters.agentType];
42097
- conditions.push(inArray4(agentInstances.agentType, types));
42585
+ conditions.push(inArray5(agentInstances.agentType, types));
42098
42586
  }
42099
42587
  if (filters?.sessionId) {
42100
42588
  conditions.push(eq9(agentInstances.sessionId, filters.sessionId));
@@ -42131,7 +42619,7 @@ async function checkAgentHealth(thresholdMs = 3e4, cwd) {
42131
42619
  const cutoff = new Date(Date.now() - thresholdMs).toISOString();
42132
42620
  return db.select().from(agentInstances).where(
42133
42621
  and7(
42134
- inArray4(agentInstances.status, ["active", "idle", "starting"]),
42622
+ inArray5(agentInstances.status, ["active", "idle", "starting"]),
42135
42623
  lt2(agentInstances.lastHeartbeat, cutoff)
42136
42624
  )
42137
42625
  ).all();
@@ -42226,12 +42714,14 @@ var init_registry2 = __esm({
42226
42714
  // packages/core/src/store/sqlite-data-accessor.ts
42227
42715
  var sqlite_data_accessor_exports = {};
42228
42716
  __export(sqlite_data_accessor_exports, {
42717
+ RENAMED_RECENT_MS: () => RENAMED_RECENT_MS,
42229
42718
  addTaskLabelsNative: () => addTaskLabelsNative,
42230
42719
  advanceTaskIdSequence: () => advanceTaskIdSequence,
42231
42720
  bindTaskAccessorScope: () => bindTaskAccessorScope,
42232
42721
  captureTaskAccessorScope: () => captureProjectScope,
42233
42722
  clearAcUidGraveyardNative: () => clearAcUidGraveyardNative,
42234
42723
  clearBirthFpNative: () => clearBirthFpNative,
42724
+ clearReplacedTaskIdentityNative: () => clearReplacedTaskIdentityNative,
42235
42725
  clearRowUidNative: () => clearRowUidNative,
42236
42726
  createSqliteDataAccessor: () => createSqliteDataAccessor,
42237
42727
  deleteDisplayIdAliasNative: () => deleteDisplayIdAliasNative,
@@ -42242,6 +42732,7 @@ __export(sqlite_data_accessor_exports, {
42242
42732
  insertIdentityRowNative: () => insertIdentityRowNative,
42243
42733
  insertQuarantineNative: () => insertQuarantineNative,
42244
42734
  insertUidAliasNative: () => insertUidAliasNative,
42735
+ readReplacedTaskBirthNative: () => readReplacedTaskBirthNative,
42245
42736
  rederiveAcIdsNative: () => rederiveAcIdsNative,
42246
42737
  rekeyQuarantineNative: () => rekeyQuarantineNative,
42247
42738
  relinkAcUidNative: () => relinkAcUidNative,
@@ -42258,7 +42749,7 @@ import {
42258
42749
  and as and8,
42259
42750
  eq as eq10,
42260
42751
  getTableColumns as getTableColumns2,
42261
- inArray as inArray5,
42752
+ inArray as inArray6,
42262
42753
  isNull as isNull4,
42263
42754
  like as like2,
42264
42755
  lte as lte3,
@@ -42282,8 +42773,8 @@ async function selectAcBindings(db, acIds) {
42282
42773
  bindingType: b.bindingType,
42283
42774
  createdAt: b.createdAt
42284
42775
  };
42285
- const byUid = await db.select(columns).from(b).innerJoin(ac, eq10(ac.uid, b.acUid)).where(inArray5(ac.id, ids)).all();
42286
- const byId = await db.select(columns).from(b).leftJoin(ac, eq10(ac.uid, b.acUid)).where(inArray5(b.acId, ids)).all();
42776
+ const byUid = await db.select(columns).from(b).innerJoin(ac, eq10(ac.uid, b.acUid)).where(inArray6(ac.id, ids)).all();
42777
+ const byId = await db.select(columns).from(b).leftJoin(ac, eq10(ac.uid, b.acUid)).where(inArray6(b.acId, ids)).all();
42287
42778
  const rows = [...byUid, ...byId];
42288
42779
  const wanted = new Set(ids);
42289
42780
  const seen = /* @__PURE__ */ new Set();
@@ -42376,6 +42867,7 @@ function renameTaskDisplayIdNative(nativeDb, uid, toId, refs, guard = {}) {
42376
42867
  if (Number(changed) !== 1) {
42377
42868
  throw taskConflictError(current.id, taskVersion(current), null);
42378
42869
  }
42870
+ recordLocalRename(nativeDb, uid, current.id, toId, taskVersion(current));
42379
42871
  const rewritten = {};
42380
42872
  const q2 = (name2) => `"${name2.replaceAll('"', '""')}"`;
42381
42873
  for (const ref of refs) {
@@ -42431,23 +42923,39 @@ function rederiveAcIdsNative(nativeDb, fromId, toId) {
42431
42923
  }
42432
42924
  return count;
42433
42925
  }
42434
- function insertDisplayIdAliasNative(nativeDb, row) {
42926
+ function insertDisplayIdAliasNative(nativeDb, row, precedes) {
42927
+ const stored = nativeDb.prepare(
42928
+ `SELECT uid, entity_table AS entityTable, display_id AS displayId, entity_uid AS entityUid,
42929
+ reason, origin, displaced_hlc AS displacedHlc, created_at AS createdAt,
42930
+ entity_birth_fp AS entityBirthFp
42931
+ FROM tasks_display_id_aliases WHERE uid = ?`
42932
+ ).get(row.uid);
42933
+ if (!stored) {
42934
+ nativeDb.prepare(
42935
+ `INSERT INTO tasks_display_id_aliases
42936
+ (uid, entity_table, display_id, entity_uid, reason, origin, displaced_hlc, created_at,
42937
+ entity_birth_fp)
42938
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
42939
+ ).run(
42940
+ row.uid,
42941
+ row.entityTable,
42942
+ row.displayId,
42943
+ row.entityUid,
42944
+ row.reason,
42945
+ row.origin,
42946
+ row.displacedHlc,
42947
+ row.createdAt,
42948
+ row.entityBirthFp
42949
+ );
42950
+ return;
42951
+ }
42952
+ if (!precedes(row, stored)) return;
42435
42953
  nativeDb.prepare(
42436
- `INSERT OR IGNORE INTO tasks_display_id_aliases
42437
- (uid, entity_table, display_id, entity_uid, reason, origin, displaced_hlc, created_at,
42438
- entity_birth_fp)
42439
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
42440
- ).run(
42441
- row.uid,
42442
- row.entityTable,
42443
- row.displayId,
42444
- row.entityUid,
42445
- row.reason,
42446
- row.origin,
42447
- row.displacedHlc,
42448
- row.createdAt,
42449
- row.entityBirthFp
42450
- );
42954
+ `UPDATE tasks_display_id_aliases
42955
+ SET origin = ?, displaced_hlc = ?, created_at = ?,
42956
+ entity_birth_fp = coalesce(entity_birth_fp, ?)
42957
+ WHERE uid = ?`
42958
+ ).run(row.origin, row.displacedHlc, row.createdAt, row.entityBirthFp, row.uid);
42451
42959
  }
42452
42960
  function deleteDisplayIdAliasNative(nativeDb, uid) {
42453
42961
  nativeDb.prepare("DELETE FROM tasks_display_id_aliases WHERE uid = ?").run(uid);
@@ -42509,6 +43017,63 @@ function relinkAcUidNative(nativeDb, acId, uid, birthFp) {
42509
43017
  function clearAcUidGraveyardNative(nativeDb) {
42510
43018
  nativeDb.exec("DELETE FROM tasks_ac_uid_graveyard");
42511
43019
  }
43020
+ function readReplacedTaskBirthNative(nativeDb, taskId) {
43021
+ return nativeDb.prepare("SELECT created_at AS createdAt, uid FROM tasks_tasks WHERE id = ?").get(taskId);
43022
+ }
43023
+ function clearReplacedTaskIdentityNative(nativeDb, taskId, before) {
43024
+ const row = nativeDb.prepare("SELECT uid, birth_fp AS fp, created_at AS createdAt FROM tasks_tasks WHERE id = ?").get(taskId);
43025
+ if (!row || row.uid === null && row.fp === null) return;
43026
+ if (before) {
43027
+ const was = parseStoreTimestamp(before.createdAt);
43028
+ if (was !== null && was === parseStoreTimestamp(row.createdAt)) {
43029
+ return;
43030
+ }
43031
+ }
43032
+ if (rowIdentityShared(nativeDb)) {
43033
+ throw new CleoError(
43034
+ 6 /* VALIDATION_ERROR */,
43035
+ `Task ${taskId} cannot be overwritten by an import: its identity is shared with other devices`,
43036
+ {
43037
+ fix: "Import it under a new id (the default duplicate strategy), or edit the task instead of overwriting it.",
43038
+ details: { field: "taskId", actual: taskId }
43039
+ }
43040
+ );
43041
+ }
43042
+ const has = (table) => nativeDb.prepare("SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) !== void 0;
43043
+ nativeDb.prepare("UPDATE tasks_tasks SET uid = NULL, birth_fp = NULL WHERE id = ?").run(taskId);
43044
+ for (const spec of ROW_IDENTITY.project) {
43045
+ if (spec.kind !== "natural" || !has(spec.table)) continue;
43046
+ const cols = (spec.keyRefs ?? []).filter((r) => r.table === "tasks_tasks").map((r) => r.column);
43047
+ if (cols.length === 0) continue;
43048
+ nativeDb.prepare(
43049
+ `UPDATE main.${quoteIdent2(spec.table)} SET uid = NULL WHERE ${cols.map((c) => `${quoteIdent2(c)} = ?`).join(" OR ")}`
43050
+ ).run(...cols.map(() => taskId));
43051
+ }
43052
+ const children = ["tasks_task_acceptance_criteria_history", "tasks_evidence_ac_bindings"].filter(
43053
+ has
43054
+ );
43055
+ const criteria = has("tasks_task_acceptance_criteria") ? nativeDb.prepare("SELECT id, uid FROM tasks_task_acceptance_criteria WHERE task_id = ?").all(taskId) : [];
43056
+ if (criteria.length > 0) {
43057
+ nativeDb.prepare(
43058
+ "UPDATE tasks_task_acceptance_criteria SET uid = NULL, birth_fp = NULL WHERE task_id = ?"
43059
+ ).run(taskId);
43060
+ }
43061
+ fillRowUids(nativeDb, "project");
43062
+ const newUid = nativeDb.prepare("SELECT uid FROM tasks_task_acceptance_criteria WHERE id = ?");
43063
+ let rekeyed = 0;
43064
+ for (const ac of criteria) {
43065
+ const now = newUid.get(ac.id)?.uid ?? null;
43066
+ for (const table of children) {
43067
+ rekeyed += Number(
43068
+ nativeDb.prepare(
43069
+ `UPDATE main.${quoteIdent2(table)} SET ac_uid = ?, birth_fp = NULL
43070
+ WHERE ac_id = ? OR (? IS NOT NULL AND ac_uid = ?)`
43071
+ ).run(now, ac.id, ac.uid, ac.uid).changes
43072
+ );
43073
+ }
43074
+ }
43075
+ if (rekeyed > 0) fillRowUids(nativeDb, "project");
43076
+ }
42512
43077
  function quoteIdent2(name2) {
42513
43078
  return `"${name2.replaceAll('"', '""')}"`;
42514
43079
  }
@@ -42596,10 +43161,50 @@ function claimPredicate(guard, allowedHolders) {
42596
43161
  if (guard.mode === "force") return void 0;
42597
43162
  const mine = guard.sessionId === null ? void 0 : eq10(holder, guard.sessionId);
42598
43163
  if (guard.mode === "renew" || guard.mode === "release") return mine ?? sql30`0`;
42599
- const related = allowedHolders.length > 0 ? inArray5(holder, [...allowedHolders]) : void 0;
43164
+ const related = allowedHolders.length > 0 ? inArray6(holder, [...allowedHolders]) : void 0;
42600
43165
  const expired = guard.mode === "take-over" ? or5(isNull4(tasksTasks.leaseExpiresAt), lte3(tasksTasks.leaseExpiresAt, guard.now)) : void 0;
42601
43166
  return or5(isNull4(holder), mine, related, expired);
42602
43167
  }
43168
+ function renameRecordKey(fromId) {
43169
+ return `renamed_from:tasks_tasks:${fromId}`;
43170
+ }
43171
+ function hasIdentityMeta(nativeDb) {
43172
+ return nativeDb.prepare(
43173
+ "SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = 'tasks_row_identity_meta'"
43174
+ ).get() !== void 0;
43175
+ }
43176
+ function recordLocalRename(nativeDb, uid, fromId, toId, fromVersion) {
43177
+ if (!hasIdentityMeta(nativeDb)) return;
43178
+ const record = { uid, fromVersion, toId, at: (/* @__PURE__ */ new Date()).toISOString() };
43179
+ writeRowIdentityMetaNative(nativeDb, renameRecordKey(fromId), JSON.stringify(record));
43180
+ }
43181
+ function assertNotRenamed(nativeDb, taskId, guard, current) {
43182
+ if (!nativeDb || !hasIdentityMeta(nativeDb)) return;
43183
+ const raw = nativeDb.prepare("SELECT value FROM tasks_row_identity_meta WHERE key = ?").get(renameRecordKey(taskId));
43184
+ if (!raw) return;
43185
+ let record;
43186
+ try {
43187
+ record = JSON.parse(raw.value);
43188
+ } catch {
43189
+ return;
43190
+ }
43191
+ if (Date.now() - Date.parse(record.at) > RENAMED_RECENT_MS) return;
43192
+ const renamed = nativeDb.prepare("SELECT id, claimed_by_session AS claimedBySession FROM tasks_tasks WHERE uid = ?").get(record.uid);
43193
+ if (!renamed || renamed.id === taskId) return;
43194
+ const expected = guard.expectedUpdatedAt;
43195
+ const session = guard.claim?.sessionId ?? null;
43196
+ const holdsRenamedClaim = session !== null && (guard.claim?.mode === "renew" || guard.claim?.mode === "release") && renamed.claimedBySession === session && current?.claimedBySession !== session;
43197
+ const readRenamed = expected !== void 0 && expected === record.fromVersion && (current === void 0 || taskVersion(current) !== expected);
43198
+ if (!(current === void 0 || holdsRenamedClaim || readRenamed)) return;
43199
+ throw new CleoError(
43200
+ 26 /* TASK_RENAMED */,
43201
+ `Task ${taskId} is now ${renamed.id}: sync re-numbered it after a display-id collision, and ${taskId} ${current ? "names another task" : "names no task"}; nothing was written`,
43202
+ {
43203
+ fix: `Re-read it with 'cleo show ${renamed.id}' and retry against ${renamed.id}.`,
43204
+ details: { field: "taskId", actual: taskId, expected: renamed.id }
43205
+ }
43206
+ );
43207
+ }
42603
43208
  function assertClaimAllowed(taskId, row, guard, allowedHolders) {
42604
43209
  const stored = claimFromColumns(row);
42605
43210
  if (claimAllows(stored, guard.mode, guard.sessionId, guard.now, allowedHolders)) return;
@@ -42774,13 +43379,13 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
42774
43379
  const db = await getDb(cwd);
42775
43380
  const conditions = [];
42776
43381
  if (query.ids && query.ids.length > 0) {
42777
- conditions.push(inArray5(tasksAuditLog.id, [...query.ids]));
43382
+ conditions.push(inArray6(tasksAuditLog.id, [...query.ids]));
42778
43383
  }
42779
43384
  if (query.taskIds && query.taskIds.length > 0) {
42780
- conditions.push(inArray5(tasksAuditLog.taskId, [...query.taskIds]));
43385
+ conditions.push(inArray6(tasksAuditLog.taskId, [...query.taskIds]));
42781
43386
  }
42782
43387
  if (query.actions && query.actions.length > 0) {
42783
- conditions.push(inArray5(tasksAuditLog.action, [...query.actions]));
43388
+ conditions.push(inArray6(tasksAuditLog.action, [...query.actions]));
42784
43389
  }
42785
43390
  if (query.since) {
42786
43391
  conditions.push(sql30`${tasksAuditLog.timestamp} >= ${query.since}`);
@@ -42813,8 +43418,13 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
42813
43418
  async upsertSingleTask(task) {
42814
43419
  await accessor.transaction((tx) => tx.upsertSingleTask(task));
42815
43420
  },
42816
- async insertNewTask(task) {
42817
- await accessor.transaction((tx) => tx.insertNewTask(task));
43421
+ async insertNewTask(task, identity) {
43422
+ await accessor.transaction((tx) => tx.insertNewTask(task, identity));
43423
+ },
43424
+ async getTaskIdentities(taskIds) {
43425
+ if (taskIds.length === 0) return [];
43426
+ const db = await getDb(cwd);
43427
+ return db.select({ id: tasksTasks.id, uid: tasksTasks.uid, birthFp: tasksTasks.birthFp }).from(tasksTasks).where(inArray6(tasksTasks.id, taskIds)).all();
42818
43428
  },
42819
43429
  async addRelation(taskId, relatedTo, relationType, reason) {
42820
43430
  return accessor.transaction(async () => {
@@ -42991,7 +43601,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
42991
43601
  if (!statuses.includes("archived")) {
42992
43602
  conditions.push(ne2(tasksTasks.status, "archived"));
42993
43603
  }
42994
- conditions.push(inArray5(tasksTasks.status, statuses));
43604
+ conditions.push(inArray6(tasksTasks.status, statuses));
42995
43605
  } else if (filters.excludeStatus) {
42996
43606
  const excluded = Array.isArray(filters.excludeStatus) ? filters.excludeStatus : [filters.excludeStatus];
42997
43607
  for (const s of excluded) {
@@ -43005,11 +43615,11 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43005
43615
  if (filters.phase) conditions.push(eq10(tasksTasks.phase, filters.phase));
43006
43616
  if (filters.severity) {
43007
43617
  const severities = Array.isArray(filters.severity) ? filters.severity : [filters.severity];
43008
- conditions.push(inArray5(tasksTasks.severity, severities));
43618
+ conditions.push(inArray6(tasksTasks.severity, severities));
43009
43619
  }
43010
43620
  if (filters.kind) {
43011
43621
  const kinds = Array.isArray(filters.kind) ? filters.kind : [filters.kind];
43012
- conditions.push(inArray5(tasksTasks.kind, kinds));
43622
+ conditions.push(inArray6(tasksTasks.kind, kinds));
43013
43623
  }
43014
43624
  if (filters.parentId !== void 0) {
43015
43625
  if (filters.parentId === null) {
@@ -43030,7 +43640,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43030
43640
  }
43031
43641
  if (filters.label) {
43032
43642
  const labelMatchIds = db.select({ taskId: tasksTaskLabels.taskId }).from(tasksTaskLabels).where(eq10(tasksTaskLabels.label, filters.label));
43033
- conditions.push(inArray5(tasksTasks.id, labelMatchIds));
43643
+ conditions.push(inArray6(tasksTasks.id, labelMatchIds));
43034
43644
  }
43035
43645
  const where = conditions.length > 0 ? and8(...conditions) : void 0;
43036
43646
  const countResult = await db.select({ count: sql30`count(*)` }).from(tasksTasks).where(where).get();
@@ -43073,7 +43683,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43073
43683
  const conditions = [];
43074
43684
  if (filters?.status) {
43075
43685
  const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
43076
- conditions.push(inArray5(tasksTasks.status, statuses));
43686
+ conditions.push(inArray6(tasksTasks.status, statuses));
43077
43687
  } else {
43078
43688
  conditions.push(ne2(tasksTasks.status, "archived"));
43079
43689
  }
@@ -43138,7 +43748,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43138
43748
  if (idRows.length === 0) return [];
43139
43749
  const db = await getDb(cwd);
43140
43750
  const ids = idRows.map((r) => r.id);
43141
- const taskRows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, ids)).all();
43751
+ const taskRows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, ids)).all();
43142
43752
  const tasks2 = taskRows.map(rowToTask);
43143
43753
  if (tasks2.length > 0) {
43144
43754
  const allIds = await getAllTaskIds();
@@ -43167,7 +43777,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43167
43777
  if (idRows.length === 0) return [];
43168
43778
  const db = await getDb(cwd);
43169
43779
  const ids = idRows.map((r) => r.id);
43170
- const rows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, ids)).all();
43780
+ const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, ids)).all();
43171
43781
  const tasks2 = rows.map(rowToTask);
43172
43782
  if (tasks2.length > 0) {
43173
43783
  const allIds = await getAllTaskIds();
@@ -43181,7 +43791,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43181
43791
  const depRows = await db.select().from(tasksTaskDependencies).where(eq10(tasksTaskDependencies.dependsOn, taskId)).all();
43182
43792
  if (depRows.length === 0) return [];
43183
43793
  const dependentIds = depRows.map((r) => r.taskId);
43184
- const rows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, dependentIds)).all();
43794
+ const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, dependentIds)).all();
43185
43795
  const tasks2 = rows.map(rowToTask);
43186
43796
  if (tasks2.length > 0) {
43187
43797
  const allIds = await getAllTaskIds();
@@ -43211,7 +43821,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43211
43821
  async loadTasks(taskIds) {
43212
43822
  if (taskIds.length === 0) return [];
43213
43823
  const db = await getDb(cwd);
43214
- const rows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, taskIds)).all();
43824
+ const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, taskIds)).all();
43215
43825
  const tasks2 = rows.map(rowToTask);
43216
43826
  if (tasks2.length > 0) {
43217
43827
  const allIds = await getAllTaskIds();
@@ -43265,6 +43875,9 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43265
43875
  createdAt: tasksTasks.createdAt,
43266
43876
  ...CLAIM_COLUMNS
43267
43877
  }).from(tasksTasks).where(eq10(tasksTasks.id, taskId)).limit(1).all();
43878
+ if (guard?.claim || guard?.expectedUpdatedAt !== void 0) {
43879
+ assertNotRenamed(getNativeTasksDb(cwd), taskId, guard, current);
43880
+ }
43268
43881
  if (!current) throw new Error(`Task not found: ${taskId}`);
43269
43882
  const claimGuard = guard?.claim;
43270
43883
  const allowedHolders = claimGuard ? await claimAllowedHolders(db, claimGuard) : [];
@@ -43342,24 +43955,37 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43342
43955
  nativeDb.prepare(`SAVEPOINT ${spName}`).run();
43343
43956
  }
43344
43957
  try {
43958
+ const replacedBirths = /* @__PURE__ */ new Map();
43345
43959
  const tx = {
43346
43960
  async upsertSingleTask(task) {
43347
43961
  scope.assertActive();
43348
43962
  return accessor.transaction(async () => {
43349
43963
  scope.assertActive();
43964
+ if (rowUidFillEnabled() && !replacedBirths.has(task.id)) {
43965
+ const before = readReplacedTaskBirthNative(nativeDb, task.id);
43966
+ if (before) replacedBirths.set(task.id, before);
43967
+ }
43350
43968
  const row = taskToRow(task);
43351
43969
  await upsertTask(db, row);
43352
43970
  await updateDependencies(db, task.id, task.depends ?? []);
43353
43971
  });
43354
43972
  },
43355
- async insertNewTask(task) {
43973
+ async insertNewTask(task, identity) {
43356
43974
  scope.assertActive();
43357
43975
  return accessor.transaction(async () => {
43358
43976
  scope.assertActive();
43359
- await insertNewTask(db, taskToRow(task));
43977
+ await insertNewTask(db, taskToRow(task), identity);
43360
43978
  await updateDependencies(db, task.id, task.depends ?? []);
43361
43979
  });
43362
43980
  },
43981
+ async clearTaskIdentity(taskId) {
43982
+ scope.assertActive();
43983
+ if (!rowUidFillEnabled()) return;
43984
+ return accessor.transaction(async () => {
43985
+ scope.assertActive();
43986
+ clearReplacedTaskIdentityNative(nativeDb, taskId, replacedBirths.get(taskId));
43987
+ });
43988
+ },
43363
43989
  async archiveSingleTask(taskId, fields) {
43364
43990
  scope.assertActive();
43365
43991
  return accessor.transaction(async () => {
@@ -43506,7 +44132,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43506
44132
  const owned = await db.select({ id: tasksTaskAcceptanceCriteria.id }).from(tasksTaskAcceptanceCriteria).where(
43507
44133
  and8(
43508
44134
  eq10(tasksTaskAcceptanceCriteria.taskId, taskId),
43509
- inArray5(tasksTaskAcceptanceCriteria.id, ids)
44135
+ inArray6(tasksTaskAcceptanceCriteria.id, ids)
43510
44136
  )
43511
44137
  ).all();
43512
44138
  await pruneAcBindingsForAcIds(
@@ -43519,7 +44145,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43519
44145
  await db.delete(tasksTaskAcceptanceCriteria).where(
43520
44146
  and8(
43521
44147
  eq10(tasksTaskAcceptanceCriteria.taskId, taskId),
43522
- inArray5(tasksTaskAcceptanceCriteria.id, ids)
44148
+ inArray6(tasksTaskAcceptanceCriteria.id, ids)
43523
44149
  )
43524
44150
  ).run();
43525
44151
  });
@@ -43778,7 +44404,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43778
44404
  };
43779
44405
  return accessor;
43780
44406
  }
43781
- var _txSavepointCounter, taskTransactionQueue, TaskTransactionScope, taskTransactionContext, CLAIM_COLUMNS;
44407
+ var _txSavepointCounter, taskTransactionQueue, TaskTransactionScope, taskTransactionContext, CLAIM_COLUMNS, RENAMED_RECENT_MS;
43782
44408
  var init_sqlite_data_accessor = __esm({
43783
44409
  "packages/core/src/store/sqlite-data-accessor.ts"() {
43784
44410
  "use strict";
@@ -43792,6 +44418,8 @@ var init_sqlite_data_accessor = __esm({
43792
44418
  init_cross_db_cleanup();
43793
44419
  init_db_helpers();
43794
44420
  init_row_identity();
44421
+ init_row_identity_flag();
44422
+ init_row_identity_registry();
43795
44423
  init_audit2();
43796
44424
  init_session_store();
43797
44425
  init_sqlite3();
@@ -43824,6 +44452,7 @@ var init_sqlite_data_accessor = __esm({
43824
44452
  claimedAt: tasksTasks.claimedAt,
43825
44453
  leaseExpiresAt: tasksTasks.leaseExpiresAt
43826
44454
  };
44455
+ RENAMED_RECENT_MS = 24 * 60 * 60 * 1e3;
43827
44456
  registerRowIdentityWriters({
43828
44457
  relinkAcUidNative,
43829
44458
  clearAcUidGraveyardNative,
@@ -44294,7 +44923,7 @@ __export(governor_exports, {
44294
44923
  resolveGovernorMode: () => resolveGovernorMode,
44295
44924
  slotFileCount: () => slotFileCount
44296
44925
  });
44297
- import { existsSync as existsSync19, mkdirSync as mkdirSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
44926
+ import { existsSync as existsSync20, mkdirSync as mkdirSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
44298
44927
  import { availableParallelism, totalmem } from "node:os";
44299
44928
  import { join as join25 } from "node:path";
44300
44929
  import lockfile2 from "proper-lockfile";
@@ -44368,11 +44997,11 @@ function governorSlotDir(cls) {
44368
44997
  return join25(getCleoHome(), "locks", `resource-${cls}`);
44369
44998
  }
44370
44999
  function ensureSlotFiles(dir, count) {
44371
- if (!existsSync19(dir)) mkdirSync6(dir, { recursive: true });
45000
+ if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
44372
45001
  const paths = [];
44373
45002
  for (let i = 0; i < count; i++) {
44374
45003
  const p = join25(dir, `slot-${i}.lock`);
44375
- if (!existsSync19(p)) writeFileSync5(p, "", { flag: "a" });
45004
+ if (!existsSync20(p)) writeFileSync5(p, "", { flag: "a" });
44376
45005
  paths.push(p);
44377
45006
  }
44378
45007
  return paths;
@@ -44412,7 +45041,7 @@ function shuffledIndices(n) {
44412
45041
  }
44413
45042
  async function countHeldSlots(cls, budget) {
44414
45043
  const dir = governorSlotDir(cls);
44415
- if (!existsSync19(dir)) return 0;
45044
+ if (!existsSync20(dir)) return 0;
44416
45045
  const slots = ensureSlotFiles(dir, budget);
44417
45046
  let held = 0;
44418
45047
  for (const path2 of slots) {
@@ -44427,7 +45056,7 @@ async function countHeldSlots(cls, budget) {
44427
45056
  }
44428
45057
  function slotFileCount(cls) {
44429
45058
  const dir = governorSlotDir(cls);
44430
- if (!existsSync19(dir)) return 0;
45059
+ if (!existsSync20(dir)) return 0;
44431
45060
  return readdirSync5(dir).filter((f) => f.startsWith("slot-") && f.endsWith(".lock")).length;
44432
45061
  }
44433
45062
  var _log2, _cachedMode2, _supervisorDegradeLogged, MB, STALE_MS, _supervisorHolderSeq, ResourceGovernor, governor;
@@ -44925,7 +45554,7 @@ var init_recovery = __esm({
44925
45554
  // packages/core/src/store/exodus/archive.ts
44926
45555
  import {
44927
45556
  copyFileSync as copyFileSync5,
44928
- existsSync as existsSync20,
45557
+ existsSync as existsSync21,
44929
45558
  mkdirSync as mkdirSync7,
44930
45559
  readFileSync as readFileSync8,
44931
45560
  renameSync as renameSync7,
@@ -44953,7 +45582,7 @@ function hasExodusCompleteMarker(scope, cwd, targetDbPath, nativeDb) {
44953
45582
  if (targetDbPath) throw error;
44954
45583
  return false;
44955
45584
  }
44956
- if (!existsSync20(markerPath)) return false;
45585
+ if (!existsSync21(markerPath)) return false;
44957
45586
  const marker = markerIdentity.parse(JSON.parse(readFileSync8(markerPath, "utf8")));
44958
45587
  if (nativeDb && (!marker.databaseIdentity || !hasExodusDatabaseIdentity(nativeDb, marker.databaseIdentity)))
44959
45588
  throw new Error(
@@ -44983,7 +45612,7 @@ function writeExodusCompleteMarker(scope, archivedSources, cwd, targetDbPath, da
44983
45612
  function moveFileInto(srcPath, destDir) {
44984
45613
  mkdirSync7(destDir, { recursive: true });
44985
45614
  let dest = join26(destDir, basename9(srcPath));
44986
- if (existsSync20(dest)) {
45615
+ if (existsSync21(dest)) {
44987
45616
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
44988
45617
  dest = join26(destDir, `${basename9(srcPath)}.${stamp}`);
44989
45618
  }
@@ -44996,14 +45625,14 @@ function moveFileInto(srcPath, destDir) {
44996
45625
  return dest;
44997
45626
  }
44998
45627
  function archiveSourceDb(source, cwd, targetDbPath) {
44999
- if (!existsSync20(source.path)) {
45628
+ if (!existsSync21(source.path)) {
45000
45629
  return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
45001
45630
  }
45002
45631
  const destDir = exodusArchiveDir(source.targetScope, cwd, targetDbPath);
45003
45632
  const archivedTo = moveFileInto(source.path, destDir);
45004
45633
  for (const suffix of SIDECAR_SUFFIXES) {
45005
45634
  const sidecar = `${source.path}${suffix}`;
45006
- if (existsSync20(sidecar)) {
45635
+ if (existsSync21(sidecar)) {
45007
45636
  try {
45008
45637
  moveFileInto(sidecar, destDir);
45009
45638
  } catch (err) {
@@ -45051,7 +45680,7 @@ function detectStrandedResidue(sources, cwd) {
45051
45680
  const stranded = [];
45052
45681
  for (const source of sources) {
45053
45682
  if (!markedScopes.has(source.targetScope)) continue;
45054
- if (existsSync20(source.path)) {
45683
+ if (existsSync21(source.path)) {
45055
45684
  stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
45056
45685
  }
45057
45686
  }
@@ -45092,13 +45721,13 @@ var init_archive2 = __esm({
45092
45721
  });
45093
45722
 
45094
45723
  // packages/core/src/store/exodus/count-parity.ts
45095
- import { existsSync as existsSync21 } from "node:fs";
45724
+ import { existsSync as existsSync22 } from "node:fs";
45096
45725
  function listTables2(db) {
45097
45726
  return db.prepare(
45098
45727
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
45099
45728
  ).all().map((r) => r.name);
45100
45729
  }
45101
- function tableExists2(db, tableName) {
45730
+ function tableExists3(db, tableName) {
45102
45731
  const escaped = tableName.replace(/'/g, "''");
45103
45732
  return db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !== void 0;
45104
45733
  }
@@ -45113,14 +45742,14 @@ function rowCount(db, tableName) {
45113
45742
  function computeCountParity(sources, projectDbPath, globalDbPath) {
45114
45743
  const entries = [];
45115
45744
  let skipped = 0;
45116
- if (!existsSync21(projectDbPath) || !existsSync21(globalDbPath)) {
45745
+ if (!existsSync22(projectDbPath) || !existsSync22(globalDbPath)) {
45117
45746
  return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
45118
45747
  }
45119
45748
  const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
45120
45749
  const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
45121
45750
  try {
45122
45751
  for (const src of sources) {
45123
- if (!existsSync21(src.path)) continue;
45752
+ if (!existsSync22(src.path)) continue;
45124
45753
  const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
45125
45754
  try {
45126
45755
  for (const legacyTable of listTables2(srcSnap.db)) {
@@ -45137,7 +45766,7 @@ function computeCountParity(sources, projectDbPath, globalDbPath) {
45137
45766
  skipped++;
45138
45767
  continue;
45139
45768
  }
45140
- const targetCount = tableExists2(targetSnap.db, targetTable) ? rowCount(targetSnap.db, targetTable) ?? 0 : 0;
45769
+ const targetCount = tableExists3(targetSnap.db, targetTable) ? rowCount(targetSnap.db, targetTable) ?? 0 : 0;
45141
45770
  const deficit = targetCount < sourceCount ? sourceCount - targetCount : 0;
45142
45771
  entries.push({
45143
45772
  sourceDb: src.name,
@@ -45178,7 +45807,7 @@ var init_count_parity = __esm({
45178
45807
  });
45179
45808
 
45180
45809
  // packages/core/src/store/exodus/plan.ts
45181
- import { existsSync as existsSync22, readdirSync as readdirSync6, statfsSync as statfsSync2, statSync as statSync6 } from "node:fs";
45810
+ import { existsSync as existsSync23, readdirSync as readdirSync6, statfsSync as statfsSync2, statSync as statSync6 } from "node:fs";
45182
45811
  import { join as join27 } from "node:path";
45183
45812
  function computeRequiredBytes(totalSourceBytes, largestSourceBytes) {
45184
45813
  return Math.ceil(STAGING_HEADROOM_FACTOR * largestSourceBytes) + totalSourceBytes;
@@ -45280,7 +45909,7 @@ function buildExodusPlan(cwd) {
45280
45909
  };
45281
45910
  }
45282
45911
  function sourcesPresent(sources) {
45283
- return sources.some((s) => existsSync22(s.path));
45912
+ return sources.some((s) => existsSync23(s.path));
45284
45913
  }
45285
45914
  var STAGING_HEADROOM_FACTOR, STAGING_COPY_SKIP_THRESHOLD_BYTES;
45286
45915
  var init_plan2 = __esm({
@@ -45294,18 +45923,18 @@ var init_plan2 = __esm({
45294
45923
  });
45295
45924
 
45296
45925
  // packages/core/src/store/exodus/health.ts
45297
- import { existsSync as existsSync23, statSync as statSync7 } from "node:fs";
45926
+ import { existsSync as existsSync24, statSync as statSync7 } from "node:fs";
45298
45927
  function buildExodusHealth(cwd) {
45299
45928
  const plan = buildExodusPlan(cwd);
45300
- const anyLegacyPresent = plan.sources.some((s) => existsSync23(s.path));
45929
+ const anyLegacyPresent = plan.sources.some((s) => existsSync24(s.path));
45301
45930
  const parity = anyLegacyPresent ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath) : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
45302
45931
  const consolidatedExistsByScope = {
45303
- project: existsSync23(plan.projectDbPath),
45304
- global: existsSync23(plan.globalDbPath)
45932
+ project: existsSync24(plan.projectDbPath),
45933
+ global: existsSync24(plan.globalDbPath)
45305
45934
  };
45306
45935
  const buildScope = (scope) => {
45307
45936
  const sources = plan.sources.filter((s) => s.targetScope === scope).map((s) => {
45308
- const present = existsSync23(s.path);
45937
+ const present = existsSync24(s.path);
45309
45938
  let bytes = 0;
45310
45939
  if (present) {
45311
45940
  try {
@@ -45410,7 +46039,7 @@ var init_types = __esm({
45410
46039
  // packages/core/src/store/exodus/migrate.ts
45411
46040
  import {
45412
46041
  copyFileSync as copyFileSync6,
45413
- existsSync as existsSync24,
46042
+ existsSync as existsSync25,
45414
46043
  mkdirSync as mkdirSync8,
45415
46044
  readFileSync as readFileSync9,
45416
46045
  renameSync as renameSync8,
@@ -45456,7 +46085,7 @@ function writeJournal(stagingDir, journal) {
45456
46085
  }
45457
46086
  function readJournal(stagingDir) {
45458
46087
  const journalPath = join28(stagingDir, JOURNAL_FILENAME);
45459
- if (!existsSync24(journalPath)) return null;
46088
+ if (!existsSync25(journalPath)) return null;
45460
46089
  try {
45461
46090
  return JSON.parse(readFileSync9(journalPath, "utf8"));
45462
46091
  } catch {
@@ -45466,7 +46095,7 @@ function readJournal(stagingDir) {
45466
46095
  function clearExodusJournal(stagingDir) {
45467
46096
  const journalPath = join28(stagingDir, JOURNAL_FILENAME);
45468
46097
  try {
45469
- if (!existsSync24(journalPath)) return false;
46098
+ if (!existsSync25(journalPath)) return false;
45470
46099
  unlinkSync5(journalPath);
45471
46100
  log10.info(
45472
46101
  { stagingDir },
@@ -45762,7 +46391,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
45762
46391
  mkdirSync8(stagingDir, { recursive: true });
45763
46392
  let sqliteVersion = "unknown";
45764
46393
  for (const src of sources) {
45765
- if (existsSync24(src.path)) {
46394
+ if (existsSync25(src.path)) {
45766
46395
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
45767
46396
  sqliteVersion = getSqliteVersion(snap.db);
45768
46397
  snap.close();
@@ -45792,7 +46421,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
45792
46421
  let reseedProject = null;
45793
46422
  try {
45794
46423
  for (const src of sources) {
45795
- if (!existsSync24(src.path)) continue;
46424
+ if (!existsSync25(src.path)) continue;
45796
46425
  const backupDest = join28(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
45797
46426
  const srcBytes = safeStatBytes(src.path);
45798
46427
  const skipStagingCopy = srcBytes > plan.stagingCopyThresholdBytes;
@@ -45800,7 +46429,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
45800
46429
  onProgress?.(
45801
46430
  `Skipping full staging copy of ${src.name} (${srcBytes} bytes > ${plan.stagingCopyThresholdBytes} threshold) \u2014 source is archived, not deleted, on success.`
45802
46431
  );
45803
- } else if (!existsSync24(backupDest)) {
46432
+ } else if (!existsSync25(backupDest)) {
45804
46433
  onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
45805
46434
  copyFileSync6(src.path, backupDest);
45806
46435
  backupPaths.push(backupDest);
@@ -45833,8 +46462,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
45833
46462
  }
45834
46463
  prepareExodusRecovery(projectNative, stagingDir);
45835
46464
  if (globalNative !== null) prepareExodusRecovery(globalNative, stagingDir);
45836
- const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync24(s.path));
45837
- const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync24(s.path));
46465
+ const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync25(s.path));
46466
+ const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync25(s.path));
45838
46467
  if (globalNative === null && globalSources.length > 0)
45839
46468
  throw new Error("A projectOnly exodus run was given global-scope sources");
45840
46469
  await migrateScope(
@@ -46083,7 +46712,8 @@ var init_migrate = __esm({
46083
46712
  GRANDFATHERED_GUARD_TRIGGERS = [
46084
46713
  "tasks_tasks_parent_type_matrix_insert",
46085
46714
  "tasks_task_relations_non_containment_insert",
46086
- "tasks_task_acceptance_child_target_insert"
46715
+ "tasks_task_acceptance_child_target_insert",
46716
+ "tasks_task_dependencies_cycle_guard_insert"
46087
46717
  ];
46088
46718
  SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
46089
46719
  ["conduit", "seconds"],
@@ -46142,7 +46772,7 @@ __export(reconcile_exports, {
46142
46772
  reconcileSupersededStores: () => reconcileSupersededStores,
46143
46773
  unmigratedBareSources: () => unmigratedBareSources
46144
46774
  });
46145
- import { copyFileSync as copyFileSync7, existsSync as existsSync25, mkdirSync as mkdirSync9, mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
46775
+ import { copyFileSync as copyFileSync7, existsSync as existsSync26, mkdirSync as mkdirSync9, mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
46146
46776
  import { tmpdir as tmpdir4 } from "node:os";
46147
46777
  import { basename as basename10, join as join29 } from "node:path";
46148
46778
  function ident2(name2) {
@@ -46213,7 +46843,7 @@ function assessSupersededProjectStores(liveStorePath, sources, resolveTarget = r
46213
46843
  }
46214
46844
  function legacySourcesHoldRows(sources) {
46215
46845
  for (const src of sources) {
46216
- if (!existsSync25(src.path)) continue;
46846
+ if (!existsSync26(src.path)) continue;
46217
46847
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
46218
46848
  try {
46219
46849
  for (const table of orderTablesForCopy(snap.db)) {
@@ -46461,8 +47091,8 @@ async function reconcileSuppressed(projectRoot, options, liveStorePath) {
46461
47091
  }
46462
47092
  }
46463
47093
  async function reconcileWithScratch(projectRoot, dryRun, additive, liveStorePath, plan, resolveTarget, scratch) {
46464
- const fileSources = plan.sources.filter((s) => s.targetScope === "project" && existsSync25(s.path));
46465
- const bare = !additive && existsSync25(liveStorePath) ? await bareTaskCoreSource(liveStorePath, resolveTarget, scratch) : null;
47094
+ const fileSources = plan.sources.filter((s) => s.targetScope === "project" && existsSync26(s.path));
47095
+ const bare = !additive && existsSync26(liveStorePath) ? await bareTaskCoreSource(liveStorePath, resolveTarget, scratch) : null;
46466
47096
  const copyResolver = additive ? (sourceName, legacyTable) => {
46467
47097
  const r = resolveTarget(sourceName, legacyTable);
46468
47098
  return r.kind !== "skip" && isLiveAuthoritative(sourceName, legacyTable, r.targetName) ? { kind: "skip", reason: "additive: live-authoritative task graph" } : r;
@@ -46481,7 +47111,7 @@ async function reconcileWithScratch(projectRoot, dryRun, additive, liveStorePath
46481
47111
  stagingDir: null,
46482
47112
  receiptPath: null
46483
47113
  };
46484
- if (sources.length === 0 || !existsSync25(liveStorePath)) {
47114
+ if (sources.length === 0 || !existsSync26(liveStorePath)) {
46485
47115
  return {
46486
47116
  ...base,
46487
47117
  outcome: "nothing-to-reconcile",
@@ -46673,11 +47303,11 @@ var init_seal = __esm({
46673
47303
  });
46674
47304
 
46675
47305
  // packages/core/src/store/exodus/status.ts
46676
- import { existsSync as existsSync26, readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync9 } from "node:fs";
47306
+ import { existsSync as existsSync27, readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync9 } from "node:fs";
46677
47307
  import { join as join30 } from "node:path";
46678
47308
  function readJournal2(stagingDir) {
46679
47309
  const p = join30(stagingDir, JOURNAL_FILENAME2);
46680
- if (!existsSync26(p)) return null;
47310
+ if (!existsSync27(p)) return null;
46681
47311
  try {
46682
47312
  return JSON.parse(readFileSync10(p, "utf8"));
46683
47313
  } catch {
@@ -46709,15 +47339,15 @@ function runExodusStatus(cwd) {
46709
47339
  const sourcesInfo = plan.sources.map((s) => ({
46710
47340
  name: s.name,
46711
47341
  path: s.path,
46712
- exists: existsSync26(s.path),
47342
+ exists: existsSync27(s.path),
46713
47343
  bytes: safeBytes(s.path)
46714
47344
  }));
46715
47345
  return {
46716
47346
  hasStaging: latestStaging !== null,
46717
47347
  stagingDir: latestStaging,
46718
47348
  journal,
46719
- projectDbExists: existsSync26(projectDbPath),
46720
- globalDbExists: existsSync26(globalDbPath),
47349
+ projectDbExists: existsSync27(projectDbPath),
47350
+ globalDbExists: existsSync27(globalDbPath),
46721
47351
  sourcesPresent: sourcesInfo.some((s) => s.exists),
46722
47352
  sources: sourcesInfo
46723
47353
  };
@@ -46734,7 +47364,7 @@ var init_status = __esm({
46734
47364
  });
46735
47365
 
46736
47366
  // packages/core/src/store/exodus/verify-migration.ts
46737
- import { existsSync as existsSync27 } from "node:fs";
47367
+ import { existsSync as existsSync28 } from "node:fs";
46738
47368
  import { createRequire as createRequire10 } from "node:module";
46739
47369
  function orderByClause(db, tableName) {
46740
47370
  try {
@@ -46849,7 +47479,7 @@ function listTables3(db) {
46849
47479
  ).all();
46850
47480
  return rows.map((r) => r.name);
46851
47481
  }
46852
- function tableExists3(db, tableName) {
47482
+ function tableExists4(db, tableName) {
46853
47483
  try {
46854
47484
  const escaped = tableName.replace(/'/g, "''");
46855
47485
  return db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !== void 0;
@@ -46999,10 +47629,10 @@ function orphanAlreadyInSource(targetDb, fk, sources, resolveTarget = resolveCon
46999
47629
  const anyFeeder = (targetTable, probe) => {
47000
47630
  for (const feeder of feedersOf(targetTable)) {
47001
47631
  const src = sources.find((s) => s.name === feeder.sourceName);
47002
- if (src === void 0 || !existsSync27(src.path)) continue;
47632
+ if (src === void 0 || !existsSync28(src.path)) continue;
47003
47633
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
47004
47634
  try {
47005
- if (!tableExists3(snap.db, feeder.legacyTable)) continue;
47635
+ if (!tableExists4(snap.db, feeder.legacyTable)) continue;
47006
47636
  const cols = new Set(
47007
47637
  snap.db.prepare(`PRAGMA table_info("${feeder.legacyTable}")`).all().map((c) => c.name)
47008
47638
  );
@@ -47054,7 +47684,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47054
47684
  const preExistingForeignKeyViolations = [];
47055
47685
  const failureLines = [];
47056
47686
  const sourceOrphanSigs = /* @__PURE__ */ new Set();
47057
- if (!existsSync27(projectDbPath)) {
47687
+ if (!existsSync28(projectDbPath)) {
47058
47688
  return {
47059
47689
  ok: false,
47060
47690
  tables: [],
@@ -47065,7 +47695,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47065
47695
  error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
47066
47696
  };
47067
47697
  }
47068
- if (!existsSync27(globalDbPath)) {
47698
+ if (!existsSync28(globalDbPath)) {
47069
47699
  return {
47070
47700
  ok: false,
47071
47701
  tables: [],
@@ -47080,7 +47710,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47080
47710
  const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
47081
47711
  try {
47082
47712
  for (const src of sources) {
47083
- if (!existsSync27(src.path)) {
47713
+ if (!existsSync28(src.path)) {
47084
47714
  onProgress?.(`Skipping ${src.name} (not present)`);
47085
47715
  continue;
47086
47716
  }
@@ -47205,7 +47835,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47205
47835
  targetOrphans.push(...foreignKeyCheck(globalSnap.db, "global"));
47206
47836
  foreignKeyViolations.push(...targetOrphans);
47207
47837
  for (const fk of targetOrphans) {
47208
- const orphanDb = tableExists3(projectSnap.db, fk.table) ? projectSnap.db : globalSnap.db;
47838
+ const orphanDb = tableExists4(projectSnap.db, fk.table) ? projectSnap.db : globalSnap.db;
47209
47839
  const sig = orphanSignature(orphanDb, fk);
47210
47840
  const preExisting = sourceOrphanSigs.has(sig) || orphanAlreadyInSource(orphanDb, fk, sources, resolveTarget);
47211
47841
  if (preExisting) {
@@ -47371,7 +48001,7 @@ __export(on_open_exports, {
47371
48001
  maybeRunExodusOnOpen: () => maybeRunExodusOnOpen,
47372
48002
  withExodusOnOpenSuppressed: () => withExodusOnOpenSuppressed
47373
48003
  });
47374
- import { existsSync as existsSync28, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
48004
+ import { existsSync as existsSync29, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
47375
48005
  import { tmpdir as tmpdir5 } from "node:os";
47376
48006
  import { join as join31, resolve as resolve13 } from "node:path";
47377
48007
  async function withExodusOnOpenSuppressed(dbPath, fn) {
@@ -47413,7 +48043,7 @@ function remedyFor(scope) {
47413
48043
  }
47414
48044
  async function strandedLegacySources(scope, cwd) {
47415
48045
  const { buildExodusPlan: buildExodusPlan2, legacySourcesHoldRows: legacySourcesHoldRows2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
47416
- return buildExodusPlan2(cwd).sources.filter((s) => s.targetScope === scope && existsSync28(s.path)).filter((s) => legacySourcesHoldRows2([s])).map((s) => s.name);
48046
+ return buildExodusPlan2(cwd).sources.filter((s) => s.targetScope === scope && existsSync29(s.path)).filter((s) => legacySourcesHoldRows2([s])).map((s) => s.name);
47417
48047
  }
47418
48048
  async function exodusStoreRewriteRefusal(dbPath, cwd) {
47419
48049
  const { assertOwnerStoreRewriteConfirmed: assertOwnerStoreRewriteConfirmed2, invocationDirectory: invocationDirectory2 } = await Promise.resolve().then(() => (init_worktree_isolation_guard(), worktree_isolation_guard_exports));
@@ -47545,7 +48175,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47545
48175
  };
47546
48176
  }
47547
48177
  const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
47548
- if (!scopeSources.some((s) => existsSync28(s.path))) {
48178
+ if (!scopeSources.some((s) => existsSync29(s.path))) {
47549
48179
  return {
47550
48180
  outcome: "skipped",
47551
48181
  reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
@@ -47570,7 +48200,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47570
48200
  {
47571
48201
  scope,
47572
48202
  dbPath,
47573
- sources: plan.sources.filter((s) => existsSync28(s.path)).map((s) => s.name)
48203
+ sources: plan.sources.filter((s) => existsSync29(s.path)).map((s) => s.name)
47574
48204
  },
47575
48205
  "exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
47576
48206
  );
@@ -47583,7 +48213,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47583
48213
  const bare = scope === "project" ? await unmigratedBareSources2(
47584
48214
  dbPath,
47585
48215
  resolveTarget,
47586
- plan.sources.find((s) => s.name === "tasks" && existsSync28(s.path))?.path,
48216
+ plan.sources.find((s) => s.name === "tasks" && existsSync29(s.path))?.path,
47587
48217
  bareScratch
47588
48218
  ) : { first: [], last: [] };
47589
48219
  const migratePlan = { ...plan, sources: [...bare.first, ...plan.sources, ...bare.last] };
@@ -47647,7 +48277,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47647
48277
  "exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
47648
48278
  );
47649
48279
  try {
47650
- const consumed = plan.sources.filter((s) => existsSync28(s.path));
48280
+ const consumed = plan.sources.filter((s) => existsSync29(s.path));
47651
48281
  const identities = await sealTargets(plan, consumed);
47652
48282
  const archiveResult = archiveMigratedSources(consumed, cwd, plan, identities);
47653
48283
  log14.info(
@@ -47722,7 +48352,7 @@ __export(dual_scope_db_exports, {
47722
48352
  upsertIdempotent: () => upsertIdempotent,
47723
48353
  withStoreSchemaOwnership: () => withStoreSchemaOwnership
47724
48354
  });
47725
- import { existsSync as existsSync29, mkdirSync as mkdirSync10 } from "node:fs";
48355
+ import { existsSync as existsSync30, mkdirSync as mkdirSync10 } from "node:fs";
47726
48356
  import { createRequire as createRequire11 } from "node:module";
47727
48357
  import { dirname as dirname20, join as join32, resolve as resolve14 } from "node:path";
47728
48358
  function getDualScopeNativeDb(handle) {
@@ -47795,11 +48425,15 @@ async function openDualScopeDb(scope, cwd, options) {
47795
48425
  open
47796
48426
  ) : open();
47797
48427
  }
48428
+ function identityWorkOnOpen(nativeDb, scope) {
48429
+ if (ROW_IDENTITY[scope].length === 0) return false;
48430
+ return rowUidFillEnabled() || missingRowIdentitySchema(nativeDb).length > 0;
48431
+ }
47798
48432
  async function openDedicatedDualScopeDb(scope, dbPath, log15, execution) {
47799
48433
  execution?.assertActive();
47800
48434
  log15.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
47801
48435
  const dir = dirname20(dbPath);
47802
- if (!existsSync29(dir)) {
48436
+ if (!existsSync30(dir)) {
47803
48437
  mkdirSync10(dir, { recursive: true });
47804
48438
  }
47805
48439
  execution?.assertActive();
@@ -47832,9 +48466,12 @@ async function openDedicatedDualScopeDb(scope, dbPath, log15, execution) {
47832
48466
  `dual-scope-db[${scope}]`
47833
48467
  );
47834
48468
  execution?.assertActive();
47835
- if (rowUidFillEnabled()) {
48469
+ if (identityWorkOnOpen(nativeDb, scope)) {
47836
48470
  await Promise.resolve().then(() => (init_sqlite_data_accessor(), sqlite_data_accessor_exports));
47837
- prepareRowIdentity(nativeDb, scope, { triggers: false });
48471
+ healRowIdentitySchema(nativeDb, scope);
48472
+ if (rowUidFillEnabled()) {
48473
+ prepareRowIdentity(nativeDb, scope, { triggers: false });
48474
+ }
47838
48475
  }
47839
48476
  execution?.assertActive();
47840
48477
  log15.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
@@ -47947,7 +48584,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
47947
48584
  execution?.assertActive();
47948
48585
  log15.debug({ scope, dbPath: normalizedPath }, "opening dual-scope cleo.db");
47949
48586
  const dir = dirname20(normalizedPath);
47950
- if (!existsSync29(dir)) {
48587
+ if (!existsSync30(dir)) {
47951
48588
  mkdirSync10(dir, { recursive: true });
47952
48589
  }
47953
48590
  execution?.assertActive();
@@ -47980,9 +48617,12 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
47980
48617
  `dual-scope-db[${scope}]`
47981
48618
  );
47982
48619
  execution?.assertActive();
47983
- if (rowUidFillEnabled()) {
48620
+ if (identityWorkOnOpen(nativeDb, scope)) {
47984
48621
  await Promise.resolve().then(() => (init_sqlite_data_accessor(), sqlite_data_accessor_exports));
47985
- prepareRowIdentity(nativeDb, scope);
48622
+ healRowIdentitySchema(nativeDb, scope);
48623
+ if (rowUidFillEnabled()) {
48624
+ prepareRowIdentity(nativeDb, scope);
48625
+ }
47986
48626
  }
47987
48627
  execution?.assertActive();
47988
48628
  log15.debug({ scope, dbPath: normalizedPath }, "dual-scope cleo.db ready");
@@ -49112,7 +49752,7 @@ __export(nexus_sqlite_exports, {
49112
49752
  resetNexusDbState: () => resetNexusDbState,
49113
49753
  resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
49114
49754
  });
49115
- import { copyFileSync as copyFileSync8, existsSync as existsSync30 } from "node:fs";
49755
+ import { copyFileSync as copyFileSync8, existsSync as existsSync31 } from "node:fs";
49116
49756
  import { join as join33 } from "node:path";
49117
49757
  function getNexusDbPath(cwd) {
49118
49758
  return resolveDualScopeDbPath("project", cwd);
@@ -49164,7 +49804,7 @@ function detectAndWarnOnNestedNexus() {
49164
49804
  } catch {
49165
49805
  return false;
49166
49806
  }
49167
- if (!existsSync30(nestedPath)) return false;
49807
+ if (!existsSync31(nestedPath)) return false;
49168
49808
  if (_warnedNestedPaths.has(nestedPath)) return false;
49169
49809
  _warnedNestedPaths.add(nestedPath);
49170
49810
  const canonicalPath = getNexusDbPath();
@@ -49184,7 +49824,7 @@ function detectAndWarnOnNestedNexus() {
49184
49824
  function _resetNestedNexusWarningGate() {
49185
49825
  _warnedNestedPaths.clear();
49186
49826
  }
49187
- function tableExists4(nativeDb, tableName) {
49827
+ function tableExists5(nativeDb, tableName) {
49188
49828
  const result = nativeDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(tableName);
49189
49829
  return !!result;
49190
49830
  }
@@ -49193,7 +49833,7 @@ function objectExists(nativeDb, type, name2) {
49193
49833
  return !!result;
49194
49834
  }
49195
49835
  function ensureNexusFts5(nativeDb) {
49196
- if (!tableExists4(nativeDb, "nexus_nodes")) return;
49836
+ if (!tableExists5(nativeDb, "nexus_nodes")) return;
49197
49837
  if (!objectExists(nativeDb, "table", "nexus_symbols_fts")) {
49198
49838
  nativeDb.exec(`
49199
49839
  CREATE VIRTUAL TABLE nexus_symbols_fts USING fts5(
@@ -49239,7 +49879,7 @@ function ensureNexusFts5(nativeDb) {
49239
49879
  `);
49240
49880
  }
49241
49881
  function ensureNexusRelationWeights(nativeDb) {
49242
- if (!tableExists4(nativeDb, "nexus_relations")) return;
49882
+ if (!tableExists5(nativeDb, "nexus_relations")) return;
49243
49883
  nativeDb.exec(`
49244
49884
  CREATE TABLE IF NOT EXISTS nexus_relation_weights (
49245
49885
  relation_id TEXT PRIMARY KEY NOT NULL,
@@ -49321,9 +49961,9 @@ function ensureNexusRelationWeights(nativeDb) {
49321
49961
  }
49322
49962
  function runNexusMigrations(nativeDb, db, dbPath) {
49323
49963
  const migrationsFolder = resolveNexusMigrationsFolder();
49324
- if (tableExists4(nativeDb, "nexus_nodes")) {
49964
+ if (tableExists5(nativeDb, "nexus_nodes")) {
49325
49965
  const backupPath = dbPath.replace(/\.db$/, "-pre-cleo.db.bak");
49326
- if (!existsSync30(backupPath)) {
49966
+ if (!existsSync31(backupPath)) {
49327
49967
  try {
49328
49968
  copyFileSync8(dbPath, backupPath);
49329
49969
  } catch {
@@ -49453,13 +50093,13 @@ var init_legacy_alias = __esm({
49453
50093
 
49454
50094
  // packages/core/src/llm/stable-device-id.ts
49455
50095
  import { randomUUID as randomUUID3 } from "node:crypto";
49456
- import { existsSync as existsSync31, mkdirSync as mkdirSync11, readFileSync as readFileSync11, renameSync as renameSync9, writeFileSync as writeFileSync9 } from "node:fs";
50096
+ import { existsSync as existsSync32, mkdirSync as mkdirSync11, readFileSync as readFileSync11, renameSync as renameSync9, writeFileSync as writeFileSync9 } from "node:fs";
49457
50097
  import { dirname as dirname21 } from "node:path";
49458
50098
  import { resolveStableDeviceIdPath } from "@cleocode/paths";
49459
50099
  function getStableDeviceId() {
49460
50100
  if (_cachedDeviceId !== null) return _cachedDeviceId;
49461
50101
  const path2 = resolveStableDeviceIdPath();
49462
- if (existsSync31(path2)) {
50102
+ if (existsSync32(path2)) {
49463
50103
  try {
49464
50104
  const raw = readFileSync11(path2, "utf-8").trim();
49465
50105
  if (raw.length > 0) {
@@ -49472,7 +50112,7 @@ function getStableDeviceId() {
49472
50112
  const fresh = randomUUID3();
49473
50113
  try {
49474
50114
  const dir = dirname21(path2);
49475
- if (!existsSync31(dir)) {
50115
+ if (!existsSync32(dir)) {
49476
50116
  mkdirSync11(dir, { recursive: true });
49477
50117
  }
49478
50118
  const tmpPath = `${path2}.tmp.${process.pid}`;
@@ -49548,11 +50188,11 @@ __export(path_map_exports, {
49548
50188
  supersededRegistryPath: () => supersededRegistryPath,
49549
50189
  touchProjectLocation: () => touchProjectLocation
49550
50190
  });
49551
- import { existsSync as existsSync32, lstatSync, readdirSync as readdirSync8 } from "node:fs";
50191
+ import { existsSync as existsSync33, lstatSync, readdirSync as readdirSync8 } from "node:fs";
49552
50192
  import { lstat, readdir as readdir2 } from "node:fs/promises";
49553
50193
  import { isAbsolute as isAbsolute5, join as join34, relative as relative3, sep as sep5 } from "node:path";
49554
50194
  import { canonicalizePath as canonicalizePath3, readDeclaredProjectIdentity as readDeclaredProjectIdentity4 } from "@cleocode/paths";
49555
- import { and as and9, desc as desc3, eq as eq12, inArray as inArray6, ne as ne3 } from "drizzle-orm";
50195
+ import { and as and9, desc as desc3, eq as eq12, inArray as inArray7, ne as ne3 } from "drizzle-orm";
49556
50196
  function holdingKey(projectId, path2) {
49557
50197
  return `${projectId}\0${path2}`;
49558
50198
  }
@@ -49700,7 +50340,7 @@ function decideEncounterBinding(db, record) {
49700
50340
  const here = db.select({ state: projectLocations.state, checkoutNonce: projectLocations.checkoutNonce }).from(projectLocations).where(
49701
50341
  and9(
49702
50342
  eq12(projectLocations.projectId, record.projectId),
49703
- inArray6(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
50343
+ inArray7(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
49704
50344
  eq12(projectLocations.path, record.projectPath)
49705
50345
  )
49706
50346
  ).all();
@@ -49711,7 +50351,7 @@ function decideEncounterBinding(db, record) {
49711
50351
  const previous = () => db.select({ checkoutNonce: projectLocations.checkoutNonce }).from(projectLocations).where(
49712
50352
  and9(
49713
50353
  eq12(projectLocations.projectId, record.projectId),
49714
- inArray6(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
50354
+ inArray7(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
49715
50355
  eq12(projectLocations.path, oldPath)
49716
50356
  )
49717
50357
  ).all();
@@ -49759,7 +50399,7 @@ function hasOtherLiveLocation(db, record, deviceId) {
49759
50399
  ne3(projectLocations.path, record.projectPath)
49760
50400
  )
49761
50401
  ).all().some(
49762
- (location) => isStrictlyInside(record.projectPath, location.path) && existsSync32(location.path) && readDeclaredProjectIdentity4(location.path)?.projectId === record.projectId
50402
+ (location) => isStrictlyInside(record.projectPath, location.path) && existsSync33(location.path) && readDeclaredProjectIdentity4(location.path)?.projectId === record.projectId
49763
50403
  );
49764
50404
  }
49765
50405
  function demoteProjectLocation(db, record, state) {
@@ -49810,7 +50450,7 @@ function rehomeDisplacedRows(db, projectId, projectPath, deviceId, probed) {
49810
50450
  ).orderBy(desc3(projectLocations.lastSeen)).all();
49811
50451
  const present = (path2) => {
49812
50452
  const holding = probed?.get(holdingKey(row.projectId, path2));
49813
- return holding === void 0 ? existsSync32(path2) : holding === "yes";
50453
+ return holding === void 0 ? existsSync33(path2) : holding === "yes";
49814
50454
  };
49815
50455
  const home = candidates.find(
49816
50456
  (c) => present(c.path) && db.select({ projectId: projectRegistry.projectId }).from(projectRegistry).where(eq12(projectRegistry.projectPath, c.path)).all().length === 0
@@ -49839,7 +50479,7 @@ async function listProjectCheckouts(projectId, opts = {}) {
49839
50479
  projectHash: generateProjectHash(row.path),
49840
50480
  firstSeen: row.firstSeen,
49841
50481
  lastSeen: row.lastSeen,
49842
- exists: local && existsSync32(row.path),
50482
+ exists: local && existsSync33(row.path),
49843
50483
  deviceId: local ? deviceId : row.deviceId,
49844
50484
  state: row.state
49845
50485
  });
@@ -49872,7 +50512,7 @@ __export(project_activity_exports, {
49872
50512
  projectLastActivitySql: () => projectLastActivitySql,
49873
50513
  projectLastActivitySqlText: () => projectLastActivitySqlText
49874
50514
  });
49875
- import { eq as eq13, inArray as inArray7, sql as sql32 } from "drizzle-orm";
50515
+ import { eq as eq13, inArray as inArray8, sql as sql32 } from "drizzle-orm";
49876
50516
  function normalizeRegistryTimestamp(value) {
49877
50517
  if (value === null || value === void 0 || value.length === 0) return null;
49878
50518
  const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$/.test(value) ? `${value.replace(" ", "T")}Z` : value;
@@ -49901,7 +50541,7 @@ function markProjectsProbed(db, projectIds, now = /* @__PURE__ */ new Date()) {
49901
50541
  for (let i = 0; i < ids.length; i += PROBED_CHUNK) {
49902
50542
  const chunk = ids.slice(i, i + PROBED_CHUNK);
49903
50543
  changed += Number(
49904
- db.update(projectRegistry).set({ lastProbedAt: at }).where(inArray7(projectRegistry.projectId, chunk)).run().changes
50544
+ db.update(projectRegistry).set({ lastProbedAt: at }).where(inArray8(projectRegistry.projectId, chunk)).run().changes
49905
50545
  );
49906
50546
  }
49907
50547
  return changed;
@@ -49934,11 +50574,11 @@ __export(checkout_nonce_exports, {
49934
50574
  readCheckoutNonce: () => readCheckoutNonce
49935
50575
  });
49936
50576
  import { randomBytes as randomBytes3 } from "node:crypto";
49937
- import { existsSync as existsSync33, readFileSync as readFileSync12, renameSync as renameSync10, writeFileSync as writeFileSync10 } from "node:fs";
50577
+ import { existsSync as existsSync34, readFileSync as readFileSync12, renameSync as renameSync10, writeFileSync as writeFileSync10 } from "node:fs";
49938
50578
  import { join as join35 } from "node:path";
49939
50579
  function readInfo(projectRoot) {
49940
50580
  const path2 = join35(projectRoot, ".cleo", "project-info.json");
49941
- if (!existsSync33(path2)) return null;
50581
+ if (!existsSync34(path2)) return null;
49942
50582
  try {
49943
50583
  const parsed = JSON.parse(readFileSync12(path2, "utf-8"));
49944
50584
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
@@ -50031,7 +50671,7 @@ __export(paths_exports, {
50031
50671
  validateProjectRoot: () => validateProjectRoot,
50032
50672
  worktreeScope: () => worktreeScope
50033
50673
  });
50034
- import { existsSync as existsSync34, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
50674
+ import { existsSync as existsSync35, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
50035
50675
  import { createRequire as createRequire12 } from "node:module";
50036
50676
  import { homedir as homedir2 } from "node:os";
50037
50677
  import { dirname as dirname22, join as join36, resolve as resolve15 } from "node:path";
@@ -50057,7 +50697,7 @@ function runWithWorktreeScopeFromEnv(fn) {
50057
50697
  function isProjectInitialized(projectRoot) {
50058
50698
  const root = projectRoot ?? getProjectRoot();
50059
50699
  const cleoDir = join36(root, ".cleo");
50060
- return existsSync34(cleoDir) && existsSync34(join36(cleoDir, "tasks.db"));
50700
+ return existsSync35(cleoDir) && existsSync35(join36(cleoDir, "tasks.db"));
50061
50701
  }
50062
50702
  function getCleoHome() {
50063
50703
  return getPlatformPaths().data;
@@ -50163,7 +50803,7 @@ function _resolveProjectByCwdFromNexus(cwd) {
50163
50803
  try {
50164
50804
  const cleoHome = getCleoHome();
50165
50805
  const globalDbPath = join36(cleoHome, "cleo.db");
50166
- if (!existsSync34(globalDbPath)) return null;
50806
+ if (!existsSync35(globalDbPath)) return null;
50167
50807
  const start = resolve15(cwd ?? process.cwd());
50168
50808
  let current = start;
50169
50809
  const DatabaseSync3 = _getDatabaseSyncCtor();
@@ -50326,7 +50966,7 @@ function _cwdHasGitAncestor(cwd) {
50326
50966
  while (true) {
50327
50967
  const gitMarker = join36(current, ".git");
50328
50968
  try {
50329
- if (existsSync34(gitMarker)) {
50969
+ if (existsSync35(gitMarker)) {
50330
50970
  return true;
50331
50971
  }
50332
50972
  } catch {
@@ -50404,7 +51044,7 @@ function getCleoGlobalCantAgentsDir() {
50404
51044
  function getAgentOutputsDir(cwd) {
50405
51045
  const projectRoot = getProjectRoot(cwd);
50406
51046
  const configPath = join36(projectRoot, ".cleo", "config.json");
50407
- if (existsSync34(configPath)) {
51047
+ if (existsSync35(configPath)) {
50408
51048
  try {
50409
51049
  const config = JSON.parse(readFileSync13(configPath, "utf-8"));
50410
51050
  if (typeof config.agentOutputs === "object" && config.agentOutputs?.directory) {
@@ -50437,7 +51077,7 @@ function getManifestPath(cwd) {
50437
51077
  const configPath = join36(projectRoot, ".cleo", "config.json");
50438
51078
  const legacyFileName = ["MANIFEST", "jsonl"].join(".");
50439
51079
  let manifestFile = legacyFileName;
50440
- if (existsSync34(configPath)) {
51080
+ if (existsSync35(configPath)) {
50441
51081
  try {
50442
51082
  const config = JSON.parse(readFileSync13(configPath, "utf-8"));
50443
51083
  const customFile = config.agentOutputs?.manifestFile ?? config.research?.manifestFile;
@@ -50493,7 +51133,7 @@ function resolveWorktreeRouting(cwdOverride) {
50493
51133
  while (current !== home && current !== "/" && current !== "") {
50494
51134
  const gitPath = join36(current, ".git");
50495
51135
  try {
50496
- if (existsSync34(gitPath)) {
51136
+ if (existsSync35(gitPath)) {
50497
51137
  const stat3 = statSync10(gitPath);
50498
51138
  if (stat3.isFile()) {
50499
51139
  worktreePath = current;
@@ -50532,7 +51172,7 @@ function detectStrayCleoDb(routing) {
50532
51172
  }
50533
51173
  const tasksDbPath = join36(routing.worktreePath, ".cleo", "tasks.db");
50534
51174
  try {
50535
- if (existsSync34(tasksDbPath) && statSync10(tasksDbPath).isFile()) {
51175
+ if (existsSync35(tasksDbPath) && statSync10(tasksDbPath).isFile()) {
50536
51176
  return tasksDbPath;
50537
51177
  }
50538
51178
  } catch {
@@ -50542,7 +51182,7 @@ function detectStrayCleoDb(routing) {
50542
51182
  async function resolveProjectById(projectId) {
50543
51183
  try {
50544
51184
  const { getNexusDb: getNexusDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
50545
- if (!existsSync34(getNexusRegistryDbPath2())) return null;
51185
+ if (!existsSync35(getNexusRegistryDbPath2())) return null;
50546
51186
  const { eq: eq16 } = await import("drizzle-orm");
50547
51187
  const { projectRegistry: projectRegistry2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
50548
51188
  const db = await getNexusDb2();
@@ -50578,7 +51218,7 @@ function _rowToRegistryEntry(row) {
50578
51218
  }
50579
51219
  function _assertProjectInfoReadable(projectRoot) {
50580
51220
  const infoPath = join36(projectRoot, ".cleo", "project-info.json");
50581
- if (existsSync34(infoPath)) JSON.parse(readFileSync13(infoPath, "utf-8"));
51221
+ if (existsSync35(infoPath)) JSON.parse(readFileSync13(infoPath, "utf-8"));
50582
51222
  }
50583
51223
  function startProjectEncounter(key, projectRoot, infoProjectId) {
50584
51224
  const inFlight2 = _encountersInFlight.get(key);
@@ -50627,7 +51267,7 @@ async function recordProjectEncounter(cwd, options = {}) {
50627
51267
  if (!shouldAutoRegisterProject(project.projectRoot, cleoHome)) return "ephemeral";
50628
51268
  const checkout = captureProjectScope(project.projectRoot, worktreeScope.getStore()).worktreeRoot;
50629
51269
  const { getNexusRegistryDb: getNexusRegistryDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
50630
- if (existsSync34(getNexusRegistryDbPath2(cleoHome))) {
51270
+ if (existsSync35(getNexusRegistryDbPath2(cleoHome))) {
50631
51271
  const { and: and12, eq: eq16 } = await import("drizzle-orm");
50632
51272
  const { projectLocations: projectLocations2, projectRegistry: projectRegistry2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
50633
51273
  const { currentDeviceId: currentDeviceId2 } = await Promise.resolve().then(() => (init_path_map(), path_map_exports));
@@ -50653,7 +51293,7 @@ async function recordProjectEncounter(cwd, options = {}) {
50653
51293
  }
50654
51294
  async function markEncounterOpened(cleoHome, projectId) {
50655
51295
  const { getNexusRegistryDb: getNexusRegistryDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
50656
- if (!existsSync34(getNexusRegistryDbPath2(cleoHome))) return;
51296
+ if (!existsSync35(getNexusRegistryDbPath2(cleoHome))) return;
50657
51297
  const { markProjectOpened: markProjectOpened2 } = await Promise.resolve().then(() => (init_project_activity(), project_activity_exports));
50658
51298
  markProjectOpened2(await getNexusRegistryDb2(cleoHome), projectId);
50659
51299
  }
@@ -50826,7 +51466,7 @@ var init_eligibility = __esm({
50826
51466
 
50827
51467
  // packages/core/src/store/background-jobs.ts
50828
51468
  import { createHash as createHash6, randomUUID as randomUUID4 } from "node:crypto";
50829
- import { and as and10, asc as asc2, eq as eq14, getTableColumns as getTableColumns3, gt as gt2, inArray as inArray8, isNull as isNull5, ne as ne4, or as or6, sql as sql33 } from "drizzle-orm";
51469
+ import { and as and10, asc as asc2, eq as eq14, getTableColumns as getTableColumns3, gt as gt2, inArray as inArray9, isNull as isNull5, ne as ne4, or as or6, sql as sql33 } from "drizzle-orm";
50830
51470
  function assertOperationWriteFence(db, execution) {
50831
51471
  assertOperationJobState(db, execution, "running");
50832
51472
  }
@@ -51801,7 +52441,7 @@ __export(memory_accessor_exports, {
51801
52441
  logConsolidationComplete: () => logConsolidationComplete,
51802
52442
  logConsolidationStart: () => logConsolidationStart
51803
52443
  });
51804
- import { and as and11, asc as asc3, desc as desc4, eq as eq15, gt as gt3, gte as gte2, inArray as inArray9, isNull as isNull6, lt as lt3, ne as ne5, or as or7, sql as sql35 } from "drizzle-orm";
52444
+ import { and as and11, asc as asc3, desc as desc4, eq as eq15, gt as gt3, gte as gte2, inArray as inArray10, isNull as isNull6, lt as lt3, ne as ne5, or as or7, sql as sql35 } from "drizzle-orm";
51805
52445
  async function getBrainAccessor(cwd) {
51806
52446
  const db = await getBrainDb(cwd);
51807
52447
  return new BrainDataAccessor(db);
@@ -52230,8 +52870,8 @@ var init_memory_accessor = __esm({
52230
52870
  }
52231
52871
  if (params.tags && params.tags.length > 0) {
52232
52872
  const wantedTags = [...new Set(params.tags)];
52233
- const matchingIds = this.db.select({ stickyId: brainStickyTags.stickyId }).from(brainStickyTags).where(inArray9(brainStickyTags.tag, wantedTags)).groupBy(brainStickyTags.stickyId).having(sql35`count(distinct ${brainStickyTags.tag}) = ${wantedTags.length}`);
52234
- conditions.push(inArray9(brainStickyNotes.id, matchingIds));
52873
+ const matchingIds = this.db.select({ stickyId: brainStickyTags.stickyId }).from(brainStickyTags).where(inArray10(brainStickyTags.tag, wantedTags)).groupBy(brainStickyTags.stickyId).having(sql35`count(distinct ${brainStickyTags.tag}) = ${wantedTags.length}`);
52874
+ conditions.push(inArray10(brainStickyNotes.id, matchingIds));
52235
52875
  }
52236
52876
  let query = this.db.select().from(brainStickyNotes).orderBy(desc4(brainStickyNotes.createdAt));
52237
52877
  if (conditions.length > 0) {
@@ -52330,8 +52970,8 @@ var init_memory_accessor = __esm({
52330
52970
  }
52331
52971
  if (params.tags && params.tags.length > 0) {
52332
52972
  const wanted = [...new Set(params.tags)];
52333
- const matchingIds = this.db.select({ id: sql35`a.id` }).from(sql35`${t} AS a, json_each(a.tags) AS je`).where(inArray9(sql35`je.value`, wanted)).groupBy(sql35`a.id`).having(sql35`count(distinct je.value) = ${wanted.length}`);
52334
- conditions.push(inArray9(t.id, matchingIds));
52973
+ const matchingIds = this.db.select({ id: sql35`a.id` }).from(sql35`${t} AS a, json_each(a.tags) AS je`).where(inArray10(sql35`je.value`, wanted)).groupBy(sql35`a.id`).having(sql35`count(distinct je.value) = ${wanted.length}`);
52974
+ conditions.push(inArray10(t.id, matchingIds));
52335
52975
  }
52336
52976
  const where = conditions.length > 0 ? and11(...conditions) : void 0;
52337
52977
  return this.selectAttention(where, params.limit);