@cleocode/core 2026.9.25 → 2026.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-attach.d.ts +94 -0
- package/dist/cloud/nexus-attach.d.ts.map +1 -0
- package/dist/cloud/nexus-attach.js +192 -0
- package/dist/cloud/nexus-attach.js.map +1 -0
- package/dist/cloud/nexus-auth.d.ts +41 -4
- package/dist/cloud/nexus-auth.d.ts.map +1 -1
- package/dist/cloud/nexus-auth.js +151 -38
- package/dist/cloud/nexus-auth.js.map +1 -1
- package/dist/cloud/nexus-cloud-status.d.ts +132 -0
- package/dist/cloud/nexus-cloud-status.d.ts.map +1 -0
- package/dist/cloud/nexus-cloud-status.js +440 -0
- package/dist/cloud/nexus-cloud-status.js.map +1 -0
- package/dist/cloud/nexus-cloud.d.ts +179 -0
- package/dist/cloud/nexus-cloud.d.ts.map +1 -0
- package/dist/cloud/nexus-cloud.js +296 -0
- package/dist/cloud/nexus-cloud.js.map +1 -0
- package/dist/cloud/nexus-credentials.js +2 -2
- package/dist/cloud/nexus-credentials.js.map +1 -1
- package/dist/cloud/nexus-device.d.ts +834 -0
- package/dist/cloud/nexus-device.d.ts.map +1 -0
- package/dist/cloud/nexus-device.js +1727 -0
- package/dist/cloud/nexus-device.js.map +1 -0
- package/dist/cloud/nexus-enrol.d.ts +241 -0
- package/dist/cloud/nexus-enrol.d.ts.map +1 -0
- package/dist/cloud/nexus-enrol.js +1163 -0
- package/dist/cloud/nexus-enrol.js.map +1 -0
- package/dist/cloud/nexus-link.d.ts +10 -0
- package/dist/cloud/nexus-link.d.ts.map +1 -1
- package/dist/cloud/nexus-link.js +172 -11
- package/dist/cloud/nexus-link.js.map +1 -1
- package/dist/cloud/nexus-logout.d.ts +114 -0
- package/dist/cloud/nexus-logout.d.ts.map +1 -0
- package/dist/cloud/nexus-logout.js +429 -0
- package/dist/cloud/nexus-logout.js.map +1 -0
- 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 +1072 -227
- 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 +1200 -355
- 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 +1203 -358
- 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/setup/sections/nexus-account.d.ts +8 -6
- package/dist/setup/sections/nexus-account.d.ts.map +1 -1
- package/dist/setup/sections/nexus-account.js +53 -9
- package/dist/setup/sections/nexus-account.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/sync/replica.d.ts +34 -3
- package/dist/store/sync/replica.d.ts.map +1 -1
- package/dist/store/sync/replica.js +39 -2
- package/dist/store/sync/replica.js.map +1 -1
- package/dist/store/sync/schema.d.ts +6 -3
- package/dist/store/sync/schema.d.ts.map +1 -1
- package/dist/store/sync/schema.js +6 -3
- package/dist/store/sync/schema.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";
|
|
@@ -17365,6 +17366,210 @@ var init_nexus_account = __esm({
|
|
|
17365
17366
|
}
|
|
17366
17367
|
});
|
|
17367
17368
|
|
|
17369
|
+
// packages/contracts/src/nexus-cloud.ts
|
|
17370
|
+
import { z as z26 } from "zod";
|
|
17371
|
+
var NEXUS_DEVICE_STATES, NEXUS_CLOUD_PROFILES, NEXUS_DEVICE_STATE_UNKNOWN, isoTime, profile, deviceState, nexusCloudCredentialSchema, nexusCloudDeviceSchema, nexusCloudOrganizationSchema, nexusCloudUserSchema, nexusCloudWhoamiSchema, nexusCloudDevicePageSchema, nexusCloudPresenceSchema, nexusCloudReplicaSchema, nexusCloudDeviceCountsSchema, projectFields, nexusCloudProjectListItemSchema, nexusCloudProjectPageSchema, nexusCloudProjectDetailSchema, nexusCloudReplicaPageSchema, NEXUS_STATUS_CHECK_IDS, NEXUS_STATUS_VERDICTS, CLOUD_STATUS_VERDICTS, knownCheckId, nexusCloudStatusCheckSchema, nexusCloudStatusSchema;
|
|
17372
|
+
var init_nexus_cloud = __esm({
|
|
17373
|
+
"packages/contracts/src/nexus-cloud.ts"() {
|
|
17374
|
+
"use strict";
|
|
17375
|
+
NEXUS_DEVICE_STATES = ["active", "signed-out", "revoked"];
|
|
17376
|
+
NEXUS_CLOUD_PROFILES = ["device", "read-only"];
|
|
17377
|
+
NEXUS_DEVICE_STATE_UNKNOWN = "unknown";
|
|
17378
|
+
isoTime = z26.iso.datetime({ offset: true });
|
|
17379
|
+
profile = z26.enum(NEXUS_CLOUD_PROFILES).nullable().catch(null);
|
|
17380
|
+
deviceState = z26.enum([...NEXUS_DEVICE_STATES, NEXUS_DEVICE_STATE_UNKNOWN]).catch(NEXUS_DEVICE_STATE_UNKNOWN);
|
|
17381
|
+
nexusCloudCredentialSchema = z26.object({
|
|
17382
|
+
kind: z26.enum(["device", "session"]),
|
|
17383
|
+
credentialId: z26.string().nullable().optional(),
|
|
17384
|
+
profile: profile.optional(),
|
|
17385
|
+
scopes: z26.array(z26.string()).default([]),
|
|
17386
|
+
createdAt: isoTime.nullable().optional(),
|
|
17387
|
+
lastUsedAt: isoTime.nullable().optional(),
|
|
17388
|
+
/** When the credential expires if it is not used again; null for sessions. */
|
|
17389
|
+
idleExpiresAt: isoTime.nullable().optional()
|
|
17390
|
+
});
|
|
17391
|
+
nexusCloudDeviceSchema = z26.object({
|
|
17392
|
+
deviceId: z26.string(),
|
|
17393
|
+
name: z26.string(),
|
|
17394
|
+
platform: z26.string().optional(),
|
|
17395
|
+
arch: z26.string().nullable().optional(),
|
|
17396
|
+
cliVersion: z26.string().nullable().optional(),
|
|
17397
|
+
createdAt: isoTime.optional(),
|
|
17398
|
+
lastSeenAt: isoTime.nullable().optional(),
|
|
17399
|
+
state: deviceState,
|
|
17400
|
+
signedOutAt: isoTime.nullable().optional(),
|
|
17401
|
+
/** Base64 device certificate; null until the device holds a key grant. */
|
|
17402
|
+
certificate: z26.string().nullable().optional(),
|
|
17403
|
+
/** The current credential's profile, or null with none (signed out or revoked). */
|
|
17404
|
+
profile: profile.optional(),
|
|
17405
|
+
/** True for the device whose credential made this request. */
|
|
17406
|
+
current: z26.boolean().default(false),
|
|
17407
|
+
projects: z26.number().int().nonnegative().optional(),
|
|
17408
|
+
replicas: z26.number().int().nonnegative().optional(),
|
|
17409
|
+
lastSyncAt: isoTime.nullable().optional(),
|
|
17410
|
+
lastPresenceAt: isoTime.nullable().optional()
|
|
17411
|
+
});
|
|
17412
|
+
nexusCloudOrganizationSchema = z26.object({
|
|
17413
|
+
id: z26.string(),
|
|
17414
|
+
name: z26.string(),
|
|
17415
|
+
slug: z26.string().nullable().optional(),
|
|
17416
|
+
role: z26.string().optional(),
|
|
17417
|
+
personal: z26.boolean().optional()
|
|
17418
|
+
});
|
|
17419
|
+
nexusCloudUserSchema = z26.object({
|
|
17420
|
+
id: z26.string(),
|
|
17421
|
+
email: z26.string(),
|
|
17422
|
+
name: z26.string().nullable().optional()
|
|
17423
|
+
});
|
|
17424
|
+
nexusCloudWhoamiSchema = z26.object({
|
|
17425
|
+
serverTime: isoTime.optional(),
|
|
17426
|
+
user: nexusCloudUserSchema,
|
|
17427
|
+
organizations: z26.array(nexusCloudOrganizationSchema).default([]),
|
|
17428
|
+
credential: nexusCloudCredentialSchema,
|
|
17429
|
+
/** The calling device; null for a session caller. */
|
|
17430
|
+
device: nexusCloudDeviceSchema.nullable()
|
|
17431
|
+
});
|
|
17432
|
+
nexusCloudDevicePageSchema = z26.object({
|
|
17433
|
+
devices: z26.array(nexusCloudDeviceSchema),
|
|
17434
|
+
nextCursor: z26.string().max(512).nullable().default(null),
|
|
17435
|
+
truncated: z26.boolean().default(false)
|
|
17436
|
+
});
|
|
17437
|
+
nexusCloudPresenceSchema = z26.looseObject({
|
|
17438
|
+
observedAt: isoTime.optional(),
|
|
17439
|
+
sync: z26.object({ enabled: z26.boolean() }).optional()
|
|
17440
|
+
});
|
|
17441
|
+
nexusCloudReplicaSchema = z26.object({
|
|
17442
|
+
projectId: z26.string(),
|
|
17443
|
+
replicaId: z26.string(),
|
|
17444
|
+
deviceId: z26.string(),
|
|
17445
|
+
deviceName: z26.string(),
|
|
17446
|
+
deviceState: deviceState.optional(),
|
|
17447
|
+
attachedAt: isoTime.optional(),
|
|
17448
|
+
lastSyncAt: isoTime.nullable(),
|
|
17449
|
+
presence: nexusCloudPresenceSchema.nullable(),
|
|
17450
|
+
presenceAt: isoTime.nullable()
|
|
17451
|
+
});
|
|
17452
|
+
nexusCloudDeviceCountsSchema = z26.object({
|
|
17453
|
+
active: z26.number().int().nonnegative(),
|
|
17454
|
+
total: z26.number().int().nonnegative()
|
|
17455
|
+
});
|
|
17456
|
+
projectFields = {
|
|
17457
|
+
projectId: z26.string(),
|
|
17458
|
+
label: z26.string().nullable(),
|
|
17459
|
+
organizationId: z26.string(),
|
|
17460
|
+
organizationName: z26.string().optional(),
|
|
17461
|
+
remoteUrl: z26.string().nullable().optional(),
|
|
17462
|
+
createdAt: isoTime.optional()
|
|
17463
|
+
};
|
|
17464
|
+
nexusCloudProjectListItemSchema = z26.object({
|
|
17465
|
+
...projectFields,
|
|
17466
|
+
role: z26.string(),
|
|
17467
|
+
streamId: z26.string().optional(),
|
|
17468
|
+
headSeq: z26.number().int().nonnegative().nullable().optional(),
|
|
17469
|
+
openConflicts: z26.number().int().nonnegative().optional(),
|
|
17470
|
+
replicas: z26.array(nexusCloudReplicaSchema).default([]),
|
|
17471
|
+
devices: nexusCloudDeviceCountsSchema.optional(),
|
|
17472
|
+
replicaCount: z26.number().int().nonnegative().optional(),
|
|
17473
|
+
lastSyncAt: isoTime.nullable().optional(),
|
|
17474
|
+
lastPresenceAt: isoTime.nullable().optional(),
|
|
17475
|
+
/** This project's replica list was cut at 50 (T12858). */
|
|
17476
|
+
replicasTruncated: z26.boolean().default(false)
|
|
17477
|
+
});
|
|
17478
|
+
nexusCloudProjectPageSchema = z26.object({
|
|
17479
|
+
projects: z26.array(nexusCloudProjectListItemSchema),
|
|
17480
|
+
nextCursor: z26.string().max(512).nullable().default(null),
|
|
17481
|
+
/** Anything in the page was cut (the project list or a replica list). */
|
|
17482
|
+
truncated: z26.boolean().default(false),
|
|
17483
|
+
/** The project list itself was cut at 1000 (T12858). */
|
|
17484
|
+
projectsTruncated: z26.boolean().default(false)
|
|
17485
|
+
});
|
|
17486
|
+
nexusCloudProjectDetailSchema = z26.object({
|
|
17487
|
+
project: z26.object({ ...projectFields, deletedAt: isoTime.nullable().optional() }),
|
|
17488
|
+
role: z26.string(),
|
|
17489
|
+
canTrash: z26.boolean().optional(),
|
|
17490
|
+
openConflicts: z26.number().int().nonnegative(),
|
|
17491
|
+
/** At most 50, oldest attachment first. */
|
|
17492
|
+
replicas: z26.array(nexusCloudReplicaSchema),
|
|
17493
|
+
devices: nexusCloudDeviceCountsSchema,
|
|
17494
|
+
replicaCount: z26.number().int().nonnegative().optional(),
|
|
17495
|
+
lastSyncAt: isoTime.nullable().optional(),
|
|
17496
|
+
/** `replicas` was cut at 50. */
|
|
17497
|
+
truncated: z26.boolean().default(false),
|
|
17498
|
+
stream: z26.object({
|
|
17499
|
+
streamId: z26.string(),
|
|
17500
|
+
headSeq: z26.number().int().nonnegative(),
|
|
17501
|
+
headCheckpointId: z26.string().nullable()
|
|
17502
|
+
}).nullable()
|
|
17503
|
+
});
|
|
17504
|
+
nexusCloudReplicaPageSchema = z26.object({
|
|
17505
|
+
replicas: z26.array(nexusCloudReplicaSchema),
|
|
17506
|
+
devices: nexusCloudDeviceCountsSchema.optional(),
|
|
17507
|
+
nextCursor: z26.string().max(512).nullable().default(null),
|
|
17508
|
+
truncated: z26.boolean().default(false)
|
|
17509
|
+
});
|
|
17510
|
+
NEXUS_STATUS_CHECK_IDS = [
|
|
17511
|
+
"credential.valid",
|
|
17512
|
+
"device.registered",
|
|
17513
|
+
"device.active",
|
|
17514
|
+
"device.certified",
|
|
17515
|
+
"project.registered",
|
|
17516
|
+
"project.writable",
|
|
17517
|
+
"replica.attached",
|
|
17518
|
+
"presence.fresh",
|
|
17519
|
+
"replica.synced",
|
|
17520
|
+
"conflicts.none"
|
|
17521
|
+
];
|
|
17522
|
+
NEXUS_STATUS_VERDICTS = ["ok", "attention", "not-linked", "not-registered"];
|
|
17523
|
+
CLOUD_STATUS_VERDICTS = [...NEXUS_STATUS_VERDICTS, "not-signed-in"];
|
|
17524
|
+
knownCheckId = z26.enum(NEXUS_STATUS_CHECK_IDS);
|
|
17525
|
+
nexusCloudStatusCheckSchema = z26.object({
|
|
17526
|
+
id: z26.enum(NEXUS_STATUS_CHECK_IDS),
|
|
17527
|
+
ok: z26.boolean(),
|
|
17528
|
+
required: z26.boolean(),
|
|
17529
|
+
detail: z26.string()
|
|
17530
|
+
});
|
|
17531
|
+
nexusCloudStatusSchema = z26.object({
|
|
17532
|
+
serverTime: isoTime.optional(),
|
|
17533
|
+
apiVersion: z26.string().optional(),
|
|
17534
|
+
user: nexusCloudUserSchema,
|
|
17535
|
+
credential: nexusCloudCredentialSchema,
|
|
17536
|
+
device: nexusCloudDeviceSchema.nullable(),
|
|
17537
|
+
project: z26.object({
|
|
17538
|
+
projectId: z26.string(),
|
|
17539
|
+
registered: z26.boolean(),
|
|
17540
|
+
organizationId: z26.string().nullable(),
|
|
17541
|
+
organizationName: z26.string().nullable(),
|
|
17542
|
+
role: z26.string().nullable()
|
|
17543
|
+
}).nullable(),
|
|
17544
|
+
replica: z26.object({
|
|
17545
|
+
replicaId: z26.string(),
|
|
17546
|
+
attached: z26.boolean(),
|
|
17547
|
+
attachedElsewhere: z26.boolean(),
|
|
17548
|
+
attachedAt: isoTime.nullable(),
|
|
17549
|
+
lastSyncAt: isoTime.nullable(),
|
|
17550
|
+
presenceAt: isoTime.nullable(),
|
|
17551
|
+
lastReplicaSeq: z26.number().int().nonnegative().nullable().optional()
|
|
17552
|
+
}).nullable(),
|
|
17553
|
+
stream: z26.object({
|
|
17554
|
+
streamId: z26.string(),
|
|
17555
|
+
headSeq: z26.number().int().nonnegative(),
|
|
17556
|
+
headCheckpointId: z26.string().nullable(),
|
|
17557
|
+
openConflicts: z26.number().int().nonnegative(),
|
|
17558
|
+
devices: nexusCloudDeviceCountsSchema
|
|
17559
|
+
}).nullable(),
|
|
17560
|
+
/** Check ids added by a newer server are dropped, never a parse failure. */
|
|
17561
|
+
checks: z26.array(nexusCloudStatusCheckSchema.extend({ id: z26.string() })).transform(
|
|
17562
|
+
(list) => list.flatMap((c) => {
|
|
17563
|
+
const id = knownCheckId.safeParse(c.id);
|
|
17564
|
+
return id.success ? [{ ...c, id: id.data }] : [];
|
|
17565
|
+
})
|
|
17566
|
+
),
|
|
17567
|
+
/** A verdict added by a newer server reads as `attention`: never `ok` by accident. */
|
|
17568
|
+
verdict: z26.enum(NEXUS_STATUS_VERDICTS).catch("attention")
|
|
17569
|
+
});
|
|
17570
|
+
}
|
|
17571
|
+
});
|
|
17572
|
+
|
|
17368
17573
|
// packages/contracts/src/task-id.ts
|
|
17369
17574
|
var init_task_id = __esm({
|
|
17370
17575
|
"packages/contracts/src/task-id.ts"() {
|
|
@@ -17449,6 +17654,7 @@ var init_src = __esm({
|
|
|
17449
17654
|
init_decide();
|
|
17450
17655
|
init_decide_sites();
|
|
17451
17656
|
init_nexus_account();
|
|
17657
|
+
init_nexus_cloud();
|
|
17452
17658
|
init_task_id();
|
|
17453
17659
|
}
|
|
17454
17660
|
});
|
|
@@ -17771,6 +17977,19 @@ var init_error_catalog = __esm({
|
|
|
17771
17977
|
`Bind a session: run 'cleo session start --scope global --name "<name>"', 'cleo session resume <id>', or set CLEO_SESSION_ID=<id>.`
|
|
17772
17978
|
)
|
|
17773
17979
|
],
|
|
17980
|
+
[
|
|
17981
|
+
26 /* TASK_RENAMED */,
|
|
17982
|
+
def(
|
|
17983
|
+
26 /* TASK_RENAMED */,
|
|
17984
|
+
"TASK_RENAMED",
|
|
17985
|
+
"CONFLICT",
|
|
17986
|
+
"Task was re-numbered by sync",
|
|
17987
|
+
409,
|
|
17988
|
+
true,
|
|
17989
|
+
"E_TASK_RENAMED",
|
|
17990
|
+
"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."
|
|
17991
|
+
)
|
|
17992
|
+
],
|
|
17774
17993
|
[
|
|
17775
17994
|
25 /* WORKTREE_LOCKED */,
|
|
17776
17995
|
def(
|
|
@@ -19718,10 +19937,10 @@ var init_table2 = __esm({
|
|
|
19718
19937
|
[IsDrizzleTable] = true;
|
|
19719
19938
|
/** @internal */
|
|
19720
19939
|
[ExtraConfigBuilder] = void 0;
|
|
19721
|
-
constructor(name2, schema,
|
|
19940
|
+
constructor(name2, schema, baseName2) {
|
|
19722
19941
|
this[TableName] = this[OriginalName] = name2;
|
|
19723
19942
|
this[TableSchema] = schema;
|
|
19724
|
-
this[BaseName] =
|
|
19943
|
+
this[BaseName] = baseName2;
|
|
19725
19944
|
}
|
|
19726
19945
|
};
|
|
19727
19946
|
}
|
|
@@ -21651,9 +21870,9 @@ var init_casing = __esm({
|
|
|
21651
21870
|
});
|
|
21652
21871
|
|
|
21653
21872
|
// 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,
|
|
21873
|
+
function sqliteTableBase(name2, columns, extraConfig, schema, casing, baseName2 = name2) {
|
|
21655
21874
|
const casingFn = getCasingFn(casing);
|
|
21656
|
-
const rawTable = new SQLiteTable(name2, schema,
|
|
21875
|
+
const rawTable = new SQLiteTable(name2, schema, baseName2);
|
|
21657
21876
|
const parsedColumns = typeof columns === "function" ? columns(getSQLiteColumnBuilders()) : columns;
|
|
21658
21877
|
const builtColumns = Object.fromEntries(Object.entries(parsedColumns).map(([name3, colBuilderBase]) => {
|
|
21659
21878
|
const colBuilder = colBuilderBase;
|
|
@@ -25450,6 +25669,10 @@ function decisionFor(dbPath) {
|
|
|
25450
25669
|
if (!decisions.has(key)) decisions.set(key, schemaWriteRefusal(key));
|
|
25451
25670
|
return decisions.get(key) ?? null;
|
|
25452
25671
|
}
|
|
25672
|
+
function schemaWritesAllowed(nativeDb) {
|
|
25673
|
+
const dbPath = nativeDb.location();
|
|
25674
|
+
return !dbPath || decisionFor(dbPath) === null;
|
|
25675
|
+
}
|
|
25453
25676
|
function isWorktreeBuildSchemaError(error) {
|
|
25454
25677
|
return error instanceof Error && error.message.includes(E_WORKTREE_BUILD_SCHEMA);
|
|
25455
25678
|
}
|
|
@@ -26488,7 +26711,10 @@ var init_row_identity_registry = __esm({
|
|
|
26488
26711
|
key: ["id"],
|
|
26489
26712
|
birth: "recorded_at",
|
|
26490
26713
|
content: ["ac_id", "previous_text", "reason"],
|
|
26491
|
-
|
|
26714
|
+
// v2 (T12802): no @refFp: the criterion's fingerprint is unknowable when
|
|
26715
|
+
// it was gone before this row got its identity, so it made the value
|
|
26716
|
+
// depend on fill timing. ac_id is always known.
|
|
26717
|
+
birthFacts: ["ac_id", "previous_text", "reason"],
|
|
26492
26718
|
storedRefUids: [{ column: "ac_uid", from: "ac_id", table: ACS }],
|
|
26493
26719
|
task: "T12341"
|
|
26494
26720
|
},
|
|
@@ -26497,7 +26723,10 @@ var init_row_identity_registry = __esm({
|
|
|
26497
26723
|
kind: "minted",
|
|
26498
26724
|
key: ["id"],
|
|
26499
26725
|
birth: "created_at",
|
|
26500
|
-
|
|
26726
|
+
// v2 (T12802): ac_id in place of @refFp:ac_uid and ac_text_hash. Both
|
|
26727
|
+
// were filled from the criterion, so a backfilled binding whose
|
|
26728
|
+
// criterion was already gone got a different value (see AC history).
|
|
26729
|
+
birthFacts: ["evidence_atom_id", "binding_type", "ac_id"],
|
|
26501
26730
|
storedRefUids: [
|
|
26502
26731
|
{ column: "ac_uid", from: "ac_id", table: ACS },
|
|
26503
26732
|
{ column: "ac_text_hash", from: "ac_id", table: ACS, source: "text_hash" }
|
|
@@ -26539,7 +26768,9 @@ var init_row_identity_registry = __esm({
|
|
|
26539
26768
|
// The uid IS the primary key: display-id-alias.ts computes it on write.
|
|
26540
26769
|
table: "tasks_display_id_aliases",
|
|
26541
26770
|
kind: "natural",
|
|
26542
|
-
|
|
26771
|
+
// T12800: the reason is part of the key (collision-remint and
|
|
26772
|
+
// remint-assigned of one id and row are distinct facts).
|
|
26773
|
+
key: ["entity_table", "display_id", "entity_uid", "reason"],
|
|
26543
26774
|
task: "T12341"
|
|
26544
26775
|
},
|
|
26545
26776
|
{
|
|
@@ -27121,6 +27352,20 @@ function installRowUidTriggers(db, scope) {
|
|
|
27121
27352
|
);
|
|
27122
27353
|
}
|
|
27123
27354
|
}
|
|
27355
|
+
function v1ReleaseBirthFp(db, table, row) {
|
|
27356
|
+
const col = (c) => row[c] ?? null;
|
|
27357
|
+
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")] : [];
|
|
27358
|
+
if (facts.length === 0) return null;
|
|
27359
|
+
const acUid = col("ac_uid");
|
|
27360
|
+
let ref = "ref:none";
|
|
27361
|
+
if (acUid !== null) {
|
|
27362
|
+
const ac = db.prepare("SELECT birth_fp AS fp FROM main.tasks_task_acceptance_criteria WHERE uid = ?").get(acUid);
|
|
27363
|
+
ref = ac === void 0 ? "ref:missing" : ac.fp;
|
|
27364
|
+
if (ref === null) return null;
|
|
27365
|
+
}
|
|
27366
|
+
const spec = rowIdentitySpec("project", table);
|
|
27367
|
+
return birthFingerprint(table, spec?.birth ? col(spec.birth) : null, [...facts, ref]);
|
|
27368
|
+
}
|
|
27124
27369
|
function hasObject(db, type, name2) {
|
|
27125
27370
|
return db.prepare("SELECT 1 FROM main.sqlite_master WHERE type = ? AND name = ?").get(type, name2) !== void 0;
|
|
27126
27371
|
}
|
|
@@ -27204,24 +27449,41 @@ function preReleaseBirthFp(db, table, row) {
|
|
|
27204
27449
|
function resetStaleIdentity(db, scope, writers) {
|
|
27205
27450
|
if (scope !== "project" || !hasTable(db, ROW_IDENTITY_META_TABLE)) return "none";
|
|
27206
27451
|
if (readMeta(db, ROW_IDENTITY_RECIPE_KEY) === ROW_IDENTITY_RECIPE) return "none";
|
|
27207
|
-
const minted = ROW_IDENTITY.project.filter(
|
|
27208
|
-
(spec) =>
|
|
27452
|
+
const minted = fingerprintOrder("project", ROW_IDENTITY.project).filter(
|
|
27453
|
+
(spec) => hasTable(db, spec.table) && columnsOf(db, spec.table).has(BIRTH_FP_COLUMN)
|
|
27209
27454
|
);
|
|
27210
27455
|
const stale = [];
|
|
27456
|
+
const cleared = /* @__PURE__ */ new Map();
|
|
27457
|
+
const mark = (table, column, value) => {
|
|
27458
|
+
if (value === null || value === void 0) return;
|
|
27459
|
+
const key = `${table}.${column}`;
|
|
27460
|
+
const set = cleared.get(key) ?? /* @__PURE__ */ new Set();
|
|
27461
|
+
set.add(String(value));
|
|
27462
|
+
cleared.set(key, set);
|
|
27463
|
+
};
|
|
27211
27464
|
for (const spec of minted) {
|
|
27465
|
+
const deps = (spec.birthFacts ?? []).map((fact) => fingerprintRef("project", spec, fact)).filter((d) => d !== null);
|
|
27466
|
+
const keyColumn = targetKey("project", spec.table);
|
|
27212
27467
|
const rows = db.prepare(
|
|
27213
27468
|
`SELECT rowid AS _rowid, * FROM main.${q(spec.table)} WHERE ${q(BIRTH_FP_COLUMN)} IS NOT NULL`
|
|
27214
27469
|
).all();
|
|
27215
27470
|
for (const row of rows) {
|
|
27216
|
-
|
|
27471
|
+
const derivedFromStale = deps.some(
|
|
27472
|
+
(d) => cleared.get(`${d.table}.${d.key}`)?.has(String(row[d.column] ?? ""))
|
|
27473
|
+
);
|
|
27474
|
+
if (derivedFromStale || row[BIRTH_FP_COLUMN] === preReleaseBirthFp(db, spec.table, row) || row[BIRTH_FP_COLUMN] === v1ReleaseBirthFp(db, spec.table, row)) {
|
|
27217
27475
|
stale.push({ table: spec.table, rowid: row._rowid });
|
|
27476
|
+
mark(spec.table, keyColumn, row[keyColumn]);
|
|
27477
|
+
mark(spec.table, UID_COLUMN, row[UID_COLUMN]);
|
|
27218
27478
|
}
|
|
27219
27479
|
}
|
|
27220
27480
|
}
|
|
27221
|
-
|
|
27481
|
+
const graveyardRows = scope === "project" && hasTable(db, AC_UID_GRAVEYARD) ? db.prepare(`SELECT count(*) AS n FROM main.${AC_UID_GRAVEYARD}`).get().n : 0;
|
|
27482
|
+
if (stale.length === 0 && graveyardRows === 0) return "none";
|
|
27222
27483
|
if (readMeta(db, ROW_IDENTITY_SYNCED_KEY) !== void 0) return "refused";
|
|
27223
27484
|
db.exec("SAVEPOINT row_identity_reset");
|
|
27224
27485
|
try {
|
|
27486
|
+
if (graveyardRows > 0) writers.clearAcUidGraveyardNative(db);
|
|
27225
27487
|
for (const { table, rowid } of stale) {
|
|
27226
27488
|
writers.clearBirthFpNative(db, table, rowid);
|
|
27227
27489
|
}
|
|
@@ -27237,6 +27499,106 @@ function writeRecipeMarker(db, writers = requireWriters()) {
|
|
|
27237
27499
|
if (!hasTable(db, ROW_IDENTITY_META_TABLE)) return;
|
|
27238
27500
|
writers.writeRowIdentityMetaNative(db, ROW_IDENTITY_RECIPE_KEY, ROW_IDENTITY_RECIPE);
|
|
27239
27501
|
}
|
|
27502
|
+
function rowIdentityShared(db) {
|
|
27503
|
+
return readMeta(db, ROW_IDENTITY_SYNCED_KEY) !== void 0;
|
|
27504
|
+
}
|
|
27505
|
+
function healRowIdentitySchema(db, scope, writers = registeredWriters) {
|
|
27506
|
+
const log15 = getLogger("row-identity");
|
|
27507
|
+
if (ROW_IDENTITY[scope].length === 0) {
|
|
27508
|
+
return [];
|
|
27509
|
+
}
|
|
27510
|
+
if (!schemaWritesAllowed(db)) {
|
|
27511
|
+
log15.debug({ scope }, "row identity schema heal skipped: schema writes refused for this build");
|
|
27512
|
+
return [];
|
|
27513
|
+
}
|
|
27514
|
+
try {
|
|
27515
|
+
db.exec("SAVEPOINT row_identity_heal");
|
|
27516
|
+
try {
|
|
27517
|
+
const healed = [
|
|
27518
|
+
...scope === "project" ? ensureIdentityTables(db) : [],
|
|
27519
|
+
...ensureRowIdentitySchema(db, scope)
|
|
27520
|
+
];
|
|
27521
|
+
if (healed.length > 0) recordHealReceipt(db, scope, healed, writers);
|
|
27522
|
+
db.exec("RELEASE SAVEPOINT row_identity_heal");
|
|
27523
|
+
if (healed.length > 0)
|
|
27524
|
+
log15.info({ scope, healed: healed.length }, "row identity schema healed");
|
|
27525
|
+
return healed;
|
|
27526
|
+
} catch (error) {
|
|
27527
|
+
db.exec("ROLLBACK TO SAVEPOINT row_identity_heal");
|
|
27528
|
+
db.exec("RELEASE SAVEPOINT row_identity_heal");
|
|
27529
|
+
throw error;
|
|
27530
|
+
}
|
|
27531
|
+
} catch (error) {
|
|
27532
|
+
log15.error({ scope, error }, "row identity schema heal failed");
|
|
27533
|
+
return [];
|
|
27534
|
+
}
|
|
27535
|
+
}
|
|
27536
|
+
function recordHealReceipt(db, scope, healed, writers) {
|
|
27537
|
+
const table = HEAL_RECEIPT_TABLE[scope];
|
|
27538
|
+
const log15 = getLogger("row-identity");
|
|
27539
|
+
if (table === null || !hasTable(db, table) || !writers) {
|
|
27540
|
+
log15.warn({ scope, healed: healed.length }, "row identity schema healed; no receipt table");
|
|
27541
|
+
return;
|
|
27542
|
+
}
|
|
27543
|
+
const objects = healed.map((stmt) => {
|
|
27544
|
+
const col = /ALTER TABLE main\.("?)(\w+)\1 ADD COLUMN ("?)(\w+)\3/.exec(stmt);
|
|
27545
|
+
if (col) return `${col[2]}.${col[4]}`;
|
|
27546
|
+
const obj = /(TABLE|INDEX|TRIGGER) IF NOT EXISTS main\.("?)(\w+)\2/.exec(stmt);
|
|
27547
|
+
return obj ? `${obj[1].toLowerCase()} ${obj[3]}` : stmt.slice(0, 60);
|
|
27548
|
+
});
|
|
27549
|
+
const receipt2 = {
|
|
27550
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27551
|
+
scope,
|
|
27552
|
+
statements: healed.length,
|
|
27553
|
+
objects
|
|
27554
|
+
};
|
|
27555
|
+
const history = [...readRowIdentityHealHistory(db), receipt2].slice(-HEAL_RECEIPTS_KEPT);
|
|
27556
|
+
writers.writeRowIdentityMetaNative(db, ROW_IDENTITY_HEAL_KEY, JSON.stringify(history));
|
|
27557
|
+
}
|
|
27558
|
+
function readRowIdentityHealHistory(db) {
|
|
27559
|
+
const raw = readMeta(db, ROW_IDENTITY_HEAL_KEY);
|
|
27560
|
+
if (raw === void 0) return [];
|
|
27561
|
+
try {
|
|
27562
|
+
const parsed = JSON.parse(raw);
|
|
27563
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
27564
|
+
} catch {
|
|
27565
|
+
return [];
|
|
27566
|
+
}
|
|
27567
|
+
}
|
|
27568
|
+
function missingRowIdentitySchema(db) {
|
|
27569
|
+
if (!hasTable(db, "tasks_task_acceptance_criteria")) return [];
|
|
27570
|
+
const missing = [];
|
|
27571
|
+
for (const table of Object.keys(IDENTITY_TABLE_DDL)) {
|
|
27572
|
+
if (!hasTable(db, table)) missing.push(`table ${table}`);
|
|
27573
|
+
}
|
|
27574
|
+
for (const [table, column] of [
|
|
27575
|
+
["tasks_display_id_aliases", "displaced_hlc"],
|
|
27576
|
+
["tasks_display_id_aliases", "entity_birth_fp"],
|
|
27577
|
+
[AC_UID_GRAVEYARD, "birth_fp"]
|
|
27578
|
+
]) {
|
|
27579
|
+
if (hasTable(db, table) && !columnsOf(db, table).has(column)) {
|
|
27580
|
+
missing.push(`column ${table}.${column}`);
|
|
27581
|
+
}
|
|
27582
|
+
}
|
|
27583
|
+
if (!hasObject(db, "trigger", "trg_tasks_ac_uid_graveyard")) {
|
|
27584
|
+
missing.push("trigger trg_tasks_ac_uid_graveyard");
|
|
27585
|
+
}
|
|
27586
|
+
for (const spec of ROW_IDENTITY.project) {
|
|
27587
|
+
if (!hasTable(db, spec.table)) continue;
|
|
27588
|
+
const cols = columnsOf(db, spec.table);
|
|
27589
|
+
for (const column of rowIdentityColumns("project", spec.table)) {
|
|
27590
|
+
if (!cols.has(column)) missing.push(`column ${spec.table}.${column}`);
|
|
27591
|
+
}
|
|
27592
|
+
if (!uidIsPrimaryKey(db, spec.table) && !hasObject(db, "index", `uq_${spec.table}_uid`)) {
|
|
27593
|
+
missing.push(`index uq_${spec.table}_uid`);
|
|
27594
|
+
}
|
|
27595
|
+
for (const ref of spec.storedRefUids ?? []) {
|
|
27596
|
+
const index2 = `idx_${spec.table}_${ref.column}`;
|
|
27597
|
+
if (!hasObject(db, "index", index2)) missing.push(`index ${index2}`);
|
|
27598
|
+
}
|
|
27599
|
+
}
|
|
27600
|
+
return missing;
|
|
27601
|
+
}
|
|
27240
27602
|
function prepareRowIdentity(db, scope, options = {}) {
|
|
27241
27603
|
if (ROW_IDENTITY[scope].length === 0) return null;
|
|
27242
27604
|
if (!rowUidFillEnabled()) return null;
|
|
@@ -27275,7 +27637,7 @@ function prepareRowIdentity(db, scope, options = {}) {
|
|
|
27275
27637
|
return null;
|
|
27276
27638
|
}
|
|
27277
27639
|
}
|
|
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;
|
|
27640
|
+
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
27641
|
var init_row_identity = __esm({
|
|
27280
27642
|
"packages/core/src/store/row-identity.ts"() {
|
|
27281
27643
|
"use strict";
|
|
@@ -27284,6 +27646,7 @@ var init_row_identity = __esm({
|
|
|
27284
27646
|
init_ac_table();
|
|
27285
27647
|
init_row_identity_flag();
|
|
27286
27648
|
init_row_identity_registry();
|
|
27649
|
+
init_worktree_build_guard();
|
|
27287
27650
|
ROW_UID_DOMAIN = "cleo/row-uid/v1";
|
|
27288
27651
|
ROW_BIRTH_DOMAIN = "cleo/row-birth/v1";
|
|
27289
27652
|
ROW_UID_SQL_FUNCTION = "cleo_row_uid";
|
|
@@ -27293,7 +27656,7 @@ var init_row_identity = __esm({
|
|
|
27293
27656
|
AC_UID_GRAVEYARD = "tasks_ac_uid_graveyard";
|
|
27294
27657
|
STORE_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?)?(Z|[+-]\d{2}:?\d{2})?$/;
|
|
27295
27658
|
MAX_UUID_MS = 2 ** 48 - 1;
|
|
27296
|
-
ROW_IDENTITY_RECIPE = "cleo/row-identity/
|
|
27659
|
+
ROW_IDENTITY_RECIPE = "cleo/row-identity/v2";
|
|
27297
27660
|
ROW_IDENTITY_META_TABLE = "tasks_row_identity_meta";
|
|
27298
27661
|
ROW_IDENTITY_RECIPE_KEY = "row_identity_recipe";
|
|
27299
27662
|
ROW_IDENTITY_SYNCED_KEY = "row_identity_synced";
|
|
@@ -27338,6 +27701,15 @@ BEGIN
|
|
|
27338
27701
|
INSERT INTO ${AC_UID_GRAVEYARD} (ac_id, uid, task_id, ordinal, text, birth_fp, deleted_at)
|
|
27339
27702
|
VALUES (OLD.id, OLD.uid, OLD.task_id, OLD.ordinal, OLD.text, OLD.birth_fp, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
27340
27703
|
END`;
|
|
27704
|
+
ROW_IDENTITY_HEAL_KEY = "row_identity_schema_healed";
|
|
27705
|
+
HEAL_RECEIPT_TABLE = {
|
|
27706
|
+
project: ROW_IDENTITY_META_TABLE,
|
|
27707
|
+
// The global store declares no identity table yet (ROW_IDENTITY.global is
|
|
27708
|
+
// empty, so its heal never runs); the change that declares one adds its
|
|
27709
|
+
// meta table here.
|
|
27710
|
+
global: null
|
|
27711
|
+
};
|
|
27712
|
+
HEAL_RECEIPTS_KEPT = 20;
|
|
27341
27713
|
}
|
|
27342
27714
|
});
|
|
27343
27715
|
|
|
@@ -33031,7 +33403,7 @@ var init_task_claim = __esm({
|
|
|
33031
33403
|
});
|
|
33032
33404
|
|
|
33033
33405
|
// packages/core/src/store/converters.ts
|
|
33034
|
-
import { z as
|
|
33406
|
+
import { z as z27 } from "zod";
|
|
33035
33407
|
function readStoredAcceptance(row) {
|
|
33036
33408
|
if (row.acceptanceJson === null || row.acceptanceJson === void 0) return void 0;
|
|
33037
33409
|
try {
|
|
@@ -33189,7 +33561,7 @@ var init_converters = __esm({
|
|
|
33189
33561
|
init_src();
|
|
33190
33562
|
init_parsers();
|
|
33191
33563
|
init_task_claim();
|
|
33192
|
-
storedAcceptanceSchema =
|
|
33564
|
+
storedAcceptanceSchema = z27.custom(
|
|
33193
33565
|
(value) => Array.isArray(value) && value.every((item) => acceptanceItemSchema.safeParse(item).success)
|
|
33194
33566
|
);
|
|
33195
33567
|
}
|
|
@@ -35852,7 +36224,7 @@ import {
|
|
|
35852
36224
|
} from "node:fs";
|
|
35853
36225
|
import { createRequire as createRequire5 } from "node:module";
|
|
35854
36226
|
import { basename as basename7, dirname as dirname12, join as join13 } from "node:path";
|
|
35855
|
-
import { z as
|
|
36227
|
+
import { z as z28 } from "zod";
|
|
35856
36228
|
function formatBackupTimestamp(d) {
|
|
35857
36229
|
const pad = (n, len = 2) => String(n).padStart(len, "0");
|
|
35858
36230
|
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
@@ -35989,16 +36361,16 @@ var init_backup_sidecar = __esm({
|
|
|
35989
36361
|
init_logger2();
|
|
35990
36362
|
PRE_COLLAPSE_BACKUP_TYPE = "migration";
|
|
35991
36363
|
MARKER_PREFIX = "twin_collapse:";
|
|
35992
|
-
backupSidecarSchema =
|
|
35993
|
-
backupId:
|
|
35994
|
-
type:
|
|
35995
|
-
timestamp:
|
|
35996
|
-
note:
|
|
35997
|
-
files:
|
|
35998
|
-
pinned:
|
|
35999
|
-
pinnedReason:
|
|
36000
|
-
releasedAt:
|
|
36001
|
-
releasedReason:
|
|
36364
|
+
backupSidecarSchema = z28.object({
|
|
36365
|
+
backupId: z28.string().min(1),
|
|
36366
|
+
type: z28.string().min(1),
|
|
36367
|
+
timestamp: z28.string().min(1),
|
|
36368
|
+
note: z28.string().optional(),
|
|
36369
|
+
files: z28.array(z28.string()),
|
|
36370
|
+
pinned: z28.boolean().optional(),
|
|
36371
|
+
pinnedReason: z28.string().optional(),
|
|
36372
|
+
releasedAt: z28.string().optional(),
|
|
36373
|
+
releasedReason: z28.string().optional()
|
|
36002
36374
|
}).passthrough();
|
|
36003
36375
|
}
|
|
36004
36376
|
});
|
|
@@ -36170,7 +36542,7 @@ var init_pre_repair_snapshot = __esm({
|
|
|
36170
36542
|
import { createHash as createHash5 } from "node:crypto";
|
|
36171
36543
|
import { basename as basename8, dirname as dirname15 } from "node:path";
|
|
36172
36544
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
36173
|
-
import { z as
|
|
36545
|
+
import { z as z29 } from "zod";
|
|
36174
36546
|
function hasMainTable(db, name2) {
|
|
36175
36547
|
return db.prepare("SELECT 1 FROM main.sqlite_master WHERE type = 'table' AND name = ?").get(name2) !== void 0;
|
|
36176
36548
|
}
|
|
@@ -37303,20 +37675,20 @@ var init_twin_collapse = __esm({
|
|
|
37303
37675
|
SHADOW_WRITE_REFUSED = "E_TWIN_COLLAPSE_FAILED: store is read-only until the twin collapse succeeds; run cleo doctor twin-collapse";
|
|
37304
37676
|
SHADOW_WRITE_OPS = ["INSERT", "UPDATE", "DELETE"];
|
|
37305
37677
|
STICKY_ARCHIVE_KEY = `${TWIN_COLLAPSE_ARCHIVE_PREFIX}sticky_tags`;
|
|
37306
|
-
FocusNotesShape =
|
|
37307
|
-
StickyArchiveShape =
|
|
37308
|
-
RecoveryReceiptShape =
|
|
37309
|
-
task:
|
|
37310
|
-
id:
|
|
37311
|
-
recoveredAt:
|
|
37312
|
-
snapshot:
|
|
37313
|
-
archived:
|
|
37314
|
-
focusNotesAdded:
|
|
37315
|
-
stickyArchived:
|
|
37316
|
-
stickyArchiveKey:
|
|
37317
|
-
before:
|
|
37318
|
-
after:
|
|
37319
|
-
rolledBackAt:
|
|
37678
|
+
FocusNotesShape = z29.object({ sessionNotes: z29.array(z29.unknown()) }).passthrough();
|
|
37679
|
+
StickyArchiveShape = z29.array(z29.string());
|
|
37680
|
+
RecoveryReceiptShape = z29.object({
|
|
37681
|
+
task: z29.literal("T12727"),
|
|
37682
|
+
id: z29.string(),
|
|
37683
|
+
recoveredAt: z29.string(),
|
|
37684
|
+
snapshot: z29.string().nullable(),
|
|
37685
|
+
archived: z29.array(z29.object({ key: z29.string(), archiveKey: z29.string(), sha: z29.string() })),
|
|
37686
|
+
focusNotesAdded: z29.number(),
|
|
37687
|
+
stickyArchived: z29.array(z29.string()),
|
|
37688
|
+
stickyArchiveKey: z29.string(),
|
|
37689
|
+
before: z29.object({ focusState: z29.string().nullable(), stickyArchive: z29.string().nullable() }),
|
|
37690
|
+
after: z29.object({ focusState: z29.string().nullable(), stickyArchive: z29.string().nullable() }),
|
|
37691
|
+
rolledBackAt: z29.string().nullable()
|
|
37320
37692
|
});
|
|
37321
37693
|
}
|
|
37322
37694
|
});
|
|
@@ -40898,12 +41270,12 @@ var init_safety_data_accessor = __esm({
|
|
|
40898
41270
|
this.getSafetyOptions()
|
|
40899
41271
|
);
|
|
40900
41272
|
}
|
|
40901
|
-
async insertNewTask(task) {
|
|
41273
|
+
async insertNewTask(task, identity) {
|
|
40902
41274
|
this.logVerbose(`Inserting new task ${task.id}`);
|
|
40903
41275
|
await safeSingleTaskWrite(
|
|
40904
41276
|
this.inner,
|
|
40905
41277
|
task.id,
|
|
40906
|
-
() => this.inner.insertNewTask(task),
|
|
41278
|
+
() => this.inner.insertNewTask(task, identity),
|
|
40907
41279
|
this.cwd,
|
|
40908
41280
|
this.getSafetyOptions()
|
|
40909
41281
|
);
|
|
@@ -40951,6 +41323,9 @@ var init_safety_data_accessor = __esm({
|
|
|
40951
41323
|
return this.inner.findOrphanAcBindings();
|
|
40952
41324
|
}
|
|
40953
41325
|
// ---- Metadata (pass-through to inner) ----
|
|
41326
|
+
async getTaskIdentities(taskIds) {
|
|
41327
|
+
return await this.inner.getTaskIdentities?.(taskIds) ?? [];
|
|
41328
|
+
}
|
|
40954
41329
|
async getMetaValue(key) {
|
|
40955
41330
|
return this.inner.getMetaValue(key);
|
|
40956
41331
|
}
|
|
@@ -41324,13 +41699,147 @@ var init_cross_db_cleanup = __esm({
|
|
|
41324
41699
|
}
|
|
41325
41700
|
});
|
|
41326
41701
|
|
|
41702
|
+
// packages/core/src/store/dependency-cycles.ts
|
|
41703
|
+
function formatDependencyCycle(cycle) {
|
|
41704
|
+
return cycle.join(" \u2192 ");
|
|
41705
|
+
}
|
|
41706
|
+
function buildAdjacency(edges) {
|
|
41707
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
41708
|
+
for (const { taskId, dependsOn } of edges) {
|
|
41709
|
+
const next = adjacency.get(taskId);
|
|
41710
|
+
if (next) next.push(dependsOn);
|
|
41711
|
+
else adjacency.set(taskId, [dependsOn]);
|
|
41712
|
+
}
|
|
41713
|
+
for (const next of adjacency.values()) next.sort();
|
|
41714
|
+
return adjacency;
|
|
41715
|
+
}
|
|
41716
|
+
function shortestPath(adjacency, from, to) {
|
|
41717
|
+
if (from === to) return [from];
|
|
41718
|
+
const previous = /* @__PURE__ */ new Map([[from, from]]);
|
|
41719
|
+
const queue = [from];
|
|
41720
|
+
for (let head = 0; head < queue.length; head++) {
|
|
41721
|
+
const id = queue[head];
|
|
41722
|
+
for (const next of adjacency.get(id) ?? []) {
|
|
41723
|
+
if (previous.has(next)) continue;
|
|
41724
|
+
previous.set(next, id);
|
|
41725
|
+
if (next === to) {
|
|
41726
|
+
const path2 = [to];
|
|
41727
|
+
let cursor = id;
|
|
41728
|
+
while (cursor !== from) {
|
|
41729
|
+
path2.push(cursor);
|
|
41730
|
+
cursor = previous.get(cursor);
|
|
41731
|
+
}
|
|
41732
|
+
path2.push(from);
|
|
41733
|
+
return path2.reverse();
|
|
41734
|
+
}
|
|
41735
|
+
queue.push(next);
|
|
41736
|
+
}
|
|
41737
|
+
}
|
|
41738
|
+
return null;
|
|
41739
|
+
}
|
|
41740
|
+
function findClosedCycle(existing, edge) {
|
|
41741
|
+
if (edge.taskId === edge.dependsOn) return [edge.taskId, edge.taskId];
|
|
41742
|
+
const path2 = shortestPath(buildAdjacency(existing), edge.dependsOn, edge.taskId);
|
|
41743
|
+
return path2 ? [edge.taskId, ...path2] : null;
|
|
41744
|
+
}
|
|
41745
|
+
function dependencyCycleError(edge, cycle) {
|
|
41746
|
+
const self = edge.taskId === edge.dependsOn;
|
|
41747
|
+
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)}`;
|
|
41748
|
+
const closing = cycle.length >= 3 ? cycle[cycle.length - 2] : void 0;
|
|
41749
|
+
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}`;
|
|
41750
|
+
return new CleoError(14 /* CIRCULAR_REFERENCE */, message, {
|
|
41751
|
+
fix,
|
|
41752
|
+
details: {
|
|
41753
|
+
field: "depends",
|
|
41754
|
+
actual: edge.dependsOn,
|
|
41755
|
+
taskId: edge.taskId,
|
|
41756
|
+
cycle: [...cycle]
|
|
41757
|
+
}
|
|
41758
|
+
});
|
|
41759
|
+
}
|
|
41760
|
+
function isDependencyCycleAbort(err) {
|
|
41761
|
+
for (let e = err, depth = 0; e instanceof Error && depth < 8; depth++) {
|
|
41762
|
+
if (e.message.includes(DEPENDENCY_CYCLE_CODE)) return true;
|
|
41763
|
+
e = e.cause;
|
|
41764
|
+
}
|
|
41765
|
+
return false;
|
|
41766
|
+
}
|
|
41767
|
+
function readDependencyEdges(db) {
|
|
41768
|
+
return db.select({
|
|
41769
|
+
taskId: tasksTaskDependencies.taskId,
|
|
41770
|
+
dependsOn: tasksTaskDependencies.dependsOn
|
|
41771
|
+
}).from(tasksTaskDependencies).all();
|
|
41772
|
+
}
|
|
41773
|
+
function rethrowDependencyCycle(db, err, attempted) {
|
|
41774
|
+
if (!isDependencyCycleAbort(err)) throw err;
|
|
41775
|
+
const edges = readDependencyEdges(db);
|
|
41776
|
+
for (const edge of attempted) {
|
|
41777
|
+
const cycle = findClosedCycle(edges, edge);
|
|
41778
|
+
if (cycle) throw dependencyCycleError(edge, cycle);
|
|
41779
|
+
edges.push(edge);
|
|
41780
|
+
}
|
|
41781
|
+
throw err;
|
|
41782
|
+
}
|
|
41783
|
+
var DEPENDENCY_CYCLE_CODE;
|
|
41784
|
+
var init_dependency_cycles = __esm({
|
|
41785
|
+
"packages/core/src/store/dependency-cycles.ts"() {
|
|
41786
|
+
"use strict";
|
|
41787
|
+
init_src();
|
|
41788
|
+
init_errors2();
|
|
41789
|
+
init_tasks_schema();
|
|
41790
|
+
DEPENDENCY_CYCLE_CODE = "E_TASK_DEPENDENCY_CYCLE";
|
|
41791
|
+
}
|
|
41792
|
+
});
|
|
41793
|
+
|
|
41327
41794
|
// packages/core/src/store/db-helpers.ts
|
|
41328
41795
|
import { and as and5, eq as eq7, inArray as inArray3, sql as sql27 } from "drizzle-orm";
|
|
41329
41796
|
async function upsertTask(db, row, archiveFields, allowOrphanParent = false) {
|
|
41330
41797
|
await writeTaskRow(db, row, archiveFields, allowOrphanParent, false);
|
|
41331
41798
|
}
|
|
41332
|
-
async function insertNewTask(db, row) {
|
|
41333
|
-
await writeTaskRow(
|
|
41799
|
+
async function insertNewTask(db, row, identity = { origin: "new" }) {
|
|
41800
|
+
await writeTaskRow(
|
|
41801
|
+
db,
|
|
41802
|
+
{ ...row, ...await importedIdentity(db, identity, row) },
|
|
41803
|
+
void 0,
|
|
41804
|
+
false,
|
|
41805
|
+
true
|
|
41806
|
+
);
|
|
41807
|
+
}
|
|
41808
|
+
async function tableExists2(db, table) {
|
|
41809
|
+
const rows = await db.all(
|
|
41810
|
+
sql27`SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ${table}`
|
|
41811
|
+
);
|
|
41812
|
+
return rows.length > 0;
|
|
41813
|
+
}
|
|
41814
|
+
async function importedIdentity(db, identity, row) {
|
|
41815
|
+
if (identity.origin === "new" || !rowUidFillEnabled()) return {};
|
|
41816
|
+
const fp = identity.birthFp ?? null;
|
|
41817
|
+
const carried2 = identity.uid ?? null;
|
|
41818
|
+
if (carried2 !== null && fp !== null) {
|
|
41819
|
+
let uid = carried2;
|
|
41820
|
+
if (await tableExists2(db, "tasks_uid_aliases")) {
|
|
41821
|
+
for (let hop = 0; hop < 32; hop++) {
|
|
41822
|
+
const found = await db.all(
|
|
41823
|
+
sql27`SELECT new_uid AS uid FROM tasks_uid_aliases
|
|
41824
|
+
WHERE entity_table = 'tasks_tasks' AND old_uid = ${uid} AND old_birth_fp = ${fp}`
|
|
41825
|
+
);
|
|
41826
|
+
const next = found[0];
|
|
41827
|
+
if (!next) break;
|
|
41828
|
+
uid = next.uid;
|
|
41829
|
+
}
|
|
41830
|
+
}
|
|
41831
|
+
const [holder] = await db.select({ id: tasksTasks.id, birthFp: tasksTasks.birthFp }).from(tasksTasks).where(eq7(tasksTasks.uid, uid)).limit(1).all();
|
|
41832
|
+
if (holder && holder.birthFp === fp) throw new SameRowPresentError(row.id, holder.id);
|
|
41833
|
+
if (await tableExists2(db, "tasks_identity_quarantine")) {
|
|
41834
|
+
const [held] = await db.all(
|
|
41835
|
+
sql27`SELECT 1 AS x FROM tasks_identity_quarantine
|
|
41836
|
+
WHERE entity_table = 'tasks_tasks' AND uid = ${uid} AND birth_fp = ${fp}`
|
|
41837
|
+
);
|
|
41838
|
+
if (held) throw new SameRowPresentError(row.id, "held");
|
|
41839
|
+
}
|
|
41840
|
+
if (!holder) return { uid, birthFp: fp };
|
|
41841
|
+
}
|
|
41842
|
+
return { uid: null, birthFp: null };
|
|
41334
41843
|
}
|
|
41335
41844
|
async function writeTaskRow(db, row, archiveFields, allowOrphanParent, insertOnly) {
|
|
41336
41845
|
if (row.parentId && row.parentId === row.id) {
|
|
@@ -41481,7 +41990,11 @@ async function batchUpdateDependencies(db, tasks2, validIds) {
|
|
|
41481
41990
|
for (const depId of want) if (!have.has(depId)) added.push({ taskId, dependsOn: depId });
|
|
41482
41991
|
}
|
|
41483
41992
|
if (added.length > 0) {
|
|
41484
|
-
|
|
41993
|
+
try {
|
|
41994
|
+
await db.insert(tasksTaskDependencies).values(added).onConflictDoNothing().run();
|
|
41995
|
+
} catch (err) {
|
|
41996
|
+
rethrowDependencyCycle(db, err, added);
|
|
41997
|
+
}
|
|
41485
41998
|
}
|
|
41486
41999
|
}
|
|
41487
42000
|
async function loadDependenciesForTasks(db, tasks2, _validationIds) {
|
|
@@ -41526,15 +42039,29 @@ async function loadRelationsForTasks(db, tasks2) {
|
|
|
41526
42039
|
task.relates = relations && relations.length > 0 ? relations : [];
|
|
41527
42040
|
}
|
|
41528
42041
|
}
|
|
41529
|
-
var log6;
|
|
42042
|
+
var log6, SameRowPresentError;
|
|
41530
42043
|
var init_db_helpers = __esm({
|
|
41531
42044
|
"packages/core/src/store/db-helpers.ts"() {
|
|
41532
42045
|
"use strict";
|
|
41533
42046
|
init_src();
|
|
41534
42047
|
init_errors2();
|
|
41535
42048
|
init_logger2();
|
|
42049
|
+
init_dependency_cycles();
|
|
42050
|
+
init_row_identity_flag();
|
|
41536
42051
|
init_tasks_schema();
|
|
41537
42052
|
log6 = getLogger("db-helpers");
|
|
42053
|
+
SameRowPresentError = class extends CleoError {
|
|
42054
|
+
/** Where the row already is: its display id, or `held` when quarantined. */
|
|
42055
|
+
presentAs;
|
|
42056
|
+
constructor(taskId, presentAs) {
|
|
42057
|
+
super(
|
|
42058
|
+
22 /* ID_COLLISION */,
|
|
42059
|
+
`Task ${taskId} is already in this store (${presentAs === "held" ? "held for sync" : `as ${presentAs}`}): same uid and birth fingerprint; not written again`,
|
|
42060
|
+
{ details: { field: "taskId", actual: taskId, expected: presentAs } }
|
|
42061
|
+
);
|
|
42062
|
+
this.presentAs = presentAs;
|
|
42063
|
+
}
|
|
42064
|
+
};
|
|
41538
42065
|
}
|
|
41539
42066
|
});
|
|
41540
42067
|
|
|
@@ -41619,46 +42146,133 @@ function readProcessEntry(pid) {
|
|
|
41619
42146
|
return null;
|
|
41620
42147
|
}
|
|
41621
42148
|
}
|
|
41622
|
-
function
|
|
42149
|
+
function readProcessArgs(pid) {
|
|
42150
|
+
if (process.platform === "win32" || !Number.isInteger(pid) || pid <= 1) return null;
|
|
42151
|
+
try {
|
|
42152
|
+
const out = execFileSync("ps", ["-o", "args=", "-p", String(pid)], {
|
|
42153
|
+
encoding: "utf8",
|
|
42154
|
+
timeout: 1e3,
|
|
42155
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
42156
|
+
env: { ...process.env, ...PS_STABLE_ENV }
|
|
42157
|
+
}).trim();
|
|
42158
|
+
return out === "" ? null : out;
|
|
42159
|
+
} catch {
|
|
42160
|
+
return null;
|
|
42161
|
+
}
|
|
42162
|
+
}
|
|
42163
|
+
function baseName(token) {
|
|
42164
|
+
return token.slice(token.lastIndexOf("/") + 1).replace(/^-/, "");
|
|
42165
|
+
}
|
|
42166
|
+
function programName(commandLine) {
|
|
42167
|
+
const tokens = commandLine.trim().split(/\s+/);
|
|
42168
|
+
const head = baseName(tokens[0] ?? "");
|
|
42169
|
+
if (!RUNTIME_PATTERN.test(head)) return head;
|
|
42170
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
42171
|
+
const token = tokens[i] ?? "";
|
|
42172
|
+
if (token === "-m") return (tokens[i + 1] ?? head).split(".")[0] ?? head;
|
|
42173
|
+
if (token.startsWith("-")) continue;
|
|
42174
|
+
return baseName(token).replace(/\.(c|m)?(js|ts)$|\.py$/, "");
|
|
42175
|
+
}
|
|
42176
|
+
return head;
|
|
42177
|
+
}
|
|
42178
|
+
function isCommandStringShell(args) {
|
|
42179
|
+
const tokens = args.trim().split(/\s+/);
|
|
42180
|
+
const shell = programName(args);
|
|
42181
|
+
let first = 1;
|
|
42182
|
+
if (RUNTIME_PATTERN.test(baseName(tokens[0] ?? ""))) {
|
|
42183
|
+
while (first < tokens.length && (tokens[first] ?? "").startsWith("-")) first++;
|
|
42184
|
+
first++;
|
|
42185
|
+
}
|
|
42186
|
+
const rest = tokens.slice(first);
|
|
42187
|
+
if (shell === "pwsh" || shell === "powershell") {
|
|
42188
|
+
return rest.some((t) => PWSH_COMMAND_SWITCHES.has(t.toLowerCase()));
|
|
42189
|
+
}
|
|
42190
|
+
for (let i = 0; i < rest.length; i++) {
|
|
42191
|
+
const token = rest[i] ?? "";
|
|
42192
|
+
if (token === "--") return false;
|
|
42193
|
+
if (token === "--command" || token === "--commands") return true;
|
|
42194
|
+
if (SHELL_OPTIONS_WITH_ARGUMENT.has(token)) {
|
|
42195
|
+
i++;
|
|
42196
|
+
continue;
|
|
42197
|
+
}
|
|
42198
|
+
if (token.startsWith("--")) continue;
|
|
42199
|
+
if (!/^[-+][A-Za-z]+$/.test(token)) return false;
|
|
42200
|
+
if (token.startsWith("-") && token.slice(1).includes("c")) return true;
|
|
42201
|
+
}
|
|
42202
|
+
return false;
|
|
42203
|
+
}
|
|
42204
|
+
function resolveAncestor(ppid, lookupProcess, lookupArgs, agentId = null) {
|
|
41623
42205
|
let pid = ppid;
|
|
41624
|
-
for (let depth = 0; depth < PPID_CHAIN_MAX_DEPTH
|
|
42206
|
+
for (let depth = 0; depth < PPID_CHAIN_MAX_DEPTH; depth++) {
|
|
42207
|
+
if (pid <= 1) return null;
|
|
41625
42208
|
const entry = lookupProcess(pid);
|
|
41626
|
-
if (!entry) return null;
|
|
41627
|
-
|
|
41628
|
-
|
|
42209
|
+
if (!entry || entry.pid <= 1) return null;
|
|
42210
|
+
const args = lookupArgs(entry.pid);
|
|
42211
|
+
const program = programName(args ?? entry.command);
|
|
42212
|
+
if (INIT_PROCESSES.has(program) || INIT_PROCESSES.has(entry.command)) return null;
|
|
42213
|
+
if (OWNER_PROCESS_SHELLS.has(program)) {
|
|
42214
|
+
if (args === null) return null;
|
|
42215
|
+
if (!isCommandStringShell(args)) return { entry, program, type: "shell" };
|
|
42216
|
+
} else if (!ANCESTOR_WRAPPERS.has(program)) {
|
|
42217
|
+
if (KNOWN_HARNESSES.has(program)) return { entry, program, type: "harness" };
|
|
42218
|
+
return agentId ? { entry, program, type: "host" } : null;
|
|
41629
42219
|
}
|
|
41630
42220
|
pid = entry.ppid;
|
|
41631
42221
|
}
|
|
41632
42222
|
return null;
|
|
41633
42223
|
}
|
|
42224
|
+
function anchorKey(anchor, agentId, under) {
|
|
42225
|
+
const proc = `${anchor.entry.pid}@${anchor.entry.startedAt}`;
|
|
42226
|
+
if (anchor.type === "shell" && !agentId) {
|
|
42227
|
+
return { key: `proc:${proc}`, source: "process", kind: "process" };
|
|
42228
|
+
}
|
|
42229
|
+
const agent = agentId ? `#agent=${agentId}` : "";
|
|
42230
|
+
const scope = under ? `|${under.key}` : "";
|
|
42231
|
+
return {
|
|
42232
|
+
key: `harness:${anchor.program}:${proc}${agent}${scope}`,
|
|
42233
|
+
source: "process",
|
|
42234
|
+
kind: "harness"
|
|
42235
|
+
};
|
|
42236
|
+
}
|
|
41634
42237
|
function resolveTerminalKeys(options = {}) {
|
|
41635
42238
|
const env = options.env ?? process.env;
|
|
41636
42239
|
const keys = [];
|
|
41637
42240
|
for (const source of TERMINAL_KEY_SOURCES) {
|
|
41638
42241
|
const value = envValue(env, source.envVar);
|
|
41639
42242
|
if (value === null) continue;
|
|
41640
|
-
const
|
|
42243
|
+
const qualifiers = [source.qualifierEnvVar, ...source.extraQualifierEnvVars ?? []].map((name2) => envValue(env, name2)).filter((q2) => q2 !== null);
|
|
41641
42244
|
keys.push({
|
|
41642
|
-
key: `env:${source.envVar}=${
|
|
42245
|
+
key: `env:${source.envVar}=${[...qualifiers, value].join("|")}`,
|
|
41643
42246
|
source: source.envVar,
|
|
41644
42247
|
kind: source.kind
|
|
41645
42248
|
});
|
|
41646
42249
|
}
|
|
41647
|
-
if (keys.
|
|
41648
|
-
const
|
|
41649
|
-
|
|
42250
|
+
if (keys.some((k) => k.kind === "provider")) return keys;
|
|
42251
|
+
const agentId = envValue(env, "CLEO_AGENT_ID");
|
|
42252
|
+
const live = options.ppid === void 0 && options.lookupProcess === void 0 && options.lookupArgs === void 0;
|
|
42253
|
+
let anchor;
|
|
41650
42254
|
if (live) {
|
|
41651
|
-
|
|
41652
|
-
|
|
42255
|
+
const memoKey2 = agentId ?? "";
|
|
42256
|
+
if (!liveAnchors.has(memoKey2))
|
|
42257
|
+
liveAnchors.set(
|
|
42258
|
+
memoKey2,
|
|
42259
|
+
resolveAncestor(process.ppid, readProcessEntry, readProcessArgs, agentId)
|
|
42260
|
+
);
|
|
42261
|
+
anchor = liveAnchors.get(memoKey2) ?? null;
|
|
41653
42262
|
} else {
|
|
41654
|
-
|
|
42263
|
+
anchor = resolveAncestor(
|
|
41655
42264
|
options.ppid ?? process.ppid,
|
|
41656
|
-
options.lookupProcess ?? readProcessEntry
|
|
42265
|
+
options.lookupProcess ?? readProcessEntry,
|
|
42266
|
+
options.lookupArgs ?? readProcessArgs,
|
|
42267
|
+
agentId
|
|
41657
42268
|
);
|
|
41658
42269
|
}
|
|
41659
|
-
|
|
42270
|
+
if (!anchor) return keys;
|
|
42271
|
+
if (keys.length === 0) return [anchorKey(anchor, agentId, void 0)];
|
|
42272
|
+
if (anchor.type === "shell" && !agentId) return keys;
|
|
42273
|
+
return [...keys, anchorKey(anchor, agentId, keys[0])];
|
|
41660
42274
|
}
|
|
41661
|
-
var TERMINAL_KEY_SOURCES,
|
|
42275
|
+
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
42276
|
var init_terminal_identity = __esm({
|
|
41663
42277
|
"packages/core/src/sessions/terminal-identity.ts"() {
|
|
41664
42278
|
"use strict";
|
|
@@ -41690,24 +42304,100 @@ var init_terminal_identity = __esm({
|
|
|
41690
42304
|
kind: "terminal",
|
|
41691
42305
|
origin: "konsole",
|
|
41692
42306
|
qualifierEnvVar: "KONSOLE_DBUS_SERVICE"
|
|
42307
|
+
},
|
|
42308
|
+
// T12864 — non-terminal callers whose platform exports a per-job / per-login id.
|
|
42309
|
+
// GitHub Actions: GITHUB_RUN_ID is per run and shared by its jobs, so it is
|
|
42310
|
+
// qualified by GITHUB_RUN_ATTEMPT and GITHUB_JOB ("Variables reference",
|
|
42311
|
+
// docs.github.com/en/actions/reference/workflows-and-actions/variables).
|
|
42312
|
+
// Every step of one job shares the key; the steps run sequentially.
|
|
42313
|
+
{
|
|
42314
|
+
envVar: "GITHUB_RUN_ID",
|
|
42315
|
+
kind: "terminal",
|
|
42316
|
+
origin: "github-actions",
|
|
42317
|
+
qualifierEnvVar: "GITHUB_RUN_ATTEMPT",
|
|
42318
|
+
extraQualifierEnvVars: ["GITHUB_JOB"]
|
|
42319
|
+
},
|
|
42320
|
+
// GitLab CI: CI_JOB_ID is unique per job across the instance ("Predefined
|
|
42321
|
+
// CI/CD variables reference", docs.gitlab.com/ci/variables/predefined_variables).
|
|
42322
|
+
{ envVar: "CI_JOB_ID", kind: "terminal", origin: "gitlab-ci" },
|
|
42323
|
+
// OpenSSH login with a tty: SSH_TTY names the login's tty and is set only
|
|
42324
|
+
// when one was allocated; SSH_CONNECTION ("client-ip client-port server-ip
|
|
42325
|
+
// server-port", ssh(1) ENVIRONMENT) disambiguates it across connections. A
|
|
42326
|
+
// one-shot `ssh host 'cmd'` has no tty and falls through to the ancestor walk.
|
|
42327
|
+
{
|
|
42328
|
+
envVar: "SSH_TTY",
|
|
42329
|
+
kind: "terminal",
|
|
42330
|
+
origin: "openssh",
|
|
42331
|
+
qualifierEnvVar: "SSH_CONNECTION"
|
|
41693
42332
|
}
|
|
41694
42333
|
];
|
|
41695
|
-
|
|
41696
|
-
|
|
42334
|
+
PPID_CHAIN_MAX_DEPTH = 12;
|
|
42335
|
+
KNOWN_HARNESSES = /* @__PURE__ */ new Set([
|
|
42336
|
+
"claude",
|
|
42337
|
+
"codex",
|
|
42338
|
+
"aider",
|
|
42339
|
+
"gemini",
|
|
42340
|
+
"kimi",
|
|
42341
|
+
"cursor-agent",
|
|
42342
|
+
"amp"
|
|
42343
|
+
]);
|
|
42344
|
+
RUNTIME_PATTERN = /^(node|nodejs|bun|deno|python[0-9.]*|pypy[0-9.]*|ruby|java|php|perl)$/;
|
|
42345
|
+
ANCESTOR_WRAPPERS = /* @__PURE__ */ new Set([
|
|
42346
|
+
"env",
|
|
42347
|
+
"timeout",
|
|
42348
|
+
"gtimeout",
|
|
42349
|
+
"nohup",
|
|
42350
|
+
"nice",
|
|
42351
|
+
"time",
|
|
42352
|
+
"xargs",
|
|
42353
|
+
"stdbuf",
|
|
42354
|
+
"sudo",
|
|
42355
|
+
"doas",
|
|
41697
42356
|
"npm",
|
|
42357
|
+
"npm-cli",
|
|
41698
42358
|
"npx",
|
|
42359
|
+
"npx-cli",
|
|
41699
42360
|
"pnpm",
|
|
41700
42361
|
"pnpx",
|
|
41701
42362
|
"yarn",
|
|
41702
|
-
"bun",
|
|
41703
42363
|
"bunx",
|
|
41704
|
-
"tsx",
|
|
41705
42364
|
"corepack",
|
|
41706
42365
|
"mise",
|
|
41707
|
-
"env",
|
|
41708
42366
|
"cleo"
|
|
41709
42367
|
]);
|
|
41710
|
-
|
|
42368
|
+
INIT_PROCESSES = /* @__PURE__ */ new Set(["launchd", "systemd", "init"]);
|
|
42369
|
+
SHELL_OPTIONS_WITH_ARGUMENT = /* @__PURE__ */ new Set([
|
|
42370
|
+
"-o",
|
|
42371
|
+
"+o",
|
|
42372
|
+
"-O",
|
|
42373
|
+
"+O",
|
|
42374
|
+
"--rcfile",
|
|
42375
|
+
"--init-file"
|
|
42376
|
+
]);
|
|
42377
|
+
PWSH_COMMAND_SWITCHES = /* @__PURE__ */ new Set([
|
|
42378
|
+
"-c",
|
|
42379
|
+
"-command",
|
|
42380
|
+
"-commandwithargs",
|
|
42381
|
+
"-cwa",
|
|
42382
|
+
"-e",
|
|
42383
|
+
"-ec",
|
|
42384
|
+
"-encodedcommand"
|
|
42385
|
+
]);
|
|
42386
|
+
OWNER_PROCESS_SHELLS = /* @__PURE__ */ new Set([
|
|
42387
|
+
"sh",
|
|
42388
|
+
"bash",
|
|
42389
|
+
"zsh",
|
|
42390
|
+
"dash",
|
|
42391
|
+
"fish",
|
|
42392
|
+
"ksh",
|
|
42393
|
+
"tcsh",
|
|
42394
|
+
"csh",
|
|
42395
|
+
"pwsh",
|
|
42396
|
+
"powershell",
|
|
42397
|
+
"nu",
|
|
42398
|
+
"xonsh"
|
|
42399
|
+
]);
|
|
42400
|
+
liveAnchors = /* @__PURE__ */ new Map();
|
|
41711
42401
|
}
|
|
41712
42402
|
});
|
|
41713
42403
|
|
|
@@ -41747,7 +42437,8 @@ var init_session_binding_schema = __esm({
|
|
|
41747
42437
|
});
|
|
41748
42438
|
|
|
41749
42439
|
// packages/core/src/store/session-store.ts
|
|
41750
|
-
import {
|
|
42440
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
42441
|
+
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
42442
|
async function getSession(sessionId, cwd) {
|
|
41752
42443
|
const scope = captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
|
|
41753
42444
|
return worktreeScope.run(scope, async () => {
|
|
@@ -41769,8 +42460,9 @@ async function getActiveSession(cwd) {
|
|
|
41769
42460
|
function splitTerminalKeys(keys) {
|
|
41770
42461
|
return {
|
|
41771
42462
|
provider: keys.find((k) => k.kind === "provider"),
|
|
41772
|
-
|
|
41773
|
-
|
|
42463
|
+
// A harness / CLEO_AGENT_ID agent (T12864) is more specific than a pane.
|
|
42464
|
+
pane: keys.find((k) => k.kind === "harness") ?? keys.find((k) => k.kind === "multiplexer"),
|
|
42465
|
+
tab: keys.find((k) => k.kind === "terminal" || k.kind === "process" || k.kind === "ppid")
|
|
41774
42466
|
};
|
|
41775
42467
|
}
|
|
41776
42468
|
async function readBinding(db, key) {
|
|
@@ -41850,6 +42542,7 @@ async function resolveCurrentSession(cwd) {
|
|
|
41850
42542
|
async function resolveBoundSession(cwd) {
|
|
41851
42543
|
const scope = captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
|
|
41852
42544
|
return worktreeScope.run(scope, async () => {
|
|
42545
|
+
if (!existsSync19(getDbPath(scope.worktreeRoot))) return null;
|
|
41853
42546
|
const connId = getCurrentConnectionSessionId();
|
|
41854
42547
|
if (connId) {
|
|
41855
42548
|
const byConn = await getSession(connId, scope.worktreeRoot);
|
|
@@ -42001,7 +42694,7 @@ __export(registry_exports2, {
|
|
|
42001
42694
|
updateAgentStatus: () => updateAgentStatus
|
|
42002
42695
|
});
|
|
42003
42696
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
42004
|
-
import { and as and7, eq as eq9, inArray as
|
|
42697
|
+
import { and as and7, eq as eq9, inArray as inArray5, lt as lt2, sql as sql29 } from "drizzle-orm";
|
|
42005
42698
|
function generateAgentId() {
|
|
42006
42699
|
const now = /* @__PURE__ */ new Date();
|
|
42007
42700
|
const ts = now.toISOString().replace(/[-:T]/g, "").substring(0, 14);
|
|
@@ -42090,11 +42783,11 @@ async function listAgentInstances(filters, cwd) {
|
|
|
42090
42783
|
const conditions = [];
|
|
42091
42784
|
if (filters?.status) {
|
|
42092
42785
|
const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
|
|
42093
|
-
conditions.push(
|
|
42786
|
+
conditions.push(inArray5(agentInstances.status, statuses));
|
|
42094
42787
|
}
|
|
42095
42788
|
if (filters?.agentType) {
|
|
42096
42789
|
const types = Array.isArray(filters.agentType) ? filters.agentType : [filters.agentType];
|
|
42097
|
-
conditions.push(
|
|
42790
|
+
conditions.push(inArray5(agentInstances.agentType, types));
|
|
42098
42791
|
}
|
|
42099
42792
|
if (filters?.sessionId) {
|
|
42100
42793
|
conditions.push(eq9(agentInstances.sessionId, filters.sessionId));
|
|
@@ -42131,7 +42824,7 @@ async function checkAgentHealth(thresholdMs = 3e4, cwd) {
|
|
|
42131
42824
|
const cutoff = new Date(Date.now() - thresholdMs).toISOString();
|
|
42132
42825
|
return db.select().from(agentInstances).where(
|
|
42133
42826
|
and7(
|
|
42134
|
-
|
|
42827
|
+
inArray5(agentInstances.status, ["active", "idle", "starting"]),
|
|
42135
42828
|
lt2(agentInstances.lastHeartbeat, cutoff)
|
|
42136
42829
|
)
|
|
42137
42830
|
).all();
|
|
@@ -42226,12 +42919,14 @@ var init_registry2 = __esm({
|
|
|
42226
42919
|
// packages/core/src/store/sqlite-data-accessor.ts
|
|
42227
42920
|
var sqlite_data_accessor_exports = {};
|
|
42228
42921
|
__export(sqlite_data_accessor_exports, {
|
|
42922
|
+
RENAMED_RECENT_MS: () => RENAMED_RECENT_MS,
|
|
42229
42923
|
addTaskLabelsNative: () => addTaskLabelsNative,
|
|
42230
42924
|
advanceTaskIdSequence: () => advanceTaskIdSequence,
|
|
42231
42925
|
bindTaskAccessorScope: () => bindTaskAccessorScope,
|
|
42232
42926
|
captureTaskAccessorScope: () => captureProjectScope,
|
|
42233
42927
|
clearAcUidGraveyardNative: () => clearAcUidGraveyardNative,
|
|
42234
42928
|
clearBirthFpNative: () => clearBirthFpNative,
|
|
42929
|
+
clearReplacedTaskIdentityNative: () => clearReplacedTaskIdentityNative,
|
|
42235
42930
|
clearRowUidNative: () => clearRowUidNative,
|
|
42236
42931
|
createSqliteDataAccessor: () => createSqliteDataAccessor,
|
|
42237
42932
|
deleteDisplayIdAliasNative: () => deleteDisplayIdAliasNative,
|
|
@@ -42242,6 +42937,7 @@ __export(sqlite_data_accessor_exports, {
|
|
|
42242
42937
|
insertIdentityRowNative: () => insertIdentityRowNative,
|
|
42243
42938
|
insertQuarantineNative: () => insertQuarantineNative,
|
|
42244
42939
|
insertUidAliasNative: () => insertUidAliasNative,
|
|
42940
|
+
readReplacedTaskBirthNative: () => readReplacedTaskBirthNative,
|
|
42245
42941
|
rederiveAcIdsNative: () => rederiveAcIdsNative,
|
|
42246
42942
|
rekeyQuarantineNative: () => rekeyQuarantineNative,
|
|
42247
42943
|
relinkAcUidNative: () => relinkAcUidNative,
|
|
@@ -42258,7 +42954,7 @@ import {
|
|
|
42258
42954
|
and as and8,
|
|
42259
42955
|
eq as eq10,
|
|
42260
42956
|
getTableColumns as getTableColumns2,
|
|
42261
|
-
inArray as
|
|
42957
|
+
inArray as inArray6,
|
|
42262
42958
|
isNull as isNull4,
|
|
42263
42959
|
like as like2,
|
|
42264
42960
|
lte as lte3,
|
|
@@ -42282,8 +42978,8 @@ async function selectAcBindings(db, acIds) {
|
|
|
42282
42978
|
bindingType: b.bindingType,
|
|
42283
42979
|
createdAt: b.createdAt
|
|
42284
42980
|
};
|
|
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(
|
|
42981
|
+
const byUid = await db.select(columns).from(b).innerJoin(ac, eq10(ac.uid, b.acUid)).where(inArray6(ac.id, ids)).all();
|
|
42982
|
+
const byId = await db.select(columns).from(b).leftJoin(ac, eq10(ac.uid, b.acUid)).where(inArray6(b.acId, ids)).all();
|
|
42287
42983
|
const rows = [...byUid, ...byId];
|
|
42288
42984
|
const wanted = new Set(ids);
|
|
42289
42985
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -42376,6 +43072,7 @@ function renameTaskDisplayIdNative(nativeDb, uid, toId, refs, guard = {}) {
|
|
|
42376
43072
|
if (Number(changed) !== 1) {
|
|
42377
43073
|
throw taskConflictError(current.id, taskVersion(current), null);
|
|
42378
43074
|
}
|
|
43075
|
+
recordLocalRename(nativeDb, uid, current.id, toId, taskVersion(current));
|
|
42379
43076
|
const rewritten = {};
|
|
42380
43077
|
const q2 = (name2) => `"${name2.replaceAll('"', '""')}"`;
|
|
42381
43078
|
for (const ref of refs) {
|
|
@@ -42431,23 +43128,39 @@ function rederiveAcIdsNative(nativeDb, fromId, toId) {
|
|
|
42431
43128
|
}
|
|
42432
43129
|
return count;
|
|
42433
43130
|
}
|
|
42434
|
-
function insertDisplayIdAliasNative(nativeDb, row) {
|
|
43131
|
+
function insertDisplayIdAliasNative(nativeDb, row, precedes) {
|
|
43132
|
+
const stored = nativeDb.prepare(
|
|
43133
|
+
`SELECT uid, entity_table AS entityTable, display_id AS displayId, entity_uid AS entityUid,
|
|
43134
|
+
reason, origin, displaced_hlc AS displacedHlc, created_at AS createdAt,
|
|
43135
|
+
entity_birth_fp AS entityBirthFp
|
|
43136
|
+
FROM tasks_display_id_aliases WHERE uid = ?`
|
|
43137
|
+
).get(row.uid);
|
|
43138
|
+
if (!stored) {
|
|
43139
|
+
nativeDb.prepare(
|
|
43140
|
+
`INSERT INTO tasks_display_id_aliases
|
|
43141
|
+
(uid, entity_table, display_id, entity_uid, reason, origin, displaced_hlc, created_at,
|
|
43142
|
+
entity_birth_fp)
|
|
43143
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
43144
|
+
).run(
|
|
43145
|
+
row.uid,
|
|
43146
|
+
row.entityTable,
|
|
43147
|
+
row.displayId,
|
|
43148
|
+
row.entityUid,
|
|
43149
|
+
row.reason,
|
|
43150
|
+
row.origin,
|
|
43151
|
+
row.displacedHlc,
|
|
43152
|
+
row.createdAt,
|
|
43153
|
+
row.entityBirthFp
|
|
43154
|
+
);
|
|
43155
|
+
return;
|
|
43156
|
+
}
|
|
43157
|
+
if (!precedes(row, stored)) return;
|
|
42435
43158
|
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
|
-
);
|
|
43159
|
+
`UPDATE tasks_display_id_aliases
|
|
43160
|
+
SET origin = ?, displaced_hlc = ?, created_at = ?,
|
|
43161
|
+
entity_birth_fp = coalesce(entity_birth_fp, ?)
|
|
43162
|
+
WHERE uid = ?`
|
|
43163
|
+
).run(row.origin, row.displacedHlc, row.createdAt, row.entityBirthFp, row.uid);
|
|
42451
43164
|
}
|
|
42452
43165
|
function deleteDisplayIdAliasNative(nativeDb, uid) {
|
|
42453
43166
|
nativeDb.prepare("DELETE FROM tasks_display_id_aliases WHERE uid = ?").run(uid);
|
|
@@ -42509,6 +43222,63 @@ function relinkAcUidNative(nativeDb, acId, uid, birthFp) {
|
|
|
42509
43222
|
function clearAcUidGraveyardNative(nativeDb) {
|
|
42510
43223
|
nativeDb.exec("DELETE FROM tasks_ac_uid_graveyard");
|
|
42511
43224
|
}
|
|
43225
|
+
function readReplacedTaskBirthNative(nativeDb, taskId) {
|
|
43226
|
+
return nativeDb.prepare("SELECT created_at AS createdAt, uid FROM tasks_tasks WHERE id = ?").get(taskId);
|
|
43227
|
+
}
|
|
43228
|
+
function clearReplacedTaskIdentityNative(nativeDb, taskId, before) {
|
|
43229
|
+
const row = nativeDb.prepare("SELECT uid, birth_fp AS fp, created_at AS createdAt FROM tasks_tasks WHERE id = ?").get(taskId);
|
|
43230
|
+
if (!row || row.uid === null && row.fp === null) return;
|
|
43231
|
+
if (before) {
|
|
43232
|
+
const was = parseStoreTimestamp(before.createdAt);
|
|
43233
|
+
if (was !== null && was === parseStoreTimestamp(row.createdAt)) {
|
|
43234
|
+
return;
|
|
43235
|
+
}
|
|
43236
|
+
}
|
|
43237
|
+
if (rowIdentityShared(nativeDb)) {
|
|
43238
|
+
throw new CleoError(
|
|
43239
|
+
6 /* VALIDATION_ERROR */,
|
|
43240
|
+
`Task ${taskId} cannot be overwritten by an import: its identity is shared with other devices`,
|
|
43241
|
+
{
|
|
43242
|
+
fix: "Import it under a new id (the default duplicate strategy), or edit the task instead of overwriting it.",
|
|
43243
|
+
details: { field: "taskId", actual: taskId }
|
|
43244
|
+
}
|
|
43245
|
+
);
|
|
43246
|
+
}
|
|
43247
|
+
const has = (table) => nativeDb.prepare("SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) !== void 0;
|
|
43248
|
+
nativeDb.prepare("UPDATE tasks_tasks SET uid = NULL, birth_fp = NULL WHERE id = ?").run(taskId);
|
|
43249
|
+
for (const spec of ROW_IDENTITY.project) {
|
|
43250
|
+
if (spec.kind !== "natural" || !has(spec.table)) continue;
|
|
43251
|
+
const cols = (spec.keyRefs ?? []).filter((r) => r.table === "tasks_tasks").map((r) => r.column);
|
|
43252
|
+
if (cols.length === 0) continue;
|
|
43253
|
+
nativeDb.prepare(
|
|
43254
|
+
`UPDATE main.${quoteIdent2(spec.table)} SET uid = NULL WHERE ${cols.map((c) => `${quoteIdent2(c)} = ?`).join(" OR ")}`
|
|
43255
|
+
).run(...cols.map(() => taskId));
|
|
43256
|
+
}
|
|
43257
|
+
const children = ["tasks_task_acceptance_criteria_history", "tasks_evidence_ac_bindings"].filter(
|
|
43258
|
+
has
|
|
43259
|
+
);
|
|
43260
|
+
const criteria = has("tasks_task_acceptance_criteria") ? nativeDb.prepare("SELECT id, uid FROM tasks_task_acceptance_criteria WHERE task_id = ?").all(taskId) : [];
|
|
43261
|
+
if (criteria.length > 0) {
|
|
43262
|
+
nativeDb.prepare(
|
|
43263
|
+
"UPDATE tasks_task_acceptance_criteria SET uid = NULL, birth_fp = NULL WHERE task_id = ?"
|
|
43264
|
+
).run(taskId);
|
|
43265
|
+
}
|
|
43266
|
+
fillRowUids(nativeDb, "project");
|
|
43267
|
+
const newUid = nativeDb.prepare("SELECT uid FROM tasks_task_acceptance_criteria WHERE id = ?");
|
|
43268
|
+
let rekeyed = 0;
|
|
43269
|
+
for (const ac of criteria) {
|
|
43270
|
+
const now = newUid.get(ac.id)?.uid ?? null;
|
|
43271
|
+
for (const table of children) {
|
|
43272
|
+
rekeyed += Number(
|
|
43273
|
+
nativeDb.prepare(
|
|
43274
|
+
`UPDATE main.${quoteIdent2(table)} SET ac_uid = ?, birth_fp = NULL
|
|
43275
|
+
WHERE ac_id = ? OR (? IS NOT NULL AND ac_uid = ?)`
|
|
43276
|
+
).run(now, ac.id, ac.uid, ac.uid).changes
|
|
43277
|
+
);
|
|
43278
|
+
}
|
|
43279
|
+
}
|
|
43280
|
+
if (rekeyed > 0) fillRowUids(nativeDb, "project");
|
|
43281
|
+
}
|
|
42512
43282
|
function quoteIdent2(name2) {
|
|
42513
43283
|
return `"${name2.replaceAll('"', '""')}"`;
|
|
42514
43284
|
}
|
|
@@ -42596,10 +43366,50 @@ function claimPredicate(guard, allowedHolders) {
|
|
|
42596
43366
|
if (guard.mode === "force") return void 0;
|
|
42597
43367
|
const mine = guard.sessionId === null ? void 0 : eq10(holder, guard.sessionId);
|
|
42598
43368
|
if (guard.mode === "renew" || guard.mode === "release") return mine ?? sql30`0`;
|
|
42599
|
-
const related = allowedHolders.length > 0 ?
|
|
43369
|
+
const related = allowedHolders.length > 0 ? inArray6(holder, [...allowedHolders]) : void 0;
|
|
42600
43370
|
const expired = guard.mode === "take-over" ? or5(isNull4(tasksTasks.leaseExpiresAt), lte3(tasksTasks.leaseExpiresAt, guard.now)) : void 0;
|
|
42601
43371
|
return or5(isNull4(holder), mine, related, expired);
|
|
42602
43372
|
}
|
|
43373
|
+
function renameRecordKey(fromId) {
|
|
43374
|
+
return `renamed_from:tasks_tasks:${fromId}`;
|
|
43375
|
+
}
|
|
43376
|
+
function hasIdentityMeta(nativeDb) {
|
|
43377
|
+
return nativeDb.prepare(
|
|
43378
|
+
"SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = 'tasks_row_identity_meta'"
|
|
43379
|
+
).get() !== void 0;
|
|
43380
|
+
}
|
|
43381
|
+
function recordLocalRename(nativeDb, uid, fromId, toId, fromVersion) {
|
|
43382
|
+
if (!hasIdentityMeta(nativeDb)) return;
|
|
43383
|
+
const record = { uid, fromVersion, toId, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
43384
|
+
writeRowIdentityMetaNative(nativeDb, renameRecordKey(fromId), JSON.stringify(record));
|
|
43385
|
+
}
|
|
43386
|
+
function assertNotRenamed(nativeDb, taskId, guard, current) {
|
|
43387
|
+
if (!nativeDb || !hasIdentityMeta(nativeDb)) return;
|
|
43388
|
+
const raw = nativeDb.prepare("SELECT value FROM tasks_row_identity_meta WHERE key = ?").get(renameRecordKey(taskId));
|
|
43389
|
+
if (!raw) return;
|
|
43390
|
+
let record;
|
|
43391
|
+
try {
|
|
43392
|
+
record = JSON.parse(raw.value);
|
|
43393
|
+
} catch {
|
|
43394
|
+
return;
|
|
43395
|
+
}
|
|
43396
|
+
if (Date.now() - Date.parse(record.at) > RENAMED_RECENT_MS) return;
|
|
43397
|
+
const renamed = nativeDb.prepare("SELECT id, claimed_by_session AS claimedBySession FROM tasks_tasks WHERE uid = ?").get(record.uid);
|
|
43398
|
+
if (!renamed || renamed.id === taskId) return;
|
|
43399
|
+
const expected = guard.expectedUpdatedAt;
|
|
43400
|
+
const session = guard.claim?.sessionId ?? null;
|
|
43401
|
+
const holdsRenamedClaim = session !== null && (guard.claim?.mode === "renew" || guard.claim?.mode === "release") && renamed.claimedBySession === session && current?.claimedBySession !== session;
|
|
43402
|
+
const readRenamed = expected !== void 0 && expected === record.fromVersion && (current === void 0 || taskVersion(current) !== expected);
|
|
43403
|
+
if (!(current === void 0 || holdsRenamedClaim || readRenamed)) return;
|
|
43404
|
+
throw new CleoError(
|
|
43405
|
+
26 /* TASK_RENAMED */,
|
|
43406
|
+
`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`,
|
|
43407
|
+
{
|
|
43408
|
+
fix: `Re-read it with 'cleo show ${renamed.id}' and retry against ${renamed.id}.`,
|
|
43409
|
+
details: { field: "taskId", actual: taskId, expected: renamed.id }
|
|
43410
|
+
}
|
|
43411
|
+
);
|
|
43412
|
+
}
|
|
42603
43413
|
function assertClaimAllowed(taskId, row, guard, allowedHolders) {
|
|
42604
43414
|
const stored = claimFromColumns(row);
|
|
42605
43415
|
if (claimAllows(stored, guard.mode, guard.sessionId, guard.now, allowedHolders)) return;
|
|
@@ -42774,13 +43584,13 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
42774
43584
|
const db = await getDb(cwd);
|
|
42775
43585
|
const conditions = [];
|
|
42776
43586
|
if (query.ids && query.ids.length > 0) {
|
|
42777
|
-
conditions.push(
|
|
43587
|
+
conditions.push(inArray6(tasksAuditLog.id, [...query.ids]));
|
|
42778
43588
|
}
|
|
42779
43589
|
if (query.taskIds && query.taskIds.length > 0) {
|
|
42780
|
-
conditions.push(
|
|
43590
|
+
conditions.push(inArray6(tasksAuditLog.taskId, [...query.taskIds]));
|
|
42781
43591
|
}
|
|
42782
43592
|
if (query.actions && query.actions.length > 0) {
|
|
42783
|
-
conditions.push(
|
|
43593
|
+
conditions.push(inArray6(tasksAuditLog.action, [...query.actions]));
|
|
42784
43594
|
}
|
|
42785
43595
|
if (query.since) {
|
|
42786
43596
|
conditions.push(sql30`${tasksAuditLog.timestamp} >= ${query.since}`);
|
|
@@ -42813,8 +43623,13 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
42813
43623
|
async upsertSingleTask(task) {
|
|
42814
43624
|
await accessor.transaction((tx) => tx.upsertSingleTask(task));
|
|
42815
43625
|
},
|
|
42816
|
-
async insertNewTask(task) {
|
|
42817
|
-
await accessor.transaction((tx) => tx.insertNewTask(task));
|
|
43626
|
+
async insertNewTask(task, identity) {
|
|
43627
|
+
await accessor.transaction((tx) => tx.insertNewTask(task, identity));
|
|
43628
|
+
},
|
|
43629
|
+
async getTaskIdentities(taskIds) {
|
|
43630
|
+
if (taskIds.length === 0) return [];
|
|
43631
|
+
const db = await getDb(cwd);
|
|
43632
|
+
return db.select({ id: tasksTasks.id, uid: tasksTasks.uid, birthFp: tasksTasks.birthFp }).from(tasksTasks).where(inArray6(tasksTasks.id, taskIds)).all();
|
|
42818
43633
|
},
|
|
42819
43634
|
async addRelation(taskId, relatedTo, relationType, reason) {
|
|
42820
43635
|
return accessor.transaction(async () => {
|
|
@@ -42991,7 +43806,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
42991
43806
|
if (!statuses.includes("archived")) {
|
|
42992
43807
|
conditions.push(ne2(tasksTasks.status, "archived"));
|
|
42993
43808
|
}
|
|
42994
|
-
conditions.push(
|
|
43809
|
+
conditions.push(inArray6(tasksTasks.status, statuses));
|
|
42995
43810
|
} else if (filters.excludeStatus) {
|
|
42996
43811
|
const excluded = Array.isArray(filters.excludeStatus) ? filters.excludeStatus : [filters.excludeStatus];
|
|
42997
43812
|
for (const s of excluded) {
|
|
@@ -43005,11 +43820,11 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43005
43820
|
if (filters.phase) conditions.push(eq10(tasksTasks.phase, filters.phase));
|
|
43006
43821
|
if (filters.severity) {
|
|
43007
43822
|
const severities = Array.isArray(filters.severity) ? filters.severity : [filters.severity];
|
|
43008
|
-
conditions.push(
|
|
43823
|
+
conditions.push(inArray6(tasksTasks.severity, severities));
|
|
43009
43824
|
}
|
|
43010
43825
|
if (filters.kind) {
|
|
43011
43826
|
const kinds = Array.isArray(filters.kind) ? filters.kind : [filters.kind];
|
|
43012
|
-
conditions.push(
|
|
43827
|
+
conditions.push(inArray6(tasksTasks.kind, kinds));
|
|
43013
43828
|
}
|
|
43014
43829
|
if (filters.parentId !== void 0) {
|
|
43015
43830
|
if (filters.parentId === null) {
|
|
@@ -43030,7 +43845,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43030
43845
|
}
|
|
43031
43846
|
if (filters.label) {
|
|
43032
43847
|
const labelMatchIds = db.select({ taskId: tasksTaskLabels.taskId }).from(tasksTaskLabels).where(eq10(tasksTaskLabels.label, filters.label));
|
|
43033
|
-
conditions.push(
|
|
43848
|
+
conditions.push(inArray6(tasksTasks.id, labelMatchIds));
|
|
43034
43849
|
}
|
|
43035
43850
|
const where = conditions.length > 0 ? and8(...conditions) : void 0;
|
|
43036
43851
|
const countResult = await db.select({ count: sql30`count(*)` }).from(tasksTasks).where(where).get();
|
|
@@ -43073,7 +43888,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43073
43888
|
const conditions = [];
|
|
43074
43889
|
if (filters?.status) {
|
|
43075
43890
|
const statuses = Array.isArray(filters.status) ? filters.status : [filters.status];
|
|
43076
|
-
conditions.push(
|
|
43891
|
+
conditions.push(inArray6(tasksTasks.status, statuses));
|
|
43077
43892
|
} else {
|
|
43078
43893
|
conditions.push(ne2(tasksTasks.status, "archived"));
|
|
43079
43894
|
}
|
|
@@ -43138,7 +43953,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43138
43953
|
if (idRows.length === 0) return [];
|
|
43139
43954
|
const db = await getDb(cwd);
|
|
43140
43955
|
const ids = idRows.map((r) => r.id);
|
|
43141
|
-
const taskRows = await db.select().from(tasksTasks).where(
|
|
43956
|
+
const taskRows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, ids)).all();
|
|
43142
43957
|
const tasks2 = taskRows.map(rowToTask);
|
|
43143
43958
|
if (tasks2.length > 0) {
|
|
43144
43959
|
const allIds = await getAllTaskIds();
|
|
@@ -43167,7 +43982,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43167
43982
|
if (idRows.length === 0) return [];
|
|
43168
43983
|
const db = await getDb(cwd);
|
|
43169
43984
|
const ids = idRows.map((r) => r.id);
|
|
43170
|
-
const rows = await db.select().from(tasksTasks).where(
|
|
43985
|
+
const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, ids)).all();
|
|
43171
43986
|
const tasks2 = rows.map(rowToTask);
|
|
43172
43987
|
if (tasks2.length > 0) {
|
|
43173
43988
|
const allIds = await getAllTaskIds();
|
|
@@ -43181,7 +43996,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43181
43996
|
const depRows = await db.select().from(tasksTaskDependencies).where(eq10(tasksTaskDependencies.dependsOn, taskId)).all();
|
|
43182
43997
|
if (depRows.length === 0) return [];
|
|
43183
43998
|
const dependentIds = depRows.map((r) => r.taskId);
|
|
43184
|
-
const rows = await db.select().from(tasksTasks).where(
|
|
43999
|
+
const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, dependentIds)).all();
|
|
43185
44000
|
const tasks2 = rows.map(rowToTask);
|
|
43186
44001
|
if (tasks2.length > 0) {
|
|
43187
44002
|
const allIds = await getAllTaskIds();
|
|
@@ -43211,7 +44026,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43211
44026
|
async loadTasks(taskIds) {
|
|
43212
44027
|
if (taskIds.length === 0) return [];
|
|
43213
44028
|
const db = await getDb(cwd);
|
|
43214
|
-
const rows = await db.select().from(tasksTasks).where(
|
|
44029
|
+
const rows = await db.select().from(tasksTasks).where(inArray6(tasksTasks.id, taskIds)).all();
|
|
43215
44030
|
const tasks2 = rows.map(rowToTask);
|
|
43216
44031
|
if (tasks2.length > 0) {
|
|
43217
44032
|
const allIds = await getAllTaskIds();
|
|
@@ -43265,6 +44080,9 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43265
44080
|
createdAt: tasksTasks.createdAt,
|
|
43266
44081
|
...CLAIM_COLUMNS
|
|
43267
44082
|
}).from(tasksTasks).where(eq10(tasksTasks.id, taskId)).limit(1).all();
|
|
44083
|
+
if (guard?.claim || guard?.expectedUpdatedAt !== void 0) {
|
|
44084
|
+
assertNotRenamed(getNativeTasksDb(cwd), taskId, guard, current);
|
|
44085
|
+
}
|
|
43268
44086
|
if (!current) throw new Error(`Task not found: ${taskId}`);
|
|
43269
44087
|
const claimGuard = guard?.claim;
|
|
43270
44088
|
const allowedHolders = claimGuard ? await claimAllowedHolders(db, claimGuard) : [];
|
|
@@ -43342,24 +44160,37 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43342
44160
|
nativeDb.prepare(`SAVEPOINT ${spName}`).run();
|
|
43343
44161
|
}
|
|
43344
44162
|
try {
|
|
44163
|
+
const replacedBirths = /* @__PURE__ */ new Map();
|
|
43345
44164
|
const tx = {
|
|
43346
44165
|
async upsertSingleTask(task) {
|
|
43347
44166
|
scope.assertActive();
|
|
43348
44167
|
return accessor.transaction(async () => {
|
|
43349
44168
|
scope.assertActive();
|
|
44169
|
+
if (rowUidFillEnabled() && !replacedBirths.has(task.id)) {
|
|
44170
|
+
const before = readReplacedTaskBirthNative(nativeDb, task.id);
|
|
44171
|
+
if (before) replacedBirths.set(task.id, before);
|
|
44172
|
+
}
|
|
43350
44173
|
const row = taskToRow(task);
|
|
43351
44174
|
await upsertTask(db, row);
|
|
43352
44175
|
await updateDependencies(db, task.id, task.depends ?? []);
|
|
43353
44176
|
});
|
|
43354
44177
|
},
|
|
43355
|
-
async insertNewTask(task) {
|
|
44178
|
+
async insertNewTask(task, identity) {
|
|
43356
44179
|
scope.assertActive();
|
|
43357
44180
|
return accessor.transaction(async () => {
|
|
43358
44181
|
scope.assertActive();
|
|
43359
|
-
await insertNewTask(db, taskToRow(task));
|
|
44182
|
+
await insertNewTask(db, taskToRow(task), identity);
|
|
43360
44183
|
await updateDependencies(db, task.id, task.depends ?? []);
|
|
43361
44184
|
});
|
|
43362
44185
|
},
|
|
44186
|
+
async clearTaskIdentity(taskId) {
|
|
44187
|
+
scope.assertActive();
|
|
44188
|
+
if (!rowUidFillEnabled()) return;
|
|
44189
|
+
return accessor.transaction(async () => {
|
|
44190
|
+
scope.assertActive();
|
|
44191
|
+
clearReplacedTaskIdentityNative(nativeDb, taskId, replacedBirths.get(taskId));
|
|
44192
|
+
});
|
|
44193
|
+
},
|
|
43363
44194
|
async archiveSingleTask(taskId, fields) {
|
|
43364
44195
|
scope.assertActive();
|
|
43365
44196
|
return accessor.transaction(async () => {
|
|
@@ -43506,7 +44337,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43506
44337
|
const owned = await db.select({ id: tasksTaskAcceptanceCriteria.id }).from(tasksTaskAcceptanceCriteria).where(
|
|
43507
44338
|
and8(
|
|
43508
44339
|
eq10(tasksTaskAcceptanceCriteria.taskId, taskId),
|
|
43509
|
-
|
|
44340
|
+
inArray6(tasksTaskAcceptanceCriteria.id, ids)
|
|
43510
44341
|
)
|
|
43511
44342
|
).all();
|
|
43512
44343
|
await pruneAcBindingsForAcIds(
|
|
@@ -43519,7 +44350,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43519
44350
|
await db.delete(tasksTaskAcceptanceCriteria).where(
|
|
43520
44351
|
and8(
|
|
43521
44352
|
eq10(tasksTaskAcceptanceCriteria.taskId, taskId),
|
|
43522
|
-
|
|
44353
|
+
inArray6(tasksTaskAcceptanceCriteria.id, ids)
|
|
43523
44354
|
)
|
|
43524
44355
|
).run();
|
|
43525
44356
|
});
|
|
@@ -43778,7 +44609,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
|
|
|
43778
44609
|
};
|
|
43779
44610
|
return accessor;
|
|
43780
44611
|
}
|
|
43781
|
-
var _txSavepointCounter, taskTransactionQueue, TaskTransactionScope, taskTransactionContext, CLAIM_COLUMNS;
|
|
44612
|
+
var _txSavepointCounter, taskTransactionQueue, TaskTransactionScope, taskTransactionContext, CLAIM_COLUMNS, RENAMED_RECENT_MS;
|
|
43782
44613
|
var init_sqlite_data_accessor = __esm({
|
|
43783
44614
|
"packages/core/src/store/sqlite-data-accessor.ts"() {
|
|
43784
44615
|
"use strict";
|
|
@@ -43792,6 +44623,8 @@ var init_sqlite_data_accessor = __esm({
|
|
|
43792
44623
|
init_cross_db_cleanup();
|
|
43793
44624
|
init_db_helpers();
|
|
43794
44625
|
init_row_identity();
|
|
44626
|
+
init_row_identity_flag();
|
|
44627
|
+
init_row_identity_registry();
|
|
43795
44628
|
init_audit2();
|
|
43796
44629
|
init_session_store();
|
|
43797
44630
|
init_sqlite3();
|
|
@@ -43824,6 +44657,7 @@ var init_sqlite_data_accessor = __esm({
|
|
|
43824
44657
|
claimedAt: tasksTasks.claimedAt,
|
|
43825
44658
|
leaseExpiresAt: tasksTasks.leaseExpiresAt
|
|
43826
44659
|
};
|
|
44660
|
+
RENAMED_RECENT_MS = 24 * 60 * 60 * 1e3;
|
|
43827
44661
|
registerRowIdentityWriters({
|
|
43828
44662
|
relinkAcUidNative,
|
|
43829
44663
|
clearAcUidGraveyardNative,
|
|
@@ -44294,7 +45128,7 @@ __export(governor_exports, {
|
|
|
44294
45128
|
resolveGovernorMode: () => resolveGovernorMode,
|
|
44295
45129
|
slotFileCount: () => slotFileCount
|
|
44296
45130
|
});
|
|
44297
|
-
import { existsSync as
|
|
45131
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
44298
45132
|
import { availableParallelism, totalmem } from "node:os";
|
|
44299
45133
|
import { join as join25 } from "node:path";
|
|
44300
45134
|
import lockfile2 from "proper-lockfile";
|
|
@@ -44368,11 +45202,11 @@ function governorSlotDir(cls) {
|
|
|
44368
45202
|
return join25(getCleoHome(), "locks", `resource-${cls}`);
|
|
44369
45203
|
}
|
|
44370
45204
|
function ensureSlotFiles(dir, count) {
|
|
44371
|
-
if (!
|
|
45205
|
+
if (!existsSync20(dir)) mkdirSync6(dir, { recursive: true });
|
|
44372
45206
|
const paths = [];
|
|
44373
45207
|
for (let i = 0; i < count; i++) {
|
|
44374
45208
|
const p = join25(dir, `slot-${i}.lock`);
|
|
44375
|
-
if (!
|
|
45209
|
+
if (!existsSync20(p)) writeFileSync5(p, "", { flag: "a" });
|
|
44376
45210
|
paths.push(p);
|
|
44377
45211
|
}
|
|
44378
45212
|
return paths;
|
|
@@ -44412,7 +45246,7 @@ function shuffledIndices(n) {
|
|
|
44412
45246
|
}
|
|
44413
45247
|
async function countHeldSlots(cls, budget) {
|
|
44414
45248
|
const dir = governorSlotDir(cls);
|
|
44415
|
-
if (!
|
|
45249
|
+
if (!existsSync20(dir)) return 0;
|
|
44416
45250
|
const slots = ensureSlotFiles(dir, budget);
|
|
44417
45251
|
let held = 0;
|
|
44418
45252
|
for (const path2 of slots) {
|
|
@@ -44427,7 +45261,7 @@ async function countHeldSlots(cls, budget) {
|
|
|
44427
45261
|
}
|
|
44428
45262
|
function slotFileCount(cls) {
|
|
44429
45263
|
const dir = governorSlotDir(cls);
|
|
44430
|
-
if (!
|
|
45264
|
+
if (!existsSync20(dir)) return 0;
|
|
44431
45265
|
return readdirSync5(dir).filter((f) => f.startsWith("slot-") && f.endsWith(".lock")).length;
|
|
44432
45266
|
}
|
|
44433
45267
|
var _log2, _cachedMode2, _supervisorDegradeLogged, MB, STALE_MS, _supervisorHolderSeq, ResourceGovernor, governor;
|
|
@@ -44578,7 +45412,7 @@ var init_governor = __esm({
|
|
|
44578
45412
|
// packages/core/src/store/exodus/recovery.ts
|
|
44579
45413
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
44580
45414
|
import { constants } from "node:sqlite";
|
|
44581
|
-
import { z as
|
|
45415
|
+
import { z as z30 } from "zod";
|
|
44582
45416
|
function identityValues(encoded) {
|
|
44583
45417
|
return identitySchema.parse(JSON.parse(encoded)).map(([kind, value]) => {
|
|
44584
45418
|
if (kind === "null") return null;
|
|
@@ -44914,8 +45748,8 @@ var init_recovery = __esm({
|
|
|
44914
45748
|
"use strict";
|
|
44915
45749
|
init_row_identity_registry();
|
|
44916
45750
|
RECEIPTS = "_exodus_recovery_rows";
|
|
44917
|
-
identitySchema =
|
|
44918
|
-
|
|
45751
|
+
identitySchema = z30.array(
|
|
45752
|
+
z30.tuple([z30.enum(["null", "integer", "real", "text", "blob"]), z30.string()])
|
|
44919
45753
|
);
|
|
44920
45754
|
ExodusRecoveryError = class extends Error {
|
|
44921
45755
|
};
|
|
@@ -44925,7 +45759,7 @@ var init_recovery = __esm({
|
|
|
44925
45759
|
// packages/core/src/store/exodus/archive.ts
|
|
44926
45760
|
import {
|
|
44927
45761
|
copyFileSync as copyFileSync5,
|
|
44928
|
-
existsSync as
|
|
45762
|
+
existsSync as existsSync21,
|
|
44929
45763
|
mkdirSync as mkdirSync7,
|
|
44930
45764
|
readFileSync as readFileSync8,
|
|
44931
45765
|
renameSync as renameSync7,
|
|
@@ -44933,7 +45767,7 @@ import {
|
|
|
44933
45767
|
writeFileSync as writeFileSync6
|
|
44934
45768
|
} from "node:fs";
|
|
44935
45769
|
import { basename as basename9, dirname as dirname19, join as join26, resolve as resolve12 } from "node:path";
|
|
44936
|
-
import { z as
|
|
45770
|
+
import { z as z31 } from "zod";
|
|
44937
45771
|
function scopeBaseDir(scope, cwd, targetDbPath) {
|
|
44938
45772
|
if (targetDbPath !== void 0) return dirname19(targetDbPath);
|
|
44939
45773
|
return scope === "project" ? resolveCleoDir(cwd) : getCleoHome();
|
|
@@ -44953,7 +45787,7 @@ function hasExodusCompleteMarker(scope, cwd, targetDbPath, nativeDb) {
|
|
|
44953
45787
|
if (targetDbPath) throw error;
|
|
44954
45788
|
return false;
|
|
44955
45789
|
}
|
|
44956
|
-
if (!
|
|
45790
|
+
if (!existsSync21(markerPath)) return false;
|
|
44957
45791
|
const marker = markerIdentity.parse(JSON.parse(readFileSync8(markerPath, "utf8")));
|
|
44958
45792
|
if (nativeDb && (!marker.databaseIdentity || !hasExodusDatabaseIdentity(nativeDb, marker.databaseIdentity)))
|
|
44959
45793
|
throw new Error(
|
|
@@ -44983,7 +45817,7 @@ function writeExodusCompleteMarker(scope, archivedSources, cwd, targetDbPath, da
|
|
|
44983
45817
|
function moveFileInto(srcPath, destDir) {
|
|
44984
45818
|
mkdirSync7(destDir, { recursive: true });
|
|
44985
45819
|
let dest = join26(destDir, basename9(srcPath));
|
|
44986
|
-
if (
|
|
45820
|
+
if (existsSync21(dest)) {
|
|
44987
45821
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
|
|
44988
45822
|
dest = join26(destDir, `${basename9(srcPath)}.${stamp}`);
|
|
44989
45823
|
}
|
|
@@ -44996,14 +45830,14 @@ function moveFileInto(srcPath, destDir) {
|
|
|
44996
45830
|
return dest;
|
|
44997
45831
|
}
|
|
44998
45832
|
function archiveSourceDb(source, cwd, targetDbPath) {
|
|
44999
|
-
if (!
|
|
45833
|
+
if (!existsSync21(source.path)) {
|
|
45000
45834
|
return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
|
|
45001
45835
|
}
|
|
45002
45836
|
const destDir = exodusArchiveDir(source.targetScope, cwd, targetDbPath);
|
|
45003
45837
|
const archivedTo = moveFileInto(source.path, destDir);
|
|
45004
45838
|
for (const suffix of SIDECAR_SUFFIXES) {
|
|
45005
45839
|
const sidecar = `${source.path}${suffix}`;
|
|
45006
|
-
if (
|
|
45840
|
+
if (existsSync21(sidecar)) {
|
|
45007
45841
|
try {
|
|
45008
45842
|
moveFileInto(sidecar, destDir);
|
|
45009
45843
|
} catch (err) {
|
|
@@ -45051,7 +45885,7 @@ function detectStrandedResidue(sources, cwd) {
|
|
|
45051
45885
|
const stranded = [];
|
|
45052
45886
|
for (const source of sources) {
|
|
45053
45887
|
if (!markedScopes.has(source.targetScope)) continue;
|
|
45054
|
-
if (
|
|
45888
|
+
if (existsSync21(source.path)) {
|
|
45055
45889
|
stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
|
|
45056
45890
|
}
|
|
45057
45891
|
}
|
|
@@ -45076,11 +45910,11 @@ var init_archive2 = __esm({
|
|
|
45076
45910
|
init_ensure_config();
|
|
45077
45911
|
init_recovery();
|
|
45078
45912
|
log8 = getLogger("exodus-archive");
|
|
45079
|
-
markerIdentity =
|
|
45080
|
-
version:
|
|
45081
|
-
scope:
|
|
45082
|
-
targetDbPath:
|
|
45083
|
-
databaseIdentity:
|
|
45913
|
+
markerIdentity = z31.object({
|
|
45914
|
+
version: z31.literal(1),
|
|
45915
|
+
scope: z31.enum(["project", "global"]),
|
|
45916
|
+
targetDbPath: z31.string().optional(),
|
|
45917
|
+
databaseIdentity: z31.string().optional()
|
|
45084
45918
|
});
|
|
45085
45919
|
ARCHIVE_DIR_NAME = "_archive";
|
|
45086
45920
|
MARKER_FILENAME_BY_SCOPE = {
|
|
@@ -45092,13 +45926,13 @@ var init_archive2 = __esm({
|
|
|
45092
45926
|
});
|
|
45093
45927
|
|
|
45094
45928
|
// packages/core/src/store/exodus/count-parity.ts
|
|
45095
|
-
import { existsSync as
|
|
45929
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
45096
45930
|
function listTables2(db) {
|
|
45097
45931
|
return db.prepare(
|
|
45098
45932
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
|
|
45099
45933
|
).all().map((r) => r.name);
|
|
45100
45934
|
}
|
|
45101
|
-
function
|
|
45935
|
+
function tableExists3(db, tableName) {
|
|
45102
45936
|
const escaped = tableName.replace(/'/g, "''");
|
|
45103
45937
|
return db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !== void 0;
|
|
45104
45938
|
}
|
|
@@ -45113,14 +45947,14 @@ function rowCount(db, tableName) {
|
|
|
45113
45947
|
function computeCountParity(sources, projectDbPath, globalDbPath) {
|
|
45114
45948
|
const entries = [];
|
|
45115
45949
|
let skipped = 0;
|
|
45116
|
-
if (!
|
|
45950
|
+
if (!existsSync22(projectDbPath) || !existsSync22(globalDbPath)) {
|
|
45117
45951
|
return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
|
|
45118
45952
|
}
|
|
45119
45953
|
const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
|
|
45120
45954
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
45121
45955
|
try {
|
|
45122
45956
|
for (const src of sources) {
|
|
45123
|
-
if (!
|
|
45957
|
+
if (!existsSync22(src.path)) continue;
|
|
45124
45958
|
const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
45125
45959
|
try {
|
|
45126
45960
|
for (const legacyTable of listTables2(srcSnap.db)) {
|
|
@@ -45137,7 +45971,7 @@ function computeCountParity(sources, projectDbPath, globalDbPath) {
|
|
|
45137
45971
|
skipped++;
|
|
45138
45972
|
continue;
|
|
45139
45973
|
}
|
|
45140
|
-
const targetCount =
|
|
45974
|
+
const targetCount = tableExists3(targetSnap.db, targetTable) ? rowCount(targetSnap.db, targetTable) ?? 0 : 0;
|
|
45141
45975
|
const deficit = targetCount < sourceCount ? sourceCount - targetCount : 0;
|
|
45142
45976
|
entries.push({
|
|
45143
45977
|
sourceDb: src.name,
|
|
@@ -45178,7 +46012,7 @@ var init_count_parity = __esm({
|
|
|
45178
46012
|
});
|
|
45179
46013
|
|
|
45180
46014
|
// packages/core/src/store/exodus/plan.ts
|
|
45181
|
-
import { existsSync as
|
|
46015
|
+
import { existsSync as existsSync23, readdirSync as readdirSync6, statfsSync as statfsSync2, statSync as statSync6 } from "node:fs";
|
|
45182
46016
|
import { join as join27 } from "node:path";
|
|
45183
46017
|
function computeRequiredBytes(totalSourceBytes, largestSourceBytes) {
|
|
45184
46018
|
return Math.ceil(STAGING_HEADROOM_FACTOR * largestSourceBytes) + totalSourceBytes;
|
|
@@ -45280,7 +46114,7 @@ function buildExodusPlan(cwd) {
|
|
|
45280
46114
|
};
|
|
45281
46115
|
}
|
|
45282
46116
|
function sourcesPresent(sources) {
|
|
45283
|
-
return sources.some((s) =>
|
|
46117
|
+
return sources.some((s) => existsSync23(s.path));
|
|
45284
46118
|
}
|
|
45285
46119
|
var STAGING_HEADROOM_FACTOR, STAGING_COPY_SKIP_THRESHOLD_BYTES;
|
|
45286
46120
|
var init_plan2 = __esm({
|
|
@@ -45294,18 +46128,18 @@ var init_plan2 = __esm({
|
|
|
45294
46128
|
});
|
|
45295
46129
|
|
|
45296
46130
|
// packages/core/src/store/exodus/health.ts
|
|
45297
|
-
import { existsSync as
|
|
46131
|
+
import { existsSync as existsSync24, statSync as statSync7 } from "node:fs";
|
|
45298
46132
|
function buildExodusHealth(cwd) {
|
|
45299
46133
|
const plan = buildExodusPlan(cwd);
|
|
45300
|
-
const anyLegacyPresent = plan.sources.some((s) =>
|
|
46134
|
+
const anyLegacyPresent = plan.sources.some((s) => existsSync24(s.path));
|
|
45301
46135
|
const parity = anyLegacyPresent ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath) : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
|
|
45302
46136
|
const consolidatedExistsByScope = {
|
|
45303
|
-
project:
|
|
45304
|
-
global:
|
|
46137
|
+
project: existsSync24(plan.projectDbPath),
|
|
46138
|
+
global: existsSync24(plan.globalDbPath)
|
|
45305
46139
|
};
|
|
45306
46140
|
const buildScope = (scope) => {
|
|
45307
46141
|
const sources = plan.sources.filter((s) => s.targetScope === scope).map((s) => {
|
|
45308
|
-
const present =
|
|
46142
|
+
const present = existsSync24(s.path);
|
|
45309
46143
|
let bytes = 0;
|
|
45310
46144
|
if (present) {
|
|
45311
46145
|
try {
|
|
@@ -45410,7 +46244,7 @@ var init_types = __esm({
|
|
|
45410
46244
|
// packages/core/src/store/exodus/migrate.ts
|
|
45411
46245
|
import {
|
|
45412
46246
|
copyFileSync as copyFileSync6,
|
|
45413
|
-
existsSync as
|
|
46247
|
+
existsSync as existsSync25,
|
|
45414
46248
|
mkdirSync as mkdirSync8,
|
|
45415
46249
|
readFileSync as readFileSync9,
|
|
45416
46250
|
renameSync as renameSync8,
|
|
@@ -45456,7 +46290,7 @@ function writeJournal(stagingDir, journal) {
|
|
|
45456
46290
|
}
|
|
45457
46291
|
function readJournal(stagingDir) {
|
|
45458
46292
|
const journalPath = join28(stagingDir, JOURNAL_FILENAME);
|
|
45459
|
-
if (!
|
|
46293
|
+
if (!existsSync25(journalPath)) return null;
|
|
45460
46294
|
try {
|
|
45461
46295
|
return JSON.parse(readFileSync9(journalPath, "utf8"));
|
|
45462
46296
|
} catch {
|
|
@@ -45466,7 +46300,7 @@ function readJournal(stagingDir) {
|
|
|
45466
46300
|
function clearExodusJournal(stagingDir) {
|
|
45467
46301
|
const journalPath = join28(stagingDir, JOURNAL_FILENAME);
|
|
45468
46302
|
try {
|
|
45469
|
-
if (!
|
|
46303
|
+
if (!existsSync25(journalPath)) return false;
|
|
45470
46304
|
unlinkSync5(journalPath);
|
|
45471
46305
|
log10.info(
|
|
45472
46306
|
{ stagingDir },
|
|
@@ -45762,7 +46596,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
|
|
|
45762
46596
|
mkdirSync8(stagingDir, { recursive: true });
|
|
45763
46597
|
let sqliteVersion = "unknown";
|
|
45764
46598
|
for (const src of sources) {
|
|
45765
|
-
if (
|
|
46599
|
+
if (existsSync25(src.path)) {
|
|
45766
46600
|
const snap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
45767
46601
|
sqliteVersion = getSqliteVersion(snap.db);
|
|
45768
46602
|
snap.close();
|
|
@@ -45792,7 +46626,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
|
|
|
45792
46626
|
let reseedProject = null;
|
|
45793
46627
|
try {
|
|
45794
46628
|
for (const src of sources) {
|
|
45795
|
-
if (!
|
|
46629
|
+
if (!existsSync25(src.path)) continue;
|
|
45796
46630
|
const backupDest = join28(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
|
|
45797
46631
|
const srcBytes = safeStatBytes(src.path);
|
|
45798
46632
|
const skipStagingCopy = srcBytes > plan.stagingCopyThresholdBytes;
|
|
@@ -45800,7 +46634,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
|
|
|
45800
46634
|
onProgress?.(
|
|
45801
46635
|
`Skipping full staging copy of ${src.name} (${srcBytes} bytes > ${plan.stagingCopyThresholdBytes} threshold) \u2014 source is archived, not deleted, on success.`
|
|
45802
46636
|
);
|
|
45803
|
-
} else if (!
|
|
46637
|
+
} else if (!existsSync25(backupDest)) {
|
|
45804
46638
|
onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
|
|
45805
46639
|
copyFileSync6(src.path, backupDest);
|
|
45806
46640
|
backupPaths.push(backupDest);
|
|
@@ -45833,8 +46667,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress, opt
|
|
|
45833
46667
|
}
|
|
45834
46668
|
prepareExodusRecovery(projectNative, stagingDir);
|
|
45835
46669
|
if (globalNative !== null) prepareExodusRecovery(globalNative, stagingDir);
|
|
45836
|
-
const projectSources = sources.filter((s) => s.targetScope === "project" &&
|
|
45837
|
-
const globalSources = sources.filter((s) => s.targetScope === "global" &&
|
|
46670
|
+
const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync25(s.path));
|
|
46671
|
+
const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync25(s.path));
|
|
45838
46672
|
if (globalNative === null && globalSources.length > 0)
|
|
45839
46673
|
throw new Error("A projectOnly exodus run was given global-scope sources");
|
|
45840
46674
|
await migrateScope(
|
|
@@ -46083,7 +46917,8 @@ var init_migrate = __esm({
|
|
|
46083
46917
|
GRANDFATHERED_GUARD_TRIGGERS = [
|
|
46084
46918
|
"tasks_tasks_parent_type_matrix_insert",
|
|
46085
46919
|
"tasks_task_relations_non_containment_insert",
|
|
46086
|
-
"tasks_task_acceptance_child_target_insert"
|
|
46920
|
+
"tasks_task_acceptance_child_target_insert",
|
|
46921
|
+
"tasks_task_dependencies_cycle_guard_insert"
|
|
46087
46922
|
];
|
|
46088
46923
|
SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
|
|
46089
46924
|
["conduit", "seconds"],
|
|
@@ -46142,7 +46977,7 @@ __export(reconcile_exports, {
|
|
|
46142
46977
|
reconcileSupersededStores: () => reconcileSupersededStores,
|
|
46143
46978
|
unmigratedBareSources: () => unmigratedBareSources
|
|
46144
46979
|
});
|
|
46145
|
-
import { copyFileSync as copyFileSync7, existsSync as
|
|
46980
|
+
import { copyFileSync as copyFileSync7, existsSync as existsSync26, mkdirSync as mkdirSync9, mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
46146
46981
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
46147
46982
|
import { basename as basename10, join as join29 } from "node:path";
|
|
46148
46983
|
function ident2(name2) {
|
|
@@ -46213,7 +47048,7 @@ function assessSupersededProjectStores(liveStorePath, sources, resolveTarget = r
|
|
|
46213
47048
|
}
|
|
46214
47049
|
function legacySourcesHoldRows(sources) {
|
|
46215
47050
|
for (const src of sources) {
|
|
46216
|
-
if (!
|
|
47051
|
+
if (!existsSync26(src.path)) continue;
|
|
46217
47052
|
const snap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
46218
47053
|
try {
|
|
46219
47054
|
for (const table of orderTablesForCopy(snap.db)) {
|
|
@@ -46461,8 +47296,8 @@ async function reconcileSuppressed(projectRoot, options, liveStorePath) {
|
|
|
46461
47296
|
}
|
|
46462
47297
|
}
|
|
46463
47298
|
async function reconcileWithScratch(projectRoot, dryRun, additive, liveStorePath, plan, resolveTarget, scratch) {
|
|
46464
|
-
const fileSources = plan.sources.filter((s) => s.targetScope === "project" &&
|
|
46465
|
-
const bare = !additive &&
|
|
47299
|
+
const fileSources = plan.sources.filter((s) => s.targetScope === "project" && existsSync26(s.path));
|
|
47300
|
+
const bare = !additive && existsSync26(liveStorePath) ? await bareTaskCoreSource(liveStorePath, resolveTarget, scratch) : null;
|
|
46466
47301
|
const copyResolver = additive ? (sourceName, legacyTable) => {
|
|
46467
47302
|
const r = resolveTarget(sourceName, legacyTable);
|
|
46468
47303
|
return r.kind !== "skip" && isLiveAuthoritative(sourceName, legacyTable, r.targetName) ? { kind: "skip", reason: "additive: live-authoritative task graph" } : r;
|
|
@@ -46481,7 +47316,7 @@ async function reconcileWithScratch(projectRoot, dryRun, additive, liveStorePath
|
|
|
46481
47316
|
stagingDir: null,
|
|
46482
47317
|
receiptPath: null
|
|
46483
47318
|
};
|
|
46484
|
-
if (sources.length === 0 || !
|
|
47319
|
+
if (sources.length === 0 || !existsSync26(liveStorePath)) {
|
|
46485
47320
|
return {
|
|
46486
47321
|
...base,
|
|
46487
47322
|
outcome: "nothing-to-reconcile",
|
|
@@ -46673,11 +47508,11 @@ var init_seal = __esm({
|
|
|
46673
47508
|
});
|
|
46674
47509
|
|
|
46675
47510
|
// packages/core/src/store/exodus/status.ts
|
|
46676
|
-
import { existsSync as
|
|
47511
|
+
import { existsSync as existsSync27, readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync9 } from "node:fs";
|
|
46677
47512
|
import { join as join30 } from "node:path";
|
|
46678
47513
|
function readJournal2(stagingDir) {
|
|
46679
47514
|
const p = join30(stagingDir, JOURNAL_FILENAME2);
|
|
46680
|
-
if (!
|
|
47515
|
+
if (!existsSync27(p)) return null;
|
|
46681
47516
|
try {
|
|
46682
47517
|
return JSON.parse(readFileSync10(p, "utf8"));
|
|
46683
47518
|
} catch {
|
|
@@ -46709,15 +47544,15 @@ function runExodusStatus(cwd) {
|
|
|
46709
47544
|
const sourcesInfo = plan.sources.map((s) => ({
|
|
46710
47545
|
name: s.name,
|
|
46711
47546
|
path: s.path,
|
|
46712
|
-
exists:
|
|
47547
|
+
exists: existsSync27(s.path),
|
|
46713
47548
|
bytes: safeBytes(s.path)
|
|
46714
47549
|
}));
|
|
46715
47550
|
return {
|
|
46716
47551
|
hasStaging: latestStaging !== null,
|
|
46717
47552
|
stagingDir: latestStaging,
|
|
46718
47553
|
journal,
|
|
46719
|
-
projectDbExists:
|
|
46720
|
-
globalDbExists:
|
|
47554
|
+
projectDbExists: existsSync27(projectDbPath),
|
|
47555
|
+
globalDbExists: existsSync27(globalDbPath),
|
|
46721
47556
|
sourcesPresent: sourcesInfo.some((s) => s.exists),
|
|
46722
47557
|
sources: sourcesInfo
|
|
46723
47558
|
};
|
|
@@ -46734,7 +47569,7 @@ var init_status = __esm({
|
|
|
46734
47569
|
});
|
|
46735
47570
|
|
|
46736
47571
|
// packages/core/src/store/exodus/verify-migration.ts
|
|
46737
|
-
import { existsSync as
|
|
47572
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
46738
47573
|
import { createRequire as createRequire10 } from "node:module";
|
|
46739
47574
|
function orderByClause(db, tableName) {
|
|
46740
47575
|
try {
|
|
@@ -46849,7 +47684,7 @@ function listTables3(db) {
|
|
|
46849
47684
|
).all();
|
|
46850
47685
|
return rows.map((r) => r.name);
|
|
46851
47686
|
}
|
|
46852
|
-
function
|
|
47687
|
+
function tableExists4(db, tableName) {
|
|
46853
47688
|
try {
|
|
46854
47689
|
const escaped = tableName.replace(/'/g, "''");
|
|
46855
47690
|
return db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !== void 0;
|
|
@@ -46999,10 +47834,10 @@ function orphanAlreadyInSource(targetDb, fk, sources, resolveTarget = resolveCon
|
|
|
46999
47834
|
const anyFeeder = (targetTable, probe) => {
|
|
47000
47835
|
for (const feeder of feedersOf(targetTable)) {
|
|
47001
47836
|
const src = sources.find((s) => s.name === feeder.sourceName);
|
|
47002
|
-
if (src === void 0 || !
|
|
47837
|
+
if (src === void 0 || !existsSync28(src.path)) continue;
|
|
47003
47838
|
const snap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
47004
47839
|
try {
|
|
47005
|
-
if (!
|
|
47840
|
+
if (!tableExists4(snap.db, feeder.legacyTable)) continue;
|
|
47006
47841
|
const cols = new Set(
|
|
47007
47842
|
snap.db.prepare(`PRAGMA table_info("${feeder.legacyTable}")`).all().map((c) => c.name)
|
|
47008
47843
|
);
|
|
@@ -47054,7 +47889,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
|
|
|
47054
47889
|
const preExistingForeignKeyViolations = [];
|
|
47055
47890
|
const failureLines = [];
|
|
47056
47891
|
const sourceOrphanSigs = /* @__PURE__ */ new Set();
|
|
47057
|
-
if (!
|
|
47892
|
+
if (!existsSync28(projectDbPath)) {
|
|
47058
47893
|
return {
|
|
47059
47894
|
ok: false,
|
|
47060
47895
|
tables: [],
|
|
@@ -47065,7 +47900,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
|
|
|
47065
47900
|
error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
|
|
47066
47901
|
};
|
|
47067
47902
|
}
|
|
47068
|
-
if (!
|
|
47903
|
+
if (!existsSync28(globalDbPath)) {
|
|
47069
47904
|
return {
|
|
47070
47905
|
ok: false,
|
|
47071
47906
|
tables: [],
|
|
@@ -47080,7 +47915,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
|
|
|
47080
47915
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
47081
47916
|
try {
|
|
47082
47917
|
for (const src of sources) {
|
|
47083
|
-
if (!
|
|
47918
|
+
if (!existsSync28(src.path)) {
|
|
47084
47919
|
onProgress?.(`Skipping ${src.name} (not present)`);
|
|
47085
47920
|
continue;
|
|
47086
47921
|
}
|
|
@@ -47205,7 +48040,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress, resol
|
|
|
47205
48040
|
targetOrphans.push(...foreignKeyCheck(globalSnap.db, "global"));
|
|
47206
48041
|
foreignKeyViolations.push(...targetOrphans);
|
|
47207
48042
|
for (const fk of targetOrphans) {
|
|
47208
|
-
const orphanDb =
|
|
48043
|
+
const orphanDb = tableExists4(projectSnap.db, fk.table) ? projectSnap.db : globalSnap.db;
|
|
47209
48044
|
const sig = orphanSignature(orphanDb, fk);
|
|
47210
48045
|
const preExisting = sourceOrphanSigs.has(sig) || orphanAlreadyInSource(orphanDb, fk, sources, resolveTarget);
|
|
47211
48046
|
if (preExisting) {
|
|
@@ -47371,7 +48206,7 @@ __export(on_open_exports, {
|
|
|
47371
48206
|
maybeRunExodusOnOpen: () => maybeRunExodusOnOpen,
|
|
47372
48207
|
withExodusOnOpenSuppressed: () => withExodusOnOpenSuppressed
|
|
47373
48208
|
});
|
|
47374
|
-
import { existsSync as
|
|
48209
|
+
import { existsSync as existsSync29, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
|
|
47375
48210
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
47376
48211
|
import { join as join31, resolve as resolve13 } from "node:path";
|
|
47377
48212
|
async function withExodusOnOpenSuppressed(dbPath, fn) {
|
|
@@ -47413,7 +48248,7 @@ function remedyFor(scope) {
|
|
|
47413
48248
|
}
|
|
47414
48249
|
async function strandedLegacySources(scope, cwd) {
|
|
47415
48250
|
const { buildExodusPlan: buildExodusPlan2, legacySourcesHoldRows: legacySourcesHoldRows2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
|
|
47416
|
-
return buildExodusPlan2(cwd).sources.filter((s) => s.targetScope === scope &&
|
|
48251
|
+
return buildExodusPlan2(cwd).sources.filter((s) => s.targetScope === scope && existsSync29(s.path)).filter((s) => legacySourcesHoldRows2([s])).map((s) => s.name);
|
|
47417
48252
|
}
|
|
47418
48253
|
async function exodusStoreRewriteRefusal(dbPath, cwd) {
|
|
47419
48254
|
const { assertOwnerStoreRewriteConfirmed: assertOwnerStoreRewriteConfirmed2, invocationDirectory: invocationDirectory2 } = await Promise.resolve().then(() => (init_worktree_isolation_guard(), worktree_isolation_guard_exports));
|
|
@@ -47545,7 +48380,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
47545
48380
|
};
|
|
47546
48381
|
}
|
|
47547
48382
|
const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
|
|
47548
|
-
if (!scopeSources.some((s) =>
|
|
48383
|
+
if (!scopeSources.some((s) => existsSync29(s.path))) {
|
|
47549
48384
|
return {
|
|
47550
48385
|
outcome: "skipped",
|
|
47551
48386
|
reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
|
|
@@ -47570,7 +48405,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
47570
48405
|
{
|
|
47571
48406
|
scope,
|
|
47572
48407
|
dbPath,
|
|
47573
|
-
sources: plan.sources.filter((s) =>
|
|
48408
|
+
sources: plan.sources.filter((s) => existsSync29(s.path)).map((s) => s.name)
|
|
47574
48409
|
},
|
|
47575
48410
|
"exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
|
|
47576
48411
|
);
|
|
@@ -47583,7 +48418,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
47583
48418
|
const bare = scope === "project" ? await unmigratedBareSources2(
|
|
47584
48419
|
dbPath,
|
|
47585
48420
|
resolveTarget,
|
|
47586
|
-
plan.sources.find((s) => s.name === "tasks" &&
|
|
48421
|
+
plan.sources.find((s) => s.name === "tasks" && existsSync29(s.path))?.path,
|
|
47587
48422
|
bareScratch
|
|
47588
48423
|
) : { first: [], last: [] };
|
|
47589
48424
|
const migratePlan = { ...plan, sources: [...bare.first, ...plan.sources, ...bare.last] };
|
|
@@ -47647,7 +48482,7 @@ async function runExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
47647
48482
|
"exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
|
|
47648
48483
|
);
|
|
47649
48484
|
try {
|
|
47650
|
-
const consumed = plan.sources.filter((s) =>
|
|
48485
|
+
const consumed = plan.sources.filter((s) => existsSync29(s.path));
|
|
47651
48486
|
const identities = await sealTargets(plan, consumed);
|
|
47652
48487
|
const archiveResult = archiveMigratedSources(consumed, cwd, plan, identities);
|
|
47653
48488
|
log14.info(
|
|
@@ -47722,7 +48557,7 @@ __export(dual_scope_db_exports, {
|
|
|
47722
48557
|
upsertIdempotent: () => upsertIdempotent,
|
|
47723
48558
|
withStoreSchemaOwnership: () => withStoreSchemaOwnership
|
|
47724
48559
|
});
|
|
47725
|
-
import { existsSync as
|
|
48560
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync10 } from "node:fs";
|
|
47726
48561
|
import { createRequire as createRequire11 } from "node:module";
|
|
47727
48562
|
import { dirname as dirname20, join as join32, resolve as resolve14 } from "node:path";
|
|
47728
48563
|
function getDualScopeNativeDb(handle) {
|
|
@@ -47795,11 +48630,15 @@ async function openDualScopeDb(scope, cwd, options) {
|
|
|
47795
48630
|
open
|
|
47796
48631
|
) : open();
|
|
47797
48632
|
}
|
|
48633
|
+
function identityWorkOnOpen(nativeDb, scope) {
|
|
48634
|
+
if (ROW_IDENTITY[scope].length === 0) return false;
|
|
48635
|
+
return rowUidFillEnabled() || missingRowIdentitySchema(nativeDb).length > 0;
|
|
48636
|
+
}
|
|
47798
48637
|
async function openDedicatedDualScopeDb(scope, dbPath, log15, execution) {
|
|
47799
48638
|
execution?.assertActive();
|
|
47800
48639
|
log15.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
|
|
47801
48640
|
const dir = dirname20(dbPath);
|
|
47802
|
-
if (!
|
|
48641
|
+
if (!existsSync30(dir)) {
|
|
47803
48642
|
mkdirSync10(dir, { recursive: true });
|
|
47804
48643
|
}
|
|
47805
48644
|
execution?.assertActive();
|
|
@@ -47832,9 +48671,12 @@ async function openDedicatedDualScopeDb(scope, dbPath, log15, execution) {
|
|
|
47832
48671
|
`dual-scope-db[${scope}]`
|
|
47833
48672
|
);
|
|
47834
48673
|
execution?.assertActive();
|
|
47835
|
-
if (
|
|
48674
|
+
if (identityWorkOnOpen(nativeDb, scope)) {
|
|
47836
48675
|
await Promise.resolve().then(() => (init_sqlite_data_accessor(), sqlite_data_accessor_exports));
|
|
47837
|
-
|
|
48676
|
+
healRowIdentitySchema(nativeDb, scope);
|
|
48677
|
+
if (rowUidFillEnabled()) {
|
|
48678
|
+
prepareRowIdentity(nativeDb, scope, { triggers: false });
|
|
48679
|
+
}
|
|
47838
48680
|
}
|
|
47839
48681
|
execution?.assertActive();
|
|
47840
48682
|
log15.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
|
|
@@ -47947,7 +48789,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
47947
48789
|
execution?.assertActive();
|
|
47948
48790
|
log15.debug({ scope, dbPath: normalizedPath }, "opening dual-scope cleo.db");
|
|
47949
48791
|
const dir = dirname20(normalizedPath);
|
|
47950
|
-
if (!
|
|
48792
|
+
if (!existsSync30(dir)) {
|
|
47951
48793
|
mkdirSync10(dir, { recursive: true });
|
|
47952
48794
|
}
|
|
47953
48795
|
execution?.assertActive();
|
|
@@ -47980,9 +48822,12 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
47980
48822
|
`dual-scope-db[${scope}]`
|
|
47981
48823
|
);
|
|
47982
48824
|
execution?.assertActive();
|
|
47983
|
-
if (
|
|
48825
|
+
if (identityWorkOnOpen(nativeDb, scope)) {
|
|
47984
48826
|
await Promise.resolve().then(() => (init_sqlite_data_accessor(), sqlite_data_accessor_exports));
|
|
47985
|
-
|
|
48827
|
+
healRowIdentitySchema(nativeDb, scope);
|
|
48828
|
+
if (rowUidFillEnabled()) {
|
|
48829
|
+
prepareRowIdentity(nativeDb, scope);
|
|
48830
|
+
}
|
|
47986
48831
|
}
|
|
47987
48832
|
execution?.assertActive();
|
|
47988
48833
|
log15.debug({ scope, dbPath: normalizedPath }, "dual-scope cleo.db ready");
|
|
@@ -49112,7 +49957,7 @@ __export(nexus_sqlite_exports, {
|
|
|
49112
49957
|
resetNexusDbState: () => resetNexusDbState,
|
|
49113
49958
|
resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
|
|
49114
49959
|
});
|
|
49115
|
-
import { copyFileSync as copyFileSync8, existsSync as
|
|
49960
|
+
import { copyFileSync as copyFileSync8, existsSync as existsSync31 } from "node:fs";
|
|
49116
49961
|
import { join as join33 } from "node:path";
|
|
49117
49962
|
function getNexusDbPath(cwd) {
|
|
49118
49963
|
return resolveDualScopeDbPath("project", cwd);
|
|
@@ -49164,7 +50009,7 @@ function detectAndWarnOnNestedNexus() {
|
|
|
49164
50009
|
} catch {
|
|
49165
50010
|
return false;
|
|
49166
50011
|
}
|
|
49167
|
-
if (!
|
|
50012
|
+
if (!existsSync31(nestedPath)) return false;
|
|
49168
50013
|
if (_warnedNestedPaths.has(nestedPath)) return false;
|
|
49169
50014
|
_warnedNestedPaths.add(nestedPath);
|
|
49170
50015
|
const canonicalPath = getNexusDbPath();
|
|
@@ -49184,7 +50029,7 @@ function detectAndWarnOnNestedNexus() {
|
|
|
49184
50029
|
function _resetNestedNexusWarningGate() {
|
|
49185
50030
|
_warnedNestedPaths.clear();
|
|
49186
50031
|
}
|
|
49187
|
-
function
|
|
50032
|
+
function tableExists5(nativeDb, tableName) {
|
|
49188
50033
|
const result = nativeDb.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").get(tableName);
|
|
49189
50034
|
return !!result;
|
|
49190
50035
|
}
|
|
@@ -49193,7 +50038,7 @@ function objectExists(nativeDb, type, name2) {
|
|
|
49193
50038
|
return !!result;
|
|
49194
50039
|
}
|
|
49195
50040
|
function ensureNexusFts5(nativeDb) {
|
|
49196
|
-
if (!
|
|
50041
|
+
if (!tableExists5(nativeDb, "nexus_nodes")) return;
|
|
49197
50042
|
if (!objectExists(nativeDb, "table", "nexus_symbols_fts")) {
|
|
49198
50043
|
nativeDb.exec(`
|
|
49199
50044
|
CREATE VIRTUAL TABLE nexus_symbols_fts USING fts5(
|
|
@@ -49239,7 +50084,7 @@ function ensureNexusFts5(nativeDb) {
|
|
|
49239
50084
|
`);
|
|
49240
50085
|
}
|
|
49241
50086
|
function ensureNexusRelationWeights(nativeDb) {
|
|
49242
|
-
if (!
|
|
50087
|
+
if (!tableExists5(nativeDb, "nexus_relations")) return;
|
|
49243
50088
|
nativeDb.exec(`
|
|
49244
50089
|
CREATE TABLE IF NOT EXISTS nexus_relation_weights (
|
|
49245
50090
|
relation_id TEXT PRIMARY KEY NOT NULL,
|
|
@@ -49321,9 +50166,9 @@ function ensureNexusRelationWeights(nativeDb) {
|
|
|
49321
50166
|
}
|
|
49322
50167
|
function runNexusMigrations(nativeDb, db, dbPath) {
|
|
49323
50168
|
const migrationsFolder = resolveNexusMigrationsFolder();
|
|
49324
|
-
if (
|
|
50169
|
+
if (tableExists5(nativeDb, "nexus_nodes")) {
|
|
49325
50170
|
const backupPath = dbPath.replace(/\.db$/, "-pre-cleo.db.bak");
|
|
49326
|
-
if (!
|
|
50171
|
+
if (!existsSync31(backupPath)) {
|
|
49327
50172
|
try {
|
|
49328
50173
|
copyFileSync8(dbPath, backupPath);
|
|
49329
50174
|
} catch {
|
|
@@ -49453,13 +50298,13 @@ var init_legacy_alias = __esm({
|
|
|
49453
50298
|
|
|
49454
50299
|
// packages/core/src/llm/stable-device-id.ts
|
|
49455
50300
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
49456
|
-
import { existsSync as
|
|
50301
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync11, readFileSync as readFileSync11, renameSync as renameSync9, writeFileSync as writeFileSync9 } from "node:fs";
|
|
49457
50302
|
import { dirname as dirname21 } from "node:path";
|
|
49458
50303
|
import { resolveStableDeviceIdPath } from "@cleocode/paths";
|
|
49459
50304
|
function getStableDeviceId() {
|
|
49460
50305
|
if (_cachedDeviceId !== null) return _cachedDeviceId;
|
|
49461
50306
|
const path2 = resolveStableDeviceIdPath();
|
|
49462
|
-
if (
|
|
50307
|
+
if (existsSync32(path2)) {
|
|
49463
50308
|
try {
|
|
49464
50309
|
const raw = readFileSync11(path2, "utf-8").trim();
|
|
49465
50310
|
if (raw.length > 0) {
|
|
@@ -49472,7 +50317,7 @@ function getStableDeviceId() {
|
|
|
49472
50317
|
const fresh = randomUUID3();
|
|
49473
50318
|
try {
|
|
49474
50319
|
const dir = dirname21(path2);
|
|
49475
|
-
if (!
|
|
50320
|
+
if (!existsSync32(dir)) {
|
|
49476
50321
|
mkdirSync11(dir, { recursive: true });
|
|
49477
50322
|
}
|
|
49478
50323
|
const tmpPath = `${path2}.tmp.${process.pid}`;
|
|
@@ -49548,11 +50393,11 @@ __export(path_map_exports, {
|
|
|
49548
50393
|
supersededRegistryPath: () => supersededRegistryPath,
|
|
49549
50394
|
touchProjectLocation: () => touchProjectLocation
|
|
49550
50395
|
});
|
|
49551
|
-
import { existsSync as
|
|
50396
|
+
import { existsSync as existsSync33, lstatSync, readdirSync as readdirSync8 } from "node:fs";
|
|
49552
50397
|
import { lstat, readdir as readdir2 } from "node:fs/promises";
|
|
49553
50398
|
import { isAbsolute as isAbsolute5, join as join34, relative as relative3, sep as sep5 } from "node:path";
|
|
49554
50399
|
import { canonicalizePath as canonicalizePath3, readDeclaredProjectIdentity as readDeclaredProjectIdentity4 } from "@cleocode/paths";
|
|
49555
|
-
import { and as and9, desc as desc3, eq as eq12, inArray as
|
|
50400
|
+
import { and as and9, desc as desc3, eq as eq12, inArray as inArray7, ne as ne3 } from "drizzle-orm";
|
|
49556
50401
|
function holdingKey(projectId, path2) {
|
|
49557
50402
|
return `${projectId}\0${path2}`;
|
|
49558
50403
|
}
|
|
@@ -49700,7 +50545,7 @@ function decideEncounterBinding(db, record) {
|
|
|
49700
50545
|
const here = db.select({ state: projectLocations.state, checkoutNonce: projectLocations.checkoutNonce }).from(projectLocations).where(
|
|
49701
50546
|
and9(
|
|
49702
50547
|
eq12(projectLocations.projectId, record.projectId),
|
|
49703
|
-
|
|
50548
|
+
inArray7(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
|
|
49704
50549
|
eq12(projectLocations.path, record.projectPath)
|
|
49705
50550
|
)
|
|
49706
50551
|
).all();
|
|
@@ -49711,7 +50556,7 @@ function decideEncounterBinding(db, record) {
|
|
|
49711
50556
|
const previous = () => db.select({ checkoutNonce: projectLocations.checkoutNonce }).from(projectLocations).where(
|
|
49712
50557
|
and9(
|
|
49713
50558
|
eq12(projectLocations.projectId, record.projectId),
|
|
49714
|
-
|
|
50559
|
+
inArray7(projectLocations.deviceId, [deviceId, LOCAL_DEVICE_SENTINEL]),
|
|
49715
50560
|
eq12(projectLocations.path, oldPath)
|
|
49716
50561
|
)
|
|
49717
50562
|
).all();
|
|
@@ -49759,7 +50604,7 @@ function hasOtherLiveLocation(db, record, deviceId) {
|
|
|
49759
50604
|
ne3(projectLocations.path, record.projectPath)
|
|
49760
50605
|
)
|
|
49761
50606
|
).all().some(
|
|
49762
|
-
(location) => isStrictlyInside(record.projectPath, location.path) &&
|
|
50607
|
+
(location) => isStrictlyInside(record.projectPath, location.path) && existsSync33(location.path) && readDeclaredProjectIdentity4(location.path)?.projectId === record.projectId
|
|
49763
50608
|
);
|
|
49764
50609
|
}
|
|
49765
50610
|
function demoteProjectLocation(db, record, state) {
|
|
@@ -49810,7 +50655,7 @@ function rehomeDisplacedRows(db, projectId, projectPath, deviceId, probed) {
|
|
|
49810
50655
|
).orderBy(desc3(projectLocations.lastSeen)).all();
|
|
49811
50656
|
const present = (path2) => {
|
|
49812
50657
|
const holding = probed?.get(holdingKey(row.projectId, path2));
|
|
49813
|
-
return holding === void 0 ?
|
|
50658
|
+
return holding === void 0 ? existsSync33(path2) : holding === "yes";
|
|
49814
50659
|
};
|
|
49815
50660
|
const home = candidates.find(
|
|
49816
50661
|
(c) => present(c.path) && db.select({ projectId: projectRegistry.projectId }).from(projectRegistry).where(eq12(projectRegistry.projectPath, c.path)).all().length === 0
|
|
@@ -49839,7 +50684,7 @@ async function listProjectCheckouts(projectId, opts = {}) {
|
|
|
49839
50684
|
projectHash: generateProjectHash(row.path),
|
|
49840
50685
|
firstSeen: row.firstSeen,
|
|
49841
50686
|
lastSeen: row.lastSeen,
|
|
49842
|
-
exists: local &&
|
|
50687
|
+
exists: local && existsSync33(row.path),
|
|
49843
50688
|
deviceId: local ? deviceId : row.deviceId,
|
|
49844
50689
|
state: row.state
|
|
49845
50690
|
});
|
|
@@ -49872,7 +50717,7 @@ __export(project_activity_exports, {
|
|
|
49872
50717
|
projectLastActivitySql: () => projectLastActivitySql,
|
|
49873
50718
|
projectLastActivitySqlText: () => projectLastActivitySqlText
|
|
49874
50719
|
});
|
|
49875
|
-
import { eq as eq13, inArray as
|
|
50720
|
+
import { eq as eq13, inArray as inArray8, sql as sql32 } from "drizzle-orm";
|
|
49876
50721
|
function normalizeRegistryTimestamp(value) {
|
|
49877
50722
|
if (value === null || value === void 0 || value.length === 0) return null;
|
|
49878
50723
|
const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$/.test(value) ? `${value.replace(" ", "T")}Z` : value;
|
|
@@ -49901,7 +50746,7 @@ function markProjectsProbed(db, projectIds, now = /* @__PURE__ */ new Date()) {
|
|
|
49901
50746
|
for (let i = 0; i < ids.length; i += PROBED_CHUNK) {
|
|
49902
50747
|
const chunk = ids.slice(i, i + PROBED_CHUNK);
|
|
49903
50748
|
changed += Number(
|
|
49904
|
-
db.update(projectRegistry).set({ lastProbedAt: at }).where(
|
|
50749
|
+
db.update(projectRegistry).set({ lastProbedAt: at }).where(inArray8(projectRegistry.projectId, chunk)).run().changes
|
|
49905
50750
|
);
|
|
49906
50751
|
}
|
|
49907
50752
|
return changed;
|
|
@@ -49934,11 +50779,11 @@ __export(checkout_nonce_exports, {
|
|
|
49934
50779
|
readCheckoutNonce: () => readCheckoutNonce
|
|
49935
50780
|
});
|
|
49936
50781
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
49937
|
-
import { existsSync as
|
|
50782
|
+
import { existsSync as existsSync34, readFileSync as readFileSync12, renameSync as renameSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
49938
50783
|
import { join as join35 } from "node:path";
|
|
49939
50784
|
function readInfo(projectRoot) {
|
|
49940
50785
|
const path2 = join35(projectRoot, ".cleo", "project-info.json");
|
|
49941
|
-
if (!
|
|
50786
|
+
if (!existsSync34(path2)) return null;
|
|
49942
50787
|
try {
|
|
49943
50788
|
const parsed = JSON.parse(readFileSync12(path2, "utf-8"));
|
|
49944
50789
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
@@ -50031,7 +50876,7 @@ __export(paths_exports, {
|
|
|
50031
50876
|
validateProjectRoot: () => validateProjectRoot,
|
|
50032
50877
|
worktreeScope: () => worktreeScope
|
|
50033
50878
|
});
|
|
50034
|
-
import { existsSync as
|
|
50879
|
+
import { existsSync as existsSync35, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
|
|
50035
50880
|
import { createRequire as createRequire12 } from "node:module";
|
|
50036
50881
|
import { homedir as homedir2 } from "node:os";
|
|
50037
50882
|
import { dirname as dirname22, join as join36, resolve as resolve15 } from "node:path";
|
|
@@ -50057,7 +50902,7 @@ function runWithWorktreeScopeFromEnv(fn) {
|
|
|
50057
50902
|
function isProjectInitialized(projectRoot) {
|
|
50058
50903
|
const root = projectRoot ?? getProjectRoot();
|
|
50059
50904
|
const cleoDir = join36(root, ".cleo");
|
|
50060
|
-
return
|
|
50905
|
+
return existsSync35(cleoDir) && existsSync35(join36(cleoDir, "tasks.db"));
|
|
50061
50906
|
}
|
|
50062
50907
|
function getCleoHome() {
|
|
50063
50908
|
return getPlatformPaths().data;
|
|
@@ -50163,7 +51008,7 @@ function _resolveProjectByCwdFromNexus(cwd) {
|
|
|
50163
51008
|
try {
|
|
50164
51009
|
const cleoHome = getCleoHome();
|
|
50165
51010
|
const globalDbPath = join36(cleoHome, "cleo.db");
|
|
50166
|
-
if (!
|
|
51011
|
+
if (!existsSync35(globalDbPath)) return null;
|
|
50167
51012
|
const start = resolve15(cwd ?? process.cwd());
|
|
50168
51013
|
let current = start;
|
|
50169
51014
|
const DatabaseSync3 = _getDatabaseSyncCtor();
|
|
@@ -50326,7 +51171,7 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
50326
51171
|
while (true) {
|
|
50327
51172
|
const gitMarker = join36(current, ".git");
|
|
50328
51173
|
try {
|
|
50329
|
-
if (
|
|
51174
|
+
if (existsSync35(gitMarker)) {
|
|
50330
51175
|
return true;
|
|
50331
51176
|
}
|
|
50332
51177
|
} catch {
|
|
@@ -50404,7 +51249,7 @@ function getCleoGlobalCantAgentsDir() {
|
|
|
50404
51249
|
function getAgentOutputsDir(cwd) {
|
|
50405
51250
|
const projectRoot = getProjectRoot(cwd);
|
|
50406
51251
|
const configPath = join36(projectRoot, ".cleo", "config.json");
|
|
50407
|
-
if (
|
|
51252
|
+
if (existsSync35(configPath)) {
|
|
50408
51253
|
try {
|
|
50409
51254
|
const config = JSON.parse(readFileSync13(configPath, "utf-8"));
|
|
50410
51255
|
if (typeof config.agentOutputs === "object" && config.agentOutputs?.directory) {
|
|
@@ -50437,7 +51282,7 @@ function getManifestPath(cwd) {
|
|
|
50437
51282
|
const configPath = join36(projectRoot, ".cleo", "config.json");
|
|
50438
51283
|
const legacyFileName = ["MANIFEST", "jsonl"].join(".");
|
|
50439
51284
|
let manifestFile = legacyFileName;
|
|
50440
|
-
if (
|
|
51285
|
+
if (existsSync35(configPath)) {
|
|
50441
51286
|
try {
|
|
50442
51287
|
const config = JSON.parse(readFileSync13(configPath, "utf-8"));
|
|
50443
51288
|
const customFile = config.agentOutputs?.manifestFile ?? config.research?.manifestFile;
|
|
@@ -50493,7 +51338,7 @@ function resolveWorktreeRouting(cwdOverride) {
|
|
|
50493
51338
|
while (current !== home && current !== "/" && current !== "") {
|
|
50494
51339
|
const gitPath = join36(current, ".git");
|
|
50495
51340
|
try {
|
|
50496
|
-
if (
|
|
51341
|
+
if (existsSync35(gitPath)) {
|
|
50497
51342
|
const stat3 = statSync10(gitPath);
|
|
50498
51343
|
if (stat3.isFile()) {
|
|
50499
51344
|
worktreePath = current;
|
|
@@ -50532,7 +51377,7 @@ function detectStrayCleoDb(routing) {
|
|
|
50532
51377
|
}
|
|
50533
51378
|
const tasksDbPath = join36(routing.worktreePath, ".cleo", "tasks.db");
|
|
50534
51379
|
try {
|
|
50535
|
-
if (
|
|
51380
|
+
if (existsSync35(tasksDbPath) && statSync10(tasksDbPath).isFile()) {
|
|
50536
51381
|
return tasksDbPath;
|
|
50537
51382
|
}
|
|
50538
51383
|
} catch {
|
|
@@ -50542,7 +51387,7 @@ function detectStrayCleoDb(routing) {
|
|
|
50542
51387
|
async function resolveProjectById(projectId) {
|
|
50543
51388
|
try {
|
|
50544
51389
|
const { getNexusDb: getNexusDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
|
|
50545
|
-
if (!
|
|
51390
|
+
if (!existsSync35(getNexusRegistryDbPath2())) return null;
|
|
50546
51391
|
const { eq: eq16 } = await import("drizzle-orm");
|
|
50547
51392
|
const { projectRegistry: projectRegistry2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
|
|
50548
51393
|
const db = await getNexusDb2();
|
|
@@ -50578,7 +51423,7 @@ function _rowToRegistryEntry(row) {
|
|
|
50578
51423
|
}
|
|
50579
51424
|
function _assertProjectInfoReadable(projectRoot) {
|
|
50580
51425
|
const infoPath = join36(projectRoot, ".cleo", "project-info.json");
|
|
50581
|
-
if (
|
|
51426
|
+
if (existsSync35(infoPath)) JSON.parse(readFileSync13(infoPath, "utf-8"));
|
|
50582
51427
|
}
|
|
50583
51428
|
function startProjectEncounter(key, projectRoot, infoProjectId) {
|
|
50584
51429
|
const inFlight2 = _encountersInFlight.get(key);
|
|
@@ -50627,7 +51472,7 @@ async function recordProjectEncounter(cwd, options = {}) {
|
|
|
50627
51472
|
if (!shouldAutoRegisterProject(project.projectRoot, cleoHome)) return "ephemeral";
|
|
50628
51473
|
const checkout = captureProjectScope(project.projectRoot, worktreeScope.getStore()).worktreeRoot;
|
|
50629
51474
|
const { getNexusRegistryDb: getNexusRegistryDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
|
|
50630
|
-
if (
|
|
51475
|
+
if (existsSync35(getNexusRegistryDbPath2(cleoHome))) {
|
|
50631
51476
|
const { and: and12, eq: eq16 } = await import("drizzle-orm");
|
|
50632
51477
|
const { projectLocations: projectLocations2, projectRegistry: projectRegistry2 } = await Promise.resolve().then(() => (init_nexus_schema(), nexus_schema_exports));
|
|
50633
51478
|
const { currentDeviceId: currentDeviceId2 } = await Promise.resolve().then(() => (init_path_map(), path_map_exports));
|
|
@@ -50653,7 +51498,7 @@ async function recordProjectEncounter(cwd, options = {}) {
|
|
|
50653
51498
|
}
|
|
50654
51499
|
async function markEncounterOpened(cleoHome, projectId) {
|
|
50655
51500
|
const { getNexusRegistryDb: getNexusRegistryDb2, getNexusRegistryDbPath: getNexusRegistryDbPath2 } = await Promise.resolve().then(() => (init_nexus_sqlite(), nexus_sqlite_exports));
|
|
50656
|
-
if (!
|
|
51501
|
+
if (!existsSync35(getNexusRegistryDbPath2(cleoHome))) return;
|
|
50657
51502
|
const { markProjectOpened: markProjectOpened2 } = await Promise.resolve().then(() => (init_project_activity(), project_activity_exports));
|
|
50658
51503
|
markProjectOpened2(await getNexusRegistryDb2(cleoHome), projectId);
|
|
50659
51504
|
}
|
|
@@ -50826,7 +51671,7 @@ var init_eligibility = __esm({
|
|
|
50826
51671
|
|
|
50827
51672
|
// packages/core/src/store/background-jobs.ts
|
|
50828
51673
|
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
|
|
51674
|
+
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
51675
|
function assertOperationWriteFence(db, execution) {
|
|
50831
51676
|
assertOperationJobState(db, execution, "running");
|
|
50832
51677
|
}
|
|
@@ -51801,7 +52646,7 @@ __export(memory_accessor_exports, {
|
|
|
51801
52646
|
logConsolidationComplete: () => logConsolidationComplete,
|
|
51802
52647
|
logConsolidationStart: () => logConsolidationStart
|
|
51803
52648
|
});
|
|
51804
|
-
import { and as and11, asc as asc3, desc as desc4, eq as eq15, gt as gt3, gte as gte2, inArray as
|
|
52649
|
+
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
52650
|
async function getBrainAccessor(cwd) {
|
|
51806
52651
|
const db = await getBrainDb(cwd);
|
|
51807
52652
|
return new BrainDataAccessor(db);
|
|
@@ -52230,8 +53075,8 @@ var init_memory_accessor = __esm({
|
|
|
52230
53075
|
}
|
|
52231
53076
|
if (params.tags && params.tags.length > 0) {
|
|
52232
53077
|
const wantedTags = [...new Set(params.tags)];
|
|
52233
|
-
const matchingIds = this.db.select({ stickyId: brainStickyTags.stickyId }).from(brainStickyTags).where(
|
|
52234
|
-
conditions.push(
|
|
53078
|
+
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}`);
|
|
53079
|
+
conditions.push(inArray10(brainStickyNotes.id, matchingIds));
|
|
52235
53080
|
}
|
|
52236
53081
|
let query = this.db.select().from(brainStickyNotes).orderBy(desc4(brainStickyNotes.createdAt));
|
|
52237
53082
|
if (conditions.length > 0) {
|
|
@@ -52330,8 +53175,8 @@ var init_memory_accessor = __esm({
|
|
|
52330
53175
|
}
|
|
52331
53176
|
if (params.tags && params.tags.length > 0) {
|
|
52332
53177
|
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(
|
|
53178
|
+
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}`);
|
|
53179
|
+
conditions.push(inArray10(t.id, matchingIds));
|
|
52335
53180
|
}
|
|
52336
53181
|
const where = conditions.length > 0 ? and11(...conditions) : void 0;
|
|
52337
53182
|
return this.selectAttention(where, params.limit);
|