@cleocode/core 2026.6.19 → 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 +1160 -329
- package/dist/docs/export-document.js.map +3 -3
- package/dist/llm/plugin-facade.js +1211 -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/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/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 +1209 -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/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/package.json +12 -12
|
@@ -12578,7 +12578,7 @@ var init_lafs = __esm({
|
|
|
12578
12578
|
|
|
12579
12579
|
// packages/contracts/src/lease-ipc/messages.ts
|
|
12580
12580
|
import { z as z11 } from "zod";
|
|
12581
|
-
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;
|
|
12582
12582
|
var init_messages2 = __esm({
|
|
12583
12583
|
"packages/contracts/src/lease-ipc/messages.ts"() {
|
|
12584
12584
|
"use strict";
|
|
@@ -12663,6 +12663,24 @@ var init_messages2 = __esm({
|
|
|
12663
12663
|
/** The worker's own view of whether it is currently inside an LLM call. */
|
|
12664
12664
|
in_flight_llm: z11.boolean()
|
|
12665
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();
|
|
12666
12684
|
LeaseIpcRequestSchema = z11.discriminatedUnion("kind", [
|
|
12667
12685
|
LeaseAcquireRequestSchema,
|
|
12668
12686
|
LeaseReleaseRequestSchema,
|
|
@@ -12670,7 +12688,9 @@ var init_messages2 = __esm({
|
|
|
12670
12688
|
RateCheckRequestSchema,
|
|
12671
12689
|
ToolGrantRequestSchema,
|
|
12672
12690
|
QueueAdmitRequestSchema,
|
|
12673
|
-
WorkerHeartbeatRequestSchema
|
|
12691
|
+
WorkerHeartbeatRequestSchema,
|
|
12692
|
+
ResourceAdmitRequestSchema,
|
|
12693
|
+
ResourceReleaseRequestSchema
|
|
12674
12694
|
]);
|
|
12675
12695
|
LeaseGrantedResponseSchema = z11.object({
|
|
12676
12696
|
/** Tag discriminating this response variant. */
|
|
@@ -12771,6 +12791,25 @@ var init_messages2 = __esm({
|
|
|
12771
12791
|
/** Tag discriminating this response variant. */
|
|
12772
12792
|
kind: z11.literal("heartbeat_ack")
|
|
12773
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();
|
|
12774
12813
|
LeaseErrorResponseSchema = z11.object({
|
|
12775
12814
|
/** Tag discriminating this response variant. */
|
|
12776
12815
|
kind: z11.literal("error"),
|
|
@@ -12789,6 +12828,8 @@ var init_messages2 = __esm({
|
|
|
12789
12828
|
ChildKilledUnresponsiveResponseSchema,
|
|
12790
12829
|
QueueAdmitResultResponseSchema,
|
|
12791
12830
|
HeartbeatAckResponseSchema,
|
|
12831
|
+
ResourceAdmitResultResponseSchema,
|
|
12832
|
+
ResourceReleaseResultResponseSchema,
|
|
12792
12833
|
LeaseErrorResponseSchema
|
|
12793
12834
|
]);
|
|
12794
12835
|
LeaseIpcRequestEnvelopeSchema = z11.object({
|
|
@@ -12822,7 +12863,9 @@ var init_messages2 = __esm({
|
|
|
12822
12863
|
"rate_check",
|
|
12823
12864
|
"tool_grant",
|
|
12824
12865
|
"queue_admit",
|
|
12825
|
-
"worker_heartbeat"
|
|
12866
|
+
"worker_heartbeat",
|
|
12867
|
+
"resource_admit",
|
|
12868
|
+
"resource_release"
|
|
12826
12869
|
];
|
|
12827
12870
|
LEASE_IPC_RESPONSE_KINDS = [
|
|
12828
12871
|
"lease_granted",
|
|
@@ -12834,6 +12877,8 @@ var init_messages2 = __esm({
|
|
|
12834
12877
|
"child_killed_unresponsive",
|
|
12835
12878
|
"queue_admit_result",
|
|
12836
12879
|
"heartbeat_ack",
|
|
12880
|
+
"resource_admit_result",
|
|
12881
|
+
"resource_release_result",
|
|
12837
12882
|
"error"
|
|
12838
12883
|
];
|
|
12839
12884
|
LEASE_IPC_MESSAGE_KINDS = [
|
|
@@ -12844,9 +12889,11 @@ var init_messages2 = __esm({
|
|
|
12844
12889
|
});
|
|
12845
12890
|
|
|
12846
12891
|
// packages/contracts/src/lease-ipc/version.ts
|
|
12892
|
+
var LEASE_IPC_PROTOCOL_VERSION;
|
|
12847
12893
|
var init_version2 = __esm({
|
|
12848
12894
|
"packages/contracts/src/lease-ipc/version.ts"() {
|
|
12849
12895
|
"use strict";
|
|
12896
|
+
LEASE_IPC_PROTOCOL_VERSION = "1.2.0";
|
|
12850
12897
|
}
|
|
12851
12898
|
});
|
|
12852
12899
|
|
|
@@ -14045,6 +14092,25 @@ var init_render = __esm({
|
|
|
14045
14092
|
}
|
|
14046
14093
|
});
|
|
14047
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
|
+
|
|
14048
14114
|
// packages/contracts/src/session.ts
|
|
14049
14115
|
var init_session2 = __esm({
|
|
14050
14116
|
"packages/contracts/src/session.ts"() {
|
|
@@ -15795,6 +15861,7 @@ var init_src = __esm({
|
|
|
15795
15861
|
init_evidence_atoms();
|
|
15796
15862
|
init_plan();
|
|
15797
15863
|
init_render();
|
|
15864
|
+
init_resource_governor();
|
|
15798
15865
|
init_session2();
|
|
15799
15866
|
init_session_journal();
|
|
15800
15867
|
init_status_registry();
|
|
@@ -17825,7 +17892,7 @@ var init_sql = __esm({
|
|
|
17825
17892
|
return new SQL([new StringChunk(str)]);
|
|
17826
17893
|
}
|
|
17827
17894
|
_sql.raw = raw;
|
|
17828
|
-
function
|
|
17895
|
+
function join34(chunks, separator) {
|
|
17829
17896
|
const result = [];
|
|
17830
17897
|
for (const [i, chunk] of chunks.entries()) {
|
|
17831
17898
|
if (i > 0 && separator !== void 0) result.push(separator);
|
|
@@ -17833,7 +17900,7 @@ var init_sql = __esm({
|
|
|
17833
17900
|
}
|
|
17834
17901
|
return new SQL(result);
|
|
17835
17902
|
}
|
|
17836
|
-
_sql.join =
|
|
17903
|
+
_sql.join = join34;
|
|
17837
17904
|
function identifier(value) {
|
|
17838
17905
|
return new Name(value);
|
|
17839
17906
|
}
|
|
@@ -20220,7 +20287,7 @@ var init_select2 = __esm({
|
|
|
20220
20287
|
const baseTableName = this.tableName;
|
|
20221
20288
|
const tableName = getTableLikeName(table);
|
|
20222
20289
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
20223
|
-
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`);
|
|
20224
20291
|
if (!this.isPartialSelect) {
|
|
20225
20292
|
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
|
|
20226
20293
|
if (typeof tableName === "string" && !is(table, SQL)) {
|
|
@@ -24030,7 +24097,7 @@ var init_dialect = __esm({
|
|
|
24030
24097
|
if (!joins2) return;
|
|
24031
24098
|
const withEntries = Object.entries(joins2).filter(([_, v]) => v);
|
|
24032
24099
|
if (!withEntries.length) return;
|
|
24033
|
-
return sql.join(withEntries.map(([k,
|
|
24100
|
+
return sql.join(withEntries.map(([k, join34]) => {
|
|
24034
24101
|
const relation = tableConfig.relations[k];
|
|
24035
24102
|
const isSingle2 = is(relation, One);
|
|
24036
24103
|
const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
|
|
@@ -24041,7 +24108,7 @@ var init_dialect = __esm({
|
|
|
24041
24108
|
table: targetTable,
|
|
24042
24109
|
mode: isSingle2 ? "first" : "many",
|
|
24043
24110
|
schema,
|
|
24044
|
-
queryConfig:
|
|
24111
|
+
queryConfig: join34,
|
|
24045
24112
|
tableConfig: schema[relation.targetTableName],
|
|
24046
24113
|
relationWhere: filter2,
|
|
24047
24114
|
isNested: true,
|
|
@@ -24055,7 +24122,7 @@ var init_dialect = __esm({
|
|
|
24055
24122
|
key: k,
|
|
24056
24123
|
selection: innerQuery.selection,
|
|
24057
24124
|
isArray: !isSingle2,
|
|
24058
|
-
isOptional: (relation.optional ?? false) ||
|
|
24125
|
+
isOptional: (relation.optional ?? false) || join34 !== true && !!join34.where
|
|
24059
24126
|
});
|
|
24060
24127
|
const jsonColumns = sql.join(innerQuery.selection.map((s) => {
|
|
24061
24128
|
return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb3}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
|
|
@@ -24876,7 +24943,7 @@ var init_update = __esm({
|
|
|
24876
24943
|
createJoin(joinType) {
|
|
24877
24944
|
return ((table, on) => {
|
|
24878
24945
|
const tableName = getTableLikeName(table);
|
|
24879
|
-
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`);
|
|
24880
24947
|
if (typeof on === "function") {
|
|
24881
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;
|
|
24882
24949
|
on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
|
|
@@ -25951,8 +26018,8 @@ function probeAndMarkApplied(nativeDb, migration, logSubsystem, eliminatedTables
|
|
|
25951
26018
|
});
|
|
25952
26019
|
if (allAltersPresent && allTablesPresent && allIndexesPresent && allTriggersPresent) {
|
|
25953
26020
|
insertJournalEntry(nativeDb, migration.hash, migration.folderMillis, migration.name ?? "");
|
|
25954
|
-
const
|
|
25955
|
-
|
|
26021
|
+
const log9 = getLogger(logSubsystem);
|
|
26022
|
+
log9.debug(
|
|
25956
26023
|
{
|
|
25957
26024
|
migration: migration.name,
|
|
25958
26025
|
alters: alterTargets.length,
|
|
@@ -26021,14 +26088,14 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26021
26088
|
if (hasOrphanedEntries) {
|
|
26022
26089
|
const dbHashes = new Set(dbEntries.map((e) => e.hash));
|
|
26023
26090
|
const allLocalHashesPresentInDb = localMigrations.every((m) => dbHashes.has(m.hash));
|
|
26024
|
-
const
|
|
26091
|
+
const log9 = getLogger(logSubsystem);
|
|
26025
26092
|
if (allLocalHashesPresentInDb) {
|
|
26026
|
-
|
|
26093
|
+
log9.debug(
|
|
26027
26094
|
{ extra: orphanedEntries.length },
|
|
26028
26095
|
`Migration journal has ${orphanedEntries.length} entries for migrations not known to this install (DB is ahead). Skipping reconciliation.`
|
|
26029
26096
|
);
|
|
26030
26097
|
} else {
|
|
26031
|
-
|
|
26098
|
+
log9.warn(
|
|
26032
26099
|
{ orphaned: orphanedEntries.length },
|
|
26033
26100
|
`Detected ${orphanedEntries.length} true-orphan journal entries from a previous CLEO lineage. Reconciling via DDL probe.`
|
|
26034
26101
|
);
|
|
@@ -26064,8 +26131,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26064
26131
|
if (alterMatches.length === 0) {
|
|
26065
26132
|
const stripped = stripSqlComments(fullSql).trim();
|
|
26066
26133
|
if (stripped === "") {
|
|
26067
|
-
const
|
|
26068
|
-
|
|
26134
|
+
const log9 = getLogger(logSubsystem);
|
|
26135
|
+
log9.debug(
|
|
26069
26136
|
{ migration: migration.name },
|
|
26070
26137
|
`Migration ${migration.name} is a comment-only baseline marker \u2014 marking applied on existing DB.`
|
|
26071
26138
|
);
|
|
@@ -26104,8 +26171,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26104
26171
|
}
|
|
26105
26172
|
}
|
|
26106
26173
|
if (missingColumns.length === 0) {
|
|
26107
|
-
const
|
|
26108
|
-
|
|
26174
|
+
const log9 = getLogger(logSubsystem);
|
|
26175
|
+
log9.warn(
|
|
26109
26176
|
{ migration: migration.name, columns: alterMatches },
|
|
26110
26177
|
`Detected partially-applied migration ${migration.name} \u2014 columns exist but journal entry missing. Auto-reconciling.`
|
|
26111
26178
|
);
|
|
@@ -26113,8 +26180,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26113
26180
|
continue;
|
|
26114
26181
|
}
|
|
26115
26182
|
if (existingColumns.length > 0 && missingColumns.length > 0) {
|
|
26116
|
-
const
|
|
26117
|
-
|
|
26183
|
+
const log9 = getLogger(logSubsystem);
|
|
26184
|
+
log9.warn(
|
|
26118
26185
|
{
|
|
26119
26186
|
migration: migration.name,
|
|
26120
26187
|
existingColumns: existingColumns.map((c) => `${c.table}.${c.column}`),
|
|
@@ -26126,12 +26193,12 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26126
26193
|
if (!tableExists(nativeDb, table)) continue;
|
|
26127
26194
|
try {
|
|
26128
26195
|
nativeDb.exec(`ALTER TABLE ${table} ADD COLUMN ${column}${ddl ? ` ${ddl}` : ""}`);
|
|
26129
|
-
|
|
26196
|
+
log9.warn(
|
|
26130
26197
|
{ migration: migration.name, table, column },
|
|
26131
26198
|
`T920: Added missing column ${table}.${column} to complete partial migration.`
|
|
26132
26199
|
);
|
|
26133
26200
|
} catch {
|
|
26134
|
-
|
|
26201
|
+
log9.warn(
|
|
26135
26202
|
{ migration: migration.name, table, column },
|
|
26136
26203
|
`T920: Could not add missing column ${table}.${column} \u2014 will let Drizzle migrate() handle it.`
|
|
26137
26204
|
);
|
|
@@ -26151,8 +26218,8 @@ function reconcileJournal(nativeDb, migrationsFolder, existenceTable2, logSubsys
|
|
|
26151
26218
|
for (const entry of unnamedEntries) {
|
|
26152
26219
|
const migrationName = hashToName.get(entry.hash);
|
|
26153
26220
|
if (!migrationName) continue;
|
|
26154
|
-
const
|
|
26155
|
-
|
|
26221
|
+
const log9 = getLogger(logSubsystem);
|
|
26222
|
+
log9.debug(
|
|
26156
26223
|
{ id: entry.id, hash: entry.hash, name: migrationName },
|
|
26157
26224
|
`Backfilling missing name on journal entry id=${entry.id} (Drizzle v1 beta legacy compat).`
|
|
26158
26225
|
);
|
|
@@ -26236,13 +26303,13 @@ function ensureColumns(nativeDb, tableName, requiredColumns, logSubsystem, conte
|
|
|
26236
26303
|
const existingCols = new Set(columns.map((c) => c.name));
|
|
26237
26304
|
for (const req of requiredColumns) {
|
|
26238
26305
|
if (!existingCols.has(req.name)) {
|
|
26239
|
-
const
|
|
26306
|
+
const log9 = getLogger(logSubsystem);
|
|
26240
26307
|
const message = `Adding missing column ${tableName}.${req.name} via ALTER TABLE`;
|
|
26241
26308
|
const fields = { column: req.name, context };
|
|
26242
26309
|
if (context === "fresh") {
|
|
26243
|
-
|
|
26310
|
+
log9.error(fields, `${message} \u2014 MIGRATION DEFECT (fresh DB should not need repair)`);
|
|
26244
26311
|
} else {
|
|
26245
|
-
|
|
26312
|
+
log9.warn(fields, message);
|
|
26246
26313
|
}
|
|
26247
26314
|
nativeDb.exec(`ALTER TABLE ${tableName} ADD COLUMN ${req.name} ${req.ddl}`);
|
|
26248
26315
|
}
|
|
@@ -35323,11 +35390,750 @@ var init_cleo_global = __esm({
|
|
|
35323
35390
|
}
|
|
35324
35391
|
});
|
|
35325
35392
|
|
|
35326
|
-
// 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";
|
|
35327
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";
|
|
35328
36134
|
async function acquireLock(filePath, options) {
|
|
35329
36135
|
try {
|
|
35330
|
-
const release = await
|
|
36136
|
+
const release = await lockfile2.lock(filePath, {
|
|
35331
36137
|
...DEFAULT_LOCK_OPTIONS,
|
|
35332
36138
|
...options?.stale !== void 0 && { stale: options.stale },
|
|
35333
36139
|
...options?.retries !== void 0 && {
|
|
@@ -35373,7 +36179,7 @@ var init_lock = __esm({
|
|
|
35373
36179
|
});
|
|
35374
36180
|
|
|
35375
36181
|
// packages/core/src/store/atomic.ts
|
|
35376
|
-
import { mkdir, readFile as
|
|
36182
|
+
import { mkdir, readFile as readFile3, rename, unlink } from "node:fs/promises";
|
|
35377
36183
|
import { dirname as dirname4 } from "node:path";
|
|
35378
36184
|
import writeFileAtomic from "write-file-atomic";
|
|
35379
36185
|
async function atomicWrite(filePath, data, options) {
|
|
@@ -35389,7 +36195,7 @@ async function atomicWrite(filePath, data, options) {
|
|
|
35389
36195
|
}
|
|
35390
36196
|
async function safeReadFile(filePath) {
|
|
35391
36197
|
try {
|
|
35392
|
-
return await
|
|
36198
|
+
return await readFile3(filePath, "utf8");
|
|
35393
36199
|
} catch (err) {
|
|
35394
36200
|
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
35395
36201
|
return null;
|
|
@@ -35410,34 +36216,34 @@ var init_atomic = __esm({
|
|
|
35410
36216
|
});
|
|
35411
36217
|
|
|
35412
36218
|
// packages/core/src/store/backup.ts
|
|
35413
|
-
import { copyFile, rename as fsRename, mkdir as mkdir2, readdir, stat, unlink as unlink2 } from "node:fs/promises";
|
|
35414
|
-
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";
|
|
35415
36221
|
async function createBackup(filePath, backupDir, maxBackups = DEFAULT_MAX_BACKUPS) {
|
|
35416
36222
|
try {
|
|
35417
36223
|
await mkdir2(backupDir, { recursive: true });
|
|
35418
36224
|
const fileName = basename(filePath);
|
|
35419
36225
|
try {
|
|
35420
|
-
await
|
|
36226
|
+
await stat2(filePath);
|
|
35421
36227
|
} catch {
|
|
35422
36228
|
throw new CleoError(3 /* FILE_ERROR */, `Cannot backup: source file not found: ${filePath}`);
|
|
35423
36229
|
}
|
|
35424
36230
|
for (let i = maxBackups; i >= 1; i--) {
|
|
35425
|
-
const current =
|
|
36231
|
+
const current = join9(backupDir, `${fileName}.${i}`);
|
|
35426
36232
|
if (i === maxBackups) {
|
|
35427
36233
|
try {
|
|
35428
36234
|
await unlink2(current);
|
|
35429
36235
|
} catch {
|
|
35430
36236
|
}
|
|
35431
36237
|
} else {
|
|
35432
|
-
const next =
|
|
36238
|
+
const next = join9(backupDir, `${fileName}.${i + 1}`);
|
|
35433
36239
|
try {
|
|
35434
|
-
await
|
|
36240
|
+
await stat2(current);
|
|
35435
36241
|
await fsRename(current, next);
|
|
35436
36242
|
} catch {
|
|
35437
36243
|
}
|
|
35438
36244
|
}
|
|
35439
36245
|
}
|
|
35440
|
-
const backupPath =
|
|
36246
|
+
const backupPath = join9(backupDir, `${fileName}.1`);
|
|
35441
36247
|
await copyFile(filePath, backupPath);
|
|
35442
36248
|
return backupPath;
|
|
35443
36249
|
} catch (err) {
|
|
@@ -35716,8 +36522,8 @@ var init_json2 = __esm({
|
|
|
35716
36522
|
});
|
|
35717
36523
|
|
|
35718
36524
|
// packages/core/src/scaffold/ensure-config.ts
|
|
35719
|
-
import { existsSync as
|
|
35720
|
-
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";
|
|
35721
36527
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
35722
36528
|
function getPackageRoot() {
|
|
35723
36529
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
@@ -35725,7 +36531,7 @@ function getPackageRoot() {
|
|
|
35725
36531
|
}
|
|
35726
36532
|
function getCleoVersion() {
|
|
35727
36533
|
try {
|
|
35728
|
-
const pkgPath =
|
|
36534
|
+
const pkgPath = join10(getPackageRoot(), "package.json");
|
|
35729
36535
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
35730
36536
|
return pkg.version ?? "0.0.0";
|
|
35731
36537
|
} catch {
|
|
@@ -35744,25 +36550,25 @@ var init_ensure_config = __esm({
|
|
|
35744
36550
|
// packages/core/src/store/exodus/archive.ts
|
|
35745
36551
|
import {
|
|
35746
36552
|
copyFileSync as copyFileSync2,
|
|
35747
|
-
existsSync as
|
|
35748
|
-
mkdirSync,
|
|
36553
|
+
existsSync as existsSync6,
|
|
36554
|
+
mkdirSync as mkdirSync2,
|
|
35749
36555
|
renameSync,
|
|
35750
36556
|
unlinkSync,
|
|
35751
|
-
writeFileSync
|
|
36557
|
+
writeFileSync as writeFileSync2
|
|
35752
36558
|
} from "node:fs";
|
|
35753
|
-
import { basename as basename3, join as
|
|
36559
|
+
import { basename as basename3, join as join11 } from "node:path";
|
|
35754
36560
|
function scopeBaseDir(scope, cwd) {
|
|
35755
36561
|
return scope === "project" ? resolveCleoDir(cwd) : getCleoHome();
|
|
35756
36562
|
}
|
|
35757
36563
|
function exodusArchiveDir(scope, cwd) {
|
|
35758
|
-
return
|
|
36564
|
+
return join11(scopeBaseDir(scope, cwd), ARCHIVE_DIR_NAME);
|
|
35759
36565
|
}
|
|
35760
36566
|
function exodusMarkerPath(scope, cwd) {
|
|
35761
|
-
return
|
|
36567
|
+
return join11(scopeBaseDir(scope, cwd), MARKER_FILENAME_BY_SCOPE[scope]);
|
|
35762
36568
|
}
|
|
35763
36569
|
function hasExodusCompleteMarker(scope, cwd) {
|
|
35764
36570
|
try {
|
|
35765
|
-
return
|
|
36571
|
+
return existsSync6(exodusMarkerPath(scope, cwd));
|
|
35766
36572
|
} catch {
|
|
35767
36573
|
return false;
|
|
35768
36574
|
}
|
|
@@ -35770,7 +36576,7 @@ function hasExodusCompleteMarker(scope, cwd) {
|
|
|
35770
36576
|
function writeExodusCompleteMarker(scope, archivedSources, cwd) {
|
|
35771
36577
|
const markerPath = exodusMarkerPath(scope, cwd);
|
|
35772
36578
|
const baseDir = scopeBaseDir(scope, cwd);
|
|
35773
|
-
|
|
36579
|
+
mkdirSync2(baseDir, { recursive: true });
|
|
35774
36580
|
const marker16 = {
|
|
35775
36581
|
version: 1,
|
|
35776
36582
|
scope,
|
|
@@ -35779,17 +36585,17 @@ function writeExodusCompleteMarker(scope, archivedSources, cwd) {
|
|
|
35779
36585
|
archivedSources: [...archivedSources]
|
|
35780
36586
|
};
|
|
35781
36587
|
const tmpPath = `${markerPath}.tmp`;
|
|
35782
|
-
|
|
36588
|
+
writeFileSync2(tmpPath, JSON.stringify(marker16, null, 2) + "\n", "utf8");
|
|
35783
36589
|
renameSync(tmpPath, markerPath);
|
|
35784
|
-
|
|
36590
|
+
log3.info({ scope, markerPath, archivedSources }, "exodus: wrote completion marker");
|
|
35785
36591
|
return markerPath;
|
|
35786
36592
|
}
|
|
35787
36593
|
function moveFileInto(srcPath, destDir) {
|
|
35788
|
-
|
|
35789
|
-
let dest =
|
|
35790
|
-
if (
|
|
36594
|
+
mkdirSync2(destDir, { recursive: true });
|
|
36595
|
+
let dest = join11(destDir, basename3(srcPath));
|
|
36596
|
+
if (existsSync6(dest)) {
|
|
35791
36597
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
|
|
35792
|
-
dest =
|
|
36598
|
+
dest = join11(destDir, `${basename3(srcPath)}.${stamp}`);
|
|
35793
36599
|
}
|
|
35794
36600
|
try {
|
|
35795
36601
|
renameSync(srcPath, dest);
|
|
@@ -35800,25 +36606,25 @@ function moveFileInto(srcPath, destDir) {
|
|
|
35800
36606
|
return dest;
|
|
35801
36607
|
}
|
|
35802
36608
|
function archiveSourceDb(source, cwd) {
|
|
35803
|
-
if (!
|
|
36609
|
+
if (!existsSync6(source.path)) {
|
|
35804
36610
|
return { name: source.name, sourcePath: source.path, archivedTo: null, action: "absent" };
|
|
35805
36611
|
}
|
|
35806
36612
|
const destDir = exodusArchiveDir(source.targetScope, cwd);
|
|
35807
36613
|
const archivedTo = moveFileInto(source.path, destDir);
|
|
35808
36614
|
for (const suffix of SIDECAR_SUFFIXES) {
|
|
35809
36615
|
const sidecar = `${source.path}${suffix}`;
|
|
35810
|
-
if (
|
|
36616
|
+
if (existsSync6(sidecar)) {
|
|
35811
36617
|
try {
|
|
35812
36618
|
moveFileInto(sidecar, destDir);
|
|
35813
36619
|
} catch (err) {
|
|
35814
|
-
|
|
36620
|
+
log3.warn(
|
|
35815
36621
|
{ err, sidecar, sourceName: source.name },
|
|
35816
36622
|
"exodus-archive: failed to archive sidecar (non-fatal)"
|
|
35817
36623
|
);
|
|
35818
36624
|
}
|
|
35819
36625
|
}
|
|
35820
36626
|
}
|
|
35821
|
-
|
|
36627
|
+
log3.info(
|
|
35822
36628
|
{ sourceName: source.name, sourcePath: source.path, archivedTo, scope: source.targetScope },
|
|
35823
36629
|
"exodus-archive: archived legacy source DB"
|
|
35824
36630
|
);
|
|
@@ -35853,7 +36659,7 @@ function detectStrandedResidue(sources, cwd) {
|
|
|
35853
36659
|
const stranded = [];
|
|
35854
36660
|
for (const source of sources) {
|
|
35855
36661
|
if (!markedScopes.has(source.targetScope)) continue;
|
|
35856
|
-
if (
|
|
36662
|
+
if (existsSync6(source.path)) {
|
|
35857
36663
|
stranded.push({ name: source.name, path: source.path, scope: source.targetScope });
|
|
35858
36664
|
}
|
|
35859
36665
|
}
|
|
@@ -35869,14 +36675,14 @@ function archiveStrandedResidue(stranded, sources, cwd) {
|
|
|
35869
36675
|
}
|
|
35870
36676
|
return results;
|
|
35871
36677
|
}
|
|
35872
|
-
var
|
|
36678
|
+
var log3, ARCHIVE_DIR_NAME, MARKER_FILENAME_BY_SCOPE, SIDECAR_SUFFIXES;
|
|
35873
36679
|
var init_archive2 = __esm({
|
|
35874
36680
|
"packages/core/src/store/exodus/archive.ts"() {
|
|
35875
36681
|
"use strict";
|
|
35876
36682
|
init_logger();
|
|
35877
36683
|
init_paths();
|
|
35878
36684
|
init_ensure_config();
|
|
35879
|
-
|
|
36685
|
+
log3 = getLogger("exodus-archive");
|
|
35880
36686
|
ARCHIVE_DIR_NAME = "_archive";
|
|
35881
36687
|
MARKER_FILENAME_BY_SCOPE = {
|
|
35882
36688
|
project: "exodus-complete",
|
|
@@ -36270,7 +37076,7 @@ var init_table_name_map = __esm({
|
|
|
36270
37076
|
});
|
|
36271
37077
|
|
|
36272
37078
|
// packages/core/src/store/exodus/count-parity.ts
|
|
36273
|
-
import { existsSync as
|
|
37079
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
36274
37080
|
function listTables(db) {
|
|
36275
37081
|
return db.prepare(
|
|
36276
37082
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
|
|
@@ -36291,14 +37097,14 @@ function rowCount(db, tableName) {
|
|
|
36291
37097
|
function computeCountParity(sources, projectDbPath, globalDbPath) {
|
|
36292
37098
|
const entries = [];
|
|
36293
37099
|
let skipped = 0;
|
|
36294
|
-
if (!
|
|
37100
|
+
if (!existsSync7(projectDbPath) || !existsSync7(globalDbPath)) {
|
|
36295
37101
|
return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
|
|
36296
37102
|
}
|
|
36297
37103
|
const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
|
|
36298
37104
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
36299
37105
|
try {
|
|
36300
37106
|
for (const src of sources) {
|
|
36301
|
-
if (!
|
|
37107
|
+
if (!existsSync7(src.path)) continue;
|
|
36302
37108
|
const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
36303
37109
|
try {
|
|
36304
37110
|
for (const legacyTable of listTables(srcSnap.db)) {
|
|
@@ -36337,27 +37143,27 @@ function computeCountParity(sources, projectDbPath, globalDbPath) {
|
|
|
36337
37143
|
}
|
|
36338
37144
|
const deficits = entries.filter((e) => e.deficit > 0);
|
|
36339
37145
|
if (deficits.length > 0) {
|
|
36340
|
-
|
|
37146
|
+
log4.warn(
|
|
36341
37147
|
{ deficitCount: deficits.length, sample: deficits.slice(0, 5) },
|
|
36342
37148
|
`exodus count-parity: ${deficits.length} table(s) have FEWER rows in the consolidated target than the legacy source`
|
|
36343
37149
|
);
|
|
36344
37150
|
}
|
|
36345
37151
|
return { ok: deficits.length === 0, entries, deficits, checked: entries.length, skipped };
|
|
36346
37152
|
}
|
|
36347
|
-
var
|
|
37153
|
+
var log4;
|
|
36348
37154
|
var init_count_parity = __esm({
|
|
36349
37155
|
"packages/core/src/store/exodus/count-parity.ts"() {
|
|
36350
37156
|
"use strict";
|
|
36351
37157
|
init_logger();
|
|
36352
37158
|
init_open_cleo_db();
|
|
36353
37159
|
init_table_name_map();
|
|
36354
|
-
|
|
37160
|
+
log4 = getLogger("exodus-count-parity");
|
|
36355
37161
|
}
|
|
36356
37162
|
});
|
|
36357
37163
|
|
|
36358
37164
|
// packages/core/src/store/exodus/plan.ts
|
|
36359
|
-
import { existsSync as
|
|
36360
|
-
import { join as
|
|
37165
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3, statfsSync, statSync } from "node:fs";
|
|
37166
|
+
import { join as join12 } from "node:path";
|
|
36361
37167
|
function computeRequiredBytes(totalSourceBytes, largestSourceBytes) {
|
|
36362
37168
|
return Math.ceil(STAGING_HEADROOM_FACTOR * largestSourceBytes) + totalSourceBytes;
|
|
36363
37169
|
}
|
|
@@ -36368,33 +37174,33 @@ function buildSourceDescriptors(cwd) {
|
|
|
36368
37174
|
// Project-tier — go into consolidated project-scope cleo.db
|
|
36369
37175
|
{
|
|
36370
37176
|
name: "tasks",
|
|
36371
|
-
path:
|
|
37177
|
+
path: join12(cleoDir, "tasks.db"),
|
|
36372
37178
|
targetScope: "project"
|
|
36373
37179
|
},
|
|
36374
37180
|
{
|
|
36375
37181
|
name: "brain (project)",
|
|
36376
|
-
path:
|
|
37182
|
+
path: join12(cleoDir, "brain.db"),
|
|
36377
37183
|
targetScope: "project"
|
|
36378
37184
|
},
|
|
36379
37185
|
{
|
|
36380
37186
|
name: "conduit",
|
|
36381
|
-
path:
|
|
37187
|
+
path: join12(cleoDir, "conduit.db"),
|
|
36382
37188
|
targetScope: "project"
|
|
36383
37189
|
},
|
|
36384
37190
|
// Global-tier — go into consolidated global-scope cleo.db
|
|
36385
37191
|
{
|
|
36386
37192
|
name: "nexus",
|
|
36387
|
-
path:
|
|
37193
|
+
path: join12(cleoHome, "nexus.db"),
|
|
36388
37194
|
targetScope: "global"
|
|
36389
37195
|
},
|
|
36390
37196
|
{
|
|
36391
37197
|
name: "signaldock",
|
|
36392
|
-
path:
|
|
37198
|
+
path: join12(cleoHome, "signaldock.db"),
|
|
36393
37199
|
targetScope: "global"
|
|
36394
37200
|
},
|
|
36395
37201
|
{
|
|
36396
37202
|
name: "skills",
|
|
36397
|
-
path:
|
|
37203
|
+
path: join12(cleoHome, "skills.db"),
|
|
36398
37204
|
targetScope: "global"
|
|
36399
37205
|
}
|
|
36400
37206
|
];
|
|
@@ -36420,10 +37226,10 @@ function deriveStagingDirName() {
|
|
|
36420
37226
|
}
|
|
36421
37227
|
function findExistingStaging(cleoDir) {
|
|
36422
37228
|
try {
|
|
36423
|
-
const entries =
|
|
37229
|
+
const entries = readdirSync3(cleoDir, { withFileTypes: true });
|
|
36424
37230
|
const stagingDirs = entries.filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => e.name).sort().reverse();
|
|
36425
37231
|
if (stagingDirs.length > 0) {
|
|
36426
|
-
return
|
|
37232
|
+
return join12(cleoDir, stagingDirs[0]);
|
|
36427
37233
|
}
|
|
36428
37234
|
} catch {
|
|
36429
37235
|
}
|
|
@@ -36439,7 +37245,7 @@ function buildExodusPlan(cwd) {
|
|
|
36439
37245
|
const availableBytes = getAvailableBytes(cleoDir);
|
|
36440
37246
|
const diskPreflight = totalSourceBytes === 0 || availableBytes >= requiredBytes;
|
|
36441
37247
|
const existingStaging = findExistingStaging(cleoDir);
|
|
36442
|
-
const stagingDir = existingStaging ??
|
|
37248
|
+
const stagingDir = existingStaging ?? join12(cleoDir, deriveStagingDirName());
|
|
36443
37249
|
const resumeFromStaging = existingStaging !== null;
|
|
36444
37250
|
const projectDbPath = resolveDualScopeDbPath("project", cwd);
|
|
36445
37251
|
const globalDbPath = resolveDualScopeDbPath("global");
|
|
@@ -36458,7 +37264,7 @@ function buildExodusPlan(cwd) {
|
|
|
36458
37264
|
};
|
|
36459
37265
|
}
|
|
36460
37266
|
function sourcesPresent(sources) {
|
|
36461
|
-
return sources.some((s) =>
|
|
37267
|
+
return sources.some((s) => existsSync8(s.path));
|
|
36462
37268
|
}
|
|
36463
37269
|
var STAGING_HEADROOM_FACTOR, STAGING_COPY_SKIP_THRESHOLD_BYTES;
|
|
36464
37270
|
var init_plan2 = __esm({
|
|
@@ -36472,18 +37278,18 @@ var init_plan2 = __esm({
|
|
|
36472
37278
|
});
|
|
36473
37279
|
|
|
36474
37280
|
// packages/core/src/store/exodus/health.ts
|
|
36475
|
-
import { existsSync as
|
|
37281
|
+
import { existsSync as existsSync9, statSync as statSync2 } from "node:fs";
|
|
36476
37282
|
function buildExodusHealth(cwd) {
|
|
36477
37283
|
const plan = buildExodusPlan(cwd);
|
|
36478
|
-
const anyLegacyPresent = plan.sources.some((s) =>
|
|
37284
|
+
const anyLegacyPresent = plan.sources.some((s) => existsSync9(s.path));
|
|
36479
37285
|
const parity = anyLegacyPresent ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath) : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
|
|
36480
37286
|
const consolidatedExistsByScope = {
|
|
36481
|
-
project:
|
|
36482
|
-
global:
|
|
37287
|
+
project: existsSync9(plan.projectDbPath),
|
|
37288
|
+
global: existsSync9(plan.globalDbPath)
|
|
36483
37289
|
};
|
|
36484
37290
|
const buildScope = (scope) => {
|
|
36485
37291
|
const sources = plan.sources.filter((s) => s.targetScope === scope).map((s) => {
|
|
36486
|
-
const present =
|
|
37292
|
+
const present = existsSync9(s.path);
|
|
36487
37293
|
let bytes = 0;
|
|
36488
37294
|
if (present) {
|
|
36489
37295
|
try {
|
|
@@ -36750,15 +37556,15 @@ var init_types = __esm({
|
|
|
36750
37556
|
// packages/core/src/store/exodus/migrate.ts
|
|
36751
37557
|
import {
|
|
36752
37558
|
copyFileSync as copyFileSync3,
|
|
36753
|
-
existsSync as
|
|
36754
|
-
mkdirSync as
|
|
37559
|
+
existsSync as existsSync10,
|
|
37560
|
+
mkdirSync as mkdirSync3,
|
|
36755
37561
|
readFileSync as readFileSync3,
|
|
36756
37562
|
renameSync as renameSync2,
|
|
36757
37563
|
statSync as statSync3,
|
|
36758
37564
|
unlinkSync as unlinkSync2,
|
|
36759
|
-
writeFileSync as
|
|
37565
|
+
writeFileSync as writeFileSync3
|
|
36760
37566
|
} from "node:fs";
|
|
36761
|
-
import { join as
|
|
37567
|
+
import { join as join13 } from "node:path";
|
|
36762
37568
|
function getSqliteVersion(db) {
|
|
36763
37569
|
try {
|
|
36764
37570
|
const row = db.prepare("SELECT sqlite_version() AS v").get();
|
|
@@ -36774,14 +37580,14 @@ function listTables2(db) {
|
|
|
36774
37580
|
return rows.map((r) => r.name);
|
|
36775
37581
|
}
|
|
36776
37582
|
function writeJournal(stagingDir, journal) {
|
|
36777
|
-
const journalPath =
|
|
37583
|
+
const journalPath = join13(stagingDir, JOURNAL_FILENAME);
|
|
36778
37584
|
const tmpPath = `${journalPath}.tmp`;
|
|
36779
|
-
|
|
37585
|
+
writeFileSync3(tmpPath, JSON.stringify(journal, null, 2) + "\n", "utf8");
|
|
36780
37586
|
renameSync2(tmpPath, journalPath);
|
|
36781
37587
|
}
|
|
36782
37588
|
function readJournal(stagingDir) {
|
|
36783
|
-
const journalPath =
|
|
36784
|
-
if (!
|
|
37589
|
+
const journalPath = join13(stagingDir, JOURNAL_FILENAME);
|
|
37590
|
+
if (!existsSync10(journalPath)) return null;
|
|
36785
37591
|
try {
|
|
36786
37592
|
return JSON.parse(readFileSync3(journalPath, "utf8"));
|
|
36787
37593
|
} catch {
|
|
@@ -36789,17 +37595,17 @@ function readJournal(stagingDir) {
|
|
|
36789
37595
|
}
|
|
36790
37596
|
}
|
|
36791
37597
|
function clearExodusJournal(stagingDir) {
|
|
36792
|
-
const journalPath =
|
|
37598
|
+
const journalPath = join13(stagingDir, JOURNAL_FILENAME);
|
|
36793
37599
|
try {
|
|
36794
|
-
if (!
|
|
37600
|
+
if (!existsSync10(journalPath)) return false;
|
|
36795
37601
|
unlinkSync2(journalPath);
|
|
36796
|
-
|
|
37602
|
+
log5.info(
|
|
36797
37603
|
{ stagingDir },
|
|
36798
37604
|
"exodus: cleared migrate journal after abort/rollback \u2014 a retry will RE-COPY all tables"
|
|
36799
37605
|
);
|
|
36800
37606
|
return true;
|
|
36801
37607
|
} catch (err) {
|
|
36802
|
-
|
|
37608
|
+
log5.warn(
|
|
36803
37609
|
{ err, stagingDir },
|
|
36804
37610
|
'exodus: failed to clear migrate journal after rollback (a retry may skip already-"done" tables)'
|
|
36805
37611
|
);
|
|
@@ -36824,7 +37630,7 @@ function lockPath(dbPath) {
|
|
|
36824
37630
|
}
|
|
36825
37631
|
function acquireAdvisoryLock(dbPath) {
|
|
36826
37632
|
const lp = lockPath(dbPath);
|
|
36827
|
-
|
|
37633
|
+
writeFileSync3(lp, JSON.stringify({ pid: process.pid, ts: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
|
|
36828
37634
|
}
|
|
36829
37635
|
function releaseAdvisoryLock(dbPath) {
|
|
36830
37636
|
try {
|
|
@@ -36887,7 +37693,7 @@ function buildSelectExpr(attachAlias, legacyTable, targetTableName, col, srcType
|
|
|
36887
37693
|
function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyTableName, sourceName, targetSchema = "main") {
|
|
36888
37694
|
const resolution = resolveConsolidatedTableName(sourceName, legacyTableName);
|
|
36889
37695
|
if (resolution.kind === "skip") {
|
|
36890
|
-
|
|
37696
|
+
log5.warn(
|
|
36891
37697
|
{ legacyTableName, sourceName, reason: resolution.reason },
|
|
36892
37698
|
`Exodus: explicitly skipping table \u2014 ${resolution.reason}`
|
|
36893
37699
|
);
|
|
@@ -36906,7 +37712,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36906
37712
|
).get();
|
|
36907
37713
|
if (!existsRow) {
|
|
36908
37714
|
const reason = `consolidated target '${targetTableName}' not found (mapped from legacy '${legacyTableName}')`;
|
|
36909
|
-
|
|
37715
|
+
log5.warn(
|
|
36910
37716
|
{ legacyTableName, targetTableName, sourceName, attachAlias, targetSchema },
|
|
36911
37717
|
`Exodus: ${reason}`
|
|
36912
37718
|
);
|
|
@@ -36917,13 +37723,13 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36917
37723
|
const sharedColumns = srcPragma.map((r) => r.name).filter((col) => tgtColMap.has(col));
|
|
36918
37724
|
if (sharedColumns.length === 0) {
|
|
36919
37725
|
const reason = `no overlapping columns between source '${legacyTableName}' and target '${targetTableName}'`;
|
|
36920
|
-
|
|
37726
|
+
log5.warn({ legacyTableName, targetTableName, sourceName }, `Exodus: ${reason}`);
|
|
36921
37727
|
return { rowsCopied: 0, skipped: true, reason };
|
|
36922
37728
|
}
|
|
36923
37729
|
const srcOnlyColumns = srcPragma.map((r) => r.name).filter((c) => !tgtColMap.has(c));
|
|
36924
37730
|
const tgtOnlyColumns = tgtPragma.map((r) => r.name).filter((c) => !srcColumns.has(c));
|
|
36925
37731
|
if (srcOnlyColumns.length > 0 || tgtOnlyColumns.length > 0) {
|
|
36926
|
-
|
|
37732
|
+
log5.info(
|
|
36927
37733
|
{ legacyTableName, targetTableName, sourceName, srcOnlyColumns, tgtOnlyColumns },
|
|
36928
37734
|
"Exodus: column drift detected \u2014 copying intersection, dropping src-only cols, using defaults for tgt-only cols"
|
|
36929
37735
|
);
|
|
@@ -36938,7 +37744,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36938
37744
|
return isoGlobCols.has(col) && (upper.includes("INT") || upper === "" || upper === "NUMERIC");
|
|
36939
37745
|
});
|
|
36940
37746
|
if (coercedCols.length > 0) {
|
|
36941
|
-
|
|
37747
|
+
log5.info(
|
|
36942
37748
|
{
|
|
36943
37749
|
legacyTableName,
|
|
36944
37750
|
targetTableName,
|
|
@@ -36954,7 +37760,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36954
37760
|
(col) => ENUM_NORMALIZATIONS.has(`${targetTableName}.${col}`)
|
|
36955
37761
|
);
|
|
36956
37762
|
if (normalizedCols.length > 0) {
|
|
36957
|
-
|
|
37763
|
+
log5.info(
|
|
36958
37764
|
{ legacyTableName, targetTableName, sourceName, normalizedCols },
|
|
36959
37765
|
`Exodus: applying enum-value normalization for ${normalizedCols.length} column(s) (T11547)`
|
|
36960
37766
|
);
|
|
@@ -36963,7 +37769,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
36963
37769
|
(col) => NUMERIC_CLAMPS.has(`${targetTableName}.${col}`)
|
|
36964
37770
|
);
|
|
36965
37771
|
if (clampedCols.length > 0) {
|
|
36966
|
-
|
|
37772
|
+
log5.info(
|
|
36967
37773
|
{ legacyTableName, targetTableName, sourceName, clampedCols },
|
|
36968
37774
|
`Exodus: applying non-finite numeric clamp for ${clampedCols.length} column(s) (T11782)`
|
|
36969
37775
|
);
|
|
@@ -37005,7 +37811,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
37005
37811
|
if (rowsCopied < sourceCount) {
|
|
37006
37812
|
const presentAccountedFor = existingBefore + rowsCopied;
|
|
37007
37813
|
if (presentAccountedFor >= sourceCount) {
|
|
37008
|
-
|
|
37814
|
+
log5.info(
|
|
37009
37815
|
{ legacyTableName, targetTableName, sourceName, sourceCount, rowsCopied, existingBefore },
|
|
37010
37816
|
`Exodus: '${legacyTableName}'\u2192'${targetTableName}' \u2014 ${sourceCount - rowsCopied} of ${sourceCount} row(s) already present in target (idempotent PK dedup), ${rowsCopied} newly copied; no loss`
|
|
37011
37817
|
);
|
|
@@ -37013,7 +37819,7 @@ function copyTableFromAttached(targetNativeDb, srcNativeDb, attachAlias, legacyT
|
|
|
37013
37819
|
}
|
|
37014
37820
|
const missing = sourceCount - presentAccountedFor;
|
|
37015
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.`;
|
|
37016
|
-
|
|
37822
|
+
log5.error(
|
|
37017
37823
|
{
|
|
37018
37824
|
legacyTableName,
|
|
37019
37825
|
targetTableName,
|
|
@@ -37033,10 +37839,10 @@ function checkSchemaVersion(journal, forceCrossVersion) {
|
|
|
37033
37839
|
if (journal.targetSchemaVersion !== EXODUS_TARGET_SCHEMA_VERSION) {
|
|
37034
37840
|
const msg = `Schema version mismatch: journal=${journal.targetSchemaVersion}, expected=${EXODUS_TARGET_SCHEMA_VERSION}`;
|
|
37035
37841
|
if (forceCrossVersion) {
|
|
37036
|
-
|
|
37842
|
+
log5.warn(msg + " (--force-cross-version: continuing anyway)");
|
|
37037
37843
|
return true;
|
|
37038
37844
|
}
|
|
37039
|
-
|
|
37845
|
+
log5.error(msg + " \u2014 pass --force-cross-version to override");
|
|
37040
37846
|
return false;
|
|
37041
37847
|
}
|
|
37042
37848
|
return true;
|
|
@@ -37053,10 +37859,10 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37053
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.`
|
|
37054
37860
|
};
|
|
37055
37861
|
}
|
|
37056
|
-
|
|
37862
|
+
mkdirSync3(stagingDir, { recursive: true });
|
|
37057
37863
|
let sqliteVersion = "unknown";
|
|
37058
37864
|
for (const src of sources) {
|
|
37059
|
-
if (
|
|
37865
|
+
if (existsSync10(src.path)) {
|
|
37060
37866
|
const snap = openCleoDbSnapshot(src.path, { readOnly: true });
|
|
37061
37867
|
sqliteVersion = getSqliteVersion(snap.db);
|
|
37062
37868
|
snap.close();
|
|
@@ -37097,15 +37903,15 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37097
37903
|
};
|
|
37098
37904
|
var extractNativeDb = extractNativeDb2;
|
|
37099
37905
|
for (const src of sources) {
|
|
37100
|
-
if (!
|
|
37101
|
-
const backupDest =
|
|
37906
|
+
if (!existsSync10(src.path)) continue;
|
|
37907
|
+
const backupDest = join13(stagingDir, `${src.name.replace(/[^a-z0-9-]/g, "_")}-backup.db`);
|
|
37102
37908
|
const srcBytes = safeStatBytes(src.path);
|
|
37103
37909
|
const skipStagingCopy = srcBytes > plan.stagingCopyThresholdBytes;
|
|
37104
37910
|
if (skipStagingCopy) {
|
|
37105
37911
|
onProgress?.(
|
|
37106
37912
|
`Skipping full staging copy of ${src.name} (${srcBytes} bytes > ${plan.stagingCopyThresholdBytes} threshold) \u2014 source is archived, not deleted, on success.`
|
|
37107
37913
|
);
|
|
37108
|
-
} else if (!
|
|
37914
|
+
} else if (!existsSync10(backupDest)) {
|
|
37109
37915
|
onProgress?.(`Backing up ${src.name} \u2192 staging dir\u2026`);
|
|
37110
37916
|
copyFileSync3(src.path, backupDest);
|
|
37111
37917
|
backupPaths.push(backupDest);
|
|
@@ -37123,8 +37929,8 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37123
37929
|
});
|
|
37124
37930
|
const projectNative = extractNativeDb2(projectHandle);
|
|
37125
37931
|
const globalNative = extractNativeDb2(globalHandle);
|
|
37126
|
-
const projectSources = sources.filter((s) => s.targetScope === "project" &&
|
|
37127
|
-
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));
|
|
37128
37934
|
await migrateScope(
|
|
37129
37935
|
"project",
|
|
37130
37936
|
projectSources,
|
|
@@ -37149,7 +37955,7 @@ async function runExodusMigrate(plan, forceCrossVersion = false, onProgress) {
|
|
|
37149
37955
|
return { ok: true, tables: allTableResults, stagingDir, backupPaths };
|
|
37150
37956
|
} catch (err) {
|
|
37151
37957
|
const error48 = err instanceof Error ? err.message : String(err);
|
|
37152
|
-
|
|
37958
|
+
log5.error({ err }, "Exodus migration failed");
|
|
37153
37959
|
return { ok: false, tables: allTableResults, stagingDir, backupPaths, error: error48 };
|
|
37154
37960
|
} finally {
|
|
37155
37961
|
try {
|
|
@@ -37169,7 +37975,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37169
37975
|
if (sources.length === 0) return;
|
|
37170
37976
|
onProgress?.(`Migrating ${scope}-scope sources\u2026`);
|
|
37171
37977
|
targetNativeDb.exec("PRAGMA foreign_keys = OFF");
|
|
37172
|
-
|
|
37978
|
+
log5.info({ scope }, "Exodus: foreign_keys=OFF for bulk copy (T11533 FK-defer)");
|
|
37173
37979
|
try {
|
|
37174
37980
|
for (let i = 0; i < sources.length; i++) {
|
|
37175
37981
|
const src = sources[i];
|
|
@@ -37236,7 +38042,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37236
38042
|
}
|
|
37237
38043
|
} catch (err) {
|
|
37238
38044
|
const msg = err instanceof Error ? err.message : String(err);
|
|
37239
|
-
|
|
38045
|
+
log5.warn({ tableName, sourceDb: src.name, err }, "Table copy failed \u2014 skipping");
|
|
37240
38046
|
status = "skipped";
|
|
37241
38047
|
errorMsg = msg;
|
|
37242
38048
|
skipped = true;
|
|
@@ -37284,7 +38090,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37284
38090
|
targetNativeDb.exec(`DETACH DATABASE "${attachAlias}"`);
|
|
37285
38091
|
onProgress?.(` [${src.name}] Detached "${attachAlias}"`);
|
|
37286
38092
|
} catch (detachErr) {
|
|
37287
|
-
|
|
38093
|
+
log5.warn(
|
|
37288
38094
|
{ attachAlias, sourceDb: src.name, err: detachErr },
|
|
37289
38095
|
"DETACH failed \u2014 alias will be released on DB close"
|
|
37290
38096
|
);
|
|
@@ -37294,7 +38100,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37294
38100
|
targetNativeDb.exec(`DETACH DATABASE "${crossAlias}"`);
|
|
37295
38101
|
onProgress?.(` [${src.name}] Cross-scope target detached "${crossAlias}"`);
|
|
37296
38102
|
} catch (detachErr) {
|
|
37297
|
-
|
|
38103
|
+
log5.warn(
|
|
37298
38104
|
{ crossAlias, sourceDb: src.name, err: detachErr },
|
|
37299
38105
|
"Cross-scope DETACH failed \u2014 alias will be released on DB close"
|
|
37300
38106
|
);
|
|
@@ -37306,28 +38112,28 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
|
|
|
37306
38112
|
try {
|
|
37307
38113
|
const orphans = targetNativeDb.prepare("PRAGMA foreign_key_check").all();
|
|
37308
38114
|
if (orphans.length > 0) {
|
|
37309
|
-
|
|
38115
|
+
log5.warn(
|
|
37310
38116
|
{ scope, orphanCount: orphans.length, sample: orphans.slice(0, 5) },
|
|
37311
38117
|
`Exodus: PRAGMA foreign_key_check found ${orphans.length} orphan row(s) after bulk copy \u2014 these are genuine data orphans (not ordering artifacts)`
|
|
37312
38118
|
);
|
|
37313
38119
|
} else {
|
|
37314
|
-
|
|
38120
|
+
log5.info({ scope }, "Exodus: PRAGMA foreign_key_check PASSED \u2014 no orphan rows");
|
|
37315
38121
|
}
|
|
37316
38122
|
} catch (checkErr) {
|
|
37317
|
-
|
|
38123
|
+
log5.warn(
|
|
37318
38124
|
{ scope, err: checkErr },
|
|
37319
38125
|
"Exodus: PRAGMA foreign_key_check failed (non-fatal) \u2014 target schema may not have FK constraints enabled"
|
|
37320
38126
|
);
|
|
37321
38127
|
}
|
|
37322
38128
|
try {
|
|
37323
38129
|
targetNativeDb.exec("PRAGMA foreign_keys = ON");
|
|
37324
|
-
|
|
38130
|
+
log5.info({ scope }, "Exodus: foreign_keys=ON restored after bulk copy");
|
|
37325
38131
|
} catch (fkErr) {
|
|
37326
|
-
|
|
38132
|
+
log5.warn({ scope, err: fkErr }, "Exodus: could not restore foreign_keys=ON (non-fatal)");
|
|
37327
38133
|
}
|
|
37328
38134
|
}
|
|
37329
38135
|
}
|
|
37330
|
-
var
|
|
38136
|
+
var log5, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, SOURCE_EPOCH_UNITS;
|
|
37331
38137
|
var init_migrate = __esm({
|
|
37332
38138
|
"packages/core/src/store/exodus/migrate.ts"() {
|
|
37333
38139
|
"use strict";
|
|
@@ -37339,7 +38145,7 @@ var init_migrate = __esm({
|
|
|
37339
38145
|
init_plan2();
|
|
37340
38146
|
init_table_name_map();
|
|
37341
38147
|
init_types();
|
|
37342
|
-
|
|
38148
|
+
log5 = getLogger("exodus-migrate");
|
|
37343
38149
|
LOCK_SENTINEL_SUFFIX = ".exodus-lock";
|
|
37344
38150
|
JOURNAL_FILENAME = "exodus-journal.json";
|
|
37345
38151
|
SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
|
|
@@ -37363,7 +38169,7 @@ function sealExodus(plan, scopeArg, cwd) {
|
|
|
37363
38169
|
const parity = computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath);
|
|
37364
38170
|
if (!parity.ok) {
|
|
37365
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(", ")}`;
|
|
37366
|
-
|
|
38172
|
+
log6.error({ deficits: parity.deficits.length }, `exodus seal refused \u2014 ${refusedReason}`);
|
|
37367
38173
|
return { ok: false, refusedReason, parity, scopes: [] };
|
|
37368
38174
|
}
|
|
37369
38175
|
const outcomes = [];
|
|
@@ -37379,7 +38185,7 @@ function sealExodus(plan, scopeArg, cwd) {
|
|
|
37379
38185
|
scopeSources.map((s) => s.name),
|
|
37380
38186
|
cwd
|
|
37381
38187
|
);
|
|
37382
|
-
|
|
38188
|
+
log6.info(
|
|
37383
38189
|
{ scope, alreadySealed, archived: archived.filter((a) => a.action === "archived").length },
|
|
37384
38190
|
`exodus seal: scope '${scope}' certified (count-parity verified, ${parity.checked} tables)`
|
|
37385
38191
|
);
|
|
@@ -37387,23 +38193,23 @@ function sealExodus(plan, scopeArg, cwd) {
|
|
|
37387
38193
|
}
|
|
37388
38194
|
return { ok: true, parity, scopes: outcomes };
|
|
37389
38195
|
}
|
|
37390
|
-
var
|
|
38196
|
+
var log6;
|
|
37391
38197
|
var init_seal = __esm({
|
|
37392
38198
|
"packages/core/src/store/exodus/seal.ts"() {
|
|
37393
38199
|
"use strict";
|
|
37394
38200
|
init_logger();
|
|
37395
38201
|
init_archive2();
|
|
37396
38202
|
init_count_parity();
|
|
37397
|
-
|
|
38203
|
+
log6 = getLogger("exodus-seal");
|
|
37398
38204
|
}
|
|
37399
38205
|
});
|
|
37400
38206
|
|
|
37401
38207
|
// packages/core/src/store/exodus/status.ts
|
|
37402
|
-
import { existsSync as
|
|
37403
|
-
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";
|
|
37404
38210
|
function readJournal2(stagingDir) {
|
|
37405
|
-
const p =
|
|
37406
|
-
if (!
|
|
38211
|
+
const p = join14(stagingDir, JOURNAL_FILENAME2);
|
|
38212
|
+
if (!existsSync11(p)) return null;
|
|
37407
38213
|
try {
|
|
37408
38214
|
return JSON.parse(readFileSync4(p, "utf8"));
|
|
37409
38215
|
} catch {
|
|
@@ -37412,7 +38218,7 @@ function readJournal2(stagingDir) {
|
|
|
37412
38218
|
}
|
|
37413
38219
|
function findStagingDirs(cleoDir) {
|
|
37414
38220
|
try {
|
|
37415
|
-
return
|
|
38221
|
+
return readdirSync4(cleoDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("exodus-staging-")).map((e) => join14(cleoDir, e.name)).sort().reverse();
|
|
37416
38222
|
} catch {
|
|
37417
38223
|
return [];
|
|
37418
38224
|
}
|
|
@@ -37435,15 +38241,15 @@ function runExodusStatus(cwd) {
|
|
|
37435
38241
|
const sourcesInfo = plan.sources.map((s) => ({
|
|
37436
38242
|
name: s.name,
|
|
37437
38243
|
path: s.path,
|
|
37438
|
-
exists:
|
|
38244
|
+
exists: existsSync11(s.path),
|
|
37439
38245
|
bytes: safeBytes(s.path)
|
|
37440
38246
|
}));
|
|
37441
38247
|
return {
|
|
37442
38248
|
hasStaging: latestStaging !== null,
|
|
37443
38249
|
stagingDir: latestStaging,
|
|
37444
38250
|
journal,
|
|
37445
|
-
projectDbExists:
|
|
37446
|
-
globalDbExists:
|
|
38251
|
+
projectDbExists: existsSync11(projectDbPath),
|
|
38252
|
+
globalDbExists: existsSync11(globalDbPath),
|
|
37447
38253
|
sourcesPresent: sourcesInfo.some((s) => s.exists),
|
|
37448
38254
|
sources: sourcesInfo
|
|
37449
38255
|
};
|
|
@@ -37460,7 +38266,7 @@ var init_status = __esm({
|
|
|
37460
38266
|
});
|
|
37461
38267
|
|
|
37462
38268
|
// packages/core/src/store/exodus/verify-migration.ts
|
|
37463
|
-
import { existsSync as
|
|
38269
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
37464
38270
|
import { createRequire as createRequire3 } from "node:module";
|
|
37465
38271
|
function orderByClause(db, tableName) {
|
|
37466
38272
|
try {
|
|
@@ -37480,7 +38286,7 @@ function computeTableDigest(db, tableName, columns, transform2) {
|
|
|
37480
38286
|
count = Number(row?.c ?? 0);
|
|
37481
38287
|
} catch (err) {
|
|
37482
38288
|
const msg = err instanceof Error ? err.message : String(err);
|
|
37483
|
-
|
|
38289
|
+
log7.warn(
|
|
37484
38290
|
{ tableName, err: msg },
|
|
37485
38291
|
"computeTableDigest: COUNT(*) failed (possibly a virtual/FTS table) \u2014 treating as 0 rows"
|
|
37486
38292
|
);
|
|
@@ -37515,7 +38321,7 @@ function computeTableDigest(db, tableName, columns, transform2) {
|
|
|
37515
38321
|
}
|
|
37516
38322
|
} catch (err) {
|
|
37517
38323
|
const msg = err instanceof Error ? err.message : String(err);
|
|
37518
|
-
|
|
38324
|
+
log7.warn(
|
|
37519
38325
|
{ tableName, err: msg },
|
|
37520
38326
|
"computeTableDigest: streamed SELECT failed (possibly a virtual/FTS table) \u2014 digest skipped (COUNT(*) parity still enforced)"
|
|
37521
38327
|
);
|
|
@@ -37641,7 +38447,7 @@ function foreignKeyCheck(db, scope) {
|
|
|
37641
38447
|
try {
|
|
37642
38448
|
const rows = db.prepare("PRAGMA foreign_key_check").all();
|
|
37643
38449
|
if (rows.length > 0) {
|
|
37644
|
-
|
|
38450
|
+
log7.warn(
|
|
37645
38451
|
{ scope, count: rows.length, sample: rows.slice(0, 5) },
|
|
37646
38452
|
`verifyMigration: PRAGMA foreign_key_check found ${rows.length} orphan row(s)`
|
|
37647
38453
|
);
|
|
@@ -37653,7 +38459,7 @@ function foreignKeyCheck(db, scope) {
|
|
|
37653
38459
|
fkid: r.fkid
|
|
37654
38460
|
}));
|
|
37655
38461
|
} catch (err) {
|
|
37656
|
-
|
|
38462
|
+
log7.warn({ scope, err }, "verifyMigration: PRAGMA foreign_key_check failed (non-fatal)");
|
|
37657
38463
|
return [];
|
|
37658
38464
|
}
|
|
37659
38465
|
}
|
|
@@ -37690,13 +38496,13 @@ function sourceOrphanSignatures(db, sourceName, scope) {
|
|
|
37690
38496
|
const rows = db.prepare("PRAGMA foreign_key_check").all();
|
|
37691
38497
|
for (const r of rows) sigs.add(orphanSignature(db, r, sourceName));
|
|
37692
38498
|
if (rows.length > 0) {
|
|
37693
|
-
|
|
38499
|
+
log7.warn(
|
|
37694
38500
|
{ scope, count: rows.length, sample: rows.slice(0, 5) },
|
|
37695
38501
|
`verifyMigration: source already has ${rows.length} pre-existing FK orphan(s) \u2014 these are tolerated (carried forward losslessly, flagged for data-hygiene)`
|
|
37696
38502
|
);
|
|
37697
38503
|
}
|
|
37698
38504
|
} catch (err) {
|
|
37699
|
-
|
|
38505
|
+
log7.warn({ scope, err }, "verifyMigration: source PRAGMA foreign_key_check failed (non-fatal)");
|
|
37700
38506
|
}
|
|
37701
38507
|
return sigs;
|
|
37702
38508
|
}
|
|
@@ -37708,7 +38514,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37708
38514
|
const preExistingForeignKeyViolations = [];
|
|
37709
38515
|
const failureLines = [];
|
|
37710
38516
|
const sourceOrphanSigs = /* @__PURE__ */ new Set();
|
|
37711
|
-
if (!
|
|
38517
|
+
if (!existsSync12(projectDbPath)) {
|
|
37712
38518
|
return {
|
|
37713
38519
|
ok: false,
|
|
37714
38520
|
tables: [],
|
|
@@ -37719,7 +38525,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37719
38525
|
error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`
|
|
37720
38526
|
};
|
|
37721
38527
|
}
|
|
37722
|
-
if (!
|
|
38528
|
+
if (!existsSync12(globalDbPath)) {
|
|
37723
38529
|
return {
|
|
37724
38530
|
ok: false,
|
|
37725
38531
|
tables: [],
|
|
@@ -37734,7 +38540,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37734
38540
|
const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
|
|
37735
38541
|
try {
|
|
37736
38542
|
for (const src of sources) {
|
|
37737
|
-
if (!
|
|
38543
|
+
if (!existsSync12(src.path)) {
|
|
37738
38544
|
onProgress?.(`Skipping ${src.name} (not present)`);
|
|
37739
38545
|
continue;
|
|
37740
38546
|
}
|
|
@@ -37819,7 +38625,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37819
38625
|
`[${scope}] ${src.name}.${legacyTableName} \u2192 ${targetTableName}: DEFICIT \u2014 source=${srcDigest.count} rows, target=${tgtDigest.count} rows (${srcDigest.count - tgtDigest.count} missing), hashMatch=${hashMatch}`
|
|
37820
38626
|
);
|
|
37821
38627
|
} else if (tgtDigest.count > srcDigest.count) {
|
|
37822
|
-
|
|
38628
|
+
log7.warn(
|
|
37823
38629
|
{
|
|
37824
38630
|
scope,
|
|
37825
38631
|
source: src.name,
|
|
@@ -37869,7 +38675,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37869
38675
|
}
|
|
37870
38676
|
}
|
|
37871
38677
|
if (preExistingForeignKeyViolations.length > 0) {
|
|
37872
|
-
|
|
38678
|
+
log7.warn(
|
|
37873
38679
|
{
|
|
37874
38680
|
count: preExistingForeignKeyViolations.length,
|
|
37875
38681
|
sample: preExistingForeignKeyViolations.slice(0, 5)
|
|
@@ -37879,7 +38685,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37879
38685
|
}
|
|
37880
38686
|
} catch (err) {
|
|
37881
38687
|
const error48 = err instanceof Error ? err.message : String(err);
|
|
37882
|
-
|
|
38688
|
+
log7.error({ err }, "verifyMigration failed");
|
|
37883
38689
|
return {
|
|
37884
38690
|
ok: false,
|
|
37885
38691
|
tables,
|
|
@@ -37896,7 +38702,7 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
|
|
|
37896
38702
|
if (failureLines.length > 0) {
|
|
37897
38703
|
const error48 = `verifyMigration FAILED: ${failureLines.length} issue(s):
|
|
37898
38704
|
${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
|
|
37899
|
-
|
|
38705
|
+
log7.error({ failureCount: failureLines.length }, error48);
|
|
37900
38706
|
return {
|
|
37901
38707
|
ok: false,
|
|
37902
38708
|
tables,
|
|
@@ -37916,7 +38722,7 @@ ${failureLines.map((l) => ` \u2022 ${l}`).join("\n")}`;
|
|
|
37916
38722
|
enumDrift
|
|
37917
38723
|
};
|
|
37918
38724
|
}
|
|
37919
|
-
var
|
|
38725
|
+
var log7, _require, CHECK_ENUM_REGEX;
|
|
37920
38726
|
var init_verify_migration = __esm({
|
|
37921
38727
|
"packages/core/src/store/exodus/verify-migration.ts"() {
|
|
37922
38728
|
"use strict";
|
|
@@ -37925,7 +38731,7 @@ var init_verify_migration = __esm({
|
|
|
37925
38731
|
init_open_cleo_db();
|
|
37926
38732
|
init_column_transforms();
|
|
37927
38733
|
init_table_name_map();
|
|
37928
|
-
|
|
38734
|
+
log7 = getLogger("verify-migration");
|
|
37929
38735
|
_require = createRequire3(import.meta.url);
|
|
37930
38736
|
CHECK_ENUM_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+(?:IS\s+NULL\s+OR\s+"[^"]+"\s+)?IN\s*\(([^)]*)\)\s*\)/gi;
|
|
37931
38737
|
}
|
|
@@ -38017,7 +38823,7 @@ __export(on_open_exports, {
|
|
|
38017
38823
|
isDataContinuityOk: () => isDataContinuityOk,
|
|
38018
38824
|
maybeRunExodusOnOpen: () => maybeRunExodusOnOpen
|
|
38019
38825
|
});
|
|
38020
|
-
import { existsSync as
|
|
38826
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
38021
38827
|
function isDisabledByEnv() {
|
|
38022
38828
|
const v = process.env.CLEO_DISABLE_EXODUS_ON_OPEN;
|
|
38023
38829
|
return v === "1" || v === "true";
|
|
@@ -38043,7 +38849,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
38043
38849
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%'"
|
|
38044
38850
|
).all().map((r) => r.name);
|
|
38045
38851
|
} catch (err) {
|
|
38046
|
-
|
|
38852
|
+
log8.error({ err, scope }, "exodus-on-open: failed to enumerate tables for rollback");
|
|
38047
38853
|
return;
|
|
38048
38854
|
}
|
|
38049
38855
|
try {
|
|
@@ -38053,7 +38859,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
38053
38859
|
try {
|
|
38054
38860
|
nativeDb.exec(`DELETE FROM "${table}"`);
|
|
38055
38861
|
} catch (err) {
|
|
38056
|
-
|
|
38862
|
+
log8.warn({ err, table, scope }, "exodus-on-open: failed to clear table during rollback");
|
|
38057
38863
|
}
|
|
38058
38864
|
}
|
|
38059
38865
|
nativeDb.exec("COMMIT");
|
|
@@ -38062,7 +38868,7 @@ function rollbackConsolidatedToEmpty(nativeDb, scope) {
|
|
|
38062
38868
|
nativeDb.exec("ROLLBACK");
|
|
38063
38869
|
} catch {
|
|
38064
38870
|
}
|
|
38065
|
-
|
|
38871
|
+
log8.error({ err, scope }, "exodus-on-open: rollback transaction failed");
|
|
38066
38872
|
} finally {
|
|
38067
38873
|
try {
|
|
38068
38874
|
nativeDb.exec("PRAGMA foreign_keys = ON");
|
|
@@ -38082,7 +38888,7 @@ async function rollbackBothScopes(scope, projectDbPath, globalDbPath) {
|
|
|
38082
38888
|
rollbackConsolidatedToEmpty(native, s);
|
|
38083
38889
|
}
|
|
38084
38890
|
} catch (err) {
|
|
38085
|
-
|
|
38891
|
+
log8.warn(
|
|
38086
38892
|
{ err, scope: s, openingScope: scope },
|
|
38087
38893
|
"exodus-on-open: could not roll back scope (best-effort)"
|
|
38088
38894
|
);
|
|
@@ -38098,7 +38904,7 @@ function isDataContinuityOk(result) {
|
|
|
38098
38904
|
const deficits = result.tables.filter((t) => t.targetCount < t.sourceCount);
|
|
38099
38905
|
const surpluses = result.tables.filter((t) => t.targetCount > t.sourceCount);
|
|
38100
38906
|
if (surpluses.length > 0) {
|
|
38101
|
-
|
|
38907
|
+
log8.warn(
|
|
38102
38908
|
{
|
|
38103
38909
|
surpluses: surpluses.map((t) => ({
|
|
38104
38910
|
table: t.targetTable,
|
|
@@ -38132,7 +38938,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38132
38938
|
const { buildExodusPlan: buildExodusPlan2, runExodusMigrate: runExodusMigrate2, verifyMigration: verifyMigration2, clearExodusJournal: clearExodusJournal2 } = await Promise.resolve().then(() => (init_exodus(), exodus_exports));
|
|
38133
38939
|
const plan = buildExodusPlan2(cwd);
|
|
38134
38940
|
const scopeSources = plan.sources.filter((s) => s.targetScope === scope);
|
|
38135
|
-
if (!scopeSources.some((s) =>
|
|
38941
|
+
if (!scopeSources.some((s) => existsSync13(s.path))) {
|
|
38136
38942
|
return {
|
|
38137
38943
|
outcome: "skipped",
|
|
38138
38944
|
reason: `no legacy ${scope}-scope source DBs present (fresh install or cross-scope-only)`
|
|
@@ -38145,11 +38951,11 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38145
38951
|
if (!consolidatedIsEmpty(nativeDb, scope)) {
|
|
38146
38952
|
return { outcome: "skipped", reason: "migrated by a concurrent process (lock winner)" };
|
|
38147
38953
|
}
|
|
38148
|
-
|
|
38954
|
+
log8.info(
|
|
38149
38955
|
{
|
|
38150
38956
|
scope,
|
|
38151
38957
|
dbPath,
|
|
38152
|
-
sources: plan.sources.filter((s) =>
|
|
38958
|
+
sources: plan.sources.filter((s) => existsSync13(s.path)).map((s) => s.name)
|
|
38153
38959
|
},
|
|
38154
38960
|
"exodus-on-open: consolidated cleo.db is empty and legacy data present \u2014 auto-migrating"
|
|
38155
38961
|
);
|
|
@@ -38158,23 +38964,23 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38158
38964
|
const migrateResult = await runExodusMigrate2(
|
|
38159
38965
|
plan,
|
|
38160
38966
|
false,
|
|
38161
|
-
(msg) =>
|
|
38967
|
+
(msg) => log8.debug({ scope }, `exodus-on-open: ${msg}`)
|
|
38162
38968
|
);
|
|
38163
38969
|
if (!migrateResult.ok) {
|
|
38164
38970
|
await rollbackBothScopes(scope, plan.projectDbPath, plan.globalDbPath);
|
|
38165
38971
|
clearExodusJournal2(migrateResult.stagingDir);
|
|
38166
38972
|
const reason = `migration failed: ${migrateResult.error ?? "unknown error"} \u2014 legacy DBs kept as source`;
|
|
38167
|
-
|
|
38973
|
+
log8.error({ scope, error: migrateResult.error }, `exodus-on-open: ${reason}`);
|
|
38168
38974
|
return { outcome: "aborted", reason };
|
|
38169
38975
|
}
|
|
38170
38976
|
const verifyResult = verifyMigration2(
|
|
38171
38977
|
plan.sources,
|
|
38172
38978
|
plan.projectDbPath,
|
|
38173
38979
|
plan.globalDbPath,
|
|
38174
|
-
(msg) =>
|
|
38980
|
+
(msg) => log8.debug({ scope }, `exodus-on-open verify: ${msg}`)
|
|
38175
38981
|
);
|
|
38176
38982
|
if (!verifyResult.ok) {
|
|
38177
|
-
|
|
38983
|
+
log8.warn(
|
|
38178
38984
|
{
|
|
38179
38985
|
scope,
|
|
38180
38986
|
enumDrift: verifyResult.enumDrift.length,
|
|
@@ -38188,7 +38994,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38188
38994
|
clearExodusJournal2(plan.stagingDir);
|
|
38189
38995
|
const deficits = verifyResult.tables.filter((t) => t.targetCount < t.sourceCount).map((t) => `${t.targetTable}(${t.sourceCount}\u2192${t.targetCount})`);
|
|
38190
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();
|
|
38191
|
-
|
|
38997
|
+
log8.error(
|
|
38192
38998
|
{
|
|
38193
38999
|
scope,
|
|
38194
39000
|
countDeficits: deficits,
|
|
@@ -38200,14 +39006,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38200
39006
|
return { outcome: "aborted", reason };
|
|
38201
39007
|
}
|
|
38202
39008
|
const rowsCopied = migrateResult.tables.filter((t) => !t.skipped).reduce((n, t) => n + t.rowsCopied, 0);
|
|
38203
|
-
|
|
39009
|
+
log8.info(
|
|
38204
39010
|
{ scope, rowsCopied, tables: migrateResult.tables.length },
|
|
38205
39011
|
"exodus-on-open: parity verified \u2014 legacy data migrated into consolidated cleo.db"
|
|
38206
39012
|
);
|
|
38207
39013
|
try {
|
|
38208
|
-
const consumed = plan.sources.filter((s) =>
|
|
39014
|
+
const consumed = plan.sources.filter((s) => existsSync13(s.path));
|
|
38209
39015
|
const archiveResult = archiveMigratedSources(consumed, cwd);
|
|
38210
|
-
|
|
39016
|
+
log8.info(
|
|
38211
39017
|
{
|
|
38212
39018
|
scope,
|
|
38213
39019
|
archived: archiveResult.sources.filter((s) => s.action === "archived").length,
|
|
@@ -38216,7 +39022,7 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38216
39022
|
"exodus-on-open: archived legacy sources + sealed completion marker(s)"
|
|
38217
39023
|
);
|
|
38218
39024
|
} catch (err) {
|
|
38219
|
-
|
|
39025
|
+
log8.error(
|
|
38220
39026
|
{ err, scope },
|
|
38221
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`)"
|
|
38222
39028
|
);
|
|
@@ -38238,14 +39044,14 @@ async function maybeRunExodusOnOpen(scope, dbPath, nativeDb, cwd) {
|
|
|
38238
39044
|
function _isExodusInProgress() {
|
|
38239
39045
|
return _exodusInProgress;
|
|
38240
39046
|
}
|
|
38241
|
-
var
|
|
39047
|
+
var log8, _exodusInProgress;
|
|
38242
39048
|
var init_on_open = __esm({
|
|
38243
39049
|
"packages/core/src/store/exodus/on-open.ts"() {
|
|
38244
39050
|
"use strict";
|
|
38245
39051
|
init_logger();
|
|
38246
39052
|
init_lock();
|
|
38247
39053
|
init_archive2();
|
|
38248
|
-
|
|
39054
|
+
log8 = getLogger("exodus-on-open");
|
|
38249
39055
|
_exodusInProgress = false;
|
|
38250
39056
|
}
|
|
38251
39057
|
});
|
|
@@ -38262,9 +39068,9 @@ __export(dual_scope_db_exports, {
|
|
|
38262
39068
|
resolveDualScopeDbPath: () => resolveDualScopeDbPath,
|
|
38263
39069
|
upsertIdempotent: () => upsertIdempotent
|
|
38264
39070
|
});
|
|
38265
|
-
import { existsSync as
|
|
39071
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4 } from "node:fs";
|
|
38266
39072
|
import { createRequire as createRequire4 } from "node:module";
|
|
38267
|
-
import { dirname as dirname6, join as
|
|
39073
|
+
import { dirname as dirname6, join as join15 } from "node:path";
|
|
38268
39074
|
function assertWriteDurable(handle) {
|
|
38269
39075
|
if (handle.exodusAbort) {
|
|
38270
39076
|
throw new ExodusAbortWriteUnsafeError(handle.exodusAbort);
|
|
@@ -38281,9 +39087,9 @@ function cacheKey(scope, dbPath) {
|
|
|
38281
39087
|
}
|
|
38282
39088
|
function resolveDualScopeDbPath(scope, cwd) {
|
|
38283
39089
|
if (scope === "project") {
|
|
38284
|
-
return
|
|
39090
|
+
return join15(resolveCleoDir(cwd), "cleo.db");
|
|
38285
39091
|
}
|
|
38286
|
-
return
|
|
39092
|
+
return join15(getCleoHome(), "cleo.db");
|
|
38287
39093
|
}
|
|
38288
39094
|
function migrationsSetName(scope) {
|
|
38289
39095
|
return scope === "project" ? "drizzle-cleo-project" : "drizzle-cleo-global";
|
|
@@ -38326,11 +39132,11 @@ async function openDualScopeDb(scope, cwd) {
|
|
|
38326
39132
|
const dbPath = resolveDualScopeDbPath(scope, cwd);
|
|
38327
39133
|
return scope === "project" ? openDualScopeDbAtPath("project", dbPath, cwd) : openDualScopeDbAtPath("global", dbPath, cwd);
|
|
38328
39134
|
}
|
|
38329
|
-
async function openDedicatedDualScopeDb(scope, dbPath,
|
|
38330
|
-
|
|
39135
|
+
async function openDedicatedDualScopeDb(scope, dbPath, log9) {
|
|
39136
|
+
log9.debug({ scope, dbPath }, "opening DEDICATED (non-cached) dual-scope cleo.db (T11782 FIX D)");
|
|
38331
39137
|
const dir = dirname6(dbPath);
|
|
38332
|
-
if (!
|
|
38333
|
-
|
|
39138
|
+
if (!existsSync14(dir)) {
|
|
39139
|
+
mkdirSync4(dir, { recursive: true });
|
|
38334
39140
|
}
|
|
38335
39141
|
const DatabaseSyncCtor = getDatabaseSyncCtor();
|
|
38336
39142
|
const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
|
|
@@ -38353,7 +39159,7 @@ async function openDedicatedDualScopeDb(scope, dbPath, log8) {
|
|
|
38353
39159
|
existenceTable(scope),
|
|
38354
39160
|
`dual-scope-db[${scope}]`
|
|
38355
39161
|
);
|
|
38356
|
-
|
|
39162
|
+
log9.debug({ scope, dbPath }, "DEDICATED dual-scope cleo.db ready (T11782 FIX D)");
|
|
38357
39163
|
return {
|
|
38358
39164
|
db,
|
|
38359
39165
|
scope,
|
|
@@ -38378,15 +39184,15 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38378
39184
|
return existing.handle;
|
|
38379
39185
|
}
|
|
38380
39186
|
}
|
|
38381
|
-
const
|
|
39187
|
+
const log9 = getLogger("dual-scope-db");
|
|
38382
39188
|
if (dedicated) {
|
|
38383
|
-
return openDedicatedDualScopeDb(scope, dbPath,
|
|
39189
|
+
return openDedicatedDualScopeDb(scope, dbPath, log9);
|
|
38384
39190
|
}
|
|
38385
39191
|
const initPromise = (async () => {
|
|
38386
|
-
|
|
39192
|
+
log9.debug({ scope, dbPath }, "opening dual-scope cleo.db");
|
|
38387
39193
|
const dir = dirname6(dbPath);
|
|
38388
|
-
if (!
|
|
38389
|
-
|
|
39194
|
+
if (!existsSync14(dir)) {
|
|
39195
|
+
mkdirSync4(dir, { recursive: true });
|
|
38390
39196
|
}
|
|
38391
39197
|
const DatabaseSyncCtor = getDatabaseSyncCtor();
|
|
38392
39198
|
const nativeDb = new DatabaseSyncCtor(dbPath, { allowExtension: true });
|
|
@@ -38413,7 +39219,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38413
39219
|
existenceTable(scope),
|
|
38414
39220
|
`dual-scope-db[${scope}]`
|
|
38415
39221
|
);
|
|
38416
|
-
|
|
39222
|
+
log9.debug({ scope, dbPath }, "dual-scope cleo.db ready");
|
|
38417
39223
|
const built = {
|
|
38418
39224
|
db,
|
|
38419
39225
|
scope,
|
|
@@ -38439,6 +39245,25 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38439
39245
|
{ dbPath }
|
|
38440
39246
|
);
|
|
38441
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
|
+
}
|
|
38442
39267
|
try {
|
|
38443
39268
|
const { maybeRunExodusOnOpen: maybeRunExodusOnOpen2 } = await Promise.resolve().then(() => (init_on_open(), on_open_exports));
|
|
38444
39269
|
const result = await maybeRunExodusOnOpen2(scope, dbPath, nativeDb, exodusCwd);
|
|
@@ -38451,7 +39276,7 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38451
39276
|
reason: result.reason,
|
|
38452
39277
|
at: Date.now()
|
|
38453
39278
|
};
|
|
38454
|
-
|
|
39279
|
+
log9.warn(
|
|
38455
39280
|
{ scope, reason: result.reason },
|
|
38456
39281
|
"exodus-on-open aborted; consolidated cleo.db left empty, legacy kept as source \u2014 mutating callers must check handle.exodusAbort / call assertWriteDurable (T11828)"
|
|
38457
39282
|
);
|
|
@@ -38464,11 +39289,14 @@ async function openDualScopeDbAtPath(scope, dbPath, exodusCwd, options) {
|
|
|
38464
39289
|
return reopened;
|
|
38465
39290
|
}
|
|
38466
39291
|
} catch (err) {
|
|
38467
|
-
|
|
39292
|
+
log9.warn(
|
|
38468
39293
|
{ err, scope },
|
|
38469
39294
|
"exodus-on-open hook failed (non-fatal); re-opening consolidated handle"
|
|
38470
39295
|
);
|
|
38471
39296
|
return scope === "project" ? openDualScopeDbAtPath("project", dbPath) : openDualScopeDbAtPath("global", dbPath);
|
|
39297
|
+
} finally {
|
|
39298
|
+
if (releaseDbHeavy) await releaseDbHeavy().catch(() => {
|
|
39299
|
+
});
|
|
38472
39300
|
}
|
|
38473
39301
|
}
|
|
38474
39302
|
return handle;
|
|
@@ -39091,8 +39919,8 @@ __export(nexus_sqlite_exports, {
|
|
|
39091
39919
|
resetNexusDbState: () => resetNexusDbState,
|
|
39092
39920
|
resolveNexusMigrationsFolder: () => resolveNexusMigrationsFolder
|
|
39093
39921
|
});
|
|
39094
|
-
import { copyFileSync as copyFileSync4, existsSync as
|
|
39095
|
-
import { join as
|
|
39922
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync15 } from "node:fs";
|
|
39923
|
+
import { join as join16 } from "node:path";
|
|
39096
39924
|
function getNexusDbPath(cwd) {
|
|
39097
39925
|
return resolveDualScopeDbPath("project", cwd);
|
|
39098
39926
|
}
|
|
@@ -39124,7 +39952,7 @@ function resolveNexusMigrationsFolder() {
|
|
|
39124
39952
|
return resolveCorePackageMigrationsFolder("drizzle-nexus");
|
|
39125
39953
|
}
|
|
39126
39954
|
function getNestedNexusSentinelPath() {
|
|
39127
|
-
return
|
|
39955
|
+
return join16(getCleoHome(), "nexus", NESTED_NEXUS_SENTINEL);
|
|
39128
39956
|
}
|
|
39129
39957
|
function detectAndWarnOnNestedNexus() {
|
|
39130
39958
|
let nestedPath;
|
|
@@ -39133,12 +39961,12 @@ function detectAndWarnOnNestedNexus() {
|
|
|
39133
39961
|
} catch {
|
|
39134
39962
|
return false;
|
|
39135
39963
|
}
|
|
39136
|
-
if (!
|
|
39964
|
+
if (!existsSync15(nestedPath)) return false;
|
|
39137
39965
|
if (_warnedNestedPaths.has(nestedPath)) return false;
|
|
39138
39966
|
_warnedNestedPaths.add(nestedPath);
|
|
39139
39967
|
const canonicalPath = getNexusDbPath();
|
|
39140
|
-
const
|
|
39141
|
-
|
|
39968
|
+
const log9 = getLogger("nexus-sqlite");
|
|
39969
|
+
log9.warn(
|
|
39142
39970
|
{
|
|
39143
39971
|
nestedPath,
|
|
39144
39972
|
canonicalPath,
|
|
@@ -39292,7 +40120,7 @@ function runNexusMigrations(nativeDb, db) {
|
|
|
39292
40120
|
const migrationsFolder = resolveNexusMigrationsFolder();
|
|
39293
40121
|
if (tableExists4(nativeDb, "nexus_nodes") && _nexusDbPath) {
|
|
39294
40122
|
const backupPath = _nexusDbPath.replace(/\.db$/, "-pre-cleo.db.bak");
|
|
39295
|
-
if (!
|
|
40123
|
+
if (!existsSync15(backupPath)) {
|
|
39296
40124
|
try {
|
|
39297
40125
|
copyFileSync4(_nexusDbPath, backupPath);
|
|
39298
40126
|
} catch {
|
|
@@ -39430,10 +40258,10 @@ var init_nexus_sqlite = __esm({
|
|
|
39430
40258
|
|
|
39431
40259
|
// packages/core/src/paths.ts
|
|
39432
40260
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
39433
|
-
import { existsSync as
|
|
40261
|
+
import { existsSync as existsSync16, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
|
|
39434
40262
|
import { createRequire as createRequire5 } from "node:module";
|
|
39435
40263
|
import { homedir } from "node:os";
|
|
39436
|
-
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";
|
|
39437
40265
|
import {
|
|
39438
40266
|
computeCanonicalProjectId as _computeCanonicalProjectId,
|
|
39439
40267
|
getCanonicalTemplatesTildePath as _getCanonicalTemplatesTildePath,
|
|
@@ -39523,8 +40351,8 @@ function getCleoDirAbsolute(cwd, opts) {
|
|
|
39523
40351
|
function _resolveProjectByCwdFromNexus(cwd) {
|
|
39524
40352
|
try {
|
|
39525
40353
|
const cleoHome = getCleoHome();
|
|
39526
|
-
const globalDbPath =
|
|
39527
|
-
if (!
|
|
40354
|
+
const globalDbPath = join17(cleoHome, "cleo.db");
|
|
40355
|
+
if (!existsSync16(globalDbPath)) return null;
|
|
39528
40356
|
const start = resolve3(cwd ?? process.cwd());
|
|
39529
40357
|
let current = start;
|
|
39530
40358
|
const DatabaseSync2 = _getDatabaseSyncCtor();
|
|
@@ -39563,7 +40391,7 @@ function _findCleoDirRoot(cwd) {
|
|
|
39563
40391
|
const isDangerousRoot = current === homeRoot || current === "/" || current === "";
|
|
39564
40392
|
if (!isDangerousRoot) {
|
|
39565
40393
|
try {
|
|
39566
|
-
if (statSync5(
|
|
40394
|
+
if (statSync5(join17(current, ".cleo")).isDirectory()) {
|
|
39567
40395
|
return current;
|
|
39568
40396
|
}
|
|
39569
40397
|
} catch {
|
|
@@ -39578,7 +40406,7 @@ function _findCleoDirRoot(cwd) {
|
|
|
39578
40406
|
function resolveCleoDir(cwd) {
|
|
39579
40407
|
const scope = worktreeScope.getStore();
|
|
39580
40408
|
if (scope !== void 0) {
|
|
39581
|
-
return
|
|
40409
|
+
return join17(scope.worktreeRoot, ".cleo");
|
|
39582
40410
|
}
|
|
39583
40411
|
const override = _cleoDirEnvOverride();
|
|
39584
40412
|
if (override !== null) {
|
|
@@ -39586,14 +40414,14 @@ function resolveCleoDir(cwd) {
|
|
|
39586
40414
|
}
|
|
39587
40415
|
const root = _findCleoDirRoot(cwd);
|
|
39588
40416
|
if (root !== null) {
|
|
39589
|
-
return
|
|
40417
|
+
return join17(root, ".cleo");
|
|
39590
40418
|
}
|
|
39591
40419
|
const start = resolve3(cwd ?? process.cwd());
|
|
39592
40420
|
let current = start;
|
|
39593
40421
|
while (true) {
|
|
39594
40422
|
const mainRepo = _resolveMainRepoFromGitlink(current);
|
|
39595
40423
|
if (mainRepo !== null) {
|
|
39596
|
-
return
|
|
40424
|
+
return join17(mainRepo, ".cleo");
|
|
39597
40425
|
}
|
|
39598
40426
|
const parent = dirname7(current);
|
|
39599
40427
|
if (parent === current) {
|
|
@@ -39635,9 +40463,9 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
39635
40463
|
const start = resolve3(cwd ?? process.cwd());
|
|
39636
40464
|
let current = start;
|
|
39637
40465
|
while (true) {
|
|
39638
|
-
const gitMarker =
|
|
40466
|
+
const gitMarker = join17(current, ".git");
|
|
39639
40467
|
try {
|
|
39640
|
-
if (
|
|
40468
|
+
if (existsSync16(gitMarker)) {
|
|
39641
40469
|
return true;
|
|
39642
40470
|
}
|
|
39643
40471
|
} catch {
|
|
@@ -39649,16 +40477,16 @@ function _cwdHasGitAncestor(cwd) {
|
|
|
39649
40477
|
}
|
|
39650
40478
|
function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
39651
40479
|
try {
|
|
39652
|
-
const gitLinkPath =
|
|
39653
|
-
if (!
|
|
39654
|
-
const
|
|
39655
|
-
if (!
|
|
40480
|
+
const gitLinkPath = join17(gitlinkDir, ".git");
|
|
40481
|
+
if (!existsSync16(gitLinkPath)) return null;
|
|
40482
|
+
const stat3 = statSync5(gitLinkPath);
|
|
40483
|
+
if (!stat3.isFile()) return null;
|
|
39656
40484
|
const gitLinkContent = readFileSync5(gitLinkPath, "utf-8").trim();
|
|
39657
40485
|
const match = gitLinkContent.match(/^gitdir:\s*(.+)$/m);
|
|
39658
40486
|
if (!match) return null;
|
|
39659
40487
|
const gitdir = match[1].trim();
|
|
39660
40488
|
const mainRepo = dirname7(dirname7(dirname7(gitdir)));
|
|
39661
|
-
if (
|
|
40489
|
+
if (existsSync16(join17(mainRepo, ".cleo")) && validateProjectRoot(mainRepo)) {
|
|
39662
40490
|
return mainRepo;
|
|
39663
40491
|
}
|
|
39664
40492
|
} catch {
|
|
@@ -39666,18 +40494,18 @@ function _resolveMainRepoFromGitlink(gitlinkDir) {
|
|
|
39666
40494
|
return null;
|
|
39667
40495
|
}
|
|
39668
40496
|
function validateProjectRoot(candidate) {
|
|
39669
|
-
const cleoDir =
|
|
39670
|
-
if (!
|
|
40497
|
+
const cleoDir = join17(candidate, ".cleo");
|
|
40498
|
+
if (!existsSync16(cleoDir)) {
|
|
39671
40499
|
return false;
|
|
39672
40500
|
}
|
|
39673
|
-
const projectInfoPath =
|
|
39674
|
-
if (
|
|
40501
|
+
const projectInfoPath = join17(cleoDir, "project-info.json");
|
|
40502
|
+
if (existsSync16(projectInfoPath)) {
|
|
39675
40503
|
try {
|
|
39676
40504
|
const raw = readFileSync5(projectInfoPath, "utf-8");
|
|
39677
40505
|
const parsed = JSON.parse(raw);
|
|
39678
40506
|
if (typeof parsed === "object" && parsed !== null && "projectId" in parsed && typeof parsed["projectId"] === "string" && parsed["projectId"] !== "") {
|
|
39679
|
-
const gitMarker =
|
|
39680
|
-
if (
|
|
40507
|
+
const gitMarker = join17(candidate, ".git");
|
|
40508
|
+
if (existsSync16(gitMarker)) {
|
|
39681
40509
|
try {
|
|
39682
40510
|
if (!statSync5(gitMarker).isDirectory()) {
|
|
39683
40511
|
return false;
|
|
@@ -39691,12 +40519,12 @@ function validateProjectRoot(candidate) {
|
|
|
39691
40519
|
} catch {
|
|
39692
40520
|
}
|
|
39693
40521
|
}
|
|
39694
|
-
const gitDir =
|
|
39695
|
-
if (
|
|
40522
|
+
const gitDir = join17(candidate, ".git");
|
|
40523
|
+
if (existsSync16(gitDir)) {
|
|
39696
40524
|
let isRealGitDir = false;
|
|
39697
40525
|
try {
|
|
39698
|
-
const
|
|
39699
|
-
isRealGitDir =
|
|
40526
|
+
const stat3 = statSync5(gitDir);
|
|
40527
|
+
isRealGitDir = stat3.isDirectory();
|
|
39700
40528
|
} catch {
|
|
39701
40529
|
isRealGitDir = false;
|
|
39702
40530
|
}
|
|
@@ -39739,16 +40567,16 @@ function getProjectRoot(cwd) {
|
|
|
39739
40567
|
const homeRoot = homedir();
|
|
39740
40568
|
const skippedCleoDirs = [];
|
|
39741
40569
|
while (true) {
|
|
39742
|
-
const cleoDir =
|
|
39743
|
-
const gitDir =
|
|
40570
|
+
const cleoDir = join17(current, ".cleo");
|
|
40571
|
+
const gitDir = join17(current, ".git");
|
|
39744
40572
|
const isDangerousRoot = current === homeRoot || current === "/" || current === "";
|
|
39745
|
-
if (
|
|
40573
|
+
if (existsSync16(cleoDir) && !isDangerousRoot) {
|
|
39746
40574
|
if (validateProjectRoot(current)) {
|
|
39747
40575
|
return current;
|
|
39748
40576
|
}
|
|
39749
40577
|
skippedCleoDirs.push(current);
|
|
39750
40578
|
}
|
|
39751
|
-
if (
|
|
40579
|
+
if (existsSync16(gitDir) && !isDangerousRoot) {
|
|
39752
40580
|
let isRealGitDir = false;
|
|
39753
40581
|
try {
|
|
39754
40582
|
isRealGitDir = statSync5(gitDir).isDirectory();
|
|
@@ -39793,18 +40621,18 @@ function resolveOrCwd(maybeRoot) {
|
|
|
39793
40621
|
return getProjectRoot();
|
|
39794
40622
|
}
|
|
39795
40623
|
function getConfigPath(cwd) {
|
|
39796
|
-
return
|
|
40624
|
+
return join17(_resolveCleoDir(cwd), "config.json");
|
|
39797
40625
|
}
|
|
39798
40626
|
function getGlobalConfigPath() {
|
|
39799
|
-
return
|
|
40627
|
+
return join17(getCleoHome(), "config.json");
|
|
39800
40628
|
}
|
|
39801
40629
|
function isAbsolutePath(path) {
|
|
39802
40630
|
return _isAbsolutePath(path);
|
|
39803
40631
|
}
|
|
39804
40632
|
function _readProjectNameFromInfo(projectRoot) {
|
|
39805
40633
|
try {
|
|
39806
|
-
const infoPath =
|
|
39807
|
-
if (!
|
|
40634
|
+
const infoPath = join17(projectRoot, ".cleo", "project-info.json");
|
|
40635
|
+
if (!existsSync16(infoPath)) return void 0;
|
|
39808
40636
|
const raw = readFileSync5(infoPath, "utf-8");
|
|
39809
40637
|
const data = JSON.parse(raw);
|
|
39810
40638
|
return typeof data.name === "string" && data.name.length > 0 ? data.name : void 0;
|
|
@@ -39830,8 +40658,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
|
|
|
39830
40658
|
if (existingRows.length > 0) {
|
|
39831
40659
|
const existingPath = existingRows[0].projectPath;
|
|
39832
40660
|
if (existingPath !== resolvedPath) {
|
|
39833
|
-
const newBrainDbPath =
|
|
39834
|
-
const newTasksDbPath =
|
|
40661
|
+
const newBrainDbPath = join17(resolvedPath, ".cleo", "brain.db");
|
|
40662
|
+
const newTasksDbPath = join17(resolvedPath, ".cleo", "tasks.db");
|
|
39835
40663
|
await db.update(projectRegistry2).set({
|
|
39836
40664
|
projectPath: resolvedPath,
|
|
39837
40665
|
projectHash: generateProjectHash2(resolvedPath),
|
|
@@ -39862,8 +40690,8 @@ async function registerProjectOnEncounter(projectRoot, infoProjectId) {
|
|
|
39862
40690
|
lastSync: now,
|
|
39863
40691
|
taskCount: 0,
|
|
39864
40692
|
labelsJson: "[]",
|
|
39865
|
-
brainDbPath:
|
|
39866
|
-
tasksDbPath:
|
|
40693
|
+
brainDbPath: join17(resolvedPath, ".cleo", "brain.db"),
|
|
40694
|
+
tasksDbPath: join17(resolvedPath, ".cleo", "tasks.db"),
|
|
39867
40695
|
statsJson: "{}"
|
|
39868
40696
|
}).onConflictDoNothing();
|
|
39869
40697
|
const aliases = canonicalResult.legacyAliases ?? [];
|
|
@@ -39964,46 +40792,46 @@ var init_api_mode = __esm({
|
|
|
39964
40792
|
// packages/core/src/store/file-utils.ts
|
|
39965
40793
|
import { randomBytes } from "node:crypto";
|
|
39966
40794
|
import {
|
|
39967
|
-
existsSync as
|
|
39968
|
-
mkdirSync as
|
|
39969
|
-
readdirSync as
|
|
40795
|
+
existsSync as existsSync17,
|
|
40796
|
+
mkdirSync as mkdirSync5,
|
|
40797
|
+
readdirSync as readdirSync5,
|
|
39970
40798
|
readFileSync as readFileSync6,
|
|
39971
40799
|
renameSync as renameSync3,
|
|
39972
40800
|
unlinkSync as unlinkSync3,
|
|
39973
|
-
writeFileSync as
|
|
40801
|
+
writeFileSync as writeFileSync4
|
|
39974
40802
|
} from "node:fs";
|
|
39975
|
-
import { basename as basename5, dirname as dirname8, join as
|
|
39976
|
-
import * as
|
|
40803
|
+
import { basename as basename5, dirname as dirname8, join as join18 } from "node:path";
|
|
40804
|
+
import * as lockfile3 from "proper-lockfile";
|
|
39977
40805
|
function rotateBackup(filePath, mode) {
|
|
39978
40806
|
const dir = dirname8(filePath);
|
|
39979
40807
|
const name15 = basename5(filePath);
|
|
39980
|
-
const backupDir =
|
|
40808
|
+
const backupDir = join18(dir, ".backups");
|
|
39981
40809
|
const dirMode = typeof mode === "number" ? modeToDirMode(mode) : void 0;
|
|
39982
|
-
if (!
|
|
39983
|
-
|
|
40810
|
+
if (!existsSync17(backupDir)) {
|
|
40811
|
+
mkdirSync5(backupDir, { recursive: true, mode: dirMode });
|
|
39984
40812
|
}
|
|
39985
40813
|
for (let i = MAX_BACKUPS; i >= 1; i--) {
|
|
39986
|
-
const current =
|
|
40814
|
+
const current = join18(backupDir, `${name15}.${i}`);
|
|
39987
40815
|
if (i === MAX_BACKUPS) {
|
|
39988
40816
|
try {
|
|
39989
40817
|
unlinkSync3(current);
|
|
39990
40818
|
} catch {
|
|
39991
40819
|
}
|
|
39992
40820
|
} else {
|
|
39993
|
-
const next =
|
|
40821
|
+
const next = join18(backupDir, `${name15}.${i + 1}`);
|
|
39994
40822
|
try {
|
|
39995
|
-
if (
|
|
40823
|
+
if (existsSync17(current)) renameSync3(current, next);
|
|
39996
40824
|
} catch {
|
|
39997
40825
|
}
|
|
39998
40826
|
}
|
|
39999
40827
|
}
|
|
40000
40828
|
try {
|
|
40001
40829
|
const content = readFileSync6(filePath, "utf-8");
|
|
40002
|
-
const backupPath =
|
|
40830
|
+
const backupPath = join18(backupDir, `${name15}.1`);
|
|
40003
40831
|
if (typeof mode === "number") {
|
|
40004
|
-
|
|
40832
|
+
writeFileSync4(backupPath, content, { encoding: "utf-8", mode });
|
|
40005
40833
|
} else {
|
|
40006
|
-
|
|
40834
|
+
writeFileSync4(backupPath, content, "utf-8");
|
|
40007
40835
|
}
|
|
40008
40836
|
} catch {
|
|
40009
40837
|
}
|
|
@@ -40020,15 +40848,15 @@ function writeJsonFileAtomic(filePath, data, optsOrIndent = 2) {
|
|
|
40020
40848
|
const indent = opts.indent ?? 2;
|
|
40021
40849
|
const mode = opts.mode;
|
|
40022
40850
|
const dir = dirname8(filePath);
|
|
40023
|
-
const tempPath =
|
|
40851
|
+
const tempPath = join18(dir, `.${basename5(filePath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
40024
40852
|
const content = JSON.stringify(data, null, indent) + "\n";
|
|
40025
40853
|
if (typeof mode === "number") {
|
|
40026
|
-
|
|
40854
|
+
writeFileSync4(tempPath, content, { encoding: "utf-8", mode });
|
|
40027
40855
|
} else {
|
|
40028
|
-
|
|
40856
|
+
writeFileSync4(tempPath, content, "utf-8");
|
|
40029
40857
|
}
|
|
40030
40858
|
try {
|
|
40031
|
-
if (
|
|
40859
|
+
if (existsSync17(filePath)) {
|
|
40032
40860
|
rotateBackup(filePath, mode);
|
|
40033
40861
|
}
|
|
40034
40862
|
renameSync3(tempPath, filePath);
|
|
@@ -40054,19 +40882,19 @@ function readJsonFile(filePath) {
|
|
|
40054
40882
|
async function withLock2(filePath, transform2, opts = {}) {
|
|
40055
40883
|
const dir = dirname8(filePath);
|
|
40056
40884
|
const dirMode = typeof opts.mode === "number" ? modeToDirMode(opts.mode) : void 0;
|
|
40057
|
-
if (!
|
|
40058
|
-
|
|
40885
|
+
if (!existsSync17(dir)) {
|
|
40886
|
+
mkdirSync5(dir, { recursive: true, mode: dirMode });
|
|
40059
40887
|
}
|
|
40060
|
-
if (!
|
|
40888
|
+
if (!existsSync17(filePath)) {
|
|
40061
40889
|
if (typeof opts.mode === "number") {
|
|
40062
|
-
|
|
40890
|
+
writeFileSync4(filePath, "", { encoding: "utf-8", mode: opts.mode });
|
|
40063
40891
|
} else {
|
|
40064
|
-
|
|
40892
|
+
writeFileSync4(filePath, "", "utf-8");
|
|
40065
40893
|
}
|
|
40066
40894
|
}
|
|
40067
40895
|
let release;
|
|
40068
40896
|
try {
|
|
40069
|
-
release = await
|
|
40897
|
+
release = await lockfile3.lock(filePath, LOCK_OPTIONS);
|
|
40070
40898
|
const current = readJsonFile(filePath);
|
|
40071
40899
|
const updated = transform2(current);
|
|
40072
40900
|
writeJsonFileAtomic(filePath, updated, { mode: opts.mode });
|
|
@@ -40079,15 +40907,15 @@ async function withLock2(filePath, transform2, opts = {}) {
|
|
|
40079
40907
|
}
|
|
40080
40908
|
async function withFileLock(filePath, operation) {
|
|
40081
40909
|
const dir = dirname8(filePath);
|
|
40082
|
-
if (!
|
|
40083
|
-
|
|
40910
|
+
if (!existsSync17(dir)) {
|
|
40911
|
+
mkdirSync5(dir, { recursive: true });
|
|
40084
40912
|
}
|
|
40085
|
-
if (!
|
|
40086
|
-
|
|
40913
|
+
if (!existsSync17(filePath)) {
|
|
40914
|
+
writeFileSync4(filePath, "", "utf-8");
|
|
40087
40915
|
}
|
|
40088
40916
|
let release;
|
|
40089
40917
|
try {
|
|
40090
|
-
release = await
|
|
40918
|
+
release = await lockfile3.lock(filePath, LOCK_OPTIONS);
|
|
40091
40919
|
return await operation();
|
|
40092
40920
|
} finally {
|
|
40093
40921
|
if (release) {
|
|
@@ -40116,8 +40944,8 @@ var init_file_utils = __esm({
|
|
|
40116
40944
|
|
|
40117
40945
|
// packages/core/src/llm/credential-removal.ts
|
|
40118
40946
|
import { unlinkSync as unlinkSync4 } from "node:fs";
|
|
40119
|
-
import { join as
|
|
40120
|
-
import { getCleoHome as
|
|
40947
|
+
import { join as join19 } from "node:path";
|
|
40948
|
+
import { getCleoHome as getCleoHome3 } from "@cleocode/paths";
|
|
40121
40949
|
function buildBuiltinRemovalRegistry() {
|
|
40122
40950
|
const registry2 = new RemovalRegistry();
|
|
40123
40951
|
registry2.register(MANUAL_REMOVAL_STEP);
|
|
@@ -40208,7 +41036,7 @@ var init_credential_removal = __esm({
|
|
|
40208
41036
|
sourceId: "cleo-pkce",
|
|
40209
41037
|
description: "Delete CLEO-issued PKCE token at <CLEO_HOME>/anthropic-oauth.json",
|
|
40210
41038
|
async remove() {
|
|
40211
|
-
const path =
|
|
41039
|
+
const path = join19(getCleoHome3(), "anthropic-oauth.json");
|
|
40212
41040
|
const cleaned = [];
|
|
40213
41041
|
try {
|
|
40214
41042
|
unlinkSync4(path);
|
|
@@ -40287,7 +41115,7 @@ __export(config_exports, {
|
|
|
40287
41115
|
parseConfigValue: () => parseConfigValue,
|
|
40288
41116
|
setConfigValue: () => setConfigValue
|
|
40289
41117
|
});
|
|
40290
|
-
import { existsSync as
|
|
41118
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
40291
41119
|
function getNestedValue(obj, path) {
|
|
40292
41120
|
const parts = path.split(".");
|
|
40293
41121
|
let current = obj;
|
|
@@ -40335,7 +41163,7 @@ function parseEnvValue(value) {
|
|
|
40335
41163
|
return value;
|
|
40336
41164
|
}
|
|
40337
41165
|
async function loadConfig(cwd) {
|
|
40338
|
-
let merged = JSON.parse(JSON.stringify(
|
|
41166
|
+
let merged = JSON.parse(JSON.stringify(DEFAULTS2));
|
|
40339
41167
|
const globalConfig2 = await readJson(getGlobalConfigPath());
|
|
40340
41168
|
if (globalConfig2) {
|
|
40341
41169
|
merged = deepMerge(merged, globalConfig2);
|
|
@@ -40381,7 +41209,7 @@ async function getConfigValue(path, cwd) {
|
|
|
40381
41209
|
return { value: val, source: "global" };
|
|
40382
41210
|
}
|
|
40383
41211
|
}
|
|
40384
|
-
const defaultVal = getNestedValue({ ...
|
|
41212
|
+
const defaultVal = getNestedValue({ ...DEFAULTS2 }, path);
|
|
40385
41213
|
return { value: defaultVal, source: "default" };
|
|
40386
41214
|
}
|
|
40387
41215
|
async function getRawConfigValue(key, cwd) {
|
|
@@ -40409,7 +41237,7 @@ function parseConfigValue(value) {
|
|
|
40409
41237
|
}
|
|
40410
41238
|
async function setConfigValue(key, value, cwd, opts) {
|
|
40411
41239
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40412
|
-
if (!
|
|
41240
|
+
if (!existsSync18(configPath)) {
|
|
40413
41241
|
await atomicWriteJson(configPath, {});
|
|
40414
41242
|
}
|
|
40415
41243
|
const config2 = await readJson(configPath) ?? {};
|
|
@@ -40421,7 +41249,7 @@ async function setConfigValue(key, value, cwd, opts) {
|
|
|
40421
41249
|
async function applyStrictnessPreset(preset, cwd, opts) {
|
|
40422
41250
|
const definition = STRICTNESS_PRESETS[preset];
|
|
40423
41251
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40424
|
-
if (!
|
|
41252
|
+
if (!existsSync18(configPath)) {
|
|
40425
41253
|
await atomicWriteJson(configPath, {});
|
|
40426
41254
|
}
|
|
40427
41255
|
const config2 = await readJson(configPath) ?? {};
|
|
@@ -40445,7 +41273,7 @@ function listStrictnessPresets() {
|
|
|
40445
41273
|
})
|
|
40446
41274
|
);
|
|
40447
41275
|
}
|
|
40448
|
-
var
|
|
41276
|
+
var DEFAULTS2, ENV_MAP, STRICTNESS_PRESETS;
|
|
40449
41277
|
var init_config = __esm({
|
|
40450
41278
|
"packages/core/src/config.ts"() {
|
|
40451
41279
|
"use strict";
|
|
@@ -40453,7 +41281,7 @@ var init_config = __esm({
|
|
|
40453
41281
|
init_paths();
|
|
40454
41282
|
init_atomic();
|
|
40455
41283
|
init_json2();
|
|
40456
|
-
|
|
41284
|
+
DEFAULTS2 = {
|
|
40457
41285
|
version: "2.10.0",
|
|
40458
41286
|
output: {
|
|
40459
41287
|
defaultFormat: "json",
|
|
@@ -40628,10 +41456,10 @@ var init_config = __esm({
|
|
|
40628
41456
|
// packages/core/src/llm/credential-seeders/claude-code-seeder.ts
|
|
40629
41457
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
40630
41458
|
import { homedir as homedir2 } from "node:os";
|
|
40631
|
-
import { join as
|
|
41459
|
+
import { join as join20 } from "node:path";
|
|
40632
41460
|
function defaultReadCredentialFile() {
|
|
40633
41461
|
try {
|
|
40634
|
-
return readFileSync7(
|
|
41462
|
+
return readFileSync7(join20(homedir2(), ".claude", ".credentials.json"), "utf-8");
|
|
40635
41463
|
} catch {
|
|
40636
41464
|
return null;
|
|
40637
41465
|
}
|
|
@@ -40726,9 +41554,9 @@ var init_claude_code_seeder = __esm({
|
|
|
40726
41554
|
|
|
40727
41555
|
// packages/core/src/llm/credential-seeders/cleo-pkce-seeder.ts
|
|
40728
41556
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
40729
|
-
import { join as
|
|
41557
|
+
import { join as join21 } from "node:path";
|
|
40730
41558
|
function defaultCleoPkcePath() {
|
|
40731
|
-
return
|
|
41559
|
+
return join21(getCleoHome(), "anthropic-oauth.json");
|
|
40732
41560
|
}
|
|
40733
41561
|
function defaultReadCredentialFile2() {
|
|
40734
41562
|
try {
|
|
@@ -40799,13 +41627,13 @@ var init_cleo_pkce_seeder = __esm({
|
|
|
40799
41627
|
});
|
|
40800
41628
|
|
|
40801
41629
|
// packages/core/src/llm/credential-seeders/codex-cli-seeder.ts
|
|
40802
|
-
import { existsSync as
|
|
41630
|
+
import { existsSync as existsSync19, readFileSync as readFileSync9 } from "node:fs";
|
|
40803
41631
|
import { homedir as homedir3 } from "node:os";
|
|
40804
|
-
import { join as
|
|
41632
|
+
import { join as join22 } from "node:path";
|
|
40805
41633
|
function getCodexAuthPath() {
|
|
40806
41634
|
const codexHome = (process.env["CODEX_HOME"] ?? "").trim();
|
|
40807
|
-
const root = codexHome ||
|
|
40808
|
-
return
|
|
41635
|
+
const root = codexHome || join22(homedir3(), ".codex");
|
|
41636
|
+
return join22(root, "auth.json");
|
|
40809
41637
|
}
|
|
40810
41638
|
var CodexCliSeeder, codexCliSeeder;
|
|
40811
41639
|
var init_codex_cli_seeder = __esm({
|
|
@@ -40824,7 +41652,7 @@ var init_codex_cli_seeder = __esm({
|
|
|
40824
41652
|
*/
|
|
40825
41653
|
async seed() {
|
|
40826
41654
|
const authPath = getCodexAuthPath();
|
|
40827
|
-
if (!
|
|
41655
|
+
if (!existsSync19(authPath)) {
|
|
40828
41656
|
return { entries: [] };
|
|
40829
41657
|
}
|
|
40830
41658
|
let raw;
|
|
@@ -41019,11 +41847,11 @@ var init_google_pkce = __esm({
|
|
|
41019
41847
|
});
|
|
41020
41848
|
|
|
41021
41849
|
// packages/core/src/llm/credential-seeders/gemini-cli-seeder.ts
|
|
41022
|
-
import { existsSync as
|
|
41023
|
-
import { join as
|
|
41024
|
-
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";
|
|
41025
41853
|
function getGoogleOauthPath() {
|
|
41026
|
-
return
|
|
41854
|
+
return join23(getCleoHome4(), "google_oauth.json");
|
|
41027
41855
|
}
|
|
41028
41856
|
function parseGoogleOauthFile(raw) {
|
|
41029
41857
|
let json3;
|
|
@@ -41068,7 +41896,7 @@ var init_gemini_cli_seeder = __esm({
|
|
|
41068
41896
|
*/
|
|
41069
41897
|
async seed() {
|
|
41070
41898
|
const path = getGoogleOauthPath();
|
|
41071
|
-
if (!
|
|
41899
|
+
if (!existsSync20(path)) {
|
|
41072
41900
|
return { entries: [] };
|
|
41073
41901
|
}
|
|
41074
41902
|
let raw;
|
|
@@ -41293,23 +42121,23 @@ var init_credential_seeders = __esm({
|
|
|
41293
42121
|
|
|
41294
42122
|
// packages/core/src/llm/global-config-migration.ts
|
|
41295
42123
|
import {
|
|
41296
|
-
existsSync as
|
|
41297
|
-
mkdirSync as
|
|
42124
|
+
existsSync as existsSync21,
|
|
42125
|
+
mkdirSync as mkdirSync6,
|
|
41298
42126
|
readFileSync as readFileSync11,
|
|
41299
42127
|
renameSync as renameSync4,
|
|
41300
42128
|
unlinkSync as unlinkSync5,
|
|
41301
|
-
writeFileSync as
|
|
42129
|
+
writeFileSync as writeFileSync5
|
|
41302
42130
|
} from "node:fs";
|
|
41303
|
-
import { join as
|
|
41304
|
-
import { getCleoHome as
|
|
42131
|
+
import { join as join24 } from "node:path";
|
|
42132
|
+
import { getCleoHome as getCleoHome5, getCleoPlatformPaths as getCleoPlatformPaths2 } from "@cleocode/paths";
|
|
41305
42133
|
function configDirGlobalConfigPath() {
|
|
41306
|
-
return
|
|
42134
|
+
return join24(getCleoPlatformPaths2().config, GLOBAL_CONFIG_FILENAME);
|
|
41307
42135
|
}
|
|
41308
42136
|
function legacyGlobalConfigPath() {
|
|
41309
|
-
return
|
|
42137
|
+
return join24(getCleoHome5(), GLOBAL_CONFIG_FILENAME);
|
|
41310
42138
|
}
|
|
41311
42139
|
function migrationMarkerPath() {
|
|
41312
|
-
return
|
|
42140
|
+
return join24(getCleoHome5(), MIGRATIONS_SUBDIR, MIGRATION_MARKER);
|
|
41313
42141
|
}
|
|
41314
42142
|
function tempTargetPath() {
|
|
41315
42143
|
return `${configDirGlobalConfigPath()}.tmp`;
|
|
@@ -41319,12 +42147,12 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41319
42147
|
const source = legacyGlobalConfigPath();
|
|
41320
42148
|
const target = configDirGlobalConfigPath();
|
|
41321
42149
|
const marker16 = migrationMarkerPath();
|
|
41322
|
-
if (
|
|
41323
|
-
if (!
|
|
42150
|
+
if (existsSync21(marker16)) return false;
|
|
42151
|
+
if (!existsSync21(source)) {
|
|
41324
42152
|
stampMarker(marker16);
|
|
41325
42153
|
return false;
|
|
41326
42154
|
}
|
|
41327
|
-
if (
|
|
42155
|
+
if (existsSync21(target)) {
|
|
41328
42156
|
backupSourceQuiet(source);
|
|
41329
42157
|
stampMarker(marker16);
|
|
41330
42158
|
return false;
|
|
@@ -41338,9 +42166,9 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41338
42166
|
);
|
|
41339
42167
|
return false;
|
|
41340
42168
|
}
|
|
41341
|
-
|
|
42169
|
+
mkdirSync6(getCleoPlatformPaths2().config, { recursive: true });
|
|
41342
42170
|
const temp = tempTargetPath();
|
|
41343
|
-
|
|
42171
|
+
writeFileSync5(temp, raw, { mode: 420 });
|
|
41344
42172
|
renameSync4(temp, target);
|
|
41345
42173
|
stampMarker(marker16);
|
|
41346
42174
|
try {
|
|
@@ -41357,7 +42185,7 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41357
42185
|
} catch (err) {
|
|
41358
42186
|
try {
|
|
41359
42187
|
const temp = tempTargetPath();
|
|
41360
|
-
if (
|
|
42188
|
+
if (existsSync21(temp)) unlinkSync5(temp);
|
|
41361
42189
|
} catch {
|
|
41362
42190
|
}
|
|
41363
42191
|
console.error(
|
|
@@ -41368,8 +42196,8 @@ function migrateGlobalConfigToConfigDir() {
|
|
|
41368
42196
|
}
|
|
41369
42197
|
function stampMarker(markerPath) {
|
|
41370
42198
|
try {
|
|
41371
|
-
|
|
41372
|
-
|
|
42199
|
+
mkdirSync6(join24(getCleoHome5(), MIGRATIONS_SUBDIR), { recursive: true });
|
|
42200
|
+
writeFileSync5(markerPath, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
41373
42201
|
`, { mode: 420 });
|
|
41374
42202
|
} catch {
|
|
41375
42203
|
}
|
|
@@ -41377,7 +42205,7 @@ function stampMarker(markerPath) {
|
|
|
41377
42205
|
function backupSourceQuiet(source) {
|
|
41378
42206
|
try {
|
|
41379
42207
|
const backup = `${source}${BACKUP_SUFFIX}`;
|
|
41380
|
-
if (
|
|
42208
|
+
if (existsSync21(backup)) return;
|
|
41381
42209
|
renameSync4(source, backup);
|
|
41382
42210
|
} catch {
|
|
41383
42211
|
}
|
|
@@ -41400,20 +42228,20 @@ var init_global_config_migration = __esm({
|
|
|
41400
42228
|
});
|
|
41401
42229
|
|
|
41402
42230
|
// packages/core/src/llm/legacy-flat-key-import.ts
|
|
41403
|
-
import { existsSync as
|
|
41404
|
-
import { join as
|
|
41405
|
-
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";
|
|
41406
42234
|
function migrationPaths() {
|
|
41407
|
-
const home =
|
|
42235
|
+
const home = getCleoHome6();
|
|
41408
42236
|
return {
|
|
41409
|
-
flatPath:
|
|
41410
|
-
bakPath:
|
|
41411
|
-
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)
|
|
41412
42240
|
};
|
|
41413
42241
|
}
|
|
41414
42242
|
function writeMarker(markerPath) {
|
|
41415
42243
|
try {
|
|
41416
|
-
|
|
42244
|
+
writeFileSync6(markerPath, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
41417
42245
|
`, {
|
|
41418
42246
|
encoding: "utf-8",
|
|
41419
42247
|
flag: "wx",
|
|
@@ -41429,7 +42257,7 @@ function writeMarker(markerPath) {
|
|
|
41429
42257
|
}
|
|
41430
42258
|
function readFlatKey(flatPath) {
|
|
41431
42259
|
try {
|
|
41432
|
-
if (!
|
|
42260
|
+
if (!existsSync22(flatPath)) return null;
|
|
41433
42261
|
const raw = readFileSync12(flatPath, "utf-8").trim();
|
|
41434
42262
|
return raw || null;
|
|
41435
42263
|
} catch (err) {
|
|
@@ -41442,7 +42270,7 @@ function readFlatKey(flatPath) {
|
|
|
41442
42270
|
}
|
|
41443
42271
|
async function importLegacyFlatAnthropicKey() {
|
|
41444
42272
|
const { flatPath, bakPath, markerPath } = migrationPaths();
|
|
41445
|
-
if (
|
|
42273
|
+
if (existsSync22(markerPath)) {
|
|
41446
42274
|
return { status: "marker-present", flatPath, bakPath: null, markerPath };
|
|
41447
42275
|
}
|
|
41448
42276
|
let existing = null;
|
|
@@ -41459,7 +42287,7 @@ async function importLegacyFlatAnthropicKey() {
|
|
|
41459
42287
|
writeMarker(markerPath);
|
|
41460
42288
|
return { status: "already-imported", flatPath, bakPath: null, markerPath };
|
|
41461
42289
|
}
|
|
41462
|
-
if (!
|
|
42290
|
+
if (!existsSync22(flatPath)) {
|
|
41463
42291
|
writeMarker(markerPath);
|
|
41464
42292
|
return { status: "no-flat-file", flatPath, bakPath: null, markerPath };
|
|
41465
42293
|
}
|
|
@@ -41521,15 +42349,15 @@ var init_legacy_flat_key_import = __esm({
|
|
|
41521
42349
|
});
|
|
41522
42350
|
|
|
41523
42351
|
// packages/core/src/llm/credentials.ts
|
|
41524
|
-
import { existsSync as
|
|
41525
|
-
import { join as
|
|
41526
|
-
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";
|
|
41527
42355
|
function globalConfigPath() {
|
|
41528
42356
|
return configDirGlobalConfigPath();
|
|
41529
42357
|
}
|
|
41530
42358
|
function projectConfigPath(projectRoot) {
|
|
41531
42359
|
const cleoDir = process.env["CLEO_DIR"] ?? ".cleo";
|
|
41532
|
-
return
|
|
42360
|
+
return join26(projectRoot, cleoDir, "config.json");
|
|
41533
42361
|
}
|
|
41534
42362
|
function readGlobalProviderKey(provider) {
|
|
41535
42363
|
ensureGlobalConfigMigrated();
|
|
@@ -41539,8 +42367,8 @@ function readGlobalProviderKey(provider) {
|
|
|
41539
42367
|
}
|
|
41540
42368
|
function readFlatAnthropicKey() {
|
|
41541
42369
|
try {
|
|
41542
|
-
const keyFile =
|
|
41543
|
-
if (!
|
|
42370
|
+
const keyFile = join26(getCleoHome7(), "anthropic-key");
|
|
42371
|
+
if (!existsSync23(keyFile)) return null;
|
|
41544
42372
|
const stored = readFileSync13(keyFile, "utf-8").trim();
|
|
41545
42373
|
return stored || null;
|
|
41546
42374
|
} catch {
|
|
@@ -41549,7 +42377,7 @@ function readFlatAnthropicKey() {
|
|
|
41549
42377
|
}
|
|
41550
42378
|
function readProviderKeyFromConfig(configFile, provider) {
|
|
41551
42379
|
try {
|
|
41552
|
-
if (!
|
|
42380
|
+
if (!existsSync23(configFile)) return null;
|
|
41553
42381
|
const raw = readFileSync13(configFile, "utf-8");
|
|
41554
42382
|
const config2 = JSON.parse(raw);
|
|
41555
42383
|
const llm = config2["llm"];
|
|
@@ -41688,17 +42516,17 @@ __export(credentials_store_exports, {
|
|
|
41688
42516
|
pickCredentialForProviderSync: () => pickCredentialForProviderSync,
|
|
41689
42517
|
removeCredential: () => removeCredential
|
|
41690
42518
|
});
|
|
41691
|
-
import { chmodSync, existsSync as
|
|
41692
|
-
import { dirname as dirname9, join as
|
|
41693
|
-
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";
|
|
41694
42522
|
function credentialsStorePath() {
|
|
41695
|
-
return
|
|
42523
|
+
return join27(getCleoHome8(), "llm-credentials.json");
|
|
41696
42524
|
}
|
|
41697
42525
|
function ensureFileInitialized(path) {
|
|
41698
|
-
if (
|
|
42526
|
+
if (existsSync24(path)) return;
|
|
41699
42527
|
const dir = dirname9(path);
|
|
41700
|
-
if (!
|
|
41701
|
-
|
|
42528
|
+
if (!existsSync24(dir)) {
|
|
42529
|
+
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
41702
42530
|
} else {
|
|
41703
42531
|
try {
|
|
41704
42532
|
chmodSync(dir, 448);
|
|
@@ -41706,7 +42534,7 @@ function ensureFileInitialized(path) {
|
|
|
41706
42534
|
}
|
|
41707
42535
|
}
|
|
41708
42536
|
try {
|
|
41709
|
-
|
|
42537
|
+
writeFileSync8(path, `${JSON.stringify(emptyStore(), null, 2)}
|
|
41710
42538
|
`, {
|
|
41711
42539
|
encoding: "utf-8",
|
|
41712
42540
|
flag: "wx",
|
|
@@ -42049,13 +42877,13 @@ var init_gemini = __esm({
|
|
|
42049
42877
|
|
|
42050
42878
|
// packages/core/src/llm/stable-device-id.ts
|
|
42051
42879
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
42052
|
-
import { existsSync as
|
|
42053
|
-
import { dirname as dirname10, join as
|
|
42054
|
-
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";
|
|
42055
42883
|
function getStableDeviceId() {
|
|
42056
42884
|
if (_cachedDeviceId !== null) return _cachedDeviceId;
|
|
42057
|
-
const path =
|
|
42058
|
-
if (
|
|
42885
|
+
const path = join28(getCleoHome9(), DEVICE_ID_FILE);
|
|
42886
|
+
if (existsSync25(path)) {
|
|
42059
42887
|
try {
|
|
42060
42888
|
const raw = readFileSync15(path, "utf-8").trim();
|
|
42061
42889
|
if (raw.length > 0) {
|
|
@@ -42068,11 +42896,11 @@ function getStableDeviceId() {
|
|
|
42068
42896
|
const fresh = randomUUID2();
|
|
42069
42897
|
try {
|
|
42070
42898
|
const dir = dirname10(path);
|
|
42071
|
-
if (!
|
|
42072
|
-
|
|
42899
|
+
if (!existsSync25(dir)) {
|
|
42900
|
+
mkdirSync9(dir, { recursive: true });
|
|
42073
42901
|
}
|
|
42074
42902
|
const tmpPath = `${path}.tmp.${process.pid}`;
|
|
42075
|
-
|
|
42903
|
+
writeFileSync9(tmpPath, fresh, { mode: 384 });
|
|
42076
42904
|
renameSync6(tmpPath, path);
|
|
42077
42905
|
} catch {
|
|
42078
42906
|
}
|
|
@@ -42370,14 +43198,14 @@ var init_xai = __esm({
|
|
|
42370
43198
|
});
|
|
42371
43199
|
|
|
42372
43200
|
// packages/core/src/llm/provider-registry/loader.ts
|
|
42373
|
-
import { readdirSync as
|
|
42374
|
-
import { join as
|
|
43201
|
+
import { readdirSync as readdirSync6, statSync as statSync7 } from "node:fs";
|
|
43202
|
+
import { join as join29 } from "node:path";
|
|
42375
43203
|
import { pathToFileURL } from "node:url";
|
|
42376
43204
|
function isPluginFile(filename) {
|
|
42377
43205
|
return PLUGIN_EXTENSIONS.some((ext) => filename.endsWith(ext));
|
|
42378
43206
|
}
|
|
42379
43207
|
function getPluginDir() {
|
|
42380
|
-
return
|
|
43208
|
+
return join29(getCleoHome(), "plugins", "model-providers");
|
|
42381
43209
|
}
|
|
42382
43210
|
async function loadOnePlugin(absPath, api) {
|
|
42383
43211
|
let mod;
|
|
@@ -42419,19 +43247,19 @@ async function loadOnePlugin(absPath, api) {
|
|
|
42419
43247
|
async function scanAndLoadPlugins(pluginDir, api) {
|
|
42420
43248
|
let entries;
|
|
42421
43249
|
try {
|
|
42422
|
-
entries =
|
|
43250
|
+
entries = readdirSync6(pluginDir);
|
|
42423
43251
|
} catch {
|
|
42424
43252
|
return;
|
|
42425
43253
|
}
|
|
42426
43254
|
const pluginFiles = entries.filter((name15) => !name15.startsWith(".") && isPluginFile(name15)).filter((name15) => {
|
|
42427
43255
|
try {
|
|
42428
|
-
return statSync7(
|
|
43256
|
+
return statSync7(join29(pluginDir, name15)).isFile();
|
|
42429
43257
|
} catch {
|
|
42430
43258
|
return false;
|
|
42431
43259
|
}
|
|
42432
43260
|
}).sort();
|
|
42433
43261
|
for (const filename of pluginFiles) {
|
|
42434
|
-
await loadOnePlugin(
|
|
43262
|
+
await loadOnePlugin(join29(pluginDir, filename), api);
|
|
42435
43263
|
}
|
|
42436
43264
|
}
|
|
42437
43265
|
async function runDiscovery(registerProvider2, builtins) {
|
|
@@ -42534,15 +43362,15 @@ var init_provider_registry = __esm({
|
|
|
42534
43362
|
});
|
|
42535
43363
|
|
|
42536
43364
|
// packages/core/src/llm/rate-limit-guard.ts
|
|
42537
|
-
import { existsSync as
|
|
42538
|
-
import { join as
|
|
42539
|
-
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";
|
|
42540
43368
|
function sanitize(value) {
|
|
42541
43369
|
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
42542
43370
|
}
|
|
42543
43371
|
function rateLimitStatePath(provider, label) {
|
|
42544
|
-
const dir =
|
|
42545
|
-
return
|
|
43372
|
+
const dir = join30(getCleoHome10(), "rate-limit-state");
|
|
43373
|
+
return join30(dir, `${sanitize(provider)}-${sanitize(label)}.json`);
|
|
42546
43374
|
}
|
|
42547
43375
|
function parseResetFromHeaders(headers) {
|
|
42548
43376
|
const get = (k) => {
|
|
@@ -42589,9 +43417,9 @@ async function recordRateLimit(provider, label, opts) {
|
|
|
42589
43417
|
source = "default";
|
|
42590
43418
|
}
|
|
42591
43419
|
const filePath = rateLimitStatePath(provider, label);
|
|
42592
|
-
const dir =
|
|
42593
|
-
if (!
|
|
42594
|
-
|
|
43420
|
+
const dir = join30(getCleoHome10(), "rate-limit-state");
|
|
43421
|
+
if (!existsSync26(dir)) {
|
|
43422
|
+
mkdirSync10(dir, { recursive: true });
|
|
42595
43423
|
}
|
|
42596
43424
|
const state = { resetAt, recordedAt: now, source };
|
|
42597
43425
|
await withFileLock(filePath, () => {
|
|
@@ -43105,28 +43933,28 @@ var init_credential_pool = __esm({
|
|
|
43105
43933
|
|
|
43106
43934
|
// packages/core/src/llm/catalog-cache.ts
|
|
43107
43935
|
import {
|
|
43108
|
-
existsSync as
|
|
43109
|
-
mkdirSync as
|
|
43110
|
-
readdirSync as
|
|
43936
|
+
existsSync as existsSync27,
|
|
43937
|
+
mkdirSync as mkdirSync11,
|
|
43938
|
+
readdirSync as readdirSync7,
|
|
43111
43939
|
readFileSync as readFileSync16,
|
|
43112
43940
|
statSync as statSync8,
|
|
43113
43941
|
symlinkSync,
|
|
43114
43942
|
unlinkSync as unlinkSync7,
|
|
43115
|
-
writeFileSync as
|
|
43943
|
+
writeFileSync as writeFileSync10
|
|
43116
43944
|
} from "node:fs";
|
|
43117
43945
|
import { homedir as homedir4 } from "node:os";
|
|
43118
|
-
import { join as
|
|
43946
|
+
import { join as join31 } from "node:path";
|
|
43119
43947
|
function getCatalogDir() {
|
|
43120
43948
|
if (process.env["CLEO_DATA_DIR"]) {
|
|
43121
|
-
return
|
|
43949
|
+
return join31(process.env["CLEO_DATA_DIR"], "llm-catalog");
|
|
43122
43950
|
}
|
|
43123
|
-
const xdg = process.env["XDG_DATA_HOME"] ??
|
|
43124
|
-
return
|
|
43951
|
+
const xdg = process.env["XDG_DATA_HOME"] ?? join31(homedir4(), ".local", "share");
|
|
43952
|
+
return join31(xdg, "cleo", "llm-catalog");
|
|
43125
43953
|
}
|
|
43126
43954
|
function findLatestCacheFile(dir) {
|
|
43127
|
-
if (!
|
|
43128
|
-
const files =
|
|
43129
|
-
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;
|
|
43130
43958
|
}
|
|
43131
43959
|
function readCacheFile(filePath) {
|
|
43132
43960
|
try {
|
|
@@ -43224,7 +44052,7 @@ var init_catalog_model_resolver = __esm({
|
|
|
43224
44052
|
});
|
|
43225
44053
|
|
|
43226
44054
|
// packages/core/src/llm/cross-provider-selector.ts
|
|
43227
|
-
import { totalmem } from "node:os";
|
|
44055
|
+
import { totalmem as totalmem2 } from "node:os";
|
|
43228
44056
|
async function probeOllamaAlive(baseUrl) {
|
|
43229
44057
|
const cached2 = _ollamaProbeCache.get(baseUrl);
|
|
43230
44058
|
if (cached2 && Date.now() - cached2.checkedAt < OLLAMA_PROBE_TTL_MS) {
|
|
@@ -43247,7 +44075,7 @@ async function probeOllamaAlive(baseUrl) {
|
|
|
43247
44075
|
return alive;
|
|
43248
44076
|
}
|
|
43249
44077
|
function ollamaDefaultModelForTier(tier, ramBytesOverride) {
|
|
43250
|
-
const ramBytes = ramBytesOverride ??
|
|
44078
|
+
const ramBytes = ramBytesOverride ?? totalmem2();
|
|
43251
44079
|
const gb = ramBytes / 1024 ** 3;
|
|
43252
44080
|
if (gb >= 8) {
|
|
43253
44081
|
return tier === "fast" || tier === "local" ? "gemma4:e2b" : "gemma4:e4b";
|
|
@@ -43371,7 +44199,7 @@ async function selectBestProvisioned(role, opts) {
|
|
|
43371
44199
|
let model;
|
|
43372
44200
|
if (winner.id === "ollama") {
|
|
43373
44201
|
const ollamaProfile2 = await getProviderProfile2("ollama");
|
|
43374
|
-
const ramBytes =
|
|
44202
|
+
const ramBytes = totalmem2();
|
|
43375
44203
|
const gb = ramBytes / 1024 ** 3;
|
|
43376
44204
|
if (gb >= 8) {
|
|
43377
44205
|
model = (winner.tier === "fast" || taskTier === "fast" ? ollamaProfile2?.defaultAuxModel : ollamaProfile2?.defaultModel) ?? ollamaDefaultModelForTier(winner.tier);
|
|
@@ -43773,7 +44601,7 @@ __export(catalog_resolver_exports, {
|
|
|
43773
44601
|
resolveCatalogEntry: () => resolveCatalogEntry
|
|
43774
44602
|
});
|
|
43775
44603
|
import { readFileSync as readFileSync17 } from "node:fs";
|
|
43776
|
-
import { dirname as dirname11, join as
|
|
44604
|
+
import { dirname as dirname11, join as join32 } from "node:path";
|
|
43777
44605
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
43778
44606
|
async function openCatalogAtPath(dbPath) {
|
|
43779
44607
|
const handle = await openDualScopeDbAtPath("global", dbPath);
|
|
@@ -43783,7 +44611,7 @@ function loadShippedSeed() {
|
|
|
43783
44611
|
if (_seed !== void 0) return _seed;
|
|
43784
44612
|
try {
|
|
43785
44613
|
const thisDir = dirname11(fileURLToPath3(import.meta.url));
|
|
43786
|
-
const jsonPath =
|
|
44614
|
+
const jsonPath = join32(thisDir, "curated-catalog.json");
|
|
43787
44615
|
_seed = JSON.parse(readFileSync17(jsonPath, "utf-8"));
|
|
43788
44616
|
} catch (err) {
|
|
43789
44617
|
logger5.warn(
|
|
@@ -44173,14 +45001,14 @@ var init_message_utils = __esm({
|
|
|
44173
45001
|
|
|
44174
45002
|
// packages/core/src/llm/model-metadata.ts
|
|
44175
45003
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
44176
|
-
import { dirname as dirname12, join as
|
|
45004
|
+
import { dirname as dirname12, join as join33 } from "node:path";
|
|
44177
45005
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
44178
45006
|
function getCuratedTable() {
|
|
44179
45007
|
if (_curated !== void 0) {
|
|
44180
45008
|
return _curated;
|
|
44181
45009
|
}
|
|
44182
45010
|
const thisDir = dirname12(fileURLToPath4(import.meta.url));
|
|
44183
|
-
const jsonPath =
|
|
45011
|
+
const jsonPath = join33(thisDir, "curated-models.json");
|
|
44184
45012
|
const raw = JSON.parse(readFileSync18(jsonPath, "utf-8"));
|
|
44185
45013
|
_curated = raw.models;
|
|
44186
45014
|
return _curated;
|
|
@@ -44259,7 +45087,7 @@ function storedToResolved(stored) {
|
|
|
44259
45087
|
awsProfile: stored.metadata?.["awsProfile"] ?? null
|
|
44260
45088
|
};
|
|
44261
45089
|
}
|
|
44262
|
-
function
|
|
45090
|
+
function sleep2(ms) {
|
|
44263
45091
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
44264
45092
|
}
|
|
44265
45093
|
function backoffMs(policy, attempt) {
|
|
@@ -44397,7 +45225,7 @@ var init_concrete_session = __esm({
|
|
|
44397
45225
|
throw err;
|
|
44398
45226
|
}
|
|
44399
45227
|
lastErr = err;
|
|
44400
|
-
await
|
|
45228
|
+
await sleep2(backoffMs(policy, attempt));
|
|
44401
45229
|
}
|
|
44402
45230
|
}
|
|
44403
45231
|
throw lastErr;
|
|
@@ -48081,7 +48909,7 @@ function normalizeOllamaToolCall(tc) {
|
|
|
48081
48909
|
arguments: JSON.stringify(tc.function.arguments ?? {})
|
|
48082
48910
|
};
|
|
48083
48911
|
}
|
|
48084
|
-
function
|
|
48912
|
+
function sleep3(ms) {
|
|
48085
48913
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
48086
48914
|
}
|
|
48087
48915
|
var OLLAMA_DEFAULT_BASE_URL, MAX_RETRIES, INITIAL_BACKOFF_MS, RETRYABLE_STATUS_CODES, OllamaTransport;
|
|
@@ -48290,7 +49118,7 @@ var init_ollama2 = __esm({
|
|
|
48290
49118
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
48291
49119
|
if (attempt > 0) {
|
|
48292
49120
|
const delay = INITIAL_BACKOFF_MS * 2 ** (attempt - 1);
|
|
48293
|
-
await
|
|
49121
|
+
await sleep3(delay);
|
|
48294
49122
|
}
|
|
48295
49123
|
let response;
|
|
48296
49124
|
try {
|
|
@@ -76222,7 +77050,7 @@ var init_model_runner = __esm({
|
|
|
76222
77050
|
});
|
|
76223
77051
|
|
|
76224
77052
|
// packages/core/src/selfimprove/fix-gen.ts
|
|
76225
|
-
import { writeFileSync as
|
|
77053
|
+
import { writeFileSync as writeFileSync11 } from "node:fs";
|
|
76226
77054
|
import { resolve as resolvePath } from "node:path";
|
|
76227
77055
|
import { cwd as processCwd } from "node:process";
|
|
76228
77056
|
|
|
@@ -76570,7 +77398,7 @@ async function generateFixPatch(opts) {
|
|
|
76570
77398
|
}
|
|
76571
77399
|
const diff = output.diff.endsWith("\n") ? output.diff : `${output.diff}
|
|
76572
77400
|
`;
|
|
76573
|
-
|
|
77401
|
+
writeFileSync11(patchPath, diff, "utf8");
|
|
76574
77402
|
const bytes = Buffer.byteLength(diff, "utf8");
|
|
76575
77403
|
logger8.info(
|
|
76576
77404
|
{ dhqId: request.dhqId, scenario: request.scenario, patchPath, bytes, model: output.model },
|