@cleocode/core 2026.6.18 → 2026.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/export-document.js +1173 -334
- package/dist/docs/export-document.js.map +3 -3
- package/dist/lifecycle/effective-stage.js +3 -3
- package/dist/lifecycle/rollup.js +3 -3
- package/dist/llm/plugin-facade.js +1218 -383
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/memory/brain-writer-handlers.d.ts.map +1 -1
- package/dist/memory/brain-writer-handlers.js +39 -0
- package/dist/memory/brain-writer-handlers.js.map +1 -1
- package/dist/orchestrate/admission.d.ts +65 -0
- package/dist/orchestrate/admission.d.ts.map +1 -0
- package/dist/orchestrate/admission.js +54 -0
- package/dist/orchestrate/admission.js.map +1 -0
- package/dist/orchestrate/lifecycle-ops.d.ts.map +1 -1
- package/dist/orchestrate/lifecycle-ops.js +10 -0
- package/dist/orchestrate/lifecycle-ops.js.map +1 -1
- package/dist/orchestrate/query-ops.d.ts.map +1 -1
- package/dist/orchestrate/query-ops.js +37 -8
- package/dist/orchestrate/query-ops.js.map +1 -1
- package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
- package/dist/orchestrate/spawn-ops.js +24 -0
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/release/pr-evidence.d.ts +14 -3
- package/dist/release/pr-evidence.d.ts.map +1 -1
- package/dist/release/pr-evidence.js +44 -4
- package/dist/release/pr-evidence.js.map +1 -1
- package/dist/resources/governor.d.ts +133 -0
- package/dist/resources/governor.d.ts.map +1 -0
- package/dist/resources/governor.js +377 -0
- package/dist/resources/governor.js.map +1 -0
- package/dist/resources/supervisor-admit.d.ts +42 -0
- package/dist/resources/supervisor-admit.d.ts.map +1 -0
- package/dist/resources/supervisor-admit.js +136 -0
- package/dist/resources/supervisor-admit.js.map +1 -0
- package/dist/selfimprove/fix-gen.js +1216 -381
- package/dist/selfimprove/fix-gen.js.map +3 -3
- package/dist/sentient/tick.d.ts.map +1 -1
- package/dist/sentient/tick.js +29 -0
- package/dist/sentient/tick.js.map +1 -1
- package/dist/store/agent-registry-store.d.ts.map +1 -1
- package/dist/store/agent-registry-store.js +17 -2
- package/dist/store/agent-registry-store.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +35 -0
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +15 -0
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/tasks-schema.d.ts +2 -0
- package/dist/store/tasks-schema.d.ts.map +1 -1
- package/dist/store/tasks-schema.js +17 -0
- package/dist/store/tasks-schema.js.map +1 -1
- package/dist/store/validation-schemas.d.ts +98 -98
- package/dist/tasks/compute-task-view.js +2 -2
- package/dist/tasks/evidence.d.ts +19 -0
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +32 -2
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/tool-semaphore.d.ts +25 -0
- package/dist/tasks/tool-semaphore.d.ts.map +1 -1
- package/dist/tasks/tool-semaphore.js +68 -1
- package/dist/tasks/tool-semaphore.js.map +1 -1
- package/dist/tasks/update.d.ts +2 -0
- package/dist/tasks/update.d.ts.map +1 -1
- package/dist/tasks/update.js +1 -0
- package/dist/tasks/update.js.map +1 -1
- package/dist/validation/engine-ops.d.ts.map +1 -1
- package/dist/validation/engine-ops.js +33 -7
- package/dist/validation/engine-ops.js.map +1 -1
- package/package.json +12 -12
|
@@ -2049,6 +2049,7 @@ var init_tasks = __esm({
|
|
|
2049
2049
|
severity: { type: "string", enum: ["P0", "P1", "P2", "P3"] },
|
|
2050
2050
|
reason: { type: "string" },
|
|
2051
2051
|
dependsWaiver: { type: "string" },
|
|
2052
|
+
blockedBy: { type: "string" },
|
|
2052
2053
|
clearBlockedBy: { type: "boolean" },
|
|
2053
2054
|
relates: {
|
|
2054
2055
|
type: "array",
|
|
@@ -4748,6 +4749,12 @@ var init_operations_registry = __esm({
|
|
|
4748
4749
|
required: false,
|
|
4749
4750
|
description: "Justification to waive the critical-priority --depends requirement"
|
|
4750
4751
|
},
|
|
4752
|
+
{
|
|
4753
|
+
name: "blockedBy",
|
|
4754
|
+
type: "string",
|
|
4755
|
+
required: false,
|
|
4756
|
+
description: "Set the free-text blockedBy reason (gh#1106)"
|
|
4757
|
+
},
|
|
4751
4758
|
{
|
|
4752
4759
|
name: "clearBlockedBy",
|
|
4753
4760
|
type: "boolean",
|
|
@@ -12571,7 +12578,7 @@ var init_lafs = __esm({
|
|
|
12571
12578
|
|
|
12572
12579
|
// packages/contracts/src/lease-ipc/messages.ts
|
|
12573
12580
|
import { z as z11 } from "zod";
|
|
12574
|
-
var LeaseScopeSchema, LeaseLaneSchema, LeaseAcquireRequestSchema, LeaseReleaseRequestSchema, LeaseRenewRequestSchema, RateCheckRequestSchema, ToolGrantRequestSchema, QueuePriorityClassSchema, QueueAdmitRequestSchema, WorkerHeartbeatRequestSchema, LeaseIpcRequestSchema, LeaseGrantedResponseSchema, LeaseQueuedResponseSchema, LeaseDeniedResponseSchema, RateResultResponseSchema, ToolGrantedResponseSchema, LeaseRevokedResponseSchema, ChildKilledUnresponsiveResponseSchema, QueueAdmitDispositionSchema, QueueAdmitResultResponseSchema, HeartbeatAckResponseSchema, LeaseErrorResponseSchema, LeaseIpcResponseSchema, LeaseIpcRequestEnvelopeSchema, LeaseIpcResponseEnvelopeSchema, LeaseIpcEnvelopeSchema, LEASE_IPC_REQUEST_KINDS, LEASE_IPC_RESPONSE_KINDS, LEASE_IPC_MESSAGE_KINDS;
|
|
12581
|
+
var LeaseScopeSchema, LeaseLaneSchema, LeaseAcquireRequestSchema, LeaseReleaseRequestSchema, LeaseRenewRequestSchema, RateCheckRequestSchema, ToolGrantRequestSchema, QueuePriorityClassSchema, QueueAdmitRequestSchema, WorkerHeartbeatRequestSchema, ResourceAdmitRequestSchema, ResourceReleaseRequestSchema, LeaseIpcRequestSchema, LeaseGrantedResponseSchema, LeaseQueuedResponseSchema, LeaseDeniedResponseSchema, RateResultResponseSchema, ToolGrantedResponseSchema, LeaseRevokedResponseSchema, ChildKilledUnresponsiveResponseSchema, QueueAdmitDispositionSchema, QueueAdmitResultResponseSchema, HeartbeatAckResponseSchema, ResourceAdmitDispositionSchema, ResourceAdmitResultResponseSchema, ResourceReleaseResultResponseSchema, LeaseErrorResponseSchema, LeaseIpcResponseSchema, LeaseIpcRequestEnvelopeSchema, LeaseIpcResponseEnvelopeSchema, LeaseIpcEnvelopeSchema, LEASE_IPC_REQUEST_KINDS, LEASE_IPC_RESPONSE_KINDS, LEASE_IPC_MESSAGE_KINDS;
|
|
12575
12582
|
var init_messages2 = __esm({
|
|
12576
12583
|
"packages/contracts/src/lease-ipc/messages.ts"() {
|
|
12577
12584
|
"use strict";
|
|
@@ -12656,6 +12663,24 @@ var init_messages2 = __esm({
|
|
|
12656
12663
|
/** The worker's own view of whether it is currently inside an LLM call. */
|
|
12657
12664
|
in_flight_llm: z11.boolean()
|
|
12658
12665
|
}).strict();
|
|
12666
|
+
ResourceAdmitRequestSchema = z11.object({
|
|
12667
|
+
/** Tag discriminating this request variant. */
|
|
12668
|
+
kind: z11.literal("resource_admit"),
|
|
12669
|
+
/** The resource class (e.g. `"db-heavy"`, `"full-build"`, `"test-run"`). */
|
|
12670
|
+
class: z11.string().min(1),
|
|
12671
|
+
/** The caller holding the slot — process/worktree-unique; the release key. */
|
|
12672
|
+
holder_id: z11.string().min(1),
|
|
12673
|
+
/** The client-computed budget: the max concurrent holders for this class. */
|
|
12674
|
+
budget: z11.number().int().nonnegative()
|
|
12675
|
+
}).strict();
|
|
12676
|
+
ResourceReleaseRequestSchema = z11.object({
|
|
12677
|
+
/** Tag discriminating this request variant. */
|
|
12678
|
+
kind: z11.literal("resource_release"),
|
|
12679
|
+
/** The resource class the slot belongs to. */
|
|
12680
|
+
class: z11.string().min(1),
|
|
12681
|
+
/** The holder that was admitted (matches the admit `holder_id`). */
|
|
12682
|
+
holder_id: z11.string().min(1)
|
|
12683
|
+
}).strict();
|
|
12659
12684
|
LeaseIpcRequestSchema = z11.discriminatedUnion("kind", [
|
|
12660
12685
|
LeaseAcquireRequestSchema,
|
|
12661
12686
|
LeaseReleaseRequestSchema,
|
|
@@ -12663,7 +12688,9 @@ var init_messages2 = __esm({
|
|
|
12663
12688
|
RateCheckRequestSchema,
|
|
12664
12689
|
ToolGrantRequestSchema,
|
|
12665
12690
|
QueueAdmitRequestSchema,
|
|
12666
|
-
WorkerHeartbeatRequestSchema
|
|
12691
|
+
WorkerHeartbeatRequestSchema,
|
|
12692
|
+
ResourceAdmitRequestSchema,
|
|
12693
|
+
ResourceReleaseRequestSchema
|
|
12667
12694
|
]);
|
|
12668
12695
|
LeaseGrantedResponseSchema = z11.object({
|
|
12669
12696
|
/** Tag discriminating this response variant. */
|
|
@@ -12764,6 +12791,25 @@ var init_messages2 = __esm({
|
|
|
12764
12791
|
/** Tag discriminating this response variant. */
|
|
12765
12792
|
kind: z11.literal("heartbeat_ack")
|
|
12766
12793
|
}).strict();
|
|
12794
|
+
ResourceAdmitDispositionSchema = z11.enum(["admitted", "deferred"]);
|
|
12795
|
+
ResourceAdmitResultResponseSchema = z11.object({
|
|
12796
|
+
/** Tag discriminating this response variant. */
|
|
12797
|
+
kind: z11.literal("resource_admit_result"),
|
|
12798
|
+
/** Whether the heavy op was admitted or deferred. */
|
|
12799
|
+
disposition: ResourceAdmitDispositionSchema,
|
|
12800
|
+
/** Back-off in ms before re-requesting (0 when admitted). */
|
|
12801
|
+
retry_after_ms: z11.number().int().nonnegative(),
|
|
12802
|
+
/** Remaining slots for the class after this decision. */
|
|
12803
|
+
slots_remaining: z11.number().int().nonnegative()
|
|
12804
|
+
}).strict();
|
|
12805
|
+
ResourceReleaseResultResponseSchema = z11.object({
|
|
12806
|
+
/** Tag discriminating this response variant. */
|
|
12807
|
+
kind: z11.literal("resource_release_result"),
|
|
12808
|
+
/** Whether a held slot was actually released (false = no such holder). */
|
|
12809
|
+
released: z11.boolean(),
|
|
12810
|
+
/** Remaining in-flight holders for the class after the release. */
|
|
12811
|
+
slots_remaining: z11.number().int().nonnegative()
|
|
12812
|
+
}).strict();
|
|
12767
12813
|
LeaseErrorResponseSchema = z11.object({
|
|
12768
12814
|
/** Tag discriminating this response variant. */
|
|
12769
12815
|
kind: z11.literal("error"),
|
|
@@ -12782,6 +12828,8 @@ var init_messages2 = __esm({
|
|
|
12782
12828
|
ChildKilledUnresponsiveResponseSchema,
|
|
12783
12829
|
QueueAdmitResultResponseSchema,
|
|
12784
12830
|
HeartbeatAckResponseSchema,
|
|
12831
|
+
ResourceAdmitResultResponseSchema,
|
|
12832
|
+
ResourceReleaseResultResponseSchema,
|
|
12785
12833
|
LeaseErrorResponseSchema
|
|
12786
12834
|
]);
|
|
12787
12835
|
LeaseIpcRequestEnvelopeSchema = z11.object({
|
|
@@ -12815,7 +12863,9 @@ var init_messages2 = __esm({
|
|
|
12815
12863
|
"rate_check",
|
|
12816
12864
|
"tool_grant",
|
|
12817
12865
|
"queue_admit",
|
|
12818
|
-
"worker_heartbeat"
|
|
12866
|
+
"worker_heartbeat",
|
|
12867
|
+
"resource_admit",
|
|
12868
|
+
"resource_release"
|
|
12819
12869
|
];
|
|
12820
12870
|
LEASE_IPC_RESPONSE_KINDS = [
|
|
12821
12871
|
"lease_granted",
|
|
@@ -12827,6 +12877,8 @@ var init_messages2 = __esm({
|
|
|
12827
12877
|
"child_killed_unresponsive",
|
|
12828
12878
|
"queue_admit_result",
|
|
12829
12879
|
"heartbeat_ack",
|
|
12880
|
+
"resource_admit_result",
|
|
12881
|
+
"resource_release_result",
|
|
12830
12882
|
"error"
|
|
12831
12883
|
];
|
|
12832
12884
|
LEASE_IPC_MESSAGE_KINDS = [
|
|
@@ -12837,9 +12889,11 @@ var init_messages2 = __esm({
|
|
|
12837
12889
|
});
|
|
12838
12890
|
|
|
12839
12891
|
// packages/contracts/src/lease-ipc/version.ts
|
|
12892
|
+
var LEASE_IPC_PROTOCOL_VERSION;
|
|
12840
12893
|
var init_version2 = __esm({
|
|
12841
12894
|
"packages/contracts/src/lease-ipc/version.ts"() {
|
|
12842
12895
|
"use strict";
|
|
12896
|
+
LEASE_IPC_PROTOCOL_VERSION = "1.2.0";
|
|
12843
12897
|
}
|
|
12844
12898
|
});
|
|
12845
12899
|
|
|
@@ -14038,6 +14092,25 @@ var init_render = __esm({
|
|
|
14038
14092
|
}
|
|
14039
14093
|
});
|
|
14040
14094
|
|
|
14095
|
+
// packages/contracts/src/resource-governor.ts
|
|
14096
|
+
var RESOURCE_CLASSES, DEFAULT_RESOURCE_RETRY_AFTER_MS;
|
|
14097
|
+
var init_resource_governor = __esm({
|
|
14098
|
+
"packages/contracts/src/resource-governor.ts"() {
|
|
14099
|
+
"use strict";
|
|
14100
|
+
RESOURCE_CLASSES = Object.freeze([
|
|
14101
|
+
"interactive-cli",
|
|
14102
|
+
"agent-session",
|
|
14103
|
+
"llm-call",
|
|
14104
|
+
"test-run",
|
|
14105
|
+
"scoped-build",
|
|
14106
|
+
"full-build",
|
|
14107
|
+
"db-heavy",
|
|
14108
|
+
"background-autonomous"
|
|
14109
|
+
]);
|
|
14110
|
+
DEFAULT_RESOURCE_RETRY_AFTER_MS = 2e3;
|
|
14111
|
+
}
|
|
14112
|
+
});
|
|
14113
|
+
|
|
14041
14114
|
// packages/contracts/src/session.ts
|
|
14042
14115
|
var init_session2 = __esm({
|
|
14043
14116
|
"packages/contracts/src/session.ts"() {
|
|
@@ -15788,6 +15861,7 @@ var init_src = __esm({
|
|
|
15788
15861
|
init_evidence_atoms();
|
|
15789
15862
|
init_plan();
|
|
15790
15863
|
init_render();
|
|
15864
|
+
init_resource_governor();
|
|
15791
15865
|
init_session2();
|
|
15792
15866
|
init_session_journal();
|
|
15793
15867
|
init_status_registry();
|
|
@@ -17818,7 +17892,7 @@ var init_sql = __esm({
|
|
|
17818
17892
|
return new SQL([new StringChunk(str)]);
|
|
17819
17893
|
}
|
|
17820
17894
|
_sql.raw = raw;
|
|
17821
|
-
function
|
|
17895
|
+
function join34(chunks, separator) {
|
|
17822
17896
|
const result = [];
|
|
17823
17897
|
for (const [i, chunk] of chunks.entries()) {
|
|
17824
17898
|
if (i > 0 && separator !== void 0) result.push(separator);
|
|
@@ -17826,7 +17900,7 @@ var init_sql = __esm({
|
|
|
17826
17900
|
}
|
|
17827
17901
|
return new SQL(result);
|
|
17828
17902
|
}
|
|
17829
|
-
_sql.join =
|
|
17903
|
+
_sql.join = join34;
|
|
17830
17904
|
function identifier(value) {
|
|
17831
17905
|
return new Name(value);
|
|
17832
17906
|
}
|
|
@@ -20213,7 +20287,7 @@ var init_select2 = __esm({
|
|
|
20213
20287
|
const baseTableName = this.tableName;
|
|
20214
20288
|
const tableName = getTableLikeName(table);
|
|
20215
20289
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
20216
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
20290
|
+
if (typeof tableName === "string" && this.config.joins?.some((join34) => join34.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
20217
20291
|
if (!this.isPartialSelect) {
|
|
20218
20292
|
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
|
|
20219
20293
|
if (typeof tableName === "string" && !is(table, SQL)) {
|
|
@@ -24023,7 +24097,7 @@ var init_dialect = __esm({
|
|
|
24023
24097
|
if (!joins2) return;
|
|
24024
24098
|
const withEntries = Object.entries(joins2).filter(([_, v]) => v);
|
|
24025
24099
|
if (!withEntries.length) return;
|
|
24026
|
-
return sql.join(withEntries.map(([k,
|
|
24100
|
+
return sql.join(withEntries.map(([k, join34]) => {
|
|
24027
24101
|
const relation = tableConfig.relations[k];
|
|
24028
24102
|
const isSingle2 = is(relation, One);
|
|
24029
24103
|
const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
|
|
@@ -24034,7 +24108,7 @@ var init_dialect = __esm({
|
|
|
24034
24108
|
table: targetTable,
|
|
24035
24109
|
mode: isSingle2 ? "first" : "many",
|
|
24036
24110
|
schema,
|
|
24037
|
-
queryConfig:
|
|
24111
|
+
queryConfig: join34,
|
|
24038
24112
|
tableConfig: schema[relation.targetTableName],
|
|
24039
24113
|
relationWhere: filter2,
|
|
24040
24114
|
isNested: true,
|
|
@@ -24048,7 +24122,7 @@ var init_dialect = __esm({
|
|
|
24048
24122
|
key: k,
|
|
24049
24123
|
selection: innerQuery.selection,
|
|
24050
24124
|
isArray: !isSingle2,
|
|
24051
|
-
isOptional: (relation.optional ?? false) ||
|
|
24125
|
+
isOptional: (relation.optional ?? false) || join34 !== true && !!join34.where
|
|
24052
24126
|
});
|
|
24053
24127
|
const jsonColumns = sql.join(innerQuery.selection.map((s) => {
|
|
24054
24128
|
return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb3}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
|
|
@@ -24869,7 +24943,7 @@ var init_update = __esm({
|
|
|
24869
24943
|
createJoin(joinType) {
|
|
24870
24944
|
return ((table, on) => {
|
|
24871
24945
|
const tableName = getTableLikeName(table);
|
|
24872
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
24946
|
+
if (typeof tableName === "string" && this.config.joins.some((join34) => join34.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
24873
24947
|
if (typeof on === "function") {
|
|
24874
24948
|
const from = this.config.from ? is(table, SQLiteTable) ? table[Table.Symbol.Columns] : is(table, Subquery) ? table._.selectedFields : is(table, SQLiteViewBase) ? table[ViewBaseConfig].selectedFields : void 0 : void 0;
|
|
24875
24949
|
on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
|
|
@@ -25944,8 +26018,8 @@ function probeAndMarkApplied(nativeDb, migration, logSubsystem, eliminatedTables
|
|
|
25944
26018
|
});
|
|
25945
26019
|
if (allAltersPresent && allTablesPresent && allIndexesPresent && allTriggersPresent) {
|
|
25946
26020
|
insertJournalEntry(nativeDb, migration.hash, migration.folderMillis, migration.name ?? "");
|
|
25947
|
-
const
|
|
25948
|
-
|
|
26021
|
+
const log9 = getLogger(logSubsystem);
|
|
26022
|
+
log9.debug(
|
|
25949
26023
|
{
|
|
25950
26024
|
migration: migration.name,
|
|
25951
26025
|
alters: alterTargets.length,
|
|
@@ -26014,14 +26088,14 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26014
26088
|
if (hasOrphanedEntries) {
|
|
26015
26089
|
const dbHashes = new Set(dbEntries.map((e) => e.hash));
|
|
26016
26090
|
const allLocalHashesPresentInDb = localMigrations.every((m) => dbHashes.has(m.hash));
|
|
26017
|
-
const
|
|
26091
|
+
const log9 = getLogger(logSubsystem);
|
|
26018
26092
|
if (allLocalHashesPresentInDb) {
|
|
26019
|
-
|
|
26093
|
+
log9.debug(
|
|
26020
26094
|
{ extra: orphanedEntries.length },
|
|
26021
26095
|
`Migration journal has ${orphanedEntries.length} entries for migrations not known to this install (DB is ahead). Skipping reconciliation.`
|
|
26022
26096
|
);
|
|
26023
26097
|
} else {
|
|
26024
|
-
|
|
26098
|
+
log9.warn(
|
|
26025
26099
|
{ orphaned: orphanedEntries.length },
|
|
26026
26100
|
`Detected ${orphanedEntries.length} true-orphan journal entries from a previous CLEO lineage. Reconciling via DDL probe.`
|
|
26027
26101
|
);
|
|
@@ -26057,8 +26131,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26057
26131
|
if (alterMatches.length === 0) {
|
|
26058
26132
|
const stripped = stripSqlComments(fullSql).trim();
|
|
26059
26133
|
if (stripped === "") {
|
|
26060
|
-
const
|
|
26061
|
-
|
|
26134
|
+
const log9 = getLogger(logSubsystem);
|
|
26135
|
+
log9.debug(
|
|
26062
26136
|
{ migration: migration.name },
|
|
26063
26137
|
`Migration ${migration.name} is a comment-only baseline marker \u2014 marking applied on existing DB.`
|
|
26064
26138
|
);
|
|
@@ -26097,8 +26171,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26097
26171
|
}
|
|
26098
26172
|
}
|
|
26099
26173
|
if (missingColumns.length === 0) {
|
|
26100
|
-
const
|
|
26101
|
-
|
|
26174
|
+
const log9 = getLogger(logSubsystem);
|
|
26175
|
+
log9.warn(
|
|
26102
26176
|
{ migration: migration.name, columns: alterMatches },
|
|
26103
26177
|
`Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
|
|
26104
26178
|
);
|
|
@@ -26106,8 +26180,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26106
26180
|
continue;
|
|
26107
26181
|
}
|
|
26108
26182
|
if (existingColumns.length > 0 && missingColumns.length > 0) {
|
|
26109
|
-
const
|
|
26110
|
-
|
|
26183
|
+
const log9 = getLogger(logSubsystem);
|
|
26184
|
+
log9.warn(
|
|
26111
26185
|
{
|
|
26112
26186
|
migration: migration.name,
|
|
26113
26187
|
existingColumns: existingColumns.map((c) => `${c.table}.${c.column}`),
|
|
@@ -26119,12 +26193,12 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26119
26193
|
if (!tableExists(nativeDb, table)) continue;
|
|
26120
26194
|
try {
|
|
26121
26195
|
nativeDb.exec(`ALTER TABLE ${table} ADD COLUMN ${column}${ddl ? ` ${ddl}` : ""}`);
|
|
26122
|
-
|
|
26196
|
+
log9.warn(
|
|
26123
26197
|
{ migration: migration.name, table, column },
|
|
26124
26198
|
`T920: Added missing column ${table}.${column} to complete partial migration.`
|
|
26125
26199
|
);
|
|
26126
26200
|
} catch {
|
|
26127
|
-
|
|
26201
|
+
log9.warn(
|
|
26128
26202
|
{ migration: migration.name, table, column },
|
|
26129
26203
|
`T920: Could not add missing column ${table}.${column} \u2014 will let Drizzle migrate() handle it.`
|
|
26130
26204
|
);
|
|
@@ -26144,8 +26218,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26144
26218
|
for (const entry of unnamedEntries) {
|
|
26145
26219
|
const migrationName = hashToName.get(entry.hash);
|
|
26146
26220
|
if (!migrationName) continue;
|
|
26147
|
-
const
|
|
26148
|
-
|
|
26221
|
+
const log9 = getLogger(logSubsystem);
|
|
26222
|
+
log9.debug(
|
|
26149
26223
|
{ id: entry.id, hash: entry.hash, name: migrationName },
|
|
26150
26224
|
`Backfilling missing name on journal entry id=${entry.id} (Drizzle v1 beta legacy compat).`
|
|
26151
26225
|
);
|
|
@@ -26229,13 +26303,13 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem, conte
|
|
|
26229
26303
|
const existingCols = new Set(columns.map((c) => c.name));
|
|
26230
26304
|
for (const req of requiredColumns) {
|
|
26231
26305
|
if (!existingCols.has(req.name)) {
|
|
26232
|
-
const
|
|
26306
|
+
const log9 = getLogger(logSubsystem);
|
|
26233
26307
|
const message = `Adding missing column ${tableName}.${req.name} via ALTER TABLE`;
|
|
26234
26308
|
const fields = { column: req.name, context };
|
|
26235
26309
|
if (context === "fresh") {
|
|
26236
|
-
|
|
26310
|
+
log9.error(fields, `${message} \u2014 MIGRATION DEFECT (fresh DB should not need repair)`);
|
|
26237
26311
|
} else {
|
|
26238
|
-
|
|
26312
|
+
log9.warn(fields, message);
|
|
26239
26313
|
}
|
|
26240
26314
|
nativeDb.exec(`ALTER TABLE ${tableName} ADD COLUMN ${req.name} ${req.ddl}`);
|
|
26241
26315
|
}
|
|
@@ -35316,11 +35390,750 @@ var init_cleo_global = __esm({
|
|
|
35316
35390
|
}
|
|
35317
35391
|
});
|
|
35318
35392
|
|
|
35319
|
-
// packages/core/src/
|
|
35393
|
+
// packages/core/src/resources/linux-backend.ts
|
|
35394
|
+
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
35395
|
+
function parsePressureLine(line2) {
|
|
35396
|
+
const avg10Match = /avg10=([\d.]+)/.exec(line2);
|
|
35397
|
+
const avg60Match = /avg60=([\d.]+)/.exec(line2);
|
|
35398
|
+
const avg300Match = /avg300=([\d.]+)/.exec(line2);
|
|
35399
|
+
const totalMatch = /total=(\d+)/.exec(line2);
|
|
35400
|
+
if (!avg10Match?.[1] || !avg60Match?.[1] || !avg300Match?.[1] || !totalMatch?.[1]) {
|
|
35401
|
+
return null;
|
|
35402
|
+
}
|
|
35403
|
+
return {
|
|
35404
|
+
avg10: parseFloat(avg10Match[1]),
|
|
35405
|
+
avg60: parseFloat(avg60Match[1]),
|
|
35406
|
+
avg300: parseFloat(avg300Match[1]),
|
|
35407
|
+
totalUs: parseInt(totalMatch[1], 10)
|
|
35408
|
+
};
|
|
35409
|
+
}
|
|
35410
|
+
function parsePsiFile(content) {
|
|
35411
|
+
const lines = content.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
35412
|
+
let some = null;
|
|
35413
|
+
let full = null;
|
|
35414
|
+
for (const line2 of lines) {
|
|
35415
|
+
if (line2.startsWith("some ")) {
|
|
35416
|
+
some = parsePressureLine(line2);
|
|
35417
|
+
} else if (line2.startsWith("full ")) {
|
|
35418
|
+
full = parsePressureLine(line2);
|
|
35419
|
+
}
|
|
35420
|
+
}
|
|
35421
|
+
if (!some) {
|
|
35422
|
+
return null;
|
|
35423
|
+
}
|
|
35424
|
+
return { some, full };
|
|
35425
|
+
}
|
|
35426
|
+
function parseMemAvailable(content) {
|
|
35427
|
+
for (const line2 of content.split("\n")) {
|
|
35428
|
+
if (line2.startsWith("MemAvailable:")) {
|
|
35429
|
+
const match = /MemAvailable:\s+(\d+)\s+kB/.exec(line2);
|
|
35430
|
+
if (match?.[1]) {
|
|
35431
|
+
return parseInt(match[1], 10) * 1024;
|
|
35432
|
+
}
|
|
35433
|
+
}
|
|
35434
|
+
}
|
|
35435
|
+
return null;
|
|
35436
|
+
}
|
|
35437
|
+
function parseSmapsRollup(content) {
|
|
35438
|
+
let rssKb = null;
|
|
35439
|
+
let pssKb = null;
|
|
35440
|
+
for (const line2 of content.split("\n")) {
|
|
35441
|
+
if (line2.startsWith("Rss:")) {
|
|
35442
|
+
const m = /Rss:\s+(\d+)\s+kB/.exec(line2);
|
|
35443
|
+
if (m?.[1]) rssKb = parseInt(m[1], 10);
|
|
35444
|
+
} else if (line2.startsWith("Pss:")) {
|
|
35445
|
+
const m = /Pss:\s+(\d+)\s+kB/.exec(line2);
|
|
35446
|
+
if (m?.[1]) pssKb = parseInt(m[1], 10);
|
|
35447
|
+
}
|
|
35448
|
+
}
|
|
35449
|
+
if (rssKb === null || pssKb === null) return null;
|
|
35450
|
+
return { rssBytes: rssKb * 1024, pssBytes: pssKb * 1024 };
|
|
35451
|
+
}
|
|
35452
|
+
var defaultReadFile, defaultStat, LinuxResourceBackend;
|
|
35453
|
+
var init_linux_backend = __esm({
|
|
35454
|
+
"packages/core/src/resources/linux-backend.ts"() {
|
|
35455
|
+
"use strict";
|
|
35456
|
+
defaultReadFile = (path, encoding) => readFile2(path, encoding);
|
|
35457
|
+
defaultStat = async (path) => {
|
|
35458
|
+
try {
|
|
35459
|
+
const s = await stat(path);
|
|
35460
|
+
return { size: s.size };
|
|
35461
|
+
} catch {
|
|
35462
|
+
return null;
|
|
35463
|
+
}
|
|
35464
|
+
};
|
|
35465
|
+
LinuxResourceBackend = class {
|
|
35466
|
+
globalPressurePath;
|
|
35467
|
+
cgroupSlicePressurePath;
|
|
35468
|
+
walPaths;
|
|
35469
|
+
readFileFn;
|
|
35470
|
+
statFileFn;
|
|
35471
|
+
constructor(opts = {}) {
|
|
35472
|
+
this.globalPressurePath = opts.globalPressurePath ?? "/proc/pressure/memory";
|
|
35473
|
+
this.cgroupSlicePressurePath = opts.cgroupSlicePressurePath ?? null;
|
|
35474
|
+
this.walPaths = opts.walPaths ?? [];
|
|
35475
|
+
this.readFileFn = opts.readFileFn ?? defaultReadFile;
|
|
35476
|
+
this.statFileFn = opts.statFileFn ?? defaultStat;
|
|
35477
|
+
}
|
|
35478
|
+
/**
|
|
35479
|
+
* Take a bounded point-in-time resource sample.
|
|
35480
|
+
*
|
|
35481
|
+
* Read-count (bounded by Amendment 1):
|
|
35482
|
+
* - 1 read: `/proc/pressure/memory`
|
|
35483
|
+
* - 0–1 reads: slice `memory.pressure` (if configured)
|
|
35484
|
+
* - 1 read: `/proc/meminfo`
|
|
35485
|
+
* - N stat calls: one per WAL path in `walPaths`
|
|
35486
|
+
*
|
|
35487
|
+
* Never spawns a child process.
|
|
35488
|
+
*/
|
|
35489
|
+
async sample() {
|
|
35490
|
+
const sampledAtMs = Date.now();
|
|
35491
|
+
const globalPressure = await this._readPsi(this.globalPressurePath);
|
|
35492
|
+
const pressureAvailable = globalPressure !== null;
|
|
35493
|
+
let slicePressure = null;
|
|
35494
|
+
if (this.cgroupSlicePressurePath) {
|
|
35495
|
+
slicePressure = await this._readPsi(this.cgroupSlicePressurePath);
|
|
35496
|
+
}
|
|
35497
|
+
const memAvailableBytes = await this._readMemAvailable();
|
|
35498
|
+
const walObservations = await this._readWalObservations();
|
|
35499
|
+
return {
|
|
35500
|
+
sampledAtMs,
|
|
35501
|
+
pressureAvailable,
|
|
35502
|
+
memAvailableBytes,
|
|
35503
|
+
globalPressure,
|
|
35504
|
+
slicePressure,
|
|
35505
|
+
walObservations
|
|
35506
|
+
};
|
|
35507
|
+
}
|
|
35508
|
+
/**
|
|
35509
|
+
* Sweep per-child RSS via `/proc/<pid>/smaps_rollup`.
|
|
35510
|
+
*
|
|
35511
|
+
* **STRUCTURALLY SEPARATED from sample()** — smaps_rollup reads are
|
|
35512
|
+
* ms-scale per multi-GB process and must never appear in the hot path.
|
|
35513
|
+
* Call on a separate low-frequency cadence (e.g. every 60s or on
|
|
35514
|
+
* backoff→hold state transition).
|
|
35515
|
+
*
|
|
35516
|
+
* @param pids - PIDs to sweep. Dead/unknown PIDs are silently skipped.
|
|
35517
|
+
*/
|
|
35518
|
+
async sweepChildRss(pids) {
|
|
35519
|
+
const sampledAtMs = Date.now();
|
|
35520
|
+
const entries = [];
|
|
35521
|
+
for (const pid of pids) {
|
|
35522
|
+
try {
|
|
35523
|
+
const content = await this.readFileFn(`/proc/${pid}/smaps_rollup`, "utf-8");
|
|
35524
|
+
const parsed = parseSmapsRollup(content);
|
|
35525
|
+
if (parsed) {
|
|
35526
|
+
entries.push({ pid, ...parsed });
|
|
35527
|
+
}
|
|
35528
|
+
} catch {
|
|
35529
|
+
}
|
|
35530
|
+
}
|
|
35531
|
+
return { sampledAtMs, entries };
|
|
35532
|
+
}
|
|
35533
|
+
// -------------------------------------------------------------------------
|
|
35534
|
+
// Private helpers
|
|
35535
|
+
// -------------------------------------------------------------------------
|
|
35536
|
+
async _readPsi(path) {
|
|
35537
|
+
try {
|
|
35538
|
+
const content = await this.readFileFn(path, "utf-8");
|
|
35539
|
+
return parsePsiFile(content);
|
|
35540
|
+
} catch {
|
|
35541
|
+
return null;
|
|
35542
|
+
}
|
|
35543
|
+
}
|
|
35544
|
+
async _readMemAvailable() {
|
|
35545
|
+
try {
|
|
35546
|
+
const content = await this.readFileFn("/proc/meminfo", "utf-8");
|
|
35547
|
+
return parseMemAvailable(content);
|
|
35548
|
+
} catch {
|
|
35549
|
+
return null;
|
|
35550
|
+
}
|
|
35551
|
+
}
|
|
35552
|
+
async _readWalObservations() {
|
|
35553
|
+
const results = [];
|
|
35554
|
+
for (const walPath of this.walPaths) {
|
|
35555
|
+
const info = await this.statFileFn(walPath);
|
|
35556
|
+
results.push({ walPath, sizeBytes: info?.size ?? null });
|
|
35557
|
+
}
|
|
35558
|
+
return results;
|
|
35559
|
+
}
|
|
35560
|
+
};
|
|
35561
|
+
}
|
|
35562
|
+
});
|
|
35563
|
+
|
|
35564
|
+
// packages/core/src/resources/monitor.ts
|
|
35565
|
+
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
35566
|
+
function resolveThresholds(cfg) {
|
|
35567
|
+
return {
|
|
35568
|
+
holdSomeAvg10: cfg.psi?.holdSomeAvg10 ?? DEFAULTS.holdSomeAvg10,
|
|
35569
|
+
backoffSomeAvg10: cfg.psi?.backoffSomeAvg10 ?? DEFAULTS.backoffSomeAvg10,
|
|
35570
|
+
holdFullAvg10: cfg.psi?.holdFullAvg10 ?? DEFAULTS.holdFullAvg10,
|
|
35571
|
+
backoffFullAvg10: cfg.psi?.backoffFullAvg10 ?? DEFAULTS.backoffFullAvg10,
|
|
35572
|
+
hysteresisPoints: cfg.hysteresisPoints ?? DEFAULTS.hysteresisPoints,
|
|
35573
|
+
headroomBytes: cfg.headroomBytes ?? DEFAULTS.headroomBytes,
|
|
35574
|
+
walWarnThresholdBytes: cfg.walWarnThresholdBytes ?? DEFAULTS.walWarnThresholdBytes,
|
|
35575
|
+
pollIntervalMs: cfg.pollIntervalMs ?? DEFAULTS.pollIntervalMs
|
|
35576
|
+
};
|
|
35577
|
+
}
|
|
35578
|
+
function evaluateState(sample, thresholds, currentState) {
|
|
35579
|
+
if (!sample.pressureAvailable) {
|
|
35580
|
+
if (sample.memAvailableBytes !== null && sample.memAvailableBytes < thresholds.headroomBytes) {
|
|
35581
|
+
return { state: "hold", reason: "degraded: memAvailable below headroom" };
|
|
35582
|
+
}
|
|
35583
|
+
return { state: "ok", reason: "degraded: PSI unavailable, memAvailable sufficient" };
|
|
35584
|
+
}
|
|
35585
|
+
const somePressure = sample.globalPressure?.some ?? sample.slicePressure?.some;
|
|
35586
|
+
const fullPressure = sample.globalPressure?.full ?? sample.slicePressure?.full;
|
|
35587
|
+
const someAvg102 = somePressure?.avg10 ?? 0;
|
|
35588
|
+
const fullAvg10 = fullPressure?.avg10 ?? 0;
|
|
35589
|
+
if (someAvg102 > thresholds.backoffSomeAvg10 || fullAvg10 > thresholds.backoffFullAvg10) {
|
|
35590
|
+
return {
|
|
35591
|
+
state: "backoff",
|
|
35592
|
+
reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 above backoff threshold`
|
|
35593
|
+
};
|
|
35594
|
+
}
|
|
35595
|
+
if (someAvg102 > thresholds.holdSomeAvg10 || fullAvg10 > thresholds.holdFullAvg10) {
|
|
35596
|
+
return {
|
|
35597
|
+
state: "hold",
|
|
35598
|
+
reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 above hold threshold`
|
|
35599
|
+
};
|
|
35600
|
+
}
|
|
35601
|
+
if (currentState !== "ok") {
|
|
35602
|
+
const hysteresisFloor = thresholds.holdSomeAvg10 - thresholds.hysteresisPoints;
|
|
35603
|
+
const fullHysteresisFloor = thresholds.holdFullAvg10 - thresholds.hysteresisPoints;
|
|
35604
|
+
if (someAvg102 > hysteresisFloor || fullAvg10 > fullHysteresisFloor) {
|
|
35605
|
+
const clamped = currentState === "backoff" ? "hold" : currentState;
|
|
35606
|
+
return {
|
|
35607
|
+
state: clamped,
|
|
35608
|
+
reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 hysteresis hold (floor: some ${hysteresisFloor}, full ${fullHysteresisFloor})`
|
|
35609
|
+
};
|
|
35610
|
+
}
|
|
35611
|
+
}
|
|
35612
|
+
return {
|
|
35613
|
+
state: "ok",
|
|
35614
|
+
reason: `some avg10=${someAvg102.toFixed(2)} full avg10=${fullAvg10.toFixed(2)} \u2014 below thresholds`
|
|
35615
|
+
};
|
|
35616
|
+
}
|
|
35617
|
+
var DEFAULTS, ResourceMonitor;
|
|
35618
|
+
var init_monitor = __esm({
|
|
35619
|
+
"packages/core/src/resources/monitor.ts"() {
|
|
35620
|
+
"use strict";
|
|
35621
|
+
init_linux_backend();
|
|
35622
|
+
DEFAULTS = {
|
|
35623
|
+
holdSomeAvg10: 10,
|
|
35624
|
+
backoffSomeAvg10: 20,
|
|
35625
|
+
holdFullAvg10: 5,
|
|
35626
|
+
backoffFullAvg10: 10,
|
|
35627
|
+
hysteresisPoints: 3,
|
|
35628
|
+
headroomBytes: 256 * 1024 * 1024,
|
|
35629
|
+
walWarnThresholdBytes: 256 * 1024 * 1024,
|
|
35630
|
+
pollIntervalMs: 1500
|
|
35631
|
+
};
|
|
35632
|
+
ResourceMonitor = class extends EventEmitter2 {
|
|
35633
|
+
thresholds;
|
|
35634
|
+
backend;
|
|
35635
|
+
_state = "ok";
|
|
35636
|
+
_timer = null;
|
|
35637
|
+
_running = false;
|
|
35638
|
+
constructor(cfg = {}) {
|
|
35639
|
+
super();
|
|
35640
|
+
this.thresholds = resolveThresholds(cfg);
|
|
35641
|
+
this.backend = cfg.backend ?? new LinuxResourceBackend();
|
|
35642
|
+
}
|
|
35643
|
+
// -------------------------------------------------------------------------
|
|
35644
|
+
// Public API
|
|
35645
|
+
// -------------------------------------------------------------------------
|
|
35646
|
+
/**
|
|
35647
|
+
* Current pressure state (only meaningful after at least one sample).
|
|
35648
|
+
*/
|
|
35649
|
+
get state() {
|
|
35650
|
+
return this._state;
|
|
35651
|
+
}
|
|
35652
|
+
/**
|
|
35653
|
+
* `true` while the continuous loop is running.
|
|
35654
|
+
*/
|
|
35655
|
+
get running() {
|
|
35656
|
+
return this._running;
|
|
35657
|
+
}
|
|
35658
|
+
/**
|
|
35659
|
+
* Take a single point-in-time resource sample.
|
|
35660
|
+
*
|
|
35661
|
+
* Safe to call with the daemon off (no child processes, bounded reads).
|
|
35662
|
+
* Does NOT update `this.state` — use {@link startContinuous} for that.
|
|
35663
|
+
*/
|
|
35664
|
+
async sample() {
|
|
35665
|
+
return this.backend.sample();
|
|
35666
|
+
}
|
|
35667
|
+
/**
|
|
35668
|
+
* Start the continuous polling loop.
|
|
35669
|
+
*
|
|
35670
|
+
* Returns a `stop()` function. Calling `stop()` is idempotent.
|
|
35671
|
+
*
|
|
35672
|
+
* Emits:
|
|
35673
|
+
* - `'sample'` on every poll (even if state did not change)
|
|
35674
|
+
* - `'transition'` when `PressureState` changes
|
|
35675
|
+
* - `'error'` if the backend throws (loop continues regardless)
|
|
35676
|
+
*/
|
|
35677
|
+
startContinuous() {
|
|
35678
|
+
if (this._running) {
|
|
35679
|
+
return () => this._stopLoop();
|
|
35680
|
+
}
|
|
35681
|
+
this._running = true;
|
|
35682
|
+
this._scheduleNext();
|
|
35683
|
+
return () => this._stopLoop();
|
|
35684
|
+
}
|
|
35685
|
+
/**
|
|
35686
|
+
* Stop the continuous polling loop. Idempotent.
|
|
35687
|
+
*/
|
|
35688
|
+
stop() {
|
|
35689
|
+
this._stopLoop();
|
|
35690
|
+
}
|
|
35691
|
+
// -------------------------------------------------------------------------
|
|
35692
|
+
// Private loop machinery
|
|
35693
|
+
// -------------------------------------------------------------------------
|
|
35694
|
+
_scheduleNext() {
|
|
35695
|
+
this._timer = setTimeout(() => {
|
|
35696
|
+
void this._tick();
|
|
35697
|
+
}, this.thresholds.pollIntervalMs);
|
|
35698
|
+
if (typeof this._timer.unref === "function") {
|
|
35699
|
+
this._timer.unref();
|
|
35700
|
+
}
|
|
35701
|
+
}
|
|
35702
|
+
async _tick() {
|
|
35703
|
+
if (!this._running) return;
|
|
35704
|
+
try {
|
|
35705
|
+
const sample = await this.backend.sample();
|
|
35706
|
+
this.emit("sample", sample);
|
|
35707
|
+
const { state: newState, reason } = evaluateState(sample, this.thresholds, this._state);
|
|
35708
|
+
if (newState !== this._state) {
|
|
35709
|
+
const transition = {
|
|
35710
|
+
from: this._state,
|
|
35711
|
+
to: newState,
|
|
35712
|
+
sample,
|
|
35713
|
+
reason
|
|
35714
|
+
};
|
|
35715
|
+
this._state = newState;
|
|
35716
|
+
this.emit("transition", transition);
|
|
35717
|
+
}
|
|
35718
|
+
} catch (err) {
|
|
35719
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
35720
|
+
}
|
|
35721
|
+
if (this._running) {
|
|
35722
|
+
this._scheduleNext();
|
|
35723
|
+
}
|
|
35724
|
+
}
|
|
35725
|
+
_stopLoop() {
|
|
35726
|
+
this._running = false;
|
|
35727
|
+
if (this._timer !== null) {
|
|
35728
|
+
clearTimeout(this._timer);
|
|
35729
|
+
this._timer = null;
|
|
35730
|
+
}
|
|
35731
|
+
}
|
|
35732
|
+
};
|
|
35733
|
+
}
|
|
35734
|
+
});
|
|
35735
|
+
|
|
35736
|
+
// packages/core/src/resources/supervisor-admit.ts
|
|
35737
|
+
import { connect } from "node:net";
|
|
35738
|
+
import { join as join7 } from "node:path";
|
|
35739
|
+
import { getCleoHome as getCleoHome2 } from "@cleocode/paths";
|
|
35740
|
+
function resolveSupervisorSocketPath() {
|
|
35741
|
+
return process.env.CLEO_SUPERVISOR_SOCKET ?? join7(getCleoHome2(), SUPERVISOR_SOCKET_NAME);
|
|
35742
|
+
}
|
|
35743
|
+
async function sendResourceAdmit(socketPath, cls, holderId, budget) {
|
|
35744
|
+
const result = await sendLeaseRequest(
|
|
35745
|
+
socketPath,
|
|
35746
|
+
{ kind: "resource_admit", class: cls, holder_id: holderId, budget },
|
|
35747
|
+
"resource_admit_result"
|
|
35748
|
+
);
|
|
35749
|
+
if ("unavailable" in result) return result;
|
|
35750
|
+
if (result.kind === "resource_admit_result") return result;
|
|
35751
|
+
return { unavailable: true, reason: `unexpected response kind: ${result.kind}` };
|
|
35752
|
+
}
|
|
35753
|
+
async function sendResourceRelease(socketPath, cls, holderId) {
|
|
35754
|
+
const result = await sendLeaseRequest(
|
|
35755
|
+
socketPath,
|
|
35756
|
+
{ kind: "resource_release", class: cls, holder_id: holderId },
|
|
35757
|
+
"resource_release_result"
|
|
35758
|
+
);
|
|
35759
|
+
if ("unavailable" in result) return result;
|
|
35760
|
+
if (result.kind === "resource_release_result") return result;
|
|
35761
|
+
return { unavailable: true, reason: `unexpected response kind: ${result.kind}` };
|
|
35762
|
+
}
|
|
35763
|
+
function sendLeaseRequest(socketPath, request, expectedKind) {
|
|
35764
|
+
return new Promise((resolve5) => {
|
|
35765
|
+
const id = `ra-${process.pid}-${request.kind}`;
|
|
35766
|
+
const envelope = LeaseIpcRequestEnvelopeSchema.parse({
|
|
35767
|
+
protocol_version: LEASE_IPC_PROTOCOL_VERSION,
|
|
35768
|
+
id,
|
|
35769
|
+
direction: "request",
|
|
35770
|
+
request
|
|
35771
|
+
});
|
|
35772
|
+
const line2 = `${JSON.stringify(envelope)}
|
|
35773
|
+
`;
|
|
35774
|
+
let settled = false;
|
|
35775
|
+
let buffer = "";
|
|
35776
|
+
const socket = connect(socketPath);
|
|
35777
|
+
const done = (value) => {
|
|
35778
|
+
if (settled) return;
|
|
35779
|
+
settled = true;
|
|
35780
|
+
socket.removeAllListeners();
|
|
35781
|
+
socket.destroy();
|
|
35782
|
+
resolve5(value);
|
|
35783
|
+
};
|
|
35784
|
+
const degrade = (reason) => done({ unavailable: true, reason });
|
|
35785
|
+
socket.setTimeout(REQUEST_TIMEOUT_MS);
|
|
35786
|
+
const connectTimer = setTimeout(
|
|
35787
|
+
() => degrade("supervisor connect timeout"),
|
|
35788
|
+
CONNECT_TIMEOUT_MS
|
|
35789
|
+
);
|
|
35790
|
+
socket.on("connect", () => {
|
|
35791
|
+
clearTimeout(connectTimer);
|
|
35792
|
+
socket.write(line2);
|
|
35793
|
+
});
|
|
35794
|
+
socket.on("timeout", () => degrade("supervisor request timeout"));
|
|
35795
|
+
socket.on("error", (err) => {
|
|
35796
|
+
clearTimeout(connectTimer);
|
|
35797
|
+
degrade(err.message);
|
|
35798
|
+
});
|
|
35799
|
+
socket.on("close", () => {
|
|
35800
|
+
if (!settled) degrade("supervisor closed the connection before responding");
|
|
35801
|
+
});
|
|
35802
|
+
socket.on("data", (chunk) => {
|
|
35803
|
+
buffer += chunk.toString("utf8");
|
|
35804
|
+
const nl = buffer.indexOf("\n");
|
|
35805
|
+
if (nl < 0) return;
|
|
35806
|
+
let json3;
|
|
35807
|
+
try {
|
|
35808
|
+
json3 = JSON.parse(buffer.slice(0, nl));
|
|
35809
|
+
} catch (cause) {
|
|
35810
|
+
degrade(`malformed lease-ipc frame: ${cause instanceof Error ? cause.message : cause}`);
|
|
35811
|
+
return;
|
|
35812
|
+
}
|
|
35813
|
+
const parsed = LeaseIpcResponseEnvelopeSchema.safeParse(json3);
|
|
35814
|
+
if (!parsed.success) {
|
|
35815
|
+
degrade(`off-contract lease-ipc response: ${parsed.error.message}`);
|
|
35816
|
+
return;
|
|
35817
|
+
}
|
|
35818
|
+
const { response } = parsed.data;
|
|
35819
|
+
if (response.kind === expectedKind) {
|
|
35820
|
+
done(response);
|
|
35821
|
+
return;
|
|
35822
|
+
}
|
|
35823
|
+
if (response.kind === "error") {
|
|
35824
|
+
degrade(`${response.code}: ${response.message}`);
|
|
35825
|
+
return;
|
|
35826
|
+
}
|
|
35827
|
+
degrade(`unexpected lease-ipc response kind for ${request.kind}: ${response.kind}`);
|
|
35828
|
+
});
|
|
35829
|
+
});
|
|
35830
|
+
}
|
|
35831
|
+
var SUPERVISOR_SOCKET_NAME, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS;
|
|
35832
|
+
var init_supervisor_admit = __esm({
|
|
35833
|
+
"packages/core/src/resources/supervisor-admit.ts"() {
|
|
35834
|
+
"use strict";
|
|
35835
|
+
init_src();
|
|
35836
|
+
SUPERVISOR_SOCKET_NAME = "cleo-supervisor.sock";
|
|
35837
|
+
CONNECT_TIMEOUT_MS = 250;
|
|
35838
|
+
REQUEST_TIMEOUT_MS = 2e3;
|
|
35839
|
+
}
|
|
35840
|
+
});
|
|
35841
|
+
|
|
35842
|
+
// packages/core/src/resources/governor.ts
|
|
35843
|
+
var governor_exports = {};
|
|
35844
|
+
__export(governor_exports, {
|
|
35845
|
+
ResourceGovernor: () => ResourceGovernor,
|
|
35846
|
+
_resetGovernorStateForTest: () => _resetGovernorStateForTest,
|
|
35847
|
+
computeClassBudget: () => computeClassBudget,
|
|
35848
|
+
governor: () => governor,
|
|
35849
|
+
governorSlotDir: () => governorSlotDir,
|
|
35850
|
+
resolveGovernorMode: () => resolveGovernorMode,
|
|
35851
|
+
slotFileCount: () => slotFileCount
|
|
35852
|
+
});
|
|
35853
|
+
import { existsSync as existsSync4, mkdirSync, readdirSync as readdirSync2, writeFileSync } from "node:fs";
|
|
35854
|
+
import { availableParallelism, totalmem } from "node:os";
|
|
35855
|
+
import { join as join8 } from "node:path";
|
|
35320
35856
|
import lockfile from "proper-lockfile";
|
|
35857
|
+
function log2() {
|
|
35858
|
+
if (_log2 === null) _log2 = getLogger("resource-governor");
|
|
35859
|
+
return _log2;
|
|
35860
|
+
}
|
|
35861
|
+
function resolveGovernorMode() {
|
|
35862
|
+
if (_cachedMode2 !== null) return _cachedMode2;
|
|
35863
|
+
const raw = process.env.CLEO_RESOURCES_MODE;
|
|
35864
|
+
_cachedMode2 = raw === "supervisor" || raw === "local" || raw === "off" ? raw : "local";
|
|
35865
|
+
return _cachedMode2;
|
|
35866
|
+
}
|
|
35867
|
+
function logSupervisorDegradeOnce(reason) {
|
|
35868
|
+
if (_supervisorDegradeLogged) return;
|
|
35869
|
+
_supervisorDegradeLogged = true;
|
|
35870
|
+
log2().info(
|
|
35871
|
+
`CLEO_RESOURCES_MODE=supervisor but the arbiter is unreachable (${reason}); degrading to local-mode admission for the process lifetime.`
|
|
35872
|
+
);
|
|
35873
|
+
}
|
|
35874
|
+
function _resetGovernorStateForTest() {
|
|
35875
|
+
_cachedMode2 = null;
|
|
35876
|
+
_supervisorDegradeLogged = false;
|
|
35877
|
+
}
|
|
35878
|
+
function someAvg10(sample) {
|
|
35879
|
+
const some = sample.globalPressure?.some ?? sample.slicePressure?.some;
|
|
35880
|
+
return some?.avg10 ?? 0;
|
|
35881
|
+
}
|
|
35882
|
+
function computeClassBudget(cls, sample, opts = {}) {
|
|
35883
|
+
if (cls === "interactive-cli") return Number.POSITIVE_INFINITY;
|
|
35884
|
+
const cpus = Math.max(1, opts.cpuCount ?? availableParallelism());
|
|
35885
|
+
const totalBytes = opts.totalMemBytes ?? totalmem();
|
|
35886
|
+
const headroomBytes = (opts.headroomMb ?? 2048) * MB;
|
|
35887
|
+
const hold = opts.holdSomeAvg10 ?? 10;
|
|
35888
|
+
const floor = opts.floorSomeAvg10 ?? 25;
|
|
35889
|
+
const some = someAvg10(sample);
|
|
35890
|
+
const availBytes = sample.memAvailableBytes ?? totalBytes;
|
|
35891
|
+
const fullStall = sample.globalPressure?.full?.avg10 ?? sample.slicePressure?.full?.avg10 ?? 0;
|
|
35892
|
+
const backoff = some > floor || fullStall > 10;
|
|
35893
|
+
switch (cls) {
|
|
35894
|
+
case "full-build":
|
|
35895
|
+
return 1;
|
|
35896
|
+
case "agent-session": {
|
|
35897
|
+
const estRamBytes = (opts.agentEstRamMb ?? 4096) * MB;
|
|
35898
|
+
const byMem = Math.floor((availBytes - headroomBytes) / estRamBytes);
|
|
35899
|
+
return clamp2(1, byMem, Math.max(1, cpus - 2));
|
|
35900
|
+
}
|
|
35901
|
+
case "llm-call":
|
|
35902
|
+
return Math.max(1, cpus - 2);
|
|
35903
|
+
case "test-run":
|
|
35904
|
+
case "scoped-build": {
|
|
35905
|
+
const base = Math.max(1, Math.floor(cpus / 4));
|
|
35906
|
+
if (some > floor) return 1;
|
|
35907
|
+
if (some > hold) return Math.max(1, Math.floor(base / 2));
|
|
35908
|
+
return base;
|
|
35909
|
+
}
|
|
35910
|
+
case "db-heavy":
|
|
35911
|
+
return backoff ? 0 : 1;
|
|
35912
|
+
case "background-autonomous":
|
|
35913
|
+
return some > hold || fullStall > 5 ? 0 : 1;
|
|
35914
|
+
default:
|
|
35915
|
+
return 1;
|
|
35916
|
+
}
|
|
35917
|
+
}
|
|
35918
|
+
function clamp2(lo, v, hi) {
|
|
35919
|
+
return Math.max(lo, Math.min(v, hi));
|
|
35920
|
+
}
|
|
35921
|
+
function governorSlotDir(cls) {
|
|
35922
|
+
return join8(getCleoHome(), "locks", `resource-${cls}`);
|
|
35923
|
+
}
|
|
35924
|
+
function ensureSlotFiles(dir, count) {
|
|
35925
|
+
if (!existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
35926
|
+
const paths = [];
|
|
35927
|
+
for (let i = 0; i < count; i++) {
|
|
35928
|
+
const p = join8(dir, `slot-${i}.lock`);
|
|
35929
|
+
if (!existsSync4(p)) writeFileSync(p, "", { flag: "a" });
|
|
35930
|
+
paths.push(p);
|
|
35931
|
+
}
|
|
35932
|
+
return paths;
|
|
35933
|
+
}
|
|
35934
|
+
function sleep(ms) {
|
|
35935
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
35936
|
+
}
|
|
35937
|
+
function passThroughGrant(cls) {
|
|
35938
|
+
return {
|
|
35939
|
+
deferred: false,
|
|
35940
|
+
class: cls,
|
|
35941
|
+
slot: -1,
|
|
35942
|
+
acquiredAtMs: Date.now(),
|
|
35943
|
+
release: async () => {
|
|
35944
|
+
}
|
|
35945
|
+
};
|
|
35946
|
+
}
|
|
35947
|
+
function deferral(cls, reason, retryAfterMs) {
|
|
35948
|
+
return { deferred: true, class: cls, retryAfterMs, reason };
|
|
35949
|
+
}
|
|
35950
|
+
function supervisorHolderId(cls) {
|
|
35951
|
+
_supervisorHolderSeq += 1;
|
|
35952
|
+
return `${process.pid}:${cls}:${_supervisorHolderSeq}`;
|
|
35953
|
+
}
|
|
35954
|
+
function shuffledIndices(n) {
|
|
35955
|
+
const order = Array.from({ length: n }, (_, i) => i);
|
|
35956
|
+
for (let i = order.length - 1; i > 0; i--) {
|
|
35957
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
35958
|
+
const a = order[i];
|
|
35959
|
+
const b = order[j];
|
|
35960
|
+
if (a !== void 0 && b !== void 0) {
|
|
35961
|
+
order[i] = b;
|
|
35962
|
+
order[j] = a;
|
|
35963
|
+
}
|
|
35964
|
+
}
|
|
35965
|
+
return order;
|
|
35966
|
+
}
|
|
35967
|
+
async function countHeldSlots(cls, budget) {
|
|
35968
|
+
const dir = governorSlotDir(cls);
|
|
35969
|
+
if (!existsSync4(dir)) return 0;
|
|
35970
|
+
const slots = ensureSlotFiles(dir, budget);
|
|
35971
|
+
let held = 0;
|
|
35972
|
+
for (const path of slots) {
|
|
35973
|
+
try {
|
|
35974
|
+
const release = await lockfile.lock(path, { retries: 0, stale: STALE_MS, realpath: false });
|
|
35975
|
+
await release();
|
|
35976
|
+
} catch {
|
|
35977
|
+
held++;
|
|
35978
|
+
}
|
|
35979
|
+
}
|
|
35980
|
+
return held;
|
|
35981
|
+
}
|
|
35982
|
+
function slotFileCount(cls) {
|
|
35983
|
+
const dir = governorSlotDir(cls);
|
|
35984
|
+
if (!existsSync4(dir)) return 0;
|
|
35985
|
+
return readdirSync2(dir).filter((f) => f.startsWith("slot-") && f.endsWith(".lock")).length;
|
|
35986
|
+
}
|
|
35987
|
+
var _log2, _cachedMode2, _supervisorDegradeLogged, MB, STALE_MS, _supervisorHolderSeq, ResourceGovernor, governor;
|
|
35988
|
+
var init_governor = __esm({
|
|
35989
|
+
"packages/core/src/resources/governor.ts"() {
|
|
35990
|
+
"use strict";
|
|
35991
|
+
init_src();
|
|
35992
|
+
init_logger();
|
|
35993
|
+
init_paths();
|
|
35994
|
+
init_monitor();
|
|
35995
|
+
init_supervisor_admit();
|
|
35996
|
+
_log2 = null;
|
|
35997
|
+
_cachedMode2 = null;
|
|
35998
|
+
_supervisorDegradeLogged = false;
|
|
35999
|
+
MB = 1024 * 1024;
|
|
36000
|
+
STALE_MS = 6e5;
|
|
36001
|
+
_supervisorHolderSeq = 0;
|
|
36002
|
+
ResourceGovernor = class {
|
|
36003
|
+
/**
|
|
36004
|
+
* Acquire one slot of `cls`. Returns a {@link ResourceGrant} on success or a
|
|
36005
|
+
* {@link ResourceDeferral} on denial. Never throws for admission control;
|
|
36006
|
+
* only genuinely unexpected I/O errors propagate.
|
|
36007
|
+
*/
|
|
36008
|
+
async acquire(cls, opts = {}) {
|
|
36009
|
+
const mode = resolveGovernorMode();
|
|
36010
|
+
if (mode === "off" || cls === "interactive-cli") {
|
|
36011
|
+
return passThroughGrant(cls);
|
|
36012
|
+
}
|
|
36013
|
+
const sample = opts.sample ?? await (opts.monitor ?? new ResourceMonitor()).sample();
|
|
36014
|
+
const budget = computeClassBudget(cls, sample, opts);
|
|
36015
|
+
if (!Number.isFinite(budget)) return passThroughGrant(cls);
|
|
36016
|
+
if (budget <= 0) {
|
|
36017
|
+
return deferral(
|
|
36018
|
+
cls,
|
|
36019
|
+
`class '${cls}' budget is 0 under current pressure (some avg10=${someAvg10(sample).toFixed(1)})`,
|
|
36020
|
+
DEFAULT_RESOURCE_RETRY_AFTER_MS
|
|
36021
|
+
);
|
|
36022
|
+
}
|
|
36023
|
+
if (mode === "supervisor") {
|
|
36024
|
+
const viaSupervisor = await this.acquireViaSupervisor(cls, Math.floor(budget));
|
|
36025
|
+
if (viaSupervisor !== null) return viaSupervisor;
|
|
36026
|
+
}
|
|
36027
|
+
const dir = governorSlotDir(cls);
|
|
36028
|
+
const slots = ensureSlotFiles(dir, budget);
|
|
36029
|
+
const blocking = opts.blocking ?? true;
|
|
36030
|
+
const timeoutMs = opts.timeoutMs ?? 36e5;
|
|
36031
|
+
const pollMs = opts.pollMs ?? 200;
|
|
36032
|
+
const startedAt = Date.now();
|
|
36033
|
+
do {
|
|
36034
|
+
const order = shuffledIndices(slots.length);
|
|
36035
|
+
for (const idx of order) {
|
|
36036
|
+
const path = slots[idx];
|
|
36037
|
+
if (!path) continue;
|
|
36038
|
+
try {
|
|
36039
|
+
const release = await lockfile.lock(path, {
|
|
36040
|
+
retries: 0,
|
|
36041
|
+
stale: STALE_MS,
|
|
36042
|
+
realpath: false
|
|
36043
|
+
});
|
|
36044
|
+
let released = false;
|
|
36045
|
+
return {
|
|
36046
|
+
deferred: false,
|
|
36047
|
+
class: cls,
|
|
36048
|
+
slot: idx,
|
|
36049
|
+
acquiredAtMs: Date.now(),
|
|
36050
|
+
release: async () => {
|
|
36051
|
+
if (released) return;
|
|
36052
|
+
released = true;
|
|
36053
|
+
try {
|
|
36054
|
+
await release();
|
|
36055
|
+
} catch {
|
|
36056
|
+
}
|
|
36057
|
+
}
|
|
36058
|
+
};
|
|
36059
|
+
} catch {
|
|
36060
|
+
}
|
|
36061
|
+
}
|
|
36062
|
+
if (!blocking) break;
|
|
36063
|
+
await sleep(pollMs);
|
|
36064
|
+
} while (Date.now() - startedAt < timeoutMs);
|
|
36065
|
+
return deferral(
|
|
36066
|
+
cls,
|
|
36067
|
+
`class '${cls}' is at capacity (${budget} slot(s)); ` + (blocking ? `timed out after ${timeoutMs}ms` : "no slot free"),
|
|
36068
|
+
Math.min(pollMs * 4, DEFAULT_RESOURCE_RETRY_AFTER_MS)
|
|
36069
|
+
);
|
|
36070
|
+
}
|
|
36071
|
+
/**
|
|
36072
|
+
* Route an admission through the supervisor's central `resource_admit` verb.
|
|
36073
|
+
* Returns a grant (whose `release` calls `resource_release`) or a deferral, or
|
|
36074
|
+
* `null` when the supervisor is unreachable so the caller degrades to the
|
|
36075
|
+
* local slot engine. Never throws — a dead arbiter never deadlocks work.
|
|
36076
|
+
*
|
|
36077
|
+
* @task T12001
|
|
36078
|
+
*/
|
|
36079
|
+
async acquireViaSupervisor(cls, budget) {
|
|
36080
|
+
const socketPath = resolveSupervisorSocketPath();
|
|
36081
|
+
const holderId = supervisorHolderId(cls);
|
|
36082
|
+
const reply = await sendResourceAdmit(socketPath, cls, holderId, budget);
|
|
36083
|
+
if ("unavailable" in reply) {
|
|
36084
|
+
logSupervisorDegradeOnce(reply.reason);
|
|
36085
|
+
return null;
|
|
36086
|
+
}
|
|
36087
|
+
if (reply.disposition === "deferred") {
|
|
36088
|
+
return deferral(
|
|
36089
|
+
cls,
|
|
36090
|
+
`class '${cls}' deferred by supervisor (budget ${budget})`,
|
|
36091
|
+
reply.retry_after_ms || DEFAULT_RESOURCE_RETRY_AFTER_MS
|
|
36092
|
+
);
|
|
36093
|
+
}
|
|
36094
|
+
let released = false;
|
|
36095
|
+
return {
|
|
36096
|
+
deferred: false,
|
|
36097
|
+
class: cls,
|
|
36098
|
+
slot: 0,
|
|
36099
|
+
acquiredAtMs: Date.now(),
|
|
36100
|
+
release: async () => {
|
|
36101
|
+
if (released) return;
|
|
36102
|
+
released = true;
|
|
36103
|
+
await sendResourceRelease(socketPath, cls, holderId).catch(() => {
|
|
36104
|
+
});
|
|
36105
|
+
}
|
|
36106
|
+
};
|
|
36107
|
+
}
|
|
36108
|
+
/** Non-blocking single-pass acquire (admission semantics). */
|
|
36109
|
+
async tryAcquire(cls, opts = {}) {
|
|
36110
|
+
return this.acquire(cls, { ...opts, blocking: false });
|
|
36111
|
+
}
|
|
36112
|
+
/**
|
|
36113
|
+
* Currently-grantable slot count for `cls` = budget − held. Held is the count
|
|
36114
|
+
* of slot files currently locked. `Infinity` for ungated classes.
|
|
36115
|
+
*/
|
|
36116
|
+
async available(cls, opts = {}) {
|
|
36117
|
+
if (resolveGovernorMode() === "off" || cls === "interactive-cli") {
|
|
36118
|
+
return Number.POSITIVE_INFINITY;
|
|
36119
|
+
}
|
|
36120
|
+
const sample = opts.sample ?? await (opts.monitor ?? new ResourceMonitor()).sample();
|
|
36121
|
+
const budget = computeClassBudget(cls, sample, opts);
|
|
36122
|
+
if (!Number.isFinite(budget)) return Number.POSITIVE_INFINITY;
|
|
36123
|
+
if (budget <= 0) return 0;
|
|
36124
|
+
const held = await countHeldSlots(cls, budget);
|
|
36125
|
+
return Math.max(0, budget - held);
|
|
36126
|
+
}
|
|
36127
|
+
};
|
|
36128
|
+
governor = new ResourceGovernor();
|
|
36129
|
+
}
|
|
36130
|
+
});
|
|
36131
|
+
|
|
36132
|
+
// packages/core/src/store/lock.ts
|
|
36133
|
+
import lockfile2 from "proper-lockfile";
|
|
35321
36134
|
async function acquireLock(filePath, options) {
|
|
35322
36135
|
try {
|
|
35323
|
-
const release = await
|
|
36136
|
+
const release = await lockfile2.lock(filePath, {
|
|
35324
36137
|
...DEFAULT_LOCK_OPTIONS,
|
|
35325
36138
|
...options?.stale !== void 0 && { stale: options.stale },
|
|
35326
36139
|
...options?.retries !== void 0 && {
|
|
@@ -35366,7 +36179,7 @@ var init_lock = __esm({
|
|
|
35366
36179
|
});
|
|
35367
36180
|
|
|
35368
36181
|
// packages/core/src/store/atomic.ts
|
|
35369
|
-
import { mkdir, readFile as
|
|
36182
|
+
import { mkdir, readFile as readFile3, rename, unlink } from "node:fs/promises";
|
|
35370
36183
|
import { dirname as dirname4 } from "node:path";
|
|
35371
36184
|
import writeFileAtomic from "write-file-atomic";
|
|
35372
36185
|
async function atomicWrite(filePath, data, options) {
|
|
@@ -35382,7 +36195,7 @@ async function atomicWrite(filePath, data, options) {
|
|
|
35382
36195
|
}
|
|
35383
36196
|
async function safeReadFile(filePath) {
|
|
35384
36197
|
try {
|
|
35385
|
-
return await
|
|
36198
|
+
return await readFile3(filePath, "utf8");
|
|
35386
36199
|
} catch (err) {
|
|
35387
36200
|
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
35388
36201
|
return null;
|
|
@@ -35403,34 +36216,34 @@ var init_atomic = __esm({
|
|
|
35403
36216
|
});
|
|
35404
36217
|
|
|
35405
36218
|
// packages/core/src/store/backup.ts
|
|
35406
|
-
import { copyFile, rename as fsRename, mkdir as mkdir2, readdir, stat, unlink as unlink2 } from "node:fs/promises";
|
|
35407
|
-
import { basename, join as
|
|
36219
|
+
import { copyFile, rename as fsRename, mkdir as mkdir2, readdir, stat as stat2, unlink as unlink2 } from "node:fs/promises";
|
|
36220
|
+
import { basename, join as join9 } from "node:path";
|
|
35408
36221
|
async function createBackup(filePath, backupDir, maxBackups = DEFAULT_MAX_BACKUPS) {
|
|
35409
36222
|
try {
|
|
35410
36223
|
await mkdir2(backupDir, { recursive: true });
|
|
35411
36224
|
const fileName = basename(filePath);
|
|
35412
36225
|
try {
|
|
35413
|
-
await
|
|
36226
|
+
await stat2(filePath);
|
|
35414
36227
|
} catch {
|
|
35415
36228
|
throw new CleoError(3 /* FILE_ERROR */, `Cannot backup: source file not found: ${filePath}`);
|
|
35416
36229
|
}
|
|
35417
36230
|
for (let i = maxBackups; i >= 1; i--) {
|
|
35418
|
-
const current =
|
|
36231
|
+
const current = join9(backupDir, `${fileName}.${i}`);
|
|
35419
36232
|
if (i === maxBackups) {
|
|
35420
36233
|
try {
|
|
35421
36234
|
await unlink2(current);
|
|
35422
36235
|
} catch {
|
|
35423
36236
|
}
|
|
35424
36237
|
} else {
|
|
35425
|
-
const next =
|
|
36238
|
+
const next = join9(backupDir, `${fileName}.${i + 1}`);
|
|
35426
36239
|
try {
|
|
35427
|
-
await
|
|
36240
|
+
await stat2(current);
|
|
35428
36241
|
await fsRename(current, next);
|
|
35429
36242
|
} catch {
|
|
35430
36243
|
}
|
|
35431
36244
|
}
|
|
35432
36245
|
}
|
|
35433
|
-
const backupPath =
|
|
36246
|
+
const backupPath = join9(backupDir, `${fileName}.1`);
|
|
35434
36247
|
await copyFile(filePath, backupPath);
|
|
35435
36248
|
return backupPath;
|
|
35436
36249
|
} catch (err) {
|
|
@@ -35709,8 +36522,8 @@ var init_json2 = __esm({
|
|
|
35709
36522
|
});
|
|
35710
36523
|
|
|
35711
36524
|
// packages/core/src/scaffold/ensure-config.ts
|
|
35712
|
-
import { existsSync as
|
|
35713
|
-
import { basename as basename2, dirname as dirname5, join as
|
|
36525
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
|
|
36526
|
+
import { basename as basename2, dirname as dirname5, join as join10, resolve as resolve2 } from "node:path";
|
|
35714
36527
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
35715
36528
|
function getPackageRoot() {
|
|
35716
36529
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
@@ -35718,7 +36531,7 @@ function getPackageRoot() {
|
|
|
35718
36531
|
}
|
|
35719
36532
|
function getCleoVersion() {
|
|
35720
36533
|
try {
|
|
35721
|
-
const pkgPath =
|
|
36534
|
+
const pkgPath = join10(getPackageRoot(), "package.json");
|
|
35722
36535
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
35723
36536
|
return pkg.version ?? "0.0.0";
|
|
35724
36537
|
} catch {
|
|
@@ -35737,25 +36550,25 @@ var init_ensure_config = __esm({
|
|
|
35737
36550
|
// packages/core/src/store/exodus/archive.ts
|
|
35738
36551
|
import {
|
|
35739
36552
|
copyFileSync as copyFileSync2,
|
|
35740
|
-
existsSync as
|
|
35741
|
-
mkdirSync,
|
|
36553
|
+
existsSync as existsSync6,
|
|
36554
|
+
mkdirSync as mkdirSync2,
|
|
35742
36555
|
renameSync,
|
|
35743
36556
|
unlinkSync,
|
|
35744
|
-
writeFileSync
|
|
36557
|
+
writeFileSync as writeFileSync2
|
|
35745
36558
|
} from "node:fs";
|
|
35746
|
-
import { basename as basename3, join as
|
|
36559
|
+
import { basename as basename3, join as join11 } from "node:path";
|
|
35747
36560
|
function scopeBaseDir(scope, cwd) {
|
|
35748
36561
|
return scope === "project" ? resolveCleoDir(cwd) : getCleoHome();
|
|
35749
36562
|
}
|
|
35750
36563
|
function exodusArchiveDir(scope, cwd) {
|
|
35751
|
-
return
|
|
36564
|
+
return join11(scopeBaseDir(scope, cwd), ARCHIVE_DIR_NAME);
|
|
35752
36565
|
}
|
|
35753
36566
|
function exodusMarkerPath(scope, cwd) {
|
|
35754
|
-
return
|
|
36567
|
+
return join11(scopeBaseDir(scope, cwd), MARKER_FILENAME_BY_SCOPE[scope]);
|
|
35755
36568
|
}
|
|
35756
36569
|
function hasExodusCompleteMarker(scope, cwd) {
|
|
35757
36570
|
try {
|
|
35758
|
-
return
|
|
36571
|
+
return existsSync6(exodusMarkerPath(scope, cwd));
|
|
35759
36572
|
} catch {
|
|
35760
36573
|
return false;
|
|
35761
36574
|
}
|
|
@@ -35763,7 +36576,7 @@ function hasExodusCompleteMarker(scope, cwd) {
|
|
|
35763
36576
|
function writeExodusCompleteMarker(scope, archivedSources, cwd) {
|
|
35764
36577
|
const markerPath = exodusMarkerPath(scope, cwd);
|
|
35765
36578
|
const baseDir = scopeBaseDir(scope, cwd);
|
|
35766
|
-
|
|
36579
|
+
mkdirSync2(baseDir, { recursive: true });
|
|
35767
36580
|
const marker16 = {
|
|
35768
36581
|
version: 1,
|
|
35769
36582
|
scope,
|
|
@@ -35772,17 +36585,17 @@ function writeExodusCompleteMarker(scope, archivedSources, cwd) {
|
|
|
35772
36585
|
archivedSources: [...archivedSources]
|
|
35773
36586
|
};
|
|
35774
36587
|
const tmpPath = `${markerPath}.tmp`;
|
|
35775
|
-
|
|
36588
|
+
writeFileSync2(tmpPath, JSON.stringify(marker16, null, 2) + "\n", "utf8");
|
|
35776
36589
|
renameSync(tmpPath, markerPath);
|
|
35777
|
-
|
|
36590
|
+
log3.info({ scope, markerPath, archivedSources }, "exodus: wrote completion marker");
|
|
35778
36591
|
return markerPath;
|
|
35779
36592
|
}
|
|
35780
36593
|
function moveFileInto(srcPath, destDir) {
|
|
35781
|
-
|
|
35782
|
-
let dest =
|
|
35783
|
-
if (
|
|
36594
|
+
mkdirSync2(destDir, { recursive: true });
|
|
36595
|
+
let dest = join11(destDir, basename3(srcPath));
|
|
36596
|
+
if (existsSync6(dest)) {
|
|
35784
36597
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
|
|
35785
|
-
dest =
|
|
36598
|
+
dest = join11(destDir, `${basename3(srcPath)}.${stamp}`);
|
|
35786
36599
|
}
|
|
35787
36600
|
try {
|
|
35788
36601
|
renameSync(srcPath, dest);
|
|
@@ -35793,25 +36606,25 @@ function moveFileInto(srcPath, destDir) {
|
|
|
35793
36606
|
return dest;
|
|
35794
36607
|
}
|
|
35795
36608
|
function archiveSourceDb(source, cwd) {
|
|
35796
|
-
if (!
|
|
36609
|
+
if (!existsSync6(source.path)) {
|
|
35797
36610
|
return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
|
|
35798
36611
|
}
|
|
35799
36612
|
const destDir = exodusArchiveDir(source.targetScope, cwd);
|
|
35800
36613
|
const archivedTo = moveFileInto(source.path, destDir);
|
|
35801
36614
|
for (const suffix of SIDECAR_SUFFIXES) {
|
|
35802
36615
|
const sidecar = `${source.path}${suffix}`;
|
|
35803
|
-
if (
|
|
36616
|
+
if (existsSync6(sidecar)) {
|
|
35804
36617
|
try {
|
|
35805
36618
|
moveFileInto(sidecar, destDir);
|
|
35806
36619
|
} catch (err) {
|
|
35807
|
-
|
|
36620
|
+
log3.warn(
|
|
35808
36621
|
{ err, sidecar, sourceName: source.name },
|
|
35809
36622
|
"exodus-archive: failed to archive sidecar (non-fatal)"
|
|
35810
36623
|
);
|
|
35811
36624
|
}
|
|
35812
36625
|
}
|
|
35813
36626
|
}
|
|
35814
|
-
|
|
36627
|
+
log3.info(
|
|
35815
36628
|
{ sourceName: source.name, sourcePath: source.path, archivedTo, scope: source.targetScope },
|
|
35816
36629
|
"exodus-archive: archived legacy source DB"
|
|
35817
36630
|
);
|
|
@@ -35846,7 +36659,7 @@ function detectStrandedResidue(sources, cwd) {
|
|
|
35846
36659
|
const stranded = [];
|
|
35847
36660
|
for (const source of sources) {
|
|
35848
36661
|
if (!markedScopes.has(source.targetScope)) continue;
|
|
35849
|
-
if (
|
|
36662
|
+
if (existsSync6(source.path)) {
|
|
35850
36663
|
stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
|
|
35851
36664
|
}
|
|
35852
36665
|
}
|
|
@@ -35862,14 +36675,14 @@ function archiveStrandedResidue(stranded, sources, cwd) {
|
|
|
35862
36675
|
}
|
|
35863
36676
|
return results;
|
|
35864
36677
|
}
|
|
35865
|
-
var
|
|
36678
|
+
var log3, ARCHIVE_DIR_NAME, MARKER_FILENAME_BY_SCOPE, SIDECAR_SUFFIXES;
|
|
35866
36679
|
var init_archive2 = __esm({
|
|
35867
36680
|
"packages/core/src/store/exodus/archive.ts"() {
|
|
35868
36681
|
"use strict";
|
|
35869
36682
|
init_logger();
|
|
35870
36683
|
init_paths();
|
|
35871
36684
|
init_ensure_config();
|
|
35872
|
-
|
|
36685
|
+
log3 = getLogger("exodus-archive");
|
|
35873
36686
|
ARCHIVE_DIR_NAME = "_archive";
|
|
35874
36687
|
MARKER_FILENAME_BY_SCOPE = {
|
|
35875
36688
|
project: "exodus-complete",
|
|
@@ -36263,7 +37076,7 @@ var init_table_name_map = __esm({
|
|
|
36263
37076
|
});
|
|
36264
37077
|
|
|
36265
37078
|
// packages/core/src/store/exodus/count-parity.ts
|
|
36266
|
-
import { existsSync as
|
|
37079
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
36267
37080
|
function listTables(db) {
|
|
36268
37081
|
return db.prepare(
|
|
36269
37082
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
|
|
@@ -36284,14 +37097,14 @@ function rowCount(db, tableName) {
|
|
|
36284
37097
|
function computeCountParity(sources, projectDbPath, globalDbPath) {
|
|
36285
37098
|
const entries = [];
|
|
36286
37099
|
let skipped = 0;
|
|
36287
|
-
if (!
|
|
37100
|
+
if (!existsSync7(projectDbPath) || !existsSync7(globalDbPath)) {
|
|
36288
37101
|
return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
|
|
36289
37102
|
}
|
|
36290
37103
|
const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
|
|
36291
37104
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
36292
37105
|
try {
|
|
36293
37106
|
for (const src of sources) {
|
|
36294
|
-
if (!
|
|
37107
|
+
if (!existsSync7(src.path)) continue;
|
|
36295
37108
|
const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
36296
37109
|
try {
|
|
36297
37110
|
for (const legacyTable of listTables(srcSnap.db)) {
|
|
@@ -36330,27 +37143,27 @@ function computeCountParity(sources, projectDbPath, globalDbPath) {
|
|
|
36330
37143
|
}
|
|
36331
37144
|
const deficits = entries.filter((e) => e.deficit > 0);
|
|
36332
37145
|
if (deficits.length > 0) {
|
|
36333
|
-
|
|
37146
|
+
log4.warn(
|
|
36334
37147
|
{ deficitCount: deficits.length, sample: deficits.slice(0, 5) },
|
|
36335
37148
|
`exodus count-parity: ${deficits.length} table(s) have FEWER rows in the consolidated target than the legacy source`
|
|
36336
37149
|
);
|
|
36337
37150
|
}
|
|
36338
37151
|
return { ok: deficits.length === 0, entries, deficits, checked: entries.length, skipped };
|
|
36339
37152
|
}
|
|
36340
|
-
var
|
|
37153
|
+
var log4;
|
|
36341
37154
|
var init_count_parity = __esm({
|
|
36342
37155
|
"packages/core/src/store/exodus/count-parity.ts"() {
|
|
36343
37156
|
"use strict";
|
|
36344
37157
|
init_logger();
|
|
36345
37158
|
init_open_cleo_db();
|
|
36346
37159
|
init_table_name_map();
|
|
36347
|
-
|
|
37160
|
+
log4 = getLogger("exodus-count-parity");
|
|
36348
37161
|
}
|
|
36349
37162
|
});
|
|
36350
37163
|
|
|
36351
37164
|
// packages/core/src/store/exodus/plan.ts
|
|
36352
|
-
import { existsSync as
|
|
36353
|
-
import { join as
|
|
37165
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3, statfsSync, statSync } from "node:fs";
|
|
37166
|
+
import { join as join12 } from "node:path";
|
|
36354
37167
|
function computeRequiredBytes(totalSourceBytes, largestSourceBytes) {
|
|
36355
37168
|
return Math.ceil(STAGING_HEADROOM_FACTOR * largestSourceBytes) + totalSourceBytes;
|
|
36356
37169
|
}
|
|
@@ -36361,33 +37174,33 @@ function buildSourceDescriptors(cwd) {
|
|
|
36361
37174
|
// Project-tier — go into consolidated project-scope cleo.db
|
|
36362
37175
|
{
|
|
36363
37176
|
name: "tasks",
|
|
36364
|
-
path:
|
|
37177
|
+
path: join12(cleoDir, "tasks.db"),
|
|
36365
37178
|
targetScope: "project"
|
|
36366
37179
|
},
|
|
36367
37180
|
{
|
|
36368
37181
|
name: "brain (project)",
|
|
36369
|
-
path:
|
|
37182
|
+
path: join12(cleoDir, "brain.db"),
|
|
36370
37183
|
targetScope: "project"
|
|
36371
37184
|
},
|
|
36372
37185
|
{
|
|
36373
37186
|
name: "conduit",
|
|
36374
|
-
path:
|
|
37187
|
+
path: join12(cleoDir, "conduit.db"),
|
|
36375
37188
|
targetScope: "project"
|
|
36376
37189
|
},
|
|
36377
37190
|
// Global-tier — go into consolidated global-scope cleo.db
|
|
36378
37191
|
{
|
|
36379
37192
|
name: "nexus",
|
|
36380
|
-
path:
|
|
37193
|
+
path: join12(cleoHome, "nexus.db"),
|
|
36381
37194
|
targetScope: "global"
|
|
36382
37195
|
},
|
|
36383
37196
|
{
|
|
36384
37197
|
name: "signaldock",
|
|
36385
|
-
path:
|
|
37198
|
+
path: join12(cleoHome, "signaldock.db"),
|
|
36386
37199
|
targetScope: "global"
|
|
36387
37200
|
},
|
|
36388
37201
|
{
|
|
36389
37202
|
name: "skills",
|
|
36390
|
-
path:
|
|
37203
|
+
path: join12(cleoHome, "skills.db"),
|
|
36391
37204
|
targetScope: "global"
|
|
36392
37205
|
}
|
|
36393
37206
|
];
|
|
@@ -36413,10 +37226,10 @@ function deriveStagingDirName() {
|
|
|
36413
37226
|
}
|
|
36414
37227
|
function findExistingStaging(cleoDir) {
|
|
36415
37228
|
try {
|
|
36416
|
-
const entries =
|
|
37229
|
+
const entries = readdirSync3(cleoDir, { withFileTypes: true });
|
|
36417
37230
|
const stagingDirs = entries.filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => e.name).sort().reverse();
|
|
36418
37231
|
if (stagingDirs.length > 0) {
|
|
36419
|
-
return
|
|
37232
|
+
return join12(cleoDir, stagingDirs[0]);
|
|
36420
37233
|
}
|
|
36421
37234
|
} catch {
|
|
36422
37235
|
}
|
|
@@ -36432,7 +37245,7 @@ function buildExodusPlan(cwd) {
|
|
|
36432
37245
|
const availableBytes = getAvailableBytes(cleoDir);
|
|
36433
37246
|
const diskPreflight = totalSourceBytes === 0 || availableBytes >= requiredBytes;
|
|
36434
37247
|
const existingStaging = findExistingStaging(cleoDir);
|
|
36435
|
-
const stagingDir = existingStaging ??
|
|
37248
|
+
const stagingDir = existingStaging ?? join12(cleoDir, deriveStagingDirName());
|
|
36436
37249
|
const resumeFromStaging = existingStaging !== null;
|
|
36437
37250
|
const projectDbPath = resolveDualScopeDbPath("project", cwd);
|
|
36438
37251
|
const globalDbPath = resolveDualScopeDbPath("global");
|
|
@@ -36451,7 +37264,7 @@ function buildExodusPlan(cwd) {
|
|
|
36451
37264
|
};
|
|
36452
37265
|
}
|
|
36453
37266
|
function sourcesPresent(sources) {
|
|
36454
|
-
return sources.some((s) =>
|
|
37267
|
+
return sources.some((s) => existsSync8(s.path));
|
|
36455
37268
|
}
|
|
36456
37269
|
var STAGING_HEADROOM_FACTOR, STAGING_COPY_SKIP_THRESHOLD_BYTES;
|
|
36457
37270
|
var init_plan2 = __esm({
|
|
@@ -36465,18 +37278,18 @@ var init_plan2 = __esm({
|
|
|
36465
37278
|
});
|
|
36466
37279
|
|
|
36467
37280
|
// packages/core/src/store/exodus/health.ts
|
|
36468
|
-
import { existsSync as
|
|
37281
|
+
import { existsSync as existsSync9, statSync as statSync2 } from "node:fs";
|
|
36469
37282
|
function buildExodusHealth(cwd) {
|
|
36470
37283
|
const plan = buildExodusPlan(cwd);
|
|
36471
|
-
const anyLegacyPresent = plan.sources.some((s) =>
|
|
37284
|
+
const anyLegacyPresent = plan.sources.some((s) => existsSync9(s.path));
|
|
36472
37285
|
const parity = anyLegacyPresent ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath) : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
|
|
36473
37286
|
const consolidatedExistsByScope = {
|
|
36474
|
-
project:
|
|
36475
|
-
global:
|
|
37287
|
+
project: existsSync9(plan.projectDbPath),
|
|
37288
|
+
global: existsSync9(plan.globalDbPath)
|
|
36476
37289
|
};
|
|
36477
37290
|
const buildScope = (scope) => {
|
|
36478
37291
|
const sources = plan.sources.filter((s) => s.targetScope === scope).map((s) => {
|
|
36479
|
-
const present =
|
|
37292
|
+
const present = existsSync9(s.path);
|
|
36480
37293
|
let bytes = 0;
|
|
36481
37294
|
if (present) {
|
|
36482
37295
|
try {
|
|
@@ -36743,15 +37556,15 @@ var init_types = __esm({
|
|
|
36743
37556
|
// packages/core/src/store/exodus/migrate.ts
|
|
36744
37557
|
import {
|
|
36745
37558
|
copyFileSync as copyFileSync3,
|
|
36746
|
-
existsSync as
|
|
36747
|
-
mkdirSync as
|
|
37559
|
+
existsSync as existsSync10,
|
|
37560
|
+
mkdirSync as mkdirSync3,
|
|
36748
37561
|
readFileSync as readFileSync3,
|
|
36749
37562
|
renameSync as renameSync2,
|
|
36750
37563
|
statSync as statSync3,
|
|
36751
37564
|
unlinkSync as unlinkSync2,
|
|
36752
|
-
writeFileSync as
|
|
37565
|
+
writeFileSync as writeFileSync3
|
|
36753
37566
|
} from "node:fs";
|
|
36754
|
-
import { join as
|
|
37567
|
+
import { join as join13 } from "node:path";
|
|
36755
37568
|
function getSqliteVersion(db) {
|
|
36756
37569
|
try {
|
|
36757
37570
|
const row = db.prepare("SELECT sqlite_version() AS v").get();
|
|
@@ -36767,14 +37580,14 @@ function listTables2(db) {
|
|
|
36767
37580
|
return rows.map((r) => r.name);
|
|
36768
37581
|
}
|
|
36769
37582
|
function writeJournal(stagingDir, journal) {
|
|
36770
|
-
const journalPath =
|
|
37583
|
+
const journalPath = join13(stagingDir, JOURNAL_FILENAME);
|
|
36771
37584
|
const tmpPath = `${journalPath}.tmp`;
|
|
36772
|
-
|
|
37585
|
+
writeFileSync3(tmpPath, JSON.stringify(journal, null, 2) + "\n", "utf8");
|
|
36773
37586
|
renameSync2(tmpPath, journalPath);
|
|
36774
37587
|
}
|
|
36775
37588
|
function readJournal(stagingDir) {
|
|
36776
|
-
const journalPath =
|
|
36777
|
-
if (!
|
|
37589
|
+
const journalPath = join13(stagingDir, JOURNAL_FILENAME);
|
|
37590
|
+
if (!existsSync10(journalPath)) return null;
|
|
36778
37591
|
try {
|
|
36779
37592
|
return JSON.parse(readFileSync3(journalPath, "utf8"));
|
|
36780
37593
|
} catch {
|
|
@@ -36782,17 +37595,17 @@ function readJournal(stagingDir) {
|
|
|
36782
37595
|
}
|
|
36783
37596
|
}
|
|
36784
37597
|
function clearExodusJournal(stagingDir) {
|
|
36785
|
-
const journalPath =
|
|
37598
|
+
const journalPath = join13(stagingDir, JOURNAL_FILENAME);
|
|
36786
37599
|
try {
|
|
36787
|
-
if (!
|
|
37600
|
+
if (!existsSync10(journalPath)) return false;
|
|
36788
37601
|
unlinkSync2(journalPath);
|
|
36789
|
-
|
|
37602
|
+
log5.info(
|
|
36790
37603
|
{ stagingDir },
|
|
36791
37604
|
"exodus: cleared migrate journal after abort/rollback \u2014 a retry will RE-COPY all tables"
|
|
36792
37605
|
);
|
|
36793
37606
|
return true;
|
|
36794
37607
|
} catch (err) {
|
|
36795
|
-
|
|
37608
|
+
log5.warn(
|
|
36796
37609
|
{ err, stagingDir },
|
|
36797
37610
|
'exodus: failed to clear migrate journal after rollback (a retry may skip already-"done" tables)'
|
|
36798
37611
|
);
|
|
@@ -36817,7 +37630,7 @@ function lockPath(dbPath) {
|
|
|
36817
37630
|
}
|
|
36818
37631
|
function acquireAdvisoryLock(dbPath) {
|
|
36819
37632
|
const lp = lockPath(dbPath);
|
|
36820
|
-
|
|
37633
|
+
writeFileSync3(lp, JSON.stringify({ pid: process.pid, ts: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
|
|
36821
37634
|
}
|
|
36822
37635
|
function releaseAdvisoryLock(dbPath) {
|
|
36823
37636
|
try {
|
|
@@ -36880,7 +37693,7 @@ function buildSelectExpr(attachAlias, legacyTable, targetTableName, col, srcType
|
|
|
36880
37693
|
function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyTableName, sourceName, targetSchema = "main") {
|
|
36881
37694
|
const resolution = resolveConsolidatedTableName(sourceName, legacyTableName);
|
|
36882
37695
|
if (resolution.kind === "skip") {
|
|
36883
|
-
|
|
37696
|
+
log5.warn(
|
|
36884
37697
|
{ legacyTableName, sourceName, reason: resolution.reason },
|
|
36885
37698
|
`Exodus: explicitly skipping table \u2014 ${resolution.reason}`
|
|
36886
37699
|
);
|
|
@@ -36899,7 +37712,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36899
37712
|
).get();
|
|
36900
37713
|
if (!existsRow) {
|
|
36901
37714
|
const reason = `consolidated target '${targetTableName}' not found (mapped from legacy '${legacyTableName}')`;
|
|
36902
|
-
|
|
37715
|
+
log5.warn(
|
|
36903
37716
|
{ legacyTableName, targetTableName, sourceName, attachAlias, targetSchema },
|
|
36904
37717
|
`Exodus: ${reason}`
|
|
36905
37718
|
);
|
|
@@ -36910,13 +37723,13 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36910
37723
|
const sharedColumns = srcPragma.map((r) => r.name).filter((col) => tgtColMap.has(col));
|
|
36911
37724
|
if (sharedColumns.length === 0) {
|
|
36912
37725
|
const reason = `no overlapping columns between source '${legacyTableName}' and target '${targetTableName}'`;
|
|
36913
|
-
|
|
37726
|
+
log5.warn({ legacyTableName, targetTableName, sourceName }, `Exodus: ${reason}`);
|
|
36914
37727
|
return { rowsCopied: 0, skipped: true, reason };
|
|
36915
37728
|
}
|
|
36916
37729
|
const srcOnlyColumns = srcPragma.map((r) => r.name).filter((c) => !tgtColMap.has(c));
|
|
36917
37730
|
const tgtOnlyColumns = tgtPragma.map((r) => r.name).filter((c) => !srcColumns.has(c));
|
|
36918
37731
|
if (srcOnlyColumns.length > 0 || tgtOnlyColumns.length > 0) {
|
|
36919
|
-
|
|
37732
|
+
log5.info(
|
|
36920
37733
|
{ legacyTableName, targetTableName, sourceName, srcOnlyColumns, tgtOnlyColumns },
|
|
36921
37734
|
"Exodus: column drift detected \u2014 copying intersection, dropping src-only cols, using defaults for tgt-only cols"
|
|
36922
37735
|
);
|
|
@@ -36931,7 +37744,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36931
37744
|
return isoGlobCols.has(col) && (upper.includes("INT") || upper === "" || upper === "NUMERIC");
|
|
36932
37745
|
});
|
|
36933
37746
|
if (coercedCols.length > 0) {
|
|
36934
|
-
|
|
37747
|
+
log5.info(
|
|
36935
37748
|
{
|
|
36936
37749
|
legacyTableName,
|
|
36937
37750
|
targetTableName,
|
|
@@ -36947,7 +37760,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36947
37760
|
(col) => ENUM_NORMALIZATIONS.has(`${targetTableName}.${col}`)
|
|
36948
37761
|
);
|
|
36949
37762
|
if (normalizedCols.length > 0) {
|
|
36950
|
-
|
|
37763
|
+
log5.info(
|
|
36951
37764
|
{ legacyTableName, targetTableName, sourceName, normalizedCols },
|
|
36952
37765
|
`Exodus: applying enum-value normalization for ${normalizedCols.length} column(s) (T11547)`
|
|
36953
37766
|
);
|
|
@@ -36956,7 +37769,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36956
37769
|
(col) => NUMERIC_CLAMPS.has(`${targetTableName}.${col}`)
|
|
36957
37770
|
);
|
|
36958
37771
|
if (clampedCols.length > 0) {
|
|
36959
|
-
|
|
37772
|
+
log5.info(
|
|
36960
37773
|
{ legacyTableName, targetTableName, sourceName, clampedCols },
|
|
36961
37774
|
`Exodus: applying non-finite numeric clamp for ${clampedCols.length} column(s) (T11782)`
|
|
36962
37775
|
);
|
|
@@ -36998,7 +37811,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36998
37811
|
if (rowsCopied < sourceCount) {
|
|
36999
37812
|
const presentAccountedFor = existingBefore + rowsCopied;
|
|
37000
37813
|
if (presentAccountedFor >= sourceCount) {
|
|
37001
|
-
|
|
37814
|
+
log5.info(
|
|
37002
37815
|
{ legacyTableName, targetTableName, sourceName, sourceCount, rowsCopied, existingBefore },
|
|
37003
37816
|
`Exodus: '${legacyTableName}'\u2192'${targetTableName}' \u2014 ${sourceCount - rowsCopied} of ${sourceCount} row(s) already present in target (idempotent PK dedup), ${rowsCopied} newly copied; no loss`
|
|
37004
37817
|
);
|
|
@@ -37006,7 +37819,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
37006
37819
|
}
|
|
37007
37820
|
const missing = sourceCount - presentAccountedFor;
|
|
37008
37821
|
const reason = `INSERT OR IGNORE lost ${missing} of ${sourceCount} rows from '${legacyTableName}'\u2192'${targetTableName}' (rowsCopied=${rowsCopied}, existingBefore=${existingBefore}) \u2014 a CHECK/NOT NULL/type/enum constraint rejected them (NOT PK dedup); inspect epoch coercion + enum normalization. verify will confirm.`;
|
|
37009
|
-
|
|
37822
|
+
log5.error(
|
|
37010
37823
|
{
|
|
37011
37824
|
legacyTableName,
|
|
37012
37825
|
targetTableName,
|
|
@@ -37026,10 +37839,10 @@ function checkSchemaVersion(journal, forceCrossVersion) {
|
|
|
37026
37839
|
if (journal.targetSchemaVersion !== EXODUS_TARGET_SCHEMA_VERSION) {
|
|
37027
37840
|
const msg = `Schema version mismatch: journal=${journal.targetSchemaVersion}, expected=${EXODUS_TARGET_SCHEMA_VERSION}`;
|
|
37028
37841
|
if (forceCrossVersion) {
|
|
37029
|
-
|
|
37842
|
+
log5.warn(msg + " (--force-cross-version: continuing anyway)");
|
|
37030
37843
|
return true;
|
|
37031
37844
|
}
|
|
37032
|
-
|
|
37845
|
+
log5.error(msg + " \u2014 pass --force-cross-version to override");
|
|
37033
37846
|
return false;
|
|
37034
37847
|
}
|
|
37035
37848
|
return true;
|
|
@@ -37046,10 +37859,10 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37046
37859
|
error: `Insufficient disk space for exodus: need \u2265${plan.requiredBytes} bytes (\u2248${STAGING_HEADROOM_FACTOR}\xD7 largest source ${plan.largestSourceBytes} + consolidated estimate ${plan.totalSourceBytes}), but only ${plan.availableBytes} bytes are free on the target filesystem \u2014 ${shortfall} bytes short. Free up at least ${shortfall} bytes (e.g. \`cleo backup prune\`, clear caches), or move the .cleo/ directory to a larger volume, then retry.`
|
|
37047
37860
|
};
|
|
37048
37861
|
}
|
|
37049
|
-
|
|
37862
|
+
mkdirSync3(stagingDir, { recursive: true });
|
|
37050
37863
|
let sqliteVersion = "unknown";
|
|
37051
37864
|
for (const src of sources) {
|
|
37052
|
-
if (
|
|
37865
|
+
if (existsSync10(src.path)) {
|
|
37053
37866
|
const snap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
37054
37867
|
sqliteVersion = getSqliteVersion(snap.db);
|
|
37055
37868
|
snap.close();
|
|
@@ -37090,15 +37903,15 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37090
37903
|
};
|
|
37091
37904
|
var extractNativeDb = extractNativeDb2;
|
|
37092
37905
|
for (const src of sources) {
|
|
37093
|
-
if (!
|
|
37094
|
-
const backupDest =
|
|
37906
|
+
if (!existsSync10(src.path)) continue;
|
|
37907
|
+
const backupDest = join13(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
|
|
37095
37908
|
const srcBytes = safeStatBytes(src.path);
|
|
37096
37909
|
const skipStagingCopy = srcBytes > plan.stagingCopyThresholdBytes;
|
|
37097
37910
|
if (skipStagingCopy) {
|
|
37098
37911
|
onProgress?.(
|
|
37099
37912
|
`Skipping full staging copy of ${src.name} (${srcBytes} bytes > ${plan.stagingCopyThresholdBytes} threshold) \u2014 source is archived, not deleted, on success.`
|
|
37100
37913
|
);
|
|
37101
|
-
} else if (!
|
|
37914
|
+
} else if (!existsSync10(backupDest)) {
|
|
37102
37915
|
onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
|
|
37103
37916
|
copyFileSync3(src.path, backupDest);
|
|
37104
37917
|
backupPaths.push(backupDest);
|
|
@@ -37116,8 +37929,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37116
37929
|
});
|
|
37117
37930
|
const projectNative = extractNativeDb2(projectHandle);
|
|
37118
37931
|
const globalNative = extractNativeDb2(globalHandle);
|
|
37119
|
-
const projectSources = sources.filter((s) => s.targetScope === "project" &&
|
|
37120
|
-
const globalSources = sources.filter((s) => s.targetScope === "global" &&
|
|
37932
|
+
const projectSources = sources.filter((s) => s.targetScope === "project" && existsSync10(s.path));
|
|
37933
|
+
const globalSources = sources.filter((s) => s.targetScope === "global" && existsSync10(s.path));
|
|
37121
37934
|
await migrateScope(
|
|
37122
37935
|
"project",
|
|
37123
37936
|
projectSources,
|
|
@@ -37142,7 +37955,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37142
37955
|
return { ok: true, tables: allTableResults, stagingDir, backupPaths };
|
|
37143
37956
|
} catch (err) {
|
|
37144
37957
|
const error48 = err instanceof Error ? err.message : String(err);
|
|
37145
|
-
|
|
37958
|
+
log5.error({ err }, "Exodus migration failed");
|
|
37146
37959
|
return { ok: false, tables: allTableResults, stagingDir, backupPaths, error: error48 };
|
|
37147
37960
|
} finally {
|
|
37148
37961
|
try {
|
|
@@ -37162,7 +37975,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37162
37975
|
if (sources.length === 0) return;
|
|
37163
37976
|
onProgress?.(`Migrating ${scope}-scope sources\u2026`);
|
|
37164
37977
|
targetNativeDb.exec("PRAGMA foreign_keys = OFF");
|
|
37165
|
-
|
|
37978
|
+
log5.info({ scope }, "Exodus: foreign_keys=OFF for bulk copy (T11533 FK-defer)");
|
|
37166
37979
|
try {
|
|
37167
37980
|
for (let i = 0; i < sources.length; i++) {
|
|
37168
37981
|
const src = sources[i];
|
|
@@ -37229,7 +38042,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37229
38042
|
}
|
|
37230
38043
|
} catch (err) {
|
|
37231
38044
|
const msg = err instanceof Error ? err.message : String(err);
|
|
37232
|
-
|
|
38045
|
+
log5.warn({ tableName, sourceDb: src.name, err }, "Table copy failed \u2014 skipping");
|
|
37233
38046
|
status = "skipped";
|
|
37234
38047
|
errorMsg = msg;
|
|
37235
38048
|
skipped = true;
|
|
@@ -37277,7 +38090,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37277
38090
|
targetNativeDb.exec(`DETACH DATABASE "${attachAlias}"`);
|
|
37278
38091
|
onProgress?.(` [${src.name}] Detached "${attachAlias}"`);
|
|
37279
38092
|
} catch (detachErr) {
|
|
37280
|
-
|
|
38093
|
+
log5.warn(
|
|
37281
38094
|
{ attachAlias, sourceDb: src.name, err: detachErr },
|
|
37282
38095
|
"DETACH failed \u2014 alias will be released on DB close"
|
|
37283
38096
|
);
|
|
@@ -37287,7 +38100,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37287
38100
|
targetNativeDb.exec(`DETACH DATABASE "${crossAlias}"`);
|
|
37288
38101
|
onProgress?.(` [${src.name}] Cross-scope target detached "${crossAlias}"`);
|
|
37289
38102
|
} catch (detachErr) {
|
|
37290
|
-
|
|
38103
|
+
log5.warn(
|
|
37291
38104
|
{ crossAlias, sourceDb: src.name, err: detachErr },
|
|
37292
38105
|
"Cross-scope DETACH failed \u2014 alias will be released on DB close"
|
|
37293
38106
|
);
|
|
@@ -37299,28 +38112,28 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37299
38112
|
try {
|
|
37300
38113
|
const orphans = targetNativeDb.prepare("PRAGMA foreign_key_check").all();
|
|
37301
38114
|
if (orphans.length > 0) {
|
|
37302
|
-
|
|
38115
|
+
log5.warn(
|
|
37303
38116
|
{ scope, orphanCount: orphans.length, sample: orphans.slice(0, 5) },
|
|
37304
38117
|
`Exodus: PRAGMA foreign_key_check found ${orphans.length} orphan row(s) after bulk copy \u2014 these are genuine data orphans (not ordering artifacts)`
|
|
37305
38118
|
);
|
|
37306
38119
|
} else {
|
|
37307
|
-
|
|
38120
|
+
log5.info({ scope }, "Exodus: PRAGMA foreign_key_check PASSED \u2014 no orphan rows");
|
|
37308
38121
|
}
|
|
37309
38122
|
} catch (checkErr) {
|
|
37310
|
-
|
|
38123
|
+
log5.warn(
|
|
37311
38124
|
{ scope, err: checkErr },
|
|
37312
38125
|
"Exodus: PRAGMA foreign_key_check failed (non-fatal) \u2014 target schema may not have FK constraints enabled"
|
|
37313
38126
|
);
|
|
37314
38127
|
}
|
|
37315
38128
|
try {
|
|
37316
38129
|
targetNativeDb.exec("PRAGMA foreign_keys = ON");
|
|
37317
|
-
|
|
38130
|
+
log5.info({ scope }, "Exodus: foreign_keys=ON restored after bulk copy");
|
|
37318
38131
|
} catch (fkErr) {
|
|
37319
|
-
|
|
38132
|
+
log5.warn({ scope, err: fkErr }, "Exodus: could not restore foreign_keys=ON (non-fatal)");
|
|
37320
38133
|
}
|
|
37321
38134
|
}
|
|
37322
38135
|
}
|
|
37323
|
-
var
|
|
38136
|
+
var log5, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, SOURCE_EPOCH_UNITS;
|
|
37324
38137
|
var init_migrate = __esm({
|
|
37325
38138
|
"packages/core/src/store/exodus/migrate.ts"() {
|
|
37326
38139
|
"use strict";
|
|
@@ -37332,7 +38145,7 @@ var init_migrate = __esm({
|
|
|
37332
38145
|
init_plan2();
|
|
37333
38146
|
init_table_name_map();
|
|
37334
38147
|
init_types();
|
|
37335
|
-
|
|
38148
|
+
log5 = getLogger("exodus-migrate");
|
|
37336
38149
|
LOCK_SENTINEL_SUFFIX = ".exodus-lock";
|
|
37337
38150
|
JOURNAL_FILENAME = "exodus-journal.json";
|
|
37338
38151
|
SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
|
|
@@ -37356,7 +38169,7 @@ function sealExodus(plan, scopeArg, cwd) {
|
|
|
37356
38169
|
const parity = computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath);
|
|
37357
38170
|
if (!parity.ok) {
|
|
37358
38171
|
const refusedReason = `Refusing to seal: ${parity.deficits.length} table(s) have FEWER rows in the consolidated cleo.db than the legacy source \u2014 the data is NOT fully migrated. Run \`cleo exodus migrate\` first. Deficits: ${parity.deficits.map((d) => `${d.targetTable}(${d.sourceCount}\u2192${d.targetCount})`).join(", ")}`;
|
|
37359
|
-
|
|
38172
|
+
log6.error({ deficits: parity.deficits.length }, `exodus seal refused \u2014 ${refusedReason}`);
|
|
37360
38173
|
return { ok: false, refusedReason, parity, scopes: [] };
|
|
37361
38174
|
}
|
|
37362
38175
|
const outcomes = [];
|
|
@@ -37372,7 +38185,7 @@ function sealExodus(plan, scopeArg, cwd) {
|
|
|
37372
38185
|
scopeSources.map((s) => s.name),
|
|
37373
38186
|
cwd
|
|
37374
38187
|
);
|
|
37375
|
-
|
|
38188
|
+
log6.info(
|
|
37376
38189
|
{ scope, alreadySealed, archived: archived.filter((a) => a.action === "archived").length },
|
|
37377
38190
|
`exodus seal: scope '${scope}' certified (count-parity verified, ${parity.checked} tables)`
|
|
37378
38191
|
);
|
|
@@ -37380,23 +38193,23 @@ function sealExodus(plan, scopeArg, cwd) {
|
|
|
37380
38193
|
}
|
|
37381
38194
|
return { ok: true, parity, scopes: outcomes };
|
|
37382
38195
|
}
|
|
37383
|
-
var
|
|
38196
|
+
var log6;
|
|
37384
38197
|
var init_seal = __esm({
|
|
37385
38198
|
"packages/core/src/store/exodus/seal.ts"() {
|
|
37386
38199
|
"use strict";
|
|
37387
38200
|
init_logger();
|
|
37388
38201
|
init_archive2();
|
|
37389
38202
|
init_count_parity();
|
|
37390
|
-
|
|
38203
|
+
log6 = getLogger("exodus-seal");
|
|
37391
38204
|
}
|
|
37392
38205
|
});
|
|
37393
38206
|
|
|
37394
38207
|
// packages/core/src/store/exodus/status.ts
|
|
37395
|
-
import { existsSync as
|
|
37396
|
-
import { join as
|
|
38208
|
+
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "node:fs";
|
|
38209
|
+
import { join as join14 } from "node:path";
|
|
37397
38210
|
function readJournal2(stagingDir) {
|
|
37398
|
-
const p =
|
|
37399
|
-
if (!
|
|
38211
|
+
const p = join14(stagingDir, JOURNAL_FILENAME2);
|
|
38212
|
+
if (!existsSync11(p)) return null;
|
|
37400
38213
|
try {
|
|
37401
38214
|
return JSON.parse(readFileSync4(p, "utf8"));
|
|
37402
38215
|
} catch {
|
|
@@ -37405,7 +38218,7 @@ function readJournal2(stagingDir) {
|
|
|
37405
38218
|
}
|
|
37406
38219
|
function findStagingDirs(cleoDir) {
|
|
37407
38220
|
try {
|
|
37408
|
-
return
|
|
38221
|
+
return readdirSync4(cleoDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => join14(cleoDir, e.name)).sort().reverse();
|
|
37409
38222
|
} catch {
|
|
37410
38223
|
return [];
|
|
37411
38224
|
}
|
|
@@ -37428,15 +38241,15 @@ function runExodusStatus(cwd) {
|
|
|
37428
38241
|
const sourcesInfo = plan.sources.map((s) => ({
|
|
37429
38242
|
name: s.name,
|
|
37430
38243
|
path: s.path,
|
|
37431
|
-
exists:
|
|
38244
|
+
exists: existsSync11(s.path),
|
|
37432
38245
|
bytes: safeBytes(s.path)
|
|
37433
38246
|
}));
|
|
37434
38247
|
return {
|
|
37435
38248
|
hasStaging: latestStaging !== null,
|
|
37436
38249
|
stagingDir: latestStaging,
|
|
37437
38250
|
journal,
|
|
37438
|
-
projectDbExists:
|
|
37439
|
-
globalDbExists:
|
|
38251
|
+
projectDbExists: existsSync11(projectDbPath),
|
|
38252
|
+
globalDbExists: existsSync11(globalDbPath),
|
|
37440
38253
|
sourcesPresent: sourcesInfo.some((s) => s.exists),
|
|
37441
38254
|
sources: sourcesInfo
|
|
37442
38255
|
};
|
|
@@ -37453,7 +38266,7 @@ var init_status = __esm({
|
|
|
37453
38266
|
});
|
|
37454
38267
|
|
|
37455
38268
|
// packages/core/src/store/exodus/verify-migration.ts
|
|
37456
|
-
import { existsSync as
|
|
38269
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
37457
38270
|
import { createRequire as createRequire3 } from "node:module";
|
|
37458
38271
|
function orderByClause(db, tableName) {
|
|
37459
38272
|
try {
|
|
@@ -37473,7 +38286,7 @@ function computeTableDigest(db, tableName, columns, transform2) {
|
|
|
37473
38286
|
count = Number(row?.c ?? 0);
|
|
37474
38287
|
} catch (err) {
|
|
37475
38288
|
const msg = err instanceof Error ? err.message : String(err);
|
|
37476
|
-
|
|
38289
|
+
log7.warn(
|
|
37477
38290
|
{ tableName, err: msg },
|
|
37478
38291
|
"computeTableDigest: COUNT(*) failed (possibly a virtual/FTS table) \u2014 treating as 0 rows"
|
|
37479
38292
|
);
|
|
@@ -37508,7 +38321,7 @@ function computeTableDigest(db, tableName, columns, transform2) {
|
|
|
37508
38321
|
}
|
|
37509
38322
|
} catch (err) {
|
|
37510
38323
|
const msg = err instanceof Error ? err.message : String(err);
|
|
37511
|
-
|
|
38324
|
+
log7.warn(
|
|
37512
38325
|
{ tableName, err: msg },
|
|
37513
38326
|
"computeTableDigest: streamed SELECT failed (possibly a virtual/FTS table) \u2014 digest skipped (COUNT(*) parity still enforced)"
|
|
37514
38327
|
);
|
|
@@ -37634,7 +38447,7 @@ function foreignKeyCheck(db, scope) {
|
|
|
37634
38447
|
try {
|
|
37635
38448
|
const rows = db.prepare("PRAGMA foreign_key_check").all();
|
|
37636
38449
|
if (rows.length > 0) {
|
|
37637
|
-
|
|
38450
|
+
log7.warn(
|
|
37638
38451
|
{ scope, count: rows.length, sample: rows.slice(0, 5) },
|
|
37639
38452
|
`verifyMigration: PRAGMA foreign_key_check found ${rows.length} orphan row(s)`
|
|
37640
38453
|
);
|
|
@@ -37646,7 +38459,7 @@ function foreignKeyCheck(db, scope) {
|
|
|
37646
38459
|
fkid: r.fkid
|
|
37647
38460
|
}));
|
|
37648
38461
|
} catch (err) {
|
|
37649
|
-
|
|
38462
|
+
log7.warn({ scope, err }, "verifyMigration: PRAGMA foreign_key_check failed (non-fatal)");
|
|
37650
38463
|
return [];
|
|
37651
38464
|
}
|
|
37652
38465
|
}
|
|
@@ -37683,13 +38496,13 @@ function sourceOrphanSignatures(db, sourceName, scope) {
|
|
|
37683
38496
|
const rows = db.prepare("PRAGMA foreign_key_check").all();
|
|
37684
38497
|
for (const r of rows) sigs.add(orphanSignature(db, r, sourceName));
|
|
37685
38498
|
if (rows.length > 0) {
|
|
37686
|
-
|
|
38499
|
+
log7.warn(
|
|
37687
38500
|
{ scope, count: rows.length, sample: rows.slice(0, 5) },
|
|
37688
38501
|
`verifyMigration: source already has ${rows.length} pre-existing FK orphan(s) \u2014 these are tolerated (carried forward losslessly, flagged for data-hygiene)`
|
|
37689
38502
|
);
|
|
37690
38503
|
}
|
|
37691
38504
|
} catch (err) {
|
|
37692
|
-
|
|
38505
|
+
log7.warn({ scope, err }, "verifyMigration: source PRAGMA foreign_key_check failed (non-fatal)");
|
|
37693
38506
|
}
|
|
37694
38507
|
return sigs;
|
|
37695
38508
|
}
|
|
@@ -37701,7 +38514,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37701
38514
|
const preExistingForeignKeyViolations = [];
|
|
37702
38515
|
const failureLines = [];
|
|
37703
38516
|
const sourceOrphanSigs = /* @__PURE__ */ new Set();
|
|
37704
|
-
if (!
|
|
38517
|
+
if (!existsSync12(projectDbPath)) {
|
|
37705
38518
|
return {
|
|
37706
38519
|
ok: false,
|
|
37707
38520
|
tables: [],
|
|
@@ -37712,7 +38525,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37712
38525
|
error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
|
|
37713
38526
|
};
|
|
37714
38527
|
}
|
|
37715
|
-
if (!
|
|
38528
|
+
if (!existsSync12(globalDbPath)) {
|
|
37716
38529
|
return {
|
|
37717
38530
|
ok: false,
|
|
37718
38531
|
tables: [],
|
|
@@ -37727,7 +38540,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37727
38540
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
37728
38541
|
try {
|
|
37729
38542
|
for (const src of sources) {
|
|
37730
|
-
if (!
|
|
38543
|
+
if (!existsSync12(src.path)) {
|
|
37731
38544
|
onProgress?.(`Skipping ${src.name} (not present)`);
|
|
37732
38545
|
continue;
|
|
37733
38546
|
}
|
|
@@ -37812,7 +38625,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37812
38625
|
`[${scope}] ${src.name}.${legacyTableName} \u2192 ${targetTableName}: DEFICIT \u2014 source=${srcDigest.count} rows, target=${tgtDigest.count} rows (${srcDigest.count - tgtDigest.count} missing), hashMatch=${hashMatch}`
|
|
37813
38626
|
);
|
|
37814
38627
|
} else if (tgtDigest.count > srcDigest.count) {
|
|
37815
|
-
|
|
38628
|
+
log7.warn(
|
|
37816
38629
|
{
|
|
37817
38630
|
scope,
|
|
37818
38631
|
source: src.name,
|
|
@@ -37862,7 +38675,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37862
38675
|
}
|
|
37863
38676
|
}
|
|
37864
38677
|
if (preExistingForeignKeyViolations.length > 0) {
|
|
37865
|
-
|
|
38678
|
+
log7.warn(
|
|
37866
38679
|
{
|
|
37867
38680
|
count: preExistingForeignKeyViolations.length,
|
|
37868
38681
|
sample: preExistingForeignKeyViolations.slice(0, 5)
|
|
@@ -37872,7 +38685,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37872
38685
|
}
|
|
37873
38686
|
} catch (err) {
|
|
37874
38687
|
const error48 = err instanceof Error ? err.message : String(err);
|
|
37875
|
-
|
|
38688
|
+
log7.error({ err }, "verifyMigration failed");
|
|
37876
38689
|
return {
|
|
37877
38690
|
ok: false,
|
|
37878
38691
|
tables,
|
|
@@ -37889,7 +38702,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37889
38702
|
if (failureLines.length > 0) {
|
|
37890
38703
|
const error48 = `verifyMigration FAILED: ${failureLines.length} issue(s):
|
|
37891
38704
|
${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
|
|
37892
|
-
|
|
38705
|
+
log7.error({ failureCount: failureLines.length }, error48);
|
|
37893
38706
|
return {
|
|
37894
38707
|
ok: false,
|
|
37895
38708
|
tables,
|
|
@@ -37909,7 +38722,7 @@ ${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
|
|
|
37909
38722
|
enumDrift
|
|
37910
38723
|
};
|
|
37911
38724
|
}
|
|
37912
|
-
var
|
|
38725
|
+
var log7, _require, CHECK_ENUM_REGEX;
|
|
37913
38726
|
var init_verify_migration = __esm({
|
|
37914
38727
|
"packages/core/src/store/exodus/verify-migration.ts"() {
|
|
37915
38728
|
"use strict";
|
|
@@ -37918,7 +38731,7 @@ var init_verify_migration = __esm({
|
|
|
37918
38731
|
init_open_cleo_db();
|
|
37919
38732
|
init_column_transforms();
|
|
37920
38733
|
init_table_name_map();
|
|
37921
|
-
|
|
38734
|
+
log7 = getLogger("verify-migration");
|
|
37922
38735
|
_require = createRequire3(import.meta.url);
|
|
37923
38736
|
CHECK_ENUM_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+(?:IS\s+NULL\s+OR\s+"[^"]+"\s+)?IN\s*\(([^)]*)\)\s*\)/gi;
|
|
37924
38737
|
}
|
|
@@ -38010,7 +38823,7 @@ __export(on_open_exports, {
|
|
|
38010
38823
|
isDataContinuityOk: () => isDataContinuityOk,
|
|
38011
38824
|
maybeRunExodusOnOpen: () => maybeRunExodusOnOpen
|
|
38012
38825
|
});
|
|
38013
|
-
import { existsSync as
|
|
38826
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
38014
38827
|
function isDisabledByEnv() {
|
|
38015
38828
|
const v = process.env.CLEO_DISABLE_EXODUS_ON_OPEN;
|
|
38016
38829
|
return v === "1" || v === "true";
|
|
@@ -38036,7 +38849,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
38036
38849
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%'"
|
|
38037
38850
|
).all().map((r) => r.name);
|
|
38038
38851
|
} catch (err) {
|
|
38039
|
-
|
|
38852
|
+
log8.error({ err, scope }, "exodus-on-open: failed to enumerate tables for rollback");
|
|
38040
38853
|
return;
|
|
38041
38854
|
}
|
|
38042
38855
|
try {
|
|
@@ -38046,7 +38859,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
38046
38859
|
try {
|
|
38047
38860
|
nativeDb.exec(`DELETE FROM "${table}"`);
|
|
38048
38861
|
} catch (err) {
|
|
38049
|
-
|
|
38862
|
+
log8.warn({ err, table, scope }, "exodus-on-open: failed to clear table during rollback");
|
|
38050
38863
|
}
|
|
38051
38864
|
}
|
|
38052
38865
|
nativeDb.exec("COMMIT");
|
|
@@ -38055,7 +38868,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
38055
38868
|
nativeDb.exec("ROLLBACK");
|
|
38056
38869
|
} catch {
|
|
38057
38870
|
}
|
|
38058
|
-
|
|
38871
|
+
log8.error({ err, scope }, "exodus-on-open: rollback transaction failed");
|
|
38059
38872
|
} finally {
|
|
38060
38873
|
try {
|
|
38061
38874
|
nativeDb.exec("PRAGMA foreign_keys = ON");
|
|
@@ -38075,7 +38888,7 @@ async function rollbackBothScopes(scope, projectDbPath, globalDbPath) {
|
|
|
38075
38888
|
rollbackConsolidatedToEmpty(native, s);
|
|
38076
38889
|
}
|
|
38077
38890
|
} catch (err) {
|
|
38078
|
-
|
|
38891
|
+
log8.warn(
|
|
38079
38892
|
{ err, scope: s, openingScope: scope },
|
|
38080
38893
|
"exodus-on-open: could not roll back scope (best-effort)"
|
|
38081
38894
|
);
|
|
@@ -38091,7 +38904,7 @@ function isDataContinuityOk(result) {
|
|
|
38091
38904
|
const deficits = result.tables.filter((t) => t.targetCount < t.sourceCount);
|
|
38092
38905
|
const surpluses = result.tables.filter((t) => t.targetCount > t.sourceCount);
|
|
38093
38906
|
if (surpluses.length > 0) {
|
|
38094
|
-
|
|
38907
|
+
log8.warn(
|
|
38095
38908
|
{
|
|
38096
38909
|
surpluses: surpluses.map((t) => ({
|
|
38097
38910
|
table: t.targetTable,
|
|
@@ -38125,7 +38938,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38125
38938
|
const { buildExodusPlan: buildExodusPlan2, runExodusMigrate: runExodusMigrate2, verifyMigration: verifyMigration2, clearExodusJournal: clearExodusJournal2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
|
|
38126
38939
|
const plan = buildExodusPlan2(cwd);
|
|
38127
38940
|
const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
|
|
38128
|
-
if (!scopeSources.some((s) =>
|
|
38941
|
+
if (!scopeSources.some((s) => existsSync13(s.path))) {
|
|
38129
38942
|
return {
|
|
38130
38943
|
outcome: "skipped",
|
|
38131
38944
|
reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
|
|
@@ -38138,11 +38951,11 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38138
38951
|
if (!consolidatedIsEmpty(nativeDb, scope)) {
|
|
38139
38952
|
return { outcome: "skipped", reason: "migrated by a concurrent process (lock winner)" };
|
|
38140
38953
|
}
|
|
38141
|
-
|
|
38954
|
+
log8.info(
|
|
38142
38955
|
{
|
|
38143
38956
|
scope,
|
|
38144
38957
|
dbPath,
|
|
38145
|
-
sources: plan.sources.filter((s) =>
|
|
38958
|
+
sources: plan.sources.filter((s) => existsSync13(s.path)).map((s) => s.name)
|
|
38146
38959
|
},
|
|
38147
38960
|
"exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
|
|
38148
38961
|
);
|
|
@@ -38151,23 +38964,23 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38151
38964
|
const migrateResult = await runExodusMigrate2(
|
|
38152
38965
|
plan,
|
|
38153
38966
|
false,
|
|
38154
|
-
(msg) =>
|
|
38967
|
+
(msg) => log8.debug({ scope }, `exodus-on-open: ${msg}`)
|
|
38155
38968
|
);
|
|
38156
38969
|
if (!migrateResult.ok) {
|
|
38157
38970
|
await rollbackBothScopes(scope, plan.projectDbPath, plan.globalDbPath);
|
|
38158
38971
|
clearExodusJournal2(migrateResult.stagingDir);
|
|
38159
38972
|
const reason = `migration failed: ${migrateResult.error ?? "unknown error"} \u2014 legacy DBs kept as source`;
|
|
38160
|
-
|
|
38973
|
+
log8.error({ scope, error: migrateResult.error }, `exodus-on-open: ${reason}`);
|
|
38161
38974
|
return { outcome: "aborted", reason };
|
|
38162
38975
|
}
|
|
38163
38976
|
const verifyResult = verifyMigration2(
|
|
38164
38977
|
plan.sources,
|
|
38165
38978
|
plan.projectDbPath,
|
|
38166
38979
|
plan.globalDbPath,
|
|
38167
|
-
(msg) =>
|
|
38980
|
+
(msg) => log8.debug({ scope }, `exodus-on-open verify: ${msg}`)
|
|
38168
38981
|
);
|
|
38169
38982
|
if (!verifyResult.ok) {
|
|
38170
|
-
|
|
38983
|
+
log8.warn(
|
|
38171
38984
|
{
|
|
38172
38985
|
scope,
|
|
38173
38986
|
enumDrift: verifyResult.enumDrift.length,
|
|
@@ -38181,7 +38994,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38181
38994
|
clearExodusJournal2(plan.stagingDir);
|
|
38182
38995
|
const deficits = verifyResult.tables.filter((t) => t.targetCount < t.sourceCount).map((t) => `${t.targetTable}(${t.sourceCount}\u2192${t.targetCount})`);
|
|
38183
38996
|
const reason = `parity verification failed \u2014 cutover aborted, legacy DBs kept as source. count deficits: [${deficits.join(", ")}]; INTRODUCED fk orphans: ${verifyResult.introducedForeignKeyViolations.length} (pre-existing source orphans tolerated: ${verifyResult.preExistingForeignKeyViolations.length}). ` + `${verifyResult.error ?? ""}`.trim();
|
|
38184
|
-
|
|
38997
|
+
log8.error(
|
|
38185
38998
|
{
|
|
38186
38999
|
scope,
|
|
38187
39000
|
countDeficits: deficits,
|
|
@@ -38193,14 +39006,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38193
39006
|
return { outcome: "aborted", reason };
|
|
38194
39007
|
}
|
|
38195
39008
|
const rowsCopied = migrateResult.tables.filter((t) => !t.skipped).reduce((n, t) => n + t.rowsCopied, 0);
|
|
38196
|
-
|
|
39009
|
+
log8.info(
|
|
38197
39010
|
{ scope, rowsCopied, tables: migrateResult.tables.length },
|
|
38198
39011
|
"exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
|
|
38199
39012
|
);
|
|
38200
39013
|
try {
|
|
38201
|
-
const consumed = plan.sources.filter((s) =>
|
|
39014
|
+
const consumed = plan.sources.filter((s) => existsSync13(s.path));
|
|
38202
39015
|
const archiveResult = archiveMigratedSources(consumed, cwd);
|
|
38203
|
-
|
|
39016
|
+
log8.info(
|
|
38204
39017
|
{
|
|
38205
39018
|
scope,
|
|
38206
39019
|
archived: archiveResult.sources.filter((s) => s.action === "archived").length,
|
|
@@ -38209,7 +39022,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38209
39022
|
"exodus-on-open: archived legacy sources + sealed completion marker(s)"
|
|
38210
39023
|
);
|
|
38211
39024
|
} catch (err) {
|
|
38212
|
-
|
|
39025
|
+
log8.error(
|
|
38213
39026
|
{ err, scope },
|
|
38214
39027
|
"exodus-on-open: post-migration archive/marker step failed (migration itself succeeded \u2014 legacy DBs left in place, will be re-checked by `cleo doctor exodus-residue`)"
|
|
38215
39028
|
);
|
|
@@ -38231,14 +39044,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38231
39044
|
function _isExodusInProgress() {
|
|
38232
39045
|
return _exodusInProgress;
|
|
38233
39046
|
}
|
|
38234
|
-
var
|
|
39047
|
+
var log8, _exodusInProgress;
|
|
38235
39048
|
var init_on_open = __esm({
|
|
38236
39049
|
"packages/core/src/store/exodus/on-open.ts"() {
|
|
38237
39050
|
"use strict";
|
|
38238
39051
|
init_logger();
|
|
38239
39052
|
init_lock();
|
|
38240
39053
|
init_archive2();
|
|
38241
|
-
|
|
39054
|
+
log8 = getLogger("exodus-on-open");
|
|
38242
39055
|
_exodusInProgress = false;
|
|
38243
39056
|
}
|
|
38244
39057
|
});
|
|
@@ -38255,9 +39068,9 @@ __export(dual_scope_db_exports, {
|
|
|
38255
39068
|
resolveDualScopeDbPath: () => resolveDualScopeDbPath,
|
|
38256
39069
|
upsertIdempotent: () => upsertIdempotent
|
|
38257
39070
|
});
|
|
38258
|
-
import { existsSync as
|
|
39071
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4 } from "node:fs";
|
|
38259
39072
|
import { createRequire as createRequire4 } from "node:module";
|
|
38260
|
-
import { dirname as dirname6, join as
|
|
39073
|
+
import { dirname as dirname6, join as join15 } from "node:path";
|
|
38261
39074
|
function assertWriteDurable(handle) {
|
|
38262
39075
|
if (handle.exodusAbort) {
|
|
38263
39076
|
throw new ExodusAbortWriteUnsafeError(handle.exodusAbort);
|
|
@@ -38274,9 +39087,9 @@ function cacheKey(scope, dbPath) {
|
|
|
38274
39087
|
}
|
|
38275
39088
|
function resolveDualScopeDbPath(scope, cwd) {
|
|
38276
39089
|
if (scope === "project") {
|
|
38277
|
-
return
|
|
39090
|
+
return join15(resolveCleoDir(cwd), "cleo.db");
|
|
38278
39091
|
}
|
|
38279
|
-
return
|
|
39092
|
+
return join15(getCleoHome(), "cleo.db");
|
|
38280
39093
|
}
|
|
38281
39094
|
function migrationsSetName(scope) {
|
|
38282
39095
|
return scope === "project" ? "drizzle-cleo-project" : "drizzle-cleo-global";
|
|
@@ -38319,11 +39132,11 @@ async function openDualScopeDb(scope, cwd) {
|
|
|
38319
39132
|
const dbPath = resolveDualScopeDbPath(scope, cwd);
|
|
38320
39133
|
return scope === "project" ? openDualScopeDbAtPath("project", dbPath, cwd) : openDualScopeDbAtPath("global", dbPath, cwd);
|
|
38321
39134
|
}
|
|
38322
|
-
async function openDedicatedDualScopeDb(scope, dbPath,
|
|
38323
|
-
|
|
39135
|
+
async function openDedicatedDualScopeDb(scope, dbPath, log9) {
|
|
39136
|
+
log9.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
|
|
38324
39137
|
const dir = dirname6(dbPath);
|
|
38325
|
-
if (!
|
|
38326
|
-
|
|
39138
|
+
if (!existsSync14(dir)) {
|
|
39139
|
+
mkdirSync4(dir, { recursive: true });
|
|
38327
39140
|
}
|
|
38328
39141
|
const DatabaseSyncCtor = getDatabaseSyncCtor();
|
|
38329
39142
|
const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
|
|
@@ -38346,7 +39159,7 @@ async function openDedicatedDualScopeDb(scope, dbPath, log8) {
|
|
|
38346
39159
|
existenceTable(scope),
|
|
38347
39160
|
`dual-scope-db[${scope}]`
|
|
38348
39161
|
);
|
|
38349
|
-
|
|
39162
|
+
log9.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
|
|
38350
39163
|
return {
|
|
38351
39164
|
db,
|
|
38352
39165
|
scope,
|
|
@@ -38371,15 +39184,15 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38371
39184
|
return existing.handle;
|
|
38372
39185
|
}
|
|
38373
39186
|
}
|
|
38374
|
-
const
|
|
39187
|
+
const log9 = getLogger("dual-scope-db");
|
|
38375
39188
|
if (dedicated) {
|
|
38376
|
-
return openDedicatedDualScopeDb(scope, dbPath,
|
|
39189
|
+
return openDedicatedDualScopeDb(scope, dbPath, log9);
|
|
38377
39190
|
}
|
|
38378
39191
|
const initPromise = (async () => {
|
|
38379
|
-
|
|
39192
|
+
log9.debug({ scope, dbPath }, "opening dual-scope cleo.db");
|
|
38380
39193
|
const dir = dirname6(dbPath);
|
|
38381
|
-
if (!
|
|
38382
|
-
|
|
39194
|
+
if (!existsSync14(dir)) {
|
|
39195
|
+
mkdirSync4(dir, { recursive: true });
|
|
38383
39196
|
}
|
|
38384
39197
|
const DatabaseSyncCtor = getDatabaseSyncCtor();
|
|
38385
39198
|
const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
|
|
@@ -38406,7 +39219,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38406
39219
|
existenceTable(scope),
|
|
38407
39220
|
`dual-scope-db[${scope}]`
|
|
38408
39221
|
);
|
|
38409
|
-
|
|
39222
|
+
log9.debug({ scope, dbPath }, "dual-scope cleo.db ready");
|
|
38410
39223
|
const built = {
|
|
38411
39224
|
db,
|
|
38412
39225
|
scope,
|
|
@@ -38432,6 +39245,25 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38432
39245
|
{ dbPath }
|
|
38433
39246
|
);
|
|
38434
39247
|
if (exodusCwd !== void 0 && dbPath === resolveDualScopeDbPath(scope, exodusCwd)) {
|
|
39248
|
+
let releaseDbHeavy = null;
|
|
39249
|
+
let dbHeavyDeferred = false;
|
|
39250
|
+
try {
|
|
39251
|
+
const { governor: governor2 } = await Promise.resolve().then(() => (init_governor(), governor_exports));
|
|
39252
|
+
const admit = await governor2.tryAcquire("db-heavy");
|
|
39253
|
+
if (admit.deferred) {
|
|
39254
|
+
dbHeavyDeferred = true;
|
|
39255
|
+
} else {
|
|
39256
|
+
releaseDbHeavy = admit.release;
|
|
39257
|
+
}
|
|
39258
|
+
} catch {
|
|
39259
|
+
}
|
|
39260
|
+
if (dbHeavyDeferred) {
|
|
39261
|
+
log9.debug(
|
|
39262
|
+
{ scope, dbPath },
|
|
39263
|
+
"exodus-on-open skipped this open \u2014 db-heavy deferred under memory pressure (re-runs idempotently on a calmer open)"
|
|
39264
|
+
);
|
|
39265
|
+
return handle;
|
|
39266
|
+
}
|
|
38435
39267
|
try {
|
|
38436
39268
|
const { maybeRunExodusOnOpen: maybeRunExodusOnOpen2 } = await Promise.resolve().then(() => (init_on_open(), on_open_exports));
|
|
38437
39269
|
const result = await maybeRunExodusOnOpen2(scope, dbPath, nativeDb, exodusCwd);
|
|
@@ -38444,7 +39276,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38444
39276
|
reason: result.reason,
|
|
38445
39277
|
at: Date.now()
|
|
38446
39278
|
};
|
|
38447
|
-
|
|
39279
|
+
log9.warn(
|
|
38448
39280
|
{ scope, reason: result.reason },
|
|
38449
39281
|
"exodus-on-open aborted; consolidated cleo.db left empty, legacy kept as source \u2014 mutating callers must check handle.exodusAbort / call assertWriteDurable (T11828)"
|
|
38450
39282
|
);
|
|
@@ -38457,11 +39289,14 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38457
39289
|
return reopened;
|
|
38458
39290
|
}
|
|
38459
39291
|
} catch (err) {
|
|
38460
|
-
|
|
39292
|
+
log9.warn(
|
|
38461
39293
|
{ err, scope },
|
|
38462
39294
|
"exodus-on-open hook failed (non-fatal); re-opening consolidated handle"
|
|
38463
39295
|
);
|
|
38464
39296
|
return scope === "project" ? openDualScopeDbAtPath("project", dbPath) : openDualScopeDbAtPath("global", dbPath);
|
|
39297
|
+
} finally {
|
|
39298
|
+
if (releaseDbHeavy) await releaseDbHeavy().catch(() => {
|
|
39299
|
+
});
|
|
38465
39300
|
}
|
|
38466
39301
|
}
|
|
38467
39302
|
return handle;
|
|
@@ -39084,8 +39919,8 @@ __export(nexus_sqlite_exports, {
|
|
|
39084
39919
|
resetNexusDbState: () => resetNexusDbState,
|
|
39085
39920
|
resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
|
|
39086
39921
|
});
|
|
39087
|
-
import { copyFileSync as copyFileSync4, existsSync as
|
|
39088
|
-
import { join as
|
|
39922
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync15 } from "node:fs";
|
|
39923
|
+
import { join as join16 } from "node:path";
|
|
39089
39924
|
function getNexusDbPath(cwd) {
|
|
39090
39925
|
return resolveDualScopeDbPath("project", cwd);
|
|
39091
39926
|
}
|
|
@@ -39117,7 +39952,7 @@ function resolveNexusMigrationsFolder() {
|
|
|
39117
39952
|
return resolveCorePackageMigrationsFolder("drizzle-nexus");
|
|
39118
39953
|
}
|
|
39119
39954
|
function getNestedNexusSentinelPath() {
|
|
39120
|
-
return
|
|
39955
|
+
return join16(getCleoHome(), "nexus", NESTED_NEXUS_SENTINEL);
|
|
39121
39956
|
}
|
|
39122
39957
|
function detectAndWarnOnNestedNexus() {
|
|
39123
39958
|
let nestedPath;
|
|
@@ -39126,12 +39961,12 @@ function detectAndWarnOnNestedNexus() {
|
|
|
39126
39961
|
} catch {
|
|
39127
39962
|
return false;
|
|
39128
39963
|
}
|
|
39129
|
-
if (!
|
|
39964
|
+
if (!existsSync15(nestedPath)) return false;
|
|
39130
39965
|
if (_warnedNestedPaths.has(nestedPath)) return false;
|
|
39131
39966
|
_warnedNestedPaths.add(nestedPath);
|
|
39132
39967
|
const canonicalPath = getNexusDbPath();
|
|
39133
|
-
const
|
|
39134
|
-
|
|
39968
|
+
const log9 = getLogger("nexus-sqlite");
|
|
39969
|
+
log9.warn(
|
|
39135
39970
|
{
|
|
39136
39971
|
nestedPath,
|
|
39137
39972
|
canonicalPath,
|
|
@@ -39285,7 +40120,7 @@ function runNexusMigrations(nativeDb, db) {
|
|
|
39285
40120
|
const migrationsFolder = resolveNexusMigrationsFolder();
|
|
39286
40121
|
if (tableExists4(nativeDb, "nexus_nodes") && _nexusDbPath) {
|
|
39287
40122
|
const backupPath = _nexusDbPath.replace(/\.db$/, "-pre-cleo.db.bak");
|
|
39288
|
-
if (!
|
|
40123
|
+
if (!existsSync15(backupPath)) {
|
|
39289
40124
|
try {
|
|
39290
40125
|
copyFileSync4(_nexusDbPath, backupPath);
|
|
39291
40126
|
} catch {
|
|
@@ -39423,10 +40258,10 @@ var init_nexus_sqlite = __esm({
|
|
|
39423
40258
|
|
|
39424
40259
|
// packages/core/src/paths.ts
|
|
39425
40260
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
39426
|
-
import { existsSync as
|
|
40261
|
+
import { existsSync as existsSync16, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
|
|
39427
40262
|
import { createRequire as createRequire5 } from "node:module";
|
|
39428
40263
|
import { homedir } from "node:os";
|
|
39429
|
-
import { basename as basename4, dirname as dirname7, join as
|
|
40264
|
+
import { basename as basename4, dirname as dirname7, join as join17, resolve as resolve3 } from "node:path";
|
|
39430
40265
|
import {
|
|
39431
40266
|
computeCanonicalProjectId as _computeCanonicalProjectId,
|
|
39432
40267
|
getCanonicalTemplatesTildePath as _getCanonicalTemplatesTildePath,
|
|
@@ -39516,8 +40351,8 @@ function getCleoDirAbsolute(cwd, opts) {
|
|
|
39516
40351
|
function _resolveProjectByCwdFromNexus(cwd) {
|
|
39517
40352
|
try {
|
|
39518
40353
|
const cleoHome = getCleoHome();
|
|
39519
|
-
const globalDbPath =
|
|
39520
|
-
if (!
|
|
40354
|
+
const globalDbPath = join17(cleoHome, "cleo.db");
|
|
40355
|
+
if (!existsSync16(globalDbPath)) return null;
|
|
39521
40356
|
const start = resolve3(cwd ?? process.cwd());
|
|
39522
40357
|
let current = start;
|
|
39523
40358
|
const DatabaseSync2 = _getDatabaseSyncCtor();
|
|
@@ -39556,7 +40391,7 @@ function _findCleoDirRoot(cwd) {
|
|
|
39556
40391
|
const isDangerousRoot = current === homeRoot || current === "/" || current === "";
|
|
39557
40392
|
if (!isDangerousRoot) {
|
|
39558
40393
|
try {
|
|
39559
|
-
if (statSync5(
|
|
40394
|
+
if (statSync5(join17(current, ".cleo")).isDirectory()) {
|
|
39560
40395
|
return current;
|
|
39561
40396
|
}
|
|
39562
40397
|
} catch {
|
|
@@ -39571,7 +40406,7 @@ function _findCleoDirRoot(cwd) {
|
|
|
39571
40406
|
function resolveCleoDir(cwd) {
|
|
39572
40407
|
const scope = worktreeScope.getStore();
|
|
39573
40408
|
if (scope !== void 0) {
|
|
39574
|
-
return
|
|
40409
|
+
return join17(scope.worktreeRoot, ".cleo");
|
|
39575
40410
|
}
|
|
39576
40411
|
const override = _cleoDirEnvOverride();
|
|
39577
40412
|
if (override !== null) {
|
|
@@ -39579,14 +40414,14 @@ function resolveCleoDir(cwd) {
|
|
|
39579
40414
|
}
|
|
39580
40415
|
const root = _findCleoDirRoot(cwd);
|
|
39581
40416
|
if (root !== null) {
|
|
39582
|
-
return
|
|
40417
|
+
return join17(root, ".cleo");
|
|
39583
40418
|
}
|
|
39584
40419
|
const start = resolve3(cwd ?? process.cwd());
|
|
39585
40420
|
let current = start;
|
|
39586
40421
|
while (true) {
|
|
39587
40422
|
const mainRepo = _resolveMainRepoFromGitlink(current);
|
|
39588
40423
|
if (mainRepo !== null) {
|
|
39589
|
-
return
|
|
40424
|
+
return join17(mainRepo, ".cleo");
|
|
39590
40425
|
}
|
|
39591
40426
|
const parent = dirname7(current);
|
|
39592
40427
|
if (parent === current) {
|
|
@@ -39628,9 +40463,9 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
39628
40463
|
const start = resolve3(cwd ?? process.cwd());
|
|
39629
40464
|
let current = start;
|
|
39630
40465
|
while (true) {
|
|
39631
|
-
const gitMarker =
|
|
40466
|
+
const gitMarker = join17(current, ".git");
|
|
39632
40467
|
try {
|
|
39633
|
-
if (
|
|
40468
|
+
if (existsSync16(gitMarker)) {
|
|
39634
40469
|
return true;
|
|
39635
40470
|
}
|
|
39636
40471
|
} catch {
|
|
@@ -39642,16 +40477,16 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
39642
40477
|
}
|
|
39643
40478
|
function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
39644
40479
|
try {
|
|
39645
|
-
const gitLinkPath =
|
|
39646
|
-
if (!
|
|
39647
|
-
const
|
|
39648
|
-
if (!
|
|
40480
|
+
const gitLinkPath = join17(gitlinkDir, ".git");
|
|
40481
|
+
if (!existsSync16(gitLinkPath)) return null;
|
|
40482
|
+
const stat3 = statSync5(gitLinkPath);
|
|
40483
|
+
if (!stat3.isFile()) return null;
|
|
39649
40484
|
const gitLinkContent = readFileSync5(gitLinkPath, "utf-8").trim();
|
|
39650
40485
|
const match = gitLinkContent.match(/^gitdir:\s*(.+)$/m);
|
|
39651
40486
|
if (!match) return null;
|
|
39652
40487
|
const gitdir = match[1].trim();
|
|
39653
40488
|
const mainRepo = dirname7(dirname7(dirname7(gitdir)));
|
|
39654
|
-
if (
|
|
40489
|
+
if (existsSync16(join17(mainRepo, ".cleo")) && validateProjectRoot(mainRepo)) {
|
|
39655
40490
|
return mainRepo;
|
|
39656
40491
|
}
|
|
39657
40492
|
} catch {
|
|
@@ -39659,18 +40494,18 @@ function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
|
39659
40494
|
return null;
|
|
39660
40495
|
}
|
|
39661
40496
|
function validateProjectRoot(candidate) {
|
|
39662
|
-
const cleoDir =
|
|
39663
|
-
if (!
|
|
40497
|
+
const cleoDir = join17(candidate, ".cleo");
|
|
40498
|
+
if (!existsSync16(cleoDir)) {
|
|
39664
40499
|
return false;
|
|
39665
40500
|
}
|
|
39666
|
-
const projectInfoPath =
|
|
39667
|
-
if (
|
|
40501
|
+
const projectInfoPath = join17(cleoDir, "project-info.json");
|
|
40502
|
+
if (existsSync16(projectInfoPath)) {
|
|
39668
40503
|
try {
|
|
39669
40504
|
const raw = readFileSync5(projectInfoPath, "utf-8");
|
|
39670
40505
|
const parsed = JSON.parse(raw);
|
|
39671
40506
|
if (typeof parsed === "object" && parsed !== null && "projectId" in parsed && typeof parsed["projectId"] === "string" && parsed["projectId"] !== "") {
|
|
39672
|
-
const gitMarker =
|
|
39673
|
-
if (
|
|
40507
|
+
const gitMarker = join17(candidate, ".git");
|
|
40508
|
+
if (existsSync16(gitMarker)) {
|
|
39674
40509
|
try {
|
|
39675
40510
|
if (!statSync5(gitMarker).isDirectory()) {
|
|
39676
40511
|
return false;
|
|
@@ -39684,12 +40519,12 @@ function validateProjectRoot(candidate) {
|
|
|
39684
40519
|
} catch {
|
|
39685
40520
|
}
|
|
39686
40521
|
}
|
|
39687
|
-
const gitDir =
|
|
39688
|
-
if (
|
|
40522
|
+
const gitDir = join17(candidate, ".git");
|
|
40523
|
+
if (existsSync16(gitDir)) {
|
|
39689
40524
|
let isRealGitDir = false;
|
|
39690
40525
|
try {
|
|
39691
|
-
const
|
|
39692
|
-
isRealGitDir =
|
|
40526
|
+
const stat3 = statSync5(gitDir);
|
|
40527
|
+
isRealGitDir = stat3.isDirectory();
|
|
39693
40528
|
} catch {
|
|
39694
40529
|
isRealGitDir = false;
|
|
39695
40530
|
}
|
|
@@ -39732,16 +40567,16 @@ function getProjectRoot(cwd) {
|
|
|
39732
40567
|
const homeRoot = homedir();
|
|
39733
40568
|
const skippedCleoDirs = [];
|
|
39734
40569
|
while (true) {
|
|
39735
|
-
const cleoDir =
|
|
39736
|
-
const gitDir =
|
|
40570
|
+
const cleoDir = join17(current, ".cleo");
|
|
40571
|
+
const gitDir = join17(current, ".git");
|
|
39737
40572
|
const isDangerousRoot = current === homeRoot || current === "/" || current === "";
|
|
39738
|
-
if (
|
|
40573
|
+
if (existsSync16(cleoDir) && !isDangerousRoot) {
|
|
39739
40574
|
if (validateProjectRoot(current)) {
|
|
39740
40575
|
return current;
|
|
39741
40576
|
}
|
|
39742
40577
|
skippedCleoDirs.push(current);
|
|
39743
40578
|
}
|
|
39744
|
-
if (
|
|
40579
|
+
if (existsSync16(gitDir) && !isDangerousRoot) {
|
|
39745
40580
|
let isRealGitDir = false;
|
|
39746
40581
|
try {
|
|
39747
40582
|
isRealGitDir = statSync5(gitDir).isDirectory();
|
|
@@ -39786,18 +40621,18 @@ function resolveOrCwd(maybeRoot) {
|
|
|
39786
40621
|
return getProjectRoot();
|
|
39787
40622
|
}
|
|
39788
40623
|
function getConfigPath(cwd) {
|
|
39789
|
-
return
|
|
40624
|
+
return join17(_resolveCleoDir(cwd), "config.json");
|
|
39790
40625
|
}
|
|
39791
40626
|
function getGlobalConfigPath() {
|
|
39792
|
-
return
|
|
40627
|
+
return join17(getCleoHome(), "config.json");
|
|
39793
40628
|
}
|
|
39794
40629
|
function isAbsolutePath(path) {
|
|
39795
40630
|
return _isAbsolutePath(path);
|
|
39796
40631
|
}
|
|
39797
40632
|
function _readProjectNameFromInfo(projectRoot) {
|
|
39798
40633
|
try {
|
|
39799
|
-
const infoPath =
|
|
39800
|
-
if (!
|
|
40634
|
+
const infoPath = join17(projectRoot, ".cleo", "project-info.json");
|
|
40635
|
+
if (!existsSync16(infoPath)) return void 0;
|
|
39801
40636
|
const raw = readFileSync5(infoPath, "utf-8");
|
|
39802
40637
|
const data = JSON.parse(raw);
|
|
39803
40638
|
return typeof data.name === "string" && data.name.length > 0 ? data.name : void 0;
|
|
@@ -39823,8 +40658,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
|
|
|
39823
40658
|
if (existingRows.length > 0) {
|
|
39824
40659
|
const existingPath = existingRows[0].projectPath;
|
|
39825
40660
|
if (existingPath !== resolvedPath) {
|
|
39826
|
-
const newBrainDbPath =
|
|
39827
|
-
const newTasksDbPath =
|
|
40661
|
+
const newBrainDbPath = join17(resolvedPath, ".cleo", "brain.db");
|
|
40662
|
+
const newTasksDbPath = join17(resolvedPath, ".cleo", "tasks.db");
|
|
39828
40663
|
await db.update(projectRegistry2).set({
|
|
39829
40664
|
projectPath: resolvedPath,
|
|
39830
40665
|
projectHash: generateProjectHash2(resolvedPath),
|
|
@@ -39855,8 +40690,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
|
|
|
39855
40690
|
lastSync: now,
|
|
39856
40691
|
taskCount: 0,
|
|
39857
40692
|
labelsJson: "[]",
|
|
39858
|
-
brainDbPath:
|
|
39859
|
-
tasksDbPath:
|
|
40693
|
+
brainDbPath: join17(resolvedPath, ".cleo", "brain.db"),
|
|
40694
|
+
tasksDbPath: join17(resolvedPath, ".cleo", "tasks.db"),
|
|
39860
40695
|
statsJson: "{}"
|
|
39861
40696
|
}).onConflictDoNothing();
|
|
39862
40697
|
const aliases = canonicalResult.legacyAliases ?? [];
|
|
@@ -39957,46 +40792,46 @@ var init_api_mode = __esm({
|
|
|
39957
40792
|
// packages/core/src/store/file-utils.ts
|
|
39958
40793
|
import { randomBytes } from "node:crypto";
|
|
39959
40794
|
import {
|
|
39960
|
-
existsSync as
|
|
39961
|
-
mkdirSync as
|
|
39962
|
-
readdirSync as
|
|
40795
|
+
existsSync as existsSync17,
|
|
40796
|
+
mkdirSync as mkdirSync5,
|
|
40797
|
+
readdirSync as readdirSync5,
|
|
39963
40798
|
readFileSync as readFileSync6,
|
|
39964
40799
|
renameSync as renameSync3,
|
|
39965
40800
|
unlinkSync as unlinkSync3,
|
|
39966
|
-
writeFileSync as
|
|
40801
|
+
writeFileSync as writeFileSync4
|
|
39967
40802
|
} from "node:fs";
|
|
39968
|
-
import { basename as basename5, dirname as dirname8, join as
|
|
39969
|
-
import * as
|
|
40803
|
+
import { basename as basename5, dirname as dirname8, join as join18 } from "node:path";
|
|
40804
|
+
import * as lockfile3 from "proper-lockfile";
|
|
39970
40805
|
function rotateBackup(filePath, mode) {
|
|
39971
40806
|
const dir = dirname8(filePath);
|
|
39972
40807
|
const name15 = basename5(filePath);
|
|
39973
|
-
const backupDir =
|
|
40808
|
+
const backupDir = join18(dir, ".backups");
|
|
39974
40809
|
const dirMode = typeof mode === "number" ? modeToDirMode(mode) : void 0;
|
|
39975
|
-
if (!
|
|
39976
|
-
|
|
40810
|
+
if (!existsSync17(backupDir)) {
|
|
40811
|
+
mkdirSync5(backupDir, { recursive: true, mode: dirMode });
|
|
39977
40812
|
}
|
|
39978
40813
|
for (let i = MAX_BACKUPS; i >= 1; i--) {
|
|
39979
|
-
const current =
|
|
40814
|
+
const current = join18(backupDir, `${name15}.${i}`);
|
|
39980
40815
|
if (i === MAX_BACKUPS) {
|
|
39981
40816
|
try {
|
|
39982
40817
|
unlinkSync3(current);
|
|
39983
40818
|
} catch {
|
|
39984
40819
|
}
|
|
39985
40820
|
} else {
|
|
39986
|
-
const next =
|
|
40821
|
+
const next = join18(backupDir, `${name15}.${i + 1}`);
|
|
39987
40822
|
try {
|
|
39988
|
-
if (
|
|
40823
|
+
if (existsSync17(current)) renameSync3(current, next);
|
|
39989
40824
|
} catch {
|
|
39990
40825
|
}
|
|
39991
40826
|
}
|
|
39992
40827
|
}
|
|
39993
40828
|
try {
|
|
39994
40829
|
const content = readFileSync6(filePath, "utf-8");
|
|
39995
|
-
const backupPath =
|
|
40830
|
+
const backupPath = join18(backupDir, `${name15}.1`);
|
|
39996
40831
|
if (typeof mode === "number") {
|
|
39997
|
-
|
|
40832
|
+
writeFileSync4(backupPath, content, { encoding: "utf-8", mode });
|
|
39998
40833
|
} else {
|
|
39999
|
-
|
|
40834
|
+
writeFileSync4(backupPath, content, "utf-8");
|
|
40000
40835
|
}
|
|
40001
40836
|
} catch {
|
|
40002
40837
|
}
|
|
@@ -40013,15 +40848,15 @@ function writeJsonFileAtomic(filePath, data, optsOrIndent = 2) {
|
|
|
40013
40848
|
const indent = opts.indent ?? 2;
|
|
40014
40849
|
const mode = opts.mode;
|
|
40015
40850
|
const dir = dirname8(filePath);
|
|
40016
|
-
const tempPath =
|
|
40851
|
+
const tempPath = join18(dir, `.${basename5(filePath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
40017
40852
|
const content = JSON.stringify(data, null, indent) + "\n";
|
|
40018
40853
|
if (typeof mode === "number") {
|
|
40019
|
-
|
|
40854
|
+
writeFileSync4(tempPath, content, { encoding: "utf-8", mode });
|
|
40020
40855
|
} else {
|
|
40021
|
-
|
|
40856
|
+
writeFileSync4(tempPath, content, "utf-8");
|
|
40022
40857
|
}
|
|
40023
40858
|
try {
|
|
40024
|
-
if (
|
|
40859
|
+
if (existsSync17(filePath)) {
|
|
40025
40860
|
rotateBackup(filePath, mode);
|
|
40026
40861
|
}
|
|
40027
40862
|
renameSync3(tempPath, filePath);
|
|
@@ -40047,19 +40882,19 @@ function readJsonFile(filePath) {
|
|
|
40047
40882
|
async function withLock2(filePath, transform2, opts = {}) {
|
|
40048
40883
|
const dir = dirname8(filePath);
|
|
40049
40884
|
const dirMode = typeof opts.mode === "number" ? modeToDirMode(opts.mode) : void 0;
|
|
40050
|
-
if (!
|
|
40051
|
-
|
|
40885
|
+
if (!existsSync17(dir)) {
|
|
40886
|
+
mkdirSync5(dir, { recursive: true, mode: dirMode });
|
|
40052
40887
|
}
|
|
40053
|
-
if (!
|
|
40888
|
+
if (!existsSync17(filePath)) {
|
|
40054
40889
|
if (typeof opts.mode === "number") {
|
|
40055
|
-
|
|
40890
|
+
writeFileSync4(filePath, "", { encoding: "utf-8", mode: opts.mode });
|
|
40056
40891
|
} else {
|
|
40057
|
-
|
|
40892
|
+
writeFileSync4(filePath, "", "utf-8");
|
|
40058
40893
|
}
|
|
40059
40894
|
}
|
|
40060
40895
|
let release;
|
|
40061
40896
|
try {
|
|
40062
|
-
release = await
|
|
40897
|
+
release = await lockfile3.lock(filePath, LOCK_OPTIONS);
|
|
40063
40898
|
const current = readJsonFile(filePath);
|
|
40064
40899
|
const updated = transform2(current);
|
|
40065
40900
|
writeJsonFileAtomic(filePath, updated, { mode: opts.mode });
|
|
@@ -40072,15 +40907,15 @@ async function withLock2(filePath, transform2, opts = {}) {
|
|
|
40072
40907
|
}
|
|
40073
40908
|
async function withFileLock(filePath, operation) {
|
|
40074
40909
|
const dir = dirname8(filePath);
|
|
40075
|
-
if (!
|
|
40076
|
-
|
|
40910
|
+
if (!existsSync17(dir)) {
|
|
40911
|
+
mkdirSync5(dir, { recursive: true });
|
|
40077
40912
|
}
|
|
40078
|
-
if (!
|
|
40079
|
-
|
|
40913
|
+
if (!existsSync17(filePath)) {
|
|
40914
|
+
writeFileSync4(filePath, "", "utf-8");
|
|
40080
40915
|
}
|
|
40081
40916
|
let release;
|
|
40082
40917
|
try {
|
|
40083
|
-
release = await
|
|
40918
|
+
release = await lockfile3.lock(filePath, LOCK_OPTIONS);
|
|
40084
40919
|
return await operation();
|
|
40085
40920
|
} finally {
|
|
40086
40921
|
if (release) {
|
|
@@ -40109,8 +40944,8 @@ var init_file_utils = __esm({
|
|
|
40109
40944
|
|
|
40110
40945
|
// packages/core/src/llm/credential-removal.ts
|
|
40111
40946
|
import { unlinkSync as unlinkSync4 } from "node:fs";
|
|
40112
|
-
import { join as
|
|
40113
|
-
import { getCleoHome as
|
|
40947
|
+
import { join as join19 } from "node:path";
|
|
40948
|
+
import { getCleoHome as getCleoHome3 } from "@cleocode/paths";
|
|
40114
40949
|
function buildBuiltinRemovalRegistry() {
|
|
40115
40950
|
const registry2 = new RemovalRegistry();
|
|
40116
40951
|
registry2.register(MANUAL_REMOVAL_STEP);
|
|
@@ -40201,7 +41036,7 @@ var init_credential_removal = __esm({
|
|
|
40201
41036
|
sourceId: "cleo-pkce",
|
|
40202
41037
|
description: "Delete CLEO-issued PKCE token at <CLEO_HOME>/anthropic-oauth.json",
|
|
40203
41038
|
async remove() {
|
|
40204
|
-
const path =
|
|
41039
|
+
const path = join19(getCleoHome3(), "anthropic-oauth.json");
|
|
40205
41040
|
const cleaned = [];
|
|
40206
41041
|
try {
|
|
40207
41042
|
unlinkSync4(path);
|
|
@@ -40280,7 +41115,7 @@ __export(config_exports, {
|
|
|
40280
41115
|
parseConfigValue: () => parseConfigValue,
|
|
40281
41116
|
setConfigValue: () => setConfigValue
|
|
40282
41117
|
});
|
|
40283
|
-
import { existsSync as
|
|
41118
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
40284
41119
|
function getNestedValue(obj, path) {
|
|
40285
41120
|
const parts = path.split(".");
|
|
40286
41121
|
let current = obj;
|
|
@@ -40328,7 +41163,7 @@ function parseEnvValue(value) {
|
|
|
40328
41163
|
return value;
|
|
40329
41164
|
}
|
|
40330
41165
|
async function loadConfig(cwd) {
|
|
40331
|
-
let merged = JSON.parse(JSON.stringify(
|
|
41166
|
+
let merged = JSON.parse(JSON.stringify(DEFAULTS2));
|
|
40332
41167
|
const globalConfig2 = await readJson(getGlobalConfigPath());
|
|
40333
41168
|
if (globalConfig2) {
|
|
40334
41169
|
merged = deepMerge(merged, globalConfig2);
|
|
@@ -40374,7 +41209,7 @@ async function getConfigValue(path, cwd) {
|
|
|
40374
41209
|
return { value: val, source: "global" };
|
|
40375
41210
|
}
|
|
40376
41211
|
}
|
|
40377
|
-
const defaultVal = getNestedValue({ ...
|
|
41212
|
+
const defaultVal = getNestedValue({ ...DEFAULTS2 }, path);
|
|
40378
41213
|
return { value: defaultVal, source: "default" };
|
|
40379
41214
|
}
|
|
40380
41215
|
async function getRawConfigValue(key, cwd) {
|
|
@@ -40402,7 +41237,7 @@ function parseConfigValue(value) {
|
|
|
40402
41237
|
}
|
|
40403
41238
|
async function setConfigValue(key, value, cwd, opts) {
|
|
40404
41239
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40405
|
-
if (!
|
|
41240
|
+
if (!existsSync18(configPath)) {
|
|
40406
41241
|
await atomicWriteJson(configPath, {});
|
|
40407
41242
|
}
|
|
40408
41243
|
const config2 = await readJson(configPath) ?? {};
|
|
@@ -40414,7 +41249,7 @@ async function setConfigValue(key, value, cwd, opts) {
|
|
|
40414
41249
|
async function applyStrictnessPreset(preset, cwd, opts) {
|
|
40415
41250
|
const definition = STRICTNESS_PRESETS[preset];
|
|
40416
41251
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40417
|
-
if (!
|
|
41252
|
+
if (!existsSync18(configPath)) {
|
|
40418
41253
|
await atomicWriteJson(configPath, {});
|
|
40419
41254
|
}
|
|
40420
41255
|
const config2 = await readJson(configPath) ?? {};
|
|
@@ -40438,7 +41273,7 @@ function listStrictnessPresets() {
|
|
|
40438
41273
|
})
|
|
40439
41274
|
);
|
|
40440
41275
|
}
|
|
40441
|
-
var
|
|
41276
|
+
var DEFAULTS2, ENV_MAP, STRICTNESS_PRESETS;
|
|
40442
41277
|
var init_config = __esm({
|
|
40443
41278
|
"packages/core/src/config.ts"() {
|
|
40444
41279
|
"use strict";
|
|
@@ -40446,7 +41281,7 @@ var init_config = __esm({
|
|
|
40446
41281
|
init_paths();
|
|
40447
41282
|
init_atomic();
|
|
40448
41283
|
init_json2();
|
|
40449
|
-
|
|
41284
|
+
DEFAULTS2 = {
|
|
40450
41285
|
version: "2.10.0",
|
|
40451
41286
|
output: {
|
|
40452
41287
|
defaultFormat: "json",
|
|
@@ -40621,10 +41456,10 @@ var init_config = __esm({
|
|
|
40621
41456
|
// packages/core/src/llm/credential-seeders/claude-code-seeder.ts
|
|
40622
41457
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
40623
41458
|
import { homedir as homedir2 } from "node:os";
|
|
40624
|
-
import { join as
|
|
41459
|
+
import { join as join20 } from "node:path";
|
|
40625
41460
|
function defaultReadCredentialFile() {
|
|
40626
41461
|
try {
|
|
40627
|
-
return readFileSync7(
|
|
41462
|
+
return readFileSync7(join20(homedir2(), ".claude", ".credentials.json"), "utf-8");
|
|
40628
41463
|
} catch {
|
|
40629
41464
|
return null;
|
|
40630
41465
|
}
|
|
@@ -40719,9 +41554,9 @@ var init_claude_code_seeder = __esm({
|
|
|
40719
41554
|
|
|
40720
41555
|
// packages/core/src/llm/credential-seeders/cleo-pkce-seeder.ts
|
|
40721
41556
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
40722
|
-
import { join as
|
|
41557
|
+
import { join as join21 } from "node:path";
|
|
40723
41558
|
function defaultCleoPkcePath() {
|
|
40724
|
-
return
|
|
41559
|
+
return join21(getCleoHome(), "anthropic-oauth.json");
|
|
40725
41560
|
}
|
|
40726
41561
|
function defaultReadCredentialFile2() {
|
|
40727
41562
|
try {
|
|
@@ -40792,13 +41627,13 @@ var init_cleo_pkce_seeder = __esm({
|
|
|
40792
41627
|
});
|
|
40793
41628
|
|
|
40794
41629
|
// packages/core/src/llm/credential-seeders/codex-cli-seeder.ts
|
|
40795
|
-
import { existsSync as
|
|
41630
|
+
import { existsSync as existsSync19, readFileSync as readFileSync9 } from "node:fs";
|
|
40796
41631
|
import { homedir as homedir3 } from "node:os";
|
|
40797
|
-
import { join as
|
|
41632
|
+
import { join as join22 } from "node:path";
|
|
40798
41633
|
function getCodexAuthPath() {
|
|
40799
41634
|
const codexHome = (process.env["CODEX_HOME"] ?? "").trim();
|
|
40800
|
-
const root = codexHome ||
|
|
40801
|
-
return
|
|
41635
|
+
const root = codexHome || join22(homedir3(), ".codex");
|
|
41636
|
+
return join22(root, "auth.json");
|
|
40802
41637
|
}
|
|
40803
41638
|
var CodexCliSeeder, codexCliSeeder;
|
|
40804
41639
|
var init_codex_cli_seeder = __esm({
|
|
@@ -40817,7 +41652,7 @@ var init_codex_cli_seeder = __esm({
|
|
|
40817
41652
|
*/
|
|
40818
41653
|
async seed() {
|
|
40819
41654
|
const authPath = getCodexAuthPath();
|
|
40820
|
-
if (!
|
|
41655
|
+
if (!existsSync19(authPath)) {
|
|
40821
41656
|
return { entries: [] };
|
|
40822
41657
|
}
|
|
40823
41658
|
let raw;
|
|
@@ -41012,11 +41847,11 @@ var init_google_pkce = __esm({
|
|
|
41012
41847
|
});
|
|
41013
41848
|
|
|
41014
41849
|
// packages/core/src/llm/credential-seeders/gemini-cli-seeder.ts
|
|
41015
|
-
import { existsSync as
|
|
41016
|
-
import { join as
|
|
41017
|
-
import { getCleoHome as
|
|
41850
|
+
import { existsSync as existsSync20, readFileSync as readFileSync10 } from "node:fs";
|
|
41851
|
+
import { join as join23 } from "node:path";
|
|
41852
|
+
import { getCleoHome as getCleoHome4 } from "@cleocode/paths";
|
|
41018
41853
|
function getGoogleOauthPath() {
|
|
41019
|
-
return
|
|
41854
|
+
return join23(getCleoHome4(), "google_oauth.json");
|
|
41020
41855
|
}
|
|
41021
41856
|
function parseGoogleOauthFile(raw) {
|
|
41022
41857
|
let json3;
|
|
@@ -41061,7 +41896,7 @@ var init_gemini_cli_seeder = __esm({
|
|
|
41061
41896
|
*/
|
|
41062
41897
|
async seed() {
|
|
41063
41898
|
const path = getGoogleOauthPath();
|
|
41064
|
-
if (!
|
|
41899
|
+
if (!existsSync20(path)) {
|
|
41065
41900
|
return { entries: [] };
|
|
41066
41901
|
}
|
|
41067
41902
|
let raw;
|
|
@@ -41286,23 +42121,23 @@ var init_credential_seeders = __esm({
|
|
|
41286
42121
|
|
|
41287
42122
|
// packages/core/src/llm/global-config-migration.ts
|
|
41288
42123
|
import {
|
|
41289
|
-
existsSync as
|
|
41290
|
-
mkdirSync as
|
|
42124
|
+
existsSync as existsSync21,
|
|
42125
|
+
mkdirSync as mkdirSync6,
|
|
41291
42126
|
readFileSync as readFileSync11,
|
|
41292
42127
|
renameSync as renameSync4,
|
|
41293
42128
|
unlinkSync as unlinkSync5,
|
|
41294
|
-
writeFileSync as
|
|
42129
|
+
writeFileSync as writeFileSync5
|
|
41295
42130
|
} from "node:fs";
|
|
41296
|
-
import { join as
|
|
41297
|
-
import { getCleoHome as
|
|
42131
|
+
import { join as join24 } from "node:path";
|
|
42132
|
+
import { getCleoHome as getCleoHome5, getCleoPlatformPaths as getCleoPlatformPaths2 } from "@cleocode/paths";
|
|
41298
42133
|
function configDirGlobalConfigPath() {
|
|
41299
|
-
return
|
|
42134
|
+
return join24(getCleoPlatformPaths2().config, GLOBAL_CONFIG_FILENAME);
|
|
41300
42135
|
}
|
|
41301
42136
|
function legacyGlobalConfigPath() {
|
|
41302
|
-
return
|
|
42137
|
+
return join24(getCleoHome5(), GLOBAL_CONFIG_FILENAME);
|
|
41303
42138
|
}
|
|
41304
42139
|
function migrationMarkerPath() {
|
|
41305
|
-
return
|
|
42140
|
+
return join24(getCleoHome5(), MIGRATIONS_SUBDIR, MIGRATION_MARKER);
|
|
41306
42141
|
}
|
|
41307
42142
|
function tempTargetPath() {
|
|
41308
42143
|
return `${configDirGlobalConfigPath()}.tmp`;
|
|
@@ -41312,12 +42147,12 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41312
42147
|
const source = legacyGlobalConfigPath();
|
|
41313
42148
|
const target = configDirGlobalConfigPath();
|
|
41314
42149
|
const marker16 = migrationMarkerPath();
|
|
41315
|
-
if (
|
|
41316
|
-
if (!
|
|
42150
|
+
if (existsSync21(marker16)) return false;
|
|
42151
|
+
if (!existsSync21(source)) {
|
|
41317
42152
|
stampMarker(marker16);
|
|
41318
42153
|
return false;
|
|
41319
42154
|
}
|
|
41320
|
-
if (
|
|
42155
|
+
if (existsSync21(target)) {
|
|
41321
42156
|
backupSourceQuiet(source);
|
|
41322
42157
|
stampMarker(marker16);
|
|
41323
42158
|
return false;
|
|
@@ -41331,9 +42166,9 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41331
42166
|
);
|
|
41332
42167
|
return false;
|
|
41333
42168
|
}
|
|
41334
|
-
|
|
42169
|
+
mkdirSync6(getCleoPlatformPaths2().config, { recursive: true });
|
|
41335
42170
|
const temp = tempTargetPath();
|
|
41336
|
-
|
|
42171
|
+
writeFileSync5(temp, raw, { mode: 420 });
|
|
41337
42172
|
renameSync4(temp, target);
|
|
41338
42173
|
stampMarker(marker16);
|
|
41339
42174
|
try {
|
|
@@ -41350,7 +42185,7 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41350
42185
|
} catch (err) {
|
|
41351
42186
|
try {
|
|
41352
42187
|
const temp = tempTargetPath();
|
|
41353
|
-
if (
|
|
42188
|
+
if (existsSync21(temp)) unlinkSync5(temp);
|
|
41354
42189
|
} catch {
|
|
41355
42190
|
}
|
|
41356
42191
|
console.error(
|
|
@@ -41361,8 +42196,8 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41361
42196
|
}
|
|
41362
42197
|
function stampMarker(markerPath) {
|
|
41363
42198
|
try {
|
|
41364
|
-
|
|
41365
|
-
|
|
42199
|
+
mkdirSync6(join24(getCleoHome5(), MIGRATIONS_SUBDIR), { recursive: true });
|
|
42200
|
+
writeFileSync5(markerPath, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
41366
42201
|
`, { mode: 420 });
|
|
41367
42202
|
} catch {
|
|
41368
42203
|
}
|
|
@@ -41370,7 +42205,7 @@ function stampMarker(markerPath) {
|
|
|
41370
42205
|
function backupSourceQuiet(source) {
|
|
41371
42206
|
try {
|
|
41372
42207
|
const backup = `${source}${BACKUP_SUFFIX}`;
|
|
41373
|
-
if (
|
|
42208
|
+
if (existsSync21(backup)) return;
|
|
41374
42209
|
renameSync4(source, backup);
|
|
41375
42210
|
} catch {
|
|
41376
42211
|
}
|
|
@@ -41393,20 +42228,20 @@ var init_global_config_migration = __esm({
|
|
|
41393
42228
|
});
|
|
41394
42229
|
|
|
41395
42230
|
// packages/core/src/llm/legacy-flat-key-import.ts
|
|
41396
|
-
import { existsSync as
|
|
41397
|
-
import { join as
|
|
41398
|
-
import { getCleoHome as
|
|
42231
|
+
import { existsSync as existsSync22, readFileSync as readFileSync12, renameSync as renameSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
42232
|
+
import { join as join25 } from "node:path";
|
|
42233
|
+
import { getCleoHome as getCleoHome6 } from "@cleocode/paths";
|
|
41399
42234
|
function migrationPaths() {
|
|
41400
|
-
const home =
|
|
42235
|
+
const home = getCleoHome6();
|
|
41401
42236
|
return {
|
|
41402
|
-
flatPath:
|
|
41403
|
-
bakPath:
|
|
41404
|
-
markerPath:
|
|
42237
|
+
flatPath: join25(home, "anthropic-key"),
|
|
42238
|
+
bakPath: join25(home, `anthropic-key${LEGACY_FLAT_KEY_BAK_SUFFIX}`),
|
|
42239
|
+
markerPath: join25(home, LEGACY_FLAT_KEY_MARKER)
|
|
41405
42240
|
};
|
|
41406
42241
|
}
|
|
41407
42242
|
function writeMarker(markerPath) {
|
|
41408
42243
|
try {
|
|
41409
|
-
|
|
42244
|
+
writeFileSync6(markerPath, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
41410
42245
|
`, {
|
|
41411
42246
|
encoding: "utf-8",
|
|
41412
42247
|
flag: "wx",
|
|
@@ -41422,7 +42257,7 @@ function writeMarker(markerPath) {
|
|
|
41422
42257
|
}
|
|
41423
42258
|
function readFlatKey(flatPath) {
|
|
41424
42259
|
try {
|
|
41425
|
-
if (!
|
|
42260
|
+
if (!existsSync22(flatPath)) return null;
|
|
41426
42261
|
const raw = readFileSync12(flatPath, "utf-8").trim();
|
|
41427
42262
|
return raw || null;
|
|
41428
42263
|
} catch (err) {
|
|
@@ -41435,7 +42270,7 @@ function readFlatKey(flatPath) {
|
|
|
41435
42270
|
}
|
|
41436
42271
|
async function importLegacyFlatAnthropicKey() {
|
|
41437
42272
|
const { flatPath, bakPath, markerPath } = migrationPaths();
|
|
41438
|
-
if (
|
|
42273
|
+
if (existsSync22(markerPath)) {
|
|
41439
42274
|
return { status: "marker-present", flatPath, bakPath: null, markerPath };
|
|
41440
42275
|
}
|
|
41441
42276
|
let existing = null;
|
|
@@ -41452,7 +42287,7 @@ async function importLegacyFlatAnthropicKey() {
|
|
|
41452
42287
|
writeMarker(markerPath);
|
|
41453
42288
|
return { status: "already-imported", flatPath, bakPath: null, markerPath };
|
|
41454
42289
|
}
|
|
41455
|
-
if (!
|
|
42290
|
+
if (!existsSync22(flatPath)) {
|
|
41456
42291
|
writeMarker(markerPath);
|
|
41457
42292
|
return { status: "no-flat-file", flatPath, bakPath: null, markerPath };
|
|
41458
42293
|
}
|
|
@@ -41514,15 +42349,15 @@ var init_legacy_flat_key_import = __esm({
|
|
|
41514
42349
|
});
|
|
41515
42350
|
|
|
41516
42351
|
// packages/core/src/llm/credentials.ts
|
|
41517
|
-
import { existsSync as
|
|
41518
|
-
import { join as
|
|
41519
|
-
import { getCleoHome as
|
|
42352
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
|
|
42353
|
+
import { join as join26 } from "node:path";
|
|
42354
|
+
import { getCleoHome as getCleoHome7 } from "@cleocode/paths";
|
|
41520
42355
|
function globalConfigPath() {
|
|
41521
42356
|
return configDirGlobalConfigPath();
|
|
41522
42357
|
}
|
|
41523
42358
|
function projectConfigPath(projectRoot) {
|
|
41524
42359
|
const cleoDir = process.env["CLEO_DIR"] ?? ".cleo";
|
|
41525
|
-
return
|
|
42360
|
+
return join26(projectRoot, cleoDir, "config.json");
|
|
41526
42361
|
}
|
|
41527
42362
|
function readGlobalProviderKey(provider) {
|
|
41528
42363
|
ensureGlobalConfigMigrated();
|
|
@@ -41532,8 +42367,8 @@ function readGlobalProviderKey(provider) {
|
|
|
41532
42367
|
}
|
|
41533
42368
|
function readFlatAnthropicKey() {
|
|
41534
42369
|
try {
|
|
41535
|
-
const keyFile =
|
|
41536
|
-
if (!
|
|
42370
|
+
const keyFile = join26(getCleoHome7(), "anthropic-key");
|
|
42371
|
+
if (!existsSync23(keyFile)) return null;
|
|
41537
42372
|
const stored = readFileSync13(keyFile, "utf-8").trim();
|
|
41538
42373
|
return stored || null;
|
|
41539
42374
|
} catch {
|
|
@@ -41542,7 +42377,7 @@ function readFlatAnthropicKey() {
|
|
|
41542
42377
|
}
|
|
41543
42378
|
function readProviderKeyFromConfig(configFile, provider) {
|
|
41544
42379
|
try {
|
|
41545
|
-
if (!
|
|
42380
|
+
if (!existsSync23(configFile)) return null;
|
|
41546
42381
|
const raw = readFileSync13(configFile, "utf-8");
|
|
41547
42382
|
const config2 = JSON.parse(raw);
|
|
41548
42383
|
const llm = config2["llm"];
|
|
@@ -41681,17 +42516,17 @@ __export(credentials_store_exports, {
|
|
|
41681
42516
|
pickCredentialForProviderSync: () => pickCredentialForProviderSync,
|
|
41682
42517
|
removeCredential: () => removeCredential
|
|
41683
42518
|
});
|
|
41684
|
-
import { chmodSync, existsSync as
|
|
41685
|
-
import { dirname as dirname9, join as
|
|
41686
|
-
import { getCleoHome as
|
|
42519
|
+
import { chmodSync, existsSync as existsSync24, mkdirSync as mkdirSync8, readFileSync as readFileSync14, statSync as statSync6, writeFileSync as writeFileSync8 } from "node:fs";
|
|
42520
|
+
import { dirname as dirname9, join as join27 } from "node:path";
|
|
42521
|
+
import { getCleoHome as getCleoHome8 } from "@cleocode/paths";
|
|
41687
42522
|
function credentialsStorePath() {
|
|
41688
|
-
return
|
|
42523
|
+
return join27(getCleoHome8(), "llm-credentials.json");
|
|
41689
42524
|
}
|
|
41690
42525
|
function ensureFileInitialized(path) {
|
|
41691
|
-
if (
|
|
42526
|
+
if (existsSync24(path)) return;
|
|
41692
42527
|
const dir = dirname9(path);
|
|
41693
|
-
if (!
|
|
41694
|
-
|
|
42528
|
+
if (!existsSync24(dir)) {
|
|
42529
|
+
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
41695
42530
|
} else {
|
|
41696
42531
|
try {
|
|
41697
42532
|
chmodSync(dir, 448);
|
|
@@ -41699,7 +42534,7 @@ function ensureFileInitialized(path) {
|
|
|
41699
42534
|
}
|
|
41700
42535
|
}
|
|
41701
42536
|
try {
|
|
41702
|
-
|
|
42537
|
+
writeFileSync8(path, `${JSON.stringify(emptyStore(), null, 2)}
|
|
41703
42538
|
`, {
|
|
41704
42539
|
encoding: "utf-8",
|
|
41705
42540
|
flag: "wx",
|
|
@@ -42042,13 +42877,13 @@ var init_gemini = __esm({
|
|
|
42042
42877
|
|
|
42043
42878
|
// packages/core/src/llm/stable-device-id.ts
|
|
42044
42879
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
42045
|
-
import { existsSync as
|
|
42046
|
-
import { dirname as dirname10, join as
|
|
42047
|
-
import { getCleoHome as
|
|
42880
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync9, readFileSync as readFileSync15, renameSync as renameSync6, writeFileSync as writeFileSync9 } from "node:fs";
|
|
42881
|
+
import { dirname as dirname10, join as join28 } from "node:path";
|
|
42882
|
+
import { getCleoHome as getCleoHome9 } from "@cleocode/paths";
|
|
42048
42883
|
function getStableDeviceId() {
|
|
42049
42884
|
if (_cachedDeviceId !== null) return _cachedDeviceId;
|
|
42050
|
-
const path =
|
|
42051
|
-
if (
|
|
42885
|
+
const path = join28(getCleoHome9(), DEVICE_ID_FILE);
|
|
42886
|
+
if (existsSync25(path)) {
|
|
42052
42887
|
try {
|
|
42053
42888
|
const raw = readFileSync15(path, "utf-8").trim();
|
|
42054
42889
|
if (raw.length > 0) {
|
|
@@ -42061,11 +42896,11 @@ function getStableDeviceId() {
|
|
|
42061
42896
|
const fresh = randomUUID2();
|
|
42062
42897
|
try {
|
|
42063
42898
|
const dir = dirname10(path);
|
|
42064
|
-
if (!
|
|
42065
|
-
|
|
42899
|
+
if (!existsSync25(dir)) {
|
|
42900
|
+
mkdirSync9(dir, { recursive: true });
|
|
42066
42901
|
}
|
|
42067
42902
|
const tmpPath = `${path}.tmp.${process.pid}`;
|
|
42068
|
-
|
|
42903
|
+
writeFileSync9(tmpPath, fresh, { mode: 384 });
|
|
42069
42904
|
renameSync6(tmpPath, path);
|
|
42070
42905
|
} catch {
|
|
42071
42906
|
}
|
|
@@ -42363,14 +43198,14 @@ var init_xai = __esm({
|
|
|
42363
43198
|
});
|
|
42364
43199
|
|
|
42365
43200
|
// packages/core/src/llm/provider-registry/loader.ts
|
|
42366
|
-
import { readdirSync as
|
|
42367
|
-
import { join as
|
|
43201
|
+
import { readdirSync as readdirSync6, statSync as statSync7 } from "node:fs";
|
|
43202
|
+
import { join as join29 } from "node:path";
|
|
42368
43203
|
import { pathToFileURL } from "node:url";
|
|
42369
43204
|
function isPluginFile(filename) {
|
|
42370
43205
|
return PLUGIN_EXTENSIONS.some((ext) => filename.endsWith(ext));
|
|
42371
43206
|
}
|
|
42372
43207
|
function getPluginDir() {
|
|
42373
|
-
return
|
|
43208
|
+
return join29(getCleoHome(), "plugins", "model-providers");
|
|
42374
43209
|
}
|
|
42375
43210
|
async function loadOnePlugin(absPath, api) {
|
|
42376
43211
|
let mod;
|
|
@@ -42412,19 +43247,19 @@ async function loadOnePlugin(absPath, api) {
|
|
|
42412
43247
|
async function scanAndLoadPlugins(pluginDir, api) {
|
|
42413
43248
|
let entries;
|
|
42414
43249
|
try {
|
|
42415
|
-
entries =
|
|
43250
|
+
entries = readdirSync6(pluginDir);
|
|
42416
43251
|
} catch {
|
|
42417
43252
|
return;
|
|
42418
43253
|
}
|
|
42419
43254
|
const pluginFiles = entries.filter((name15) => !name15.startsWith(".") && isPluginFile(name15)).filter((name15) => {
|
|
42420
43255
|
try {
|
|
42421
|
-
return statSync7(
|
|
43256
|
+
return statSync7(join29(pluginDir, name15)).isFile();
|
|
42422
43257
|
} catch {
|
|
42423
43258
|
return false;
|
|
42424
43259
|
}
|
|
42425
43260
|
}).sort();
|
|
42426
43261
|
for (const filename of pluginFiles) {
|
|
42427
|
-
await loadOnePlugin(
|
|
43262
|
+
await loadOnePlugin(join29(pluginDir, filename), api);
|
|
42428
43263
|
}
|
|
42429
43264
|
}
|
|
42430
43265
|
async function runDiscovery(registerProvider2, builtins) {
|
|
@@ -42527,15 +43362,15 @@ var init_provider_registry = __esm({
|
|
|
42527
43362
|
});
|
|
42528
43363
|
|
|
42529
43364
|
// packages/core/src/llm/rate-limit-guard.ts
|
|
42530
|
-
import { existsSync as
|
|
42531
|
-
import { join as
|
|
42532
|
-
import { getCleoHome as
|
|
43365
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync10, unlinkSync as unlinkSync6 } from "node:fs";
|
|
43366
|
+
import { join as join30 } from "node:path";
|
|
43367
|
+
import { getCleoHome as getCleoHome10 } from "@cleocode/paths";
|
|
42533
43368
|
function sanitize(value) {
|
|
42534
43369
|
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
42535
43370
|
}
|
|
42536
43371
|
function rateLimitStatePath(provider, label) {
|
|
42537
|
-
const dir =
|
|
42538
|
-
return
|
|
43372
|
+
const dir = join30(getCleoHome10(), "rate-limit-state");
|
|
43373
|
+
return join30(dir, `${sanitize(provider)}-${sanitize(label)}.json`);
|
|
42539
43374
|
}
|
|
42540
43375
|
function parseResetFromHeaders(headers) {
|
|
42541
43376
|
const get = (k) => {
|
|
@@ -42582,9 +43417,9 @@ async function recordRateLimit(provider, label, opts) {
|
|
|
42582
43417
|
source = "default";
|
|
42583
43418
|
}
|
|
42584
43419
|
const filePath = rateLimitStatePath(provider, label);
|
|
42585
|
-
const dir =
|
|
42586
|
-
if (!
|
|
42587
|
-
|
|
43420
|
+
const dir = join30(getCleoHome10(), "rate-limit-state");
|
|
43421
|
+
if (!existsSync26(dir)) {
|
|
43422
|
+
mkdirSync10(dir, { recursive: true });
|
|
42588
43423
|
}
|
|
42589
43424
|
const state = { resetAt, recordedAt: now, source };
|
|
42590
43425
|
await withFileLock(filePath, () => {
|
|
@@ -43098,28 +43933,28 @@ var init_credential_pool = __esm({
|
|
|
43098
43933
|
|
|
43099
43934
|
// packages/core/src/llm/catalog-cache.ts
|
|
43100
43935
|
import {
|
|
43101
|
-
existsSync as
|
|
43102
|
-
mkdirSync as
|
|
43103
|
-
readdirSync as
|
|
43936
|
+
existsSync as existsSync27,
|
|
43937
|
+
mkdirSync as mkdirSync11,
|
|
43938
|
+
readdirSync as readdirSync7,
|
|
43104
43939
|
readFileSync as readFileSync16,
|
|
43105
43940
|
statSync as statSync8,
|
|
43106
43941
|
symlinkSync,
|
|
43107
43942
|
unlinkSync as unlinkSync7,
|
|
43108
|
-
writeFileSync as
|
|
43943
|
+
writeFileSync as writeFileSync10
|
|
43109
43944
|
} from "node:fs";
|
|
43110
43945
|
import { homedir as homedir4 } from "node:os";
|
|
43111
|
-
import { join as
|
|
43946
|
+
import { join as join31 } from "node:path";
|
|
43112
43947
|
function getCatalogDir() {
|
|
43113
43948
|
if (process.env["CLEO_DATA_DIR"]) {
|
|
43114
|
-
return
|
|
43949
|
+
return join31(process.env["CLEO_DATA_DIR"], "llm-catalog");
|
|
43115
43950
|
}
|
|
43116
|
-
const xdg = process.env["XDG_DATA_HOME"] ??
|
|
43117
|
-
return
|
|
43951
|
+
const xdg = process.env["XDG_DATA_HOME"] ?? join31(homedir4(), ".local", "share");
|
|
43952
|
+
return join31(xdg, "cleo", "llm-catalog");
|
|
43118
43953
|
}
|
|
43119
43954
|
function findLatestCacheFile(dir) {
|
|
43120
|
-
if (!
|
|
43121
|
-
const files =
|
|
43122
|
-
return files.length > 0 ?
|
|
43955
|
+
if (!existsSync27(dir)) return null;
|
|
43956
|
+
const files = readdirSync7(dir).filter((f) => f.endsWith("-models.json")).map((f) => ({ name: f, mtime: statSync8(join31(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
43957
|
+
return files.length > 0 ? join31(dir, files[0].name) : null;
|
|
43123
43958
|
}
|
|
43124
43959
|
function readCacheFile(filePath) {
|
|
43125
43960
|
try {
|
|
@@ -43217,7 +44052,7 @@ var init_catalog_model_resolver = __esm({
|
|
|
43217
44052
|
});
|
|
43218
44053
|
|
|
43219
44054
|
// packages/core/src/llm/cross-provider-selector.ts
|
|
43220
|
-
import { totalmem } from "node:os";
|
|
44055
|
+
import { totalmem as totalmem2 } from "node:os";
|
|
43221
44056
|
async function probeOllamaAlive(baseUrl) {
|
|
43222
44057
|
const cached2 = _ollamaProbeCache.get(baseUrl);
|
|
43223
44058
|
if (cached2 && Date.now() - cached2.checkedAt < OLLAMA_PROBE_TTL_MS) {
|
|
@@ -43240,7 +44075,7 @@ async function probeOllamaAlive(baseUrl) {
|
|
|
43240
44075
|
return alive;
|
|
43241
44076
|
}
|
|
43242
44077
|
function ollamaDefaultModelForTier(tier, ramBytesOverride) {
|
|
43243
|
-
const ramBytes = ramBytesOverride ??
|
|
44078
|
+
const ramBytes = ramBytesOverride ?? totalmem2();
|
|
43244
44079
|
const gb = ramBytes / 1024 ** 3;
|
|
43245
44080
|
if (gb >= 8) {
|
|
43246
44081
|
return tier === "fast" || tier === "local" ? "gemma4:e2b" : "gemma4:e4b";
|
|
@@ -43364,7 +44199,7 @@ async function selectBestProvisioned(role, opts) {
|
|
|
43364
44199
|
let model;
|
|
43365
44200
|
if (winner.id === "ollama") {
|
|
43366
44201
|
const ollamaProfile2 = await getProviderProfile2("ollama");
|
|
43367
|
-
const ramBytes =
|
|
44202
|
+
const ramBytes = totalmem2();
|
|
43368
44203
|
const gb = ramBytes / 1024 ** 3;
|
|
43369
44204
|
if (gb >= 8) {
|
|
43370
44205
|
model = (winner.tier === "fast" || taskTier === "fast" ? ollamaProfile2?.defaultAuxModel : ollamaProfile2?.defaultModel) ?? ollamaDefaultModelForTier(winner.tier);
|
|
@@ -43766,7 +44601,7 @@ __export(catalog_resolver_exports, {
|
|
|
43766
44601
|
resolveCatalogEntry: () => resolveCatalogEntry
|
|
43767
44602
|
});
|
|
43768
44603
|
import { readFileSync as readFileSync17 } from "node:fs";
|
|
43769
|
-
import { dirname as dirname11, join as
|
|
44604
|
+
import { dirname as dirname11, join as join32 } from "node:path";
|
|
43770
44605
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
43771
44606
|
async function openCatalogAtPath(dbPath) {
|
|
43772
44607
|
const handle = await openDualScopeDbAtPath("global", dbPath);
|
|
@@ -43776,7 +44611,7 @@ function loadShippedSeed() {
|
|
|
43776
44611
|
if (_seed !== void 0) return _seed;
|
|
43777
44612
|
try {
|
|
43778
44613
|
const thisDir = dirname11(fileURLToPath3(import.meta.url));
|
|
43779
|
-
const jsonPath =
|
|
44614
|
+
const jsonPath = join32(thisDir, "curated-catalog.json");
|
|
43780
44615
|
_seed = JSON.parse(readFileSync17(jsonPath, "utf-8"));
|
|
43781
44616
|
} catch (err) {
|
|
43782
44617
|
logger5.warn(
|
|
@@ -44166,14 +45001,14 @@ var init_message_utils = __esm({
|
|
|
44166
45001
|
|
|
44167
45002
|
// packages/core/src/llm/model-metadata.ts
|
|
44168
45003
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
44169
|
-
import { dirname as dirname12, join as
|
|
45004
|
+
import { dirname as dirname12, join as join33 } from "node:path";
|
|
44170
45005
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
44171
45006
|
function getCuratedTable() {
|
|
44172
45007
|
if (_curated !== void 0) {
|
|
44173
45008
|
return _curated;
|
|
44174
45009
|
}
|
|
44175
45010
|
const thisDir = dirname12(fileURLToPath4(import.meta.url));
|
|
44176
|
-
const jsonPath =
|
|
45011
|
+
const jsonPath = join33(thisDir, "curated-models.json");
|
|
44177
45012
|
const raw = JSON.parse(readFileSync18(jsonPath, "utf-8"));
|
|
44178
45013
|
_curated = raw.models;
|
|
44179
45014
|
return _curated;
|
|
@@ -44252,7 +45087,7 @@ function storedToResolved(stored) {
|
|
|
44252
45087
|
awsProfile: stored.metadata?.["awsProfile"] ?? null
|
|
44253
45088
|
};
|
|
44254
45089
|
}
|
|
44255
|
-
function
|
|
45090
|
+
function sleep2(ms) {
|
|
44256
45091
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
44257
45092
|
}
|
|
44258
45093
|
function backoffMs(policy, attempt) {
|
|
@@ -44390,7 +45225,7 @@ var init_concrete_session = __esm({
|
|
|
44390
45225
|
throw err;
|
|
44391
45226
|
}
|
|
44392
45227
|
lastErr = err;
|
|
44393
|
-
await
|
|
45228
|
+
await sleep2(backoffMs(policy, attempt));
|
|
44394
45229
|
}
|
|
44395
45230
|
}
|
|
44396
45231
|
throw lastErr;
|
|
@@ -48074,7 +48909,7 @@ function normalizeOllamaToolCall(tc) {
|
|
|
48074
48909
|
arguments: JSON.stringify(tc.function.arguments ?? {})
|
|
48075
48910
|
};
|
|
48076
48911
|
}
|
|
48077
|
-
function
|
|
48912
|
+
function sleep3(ms) {
|
|
48078
48913
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
48079
48914
|
}
|
|
48080
48915
|
var OLLAMA_DEFAULT_BASE_URL, MAX_RETRIES, INITIAL_BACKOFF_MS, RETRYABLE_STATUS_CODES, OllamaTransport;
|
|
@@ -48283,7 +49118,7 @@ var init_ollama2 = __esm({
|
|
|
48283
49118
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
48284
49119
|
if (attempt > 0) {
|
|
48285
49120
|
const delay = INITIAL_BACKOFF_MS * 2 ** (attempt - 1);
|
|
48286
|
-
await
|
|
49121
|
+
await sleep3(delay);
|
|
48287
49122
|
}
|
|
48288
49123
|
let response;
|
|
48289
49124
|
try {
|
|
@@ -76215,7 +77050,7 @@ var init_model_runner = __esm({
|
|
|
76215
77050
|
});
|
|
76216
77051
|
|
|
76217
77052
|
// packages/core/src/selfimprove/fix-gen.ts
|
|
76218
|
-
import { writeFileSync as
|
|
77053
|
+
import { writeFileSync as writeFileSync11 } from "node:fs";
|
|
76219
77054
|
import { resolve as resolvePath } from "node:path";
|
|
76220
77055
|
import { cwd as processCwd } from "node:process";
|
|
76221
77056
|
|
|
@@ -76563,7 +77398,7 @@ async function generateFixPatch(opts) {
|
|
|
76563
77398
|
}
|
|
76564
77399
|
const diff = output.diff.endsWith("\n") ? output.diff : `${output.diff}
|
|
76565
77400
|
`;
|
|
76566
|
-
|
|
77401
|
+
writeFileSync11(patchPath, diff, "utf8");
|
|
76567
77402
|
const bytes = Buffer.byteLength(diff, "utf8");
|
|
76568
77403
|
logger8.info(
|
|
76569
77404
|
{ dhqId: request.dhqId, scenario: request.scenario, patchPath, bytes, model: output.model },
|