@cortexkit/opencode-magic-context 0.17.2 → 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 +15 -0
- 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/sidekick/agent.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 +70 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +1 -0
- package/dist/features/magic-context/storage-meta-shared.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/features/magic-context/types.d.ts +1 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +2 -0
- package/dist/features/magic-context/user-memory/review-user-memories.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 +2 -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-compressor.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +7 -0
- 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 +18 -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/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/todo-view.d.ts +102 -0
- package/dist/hooks/magic-context/todo-view.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +11 -4
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-message-helpers.d.ts +22 -0
- package/dist/hooks/magic-context/transform-message-helpers.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 +4 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +1789 -711
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +2 -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/index.d.ts +1 -0
- package/dist/shared/index.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/model-suggestion-retry.d.ts +37 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/shared/resolve-fallbacks.d.ts +32 -0
- package/dist/shared/resolve-fallbacks.d.ts.map +1 -0
- 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/shared/tag-transcript.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- 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/index.ts +1 -0
- package/src/shared/logger.ts +29 -3
- package/src/shared/model-suggestion-retry.test.ts +251 -0
- package/src/shared/model-suggestion-retry.ts +194 -6
- package/src/shared/models-dev-cache.ts +7 -7
- package/src/shared/resolve-fallbacks.test.ts +136 -0
- package/src/shared/resolve-fallbacks.ts +76 -0
- 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/shared/tag-transcript.ts +3 -2
- package/src/tui/data/context-db.ts +20 -1
- package/src/tui/index.tsx +114 -18
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);
|
|
@@ -15122,6 +15170,161 @@ var init_model_requirements = __esm(() => {
|
|
|
15122
15170
|
};
|
|
15123
15171
|
});
|
|
15124
15172
|
|
|
15173
|
+
// src/features/magic-context/overflow-detection.ts
|
|
15174
|
+
function extractErrorMessage(error51) {
|
|
15175
|
+
if (!error51)
|
|
15176
|
+
return "";
|
|
15177
|
+
if (typeof error51 === "string")
|
|
15178
|
+
return error51;
|
|
15179
|
+
if (typeof error51 === "object") {
|
|
15180
|
+
const obj = error51;
|
|
15181
|
+
const nested = obj.error;
|
|
15182
|
+
if (nested && typeof nested.message === "string" && nested.message.length > 0) {
|
|
15183
|
+
return nested.message;
|
|
15184
|
+
}
|
|
15185
|
+
}
|
|
15186
|
+
if (error51 instanceof Error)
|
|
15187
|
+
return error51.message;
|
|
15188
|
+
if (typeof error51 === "object") {
|
|
15189
|
+
const obj = error51;
|
|
15190
|
+
if (typeof obj.message === "string")
|
|
15191
|
+
return obj.message;
|
|
15192
|
+
if (typeof obj.responseBody === "string")
|
|
15193
|
+
return obj.responseBody;
|
|
15194
|
+
try {
|
|
15195
|
+
return JSON.stringify(error51);
|
|
15196
|
+
} catch {
|
|
15197
|
+
return String(error51);
|
|
15198
|
+
}
|
|
15199
|
+
}
|
|
15200
|
+
return String(error51);
|
|
15201
|
+
}
|
|
15202
|
+
function detectOverflow(error51) {
|
|
15203
|
+
const message = extractErrorMessage(error51);
|
|
15204
|
+
if (!message) {
|
|
15205
|
+
return { isOverflow: false };
|
|
15206
|
+
}
|
|
15207
|
+
const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
|
|
15208
|
+
let matched;
|
|
15209
|
+
for (const pattern of OVERFLOW_PATTERNS) {
|
|
15210
|
+
if (pattern.test(message)) {
|
|
15211
|
+
matched = pattern;
|
|
15212
|
+
break;
|
|
15213
|
+
}
|
|
15214
|
+
}
|
|
15215
|
+
if (!matched && !hasStatus413) {
|
|
15216
|
+
return { isOverflow: false };
|
|
15217
|
+
}
|
|
15218
|
+
const reportedLimit = parseReportedLimit(message);
|
|
15219
|
+
return {
|
|
15220
|
+
isOverflow: true,
|
|
15221
|
+
reportedLimit,
|
|
15222
|
+
matchedPattern: matched?.source
|
|
15223
|
+
};
|
|
15224
|
+
}
|
|
15225
|
+
function parseReportedLimit(message) {
|
|
15226
|
+
if (!message)
|
|
15227
|
+
return;
|
|
15228
|
+
for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
|
|
15229
|
+
const match = message.match(pattern);
|
|
15230
|
+
if (!match)
|
|
15231
|
+
continue;
|
|
15232
|
+
const raw = match[1];
|
|
15233
|
+
if (!raw)
|
|
15234
|
+
continue;
|
|
15235
|
+
const value = Number.parseInt(raw, 10);
|
|
15236
|
+
if (!Number.isFinite(value))
|
|
15237
|
+
continue;
|
|
15238
|
+
if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
|
|
15239
|
+
continue;
|
|
15240
|
+
return value;
|
|
15241
|
+
}
|
|
15242
|
+
return;
|
|
15243
|
+
}
|
|
15244
|
+
var OVERFLOW_PATTERNS, LIMIT_EXTRACTION_PATTERNS, MIN_PLAUSIBLE_LIMIT = 1024, MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
15245
|
+
var init_overflow_detection = __esm(() => {
|
|
15246
|
+
OVERFLOW_PATTERNS = [
|
|
15247
|
+
/prompt is too long/i,
|
|
15248
|
+
/input is too long for requested model/i,
|
|
15249
|
+
/exceeds the context window/i,
|
|
15250
|
+
/input token count.*exceeds the maximum/i,
|
|
15251
|
+
/maximum prompt length is \d+/i,
|
|
15252
|
+
/reduce the length of the messages/i,
|
|
15253
|
+
/maximum context length is \d+ tokens/i,
|
|
15254
|
+
/exceeds the limit of \d+/i,
|
|
15255
|
+
/exceeds the available context size/i,
|
|
15256
|
+
/greater than the context length/i,
|
|
15257
|
+
/context window exceeds limit/i,
|
|
15258
|
+
/exceeded model token limit/i,
|
|
15259
|
+
/context[_ ]length[_ ]exceeded/i,
|
|
15260
|
+
/request entity too large/i,
|
|
15261
|
+
/context length is only \d+ tokens/i,
|
|
15262
|
+
/input length.*exceeds.*context length/i,
|
|
15263
|
+
/prompt too long; exceeded (?:max )?context length/i,
|
|
15264
|
+
/too large for model with \d+ maximum context length/i,
|
|
15265
|
+
/model_context_window_exceeded/i,
|
|
15266
|
+
/context size has been exceeded/i
|
|
15267
|
+
];
|
|
15268
|
+
LIMIT_EXTRACTION_PATTERNS = [
|
|
15269
|
+
/maximum prompt length is (\d+)/i,
|
|
15270
|
+
/maximum context length is (\d+) tokens?/i,
|
|
15271
|
+
/context length is only (\d+) tokens?/i,
|
|
15272
|
+
/exceeds the limit of (\d+)/i,
|
|
15273
|
+
/too large for model with (\d+) maximum context length/i,
|
|
15274
|
+
/context size.*(\d+) tokens?/i,
|
|
15275
|
+
/exceeds? the context length of (\d+)/i,
|
|
15276
|
+
/max(?:imum)?.*context.*?(\d+)/i
|
|
15277
|
+
];
|
|
15278
|
+
});
|
|
15279
|
+
|
|
15280
|
+
// src/shared/resolve-fallbacks.ts
|
|
15281
|
+
function resolveFallbackChain(agentName, userFallbacks) {
|
|
15282
|
+
const userList = normalizeUserFallbacks(userFallbacks);
|
|
15283
|
+
if (userList.length > 0) {
|
|
15284
|
+
return dedupe(userList.filter(isValidModelSpec));
|
|
15285
|
+
}
|
|
15286
|
+
const builtin = getAgentFallbackModels(agentName);
|
|
15287
|
+
if (!builtin || builtin.length === 0)
|
|
15288
|
+
return [];
|
|
15289
|
+
return dedupe(builtin.filter(isValidModelSpec));
|
|
15290
|
+
}
|
|
15291
|
+
function normalizeUserFallbacks(userFallbacks) {
|
|
15292
|
+
if (!userFallbacks)
|
|
15293
|
+
return [];
|
|
15294
|
+
if (typeof userFallbacks === "string") {
|
|
15295
|
+
const trimmed = userFallbacks.trim();
|
|
15296
|
+
return trimmed ? [trimmed] : [];
|
|
15297
|
+
}
|
|
15298
|
+
return userFallbacks.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
15299
|
+
}
|
|
15300
|
+
function isValidModelSpec(spec) {
|
|
15301
|
+
const slash = spec.indexOf("/");
|
|
15302
|
+
return slash > 0 && slash < spec.length - 1;
|
|
15303
|
+
}
|
|
15304
|
+
function dedupe(list) {
|
|
15305
|
+
const seen = new Set;
|
|
15306
|
+
const out = [];
|
|
15307
|
+
for (const item of list) {
|
|
15308
|
+
if (seen.has(item))
|
|
15309
|
+
continue;
|
|
15310
|
+
seen.add(item);
|
|
15311
|
+
out.push(item);
|
|
15312
|
+
}
|
|
15313
|
+
return out;
|
|
15314
|
+
}
|
|
15315
|
+
function parseProviderModel(spec) {
|
|
15316
|
+
const slash = spec.indexOf("/");
|
|
15317
|
+
if (slash < 1 || slash >= spec.length - 1)
|
|
15318
|
+
return null;
|
|
15319
|
+
return {
|
|
15320
|
+
providerID: spec.slice(0, slash).trim(),
|
|
15321
|
+
modelID: spec.slice(slash + 1).trim()
|
|
15322
|
+
};
|
|
15323
|
+
}
|
|
15324
|
+
var init_resolve_fallbacks = __esm(() => {
|
|
15325
|
+
init_model_requirements();
|
|
15326
|
+
});
|
|
15327
|
+
|
|
15125
15328
|
// src/shared/model-suggestion-retry.ts
|
|
15126
15329
|
function extractMessage(error51) {
|
|
15127
15330
|
if (typeof error51 === "string")
|
|
@@ -15177,6 +15380,9 @@ function parseModelSuggestion(error51) {
|
|
|
15177
15380
|
};
|
|
15178
15381
|
}
|
|
15179
15382
|
async function promptWithTimeout(client, args, timeoutMs, signal) {
|
|
15383
|
+
if (signal?.aborted) {
|
|
15384
|
+
throw new Error("prompt aborted by external signal");
|
|
15385
|
+
}
|
|
15180
15386
|
const controller = new AbortController;
|
|
15181
15387
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
15182
15388
|
const onExternalAbort = () => controller.abort();
|
|
@@ -15199,16 +15405,39 @@ async function promptWithTimeout(client, args, timeoutMs, signal) {
|
|
|
15199
15405
|
signal?.removeEventListener("abort", onExternalAbort);
|
|
15200
15406
|
}
|
|
15201
15407
|
}
|
|
15202
|
-
|
|
15203
|
-
|
|
15408
|
+
function isNonRetryable(error51, externalSignal) {
|
|
15409
|
+
if (externalSignal?.aborted)
|
|
15410
|
+
return true;
|
|
15411
|
+
if (error51 instanceof Error) {
|
|
15412
|
+
if (error51.name === "AbortError")
|
|
15413
|
+
return true;
|
|
15414
|
+
if (error51.message === "prompt aborted by external signal")
|
|
15415
|
+
return true;
|
|
15416
|
+
if (/^prompt timed out after \d+ms$/.test(error51.message))
|
|
15417
|
+
return true;
|
|
15418
|
+
}
|
|
15419
|
+
if (detectOverflow(error51).isOverflow)
|
|
15420
|
+
return true;
|
|
15421
|
+
return false;
|
|
15422
|
+
}
|
|
15423
|
+
function shortErr(error51) {
|
|
15424
|
+
if (error51 instanceof Error) {
|
|
15425
|
+
return error51.name && error51.name !== "Error" ? `${error51.name}: ${error51.message}` : error51.message;
|
|
15426
|
+
}
|
|
15427
|
+
return extractMessage(error51);
|
|
15428
|
+
}
|
|
15429
|
+
async function attemptOnce(client, args, timeoutMs, signal, callContext, label) {
|
|
15204
15430
|
try {
|
|
15205
|
-
await promptWithTimeout(client, args, timeoutMs,
|
|
15431
|
+
await promptWithTimeout(client, args, timeoutMs, signal);
|
|
15432
|
+
return;
|
|
15206
15433
|
} catch (error51) {
|
|
15434
|
+
if (isNonRetryable(error51, signal))
|
|
15435
|
+
throw error51;
|
|
15207
15436
|
const suggestion = parseModelSuggestion(error51);
|
|
15208
15437
|
if (!suggestion || !args.body.model) {
|
|
15209
15438
|
throw error51;
|
|
15210
15439
|
}
|
|
15211
|
-
log(
|
|
15440
|
+
log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
|
|
15212
15441
|
original: `${suggestion.providerID}/${suggestion.modelID}`,
|
|
15213
15442
|
suggested: suggestion.suggestion
|
|
15214
15443
|
});
|
|
@@ -15221,11 +15450,59 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
|
|
|
15221
15450
|
modelID: suggestion.suggestion
|
|
15222
15451
|
}
|
|
15223
15452
|
}
|
|
15224
|
-
}, timeoutMs,
|
|
15453
|
+
}, timeoutMs, signal);
|
|
15454
|
+
}
|
|
15455
|
+
}
|
|
15456
|
+
async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
|
|
15457
|
+
const timeoutMs = options.timeoutMs ?? 300000;
|
|
15458
|
+
const callContext = options.callContext ?? "subagent";
|
|
15459
|
+
const fallbacks = options.fallbackModels ?? [];
|
|
15460
|
+
const explicitPrimaryLabel = args.body.model?.providerID && args.body.model.modelID ? `${args.body.model.providerID}/${args.body.model.modelID}` : "primary";
|
|
15461
|
+
let lastError = null;
|
|
15462
|
+
try {
|
|
15463
|
+
await attemptOnce(client, args, timeoutMs, options.signal, callContext, explicitPrimaryLabel);
|
|
15464
|
+
return;
|
|
15465
|
+
} catch (error51) {
|
|
15466
|
+
lastError = error51;
|
|
15467
|
+
if (isNonRetryable(error51, options.signal))
|
|
15468
|
+
throw error51;
|
|
15469
|
+
if (fallbacks.length === 0) {
|
|
15470
|
+
throw error51;
|
|
15471
|
+
}
|
|
15472
|
+
log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error51)}; trying ${fallbacks.length} fallback(s)`);
|
|
15473
|
+
}
|
|
15474
|
+
for (let i = 0;i < fallbacks.length; i += 1) {
|
|
15475
|
+
const parsed = parseProviderModel(fallbacks[i]);
|
|
15476
|
+
if (!parsed) {
|
|
15477
|
+
log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
|
|
15478
|
+
continue;
|
|
15479
|
+
}
|
|
15480
|
+
const label = `${parsed.providerID}/${parsed.modelID}`;
|
|
15481
|
+
const attemptArgs = {
|
|
15482
|
+
...args,
|
|
15483
|
+
body: { ...args.body, model: parsed }
|
|
15484
|
+
};
|
|
15485
|
+
try {
|
|
15486
|
+
await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
|
|
15487
|
+
log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
|
|
15488
|
+
return;
|
|
15489
|
+
} catch (error51) {
|
|
15490
|
+
lastError = error51;
|
|
15491
|
+
if (isNonRetryable(error51, options.signal))
|
|
15492
|
+
throw error51;
|
|
15493
|
+
const remaining = fallbacks.length - i - 1;
|
|
15494
|
+
if (remaining > 0) {
|
|
15495
|
+
log(`[${callContext}] ${label} failed: ${shortErr(error51)}; ${remaining} fallback(s) left`);
|
|
15496
|
+
}
|
|
15497
|
+
}
|
|
15225
15498
|
}
|
|
15499
|
+
log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
|
|
15500
|
+
throw lastError ?? new Error("All fallback models failed");
|
|
15226
15501
|
}
|
|
15227
15502
|
var init_model_suggestion_retry = __esm(() => {
|
|
15503
|
+
init_overflow_detection();
|
|
15228
15504
|
init_logger();
|
|
15505
|
+
init_resolve_fallbacks();
|
|
15229
15506
|
});
|
|
15230
15507
|
|
|
15231
15508
|
// src/shared/normalize-sdk-response.ts
|
|
@@ -15257,6 +15534,7 @@ var init_shared = __esm(() => {
|
|
|
15257
15534
|
init_logger();
|
|
15258
15535
|
init_model_requirements();
|
|
15259
15536
|
init_model_suggestion_retry();
|
|
15537
|
+
init_resolve_fallbacks();
|
|
15260
15538
|
});
|
|
15261
15539
|
|
|
15262
15540
|
// src/shared/record-type-guard.ts
|
|
@@ -147908,21 +148186,36 @@ var init_read_session_formatting = __esm(() => {
|
|
|
147908
148186
|
tokenizer = new src_default(exports_claude);
|
|
147909
148187
|
});
|
|
147910
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
|
+
|
|
147911
148211
|
// src/features/magic-context/tool-definition-tokens.ts
|
|
148212
|
+
import { createHash } from "node:crypto";
|
|
147912
148213
|
function keyFor(providerID, modelID, agentName) {
|
|
147913
148214
|
const agent = agentName && agentName.length > 0 ? agentName : "default";
|
|
147914
148215
|
return `${providerID}/${modelID}/${agent}`;
|
|
147915
148216
|
}
|
|
147916
148217
|
function fingerprintFor(description, parameters) {
|
|
147917
|
-
|
|
147918
|
-
if (parameters === undefined)
|
|
147919
|
-
return `${descLen}:none`;
|
|
147920
|
-
if (parameters === null)
|
|
147921
|
-
return `${descLen}:null`;
|
|
147922
|
-
if (typeof parameters !== "object")
|
|
147923
|
-
return `${descLen}:${typeof parameters}`;
|
|
147924
|
-
const keys = Object.keys(parameters);
|
|
147925
|
-
return `${descLen}:obj:${keys.length}:${keys.sort().join(",")}`;
|
|
148218
|
+
return createHash("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
|
|
147926
148219
|
}
|
|
147927
148220
|
function setDatabase(db) {
|
|
147928
148221
|
persistenceDb = db;
|
|
@@ -155760,12 +156053,6 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
155760
156053
|
};
|
|
155761
156054
|
});
|
|
155762
156055
|
|
|
155763
|
-
// src/shared/harness.ts
|
|
155764
|
-
function getHarness() {
|
|
155765
|
-
return currentHarness;
|
|
155766
|
-
}
|
|
155767
|
-
var currentHarness = "opencode";
|
|
155768
|
-
|
|
155769
156056
|
// src/features/magic-context/compartment-storage.ts
|
|
155770
156057
|
function getInsertCompartmentStatement(db) {
|
|
155771
156058
|
let stmt = insertCompartmentStatements.get(db);
|
|
@@ -155839,6 +156126,10 @@ function getLastCompartmentEndMessage(db, sessionId) {
|
|
|
155839
156126
|
const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
|
|
155840
156127
|
return row?.max_end ?? -1;
|
|
155841
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
|
+
}
|
|
155842
156133
|
function appendCompartments(db, sessionId, compartments) {
|
|
155843
156134
|
if (compartments.length === 0)
|
|
155844
156135
|
return;
|
|
@@ -156342,7 +156633,7 @@ var init_compartment_prompt = __esm(() => {
|
|
|
156342
156633
|
});
|
|
156343
156634
|
|
|
156344
156635
|
// src/shared/opencode-config-dir.ts
|
|
156345
|
-
import { homedir as
|
|
156636
|
+
import { homedir as homedir6 } from "node:os";
|
|
156346
156637
|
import { join as join7, resolve as resolve3 } from "node:path";
|
|
156347
156638
|
function getCliConfigDir() {
|
|
156348
156639
|
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
@@ -156350,9 +156641,9 @@ function getCliConfigDir() {
|
|
|
156350
156641
|
return resolve3(envConfigDir);
|
|
156351
156642
|
}
|
|
156352
156643
|
if (process.platform === "win32") {
|
|
156353
|
-
return join7(
|
|
156644
|
+
return join7(homedir6(), ".config", "opencode");
|
|
156354
156645
|
}
|
|
156355
|
-
return join7(process.env.XDG_CONFIG_HOME || join7(
|
|
156646
|
+
return join7(process.env.XDG_CONFIG_HOME || join7(homedir6(), ".config"), "opencode");
|
|
156356
156647
|
}
|
|
156357
156648
|
function getOpenCodeConfigDir(_options) {
|
|
156358
156649
|
return getCliConfigDir();
|
|
@@ -156583,11 +156874,11 @@ __export(exports_conflict_warning_hook, {
|
|
|
156583
156874
|
cleanupConflictWarnings: () => cleanupConflictWarnings
|
|
156584
156875
|
});
|
|
156585
156876
|
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
156586
|
-
import { homedir as
|
|
156877
|
+
import { homedir as homedir7, platform as platform2 } from "node:os";
|
|
156587
156878
|
import { join as join9 } from "node:path";
|
|
156588
156879
|
function getDesktopStatePath() {
|
|
156589
156880
|
const os2 = platform2();
|
|
156590
|
-
const home =
|
|
156881
|
+
const home = homedir7();
|
|
156591
156882
|
if (os2 === "darwin") {
|
|
156592
156883
|
return join9(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
|
|
156593
156884
|
}
|
|
@@ -156866,26 +157157,6 @@ var init_conflict_warning_hook = __esm(() => {
|
|
|
156866
157157
|
cachedDesktopStateByDir = new Map;
|
|
156867
157158
|
});
|
|
156868
157159
|
|
|
156869
|
-
// src/shared/data-path.ts
|
|
156870
|
-
import * as os2 from "node:os";
|
|
156871
|
-
import * as path2 from "node:path";
|
|
156872
|
-
function getDataDir() {
|
|
156873
|
-
return process.env.XDG_DATA_HOME ?? path2.join(os2.homedir(), ".local", "share");
|
|
156874
|
-
}
|
|
156875
|
-
function getOpenCodeStorageDir() {
|
|
156876
|
-
return path2.join(getDataDir(), "opencode", "storage");
|
|
156877
|
-
}
|
|
156878
|
-
function getMagicContextStorageDir() {
|
|
156879
|
-
return path2.join(getDataDir(), "cortexkit", "magic-context");
|
|
156880
|
-
}
|
|
156881
|
-
function getLegacyOpenCodeMagicContextStorageDir() {
|
|
156882
|
-
return path2.join(getOpenCodeStorageDir(), "plugin", "magic-context");
|
|
156883
|
-
}
|
|
156884
|
-
function getCacheDir() {
|
|
156885
|
-
return process.env.XDG_CACHE_HOME ?? path2.join(os2.homedir(), ".cache");
|
|
156886
|
-
}
|
|
156887
|
-
var init_data_path = () => {};
|
|
156888
|
-
|
|
156889
157160
|
// src/shared/error-message.ts
|
|
156890
157161
|
function getErrorMessage(error51) {
|
|
156891
157162
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -157143,7 +157414,7 @@ var exports_native_binding = {};
|
|
|
157143
157414
|
__export(exports_native_binding, {
|
|
157144
157415
|
resolveBetterSqliteNativeBinding: () => resolveBetterSqliteNativeBinding
|
|
157145
157416
|
});
|
|
157146
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
157417
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
157147
157418
|
import { createRequire } from "node:module";
|
|
157148
157419
|
import * as path3 from "node:path";
|
|
157149
157420
|
function logInfo(message) {
|
|
@@ -157243,7 +157514,7 @@ async function resolveBetterSqliteNativeBinding() {
|
|
|
157243
157514
|
}
|
|
157244
157515
|
logWarn(`cached binary at ${cachedPath} has wrong ABI (${cachedProbe.actual ?? "unknown"} != ${expected}); refetching`);
|
|
157245
157516
|
}
|
|
157246
|
-
|
|
157517
|
+
mkdirSync3(path3.dirname(cachedPath), { recursive: true });
|
|
157247
157518
|
const nodeFileBytes = await downloadElectronPrebuild(pkgVersion, expected);
|
|
157248
157519
|
writeFileSync4(cachedPath, nodeFileBytes);
|
|
157249
157520
|
logInfo(`cached Electron prebuild at ${cachedPath} (${(nodeFileBytes.length / 1024).toFixed(1)} KB)`);
|
|
@@ -157421,13 +157692,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
157421
157692
|
});
|
|
157422
157693
|
|
|
157423
157694
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
157424
|
-
import { createHash } from "node:crypto";
|
|
157695
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
157425
157696
|
function normalizeMemoryContent(content) {
|
|
157426
157697
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
157427
157698
|
}
|
|
157428
157699
|
function computeNormalizedHash(content) {
|
|
157429
157700
|
const normalized = normalizeMemoryContent(content);
|
|
157430
|
-
return
|
|
157701
|
+
return createHash2("md5").update(normalized).digest("hex");
|
|
157431
157702
|
}
|
|
157432
157703
|
var init_normalize_hash = () => {};
|
|
157433
157704
|
|
|
@@ -158021,9 +158292,9 @@ __export(exports_read_session_db, {
|
|
|
158021
158292
|
findLastAssistantModelFromOpenCodeDb: () => findLastAssistantModelFromOpenCodeDb,
|
|
158022
158293
|
closeReadOnlySessionDb: () => closeReadOnlySessionDb
|
|
158023
158294
|
});
|
|
158024
|
-
import { join as
|
|
158295
|
+
import { join as join11 } from "node:path";
|
|
158025
158296
|
function getOpenCodeDbPath() {
|
|
158026
|
-
return
|
|
158297
|
+
return join11(getDataDir(), "opencode", "opencode.db");
|
|
158027
158298
|
}
|
|
158028
158299
|
function closeCachedReadOnlyDb() {
|
|
158029
158300
|
if (!cachedReadOnlyDb) {
|
|
@@ -158130,10 +158401,36 @@ function cosineSimilarity(a, b) {
|
|
|
158130
158401
|
return denominator === 0 ? 0 : dotProduct / denominator;
|
|
158131
158402
|
}
|
|
158132
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
|
+
|
|
158133
158430
|
// src/features/magic-context/memory/embedding-local.ts
|
|
158134
|
-
import { mkdirSync as
|
|
158431
|
+
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
158135
158432
|
import { open, stat, unlink, writeFile } from "node:fs/promises";
|
|
158136
|
-
import { join as
|
|
158433
|
+
import { join as join13 } from "node:path";
|
|
158137
158434
|
async function acquireModelLoadLock(lockPath) {
|
|
158138
158435
|
const waitStart = Date.now();
|
|
158139
158436
|
while (true) {
|
|
@@ -158248,7 +158545,7 @@ class LocalEmbeddingProvider {
|
|
|
158248
158545
|
initPromise = null;
|
|
158249
158546
|
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
158250
158547
|
this.model = model;
|
|
158251
|
-
this.modelId =
|
|
158548
|
+
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
158252
158549
|
}
|
|
158253
158550
|
async initialize() {
|
|
158254
158551
|
if (this.pipeline) {
|
|
@@ -158267,15 +158564,15 @@ class LocalEmbeddingProvider {
|
|
|
158267
158564
|
if (LogLevel && "ERROR" in LogLevel) {
|
|
158268
158565
|
env.logLevel = LogLevel.ERROR;
|
|
158269
158566
|
}
|
|
158270
|
-
const modelCacheDir =
|
|
158567
|
+
const modelCacheDir = join13(getMagicContextStorageDir(), "models");
|
|
158271
158568
|
try {
|
|
158272
|
-
|
|
158569
|
+
mkdirSync4(modelCacheDir, { recursive: true });
|
|
158273
158570
|
env.cacheDir = modelCacheDir;
|
|
158274
158571
|
} catch {
|
|
158275
158572
|
log("[magic-context] could not create model cache dir, using library default");
|
|
158276
158573
|
}
|
|
158277
158574
|
const createPipeline = transformersModule.pipeline;
|
|
158278
|
-
const lockPath =
|
|
158575
|
+
const lockPath = join13(modelCacheDir, ".load.lock");
|
|
158279
158576
|
const releaseLock = await acquireModelLoadLock(lockPath);
|
|
158280
158577
|
const stopHeartbeat = startLockHeartbeat(lockPath);
|
|
158281
158578
|
try {
|
|
@@ -158390,12 +158687,13 @@ var init_embedding_local = __esm(() => {
|
|
|
158390
158687
|
init_magic_context();
|
|
158391
158688
|
init_data_path();
|
|
158392
158689
|
init_logger();
|
|
158690
|
+
init_embedding_identity();
|
|
158393
158691
|
STALE_LOCK_MS = 3 * 60000;
|
|
158394
158692
|
MAX_LOCK_WAIT_MS = 5 * 60000;
|
|
158395
158693
|
});
|
|
158396
158694
|
|
|
158397
158695
|
// src/features/magic-context/memory/embedding-openai.ts
|
|
158398
|
-
function
|
|
158696
|
+
function normalizeEndpoint2(endpoint) {
|
|
158399
158697
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
158400
158698
|
}
|
|
158401
158699
|
|
|
@@ -158410,10 +158708,15 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158410
158708
|
openLogged = false;
|
|
158411
158709
|
halfOpenProbeInFlight = false;
|
|
158412
158710
|
constructor(options) {
|
|
158413
|
-
this.endpoint =
|
|
158711
|
+
this.endpoint = normalizeEndpoint2(options.endpoint);
|
|
158414
158712
|
this.model = options.model?.trim() ?? "";
|
|
158415
158713
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
158416
|
-
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
|
+
});
|
|
158417
158720
|
}
|
|
158418
158721
|
async initialize() {
|
|
158419
158722
|
if (this.initialized)
|
|
@@ -158595,6 +158898,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158595
158898
|
var FAILURE_THRESHOLD = 3, FAILURE_WINDOW_MS = 60000, OPEN_DURATION_MS, FETCH_TIMEOUT_MS = 30000;
|
|
158596
158899
|
var init_embedding_openai = __esm(() => {
|
|
158597
158900
|
init_logger();
|
|
158901
|
+
init_embedding_identity();
|
|
158598
158902
|
OPEN_DURATION_MS = 5 * 60000;
|
|
158599
158903
|
});
|
|
158600
158904
|
|
|
@@ -158632,17 +158936,8 @@ function resolveEmbeddingConfig(config2) {
|
|
|
158632
158936
|
}
|
|
158633
158937
|
return { provider: "off" };
|
|
158634
158938
|
}
|
|
158635
|
-
function
|
|
158636
|
-
|
|
158637
|
-
return "off";
|
|
158638
|
-
}
|
|
158639
|
-
if (config2.provider === "openai-compatible") {
|
|
158640
|
-
const endpoint = config2.endpoint.trim();
|
|
158641
|
-
const model = config2.model.trim();
|
|
158642
|
-
const keyHash = config2.api_key ? computeNormalizedHash(config2.api_key) : "nokey";
|
|
158643
|
-
return `openai-compat:${endpoint}:${model}:${keyHash}`;
|
|
158644
|
-
}
|
|
158645
|
-
return config2.model.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL;
|
|
158939
|
+
function resolveProviderIdentity(config2) {
|
|
158940
|
+
return getEmbeddingProviderIdentity(config2);
|
|
158646
158941
|
}
|
|
158647
158942
|
function createProvider(config2) {
|
|
158648
158943
|
if (config2.provider === "off") {
|
|
@@ -158666,10 +158961,10 @@ function getOrCreateProvider() {
|
|
|
158666
158961
|
}
|
|
158667
158962
|
function initializeEmbedding(config2) {
|
|
158668
158963
|
const nextConfig = resolveEmbeddingConfig(config2);
|
|
158669
|
-
const
|
|
158964
|
+
const nextProviderIdentity = resolveProviderIdentity(nextConfig);
|
|
158670
158965
|
const previousProvider = provider;
|
|
158671
|
-
const
|
|
158672
|
-
if (
|
|
158966
|
+
const previousProviderIdentity = previousProvider?.modelId ?? resolveProviderIdentity(embeddingConfig);
|
|
158967
|
+
if (previousProviderIdentity === nextProviderIdentity) {
|
|
158673
158968
|
embeddingConfig = nextConfig;
|
|
158674
158969
|
return;
|
|
158675
158970
|
}
|
|
@@ -158796,9 +159091,9 @@ var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMe
|
|
|
158796
159091
|
var init_embedding = __esm(() => {
|
|
158797
159092
|
init_magic_context();
|
|
158798
159093
|
init_logger();
|
|
159094
|
+
init_embedding_identity();
|
|
158799
159095
|
init_embedding_local();
|
|
158800
159096
|
init_embedding_openai();
|
|
158801
|
-
init_normalize_hash();
|
|
158802
159097
|
init_storage_memory_embeddings();
|
|
158803
159098
|
DEFAULT_EMBEDDING_CONFIG = {
|
|
158804
159099
|
provider: "local",
|
|
@@ -158845,7 +159140,7 @@ var init_storage_memory_fts = __esm(() => {
|
|
|
158845
159140
|
|
|
158846
159141
|
// src/features/magic-context/memory/project-identity.ts
|
|
158847
159142
|
import { execSync } from "node:child_process";
|
|
158848
|
-
import { createHash as
|
|
159143
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
158849
159144
|
import path4 from "node:path";
|
|
158850
159145
|
function getRootCommitHash(directory) {
|
|
158851
159146
|
try {
|
|
@@ -158864,7 +159159,7 @@ function getRootCommitHash(directory) {
|
|
|
158864
159159
|
}
|
|
158865
159160
|
function directoryFallback(directory) {
|
|
158866
159161
|
const canonical = path4.resolve(directory);
|
|
158867
|
-
const hash2 =
|
|
159162
|
+
const hash2 = createHash3("md5").update(canonical).digest("hex").slice(0, 12);
|
|
158868
159163
|
return `dir:${hash2}`;
|
|
158869
159164
|
}
|
|
158870
159165
|
function resolveProjectIdentity(directory) {
|
|
@@ -159914,6 +160209,9 @@ var init_migrations = __esm(async () => {
|
|
|
159914
160209
|
embedding BLOB NOT NULL,
|
|
159915
160210
|
model_id TEXT NOT NULL,
|
|
159916
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.
|
|
159917
160215
|
FOREIGN KEY(sha) REFERENCES git_commits(sha) ON DELETE CASCADE
|
|
159918
160216
|
);
|
|
159919
160217
|
|
|
@@ -160034,15 +160332,57 @@ var init_migrations = __esm(async () => {
|
|
|
160034
160332
|
WHERE type = 'tool' AND tool_owner_message_id IS NULL;
|
|
160035
160333
|
`);
|
|
160036
160334
|
}
|
|
160335
|
+
},
|
|
160336
|
+
{
|
|
160337
|
+
version: 11,
|
|
160338
|
+
description: "Add todo state synthesis columns to session_meta",
|
|
160339
|
+
up: (db) => {
|
|
160340
|
+
const cols = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
160341
|
+
if (!cols.some((c) => c.name === "last_todo_state")) {
|
|
160342
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN last_todo_state TEXT DEFAULT ''");
|
|
160343
|
+
}
|
|
160344
|
+
if (!cols.some((c) => c.name === "todo_synthetic_call_id")) {
|
|
160345
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_call_id TEXT DEFAULT ''");
|
|
160346
|
+
}
|
|
160347
|
+
if (!cols.some((c) => c.name === "todo_synthetic_anchor_message_id")) {
|
|
160348
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_anchor_message_id TEXT DEFAULT ''");
|
|
160349
|
+
}
|
|
160350
|
+
if (!cols.some((c) => c.name === "todo_synthetic_state_json")) {
|
|
160351
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_state_json TEXT DEFAULT ''");
|
|
160352
|
+
}
|
|
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
|
+
}
|
|
160037
160377
|
}
|
|
160038
160378
|
];
|
|
160039
160379
|
});
|
|
160040
160380
|
|
|
160041
160381
|
// src/features/magic-context/tool-owner-backfill.ts
|
|
160042
160382
|
import { existsSync as existsSync10 } from "node:fs";
|
|
160043
|
-
import { join as
|
|
160383
|
+
import { join as join14 } from "node:path";
|
|
160044
160384
|
function resolveOpencodeDbPath() {
|
|
160045
|
-
return
|
|
160385
|
+
return join14(getDataDir(), "opencode", "opencode.db");
|
|
160046
160386
|
}
|
|
160047
160387
|
function ensureBackfillStateTable(db) {
|
|
160048
160388
|
db.exec(`
|
|
@@ -160287,24 +160627,24 @@ var init_tool_owner_backfill = __esm(() => {
|
|
|
160287
160627
|
});
|
|
160288
160628
|
|
|
160289
160629
|
// src/features/magic-context/storage-db.ts
|
|
160290
|
-
import { copyFileSync, cpSync, existsSync as existsSync11, mkdirSync as
|
|
160291
|
-
import { join as
|
|
160630
|
+
import { copyFileSync, cpSync, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "node:fs";
|
|
160631
|
+
import { join as join15 } from "node:path";
|
|
160292
160632
|
function resolveDatabasePath() {
|
|
160293
160633
|
const dbDir = getMagicContextStorageDir();
|
|
160294
|
-
return { dbDir, dbPath:
|
|
160634
|
+
return { dbDir, dbPath: join15(dbDir, "context.db") };
|
|
160295
160635
|
}
|
|
160296
160636
|
function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
160297
160637
|
if (existsSync11(targetDbPath))
|
|
160298
160638
|
return;
|
|
160299
160639
|
const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
|
|
160300
|
-
const legacyDbPath =
|
|
160640
|
+
const legacyDbPath = join15(legacyDir, "context.db");
|
|
160301
160641
|
if (!existsSync11(legacyDbPath))
|
|
160302
160642
|
return;
|
|
160303
160643
|
log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
|
|
160304
|
-
|
|
160644
|
+
mkdirSync5(targetDbDir, { recursive: true });
|
|
160305
160645
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
160306
160646
|
const src = `${legacyDbPath}${suffix}`;
|
|
160307
|
-
const dst =
|
|
160647
|
+
const dst = join15(targetDbDir, `context.db${suffix}`);
|
|
160308
160648
|
if (existsSync11(src)) {
|
|
160309
160649
|
try {
|
|
160310
160650
|
copyFileSync(src, dst);
|
|
@@ -160313,8 +160653,8 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
160313
160653
|
}
|
|
160314
160654
|
}
|
|
160315
160655
|
}
|
|
160316
|
-
const legacyModelsDir =
|
|
160317
|
-
const targetModelsDir =
|
|
160656
|
+
const legacyModelsDir = join15(legacyDir, "models");
|
|
160657
|
+
const targetModelsDir = join15(targetDbDir, "models");
|
|
160318
160658
|
if (existsSync11(legacyModelsDir) && !existsSync11(targetModelsDir)) {
|
|
160319
160659
|
try {
|
|
160320
160660
|
cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
|
|
@@ -160324,9 +160664,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
160324
160664
|
}
|
|
160325
160665
|
}
|
|
160326
160666
|
function initializeDatabase(db) {
|
|
160667
|
+
db.exec("PRAGMA foreign_keys=ON");
|
|
160327
160668
|
db.exec("PRAGMA journal_mode=WAL");
|
|
160328
160669
|
db.exec("PRAGMA busy_timeout=5000");
|
|
160329
|
-
db.exec("PRAGMA foreign_keys=ON");
|
|
160330
160670
|
db.exec(`
|
|
160331
160671
|
CREATE TABLE IF NOT EXISTS tags (
|
|
160332
160672
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -160424,6 +160764,9 @@ function initializeDatabase(db) {
|
|
|
160424
160764
|
);
|
|
160425
160765
|
|
|
160426
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.
|
|
160427
160770
|
memory_id INTEGER PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
|
|
160428
160771
|
embedding BLOB NOT NULL,
|
|
160429
160772
|
model_id TEXT
|
|
@@ -160516,6 +160859,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160516
160859
|
note_nudge_trigger_message_id TEXT DEFAULT '',
|
|
160517
160860
|
note_nudge_sticky_text TEXT DEFAULT '',
|
|
160518
160861
|
note_nudge_sticky_message_id TEXT DEFAULT '',
|
|
160862
|
+
last_todo_state TEXT DEFAULT '',
|
|
160863
|
+
todo_synthetic_call_id TEXT DEFAULT '',
|
|
160864
|
+
todo_synthetic_anchor_message_id TEXT DEFAULT '',
|
|
160865
|
+
todo_synthetic_state_json TEXT DEFAULT '',
|
|
160519
160866
|
is_subagent INTEGER DEFAULT 0,
|
|
160520
160867
|
last_context_percentage REAL DEFAULT 0,
|
|
160521
160868
|
last_input_tokens INTEGER DEFAULT 0,
|
|
@@ -160527,7 +160874,13 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160527
160874
|
system_prompt_hash TEXT DEFAULT '',
|
|
160528
160875
|
memory_block_cache TEXT DEFAULT '',
|
|
160529
160876
|
memory_block_count INTEGER DEFAULT 0,
|
|
160530
|
-
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
|
|
160531
160884
|
);
|
|
160532
160885
|
|
|
160533
160886
|
CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
|
|
@@ -160580,6 +160933,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160580
160933
|
ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
|
|
160581
160934
|
ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
|
|
160582
160935
|
ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
|
|
160936
|
+
ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
|
|
160937
|
+
ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
|
|
160938
|
+
ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
|
|
160939
|
+
ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
|
|
160583
160940
|
ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
|
|
160584
160941
|
ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
|
|
160585
160942
|
ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
|
|
@@ -160611,6 +160968,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160611
160968
|
ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
|
|
160612
160969
|
ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
|
|
160613
160970
|
ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
|
|
160971
|
+
ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
|
|
160614
160972
|
ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
160615
160973
|
ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
160616
160974
|
ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
@@ -160644,6 +161002,10 @@ function healNullTextColumns(db) {
|
|
|
160644
161002
|
["note_nudge_trigger_message_id", ""],
|
|
160645
161003
|
["note_nudge_sticky_text", ""],
|
|
160646
161004
|
["note_nudge_sticky_message_id", ""],
|
|
161005
|
+
["last_todo_state", ""],
|
|
161006
|
+
["todo_synthetic_call_id", ""],
|
|
161007
|
+
["todo_synthetic_anchor_message_id", ""],
|
|
161008
|
+
["todo_synthetic_state_json", ""],
|
|
160647
161009
|
["system_prompt_hash", ""],
|
|
160648
161010
|
["stripped_placeholder_ids", ""],
|
|
160649
161011
|
["memory_block_cache", ""],
|
|
@@ -160696,7 +161058,7 @@ function openDatabase() {
|
|
|
160696
161058
|
}
|
|
160697
161059
|
try {
|
|
160698
161060
|
migrateLegacyStorageIfNeeded(dbPath, dbDir);
|
|
160699
|
-
|
|
161061
|
+
mkdirSync5(dbDir, { recursive: true });
|
|
160700
161062
|
const db = new Database(dbPath);
|
|
160701
161063
|
initializeDatabase(db);
|
|
160702
161064
|
runMigrations(db);
|
|
@@ -160749,7 +161111,7 @@ function isSessionMetaRow(row) {
|
|
|
160749
161111
|
if (row === null || typeof row !== "object")
|
|
160750
161112
|
return false;
|
|
160751
161113
|
const r = row;
|
|
160752
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag);
|
|
161114
|
+
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state);
|
|
160753
161115
|
}
|
|
160754
161116
|
function getDefaultSessionMeta(sessionId) {
|
|
160755
161117
|
return {
|
|
@@ -160769,7 +161131,8 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
160769
161131
|
systemPromptTokens: 0,
|
|
160770
161132
|
conversationTokens: 0,
|
|
160771
161133
|
toolCallTokens: 0,
|
|
160772
|
-
clearedReasoningThroughTag: 0
|
|
161134
|
+
clearedReasoningThroughTag: 0,
|
|
161135
|
+
lastTodoState: ""
|
|
160773
161136
|
};
|
|
160774
161137
|
}
|
|
160775
161138
|
function ensureSessionMetaRow(db, sessionId) {
|
|
@@ -160781,6 +161144,7 @@ function toSessionMeta(row) {
|
|
|
160781
161144
|
const transformErrorRaw = typeof row.last_transform_error === "string" ? row.last_transform_error : "";
|
|
160782
161145
|
const cacheTtlRaw = typeof row.cache_ttl === "string" && row.cache_ttl.length > 0 ? row.cache_ttl : "5m";
|
|
160783
161146
|
const systemPromptHashRaw = row.system_prompt_hash == null ? "" : row.system_prompt_hash;
|
|
161147
|
+
const lastTodoStateRaw = typeof row.last_todo_state === "string" ? row.last_todo_state : "";
|
|
160784
161148
|
const numOrZero = (value) => typeof value === "number" ? value : 0;
|
|
160785
161149
|
return {
|
|
160786
161150
|
sessionId: row.session_id,
|
|
@@ -160799,7 +161163,8 @@ function toSessionMeta(row) {
|
|
|
160799
161163
|
systemPromptTokens: numOrZero(row.system_prompt_tokens),
|
|
160800
161164
|
conversationTokens: numOrZero(row.conversation_tokens),
|
|
160801
161165
|
toolCallTokens: numOrZero(row.tool_call_tokens),
|
|
160802
|
-
clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag)
|
|
161166
|
+
clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag),
|
|
161167
|
+
lastTodoState: lastTodoStateRaw
|
|
160803
161168
|
};
|
|
160804
161169
|
}
|
|
160805
161170
|
var META_COLUMNS, BOOLEAN_META_KEYS;
|
|
@@ -160820,7 +161185,8 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
160820
161185
|
systemPromptTokens: "system_prompt_tokens",
|
|
160821
161186
|
conversationTokens: "conversation_tokens",
|
|
160822
161187
|
toolCallTokens: "tool_call_tokens",
|
|
160823
|
-
clearedReasoningThroughTag: "cleared_reasoning_through_tag"
|
|
161188
|
+
clearedReasoningThroughTag: "cleared_reasoning_through_tag",
|
|
161189
|
+
lastTodoState: "last_todo_state"
|
|
160824
161190
|
};
|
|
160825
161191
|
BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress"]);
|
|
160826
161192
|
});
|
|
@@ -160856,6 +161222,12 @@ function isPersistedNoteNudgeRow(row) {
|
|
|
160856
161222
|
const r = row;
|
|
160857
161223
|
return typeof r.note_nudge_trigger_pending === "number" && typeof r.note_nudge_trigger_message_id === "string" && typeof r.note_nudge_sticky_text === "string" && typeof r.note_nudge_sticky_message_id === "string";
|
|
160858
161224
|
}
|
|
161225
|
+
function isPersistedTodoSyntheticAnchorRow(row) {
|
|
161226
|
+
if (row === null || typeof row !== "object")
|
|
161227
|
+
return false;
|
|
161228
|
+
const r = row;
|
|
161229
|
+
return typeof r.todo_synthetic_call_id === "string" && typeof r.todo_synthetic_anchor_message_id === "string" && typeof r.todo_synthetic_state_json === "string";
|
|
161230
|
+
}
|
|
160859
161231
|
function isPersistedHistorianFailureRow(row) {
|
|
160860
161232
|
if (row === null || typeof row !== "object")
|
|
160861
161233
|
return false;
|
|
@@ -160978,6 +161350,29 @@ function setPersistedDeliveredNoteNudge(db, sessionId, text, messageId = "") {
|
|
|
160978
161350
|
function clearPersistedNoteNudge(db, sessionId) {
|
|
160979
161351
|
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '', note_nudge_sticky_text = '', note_nudge_sticky_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
160980
161352
|
}
|
|
161353
|
+
function getPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
161354
|
+
const result = db.prepare("SELECT todo_synthetic_call_id, todo_synthetic_anchor_message_id, todo_synthetic_state_json FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161355
|
+
if (!isPersistedTodoSyntheticAnchorRow(result)) {
|
|
161356
|
+
return null;
|
|
161357
|
+
}
|
|
161358
|
+
if (result.todo_synthetic_call_id.length === 0 || result.todo_synthetic_anchor_message_id.length === 0) {
|
|
161359
|
+
return null;
|
|
161360
|
+
}
|
|
161361
|
+
return {
|
|
161362
|
+
callId: result.todo_synthetic_call_id,
|
|
161363
|
+
messageId: result.todo_synthetic_anchor_message_id,
|
|
161364
|
+
stateJson: result.todo_synthetic_state_json
|
|
161365
|
+
};
|
|
161366
|
+
}
|
|
161367
|
+
function setPersistedTodoSyntheticAnchor(db, sessionId, callId, messageId, stateJson) {
|
|
161368
|
+
db.transaction(() => {
|
|
161369
|
+
ensureSessionMetaRow(db, sessionId);
|
|
161370
|
+
db.prepare("UPDATE session_meta SET todo_synthetic_call_id = ?, todo_synthetic_anchor_message_id = ?, todo_synthetic_state_json = ? WHERE session_id = ?").run(callId, messageId, stateJson, sessionId);
|
|
161371
|
+
})();
|
|
161372
|
+
}
|
|
161373
|
+
function clearPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
161374
|
+
db.prepare("UPDATE session_meta SET todo_synthetic_call_id = '', todo_synthetic_anchor_message_id = '', todo_synthetic_state_json = '' WHERE session_id = ?").run(sessionId);
|
|
161375
|
+
}
|
|
160981
161376
|
function getNoteLastReadAt(db, sessionId) {
|
|
160982
161377
|
try {
|
|
160983
161378
|
const result = db.prepare("SELECT note_last_read_at FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
@@ -161104,6 +161499,39 @@ function removeStrippedPlaceholderId(db, sessionId, messageId) {
|
|
|
161104
161499
|
setStrippedPlaceholderIds(db, sessionId, ids);
|
|
161105
161500
|
return true;
|
|
161106
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
|
+
}
|
|
161107
161535
|
var init_storage_meta_persisted = __esm(() => {
|
|
161108
161536
|
init_logger();
|
|
161109
161537
|
init_storage_meta_shared();
|
|
@@ -161130,7 +161558,7 @@ var init_resolve_subagent_fallback = __esm(async () => {
|
|
|
161130
161558
|
|
|
161131
161559
|
// src/features/magic-context/storage-meta-session.ts
|
|
161132
161560
|
function getOrCreateSessionMeta(db, sessionId) {
|
|
161133
|
-
const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161561
|
+
const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag, last_todo_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161134
161562
|
if (isSessionMetaRow(result)) {
|
|
161135
161563
|
return toSessionMeta(result);
|
|
161136
161564
|
}
|
|
@@ -161631,12 +162059,12 @@ var init_storage = __esm(async () => {
|
|
|
161631
162059
|
});
|
|
161632
162060
|
|
|
161633
162061
|
// src/shared/models-dev-cache.ts
|
|
161634
|
-
import { createHash as
|
|
162062
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
161635
162063
|
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
|
|
161636
162064
|
import { homedir as homedir8, platform as platform3 } from "node:os";
|
|
161637
|
-
import { join as
|
|
162065
|
+
import { join as join16 } from "node:path";
|
|
161638
162066
|
function hashFast(input) {
|
|
161639
|
-
return
|
|
162067
|
+
return createHash4("sha1").update(input).digest("hex");
|
|
161640
162068
|
}
|
|
161641
162069
|
function getModelsJsonPath() {
|
|
161642
162070
|
const explicit = process.env.OPENCODE_MODELS_PATH?.trim();
|
|
@@ -161645,15 +162073,15 @@ function getModelsJsonPath() {
|
|
|
161645
162073
|
const cacheBase = getCacheDir();
|
|
161646
162074
|
const source = process.env.OPENCODE_MODELS_URL?.trim();
|
|
161647
162075
|
const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
|
|
161648
|
-
return
|
|
162076
|
+
return join16(cacheBase, "opencode", filename);
|
|
161649
162077
|
}
|
|
161650
162078
|
function getOpencodeConfigPath() {
|
|
161651
162079
|
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
161652
|
-
const configDir = envDir ? envDir : platform3() === "win32" ?
|
|
161653
|
-
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");
|
|
161654
162082
|
if (existsSync12(jsonc))
|
|
161655
162083
|
return jsonc;
|
|
161656
|
-
const json2 =
|
|
162084
|
+
const json2 = join16(configDir, "opencode.json");
|
|
161657
162085
|
if (existsSync12(json2))
|
|
161658
162086
|
return json2;
|
|
161659
162087
|
return null;
|
|
@@ -161704,9 +162132,7 @@ function loadModelsDevMetadataFromFile() {
|
|
|
161704
162132
|
try {
|
|
161705
162133
|
const configPath = getOpencodeConfigPath();
|
|
161706
162134
|
if (configPath && existsSync12(configPath)) {
|
|
161707
|
-
|
|
161708
|
-
raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
|
|
161709
|
-
const config2 = JSON.parse(raw);
|
|
162135
|
+
const config2 = parseJsonc(readFileSync8(configPath, "utf-8"));
|
|
161710
162136
|
if (config2.provider && typeof config2.provider === "object") {
|
|
161711
162137
|
for (const [providerId, provider2] of Object.entries(config2.provider)) {
|
|
161712
162138
|
if (!provider2?.models || typeof provider2.models !== "object")
|
|
@@ -161778,6 +162204,7 @@ function getModelsDevContextLimit(providerID, modelID) {
|
|
|
161778
162204
|
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, recentlySeenApiSizes, oscillationLogged = false, fileCache = null, fileLastAttempt = 0;
|
|
161779
162205
|
var init_models_dev_cache = __esm(() => {
|
|
161780
162206
|
init_data_path();
|
|
162207
|
+
init_jsonc_parser();
|
|
161781
162208
|
init_logger();
|
|
161782
162209
|
RELOAD_INTERVAL_MS = 5 * 60 * 1000;
|
|
161783
162210
|
recentlySeenApiSizes = new Set;
|
|
@@ -161791,25 +162218,359 @@ __export(exports_rpc_notifications, {
|
|
|
161791
162218
|
drainNotifications: () => drainNotifications
|
|
161792
162219
|
});
|
|
161793
162220
|
function pushNotification(type, payload, sessionId) {
|
|
161794
|
-
queue2.push({ type, payload, sessionId });
|
|
162221
|
+
queue2.push({ id: nextNotificationId++, type, payload, sessionId });
|
|
161795
162222
|
if (queue2.length > 100) {
|
|
161796
162223
|
queue2 = queue2.slice(-50);
|
|
161797
162224
|
}
|
|
161798
162225
|
}
|
|
161799
|
-
function drainNotifications() {
|
|
162226
|
+
function drainNotifications(lastReceivedId = 0) {
|
|
161800
162227
|
lastDrainAt = Date.now();
|
|
161801
|
-
|
|
161802
|
-
|
|
161803
|
-
|
|
162228
|
+
if (lastReceivedId > 0) {
|
|
162229
|
+
queue2 = queue2.filter((notification) => notification.id > lastReceivedId);
|
|
162230
|
+
}
|
|
162231
|
+
return [...queue2];
|
|
161804
162232
|
}
|
|
161805
162233
|
function isTuiConnected() {
|
|
161806
162234
|
return lastDrainAt > 0 && Date.now() - lastDrainAt < TUI_CONNECTED_WINDOW_MS;
|
|
161807
162235
|
}
|
|
161808
|
-
var queue2, lastDrainAt = 0, TUI_CONNECTED_WINDOW_MS = 3000;
|
|
162236
|
+
var queue2, nextNotificationId = 1, lastDrainAt = 0, TUI_CONNECTED_WINDOW_MS = 3000;
|
|
161809
162237
|
var init_rpc_notifications = __esm(() => {
|
|
161810
162238
|
queue2 = [];
|
|
161811
162239
|
});
|
|
161812
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
|
+
|
|
161813
162574
|
// src/hooks/magic-context/compartment-parser.ts
|
|
161814
162575
|
function parseCompartmentOutput(text) {
|
|
161815
162576
|
const compartments = [];
|
|
@@ -162030,9 +162791,11 @@ var init_compartment_runner_validation = __esm(async () => {
|
|
|
162030
162791
|
});
|
|
162031
162792
|
|
|
162032
162793
|
// src/hooks/magic-context/compartment-runner-historian.ts
|
|
162033
|
-
import { mkdirSync as
|
|
162034
|
-
import {
|
|
162035
|
-
|
|
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
|
+
}
|
|
162036
162799
|
async function runValidatedHistorianPass(args) {
|
|
162037
162800
|
const firstRun = await runHistorianPrompt({
|
|
162038
162801
|
...args,
|
|
@@ -162125,7 +162888,8 @@ async function runHistorianPrompt(args) {
|
|
|
162125
162888
|
timeoutMs,
|
|
162126
162889
|
dumpLabel,
|
|
162127
162890
|
modelOverride,
|
|
162128
|
-
agentId = HISTORIAN_AGENT
|
|
162891
|
+
agentId = HISTORIAN_AGENT,
|
|
162892
|
+
fallbackModels
|
|
162129
162893
|
} = args;
|
|
162130
162894
|
let agentSessionId = null;
|
|
162131
162895
|
try {
|
|
@@ -162152,7 +162916,11 @@ async function runHistorianPrompt(args) {
|
|
|
162152
162916
|
...modelOverride ? { model: modelOverride } : {},
|
|
162153
162917
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
162154
162918
|
}
|
|
162155
|
-
}, {
|
|
162919
|
+
}, {
|
|
162920
|
+
timeoutMs: timeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
162921
|
+
fallbackModels: modelOverride ? undefined : fallbackModels,
|
|
162922
|
+
callContext: agentId === HISTORIAN_EDITOR_AGENT ? "historian:editor" : "historian"
|
|
162923
|
+
});
|
|
162156
162924
|
sessionLog(parentSessionId, `historian: prompt completed (attempt ${retryIndex + 1}/${MAX_HISTORIAN_RETRIES + 1})`);
|
|
162157
162925
|
break;
|
|
162158
162926
|
} catch (error51) {
|
|
@@ -162178,7 +162946,7 @@ async function runHistorianPrompt(args) {
|
|
|
162178
162946
|
if (!result) {
|
|
162179
162947
|
return { ok: false, error: "Historian returned no assistant output." };
|
|
162180
162948
|
}
|
|
162181
|
-
const dumpPath = dumpHistorianResponse(parentSessionId, dumpLabel ?? "historian-response", result);
|
|
162949
|
+
const dumpPath = dumpHistorianResponse(parentSessionId, sessionDirectory, dumpLabel ?? "historian-response", result);
|
|
162182
162950
|
return { ok: true, result, dumpPath };
|
|
162183
162951
|
} catch (modelError) {
|
|
162184
162952
|
const desc = describeError(modelError);
|
|
@@ -162270,12 +163038,13 @@ function cleanupHistorianDump(sessionId, dumpPath) {
|
|
|
162270
163038
|
});
|
|
162271
163039
|
}
|
|
162272
163040
|
}
|
|
162273
|
-
function dumpHistorianResponse(sessionId, label, text) {
|
|
163041
|
+
function dumpHistorianResponse(sessionId, directory, label, text) {
|
|
162274
163042
|
try {
|
|
162275
|
-
|
|
163043
|
+
const dumpDir = historianResponseDumpDir(directory);
|
|
163044
|
+
mkdirSync6(dumpDir, { recursive: true });
|
|
162276
163045
|
const safeSessionId = sanitizeDumpName(sessionId);
|
|
162277
163046
|
const safeLabel = sanitizeDumpName(label);
|
|
162278
|
-
const dumpPath =
|
|
163047
|
+
const dumpPath = join19(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
|
|
162279
163048
|
writeFileSync5(dumpPath, text, "utf8");
|
|
162280
163049
|
sessionLog(sessionId, "compartment agent: historian response dumped", {
|
|
162281
163050
|
label,
|
|
@@ -162293,14 +163062,14 @@ function dumpHistorianResponse(sessionId, label, text) {
|
|
|
162293
163062
|
function sanitizeDumpName(value) {
|
|
162294
163063
|
return value.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
162295
163064
|
}
|
|
162296
|
-
var
|
|
163065
|
+
var MAX_HISTORIAN_RETRIES = 2;
|
|
162297
163066
|
var init_compartment_runner_historian = __esm(async () => {
|
|
162298
163067
|
init_magic_context();
|
|
162299
163068
|
init_shared();
|
|
162300
163069
|
init_assistant_message_extractor();
|
|
163070
|
+
init_data_path();
|
|
162301
163071
|
init_compartment_prompt();
|
|
162302
163072
|
await init_compartment_runner_validation();
|
|
162303
|
-
HISTORIAN_RESPONSE_DUMP_DIR = join18(tmpdir2(), "magic-context-historian");
|
|
162304
163073
|
});
|
|
162305
163074
|
|
|
162306
163075
|
// src/hooks/magic-context/compartment-runner-state-xml.ts
|
|
@@ -162602,16 +163371,24 @@ function trimMemoriesToBudget(sessionId, memories, budgetTokens) {
|
|
|
162602
163371
|
function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectPath, injectionBudgetTokens, temporalAwareness) {
|
|
162603
163372
|
const cached2 = injectionCache.get(sessionId);
|
|
162604
163373
|
if (!isCacheBusting && cached2) {
|
|
162605
|
-
if (cached2.
|
|
162606
|
-
|
|
162607
|
-
|
|
162608
|
-
|
|
162609
|
-
|
|
162610
|
-
|
|
162611
|
-
|
|
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
|
+
}
|
|
162612
163389
|
}
|
|
163390
|
+
return { ...prepared, rebuiltFromDb: false };
|
|
162613
163391
|
}
|
|
162614
|
-
return cached2;
|
|
162615
163392
|
}
|
|
162616
163393
|
const compartments = getCompartments(db, sessionId);
|
|
162617
163394
|
const facts = getSessionFacts(db, sessionId);
|
|
@@ -162643,7 +163420,11 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162643
163420
|
}
|
|
162644
163421
|
}
|
|
162645
163422
|
if (compartments.length === 0 && facts.length === 0 && !memoryBlock) {
|
|
162646
|
-
injectionCache.
|
|
163423
|
+
injectionCache.set(sessionId, {
|
|
163424
|
+
kind: "empty",
|
|
163425
|
+
compartmentEndMessageId: "",
|
|
163426
|
+
renderedBytes: 0
|
|
163427
|
+
});
|
|
162647
163428
|
return null;
|
|
162648
163429
|
}
|
|
162649
163430
|
let dateRanges;
|
|
@@ -162676,9 +163457,10 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162676
163457
|
compartmentCount: 0,
|
|
162677
163458
|
skippedVisibleMessages: 0,
|
|
162678
163459
|
factCount: facts.length,
|
|
162679
|
-
memoryCount
|
|
163460
|
+
memoryCount,
|
|
163461
|
+
rebuiltFromDb: true
|
|
162680
163462
|
};
|
|
162681
|
-
injectionCache.set(sessionId, result2);
|
|
163463
|
+
injectionCache.set(sessionId, { kind: "populated", injection: result2 });
|
|
162682
163464
|
return result2;
|
|
162683
163465
|
}
|
|
162684
163466
|
const lastCompartment = compartments[compartments.length - 1];
|
|
@@ -162696,9 +163478,10 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162696
163478
|
compartmentCount: compartments.length,
|
|
162697
163479
|
skippedVisibleMessages: 0,
|
|
162698
163480
|
factCount: facts.length,
|
|
162699
|
-
memoryCount
|
|
163481
|
+
memoryCount,
|
|
163482
|
+
rebuiltFromDb: true
|
|
162700
163483
|
};
|
|
162701
|
-
injectionCache.set(sessionId, result2);
|
|
163484
|
+
injectionCache.set(sessionId, { kind: "populated", injection: result2 });
|
|
162702
163485
|
return result2;
|
|
162703
163486
|
}
|
|
162704
163487
|
let skippedVisibleMessages = 0;
|
|
@@ -162707,17 +163490,20 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
162707
163490
|
skippedVisibleMessages = cutoffIndex + 1;
|
|
162708
163491
|
const remaining = messages.slice(cutoffIndex + 1);
|
|
162709
163492
|
messages.splice(0, messages.length, ...remaining);
|
|
163493
|
+
} else {
|
|
163494
|
+
sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${lastEndMessageId} not in visible messages`);
|
|
162710
163495
|
}
|
|
162711
163496
|
const result = {
|
|
162712
163497
|
block,
|
|
162713
163498
|
compartmentEndMessage: lastEnd,
|
|
162714
|
-
compartmentEndMessageId: lastEndMessageId,
|
|
163499
|
+
compartmentEndMessageId: cutoffIndex >= 0 ? lastEndMessageId : null,
|
|
162715
163500
|
compartmentCount: compartments.length,
|
|
162716
163501
|
skippedVisibleMessages,
|
|
162717
163502
|
factCount: facts.length,
|
|
162718
|
-
memoryCount
|
|
163503
|
+
memoryCount,
|
|
163504
|
+
rebuiltFromDb: true
|
|
162719
163505
|
};
|
|
162720
|
-
injectionCache.set(sessionId, result);
|
|
163506
|
+
injectionCache.set(sessionId, { kind: "populated", injection: result });
|
|
162721
163507
|
return result;
|
|
162722
163508
|
}
|
|
162723
163509
|
function renderCompartmentInjection(sessionId, messages, prepared) {
|
|
@@ -163009,9 +163795,18 @@ async function executePartialRecompInternal(deps, range) {
|
|
|
163009
163795
|
}
|
|
163010
163796
|
setRecompPartialRange(db, sessionId, null);
|
|
163011
163797
|
clearCompressionDepthRange(db, sessionId, snapStart, snapEnd);
|
|
163012
|
-
|
|
163013
|
-
|
|
163798
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
163799
|
+
clearInjectionCache(sessionId);
|
|
163800
|
+
}
|
|
163801
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
163014
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
|
+
}
|
|
163015
163810
|
return { compartmentCount: merged.length, lastEndMessage: lastEnd };
|
|
163016
163811
|
};
|
|
163017
163812
|
const protectedTailStart = getProtectedTailStartOrdinal(sessionId);
|
|
@@ -163117,6 +163912,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
163117
163912
|
dumpLabelBase: `partial-recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
|
|
163118
163913
|
timeoutMs: historianTimeoutMs,
|
|
163119
163914
|
fallbackModelId: deps.fallbackModelId,
|
|
163915
|
+
fallbackModels: deps.fallbackModels,
|
|
163120
163916
|
twoPass: deps.historianTwoPass,
|
|
163121
163917
|
callbacks: {
|
|
163122
163918
|
onRepairRetry: async (error51) => {
|
|
@@ -163210,6 +164006,7 @@ var init_compartment_runner_partial_recomp = __esm(async () => {
|
|
|
163210
164006
|
init_send_session_notification();
|
|
163211
164007
|
await __promiseAll([
|
|
163212
164008
|
init_storage_meta(),
|
|
164009
|
+
init_compaction_marker_manager(),
|
|
163213
164010
|
init_compartment_runner_historian(),
|
|
163214
164011
|
init_compartment_runner_validation(),
|
|
163215
164012
|
init_inject_compartments(),
|
|
@@ -163278,269 +164075,6 @@ var init_derive_budgets = __esm(() => {
|
|
|
163278
164075
|
init_models_dev_cache();
|
|
163279
164076
|
});
|
|
163280
164077
|
|
|
163281
|
-
// src/features/magic-context/compaction-marker.ts
|
|
163282
|
-
import { join as join19 } from "node:path";
|
|
163283
|
-
function randomBase62(length) {
|
|
163284
|
-
const chars = [];
|
|
163285
|
-
for (let i = 0;i < length; i++) {
|
|
163286
|
-
chars.push(BASE62_CHARS[Math.floor(Math.random() * BASE62_CHARS.length)]);
|
|
163287
|
-
}
|
|
163288
|
-
return chars.join("");
|
|
163289
|
-
}
|
|
163290
|
-
function generateId(prefix, timestampMs, counter = 0n) {
|
|
163291
|
-
const encoded = BigInt(timestampMs) * 0x1000n + counter;
|
|
163292
|
-
const hex3 = encoded.toString(16).padStart(14, "0");
|
|
163293
|
-
return `${prefix}_${hex3}${randomBase62(14)}`;
|
|
163294
|
-
}
|
|
163295
|
-
function generateMessageId(timestampMs, counter = 0n) {
|
|
163296
|
-
return generateId("msg", timestampMs, counter);
|
|
163297
|
-
}
|
|
163298
|
-
function generatePartId(timestampMs, counter = 0n) {
|
|
163299
|
-
return generateId("prt", timestampMs, counter);
|
|
163300
|
-
}
|
|
163301
|
-
function getOpenCodeDbPath3() {
|
|
163302
|
-
return join19(getDataDir(), "opencode", "opencode.db");
|
|
163303
|
-
}
|
|
163304
|
-
function isOpenCodeSchemaCompatible(db, dbPath) {
|
|
163305
|
-
if (cachedSchemaCompatible?.path === dbPath) {
|
|
163306
|
-
return cachedSchemaCompatible.compatible;
|
|
163307
|
-
}
|
|
163308
|
-
try {
|
|
163309
|
-
const messageCols = new Set(db.prepare("PRAGMA table_info(message)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
163310
|
-
const partCols = new Set(db.prepare("PRAGMA table_info(part)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
163311
|
-
const missingMessage = REQUIRED_MESSAGE_COLUMNS.filter((c) => !messageCols.has(c));
|
|
163312
|
-
const missingPart = REQUIRED_PART_COLUMNS.filter((c) => !partCols.has(c));
|
|
163313
|
-
if (missingMessage.length > 0 || missingPart.length > 0) {
|
|
163314
|
-
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.`);
|
|
163315
|
-
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
163316
|
-
return false;
|
|
163317
|
-
}
|
|
163318
|
-
cachedSchemaCompatible = { path: dbPath, compatible: true };
|
|
163319
|
-
return true;
|
|
163320
|
-
} catch (error51) {
|
|
163321
|
-
log(`[magic-context] compaction-marker: schema probe failed: ${error51 instanceof Error ? error51.message : String(error51)}. ` + `Marker injection disabled until next process restart.`);
|
|
163322
|
-
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
163323
|
-
return false;
|
|
163324
|
-
}
|
|
163325
|
-
}
|
|
163326
|
-
function getWritableOpenCodeDb() {
|
|
163327
|
-
const dbPath = getOpenCodeDbPath3();
|
|
163328
|
-
if (cachedWriteDb?.path === dbPath) {
|
|
163329
|
-
return cachedWriteDb.db;
|
|
163330
|
-
}
|
|
163331
|
-
if (cachedWriteDb) {
|
|
163332
|
-
try {
|
|
163333
|
-
closeQuietly(cachedWriteDb.db);
|
|
163334
|
-
} catch {}
|
|
163335
|
-
}
|
|
163336
|
-
const db = new Database(dbPath);
|
|
163337
|
-
db.exec("PRAGMA journal_mode=WAL");
|
|
163338
|
-
db.exec("PRAGMA busy_timeout=5000");
|
|
163339
|
-
cachedWriteDb = { path: dbPath, db };
|
|
163340
|
-
return db;
|
|
163341
|
-
}
|
|
163342
|
-
function findBoundaryUserMessage(sessionId, endOrdinal) {
|
|
163343
|
-
const db = getWritableOpenCodeDb();
|
|
163344
|
-
const rows = db.prepare(`SELECT id, time_created, data
|
|
163345
|
-
FROM message
|
|
163346
|
-
WHERE session_id = ?
|
|
163347
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
163348
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
163349
|
-
ORDER BY time_created ASC, id ASC
|
|
163350
|
-
LIMIT ?`).all(sessionId, endOrdinal);
|
|
163351
|
-
let bestMatch = null;
|
|
163352
|
-
for (const row of rows) {
|
|
163353
|
-
try {
|
|
163354
|
-
const info = JSON.parse(row.data);
|
|
163355
|
-
if (info.role === "user") {
|
|
163356
|
-
bestMatch = { id: row.id, timeCreated: row.time_created };
|
|
163357
|
-
}
|
|
163358
|
-
} catch {}
|
|
163359
|
-
}
|
|
163360
|
-
return bestMatch;
|
|
163361
|
-
}
|
|
163362
|
-
function injectCompactionMarker(args) {
|
|
163363
|
-
const db = getWritableOpenCodeDb();
|
|
163364
|
-
if (!isOpenCodeSchemaCompatible(db, getOpenCodeDbPath3())) {
|
|
163365
|
-
return null;
|
|
163366
|
-
}
|
|
163367
|
-
const boundary = findBoundaryUserMessage(args.sessionId, args.endOrdinal);
|
|
163368
|
-
if (!boundary) {
|
|
163369
|
-
log(`[magic-context] compaction-marker: no user message found at or before ordinal ${args.endOrdinal}`);
|
|
163370
|
-
return null;
|
|
163371
|
-
}
|
|
163372
|
-
const boundaryTime = boundary.timeCreated;
|
|
163373
|
-
const summaryMsgId = generateMessageId(boundaryTime + 1, 1n);
|
|
163374
|
-
const compactionPartId = generatePartId(boundaryTime, 1n);
|
|
163375
|
-
const summaryPartId = generatePartId(boundaryTime + 1, 2n);
|
|
163376
|
-
const summaryMsgData = JSON.stringify({
|
|
163377
|
-
role: "assistant",
|
|
163378
|
-
parentID: boundary.id,
|
|
163379
|
-
summary: true,
|
|
163380
|
-
finish: "stop",
|
|
163381
|
-
mode: "compaction",
|
|
163382
|
-
agent: "compaction",
|
|
163383
|
-
path: { cwd: args.directory, root: args.directory },
|
|
163384
|
-
cost: 0,
|
|
163385
|
-
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
163386
|
-
modelID: "magic-context",
|
|
163387
|
-
providerID: "magic-context",
|
|
163388
|
-
time: { created: boundaryTime + 1 }
|
|
163389
|
-
});
|
|
163390
|
-
try {
|
|
163391
|
-
db.transaction(() => {
|
|
163392
|
-
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}');
|
|
163393
|
-
db.prepare("INSERT INTO message (id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?)").run(summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, summaryMsgData);
|
|
163394
|
-
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 }));
|
|
163395
|
-
})();
|
|
163396
|
-
log(`[magic-context] compaction-marker: injected boundary at user msg ${boundary.id} (ordinal ~${args.endOrdinal}), summary msg ${summaryMsgId}`);
|
|
163397
|
-
return {
|
|
163398
|
-
boundaryMessageId: boundary.id,
|
|
163399
|
-
summaryMessageId: summaryMsgId,
|
|
163400
|
-
compactionPartId,
|
|
163401
|
-
summaryPartId
|
|
163402
|
-
};
|
|
163403
|
-
} catch (error51) {
|
|
163404
|
-
log(`[magic-context] compaction-marker: injection failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163405
|
-
return null;
|
|
163406
|
-
}
|
|
163407
|
-
}
|
|
163408
|
-
function removeCompactionMarker(state) {
|
|
163409
|
-
try {
|
|
163410
|
-
const db = getWritableOpenCodeDb();
|
|
163411
|
-
db.transaction(() => {
|
|
163412
|
-
db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
|
|
163413
|
-
db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
|
|
163414
|
-
db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
|
|
163415
|
-
})();
|
|
163416
|
-
return true;
|
|
163417
|
-
} catch (error51) {
|
|
163418
|
-
log(`[magic-context] compaction-marker: removal failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163419
|
-
return false;
|
|
163420
|
-
}
|
|
163421
|
-
}
|
|
163422
|
-
var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", cachedWriteDb = null, REQUIRED_MESSAGE_COLUMNS, REQUIRED_PART_COLUMNS, cachedSchemaCompatible = null;
|
|
163423
|
-
var init_compaction_marker = __esm(async () => {
|
|
163424
|
-
init_data_path();
|
|
163425
|
-
init_logger();
|
|
163426
|
-
await init_sqlite();
|
|
163427
|
-
REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
|
|
163428
|
-
REQUIRED_PART_COLUMNS = [
|
|
163429
|
-
"id",
|
|
163430
|
-
"message_id",
|
|
163431
|
-
"session_id",
|
|
163432
|
-
"time_created",
|
|
163433
|
-
"time_updated",
|
|
163434
|
-
"data"
|
|
163435
|
-
];
|
|
163436
|
-
});
|
|
163437
|
-
|
|
163438
|
-
// src/hooks/magic-context/compaction-marker-manager.ts
|
|
163439
|
-
import { join as join20 } from "node:path";
|
|
163440
|
-
function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, directory) {
|
|
163441
|
-
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
163442
|
-
if (existing) {
|
|
163443
|
-
if (existing.boundaryOrdinal === lastCompartmentEnd) {
|
|
163444
|
-
return;
|
|
163445
|
-
}
|
|
163446
|
-
try {
|
|
163447
|
-
removeCompactionMarker(existing);
|
|
163448
|
-
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
163449
|
-
sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
|
|
163450
|
-
} catch (error51) {
|
|
163451
|
-
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}, proceeding with new injection:`, error51);
|
|
163452
|
-
}
|
|
163453
|
-
}
|
|
163454
|
-
const result = injectCompactionMarker({
|
|
163455
|
-
sessionId,
|
|
163456
|
-
endOrdinal: lastCompartmentEnd,
|
|
163457
|
-
summaryText: MARKER_SUMMARY_TEXT,
|
|
163458
|
-
directory: directory ?? process.cwd()
|
|
163459
|
-
});
|
|
163460
|
-
if (result) {
|
|
163461
|
-
setPersistedCompactionMarkerState(db, sessionId, {
|
|
163462
|
-
...result,
|
|
163463
|
-
boundaryOrdinal: lastCompartmentEnd
|
|
163464
|
-
});
|
|
163465
|
-
sessionLog(sessionId, `compaction-marker: injected at ordinal ${lastCompartmentEnd}, boundary user msg ${result.boundaryMessageId}`);
|
|
163466
|
-
}
|
|
163467
|
-
}
|
|
163468
|
-
function removeCompactionMarkerForSession(db, sessionId) {
|
|
163469
|
-
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
163470
|
-
if (existing) {
|
|
163471
|
-
try {
|
|
163472
|
-
removeCompactionMarker(existing);
|
|
163473
|
-
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
163474
|
-
sessionLog(sessionId, "compaction-marker: removed on session cleanup");
|
|
163475
|
-
} catch (error51) {
|
|
163476
|
-
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
163477
|
-
sessionLog(sessionId, "compaction-marker: removal failed during session cleanup, cleared persisted state:", error51);
|
|
163478
|
-
}
|
|
163479
|
-
}
|
|
163480
|
-
}
|
|
163481
|
-
function checkCompactionMarkerConsistency(db) {
|
|
163482
|
-
const opencodeDbPath = join20(getDataDir(), "opencode", "opencode.db");
|
|
163483
|
-
let opencodeDb;
|
|
163484
|
-
try {
|
|
163485
|
-
opencodeDb = new Database(opencodeDbPath, { readonly: true });
|
|
163486
|
-
} catch (error51) {
|
|
163487
|
-
log(`[magic-context] compaction-marker consistency check skipped: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163488
|
-
return;
|
|
163489
|
-
}
|
|
163490
|
-
try {
|
|
163491
|
-
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();
|
|
163492
|
-
if (persistedRows.length === 0)
|
|
163493
|
-
return;
|
|
163494
|
-
const checkMessage = opencodeDb.prepare("SELECT 1 FROM message WHERE id = ? LIMIT 1");
|
|
163495
|
-
const checkPart = opencodeDb.prepare("SELECT 1 FROM part WHERE id = ? LIMIT 1");
|
|
163496
|
-
let reconciledCount = 0;
|
|
163497
|
-
for (const row of persistedRows) {
|
|
163498
|
-
const state = getPersistedCompactionMarkerState(db, row.session_id);
|
|
163499
|
-
if (!state)
|
|
163500
|
-
continue;
|
|
163501
|
-
const boundaryExists = checkMessage.get(state.boundaryMessageId) !== null;
|
|
163502
|
-
const summaryMessageExists = checkMessage.get(state.summaryMessageId) !== null;
|
|
163503
|
-
const compactionPartExists = checkPart.get(state.compactionPartId) !== null;
|
|
163504
|
-
const summaryPartExists = checkPart.get(state.summaryPartId) !== null;
|
|
163505
|
-
const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
|
|
163506
|
-
if (allPresent)
|
|
163507
|
-
continue;
|
|
163508
|
-
let removedOk = false;
|
|
163509
|
-
try {
|
|
163510
|
-
removedOk = removeCompactionMarker(state);
|
|
163511
|
-
} catch (error51) {
|
|
163512
|
-
sessionLog(row.session_id, "compaction-marker consistency: partial cleanup of half-written marker failed:", error51);
|
|
163513
|
-
}
|
|
163514
|
-
if (removedOk) {
|
|
163515
|
-
setPersistedCompactionMarkerState(db, row.session_id, null);
|
|
163516
|
-
sessionLog(row.session_id, `compaction-marker consistency: cleared orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); next publication will re-inject`);
|
|
163517
|
-
reconciledCount++;
|
|
163518
|
-
} else {
|
|
163519
|
-
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`);
|
|
163520
|
-
}
|
|
163521
|
-
}
|
|
163522
|
-
if (reconciledCount > 0) {
|
|
163523
|
-
log(`[magic-context] compaction-marker consistency: reconciled ${reconciledCount} session(s) with orphaned marker state at startup`);
|
|
163524
|
-
}
|
|
163525
|
-
} catch (error51) {
|
|
163526
|
-
log(`[magic-context] compaction-marker consistency check failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
163527
|
-
} finally {
|
|
163528
|
-
try {
|
|
163529
|
-
closeQuietly(opencodeDb);
|
|
163530
|
-
} catch {}
|
|
163531
|
-
}
|
|
163532
|
-
}
|
|
163533
|
-
var MARKER_SUMMARY_TEXT = "[Compacted by magic-context — session history is managed by the plugin]";
|
|
163534
|
-
var init_compaction_marker_manager = __esm(async () => {
|
|
163535
|
-
init_storage_meta_persisted();
|
|
163536
|
-
init_data_path();
|
|
163537
|
-
init_logger();
|
|
163538
|
-
await __promiseAll([
|
|
163539
|
-
init_compaction_marker(),
|
|
163540
|
-
init_sqlite()
|
|
163541
|
-
]);
|
|
163542
|
-
});
|
|
163543
|
-
|
|
163544
164078
|
// src/hooks/magic-context/note-nudger.ts
|
|
163545
164079
|
function getPersistedNoteNudgeDeliveredAt(_db, sessionId) {
|
|
163546
164080
|
return lastDeliveredAt.get(sessionId) ?? 0;
|
|
@@ -163866,15 +164400,15 @@ var init_caveman = __esm(() => {
|
|
|
163866
164400
|
});
|
|
163867
164401
|
|
|
163868
164402
|
// src/hooks/magic-context/historian-state-file.ts
|
|
163869
|
-
import { mkdirSync as
|
|
163870
|
-
import {
|
|
163871
|
-
|
|
163872
|
-
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) {
|
|
163873
164406
|
if (existingState.length <= HISTORIAN_STATE_INLINE_THRESHOLD)
|
|
163874
164407
|
return;
|
|
163875
164408
|
try {
|
|
163876
|
-
|
|
163877
|
-
|
|
164409
|
+
const dir = getProjectMagicContextHistorianDir(directory);
|
|
164410
|
+
mkdirSync7(dir, { recursive: true });
|
|
164411
|
+
const path5 = join20(dir, `state-${sessionId}-${Date.now()}.xml`);
|
|
163878
164412
|
writeFileSync6(path5, existingState, "utf8");
|
|
163879
164413
|
return path5;
|
|
163880
164414
|
} catch {
|
|
@@ -163888,9 +164422,9 @@ function cleanupHistorianStateFile(path5) {
|
|
|
163888
164422
|
unlinkSync2(path5);
|
|
163889
164423
|
} catch {}
|
|
163890
164424
|
}
|
|
163891
|
-
var HISTORIAN_STATE_INLINE_THRESHOLD = 30000
|
|
164425
|
+
var HISTORIAN_STATE_INLINE_THRESHOLD = 30000;
|
|
163892
164426
|
var init_historian_state_file = __esm(() => {
|
|
163893
|
-
|
|
164427
|
+
init_data_path();
|
|
163894
164428
|
});
|
|
163895
164429
|
|
|
163896
164430
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
@@ -164318,7 +164852,8 @@ async function runCompressorPass(args) {
|
|
|
164318
164852
|
targetTokens,
|
|
164319
164853
|
outputCount,
|
|
164320
164854
|
outputDepth,
|
|
164321
|
-
historianTimeoutMs
|
|
164855
|
+
historianTimeoutMs,
|
|
164856
|
+
fallbackModels
|
|
164322
164857
|
} = args;
|
|
164323
164858
|
const prompt = buildCompressorPrompt(compartments, currentTokens, targetTokens, outputDepth, outputCount);
|
|
164324
164859
|
let agentSessionId = null;
|
|
@@ -164340,7 +164875,11 @@ async function runCompressorPass(args) {
|
|
|
164340
164875
|
agent: HISTORIAN_AGENT2,
|
|
164341
164876
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
164342
164877
|
}
|
|
164343
|
-
}, {
|
|
164878
|
+
}, {
|
|
164879
|
+
timeoutMs: historianTimeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
164880
|
+
fallbackModels,
|
|
164881
|
+
callContext: "compressor"
|
|
164882
|
+
});
|
|
164344
164883
|
const messagesResponse = await client.session.messages({
|
|
164345
164884
|
path: { id: agentSessionId },
|
|
164346
164885
|
query: { directory }
|
|
@@ -164497,7 +165036,7 @@ No new compartments or facts were written.`);
|
|
|
164497
165036
|
const existingState = priorCompartments.length > 0 || priorFacts.length > 0 ? buildExistingStateXml(priorCompartments, priorFacts, memoryBlock) : memoryBlock ? `${memoryBlock}
|
|
164498
165037
|
|
|
164499
165038
|
This is your first run. No existing compartments or facts.` : "This is your first run. No existing state.";
|
|
164500
|
-
stateFilePath = maybeWriteHistorianStateFile(sessionId, existingState);
|
|
165039
|
+
stateFilePath = maybeWriteHistorianStateFile(sessionId, existingState, directory);
|
|
164501
165040
|
if (stateFilePath) {
|
|
164502
165041
|
sessionLog(sessionId, `historian: existing state offloaded to file (${existingState.length} chars) → ${stateFilePath}`);
|
|
164503
165042
|
}
|
|
@@ -164520,6 +165059,7 @@ ${chunk.text}`, { stateFilePath });
|
|
|
164520
165059
|
dumpLabelBase: `incremental-${sessionId}-${chunk.startIndex}-${chunk.endIndex}`,
|
|
164521
165060
|
timeoutMs: historianTimeoutMs,
|
|
164522
165061
|
fallbackModelId: deps.fallbackModelId,
|
|
165062
|
+
fallbackModels: deps.fallbackModels,
|
|
164523
165063
|
twoPass: deps.historianTwoPass
|
|
164524
165064
|
});
|
|
164525
165065
|
if (!validatedPass.ok) {
|
|
@@ -164544,21 +165084,36 @@ Historian returned compartments that made no forward progress beyond raw message
|
|
|
164544
165084
|
No new compartments or facts were written. Check the historian model/output and try again.`);
|
|
164545
165085
|
return;
|
|
164546
165086
|
}
|
|
165087
|
+
const deferMarkerApplication = deps.preserveInjectionCacheUntilConsumed === true && deps.experimentalCompactionMarkers === true;
|
|
165088
|
+
const lastCompartmentEnd = lastNewEnd;
|
|
165089
|
+
const lastNewEndMessageId = newCompartments[newCompartments.length - 1]?.endMessageId;
|
|
164547
165090
|
db.transaction(() => {
|
|
164548
165091
|
appendCompartments(db, sessionId, newCompartments);
|
|
164549
165092
|
replaceSessionFacts(db, sessionId, validatedPass.facts ?? []);
|
|
164550
165093
|
clearHistorianFailureState(db, sessionId);
|
|
164551
165094
|
clearEmergencyRecovery(db, sessionId);
|
|
165095
|
+
if (deferMarkerApplication && lastNewEndMessageId) {
|
|
165096
|
+
setPendingCompactionMarkerState(db, sessionId, {
|
|
165097
|
+
ordinal: lastCompartmentEnd,
|
|
165098
|
+
endMessageId: lastNewEndMessageId,
|
|
165099
|
+
publishedAt: Date.now()
|
|
165100
|
+
});
|
|
165101
|
+
}
|
|
164552
165102
|
})();
|
|
164553
|
-
|
|
164554
|
-
|
|
165103
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
165104
|
+
clearInjectionCache(sessionId);
|
|
165105
|
+
}
|
|
165106
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
164555
165107
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
164556
165108
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), validatedPass.facts ?? []);
|
|
164557
165109
|
}
|
|
164558
|
-
const lastCompartmentEnd = lastNewEnd;
|
|
164559
165110
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
164560
165111
|
if (deps.experimentalCompactionMarkers) {
|
|
164561
|
-
|
|
165112
|
+
if (deferMarkerApplication) {
|
|
165113
|
+
deps.onDeferredMarkerPending?.(sessionId);
|
|
165114
|
+
} else {
|
|
165115
|
+
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, sessionDirectory);
|
|
165116
|
+
}
|
|
164562
165117
|
}
|
|
164563
165118
|
if (deps.historyBudgetTokens && deps.historyBudgetTokens > 0) {
|
|
164564
165119
|
await runCompressionPassIfNeeded({
|
|
@@ -164568,6 +165123,7 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
164568
165123
|
directory: sessionDirectory,
|
|
164569
165124
|
historyBudgetTokens: deps.historyBudgetTokens,
|
|
164570
165125
|
historianTimeoutMs,
|
|
165126
|
+
fallbackModels: deps.fallbackModels,
|
|
164571
165127
|
minCompartmentRatio: deps.compressorMinCompartmentRatio,
|
|
164572
165128
|
maxMergeDepth: deps.compressorMaxMergeDepth
|
|
164573
165129
|
});
|
|
@@ -164662,8 +165218,10 @@ async function executeContextRecompInternal(deps) {
|
|
|
164662
165218
|
if (!promoted2)
|
|
164663
165219
|
return null;
|
|
164664
165220
|
clearCompressionDepth(db, sessionId);
|
|
164665
|
-
|
|
164666
|
-
|
|
165221
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
165222
|
+
clearInjectionCache(sessionId);
|
|
165223
|
+
}
|
|
165224
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
164667
165225
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
164668
165226
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), promoted2.facts);
|
|
164669
165227
|
}
|
|
@@ -164673,6 +165231,10 @@ async function executeContextRecompInternal(deps) {
|
|
|
164673
165231
|
}
|
|
164674
165232
|
if (deps.experimentalCompactionMarkers && lastCompartmentEnd2 > 0) {
|
|
164675
165233
|
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
|
|
165234
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
165235
|
+
if (stalePending) {
|
|
165236
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
165237
|
+
}
|
|
164676
165238
|
}
|
|
164677
165239
|
return [
|
|
164678
165240
|
`Persisted ${promoted2.compartments.length} compartment${promoted2.compartments.length === 1 ? "" : "s"} from ${passCount} successful pass${passCount === 1 ? "" : "es"}.`,
|
|
@@ -164738,7 +165300,7 @@ Nothing was written.`;
|
|
|
164738
165300
|
|
|
164739
165301
|
This is your first run. No existing compartments or facts.` : "This is your first run. No existing state.";
|
|
164740
165302
|
cleanupHistorianStateFile(currentStateFilePath);
|
|
164741
|
-
currentStateFilePath = maybeWriteHistorianStateFile(sessionId, existingState);
|
|
165303
|
+
currentStateFilePath = maybeWriteHistorianStateFile(sessionId, existingState, sessionDirectory);
|
|
164742
165304
|
const prompt = buildCompartmentAgentPrompt(existingState, `Messages ${chunk.startIndex}-${chunk.endIndex}:
|
|
164743
165305
|
|
|
164744
165306
|
${chunk.text}`, { stateFilePath: currentStateFilePath });
|
|
@@ -164756,6 +165318,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
164756
165318
|
dumpLabelBase: `recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
|
|
164757
165319
|
timeoutMs: historianTimeoutMs,
|
|
164758
165320
|
fallbackModelId: deps.fallbackModelId,
|
|
165321
|
+
fallbackModels: deps.fallbackModels,
|
|
164759
165322
|
twoPass: deps.historianTwoPass,
|
|
164760
165323
|
callbacks: {
|
|
164761
165324
|
onRepairRetry: async (error51) => {
|
|
@@ -164833,8 +165396,10 @@ Nothing was written.`;
|
|
|
164833
165396
|
clearRecompStaging(db, sessionId);
|
|
164834
165397
|
}
|
|
164835
165398
|
clearCompressionDepth(db, sessionId);
|
|
164836
|
-
|
|
164837
|
-
|
|
165399
|
+
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
165400
|
+
clearInjectionCache(sessionId);
|
|
165401
|
+
}
|
|
165402
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
164838
165403
|
const finalCompartments = promoted?.compartments ?? candidateCompartments;
|
|
164839
165404
|
const finalFacts = promoted?.facts ?? candidateFacts;
|
|
164840
165405
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
@@ -164853,6 +165418,7 @@ Nothing was written.`;
|
|
|
164853
165418
|
directory: sessionDirectory,
|
|
164854
165419
|
historyBudgetTokens: deps.historyBudgetTokens,
|
|
164855
165420
|
historianTimeoutMs,
|
|
165421
|
+
fallbackModels: deps.fallbackModels,
|
|
164856
165422
|
minCompartmentRatio: deps.compressorMinCompartmentRatio,
|
|
164857
165423
|
maxMergeDepth: deps.compressorMaxMergeDepth
|
|
164858
165424
|
});
|
|
@@ -164908,50 +165474,78 @@ __export(exports_compartment_runner, {
|
|
|
164908
165474
|
startCompartmentAgent: () => startCompartmentAgent,
|
|
164909
165475
|
runCompartmentAgent: () => runCompartmentAgent,
|
|
164910
165476
|
registerActiveCompartmentRun: () => registerActiveCompartmentRun,
|
|
165477
|
+
markActiveCompartmentRunPublished: () => markActiveCompartmentRunPublished,
|
|
164911
165478
|
getActiveCompartmentRun: () => getActiveCompartmentRun,
|
|
164912
165479
|
executeContextRecomp: () => executeContextRecomp
|
|
164913
165480
|
});
|
|
164914
165481
|
function getActiveCompartmentRun(sessionId) {
|
|
164915
165482
|
return activeRuns.get(sessionId);
|
|
164916
165483
|
}
|
|
165484
|
+
function markActiveCompartmentRunPublished(sessionId) {
|
|
165485
|
+
const activeRun = activeRuns.get(sessionId);
|
|
165486
|
+
if (activeRun)
|
|
165487
|
+
activeRun.published = true;
|
|
165488
|
+
}
|
|
164917
165489
|
function registerActiveCompartmentRun(sessionId, promise2) {
|
|
165490
|
+
const activeRun = {
|
|
165491
|
+
promise: Promise.resolve(),
|
|
165492
|
+
published: false
|
|
165493
|
+
};
|
|
164918
165494
|
const wrapped = promise2.finally(() => {
|
|
164919
|
-
if (activeRuns.get(sessionId) === wrapped) {
|
|
165495
|
+
if (activeRuns.get(sessionId)?.promise === wrapped) {
|
|
164920
165496
|
activeRuns.delete(sessionId);
|
|
164921
165497
|
}
|
|
164922
165498
|
});
|
|
164923
|
-
|
|
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
|
+
};
|
|
164924
165511
|
}
|
|
164925
165512
|
function startCompartmentAgent(deps) {
|
|
164926
165513
|
const existing = activeRuns.get(deps.sessionId);
|
|
164927
165514
|
if (existing) {
|
|
164928
165515
|
return;
|
|
164929
165516
|
}
|
|
164930
|
-
const
|
|
165517
|
+
const runnerDeps = withPublishedCallback(deps);
|
|
165518
|
+
const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
|
|
164931
165519
|
sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
|
|
164932
165520
|
try {
|
|
164933
165521
|
updateSessionMeta(deps.db, deps.sessionId, { compartmentInProgress: false });
|
|
164934
165522
|
} catch {}
|
|
164935
165523
|
}).finally(() => {
|
|
164936
|
-
activeRuns.
|
|
165524
|
+
if (activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
165525
|
+
activeRuns.delete(deps.sessionId);
|
|
165526
|
+
}
|
|
164937
165527
|
});
|
|
164938
|
-
activeRuns.set(deps.sessionId, promise2);
|
|
165528
|
+
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
164939
165529
|
}
|
|
164940
165530
|
async function executeContextRecomp(deps, options = {}) {
|
|
164941
165531
|
const { sessionId } = deps;
|
|
164942
165532
|
if (activeRuns.has(sessionId)) {
|
|
164943
165533
|
return "## Magic Recomp\n\nHistorian is already running for this session. Wait for it to finish, then try `/ctx-recomp` again.";
|
|
164944
165534
|
}
|
|
164945
|
-
const
|
|
164946
|
-
|
|
165535
|
+
const runnerDeps = withPublishedCallback(deps);
|
|
165536
|
+
const promise2 = options.range ? executePartialRecompInternal(runnerDeps, options.range) : executeContextRecompInternal(runnerDeps);
|
|
165537
|
+
const wrappedPromise = promise2.then(() => {
|
|
164947
165538
|
return;
|
|
164948
165539
|
}).catch((err) => {
|
|
164949
165540
|
sessionLog(sessionId, "compartment agent: recomp unhandled rejection:", err);
|
|
164950
|
-
})
|
|
165541
|
+
});
|
|
165542
|
+
activeRuns.set(sessionId, { promise: wrappedPromise, published: false });
|
|
164951
165543
|
try {
|
|
164952
165544
|
return await promise2;
|
|
164953
165545
|
} finally {
|
|
164954
|
-
activeRuns.
|
|
165546
|
+
if (activeRuns.get(sessionId)?.promise === wrappedPromise) {
|
|
165547
|
+
activeRuns.delete(sessionId);
|
|
165548
|
+
}
|
|
164955
165549
|
}
|
|
164956
165550
|
}
|
|
164957
165551
|
var activeRuns;
|
|
@@ -164972,8 +165566,8 @@ var exports_tui_config = {};
|
|
|
164972
165566
|
__export(exports_tui_config, {
|
|
164973
165567
|
ensureTuiPluginEntry: () => ensureTuiPluginEntry
|
|
164974
165568
|
});
|
|
164975
|
-
import { existsSync as existsSync14, mkdirSync as
|
|
164976
|
-
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";
|
|
164977
165571
|
function isMagicContextEntry(entry) {
|
|
164978
165572
|
if (!entry)
|
|
164979
165573
|
return false;
|
|
@@ -164987,8 +165581,8 @@ function isMagicContextEntry(entry) {
|
|
|
164987
165581
|
}
|
|
164988
165582
|
function resolveTuiConfigPath() {
|
|
164989
165583
|
const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
164990
|
-
const jsoncPath =
|
|
164991
|
-
const jsonPath =
|
|
165584
|
+
const jsoncPath = join23(configDir, "tui.jsonc");
|
|
165585
|
+
const jsonPath = join23(configDir, "tui.json");
|
|
164992
165586
|
if (existsSync14(jsoncPath))
|
|
164993
165587
|
return jsoncPath;
|
|
164994
165588
|
if (existsSync14(jsonPath))
|
|
@@ -165000,7 +165594,7 @@ function ensureTuiPluginEntry() {
|
|
|
165000
165594
|
const configPath = resolveTuiConfigPath();
|
|
165001
165595
|
let config2 = {};
|
|
165002
165596
|
if (existsSync14(configPath)) {
|
|
165003
|
-
const raw =
|
|
165597
|
+
const raw = readFileSync11(configPath, "utf-8");
|
|
165004
165598
|
config2 = import_comment_json3.parse(raw) ?? {};
|
|
165005
165599
|
}
|
|
165006
165600
|
const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p) => typeof p === "string") : [];
|
|
@@ -165019,7 +165613,7 @@ function ensureTuiPluginEntry() {
|
|
|
165019
165613
|
plugins.push(PLUGIN_ENTRY);
|
|
165020
165614
|
}
|
|
165021
165615
|
config2.plugin = plugins;
|
|
165022
|
-
|
|
165616
|
+
mkdirSync9(dirname8(configPath), { recursive: true });
|
|
165023
165617
|
writeFileSync8(configPath, `${import_comment_json3.stringify(config2, null, 2)}
|
|
165024
165618
|
`);
|
|
165025
165619
|
log(`[magic-context] updated TUI plugin entry in ${configPath}`);
|
|
@@ -165130,34 +165724,20 @@ function loadConfigFile(configPath) {
|
|
|
165130
165724
|
return null;
|
|
165131
165725
|
}
|
|
165132
165726
|
}
|
|
165133
|
-
function
|
|
165134
|
-
const
|
|
165135
|
-
|
|
165136
|
-
|
|
165137
|
-
|
|
165138
|
-
|
|
165139
|
-
|
|
165140
|
-
|
|
165141
|
-
|
|
165142
|
-
|
|
165143
|
-
|
|
165144
|
-
dreamer: override.dreamer ? {
|
|
165145
|
-
...base.dreamer ?? {},
|
|
165146
|
-
...override.dreamer
|
|
165147
|
-
} : base.dreamer,
|
|
165148
|
-
sidekick: override.sidekick ? {
|
|
165149
|
-
...base.sidekick ?? {},
|
|
165150
|
-
...override.sidekick
|
|
165151
|
-
} : base.sidekick,
|
|
165152
|
-
disabled_hooks: [
|
|
165153
|
-
...new Set([...base.disabled_hooks ?? [], ...override.disabled_hooks ?? []])
|
|
165154
|
-
],
|
|
165155
|
-
command: {
|
|
165156
|
-
...base.command ?? {},
|
|
165157
|
-
...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;
|
|
165158
165738
|
}
|
|
165159
|
-
}
|
|
165160
|
-
return
|
|
165739
|
+
}
|
|
165740
|
+
return result;
|
|
165161
165741
|
}
|
|
165162
165742
|
function getProjectUserOnlyFields(config2) {
|
|
165163
165743
|
return "auto_update" in config2 ? ["auto_update"] : [];
|
|
@@ -165298,30 +165878,38 @@ function loadPluginConfig(directory) {
|
|
|
165298
165878
|
const projectDetected = rootDetected.format !== "none" ? rootDetected : dotOpenCodeDetected;
|
|
165299
165879
|
const userLoaded = userDetected.format === "none" ? null : loadConfigFile(userDetected.path);
|
|
165300
165880
|
const projectLoaded = projectDetected.format === "none" ? null : loadConfigFile(projectDetected.path);
|
|
165301
|
-
let config2 = parsePluginConfig({});
|
|
165302
165881
|
const allWarnings = [];
|
|
165882
|
+
let mergedRaw = {};
|
|
165303
165883
|
if (userLoaded) {
|
|
165304
165884
|
allWarnings.push(...userLoaded.warnings.map((w) => `[user config] ${w}`));
|
|
165305
|
-
|
|
165306
|
-
if (parsed.configWarnings?.length) {
|
|
165307
|
-
allWarnings.push(...parsed.configWarnings.map((w) => `[user config] ${w}`));
|
|
165308
|
-
}
|
|
165309
|
-
config2 = mergeConfigs(config2, parsed, { allowUserOnlyFields: true });
|
|
165885
|
+
mergedRaw = deepMergeRawConfig(mergedRaw, userLoaded.config);
|
|
165310
165886
|
}
|
|
165311
165887
|
if (projectLoaded) {
|
|
165312
165888
|
allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
|
|
165313
|
-
const
|
|
165314
|
-
|
|
165315
|
-
allWarnings.push(...parsed.configWarnings.map((w) => `[project config] ${w}`));
|
|
165316
|
-
}
|
|
165317
|
-
const strippedUserOnlyFields = getProjectUserOnlyFields(projectLoaded.config);
|
|
165889
|
+
const projectRaw = { ...projectLoaded.config };
|
|
165890
|
+
const strippedUserOnlyFields = getProjectUserOnlyFields(projectRaw);
|
|
165318
165891
|
if (strippedUserOnlyFields.length > 0) {
|
|
165892
|
+
for (const key of strippedUserOnlyFields) {
|
|
165893
|
+
delete projectRaw[key];
|
|
165894
|
+
}
|
|
165319
165895
|
allWarnings.push(`[project config] Ignoring ${strippedUserOnlyFields.join(", ")} from project config (security: these settings only honor user-level config)`);
|
|
165320
165896
|
}
|
|
165321
|
-
|
|
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
|
+
}));
|
|
165322
165908
|
}
|
|
165323
165909
|
if (allWarnings.length > 0) {
|
|
165324
165910
|
config2.configWarnings = allWarnings;
|
|
165911
|
+
} else if ("configWarnings" in config2) {
|
|
165912
|
+
config2.configWarnings = undefined;
|
|
165325
165913
|
}
|
|
165326
165914
|
return config2;
|
|
165327
165915
|
}
|
|
@@ -165722,6 +166310,7 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
165722
166310
|
init_shared();
|
|
165723
166311
|
init_assistant_message_extractor();
|
|
165724
166312
|
init_logger();
|
|
166313
|
+
init_resolve_fallbacks();
|
|
165725
166314
|
|
|
165726
166315
|
// src/features/magic-context/sidekick/core.ts
|
|
165727
166316
|
var SIDEKICK_SYSTEM_PROMPT = `You are Sidekick, a focused memory-retrieval subagent for an AI coding assistant.
|
|
@@ -165741,6 +166330,7 @@ function stripThinkingBlocks(text) {
|
|
|
165741
166330
|
|
|
165742
166331
|
// src/features/magic-context/sidekick/agent.ts
|
|
165743
166332
|
async function runSidekick(deps) {
|
|
166333
|
+
const fallbackModels = resolveFallbackChain(SIDEKICK_AGENT, deps.config.fallback_models);
|
|
165744
166334
|
let agentSessionId = null;
|
|
165745
166335
|
try {
|
|
165746
166336
|
const createResponse = await deps.client.session.create({
|
|
@@ -165763,7 +166353,7 @@ async function runSidekick(deps) {
|
|
|
165763
166353
|
system: deps.config.system_prompt?.trim() || deps.config.prompt?.trim() || SIDEKICK_SYSTEM_PROMPT,
|
|
165764
166354
|
parts: [{ type: "text", text: deps.userMessage, synthetic: true }]
|
|
165765
166355
|
}
|
|
165766
|
-
}, { timeoutMs: deps.config.timeout_ms });
|
|
166356
|
+
}, { timeoutMs: deps.config.timeout_ms, fallbackModels, callContext: "sidekick" });
|
|
165767
166357
|
const messagesResponse = await deps.client.session.messages({
|
|
165768
166358
|
path: { id: agentSessionId },
|
|
165769
166359
|
query: { directory: deps.sessionDirectory ?? deps.projectPath }
|
|
@@ -165801,41 +166391,41 @@ init_tool_definition_tokens();
|
|
|
165801
166391
|
|
|
165802
166392
|
// src/hooks/auto-update-checker/index.ts
|
|
165803
166393
|
init_logger();
|
|
165804
|
-
import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync6, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
165805
|
-
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";
|
|
165806
166396
|
|
|
165807
166397
|
// src/hooks/auto-update-checker/cache.ts
|
|
165808
166398
|
init_logger();
|
|
165809
166399
|
var import_comment_json2 = __toESM(require_src2(), 1);
|
|
165810
166400
|
import { spawn } from "node:child_process";
|
|
165811
166401
|
import { existsSync as existsSync5, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
165812
|
-
import { basename, dirname as
|
|
166402
|
+
import { basename, dirname as dirname4, join as join5 } from "node:path";
|
|
165813
166403
|
|
|
165814
166404
|
// src/hooks/auto-update-checker/checker.ts
|
|
165815
166405
|
init_logger();
|
|
165816
166406
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
165817
166407
|
import { existsSync as existsSync4, readFileSync as readFileSync4, statSync, writeFileSync } from "node:fs";
|
|
165818
|
-
import { homedir as
|
|
165819
|
-
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";
|
|
165820
166410
|
import { fileURLToPath } from "node:url";
|
|
165821
166411
|
|
|
165822
166412
|
// src/hooks/auto-update-checker/constants.ts
|
|
165823
|
-
import { homedir as
|
|
166413
|
+
import { homedir as homedir4, platform } from "node:os";
|
|
165824
166414
|
import { join as join3 } from "node:path";
|
|
165825
166415
|
var PACKAGE_NAME = "@cortexkit/opencode-magic-context";
|
|
165826
166416
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
165827
166417
|
var NPM_FETCH_TIMEOUT = 1e4;
|
|
165828
166418
|
function getOpenCodeCacheRoot() {
|
|
165829
166419
|
if (platform() === "win32") {
|
|
165830
|
-
return join3(process.env.LOCALAPPDATA ??
|
|
166420
|
+
return join3(process.env.LOCALAPPDATA ?? homedir4(), "opencode");
|
|
165831
166421
|
}
|
|
165832
|
-
return join3(
|
|
166422
|
+
return join3(homedir4(), ".cache", "opencode");
|
|
165833
166423
|
}
|
|
165834
166424
|
function getOpenCodeConfigRoot() {
|
|
165835
166425
|
if (platform() === "win32") {
|
|
165836
|
-
return join3(process.env.APPDATA ?? join3(
|
|
166426
|
+
return join3(process.env.APPDATA ?? join3(homedir4(), "AppData", "Roaming"), "opencode");
|
|
165837
166427
|
}
|
|
165838
|
-
return join3(process.env.XDG_CONFIG_HOME ?? join3(
|
|
166428
|
+
return join3(process.env.XDG_CONFIG_HOME ?? join3(homedir4(), ".config"), "opencode");
|
|
165839
166429
|
}
|
|
165840
166430
|
var CACHE_DIR = join3(getOpenCodeCacheRoot(), "packages");
|
|
165841
166431
|
var USER_OPENCODE_CONFIG = join3(getOpenCodeConfigRoot(), "opencode.json");
|
|
@@ -165917,12 +166507,12 @@ function resolvePathPluginSpec(spec, configPath) {
|
|
|
165917
166507
|
}
|
|
165918
166508
|
if (isAbsolute2(spec) || /^[A-Za-z]:[\\/]/.test(spec))
|
|
165919
166509
|
return spec;
|
|
165920
|
-
return resolve2(
|
|
166510
|
+
return resolve2(dirname3(configPath), spec);
|
|
165921
166511
|
}
|
|
165922
166512
|
function findPackageJsonUp(startPath) {
|
|
165923
166513
|
try {
|
|
165924
166514
|
const stat = statSync(startPath);
|
|
165925
|
-
let dir = stat.isDirectory() ? startPath :
|
|
166515
|
+
let dir = stat.isDirectory() ? startPath : dirname3(startPath);
|
|
165926
166516
|
for (let i = 0;i < 10; i++) {
|
|
165927
166517
|
const pkgPath = join4(dir, "package.json");
|
|
165928
166518
|
if (existsSync4(pkgPath)) {
|
|
@@ -165932,7 +166522,7 @@ function findPackageJsonUp(startPath) {
|
|
|
165932
166522
|
return pkgPath;
|
|
165933
166523
|
} catch {}
|
|
165934
166524
|
}
|
|
165935
|
-
const parent =
|
|
166525
|
+
const parent = dirname3(dir);
|
|
165936
166526
|
if (parent === dir)
|
|
165937
166527
|
break;
|
|
165938
166528
|
dir = parent;
|
|
@@ -165980,7 +166570,7 @@ function getLocalDevVersion(directory) {
|
|
|
165980
166570
|
}
|
|
165981
166571
|
function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
|
|
165982
166572
|
try {
|
|
165983
|
-
return findPackageJsonUp(
|
|
166573
|
+
return findPackageJsonUp(dirname3(fileURLToPath(currentModuleUrl)));
|
|
165984
166574
|
} catch (err) {
|
|
165985
166575
|
warn(`[auto-update-checker] Failed to resolve runtime package path: ${String(err)}`);
|
|
165986
166576
|
return null;
|
|
@@ -166023,7 +166613,7 @@ function getCachedVersion(spec) {
|
|
|
166023
166613
|
getCurrentRuntimePackageJsonPath(),
|
|
166024
166614
|
spec ? getSpecCachePackageJsonPath(spec) : null,
|
|
166025
166615
|
getSpecCachePackageJsonPath(`${PACKAGE_NAME}@latest`),
|
|
166026
|
-
join4(
|
|
166616
|
+
join4(homedir5(), ".cache", "opencode", "node_modules", PACKAGE_NAME, "package.json")
|
|
166027
166617
|
].filter(isString);
|
|
166028
166618
|
for (const packageJsonPath of candidates) {
|
|
166029
166619
|
try {
|
|
@@ -166077,7 +166667,7 @@ function stripPackageNameFromPath(pathValue, packageName) {
|
|
|
166077
166667
|
for (const segment of [...packageName.split("/")].reverse()) {
|
|
166078
166668
|
if (basename(current) !== segment)
|
|
166079
166669
|
return null;
|
|
166080
|
-
current =
|
|
166670
|
+
current = dirname4(current);
|
|
166081
166671
|
}
|
|
166082
166672
|
return current;
|
|
166083
166673
|
}
|
|
@@ -166140,19 +166730,19 @@ function removeInstalledPackage(installDir, packageName) {
|
|
|
166140
166730
|
}
|
|
166141
166731
|
function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
166142
166732
|
if (runtimePackageJsonPath) {
|
|
166143
|
-
const packageDir =
|
|
166733
|
+
const packageDir = dirname4(runtimePackageJsonPath);
|
|
166144
166734
|
const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
|
|
166145
166735
|
if (nodeModulesDir && basename(nodeModulesDir) === "node_modules") {
|
|
166146
|
-
const installDir =
|
|
166736
|
+
const installDir = dirname4(nodeModulesDir);
|
|
166147
166737
|
const packageJsonPath = join5(installDir, "package.json");
|
|
166148
166738
|
if (existsSync5(packageJsonPath))
|
|
166149
166739
|
return { installDir, packageJsonPath };
|
|
166150
166740
|
}
|
|
166151
166741
|
return null;
|
|
166152
166742
|
}
|
|
166153
|
-
const legacyPackageJsonPath = join5(
|
|
166743
|
+
const legacyPackageJsonPath = join5(dirname4(CACHE_DIR), "package.json");
|
|
166154
166744
|
if (existsSync5(legacyPackageJsonPath)) {
|
|
166155
|
-
return { installDir:
|
|
166745
|
+
return { installDir: dirname4(CACHE_DIR), packageJsonPath: legacyPackageJsonPath };
|
|
166156
166746
|
}
|
|
166157
166747
|
return null;
|
|
166158
166748
|
}
|
|
@@ -166281,7 +166871,7 @@ function claimCheckSlot(storageDir, intervalMs) {
|
|
|
166281
166871
|
}
|
|
166282
166872
|
} catch {}
|
|
166283
166873
|
}
|
|
166284
|
-
|
|
166874
|
+
mkdirSync2(dirname5(file2), { recursive: true });
|
|
166285
166875
|
const tmp = `${file2}.tmp.${process.pid}`;
|
|
166286
166876
|
writeFileSync3(tmp, JSON.stringify({ lastCheckedMs: Date.now() }), "utf-8");
|
|
166287
166877
|
renameSync(tmp, file2);
|
|
@@ -166379,15 +166969,16 @@ function createLiveSessionState() {
|
|
|
166379
166969
|
variantBySession: new Map,
|
|
166380
166970
|
agentBySession: new Map,
|
|
166381
166971
|
historyRefreshSessions: new Set,
|
|
166972
|
+
deferredHistoryRefreshSessions: new Set,
|
|
166382
166973
|
systemPromptRefreshSessions: new Set,
|
|
166383
166974
|
pendingMaterializationSessions: new Set,
|
|
166975
|
+
deferredMaterializationSessions: new Set,
|
|
166384
166976
|
sessionDirectoryBySession: new Map
|
|
166385
166977
|
};
|
|
166386
166978
|
}
|
|
166387
166979
|
|
|
166388
166980
|
// src/index.ts
|
|
166389
166981
|
init_conflict_warning_hook();
|
|
166390
|
-
|
|
166391
166982
|
// src/features/magic-context/dreamer/storage-dream-state.ts
|
|
166392
166983
|
var getDreamStateStatements = new WeakMap;
|
|
166393
166984
|
var setDreamStateStatements = new WeakMap;
|
|
@@ -166484,11 +167075,23 @@ function releaseLease(db, holderId) {
|
|
|
166484
167075
|
})();
|
|
166485
167076
|
}
|
|
166486
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
|
+
}
|
|
166487
167088
|
function enqueueDream(db, projectIdentity, reason, force = false) {
|
|
166488
167089
|
const now = Date.now();
|
|
166489
167090
|
return db.transaction(() => {
|
|
166490
|
-
|
|
166491
|
-
|
|
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
|
+
}
|
|
166492
167095
|
const existing = db.prepare("SELECT id FROM dream_queue WHERE project_path = ?").get(projectIdentity);
|
|
166493
167096
|
if (existing) {
|
|
166494
167097
|
return null;
|
|
@@ -166549,7 +167152,7 @@ init_data_path();
|
|
|
166549
167152
|
init_logger();
|
|
166550
167153
|
await init_sqlite();
|
|
166551
167154
|
import { existsSync as existsSync9 } from "node:fs";
|
|
166552
|
-
import { join as
|
|
167155
|
+
import { join as join12 } from "node:path";
|
|
166553
167156
|
|
|
166554
167157
|
// src/features/magic-context/key-files/identify-key-files.ts
|
|
166555
167158
|
init_logger();
|
|
@@ -166833,7 +167436,12 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
166833
167436
|
system: DREAMER_SYSTEM_PROMPT,
|
|
166834
167437
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
166835
167438
|
}
|
|
166836
|
-
}, {
|
|
167439
|
+
}, {
|
|
167440
|
+
timeoutMs: Math.min(remainingMs, 5 * 60 * 1000),
|
|
167441
|
+
signal: abortController.signal,
|
|
167442
|
+
fallbackModels: args.fallbackModels,
|
|
167443
|
+
callContext: "dreamer:user-memories"
|
|
167444
|
+
});
|
|
166837
167445
|
const messagesResponse = await args.client.session.messages({
|
|
166838
167446
|
path: { id: agentSessionId },
|
|
166839
167447
|
query: { directory: args.sessionDirectory }
|
|
@@ -166892,7 +167500,8 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
166892
167500
|
}
|
|
166893
167501
|
return result;
|
|
166894
167502
|
} catch (error51) {
|
|
166895
|
-
|
|
167503
|
+
const errorDescription = describeError(error51);
|
|
167504
|
+
log(`[dreamer] user-memories: review failed: ${errorDescription.brief}`, errorDescription.stackHead ? { stackHead: errorDescription.stackHead } : undefined);
|
|
166896
167505
|
return result;
|
|
166897
167506
|
} finally {
|
|
166898
167507
|
clearInterval(leaseInterval);
|
|
@@ -166923,6 +167532,7 @@ function insertDreamRun(db, run) {
|
|
|
166923
167532
|
|
|
166924
167533
|
// src/features/magic-context/dreamer/runner.ts
|
|
166925
167534
|
var dreamProjectDirectories = new Map;
|
|
167535
|
+
var CIRCUIT_BREAKER_THRESHOLD = 3;
|
|
166926
167536
|
function registerDreamProjectDirectory(projectIdentity, directory) {
|
|
166927
167537
|
dreamProjectDirectories.set(projectIdentity, directory);
|
|
166928
167538
|
}
|
|
@@ -166939,8 +167549,27 @@ function countNewIds(beforeIds, afterIds) {
|
|
|
166939
167549
|
}
|
|
166940
167550
|
return count;
|
|
166941
167551
|
}
|
|
167552
|
+
function getCircuitBreakerSignature(error51, brief) {
|
|
167553
|
+
if (error51 instanceof Error && error51.name && error51.name !== "Error") {
|
|
167554
|
+
return error51.name;
|
|
167555
|
+
}
|
|
167556
|
+
const namedError = error51;
|
|
167557
|
+
if (namedError && typeof namedError === "object" && typeof namedError.name === "string" && namedError.name.length > 0 && namedError.name !== "Error") {
|
|
167558
|
+
return namedError.name;
|
|
167559
|
+
}
|
|
167560
|
+
return brief.split(":")[0]?.trim().split(/\s+/)[0] || brief || "unknown";
|
|
167561
|
+
}
|
|
167562
|
+
function shouldSkipCircuitBreaker(error51, brief) {
|
|
167563
|
+
const namedError = error51;
|
|
167564
|
+
const name2 = error51 instanceof Error ? error51.name : namedError && typeof namedError === "object" && typeof namedError.name === "string" ? namedError.name : "";
|
|
167565
|
+
const combined = `${name2} ${brief}`.toLowerCase();
|
|
167566
|
+
return name2 === "AbortError" || combined.includes("lease");
|
|
167567
|
+
}
|
|
167568
|
+
function logWithStackHead(message, stackHead) {
|
|
167569
|
+
log(message, stackHead ? { stackHead } : undefined);
|
|
167570
|
+
}
|
|
166942
167571
|
function getOpenCodeDbPath2() {
|
|
166943
|
-
return
|
|
167572
|
+
return join12(getDataDir(), "opencode", "opencode.db");
|
|
166944
167573
|
}
|
|
166945
167574
|
function openOpenCodeDb() {
|
|
166946
167575
|
const dbPath = getOpenCodeDbPath2();
|
|
@@ -167015,9 +167644,11 @@ async function identifyKeyFilesForSession(args) {
|
|
|
167015
167644
|
try {
|
|
167016
167645
|
if (!renewLease(args.db, args.holderId)) {
|
|
167017
167646
|
log(`[key-files][${args.sessionId}] lease renewal failed — aborting`);
|
|
167647
|
+
args.onLeaseLost?.(`key-files:${args.sessionId}`);
|
|
167018
167648
|
abortController.abort();
|
|
167019
167649
|
}
|
|
167020
|
-
} catch {
|
|
167650
|
+
} catch (error51) {
|
|
167651
|
+
args.onLeaseLost?.(`key-files:${args.sessionId}`, error51);
|
|
167021
167652
|
abortController.abort();
|
|
167022
167653
|
}
|
|
167023
167654
|
}, 60000);
|
|
@@ -167044,7 +167675,12 @@ async function identifyKeyFilesForSession(args) {
|
|
|
167044
167675
|
system: KEY_FILES_SYSTEM_PROMPT,
|
|
167045
167676
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
167046
167677
|
}
|
|
167047
|
-
}, {
|
|
167678
|
+
}, {
|
|
167679
|
+
timeoutMs: Math.min(remainingMs, 300000),
|
|
167680
|
+
signal: abortController.signal,
|
|
167681
|
+
fallbackModels: args.fallbackModels,
|
|
167682
|
+
callContext: `dreamer:key-files:${args.sessionId.slice(0, 12)}`
|
|
167683
|
+
});
|
|
167048
167684
|
const messagesResponse = await args.client.session.messages({
|
|
167049
167685
|
path: { id: agentSessionId },
|
|
167050
167686
|
query: { directory: args.sessionDirectory }
|
|
@@ -167067,6 +167703,10 @@ async function identifyKeyFilesForSession(args) {
|
|
|
167067
167703
|
log(`[key-files][${args.sessionId}] could not parse agent output — using heuristic fallback`);
|
|
167068
167704
|
applyHeuristicFallback();
|
|
167069
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
|
+
}
|
|
167070
167710
|
log(`[key-files][${args.sessionId}] identification failed: ${getErrorMessage(error51)} — using heuristic fallback`);
|
|
167071
167711
|
try {
|
|
167072
167712
|
applyHeuristicFallback();
|
|
@@ -167107,6 +167747,10 @@ async function identifyKeyFiles(args) {
|
|
|
167107
167747
|
}
|
|
167108
167748
|
log(`[key-files] evaluating ${sessionIds.length} active session(s) for ${args.projectIdentity}`);
|
|
167109
167749
|
for (const sessionId of sessionIds) {
|
|
167750
|
+
if (args.isLeaseLost?.()) {
|
|
167751
|
+
log("[key-files] lease lost — stopping key-file identification");
|
|
167752
|
+
break;
|
|
167753
|
+
}
|
|
167110
167754
|
if (Date.now() > args.deadline) {
|
|
167111
167755
|
log("[key-files] deadline reached — stopping key-file identification");
|
|
167112
167756
|
break;
|
|
@@ -167117,6 +167761,9 @@ async function identifyKeyFiles(args) {
|
|
|
167117
167761
|
parentSessionId: args.parentSessionId,
|
|
167118
167762
|
sessionDirectory: args.sessionDirectory,
|
|
167119
167763
|
holderId: args.holderId,
|
|
167764
|
+
fallbackModels: args.fallbackModels,
|
|
167765
|
+
onLeaseLost: args.onLeaseLost,
|
|
167766
|
+
isLeaseLost: args.isLeaseLost,
|
|
167120
167767
|
deadline: args.deadline,
|
|
167121
167768
|
sessionId,
|
|
167122
167769
|
config: args.config
|
|
@@ -167170,8 +167817,53 @@ async function runDream(args) {
|
|
|
167170
167817
|
const deadline = startedAt + args.maxRuntimeMinutes * 60 * 1000;
|
|
167171
167818
|
const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`) ?? getDreamState(args.db, "last_dream_at");
|
|
167172
167819
|
log(`[dreamer] last dream at: ${lastDreamAt ?? "never"} (project=${args.projectIdentity})`);
|
|
167820
|
+
let lastErrorSignature = null;
|
|
167821
|
+
let consecutiveSameErrorFailures = 0;
|
|
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
|
+
};
|
|
167173
167861
|
try {
|
|
167174
167862
|
for (const taskName of args.tasks) {
|
|
167863
|
+
if (!verifyLeaseStillHeld(`before task ${taskName}`)) {
|
|
167864
|
+
recordLeaseLostTask(`before task ${taskName}`);
|
|
167865
|
+
break;
|
|
167866
|
+
}
|
|
167175
167867
|
if (Date.now() > deadline) {
|
|
167176
167868
|
log(`[dreamer] deadline reached, stopping after ${result.tasks.length} tasks`);
|
|
167177
167869
|
break;
|
|
@@ -167184,18 +167876,20 @@ async function runDream(args) {
|
|
|
167184
167876
|
try {
|
|
167185
167877
|
if (!renewLease(args.db, holderId)) {
|
|
167186
167878
|
log(`[dreamer] task ${taskName}: lease renewal failed — aborting LLM call`);
|
|
167879
|
+
markLeaseLost(`task ${taskName} lease renewal`);
|
|
167187
167880
|
taskAbortController.abort();
|
|
167188
167881
|
}
|
|
167189
167882
|
} catch (err) {
|
|
167190
167883
|
log(`[dreamer] task ${taskName}: lease renewal threw — aborting LLM call: ${err}`);
|
|
167884
|
+
markLeaseLost(`task ${taskName} lease renewal`, err);
|
|
167191
167885
|
taskAbortController.abort();
|
|
167192
167886
|
}
|
|
167193
167887
|
}, 60000);
|
|
167194
167888
|
try {
|
|
167195
167889
|
const docsDir = args.sessionDirectory ?? args.projectIdentity;
|
|
167196
167890
|
const existingDocs = taskName === "maintain-docs" ? {
|
|
167197
|
-
architecture: existsSync9(
|
|
167198
|
-
structure: existsSync9(
|
|
167891
|
+
architecture: existsSync9(join12(docsDir, "ARCHITECTURE.md")),
|
|
167892
|
+
structure: existsSync9(join12(docsDir, "STRUCTURE.md"))
|
|
167199
167893
|
} : undefined;
|
|
167200
167894
|
const userMemories = taskName === "archive-stale" ? getActiveUserMemories(args.db).map((um) => ({
|
|
167201
167895
|
id: um.id,
|
|
@@ -167230,8 +167924,13 @@ async function runDream(args) {
|
|
|
167230
167924
|
}
|
|
167231
167925
|
}, {
|
|
167232
167926
|
timeoutMs: args.taskTimeoutMinutes * 60 * 1000,
|
|
167233
|
-
signal: taskAbortController.signal
|
|
167927
|
+
signal: taskAbortController.signal,
|
|
167928
|
+
fallbackModels: args.fallbackModels,
|
|
167929
|
+
callContext: `dreamer:${taskName}`
|
|
167234
167930
|
});
|
|
167931
|
+
if (lostLease) {
|
|
167932
|
+
throw new Error(lostLeaseReason ?? `Dream lease lost during ${taskName}`);
|
|
167933
|
+
}
|
|
167235
167934
|
const messagesResponse = await args.client.session.messages({
|
|
167236
167935
|
path: { id: agentSessionId },
|
|
167237
167936
|
query: { directory: args.sessionDirectory ?? args.projectIdentity }
|
|
@@ -167250,16 +167949,43 @@ async function runDream(args) {
|
|
|
167250
167949
|
durationMs,
|
|
167251
167950
|
result: taskResult
|
|
167252
167951
|
});
|
|
167952
|
+
lastErrorSignature = null;
|
|
167953
|
+
consecutiveSameErrorFailures = 0;
|
|
167253
167954
|
} catch (error51) {
|
|
167254
167955
|
const durationMs = Date.now() - taskStartedAt;
|
|
167255
|
-
const
|
|
167256
|
-
|
|
167956
|
+
const errorDescription = describeError(error51);
|
|
167957
|
+
logWithStackHead(`[dreamer] task ${taskName}: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167257
167958
|
result.tasks.push({
|
|
167258
167959
|
name: taskName,
|
|
167259
167960
|
durationMs,
|
|
167260
167961
|
result: null,
|
|
167261
|
-
error:
|
|
167962
|
+
error: errorDescription.brief
|
|
167262
167963
|
});
|
|
167964
|
+
if (lostLease) {
|
|
167965
|
+
lastErrorSignature = null;
|
|
167966
|
+
consecutiveSameErrorFailures = 0;
|
|
167967
|
+
} else if (shouldSkipCircuitBreaker(error51, errorDescription.brief)) {
|
|
167968
|
+
lastErrorSignature = null;
|
|
167969
|
+
consecutiveSameErrorFailures = 0;
|
|
167970
|
+
} else {
|
|
167971
|
+
const signature = getCircuitBreakerSignature(error51, errorDescription.brief);
|
|
167972
|
+
if (signature === lastErrorSignature) {
|
|
167973
|
+
consecutiveSameErrorFailures += 1;
|
|
167974
|
+
} else {
|
|
167975
|
+
lastErrorSignature = signature;
|
|
167976
|
+
consecutiveSameErrorFailures = 1;
|
|
167977
|
+
}
|
|
167978
|
+
if (consecutiveSameErrorFailures >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
167979
|
+
circuitBreakerTripped = true;
|
|
167980
|
+
log(`[dreamer] circuit breaker: ${consecutiveSameErrorFailures} consecutive ${signature} failures — aborting remaining tasks`);
|
|
167981
|
+
result.tasks.push({
|
|
167982
|
+
name: "circuit-breaker",
|
|
167983
|
+
durationMs: 0,
|
|
167984
|
+
result: "",
|
|
167985
|
+
error: `Aborted remaining tasks: ${consecutiveSameErrorFailures} consecutive ${signature} failures. Configure dreamer model/fallback_models in magic-context.jsonc.`
|
|
167986
|
+
});
|
|
167987
|
+
}
|
|
167988
|
+
}
|
|
167263
167989
|
} finally {
|
|
167264
167990
|
clearInterval(leaseRenewalInterval);
|
|
167265
167991
|
if (agentSessionId) {
|
|
@@ -167271,10 +167997,32 @@ async function runDream(args) {
|
|
|
167271
167997
|
});
|
|
167272
167998
|
}
|
|
167273
167999
|
}
|
|
168000
|
+
if (lostLease) {
|
|
168001
|
+
recordLeaseLostTask(`task ${taskName}`);
|
|
168002
|
+
break;
|
|
168003
|
+
}
|
|
168004
|
+
if (circuitBreakerTripped) {
|
|
168005
|
+
break;
|
|
168006
|
+
}
|
|
168007
|
+
}
|
|
168008
|
+
if (lostLease) {
|
|
168009
|
+
log("[dreamer] lease lost: skipping all post-task phases");
|
|
168010
|
+
recordLeaseLostTask("post-task phases");
|
|
168011
|
+
} else if (circuitBreakerTripped) {
|
|
168012
|
+
log("[dreamer] circuit breaker: skipping post-task phases");
|
|
168013
|
+
result.tasks.push({
|
|
168014
|
+
name: "post-task-phases",
|
|
168015
|
+
durationMs: 0,
|
|
168016
|
+
result: "",
|
|
168017
|
+
error: "Skipped post-task phases after circuit breaker tripped; configure dreamer model/fallback_models in magic-context.jsonc."
|
|
168018
|
+
});
|
|
167274
168019
|
}
|
|
167275
|
-
if (args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
|
|
168020
|
+
if (!circuitBreakerTripped && !lostLease && args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
|
|
167276
168021
|
const umStart = Date.now();
|
|
167277
168022
|
try {
|
|
168023
|
+
if (!verifyLeaseStillHeld("before user-memory review")) {
|
|
168024
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost before user-memory review");
|
|
168025
|
+
}
|
|
167278
168026
|
const reviewResult = await reviewUserMemories({
|
|
167279
168027
|
db: args.db,
|
|
167280
168028
|
client: args.client,
|
|
@@ -167282,8 +168030,12 @@ async function runDream(args) {
|
|
|
167282
168030
|
sessionDirectory: args.sessionDirectory,
|
|
167283
168031
|
holderId,
|
|
167284
168032
|
deadline,
|
|
167285
|
-
promotionThreshold: args.experimentalUserMemories.promotionThreshold
|
|
168033
|
+
promotionThreshold: args.experimentalUserMemories.promotionThreshold,
|
|
168034
|
+
fallbackModels: args.fallbackModels
|
|
167286
168035
|
});
|
|
168036
|
+
if (!verifyLeaseStillHeld("after user-memory review")) {
|
|
168037
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost after user-memory review");
|
|
168038
|
+
}
|
|
167287
168039
|
const umOutput = `promoted=${reviewResult.promoted} merged=${reviewResult.merged} dismissed=${reviewResult.dismissed} consumed=${reviewResult.candidatesConsumed}`;
|
|
167288
168040
|
if (reviewResult.promoted > 0 || reviewResult.merged > 0 || reviewResult.dismissed > 0) {
|
|
167289
168041
|
log(`[dreamer] user-memories: ${umOutput}`);
|
|
@@ -167294,17 +168046,23 @@ async function runDream(args) {
|
|
|
167294
168046
|
result: umOutput
|
|
167295
168047
|
});
|
|
167296
168048
|
} catch (error51) {
|
|
167297
|
-
|
|
168049
|
+
const errorDescription = describeError(error51);
|
|
168050
|
+
logWithStackHead(`[dreamer] user-memory review failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167298
168051
|
result.tasks.push({
|
|
167299
168052
|
name: "user memories",
|
|
167300
168053
|
durationMs: Date.now() - umStart,
|
|
167301
168054
|
result: "",
|
|
167302
|
-
error:
|
|
168055
|
+
error: errorDescription.brief
|
|
167303
168056
|
});
|
|
167304
168057
|
}
|
|
168058
|
+
if (lostLease)
|
|
168059
|
+
recordLeaseLostTask("user-memory review");
|
|
167305
168060
|
}
|
|
167306
|
-
if (Date.now() <= deadline) {
|
|
168061
|
+
if (!circuitBreakerTripped && !lostLease && Date.now() <= deadline) {
|
|
167307
168062
|
try {
|
|
168063
|
+
if (!verifyLeaseStillHeld("before smart-note evaluation")) {
|
|
168064
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost before smart-note evaluation");
|
|
168065
|
+
}
|
|
167308
168066
|
await evaluateSmartNotes({
|
|
167309
168067
|
db: args.db,
|
|
167310
168068
|
client: args.client,
|
|
@@ -167313,15 +168071,27 @@ async function runDream(args) {
|
|
|
167313
168071
|
sessionDirectory: args.sessionDirectory,
|
|
167314
168072
|
holderId,
|
|
167315
168073
|
deadline,
|
|
167316
|
-
result
|
|
168074
|
+
result,
|
|
168075
|
+
fallbackModels: args.fallbackModels,
|
|
168076
|
+
onLeaseLost: markLeaseLost,
|
|
168077
|
+
isLeaseLost: () => lostLease
|
|
167317
168078
|
});
|
|
168079
|
+
if (!verifyLeaseStillHeld("after smart-note evaluation")) {
|
|
168080
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost after smart-note evaluation");
|
|
168081
|
+
}
|
|
167318
168082
|
} catch (error51) {
|
|
167319
|
-
|
|
168083
|
+
const errorDescription = describeError(error51);
|
|
168084
|
+
logWithStackHead(`[dreamer] smart note evaluation failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167320
168085
|
}
|
|
168086
|
+
if (lostLease)
|
|
168087
|
+
recordLeaseLostTask("smart-note evaluation");
|
|
167321
168088
|
}
|
|
167322
|
-
if (args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
|
|
168089
|
+
if (!circuitBreakerTripped && !lostLease && args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
|
|
167323
168090
|
const kfStart = Date.now();
|
|
167324
168091
|
try {
|
|
168092
|
+
if (!verifyLeaseStillHeld("before key-file identification")) {
|
|
168093
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost before key-file identification");
|
|
168094
|
+
}
|
|
167325
168095
|
await identifyKeyFiles({
|
|
167326
168096
|
db: args.db,
|
|
167327
168097
|
client: args.client,
|
|
@@ -167330,22 +168100,31 @@ async function runDream(args) {
|
|
|
167330
168100
|
sessionDirectory: args.sessionDirectory ?? args.projectIdentity,
|
|
167331
168101
|
holderId,
|
|
167332
168102
|
deadline,
|
|
167333
|
-
config: args.experimentalPinKeyFiles
|
|
168103
|
+
config: args.experimentalPinKeyFiles,
|
|
168104
|
+
fallbackModels: args.fallbackModels,
|
|
168105
|
+
onLeaseLost: markLeaseLost,
|
|
168106
|
+
isLeaseLost: () => lostLease
|
|
167334
168107
|
});
|
|
168108
|
+
if (!verifyLeaseStillHeld("after key-file identification")) {
|
|
168109
|
+
throw new Error(lostLeaseReason ?? "Dream lease lost after key-file identification");
|
|
168110
|
+
}
|
|
167335
168111
|
result.tasks.push({
|
|
167336
168112
|
name: "key files",
|
|
167337
168113
|
durationMs: Date.now() - kfStart,
|
|
167338
168114
|
result: "completed"
|
|
167339
168115
|
});
|
|
167340
168116
|
} catch (error51) {
|
|
167341
|
-
|
|
168117
|
+
const errorDescription = describeError(error51);
|
|
168118
|
+
logWithStackHead(`[key-files] identification phase failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167342
168119
|
result.tasks.push({
|
|
167343
168120
|
name: "key files",
|
|
167344
168121
|
durationMs: Date.now() - kfStart,
|
|
167345
168122
|
result: "",
|
|
167346
|
-
error:
|
|
168123
|
+
error: errorDescription.brief
|
|
167347
168124
|
});
|
|
167348
168125
|
}
|
|
168126
|
+
if (lostLease)
|
|
168127
|
+
recordLeaseLostTask("key-file identification");
|
|
167349
168128
|
}
|
|
167350
168129
|
} finally {
|
|
167351
168130
|
releaseLease(args.db, holderId);
|
|
@@ -167378,9 +168157,15 @@ async function runDream(args) {
|
|
|
167378
168157
|
smartNotesPending: result.smartNotesPending,
|
|
167379
168158
|
memoryChanges: persistedMemoryChanges
|
|
167380
168159
|
});
|
|
167381
|
-
const POST_TASK_NAMES = new Set([
|
|
168160
|
+
const POST_TASK_NAMES = new Set([
|
|
168161
|
+
"smart-notes",
|
|
168162
|
+
"user memories",
|
|
168163
|
+
"key files",
|
|
168164
|
+
"post-task-phases",
|
|
168165
|
+
"circuit-breaker"
|
|
168166
|
+
]);
|
|
167382
168167
|
const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
|
|
167383
|
-
if (hasSuccessfulTask) {
|
|
168168
|
+
if (hasSuccessfulTask && !lostLease) {
|
|
167384
168169
|
setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
|
|
167385
168170
|
setDreamState(args.db, "last_dream_at", String(result.finishedAt));
|
|
167386
168171
|
}
|
|
@@ -167429,9 +168214,11 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
|
|
|
167429
168214
|
try {
|
|
167430
168215
|
if (!renewLease(args.db, args.holderId)) {
|
|
167431
168216
|
log("[dreamer] smart notes: lease renewal failed — aborting");
|
|
168217
|
+
args.onLeaseLost?.("smart notes");
|
|
167432
168218
|
abortController.abort();
|
|
167433
168219
|
}
|
|
167434
|
-
} catch {
|
|
168220
|
+
} catch (error51) {
|
|
168221
|
+
args.onLeaseLost?.("smart notes", error51);
|
|
167435
168222
|
abortController.abort();
|
|
167436
168223
|
}
|
|
167437
168224
|
}, 60000);
|
|
@@ -167457,7 +168244,12 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
|
|
|
167457
168244
|
system: DREAMER_SYSTEM_PROMPT,
|
|
167458
168245
|
parts: [{ type: "text", text: evaluationPrompt, synthetic: true }]
|
|
167459
168246
|
}
|
|
167460
|
-
}, {
|
|
168247
|
+
}, {
|
|
168248
|
+
timeoutMs: Math.min(remainingMs, 300000),
|
|
168249
|
+
signal: abortController.signal,
|
|
168250
|
+
fallbackModels: args.fallbackModels,
|
|
168251
|
+
callContext: "dreamer:smart-notes"
|
|
168252
|
+
});
|
|
167461
168253
|
const messagesResponse = await args.client.session.messages({
|
|
167462
168254
|
path: { id: agentSessionId },
|
|
167463
168255
|
query: { directory: args.sessionDirectory ?? args.projectIdentity }
|
|
@@ -167516,15 +168308,15 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
|
|
|
167516
168308
|
});
|
|
167517
168309
|
} catch (error51) {
|
|
167518
168310
|
const durationMs = Date.now() - taskStartedAt;
|
|
167519
|
-
const
|
|
168311
|
+
const errorDescription = describeError(error51);
|
|
167520
168312
|
args.result.smartNotesSurfaced = 0;
|
|
167521
168313
|
args.result.smartNotesPending = pendingNotes.length;
|
|
167522
|
-
|
|
168314
|
+
logWithStackHead(`[dreamer] smart notes: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167523
168315
|
args.result.tasks.push({
|
|
167524
168316
|
name: "smart-notes",
|
|
167525
168317
|
durationMs,
|
|
167526
168318
|
result: null,
|
|
167527
|
-
error:
|
|
168319
|
+
error: errorDescription.brief
|
|
167528
168320
|
});
|
|
167529
168321
|
} finally {
|
|
167530
168322
|
clearInterval(leaseInterval);
|
|
@@ -167557,7 +168349,8 @@ async function processDreamQueue(args) {
|
|
|
167557
168349
|
maxRuntimeMinutes: args.maxRuntimeMinutes,
|
|
167558
168350
|
sessionDirectory: projectDirectory,
|
|
167559
168351
|
experimentalUserMemories: args.experimentalUserMemories,
|
|
167560
|
-
experimentalPinKeyFiles: args.experimentalPinKeyFiles
|
|
168352
|
+
experimentalPinKeyFiles: args.experimentalPinKeyFiles,
|
|
168353
|
+
fallbackModels: args.fallbackModels
|
|
167561
168354
|
});
|
|
167562
168355
|
} catch (error51) {
|
|
167563
168356
|
log(`[dreamer] runDream threw for ${entry.projectIdentity}: ${getErrorMessage(error51)}`);
|
|
@@ -168165,6 +168958,7 @@ function searchGitCommitsSync(db, projectPath, query, options) {
|
|
|
168165
168958
|
init_embedding();
|
|
168166
168959
|
init_project_identity();
|
|
168167
168960
|
init_logger();
|
|
168961
|
+
init_resolve_fallbacks();
|
|
168168
168962
|
await init_storage();
|
|
168169
168963
|
var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
|
|
168170
168964
|
var activeTimer = null;
|
|
@@ -168251,7 +169045,8 @@ async function sweepProject(reg, origin) {
|
|
|
168251
169045
|
maxRuntimeMinutes: reg.dreamerConfig.max_runtime_minutes,
|
|
168252
169046
|
experimentalUserMemories: reg.experimentalUserMemories,
|
|
168253
169047
|
experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
|
|
168254
|
-
projectIdentity: registrationIdentity
|
|
169048
|
+
projectIdentity: registrationIdentity,
|
|
169049
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
|
|
168255
169050
|
});
|
|
168256
169051
|
} catch (error51) {
|
|
168257
169052
|
log(`[dreamer] timer-triggered queue processing failed for ${reg.directory}:`, error51);
|
|
@@ -168779,6 +169574,7 @@ function createTagger() {
|
|
|
168779
169574
|
init_magic_context();
|
|
168780
169575
|
init_project_identity();
|
|
168781
169576
|
init_logger();
|
|
169577
|
+
init_resolve_fallbacks();
|
|
168782
169578
|
await init_storage();
|
|
168783
169579
|
|
|
168784
169580
|
// src/hooks/magic-context/command-handler.ts
|
|
@@ -169259,7 +170055,8 @@ Dreaming is not configured for this project.`, {});
|
|
|
169259
170055
|
maxRuntimeMinutes: deps.dreamer.config.max_runtime_minutes,
|
|
169260
170056
|
experimentalUserMemories: deps.dreamer.experimentalUserMemories,
|
|
169261
170057
|
experimentalPinKeyFiles: deps.dreamer.experimentalPinKeyFiles,
|
|
169262
|
-
projectIdentity: deps.dreamer.projectPath
|
|
170058
|
+
projectIdentity: deps.dreamer.projectPath,
|
|
170059
|
+
fallbackModels: deps.dreamer.fallbackModels
|
|
169263
170060
|
});
|
|
169264
170061
|
await deps.sendNotification(sessionId, result ? summarizeDreamResult(result) : "Dream queued, but another worker is already processing the queue.", {});
|
|
169265
170062
|
throwSentinel("CTX-DREAM");
|
|
@@ -169555,113 +170352,8 @@ function clearSessionTracking(sessionId) {
|
|
|
169555
170352
|
}
|
|
169556
170353
|
}
|
|
169557
170354
|
|
|
169558
|
-
// src/features/magic-context/overflow-detection.ts
|
|
169559
|
-
var OVERFLOW_PATTERNS = [
|
|
169560
|
-
/prompt is too long/i,
|
|
169561
|
-
/input is too long for requested model/i,
|
|
169562
|
-
/exceeds the context window/i,
|
|
169563
|
-
/input token count.*exceeds the maximum/i,
|
|
169564
|
-
/maximum prompt length is \d+/i,
|
|
169565
|
-
/reduce the length of the messages/i,
|
|
169566
|
-
/maximum context length is \d+ tokens/i,
|
|
169567
|
-
/exceeds the limit of \d+/i,
|
|
169568
|
-
/exceeds the available context size/i,
|
|
169569
|
-
/greater than the context length/i,
|
|
169570
|
-
/context window exceeds limit/i,
|
|
169571
|
-
/exceeded model token limit/i,
|
|
169572
|
-
/context[_ ]length[_ ]exceeded/i,
|
|
169573
|
-
/request entity too large/i,
|
|
169574
|
-
/context length is only \d+ tokens/i,
|
|
169575
|
-
/input length.*exceeds.*context length/i,
|
|
169576
|
-
/prompt too long; exceeded (?:max )?context length/i,
|
|
169577
|
-
/too large for model with \d+ maximum context length/i,
|
|
169578
|
-
/model_context_window_exceeded/i,
|
|
169579
|
-
/context size has been exceeded/i
|
|
169580
|
-
];
|
|
169581
|
-
var LIMIT_EXTRACTION_PATTERNS = [
|
|
169582
|
-
/maximum prompt length is (\d+)/i,
|
|
169583
|
-
/maximum context length is (\d+) tokens?/i,
|
|
169584
|
-
/context length is only (\d+) tokens?/i,
|
|
169585
|
-
/exceeds the limit of (\d+)/i,
|
|
169586
|
-
/too large for model with (\d+) maximum context length/i,
|
|
169587
|
-
/context size.*(\d+) tokens?/i,
|
|
169588
|
-
/exceeds? the context length of (\d+)/i,
|
|
169589
|
-
/max(?:imum)?.*context.*?(\d+)/i
|
|
169590
|
-
];
|
|
169591
|
-
var MIN_PLAUSIBLE_LIMIT = 1024;
|
|
169592
|
-
var MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
169593
|
-
function extractErrorMessage(error51) {
|
|
169594
|
-
if (!error51)
|
|
169595
|
-
return "";
|
|
169596
|
-
if (typeof error51 === "string")
|
|
169597
|
-
return error51;
|
|
169598
|
-
if (typeof error51 === "object") {
|
|
169599
|
-
const obj = error51;
|
|
169600
|
-
const nested = obj.error;
|
|
169601
|
-
if (nested && typeof nested.message === "string" && nested.message.length > 0) {
|
|
169602
|
-
return nested.message;
|
|
169603
|
-
}
|
|
169604
|
-
}
|
|
169605
|
-
if (error51 instanceof Error)
|
|
169606
|
-
return error51.message;
|
|
169607
|
-
if (typeof error51 === "object") {
|
|
169608
|
-
const obj = error51;
|
|
169609
|
-
if (typeof obj.message === "string")
|
|
169610
|
-
return obj.message;
|
|
169611
|
-
if (typeof obj.responseBody === "string")
|
|
169612
|
-
return obj.responseBody;
|
|
169613
|
-
try {
|
|
169614
|
-
return JSON.stringify(error51);
|
|
169615
|
-
} catch {
|
|
169616
|
-
return String(error51);
|
|
169617
|
-
}
|
|
169618
|
-
}
|
|
169619
|
-
return String(error51);
|
|
169620
|
-
}
|
|
169621
|
-
function detectOverflow(error51) {
|
|
169622
|
-
const message = extractErrorMessage(error51);
|
|
169623
|
-
if (!message) {
|
|
169624
|
-
return { isOverflow: false };
|
|
169625
|
-
}
|
|
169626
|
-
const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
|
|
169627
|
-
let matched;
|
|
169628
|
-
for (const pattern of OVERFLOW_PATTERNS) {
|
|
169629
|
-
if (pattern.test(message)) {
|
|
169630
|
-
matched = pattern;
|
|
169631
|
-
break;
|
|
169632
|
-
}
|
|
169633
|
-
}
|
|
169634
|
-
if (!matched && !hasStatus413) {
|
|
169635
|
-
return { isOverflow: false };
|
|
169636
|
-
}
|
|
169637
|
-
const reportedLimit = parseReportedLimit(message);
|
|
169638
|
-
return {
|
|
169639
|
-
isOverflow: true,
|
|
169640
|
-
reportedLimit,
|
|
169641
|
-
matchedPattern: matched?.source
|
|
169642
|
-
};
|
|
169643
|
-
}
|
|
169644
|
-
function parseReportedLimit(message) {
|
|
169645
|
-
if (!message)
|
|
169646
|
-
return;
|
|
169647
|
-
for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
|
|
169648
|
-
const match = message.match(pattern);
|
|
169649
|
-
if (!match)
|
|
169650
|
-
continue;
|
|
169651
|
-
const raw = match[1];
|
|
169652
|
-
if (!raw)
|
|
169653
|
-
continue;
|
|
169654
|
-
const value = Number.parseInt(raw, 10);
|
|
169655
|
-
if (!Number.isFinite(value))
|
|
169656
|
-
continue;
|
|
169657
|
-
if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
|
|
169658
|
-
continue;
|
|
169659
|
-
return value;
|
|
169660
|
-
}
|
|
169661
|
-
return;
|
|
169662
|
-
}
|
|
169663
|
-
|
|
169664
170355
|
// src/hooks/magic-context/event-handler.ts
|
|
170356
|
+
init_overflow_detection();
|
|
169665
170357
|
init_storage_meta_persisted();
|
|
169666
170358
|
init_logger();
|
|
169667
170359
|
await __promiseAll([
|
|
@@ -169774,6 +170466,15 @@ init_project_identity();
|
|
|
169774
170466
|
init_logger();
|
|
169775
170467
|
await init_storage();
|
|
169776
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
|
+
|
|
169777
170478
|
// src/hooks/magic-context/caveman-cleanup.ts
|
|
169778
170479
|
init_shared();
|
|
169779
170480
|
init_caveman();
|
|
@@ -170521,6 +171222,9 @@ function clearCompressorCooldown(sessionId) {
|
|
|
170521
171222
|
async function runCompartmentPhase(args) {
|
|
170522
171223
|
let pendingCompartmentInjection = args.pendingCompartmentInjection;
|
|
170523
171224
|
let compartmentInProgress = args.sessionMeta.compartmentInProgress;
|
|
171225
|
+
let published = false;
|
|
171226
|
+
let justAwaitedPublication = false;
|
|
171227
|
+
let rebuiltHistoryThisPass = false;
|
|
170524
171228
|
let lastCompartmentEnd = null;
|
|
170525
171229
|
let rawMessageCount = null;
|
|
170526
171230
|
let cachedProtectedTailStart = null;
|
|
@@ -170548,13 +171252,19 @@ async function runCompartmentPhase(args) {
|
|
|
170548
171252
|
sessionLog(args.sessionId, reason);
|
|
170549
171253
|
const timeoutMs = args.historianTimeoutMs ?? 120000;
|
|
170550
171254
|
const timeout = new Promise((resolve4) => setTimeout(() => resolve4("timeout"), timeoutMs));
|
|
170551
|
-
const result = await Promise.race([activeRun.then(() => "done"), timeout]);
|
|
171255
|
+
const result = await Promise.race([activeRun.promise.then(() => "done"), timeout]);
|
|
170552
171256
|
if (result === "timeout") {
|
|
170553
171257
|
sessionLog(args.sessionId, `transform: compartment await timed out after ${timeoutMs}ms — proceeding without waiting`);
|
|
170554
171258
|
return "timed_out";
|
|
170555
171259
|
}
|
|
170556
171260
|
sessionLog(args.sessionId, "transform: compartment agent completed, refreshing compartment coverage");
|
|
170557
|
-
|
|
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
|
+
}
|
|
170558
171268
|
return "completed";
|
|
170559
171269
|
}
|
|
170560
171270
|
if (args.canRunCompartments && args.sessionMeta.compartmentInProgress && !getActiveCompartmentRun(args.sessionId)) {
|
|
@@ -170575,6 +171285,7 @@ async function runCompartmentPhase(args) {
|
|
|
170575
171285
|
historianChunkTokens: args.historianChunkTokens,
|
|
170576
171286
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
170577
171287
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
171288
|
+
fallbackModels: args.fallbackModels,
|
|
170578
171289
|
directory: args.compartmentDirectory,
|
|
170579
171290
|
fallbackModelId: args.fallbackModelId,
|
|
170580
171291
|
getNotificationParams: args.getNotificationParams,
|
|
@@ -170585,7 +171296,8 @@ async function runCompartmentPhase(args) {
|
|
|
170585
171296
|
compressorMaxMergeDepth: args.compressorMaxMergeDepth,
|
|
170586
171297
|
memoryEnabled: args.memoryEnabled,
|
|
170587
171298
|
autoPromote: args.autoPromote,
|
|
170588
|
-
|
|
171299
|
+
onCompartmentStatePublished: args.onCompartmentStatePublished,
|
|
171300
|
+
preserveInjectionCacheUntilConsumed: true
|
|
170589
171301
|
});
|
|
170590
171302
|
compartmentInProgress = true;
|
|
170591
171303
|
}
|
|
@@ -170602,6 +171314,7 @@ async function runCompartmentPhase(args) {
|
|
|
170602
171314
|
historianChunkTokens: args.historianChunkTokens,
|
|
170603
171315
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
170604
171316
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
171317
|
+
fallbackModels: args.fallbackModels,
|
|
170605
171318
|
directory: args.compartmentDirectory,
|
|
170606
171319
|
fallbackModelId: args.fallbackModelId,
|
|
170607
171320
|
getNotificationParams: args.getNotificationParams,
|
|
@@ -170612,7 +171325,8 @@ async function runCompartmentPhase(args) {
|
|
|
170612
171325
|
compressorMaxMergeDepth: args.compressorMaxMergeDepth,
|
|
170613
171326
|
memoryEnabled: args.memoryEnabled,
|
|
170614
171327
|
autoPromote: args.autoPromote,
|
|
170615
|
-
|
|
171328
|
+
onCompartmentStatePublished: args.onCompartmentStatePublished,
|
|
171329
|
+
preserveInjectionCacheUntilConsumed: true
|
|
170616
171330
|
});
|
|
170617
171331
|
activeRun = getActiveCompartmentRun(args.sessionId);
|
|
170618
171332
|
} else if (!activeRun && hasEligibleHistoryForCompartment()) {
|
|
@@ -170632,7 +171346,7 @@ async function runCompartmentPhase(args) {
|
|
|
170632
171346
|
}
|
|
170633
171347
|
}
|
|
170634
171348
|
}
|
|
170635
|
-
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)) {
|
|
170636
171350
|
markCompressorRun(args.sessionId);
|
|
170637
171351
|
const compressorPromise = runCompressionPassIfNeeded({
|
|
170638
171352
|
client: args.client,
|
|
@@ -170641,10 +171355,14 @@ async function runCompartmentPhase(args) {
|
|
|
170641
171355
|
directory: args.compartmentDirectory,
|
|
170642
171356
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
170643
171357
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
171358
|
+
fallbackModels: args.fallbackModels,
|
|
170644
171359
|
minCompartmentRatio: args.compressorMinCompartmentRatio,
|
|
170645
171360
|
maxMergeDepth: args.compressorMaxMergeDepth
|
|
170646
171361
|
}).then((compressed) => {
|
|
170647
171362
|
if (compressed) {
|
|
171363
|
+
markActiveCompartmentRunPublished(args.sessionId);
|
|
171364
|
+
published = true;
|
|
171365
|
+
args.deferredHistoryRefreshSessions.add(args.sessionId);
|
|
170648
171366
|
sessionLog(args.sessionId, "independent compressor completed in background — compressed history will appear on next cache-busting pass");
|
|
170649
171367
|
}
|
|
170650
171368
|
}).catch((error51) => {
|
|
@@ -170652,7 +171370,14 @@ async function runCompartmentPhase(args) {
|
|
|
170652
171370
|
});
|
|
170653
171371
|
registerActiveCompartmentRun(args.sessionId, compressorPromise);
|
|
170654
171372
|
}
|
|
170655
|
-
return {
|
|
171373
|
+
return {
|
|
171374
|
+
pendingCompartmentInjection,
|
|
171375
|
+
awaitedCompartmentRun,
|
|
171376
|
+
compartmentInProgress,
|
|
171377
|
+
published,
|
|
171378
|
+
justAwaitedPublication,
|
|
171379
|
+
rebuiltHistoryThisPass
|
|
171380
|
+
};
|
|
170656
171381
|
}
|
|
170657
171382
|
|
|
170658
171383
|
// src/hooks/magic-context/transform-context-state.ts
|
|
@@ -170738,6 +171463,46 @@ function countMessagesSinceLastUser(messages) {
|
|
|
170738
171463
|
}
|
|
170739
171464
|
return messagesSinceLastUser;
|
|
170740
171465
|
}
|
|
171466
|
+
function injectToolPartIntoLatestAssistant(messages, part) {
|
|
171467
|
+
for (let index = messages.length - 1;index >= 0; index -= 1) {
|
|
171468
|
+
const message = messages[index];
|
|
171469
|
+
if (message.info.role !== "assistant")
|
|
171470
|
+
continue;
|
|
171471
|
+
if (typeof message.info.id !== "string")
|
|
171472
|
+
continue;
|
|
171473
|
+
if (hasToolPartWithCallId(message, part.callID)) {
|
|
171474
|
+
return message.info.id;
|
|
171475
|
+
}
|
|
171476
|
+
message.parts.push(part);
|
|
171477
|
+
return message.info.id;
|
|
171478
|
+
}
|
|
171479
|
+
return null;
|
|
171480
|
+
}
|
|
171481
|
+
function injectToolPartIntoAssistantById(messages, messageId, part) {
|
|
171482
|
+
for (const message of messages) {
|
|
171483
|
+
if (message.info.id !== messageId)
|
|
171484
|
+
continue;
|
|
171485
|
+
if (message.info.role !== "assistant")
|
|
171486
|
+
continue;
|
|
171487
|
+
if (hasToolPartWithCallId(message, part.callID))
|
|
171488
|
+
return true;
|
|
171489
|
+
message.parts.push(part);
|
|
171490
|
+
return true;
|
|
171491
|
+
}
|
|
171492
|
+
return false;
|
|
171493
|
+
}
|
|
171494
|
+
function hasToolPartWithCallId(message, callId) {
|
|
171495
|
+
for (const part of message.parts) {
|
|
171496
|
+
if (part === null || typeof part !== "object")
|
|
171497
|
+
continue;
|
|
171498
|
+
const p = part;
|
|
171499
|
+
if (p.type !== "tool")
|
|
171500
|
+
continue;
|
|
171501
|
+
if (p.callID === callId)
|
|
171502
|
+
return true;
|
|
171503
|
+
}
|
|
171504
|
+
return false;
|
|
171505
|
+
}
|
|
170741
171506
|
function appendReminderToUserMessage(message, reminder) {
|
|
170742
171507
|
for (const part of message.parts) {
|
|
170743
171508
|
if (!isTextPart(part)) {
|
|
@@ -171974,7 +172739,10 @@ function clearAutoSearchForSession(sessionId) {
|
|
|
171974
172739
|
}
|
|
171975
172740
|
|
|
171976
172741
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
171977
|
-
await
|
|
172742
|
+
await __promiseAll([
|
|
172743
|
+
init_compaction_marker_manager(),
|
|
172744
|
+
init_compartment_runner()
|
|
172745
|
+
]);
|
|
171978
172746
|
|
|
171979
172747
|
// src/hooks/magic-context/heuristic-cleanup.ts
|
|
171980
172748
|
init_shared();
|
|
@@ -172247,6 +173015,84 @@ function isVisibleNoteReadPart(part) {
|
|
|
172247
173015
|
return false;
|
|
172248
173016
|
}
|
|
172249
173017
|
|
|
173018
|
+
// src/hooks/magic-context/todo-view.ts
|
|
173019
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
173020
|
+
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
173021
|
+
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
173022
|
+
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
173023
|
+
function normalizeTodoStateJson(todos) {
|
|
173024
|
+
if (!Array.isArray(todos))
|
|
173025
|
+
return null;
|
|
173026
|
+
const normalized = [];
|
|
173027
|
+
for (const todo of todos) {
|
|
173028
|
+
if (!isTodoItem(todo))
|
|
173029
|
+
return null;
|
|
173030
|
+
normalized.push({
|
|
173031
|
+
content: todo.content,
|
|
173032
|
+
status: todo.status,
|
|
173033
|
+
priority: todo.priority
|
|
173034
|
+
});
|
|
173035
|
+
}
|
|
173036
|
+
return JSON.stringify(normalized);
|
|
173037
|
+
}
|
|
173038
|
+
function buildSyntheticTodoPart(stateJson) {
|
|
173039
|
+
const todos = parseTodoState(stateJson);
|
|
173040
|
+
if (todos === null || todos.length === 0)
|
|
173041
|
+
return null;
|
|
173042
|
+
if (todos.every((t) => TERMINAL_STATUSES.has(t.status)))
|
|
173043
|
+
return null;
|
|
173044
|
+
const callID = computeSyntheticCallId(stateJson);
|
|
173045
|
+
const activeCount = todos.filter((t) => !TITLE_DONE_STATUSES.has(t.status)).length;
|
|
173046
|
+
const output = JSON.stringify(todos, null, 2);
|
|
173047
|
+
const ts = 0;
|
|
173048
|
+
return {
|
|
173049
|
+
type: "tool",
|
|
173050
|
+
callID,
|
|
173051
|
+
tool: "todowrite",
|
|
173052
|
+
state: {
|
|
173053
|
+
status: "completed",
|
|
173054
|
+
input: { todos },
|
|
173055
|
+
output,
|
|
173056
|
+
title: `${activeCount} todos`,
|
|
173057
|
+
metadata: { todos, truncated: false },
|
|
173058
|
+
time: { start: ts, end: ts }
|
|
173059
|
+
},
|
|
173060
|
+
syntheticTodoMarker: true
|
|
173061
|
+
};
|
|
173062
|
+
}
|
|
173063
|
+
function computeSyntheticCallId(stateJson) {
|
|
173064
|
+
const hash2 = createHash5("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
173065
|
+
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
173066
|
+
}
|
|
173067
|
+
function parseTodoState(stateJson) {
|
|
173068
|
+
if (stateJson.length === 0)
|
|
173069
|
+
return null;
|
|
173070
|
+
try {
|
|
173071
|
+
const parsed = JSON.parse(stateJson);
|
|
173072
|
+
if (!Array.isArray(parsed))
|
|
173073
|
+
return null;
|
|
173074
|
+
const result = [];
|
|
173075
|
+
for (const item of parsed) {
|
|
173076
|
+
if (!isTodoItem(item))
|
|
173077
|
+
continue;
|
|
173078
|
+
result.push({
|
|
173079
|
+
content: item.content,
|
|
173080
|
+
status: item.status,
|
|
173081
|
+
priority: item.priority
|
|
173082
|
+
});
|
|
173083
|
+
}
|
|
173084
|
+
return result;
|
|
173085
|
+
} catch {
|
|
173086
|
+
return null;
|
|
173087
|
+
}
|
|
173088
|
+
}
|
|
173089
|
+
function isTodoItem(value) {
|
|
173090
|
+
if (value === null || typeof value !== "object")
|
|
173091
|
+
return false;
|
|
173092
|
+
const todo = value;
|
|
173093
|
+
return typeof todo.content === "string" && typeof todo.status === "string" && typeof todo.priority === "string";
|
|
173094
|
+
}
|
|
173095
|
+
|
|
172250
173096
|
// src/hooks/magic-context/transform-stage-logger.ts
|
|
172251
173097
|
init_logger();
|
|
172252
173098
|
function logTransformTiming(sessionId, stage, startMs, extra) {
|
|
@@ -172256,26 +173102,34 @@ function logTransformTiming(sessionId, stage, startMs, extra) {
|
|
|
172256
173102
|
}
|
|
172257
173103
|
|
|
172258
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
|
+
}
|
|
172259
173110
|
async function runPostTransformPhase(args) {
|
|
172260
173111
|
let didMutateFromPendingOperations = false;
|
|
172261
173112
|
const isExplicitFlush = args.pendingMaterializationSessions.has(args.sessionId);
|
|
173113
|
+
const deferredMaterializationWasPending = args.deferredMaterializationSessions.has(args.sessionId);
|
|
172262
173114
|
const alreadyRanThisTurn = args.currentTurnId !== null && args.lastHeuristicsTurnId.get(args.sessionId) === args.currentTurnId;
|
|
172263
173115
|
const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
|
|
172264
173116
|
const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
|
|
172265
173117
|
const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
|
|
172266
173118
|
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
172267
|
-
const
|
|
173119
|
+
const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
173120
|
+
const materializationRequested = isExplicitFlush || deferredMaterialize;
|
|
173121
|
+
const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || compartmentRunning;
|
|
172268
173122
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
172269
173123
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
172270
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" ||
|
|
172271
|
-
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));
|
|
172272
173126
|
const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
|
|
172273
173127
|
if (shouldRunHeuristics) {
|
|
172274
173128
|
const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
|
|
172275
|
-
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})`;
|
|
172276
173130
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
172277
173131
|
}
|
|
172278
|
-
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !
|
|
173132
|
+
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
|
|
172279
173133
|
sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
|
|
172280
173134
|
}
|
|
172281
173135
|
if (compartmentRunning && hasPendingUserOps) {
|
|
@@ -172285,9 +173139,11 @@ async function runPostTransformPhase(args) {
|
|
|
172285
173139
|
sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
|
|
172286
173140
|
}
|
|
172287
173141
|
}
|
|
173142
|
+
let explicitMaterializedSuccessfully = false;
|
|
173143
|
+
let deferredMaterializedSuccessfully = false;
|
|
172288
173144
|
try {
|
|
172289
173145
|
if (shouldApplyPendingOps) {
|
|
172290
|
-
const applyReason = isExplicitFlush ? "explicit_flush" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
173146
|
+
const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
172291
173147
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
172292
173148
|
const pendingCountBefore = pendingOps.length;
|
|
172293
173149
|
const tApply = performance.now();
|
|
@@ -172349,7 +173205,7 @@ async function runPostTransformPhase(args) {
|
|
|
172349
173205
|
args.lastHeuristicsTurnId.set(args.sessionId, args.currentTurnId);
|
|
172350
173206
|
}
|
|
172351
173207
|
}
|
|
172352
|
-
if (args.schedulerDecision === "execute" && !
|
|
173208
|
+
if (args.schedulerDecision === "execute" && !materializationRequested) {
|
|
172353
173209
|
updateSessionMeta(args.db, args.sessionId, { lastResponseTime: Date.now() });
|
|
172354
173210
|
}
|
|
172355
173211
|
args.batch?.finalize();
|
|
@@ -172357,6 +173213,12 @@ async function runPostTransformPhase(args) {
|
|
|
172357
173213
|
if (args.sessionMeta.lastTransformError !== null) {
|
|
172358
173214
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: null });
|
|
172359
173215
|
}
|
|
173216
|
+
if (shouldRunHeuristics) {
|
|
173217
|
+
if (isExplicitFlush)
|
|
173218
|
+
explicitMaterializedSuccessfully = true;
|
|
173219
|
+
if (deferredMaterialize)
|
|
173220
|
+
deferredMaterializedSuccessfully = true;
|
|
173221
|
+
}
|
|
172360
173222
|
} catch (error51) {
|
|
172361
173223
|
sessionLog(args.sessionId, "transform failed applying pending operations:", error51);
|
|
172362
173224
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error51) });
|
|
@@ -172488,6 +173350,72 @@ async function runPostTransformPhase(args) {
|
|
|
172488
173350
|
const anchoredMessageId = appendReminderToLatestUserMessage(args.messages, noteInstruction);
|
|
172489
173351
|
markNoteNudgeDelivered(args.db, args.sessionId, noteInstruction, anchoredMessageId);
|
|
172490
173352
|
}
|
|
173353
|
+
if (args.fullFeatureMode) {
|
|
173354
|
+
const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
173355
|
+
if (isCacheBustingPass) {
|
|
173356
|
+
const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
|
|
173357
|
+
if (part === null) {
|
|
173358
|
+
if (persistedAnchor) {
|
|
173359
|
+
clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
173360
|
+
}
|
|
173361
|
+
} else if (persistedAnchor && persistedAnchor.callId === part.callID && injectToolPartIntoAssistantById(args.messages, persistedAnchor.messageId, part)) {
|
|
173362
|
+
if (persistedAnchor.stateJson.length === 0) {
|
|
173363
|
+
setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
|
|
173364
|
+
}
|
|
173365
|
+
} else {
|
|
173366
|
+
const anchoredMessageId = injectToolPartIntoLatestAssistant(args.messages, part);
|
|
173367
|
+
if (anchoredMessageId) {
|
|
173368
|
+
setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, anchoredMessageId, args.sessionMeta.lastTodoState);
|
|
173369
|
+
} else if (persistedAnchor) {
|
|
173370
|
+
clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
173371
|
+
}
|
|
173372
|
+
}
|
|
173373
|
+
} else if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
|
|
173374
|
+
const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
|
|
173375
|
+
if (part !== null && part.callID === persistedAnchor.callId) {
|
|
173376
|
+
injectToolPartIntoAssistantById(args.messages, persistedAnchor.messageId, part);
|
|
173377
|
+
}
|
|
173378
|
+
}
|
|
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
|
+
}
|
|
172491
173419
|
if (args.fullFeatureMode && args.autoSearch?.enabled && args.projectPath) {
|
|
172492
173420
|
const visibleMemoryIds = getVisibleMemoryIds(args.db, args.sessionId) ?? undefined;
|
|
172493
173421
|
try {
|
|
@@ -172510,6 +173438,7 @@ async function runPostTransformPhase(args) {
|
|
|
172510
173438
|
sessionLog(args.sessionId, "auto-search runner failed:", error51);
|
|
172511
173439
|
}
|
|
172512
173440
|
}
|
|
173441
|
+
return { explicitMaterializedSuccessfully, deferredMaterializedSuccessfully };
|
|
172513
173442
|
}
|
|
172514
173443
|
|
|
172515
173444
|
// src/hooks/magic-context/nudge-placement-store.ts
|
|
@@ -172583,6 +173512,8 @@ function findLastAssistantModel(messages) {
|
|
|
172583
173512
|
function createTransform(deps) {
|
|
172584
173513
|
const loadedSessions = new Set;
|
|
172585
173514
|
const lastEmergencyNotificationCount = new Map;
|
|
173515
|
+
const deferredHistoryRefreshSessions = deps.deferredHistoryRefreshSessions ?? new Set;
|
|
173516
|
+
const deferredMaterializationSessions = deps.deferredMaterializationSessions ?? new Set;
|
|
172586
173517
|
return async (_input, output) => {
|
|
172587
173518
|
const startTime = performance.now();
|
|
172588
173519
|
const messages = output.messages;
|
|
@@ -172691,7 +173622,17 @@ function createTransform(deps) {
|
|
|
172691
173622
|
}
|
|
172692
173623
|
const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens);
|
|
172693
173624
|
const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId));
|
|
172694
|
-
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;
|
|
172695
173636
|
if (historianFailureState.failureCount === 0) {
|
|
172696
173637
|
lastEmergencyNotificationCount.delete(sessionId);
|
|
172697
173638
|
}
|
|
@@ -172719,6 +173660,7 @@ function createTransform(deps) {
|
|
|
172719
173660
|
historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
|
|
172720
173661
|
historyBudgetTokens,
|
|
172721
173662
|
historianTimeoutMs: deps.historianTimeoutMs,
|
|
173663
|
+
fallbackModels: deps.fallbackModels,
|
|
172722
173664
|
directory: compartmentDirectory,
|
|
172723
173665
|
fallbackModelId,
|
|
172724
173666
|
getNotificationParams: () => notificationParams,
|
|
@@ -172730,9 +173672,10 @@ function createTransform(deps) {
|
|
|
172730
173672
|
compressorMaxMergeDepth: deps.compressorMaxMergeDepth,
|
|
172731
173673
|
memoryEnabled: deps.memoryConfig?.enabled,
|
|
172732
173674
|
autoPromote: deps.memoryConfig?.autoPromote,
|
|
172733
|
-
|
|
172734
|
-
|
|
172735
|
-
|
|
173675
|
+
preserveInjectionCacheUntilConsumed: true,
|
|
173676
|
+
onCompartmentStatePublished: (sid) => {
|
|
173677
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
173678
|
+
deferredMaterializationSessions.add(sid);
|
|
172736
173679
|
}
|
|
172737
173680
|
});
|
|
172738
173681
|
skipCompartmentAwaitForThisPass = true;
|
|
@@ -172765,11 +173708,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172765
173708
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
172766
173709
|
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(compartmentDirectory || process.cwd()) : undefined;
|
|
172767
173710
|
let pendingCompartmentInjection = null;
|
|
173711
|
+
let rebuiltHistoryFromInitialPrepare = false;
|
|
172768
173712
|
if (fullFeatureMode) {
|
|
172769
173713
|
const tInj = performance.now();
|
|
172770
173714
|
pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
|
|
172771
173715
|
logTransformTiming(sessionId, "prepareCompartmentInjection", tInj);
|
|
172772
173716
|
if (isCacheBusting) {
|
|
173717
|
+
rebuiltHistoryFromInitialPrepare = true;
|
|
173718
|
+
}
|
|
173719
|
+
if (historyRefreshExplicitBeforePrepare) {
|
|
172773
173720
|
deps.historyRefreshSessions.delete(sessionId);
|
|
172774
173721
|
}
|
|
172775
173722
|
}
|
|
@@ -172888,6 +173835,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172888
173835
|
historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
|
|
172889
173836
|
historyBudgetTokens,
|
|
172890
173837
|
historianTimeoutMs: deps.historianTimeoutMs,
|
|
173838
|
+
fallbackModels: deps.fallbackModels,
|
|
172891
173839
|
compartmentDirectory,
|
|
172892
173840
|
messages,
|
|
172893
173841
|
pendingCompartmentInjection,
|
|
@@ -172895,7 +173843,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172895
173843
|
projectPath: projectIdentity,
|
|
172896
173844
|
injectionBudgetTokens: deps.memoryConfig?.injectionBudgetTokens,
|
|
172897
173845
|
getNotificationParams: rawGetNotifParams ? () => rawGetNotifParams(sessionId) : undefined,
|
|
172898
|
-
|
|
173846
|
+
safeForBackgroundCompression: isCacheBusting || schedulerDecisionEarly === "execute",
|
|
173847
|
+
suppressBackgroundCompressionThisPass: historyBustThisPass,
|
|
173848
|
+
deferredHistoryRefreshSessions,
|
|
172899
173849
|
skipAwaitForThisPass: skipCompartmentAwaitForThisPass,
|
|
172900
173850
|
experimentalCompactionMarkers: deps.experimentalCompactionMarkers,
|
|
172901
173851
|
experimentalUserMemories: deps.experimentalUserMemories,
|
|
@@ -172906,9 +173856,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172906
173856
|
compressorCooldownMs: deps.compressorCooldownMs,
|
|
172907
173857
|
memoryEnabled: deps.memoryConfig?.enabled,
|
|
172908
173858
|
autoPromote: deps.memoryConfig?.autoPromote,
|
|
172909
|
-
|
|
172910
|
-
|
|
172911
|
-
|
|
173859
|
+
onCompartmentStatePublished: (sid) => {
|
|
173860
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
173861
|
+
deferredMaterializationSessions.add(sid);
|
|
172912
173862
|
}
|
|
172913
173863
|
});
|
|
172914
173864
|
pendingCompartmentInjection = compartmentPhase.pendingCompartmentInjection;
|
|
@@ -172916,6 +173866,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172916
173866
|
const compartmentInProgress = compartmentPhase.compartmentInProgress;
|
|
172917
173867
|
sessionMeta = { ...sessionMeta, compartmentInProgress };
|
|
172918
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;
|
|
172919
173878
|
const tPostProcess = performance.now();
|
|
172920
173879
|
await runPostTransformPhase({
|
|
172921
173880
|
sessionId,
|
|
@@ -172931,10 +173890,18 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172931
173890
|
fullFeatureMode,
|
|
172932
173891
|
canRunCompartments,
|
|
172933
173892
|
awaitedCompartmentRun,
|
|
173893
|
+
phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
|
|
172934
173894
|
compartmentInProgress,
|
|
173895
|
+
historyRefreshExplicitBeforePrepare,
|
|
173896
|
+
compartmentInjectionRebuiltFromDb: pendingCompartmentInjection?.rebuiltFromDb === true,
|
|
173897
|
+
rebuiltHistoryFromInitialPrepare,
|
|
173898
|
+
historyRebuiltThisPass,
|
|
173899
|
+
canConsumeDeferredLate,
|
|
172935
173900
|
sessionMeta,
|
|
172936
173901
|
currentTurnId,
|
|
172937
173902
|
pendingMaterializationSessions: deps.pendingMaterializationSessions,
|
|
173903
|
+
deferredHistoryRefreshSessions,
|
|
173904
|
+
deferredMaterializationSessions,
|
|
172938
173905
|
lastHeuristicsTurnId: deps.lastHeuristicsTurnId,
|
|
172939
173906
|
autoDropToolAge: deps.autoDropToolAge,
|
|
172940
173907
|
dropToolStructure: deps.dropToolStructure ?? true,
|
|
@@ -172948,6 +173915,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172948
173915
|
forceMaterializationPercentage: FORCE_MATERIALIZE_PERCENTAGE,
|
|
172949
173916
|
hasRecentReduceCall,
|
|
172950
173917
|
projectPath: deps.projectPath,
|
|
173918
|
+
sessionDirectory,
|
|
172951
173919
|
autoSearch: deps.autoSearch,
|
|
172952
173920
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
172953
173921
|
liveProviderID
|
|
@@ -173355,6 +174323,15 @@ function createEventHandler2(deps) {
|
|
|
173355
174323
|
} catch (error51) {
|
|
173356
174324
|
sessionLog(sessionId, "event session.compacted marker cleanup failed:", error51);
|
|
173357
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);
|
|
173358
174335
|
clearMessageTokensCache(sessionId);
|
|
173359
174336
|
deps.onSessionCacheInvalidated?.(sessionId);
|
|
173360
174337
|
return;
|
|
@@ -173371,6 +174348,7 @@ function createEventHandler2(deps) {
|
|
|
173371
174348
|
} catch (error51) {
|
|
173372
174349
|
sessionLog(sessionId, "event session.deleted persistence failed:", error51);
|
|
173373
174350
|
}
|
|
174351
|
+
resetDegradedCacheCount(sessionId);
|
|
173374
174352
|
deps.onSessionCacheInvalidated?.(sessionId);
|
|
173375
174353
|
deps.onSessionDeleted?.(sessionId);
|
|
173376
174354
|
deps.contextUsageMap.delete(sessionId);
|
|
@@ -173579,6 +174557,10 @@ function applyStickySnapshotCache(sessionId, fresh) {
|
|
|
173579
174557
|
cache.delete(sessionId);
|
|
173580
174558
|
return fresh;
|
|
173581
174559
|
}
|
|
174560
|
+
if (!hasInFlightEvidence(fresh)) {
|
|
174561
|
+
cache.delete(sessionId);
|
|
174562
|
+
return fresh;
|
|
174563
|
+
}
|
|
173582
174564
|
return {
|
|
173583
174565
|
...fresh,
|
|
173584
174566
|
usagePercentage: cached2.snapshot.usagePercentage,
|
|
@@ -173592,6 +174574,9 @@ function applyStickySnapshotCache(sessionId, fresh) {
|
|
|
173592
174574
|
toolDefinitionTokens: cached2.snapshot.toolDefinitionTokens
|
|
173593
174575
|
};
|
|
173594
174576
|
}
|
|
174577
|
+
function hasInFlightEvidence(snapshot) {
|
|
174578
|
+
return snapshot.compartmentInProgress || snapshot.historianRunning || snapshot.pendingOpsCount > 0;
|
|
174579
|
+
}
|
|
173595
174580
|
function clearSidebarSnapshotCache(sessionId) {
|
|
173596
174581
|
cache.delete(sessionId);
|
|
173597
174582
|
}
|
|
@@ -173692,8 +174677,10 @@ function createEventHook(args) {
|
|
|
173692
174677
|
args.recentReduceBySession.delete(sessionId);
|
|
173693
174678
|
args.toolUsageSinceUserTurn.delete(sessionId);
|
|
173694
174679
|
args.historyRefreshSessions.delete(sessionId);
|
|
174680
|
+
args.deferredHistoryRefreshSessions.delete(sessionId);
|
|
173695
174681
|
args.systemPromptRefreshSessions.delete(sessionId);
|
|
173696
174682
|
args.pendingMaterializationSessions.delete(sessionId);
|
|
174683
|
+
args.deferredMaterializationSessions.delete(sessionId);
|
|
173697
174684
|
args.lastHeuristicsTurnId.delete(sessionId);
|
|
173698
174685
|
args.commitSeenLastPass?.delete(sessionId);
|
|
173699
174686
|
clearNoteNudgeState(args.db, sessionId);
|
|
@@ -173728,9 +174715,17 @@ function createToolExecuteAfterHook(args) {
|
|
|
173728
174715
|
if (typedInput.tool === "todowrite") {
|
|
173729
174716
|
const todoArgs = typedInput.args;
|
|
173730
174717
|
const todos = todoArgs?.todos;
|
|
173731
|
-
|
|
173732
|
-
|
|
173733
|
-
|
|
174718
|
+
const sessionMeta = Array.isArray(todos) ? getOrCreateSessionMeta(args.db, typedInput.sessionID) : null;
|
|
174719
|
+
if (sessionMeta && !sessionMeta.isSubagent) {
|
|
174720
|
+
const normalizedTodos = normalizeTodoStateJson(todos);
|
|
174721
|
+
if (normalizedTodos !== null) {
|
|
174722
|
+
updateSessionMeta(args.db, typedInput.sessionID, {
|
|
174723
|
+
lastTodoState: normalizedTodos
|
|
174724
|
+
});
|
|
174725
|
+
}
|
|
174726
|
+
}
|
|
174727
|
+
if (Array.isArray(todos) && todos.length > 0 && todos.every((t) => typeof t === "object" && t !== null && (t.status === "completed" || t.status === "cancelled"))) {
|
|
174728
|
+
if (sessionMeta && !sessionMeta.isSubagent) {
|
|
173734
174729
|
onNoteTrigger(args.db, typedInput.sessionID, "todos_complete");
|
|
173735
174730
|
}
|
|
173736
174731
|
}
|
|
@@ -173746,9 +174741,9 @@ function createToolExecuteAfterHook(args) {
|
|
|
173746
174741
|
init_send_session_notification();
|
|
173747
174742
|
|
|
173748
174743
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
173749
|
-
import { createHash as
|
|
174744
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
173750
174745
|
import { existsSync as existsSync13, readFileSync as readFileSync9, realpathSync } from "node:fs";
|
|
173751
|
-
import { join as
|
|
174746
|
+
import { join as join21, resolve as resolve4, sep } from "node:path";
|
|
173752
174747
|
|
|
173753
174748
|
// src/agents/magic-context-prompt.ts
|
|
173754
174749
|
function getToolHistoryGuidance(dropToolStructure) {
|
|
@@ -173861,7 +174856,7 @@ var DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
|
173861
174856
|
function readProjectDocs(directory) {
|
|
173862
174857
|
const sections = [];
|
|
173863
174858
|
for (const filename of DOC_FILES) {
|
|
173864
|
-
const filePath =
|
|
174859
|
+
const filePath = join21(directory, filename);
|
|
173865
174860
|
try {
|
|
173866
174861
|
if (existsSync13(filePath)) {
|
|
173867
174862
|
const content = readFileSync9(filePath, "utf-8").trim();
|
|
@@ -174051,7 +175046,7 @@ ${sections.join(`
|
|
|
174051
175046
|
`);
|
|
174052
175047
|
if (systemContent.length === 0)
|
|
174053
175048
|
return;
|
|
174054
|
-
const currentHash =
|
|
175049
|
+
const currentHash = createHash6("md5").update(systemContent).digest("hex");
|
|
174055
175050
|
if (!sessionMetaEarly) {
|
|
174056
175051
|
return;
|
|
174057
175052
|
}
|
|
@@ -174066,14 +175061,12 @@ ${sections.join(`
|
|
|
174066
175061
|
} else if (previousHash === "" || previousHash === "0") {
|
|
174067
175062
|
sessionLog(sessionId, `system prompt hash initialized: ${currentHash} (len=${systemContent.length})`);
|
|
174068
175063
|
}
|
|
174069
|
-
const systemPromptTokens = estimateTokens(systemContent);
|
|
174070
175064
|
if (currentHash !== previousHash) {
|
|
175065
|
+
const systemPromptTokens = estimateTokens(systemContent);
|
|
174071
175066
|
updateSessionMeta(deps.db, sessionId, {
|
|
174072
175067
|
systemPromptHash: currentHash,
|
|
174073
175068
|
systemPromptTokens
|
|
174074
175069
|
});
|
|
174075
|
-
} else if (Math.abs(sessionMeta.systemPromptTokens - systemPromptTokens) > 50) {
|
|
174076
|
-
updateSessionMeta(deps.db, sessionId, { systemPromptTokens });
|
|
174077
175070
|
}
|
|
174078
175071
|
if (isCacheBusting) {
|
|
174079
175072
|
deps.systemPromptRefreshSessions.delete(sessionId);
|
|
@@ -174135,10 +175128,24 @@ function createMagicContextHook(deps) {
|
|
|
174135
175128
|
}
|
|
174136
175129
|
let lastScheduleCheckMs = 0;
|
|
174137
175130
|
const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
|
|
175131
|
+
const historianFallbackModels = resolveFallbackChain(HISTORIAN_AGENT, deps.config.historian?.fallback_models);
|
|
174138
175132
|
const nudgePlacements = createNudgePlacementStore(db);
|
|
174139
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
|
+
}
|
|
174140
175146
|
const systemPromptRefreshSessions = deps.liveSessionState?.systemPromptRefreshSessions ?? new Set;
|
|
174141
175147
|
const pendingMaterializationSessions = deps.liveSessionState?.pendingMaterializationSessions ?? new Set;
|
|
175148
|
+
const deferredMaterializationSessions = deps.liveSessionState?.deferredMaterializationSessions ?? new Set;
|
|
174142
175149
|
const lastHeuristicsTurnId = new Map;
|
|
174143
175150
|
const commitSeenLastPass = new Map;
|
|
174144
175151
|
const variantBySession = deps.liveSessionState?.variantBySession ?? new Map;
|
|
@@ -174179,7 +175186,9 @@ function createMagicContextHook(deps) {
|
|
|
174179
175186
|
dropToolStructure: deps.config.drop_tool_structure ?? true,
|
|
174180
175187
|
clearReasoningAge: deps.config.clear_reasoning_age ?? 50,
|
|
174181
175188
|
historyRefreshSessions,
|
|
175189
|
+
deferredHistoryRefreshSessions,
|
|
174182
175190
|
pendingMaterializationSessions,
|
|
175191
|
+
deferredMaterializationSessions,
|
|
174183
175192
|
lastHeuristicsTurnId,
|
|
174184
175193
|
commitSeenLastPass,
|
|
174185
175194
|
client: deps.client,
|
|
@@ -174194,6 +175203,7 @@ function createMagicContextHook(deps) {
|
|
|
174194
175203
|
executeThresholdPercentage: deps.config.execute_threshold_percentage,
|
|
174195
175204
|
executeThresholdTokens: deps.config.execute_threshold_tokens,
|
|
174196
175205
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
175206
|
+
fallbackModels: historianFallbackModels,
|
|
174197
175207
|
getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
174198
175208
|
getModelKey: (sessionId) => {
|
|
174199
175209
|
const model = liveModelBySession.get(sessionId);
|
|
@@ -174251,7 +175261,7 @@ function createMagicContextHook(deps) {
|
|
|
174251
175261
|
return;
|
|
174252
175262
|
}
|
|
174253
175263
|
try {
|
|
174254
|
-
checkScheduleAndEnqueue(db, dreaming.schedule);
|
|
175264
|
+
checkScheduleAndEnqueue(db, dreaming.schedule, projectPath);
|
|
174255
175265
|
lastScheduleCheckMs = now;
|
|
174256
175266
|
} catch (error51) {
|
|
174257
175267
|
log("[dreamer] scheduled enqueue check failed:", error51);
|
|
@@ -174271,7 +175281,9 @@ function createMagicContextHook(deps) {
|
|
|
174271
175281
|
enabled: true,
|
|
174272
175282
|
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
174273
175283
|
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
174274
|
-
} : undefined
|
|
175284
|
+
} : undefined,
|
|
175285
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer?.fallback_models),
|
|
175286
|
+
projectIdentity: projectPath
|
|
174275
175287
|
}).catch((error51) => {
|
|
174276
175288
|
log("[dreamer] scheduled queue processing failed:", error51);
|
|
174277
175289
|
});
|
|
@@ -174305,6 +175317,7 @@ function createMagicContextHook(deps) {
|
|
|
174305
175317
|
sessionId,
|
|
174306
175318
|
historianChunkTokens: getHistorianChunkTokens(),
|
|
174307
175319
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
175320
|
+
fallbackModels: historianFallbackModels,
|
|
174308
175321
|
directory: deps.directory,
|
|
174309
175322
|
fallbackModelId: (() => {
|
|
174310
175323
|
const model = resolveLiveModel(sessionId);
|
|
@@ -174314,9 +175327,12 @@ function createMagicContextHook(deps) {
|
|
|
174314
175327
|
historianTwoPass: deps.config.historian?.two_pass === true,
|
|
174315
175328
|
memoryEnabled: deps.config.memory?.enabled,
|
|
174316
175329
|
autoPromote: deps.config.memory?.auto_promote ?? true,
|
|
174317
|
-
|
|
175330
|
+
onCompartmentStatePublished: (sid) => {
|
|
174318
175331
|
historyRefreshSessions.add(sid);
|
|
174319
175332
|
pendingMaterializationSessions.add(sid);
|
|
175333
|
+
},
|
|
175334
|
+
onDeferredMarkerPending: (sid) => {
|
|
175335
|
+
deferredHistoryRefreshSessions.add(sid);
|
|
174320
175336
|
}
|
|
174321
175337
|
}, options),
|
|
174322
175338
|
sendNotification: async (sessionId, text, params) => {
|
|
@@ -174344,7 +175360,8 @@ function createMagicContextHook(deps) {
|
|
|
174344
175360
|
enabled: true,
|
|
174345
175361
|
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
174346
175362
|
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
174347
|
-
} : undefined
|
|
175363
|
+
} : undefined,
|
|
175364
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer.fallback_models)
|
|
174348
175365
|
} : undefined
|
|
174349
175366
|
});
|
|
174350
175367
|
const systemPromptHash = createSystemPromptHashHandler({
|
|
@@ -174381,8 +175398,10 @@ function createMagicContextHook(deps) {
|
|
|
174381
175398
|
recentReduceBySession,
|
|
174382
175399
|
toolUsageSinceUserTurn,
|
|
174383
175400
|
historyRefreshSessions,
|
|
175401
|
+
deferredHistoryRefreshSessions,
|
|
174384
175402
|
systemPromptRefreshSessions,
|
|
174385
175403
|
pendingMaterializationSessions,
|
|
175404
|
+
deferredMaterializationSessions,
|
|
174386
175405
|
lastHeuristicsTurnId,
|
|
174387
175406
|
commitSeenLastPass,
|
|
174388
175407
|
client: deps.client,
|
|
@@ -175006,19 +176025,7 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config2, liveSess
|
|
|
175006
176025
|
}
|
|
175007
176026
|
detail.nextNudgeAfter = detail.lastNudgeTokens + detail.nudgeInterval;
|
|
175008
176027
|
try {
|
|
175009
|
-
const
|
|
175010
|
-
const facts = db.prepare("SELECT content FROM session_facts WHERE session_id = ?").all(sessionId);
|
|
175011
|
-
let histTokens = 0;
|
|
175012
|
-
for (const c of compartments) {
|
|
175013
|
-
histTokens += estimateTokens(`<compartment start="${c.start_message}" end="${c.end_message}" title="${c.title}">
|
|
175014
|
-
${c.content}
|
|
175015
|
-
</compartment>
|
|
175016
|
-
`);
|
|
175017
|
-
}
|
|
175018
|
-
for (const f of facts) {
|
|
175019
|
-
histTokens += estimateTokens(`* ${f.content}
|
|
175020
|
-
`);
|
|
175021
|
-
}
|
|
176028
|
+
const histTokens = base.compartmentTokens + base.factTokens;
|
|
175022
176029
|
detail.historyBlockTokens = histTokens;
|
|
175023
176030
|
if (detail.contextLimit > 0) {
|
|
175024
176031
|
const budget = Math.floor(detail.contextLimit * (Math.min(detail.executeThreshold, 80) / 100) * detail.historyBudgetPercentage);
|
|
@@ -175088,7 +176095,7 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
175088
176095
|
memoryEnabled: config2.memory?.enabled,
|
|
175089
176096
|
autoPromote: config2.memory?.auto_promote ?? true,
|
|
175090
176097
|
getNotificationParams: () => getNotificationParams(sessionId),
|
|
175091
|
-
|
|
176098
|
+
onCompartmentStatePublished: (sid) => {
|
|
175092
176099
|
liveSessionState.historyRefreshSessions.add(sid);
|
|
175093
176100
|
liveSessionState.pendingMaterializationSessions.add(sid);
|
|
175094
176101
|
}
|
|
@@ -175099,8 +176106,9 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
175099
176106
|
});
|
|
175100
176107
|
return { ok: true };
|
|
175101
176108
|
});
|
|
175102
|
-
rpcServer.handle("pending-notifications", async () => {
|
|
175103
|
-
const
|
|
176109
|
+
rpcServer.handle("pending-notifications", async (params) => {
|
|
176110
|
+
const lastReceivedId = Number(params.lastReceivedId ?? 0);
|
|
176111
|
+
const notifications = drainNotifications(Number.isFinite(lastReceivedId) ? lastReceivedId : 0);
|
|
175104
176112
|
return { messages: notifications };
|
|
175105
176113
|
});
|
|
175106
176114
|
}
|
|
@@ -175191,7 +176199,7 @@ function normalizeLimit2(limit) {
|
|
|
175191
176199
|
return Math.max(1, Math.floor(limit));
|
|
175192
176200
|
}
|
|
175193
176201
|
function getAllowedActions(deps) {
|
|
175194
|
-
const allowed = deps.allowedActions?.length ? deps.allowedActions : [
|
|
176202
|
+
const allowed = deps.allowedActions?.length ? deps.allowedActions : ["write", "delete"];
|
|
175195
176203
|
return [...allowed];
|
|
175196
176204
|
}
|
|
175197
176205
|
function normalizeCategory(category) {
|
|
@@ -175297,7 +176305,7 @@ function createCtxMemoryTool(deps) {
|
|
|
175297
176305
|
return tool2({
|
|
175298
176306
|
description: CTX_MEMORY_DESCRIPTION,
|
|
175299
176307
|
args: {
|
|
175300
|
-
action: tool2.schema.enum(
|
|
176308
|
+
action: tool2.schema.enum([...CTX_MEMORY_DREAMER_ACTIONS]).describe("Action to perform on memories"),
|
|
175301
176309
|
content: tool2.schema.string().optional().describe("Memory content (required for write, update, merge)"),
|
|
175302
176310
|
category: tool2.schema.string().optional().describe("Memory category (required for write, optional filter for list, optional override for merge)"),
|
|
175303
176311
|
id: tool2.schema.number().optional().describe("Memory ID (required for delete, update, archive)"),
|
|
@@ -176058,19 +177066,68 @@ init_models_dev_cache();
|
|
|
176058
177066
|
|
|
176059
177067
|
// src/shared/rpc-server.ts
|
|
176060
177068
|
init_logger();
|
|
176061
|
-
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";
|
|
176062
177077
|
import { createServer } from "node:http";
|
|
176063
|
-
import { dirname as
|
|
177078
|
+
import { dirname as dirname7 } from "node:path";
|
|
176064
177079
|
|
|
176065
177080
|
// src/shared/rpc-utils.ts
|
|
176066
|
-
import { createHash as
|
|
176067
|
-
import { join as
|
|
177081
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
177082
|
+
import { join as join22 } from "node:path";
|
|
176068
177083
|
function projectHash(directory) {
|
|
176069
177084
|
const normalized = directory.replace(/\/+$/, "");
|
|
176070
|
-
return
|
|
177085
|
+
return createHash7("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
176071
177086
|
}
|
|
176072
|
-
function
|
|
176073
|
-
return
|
|
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 };
|
|
177128
|
+
}
|
|
177129
|
+
function isValidPort(port) {
|
|
177130
|
+
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
176074
177131
|
}
|
|
176075
177132
|
|
|
176076
177133
|
// src/shared/rpc-server.ts
|
|
@@ -176079,8 +177136,11 @@ class MagicContextRpcServer {
|
|
|
176079
177136
|
port = 0;
|
|
176080
177137
|
handlers = new Map;
|
|
176081
177138
|
portFilePath;
|
|
177139
|
+
portDir;
|
|
177140
|
+
startedAt = Date.now();
|
|
176082
177141
|
constructor(storageDir, directory) {
|
|
176083
177142
|
this.portFilePath = rpcPortFilePath(storageDir, directory);
|
|
177143
|
+
this.portDir = rpcPortDir(storageDir, directory);
|
|
176084
177144
|
}
|
|
176085
177145
|
handle(method, handler) {
|
|
176086
177146
|
this.handlers.set(method, handler);
|
|
@@ -176101,10 +177161,15 @@ class MagicContextRpcServer {
|
|
|
176101
177161
|
this.port = addr.port;
|
|
176102
177162
|
this.server = server;
|
|
176103
177163
|
try {
|
|
176104
|
-
|
|
176105
|
-
|
|
177164
|
+
this.warnIfOtherLiveInstance();
|
|
177165
|
+
const dir = dirname7(this.portFilePath);
|
|
177166
|
+
mkdirSync8(dir, { recursive: true });
|
|
176106
177167
|
const tmpPath = `${this.portFilePath}.tmp`;
|
|
176107
|
-
writeFileSync7(tmpPath,
|
|
177168
|
+
writeFileSync7(tmpPath, JSON.stringify({
|
|
177169
|
+
port: this.port,
|
|
177170
|
+
pid: process.pid,
|
|
177171
|
+
started_at: this.startedAt
|
|
177172
|
+
}), "utf-8");
|
|
176108
177173
|
renameSync2(tmpPath, this.portFilePath);
|
|
176109
177174
|
log(`[rpc] server listening on 127.0.0.1:${this.port}`);
|
|
176110
177175
|
} catch (err) {
|
|
@@ -176115,6 +177180,19 @@ class MagicContextRpcServer {
|
|
|
176115
177180
|
server.unref();
|
|
176116
177181
|
});
|
|
176117
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
|
+
}
|
|
176118
177196
|
stop() {
|
|
176119
177197
|
if (this.server) {
|
|
176120
177198
|
this.server.close();
|