@cortexkit/opencode-magic-context 0.18.0 → 0.19.0
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/README.md +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts +17 -0
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts +11 -0
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/queue.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-identity.d.ts +11 -0
- package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +56 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +1 -1
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/cache-busting-signals.d.ts +10 -0
- package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +50 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +16 -7
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts +7 -2
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-state-file.d.ts +25 -11
- package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +11 -4
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +2 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/live-session-state.d.ts +3 -1
- package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +10 -4
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +15 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +2 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +1177 -547
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/sidebar-snapshot-cache.d.ts.map +1 -1
- package/dist/shared/conflict-detector.d.ts +49 -0
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/conflict-fixer.d.ts +1 -1
- package/dist/shared/conflict-fixer.d.ts.map +1 -1
- package/dist/shared/data-path.d.ts +84 -0
- package/dist/shared/data-path.d.ts.map +1 -1
- package/dist/shared/logger.d.ts +6 -0
- package/dist/shared/logger.d.ts.map +1 -1
- package/dist/shared/rpc-client.d.ts +2 -1
- package/dist/shared/rpc-client.d.ts.map +1 -1
- package/dist/shared/rpc-notifications.d.ts +3 -2
- package/dist/shared/rpc-notifications.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts +3 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +1 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts +13 -2
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/stable-json.d.ts +21 -0
- package/dist/shared/stable-json.d.ts.map +1 -0
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/conflict-detector.ts +4 -4
- package/src/shared/conflict-fixer.test.ts +124 -0
- package/src/shared/conflict-fixer.ts +34 -28
- package/src/shared/data-path.test.ts +38 -0
- package/src/shared/data-path.ts +99 -0
- package/src/shared/logger.ts +29 -3
- package/src/shared/rpc-client.test.ts +161 -0
- package/src/shared/rpc-client.ts +82 -22
- package/src/shared/rpc-notifications.test.ts +20 -0
- package/src/shared/rpc-notifications.ts +9 -6
- package/src/shared/rpc-server.ts +42 -4
- package/src/shared/rpc-types.ts +1 -0
- package/src/shared/rpc-utils.ts +59 -3
- package/src/shared/stable-json.test.ts +87 -0
- package/src/shared/stable-json.ts +37 -0
- package/src/tui/data/context-db.ts +20 -1
package/dist/index.js
CHANGED
|
@@ -11403,7 +11403,7 @@ function finalize(ctx, schema) {
|
|
|
11403
11403
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
11404
11404
|
} else if (ctx.target === "draft-04") {
|
|
11405
11405
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
11406
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
11406
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
11407
11407
|
if (ctx.external?.uri) {
|
|
11408
11408
|
const id = ctx.external.registry.get(schema)?.id;
|
|
11409
11409
|
if (!id)
|
|
@@ -11664,7 +11664,7 @@ var formatMap, stringProcessor = (schema, ctx, _json, _params) => {
|
|
|
11664
11664
|
if (val === undefined) {
|
|
11665
11665
|
if (ctx.unrepresentable === "throw") {
|
|
11666
11666
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
11667
|
-
}
|
|
11667
|
+
}
|
|
11668
11668
|
} else if (typeof val === "bigint") {
|
|
11669
11669
|
if (ctx.unrepresentable === "throw") {
|
|
11670
11670
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -15017,10 +15017,56 @@ var init_magic_context = __esm(() => {
|
|
|
15017
15017
|
});
|
|
15018
15018
|
});
|
|
15019
15019
|
|
|
15020
|
-
// src/shared/
|
|
15021
|
-
|
|
15020
|
+
// src/shared/harness.ts
|
|
15021
|
+
function getHarness() {
|
|
15022
|
+
return currentHarness;
|
|
15023
|
+
}
|
|
15024
|
+
var currentHarness = "opencode";
|
|
15025
|
+
|
|
15026
|
+
// src/shared/data-path.ts
|
|
15022
15027
|
import * as os from "node:os";
|
|
15023
15028
|
import * as path from "node:path";
|
|
15029
|
+
function getDataDir() {
|
|
15030
|
+
return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
|
|
15031
|
+
}
|
|
15032
|
+
function getMagicContextTempDir(harness = getHarness()) {
|
|
15033
|
+
return path.join(os.tmpdir(), harness, "magic-context");
|
|
15034
|
+
}
|
|
15035
|
+
function getMagicContextLogPath(harness = getHarness()) {
|
|
15036
|
+
return path.join(getMagicContextTempDir(harness), "magic-context.log");
|
|
15037
|
+
}
|
|
15038
|
+
function getProjectMagicContextDir(directory) {
|
|
15039
|
+
return path.join(directory, ".opencode", "magic-context");
|
|
15040
|
+
}
|
|
15041
|
+
function getProjectMagicContextHistorianDir(directory) {
|
|
15042
|
+
return path.join(getProjectMagicContextDir(directory), "historian");
|
|
15043
|
+
}
|
|
15044
|
+
function getOpenCodeStorageDir() {
|
|
15045
|
+
return path.join(getDataDir(), "opencode", "storage");
|
|
15046
|
+
}
|
|
15047
|
+
function getMagicContextStorageDir() {
|
|
15048
|
+
return path.join(getDataDir(), "cortexkit", "magic-context");
|
|
15049
|
+
}
|
|
15050
|
+
function getLegacyOpenCodeMagicContextStorageDir() {
|
|
15051
|
+
return path.join(getOpenCodeStorageDir(), "plugin", "magic-context");
|
|
15052
|
+
}
|
|
15053
|
+
function getCacheDir() {
|
|
15054
|
+
return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
|
|
15055
|
+
}
|
|
15056
|
+
var init_data_path = () => {};
|
|
15057
|
+
|
|
15058
|
+
// src/shared/logger.ts
|
|
15059
|
+
import * as fs from "node:fs";
|
|
15060
|
+
import * as path2 from "node:path";
|
|
15061
|
+
function ensureDir(filePath) {
|
|
15062
|
+
const dir = path2.dirname(filePath);
|
|
15063
|
+
if (dir === lastEnsuredDir)
|
|
15064
|
+
return;
|
|
15065
|
+
try {
|
|
15066
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
15067
|
+
lastEnsuredDir = dir;
|
|
15068
|
+
} catch {}
|
|
15069
|
+
}
|
|
15024
15070
|
function flush() {
|
|
15025
15071
|
if (flushTimer) {
|
|
15026
15072
|
clearTimeout(flushTimer);
|
|
@@ -15031,6 +15077,8 @@ function flush() {
|
|
|
15031
15077
|
const data = buffer.join("");
|
|
15032
15078
|
buffer = [];
|
|
15033
15079
|
try {
|
|
15080
|
+
const logFile = getMagicContextLogPath();
|
|
15081
|
+
ensureDir(logFile);
|
|
15034
15082
|
fs.appendFileSync(logFile, data);
|
|
15035
15083
|
} catch {}
|
|
15036
15084
|
}
|
|
@@ -15061,9 +15109,9 @@ ${data.stack}` : ""}` : ` ${JSON.stringify(data)}`;
|
|
|
15061
15109
|
function sessionLog(sessionId, message, data) {
|
|
15062
15110
|
log(`[magic-context][${sessionId}] ${message}`, data);
|
|
15063
15111
|
}
|
|
15064
|
-
var
|
|
15112
|
+
var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, lastEnsuredDir = null;
|
|
15065
15113
|
var init_logger = __esm(() => {
|
|
15066
|
-
|
|
15114
|
+
init_data_path();
|
|
15067
15115
|
buffer = [];
|
|
15068
15116
|
if (!isTestEnv) {
|
|
15069
15117
|
process.on("exit", flush);
|
|
@@ -148138,21 +148186,36 @@ var init_read_session_formatting = __esm(() => {
|
|
|
148138
148186
|
tokenizer = new src_default(exports_claude);
|
|
148139
148187
|
});
|
|
148140
148188
|
|
|
148189
|
+
// src/shared/stable-json.ts
|
|
148190
|
+
function stableStringify(value, seen = new WeakSet) {
|
|
148191
|
+
if (value === undefined)
|
|
148192
|
+
return "undefined";
|
|
148193
|
+
if (value === null || typeof value !== "object")
|
|
148194
|
+
return JSON.stringify(value) ?? String(value);
|
|
148195
|
+
if (seen.has(value))
|
|
148196
|
+
return '"[Circular]"';
|
|
148197
|
+
seen.add(value);
|
|
148198
|
+
if (Array.isArray(value)) {
|
|
148199
|
+
return `[${value.map((item) => stableStringify(item, seen)).join(",")}]`;
|
|
148200
|
+
}
|
|
148201
|
+
const entries = Object.entries(value).sort(([a], [b]) => {
|
|
148202
|
+
if (a < b)
|
|
148203
|
+
return -1;
|
|
148204
|
+
if (a > b)
|
|
148205
|
+
return 1;
|
|
148206
|
+
return 0;
|
|
148207
|
+
});
|
|
148208
|
+
return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableStringify(child, seen)}`).join(",")}}`;
|
|
148209
|
+
}
|
|
148210
|
+
|
|
148141
148211
|
// src/features/magic-context/tool-definition-tokens.ts
|
|
148212
|
+
import { createHash } from "node:crypto";
|
|
148142
148213
|
function keyFor(providerID, modelID, agentName) {
|
|
148143
148214
|
const agent = agentName && agentName.length > 0 ? agentName : "default";
|
|
148144
148215
|
return `${providerID}/${modelID}/${agent}`;
|
|
148145
148216
|
}
|
|
148146
148217
|
function fingerprintFor(description, parameters) {
|
|
148147
|
-
|
|
148148
|
-
if (parameters === undefined)
|
|
148149
|
-
return `${descLen}:none`;
|
|
148150
|
-
if (parameters === null)
|
|
148151
|
-
return `${descLen}:null`;
|
|
148152
|
-
if (typeof parameters !== "object")
|
|
148153
|
-
return `${descLen}:${typeof parameters}`;
|
|
148154
|
-
const keys = Object.keys(parameters);
|
|
148155
|
-
return `${descLen}:obj:${keys.length}:${keys.sort().join(",")}`;
|
|
148218
|
+
return createHash("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
|
|
148156
148219
|
}
|
|
148157
148220
|
function setDatabase(db) {
|
|
148158
148221
|
persistenceDb = db;
|
|
@@ -155990,12 +156053,6 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
155990
156053
|
};
|
|
155991
156054
|
});
|
|
155992
156055
|
|
|
155993
|
-
// src/shared/harness.ts
|
|
155994
|
-
function getHarness() {
|
|
155995
|
-
return currentHarness;
|
|
155996
|
-
}
|
|
155997
|
-
var currentHarness = "opencode";
|
|
155998
|
-
|
|
155999
156056
|
// src/features/magic-context/compartment-storage.ts
|
|
156000
156057
|
function getInsertCompartmentStatement(db) {
|
|
156001
156058
|
let stmt = insertCompartmentStatements.get(db);
|
|
@@ -156069,6 +156126,10 @@ function getLastCompartmentEndMessage(db, sessionId) {
|
|
|
156069
156126
|
const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
|
|
156070
156127
|
return row?.max_end ?? -1;
|
|
156071
156128
|
}
|
|
156129
|
+
function getCompartmentsByEndMessageId(db, sessionId, endMessageId) {
|
|
156130
|
+
const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? AND end_message_id = ? ORDER BY sequence ASC").all(sessionId, endMessageId).filter(isCompartmentRow);
|
|
156131
|
+
return rows.map(toCompartment);
|
|
156132
|
+
}
|
|
156072
156133
|
function appendCompartments(db, sessionId, compartments) {
|
|
156073
156134
|
if (compartments.length === 0)
|
|
156074
156135
|
return;
|
|
@@ -156572,7 +156633,7 @@ var init_compartment_prompt = __esm(() => {
|
|
|
156572
156633
|
});
|
|
156573
156634
|
|
|
156574
156635
|
// src/shared/opencode-config-dir.ts
|
|
156575
|
-
import { homedir as
|
|
156636
|
+
import { homedir as homedir6 } from "node:os";
|
|
156576
156637
|
import { join as join7, resolve as resolve3 } from "node:path";
|
|
156577
156638
|
function getCliConfigDir() {
|
|
156578
156639
|
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
@@ -156580,9 +156641,9 @@ function getCliConfigDir() {
|
|
|
156580
156641
|
return resolve3(envConfigDir);
|
|
156581
156642
|
}
|
|
156582
156643
|
if (process.platform === "win32") {
|
|
156583
|
-
return join7(
|
|
156644
|
+
return join7(homedir6(), ".config", "opencode");
|
|
156584
156645
|
}
|
|
156585
|
-
return join7(process.env.XDG_CONFIG_HOME || join7(
|
|
156646
|
+
return join7(process.env.XDG_CONFIG_HOME || join7(homedir6(), ".config"), "opencode");
|
|
156586
156647
|
}
|
|
156587
156648
|
function getOpenCodeConfigDir(_options) {
|
|
156588
156649
|
return getCliConfigDir();
|
|
@@ -156813,11 +156874,11 @@ __export(exports_conflict_warning_hook, {
|
|
|
156813
156874
|
cleanupConflictWarnings: () => cleanupConflictWarnings
|
|
156814
156875
|
});
|
|
156815
156876
|
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
156816
|
-
import { homedir as
|
|
156877
|
+
import { homedir as homedir7, platform as platform2 } from "node:os";
|
|
156817
156878
|
import { join as join9 } from "node:path";
|
|
156818
156879
|
function getDesktopStatePath() {
|
|
156819
156880
|
const os2 = platform2();
|
|
156820
|
-
const home =
|
|
156881
|
+
const home = homedir7();
|
|
156821
156882
|
if (os2 === "darwin") {
|
|
156822
156883
|
return join9(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
|
|
156823
156884
|
}
|
|
@@ -157096,26 +157157,6 @@ var init_conflict_warning_hook = __esm(() => {
|
|
|
157096
157157
|
cachedDesktopStateByDir = new Map;
|
|
157097
157158
|
});
|
|
157098
157159
|
|
|
157099
|
-
// src/shared/data-path.ts
|
|
157100
|
-
import * as os2 from "node:os";
|
|
157101
|
-
import * as path2 from "node:path";
|
|
157102
|
-
function getDataDir() {
|
|
157103
|
-
return process.env.XDG_DATA_HOME ?? path2.join(os2.homedir(), ".local", "share");
|
|
157104
|
-
}
|
|
157105
|
-
function getOpenCodeStorageDir() {
|
|
157106
|
-
return path2.join(getDataDir(), "opencode", "storage");
|
|
157107
|
-
}
|
|
157108
|
-
function getMagicContextStorageDir() {
|
|
157109
|
-
return path2.join(getDataDir(), "cortexkit", "magic-context");
|
|
157110
|
-
}
|
|
157111
|
-
function getLegacyOpenCodeMagicContextStorageDir() {
|
|
157112
|
-
return path2.join(getOpenCodeStorageDir(), "plugin", "magic-context");
|
|
157113
|
-
}
|
|
157114
|
-
function getCacheDir() {
|
|
157115
|
-
return process.env.XDG_CACHE_HOME ?? path2.join(os2.homedir(), ".cache");
|
|
157116
|
-
}
|
|
157117
|
-
var init_data_path = () => {};
|
|
157118
|
-
|
|
157119
157160
|
// src/shared/error-message.ts
|
|
157120
157161
|
function getErrorMessage(error51) {
|
|
157121
157162
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -157373,7 +157414,7 @@ var exports_native_binding = {};
|
|
|
157373
157414
|
__export(exports_native_binding, {
|
|
157374
157415
|
resolveBetterSqliteNativeBinding: () => resolveBetterSqliteNativeBinding
|
|
157375
157416
|
});
|
|
157376
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
157417
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
157377
157418
|
import { createRequire } from "node:module";
|
|
157378
157419
|
import * as path3 from "node:path";
|
|
157379
157420
|
function logInfo(message) {
|
|
@@ -157473,7 +157514,7 @@ async function resolveBetterSqliteNativeBinding() {
|
|
|
157473
157514
|
}
|
|
157474
157515
|
logWarn(`cached binary at ${cachedPath} has wrong ABI (${cachedProbe.actual ?? "unknown"} != ${expected}); refetching`);
|
|
157475
157516
|
}
|
|
157476
|
-
|
|
157517
|
+
mkdirSync3(path3.dirname(cachedPath), { recursive: true });
|
|
157477
157518
|
const nodeFileBytes = await downloadElectronPrebuild(pkgVersion, expected);
|
|
157478
157519
|
writeFileSync4(cachedPath, nodeFileBytes);
|
|
157479
157520
|
logInfo(`cached Electron prebuild at ${cachedPath} (${(nodeFileBytes.length / 1024).toFixed(1)} KB)`);
|
|
@@ -157651,13 +157692,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
157651
157692
|
});
|
|
157652
157693
|
|
|
157653
157694
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
157654
|
-
import { createHash } from "node:crypto";
|
|
157695
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
157655
157696
|
function normalizeMemoryContent(content) {
|
|
157656
157697
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
157657
157698
|
}
|
|
157658
157699
|
function computeNormalizedHash(content) {
|
|
157659
157700
|
const normalized = normalizeMemoryContent(content);
|
|
157660
|
-
return
|
|
157701
|
+
return createHash2("md5").update(normalized).digest("hex");
|
|
157661
157702
|
}
|
|
157662
157703
|
var init_normalize_hash = () => {};
|
|
157663
157704
|
|
|
@@ -158251,9 +158292,9 @@ __export(exports_read_session_db, {
|
|
|
158251
158292
|
findLastAssistantModelFromOpenCodeDb: () => findLastAssistantModelFromOpenCodeDb,
|
|
158252
158293
|
closeReadOnlySessionDb: () => closeReadOnlySessionDb
|
|
158253
158294
|
});
|
|
158254
|
-
import { join as
|
|
158295
|
+
import { join as join11 } from "node:path";
|
|
158255
158296
|
function getOpenCodeDbPath() {
|
|
158256
|
-
return
|
|
158297
|
+
return join11(getDataDir(), "opencode", "opencode.db");
|
|
158257
158298
|
}
|
|
158258
158299
|
function closeCachedReadOnlyDb() {
|
|
158259
158300
|
if (!cachedReadOnlyDb) {
|
|
@@ -158360,10 +158401,36 @@ function cosineSimilarity(a, b) {
|
|
|
158360
158401
|
return denominator === 0 ? 0 : dotProduct / denominator;
|
|
158361
158402
|
}
|
|
158362
158403
|
|
|
158404
|
+
// src/features/magic-context/memory/embedding-identity.ts
|
|
158405
|
+
function normalizeEndpoint(endpoint) {
|
|
158406
|
+
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
158407
|
+
}
|
|
158408
|
+
function getEmbeddingProviderIdentity(config2) {
|
|
158409
|
+
if (config2.provider === "off") {
|
|
158410
|
+
return "embedding-provider:off";
|
|
158411
|
+
}
|
|
158412
|
+
const identityInput = config2.provider === "openai-compatible" ? {
|
|
158413
|
+
provider: "openai-compatible",
|
|
158414
|
+
model: config2.model.trim(),
|
|
158415
|
+
endpoint: normalizeEndpoint(config2.endpoint),
|
|
158416
|
+
apiKeyPresent: Boolean(config2.api_key?.trim())
|
|
158417
|
+
} : {
|
|
158418
|
+
provider: "local",
|
|
158419
|
+
model: config2.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
158420
|
+
endpoint: "",
|
|
158421
|
+
apiKeyPresent: false
|
|
158422
|
+
};
|
|
158423
|
+
return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
|
|
158424
|
+
}
|
|
158425
|
+
var init_embedding_identity = __esm(() => {
|
|
158426
|
+
init_magic_context();
|
|
158427
|
+
init_normalize_hash();
|
|
158428
|
+
});
|
|
158429
|
+
|
|
158363
158430
|
// src/features/magic-context/memory/embedding-local.ts
|
|
158364
|
-
import { mkdirSync as
|
|
158431
|
+
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
158365
158432
|
import { open, stat, unlink, writeFile } from "node:fs/promises";
|
|
158366
|
-
import { join as
|
|
158433
|
+
import { join as join13 } from "node:path";
|
|
158367
158434
|
async function acquireModelLoadLock(lockPath) {
|
|
158368
158435
|
const waitStart = Date.now();
|
|
158369
158436
|
while (true) {
|
|
@@ -158478,7 +158545,7 @@ class LocalEmbeddingProvider {
|
|
|
158478
158545
|
initPromise = null;
|
|
158479
158546
|
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
158480
158547
|
this.model = model;
|
|
158481
|
-
this.modelId =
|
|
158548
|
+
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
158482
158549
|
}
|
|
158483
158550
|
async initialize() {
|
|
158484
158551
|
if (this.pipeline) {
|
|
@@ -158497,15 +158564,15 @@ class LocalEmbeddingProvider {
|
|
|
158497
158564
|
if (LogLevel && "ERROR" in LogLevel) {
|
|
158498
158565
|
env.logLevel = LogLevel.ERROR;
|
|
158499
158566
|
}
|
|
158500
|
-
const modelCacheDir =
|
|
158567
|
+
const modelCacheDir = join13(getMagicContextStorageDir(), "models");
|
|
158501
158568
|
try {
|
|
158502
|
-
|
|
158569
|
+
mkdirSync4(modelCacheDir, { recursive: true });
|
|
158503
158570
|
env.cacheDir = modelCacheDir;
|
|
158504
158571
|
} catch {
|
|
158505
158572
|
log("[magic-context] could not create model cache dir, using library default");
|
|
158506
158573
|
}
|
|
158507
158574
|
const createPipeline = transformersModule.pipeline;
|
|
158508
|
-
const lockPath =
|
|
158575
|
+
const lockPath = join13(modelCacheDir, ".load.lock");
|
|
158509
158576
|
const releaseLock = await acquireModelLoadLock(lockPath);
|
|
158510
158577
|
const stopHeartbeat = startLockHeartbeat(lockPath);
|
|
158511
158578
|
try {
|
|
@@ -158620,12 +158687,13 @@ var init_embedding_local = __esm(() => {
|
|
|
158620
158687
|
init_magic_context();
|
|
158621
158688
|
init_data_path();
|
|
158622
158689
|
init_logger();
|
|
158690
|
+
init_embedding_identity();
|
|
158623
158691
|
STALE_LOCK_MS = 3 * 60000;
|
|
158624
158692
|
MAX_LOCK_WAIT_MS = 5 * 60000;
|
|
158625
158693
|
});
|
|
158626
158694
|
|
|
158627
158695
|
// src/features/magic-context/memory/embedding-openai.ts
|
|
158628
|
-
function
|
|
158696
|
+
function normalizeEndpoint2(endpoint) {
|
|
158629
158697
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
158630
158698
|
}
|
|
158631
158699
|
|
|
@@ -158640,10 +158708,15 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158640
158708
|
openLogged = false;
|
|
158641
158709
|
halfOpenProbeInFlight = false;
|
|
158642
158710
|
constructor(options) {
|
|
158643
|
-
this.endpoint =
|
|
158711
|
+
this.endpoint = normalizeEndpoint2(options.endpoint);
|
|
158644
158712
|
this.model = options.model?.trim() ?? "";
|
|
158645
158713
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
158646
|
-
this.modelId =
|
|
158714
|
+
this.modelId = getEmbeddingProviderIdentity({
|
|
158715
|
+
provider: "openai-compatible",
|
|
158716
|
+
endpoint: this.endpoint,
|
|
158717
|
+
model: this.model,
|
|
158718
|
+
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
158719
|
+
});
|
|
158647
158720
|
}
|
|
158648
158721
|
async initialize() {
|
|
158649
158722
|
if (this.initialized)
|
|
@@ -158825,6 +158898,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158825
158898
|
var FAILURE_THRESHOLD = 3, FAILURE_WINDOW_MS = 60000, OPEN_DURATION_MS, FETCH_TIMEOUT_MS = 30000;
|
|
158826
158899
|
var init_embedding_openai = __esm(() => {
|
|
158827
158900
|
init_logger();
|
|
158901
|
+
init_embedding_identity();
|
|
158828
158902
|
OPEN_DURATION_MS = 5 * 60000;
|
|
158829
158903
|
});
|
|
158830
158904
|
|
|
@@ -158862,17 +158936,8 @@ function resolveEmbeddingConfig(config2) {
|
|
|
158862
158936
|
}
|
|
158863
158937
|
return { provider: "off" };
|
|
158864
158938
|
}
|
|
158865
|
-
function
|
|
158866
|
-
|
|
158867
|
-
return "off";
|
|
158868
|
-
}
|
|
158869
|
-
if (config2.provider === "openai-compatible") {
|
|
158870
|
-
const endpoint = config2.endpoint.trim();
|
|
158871
|
-
const model = config2.model.trim();
|
|
158872
|
-
const keyHash = config2.api_key ? computeNormalizedHash(config2.api_key) : "nokey";
|
|
158873
|
-
return `openai-compat:${endpoint}:${model}:${keyHash}`;
|
|
158874
|
-
}
|
|
158875
|
-
return config2.model.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL;
|
|
158939
|
+
function resolveProviderIdentity(config2) {
|
|
158940
|
+
return getEmbeddingProviderIdentity(config2);
|
|
158876
158941
|
}
|
|
158877
158942
|
function createProvider(config2) {
|
|
158878
158943
|
if (config2.provider === "off") {
|
|
@@ -158896,10 +158961,10 @@ function getOrCreateProvider() {
|
|
|
158896
158961
|
}
|
|
158897
158962
|
function initializeEmbedding(config2) {
|
|
158898
158963
|
const nextConfig = resolveEmbeddingConfig(config2);
|
|
158899
|
-
const
|
|
158964
|
+
const nextProviderIdentity = resolveProviderIdentity(nextConfig);
|
|
158900
158965
|
const previousProvider = provider;
|
|
158901
|
-
const
|
|
158902
|
-
if (
|
|
158966
|
+
const previousProviderIdentity = previousProvider?.modelId ?? resolveProviderIdentity(embeddingConfig);
|
|
158967
|
+
if (previousProviderIdentity === nextProviderIdentity) {
|
|
158903
158968
|
embeddingConfig = nextConfig;
|
|
158904
158969
|
return;
|
|
158905
158970
|
}
|
|
@@ -159026,9 +159091,9 @@ var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMe
|
|
|
159026
159091
|
var init_embedding = __esm(() => {
|
|
159027
159092
|
init_magic_context();
|
|
159028
159093
|
init_logger();
|
|
159094
|
+
init_embedding_identity();
|
|
159029
159095
|
init_embedding_local();
|
|
159030
159096
|
init_embedding_openai();
|
|
159031
|
-
init_normalize_hash();
|
|
159032
159097
|
init_storage_memory_embeddings();
|
|
159033
159098
|
DEFAULT_EMBEDDING_CONFIG = {
|
|
159034
159099
|
provider: "local",
|
|
@@ -159075,7 +159140,7 @@ var init_storage_memory_fts = __esm(() => {
|
|
|
159075
159140
|
|
|
159076
159141
|
// src/features/magic-context/memory/project-identity.ts
|
|
159077
159142
|
import { execSync } from "node:child_process";
|
|
159078
|
-
import { createHash as
|
|
159143
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
159079
159144
|
import path4 from "node:path";
|
|
159080
159145
|
function getRootCommitHash(directory) {
|
|
159081
159146
|
try {
|
|
@@ -159094,7 +159159,7 @@ function getRootCommitHash(directory) {
|
|
|
159094
159159
|
}
|
|
159095
159160
|
function directoryFallback(directory) {
|
|
159096
159161
|
const canonical = path4.resolve(directory);
|
|
159097
|
-
const hash2 =
|
|
159162
|
+
const hash2 = createHash3("md5").update(canonical).digest("hex").slice(0, 12);
|
|
159098
159163
|
return `dir:${hash2}`;
|
|
159099
159164
|
}
|
|
159100
159165
|
function resolveProjectIdentity(directory) {
|
|
@@ -160144,6 +160209,9 @@ var init_migrations = __esm(async () => {
|
|
|
160144
160209
|
embedding BLOB NOT NULL,
|
|
160145
160210
|
model_id TEXT NOT NULL,
|
|
160146
160211
|
created_at INTEGER NOT NULL,
|
|
160212
|
+
-- FK-cascade audit (v12): git_commit_embeddings.sha -> git_commits.sha
|
|
160213
|
+
-- uses ON DELETE CASCADE, so SQLite PRAGMA foreign_keys must be ON on
|
|
160214
|
+
-- every connection and v12 cleans historical orphan rows.
|
|
160147
160215
|
FOREIGN KEY(sha) REFERENCES git_commits(sha) ON DELETE CASCADE
|
|
160148
160216
|
);
|
|
160149
160217
|
|
|
@@ -160283,15 +160351,38 @@ var init_migrations = __esm(async () => {
|
|
|
160283
160351
|
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_state_json TEXT DEFAULT ''");
|
|
160284
160352
|
}
|
|
160285
160353
|
}
|
|
160354
|
+
},
|
|
160355
|
+
{
|
|
160356
|
+
version: 12,
|
|
160357
|
+
description: "Clean orphan rows from FK-cascade embedding tables",
|
|
160358
|
+
up: (db) => {
|
|
160359
|
+
const hasTable = (name2) => Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
160360
|
+
const memoryEmbeddings = hasTable("memory_embeddings") ? db.prepare(`DELETE FROM memory_embeddings
|
|
160361
|
+
WHERE memory_id NOT IN (SELECT id FROM memories)`).run().changes : 0;
|
|
160362
|
+
log(`[migrations] v12 cleaned ${memoryEmbeddings} orphan memory_embeddings row(s)`);
|
|
160363
|
+
const gitCommitEmbeddings = hasTable("git_commit_embeddings") ? db.prepare(`DELETE FROM git_commit_embeddings
|
|
160364
|
+
WHERE sha NOT IN (SELECT sha FROM git_commits)`).run().changes : 0;
|
|
160365
|
+
log(`[migrations] v12 cleaned ${gitCommitEmbeddings} orphan git_commit_embeddings row(s)`);
|
|
160366
|
+
}
|
|
160367
|
+
},
|
|
160368
|
+
{
|
|
160369
|
+
version: 13,
|
|
160370
|
+
description: "Add pending_compaction_marker_state column for deferred marker drain",
|
|
160371
|
+
up: (db) => {
|
|
160372
|
+
const cols = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
160373
|
+
if (!cols.some((c) => c.name === "pending_compaction_marker_state")) {
|
|
160374
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN pending_compaction_marker_state TEXT");
|
|
160375
|
+
}
|
|
160376
|
+
}
|
|
160286
160377
|
}
|
|
160287
160378
|
];
|
|
160288
160379
|
});
|
|
160289
160380
|
|
|
160290
160381
|
// src/features/magic-context/tool-owner-backfill.ts
|
|
160291
160382
|
import { existsSync as existsSync10 } from "node:fs";
|
|
160292
|
-
import { join as
|
|
160383
|
+
import { join as join14 } from "node:path";
|
|
160293
160384
|
function resolveOpencodeDbPath() {
|
|
160294
|
-
return
|
|
160385
|
+
return join14(getDataDir(), "opencode", "opencode.db");
|
|
160295
160386
|
}
|
|
160296
160387
|
function ensureBackfillStateTable(db) {
|
|
160297
160388
|
db.exec(`
|
|
@@ -160536,24 +160627,24 @@ var init_tool_owner_backfill = __esm(() => {
|
|
|
160536
160627
|
});
|
|
160537
160628
|
|
|
160538
160629
|
// src/features/magic-context/storage-db.ts
|
|
160539
|
-
import { copyFileSync, cpSync, existsSync as existsSync11, mkdirSync as
|
|
160540
|
-
import { join as
|
|
160630
|
+
import { copyFileSync, cpSync, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "node:fs";
|
|
160631
|
+
import { join as join15 } from "node:path";
|
|
160541
160632
|
function resolveDatabasePath() {
|
|
160542
160633
|
const dbDir = getMagicContextStorageDir();
|
|
160543
|
-
return { dbDir, dbPath:
|
|
160634
|
+
return { dbDir, dbPath: join15(dbDir, "context.db") };
|
|
160544
160635
|
}
|
|
160545
160636
|
function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
160546
160637
|
if (existsSync11(targetDbPath))
|
|
160547
160638
|
return;
|
|
160548
160639
|
const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
|
|
160549
|
-
const legacyDbPath =
|
|
160640
|
+
const legacyDbPath = join15(legacyDir, "context.db");
|
|
160550
160641
|
if (!existsSync11(legacyDbPath))
|
|
160551
160642
|
return;
|
|
160552
160643
|
log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
|
|
160553
|
-
|
|
160644
|
+
mkdirSync5(targetDbDir, { recursive: true });
|
|
160554
160645
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
160555
160646
|
const src = `${legacyDbPath}${suffix}`;
|
|
160556
|
-
const dst =
|
|
160647
|
+
const dst = join15(targetDbDir, `context.db${suffix}`);
|
|
160557
160648
|
if (existsSync11(src)) {
|
|
160558
160649
|
try {
|
|
160559
160650
|
copyFileSync(src, dst);
|
|
@@ -160562,8 +160653,8 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
160562
160653
|
}
|
|
160563
160654
|
}
|
|
160564
160655
|
}
|
|
160565
|
-
const legacyModelsDir =
|
|
160566
|
-
const targetModelsDir =
|
|
160656
|
+
const legacyModelsDir = join15(legacyDir, "models");
|
|
160657
|
+
const targetModelsDir = join15(targetDbDir, "models");
|
|
160567
160658
|
if (existsSync11(legacyModelsDir) && !existsSync11(targetModelsDir)) {
|
|
160568
160659
|
try {
|
|
160569
160660
|
cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
|
|
@@ -160573,9 +160664,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
160573
160664
|
}
|
|
160574
160665
|
}
|
|
160575
160666
|
function initializeDatabase(db) {
|
|
160667
|
+
db.exec("PRAGMA foreign_keys=ON");
|
|
160576
160668
|
db.exec("PRAGMA journal_mode=WAL");
|
|
160577
160669
|
db.exec("PRAGMA busy_timeout=5000");
|
|
160578
|
-
db.exec("PRAGMA foreign_keys=ON");
|
|
160579
160670
|
db.exec(`
|
|
160580
160671
|
CREATE TABLE IF NOT EXISTS tags (
|
|
160581
160672
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -160673,6 +160764,9 @@ function initializeDatabase(db) {
|
|
|
160673
160764
|
);
|
|
160674
160765
|
|
|
160675
160766
|
CREATE TABLE IF NOT EXISTS memory_embeddings (
|
|
160767
|
+
-- FK-cascade audit (v12): memory_embeddings.memory_id -> memories.id
|
|
160768
|
+
-- uses ON DELETE CASCADE, so SQLite PRAGMA foreign_keys must be ON on
|
|
160769
|
+
-- every connection and v12 cleans historical orphan rows.
|
|
160676
160770
|
memory_id INTEGER PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
|
|
160677
160771
|
embedding BLOB NOT NULL,
|
|
160678
160772
|
model_id TEXT
|
|
@@ -160780,7 +160874,13 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160780
160874
|
system_prompt_hash TEXT DEFAULT '',
|
|
160781
160875
|
memory_block_cache TEXT DEFAULT '',
|
|
160782
160876
|
memory_block_count INTEGER DEFAULT 0,
|
|
160783
|
-
memory_block_ids TEXT DEFAULT ''
|
|
160877
|
+
memory_block_ids TEXT DEFAULT '',
|
|
160878
|
+
-- pending_compaction_marker_state: intentionally NULLABLE without a
|
|
160879
|
+
-- default. Absence of a deferred marker is SQL NULL; presence is a
|
|
160880
|
+
-- valid JSON blob written via setPendingCompactionMarkerState.
|
|
160881
|
+
-- Excluded from healNullTextColumns. Readers filter IS NOT NULL AND
|
|
160882
|
+
-- != empty-string defensively. Plan v6 section 3.
|
|
160883
|
+
pending_compaction_marker_state TEXT
|
|
160784
160884
|
);
|
|
160785
160885
|
|
|
160786
160886
|
CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
|
|
@@ -160868,6 +160968,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160868
160968
|
ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
|
|
160869
160969
|
ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
|
|
160870
160970
|
ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
|
|
160971
|
+
ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
|
|
160871
160972
|
ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
160872
160973
|
ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
160873
160974
|
ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
@@ -160957,7 +161058,7 @@ function openDatabase() {
|
|
|
160957
161058
|
}
|
|
160958
161059
|
try {
|
|
160959
161060
|
migrateLegacyStorageIfNeeded(dbPath, dbDir);
|
|
160960
|
-
|
|
161061
|
+
mkdirSync5(dbDir, { recursive: true });
|
|
160961
161062
|
const db = new Database(dbPath);
|
|
160962
161063
|
initializeDatabase(db);
|
|
160963
161064
|
runMigrations(db);
|
|
@@ -161398,6 +161499,39 @@ function removeStrippedPlaceholderId(db, sessionId, messageId) {
|
|
|
161398
161499
|
setStrippedPlaceholderIds(db, sessionId, ids);
|
|
161399
161500
|
return true;
|
|
161400
161501
|
}
|
|
161502
|
+
function isPendingCompactionMarker(value) {
|
|
161503
|
+
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
161504
|
+
}
|
|
161505
|
+
function getPendingCompactionMarkerState(db, sessionId) {
|
|
161506
|
+
const row = db.prepare("SELECT pending_compaction_marker_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161507
|
+
const raw = row?.pending_compaction_marker_state;
|
|
161508
|
+
if (raw === null || raw === undefined || raw === "")
|
|
161509
|
+
return null;
|
|
161510
|
+
try {
|
|
161511
|
+
const parsed = JSON.parse(raw);
|
|
161512
|
+
if (isPendingCompactionMarker(parsed)) {
|
|
161513
|
+
return parsed;
|
|
161514
|
+
}
|
|
161515
|
+
} catch {}
|
|
161516
|
+
return null;
|
|
161517
|
+
}
|
|
161518
|
+
function setPendingCompactionMarkerState(db, sessionId, state) {
|
|
161519
|
+
ensureSessionMetaRow(db, sessionId);
|
|
161520
|
+
const blob = state ? stableStringify(state) : null;
|
|
161521
|
+
db.prepare("UPDATE session_meta SET pending_compaction_marker_state = ? WHERE session_id = ?").run(blob, sessionId);
|
|
161522
|
+
}
|
|
161523
|
+
function clearPendingCompactionMarkerStateIf(db, sessionId, expected) {
|
|
161524
|
+
const expectedBlob = stableStringify(expected);
|
|
161525
|
+
const result = db.prepare(`UPDATE session_meta SET pending_compaction_marker_state = NULL
|
|
161526
|
+
WHERE session_id = ? AND pending_compaction_marker_state = ?`).run(sessionId, expectedBlob);
|
|
161527
|
+
return result.changes > 0;
|
|
161528
|
+
}
|
|
161529
|
+
function getSessionsWithPendingMarker(db) {
|
|
161530
|
+
const rows = db.prepare(`SELECT session_id FROM session_meta
|
|
161531
|
+
WHERE pending_compaction_marker_state IS NOT NULL
|
|
161532
|
+
AND pending_compaction_marker_state != ''`).all();
|
|
161533
|
+
return rows.map((r) => r.session_id);
|
|
161534
|
+
}
|
|
161401
161535
|
var init_storage_meta_persisted = __esm(() => {
|
|
161402
161536
|
init_logger();
|
|
161403
161537
|
init_storage_meta_shared();
|
|
@@ -161925,12 +162059,12 @@ var init_storage = __esm(async () => {
|
|
|
161925
162059
|
});
|
|
161926
162060
|
|
|
161927
162061
|
// src/shared/models-dev-cache.ts
|
|
161928
|
-
import { createHash as
|
|
162062
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
161929
162063
|
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
|
|
161930
162064
|
import { homedir as homedir8, platform as platform3 } from "node:os";
|
|
161931
|
-
import { join as
|
|
162065
|
+
import { join as join16 } from "node:path";
|
|
161932
162066
|
function hashFast(input) {
|
|
161933
|
-
return
|
|
162067
|
+
return createHash4("sha1").update(input).digest("hex");
|
|
161934
162068
|
}
|
|
161935
162069
|
function getModelsJsonPath() {
|
|
161936
162070
|
const explicit = process.env.OPENCODE_MODELS_PATH?.trim();
|
|
@@ -161939,15 +162073,15 @@ function getModelsJsonPath() {
|
|
|
161939
162073
|
const cacheBase = getCacheDir();
|
|
161940
162074
|
const source = process.env.OPENCODE_MODELS_URL?.trim();
|
|
161941
162075
|
const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
|
|
161942
|
-
return
|
|
162076
|
+
return join16(cacheBase, "opencode", filename);
|
|
161943
162077
|
}
|
|
161944
162078
|
function getOpencodeConfigPath() {
|
|
161945
162079
|
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
161946
|
-
const configDir = envDir ? envDir : platform3() === "win32" ?
|
|
161947
|
-
const jsonc =
|
|
162080
|
+
const configDir = envDir ? envDir : platform3() === "win32" ? join16(homedir8(), ".config", "opencode") : join16(process.env.XDG_CONFIG_HOME || join16(homedir8(), ".config"), "opencode");
|
|
162081
|
+
const jsonc = join16(configDir, "opencode.jsonc");
|
|
161948
162082
|
if (existsSync12(jsonc))
|
|
161949
162083
|
return jsonc;
|
|
161950
|
-
const json2 =
|
|
162084
|
+
const json2 = join16(configDir, "opencode.json");
|
|
161951
162085
|
if (existsSync12(json2))
|
|
161952
162086
|
return json2;
|
|
161953
162087
|
return null;
|
|
@@ -162084,25 +162218,359 @@ __export(exports_rpc_notifications, {
|
|
|
162084
162218
|
drainNotifications: () => drainNotifications
|
|
162085
162219
|
});
|
|
162086
162220
|
function pushNotification(type, payload, sessionId) {
|
|
162087
|
-
queue2.push({ type, payload, sessionId });
|
|
162221
|
+
queue2.push({ id: nextNotificationId++, type, payload, sessionId });
|
|
162088
162222
|
if (queue2.length > 100) {
|
|
162089
162223
|
queue2 = queue2.slice(-50);
|
|
162090
162224
|
}
|
|
162091
162225
|
}
|
|
162092
|
-
function drainNotifications() {
|
|
162226
|
+
function drainNotifications(lastReceivedId = 0) {
|
|
162093
162227
|
lastDrainAt = Date.now();
|
|
162094
|
-
|
|
162095
|
-
|
|
162096
|
-
|
|
162228
|
+
if (lastReceivedId > 0) {
|
|
162229
|
+
queue2 = queue2.filter((notification) => notification.id > lastReceivedId);
|
|
162230
|
+
}
|
|
162231
|
+
return [...queue2];
|
|
162097
162232
|
}
|
|
162098
162233
|
function isTuiConnected() {
|
|
162099
162234
|
return lastDrainAt > 0 && Date.now() - lastDrainAt < TUI_CONNECTED_WINDOW_MS;
|
|
162100
162235
|
}
|
|
162101
|
-
var queue2, lastDrainAt = 0, TUI_CONNECTED_WINDOW_MS = 3000;
|
|
162236
|
+
var queue2, nextNotificationId = 1, lastDrainAt = 0, TUI_CONNECTED_WINDOW_MS = 3000;
|
|
162102
162237
|
var init_rpc_notifications = __esm(() => {
|
|
162103
162238
|
queue2 = [];
|
|
162104
162239
|
});
|
|
162105
162240
|
|
|
162241
|
+
// src/features/magic-context/compaction-marker.ts
|
|
162242
|
+
import { join as join17 } from "node:path";
|
|
162243
|
+
function randomBase62(length) {
|
|
162244
|
+
const chars = [];
|
|
162245
|
+
for (let i = 0;i < length; i++) {
|
|
162246
|
+
chars.push(BASE62_CHARS[Math.floor(Math.random() * BASE62_CHARS.length)]);
|
|
162247
|
+
}
|
|
162248
|
+
return chars.join("");
|
|
162249
|
+
}
|
|
162250
|
+
function generateId(prefix, timestampMs, counter = 0n) {
|
|
162251
|
+
const encoded = BigInt(timestampMs) * 0x1000n + counter;
|
|
162252
|
+
const hex3 = encoded.toString(16).padStart(14, "0");
|
|
162253
|
+
return `${prefix}_${hex3}${randomBase62(14)}`;
|
|
162254
|
+
}
|
|
162255
|
+
function generateMessageId(timestampMs, counter = 0n) {
|
|
162256
|
+
return generateId("msg", timestampMs, counter);
|
|
162257
|
+
}
|
|
162258
|
+
function generatePartId(timestampMs, counter = 0n) {
|
|
162259
|
+
return generateId("prt", timestampMs, counter);
|
|
162260
|
+
}
|
|
162261
|
+
function getOpenCodeDbPath3() {
|
|
162262
|
+
return join17(getDataDir(), "opencode", "opencode.db");
|
|
162263
|
+
}
|
|
162264
|
+
function isOpenCodeSchemaCompatible(db, dbPath) {
|
|
162265
|
+
if (cachedSchemaCompatible?.path === dbPath) {
|
|
162266
|
+
return cachedSchemaCompatible.compatible;
|
|
162267
|
+
}
|
|
162268
|
+
try {
|
|
162269
|
+
const messageCols = new Set(db.prepare("PRAGMA table_info(message)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
162270
|
+
const partCols = new Set(db.prepare("PRAGMA table_info(part)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
162271
|
+
const missingMessage = REQUIRED_MESSAGE_COLUMNS.filter((c) => !messageCols.has(c));
|
|
162272
|
+
const missingPart = REQUIRED_PART_COLUMNS.filter((c) => !partCols.has(c));
|
|
162273
|
+
if (missingMessage.length > 0 || missingPart.length > 0) {
|
|
162274
|
+
log(`[magic-context] compaction-marker: OpenCode DB schema missing required columns ` + `(message: [${missingMessage.join(", ")}], part: [${missingPart.join(", ")}]). ` + `Marker injection disabled for this process. ` + `This usually means OpenCode was updated and magic-context is out of date.`);
|
|
162275
|
+
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
162276
|
+
return false;
|
|
162277
|
+
}
|
|
162278
|
+
cachedSchemaCompatible = { path: dbPath, compatible: true };
|
|
162279
|
+
return true;
|
|
162280
|
+
} catch (error51) {
|
|
162281
|
+
log(`[magic-context] compaction-marker: schema probe failed: ${error51 instanceof Error ? error51.message : String(error51)}. ` + `Marker injection disabled until next process restart.`);
|
|
162282
|
+
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
162283
|
+
return false;
|
|
162284
|
+
}
|
|
162285
|
+
}
|
|
162286
|
+
function getWritableOpenCodeDb() {
|
|
162287
|
+
const dbPath = getOpenCodeDbPath3();
|
|
162288
|
+
if (cachedWriteDb?.path === dbPath) {
|
|
162289
|
+
return cachedWriteDb.db;
|
|
162290
|
+
}
|
|
162291
|
+
if (cachedWriteDb) {
|
|
162292
|
+
try {
|
|
162293
|
+
closeQuietly(cachedWriteDb.db);
|
|
162294
|
+
} catch {}
|
|
162295
|
+
}
|
|
162296
|
+
const db = new Database(dbPath);
|
|
162297
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
162298
|
+
db.exec("PRAGMA busy_timeout=5000");
|
|
162299
|
+
cachedWriteDb = { path: dbPath, db };
|
|
162300
|
+
return db;
|
|
162301
|
+
}
|
|
162302
|
+
function findBoundaryUserMessage(sessionId, endOrdinal) {
|
|
162303
|
+
const db = getWritableOpenCodeDb();
|
|
162304
|
+
const rows = db.prepare(`SELECT id, time_created, data
|
|
162305
|
+
FROM message
|
|
162306
|
+
WHERE session_id = ?
|
|
162307
|
+
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
162308
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
162309
|
+
ORDER BY time_created ASC, id ASC
|
|
162310
|
+
LIMIT ?`).all(sessionId, endOrdinal);
|
|
162311
|
+
let bestMatch = null;
|
|
162312
|
+
for (const row of rows) {
|
|
162313
|
+
try {
|
|
162314
|
+
const info = JSON.parse(row.data);
|
|
162315
|
+
if (info.role === "user") {
|
|
162316
|
+
bestMatch = { id: row.id, timeCreated: row.time_created };
|
|
162317
|
+
}
|
|
162318
|
+
} catch {}
|
|
162319
|
+
}
|
|
162320
|
+
return bestMatch;
|
|
162321
|
+
}
|
|
162322
|
+
function getOpenCodeMessageById(sessionId, messageId) {
|
|
162323
|
+
const db = getWritableOpenCodeDb();
|
|
162324
|
+
const row = db.prepare(`SELECT id FROM message WHERE session_id = ? AND id = ? LIMIT 1`).get(sessionId, messageId);
|
|
162325
|
+
return row ?? null;
|
|
162326
|
+
}
|
|
162327
|
+
function injectCompactionMarker(args) {
|
|
162328
|
+
const db = getWritableOpenCodeDb();
|
|
162329
|
+
if (!isOpenCodeSchemaCompatible(db, getOpenCodeDbPath3())) {
|
|
162330
|
+
return null;
|
|
162331
|
+
}
|
|
162332
|
+
const boundary = findBoundaryUserMessage(args.sessionId, args.endOrdinal);
|
|
162333
|
+
if (!boundary) {
|
|
162334
|
+
log(`[magic-context] compaction-marker: no user message found at or before ordinal ${args.endOrdinal}`);
|
|
162335
|
+
return null;
|
|
162336
|
+
}
|
|
162337
|
+
const boundaryTime = boundary.timeCreated;
|
|
162338
|
+
const summaryMsgId = generateMessageId(boundaryTime + 1, 1n);
|
|
162339
|
+
const compactionPartId = generatePartId(boundaryTime, 1n);
|
|
162340
|
+
const summaryPartId = generatePartId(boundaryTime + 1, 2n);
|
|
162341
|
+
const summaryMsgData = JSON.stringify({
|
|
162342
|
+
role: "assistant",
|
|
162343
|
+
parentID: boundary.id,
|
|
162344
|
+
summary: true,
|
|
162345
|
+
finish: "stop",
|
|
162346
|
+
mode: "compaction",
|
|
162347
|
+
agent: "compaction",
|
|
162348
|
+
path: { cwd: args.directory, root: args.directory },
|
|
162349
|
+
cost: 0,
|
|
162350
|
+
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
162351
|
+
modelID: "magic-context",
|
|
162352
|
+
providerID: "magic-context",
|
|
162353
|
+
time: { created: boundaryTime + 1 }
|
|
162354
|
+
});
|
|
162355
|
+
try {
|
|
162356
|
+
db.transaction(() => {
|
|
162357
|
+
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(compactionPartId, boundary.id, args.sessionId, boundaryTime, boundaryTime, '{"type":"compaction","auto":true}');
|
|
162358
|
+
db.prepare("INSERT INTO message (id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?)").run(summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, summaryMsgData);
|
|
162359
|
+
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(summaryPartId, summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, JSON.stringify({ type: "text", text: args.summaryText }));
|
|
162360
|
+
})();
|
|
162361
|
+
log(`[magic-context] compaction-marker: injected boundary at user msg ${boundary.id} (ordinal ~${args.endOrdinal}), summary msg ${summaryMsgId}`);
|
|
162362
|
+
return {
|
|
162363
|
+
boundaryMessageId: boundary.id,
|
|
162364
|
+
summaryMessageId: summaryMsgId,
|
|
162365
|
+
compactionPartId,
|
|
162366
|
+
summaryPartId
|
|
162367
|
+
};
|
|
162368
|
+
} catch (error51) {
|
|
162369
|
+
log(`[magic-context] compaction-marker: injection failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
162370
|
+
return null;
|
|
162371
|
+
}
|
|
162372
|
+
}
|
|
162373
|
+
function removeCompactionMarker(state) {
|
|
162374
|
+
try {
|
|
162375
|
+
const db = getWritableOpenCodeDb();
|
|
162376
|
+
db.transaction(() => {
|
|
162377
|
+
db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
|
|
162378
|
+
db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
|
|
162379
|
+
db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
|
|
162380
|
+
})();
|
|
162381
|
+
return true;
|
|
162382
|
+
} catch (error51) {
|
|
162383
|
+
log(`[magic-context] compaction-marker: removal failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
162384
|
+
return false;
|
|
162385
|
+
}
|
|
162386
|
+
}
|
|
162387
|
+
var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", cachedWriteDb = null, REQUIRED_MESSAGE_COLUMNS, REQUIRED_PART_COLUMNS, cachedSchemaCompatible = null;
|
|
162388
|
+
var init_compaction_marker = __esm(async () => {
|
|
162389
|
+
init_data_path();
|
|
162390
|
+
init_logger();
|
|
162391
|
+
await init_sqlite();
|
|
162392
|
+
REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
|
|
162393
|
+
REQUIRED_PART_COLUMNS = [
|
|
162394
|
+
"id",
|
|
162395
|
+
"message_id",
|
|
162396
|
+
"session_id",
|
|
162397
|
+
"time_created",
|
|
162398
|
+
"time_updated",
|
|
162399
|
+
"data"
|
|
162400
|
+
];
|
|
162401
|
+
});
|
|
162402
|
+
|
|
162403
|
+
// src/hooks/magic-context/compaction-marker-manager.ts
|
|
162404
|
+
import { join as join18 } from "node:path";
|
|
162405
|
+
function validatePendingTarget(db, sessionId, pending) {
|
|
162406
|
+
const ocMessage = getOpenCodeMessageById(sessionId, pending.endMessageId);
|
|
162407
|
+
if (!ocMessage) {
|
|
162408
|
+
return "compartment-removed";
|
|
162409
|
+
}
|
|
162410
|
+
const compartments = getCompartmentsByEndMessageId(db, sessionId, pending.endMessageId);
|
|
162411
|
+
if (compartments.length === 0) {
|
|
162412
|
+
return "compartment-removed";
|
|
162413
|
+
}
|
|
162414
|
+
if (compartments.length > 1) {
|
|
162415
|
+
log(`[magic-context][${sessionId}] WARNING: ${compartments.length} compartments share endMessageId=${pending.endMessageId} — schema invariant violated; treating as stale`);
|
|
162416
|
+
return "compartment-removed";
|
|
162417
|
+
}
|
|
162418
|
+
const compartment = compartments[0];
|
|
162419
|
+
if (compartment.endMessage !== pending.ordinal) {
|
|
162420
|
+
return "target-superseded";
|
|
162421
|
+
}
|
|
162422
|
+
return "ok";
|
|
162423
|
+
}
|
|
162424
|
+
function applyDeferredCompactionMarker(db, sessionId, pending, directory) {
|
|
162425
|
+
try {
|
|
162426
|
+
const validation = validatePendingTarget(db, sessionId, pending);
|
|
162427
|
+
if (validation !== "ok") {
|
|
162428
|
+
sessionLog(sessionId, `compaction-marker drain: stale-skip (${validation}) for ordinal ${pending.ordinal} endMessageId=${pending.endMessageId}`);
|
|
162429
|
+
return { kind: "stale-skip", reason: validation };
|
|
162430
|
+
}
|
|
162431
|
+
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
162432
|
+
if (existing && existing.boundaryOrdinal >= pending.ordinal) {
|
|
162433
|
+
return { kind: "already-current" };
|
|
162434
|
+
}
|
|
162435
|
+
if (existing) {
|
|
162436
|
+
const removed = removeCompactionMarker(existing);
|
|
162437
|
+
if (!removed) {
|
|
162438
|
+
return {
|
|
162439
|
+
kind: "retryable-failure",
|
|
162440
|
+
error: new Error(`failed to remove old compaction marker at ordinal ${existing.boundaryOrdinal}`)
|
|
162441
|
+
};
|
|
162442
|
+
}
|
|
162443
|
+
sessionLog(sessionId, `compaction-marker drain: removed old boundary at ordinal ${existing.boundaryOrdinal}, advancing to ${pending.ordinal}`);
|
|
162444
|
+
}
|
|
162445
|
+
const result = injectCompactionMarker({
|
|
162446
|
+
sessionId,
|
|
162447
|
+
endOrdinal: pending.ordinal,
|
|
162448
|
+
summaryText: MARKER_SUMMARY_TEXT,
|
|
162449
|
+
directory: directory ?? process.cwd()
|
|
162450
|
+
});
|
|
162451
|
+
if (!result) {
|
|
162452
|
+
return {
|
|
162453
|
+
kind: "retryable-failure",
|
|
162454
|
+
error: new Error(`injectCompactionMarker returned null for ordinal ${pending.ordinal}; will retry`)
|
|
162455
|
+
};
|
|
162456
|
+
}
|
|
162457
|
+
setPersistedCompactionMarkerState(db, sessionId, {
|
|
162458
|
+
...result,
|
|
162459
|
+
boundaryOrdinal: pending.ordinal
|
|
162460
|
+
});
|
|
162461
|
+
sessionLog(sessionId, `compaction-marker drain: applied at ordinal ${pending.ordinal}, boundary user msg ${result.boundaryMessageId}`);
|
|
162462
|
+
return { kind: "applied", markerOrdinal: pending.ordinal };
|
|
162463
|
+
} catch (err) {
|
|
162464
|
+
const error51 = err instanceof Error ? err : new Error(String(err));
|
|
162465
|
+
sessionLog(sessionId, `compaction-marker drain: retryable failure for ordinal ${pending.ordinal}:`, error51);
|
|
162466
|
+
return { kind: "retryable-failure", error: error51 };
|
|
162467
|
+
}
|
|
162468
|
+
}
|
|
162469
|
+
function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, directory) {
|
|
162470
|
+
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
162471
|
+
if (existing) {
|
|
162472
|
+
if (existing.boundaryOrdinal === lastCompartmentEnd) {
|
|
162473
|
+
return;
|
|
162474
|
+
}
|
|
162475
|
+
try {
|
|
162476
|
+
removeCompactionMarker(existing);
|
|
162477
|
+
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
162478
|
+
sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
|
|
162479
|
+
} catch (error51) {
|
|
162480
|
+
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}, proceeding with new injection:`, error51);
|
|
162481
|
+
}
|
|
162482
|
+
}
|
|
162483
|
+
const result = injectCompactionMarker({
|
|
162484
|
+
sessionId,
|
|
162485
|
+
endOrdinal: lastCompartmentEnd,
|
|
162486
|
+
summaryText: MARKER_SUMMARY_TEXT,
|
|
162487
|
+
directory: directory ?? process.cwd()
|
|
162488
|
+
});
|
|
162489
|
+
if (result) {
|
|
162490
|
+
setPersistedCompactionMarkerState(db, sessionId, {
|
|
162491
|
+
...result,
|
|
162492
|
+
boundaryOrdinal: lastCompartmentEnd
|
|
162493
|
+
});
|
|
162494
|
+
sessionLog(sessionId, `compaction-marker: injected at ordinal ${lastCompartmentEnd}, boundary user msg ${result.boundaryMessageId}`);
|
|
162495
|
+
}
|
|
162496
|
+
}
|
|
162497
|
+
function removeCompactionMarkerForSession(db, sessionId) {
|
|
162498
|
+
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
162499
|
+
if (existing) {
|
|
162500
|
+
try {
|
|
162501
|
+
removeCompactionMarker(existing);
|
|
162502
|
+
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
162503
|
+
sessionLog(sessionId, "compaction-marker: removed on session cleanup");
|
|
162504
|
+
} catch (error51) {
|
|
162505
|
+
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
162506
|
+
sessionLog(sessionId, "compaction-marker: removal failed during session cleanup, cleared persisted state:", error51);
|
|
162507
|
+
}
|
|
162508
|
+
}
|
|
162509
|
+
}
|
|
162510
|
+
function checkCompactionMarkerConsistency(db) {
|
|
162511
|
+
const opencodeDbPath = join18(getDataDir(), "opencode", "opencode.db");
|
|
162512
|
+
let opencodeDb;
|
|
162513
|
+
try {
|
|
162514
|
+
opencodeDb = new Database(opencodeDbPath, { readonly: true });
|
|
162515
|
+
} catch (error51) {
|
|
162516
|
+
log(`[magic-context] compaction-marker consistency check skipped: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
162517
|
+
return;
|
|
162518
|
+
}
|
|
162519
|
+
try {
|
|
162520
|
+
const persistedRows = db.prepare("SELECT session_id, compaction_marker_state FROM session_meta WHERE compaction_marker_state IS NOT NULL AND compaction_marker_state != ''").all();
|
|
162521
|
+
if (persistedRows.length === 0)
|
|
162522
|
+
return;
|
|
162523
|
+
const checkMessage = opencodeDb.prepare("SELECT 1 FROM message WHERE id = ? LIMIT 1");
|
|
162524
|
+
const checkPart = opencodeDb.prepare("SELECT 1 FROM part WHERE id = ? LIMIT 1");
|
|
162525
|
+
let reconciledCount = 0;
|
|
162526
|
+
for (const row of persistedRows) {
|
|
162527
|
+
const state = getPersistedCompactionMarkerState(db, row.session_id);
|
|
162528
|
+
if (!state)
|
|
162529
|
+
continue;
|
|
162530
|
+
const boundaryExists = checkMessage.get(state.boundaryMessageId) !== null;
|
|
162531
|
+
const summaryMessageExists = checkMessage.get(state.summaryMessageId) !== null;
|
|
162532
|
+
const compactionPartExists = checkPart.get(state.compactionPartId) !== null;
|
|
162533
|
+
const summaryPartExists = checkPart.get(state.summaryPartId) !== null;
|
|
162534
|
+
const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
|
|
162535
|
+
if (allPresent)
|
|
162536
|
+
continue;
|
|
162537
|
+
let removedOk = false;
|
|
162538
|
+
try {
|
|
162539
|
+
removedOk = removeCompactionMarker(state);
|
|
162540
|
+
} catch (error51) {
|
|
162541
|
+
sessionLog(row.session_id, "compaction-marker consistency: partial cleanup of half-written marker failed:", error51);
|
|
162542
|
+
}
|
|
162543
|
+
if (removedOk) {
|
|
162544
|
+
setPersistedCompactionMarkerState(db, row.session_id, null);
|
|
162545
|
+
sessionLog(row.session_id, `compaction-marker consistency: cleared orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); next publication will re-inject`);
|
|
162546
|
+
reconciledCount++;
|
|
162547
|
+
} else {
|
|
162548
|
+
sessionLog(row.session_id, `compaction-marker consistency: cleanup failed for orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); will retry on next startup`);
|
|
162549
|
+
}
|
|
162550
|
+
}
|
|
162551
|
+
if (reconciledCount > 0) {
|
|
162552
|
+
log(`[magic-context] compaction-marker consistency: reconciled ${reconciledCount} session(s) with orphaned marker state at startup`);
|
|
162553
|
+
}
|
|
162554
|
+
} catch (error51) {
|
|
162555
|
+
log(`[magic-context] compaction-marker consistency check failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
162556
|
+
} finally {
|
|
162557
|
+
try {
|
|
162558
|
+
closeQuietly(opencodeDb);
|
|
162559
|
+
} catch {}
|
|
162560
|
+
}
|
|
162561
|
+
}
|
|
162562
|
+
var MARKER_SUMMARY_TEXT = "[Compacted by magic-context — session history is managed by the plugin]";
|
|
162563
|
+
var init_compaction_marker_manager = __esm(async () => {
|
|
162564
|
+
init_compartment_storage();
|
|
162565
|
+
init_storage_meta_persisted();
|
|
162566
|
+
init_data_path();
|
|
162567
|
+
init_logger();
|
|
162568
|
+
await __promiseAll([
|
|
162569
|
+
init_compaction_marker(),
|
|
162570
|
+
init_sqlite()
|
|
162571
|
+
]);
|
|
162572
|
+
});
|
|
162573
|
+
|
|
162106
162574
|
// src/hooks/magic-context/compartment-parser.ts
|
|
162107
162575
|
function parseCompartmentOutput(text) {
|
|
162108
162576
|
const compartments = [];
|
|
@@ -162323,9 +162791,11 @@ var init_compartment_runner_validation = __esm(async () => {
|
|
|
162323
162791
|
});
|
|
162324
162792
|
|
|
162325
162793
|
// src/hooks/magic-context/compartment-runner-historian.ts
|
|
162326
|
-
import { mkdirSync as
|
|
162327
|
-
import {
|
|
162328
|
-
|
|
162794
|
+
import { mkdirSync as mkdirSync6, unlinkSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
162795
|
+
import { join as join19 } from "node:path";
|
|
162796
|
+
function historianResponseDumpDir(directory) {
|
|
162797
|
+
return getProjectMagicContextHistorianDir(directory);
|
|
162798
|
+
}
|
|
162329
162799
|
async function runValidatedHistorianPass(args) {
|
|
162330
162800
|
const firstRun = await runHistorianPrompt({
|
|
162331
162801
|
...args,
|
|
@@ -162476,7 +162946,7 @@ async function runHistorianPrompt(args) {
|
|
|
162476
162946
|
if (!result) {
|
|
162477
162947
|
return { ok: false, error: "Historian returned no assistant output." };
|
|
162478
162948
|
}
|
|
162479
|
-
const dumpPath = dumpHistorianResponse(parentSessionId, dumpLabel ?? "historian-response", result);
|
|
162949
|
+
const dumpPath = dumpHistorianResponse(parentSessionId, sessionDirectory, dumpLabel ?? "historian-response", result);
|
|
162480
162950
|
return { ok: true, result, dumpPath };
|
|
162481
162951
|
} catch (modelError) {
|
|
162482
162952
|
const desc = describeError(modelError);
|
|
@@ -162568,12 +163038,13 @@ function cleanupHistorianDump(sessionId, dumpPath) {
|
|
|
162568
163038
|
});
|
|
162569
163039
|
}
|
|
162570
163040
|
}
|
|
162571
|
-
function dumpHistorianResponse(sessionId, label, text) {
|
|
163041
|
+
function dumpHistorianResponse(sessionId, directory, label, text) {
|
|
162572
163042
|
try {
|
|
162573
|
-
|
|
163043
|
+
const dumpDir = historianResponseDumpDir(directory);
|
|
163044
|
+
mkdirSync6(dumpDir, { recursive: true });
|
|
162574
163045
|
const safeSessionId = sanitizeDumpName(sessionId);
|
|
162575
163046
|
const safeLabel = sanitizeDumpName(label);
|
|
162576
|
-
const dumpPath =
|
|
163047
|
+
const dumpPath = join19(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
|
|
162577
163048
|
writeFileSync5(dumpPath, text, "utf8");
|
|
162578
163049
|
sessionLog(sessionId, "compartment agent: historian response dumped", {
|
|
162579
163050
|
label,
|
|
@@ -162591,14 +163062,14 @@ function dumpHistorianResponse(sessionId, label, text) {
|
|
|
162591
163062
|
function sanitizeDumpName(value) {
|
|
162592
163063
|
return value.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
162593
163064
|
}
|
|
162594
|
-
var
|
|
163065
|
+
var MAX_HISTORIAN_RETRIES = 2;
|
|
162595
163066
|
var init_compartment_runner_historian = __esm(async () => {
|
|
162596
163067
|
init_magic_context();
|
|
162597
163068
|
init_shared();
|
|
162598
163069
|
init_assistant_message_extractor();
|
|
163070
|
+
init_data_path();
|
|
162599
163071
|
init_compartment_prompt();
|
|
162600
163072
|
await init_compartment_runner_validation();
|
|
162601
|
-
HISTORIAN_RESPONSE_DUMP_DIR = join18(tmpdir2(), "magic-context-historian");
|
|
162602
163073
|
});
|
|
162603
163074
|
|
|
162604
163075
|
// src/hooks/magic-context/compartment-runner-state-xml.ts
|
|
@@ -162900,16 +163371,24 @@ function trimMemoriesToBudget(sessionId, memories, budgetTokens) {
|
|
|
162900
163371
|
function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectPath, injectionBudgetTokens, temporalAwareness) {
|
|
162901
163372
|
const cached2 = injectionCache.get(sessionId);
|
|
162902
163373
|
if (!isCacheBusting && cached2) {
|
|
162903
|
-
if (cached2.
|
|
162904
|
-
|
|
162905
|
-
|
|
162906
|
-
|
|
162907
|
-
|
|
162908
|
-
|
|
162909
|
-
|
|
163374
|
+
if (cached2.kind === "empty") {
|
|
163375
|
+
return null;
|
|
163376
|
+
}
|
|
163377
|
+
const prepared = cached2.injection;
|
|
163378
|
+
if (prepared.compartmentEndMessageId === null) {
|
|
163379
|
+
sessionLog(sessionId, "compartment injection cache in degraded mode (null boundary), forcing rebuild");
|
|
163380
|
+
} else {
|
|
163381
|
+
if (prepared.compartmentEndMessageId.length > 0) {
|
|
163382
|
+
const cutoffIndex2 = messages.findIndex((message) => message.info.id === prepared.compartmentEndMessageId);
|
|
163383
|
+
if (cutoffIndex2 >= 0) {
|
|
163384
|
+
const remaining = messages.slice(cutoffIndex2 + 1);
|
|
163385
|
+
messages.splice(0, messages.length, ...remaining);
|
|
163386
|
+
} else {
|
|
163387
|
+
sessionLog(sessionId, `compartment injection: cached boundary ${prepared.compartmentEndMessageId} not in messages (already trimmed), reusing cache`);
|
|
163388
|
+
}
|
|
162910
163389
|
}
|
|
163390
|
+
return { ...prepared, rebuiltFromDb: false };
|
|
162911
163391
|
}
|
|
162912
|
-
return cached2;
|
|
162913
163392
|
}
|
|
162914
163393
|
const compartments = getCompartments(db, sessionId);
|
|
162915
163394
|
const facts = getSessionFacts(db, sessionId);
|
|
@@ -162941,7 +163420,11 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162941
163420
|
}
|
|
162942
163421
|
}
|
|
162943
163422
|
if (compartments.length === 0 && facts.length === 0 && !memoryBlock) {
|
|
162944
|
-
injectionCache.
|
|
163423
|
+
injectionCache.set(sessionId, {
|
|
163424
|
+
kind: "empty",
|
|
163425
|
+
compartmentEndMessageId: "",
|
|
163426
|
+
renderedBytes: 0
|
|
163427
|
+
});
|
|
162945
163428
|
return null;
|
|
162946
163429
|
}
|
|
162947
163430
|
let dateRanges;
|
|
@@ -162974,9 +163457,10 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162974
163457
|
compartmentCount: 0,
|
|
162975
163458
|
skippedVisibleMessages: 0,
|
|
162976
163459
|
factCount: facts.length,
|
|
162977
|
-
memoryCount
|
|
163460
|
+
memoryCount,
|
|
163461
|
+
rebuiltFromDb: true
|
|
162978
163462
|
};
|
|
162979
|
-
injectionCache.set(sessionId, result2);
|
|
163463
|
+
injectionCache.set(sessionId, { kind: "populated", injection: result2 });
|
|
162980
163464
|
return result2;
|
|
162981
163465
|
}
|
|
162982
163466
|
const lastCompartment = compartments[compartments.length - 1];
|
|
@@ -162994,9 +163478,10 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162994
163478
|
compartmentCount: compartments.length,
|
|
162995
163479
|
skippedVisibleMessages: 0,
|
|
162996
163480
|
factCount: facts.length,
|
|
162997
|
-
memoryCount
|
|
163481
|
+
memoryCount,
|
|
163482
|
+
rebuiltFromDb: true
|
|
162998
163483
|
};
|
|
162999
|
-
injectionCache.set(sessionId, result2);
|
|
163484
|
+
injectionCache.set(sessionId, { kind: "populated", injection: result2 });
|
|
163000
163485
|
return result2;
|
|
163001
163486
|
}
|
|
163002
163487
|
let skippedVisibleMessages = 0;
|
|
@@ -163005,17 +163490,20 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
163005
163490
|
skippedVisibleMessages = cutoffIndex + 1;
|
|
163006
163491
|
const remaining = messages.slice(cutoffIndex + 1);
|
|
163007
163492
|
messages.splice(0, messages.length, ...remaining);
|
|
163493
|
+
} else {
|
|
163494
|
+
sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${lastEndMessageId} not in visible messages`);
|
|
163008
163495
|
}
|
|
163009
163496
|
const result = {
|
|
163010
163497
|
block,
|
|
163011
163498
|
compartmentEndMessage: lastEnd,
|
|
163012
|
-
compartmentEndMessageId: lastEndMessageId,
|
|
163499
|
+
compartmentEndMessageId: cutoffIndex >= 0 ? lastEndMessageId : null,
|
|
163013
163500
|
compartmentCount: compartments.length,
|
|
163014
163501
|
skippedVisibleMessages,
|
|
163015
163502
|
factCount: facts.length,
|
|
163016
|
-
memoryCount
|
|
163503
|
+
memoryCount,
|
|
163504
|
+
rebuiltFromDb: true
|
|
163017
163505
|
};
|
|
163018
|
-
injectionCache.set(sessionId, result);
|
|
163506
|
+
injectionCache.set(sessionId, { kind: "populated", injection: result });
|
|
163019
163507
|
return result;
|
|
163020
163508
|
}
|
|
163021
163509
|
function renderCompartmentInjection(sessionId, messages, prepared) {
|
|
@@ -163307,9 +163795,18 @@ async function executePartialRecompInternal(deps, range) {
|
|
|
163307
163795
|
}
|
|
163308
163796
|
setRecompPartialRange(db, sessionId, null);
|
|
163309
163797
|
clearCompressionDepthRange(db, sessionId, snapStart, snapEnd);
|
|
163310
|
-
|
|
163311
|
-
|
|
163798
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
163799
|
+
clearInjectionCache(sessionId);
|
|
163800
|
+
}
|
|
163801
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
163312
163802
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
163803
|
+
if (deps.experimentalCompactionMarkers && lastEnd > 0) {
|
|
163804
|
+
updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
|
|
163805
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
163806
|
+
if (stalePending) {
|
|
163807
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
163808
|
+
}
|
|
163809
|
+
}
|
|
163313
163810
|
return { compartmentCount: merged.length, lastEndMessage: lastEnd };
|
|
163314
163811
|
};
|
|
163315
163812
|
const protectedTailStart = getProtectedTailStartOrdinal(sessionId);
|
|
@@ -163509,6 +164006,7 @@ var init_compartment_runner_partial_recomp = __esm(async () => {
|
|
|
163509
164006
|
init_send_session_notification();
|
|
163510
164007
|
await __promiseAll([
|
|
163511
164008
|
init_storage_meta(),
|
|
164009
|
+
init_compaction_marker_manager(),
|
|
163512
164010
|
init_compartment_runner_historian(),
|
|
163513
164011
|
init_compartment_runner_validation(),
|
|
163514
164012
|
init_inject_compartments(),
|
|
@@ -163577,269 +164075,6 @@ var init_derive_budgets = __esm(() => {
|
|
|
163577
164075
|
init_models_dev_cache();
|
|
163578
164076
|
});
|
|
163579
164077
|
|
|
163580
|
-
// src/features/magic-context/compaction-marker.ts
|
|
163581
|
-
import { join as join19 } from "node:path";
|
|
163582
|
-
function randomBase62(length) {
|
|
163583
|
-
const chars = [];
|
|
163584
|
-
for (let i = 0;i < length; i++) {
|
|
163585
|
-
chars.push(BASE62_CHARS[Math.floor(Math.random() * BASE62_CHARS.length)]);
|
|
163586
|
-
}
|
|
163587
|
-
return chars.join("");
|
|
163588
|
-
}
|
|
163589
|
-
function generateId(prefix, timestampMs, counter = 0n) {
|
|
163590
|
-
const encoded = BigInt(timestampMs) * 0x1000n + counter;
|
|
163591
|
-
const hex3 = encoded.toString(16).padStart(14, "0");
|
|
163592
|
-
return `${prefix}_${hex3}${randomBase62(14)}`;
|
|
163593
|
-
}
|
|
163594
|
-
function generateMessageId(timestampMs, counter = 0n) {
|
|
163595
|
-
return generateId("msg", timestampMs, counter);
|
|
163596
|
-
}
|
|
163597
|
-
function generatePartId(timestampMs, counter = 0n) {
|
|
163598
|
-
return generateId("prt", timestampMs, counter);
|
|
163599
|
-
}
|
|
163600
|
-
function getOpenCodeDbPath3() {
|
|
163601
|
-
return join19(getDataDir(), "opencode", "opencode.db");
|
|
163602
|
-
}
|
|
163603
|
-
function isOpenCodeSchemaCompatible(db, dbPath) {
|
|
163604
|
-
if (cachedSchemaCompatible?.path === dbPath) {
|
|
163605
|
-
return cachedSchemaCompatible.compatible;
|
|
163606
|
-
}
|
|
163607
|
-
try {
|
|
163608
|
-
const messageCols = new Set(db.prepare("PRAGMA table_info(message)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
163609
|
-
const partCols = new Set(db.prepare("PRAGMA table_info(part)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
163610
|
-
const missingMessage = REQUIRED_MESSAGE_COLUMNS.filter((c) => !messageCols.has(c));
|
|
163611
|
-
const missingPart = REQUIRED_PART_COLUMNS.filter((c) => !partCols.has(c));
|
|
163612
|
-
if (missingMessage.length > 0 || missingPart.length > 0) {
|
|
163613
|
-
log(`[magic-context] compaction-marker: OpenCode DB schema missing required columns ` + `(message: [${missingMessage.join(", ")}], part: [${missingPart.join(", ")}]). ` + `Marker injection disabled for this process. ` + `This usually means OpenCode was updated and magic-context is out of date.`);
|
|
163614
|
-
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
163615
|
-
return false;
|
|
163616
|
-
}
|
|
163617
|
-
cachedSchemaCompatible = { path: dbPath, compatible: true };
|
|
163618
|
-
return true;
|
|
163619
|
-
} catch (error51) {
|
|
163620
|
-
log(`[magic-context] compaction-marker: schema probe failed: ${error51 instanceof Error ? error51.message : String(error51)}. ` + `Marker injection disabled until next process restart.`);
|
|
163621
|
-
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
163622
|
-
return false;
|
|
163623
|
-
}
|
|
163624
|
-
}
|
|
163625
|
-
function getWritableOpenCodeDb() {
|
|
163626
|
-
const dbPath = getOpenCodeDbPath3();
|
|
163627
|
-
if (cachedWriteDb?.path === dbPath) {
|
|
163628
|
-
return cachedWriteDb.db;
|
|
163629
|
-
}
|
|
163630
|
-
if (cachedWriteDb) {
|
|
163631
|
-
try {
|
|
163632
|
-
closeQuietly(cachedWriteDb.db);
|
|
163633
|
-
} catch {}
|
|
163634
|
-
}
|
|
163635
|
-
const db = new Database(dbPath);
|
|
163636
|
-
db.exec("PRAGMA journal_mode=WAL");
|
|
163637
|
-
db.exec("PRAGMA busy_timeout=5000");
|
|
163638
|
-
cachedWriteDb = { path: dbPath, db };
|
|
163639
|
-
return db;
|
|
163640
|
-
}
|
|
163641
|
-
function findBoundaryUserMessage(sessionId, endOrdinal) {
|
|
163642
|
-
const db = getWritableOpenCodeDb();
|
|
163643
|
-
const rows = db.prepare(`SELECT id, time_created, data
|
|
163644
|
-
FROM message
|
|
163645
|
-
WHERE session_id = ?
|
|
163646
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
163647
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
163648
|
-
ORDER BY time_created ASC, id ASC
|
|
163649
|
-
LIMIT ?`).all(sessionId, endOrdinal);
|
|
163650
|
-
let bestMatch = null;
|
|
163651
|
-
for (const row of rows) {
|
|
163652
|
-
try {
|
|
163653
|
-
const info = JSON.parse(row.data);
|
|
163654
|
-
if (info.role === "user") {
|
|
163655
|
-
bestMatch = { id: row.id, timeCreated: row.time_created };
|
|
163656
|
-
}
|
|
163657
|
-
} catch {}
|
|
163658
|
-
}
|
|
163659
|
-
return bestMatch;
|
|
163660
|
-
}
|
|
163661
|
-
function injectCompactionMarker(args) {
|
|
163662
|
-
const db = getWritableOpenCodeDb();
|
|
163663
|
-
if (!isOpenCodeSchemaCompatible(db, getOpenCodeDbPath3())) {
|
|
163664
|
-
return null;
|
|
163665
|
-
}
|
|
163666
|
-
const boundary = findBoundaryUserMessage(args.sessionId, args.endOrdinal);
|
|
163667
|
-
if (!boundary) {
|
|
163668
|
-
log(`[magic-context] compaction-marker: no user message found at or before ordinal ${args.endOrdinal}`);
|
|
163669
|
-
return null;
|
|
163670
|
-
}
|
|
163671
|
-
const boundaryTime = boundary.timeCreated;
|
|
163672
|
-
const summaryMsgId = generateMessageId(boundaryTime + 1, 1n);
|
|
163673
|
-
const compactionPartId = generatePartId(boundaryTime, 1n);
|
|
163674
|
-
const summaryPartId = generatePartId(boundaryTime + 1, 2n);
|
|
163675
|
-
const summaryMsgData = JSON.stringify({
|
|
163676
|
-
role: "assistant",
|
|
163677
|
-
parentID: boundary.id,
|
|
163678
|
-
summary: true,
|
|
163679
|
-
finish: "stop",
|
|
163680
|
-
mode: "compaction",
|
|
163681
|
-
agent: "compaction",
|
|
163682
|
-
path: { cwd: args.directory, root: args.directory },
|
|
163683
|
-
cost: 0,
|
|
163684
|
-
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
163685
|
-
modelID: "magic-context",
|
|
163686
|
-
providerID: "magic-context",
|
|
163687
|
-
time: { created: boundaryTime + 1 }
|
|
163688
|
-
});
|
|
163689
|
-
try {
|
|
163690
|
-
db.transaction(() => {
|
|
163691
|
-
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(compactionPartId, boundary.id, args.sessionId, boundaryTime, boundaryTime, '{"type":"compaction","auto":true}');
|
|
163692
|
-
db.prepare("INSERT INTO message (id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?)").run(summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, summaryMsgData);
|
|
163693
|
-
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(summaryPartId, summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, JSON.stringify({ type: "text", text: args.summaryText }));
|
|
163694
|
-
})();
|
|
163695
|
-
log(`[magic-context] compaction-marker: injected boundary at user msg ${boundary.id} (ordinal ~${args.endOrdinal}), summary msg ${summaryMsgId}`);
|
|
163696
|
-
return {
|
|
163697
|
-
boundaryMessageId: boundary.id,
|
|
163698
|
-
summaryMessageId: summaryMsgId,
|
|
163699
|
-
compactionPartId,
|
|
163700
|
-
summaryPartId
|
|
163701
|
-
};
|
|
163702
|
-
} catch (error51) {
|
|
163703
|
-
log(`[magic-context] compaction-marker: injection failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163704
|
-
return null;
|
|
163705
|
-
}
|
|
163706
|
-
}
|
|
163707
|
-
function removeCompactionMarker(state) {
|
|
163708
|
-
try {
|
|
163709
|
-
const db = getWritableOpenCodeDb();
|
|
163710
|
-
db.transaction(() => {
|
|
163711
|
-
db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
|
|
163712
|
-
db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
|
|
163713
|
-
db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
|
|
163714
|
-
})();
|
|
163715
|
-
return true;
|
|
163716
|
-
} catch (error51) {
|
|
163717
|
-
log(`[magic-context] compaction-marker: removal failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163718
|
-
return false;
|
|
163719
|
-
}
|
|
163720
|
-
}
|
|
163721
|
-
var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", cachedWriteDb = null, REQUIRED_MESSAGE_COLUMNS, REQUIRED_PART_COLUMNS, cachedSchemaCompatible = null;
|
|
163722
|
-
var init_compaction_marker = __esm(async () => {
|
|
163723
|
-
init_data_path();
|
|
163724
|
-
init_logger();
|
|
163725
|
-
await init_sqlite();
|
|
163726
|
-
REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
|
|
163727
|
-
REQUIRED_PART_COLUMNS = [
|
|
163728
|
-
"id",
|
|
163729
|
-
"message_id",
|
|
163730
|
-
"session_id",
|
|
163731
|
-
"time_created",
|
|
163732
|
-
"time_updated",
|
|
163733
|
-
"data"
|
|
163734
|
-
];
|
|
163735
|
-
});
|
|
163736
|
-
|
|
163737
|
-
// src/hooks/magic-context/compaction-marker-manager.ts
|
|
163738
|
-
import { join as join20 } from "node:path";
|
|
163739
|
-
function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, directory) {
|
|
163740
|
-
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
163741
|
-
if (existing) {
|
|
163742
|
-
if (existing.boundaryOrdinal === lastCompartmentEnd) {
|
|
163743
|
-
return;
|
|
163744
|
-
}
|
|
163745
|
-
try {
|
|
163746
|
-
removeCompactionMarker(existing);
|
|
163747
|
-
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
163748
|
-
sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
|
|
163749
|
-
} catch (error51) {
|
|
163750
|
-
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}, proceeding with new injection:`, error51);
|
|
163751
|
-
}
|
|
163752
|
-
}
|
|
163753
|
-
const result = injectCompactionMarker({
|
|
163754
|
-
sessionId,
|
|
163755
|
-
endOrdinal: lastCompartmentEnd,
|
|
163756
|
-
summaryText: MARKER_SUMMARY_TEXT,
|
|
163757
|
-
directory: directory ?? process.cwd()
|
|
163758
|
-
});
|
|
163759
|
-
if (result) {
|
|
163760
|
-
setPersistedCompactionMarkerState(db, sessionId, {
|
|
163761
|
-
...result,
|
|
163762
|
-
boundaryOrdinal: lastCompartmentEnd
|
|
163763
|
-
});
|
|
163764
|
-
sessionLog(sessionId, `compaction-marker: injected at ordinal ${lastCompartmentEnd}, boundary user msg ${result.boundaryMessageId}`);
|
|
163765
|
-
}
|
|
163766
|
-
}
|
|
163767
|
-
function removeCompactionMarkerForSession(db, sessionId) {
|
|
163768
|
-
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
163769
|
-
if (existing) {
|
|
163770
|
-
try {
|
|
163771
|
-
removeCompactionMarker(existing);
|
|
163772
|
-
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
163773
|
-
sessionLog(sessionId, "compaction-marker: removed on session cleanup");
|
|
163774
|
-
} catch (error51) {
|
|
163775
|
-
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
163776
|
-
sessionLog(sessionId, "compaction-marker: removal failed during session cleanup, cleared persisted state:", error51);
|
|
163777
|
-
}
|
|
163778
|
-
}
|
|
163779
|
-
}
|
|
163780
|
-
function checkCompactionMarkerConsistency(db) {
|
|
163781
|
-
const opencodeDbPath = join20(getDataDir(), "opencode", "opencode.db");
|
|
163782
|
-
let opencodeDb;
|
|
163783
|
-
try {
|
|
163784
|
-
opencodeDb = new Database(opencodeDbPath, { readonly: true });
|
|
163785
|
-
} catch (error51) {
|
|
163786
|
-
log(`[magic-context] compaction-marker consistency check skipped: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163787
|
-
return;
|
|
163788
|
-
}
|
|
163789
|
-
try {
|
|
163790
|
-
const persistedRows = db.prepare("SELECT session_id, compaction_marker_state FROM session_meta WHERE compaction_marker_state IS NOT NULL AND compaction_marker_state != ''").all();
|
|
163791
|
-
if (persistedRows.length === 0)
|
|
163792
|
-
return;
|
|
163793
|
-
const checkMessage = opencodeDb.prepare("SELECT 1 FROM message WHERE id = ? LIMIT 1");
|
|
163794
|
-
const checkPart = opencodeDb.prepare("SELECT 1 FROM part WHERE id = ? LIMIT 1");
|
|
163795
|
-
let reconciledCount = 0;
|
|
163796
|
-
for (const row of persistedRows) {
|
|
163797
|
-
const state = getPersistedCompactionMarkerState(db, row.session_id);
|
|
163798
|
-
if (!state)
|
|
163799
|
-
continue;
|
|
163800
|
-
const boundaryExists = checkMessage.get(state.boundaryMessageId) !== null;
|
|
163801
|
-
const summaryMessageExists = checkMessage.get(state.summaryMessageId) !== null;
|
|
163802
|
-
const compactionPartExists = checkPart.get(state.compactionPartId) !== null;
|
|
163803
|
-
const summaryPartExists = checkPart.get(state.summaryPartId) !== null;
|
|
163804
|
-
const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
|
|
163805
|
-
if (allPresent)
|
|
163806
|
-
continue;
|
|
163807
|
-
let removedOk = false;
|
|
163808
|
-
try {
|
|
163809
|
-
removedOk = removeCompactionMarker(state);
|
|
163810
|
-
} catch (error51) {
|
|
163811
|
-
sessionLog(row.session_id, "compaction-marker consistency: partial cleanup of half-written marker failed:", error51);
|
|
163812
|
-
}
|
|
163813
|
-
if (removedOk) {
|
|
163814
|
-
setPersistedCompactionMarkerState(db, row.session_id, null);
|
|
163815
|
-
sessionLog(row.session_id, `compaction-marker consistency: cleared orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); next publication will re-inject`);
|
|
163816
|
-
reconciledCount++;
|
|
163817
|
-
} else {
|
|
163818
|
-
sessionLog(row.session_id, `compaction-marker consistency: cleanup failed for orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); will retry on next startup`);
|
|
163819
|
-
}
|
|
163820
|
-
}
|
|
163821
|
-
if (reconciledCount > 0) {
|
|
163822
|
-
log(`[magic-context] compaction-marker consistency: reconciled ${reconciledCount} session(s) with orphaned marker state at startup`);
|
|
163823
|
-
}
|
|
163824
|
-
} catch (error51) {
|
|
163825
|
-
log(`[magic-context] compaction-marker consistency check failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163826
|
-
} finally {
|
|
163827
|
-
try {
|
|
163828
|
-
closeQuietly(opencodeDb);
|
|
163829
|
-
} catch {}
|
|
163830
|
-
}
|
|
163831
|
-
}
|
|
163832
|
-
var MARKER_SUMMARY_TEXT = "[Compacted by magic-context — session history is managed by the plugin]";
|
|
163833
|
-
var init_compaction_marker_manager = __esm(async () => {
|
|
163834
|
-
init_storage_meta_persisted();
|
|
163835
|
-
init_data_path();
|
|
163836
|
-
init_logger();
|
|
163837
|
-
await __promiseAll([
|
|
163838
|
-
init_compaction_marker(),
|
|
163839
|
-
init_sqlite()
|
|
163840
|
-
]);
|
|
163841
|
-
});
|
|
163842
|
-
|
|
163843
164078
|
// src/hooks/magic-context/note-nudger.ts
|
|
163844
164079
|
function getPersistedNoteNudgeDeliveredAt(_db, sessionId) {
|
|
163845
164080
|
return lastDeliveredAt.get(sessionId) ?? 0;
|
|
@@ -164165,15 +164400,15 @@ var init_caveman = __esm(() => {
|
|
|
164165
164400
|
});
|
|
164166
164401
|
|
|
164167
164402
|
// src/hooks/magic-context/historian-state-file.ts
|
|
164168
|
-
import { mkdirSync as
|
|
164169
|
-
import {
|
|
164170
|
-
|
|
164171
|
-
function maybeWriteHistorianStateFile(sessionId, existingState) {
|
|
164403
|
+
import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
164404
|
+
import { join as join20 } from "node:path";
|
|
164405
|
+
function maybeWriteHistorianStateFile(sessionId, existingState, directory) {
|
|
164172
164406
|
if (existingState.length <= HISTORIAN_STATE_INLINE_THRESHOLD)
|
|
164173
164407
|
return;
|
|
164174
164408
|
try {
|
|
164175
|
-
|
|
164176
|
-
|
|
164409
|
+
const dir = getProjectMagicContextHistorianDir(directory);
|
|
164410
|
+
mkdirSync7(dir, { recursive: true });
|
|
164411
|
+
const path5 = join20(dir, `state-${sessionId}-${Date.now()}.xml`);
|
|
164177
164412
|
writeFileSync6(path5, existingState, "utf8");
|
|
164178
164413
|
return path5;
|
|
164179
164414
|
} catch {
|
|
@@ -164187,9 +164422,9 @@ function cleanupHistorianStateFile(path5) {
|
|
|
164187
164422
|
unlinkSync2(path5);
|
|
164188
164423
|
} catch {}
|
|
164189
164424
|
}
|
|
164190
|
-
var HISTORIAN_STATE_INLINE_THRESHOLD = 30000
|
|
164425
|
+
var HISTORIAN_STATE_INLINE_THRESHOLD = 30000;
|
|
164191
164426
|
var init_historian_state_file = __esm(() => {
|
|
164192
|
-
|
|
164427
|
+
init_data_path();
|
|
164193
164428
|
});
|
|
164194
164429
|
|
|
164195
164430
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
@@ -164801,7 +165036,7 @@ No new compartments or facts were written.`);
|
|
|
164801
165036
|
const existingState = priorCompartments.length > 0 || priorFacts.length > 0 ? buildExistingStateXml(priorCompartments, priorFacts, memoryBlock) : memoryBlock ? `${memoryBlock}
|
|
164802
165037
|
|
|
164803
165038
|
This is your first run. No existing compartments or facts.` : "This is your first run. No existing state.";
|
|
164804
|
-
stateFilePath = maybeWriteHistorianStateFile(sessionId, existingState);
|
|
165039
|
+
stateFilePath = maybeWriteHistorianStateFile(sessionId, existingState, directory);
|
|
164805
165040
|
if (stateFilePath) {
|
|
164806
165041
|
sessionLog(sessionId, `historian: existing state offloaded to file (${existingState.length} chars) → ${stateFilePath}`);
|
|
164807
165042
|
}
|
|
@@ -164849,21 +165084,36 @@ Historian returned compartments that made no forward progress beyond raw message
|
|
|
164849
165084
|
No new compartments or facts were written. Check the historian model/output and try again.`);
|
|
164850
165085
|
return;
|
|
164851
165086
|
}
|
|
165087
|
+
const deferMarkerApplication = deps.preserveInjectionCacheUntilConsumed === true && deps.experimentalCompactionMarkers === true;
|
|
165088
|
+
const lastCompartmentEnd = lastNewEnd;
|
|
165089
|
+
const lastNewEndMessageId = newCompartments[newCompartments.length - 1]?.endMessageId;
|
|
164852
165090
|
db.transaction(() => {
|
|
164853
165091
|
appendCompartments(db, sessionId, newCompartments);
|
|
164854
165092
|
replaceSessionFacts(db, sessionId, validatedPass.facts ?? []);
|
|
164855
165093
|
clearHistorianFailureState(db, sessionId);
|
|
164856
165094
|
clearEmergencyRecovery(db, sessionId);
|
|
165095
|
+
if (deferMarkerApplication && lastNewEndMessageId) {
|
|
165096
|
+
setPendingCompactionMarkerState(db, sessionId, {
|
|
165097
|
+
ordinal: lastCompartmentEnd,
|
|
165098
|
+
endMessageId: lastNewEndMessageId,
|
|
165099
|
+
publishedAt: Date.now()
|
|
165100
|
+
});
|
|
165101
|
+
}
|
|
164857
165102
|
})();
|
|
164858
|
-
|
|
164859
|
-
|
|
165103
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
165104
|
+
clearInjectionCache(sessionId);
|
|
165105
|
+
}
|
|
165106
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
164860
165107
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
164861
165108
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), validatedPass.facts ?? []);
|
|
164862
165109
|
}
|
|
164863
|
-
const lastCompartmentEnd = lastNewEnd;
|
|
164864
165110
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
164865
165111
|
if (deps.experimentalCompactionMarkers) {
|
|
164866
|
-
|
|
165112
|
+
if (deferMarkerApplication) {
|
|
165113
|
+
deps.onDeferredMarkerPending?.(sessionId);
|
|
165114
|
+
} else {
|
|
165115
|
+
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, sessionDirectory);
|
|
165116
|
+
}
|
|
164867
165117
|
}
|
|
164868
165118
|
if (deps.historyBudgetTokens && deps.historyBudgetTokens > 0) {
|
|
164869
165119
|
await runCompressionPassIfNeeded({
|
|
@@ -164968,8 +165218,10 @@ async function executeContextRecompInternal(deps) {
|
|
|
164968
165218
|
if (!promoted2)
|
|
164969
165219
|
return null;
|
|
164970
165220
|
clearCompressionDepth(db, sessionId);
|
|
164971
|
-
|
|
164972
|
-
|
|
165221
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
165222
|
+
clearInjectionCache(sessionId);
|
|
165223
|
+
}
|
|
165224
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
164973
165225
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
164974
165226
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), promoted2.facts);
|
|
164975
165227
|
}
|
|
@@ -164979,6 +165231,10 @@ async function executeContextRecompInternal(deps) {
|
|
|
164979
165231
|
}
|
|
164980
165232
|
if (deps.experimentalCompactionMarkers && lastCompartmentEnd2 > 0) {
|
|
164981
165233
|
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
|
|
165234
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
165235
|
+
if (stalePending) {
|
|
165236
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
165237
|
+
}
|
|
164982
165238
|
}
|
|
164983
165239
|
return [
|
|
164984
165240
|
`Persisted ${promoted2.compartments.length} compartment${promoted2.compartments.length === 1 ? "" : "s"} from ${passCount} successful pass${passCount === 1 ? "" : "es"}.`,
|
|
@@ -165044,7 +165300,7 @@ Nothing was written.`;
|
|
|
165044
165300
|
|
|
165045
165301
|
This is your first run. No existing compartments or facts.` : "This is your first run. No existing state.";
|
|
165046
165302
|
cleanupHistorianStateFile(currentStateFilePath);
|
|
165047
|
-
currentStateFilePath = maybeWriteHistorianStateFile(sessionId, existingState);
|
|
165303
|
+
currentStateFilePath = maybeWriteHistorianStateFile(sessionId, existingState, sessionDirectory);
|
|
165048
165304
|
const prompt = buildCompartmentAgentPrompt(existingState, `Messages ${chunk.startIndex}-${chunk.endIndex}:
|
|
165049
165305
|
|
|
165050
165306
|
${chunk.text}`, { stateFilePath: currentStateFilePath });
|
|
@@ -165140,8 +165396,10 @@ Nothing was written.`;
|
|
|
165140
165396
|
clearRecompStaging(db, sessionId);
|
|
165141
165397
|
}
|
|
165142
165398
|
clearCompressionDepth(db, sessionId);
|
|
165143
|
-
|
|
165144
|
-
|
|
165399
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
165400
|
+
clearInjectionCache(sessionId);
|
|
165401
|
+
}
|
|
165402
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
165145
165403
|
const finalCompartments = promoted?.compartments ?? candidateCompartments;
|
|
165146
165404
|
const finalFacts = promoted?.facts ?? candidateFacts;
|
|
165147
165405
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
@@ -165216,50 +165474,78 @@ __export(exports_compartment_runner, {
|
|
|
165216
165474
|
startCompartmentAgent: () => startCompartmentAgent,
|
|
165217
165475
|
runCompartmentAgent: () => runCompartmentAgent,
|
|
165218
165476
|
registerActiveCompartmentRun: () => registerActiveCompartmentRun,
|
|
165477
|
+
markActiveCompartmentRunPublished: () => markActiveCompartmentRunPublished,
|
|
165219
165478
|
getActiveCompartmentRun: () => getActiveCompartmentRun,
|
|
165220
165479
|
executeContextRecomp: () => executeContextRecomp
|
|
165221
165480
|
});
|
|
165222
165481
|
function getActiveCompartmentRun(sessionId) {
|
|
165223
165482
|
return activeRuns.get(sessionId);
|
|
165224
165483
|
}
|
|
165484
|
+
function markActiveCompartmentRunPublished(sessionId) {
|
|
165485
|
+
const activeRun = activeRuns.get(sessionId);
|
|
165486
|
+
if (activeRun)
|
|
165487
|
+
activeRun.published = true;
|
|
165488
|
+
}
|
|
165225
165489
|
function registerActiveCompartmentRun(sessionId, promise2) {
|
|
165490
|
+
const activeRun = {
|
|
165491
|
+
promise: Promise.resolve(),
|
|
165492
|
+
published: false
|
|
165493
|
+
};
|
|
165226
165494
|
const wrapped = promise2.finally(() => {
|
|
165227
|
-
if (activeRuns.get(sessionId) === wrapped) {
|
|
165495
|
+
if (activeRuns.get(sessionId)?.promise === wrapped) {
|
|
165228
165496
|
activeRuns.delete(sessionId);
|
|
165229
165497
|
}
|
|
165230
165498
|
});
|
|
165231
|
-
|
|
165499
|
+
activeRun.promise = wrapped;
|
|
165500
|
+
activeRuns.set(sessionId, activeRun);
|
|
165501
|
+
return activeRun;
|
|
165502
|
+
}
|
|
165503
|
+
function withPublishedCallback(deps) {
|
|
165504
|
+
return {
|
|
165505
|
+
...deps,
|
|
165506
|
+
onCompartmentStatePublished: (sid) => {
|
|
165507
|
+
markActiveCompartmentRunPublished(sid);
|
|
165508
|
+
deps.onCompartmentStatePublished?.(sid);
|
|
165509
|
+
}
|
|
165510
|
+
};
|
|
165232
165511
|
}
|
|
165233
165512
|
function startCompartmentAgent(deps) {
|
|
165234
165513
|
const existing = activeRuns.get(deps.sessionId);
|
|
165235
165514
|
if (existing) {
|
|
165236
165515
|
return;
|
|
165237
165516
|
}
|
|
165238
|
-
const
|
|
165517
|
+
const runnerDeps = withPublishedCallback(deps);
|
|
165518
|
+
const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
|
|
165239
165519
|
sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
|
|
165240
165520
|
try {
|
|
165241
165521
|
updateSessionMeta(deps.db, deps.sessionId, { compartmentInProgress: false });
|
|
165242
165522
|
} catch {}
|
|
165243
165523
|
}).finally(() => {
|
|
165244
|
-
activeRuns.
|
|
165524
|
+
if (activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
165525
|
+
activeRuns.delete(deps.sessionId);
|
|
165526
|
+
}
|
|
165245
165527
|
});
|
|
165246
|
-
activeRuns.set(deps.sessionId, promise2);
|
|
165528
|
+
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
165247
165529
|
}
|
|
165248
165530
|
async function executeContextRecomp(deps, options = {}) {
|
|
165249
165531
|
const { sessionId } = deps;
|
|
165250
165532
|
if (activeRuns.has(sessionId)) {
|
|
165251
165533
|
return "## Magic Recomp\n\nHistorian is already running for this session. Wait for it to finish, then try `/ctx-recomp` again.";
|
|
165252
165534
|
}
|
|
165253
|
-
const
|
|
165254
|
-
|
|
165535
|
+
const runnerDeps = withPublishedCallback(deps);
|
|
165536
|
+
const promise2 = options.range ? executePartialRecompInternal(runnerDeps, options.range) : executeContextRecompInternal(runnerDeps);
|
|
165537
|
+
const wrappedPromise = promise2.then(() => {
|
|
165255
165538
|
return;
|
|
165256
165539
|
}).catch((err) => {
|
|
165257
165540
|
sessionLog(sessionId, "compartment agent: recomp unhandled rejection:", err);
|
|
165258
|
-
})
|
|
165541
|
+
});
|
|
165542
|
+
activeRuns.set(sessionId, { promise: wrappedPromise, published: false });
|
|
165259
165543
|
try {
|
|
165260
165544
|
return await promise2;
|
|
165261
165545
|
} finally {
|
|
165262
|
-
activeRuns.
|
|
165546
|
+
if (activeRuns.get(sessionId)?.promise === wrappedPromise) {
|
|
165547
|
+
activeRuns.delete(sessionId);
|
|
165548
|
+
}
|
|
165263
165549
|
}
|
|
165264
165550
|
}
|
|
165265
165551
|
var activeRuns;
|
|
@@ -165280,8 +165566,8 @@ var exports_tui_config = {};
|
|
|
165280
165566
|
__export(exports_tui_config, {
|
|
165281
165567
|
ensureTuiPluginEntry: () => ensureTuiPluginEntry
|
|
165282
165568
|
});
|
|
165283
|
-
import { existsSync as existsSync14, mkdirSync as
|
|
165284
|
-
import { dirname as
|
|
165569
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "node:fs";
|
|
165570
|
+
import { dirname as dirname8, join as join23 } from "node:path";
|
|
165285
165571
|
function isMagicContextEntry(entry) {
|
|
165286
165572
|
if (!entry)
|
|
165287
165573
|
return false;
|
|
@@ -165295,8 +165581,8 @@ function isMagicContextEntry(entry) {
|
|
|
165295
165581
|
}
|
|
165296
165582
|
function resolveTuiConfigPath() {
|
|
165297
165583
|
const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
165298
|
-
const jsoncPath =
|
|
165299
|
-
const jsonPath =
|
|
165584
|
+
const jsoncPath = join23(configDir, "tui.jsonc");
|
|
165585
|
+
const jsonPath = join23(configDir, "tui.json");
|
|
165300
165586
|
if (existsSync14(jsoncPath))
|
|
165301
165587
|
return jsoncPath;
|
|
165302
165588
|
if (existsSync14(jsonPath))
|
|
@@ -165308,7 +165594,7 @@ function ensureTuiPluginEntry() {
|
|
|
165308
165594
|
const configPath = resolveTuiConfigPath();
|
|
165309
165595
|
let config2 = {};
|
|
165310
165596
|
if (existsSync14(configPath)) {
|
|
165311
|
-
const raw =
|
|
165597
|
+
const raw = readFileSync11(configPath, "utf-8");
|
|
165312
165598
|
config2 = import_comment_json3.parse(raw) ?? {};
|
|
165313
165599
|
}
|
|
165314
165600
|
const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p) => typeof p === "string") : [];
|
|
@@ -165327,7 +165613,7 @@ function ensureTuiPluginEntry() {
|
|
|
165327
165613
|
plugins.push(PLUGIN_ENTRY);
|
|
165328
165614
|
}
|
|
165329
165615
|
config2.plugin = plugins;
|
|
165330
|
-
|
|
165616
|
+
mkdirSync9(dirname8(configPath), { recursive: true });
|
|
165331
165617
|
writeFileSync8(configPath, `${import_comment_json3.stringify(config2, null, 2)}
|
|
165332
165618
|
`);
|
|
165333
165619
|
log(`[magic-context] updated TUI plugin entry in ${configPath}`);
|
|
@@ -165438,34 +165724,20 @@ function loadConfigFile(configPath) {
|
|
|
165438
165724
|
return null;
|
|
165439
165725
|
}
|
|
165440
165726
|
}
|
|
165441
|
-
function
|
|
165442
|
-
const
|
|
165443
|
-
|
|
165444
|
-
|
|
165445
|
-
|
|
165446
|
-
|
|
165447
|
-
|
|
165448
|
-
|
|
165449
|
-
|
|
165450
|
-
|
|
165451
|
-
|
|
165452
|
-
dreamer: override.dreamer ? {
|
|
165453
|
-
...base.dreamer ?? {},
|
|
165454
|
-
...override.dreamer
|
|
165455
|
-
} : base.dreamer,
|
|
165456
|
-
sidekick: override.sidekick ? {
|
|
165457
|
-
...base.sidekick ?? {},
|
|
165458
|
-
...override.sidekick
|
|
165459
|
-
} : base.sidekick,
|
|
165460
|
-
disabled_hooks: [
|
|
165461
|
-
...new Set([...base.disabled_hooks ?? [], ...override.disabled_hooks ?? []])
|
|
165462
|
-
],
|
|
165463
|
-
command: {
|
|
165464
|
-
...base.command ?? {},
|
|
165465
|
-
...override.command ?? {}
|
|
165727
|
+
function deepMergeRawConfig(base, override) {
|
|
165728
|
+
const result = { ...base };
|
|
165729
|
+
for (const key of Object.keys(override)) {
|
|
165730
|
+
const baseVal = base[key];
|
|
165731
|
+
const overrideVal = override[key];
|
|
165732
|
+
if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
|
|
165733
|
+
result[key] = deepMergeRawConfig(baseVal, overrideVal);
|
|
165734
|
+
} else if (key === "disabled_hooks" && Array.isArray(baseVal) && Array.isArray(overrideVal)) {
|
|
165735
|
+
result[key] = [...new Set([...baseVal, ...overrideVal])];
|
|
165736
|
+
} else {
|
|
165737
|
+
result[key] = overrideVal;
|
|
165466
165738
|
}
|
|
165467
|
-
}
|
|
165468
|
-
return
|
|
165739
|
+
}
|
|
165740
|
+
return result;
|
|
165469
165741
|
}
|
|
165470
165742
|
function getProjectUserOnlyFields(config2) {
|
|
165471
165743
|
return "auto_update" in config2 ? ["auto_update"] : [];
|
|
@@ -165606,30 +165878,38 @@ function loadPluginConfig(directory) {
|
|
|
165606
165878
|
const projectDetected = rootDetected.format !== "none" ? rootDetected : dotOpenCodeDetected;
|
|
165607
165879
|
const userLoaded = userDetected.format === "none" ? null : loadConfigFile(userDetected.path);
|
|
165608
165880
|
const projectLoaded = projectDetected.format === "none" ? null : loadConfigFile(projectDetected.path);
|
|
165609
|
-
let config2 = parsePluginConfig({});
|
|
165610
165881
|
const allWarnings = [];
|
|
165882
|
+
let mergedRaw = {};
|
|
165611
165883
|
if (userLoaded) {
|
|
165612
165884
|
allWarnings.push(...userLoaded.warnings.map((w) => `[user config] ${w}`));
|
|
165613
|
-
|
|
165614
|
-
if (parsed.configWarnings?.length) {
|
|
165615
|
-
allWarnings.push(...parsed.configWarnings.map((w) => `[user config] ${w}`));
|
|
165616
|
-
}
|
|
165617
|
-
config2 = mergeConfigs(config2, parsed, { allowUserOnlyFields: true });
|
|
165885
|
+
mergedRaw = deepMergeRawConfig(mergedRaw, userLoaded.config);
|
|
165618
165886
|
}
|
|
165619
165887
|
if (projectLoaded) {
|
|
165620
165888
|
allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
|
|
165621
|
-
const
|
|
165622
|
-
|
|
165623
|
-
allWarnings.push(...parsed.configWarnings.map((w) => `[project config] ${w}`));
|
|
165624
|
-
}
|
|
165625
|
-
const strippedUserOnlyFields = getProjectUserOnlyFields(projectLoaded.config);
|
|
165889
|
+
const projectRaw = { ...projectLoaded.config };
|
|
165890
|
+
const strippedUserOnlyFields = getProjectUserOnlyFields(projectRaw);
|
|
165626
165891
|
if (strippedUserOnlyFields.length > 0) {
|
|
165892
|
+
for (const key of strippedUserOnlyFields) {
|
|
165893
|
+
delete projectRaw[key];
|
|
165894
|
+
}
|
|
165627
165895
|
allWarnings.push(`[project config] Ignoring ${strippedUserOnlyFields.join(", ")} from project config (security: these settings only honor user-level config)`);
|
|
165628
165896
|
}
|
|
165629
|
-
|
|
165897
|
+
mergedRaw = deepMergeRawConfig(mergedRaw, projectRaw);
|
|
165898
|
+
}
|
|
165899
|
+
const config2 = parsePluginConfig(mergedRaw);
|
|
165900
|
+
if (config2.configWarnings?.length) {
|
|
165901
|
+
allWarnings.push(...config2.configWarnings.map((w) => {
|
|
165902
|
+
if (userLoaded && projectLoaded)
|
|
165903
|
+
return `[config] ${w}`;
|
|
165904
|
+
if (userLoaded)
|
|
165905
|
+
return `[user config] ${w}`;
|
|
165906
|
+
return `[project config] ${w}`;
|
|
165907
|
+
}));
|
|
165630
165908
|
}
|
|
165631
165909
|
if (allWarnings.length > 0) {
|
|
165632
165910
|
config2.configWarnings = allWarnings;
|
|
165911
|
+
} else if ("configWarnings" in config2) {
|
|
165912
|
+
config2.configWarnings = undefined;
|
|
165633
165913
|
}
|
|
165634
165914
|
return config2;
|
|
165635
165915
|
}
|
|
@@ -166111,41 +166391,41 @@ init_tool_definition_tokens();
|
|
|
166111
166391
|
|
|
166112
166392
|
// src/hooks/auto-update-checker/index.ts
|
|
166113
166393
|
init_logger();
|
|
166114
|
-
import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync6, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
166115
|
-
import { dirname as
|
|
166394
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync6, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
166395
|
+
import { dirname as dirname5, join as join6 } from "node:path";
|
|
166116
166396
|
|
|
166117
166397
|
// src/hooks/auto-update-checker/cache.ts
|
|
166118
166398
|
init_logger();
|
|
166119
166399
|
var import_comment_json2 = __toESM(require_src2(), 1);
|
|
166120
166400
|
import { spawn } from "node:child_process";
|
|
166121
166401
|
import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
166122
|
-
import { basename, dirname as
|
|
166402
|
+
import { basename, dirname as dirname4, join as join5 } from "node:path";
|
|
166123
166403
|
|
|
166124
166404
|
// src/hooks/auto-update-checker/checker.ts
|
|
166125
166405
|
init_logger();
|
|
166126
166406
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
166127
166407
|
import { existsSync as existsSync4, readFileSync as readFileSync4, statSync, writeFileSync } from "node:fs";
|
|
166128
|
-
import { homedir as
|
|
166129
|
-
import { dirname as
|
|
166408
|
+
import { homedir as homedir5 } from "node:os";
|
|
166409
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
|
|
166130
166410
|
import { fileURLToPath } from "node:url";
|
|
166131
166411
|
|
|
166132
166412
|
// src/hooks/auto-update-checker/constants.ts
|
|
166133
|
-
import { homedir as
|
|
166413
|
+
import { homedir as homedir4, platform } from "node:os";
|
|
166134
166414
|
import { join as join3 } from "node:path";
|
|
166135
166415
|
var PACKAGE_NAME = "@cortexkit/opencode-magic-context";
|
|
166136
166416
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
166137
166417
|
var NPM_FETCH_TIMEOUT = 1e4;
|
|
166138
166418
|
function getOpenCodeCacheRoot() {
|
|
166139
166419
|
if (platform() === "win32") {
|
|
166140
|
-
return join3(process.env.LOCALAPPDATA ??
|
|
166420
|
+
return join3(process.env.LOCALAPPDATA ?? homedir4(), "opencode");
|
|
166141
166421
|
}
|
|
166142
|
-
return join3(
|
|
166422
|
+
return join3(homedir4(), ".cache", "opencode");
|
|
166143
166423
|
}
|
|
166144
166424
|
function getOpenCodeConfigRoot() {
|
|
166145
166425
|
if (platform() === "win32") {
|
|
166146
|
-
return join3(process.env.APPDATA ?? join3(
|
|
166426
|
+
return join3(process.env.APPDATA ?? join3(homedir4(), "AppData", "Roaming"), "opencode");
|
|
166147
166427
|
}
|
|
166148
|
-
return join3(process.env.XDG_CONFIG_HOME ?? join3(
|
|
166428
|
+
return join3(process.env.XDG_CONFIG_HOME ?? join3(homedir4(), ".config"), "opencode");
|
|
166149
166429
|
}
|
|
166150
166430
|
var CACHE_DIR = join3(getOpenCodeCacheRoot(), "packages");
|
|
166151
166431
|
var USER_OPENCODE_CONFIG = join3(getOpenCodeConfigRoot(), "opencode.json");
|
|
@@ -166227,12 +166507,12 @@ function resolvePathPluginSpec(spec, configPath) {
|
|
|
166227
166507
|
}
|
|
166228
166508
|
if (isAbsolute2(spec) || /^[A-Za-z]:[\\/]/.test(spec))
|
|
166229
166509
|
return spec;
|
|
166230
|
-
return resolve2(
|
|
166510
|
+
return resolve2(dirname3(configPath), spec);
|
|
166231
166511
|
}
|
|
166232
166512
|
function findPackageJsonUp(startPath) {
|
|
166233
166513
|
try {
|
|
166234
166514
|
const stat = statSync(startPath);
|
|
166235
|
-
let dir = stat.isDirectory() ? startPath :
|
|
166515
|
+
let dir = stat.isDirectory() ? startPath : dirname3(startPath);
|
|
166236
166516
|
for (let i = 0;i < 10; i++) {
|
|
166237
166517
|
const pkgPath = join4(dir, "package.json");
|
|
166238
166518
|
if (existsSync4(pkgPath)) {
|
|
@@ -166242,7 +166522,7 @@ function findPackageJsonUp(startPath) {
|
|
|
166242
166522
|
return pkgPath;
|
|
166243
166523
|
} catch {}
|
|
166244
166524
|
}
|
|
166245
|
-
const parent =
|
|
166525
|
+
const parent = dirname3(dir);
|
|
166246
166526
|
if (parent === dir)
|
|
166247
166527
|
break;
|
|
166248
166528
|
dir = parent;
|
|
@@ -166290,7 +166570,7 @@ function getLocalDevVersion(directory) {
|
|
|
166290
166570
|
}
|
|
166291
166571
|
function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
|
|
166292
166572
|
try {
|
|
166293
|
-
return findPackageJsonUp(
|
|
166573
|
+
return findPackageJsonUp(dirname3(fileURLToPath(currentModuleUrl)));
|
|
166294
166574
|
} catch (err) {
|
|
166295
166575
|
warn(`[auto-update-checker] Failed to resolve runtime package path: ${String(err)}`);
|
|
166296
166576
|
return null;
|
|
@@ -166333,7 +166613,7 @@ function getCachedVersion(spec) {
|
|
|
166333
166613
|
getCurrentRuntimePackageJsonPath(),
|
|
166334
166614
|
spec ? getSpecCachePackageJsonPath(spec) : null,
|
|
166335
166615
|
getSpecCachePackageJsonPath(`${PACKAGE_NAME}@latest`),
|
|
166336
|
-
join4(
|
|
166616
|
+
join4(homedir5(), ".cache", "opencode", "node_modules", PACKAGE_NAME, "package.json")
|
|
166337
166617
|
].filter(isString);
|
|
166338
166618
|
for (const packageJsonPath of candidates) {
|
|
166339
166619
|
try {
|
|
@@ -166387,7 +166667,7 @@ function stripPackageNameFromPath(pathValue, packageName) {
|
|
|
166387
166667
|
for (const segment of [...packageName.split("/")].reverse()) {
|
|
166388
166668
|
if (basename(current) !== segment)
|
|
166389
166669
|
return null;
|
|
166390
|
-
current =
|
|
166670
|
+
current = dirname4(current);
|
|
166391
166671
|
}
|
|
166392
166672
|
return current;
|
|
166393
166673
|
}
|
|
@@ -166450,19 +166730,19 @@ function removeInstalledPackage(installDir, packageName) {
|
|
|
166450
166730
|
}
|
|
166451
166731
|
function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
166452
166732
|
if (runtimePackageJsonPath) {
|
|
166453
|
-
const packageDir =
|
|
166733
|
+
const packageDir = dirname4(runtimePackageJsonPath);
|
|
166454
166734
|
const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
|
|
166455
166735
|
if (nodeModulesDir && basename(nodeModulesDir) === "node_modules") {
|
|
166456
|
-
const installDir =
|
|
166736
|
+
const installDir = dirname4(nodeModulesDir);
|
|
166457
166737
|
const packageJsonPath = join5(installDir, "package.json");
|
|
166458
166738
|
if (existsSync5(packageJsonPath))
|
|
166459
166739
|
return { installDir, packageJsonPath };
|
|
166460
166740
|
}
|
|
166461
166741
|
return null;
|
|
166462
166742
|
}
|
|
166463
|
-
const legacyPackageJsonPath = join5(
|
|
166743
|
+
const legacyPackageJsonPath = join5(dirname4(CACHE_DIR), "package.json");
|
|
166464
166744
|
if (existsSync5(legacyPackageJsonPath)) {
|
|
166465
|
-
return { installDir:
|
|
166745
|
+
return { installDir: dirname4(CACHE_DIR), packageJsonPath: legacyPackageJsonPath };
|
|
166466
166746
|
}
|
|
166467
166747
|
return null;
|
|
166468
166748
|
}
|
|
@@ -166591,7 +166871,7 @@ function claimCheckSlot(storageDir, intervalMs) {
|
|
|
166591
166871
|
}
|
|
166592
166872
|
} catch {}
|
|
166593
166873
|
}
|
|
166594
|
-
|
|
166874
|
+
mkdirSync2(dirname5(file2), { recursive: true });
|
|
166595
166875
|
const tmp = `${file2}.tmp.${process.pid}`;
|
|
166596
166876
|
writeFileSync3(tmp, JSON.stringify({ lastCheckedMs: Date.now() }), "utf-8");
|
|
166597
166877
|
renameSync(tmp, file2);
|
|
@@ -166689,8 +166969,10 @@ function createLiveSessionState() {
|
|
|
166689
166969
|
variantBySession: new Map,
|
|
166690
166970
|
agentBySession: new Map,
|
|
166691
166971
|
historyRefreshSessions: new Set,
|
|
166972
|
+
deferredHistoryRefreshSessions: new Set,
|
|
166692
166973
|
systemPromptRefreshSessions: new Set,
|
|
166693
166974
|
pendingMaterializationSessions: new Set,
|
|
166975
|
+
deferredMaterializationSessions: new Set,
|
|
166694
166976
|
sessionDirectoryBySession: new Map
|
|
166695
166977
|
};
|
|
166696
166978
|
}
|
|
@@ -166793,11 +167075,23 @@ function releaseLease(db, holderId) {
|
|
|
166793
167075
|
})();
|
|
166794
167076
|
}
|
|
166795
167077
|
// src/features/magic-context/dreamer/queue.ts
|
|
167078
|
+
function hasActiveDreamLease(db) {
|
|
167079
|
+
try {
|
|
167080
|
+
return isLeaseActive(db);
|
|
167081
|
+
} catch (error51) {
|
|
167082
|
+
if (String(error51).includes("no such table: dream_state")) {
|
|
167083
|
+
return false;
|
|
167084
|
+
}
|
|
167085
|
+
throw error51;
|
|
167086
|
+
}
|
|
167087
|
+
}
|
|
166796
167088
|
function enqueueDream(db, projectIdentity, reason, force = false) {
|
|
166797
167089
|
const now = Date.now();
|
|
166798
167090
|
return db.transaction(() => {
|
|
166799
|
-
|
|
166800
|
-
|
|
167091
|
+
if (!hasActiveDreamLease(db)) {
|
|
167092
|
+
const staleThresholdMs = force ? 2 * 60 * 1000 : 120 * 60 * 1000;
|
|
167093
|
+
db.prepare("DELETE FROM dream_queue WHERE project_path = ? AND started_at IS NOT NULL AND started_at < ?").run([projectIdentity, now - staleThresholdMs]);
|
|
167094
|
+
}
|
|
166801
167095
|
const existing = db.prepare("SELECT id FROM dream_queue WHERE project_path = ?").get(projectIdentity);
|
|
166802
167096
|
if (existing) {
|
|
166803
167097
|
return null;
|
|
@@ -166858,7 +167152,7 @@ init_data_path();
|
|
|
166858
167152
|
init_logger();
|
|
166859
167153
|
await init_sqlite();
|
|
166860
167154
|
import { existsSync as existsSync9 } from "node:fs";
|
|
166861
|
-
import { join as
|
|
167155
|
+
import { join as join12 } from "node:path";
|
|
166862
167156
|
|
|
166863
167157
|
// src/features/magic-context/key-files/identify-key-files.ts
|
|
166864
167158
|
init_logger();
|
|
@@ -167275,7 +167569,7 @@ function logWithStackHead(message, stackHead) {
|
|
|
167275
167569
|
log(message, stackHead ? { stackHead } : undefined);
|
|
167276
167570
|
}
|
|
167277
167571
|
function getOpenCodeDbPath2() {
|
|
167278
|
-
return
|
|
167572
|
+
return join12(getDataDir(), "opencode", "opencode.db");
|
|
167279
167573
|
}
|
|
167280
167574
|
function openOpenCodeDb() {
|
|
167281
167575
|
const dbPath = getOpenCodeDbPath2();
|
|
@@ -167350,9 +167644,11 @@ async function identifyKeyFilesForSession(args) {
|
|
|
167350
167644
|
try {
|
|
167351
167645
|
if (!renewLease(args.db, args.holderId)) {
|
|
167352
167646
|
log(`[key-files][${args.sessionId}] lease renewal failed — aborting`);
|
|
167647
|
+
args.onLeaseLost?.(`key-files:${args.sessionId}`);
|
|
167353
167648
|
abortController.abort();
|
|
167354
167649
|
}
|
|
167355
|
-
} catch {
|
|
167650
|
+
} catch (error51) {
|
|
167651
|
+
args.onLeaseLost?.(`key-files:${args.sessionId}`, error51);
|
|
167356
167652
|
abortController.abort();
|
|
167357
167653
|
}
|
|
167358
167654
|
}, 60000);
|
|
@@ -167407,6 +167703,10 @@ async function identifyKeyFilesForSession(args) {
|
|
|
167407
167703
|
log(`[key-files][${args.sessionId}] could not parse agent output — using heuristic fallback`);
|
|
167408
167704
|
applyHeuristicFallback();
|
|
167409
167705
|
} catch (error51) {
|
|
167706
|
+
if (args.isLeaseLost?.() || abortController.signal.aborted) {
|
|
167707
|
+
log(`[key-files][${args.sessionId}] lease lost during identification — skipping heuristic fallback`);
|
|
167708
|
+
throw error51;
|
|
167709
|
+
}
|
|
167410
167710
|
log(`[key-files][${args.sessionId}] identification failed: ${getErrorMessage(error51)} — using heuristic fallback`);
|
|
167411
167711
|
try {
|
|
167412
167712
|
applyHeuristicFallback();
|
|
@@ -167447,6 +167747,10 @@ async function identifyKeyFiles(args) {
|
|
|
167447
167747
|
}
|
|
167448
167748
|
log(`[key-files] evaluating ${sessionIds.length} active session(s) for ${args.projectIdentity}`);
|
|
167449
167749
|
for (const sessionId of sessionIds) {
|
|
167750
|
+
if (args.isLeaseLost?.()) {
|
|
167751
|
+
log("[key-files] lease lost — stopping key-file identification");
|
|
167752
|
+
break;
|
|
167753
|
+
}
|
|
167450
167754
|
if (Date.now() > args.deadline) {
|
|
167451
167755
|
log("[key-files] deadline reached — stopping key-file identification");
|
|
167452
167756
|
break;
|
|
@@ -167458,6 +167762,8 @@ async function identifyKeyFiles(args) {
|
|
|
167458
167762
|
sessionDirectory: args.sessionDirectory,
|
|
167459
167763
|
holderId: args.holderId,
|
|
167460
167764
|
fallbackModels: args.fallbackModels,
|
|
167765
|
+
onLeaseLost: args.onLeaseLost,
|
|
167766
|
+
isLeaseLost: args.isLeaseLost,
|
|
167461
167767
|
deadline: args.deadline,
|
|
167462
167768
|
sessionId,
|
|
167463
167769
|
config: args.config
|
|
@@ -167514,8 +167820,50 @@ async function runDream(args) {
|
|
|
167514
167820
|
let lastErrorSignature = null;
|
|
167515
167821
|
let consecutiveSameErrorFailures = 0;
|
|
167516
167822
|
let circuitBreakerTripped = false;
|
|
167823
|
+
let lostLease = false;
|
|
167824
|
+
let lostLeaseReason = null;
|
|
167825
|
+
let lostLeaseRecorded = false;
|
|
167826
|
+
const markLeaseLost = (phase, error51) => {
|
|
167827
|
+
const detail = error51 ? `: ${getErrorMessage(error51)}` : "";
|
|
167828
|
+
lostLeaseReason = `Dream lease lost during ${phase}${detail}`;
|
|
167829
|
+
if (!lostLease) {
|
|
167830
|
+
log(`[dreamer] FATAL: ${lostLeaseReason}; aborting all remaining dream work`);
|
|
167831
|
+
} else {
|
|
167832
|
+
log(`[dreamer] FATAL: ${lostLeaseReason}; dream work is already aborting`);
|
|
167833
|
+
}
|
|
167834
|
+
lostLease = true;
|
|
167835
|
+
};
|
|
167836
|
+
const recordLeaseLostTask = (phase) => {
|
|
167837
|
+
if (lostLeaseRecorded)
|
|
167838
|
+
return;
|
|
167839
|
+
lostLeaseRecorded = true;
|
|
167840
|
+
result.tasks.push({
|
|
167841
|
+
name: "lease-lost",
|
|
167842
|
+
durationMs: 0,
|
|
167843
|
+
result: "",
|
|
167844
|
+
error: lostLeaseReason ?? `Dream lease lost during ${phase}; aborted remaining work`
|
|
167845
|
+
});
|
|
167846
|
+
};
|
|
167847
|
+
const verifyLeaseStillHeld = (phase) => {
|
|
167848
|
+
if (lostLease)
|
|
167849
|
+
return false;
|
|
167850
|
+
try {
|
|
167851
|
+
if (!renewLease(args.db, holderId)) {
|
|
167852
|
+
markLeaseLost(phase);
|
|
167853
|
+
return false;
|
|
167854
|
+
}
|
|
167855
|
+
return true;
|
|
167856
|
+
} catch (error51) {
|
|
167857
|
+
markLeaseLost(phase, error51);
|
|
167858
|
+
return false;
|
|
167859
|
+
}
|
|
167860
|
+
};
|
|
167517
167861
|
try {
|
|
167518
167862
|
for (const taskName of args.tasks) {
|
|
167863
|
+
if (!verifyLeaseStillHeld(`before task ${taskName}`)) {
|
|
167864
|
+
recordLeaseLostTask(`before task ${taskName}`);
|
|
167865
|
+
break;
|
|
167866
|
+
}
|
|
167519
167867
|
if (Date.now() > deadline) {
|
|
167520
167868
|
log(`[dreamer] deadline reached, stopping after ${result.tasks.length} tasks`);
|
|
167521
167869
|
break;
|
|
@@ -167528,18 +167876,20 @@ async function runDream(args) {
|
|
|
167528
167876
|
try {
|
|
167529
167877
|
if (!renewLease(args.db, holderId)) {
|
|
167530
167878
|
log(`[dreamer] task ${taskName}: lease renewal failed — aborting LLM call`);
|
|
167879
|
+
markLeaseLost(`task ${taskName} lease renewal`);
|
|
167531
167880
|
taskAbortController.abort();
|
|
167532
167881
|
}
|
|
167533
167882
|
} catch (err) {
|
|
167534
167883
|
log(`[dreamer] task ${taskName}: lease renewal threw — aborting LLM call: ${err}`);
|
|
167884
|
+
markLeaseLost(`task ${taskName} lease renewal`, err);
|
|
167535
167885
|
taskAbortController.abort();
|
|
167536
167886
|
}
|
|
167537
167887
|
}, 60000);
|
|
167538
167888
|
try {
|
|
167539
167889
|
const docsDir = args.sessionDirectory ?? args.projectIdentity;
|
|
167540
167890
|
const existingDocs = taskName === "maintain-docs" ? {
|
|
167541
|
-
architecture: existsSync9(
|
|
167542
|
-
structure: existsSync9(
|
|
167891
|
+
architecture: existsSync9(join12(docsDir, "ARCHITECTURE.md")),
|
|
167892
|
+
structure: existsSync9(join12(docsDir, "STRUCTURE.md"))
|
|
167543
167893
|
} : undefined;
|
|
167544
167894
|
const userMemories = taskName === "archive-stale" ? getActiveUserMemories(args.db).map((um) => ({
|
|
167545
167895
|
id: um.id,
|
|
@@ -167578,6 +167928,9 @@ async function runDream(args) {
|
|
|
167578
167928
|
fallbackModels: args.fallbackModels,
|
|
167579
167929
|
callContext: `dreamer:${taskName}`
|
|
167580
167930
|
});
|
|
167931
|
+
if (lostLease) {
|
|
167932
|
+
throw new Error(lostLeaseReason ?? `Dream lease lost during ${taskName}`);
|
|
167933
|
+
}
|
|
167581
167934
|
const messagesResponse = await args.client.session.messages({
|
|
167582
167935
|
path: { id: agentSessionId },
|
|
167583
167936
|
query: { directory: args.sessionDirectory ?? args.projectIdentity }
|
|
@@ -167608,7 +167961,10 @@ async function runDream(args) {
|
|
|
167608
167961
|
result: null,
|
|
167609
167962
|
error: errorDescription.brief
|
|
167610
167963
|
});
|
|
167611
|
-
if (
|
|
167964
|
+
if (lostLease) {
|
|
167965
|
+
lastErrorSignature = null;
|
|
167966
|
+
consecutiveSameErrorFailures = 0;
|
|
167967
|
+
} else if (shouldSkipCircuitBreaker(error51, errorDescription.brief)) {
|
|
167612
167968
|
lastErrorSignature = null;
|
|
167613
167969
|
consecutiveSameErrorFailures = 0;
|
|
167614
167970
|
} else {
|
|
@@ -167641,11 +167997,18 @@ async function runDream(args) {
|
|
|
167641
167997
|
});
|
|
167642
167998
|
}
|
|
167643
167999
|
}
|
|
168000
|
+
if (lostLease) {
|
|
168001
|
+
recordLeaseLostTask(`task ${taskName}`);
|
|
168002
|
+
break;
|
|
168003
|
+
}
|
|
167644
168004
|
if (circuitBreakerTripped) {
|
|
167645
168005
|
break;
|
|
167646
168006
|
}
|
|
167647
168007
|
}
|
|
167648
|
-
if (
|
|
168008
|
+
if (lostLease) {
|
|
168009
|
+
log("[dreamer] lease lost: skipping all post-task phases");
|
|
168010
|
+
recordLeaseLostTask("post-task phases");
|
|
168011
|
+
} else if (circuitBreakerTripped) {
|
|
167649
168012
|
log("[dreamer] circuit breaker: skipping post-task phases");
|
|
167650
168013
|
result.tasks.push({
|
|
167651
168014
|
name: "post-task-phases",
|
|
@@ -167654,9 +168017,12 @@ async function runDream(args) {
|
|
|
167654
168017
|
error: "Skipped post-task phases after circuit breaker tripped; configure dreamer model/fallback_models in magic-context.jsonc."
|
|
167655
168018
|
});
|
|
167656
168019
|
}
|
|
167657
|
-
if (!circuitBreakerTripped && args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
|
|
168020
|
+
if (!circuitBreakerTripped && !lostLease && args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
|
|
167658
168021
|
const umStart = Date.now();
|
|
167659
168022
|
try {
|
|
168023
|
+
if (!verifyLeaseStillHeld("before user-memory review")) {
|
|
168024
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost before user-memory review");
|
|
168025
|
+
}
|
|
167660
168026
|
const reviewResult = await reviewUserMemories({
|
|
167661
168027
|
db: args.db,
|
|
167662
168028
|
client: args.client,
|
|
@@ -167667,6 +168033,9 @@ async function runDream(args) {
|
|
|
167667
168033
|
promotionThreshold: args.experimentalUserMemories.promotionThreshold,
|
|
167668
168034
|
fallbackModels: args.fallbackModels
|
|
167669
168035
|
});
|
|
168036
|
+
if (!verifyLeaseStillHeld("after user-memory review")) {
|
|
168037
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost after user-memory review");
|
|
168038
|
+
}
|
|
167670
168039
|
const umOutput = `promoted=${reviewResult.promoted} merged=${reviewResult.merged} dismissed=${reviewResult.dismissed} consumed=${reviewResult.candidatesConsumed}`;
|
|
167671
168040
|
if (reviewResult.promoted > 0 || reviewResult.merged > 0 || reviewResult.dismissed > 0) {
|
|
167672
168041
|
log(`[dreamer] user-memories: ${umOutput}`);
|
|
@@ -167686,9 +168055,14 @@ async function runDream(args) {
|
|
|
167686
168055
|
error: errorDescription.brief
|
|
167687
168056
|
});
|
|
167688
168057
|
}
|
|
168058
|
+
if (lostLease)
|
|
168059
|
+
recordLeaseLostTask("user-memory review");
|
|
167689
168060
|
}
|
|
167690
|
-
if (!circuitBreakerTripped && Date.now() <= deadline) {
|
|
168061
|
+
if (!circuitBreakerTripped && !lostLease && Date.now() <= deadline) {
|
|
167691
168062
|
try {
|
|
168063
|
+
if (!verifyLeaseStillHeld("before smart-note evaluation")) {
|
|
168064
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost before smart-note evaluation");
|
|
168065
|
+
}
|
|
167692
168066
|
await evaluateSmartNotes({
|
|
167693
168067
|
db: args.db,
|
|
167694
168068
|
client: args.client,
|
|
@@ -167698,16 +168072,26 @@ async function runDream(args) {
|
|
|
167698
168072
|
holderId,
|
|
167699
168073
|
deadline,
|
|
167700
168074
|
result,
|
|
167701
|
-
fallbackModels: args.fallbackModels
|
|
168075
|
+
fallbackModels: args.fallbackModels,
|
|
168076
|
+
onLeaseLost: markLeaseLost,
|
|
168077
|
+
isLeaseLost: () => lostLease
|
|
167702
168078
|
});
|
|
168079
|
+
if (!verifyLeaseStillHeld("after smart-note evaluation")) {
|
|
168080
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost after smart-note evaluation");
|
|
168081
|
+
}
|
|
167703
168082
|
} catch (error51) {
|
|
167704
168083
|
const errorDescription = describeError(error51);
|
|
167705
168084
|
logWithStackHead(`[dreamer] smart note evaluation failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167706
168085
|
}
|
|
168086
|
+
if (lostLease)
|
|
168087
|
+
recordLeaseLostTask("smart-note evaluation");
|
|
167707
168088
|
}
|
|
167708
|
-
if (!circuitBreakerTripped && args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
|
|
168089
|
+
if (!circuitBreakerTripped && !lostLease && args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
|
|
167709
168090
|
const kfStart = Date.now();
|
|
167710
168091
|
try {
|
|
168092
|
+
if (!verifyLeaseStillHeld("before key-file identification")) {
|
|
168093
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost before key-file identification");
|
|
168094
|
+
}
|
|
167711
168095
|
await identifyKeyFiles({
|
|
167712
168096
|
db: args.db,
|
|
167713
168097
|
client: args.client,
|
|
@@ -167717,8 +168101,13 @@ async function runDream(args) {
|
|
|
167717
168101
|
holderId,
|
|
167718
168102
|
deadline,
|
|
167719
168103
|
config: args.experimentalPinKeyFiles,
|
|
167720
|
-
fallbackModels: args.fallbackModels
|
|
168104
|
+
fallbackModels: args.fallbackModels,
|
|
168105
|
+
onLeaseLost: markLeaseLost,
|
|
168106
|
+
isLeaseLost: () => lostLease
|
|
167721
168107
|
});
|
|
168108
|
+
if (!verifyLeaseStillHeld("after key-file identification")) {
|
|
168109
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost after key-file identification");
|
|
168110
|
+
}
|
|
167722
168111
|
result.tasks.push({
|
|
167723
168112
|
name: "key files",
|
|
167724
168113
|
durationMs: Date.now() - kfStart,
|
|
@@ -167734,6 +168123,8 @@ async function runDream(args) {
|
|
|
167734
168123
|
error: errorDescription.brief
|
|
167735
168124
|
});
|
|
167736
168125
|
}
|
|
168126
|
+
if (lostLease)
|
|
168127
|
+
recordLeaseLostTask("key-file identification");
|
|
167737
168128
|
}
|
|
167738
168129
|
} finally {
|
|
167739
168130
|
releaseLease(args.db, holderId);
|
|
@@ -167774,7 +168165,7 @@ async function runDream(args) {
|
|
|
167774
168165
|
"circuit-breaker"
|
|
167775
168166
|
]);
|
|
167776
168167
|
const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
|
|
167777
|
-
if (hasSuccessfulTask) {
|
|
168168
|
+
if (hasSuccessfulTask && !lostLease) {
|
|
167778
168169
|
setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
|
|
167779
168170
|
setDreamState(args.db, "last_dream_at", String(result.finishedAt));
|
|
167780
168171
|
}
|
|
@@ -167823,9 +168214,11 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
|
|
|
167823
168214
|
try {
|
|
167824
168215
|
if (!renewLease(args.db, args.holderId)) {
|
|
167825
168216
|
log("[dreamer] smart notes: lease renewal failed — aborting");
|
|
168217
|
+
args.onLeaseLost?.("smart notes");
|
|
167826
168218
|
abortController.abort();
|
|
167827
168219
|
}
|
|
167828
|
-
} catch {
|
|
168220
|
+
} catch (error51) {
|
|
168221
|
+
args.onLeaseLost?.("smart notes", error51);
|
|
167829
168222
|
abortController.abort();
|
|
167830
168223
|
}
|
|
167831
168224
|
}, 60000);
|
|
@@ -170073,6 +170466,15 @@ init_project_identity();
|
|
|
170073
170466
|
init_logger();
|
|
170074
170467
|
await init_storage();
|
|
170075
170468
|
|
|
170469
|
+
// src/hooks/magic-context/cache-busting-signals.ts
|
|
170470
|
+
function canConsumeDeferredOnThisPass(args) {
|
|
170471
|
+
if (args.justAwaitedPublication)
|
|
170472
|
+
return true;
|
|
170473
|
+
if (args.activeRunBlocksMaterialization)
|
|
170474
|
+
return false;
|
|
170475
|
+
return args.schedulerDecision === "execute" || args.contextPercentage >= FORCE_MATERIALIZE_PERCENTAGE;
|
|
170476
|
+
}
|
|
170477
|
+
|
|
170076
170478
|
// src/hooks/magic-context/caveman-cleanup.ts
|
|
170077
170479
|
init_shared();
|
|
170078
170480
|
init_caveman();
|
|
@@ -170820,6 +171222,9 @@ function clearCompressorCooldown(sessionId) {
|
|
|
170820
171222
|
async function runCompartmentPhase(args) {
|
|
170821
171223
|
let pendingCompartmentInjection = args.pendingCompartmentInjection;
|
|
170822
171224
|
let compartmentInProgress = args.sessionMeta.compartmentInProgress;
|
|
171225
|
+
let published = false;
|
|
171226
|
+
let justAwaitedPublication = false;
|
|
171227
|
+
let rebuiltHistoryThisPass = false;
|
|
170823
171228
|
let lastCompartmentEnd = null;
|
|
170824
171229
|
let rawMessageCount = null;
|
|
170825
171230
|
let cachedProtectedTailStart = null;
|
|
@@ -170847,13 +171252,19 @@ async function runCompartmentPhase(args) {
|
|
|
170847
171252
|
sessionLog(args.sessionId, reason);
|
|
170848
171253
|
const timeoutMs = args.historianTimeoutMs ?? 120000;
|
|
170849
171254
|
const timeout = new Promise((resolve4) => setTimeout(() => resolve4("timeout"), timeoutMs));
|
|
170850
|
-
const result = await Promise.race([activeRun.then(() => "done"), timeout]);
|
|
171255
|
+
const result = await Promise.race([activeRun.promise.then(() => "done"), timeout]);
|
|
170851
171256
|
if (result === "timeout") {
|
|
170852
171257
|
sessionLog(args.sessionId, `transform: compartment await timed out after ${timeoutMs}ms — proceeding without waiting`);
|
|
170853
171258
|
return "timed_out";
|
|
170854
171259
|
}
|
|
170855
171260
|
sessionLog(args.sessionId, "transform: compartment agent completed, refreshing compartment coverage");
|
|
170856
|
-
|
|
171261
|
+
justAwaitedPublication = activeRun.published;
|
|
171262
|
+
published = published || activeRun.published;
|
|
171263
|
+
const historyReprepareShouldBust = activeRun.published && args.deferredHistoryRefreshSessions.has(args.sessionId);
|
|
171264
|
+
pendingCompartmentInjection = prepareCompartmentInjection(args.db, args.resolvedSessionId, args.messages, historyReprepareShouldBust, args.projectPath, args.injectionBudgetTokens, args.experimentalTemporalAwareness);
|
|
171265
|
+
if (historyReprepareShouldBust) {
|
|
171266
|
+
rebuiltHistoryThisPass = true;
|
|
171267
|
+
}
|
|
170857
171268
|
return "completed";
|
|
170858
171269
|
}
|
|
170859
171270
|
if (args.canRunCompartments && args.sessionMeta.compartmentInProgress && !getActiveCompartmentRun(args.sessionId)) {
|
|
@@ -170885,7 +171296,8 @@ async function runCompartmentPhase(args) {
|
|
|
170885
171296
|
compressorMaxMergeDepth: args.compressorMaxMergeDepth,
|
|
170886
171297
|
memoryEnabled: args.memoryEnabled,
|
|
170887
171298
|
autoPromote: args.autoPromote,
|
|
170888
|
-
|
|
171299
|
+
onCompartmentStatePublished: args.onCompartmentStatePublished,
|
|
171300
|
+
preserveInjectionCacheUntilConsumed: true
|
|
170889
171301
|
});
|
|
170890
171302
|
compartmentInProgress = true;
|
|
170891
171303
|
}
|
|
@@ -170913,7 +171325,8 @@ async function runCompartmentPhase(args) {
|
|
|
170913
171325
|
compressorMaxMergeDepth: args.compressorMaxMergeDepth,
|
|
170914
171326
|
memoryEnabled: args.memoryEnabled,
|
|
170915
171327
|
autoPromote: args.autoPromote,
|
|
170916
|
-
|
|
171328
|
+
onCompartmentStatePublished: args.onCompartmentStatePublished,
|
|
171329
|
+
preserveInjectionCacheUntilConsumed: true
|
|
170917
171330
|
});
|
|
170918
171331
|
activeRun = getActiveCompartmentRun(args.sessionId);
|
|
170919
171332
|
} else if (!activeRun && hasEligibleHistoryForCompartment()) {
|
|
@@ -170933,7 +171346,7 @@ async function runCompartmentPhase(args) {
|
|
|
170933
171346
|
}
|
|
170934
171347
|
}
|
|
170935
171348
|
}
|
|
170936
|
-
if (args.
|
|
171349
|
+
if (args.safeForBackgroundCompression && !args.suppressBackgroundCompressionThisPass && args.historyBudgetTokens && args.historyBudgetTokens > 0 && args.client && !compartmentInProgress && !awaitedCompartmentRun && !isCompressorOnCooldown(args.sessionId, args.compressorCooldownMs ?? DEFAULT_COMPRESSOR_COOLDOWN_MS)) {
|
|
170937
171350
|
markCompressorRun(args.sessionId);
|
|
170938
171351
|
const compressorPromise = runCompressionPassIfNeeded({
|
|
170939
171352
|
client: args.client,
|
|
@@ -170947,6 +171360,9 @@ async function runCompartmentPhase(args) {
|
|
|
170947
171360
|
maxMergeDepth: args.compressorMaxMergeDepth
|
|
170948
171361
|
}).then((compressed) => {
|
|
170949
171362
|
if (compressed) {
|
|
171363
|
+
markActiveCompartmentRunPublished(args.sessionId);
|
|
171364
|
+
published = true;
|
|
171365
|
+
args.deferredHistoryRefreshSessions.add(args.sessionId);
|
|
170950
171366
|
sessionLog(args.sessionId, "independent compressor completed in background — compressed history will appear on next cache-busting pass");
|
|
170951
171367
|
}
|
|
170952
171368
|
}).catch((error51) => {
|
|
@@ -170954,7 +171370,14 @@ async function runCompartmentPhase(args) {
|
|
|
170954
171370
|
});
|
|
170955
171371
|
registerActiveCompartmentRun(args.sessionId, compressorPromise);
|
|
170956
171372
|
}
|
|
170957
|
-
return {
|
|
171373
|
+
return {
|
|
171374
|
+
pendingCompartmentInjection,
|
|
171375
|
+
awaitedCompartmentRun,
|
|
171376
|
+
compartmentInProgress,
|
|
171377
|
+
published,
|
|
171378
|
+
justAwaitedPublication,
|
|
171379
|
+
rebuiltHistoryThisPass
|
|
171380
|
+
};
|
|
170958
171381
|
}
|
|
170959
171382
|
|
|
170960
171383
|
// src/hooks/magic-context/transform-context-state.ts
|
|
@@ -172316,7 +172739,10 @@ function clearAutoSearchForSession(sessionId) {
|
|
|
172316
172739
|
}
|
|
172317
172740
|
|
|
172318
172741
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
172319
|
-
await
|
|
172742
|
+
await __promiseAll([
|
|
172743
|
+
init_compaction_marker_manager(),
|
|
172744
|
+
init_compartment_runner()
|
|
172745
|
+
]);
|
|
172320
172746
|
|
|
172321
172747
|
// src/hooks/magic-context/heuristic-cleanup.ts
|
|
172322
172748
|
init_shared();
|
|
@@ -172590,7 +173016,7 @@ function isVisibleNoteReadPart(part) {
|
|
|
172590
173016
|
}
|
|
172591
173017
|
|
|
172592
173018
|
// src/hooks/magic-context/todo-view.ts
|
|
172593
|
-
import { createHash as
|
|
173019
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
172594
173020
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
172595
173021
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
172596
173022
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -172635,7 +173061,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
172635
173061
|
};
|
|
172636
173062
|
}
|
|
172637
173063
|
function computeSyntheticCallId(stateJson) {
|
|
172638
|
-
const hash2 =
|
|
173064
|
+
const hash2 = createHash5("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
172639
173065
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
172640
173066
|
}
|
|
172641
173067
|
function parseTodoState(stateJson) {
|
|
@@ -172676,26 +173102,34 @@ function logTransformTiming(sessionId, stage, startMs, extra) {
|
|
|
172676
173102
|
}
|
|
172677
173103
|
|
|
172678
173104
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
173105
|
+
var DEGRADE_CACHE_WARNING_THRESHOLD = 10;
|
|
173106
|
+
var degradedCacheCountBySession = new Map;
|
|
173107
|
+
function resetDegradedCacheCount(sessionId) {
|
|
173108
|
+
degradedCacheCountBySession.delete(sessionId);
|
|
173109
|
+
}
|
|
172679
173110
|
async function runPostTransformPhase(args) {
|
|
172680
173111
|
let didMutateFromPendingOperations = false;
|
|
172681
173112
|
const isExplicitFlush = args.pendingMaterializationSessions.has(args.sessionId);
|
|
173113
|
+
const deferredMaterializationWasPending = args.deferredMaterializationSessions.has(args.sessionId);
|
|
172682
173114
|
const alreadyRanThisTurn = args.currentTurnId !== null && args.lastHeuristicsTurnId.get(args.sessionId) === args.currentTurnId;
|
|
172683
173115
|
const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
|
|
172684
173116
|
const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
|
|
172685
173117
|
const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
|
|
172686
173118
|
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
172687
|
-
const
|
|
173119
|
+
const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
173120
|
+
const materializationRequested = isExplicitFlush || deferredMaterialize;
|
|
173121
|
+
const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || compartmentRunning;
|
|
172688
173122
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
172689
173123
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
172690
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" ||
|
|
172691
|
-
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (
|
|
173124
|
+
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
173125
|
+
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
172692
173126
|
const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
|
|
172693
173127
|
if (shouldRunHeuristics) {
|
|
172694
173128
|
const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
|
|
172695
|
-
const reason = isExplicitFlush ? "explicit_flush" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
173129
|
+
const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
172696
173130
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
172697
173131
|
}
|
|
172698
|
-
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !
|
|
173132
|
+
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
|
|
172699
173133
|
sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
|
|
172700
173134
|
}
|
|
172701
173135
|
if (compartmentRunning && hasPendingUserOps) {
|
|
@@ -172705,9 +173139,11 @@ async function runPostTransformPhase(args) {
|
|
|
172705
173139
|
sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
|
|
172706
173140
|
}
|
|
172707
173141
|
}
|
|
173142
|
+
let explicitMaterializedSuccessfully = false;
|
|
173143
|
+
let deferredMaterializedSuccessfully = false;
|
|
172708
173144
|
try {
|
|
172709
173145
|
if (shouldApplyPendingOps) {
|
|
172710
|
-
const applyReason = isExplicitFlush ? "explicit_flush" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
173146
|
+
const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
172711
173147
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
172712
173148
|
const pendingCountBefore = pendingOps.length;
|
|
172713
173149
|
const tApply = performance.now();
|
|
@@ -172769,7 +173205,7 @@ async function runPostTransformPhase(args) {
|
|
|
172769
173205
|
args.lastHeuristicsTurnId.set(args.sessionId, args.currentTurnId);
|
|
172770
173206
|
}
|
|
172771
173207
|
}
|
|
172772
|
-
if (args.schedulerDecision === "execute" && !
|
|
173208
|
+
if (args.schedulerDecision === "execute" && !materializationRequested) {
|
|
172773
173209
|
updateSessionMeta(args.db, args.sessionId, { lastResponseTime: Date.now() });
|
|
172774
173210
|
}
|
|
172775
173211
|
args.batch?.finalize();
|
|
@@ -172777,6 +173213,12 @@ async function runPostTransformPhase(args) {
|
|
|
172777
173213
|
if (args.sessionMeta.lastTransformError !== null) {
|
|
172778
173214
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: null });
|
|
172779
173215
|
}
|
|
173216
|
+
if (shouldRunHeuristics) {
|
|
173217
|
+
if (isExplicitFlush)
|
|
173218
|
+
explicitMaterializedSuccessfully = true;
|
|
173219
|
+
if (deferredMaterialize)
|
|
173220
|
+
deferredMaterializedSuccessfully = true;
|
|
173221
|
+
}
|
|
172780
173222
|
} catch (error51) {
|
|
172781
173223
|
sessionLog(args.sessionId, "transform failed applying pending operations:", error51);
|
|
172782
173224
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error51) });
|
|
@@ -172935,6 +173377,45 @@ async function runPostTransformPhase(args) {
|
|
|
172935
173377
|
}
|
|
172936
173378
|
}
|
|
172937
173379
|
}
|
|
173380
|
+
const explicitRebuildHappened = args.historyRefreshExplicitBeforePrepare && args.rebuiltHistoryFromInitialPrepare;
|
|
173381
|
+
const materializationSatisfied = !deferredMaterializationWasPending || explicitMaterializedSuccessfully || deferredMaterializedSuccessfully;
|
|
173382
|
+
const historyWasConsumedThisPass = args.historyRebuiltThisPass && (args.canConsumeDeferredLate || args.phaseJustAwaitedPublication || explicitRebuildHappened) && materializationSatisfied;
|
|
173383
|
+
if (args.compartmentInjectionRebuiltFromDb && args.pendingCompartmentInjection) {
|
|
173384
|
+
if (args.pendingCompartmentInjection.compartmentEndMessageId === null) {
|
|
173385
|
+
const nextCount = (degradedCacheCountBySession.get(args.sessionId) ?? 0) + 1;
|
|
173386
|
+
degradedCacheCountBySession.set(args.sessionId, nextCount);
|
|
173387
|
+
if (nextCount === DEGRADE_CACHE_WARNING_THRESHOLD) {
|
|
173388
|
+
sessionLog(args.sessionId, `WARNING: compartment injection cache has rebuilt with a degraded null boundary ${nextCount} consecutive times; investigate missing boundary messages`);
|
|
173389
|
+
}
|
|
173390
|
+
} else {
|
|
173391
|
+
degradedCacheCountBySession.delete(args.sessionId);
|
|
173392
|
+
}
|
|
173393
|
+
}
|
|
173394
|
+
let suppressV12HistoryDrain = false;
|
|
173395
|
+
if (historyWasConsumedThisPass && args.deferredHistoryRefreshSessions.has(args.sessionId)) {
|
|
173396
|
+
const pending = getPendingCompactionMarkerState(args.db, args.sessionId);
|
|
173397
|
+
if (pending) {
|
|
173398
|
+
const outcome = applyDeferredCompactionMarker(args.db, args.sessionId, pending, args.sessionDirectory);
|
|
173399
|
+
switch (outcome.kind) {
|
|
173400
|
+
case "applied":
|
|
173401
|
+
case "already-current":
|
|
173402
|
+
case "stale-skip":
|
|
173403
|
+
clearPendingCompactionMarkerStateIf(args.db, args.sessionId, pending);
|
|
173404
|
+
break;
|
|
173405
|
+
case "retryable-failure":
|
|
173406
|
+
sessionLog(args.sessionId, "compaction-marker drain: retryable failure; preserving deferred history refresh signal", outcome.error);
|
|
173407
|
+
suppressV12HistoryDrain = true;
|
|
173408
|
+
break;
|
|
173409
|
+
}
|
|
173410
|
+
}
|
|
173411
|
+
}
|
|
173412
|
+
const deferredHistoryDrainEligible = historyWasConsumedThisPass && !suppressV12HistoryDrain;
|
|
173413
|
+
if (deferredHistoryDrainEligible) {
|
|
173414
|
+
args.deferredHistoryRefreshSessions.delete(args.sessionId);
|
|
173415
|
+
}
|
|
173416
|
+
if (explicitMaterializedSuccessfully || deferredMaterializedSuccessfully) {
|
|
173417
|
+
args.deferredMaterializationSessions.delete(args.sessionId);
|
|
173418
|
+
}
|
|
172938
173419
|
if (args.fullFeatureMode && args.autoSearch?.enabled && args.projectPath) {
|
|
172939
173420
|
const visibleMemoryIds = getVisibleMemoryIds(args.db, args.sessionId) ?? undefined;
|
|
172940
173421
|
try {
|
|
@@ -172957,6 +173438,7 @@ async function runPostTransformPhase(args) {
|
|
|
172957
173438
|
sessionLog(args.sessionId, "auto-search runner failed:", error51);
|
|
172958
173439
|
}
|
|
172959
173440
|
}
|
|
173441
|
+
return { explicitMaterializedSuccessfully, deferredMaterializedSuccessfully };
|
|
172960
173442
|
}
|
|
172961
173443
|
|
|
172962
173444
|
// src/hooks/magic-context/nudge-placement-store.ts
|
|
@@ -173030,6 +173512,8 @@ function findLastAssistantModel(messages) {
|
|
|
173030
173512
|
function createTransform(deps) {
|
|
173031
173513
|
const loadedSessions = new Set;
|
|
173032
173514
|
const lastEmergencyNotificationCount = new Map;
|
|
173515
|
+
const deferredHistoryRefreshSessions = deps.deferredHistoryRefreshSessions ?? new Set;
|
|
173516
|
+
const deferredMaterializationSessions = deps.deferredMaterializationSessions ?? new Set;
|
|
173033
173517
|
return async (_input, output) => {
|
|
173034
173518
|
const startTime = performance.now();
|
|
173035
173519
|
const messages = output.messages;
|
|
@@ -173138,7 +173622,17 @@ function createTransform(deps) {
|
|
|
173138
173622
|
}
|
|
173139
173623
|
const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens);
|
|
173140
173624
|
const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId));
|
|
173141
|
-
const
|
|
173625
|
+
const historyRefreshExplicitBeforePrepare = deps.historyRefreshSessions.has(sessionId);
|
|
173626
|
+
const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
|
|
173627
|
+
const canConsumeDeferredEarly = canConsumeDeferredOnThisPass({
|
|
173628
|
+
schedulerDecision: schedulerDecisionEarly,
|
|
173629
|
+
contextPercentage: contextUsageEarly.percentage,
|
|
173630
|
+
justAwaitedPublication: false,
|
|
173631
|
+
activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization
|
|
173632
|
+
});
|
|
173633
|
+
const consumingDeferredEarly = canConsumeDeferredEarly && deferredHistoryRefreshSessions.has(sessionId);
|
|
173634
|
+
const isCacheBusting = historyRefreshExplicitBeforePrepare || consumingDeferredEarly;
|
|
173635
|
+
const historyBustThisPass = isCacheBusting;
|
|
173142
173636
|
if (historianFailureState.failureCount === 0) {
|
|
173143
173637
|
lastEmergencyNotificationCount.delete(sessionId);
|
|
173144
173638
|
}
|
|
@@ -173178,9 +173672,10 @@ function createTransform(deps) {
|
|
|
173178
173672
|
compressorMaxMergeDepth: deps.compressorMaxMergeDepth,
|
|
173179
173673
|
memoryEnabled: deps.memoryConfig?.enabled,
|
|
173180
173674
|
autoPromote: deps.memoryConfig?.autoPromote,
|
|
173181
|
-
|
|
173182
|
-
|
|
173183
|
-
|
|
173675
|
+
preserveInjectionCacheUntilConsumed: true,
|
|
173676
|
+
onCompartmentStatePublished: (sid) => {
|
|
173677
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
173678
|
+
deferredMaterializationSessions.add(sid);
|
|
173184
173679
|
}
|
|
173185
173680
|
});
|
|
173186
173681
|
skipCompartmentAwaitForThisPass = true;
|
|
@@ -173213,11 +173708,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
173213
173708
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
173214
173709
|
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(compartmentDirectory || process.cwd()) : undefined;
|
|
173215
173710
|
let pendingCompartmentInjection = null;
|
|
173711
|
+
let rebuiltHistoryFromInitialPrepare = false;
|
|
173216
173712
|
if (fullFeatureMode) {
|
|
173217
173713
|
const tInj = performance.now();
|
|
173218
173714
|
pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
|
|
173219
173715
|
logTransformTiming(sessionId, "prepareCompartmentInjection", tInj);
|
|
173220
173716
|
if (isCacheBusting) {
|
|
173717
|
+
rebuiltHistoryFromInitialPrepare = true;
|
|
173718
|
+
}
|
|
173719
|
+
if (historyRefreshExplicitBeforePrepare) {
|
|
173221
173720
|
deps.historyRefreshSessions.delete(sessionId);
|
|
173222
173721
|
}
|
|
173223
173722
|
}
|
|
@@ -173344,7 +173843,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
173344
173843
|
projectPath: projectIdentity,
|
|
173345
173844
|
injectionBudgetTokens: deps.memoryConfig?.injectionBudgetTokens,
|
|
173346
173845
|
getNotificationParams: rawGetNotifParams ? () => rawGetNotifParams(sessionId) : undefined,
|
|
173347
|
-
|
|
173846
|
+
safeForBackgroundCompression: isCacheBusting || schedulerDecisionEarly === "execute",
|
|
173847
|
+
suppressBackgroundCompressionThisPass: historyBustThisPass,
|
|
173848
|
+
deferredHistoryRefreshSessions,
|
|
173348
173849
|
skipAwaitForThisPass: skipCompartmentAwaitForThisPass,
|
|
173349
173850
|
experimentalCompactionMarkers: deps.experimentalCompactionMarkers,
|
|
173350
173851
|
experimentalUserMemories: deps.experimentalUserMemories,
|
|
@@ -173355,9 +173856,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
173355
173856
|
compressorCooldownMs: deps.compressorCooldownMs,
|
|
173356
173857
|
memoryEnabled: deps.memoryConfig?.enabled,
|
|
173357
173858
|
autoPromote: deps.memoryConfig?.autoPromote,
|
|
173358
|
-
|
|
173359
|
-
|
|
173360
|
-
|
|
173859
|
+
onCompartmentStatePublished: (sid) => {
|
|
173860
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
173861
|
+
deferredMaterializationSessions.add(sid);
|
|
173361
173862
|
}
|
|
173362
173863
|
});
|
|
173363
173864
|
pendingCompartmentInjection = compartmentPhase.pendingCompartmentInjection;
|
|
@@ -173365,6 +173866,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
173365
173866
|
const compartmentInProgress = compartmentPhase.compartmentInProgress;
|
|
173366
173867
|
sessionMeta = { ...sessionMeta, compartmentInProgress };
|
|
173367
173868
|
logTransformTiming(sessionId, "compartmentPhase", tCompartmentPhase);
|
|
173869
|
+
const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
|
|
173870
|
+
const canConsumeDeferredLate = canConsumeDeferredOnThisPass({
|
|
173871
|
+
schedulerDecision: schedulerDecisionEarly,
|
|
173872
|
+
contextPercentage: contextUsageEarly.percentage,
|
|
173873
|
+
justAwaitedPublication: compartmentPhase.justAwaitedPublication,
|
|
173874
|
+
activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization
|
|
173875
|
+
});
|
|
173876
|
+
const wasEmergencyBlock = contextUsageEarly.percentage >= FORCE_MATERIALIZE_PERCENTAGE && compartmentPhase.justAwaitedPublication;
|
|
173877
|
+
const historyRebuiltThisPass = wasEmergencyBlock ? compartmentPhase.rebuiltHistoryThisPass : rebuiltHistoryFromInitialPrepare || compartmentPhase.rebuiltHistoryThisPass;
|
|
173368
173878
|
const tPostProcess = performance.now();
|
|
173369
173879
|
await runPostTransformPhase({
|
|
173370
173880
|
sessionId,
|
|
@@ -173380,10 +173890,18 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
173380
173890
|
fullFeatureMode,
|
|
173381
173891
|
canRunCompartments,
|
|
173382
173892
|
awaitedCompartmentRun,
|
|
173893
|
+
phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
|
|
173383
173894
|
compartmentInProgress,
|
|
173895
|
+
historyRefreshExplicitBeforePrepare,
|
|
173896
|
+
compartmentInjectionRebuiltFromDb: pendingCompartmentInjection?.rebuiltFromDb === true,
|
|
173897
|
+
rebuiltHistoryFromInitialPrepare,
|
|
173898
|
+
historyRebuiltThisPass,
|
|
173899
|
+
canConsumeDeferredLate,
|
|
173384
173900
|
sessionMeta,
|
|
173385
173901
|
currentTurnId,
|
|
173386
173902
|
pendingMaterializationSessions: deps.pendingMaterializationSessions,
|
|
173903
|
+
deferredHistoryRefreshSessions,
|
|
173904
|
+
deferredMaterializationSessions,
|
|
173387
173905
|
lastHeuristicsTurnId: deps.lastHeuristicsTurnId,
|
|
173388
173906
|
autoDropToolAge: deps.autoDropToolAge,
|
|
173389
173907
|
dropToolStructure: deps.dropToolStructure ?? true,
|
|
@@ -173397,6 +173915,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
173397
173915
|
forceMaterializationPercentage: FORCE_MATERIALIZE_PERCENTAGE,
|
|
173398
173916
|
hasRecentReduceCall,
|
|
173399
173917
|
projectPath: deps.projectPath,
|
|
173918
|
+
sessionDirectory,
|
|
173400
173919
|
autoSearch: deps.autoSearch,
|
|
173401
173920
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
173402
173921
|
liveProviderID
|
|
@@ -173804,6 +174323,15 @@ function createEventHandler2(deps) {
|
|
|
173804
174323
|
} catch (error51) {
|
|
173805
174324
|
sessionLog(sessionId, "event session.compacted marker cleanup failed:", error51);
|
|
173806
174325
|
}
|
|
174326
|
+
try {
|
|
174327
|
+
const pending = getPendingCompactionMarkerState(deps.db, sessionId);
|
|
174328
|
+
if (pending) {
|
|
174329
|
+
clearPendingCompactionMarkerStateIf(deps.db, sessionId, pending);
|
|
174330
|
+
}
|
|
174331
|
+
} catch (error51) {
|
|
174332
|
+
sessionLog(sessionId, "event session.compacted pending-marker cleanup failed:", error51);
|
|
174333
|
+
}
|
|
174334
|
+
resetDegradedCacheCount(sessionId);
|
|
173807
174335
|
clearMessageTokensCache(sessionId);
|
|
173808
174336
|
deps.onSessionCacheInvalidated?.(sessionId);
|
|
173809
174337
|
return;
|
|
@@ -173820,6 +174348,7 @@ function createEventHandler2(deps) {
|
|
|
173820
174348
|
} catch (error51) {
|
|
173821
174349
|
sessionLog(sessionId, "event session.deleted persistence failed:", error51);
|
|
173822
174350
|
}
|
|
174351
|
+
resetDegradedCacheCount(sessionId);
|
|
173823
174352
|
deps.onSessionCacheInvalidated?.(sessionId);
|
|
173824
174353
|
deps.onSessionDeleted?.(sessionId);
|
|
173825
174354
|
deps.contextUsageMap.delete(sessionId);
|
|
@@ -174028,6 +174557,10 @@ function applyStickySnapshotCache(sessionId, fresh) {
|
|
|
174028
174557
|
cache.delete(sessionId);
|
|
174029
174558
|
return fresh;
|
|
174030
174559
|
}
|
|
174560
|
+
if (!hasInFlightEvidence(fresh)) {
|
|
174561
|
+
cache.delete(sessionId);
|
|
174562
|
+
return fresh;
|
|
174563
|
+
}
|
|
174031
174564
|
return {
|
|
174032
174565
|
...fresh,
|
|
174033
174566
|
usagePercentage: cached2.snapshot.usagePercentage,
|
|
@@ -174041,6 +174574,9 @@ function applyStickySnapshotCache(sessionId, fresh) {
|
|
|
174041
174574
|
toolDefinitionTokens: cached2.snapshot.toolDefinitionTokens
|
|
174042
174575
|
};
|
|
174043
174576
|
}
|
|
174577
|
+
function hasInFlightEvidence(snapshot) {
|
|
174578
|
+
return snapshot.compartmentInProgress || snapshot.historianRunning || snapshot.pendingOpsCount > 0;
|
|
174579
|
+
}
|
|
174044
174580
|
function clearSidebarSnapshotCache(sessionId) {
|
|
174045
174581
|
cache.delete(sessionId);
|
|
174046
174582
|
}
|
|
@@ -174141,8 +174677,10 @@ function createEventHook(args) {
|
|
|
174141
174677
|
args.recentReduceBySession.delete(sessionId);
|
|
174142
174678
|
args.toolUsageSinceUserTurn.delete(sessionId);
|
|
174143
174679
|
args.historyRefreshSessions.delete(sessionId);
|
|
174680
|
+
args.deferredHistoryRefreshSessions.delete(sessionId);
|
|
174144
174681
|
args.systemPromptRefreshSessions.delete(sessionId);
|
|
174145
174682
|
args.pendingMaterializationSessions.delete(sessionId);
|
|
174683
|
+
args.deferredMaterializationSessions.delete(sessionId);
|
|
174146
174684
|
args.lastHeuristicsTurnId.delete(sessionId);
|
|
174147
174685
|
args.commitSeenLastPass?.delete(sessionId);
|
|
174148
174686
|
clearNoteNudgeState(args.db, sessionId);
|
|
@@ -174203,9 +174741,9 @@ function createToolExecuteAfterHook(args) {
|
|
|
174203
174741
|
init_send_session_notification();
|
|
174204
174742
|
|
|
174205
174743
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
174206
|
-
import { createHash as
|
|
174744
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
174207
174745
|
import { existsSync as existsSync13, readFileSync as readFileSync9, realpathSync } from "node:fs";
|
|
174208
|
-
import { join as
|
|
174746
|
+
import { join as join21, resolve as resolve4, sep } from "node:path";
|
|
174209
174747
|
|
|
174210
174748
|
// src/agents/magic-context-prompt.ts
|
|
174211
174749
|
function getToolHistoryGuidance(dropToolStructure) {
|
|
@@ -174318,7 +174856,7 @@ var DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
|
174318
174856
|
function readProjectDocs(directory) {
|
|
174319
174857
|
const sections = [];
|
|
174320
174858
|
for (const filename of DOC_FILES) {
|
|
174321
|
-
const filePath =
|
|
174859
|
+
const filePath = join21(directory, filename);
|
|
174322
174860
|
try {
|
|
174323
174861
|
if (existsSync13(filePath)) {
|
|
174324
174862
|
const content = readFileSync9(filePath, "utf-8").trim();
|
|
@@ -174508,7 +175046,7 @@ ${sections.join(`
|
|
|
174508
175046
|
`);
|
|
174509
175047
|
if (systemContent.length === 0)
|
|
174510
175048
|
return;
|
|
174511
|
-
const currentHash =
|
|
175049
|
+
const currentHash = createHash6("md5").update(systemContent).digest("hex");
|
|
174512
175050
|
if (!sessionMetaEarly) {
|
|
174513
175051
|
return;
|
|
174514
175052
|
}
|
|
@@ -174593,8 +175131,21 @@ function createMagicContextHook(deps) {
|
|
|
174593
175131
|
const historianFallbackModels = resolveFallbackChain(HISTORIAN_AGENT, deps.config.historian?.fallback_models);
|
|
174594
175132
|
const nudgePlacements = createNudgePlacementStore(db);
|
|
174595
175133
|
const historyRefreshSessions = deps.liveSessionState?.historyRefreshSessions ?? new Set;
|
|
175134
|
+
const deferredHistoryRefreshSessions = deps.liveSessionState?.deferredHistoryRefreshSessions ?? new Set;
|
|
175135
|
+
try {
|
|
175136
|
+
const sessionsWithPending = getSessionsWithPendingMarker(db);
|
|
175137
|
+
if (sessionsWithPending.length > 0) {
|
|
175138
|
+
for (const sid of sessionsWithPending) {
|
|
175139
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
175140
|
+
}
|
|
175141
|
+
log(`[magic-context] rehydrated ${sessionsWithPending.length} session(s) with pending compaction-marker drain at hook init`);
|
|
175142
|
+
}
|
|
175143
|
+
} catch (error51) {
|
|
175144
|
+
log("[magic-context] hook init: pending-marker rehydration failed:", error51);
|
|
175145
|
+
}
|
|
174596
175146
|
const systemPromptRefreshSessions = deps.liveSessionState?.systemPromptRefreshSessions ?? new Set;
|
|
174597
175147
|
const pendingMaterializationSessions = deps.liveSessionState?.pendingMaterializationSessions ?? new Set;
|
|
175148
|
+
const deferredMaterializationSessions = deps.liveSessionState?.deferredMaterializationSessions ?? new Set;
|
|
174598
175149
|
const lastHeuristicsTurnId = new Map;
|
|
174599
175150
|
const commitSeenLastPass = new Map;
|
|
174600
175151
|
const variantBySession = deps.liveSessionState?.variantBySession ?? new Map;
|
|
@@ -174635,7 +175186,9 @@ function createMagicContextHook(deps) {
|
|
|
174635
175186
|
dropToolStructure: deps.config.drop_tool_structure ?? true,
|
|
174636
175187
|
clearReasoningAge: deps.config.clear_reasoning_age ?? 50,
|
|
174637
175188
|
historyRefreshSessions,
|
|
175189
|
+
deferredHistoryRefreshSessions,
|
|
174638
175190
|
pendingMaterializationSessions,
|
|
175191
|
+
deferredMaterializationSessions,
|
|
174639
175192
|
lastHeuristicsTurnId,
|
|
174640
175193
|
commitSeenLastPass,
|
|
174641
175194
|
client: deps.client,
|
|
@@ -174708,7 +175261,7 @@ function createMagicContextHook(deps) {
|
|
|
174708
175261
|
return;
|
|
174709
175262
|
}
|
|
174710
175263
|
try {
|
|
174711
|
-
checkScheduleAndEnqueue(db, dreaming.schedule);
|
|
175264
|
+
checkScheduleAndEnqueue(db, dreaming.schedule, projectPath);
|
|
174712
175265
|
lastScheduleCheckMs = now;
|
|
174713
175266
|
} catch (error51) {
|
|
174714
175267
|
log("[dreamer] scheduled enqueue check failed:", error51);
|
|
@@ -174729,7 +175282,8 @@ function createMagicContextHook(deps) {
|
|
|
174729
175282
|
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
174730
175283
|
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
174731
175284
|
} : undefined,
|
|
174732
|
-
fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer?.fallback_models)
|
|
175285
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer?.fallback_models),
|
|
175286
|
+
projectIdentity: projectPath
|
|
174733
175287
|
}).catch((error51) => {
|
|
174734
175288
|
log("[dreamer] scheduled queue processing failed:", error51);
|
|
174735
175289
|
});
|
|
@@ -174773,9 +175327,12 @@ function createMagicContextHook(deps) {
|
|
|
174773
175327
|
historianTwoPass: deps.config.historian?.two_pass === true,
|
|
174774
175328
|
memoryEnabled: deps.config.memory?.enabled,
|
|
174775
175329
|
autoPromote: deps.config.memory?.auto_promote ?? true,
|
|
174776
|
-
|
|
175330
|
+
onCompartmentStatePublished: (sid) => {
|
|
174777
175331
|
historyRefreshSessions.add(sid);
|
|
174778
175332
|
pendingMaterializationSessions.add(sid);
|
|
175333
|
+
},
|
|
175334
|
+
onDeferredMarkerPending: (sid) => {
|
|
175335
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
174779
175336
|
}
|
|
174780
175337
|
}, options),
|
|
174781
175338
|
sendNotification: async (sessionId, text, params) => {
|
|
@@ -174841,8 +175398,10 @@ function createMagicContextHook(deps) {
|
|
|
174841
175398
|
recentReduceBySession,
|
|
174842
175399
|
toolUsageSinceUserTurn,
|
|
174843
175400
|
historyRefreshSessions,
|
|
175401
|
+
deferredHistoryRefreshSessions,
|
|
174844
175402
|
systemPromptRefreshSessions,
|
|
174845
175403
|
pendingMaterializationSessions,
|
|
175404
|
+
deferredMaterializationSessions,
|
|
174846
175405
|
lastHeuristicsTurnId,
|
|
174847
175406
|
commitSeenLastPass,
|
|
174848
175407
|
client: deps.client,
|
|
@@ -175536,7 +176095,7 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
175536
176095
|
memoryEnabled: config2.memory?.enabled,
|
|
175537
176096
|
autoPromote: config2.memory?.auto_promote ?? true,
|
|
175538
176097
|
getNotificationParams: () => getNotificationParams(sessionId),
|
|
175539
|
-
|
|
176098
|
+
onCompartmentStatePublished: (sid) => {
|
|
175540
176099
|
liveSessionState.historyRefreshSessions.add(sid);
|
|
175541
176100
|
liveSessionState.pendingMaterializationSessions.add(sid);
|
|
175542
176101
|
}
|
|
@@ -175547,8 +176106,9 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
175547
176106
|
});
|
|
175548
176107
|
return { ok: true };
|
|
175549
176108
|
});
|
|
175550
|
-
rpcServer.handle("pending-notifications", async () => {
|
|
175551
|
-
const
|
|
176109
|
+
rpcServer.handle("pending-notifications", async (params) => {
|
|
176110
|
+
const lastReceivedId = Number(params.lastReceivedId ?? 0);
|
|
176111
|
+
const notifications = drainNotifications(Number.isFinite(lastReceivedId) ? lastReceivedId : 0);
|
|
175552
176112
|
return { messages: notifications };
|
|
175553
176113
|
});
|
|
175554
176114
|
}
|
|
@@ -176506,19 +177066,68 @@ init_models_dev_cache();
|
|
|
176506
177066
|
|
|
176507
177067
|
// src/shared/rpc-server.ts
|
|
176508
177068
|
init_logger();
|
|
176509
|
-
import {
|
|
177069
|
+
import {
|
|
177070
|
+
mkdirSync as mkdirSync8,
|
|
177071
|
+
readdirSync,
|
|
177072
|
+
readFileSync as readFileSync10,
|
|
177073
|
+
renameSync as renameSync2,
|
|
177074
|
+
unlinkSync as unlinkSync3,
|
|
177075
|
+
writeFileSync as writeFileSync7
|
|
177076
|
+
} from "node:fs";
|
|
176510
177077
|
import { createServer } from "node:http";
|
|
176511
|
-
import { dirname as
|
|
177078
|
+
import { dirname as dirname7 } from "node:path";
|
|
176512
177079
|
|
|
176513
177080
|
// src/shared/rpc-utils.ts
|
|
176514
|
-
import { createHash as
|
|
176515
|
-
import { join as
|
|
177081
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
177082
|
+
import { join as join22 } from "node:path";
|
|
176516
177083
|
function projectHash(directory) {
|
|
176517
177084
|
const normalized = directory.replace(/\/+$/, "");
|
|
176518
|
-
return
|
|
177085
|
+
return createHash7("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
177086
|
+
}
|
|
177087
|
+
function rpcPortDir(storageDir, directory) {
|
|
177088
|
+
return join22(storageDir, "rpc", projectHash(directory));
|
|
177089
|
+
}
|
|
177090
|
+
function rpcPortFilePath(storageDir, directory, pid = process.pid) {
|
|
177091
|
+
return join22(rpcPortDir(storageDir, directory), `port-${pid}.json`);
|
|
177092
|
+
}
|
|
177093
|
+
function isPidAlive(pid) {
|
|
177094
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
177095
|
+
return false;
|
|
177096
|
+
try {
|
|
177097
|
+
process.kill(pid, 0);
|
|
177098
|
+
return true;
|
|
177099
|
+
} catch (err) {
|
|
177100
|
+
return err.code === "EPERM";
|
|
177101
|
+
}
|
|
177102
|
+
}
|
|
177103
|
+
function parseRpcPortFile(content, fallbackPid = 0) {
|
|
177104
|
+
const trimmed = content.trim();
|
|
177105
|
+
if (!trimmed)
|
|
177106
|
+
return null;
|
|
177107
|
+
if (trimmed.startsWith("{")) {
|
|
177108
|
+
try {
|
|
177109
|
+
const parsed = JSON.parse(trimmed);
|
|
177110
|
+
const port2 = Number(parsed.port);
|
|
177111
|
+
const pid = Number(parsed.pid);
|
|
177112
|
+
const startedAt = Number(parsed.started_at);
|
|
177113
|
+
if (!isValidPort(port2) || !Number.isInteger(pid) || pid <= 0)
|
|
177114
|
+
return null;
|
|
177115
|
+
return {
|
|
177116
|
+
port: port2,
|
|
177117
|
+
pid,
|
|
177118
|
+
started_at: Number.isFinite(startedAt) ? startedAt : 0
|
|
177119
|
+
};
|
|
177120
|
+
} catch {
|
|
177121
|
+
return null;
|
|
177122
|
+
}
|
|
177123
|
+
}
|
|
177124
|
+
const port = Number.parseInt(trimmed, 10);
|
|
177125
|
+
if (!isValidPort(port))
|
|
177126
|
+
return null;
|
|
177127
|
+
return { port, pid: fallbackPid, started_at: 0 };
|
|
176519
177128
|
}
|
|
176520
|
-
function
|
|
176521
|
-
return
|
|
177129
|
+
function isValidPort(port) {
|
|
177130
|
+
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
176522
177131
|
}
|
|
176523
177132
|
|
|
176524
177133
|
// src/shared/rpc-server.ts
|
|
@@ -176527,8 +177136,11 @@ class MagicContextRpcServer {
|
|
|
176527
177136
|
port = 0;
|
|
176528
177137
|
handlers = new Map;
|
|
176529
177138
|
portFilePath;
|
|
177139
|
+
portDir;
|
|
177140
|
+
startedAt = Date.now();
|
|
176530
177141
|
constructor(storageDir, directory) {
|
|
176531
177142
|
this.portFilePath = rpcPortFilePath(storageDir, directory);
|
|
177143
|
+
this.portDir = rpcPortDir(storageDir, directory);
|
|
176532
177144
|
}
|
|
176533
177145
|
handle(method, handler) {
|
|
176534
177146
|
this.handlers.set(method, handler);
|
|
@@ -176549,10 +177161,15 @@ class MagicContextRpcServer {
|
|
|
176549
177161
|
this.port = addr.port;
|
|
176550
177162
|
this.server = server;
|
|
176551
177163
|
try {
|
|
176552
|
-
|
|
176553
|
-
|
|
177164
|
+
this.warnIfOtherLiveInstance();
|
|
177165
|
+
const dir = dirname7(this.portFilePath);
|
|
177166
|
+
mkdirSync8(dir, { recursive: true });
|
|
176554
177167
|
const tmpPath = `${this.portFilePath}.tmp`;
|
|
176555
|
-
writeFileSync7(tmpPath,
|
|
177168
|
+
writeFileSync7(tmpPath, JSON.stringify({
|
|
177169
|
+
port: this.port,
|
|
177170
|
+
pid: process.pid,
|
|
177171
|
+
started_at: this.startedAt
|
|
177172
|
+
}), "utf-8");
|
|
176556
177173
|
renameSync2(tmpPath, this.portFilePath);
|
|
176557
177174
|
log(`[rpc] server listening on 127.0.0.1:${this.port}`);
|
|
176558
177175
|
} catch (err) {
|
|
@@ -176563,6 +177180,19 @@ class MagicContextRpcServer {
|
|
|
176563
177180
|
server.unref();
|
|
176564
177181
|
});
|
|
176565
177182
|
}
|
|
177183
|
+
warnIfOtherLiveInstance() {
|
|
177184
|
+
try {
|
|
177185
|
+
for (const entry of readdirSync(this.portDir)) {
|
|
177186
|
+
if (!entry.startsWith("port-") || !entry.endsWith(".json"))
|
|
177187
|
+
continue;
|
|
177188
|
+
const record2 = parseRpcPortFile(readFileSync10(`${this.portDir}/${entry}`, "utf-8"));
|
|
177189
|
+
if (!record2 || record2.pid === process.pid || !isPidAlive(record2.pid))
|
|
177190
|
+
continue;
|
|
177191
|
+
log(`[rpc] another Magic Context RPC server is active for this project (pid ${record2.pid}, port ${record2.port}); starting separate instance on a new port`);
|
|
177192
|
+
return;
|
|
177193
|
+
}
|
|
177194
|
+
} catch {}
|
|
177195
|
+
}
|
|
176566
177196
|
stop() {
|
|
176567
177197
|
if (this.server) {
|
|
176568
177198
|
this.server.close();
|