@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
@@ -2009,7 +2009,7 @@ var init_output_contracts_data = __esm({
2009
2009
  // T12503: the optimistic-concurrency version agents pass to --if-match.
2010
2010
  updatedAt: {
2011
2011
  type: ["string", "null"],
2012
- description: "Task version for optimistic concurrency: pass it to `cleo update|complete --if-match`."
2012
+ 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)."
2013
2013
  },
2014
2014
  // T12502: the human assignee and the agent claim lease are separate.
2015
2015
  assignee: {
@@ -13270,6 +13270,7 @@ var init_exit_codes = __esm({
13270
13270
  ExitCode2[ExitCode2["VERSION_CONFLICT"] = 23] = "VERSION_CONFLICT";
13271
13271
  ExitCode2[ExitCode2["SESSION_UNBOUND"] = 24] = "SESSION_UNBOUND";
13272
13272
  ExitCode2[ExitCode2["WORKTREE_LOCKED"] = 25] = "WORKTREE_LOCKED";
13273
+ ExitCode2[ExitCode2["TASK_RENAMED"] = 26] = "TASK_RENAMED";
13273
13274
  ExitCode2[ExitCode2["SESSION_EXISTS"] = 30] = "SESSION_EXISTS";
13274
13275
  ExitCode2[ExitCode2["SESSION_NOT_FOUND"] = 31] = "SESSION_NOT_FOUND";
13275
13276
  ExitCode2[ExitCode2["SCOPE_CONFLICT"] = 32] = "SCOPE_CONFLICT";
@@ -18059,6 +18060,19 @@ var init_error_catalog = __esm({
18059
18060
  `Bind a session: run 'cleo session start --scope global --name "<name>"', 'cleo session resume <id>', or set CLEO_SESSION_ID=<id>.`
18060
18061
  )
18061
18062
  ],
18063
+ [
18064
+ 26 /* TASK_RENAMED */,
18065
+ def(
18066
+ 26 /* TASK_RENAMED */,
18067
+ "TASK_RENAMED",
18068
+ "CONFLICT",
18069
+ "Task was re-numbered by sync",
18070
+ 409,
18071
+ true,
18072
+ "E_TASK_RENAMED",
18073
+ "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."
18074
+ )
18075
+ ],
18062
18076
  [
18063
18077
  25 /* WORKTREE_LOCKED */,
18064
18078
  def(
@@ -20006,10 +20020,10 @@ var init_table2 = __esm({
20006
20020
  [IsDrizzleTable] = true;
20007
20021
  /** @internal */
20008
20022
  [ExtraConfigBuilder] = void 0;
20009
- constructor(name15, schema, baseName) {
20023
+ constructor(name15, schema, baseName2) {
20010
20024
  this[TableName] = this[OriginalName] = name15;
20011
20025
  this[TableSchema] = schema;
20012
- this[BaseName] = baseName;
20026
+ this[BaseName] = baseName2;
20013
20027
  }
20014
20028
  };
20015
20029
  }
@@ -21939,9 +21953,9 @@ var init_casing = __esm({
21939
21953
  });
21940
21954
 
21941
21955
  // 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
21942
- function sqliteTableBase(name15, columns, extraConfig, schema, casing, baseName = name15) {
21956
+ function sqliteTableBase(name15, columns, extraConfig, schema, casing, baseName2 = name15) {
21943
21957
  const casingFn = getCasingFn(casing);
21944
- const rawTable = new SQLiteTable(name15, schema, baseName);
21958
+ const rawTable = new SQLiteTable(name15, schema, baseName2);
21945
21959
  const parsedColumns = typeof columns === "function" ? columns(getSQLiteColumnBuilders()) : columns;
21946
21960
  const builtColumns = Object.fromEntries(Object.entries(parsedColumns).map(([name16, colBuilderBase]) => {
21947
21961
  const colBuilder = colBuilderBase;
@@ -25707,6 +25721,10 @@ function decisionFor(dbPath) {
25707
25721
  if (!decisions.has(key)) decisions.set(key, schemaWriteRefusal(key));
25708
25722
  return decisions.get(key) ?? null;
25709
25723
  }
25724
+ function schemaWritesAllowed(nativeDb) {
25725
+ const dbPath = nativeDb.location();
25726
+ return !dbPath || decisionFor(dbPath) === null;
25727
+ }
25710
25728
  function isWorktreeBuildSchemaError(error48) {
25711
25729
  return error48 instanceof Error && error48.message.includes(E_WORKTREE_BUILD_SCHEMA);
25712
25730
  }
@@ -26745,7 +26763,10 @@ var init_row_identity_registry = __esm({
26745
26763
  key: ["id"],
26746
26764
  birth: "recorded_at",
26747
26765
  content: ["ac_id", "previous_text", "reason"],
26748
- birthFacts: ["ac_id", "previous_text", "reason", "@refFp:ac_uid"],
26766
+ // v2 (T12802): no @refFp: the criterion's fingerprint is unknowable when
26767
+ // it was gone before this row got its identity, so it made the value
26768
+ // depend on fill timing. ac_id is always known.
26769
+ birthFacts: ["ac_id", "previous_text", "reason"],
26749
26770
  storedRefUids: [{ column: "ac_uid", from: "ac_id", table: ACS }],
26750
26771
  task: "T12341"
26751
26772
  },
@@ -26754,7 +26775,10 @@ var init_row_identity_registry = __esm({
26754
26775
  kind: "minted",
26755
26776
  key: ["id"],
26756
26777
  birth: "created_at",
26757
- birthFacts: ["evidence_atom_id", "binding_type", "ac_text_hash", "@refFp:ac_uid"],
26778
+ // v2 (T12802): ac_id in place of @refFp:ac_uid and ac_text_hash. Both
26779
+ // were filled from the criterion, so a backfilled binding whose
26780
+ // criterion was already gone got a different value (see AC history).
26781
+ birthFacts: ["evidence_atom_id", "binding_type", "ac_id"],
26758
26782
  storedRefUids: [
26759
26783
  { column: "ac_uid", from: "ac_id", table: ACS },
26760
26784
  { column: "ac_text_hash", from: "ac_id", table: ACS, source: "text_hash" }
@@ -26796,7 +26820,9 @@ var init_row_identity_registry = __esm({
26796
26820
  // The uid IS the primary key: display-id-alias.ts computes it on write.
26797
26821
  table: "tasks_display_id_aliases",
26798
26822
  kind: "natural",
26799
- key: ["entity_table", "display_id", "entity_uid"],
26823
+ // T12800: the reason is part of the key (collision-remint and
26824
+ // remint-assigned of one id and row are distinct facts).
26825
+ key: ["entity_table", "display_id", "entity_uid", "reason"],
26800
26826
  task: "T12341"
26801
26827
  },
26802
26828
  {
@@ -27378,6 +27404,20 @@ function installRowUidTriggers(db, scope) {
27378
27404
  );
27379
27405
  }
27380
27406
  }
27407
+ function v1ReleaseBirthFp(db, table, row) {
27408
+ const col = (c) => row[c] ?? null;
27409
+ 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")] : [];
27410
+ if (facts.length === 0) return null;
27411
+ const acUid = col("ac_uid");
27412
+ let ref = "ref:none";
27413
+ if (acUid !== null) {
27414
+ const ac = db.prepare("SELECT birth_fp AS fp FROM main.tasks_task_acceptance_criteria WHERE uid = ?").get(acUid);
27415
+ ref = ac === void 0 ? "ref:missing" : ac.fp;
27416
+ if (ref === null) return null;
27417
+ }
27418
+ const spec = rowIdentitySpec("project", table);
27419
+ return birthFingerprint(table, spec?.birth ? col(spec.birth) : null, [...facts, ref]);
27420
+ }
27381
27421
  function hasObject(db, type, name15) {
27382
27422
  return db.prepare("SELECT 1 FROM main.sqlite_master WHERE type = ? AND name = ?").get(type, name15) !== void 0;
27383
27423
  }
@@ -27461,24 +27501,41 @@ function preReleaseBirthFp(db, table, row) {
27461
27501
  function resetStaleIdentity(db, scope, writers) {
27462
27502
  if (scope !== "project" || !hasTable(db, ROW_IDENTITY_META_TABLE)) return "none";
27463
27503
  if (readMeta(db, ROW_IDENTITY_RECIPE_KEY) === ROW_IDENTITY_RECIPE) return "none";
27464
- const minted = ROW_IDENTITY.project.filter(
27465
- (spec) => spec.kind === "minted" && hasTable(db, spec.table) && columnsOf(db, spec.table).has(BIRTH_FP_COLUMN)
27504
+ const minted = fingerprintOrder("project", ROW_IDENTITY.project).filter(
27505
+ (spec) => hasTable(db, spec.table) && columnsOf(db, spec.table).has(BIRTH_FP_COLUMN)
27466
27506
  );
27467
27507
  const stale = [];
27508
+ const cleared = /* @__PURE__ */ new Map();
27509
+ const mark = (table, column, value) => {
27510
+ if (value === null || value === void 0) return;
27511
+ const key = `${table}.${column}`;
27512
+ const set2 = cleared.get(key) ?? /* @__PURE__ */ new Set();
27513
+ set2.add(String(value));
27514
+ cleared.set(key, set2);
27515
+ };
27468
27516
  for (const spec of minted) {
27517
+ const deps = (spec.birthFacts ?? []).map((fact) => fingerprintRef("project", spec, fact)).filter((d) => d !== null);
27518
+ const keyColumn = targetKey("project", spec.table);
27469
27519
  const rows = db.prepare(
27470
27520
  `SELECT rowid AS _rowid, * FROM main.${q(spec.table)} WHERE ${q(BIRTH_FP_COLUMN)} IS NOT NULL`
27471
27521
  ).all();
27472
27522
  for (const row of rows) {
27473
- if (row[BIRTH_FP_COLUMN] === preReleaseBirthFp(db, spec.table, row)) {
27523
+ const derivedFromStale = deps.some(
27524
+ (d) => cleared.get(`${d.table}.${d.key}`)?.has(String(row[d.column] ?? ""))
27525
+ );
27526
+ if (derivedFromStale || row[BIRTH_FP_COLUMN] === preReleaseBirthFp(db, spec.table, row) || row[BIRTH_FP_COLUMN] === v1ReleaseBirthFp(db, spec.table, row)) {
27474
27527
  stale.push({ table: spec.table, rowid: row._rowid });
27528
+ mark(spec.table, keyColumn, row[keyColumn]);
27529
+ mark(spec.table, UID_COLUMN, row[UID_COLUMN]);
27475
27530
  }
27476
27531
  }
27477
27532
  }
27478
- if (stale.length === 0) return "none";
27533
+ const graveyardRows = scope === "project" && hasTable(db, AC_UID_GRAVEYARD) ? db.prepare(`SELECT count(*) AS n FROM main.${AC_UID_GRAVEYARD}`).get().n : 0;
27534
+ if (stale.length === 0 && graveyardRows === 0) return "none";
27479
27535
  if (readMeta(db, ROW_IDENTITY_SYNCED_KEY) !== void 0) return "refused";
27480
27536
  db.exec("SAVEPOINT row_identity_reset");
27481
27537
  try {
27538
+ if (graveyardRows > 0) writers.clearAcUidGraveyardNative(db);
27482
27539
  for (const { table, rowid } of stale) {
27483
27540
  writers.clearBirthFpNative(db, table, rowid);
27484
27541
  }
@@ -27494,6 +27551,106 @@ function writeRecipeMarker(db, writers = requireWriters()) {
27494
27551
  if (!hasTable(db, ROW_IDENTITY_META_TABLE)) return;
27495
27552
  writers.writeRowIdentityMetaNative(db, ROW_IDENTITY_RECIPE_KEY, ROW_IDENTITY_RECIPE);
27496
27553
  }
27554
+ function rowIdentityShared(db) {
27555
+ return readMeta(db, ROW_IDENTITY_SYNCED_KEY) !== void 0;
27556
+ }
27557
+ function healRowIdentitySchema(db, scope, writers = registeredWriters) {
27558
+ const log15 = getLogger("row-identity");
27559
+ if (ROW_IDENTITY[scope].length === 0) {
27560
+ return [];
27561
+ }
27562
+ if (!schemaWritesAllowed(db)) {
27563
+ log15.debug({ scope }, "row identity schema heal skipped: schema writes refused for this build");
27564
+ return [];
27565
+ }
27566
+ try {
27567
+ db.exec("SAVEPOINT row_identity_heal");
27568
+ try {
27569
+ const healed = [
27570
+ ...scope === "project" ? ensureIdentityTables(db) : [],
27571
+ ...ensureRowIdentitySchema(db, scope)
27572
+ ];
27573
+ if (healed.length > 0) recordHealReceipt(db, scope, healed, writers);
27574
+ db.exec("RELEASE SAVEPOINT row_identity_heal");
27575
+ if (healed.length > 0)
27576
+ log15.info({ scope, healed: healed.length }, "row identity schema healed");
27577
+ return healed;
27578
+ } catch (error48) {
27579
+ db.exec("ROLLBACK TO SAVEPOINT row_identity_heal");
27580
+ db.exec("RELEASE SAVEPOINT row_identity_heal");
27581
+ throw error48;
27582
+ }
27583
+ } catch (error48) {
27584
+ log15.error({ scope, error: error48 }, "row identity schema heal failed");
27585
+ return [];
27586
+ }
27587
+ }
27588
+ function recordHealReceipt(db, scope, healed, writers) {
27589
+ const table = HEAL_RECEIPT_TABLE[scope];
27590
+ const log15 = getLogger("row-identity");
27591
+ if (table === null || !hasTable(db, table) || !writers) {
27592
+ log15.warn({ scope, healed: healed.length }, "row identity schema healed; no receipt table");
27593
+ return;
27594
+ }
27595
+ const objects = healed.map((stmt) => {
27596
+ const col = /ALTER TABLE main\.("?)(\w+)\1 ADD COLUMN ("?)(\w+)\3/.exec(stmt);
27597
+ if (col) return `${col[2]}.${col[4]}`;
27598
+ const obj = /(TABLE|INDEX|TRIGGER) IF NOT EXISTS main\.("?)(\w+)\2/.exec(stmt);
27599
+ return obj ? `${obj[1].toLowerCase()} ${obj[3]}` : stmt.slice(0, 60);
27600
+ });
27601
+ const receipt2 = {
27602
+ at: (/* @__PURE__ */ new Date()).toISOString(),
27603
+ scope,
27604
+ statements: healed.length,
27605
+ objects
27606
+ };
27607
+ const history = [...readRowIdentityHealHistory(db), receipt2].slice(-HEAL_RECEIPTS_KEPT);
27608
+ writers.writeRowIdentityMetaNative(db, ROW_IDENTITY_HEAL_KEY, JSON.stringify(history));
27609
+ }
27610
+ function readRowIdentityHealHistory(db) {
27611
+ const raw = readMeta(db, ROW_IDENTITY_HEAL_KEY);
27612
+ if (raw === void 0) return [];
27613
+ try {
27614
+ const parsed = JSON.parse(raw);
27615
+ return Array.isArray(parsed) ? parsed : [parsed];
27616
+ } catch {
27617
+ return [];
27618
+ }
27619
+ }
27620
+ function missingRowIdentitySchema(db) {
27621
+ if (!hasTable(db, "tasks_task_acceptance_criteria")) return [];
27622
+ const missing = [];
27623
+ for (const table of Object.keys(IDENTITY_TABLE_DDL)) {
27624
+ if (!hasTable(db, table)) missing.push(`table ${table}`);
27625
+ }
27626
+ for (const [table, column] of [
27627
+ ["tasks_display_id_aliases", "displaced_hlc"],
27628
+ ["tasks_display_id_aliases", "entity_birth_fp"],
27629
+ [AC_UID_GRAVEYARD, "birth_fp"]
27630
+ ]) {
27631
+ if (hasTable(db, table) && !columnsOf(db, table).has(column)) {
27632
+ missing.push(`column ${table}.${column}`);
27633
+ }
27634
+ }
27635
+ if (!hasObject(db, "trigger", "trg_tasks_ac_uid_graveyard")) {
27636
+ missing.push("trigger trg_tasks_ac_uid_graveyard");
27637
+ }
27638
+ for (const spec of ROW_IDENTITY.project) {
27639
+ if (!hasTable(db, spec.table)) continue;
27640
+ const cols = columnsOf(db, spec.table);
27641
+ for (const column of rowIdentityColumns("project", spec.table)) {
27642
+ if (!cols.has(column)) missing.push(`column ${spec.table}.${column}`);
27643
+ }
27644
+ if (!uidIsPrimaryKey(db, spec.table) && !hasObject(db, "index", `uq_${spec.table}_uid`)) {
27645
+ missing.push(`index uq_${spec.table}_uid`);
27646
+ }
27647
+ for (const ref of spec.storedRefUids ?? []) {
27648
+ const index2 = `idx_${spec.table}_${ref.column}`;
27649
+ if (!hasObject(db, "index", index2)) missing.push(`index ${index2}`);
27650
+ }
27651
+ }
27652
+ return missing;
27653
+ }
27497
27654
  function prepareRowIdentity(db, scope, options = {}) {
27498
27655
  if (ROW_IDENTITY[scope].length === 0) return null;
27499
27656
  if (!rowUidFillEnabled()) return null;
@@ -27532,7 +27689,7 @@ function prepareRowIdentity(db, scope, options = {}) {
27532
27689
  return null;
27533
27690
  }
27534
27691
  }
27535
- 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;
27692
+ 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;
27536
27693
  var init_row_identity = __esm({
27537
27694
  "packages/core/src/store/row-identity.ts"() {
27538
27695
  "use strict";
@@ -27541,6 +27698,7 @@ var init_row_identity = __esm({
27541
27698
  init_ac_table();
27542
27699
  init_row_identity_flag();
27543
27700
  init_row_identity_registry();
27701
+ init_worktree_build_guard();
27544
27702
  ROW_UID_DOMAIN = "cleo/row-uid/v1";
27545
27703
  ROW_BIRTH_DOMAIN = "cleo/row-birth/v1";
27546
27704
  ROW_UID_SQL_FUNCTION = "cleo_row_uid";
@@ -27550,7 +27708,7 @@ var init_row_identity = __esm({
27550
27708
  AC_UID_GRAVEYARD = "tasks_ac_uid_graveyard";
27551
27709
  STORE_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?)?(Z|[+-]\d{2}:?\d{2})?$/;
27552
27710
  MAX_UUID_MS = 2 ** 48 - 1;
27553
- ROW_IDENTITY_RECIPE = "cleo/row-identity/v1";
27711
+ ROW_IDENTITY_RECIPE = "cleo/row-identity/v2";
27554
27712
  ROW_IDENTITY_META_TABLE = "tasks_row_identity_meta";
27555
27713
  ROW_IDENTITY_RECIPE_KEY = "row_identity_recipe";
27556
27714
  ROW_IDENTITY_SYNCED_KEY = "row_identity_synced";
@@ -27595,6 +27753,15 @@ BEGIN
27595
27753
  INSERT INTO ${AC_UID_GRAVEYARD} (ac_id, uid, task_id, ordinal, text, birth_fp, deleted_at)
27596
27754
  VALUES (OLD.id, OLD.uid, OLD.task_id, OLD.ordinal, OLD.text, OLD.birth_fp, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
27597
27755
  END`;
27756
+ ROW_IDENTITY_HEAL_KEY = "row_identity_schema_healed";
27757
+ HEAL_RECEIPT_TABLE = {
27758
+ project: ROW_IDENTITY_META_TABLE,
27759
+ // The global store declares no identity table yet (ROW_IDENTITY.global is
27760
+ // empty, so its heal never runs); the change that declares one adds its
27761
+ // meta table here.
27762
+ global: null
27763
+ };
27764
+ HEAL_RECEIPTS_KEPT = 20;
27598
27765
  }
27599
27766
  });
27600
27767
 
@@ -41141,12 +41308,12 @@ var init_safety_data_accessor = __esm({
41141
41308
  this.getSafetyOptions()
41142
41309
  );
41143
41310
  }
41144
- async insertNewTask(task) {
41311
+ async insertNewTask(task, identity) {
41145
41312
  this.logVerbose(`Inserting new task ${task.id}`);
41146
41313
  await safeSingleTaskWrite(
41147
41314
  this.inner,
41148
41315
  task.id,
41149
- () => this.inner.insertNewTask(task),
41316
+ () => this.inner.insertNewTask(task, identity),
41150
41317
  this.cwd,
41151
41318
  this.getSafetyOptions()
41152
41319
  );
@@ -41194,6 +41361,9 @@ var init_safety_data_accessor = __esm({
41194
41361
  return this.inner.findOrphanAcBindings();
41195
41362
  }
41196
41363
  // ---- Metadata (pass-through to inner) ----
41364
+ async getTaskIdentities(taskIds) {
41365
+ return await this.inner.getTaskIdentities?.(taskIds) ?? [];
41366
+ }
41197
41367
  async getMetaValue(key) {
41198
41368
  return this.inner.getMetaValue(key);
41199
41369
  }
@@ -41567,13 +41737,147 @@ var init_cross_db_cleanup = __esm({
41567
41737
  }
41568
41738
  });
41569
41739
 
41740
+ // packages/core/src/store/dependency-cycles.ts
41741
+ function formatDependencyCycle(cycle) {
41742
+ return cycle.join(" \u2192 ");
41743
+ }
41744
+ function buildAdjacency(edges) {
41745
+ const adjacency = /* @__PURE__ */ new Map();
41746
+ for (const { taskId, dependsOn } of edges) {
41747
+ const next = adjacency.get(taskId);
41748
+ if (next) next.push(dependsOn);
41749
+ else adjacency.set(taskId, [dependsOn]);
41750
+ }
41751
+ for (const next of adjacency.values()) next.sort();
41752
+ return adjacency;
41753
+ }
41754
+ function shortestPath(adjacency, from, to) {
41755
+ if (from === to) return [from];
41756
+ const previous = /* @__PURE__ */ new Map([[from, from]]);
41757
+ const queue = [from];
41758
+ for (let head = 0; head < queue.length; head++) {
41759
+ const id = queue[head];
41760
+ for (const next of adjacency.get(id) ?? []) {
41761
+ if (previous.has(next)) continue;
41762
+ previous.set(next, id);
41763
+ if (next === to) {
41764
+ const path = [to];
41765
+ let cursor = id;
41766
+ while (cursor !== from) {
41767
+ path.push(cursor);
41768
+ cursor = previous.get(cursor);
41769
+ }
41770
+ path.push(from);
41771
+ return path.reverse();
41772
+ }
41773
+ queue.push(next);
41774
+ }
41775
+ }
41776
+ return null;
41777
+ }
41778
+ function findClosedCycle(existing, edge) {
41779
+ if (edge.taskId === edge.dependsOn) return [edge.taskId, edge.taskId];
41780
+ const path = shortestPath(buildAdjacency(existing), edge.dependsOn, edge.taskId);
41781
+ return path ? [edge.taskId, ...path] : null;
41782
+ }
41783
+ function dependencyCycleError(edge, cycle) {
41784
+ const self = edge.taskId === edge.dependsOn;
41785
+ 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)}`;
41786
+ const closing = cycle.length >= 3 ? cycle[cycle.length - 2] : void 0;
41787
+ 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}`;
41788
+ return new CleoError(14 /* CIRCULAR_REFERENCE */, message, {
41789
+ fix,
41790
+ details: {
41791
+ field: "depends",
41792
+ actual: edge.dependsOn,
41793
+ taskId: edge.taskId,
41794
+ cycle: [...cycle]
41795
+ }
41796
+ });
41797
+ }
41798
+ function isDependencyCycleAbort(err) {
41799
+ for (let e = err, depth = 0; e instanceof Error && depth < 8; depth++) {
41800
+ if (e.message.includes(DEPENDENCY_CYCLE_CODE)) return true;
41801
+ e = e.cause;
41802
+ }
41803
+ return false;
41804
+ }
41805
+ function readDependencyEdges(db) {
41806
+ return db.select({
41807
+ taskId: tasksTaskDependencies.taskId,
41808
+ dependsOn: tasksTaskDependencies.dependsOn
41809
+ }).from(tasksTaskDependencies).all();
41810
+ }
41811
+ function rethrowDependencyCycle(db, err, attempted) {
41812
+ if (!isDependencyCycleAbort(err)) throw err;
41813
+ const edges = readDependencyEdges(db);
41814
+ for (const edge of attempted) {
41815
+ const cycle = findClosedCycle(edges, edge);
41816
+ if (cycle) throw dependencyCycleError(edge, cycle);
41817
+ edges.push(edge);
41818
+ }
41819
+ throw err;
41820
+ }
41821
+ var DEPENDENCY_CYCLE_CODE;
41822
+ var init_dependency_cycles = __esm({
41823
+ "packages/core/src/store/dependency-cycles.ts"() {
41824
+ "use strict";
41825
+ init_src();
41826
+ init_errors2();
41827
+ init_tasks_schema();
41828
+ DEPENDENCY_CYCLE_CODE = "E_TASK_DEPENDENCY_CYCLE";
41829
+ }
41830
+ });
41831
+
41570
41832
  // packages/core/src/store/db-helpers.ts
41571
41833
  import { and as and5, eq as eq7, inArray as inArray3, sql as sql27 } from "drizzle-orm";
41572
41834
  async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
41573
41835
  await writeTaskRow(db, row, archiveFields, allowOrphanParent, false);
41574
41836
  }
41575
- async function insertNewTask(db, row) {
41576
- await writeTaskRow(db, row, void 0, false, true);
41837
+ async function insertNewTask(db, row, identity = { origin: "new" }) {
41838
+ await writeTaskRow(
41839
+ db,
41840
+ { ...row, ...await importedIdentity(db, identity, row) },
41841
+ void 0,
41842
+ false,
41843
+ true
41844
+ );
41845
+ }
41846
+ async function tableExists2(db, table) {
41847
+ const rows = await db.all(
41848
+ sql27`SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ${table}`
41849
+ );
41850
+ return rows.length > 0;
41851
+ }
41852
+ async function importedIdentity(db, identity, row) {
41853
+ if (identity.origin === "new" || !rowUidFillEnabled()) return {};
41854
+ const fp = identity.birthFp ?? null;
41855
+ const carried2 = identity.uid ?? null;
41856
+ if (carried2 !== null && fp !== null) {
41857
+ let uid = carried2;
41858
+ if (await tableExists2(db, "tasks_uid_aliases")) {
41859
+ for (let hop = 0; hop < 32; hop++) {
41860
+ const found = await db.all(
41861
+ sql27`SELECT new_uid AS uid FROM tasks_uid_aliases
41862
+ WHERE entity_table = 'tasks_tasks' AND old_uid = ${uid} AND old_birth_fp = ${fp}`
41863
+ );
41864
+ const next = found[0];
41865
+ if (!next) break;
41866
+ uid = next.uid;
41867
+ }
41868
+ }
41869
+ const [holder] = await db.select({ id: tasksTasks.id, birthFp: tasksTasks.birthFp }).from(tasksTasks).where(eq7(tasksTasks.uid, uid)).limit(1).all();
41870
+ if (holder && holder.birthFp === fp) throw new SameRowPresentError(row.id, holder.id);
41871
+ if (await tableExists2(db, "tasks_identity_quarantine")) {
41872
+ const [held] = await db.all(
41873
+ sql27`SELECT 1 AS x FROM tasks_identity_quarantine
41874
+ WHERE entity_table = 'tasks_tasks' AND uid = ${uid} AND birth_fp = ${fp}`
41875
+ );
41876
+ if (held) throw new SameRowPresentError(row.id, "held");
41877
+ }
41878
+ if (!holder) return { uid, birthFp: fp };
41879
+ }
41880
+ return { uid: null, birthFp: null };
41577
41881
  }
41578
41882
  async function writeTaskRow(db, row, archiveFields, allowOrphanParent, insertOnly) {
41579
41883
  if (row.parentId && row.parentId === row.id) {
@@ -41724,7 +42028,11 @@ async function batchUpdateDependencies(db, tasks2, validIds) {
41724
42028
  for (const depId of want) if (!have.has(depId)) added.push({ taskId, dependsOn: depId });
41725
42029
  }
41726
42030
  if (added.length > 0) {
41727
- await db.insert(tasksTaskDependencies).values(added).onConflictDoNothing().run();
42031
+ try {
42032
+ await db.insert(tasksTaskDependencies).values(added).onConflictDoNothing().run();
42033
+ } catch (err) {
42034
+ rethrowDependencyCycle(db, err, added);
42035
+ }
41728
42036
  }
41729
42037
  }
41730
42038
  async function loadDependenciesForTasks(db, tasks2, _validationIds) {
@@ -41769,15 +42077,29 @@ async function loadRelationsForTasks(db, tasks2) {
41769
42077
  task.relates = relations && relations.length > 0 ? relations : [];
41770
42078
  }
41771
42079
  }
41772
- var log6;
42080
+ var log6, SameRowPresentError;
41773
42081
  var init_db_helpers = __esm({
41774
42082
  "packages/core/src/store/db-helpers.ts"() {
41775
42083
  "use strict";
41776
42084
  init_src();
41777
42085
  init_errors2();
41778
42086
  init_logger();
42087
+ init_dependency_cycles();
42088
+ init_row_identity_flag();
41779
42089
  init_tasks_schema();
41780
42090
  log6 = getLogger("db-helpers");
42091
+ SameRowPresentError = class extends CleoError {
42092
+ /** Where the row already is: its display id, or `held` when quarantined. */
42093
+ presentAs;
42094
+ constructor(taskId, presentAs) {
42095
+ super(
42096
+ 22 /* ID_COLLISION */,
42097
+ `Task ${taskId} is already in this store (${presentAs === "held" ? "held for sync" : `as ${presentAs}`}): same uid and birth fingerprint; not written again`,
42098
+ { details: { field: "taskId", actual: taskId, expected: presentAs } }
42099
+ );
42100
+ this.presentAs = presentAs;
42101
+ }
42102
+ };
41781
42103
  }
41782
42104
  });
41783
42105
 
@@ -41862,46 +42184,133 @@ function readProcessEntry(pid) {
41862
42184
  return null;
41863
42185
  }
41864
42186
  }
41865
- function resolvePpidKey(ppid, lookupProcess) {
42187
+ function readProcessArgs(pid) {
42188
+ if (process.platform === "win32" || !Number.isInteger(pid) || pid <= 1) return null;
42189
+ try {
42190
+ const out = execFileSync("ps", ["-o", "args=", "-p", String(pid)], {
42191
+ encoding: "utf8",
42192
+ timeout: 1e3,
42193
+ stdio: ["ignore", "pipe", "ignore"],
42194
+ env: { ...process.env, ...PS_STABLE_ENV }
42195
+ }).trim();
42196
+ return out === "" ? null : out;
42197
+ } catch {
42198
+ return null;
42199
+ }
42200
+ }
42201
+ function baseName(token) {
42202
+ return token.slice(token.lastIndexOf("/") + 1).replace(/^-/, "");
42203
+ }
42204
+ function programName(commandLine) {
42205
+ const tokens = commandLine.trim().split(/\s+/);
42206
+ const head = baseName(tokens[0] ?? "");
42207
+ if (!RUNTIME_PATTERN.test(head)) return head;
42208
+ for (let i = 1; i < tokens.length; i++) {
42209
+ const token = tokens[i] ?? "";
42210
+ if (token === "-m") return (tokens[i + 1] ?? head).split(".")[0] ?? head;
42211
+ if (token.startsWith("-")) continue;
42212
+ return baseName(token).replace(/\.(c|m)?(js|ts)$|\.py$/, "");
42213
+ }
42214
+ return head;
42215
+ }
42216
+ function isCommandStringShell(args) {
42217
+ const tokens = args.trim().split(/\s+/);
42218
+ const shell = programName(args);
42219
+ let first = 1;
42220
+ if (RUNTIME_PATTERN.test(baseName(tokens[0] ?? ""))) {
42221
+ while (first < tokens.length && (tokens[first] ?? "").startsWith("-")) first++;
42222
+ first++;
42223
+ }
42224
+ const rest = tokens.slice(first);
42225
+ if (shell === "pwsh" || shell === "powershell") {
42226
+ return rest.some((t) => PWSH_COMMAND_SWITCHES.has(t.toLowerCase()));
42227
+ }
42228
+ for (let i = 0; i < rest.length; i++) {
42229
+ const token = rest[i] ?? "";
42230
+ if (token === "--") return false;
42231
+ if (token === "--command" || token === "--commands") return true;
42232
+ if (SHELL_OPTIONS_WITH_ARGUMENT.has(token)) {
42233
+ i++;
42234
+ continue;
42235
+ }
42236
+ if (token.startsWith("--")) continue;
42237
+ if (!/^[-+][A-Za-z]+$/.test(token)) return false;
42238
+ if (token.startsWith("-") && token.slice(1).includes("c")) return true;
42239
+ }
42240
+ return false;
42241
+ }
42242
+ function resolveAncestor(ppid, lookupProcess, lookupArgs, agentId = null) {
41866
42243
  let pid = ppid;
41867
- for (let depth = 0; depth < PPID_CHAIN_MAX_DEPTH && pid > 1; depth++) {
42244
+ for (let depth = 0; depth < PPID_CHAIN_MAX_DEPTH; depth++) {
42245
+ if (pid <= 1) return null;
41868
42246
  const entry = lookupProcess(pid);
41869
- if (!entry) return null;
41870
- if (!PPID_CHAIN_LAUNCHERS.has(entry.command)) {
41871
- return { key: `ppid:${entry.pid}@${entry.startedAt}`, source: "ppid", kind: "ppid" };
42247
+ if (!entry || entry.pid <= 1) return null;
42248
+ const args = lookupArgs(entry.pid);
42249
+ const program = programName(args ?? entry.command);
42250
+ if (INIT_PROCESSES.has(program) || INIT_PROCESSES.has(entry.command)) return null;
42251
+ if (OWNER_PROCESS_SHELLS.has(program)) {
42252
+ if (args === null) return null;
42253
+ if (!isCommandStringShell(args)) return { entry, program, type: "shell" };
42254
+ } else if (!ANCESTOR_WRAPPERS.has(program)) {
42255
+ if (KNOWN_HARNESSES.has(program)) return { entry, program, type: "harness" };
42256
+ return agentId ? { entry, program, type: "host" } : null;
41872
42257
  }
41873
42258
  pid = entry.ppid;
41874
42259
  }
41875
42260
  return null;
41876
42261
  }
42262
+ function anchorKey(anchor, agentId, under) {
42263
+ const proc = `${anchor.entry.pid}@${anchor.entry.startedAt}`;
42264
+ if (anchor.type === "shell" && !agentId) {
42265
+ return { key: `proc:${proc}`, source: "process", kind: "process" };
42266
+ }
42267
+ const agent = agentId ? `#agent=${agentId}` : "";
42268
+ const scope = under ? `|${under.key}` : "";
42269
+ return {
42270
+ key: `harness:${anchor.program}:${proc}${agent}${scope}`,
42271
+ source: "process",
42272
+ kind: "harness"
42273
+ };
42274
+ }
41877
42275
  function resolveTerminalKeys(options = {}) {
41878
42276
  const env = options.env ?? process.env;
41879
42277
  const keys = [];
41880
42278
  for (const source of TERMINAL_KEY_SOURCES) {
41881
42279
  const value = envValue(env, source.envVar);
41882
42280
  if (value === null) continue;
41883
- const qualifier = envValue(env, source.qualifierEnvVar);
42281
+ const qualifiers = [source.qualifierEnvVar, ...source.extraQualifierEnvVars ?? []].map((name15) => envValue(env, name15)).filter((q2) => q2 !== null);
41884
42282
  keys.push({
41885
- key: `env:${source.envVar}=${qualifier === null ? value : `${qualifier}|${value}`}`,
42283
+ key: `env:${source.envVar}=${[...qualifiers, value].join("|")}`,
41886
42284
  source: source.envVar,
41887
42285
  kind: source.kind
41888
42286
  });
41889
42287
  }
41890
- if (keys.length > 0) return keys;
41891
- const live = options.ppid === void 0 && options.lookupProcess === void 0;
41892
- let ppidKey;
42288
+ if (keys.some((k) => k.kind === "provider")) return keys;
42289
+ const agentId = envValue(env, "CLEO_AGENT_ID");
42290
+ const live = options.ppid === void 0 && options.lookupProcess === void 0 && options.lookupArgs === void 0;
42291
+ let anchor;
41893
42292
  if (live) {
41894
- if (livePpidKey === void 0) livePpidKey = resolvePpidKey(process.ppid, readProcessEntry);
41895
- ppidKey = livePpidKey;
42293
+ const memoKey2 = agentId ?? "";
42294
+ if (!liveAnchors.has(memoKey2))
42295
+ liveAnchors.set(
42296
+ memoKey2,
42297
+ resolveAncestor(process.ppid, readProcessEntry, readProcessArgs, agentId)
42298
+ );
42299
+ anchor = liveAnchors.get(memoKey2) ?? null;
41896
42300
  } else {
41897
- ppidKey = resolvePpidKey(
42301
+ anchor = resolveAncestor(
41898
42302
  options.ppid ?? process.ppid,
41899
- options.lookupProcess ?? readProcessEntry
42303
+ options.lookupProcess ?? readProcessEntry,
42304
+ options.lookupArgs ?? readProcessArgs,
42305
+ agentId
41900
42306
  );
41901
42307
  }
41902
- return ppidKey ? [ppidKey] : [];
42308
+ if (!anchor) return keys;
42309
+ if (keys.length === 0) return [anchorKey(anchor, agentId, void 0)];
42310
+ if (anchor.type === "shell" && !agentId) return keys;
42311
+ return [...keys, anchorKey(anchor, agentId, keys[0])];
41903
42312
  }
41904
- var TERMINAL_KEY_SOURCES, PPID_CHAIN_LAUNCHERS, PPID_CHAIN_MAX_DEPTH, livePpidKey;
42313
+ 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;
41905
42314
  var init_terminal_identity = __esm({
41906
42315
  "packages/core/src/sessions/terminal-identity.ts"() {
41907
42316
  "use strict";
@@ -41933,24 +42342,100 @@ var init_terminal_identity = __esm({
41933
42342
  kind: "terminal",
41934
42343
  origin: "konsole",
41935
42344
  qualifierEnvVar: "KONSOLE_DBUS_SERVICE"
42345
+ },
42346
+ // T12864 — non-terminal callers whose platform exports a per-job / per-login id.
42347
+ // GitHub Actions: GITHUB_RUN_ID is per run and shared by its jobs, so it is
42348
+ // qualified by GITHUB_RUN_ATTEMPT and GITHUB_JOB ("Variables reference",
42349
+ // docs.github.com/en/actions/reference/workflows-and-actions/variables).
42350
+ // Every step of one job shares the key; the steps run sequentially.
42351
+ {
42352
+ envVar: "GITHUB_RUN_ID",
42353
+ kind: "terminal",
42354
+ origin: "github-actions",
42355
+ qualifierEnvVar: "GITHUB_RUN_ATTEMPT",
42356
+ extraQualifierEnvVars: ["GITHUB_JOB"]
42357
+ },
42358
+ // GitLab CI: CI_JOB_ID is unique per job across the instance ("Predefined
42359
+ // CI/CD variables reference", docs.gitlab.com/ci/variables/predefined_variables).
42360
+ { envVar: "CI_JOB_ID", kind: "terminal", origin: "gitlab-ci" },
42361
+ // OpenSSH login with a tty: SSH_TTY names the login's tty and is set only
42362
+ // when one was allocated; SSH_CONNECTION ("client-ip client-port server-ip
42363
+ // server-port", ssh(1) ENVIRONMENT) disambiguates it across connections. A
42364
+ // one-shot `ssh host 'cmd'` has no tty and falls through to the ancestor walk.
42365
+ {
42366
+ envVar: "SSH_TTY",
42367
+ kind: "terminal",
42368
+ origin: "openssh",
42369
+ qualifierEnvVar: "SSH_CONNECTION"
41936
42370
  }
41937
42371
  ];
41938
- PPID_CHAIN_LAUNCHERS = /* @__PURE__ */ new Set([
41939
- "node",
42372
+ PPID_CHAIN_MAX_DEPTH = 12;
42373
+ KNOWN_HARNESSES = /* @__PURE__ */ new Set([
42374
+ "claude",
42375
+ "codex",
42376
+ "aider",
42377
+ "gemini",
42378
+ "kimi",
42379
+ "cursor-agent",
42380
+ "amp"
42381
+ ]);
42382
+ RUNTIME_PATTERN = /^(node|nodejs|bun|deno|python[0-9.]*|pypy[0-9.]*|ruby|java|php|perl)$/;
42383
+ ANCESTOR_WRAPPERS = /* @__PURE__ */ new Set([
42384
+ "env",
42385
+ "timeout",
42386
+ "gtimeout",
42387
+ "nohup",
42388
+ "nice",
42389
+ "time",
42390
+ "xargs",
42391
+ "stdbuf",
42392
+ "sudo",
42393
+ "doas",
41940
42394
  "npm",
42395
+ "npm-cli",
41941
42396
  "npx",
42397
+ "npx-cli",
41942
42398
  "pnpm",
41943
42399
  "pnpx",
41944
42400
  "yarn",
41945
- "bun",
41946
42401
  "bunx",
41947
- "tsx",
41948
42402
  "corepack",
41949
42403
  "mise",
41950
- "env",
41951
42404
  "cleo"
41952
42405
  ]);
41953
- PPID_CHAIN_MAX_DEPTH = 4;
42406
+ INIT_PROCESSES = /* @__PURE__ */ new Set(["launchd", "systemd", "init"]);
42407
+ SHELL_OPTIONS_WITH_ARGUMENT = /* @__PURE__ */ new Set([
42408
+ "-o",
42409
+ "+o",
42410
+ "-O",
42411
+ "+O",
42412
+ "--rcfile",
42413
+ "--init-file"
42414
+ ]);
42415
+ PWSH_COMMAND_SWITCHES = /* @__PURE__ */ new Set([
42416
+ "-c",
42417
+ "-command",
42418
+ "-commandwithargs",
42419
+ "-cwa",
42420
+ "-e",
42421
+ "-ec",
42422
+ "-encodedcommand"
42423
+ ]);
42424
+ OWNER_PROCESS_SHELLS = /* @__PURE__ */ new Set([
42425
+ "sh",
42426
+ "bash",
42427
+ "zsh",
42428
+ "dash",
42429
+ "fish",
42430
+ "ksh",
42431
+ "tcsh",
42432
+ "csh",
42433
+ "pwsh",
42434
+ "powershell",
42435
+ "nu",
42436
+ "xonsh"
42437
+ ]);
42438
+ liveAnchors = /* @__PURE__ */ new Map();
41954
42439
  }
41955
42440
  });
41956
42441
 
@@ -41990,7 +42475,8 @@ var init_session_binding_schema = __esm({
41990
42475
  });
41991
42476
 
41992
42477
  // packages/core/src/store/session-store.ts
41993
- import { and as and6, desc as desc2, eq as eq8, isNull as isNull3, lte as lte2, or as or4 } from "drizzle-orm";
42478
+ import { existsSync as existsSync20 } from "node:fs";
42479
+ 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";
41994
42480
  async function getSession(sessionId, cwd) {
41995
42481
  const scope = captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
41996
42482
  return worktreeScope.run(scope, async () => {
@@ -42012,8 +42498,9 @@ async function getActiveSession(cwd) {
42012
42498
  function splitTerminalKeys(keys) {
42013
42499
  return {
42014
42500
  provider: keys.find((k) => k.kind === "provider"),
42015
- pane: keys.find((k) => k.kind === "multiplexer"),
42016
- tab: keys.find((k) => k.kind === "terminal" || k.kind === "ppid")
42501
+ // A harness / CLEO_AGENT_ID agent (T12864) is more specific than a pane.
42502
+ pane: keys.find((k) => k.kind === "harness") ?? keys.find((k) => k.kind === "multiplexer"),
42503
+ tab: keys.find((k) => k.kind === "terminal" || k.kind === "process" || k.kind === "ppid")
42017
42504
  };
42018
42505
  }
42019
42506
  async function readBinding(db, key) {
@@ -42093,6 +42580,7 @@ async function resolveCurrentSession(cwd) {
42093
42580
  async function resolveBoundSession(cwd) {
42094
42581
  const scope = captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
42095
42582
  return worktreeScope.run(scope, async () => {
42583
+ if (!existsSync20(getDbPath(scope.worktreeRoot))) return null;
42096
42584
  const connId = getCurrentConnectionSessionId();
42097
42585
  if (connId) {
42098
42586
  const byConn = await getSession(connId, scope.worktreeRoot);
@@ -42244,7 +42732,7 @@ __export(registry_exports2, {
42244
42732
  updateAgentStatus: () => updateAgentStatus
42245
42733
  });
42246
42734
  import { randomBytes as randomBytes2 } from "node:crypto";
42247
- import { and as and7, eq as eq9, inArray as inArray4, lt as lt2, sql as sql29 } from "drizzle-orm";
42735
+ import { and as and7, eq as eq9, inArray as inArray5, lt as lt2, sql as sql29 } from "drizzle-orm";
42248
42736
  function generateAgentId() {
42249
42737
  const now = /* @__PURE__ */ new Date();
42250
42738
  const ts = now.toISOString().replace(/[-:T]/g, "").substring(0, 14);
@@ -42333,11 +42821,11 @@ async function listAgentInstances(filters, cwd) {
42333
42821
  const conditions = [];
42334
42822
  if (filters?.status) {
42335
42823
  const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
42336
- conditions.push(inArray4(agentInstances.status, statuses));
42824
+ conditions.push(inArray5(agentInstances.status, statuses));
42337
42825
  }
42338
42826
  if (filters?.agentType) {
42339
42827
  const types = Array.isArray(filters.agentType) ? filters.agentType : [filters.agentType];
42340
- conditions.push(inArray4(agentInstances.agentType, types));
42828
+ conditions.push(inArray5(agentInstances.agentType, types));
42341
42829
  }
42342
42830
  if (filters?.sessionId) {
42343
42831
  conditions.push(eq9(agentInstances.sessionId, filters.sessionId));
@@ -42374,7 +42862,7 @@ async function checkAgentHealth(thresholdMs = 3e4, cwd) {
42374
42862
  const cutoff = new Date(Date.now() - thresholdMs).toISOString();
42375
42863
  return db.select().from(agentInstances).where(
42376
42864
  and7(
42377
- inArray4(agentInstances.status, ["active", "idle", "starting"]),
42865
+ inArray5(agentInstances.status, ["active", "idle", "starting"]),
42378
42866
  lt2(agentInstances.lastHeartbeat, cutoff)
42379
42867
  )
42380
42868
  ).all();
@@ -42469,12 +42957,14 @@ var init_registry2 = __esm({
42469
42957
  // packages/core/src/store/sqlite-data-accessor.ts
42470
42958
  var sqlite_data_accessor_exports = {};
42471
42959
  __export(sqlite_data_accessor_exports, {
42960
+ RENAMED_RECENT_MS: () => RENAMED_RECENT_MS,
42472
42961
  addTaskLabelsNative: () => addTaskLabelsNative,
42473
42962
  advanceTaskIdSequence: () => advanceTaskIdSequence,
42474
42963
  bindTaskAccessorScope: () => bindTaskAccessorScope,
42475
42964
  captureTaskAccessorScope: () => captureProjectScope,
42476
42965
  clearAcUidGraveyardNative: () => clearAcUidGraveyardNative,
42477
42966
  clearBirthFpNative: () => clearBirthFpNative,
42967
+ clearReplacedTaskIdentityNative: () => clearReplacedTaskIdentityNative,
42478
42968
  clearRowUidNative: () => clearRowUidNative,
42479
42969
  createSqliteDataAccessor: () => createSqliteDataAccessor,
42480
42970
  deleteDisplayIdAliasNative: () => deleteDisplayIdAliasNative,
@@ -42485,6 +42975,7 @@ __export(sqlite_data_accessor_exports, {
42485
42975
  insertIdentityRowNative: () => insertIdentityRowNative,
42486
42976
  insertQuarantineNative: () => insertQuarantineNative,
42487
42977
  insertUidAliasNative: () => insertUidAliasNative,
42978
+ readReplacedTaskBirthNative: () => readReplacedTaskBirthNative,
42488
42979
  rederiveAcIdsNative: () => rederiveAcIdsNative,
42489
42980
  rekeyQuarantineNative: () => rekeyQuarantineNative,
42490
42981
  relinkAcUidNative: () => relinkAcUidNative,
@@ -42501,7 +42992,7 @@ import {
42501
42992
  and as and8,
42502
42993
  eq as eq10,
42503
42994
  getTableColumns as getTableColumns2,
42504
- inArray as inArray5,
42995
+ inArray as inArray6,
42505
42996
  isNull as isNull4,
42506
42997
  like as like2,
42507
42998
  lte as lte3,
@@ -42525,8 +43016,8 @@ async function selectAcBindings(db, acIds) {
42525
43016
  bindingType: b.bindingType,
42526
43017
  createdAt: b.createdAt
42527
43018
  };
42528
- const byUid = await db.select(columns).from(b).innerJoin(ac, eq10(ac.uid, b.acUid)).where(inArray5(ac.id, ids)).all();
42529
- const byId = await db.select(columns).from(b).leftJoin(ac, eq10(ac.uid, b.acUid)).where(inArray5(b.acId, ids)).all();
43019
+ const byUid = await db.select(columns).from(b).innerJoin(ac, eq10(ac.uid, b.acUid)).where(inArray6(ac.id, ids)).all();
43020
+ const byId = await db.select(columns).from(b).leftJoin(ac, eq10(ac.uid, b.acUid)).where(inArray6(b.acId, ids)).all();
42530
43021
  const rows = [...byUid, ...byId];
42531
43022
  const wanted = new Set(ids);
42532
43023
  const seen = /* @__PURE__ */ new Set();
@@ -42619,6 +43110,7 @@ function renameTaskDisplayIdNative(nativeDb, uid, toId, refs, guard = {}) {
42619
43110
  if (Number(changed) !== 1) {
42620
43111
  throw taskConflictError(current.id, taskVersion(current), null);
42621
43112
  }
43113
+ recordLocalRename(nativeDb, uid, current.id, toId, taskVersion(current));
42622
43114
  const rewritten = {};
42623
43115
  const q2 = (name15) => `"${name15.replaceAll('"', '""')}"`;
42624
43116
  for (const ref of refs) {
@@ -42674,23 +43166,39 @@ function rederiveAcIdsNative(nativeDb, fromId, toId) {
42674
43166
  }
42675
43167
  return count;
42676
43168
  }
42677
- function insertDisplayIdAliasNative(nativeDb, row) {
43169
+ function insertDisplayIdAliasNative(nativeDb, row, precedes) {
43170
+ const stored = nativeDb.prepare(
43171
+ `SELECT uid, entity_table AS entityTable, display_id AS displayId, entity_uid AS entityUid,
43172
+ reason, origin, displaced_hlc AS displacedHlc, created_at AS createdAt,
43173
+ entity_birth_fp AS entityBirthFp
43174
+ FROM tasks_display_id_aliases WHERE uid = ?`
43175
+ ).get(row.uid);
43176
+ if (!stored) {
43177
+ nativeDb.prepare(
43178
+ `INSERT INTO tasks_display_id_aliases
43179
+ (uid, entity_table, display_id, entity_uid, reason, origin, displaced_hlc, created_at,
43180
+ entity_birth_fp)
43181
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
43182
+ ).run(
43183
+ row.uid,
43184
+ row.entityTable,
43185
+ row.displayId,
43186
+ row.entityUid,
43187
+ row.reason,
43188
+ row.origin,
43189
+ row.displacedHlc,
43190
+ row.createdAt,
43191
+ row.entityBirthFp
43192
+ );
43193
+ return;
43194
+ }
43195
+ if (!precedes(row, stored)) return;
42678
43196
  nativeDb.prepare(
42679
- `INSERT OR IGNORE INTO tasks_display_id_aliases
42680
- (uid, entity_table, display_id, entity_uid, reason, origin, displaced_hlc, created_at,
42681
- entity_birth_fp)
42682
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
42683
- ).run(
42684
- row.uid,
42685
- row.entityTable,
42686
- row.displayId,
42687
- row.entityUid,
42688
- row.reason,
42689
- row.origin,
42690
- row.displacedHlc,
42691
- row.createdAt,
42692
- row.entityBirthFp
42693
- );
43197
+ `UPDATE tasks_display_id_aliases
43198
+ SET origin = ?, displaced_hlc = ?, created_at = ?,
43199
+ entity_birth_fp = coalesce(entity_birth_fp, ?)
43200
+ WHERE uid = ?`
43201
+ ).run(row.origin, row.displacedHlc, row.createdAt, row.entityBirthFp, row.uid);
42694
43202
  }
42695
43203
  function deleteDisplayIdAliasNative(nativeDb, uid) {
42696
43204
  nativeDb.prepare("DELETE FROM tasks_display_id_aliases WHERE uid = ?").run(uid);
@@ -42752,6 +43260,63 @@ function relinkAcUidNative(nativeDb, acId, uid, birthFp) {
42752
43260
  function clearAcUidGraveyardNative(nativeDb) {
42753
43261
  nativeDb.exec("DELETE FROM tasks_ac_uid_graveyard");
42754
43262
  }
43263
+ function readReplacedTaskBirthNative(nativeDb, taskId) {
43264
+ return nativeDb.prepare("SELECT created_at AS createdAt, uid FROM tasks_tasks WHERE id = ?").get(taskId);
43265
+ }
43266
+ function clearReplacedTaskIdentityNative(nativeDb, taskId, before) {
43267
+ const row = nativeDb.prepare("SELECT uid, birth_fp AS fp, created_at AS createdAt FROM tasks_tasks WHERE id = ?").get(taskId);
43268
+ if (!row || row.uid === null && row.fp === null) return;
43269
+ if (before) {
43270
+ const was = parseStoreTimestamp(before.createdAt);
43271
+ if (was !== null && was === parseStoreTimestamp(row.createdAt)) {
43272
+ return;
43273
+ }
43274
+ }
43275
+ if (rowIdentityShared(nativeDb)) {
43276
+ throw new CleoError(
43277
+ 6 /* VALIDATION_ERROR */,
43278
+ `Task ${taskId} cannot be overwritten by an import: its identity is shared with other devices`,
43279
+ {
43280
+ fix: "Import it under a new id (the default duplicate strategy), or edit the task instead of overwriting it.",
43281
+ details: { field: "taskId", actual: taskId }
43282
+ }
43283
+ );
43284
+ }
43285
+ const has = (table) => nativeDb.prepare("SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) !== void 0;
43286
+ nativeDb.prepare("UPDATE tasks_tasks SET uid = NULL, birth_fp = NULL WHERE id = ?").run(taskId);
43287
+ for (const spec of ROW_IDENTITY.project) {
43288
+ if (spec.kind !== "natural" || !has(spec.table)) continue;
43289
+ const cols = (spec.keyRefs ?? []).filter((r) => r.table === "tasks_tasks").map((r) => r.column);
43290
+ if (cols.length === 0) continue;
43291
+ nativeDb.prepare(
43292
+ `UPDATE main.${quoteIdent2(spec.table)} SET uid = NULL WHERE ${cols.map((c) => `${quoteIdent2(c)} = ?`).join(" OR ")}`
43293
+ ).run(...cols.map(() => taskId));
43294
+ }
43295
+ const children = ["tasks_task_acceptance_criteria_history", "tasks_evidence_ac_bindings"].filter(
43296
+ has
43297
+ );
43298
+ const criteria = has("tasks_task_acceptance_criteria") ? nativeDb.prepare("SELECT id, uid FROM tasks_task_acceptance_criteria WHERE task_id = ?").all(taskId) : [];
43299
+ if (criteria.length > 0) {
43300
+ nativeDb.prepare(
43301
+ "UPDATE tasks_task_acceptance_criteria SET uid = NULL, birth_fp = NULL WHERE task_id = ?"
43302
+ ).run(taskId);
43303
+ }
43304
+ fillRowUids(nativeDb, "project");
43305
+ const newUid = nativeDb.prepare("SELECT uid FROM tasks_task_acceptance_criteria WHERE id = ?");
43306
+ let rekeyed = 0;
43307
+ for (const ac of criteria) {
43308
+ const now = newUid.get(ac.id)?.uid ?? null;
43309
+ for (const table of children) {
43310
+ rekeyed += Number(
43311
+ nativeDb.prepare(
43312
+ `UPDATE main.${quoteIdent2(table)} SET ac_uid = ?, birth_fp = NULL
43313
+ WHERE ac_id = ? OR (? IS NOT NULL AND ac_uid = ?)`
43314
+ ).run(now, ac.id, ac.uid, ac.uid).changes
43315
+ );
43316
+ }
43317
+ }
43318
+ if (rekeyed > 0) fillRowUids(nativeDb, "project");
43319
+ }
42755
43320
  function quoteIdent2(name15) {
42756
43321
  return `"${name15.replaceAll('"', '""')}"`;
42757
43322
  }
@@ -42839,10 +43404,50 @@ function claimPredicate(guard, allowedHolders) {
42839
43404
  if (guard.mode === "force") return void 0;
42840
43405
  const mine = guard.sessionId === null ? void 0 : eq10(holder, guard.sessionId);
42841
43406
  if (guard.mode === "renew" || guard.mode === "release") return mine ?? sql30`0`;
42842
- const related = allowedHolders.length > 0 ? inArray5(holder, [...allowedHolders]) : void 0;
43407
+ const related = allowedHolders.length > 0 ? inArray6(holder, [...allowedHolders]) : void 0;
42843
43408
  const expired = guard.mode === "take-over" ? or5(isNull4(tasksTasks.leaseExpiresAt), lte3(tasksTasks.leaseExpiresAt, guard.now)) : void 0;
42844
43409
  return or5(isNull4(holder), mine, related, expired);
42845
43410
  }
43411
+ function renameRecordKey(fromId) {
43412
+ return `renamed_from:tasks_tasks:${fromId}`;
43413
+ }
43414
+ function hasIdentityMeta(nativeDb) {
43415
+ return nativeDb.prepare(
43416
+ "SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = 'tasks_row_identity_meta'"
43417
+ ).get() !== void 0;
43418
+ }
43419
+ function recordLocalRename(nativeDb, uid, fromId, toId, fromVersion) {
43420
+ if (!hasIdentityMeta(nativeDb)) return;
43421
+ const record2 = { uid, fromVersion, toId, at: (/* @__PURE__ */ new Date()).toISOString() };
43422
+ writeRowIdentityMetaNative(nativeDb, renameRecordKey(fromId), JSON.stringify(record2));
43423
+ }
43424
+ function assertNotRenamed(nativeDb, taskId, guard, current) {
43425
+ if (!nativeDb || !hasIdentityMeta(nativeDb)) return;
43426
+ const raw = nativeDb.prepare("SELECT value FROM tasks_row_identity_meta WHERE key = ?").get(renameRecordKey(taskId));
43427
+ if (!raw) return;
43428
+ let record2;
43429
+ try {
43430
+ record2 = JSON.parse(raw.value);
43431
+ } catch {
43432
+ return;
43433
+ }
43434
+ if (Date.now() - Date.parse(record2.at) > RENAMED_RECENT_MS) return;
43435
+ const renamed = nativeDb.prepare("SELECT id, claimed_by_session AS claimedBySession FROM tasks_tasks WHERE uid = ?").get(record2.uid);
43436
+ if (!renamed || renamed.id === taskId) return;
43437
+ const expected = guard.expectedUpdatedAt;
43438
+ const session = guard.claim?.sessionId ?? null;
43439
+ const holdsRenamedClaim = session !== null && (guard.claim?.mode === "renew" || guard.claim?.mode === "release") && renamed.claimedBySession === session && current?.claimedBySession !== session;
43440
+ const readRenamed = expected !== void 0 && expected === record2.fromVersion && (current === void 0 || taskVersion(current) !== expected);
43441
+ if (!(current === void 0 || holdsRenamedClaim || readRenamed)) return;
43442
+ throw new CleoError(
43443
+ 26 /* TASK_RENAMED */,
43444
+ `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`,
43445
+ {
43446
+ fix: `Re-read it with 'cleo show ${renamed.id}' and retry against ${renamed.id}.`,
43447
+ details: { field: "taskId", actual: taskId, expected: renamed.id }
43448
+ }
43449
+ );
43450
+ }
42846
43451
  function assertClaimAllowed(taskId, row, guard, allowedHolders) {
42847
43452
  const stored = claimFromColumns(row);
42848
43453
  if (claimAllows(stored, guard.mode, guard.sessionId, guard.now, allowedHolders)) return;
@@ -43017,13 +43622,13 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43017
43622
  const db = await getDb(cwd);
43018
43623
  const conditions = [];
43019
43624
  if (query.ids && query.ids.length > 0) {
43020
- conditions.push(inArray5(tasksAuditLog.id, [...query.ids]));
43625
+ conditions.push(inArray6(tasksAuditLog.id, [...query.ids]));
43021
43626
  }
43022
43627
  if (query.taskIds && query.taskIds.length > 0) {
43023
- conditions.push(inArray5(tasksAuditLog.taskId, [...query.taskIds]));
43628
+ conditions.push(inArray6(tasksAuditLog.taskId, [...query.taskIds]));
43024
43629
  }
43025
43630
  if (query.actions && query.actions.length > 0) {
43026
- conditions.push(inArray5(tasksAuditLog.action, [...query.actions]));
43631
+ conditions.push(inArray6(tasksAuditLog.action, [...query.actions]));
43027
43632
  }
43028
43633
  if (query.since) {
43029
43634
  conditions.push(sql30`${tasksAuditLog.timestamp} >= ${query.since}`);
@@ -43056,8 +43661,13 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43056
43661
  async upsertSingleTask(task) {
43057
43662
  await accessor.transaction((tx) => tx.upsertSingleTask(task));
43058
43663
  },
43059
- async insertNewTask(task) {
43060
- await accessor.transaction((tx) => tx.insertNewTask(task));
43664
+ async insertNewTask(task, identity) {
43665
+ await accessor.transaction((tx) => tx.insertNewTask(task, identity));
43666
+ },
43667
+ async getTaskIdentities(taskIds) {
43668
+ if (taskIds.length === 0) return [];
43669
+ const db = await getDb(cwd);
43670
+ return db.select({ id: tasksTasks.id, uid: tasksTasks.uid, birthFp: tasksTasks.birthFp }).from(tasksTasks).where(inArray6(tasksTasks.id, taskIds)).all();
43061
43671
  },
43062
43672
  async addRelation(taskId, relatedTo, relationType, reason) {
43063
43673
  return accessor.transaction(async () => {
@@ -43234,7 +43844,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43234
43844
  if (!statuses.includes("archived")) {
43235
43845
  conditions.push(ne2(tasksTasks.status, "archived"));
43236
43846
  }
43237
- conditions.push(inArray5(tasksTasks.status, statuses));
43847
+ conditions.push(inArray6(tasksTasks.status, statuses));
43238
43848
  } else if (filters.excludeStatus) {
43239
43849
  const excluded = Array.isArray(filters.excludeStatus) ? filters.excludeStatus : [filters.excludeStatus];
43240
43850
  for (const s of excluded) {
@@ -43248,11 +43858,11 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43248
43858
  if (filters.phase) conditions.push(eq10(tasksTasks.phase, filters.phase));
43249
43859
  if (filters.severity) {
43250
43860
  const severities = Array.isArray(filters.severity) ? filters.severity : [filters.severity];
43251
- conditions.push(inArray5(tasksTasks.severity, severities));
43861
+ conditions.push(inArray6(tasksTasks.severity, severities));
43252
43862
  }
43253
43863
  if (filters.kind) {
43254
43864
  const kinds = Array.isArray(filters.kind) ? filters.kind : [filters.kind];
43255
- conditions.push(inArray5(tasksTasks.kind, kinds));
43865
+ conditions.push(inArray6(tasksTasks.kind, kinds));
43256
43866
  }
43257
43867
  if (filters.parentId !== void 0) {
43258
43868
  if (filters.parentId === null) {
@@ -43273,7 +43883,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43273
43883
  }
43274
43884
  if (filters.label) {
43275
43885
  const labelMatchIds = db.select({ taskId: tasksTaskLabels.taskId }).from(tasksTaskLabels).where(eq10(tasksTaskLabels.label, filters.label));
43276
- conditions.push(inArray5(tasksTasks.id, labelMatchIds));
43886
+ conditions.push(inArray6(tasksTasks.id, labelMatchIds));
43277
43887
  }
43278
43888
  const where = conditions.length > 0 ? and8(...conditions) : void 0;
43279
43889
  const countResult = await db.select({ count: sql30`count(*)` }).from(tasksTasks).where(where).get();
@@ -43316,7 +43926,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43316
43926
  const conditions = [];
43317
43927
  if (filters?.status) {
43318
43928
  const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
43319
- conditions.push(inArray5(tasksTasks.status, statuses));
43929
+ conditions.push(inArray6(tasksTasks.status, statuses));
43320
43930
  } else {
43321
43931
  conditions.push(ne2(tasksTasks.status, "archived"));
43322
43932
  }
@@ -43381,7 +43991,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43381
43991
  if (idRows.length === 0) return [];
43382
43992
  const db = await getDb(cwd);
43383
43993
  const ids = idRows.map((r) => r.id);
43384
- const taskRows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, ids)).all();
43994
+ const taskRows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, ids)).all();
43385
43995
  const tasks2 = taskRows.map(rowToTask);
43386
43996
  if (tasks2.length > 0) {
43387
43997
  const allIds = await getAllTaskIds();
@@ -43410,7 +44020,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43410
44020
  if (idRows.length === 0) return [];
43411
44021
  const db = await getDb(cwd);
43412
44022
  const ids = idRows.map((r) => r.id);
43413
- const rows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, ids)).all();
44023
+ const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, ids)).all();
43414
44024
  const tasks2 = rows.map(rowToTask);
43415
44025
  if (tasks2.length > 0) {
43416
44026
  const allIds = await getAllTaskIds();
@@ -43424,7 +44034,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43424
44034
  const depRows = await db.select().from(tasksTaskDependencies).where(eq10(tasksTaskDependencies.dependsOn, taskId)).all();
43425
44035
  if (depRows.length === 0) return [];
43426
44036
  const dependentIds = depRows.map((r) => r.taskId);
43427
- const rows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, dependentIds)).all();
44037
+ const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, dependentIds)).all();
43428
44038
  const tasks2 = rows.map(rowToTask);
43429
44039
  if (tasks2.length > 0) {
43430
44040
  const allIds = await getAllTaskIds();
@@ -43454,7 +44064,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43454
44064
  async loadTasks(taskIds) {
43455
44065
  if (taskIds.length === 0) return [];
43456
44066
  const db = await getDb(cwd);
43457
- const rows = await db.select().from(tasksTasks).where(inArray5(tasksTasks.id, taskIds)).all();
44067
+ const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, taskIds)).all();
43458
44068
  const tasks2 = rows.map(rowToTask);
43459
44069
  if (tasks2.length > 0) {
43460
44070
  const allIds = await getAllTaskIds();
@@ -43508,6 +44118,9 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43508
44118
  createdAt: tasksTasks.createdAt,
43509
44119
  ...CLAIM_COLUMNS
43510
44120
  }).from(tasksTasks).where(eq10(tasksTasks.id, taskId)).limit(1).all();
44121
+ if (guard?.claim || guard?.expectedUpdatedAt !== void 0) {
44122
+ assertNotRenamed(getNativeTasksDb(cwd), taskId, guard, current);
44123
+ }
43511
44124
  if (!current) throw new Error(`Task not found: ${taskId}`);
43512
44125
  const claimGuard = guard?.claim;
43513
44126
  const allowedHolders = claimGuard ? await claimAllowedHolders(db, claimGuard) : [];
@@ -43585,24 +44198,37 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43585
44198
  nativeDb.prepare(`SAVEPOINT ${spName}`).run();
43586
44199
  }
43587
44200
  try {
44201
+ const replacedBirths = /* @__PURE__ */ new Map();
43588
44202
  const tx = {
43589
44203
  async upsertSingleTask(task) {
43590
44204
  scope.assertActive();
43591
44205
  return accessor.transaction(async () => {
43592
44206
  scope.assertActive();
44207
+ if (rowUidFillEnabled() && !replacedBirths.has(task.id)) {
44208
+ const before = readReplacedTaskBirthNative(nativeDb, task.id);
44209
+ if (before) replacedBirths.set(task.id, before);
44210
+ }
43593
44211
  const row = taskToRow(task);
43594
44212
  await upsertTask(db, row);
43595
44213
  await updateDependencies(db, task.id, task.depends ?? []);
43596
44214
  });
43597
44215
  },
43598
- async insertNewTask(task) {
44216
+ async insertNewTask(task, identity) {
43599
44217
  scope.assertActive();
43600
44218
  return accessor.transaction(async () => {
43601
44219
  scope.assertActive();
43602
- await insertNewTask(db, taskToRow(task));
44220
+ await insertNewTask(db, taskToRow(task), identity);
43603
44221
  await updateDependencies(db, task.id, task.depends ?? []);
43604
44222
  });
43605
44223
  },
44224
+ async clearTaskIdentity(taskId) {
44225
+ scope.assertActive();
44226
+ if (!rowUidFillEnabled()) return;
44227
+ return accessor.transaction(async () => {
44228
+ scope.assertActive();
44229
+ clearReplacedTaskIdentityNative(nativeDb, taskId, replacedBirths.get(taskId));
44230
+ });
44231
+ },
43606
44232
  async archiveSingleTask(taskId, fields) {
43607
44233
  scope.assertActive();
43608
44234
  return accessor.transaction(async () => {
@@ -43749,7 +44375,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43749
44375
  const owned = await db.select({ id: tasksTaskAcceptanceCriteria.id }).from(tasksTaskAcceptanceCriteria).where(
43750
44376
  and8(
43751
44377
  eq10(tasksTaskAcceptanceCriteria.taskId, taskId),
43752
- inArray5(tasksTaskAcceptanceCriteria.id, ids)
44378
+ inArray6(tasksTaskAcceptanceCriteria.id, ids)
43753
44379
  )
43754
44380
  ).all();
43755
44381
  await pruneAcBindingsForAcIds(
@@ -43762,7 +44388,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
43762
44388
  await db.delete(tasksTaskAcceptanceCriteria).where(
43763
44389
  and8(
43764
44390
  eq10(tasksTaskAcceptanceCriteria.taskId, taskId),
43765
- inArray5(tasksTaskAcceptanceCriteria.id, ids)
44391
+ inArray6(tasksTaskAcceptanceCriteria.id, ids)
43766
44392
  )
43767
44393
  ).run();
43768
44394
  });
@@ -44021,7 +44647,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
44021
44647
  };
44022
44648
  return accessor;
44023
44649
  }
44024
- var _txSavepointCounter, taskTransactionQueue, TaskTransactionScope, taskTransactionContext, CLAIM_COLUMNS;
44650
+ var _txSavepointCounter, taskTransactionQueue, TaskTransactionScope, taskTransactionContext, CLAIM_COLUMNS, RENAMED_RECENT_MS;
44025
44651
  var init_sqlite_data_accessor = __esm({
44026
44652
  "packages/core/src/store/sqlite-data-accessor.ts"() {
44027
44653
  "use strict";
@@ -44035,6 +44661,8 @@ var init_sqlite_data_accessor = __esm({
44035
44661
  init_cross_db_cleanup();
44036
44662
  init_db_helpers();
44037
44663
  init_row_identity();
44664
+ init_row_identity_flag();
44665
+ init_row_identity_registry();
44038
44666
  init_audit2();
44039
44667
  init_session_store();
44040
44668
  init_sqlite3();
@@ -44067,6 +44695,7 @@ var init_sqlite_data_accessor = __esm({
44067
44695
  claimedAt: tasksTasks.claimedAt,
44068
44696
  leaseExpiresAt: tasksTasks.leaseExpiresAt
44069
44697
  };
44698
+ RENAMED_RECENT_MS = 24 * 60 * 60 * 1e3;
44070
44699
  registerRowIdentityWriters({
44071
44700
  relinkAcUidNative,
44072
44701
  clearAcUidGraveyardNative,
@@ -44537,7 +45166,7 @@ __export(governor_exports, {
44537
45166
  resolveGovernorMode: () => resolveGovernorMode,
44538
45167
  slotFileCount: () => slotFileCount
44539
45168
  });
44540
- import { existsSync as existsSync20, mkdirSync as mkdirSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
45169
+ import { existsSync as existsSync21, mkdirSync as mkdirSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
44541
45170
  import { availableParallelism, totalmem } from "node:os";
44542
45171
  import { join as join27 } from "node:path";
44543
45172
  import lockfile2 from "proper-lockfile";
@@ -44611,11 +45240,11 @@ function governorSlotDir(cls) {
44611
45240
  return join27(getCleoHome(), "locks", `resource-${cls}`);
44612
45241
  }
44613
45242
  function ensureSlotFiles(dir, count) {
44614
- if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
45243
+ if (!existsSync21(dir)) mkdirSync6(dir, { recursive: true });
44615
45244
  const paths = [];
44616
45245
  for (let i = 0; i < count; i++) {
44617
45246
  const p = join27(dir, `slot-${i}.lock`);
44618
- if (!existsSync20(p)) writeFileSync5(p, "", { flag: "a" });
45247
+ if (!existsSync21(p)) writeFileSync5(p, "", { flag: "a" });
44619
45248
  paths.push(p);
44620
45249
  }
44621
45250
  return paths;
@@ -44655,7 +45284,7 @@ function shuffledIndices(n) {
44655
45284
  }
44656
45285
  async function countHeldSlots(cls, budget) {
44657
45286
  const dir = governorSlotDir(cls);
44658
- if (!existsSync20(dir)) return 0;
45287
+ if (!existsSync21(dir)) return 0;
44659
45288
  const slots = ensureSlotFiles(dir, budget);
44660
45289
  let held = 0;
44661
45290
  for (const path of slots) {
@@ -44670,7 +45299,7 @@ async function countHeldSlots(cls, budget) {
44670
45299
  }
44671
45300
  function slotFileCount(cls) {
44672
45301
  const dir = governorSlotDir(cls);
44673
- if (!existsSync20(dir)) return 0;
45302
+ if (!existsSync21(dir)) return 0;
44674
45303
  return readdirSync5(dir).filter((f) => f.startsWith("slot-") && f.endsWith(".lock")).length;
44675
45304
  }
44676
45305
  var _log2, _cachedMode2, _supervisorDegradeLogged, MB, STALE_MS, _supervisorHolderSeq, ResourceGovernor, governor;
@@ -45168,7 +45797,7 @@ var init_recovery = __esm({
45168
45797
  // packages/core/src/store/exodus/archive.ts
45169
45798
  import {
45170
45799
  copyFileSync as copyFileSync5,
45171
- existsSync as existsSync21,
45800
+ existsSync as existsSync22,
45172
45801
  mkdirSync as mkdirSync7,
45173
45802
  readFileSync as readFileSync9,
45174
45803
  renameSync as renameSync7,
@@ -45196,7 +45825,7 @@ function hasExodusCompleteMarker(scope, cwd, targetDbPath, nativeDb) {
45196
45825
  if (targetDbPath) throw error48;
45197
45826
  return false;
45198
45827
  }
45199
- if (!existsSync21(markerPath)) return false;
45828
+ if (!existsSync22(markerPath)) return false;
45200
45829
  const marker16 = markerIdentity.parse(JSON.parse(readFileSync9(markerPath, "utf8")));
45201
45830
  if (nativeDb && (!marker16.databaseIdentity || !hasExodusDatabaseIdentity(nativeDb, marker16.databaseIdentity)))
45202
45831
  throw new Error(
@@ -45226,7 +45855,7 @@ function writeExodusCompleteMarker(scope, archivedSources, cwd, targetDbPath, da
45226
45855
  function moveFileInto(srcPath, destDir) {
45227
45856
  mkdirSync7(destDir, { recursive: true });
45228
45857
  let dest = join28(destDir, basename9(srcPath));
45229
- if (existsSync21(dest)) {
45858
+ if (existsSync22(dest)) {
45230
45859
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
45231
45860
  dest = join28(destDir, `${basename9(srcPath)}.${stamp}`);
45232
45861
  }
@@ -45239,14 +45868,14 @@ function moveFileInto(srcPath, destDir) {
45239
45868
  return dest;
45240
45869
  }
45241
45870
  function archiveSourceDb(source, cwd, targetDbPath) {
45242
- if (!existsSync21(source.path)) {
45871
+ if (!existsSync22(source.path)) {
45243
45872
  return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
45244
45873
  }
45245
45874
  const destDir = exodusArchiveDir(source.targetScope, cwd, targetDbPath);
45246
45875
  const archivedTo = moveFileInto(source.path, destDir);
45247
45876
  for (const suffix of SIDECAR_SUFFIXES) {
45248
45877
  const sidecar = `${source.path}${suffix}`;
45249
- if (existsSync21(sidecar)) {
45878
+ if (existsSync22(sidecar)) {
45250
45879
  try {
45251
45880
  moveFileInto(sidecar, destDir);
45252
45881
  } catch (err) {
@@ -45294,7 +45923,7 @@ function detectStrandedResidue(sources, cwd) {
45294
45923
  const stranded = [];
45295
45924
  for (const source of sources) {
45296
45925
  if (!markedScopes.has(source.targetScope)) continue;
45297
- if (existsSync21(source.path)) {
45926
+ if (existsSync22(source.path)) {
45298
45927
  stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
45299
45928
  }
45300
45929
  }
@@ -45335,13 +45964,13 @@ var init_archive2 = __esm({
45335
45964
  });
45336
45965
 
45337
45966
  // packages/core/src/store/exodus/count-parity.ts
45338
- import { existsSync as existsSync22 } from "node:fs";
45967
+ import { existsSync as existsSync23 } from "node:fs";
45339
45968
  function listTables2(db) {
45340
45969
  return db.prepare(
45341
45970
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
45342
45971
  ).all().map((r) => r.name);
45343
45972
  }
45344
- function tableExists2(db, tableName) {
45973
+ function tableExists3(db, tableName) {
45345
45974
  const escaped = tableName.replace(/'/g, "''");
45346
45975
  return db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !== void 0;
45347
45976
  }
@@ -45356,14 +45985,14 @@ function rowCount(db, tableName) {
45356
45985
  function computeCountParity(sources, projectDbPath, globalDbPath) {
45357
45986
  const entries = [];
45358
45987
  let skipped = 0;
45359
- if (!existsSync22(projectDbPath) || !existsSync22(globalDbPath)) {
45988
+ if (!existsSync23(projectDbPath) || !existsSync23(globalDbPath)) {
45360
45989
  return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
45361
45990
  }
45362
45991
  const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
45363
45992
  const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
45364
45993
  try {
45365
45994
  for (const src of sources) {
45366
- if (!existsSync22(src.path)) continue;
45995
+ if (!existsSync23(src.path)) continue;
45367
45996
  const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
45368
45997
  try {
45369
45998
  for (const legacyTable of listTables2(srcSnap.db)) {
@@ -45380,7 +46009,7 @@ function computeCountParity(sources, projectDbPath, globalDbPath) {
45380
46009
  skipped++;
45381
46010
  continue;
45382
46011
  }
45383
- const targetCount = tableExists2(targetSnap.db, targetTable) ? rowCount(targetSnap.db, targetTable) ?? 0 : 0;
46012
+ const targetCount = tableExists3(targetSnap.db, targetTable) ? rowCount(targetSnap.db, targetTable) ?? 0 : 0;
45384
46013
  const deficit = targetCount < sourceCount ? sourceCount - targetCount : 0;
45385
46014
  entries.push({
45386
46015
  sourceDb: src.name,
@@ -45421,7 +46050,7 @@ var init_count_parity = __esm({
45421
46050
  });
45422
46051
 
45423
46052
  // packages/core/src/store/exodus/plan.ts
45424
- import { existsSync as existsSync23, readdirSync as readdirSync6, statfsSync as statfsSync2, statSync as statSync6 } from "node:fs";
46053
+ import { existsSync as existsSync24, readdirSync as readdirSync6, statfsSync as statfsSync2, statSync as statSync6 } from "node:fs";
45425
46054
  import { join as join29 } from "node:path";
45426
46055
  function computeRequiredBytes(totalSourceBytes, largestSourceBytes) {
45427
46056
  return Math.ceil(STAGING_HEADROOM_FACTOR * largestSourceBytes) + totalSourceBytes;
@@ -45523,7 +46152,7 @@ function buildExodusPlan(cwd) {
45523
46152
  };
45524
46153
  }
45525
46154
  function sourcesPresent(sources) {
45526
- return sources.some((s) => existsSync23(s.path));
46155
+ return sources.some((s) => existsSync24(s.path));
45527
46156
  }
45528
46157
  var STAGING_HEADROOM_FACTOR, STAGING_COPY_SKIP_THRESHOLD_BYTES;
45529
46158
  var init_plan2 = __esm({
@@ -45537,18 +46166,18 @@ var init_plan2 = __esm({
45537
46166
  });
45538
46167
 
45539
46168
  // packages/core/src/store/exodus/health.ts
45540
- import { existsSync as existsSync24, statSync as statSync7 } from "node:fs";
46169
+ import { existsSync as existsSync25, statSync as statSync7 } from "node:fs";
45541
46170
  function buildExodusHealth(cwd) {
45542
46171
  const plan = buildExodusPlan(cwd);
45543
- const anyLegacyPresent = plan.sources.some((s) => existsSync24(s.path));
46172
+ const anyLegacyPresent = plan.sources.some((s) => existsSync25(s.path));
45544
46173
  const parity = anyLegacyPresent ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath) : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
45545
46174
  const consolidatedExistsByScope = {
45546
- project: existsSync24(plan.projectDbPath),
45547
- global: existsSync24(plan.globalDbPath)
46175
+ project: existsSync25(plan.projectDbPath),
46176
+ global: existsSync25(plan.globalDbPath)
45548
46177
  };
45549
46178
  const buildScope = (scope) => {
45550
46179
  const sources = plan.sources.filter((s) => s.targetScope === scope).map((s) => {
45551
- const present = existsSync24(s.path);
46180
+ const present = existsSync25(s.path);
45552
46181
  let bytes = 0;
45553
46182
  if (present) {
45554
46183
  try {
@@ -45653,7 +46282,7 @@ var init_types = __esm({
45653
46282
  // packages/core/src/store/exodus/migrate.ts
45654
46283
  import {
45655
46284
  copyFileSync as copyFileSync6,
45656
- existsSync as existsSync25,
46285
+ existsSync as existsSync26,
45657
46286
  mkdirSync as mkdirSync8,
45658
46287
  readFileSync as readFileSync10,
45659
46288
  renameSync as renameSync8,
@@ -45699,7 +46328,7 @@ function writeJournal(stagingDir, journal) {
45699
46328
  }
45700
46329
  function readJournal(stagingDir) {
45701
46330
  const journalPath = join30(stagingDir, JOURNAL_FILENAME);
45702
- if (!existsSync25(journalPath)) return null;
46331
+ if (!existsSync26(journalPath)) return null;
45703
46332
  try {
45704
46333
  return JSON.parse(readFileSync10(journalPath, "utf8"));
45705
46334
  } catch {
@@ -45709,7 +46338,7 @@ function readJournal(stagingDir) {
45709
46338
  function clearExodusJournal(stagingDir) {
45710
46339
  const journalPath = join30(stagingDir, JOURNAL_FILENAME);
45711
46340
  try {
45712
- if (!existsSync25(journalPath)) return false;
46341
+ if (!existsSync26(journalPath)) return false;
45713
46342
  unlinkSync5(journalPath);
45714
46343
  log10.info(
45715
46344
  { stagingDir },
@@ -46005,7 +46634,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
46005
46634
  mkdirSync8(stagingDir, { recursive: true });
46006
46635
  let sqliteVersion = "unknown";
46007
46636
  for (const src of sources) {
46008
- if (existsSync25(src.path)) {
46637
+ if (existsSync26(src.path)) {
46009
46638
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
46010
46639
  sqliteVersion = getSqliteVersion(snap.db);
46011
46640
  snap.close();
@@ -46035,7 +46664,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
46035
46664
  let reseedProject = null;
46036
46665
  try {
46037
46666
  for (const src of sources) {
46038
- if (!existsSync25(src.path)) continue;
46667
+ if (!existsSync26(src.path)) continue;
46039
46668
  const backupDest = join30(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
46040
46669
  const srcBytes = safeStatBytes(src.path);
46041
46670
  const skipStagingCopy = srcBytes > plan.stagingCopyThresholdBytes;
@@ -46043,7 +46672,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
46043
46672
  onProgress?.(
46044
46673
  `Skipping full staging copy of ${src.name} (${srcBytes} bytes > ${plan.stagingCopyThresholdBytes} threshold) \u2014 source is archived, not deleted, on success.`
46045
46674
  );
46046
- } else if (!existsSync25(backupDest)) {
46675
+ } else if (!existsSync26(backupDest)) {
46047
46676
  onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
46048
46677
  copyFileSync6(src.path, backupDest);
46049
46678
  backupPaths.push(backupDest);
@@ -46076,8 +46705,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
46076
46705
  }
46077
46706
  prepareExodusRecovery(projectNative, stagingDir);
46078
46707
  if (globalNative !== null) prepareExodusRecovery(globalNative, stagingDir);
46079
- const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync25(s.path));
46080
- const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync25(s.path));
46708
+ const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync26(s.path));
46709
+ const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync26(s.path));
46081
46710
  if (globalNative === null && globalSources.length > 0)
46082
46711
  throw new Error("A projectOnly exodus run was given global-scope sources");
46083
46712
  await migrateScope(
@@ -46326,7 +46955,8 @@ var init_migrate = __esm({
46326
46955
  GRANDFATHERED_GUARD_TRIGGERS = [
46327
46956
  "tasks_tasks_parent_type_matrix_insert",
46328
46957
  "tasks_task_relations_non_containment_insert",
46329
- "tasks_task_acceptance_child_target_insert"
46958
+ "tasks_task_acceptance_child_target_insert",
46959
+ "tasks_task_dependencies_cycle_guard_insert"
46330
46960
  ];
46331
46961
  SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
46332
46962
  ["conduit", "seconds"],
@@ -46385,7 +47015,7 @@ __export(reconcile_exports, {
46385
47015
  reconcileSupersededStores: () => reconcileSupersededStores,
46386
47016
  unmigratedBareSources: () => unmigratedBareSources
46387
47017
  });
46388
- import { copyFileSync as copyFileSync7, existsSync as existsSync26, mkdirSync as mkdirSync9, mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
47018
+ import { copyFileSync as copyFileSync7, existsSync as existsSync27, mkdirSync as mkdirSync9, mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
46389
47019
  import { tmpdir as tmpdir4 } from "node:os";
46390
47020
  import { basename as basename10, join as join31 } from "node:path";
46391
47021
  function ident2(name15) {
@@ -46456,7 +47086,7 @@ function assessSupersededProjectStores(liveStorePath, sources, resolveTarget = r
46456
47086
  }
46457
47087
  function legacySourcesHoldRows(sources) {
46458
47088
  for (const src of sources) {
46459
- if (!existsSync26(src.path)) continue;
47089
+ if (!existsSync27(src.path)) continue;
46460
47090
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
46461
47091
  try {
46462
47092
  for (const table of orderTablesForCopy(snap.db)) {
@@ -46704,8 +47334,8 @@ async function reconcileSuppressed(projectRoot, options, liveStorePath) {
46704
47334
  }
46705
47335
  }
46706
47336
  async function reconcileWithScratch(projectRoot, dryRun, additive, liveStorePath, plan, resolveTarget, scratch) {
46707
- const fileSources = plan.sources.filter((s) => s.targetScope === "project" && existsSync26(s.path));
46708
- const bare = !additive && existsSync26(liveStorePath) ? await bareTaskCoreSource(liveStorePath, resolveTarget, scratch) : null;
47337
+ const fileSources = plan.sources.filter((s) => s.targetScope === "project" && existsSync27(s.path));
47338
+ const bare = !additive && existsSync27(liveStorePath) ? await bareTaskCoreSource(liveStorePath, resolveTarget, scratch) : null;
46709
47339
  const copyResolver = additive ? (sourceName, legacyTable) => {
46710
47340
  const r = resolveTarget(sourceName, legacyTable);
46711
47341
  return r.kind !== "skip" && isLiveAuthoritative(sourceName, legacyTable, r.targetName) ? { kind: "skip", reason: "additive: live-authoritative task graph" } : r;
@@ -46724,7 +47354,7 @@ async function reconcileWithScratch(projectRoot, dryRun, additive, liveStorePath
46724
47354
  stagingDir: null,
46725
47355
  receiptPath: null
46726
47356
  };
46727
- if (sources.length === 0 || !existsSync26(liveStorePath)) {
47357
+ if (sources.length === 0 || !existsSync27(liveStorePath)) {
46728
47358
  return {
46729
47359
  ...base,
46730
47360
  outcome: "nothing-to-reconcile",
@@ -46916,11 +47546,11 @@ var init_seal = __esm({
46916
47546
  });
46917
47547
 
46918
47548
  // packages/core/src/store/exodus/status.ts
46919
- import { existsSync as existsSync27, readdirSync as readdirSync7, readFileSync as readFileSync11, statSync as statSync9 } from "node:fs";
47549
+ import { existsSync as existsSync28, readdirSync as readdirSync7, readFileSync as readFileSync11, statSync as statSync9 } from "node:fs";
46920
47550
  import { join as join32 } from "node:path";
46921
47551
  function readJournal2(stagingDir) {
46922
47552
  const p = join32(stagingDir, JOURNAL_FILENAME2);
46923
- if (!existsSync27(p)) return null;
47553
+ if (!existsSync28(p)) return null;
46924
47554
  try {
46925
47555
  return JSON.parse(readFileSync11(p, "utf8"));
46926
47556
  } catch {
@@ -46952,15 +47582,15 @@ function runExodusStatus(cwd) {
46952
47582
  const sourcesInfo = plan.sources.map((s) => ({
46953
47583
  name: s.name,
46954
47584
  path: s.path,
46955
- exists: existsSync27(s.path),
47585
+ exists: existsSync28(s.path),
46956
47586
  bytes: safeBytes(s.path)
46957
47587
  }));
46958
47588
  return {
46959
47589
  hasStaging: latestStaging !== null,
46960
47590
  stagingDir: latestStaging,
46961
47591
  journal,
46962
- projectDbExists: existsSync27(projectDbPath),
46963
- globalDbExists: existsSync27(globalDbPath),
47592
+ projectDbExists: existsSync28(projectDbPath),
47593
+ globalDbExists: existsSync28(globalDbPath),
46964
47594
  sourcesPresent: sourcesInfo.some((s) => s.exists),
46965
47595
  sources: sourcesInfo
46966
47596
  };
@@ -46977,7 +47607,7 @@ var init_status = __esm({
46977
47607
  });
46978
47608
 
46979
47609
  // packages/core/src/store/exodus/verify-migration.ts
46980
- import { existsSync as existsSync28 } from "node:fs";
47610
+ import { existsSync as existsSync29 } from "node:fs";
46981
47611
  import { createRequire as createRequire10 } from "node:module";
46982
47612
  function orderByClause(db, tableName) {
46983
47613
  try {
@@ -47092,7 +47722,7 @@ function listTables3(db) {
47092
47722
  ).all();
47093
47723
  return rows.map((r) => r.name);
47094
47724
  }
47095
- function tableExists3(db, tableName) {
47725
+ function tableExists4(db, tableName) {
47096
47726
  try {
47097
47727
  const escaped = tableName.replace(/'/g, "''");
47098
47728
  return db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !== void 0;
@@ -47242,10 +47872,10 @@ function orphanAlreadyInSource(targetDb, fk, sources, resolveTarget = resolveCon
47242
47872
  const anyFeeder = (targetTable, probe) => {
47243
47873
  for (const feeder of feedersOf(targetTable)) {
47244
47874
  const src = sources.find((s) => s.name === feeder.sourceName);
47245
- if (src === void 0 || !existsSync28(src.path)) continue;
47875
+ if (src === void 0 || !existsSync29(src.path)) continue;
47246
47876
  const snap = openCleoDbSnapshot(src.path, { readOnly: true });
47247
47877
  try {
47248
- if (!tableExists3(snap.db, feeder.legacyTable)) continue;
47878
+ if (!tableExists4(snap.db, feeder.legacyTable)) continue;
47249
47879
  const cols = new Set(
47250
47880
  snap.db.prepare(`PRAGMA table_info("${feeder.legacyTable}")`).all().map((c) => c.name)
47251
47881
  );
@@ -47297,7 +47927,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47297
47927
  const preExistingForeignKeyViolations = [];
47298
47928
  const failureLines = [];
47299
47929
  const sourceOrphanSigs = /* @__PURE__ */ new Set();
47300
- if (!existsSync28(projectDbPath)) {
47930
+ if (!existsSync29(projectDbPath)) {
47301
47931
  return {
47302
47932
  ok: false,
47303
47933
  tables: [],
@@ -47308,7 +47938,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47308
47938
  error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
47309
47939
  };
47310
47940
  }
47311
- if (!existsSync28(globalDbPath)) {
47941
+ if (!existsSync29(globalDbPath)) {
47312
47942
  return {
47313
47943
  ok: false,
47314
47944
  tables: [],
@@ -47323,7 +47953,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47323
47953
  const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
47324
47954
  try {
47325
47955
  for (const src of sources) {
47326
- if (!existsSync28(src.path)) {
47956
+ if (!existsSync29(src.path)) {
47327
47957
  onProgress?.(`Skipping ${src.name} (not present)`);
47328
47958
  continue;
47329
47959
  }
@@ -47448,7 +48078,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
47448
48078
  targetOrphans.push(...foreignKeyCheck(globalSnap.db, "global"));
47449
48079
  foreignKeyViolations.push(...targetOrphans);
47450
48080
  for (const fk of targetOrphans) {
47451
- const orphanDb = tableExists3(projectSnap.db, fk.table) ? projectSnap.db : globalSnap.db;
48081
+ const orphanDb = tableExists4(projectSnap.db, fk.table) ? projectSnap.db : globalSnap.db;
47452
48082
  const sig = orphanSignature(orphanDb, fk);
47453
48083
  const preExisting = sourceOrphanSigs.has(sig) || orphanAlreadyInSource(orphanDb, fk, sources, resolveTarget);
47454
48084
  if (preExisting) {
@@ -47614,7 +48244,7 @@ __export(on_open_exports, {
47614
48244
  maybeRunExodusOnOpen: () => maybeRunExodusOnOpen,
47615
48245
  withExodusOnOpenSuppressed: () => withExodusOnOpenSuppressed
47616
48246
  });
47617
- import { existsSync as existsSync29, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
48247
+ import { existsSync as existsSync30, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
47618
48248
  import { tmpdir as tmpdir5 } from "node:os";
47619
48249
  import { join as join33, resolve as resolve13 } from "node:path";
47620
48250
  async function withExodusOnOpenSuppressed(dbPath, fn) {
@@ -47656,7 +48286,7 @@ function remedyFor(scope) {
47656
48286
  }
47657
48287
  async function strandedLegacySources(scope, cwd) {
47658
48288
  const { buildExodusPlan: buildExodusPlan2, legacySourcesHoldRows: legacySourcesHoldRows2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
47659
- return buildExodusPlan2(cwd).sources.filter((s) => s.targetScope === scope && existsSync29(s.path)).filter((s) => legacySourcesHoldRows2([s])).map((s) => s.name);
48289
+ return buildExodusPlan2(cwd).sources.filter((s) => s.targetScope === scope && existsSync30(s.path)).filter((s) => legacySourcesHoldRows2([s])).map((s) => s.name);
47660
48290
  }
47661
48291
  async function exodusStoreRewriteRefusal(dbPath, cwd) {
47662
48292
  const { assertOwnerStoreRewriteConfirmed: assertOwnerStoreRewriteConfirmed2, invocationDirectory: invocationDirectory2 } = await Promise.resolve().then(() => (init_worktree_isolation_guard(), worktree_isolation_guard_exports));
@@ -47788,7 +48418,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47788
48418
  };
47789
48419
  }
47790
48420
  const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
47791
- if (!scopeSources.some((s) => existsSync29(s.path))) {
48421
+ if (!scopeSources.some((s) => existsSync30(s.path))) {
47792
48422
  return {
47793
48423
  outcome: "skipped",
47794
48424
  reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
@@ -47813,7 +48443,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47813
48443
  {
47814
48444
  scope,
47815
48445
  dbPath,
47816
- sources: plan.sources.filter((s) => existsSync29(s.path)).map((s) => s.name)
48446
+ sources: plan.sources.filter((s) => existsSync30(s.path)).map((s) => s.name)
47817
48447
  },
47818
48448
  "exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
47819
48449
  );
@@ -47826,7 +48456,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47826
48456
  const bare = scope === "project" ? await unmigratedBareSources2(
47827
48457
  dbPath,
47828
48458
  resolveTarget,
47829
- plan.sources.find((s) => s.name === "tasks" && existsSync29(s.path))?.path,
48459
+ plan.sources.find((s) => s.name === "tasks" && existsSync30(s.path))?.path,
47830
48460
  bareScratch
47831
48461
  ) : { first: [], last: [] };
47832
48462
  const migratePlan = { ...plan, sources: [...bare.first, ...plan.sources, ...bare.last] };
@@ -47890,7 +48520,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
47890
48520
  "exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
47891
48521
  );
47892
48522
  try {
47893
- const consumed = plan.sources.filter((s) => existsSync29(s.path));
48523
+ const consumed = plan.sources.filter((s) => existsSync30(s.path));
47894
48524
  const identities = await sealTargets(plan, consumed);
47895
48525
  const archiveResult = archiveMigratedSources(consumed, cwd, plan, identities);
47896
48526
  log14.info(
@@ -47965,7 +48595,7 @@ __export(dual_scope_db_exports, {
47965
48595
  upsertIdempotent: () => upsertIdempotent,
47966
48596
  withStoreSchemaOwnership: () => withStoreSchemaOwnership
47967
48597
  });
47968
- import { existsSync as existsSync30, mkdirSync as mkdirSync10 } from "node:fs";
48598
+ import { existsSync as existsSync31, mkdirSync as mkdirSync10 } from "node:fs";
47969
48599
  import { createRequire as createRequire11 } from "node:module";
47970
48600
  import { dirname as dirname21, join as join34, resolve as resolve14 } from "node:path";
47971
48601
  function getDualScopeNativeDb(handle) {
@@ -48038,11 +48668,15 @@ async function openDualScopeDb(scope, cwd, options) {
48038
48668
  open
48039
48669
  ) : open();
48040
48670
  }
48671
+ function identityWorkOnOpen(nativeDb, scope) {
48672
+ if (ROW_IDENTITY[scope].length === 0) return false;
48673
+ return rowUidFillEnabled() || missingRowIdentitySchema(nativeDb).length > 0;
48674
+ }
48041
48675
  async function openDedicatedDualScopeDb(scope, dbPath, log15, execution) {
48042
48676
  execution?.assertActive();
48043
48677
  log15.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
48044
48678
  const dir = dirname21(dbPath);
48045
- if (!existsSync30(dir)) {
48679
+ if (!existsSync31(dir)) {
48046
48680
  mkdirSync10(dir, { recursive: true });
48047
48681
  }
48048
48682
  execution?.assertActive();
@@ -48075,9 +48709,12 @@ async function openDedicatedDualScopeDb(scope, dbPath, log15, execution) {
48075
48709
  `dual-scope-db[${scope}]`
48076
48710
  );
48077
48711
  execution?.assertActive();
48078
- if (rowUidFillEnabled()) {
48712
+ if (identityWorkOnOpen(nativeDb, scope)) {
48079
48713
  await Promise.resolve().then(() => (init_sqlite_data_accessor(), sqlite_data_accessor_exports));
48080
- prepareRowIdentity(nativeDb, scope, { triggers: false });
48714
+ healRowIdentitySchema(nativeDb, scope);
48715
+ if (rowUidFillEnabled()) {
48716
+ prepareRowIdentity(nativeDb, scope, { triggers: false });
48717
+ }
48081
48718
  }
48082
48719
  execution?.assertActive();
48083
48720
  log15.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
@@ -48190,7 +48827,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
48190
48827
  execution?.assertActive();
48191
48828
  log15.debug({ scope, dbPath: normalizedPath }, "opening dual-scope cleo.db");
48192
48829
  const dir = dirname21(normalizedPath);
48193
- if (!existsSync30(dir)) {
48830
+ if (!existsSync31(dir)) {
48194
48831
  mkdirSync10(dir, { recursive: true });
48195
48832
  }
48196
48833
  execution?.assertActive();
@@ -48223,9 +48860,12 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
48223
48860
  `dual-scope-db[${scope}]`
48224
48861
  );
48225
48862
  execution?.assertActive();
48226
- if (rowUidFillEnabled()) {
48863
+ if (identityWorkOnOpen(nativeDb, scope)) {
48227
48864
  await Promise.resolve().then(() => (init_sqlite_data_accessor(), sqlite_data_accessor_exports));
48228
- prepareRowIdentity(nativeDb, scope);
48865
+ healRowIdentitySchema(nativeDb, scope);
48866
+ if (rowUidFillEnabled()) {
48867
+ prepareRowIdentity(nativeDb, scope);
48868
+ }
48229
48869
  }
48230
48870
  execution?.assertActive();
48231
48871
  log15.debug({ scope, dbPath: normalizedPath }, "dual-scope cleo.db ready");
@@ -49355,7 +49995,7 @@ __export(nexus_sqlite_exports, {
49355
49995
  resetNexusDbState: () => resetNexusDbState,
49356
49996
  resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
49357
49997
  });
49358
- import { copyFileSync as copyFileSync8, existsSync as existsSync31 } from "node:fs";
49998
+ import { copyFileSync as copyFileSync8, existsSync as existsSync32 } from "node:fs";
49359
49999
  import { join as join35 } from "node:path";
49360
50000
  function getNexusDbPath(cwd) {
49361
50001
  return resolveDualScopeDbPath("project", cwd);
@@ -49407,7 +50047,7 @@ function detectAndWarnOnNestedNexus() {
49407
50047
  } catch {
49408
50048
  return false;
49409
50049
  }
49410
- if (!existsSync31(nestedPath)) return false;
50050
+ if (!existsSync32(nestedPath)) return false;
49411
50051
  if (_warnedNestedPaths.has(nestedPath)) return false;
49412
50052
  _warnedNestedPaths.add(nestedPath);
49413
50053
  const canonicalPath = getNexusDbPath();
@@ -49427,7 +50067,7 @@ function detectAndWarnOnNestedNexus() {
49427
50067
  function _resetNestedNexusWarningGate() {
49428
50068
  _warnedNestedPaths.clear();
49429
50069
  }
49430
- function tableExists4(nativeDb, tableName) {
50070
+ function tableExists5(nativeDb, tableName) {
49431
50071
  const result = nativeDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(tableName);
49432
50072
  return !!result;
49433
50073
  }
@@ -49436,7 +50076,7 @@ function objectExists(nativeDb, type, name15) {
49436
50076
  return !!result;
49437
50077
  }
49438
50078
  function ensureNexusFts5(nativeDb) {
49439
- if (!tableExists4(nativeDb, "nexus_nodes")) return;
50079
+ if (!tableExists5(nativeDb, "nexus_nodes")) return;
49440
50080
  if (!objectExists(nativeDb, "table", "nexus_symbols_fts")) {
49441
50081
  nativeDb.exec(`
49442
50082
  CREATE VIRTUAL TABLE nexus_symbols_fts USING fts5(
@@ -49482,7 +50122,7 @@ function ensureNexusFts5(nativeDb) {
49482
50122
  `);
49483
50123
  }
49484
50124
  function ensureNexusRelationWeights(nativeDb) {
49485
- if (!tableExists4(nativeDb, "nexus_relations")) return;
50125
+ if (!tableExists5(nativeDb, "nexus_relations")) return;
49486
50126
  nativeDb.exec(`
49487
50127
  CREATE TABLE IF NOT EXISTS nexus_relation_weights (
49488
50128
  relation_id TEXT PRIMARY KEY NOT NULL,
@@ -49564,9 +50204,9 @@ function ensureNexusRelationWeights(nativeDb) {
49564
50204
  }
49565
50205
  function runNexusMigrations(nativeDb, db, dbPath) {
49566
50206
  const migrationsFolder = resolveNexusMigrationsFolder();
49567
- if (tableExists4(nativeDb, "nexus_nodes")) {
50207
+ if (tableExists5(nativeDb, "nexus_nodes")) {
49568
50208
  const backupPath = dbPath.replace(/\.db$/, "-pre-cleo.db.bak");
49569
- if (!existsSync31(backupPath)) {
50209
+ if (!existsSync32(backupPath)) {
49570
50210
  try {
49571
50211
  copyFileSync8(dbPath, backupPath);
49572
50212
  } catch {
@@ -49696,13 +50336,13 @@ var init_legacy_alias = __esm({
49696
50336
 
49697
50337
  // packages/core/src/llm/stable-device-id.ts
49698
50338
  import { randomUUID as randomUUID3 } from "node:crypto";
49699
- import { existsSync as existsSync32, mkdirSync as mkdirSync11, readFileSync as readFileSync12, renameSync as renameSync9, writeFileSync as writeFileSync9 } from "node:fs";
50339
+ import { existsSync as existsSync33, mkdirSync as mkdirSync11, readFileSync as readFileSync12, renameSync as renameSync9, writeFileSync as writeFileSync9 } from "node:fs";
49700
50340
  import { dirname as dirname22 } from "node:path";
49701
50341
  import { resolveStableDeviceIdPath } from "@cleocode/paths";
49702
50342
  function getStableDeviceId() {
49703
50343
  if (_cachedDeviceId !== null) return _cachedDeviceId;
49704
50344
  const path = resolveStableDeviceIdPath();
49705
- if (existsSync32(path)) {
50345
+ if (existsSync33(path)) {
49706
50346
  try {
49707
50347
  const raw = readFileSync12(path, "utf-8").trim();
49708
50348
  if (raw.length > 0) {
@@ -49715,7 +50355,7 @@ function getStableDeviceId() {
49715
50355
  const fresh = randomUUID3();
49716
50356
  try {
49717
50357
  const dir = dirname22(path);
49718
- if (!existsSync32(dir)) {
50358
+ if (!existsSync33(dir)) {
49719
50359
  mkdirSync11(dir, { recursive: true });
49720
50360
  }
49721
50361
  const tmpPath = `${path}.tmp.${process.pid}`;
@@ -49791,11 +50431,11 @@ __export(path_map_exports, {
49791
50431
  supersededRegistryPath: () => supersededRegistryPath,
49792
50432
  touchProjectLocation: () => touchProjectLocation
49793
50433
  });
49794
- import { existsSync as existsSync33, lstatSync, readdirSync as readdirSync8 } from "node:fs";
50434
+ import { existsSync as existsSync34, lstatSync, readdirSync as readdirSync8 } from "node:fs";
49795
50435
  import { lstat, readdir as readdir2 } from "node:fs/promises";
49796
50436
  import { isAbsolute as isAbsolute5, join as join36, relative as relative3, sep as sep5 } from "node:path";
49797
50437
  import { canonicalizePath as canonicalizePath3, readDeclaredProjectIdentity as readDeclaredProjectIdentity4 } from "@cleocode/paths";
49798
- import { and as and9, desc as desc3, eq as eq12, inArray as inArray6, ne as ne3 } from "drizzle-orm";
50438
+ import { and as and9, desc as desc3, eq as eq12, inArray as inArray7, ne as ne3 } from "drizzle-orm";
49799
50439
  function holdingKey(projectId, path) {
49800
50440
  return `${projectId}\0${path}`;
49801
50441
  }
@@ -49943,7 +50583,7 @@ function decideEncounterBinding(db, record2) {
49943
50583
  const here = db.select({ state: projectLocations.state, checkoutNonce: projectLocations.checkoutNonce }).from(projectLocations).where(
49944
50584
  and9(
49945
50585
  eq12(projectLocations.projectId, record2.projectId),
49946
- inArray6(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
50586
+ inArray7(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
49947
50587
  eq12(projectLocations.path, record2.projectPath)
49948
50588
  )
49949
50589
  ).all();
@@ -49954,7 +50594,7 @@ function decideEncounterBinding(db, record2) {
49954
50594
  const previous = () => db.select({ checkoutNonce: projectLocations.checkoutNonce }).from(projectLocations).where(
49955
50595
  and9(
49956
50596
  eq12(projectLocations.projectId, record2.projectId),
49957
- inArray6(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
50597
+ inArray7(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
49958
50598
  eq12(projectLocations.path, oldPath)
49959
50599
  )
49960
50600
  ).all();
@@ -50002,7 +50642,7 @@ function hasOtherLiveLocation(db, record2, deviceId) {
50002
50642
  ne3(projectLocations.path, record2.projectPath)
50003
50643
  )
50004
50644
  ).all().some(
50005
- (location) => isStrictlyInside(record2.projectPath, location.path) && existsSync33(location.path) && readDeclaredProjectIdentity4(location.path)?.projectId === record2.projectId
50645
+ (location) => isStrictlyInside(record2.projectPath, location.path) && existsSync34(location.path) && readDeclaredProjectIdentity4(location.path)?.projectId === record2.projectId
50006
50646
  );
50007
50647
  }
50008
50648
  function demoteProjectLocation(db, record2, state) {
@@ -50053,7 +50693,7 @@ function rehomeDisplacedRows(db, projectId, projectPath, deviceId, probed) {
50053
50693
  ).orderBy(desc3(projectLocations.lastSeen)).all();
50054
50694
  const present = (path) => {
50055
50695
  const holding = probed?.get(holdingKey(row.projectId, path));
50056
- return holding === void 0 ? existsSync33(path) : holding === "yes";
50696
+ return holding === void 0 ? existsSync34(path) : holding === "yes";
50057
50697
  };
50058
50698
  const home = candidates.find(
50059
50699
  (c) => present(c.path) && db.select({ projectId: projectRegistry.projectId }).from(projectRegistry).where(eq12(projectRegistry.projectPath, c.path)).all().length === 0
@@ -50082,7 +50722,7 @@ async function listProjectCheckouts(projectId, opts = {}) {
50082
50722
  projectHash: generateProjectHash(row.path),
50083
50723
  firstSeen: row.firstSeen,
50084
50724
  lastSeen: row.lastSeen,
50085
- exists: local && existsSync33(row.path),
50725
+ exists: local && existsSync34(row.path),
50086
50726
  deviceId: local ? deviceId : row.deviceId,
50087
50727
  state: row.state
50088
50728
  });
@@ -50115,7 +50755,7 @@ __export(project_activity_exports, {
50115
50755
  projectLastActivitySql: () => projectLastActivitySql,
50116
50756
  projectLastActivitySqlText: () => projectLastActivitySqlText
50117
50757
  });
50118
- import { eq as eq13, inArray as inArray7, sql as sql32 } from "drizzle-orm";
50758
+ import { eq as eq13, inArray as inArray8, sql as sql32 } from "drizzle-orm";
50119
50759
  function normalizeRegistryTimestamp(value) {
50120
50760
  if (value === null || value === void 0 || value.length === 0) return null;
50121
50761
  const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$/.test(value) ? `${value.replace(" ", "T")}Z` : value;
@@ -50144,7 +50784,7 @@ function markProjectsProbed(db, projectIds, now = /* @__PURE__ */ new Date()) {
50144
50784
  for (let i = 0; i < ids.length; i += PROBED_CHUNK) {
50145
50785
  const chunk = ids.slice(i, i + PROBED_CHUNK);
50146
50786
  changed += Number(
50147
- db.update(projectRegistry).set({ lastProbedAt: at }).where(inArray7(projectRegistry.projectId, chunk)).run().changes
50787
+ db.update(projectRegistry).set({ lastProbedAt: at }).where(inArray8(projectRegistry.projectId, chunk)).run().changes
50148
50788
  );
50149
50789
  }
50150
50790
  return changed;
@@ -50177,11 +50817,11 @@ __export(checkout_nonce_exports, {
50177
50817
  readCheckoutNonce: () => readCheckoutNonce
50178
50818
  });
50179
50819
  import { randomBytes as randomBytes3 } from "node:crypto";
50180
- import { existsSync as existsSync34, readFileSync as readFileSync13, renameSync as renameSync10, writeFileSync as writeFileSync10 } from "node:fs";
50820
+ import { existsSync as existsSync35, readFileSync as readFileSync13, renameSync as renameSync10, writeFileSync as writeFileSync10 } from "node:fs";
50181
50821
  import { join as join37 } from "node:path";
50182
50822
  function readInfo(projectRoot) {
50183
50823
  const path = join37(projectRoot, ".cleo", "project-info.json");
50184
- if (!existsSync34(path)) return null;
50824
+ if (!existsSync35(path)) return null;
50185
50825
  try {
50186
50826
  const parsed = JSON.parse(readFileSync13(path, "utf-8"));
50187
50827
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
@@ -50274,7 +50914,7 @@ __export(paths_exports, {
50274
50914
  validateProjectRoot: () => validateProjectRoot,
50275
50915
  worktreeScope: () => worktreeScope
50276
50916
  });
50277
- import { existsSync as existsSync35, readFileSync as readFileSync14, statSync as statSync10 } from "node:fs";
50917
+ import { existsSync as existsSync36, readFileSync as readFileSync14, statSync as statSync10 } from "node:fs";
50278
50918
  import { createRequire as createRequire12 } from "node:module";
50279
50919
  import { homedir as homedir2 } from "node:os";
50280
50920
  import { dirname as dirname23, join as join38, resolve as resolve15 } from "node:path";
@@ -50300,7 +50940,7 @@ function runWithWorktreeScopeFromEnv(fn) {
50300
50940
  function isProjectInitialized(projectRoot) {
50301
50941
  const root = projectRoot ?? getProjectRoot();
50302
50942
  const cleoDir = join38(root, ".cleo");
50303
- return existsSync35(cleoDir) && existsSync35(join38(cleoDir, "tasks.db"));
50943
+ return existsSync36(cleoDir) && existsSync36(join38(cleoDir, "tasks.db"));
50304
50944
  }
50305
50945
  function getCleoHome() {
50306
50946
  return getPlatformPaths().data;
@@ -50406,7 +51046,7 @@ function _resolveProjectByCwdFromNexus(cwd) {
50406
51046
  try {
50407
51047
  const cleoHome = getCleoHome();
50408
51048
  const globalDbPath = join38(cleoHome, "cleo.db");
50409
- if (!existsSync35(globalDbPath)) return null;
51049
+ if (!existsSync36(globalDbPath)) return null;
50410
51050
  const start = resolve15(cwd ?? process.cwd());
50411
51051
  let current = start;
50412
51052
  const DatabaseSync3 = _getDatabaseSyncCtor();
@@ -50569,7 +51209,7 @@ function _cwdHasGitAncestor(cwd) {
50569
51209
  while (true) {
50570
51210
  const gitMarker = join38(current, ".git");
50571
51211
  try {
50572
- if (existsSync35(gitMarker)) {
51212
+ if (existsSync36(gitMarker)) {
50573
51213
  return true;
50574
51214
  }
50575
51215
  } catch {
@@ -50647,7 +51287,7 @@ function getCleoGlobalCantAgentsDir() {
50647
51287
  function getAgentOutputsDir(cwd) {
50648
51288
  const projectRoot = getProjectRoot(cwd);
50649
51289
  const configPath = join38(projectRoot, ".cleo", "config.json");
50650
- if (existsSync35(configPath)) {
51290
+ if (existsSync36(configPath)) {
50651
51291
  try {
50652
51292
  const config2 = JSON.parse(readFileSync14(configPath, "utf-8"));
50653
51293
  if (typeof config2.agentOutputs === "object" && config2.agentOutputs?.directory) {
@@ -50680,7 +51320,7 @@ function getManifestPath(cwd) {
50680
51320
  const configPath = join38(projectRoot, ".cleo", "config.json");
50681
51321
  const legacyFileName = ["MANIFEST", "jsonl"].join(".");
50682
51322
  let manifestFile = legacyFileName;
50683
- if (existsSync35(configPath)) {
51323
+ if (existsSync36(configPath)) {
50684
51324
  try {
50685
51325
  const config2 = JSON.parse(readFileSync14(configPath, "utf-8"));
50686
51326
  const customFile = config2.agentOutputs?.manifestFile ?? config2.research?.manifestFile;
@@ -50736,7 +51376,7 @@ function resolveWorktreeRouting(cwdOverride) {
50736
51376
  while (current !== home && current !== "/" && current !== "") {
50737
51377
  const gitPath = join38(current, ".git");
50738
51378
  try {
50739
- if (existsSync35(gitPath)) {
51379
+ if (existsSync36(gitPath)) {
50740
51380
  const stat3 = statSync10(gitPath);
50741
51381
  if (stat3.isFile()) {
50742
51382
  worktreePath = current;
@@ -50775,7 +51415,7 @@ function detectStrayCleoDb(routing) {
50775
51415
  }
50776
51416
  const tasksDbPath = join38(routing.worktreePath, ".cleo", "tasks.db");
50777
51417
  try {
50778
- if (existsSync35(tasksDbPath) && statSync10(tasksDbPath).isFile()) {
51418
+ if (existsSync36(tasksDbPath) && statSync10(tasksDbPath).isFile()) {
50779
51419
  return tasksDbPath;
50780
51420
  }
50781
51421
  } catch {
@@ -50785,7 +51425,7 @@ function detectStrayCleoDb(routing) {
50785
51425
  async function resolveProjectById(projectId) {
50786
51426
  try {
50787
51427
  const { getNexusDb: getNexusDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
50788
- if (!existsSync35(getNexusRegistryDbPath2())) return null;
51428
+ if (!existsSync36(getNexusRegistryDbPath2())) return null;
50789
51429
  const { eq: eq14 } = await import("drizzle-orm");
50790
51430
  const { projectRegistry: projectRegistry2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
50791
51431
  const db = await getNexusDb2();
@@ -50821,7 +51461,7 @@ function _rowToRegistryEntry(row) {
50821
51461
  }
50822
51462
  function _assertProjectInfoReadable(projectRoot) {
50823
51463
  const infoPath = join38(projectRoot, ".cleo", "project-info.json");
50824
- if (existsSync35(infoPath)) JSON.parse(readFileSync14(infoPath, "utf-8"));
51464
+ if (existsSync36(infoPath)) JSON.parse(readFileSync14(infoPath, "utf-8"));
50825
51465
  }
50826
51466
  function startProjectEncounter(key, projectRoot, infoProjectId) {
50827
51467
  const inFlight2 = _encountersInFlight.get(key);
@@ -50870,7 +51510,7 @@ async function recordProjectEncounter(cwd, options = {}) {
50870
51510
  if (!shouldAutoRegisterProject(project.projectRoot, cleoHome)) return "ephemeral";
50871
51511
  const checkout = captureProjectScope(project.projectRoot, worktreeScope.getStore()).worktreeRoot;
50872
51512
  const { getNexusRegistryDb: getNexusRegistryDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
50873
- if (existsSync35(getNexusRegistryDbPath2(cleoHome))) {
51513
+ if (existsSync36(getNexusRegistryDbPath2(cleoHome))) {
50874
51514
  const { and: and10, eq: eq14 } = await import("drizzle-orm");
50875
51515
  const { projectLocations: projectLocations2, projectRegistry: projectRegistry2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
50876
51516
  const { currentDeviceId: currentDeviceId2 } = await Promise.resolve().then(() => (init_path_map(), path_map_exports));
@@ -50896,7 +51536,7 @@ async function recordProjectEncounter(cwd, options = {}) {
50896
51536
  }
50897
51537
  async function markEncounterOpened(cleoHome, projectId) {
50898
51538
  const { getNexusRegistryDb: getNexusRegistryDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
50899
- if (!existsSync35(getNexusRegistryDbPath2(cleoHome))) return;
51539
+ if (!existsSync36(getNexusRegistryDbPath2(cleoHome))) return;
50900
51540
  const { markProjectOpened: markProjectOpened2 } = await Promise.resolve().then(() => (init_project_activity(), project_activity_exports));
50901
51541
  markProjectOpened2(await getNexusRegistryDb2(cleoHome), projectId);
50902
51542
  }
@@ -51139,7 +51779,7 @@ var init_api_mode = __esm({
51139
51779
  // packages/core/src/store/file-utils.ts
51140
51780
  import { randomBytes as randomBytes4 } from "node:crypto";
51141
51781
  import {
51142
- existsSync as existsSync36,
51782
+ existsSync as existsSync37,
51143
51783
  mkdirSync as mkdirSync12,
51144
51784
  readdirSync as readdirSync9,
51145
51785
  readFileSync as readFileSync15,
@@ -51154,7 +51794,7 @@ function rotateBackup(filePath, mode) {
51154
51794
  const name15 = basename11(filePath);
51155
51795
  const backupDir = join39(dir, ".backups");
51156
51796
  const dirMode = typeof mode === "number" ? modeToDirMode(mode) : void 0;
51157
- if (!existsSync36(backupDir)) {
51797
+ if (!existsSync37(backupDir)) {
51158
51798
  mkdirSync12(backupDir, { recursive: true, mode: dirMode });
51159
51799
  }
51160
51800
  for (let i = MAX_BACKUPS; i >= 1; i--) {
@@ -51167,7 +51807,7 @@ function rotateBackup(filePath, mode) {
51167
51807
  } else {
51168
51808
  const next = join39(backupDir, `${name15}.${i + 1}`);
51169
51809
  try {
51170
- if (existsSync36(current)) renameSync11(current, next);
51810
+ if (existsSync37(current)) renameSync11(current, next);
51171
51811
  } catch {
51172
51812
  }
51173
51813
  }
@@ -51203,7 +51843,7 @@ function writeJsonFileAtomic(filePath, data, optsOrIndent = 2) {
51203
51843
  writeFileSync11(tempPath, content, "utf-8");
51204
51844
  }
51205
51845
  try {
51206
- if (existsSync36(filePath)) {
51846
+ if (existsSync37(filePath)) {
51207
51847
  rotateBackup(filePath, mode);
51208
51848
  }
51209
51849
  renameSync11(tempPath, filePath);
@@ -51229,10 +51869,10 @@ function readJsonFile(filePath) {
51229
51869
  async function withLock2(filePath, transform2, opts = {}) {
51230
51870
  const dir = dirname24(filePath);
51231
51871
  const dirMode = typeof opts.mode === "number" ? modeToDirMode(opts.mode) : void 0;
51232
- if (!existsSync36(dir)) {
51872
+ if (!existsSync37(dir)) {
51233
51873
  mkdirSync12(dir, { recursive: true, mode: dirMode });
51234
51874
  }
51235
- if (!existsSync36(filePath)) {
51875
+ if (!existsSync37(filePath)) {
51236
51876
  if (typeof opts.mode === "number") {
51237
51877
  writeFileSync11(filePath, "", { encoding: "utf-8", mode: opts.mode });
51238
51878
  } else {
@@ -51254,10 +51894,10 @@ async function withLock2(filePath, transform2, opts = {}) {
51254
51894
  }
51255
51895
  async function withFileLock(filePath, operation) {
51256
51896
  const dir = dirname24(filePath);
51257
- if (!existsSync36(dir)) {
51897
+ if (!existsSync37(dir)) {
51258
51898
  mkdirSync12(dir, { recursive: true });
51259
51899
  }
51260
- if (!existsSync36(filePath)) {
51900
+ if (!existsSync37(filePath)) {
51261
51901
  writeFileSync11(filePath, "", "utf-8");
51262
51902
  }
51263
51903
  let release;
@@ -51614,7 +52254,7 @@ var init_cleo_pkce_seeder = __esm({
51614
52254
  });
51615
52255
 
51616
52256
  // packages/core/src/llm/credential-seeders/codex-cli-seeder.ts
51617
- import { existsSync as existsSync37, readFileSync as readFileSync18 } from "node:fs";
52257
+ import { existsSync as existsSync38, readFileSync as readFileSync18 } from "node:fs";
51618
52258
  import { homedir as homedir4 } from "node:os";
51619
52259
  import { join as join43 } from "node:path";
51620
52260
  function getCodexAuthPath() {
@@ -51639,7 +52279,7 @@ var init_codex_cli_seeder = __esm({
51639
52279
  */
51640
52280
  async seed() {
51641
52281
  const authPath = getCodexAuthPath();
51642
- if (!existsSync37(authPath)) {
52282
+ if (!existsSync38(authPath)) {
51643
52283
  return { entries: [] };
51644
52284
  }
51645
52285
  let raw;
@@ -51834,7 +52474,7 @@ var init_google_pkce = __esm({
51834
52474
  });
51835
52475
 
51836
52476
  // packages/core/src/llm/credential-seeders/gemini-cli-seeder.ts
51837
- import { existsSync as existsSync38, readFileSync as readFileSync19 } from "node:fs";
52477
+ import { existsSync as existsSync39, readFileSync as readFileSync19 } from "node:fs";
51838
52478
  import { join as join44 } from "node:path";
51839
52479
  import { getCleoHome as getCleoHome5 } from "@cleocode/paths";
51840
52480
  function getGoogleOauthPath() {
@@ -51883,7 +52523,7 @@ var init_gemini_cli_seeder = __esm({
51883
52523
  */
51884
52524
  async seed() {
51885
52525
  const path = getGoogleOauthPath();
51886
- if (!existsSync38(path)) {
52526
+ if (!existsSync39(path)) {
51887
52527
  return { entries: [] };
51888
52528
  }
51889
52529
  let raw;
@@ -52108,7 +52748,7 @@ var init_credential_seeders = __esm({
52108
52748
 
52109
52749
  // packages/core/src/llm/global-config-migration.ts
52110
52750
  import {
52111
- existsSync as existsSync39,
52751
+ existsSync as existsSync40,
52112
52752
  mkdirSync as mkdirSync13,
52113
52753
  readFileSync as readFileSync20,
52114
52754
  renameSync as renameSync12,
@@ -52134,12 +52774,12 @@ function migrateGlobalConfigToConfigDir() {
52134
52774
  const source = legacyGlobalConfigPath();
52135
52775
  const target = configDirGlobalConfigPath();
52136
52776
  const marker16 = migrationMarkerPath();
52137
- if (existsSync39(marker16)) return false;
52138
- if (!existsSync39(source)) {
52777
+ if (existsSync40(marker16)) return false;
52778
+ if (!existsSync40(source)) {
52139
52779
  stampMarker(marker16);
52140
52780
  return false;
52141
52781
  }
52142
- if (existsSync39(target)) {
52782
+ if (existsSync40(target)) {
52143
52783
  backupSourceQuiet(source);
52144
52784
  stampMarker(marker16);
52145
52785
  return false;
@@ -52172,7 +52812,7 @@ function migrateGlobalConfigToConfigDir() {
52172
52812
  } catch (err) {
52173
52813
  try {
52174
52814
  const temp = tempTargetPath();
52175
- if (existsSync39(temp)) unlinkSync8(temp);
52815
+ if (existsSync40(temp)) unlinkSync8(temp);
52176
52816
  } catch {
52177
52817
  }
52178
52818
  console.error(
@@ -52192,7 +52832,7 @@ function stampMarker(markerPath) {
52192
52832
  function backupSourceQuiet(source) {
52193
52833
  try {
52194
52834
  const backup = `${source}${BACKUP_SUFFIX}`;
52195
- if (existsSync39(backup)) return;
52835
+ if (existsSync40(backup)) return;
52196
52836
  renameSync12(source, backup);
52197
52837
  } catch {
52198
52838
  }
@@ -52215,7 +52855,7 @@ var init_global_config_migration = __esm({
52215
52855
  });
52216
52856
 
52217
52857
  // packages/core/src/llm/legacy-flat-key-import.ts
52218
- import { existsSync as existsSync40, readFileSync as readFileSync21, renameSync as renameSync13, writeFileSync as writeFileSync13 } from "node:fs";
52858
+ import { existsSync as existsSync41, readFileSync as readFileSync21, renameSync as renameSync13, writeFileSync as writeFileSync13 } from "node:fs";
52219
52859
  import { join as join46 } from "node:path";
52220
52860
  import { getCleoHome as getCleoHome7 } from "@cleocode/paths";
52221
52861
  function migrationPaths() {
@@ -52244,7 +52884,7 @@ function writeMarker(markerPath) {
52244
52884
  }
52245
52885
  function readFlatKey(flatPath) {
52246
52886
  try {
52247
- if (!existsSync40(flatPath)) return null;
52887
+ if (!existsSync41(flatPath)) return null;
52248
52888
  const raw = readFileSync21(flatPath, "utf-8").trim();
52249
52889
  return raw || null;
52250
52890
  } catch (err) {
@@ -52257,7 +52897,7 @@ function readFlatKey(flatPath) {
52257
52897
  }
52258
52898
  async function importLegacyFlatAnthropicKey() {
52259
52899
  const { flatPath, bakPath, markerPath } = migrationPaths();
52260
- if (existsSync40(markerPath)) {
52900
+ if (existsSync41(markerPath)) {
52261
52901
  return { status: "marker-present", flatPath, bakPath: null, markerPath };
52262
52902
  }
52263
52903
  let existing = null;
@@ -52274,7 +52914,7 @@ async function importLegacyFlatAnthropicKey() {
52274
52914
  writeMarker(markerPath);
52275
52915
  return { status: "already-imported", flatPath, bakPath: null, markerPath };
52276
52916
  }
52277
- if (!existsSync40(flatPath)) {
52917
+ if (!existsSync41(flatPath)) {
52278
52918
  writeMarker(markerPath);
52279
52919
  return { status: "no-flat-file", flatPath, bakPath: null, markerPath };
52280
52920
  }
@@ -52336,7 +52976,7 @@ var init_legacy_flat_key_import = __esm({
52336
52976
  });
52337
52977
 
52338
52978
  // packages/core/src/llm/credentials.ts
52339
- import { existsSync as existsSync41, mkdirSync as mkdirSync14, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
52979
+ import { existsSync as existsSync42, mkdirSync as mkdirSync14, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "node:fs";
52340
52980
  import { join as join47 } from "node:path";
52341
52981
  import { getCleoHome as getCleoHome8 } from "@cleocode/paths";
52342
52982
  function globalConfigPath() {
@@ -52355,7 +52995,7 @@ function readGlobalProviderKey(provider) {
52355
52995
  function readFlatAnthropicKey() {
52356
52996
  try {
52357
52997
  const keyFile = join47(getCleoHome8(), "anthropic-key");
52358
- if (!existsSync41(keyFile)) return null;
52998
+ if (!existsSync42(keyFile)) return null;
52359
52999
  const stored = readFileSync22(keyFile, "utf-8").trim();
52360
53000
  return stored || null;
52361
53001
  } catch {
@@ -52364,7 +53004,7 @@ function readFlatAnthropicKey() {
52364
53004
  }
52365
53005
  function readProviderKeyFromConfig(configFile, provider) {
52366
53006
  try {
52367
- if (!existsSync41(configFile)) return null;
53007
+ if (!existsSync42(configFile)) return null;
52368
53008
  const raw = readFileSync22(configFile, "utf-8");
52369
53009
  const config2 = JSON.parse(raw);
52370
53010
  const llm = config2["llm"];
@@ -52504,16 +53144,16 @@ __export(credentials_store_exports, {
52504
53144
  pickCredentialForProviderSync: () => pickCredentialForProviderSync,
52505
53145
  removeCredential: () => removeCredential
52506
53146
  });
52507
- import { chmodSync as chmodSync2, existsSync as existsSync42, mkdirSync as mkdirSync15, readFileSync as readFileSync23, statSync as statSync11, writeFileSync as writeFileSync15 } from "node:fs";
53147
+ import { chmodSync as chmodSync2, existsSync as existsSync43, mkdirSync as mkdirSync15, readFileSync as readFileSync23, statSync as statSync11, writeFileSync as writeFileSync15 } from "node:fs";
52508
53148
  import { dirname as dirname25, join as join48 } from "node:path";
52509
53149
  import { getCleoHome as getCleoHome9 } from "@cleocode/paths";
52510
53150
  function credentialsStorePath() {
52511
53151
  return join48(getCleoHome9(), "llm-credentials.json");
52512
53152
  }
52513
53153
  function ensureFileInitialized(path) {
52514
- if (existsSync42(path)) return;
53154
+ if (existsSync43(path)) return;
52515
53155
  const dir = dirname25(path);
52516
- if (!existsSync42(dir)) {
53156
+ if (!existsSync43(dir)) {
52517
53157
  mkdirSync15(dir, { recursive: true, mode: 448 });
52518
53158
  } else {
52519
53159
  try {
@@ -53309,7 +53949,7 @@ var init_provider_registry = __esm({
53309
53949
  });
53310
53950
 
53311
53951
  // packages/core/src/llm/rate-limit-guard.ts
53312
- import { existsSync as existsSync43, mkdirSync as mkdirSync16, unlinkSync as unlinkSync9 } from "node:fs";
53952
+ import { existsSync as existsSync44, mkdirSync as mkdirSync16, unlinkSync as unlinkSync9 } from "node:fs";
53313
53953
  import { join as join50 } from "node:path";
53314
53954
  import { getCleoHome as getCleoHome10 } from "@cleocode/paths";
53315
53955
  function sanitize(value) {
@@ -53365,7 +54005,7 @@ async function recordRateLimit(provider, label, opts) {
53365
54005
  }
53366
54006
  const filePath = rateLimitStatePath(provider, label);
53367
54007
  const dir = join50(getCleoHome10(), "rate-limit-state");
53368
- if (!existsSync43(dir)) {
54008
+ if (!existsSync44(dir)) {
53369
54009
  mkdirSync16(dir, { recursive: true });
53370
54010
  }
53371
54011
  const state = { resetAt, recordedAt: now, source };
@@ -53950,7 +54590,7 @@ var init_local_inference_probe = __esm({
53950
54590
 
53951
54591
  // packages/core/src/llm/catalog-cache.ts
53952
54592
  import {
53953
- existsSync as existsSync44,
54593
+ existsSync as existsSync45,
53954
54594
  mkdirSync as mkdirSync17,
53955
54595
  readdirSync as readdirSync11,
53956
54596
  readFileSync as readFileSync24,
@@ -53968,7 +54608,7 @@ function getCatalogDir() {
53968
54608
  return join51(getCleoHome11(), "llm-catalog");
53969
54609
  }
53970
54610
  function findLatestCacheFile(dir) {
53971
- if (!existsSync44(dir)) return null;
54611
+ if (!existsSync45(dir)) return null;
53972
54612
  const files = readdirSync11(dir).filter((f) => f.endsWith("-models.json")).map((f) => ({ name: f, mtime: statSync13(join51(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
53973
54613
  return files.length > 0 ? join51(dir, files[0].name) : null;
53974
54614
  }