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