@cortexkit/opencode-magic-context 0.20.0 → 0.21.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/dist/config/index.d.ts +18 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/indexer.d.ts +2 -3
- package/dist/features/magic-context/git-commits/indexer.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +1 -0
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-backfill.d.ts +1 -0
- package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +6 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +2 -0
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +1 -0
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +44 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -0
- package/dist/features/magic-context/search.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 +48 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +2 -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/types.d.ts +2 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-runner.d.ts +6 -4
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.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 +1 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts +3 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- 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/note-nudger.d.ts +7 -1
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/text-complete.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +2 -3
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +3 -3
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1340 -548
- package/dist/plugin/dream-timer.d.ts +5 -4
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/embedding-bootstrap-helpers.d.ts +35 -0
- package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -0
- package/dist/plugin/embedding-bootstrap.d.ts +3 -0
- package/dist/plugin/embedding-bootstrap.d.ts.map +1 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts +8 -7
- package/dist/shared/models-dev-cache.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/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/types.d.ts +3 -2
- package/dist/tools/ctx-memory/types.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +3 -2
- package/dist/tools/ctx-search/types.d.ts.map +1 -1
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/shared/models-dev-cache.test.ts +5 -10
- package/src/shared/models-dev-cache.ts +15 -45
- package/src/shared/rpc-types.ts +1 -0
- package/src/tui/data/context-db.ts +1 -0
- package/src/tui/slots/sidebar-content.tsx +15 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __getProtoOf = Object.getPrototypeOf;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -44,6 +45,7 @@ var __export = (target, all) => {
|
|
|
44
45
|
};
|
|
45
46
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
46
47
|
var __promiseAll = (args) => Promise.all(args);
|
|
48
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
47
49
|
|
|
48
50
|
// src/agents/dreamer.ts
|
|
49
51
|
var DREAMER_AGENT = "dreamer";
|
|
@@ -15017,6 +15019,46 @@ var init_magic_context = __esm(() => {
|
|
|
15017
15019
|
});
|
|
15018
15020
|
});
|
|
15019
15021
|
|
|
15022
|
+
// src/features/magic-context/memory/project-identity.ts
|
|
15023
|
+
import { execSync } from "node:child_process";
|
|
15024
|
+
import { createHash } from "node:crypto";
|
|
15025
|
+
import path from "node:path";
|
|
15026
|
+
function getRootCommitHash(directory) {
|
|
15027
|
+
try {
|
|
15028
|
+
const hash2 = execSync("git rev-list --max-parents=0 HEAD", {
|
|
15029
|
+
cwd: directory,
|
|
15030
|
+
encoding: "utf-8",
|
|
15031
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
15032
|
+
timeout: GIT_TIMEOUT_MS
|
|
15033
|
+
}).trim();
|
|
15034
|
+
const firstLine = hash2.split(`
|
|
15035
|
+
`)[0]?.trim();
|
|
15036
|
+
return firstLine && firstLine.length >= 7 ? firstLine : undefined;
|
|
15037
|
+
} catch {
|
|
15038
|
+
return;
|
|
15039
|
+
}
|
|
15040
|
+
}
|
|
15041
|
+
function directoryFallback(directory) {
|
|
15042
|
+
const canonical = path.resolve(directory);
|
|
15043
|
+
const hash2 = createHash("md5").update(canonical).digest("hex").slice(0, 12);
|
|
15044
|
+
return `dir:${hash2}`;
|
|
15045
|
+
}
|
|
15046
|
+
function resolveProjectIdentity(directory) {
|
|
15047
|
+
const resolved = path.resolve(directory);
|
|
15048
|
+
const cached2 = resolvedCache.get(resolved);
|
|
15049
|
+
if (cached2 !== undefined) {
|
|
15050
|
+
return cached2;
|
|
15051
|
+
}
|
|
15052
|
+
const rootHash = getRootCommitHash(resolved);
|
|
15053
|
+
const identity = rootHash ? `git:${rootHash}` : directoryFallback(resolved);
|
|
15054
|
+
resolvedCache.set(resolved, identity);
|
|
15055
|
+
return identity;
|
|
15056
|
+
}
|
|
15057
|
+
var GIT_TIMEOUT_MS = 5000, resolvedCache;
|
|
15058
|
+
var init_project_identity = __esm(() => {
|
|
15059
|
+
resolvedCache = new Map;
|
|
15060
|
+
});
|
|
15061
|
+
|
|
15020
15062
|
// src/shared/harness.ts
|
|
15021
15063
|
function getHarness() {
|
|
15022
15064
|
return currentHarness;
|
|
@@ -15025,41 +15067,41 @@ var currentHarness = "opencode";
|
|
|
15025
15067
|
|
|
15026
15068
|
// src/shared/data-path.ts
|
|
15027
15069
|
import * as os from "node:os";
|
|
15028
|
-
import * as
|
|
15070
|
+
import * as path2 from "node:path";
|
|
15029
15071
|
function getDataDir() {
|
|
15030
|
-
return process.env.XDG_DATA_HOME ??
|
|
15072
|
+
return process.env.XDG_DATA_HOME ?? path2.join(os.homedir(), ".local", "share");
|
|
15031
15073
|
}
|
|
15032
15074
|
function getMagicContextTempDir(harness = getHarness()) {
|
|
15033
|
-
return
|
|
15075
|
+
return path2.join(os.tmpdir(), harness, "magic-context");
|
|
15034
15076
|
}
|
|
15035
15077
|
function getMagicContextLogPath(harness = getHarness()) {
|
|
15036
|
-
return
|
|
15078
|
+
return path2.join(getMagicContextTempDir(harness), "magic-context.log");
|
|
15037
15079
|
}
|
|
15038
15080
|
function getProjectMagicContextDir(directory) {
|
|
15039
|
-
return
|
|
15081
|
+
return path2.join(directory, ".opencode", "magic-context");
|
|
15040
15082
|
}
|
|
15041
15083
|
function getProjectMagicContextHistorianDir(directory) {
|
|
15042
|
-
return
|
|
15084
|
+
return path2.join(getProjectMagicContextDir(directory), "historian");
|
|
15043
15085
|
}
|
|
15044
15086
|
function getOpenCodeStorageDir() {
|
|
15045
|
-
return
|
|
15087
|
+
return path2.join(getDataDir(), "opencode", "storage");
|
|
15046
15088
|
}
|
|
15047
15089
|
function getMagicContextStorageDir() {
|
|
15048
|
-
return
|
|
15090
|
+
return path2.join(getDataDir(), "cortexkit", "magic-context");
|
|
15049
15091
|
}
|
|
15050
15092
|
function getLegacyOpenCodeMagicContextStorageDir() {
|
|
15051
|
-
return
|
|
15093
|
+
return path2.join(getOpenCodeStorageDir(), "plugin", "magic-context");
|
|
15052
15094
|
}
|
|
15053
15095
|
function getCacheDir() {
|
|
15054
|
-
return process.env.XDG_CACHE_HOME ??
|
|
15096
|
+
return process.env.XDG_CACHE_HOME ?? path2.join(os.homedir(), ".cache");
|
|
15055
15097
|
}
|
|
15056
15098
|
var init_data_path = () => {};
|
|
15057
15099
|
|
|
15058
15100
|
// src/shared/logger.ts
|
|
15059
15101
|
import * as fs from "node:fs";
|
|
15060
|
-
import * as
|
|
15102
|
+
import * as path3 from "node:path";
|
|
15061
15103
|
function ensureDir(filePath) {
|
|
15062
|
-
const dir =
|
|
15104
|
+
const dir = path3.dirname(filePath);
|
|
15063
15105
|
if (dir === lastEnsuredDir)
|
|
15064
15106
|
return;
|
|
15065
15107
|
try {
|
|
@@ -148209,13 +148251,13 @@ function stableStringify(value, seen = new WeakSet) {
|
|
|
148209
148251
|
}
|
|
148210
148252
|
|
|
148211
148253
|
// src/features/magic-context/tool-definition-tokens.ts
|
|
148212
|
-
import { createHash } from "node:crypto";
|
|
148254
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
148213
148255
|
function keyFor(providerID, modelID, agentName) {
|
|
148214
148256
|
const agent = agentName && agentName.length > 0 ? agentName : "default";
|
|
148215
148257
|
return `${providerID}/${modelID}/${agent}`;
|
|
148216
148258
|
}
|
|
148217
148259
|
function fingerprintFor(description, parameters) {
|
|
148218
|
-
return
|
|
148260
|
+
return createHash2("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
|
|
148219
148261
|
}
|
|
148220
148262
|
function setDatabase(db) {
|
|
148221
148263
|
persistenceDb = db;
|
|
@@ -157333,8 +157375,8 @@ async function parseTarGzip(data, opts = {}) {
|
|
|
157333
157375
|
const decompressedData = await new Response(stream).arrayBuffer();
|
|
157334
157376
|
return parseTar(decompressedData, opts);
|
|
157335
157377
|
}
|
|
157336
|
-
function _sanitizePath(
|
|
157337
|
-
let normalized =
|
|
157378
|
+
function _sanitizePath(path4) {
|
|
157379
|
+
let normalized = path4.replace(/\\/g, "/");
|
|
157338
157380
|
normalized = normalized.replace(/^[a-zA-Z]:\//, "");
|
|
157339
157381
|
normalized = normalized.replace(/^\/+/, "");
|
|
157340
157382
|
const hasLeadingDotSlash = normalized.startsWith("./");
|
|
@@ -157351,7 +157393,7 @@ function _sanitizePath(path3) {
|
|
|
157351
157393
|
if (hasLeadingDotSlash && !result.startsWith("./")) {
|
|
157352
157394
|
result = "./" + result;
|
|
157353
157395
|
}
|
|
157354
|
-
if (
|
|
157396
|
+
if (path4.endsWith("/") && !result.endsWith("/")) {
|
|
157355
157397
|
result += "/";
|
|
157356
157398
|
}
|
|
157357
157399
|
return result;
|
|
@@ -157415,8 +157457,8 @@ __export(exports_native_binding, {
|
|
|
157415
157457
|
resolveBetterSqliteNativeBinding: () => resolveBetterSqliteNativeBinding
|
|
157416
157458
|
});
|
|
157417
157459
|
import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
157418
|
-
import { createRequire } from "node:module";
|
|
157419
|
-
import * as
|
|
157460
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
157461
|
+
import * as path4 from "node:path";
|
|
157420
157462
|
function logInfo(message) {
|
|
157421
157463
|
log(`${PREFIX} ${message}`);
|
|
157422
157464
|
}
|
|
@@ -157446,9 +157488,9 @@ function probeAbi(binaryPath) {
|
|
|
157446
157488
|
function resolveBetterSqlite3OnDisk(requireFn) {
|
|
157447
157489
|
try {
|
|
157448
157490
|
const pkgJsonPath = requireFn.resolve("better-sqlite3/package.json");
|
|
157449
|
-
const pkgDir =
|
|
157491
|
+
const pkgDir = path4.dirname(pkgJsonPath);
|
|
157450
157492
|
const pkgJson = requireFn(pkgJsonPath);
|
|
157451
|
-
const binaryPath =
|
|
157493
|
+
const binaryPath = path4.join(pkgDir, "build", "Release", "better_sqlite3.node");
|
|
157452
157494
|
return { binaryPath, pkgVersion: pkgJson.version };
|
|
157453
157495
|
} catch (err) {
|
|
157454
157496
|
logWarn(`could not resolve better-sqlite3 in node_modules: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -157456,7 +157498,7 @@ function resolveBetterSqlite3OnDisk(requireFn) {
|
|
|
157456
157498
|
}
|
|
157457
157499
|
}
|
|
157458
157500
|
function getCachedBinaryPath(pkgVersion, abi) {
|
|
157459
|
-
return
|
|
157501
|
+
return path4.join(getCacheDir(), "cortexkit", "native-bindings", "better-sqlite3", `v${pkgVersion}`, `electron-v${abi}-${process.platform}-${process.arch}`, "better_sqlite3.node");
|
|
157460
157502
|
}
|
|
157461
157503
|
async function downloadElectronPrebuild(pkgVersion, abi) {
|
|
157462
157504
|
const filename = `better-sqlite3-v${pkgVersion}-electron-v${abi}-${process.platform}-${process.arch}.tar.gz`;
|
|
@@ -157489,7 +157531,7 @@ async function resolveBetterSqliteNativeBinding() {
|
|
|
157489
157531
|
const promise2 = (async () => {
|
|
157490
157532
|
const expected = process.versions.modules;
|
|
157491
157533
|
logInfo(`Electron detected (v${process.versions.electron}, NODE_MODULE_VERSION ${expected}); verifying better-sqlite3 binding`);
|
|
157492
|
-
const requireFn =
|
|
157534
|
+
const requireFn = createRequire2(import.meta.url);
|
|
157493
157535
|
const resolved = resolveBetterSqlite3OnDisk(requireFn);
|
|
157494
157536
|
if (!resolved) {
|
|
157495
157537
|
return null;
|
|
@@ -157514,7 +157556,7 @@ async function resolveBetterSqliteNativeBinding() {
|
|
|
157514
157556
|
}
|
|
157515
157557
|
logWarn(`cached binary at ${cachedPath} has wrong ABI (${cachedProbe.actual ?? "unknown"} != ${expected}); refetching`);
|
|
157516
157558
|
}
|
|
157517
|
-
mkdirSync3(
|
|
157559
|
+
mkdirSync3(path4.dirname(cachedPath), { recursive: true });
|
|
157518
157560
|
const nodeFileBytes = await downloadElectronPrebuild(pkgVersion, expected);
|
|
157519
157561
|
writeFileSync4(cachedPath, nodeFileBytes);
|
|
157520
157562
|
logInfo(`cached Electron prebuild at ${cachedPath} (${(nodeFileBytes.length / 1024).toFixed(1)} KB)`);
|
|
@@ -157574,11 +157616,11 @@ function closeQuietly(db) {
|
|
|
157574
157616
|
}
|
|
157575
157617
|
|
|
157576
157618
|
// src/features/magic-context/key-files/project-key-files.ts
|
|
157577
|
-
import { createHash as
|
|
157619
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
157578
157620
|
import { existsSync as existsSync10, readFileSync as readFileSync9, realpathSync } from "node:fs";
|
|
157579
157621
|
import { join as join12, resolve as resolve4, sep } from "node:path";
|
|
157580
157622
|
function sha256(input) {
|
|
157581
|
-
return
|
|
157623
|
+
return createHash3("sha256").update(input).digest("hex");
|
|
157582
157624
|
}
|
|
157583
157625
|
function resolveProjectPath(directory) {
|
|
157584
157626
|
if (!directory?.trim())
|
|
@@ -157721,14 +157763,6 @@ function getLoadAllEmbeddingsStatement(db) {
|
|
|
157721
157763
|
}
|
|
157722
157764
|
return stmt;
|
|
157723
157765
|
}
|
|
157724
|
-
function getStoredModelIdStatement(db) {
|
|
157725
|
-
let stmt = getStoredModelIdStatements.get(db);
|
|
157726
|
-
if (!stmt) {
|
|
157727
|
-
stmt = db.prepare("SELECT memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? AND memory_embeddings.model_id IS NOT NULL LIMIT 1");
|
|
157728
|
-
getStoredModelIdStatements.set(db, stmt);
|
|
157729
|
-
}
|
|
157730
|
-
return stmt;
|
|
157731
|
-
}
|
|
157732
157766
|
function getClearAllEmbeddingsStatement(db) {
|
|
157733
157767
|
let stmt = clearAllEmbeddingsStatements.get(db);
|
|
157734
157768
|
if (!stmt) {
|
|
@@ -157737,6 +157771,14 @@ function getClearAllEmbeddingsStatement(db) {
|
|
|
157737
157771
|
}
|
|
157738
157772
|
return stmt;
|
|
157739
157773
|
}
|
|
157774
|
+
function getDistinctStoredModelIdsStatement(db) {
|
|
157775
|
+
let stmt = getDistinctStoredModelIdsStatements.get(db);
|
|
157776
|
+
if (!stmt) {
|
|
157777
|
+
stmt = db.prepare("SELECT DISTINCT memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ?");
|
|
157778
|
+
getDistinctStoredModelIdsStatements.set(db, stmt);
|
|
157779
|
+
}
|
|
157780
|
+
return stmt;
|
|
157781
|
+
}
|
|
157740
157782
|
function saveEmbedding(db, memoryId, embedding, modelId) {
|
|
157741
157783
|
const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
157742
157784
|
getSaveEmbeddingStatement(db).run(memoryId, blob, modelId);
|
|
@@ -157749,20 +157791,21 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
157749
157791
|
}
|
|
157750
157792
|
return embeddings;
|
|
157751
157793
|
}
|
|
157752
|
-
function getStoredModelId(db, projectPath) {
|
|
157753
|
-
const row = getStoredModelIdStatement(db).get(projectPath);
|
|
157754
|
-
return typeof row?.modelId === "string" ? row.modelId : null;
|
|
157755
|
-
}
|
|
157756
157794
|
function clearEmbeddingsForProject(db, projectPath) {
|
|
157757
157795
|
getClearAllEmbeddingsStatement(db).run(projectPath);
|
|
157758
157796
|
}
|
|
157759
|
-
|
|
157797
|
+
function getDistinctStoredModelIds(db, projectPath) {
|
|
157798
|
+
const rows = getDistinctStoredModelIdsStatement(db).all(projectPath);
|
|
157799
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
157800
|
+
}
|
|
157801
|
+
var saveEmbeddingStatements, loadAllEmbeddingsStatements, deleteEmbeddingStatements, getStoredModelIdStatements, clearAllEmbeddingsStatements, getDistinctStoredModelIdsStatements;
|
|
157760
157802
|
var init_storage_memory_embeddings = __esm(() => {
|
|
157761
157803
|
saveEmbeddingStatements = new WeakMap;
|
|
157762
157804
|
loadAllEmbeddingsStatements = new WeakMap;
|
|
157763
157805
|
deleteEmbeddingStatements = new WeakMap;
|
|
157764
157806
|
getStoredModelIdStatements = new WeakMap;
|
|
157765
157807
|
clearAllEmbeddingsStatements = new WeakMap;
|
|
157808
|
+
getDistinctStoredModelIdsStatements = new WeakMap;
|
|
157766
157809
|
});
|
|
157767
157810
|
|
|
157768
157811
|
// src/features/magic-context/memory/embedding-cache.ts
|
|
@@ -157807,13 +157850,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
157807
157850
|
});
|
|
157808
157851
|
|
|
157809
157852
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
157810
|
-
import { createHash as
|
|
157853
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
157811
157854
|
function normalizeMemoryContent(content) {
|
|
157812
157855
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
157813
157856
|
}
|
|
157814
157857
|
function computeNormalizedHash(content) {
|
|
157815
157858
|
const normalized = normalizeMemoryContent(content);
|
|
157816
|
-
return
|
|
157859
|
+
return createHash4("md5").update(normalized).digest("hex");
|
|
157817
157860
|
}
|
|
157818
157861
|
var init_normalize_hash = () => {};
|
|
157819
157862
|
|
|
@@ -158444,7 +158487,8 @@ var init_embedding_identity = __esm(() => {
|
|
|
158444
158487
|
// src/features/magic-context/memory/embedding-local.ts
|
|
158445
158488
|
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
158446
158489
|
import { open, stat, unlink, writeFile } from "node:fs/promises";
|
|
158447
|
-
import { join as join15 } from "node:path";
|
|
158490
|
+
import { dirname as dirname7, join as join15 } from "node:path";
|
|
158491
|
+
import { pathToFileURL } from "node:url";
|
|
158448
158492
|
async function acquireModelLoadLock(lockPath) {
|
|
158449
158493
|
const waitStart = Date.now();
|
|
158450
158494
|
while (true) {
|
|
@@ -158494,6 +158538,33 @@ function startLockHeartbeat(lockPath) {
|
|
|
158494
158538
|
timer.unref?.();
|
|
158495
158539
|
return () => clearInterval(timer);
|
|
158496
158540
|
}
|
|
158541
|
+
async function injectWasmOrtForElectron() {
|
|
158542
|
+
if (typeof process === "undefined" || !process.versions?.electron) {
|
|
158543
|
+
return false;
|
|
158544
|
+
}
|
|
158545
|
+
try {
|
|
158546
|
+
const ortWebSpec = `onnxruntime-${"web"}`;
|
|
158547
|
+
const ortWeb = await import(ortWebSpec);
|
|
158548
|
+
try {
|
|
158549
|
+
const { createRequire: createRequireFn } = await import("node:module");
|
|
158550
|
+
const requireFn = createRequireFn(import.meta.url);
|
|
158551
|
+
const pkgPath = requireFn.resolve("onnxruntime-web/package.json");
|
|
158552
|
+
const distDir = join15(dirname7(pkgPath), "dist");
|
|
158553
|
+
const wasmPathsPrefix = `${pathToFileURL(distDir).href}/`;
|
|
158554
|
+
if (ortWeb.env?.wasm) {
|
|
158555
|
+
ortWeb.env.wasm.wasmPaths = wasmPathsPrefix;
|
|
158556
|
+
}
|
|
158557
|
+
} catch (pathError) {
|
|
158558
|
+
log("[magic-context] could not resolve local onnxruntime-web/dist, falling back to default WASM paths:", pathError instanceof Error ? pathError.message : String(pathError));
|
|
158559
|
+
}
|
|
158560
|
+
globalThis[Symbol.for("onnxruntime")] = ortWeb;
|
|
158561
|
+
log("[magic-context] Electron detected — using onnxruntime-web (WASM) for embeddings (bypasses onnxruntime-node native load)");
|
|
158562
|
+
return true;
|
|
158563
|
+
} catch (error51) {
|
|
158564
|
+
log("[magic-context] failed to inject onnxruntime-web for Electron — letting transformers fall back to native:", error51 instanceof Error ? error51.message : String(error51));
|
|
158565
|
+
return false;
|
|
158566
|
+
}
|
|
158567
|
+
}
|
|
158497
158568
|
async function withQuietConsole(fn) {
|
|
158498
158569
|
const origWarn = console.warn;
|
|
158499
158570
|
const origError = console.error;
|
|
@@ -158557,11 +158628,18 @@ class LocalEmbeddingProvider {
|
|
|
158557
158628
|
model;
|
|
158558
158629
|
pipeline = null;
|
|
158559
158630
|
initPromise = null;
|
|
158631
|
+
inFlight = 0;
|
|
158632
|
+
disposing = false;
|
|
158633
|
+
disposePromise = null;
|
|
158634
|
+
inFlightWaiters = [];
|
|
158560
158635
|
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
158561
158636
|
this.model = model;
|
|
158562
158637
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
158563
158638
|
}
|
|
158564
158639
|
async initialize() {
|
|
158640
|
+
if (this.disposing) {
|
|
158641
|
+
return false;
|
|
158642
|
+
}
|
|
158565
158643
|
if (this.pipeline) {
|
|
158566
158644
|
return true;
|
|
158567
158645
|
}
|
|
@@ -158571,7 +158649,11 @@ class LocalEmbeddingProvider {
|
|
|
158571
158649
|
}
|
|
158572
158650
|
this.initPromise = (async () => {
|
|
158573
158651
|
try {
|
|
158574
|
-
|
|
158652
|
+
if (this.disposing) {
|
|
158653
|
+
return;
|
|
158654
|
+
}
|
|
158655
|
+
await injectWasmOrtForElectron();
|
|
158656
|
+
const transformersSpec = "@huggingface/transformers";
|
|
158575
158657
|
const transformersModule = await import(transformersSpec);
|
|
158576
158658
|
const env = transformersModule.env;
|
|
158577
158659
|
const LogLevel = transformersModule.LogLevel;
|
|
@@ -158594,9 +158676,15 @@ class LocalEmbeddingProvider {
|
|
|
158594
158676
|
let lastError;
|
|
158595
158677
|
for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
|
|
158596
158678
|
try {
|
|
158597
|
-
|
|
158679
|
+
const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
|
|
158598
158680
|
dtype: "fp32"
|
|
158599
158681
|
}));
|
|
158682
|
+
if (this.disposing) {
|
|
158683
|
+
await pipeline.dispose?.();
|
|
158684
|
+
this.pipeline = null;
|
|
158685
|
+
} else {
|
|
158686
|
+
this.pipeline = pipeline;
|
|
158687
|
+
}
|
|
158600
158688
|
lastError = undefined;
|
|
158601
158689
|
break;
|
|
158602
158690
|
} catch (error51) {
|
|
@@ -158611,6 +158699,8 @@ class LocalEmbeddingProvider {
|
|
|
158611
158699
|
}
|
|
158612
158700
|
if (this.pipeline) {
|
|
158613
158701
|
log(`[magic-context] embedding model loaded: ${this.model}`);
|
|
158702
|
+
} else if (this.disposing) {
|
|
158703
|
+
return;
|
|
158614
158704
|
} else {
|
|
158615
158705
|
throw lastError ?? new Error("unknown embedding load failure");
|
|
158616
158706
|
}
|
|
@@ -158628,13 +158718,33 @@ class LocalEmbeddingProvider {
|
|
|
158628
158718
|
await this.initPromise;
|
|
158629
158719
|
return this.pipeline !== null;
|
|
158630
158720
|
}
|
|
158721
|
+
waitForInFlightToDrain() {
|
|
158722
|
+
if (this.inFlight === 0) {
|
|
158723
|
+
return Promise.resolve();
|
|
158724
|
+
}
|
|
158725
|
+
return new Promise((resolve6) => {
|
|
158726
|
+
this.inFlightWaiters.push(resolve6);
|
|
158727
|
+
});
|
|
158728
|
+
}
|
|
158729
|
+
finishInFlight() {
|
|
158730
|
+
this.inFlight = Math.max(0, this.inFlight - 1);
|
|
158731
|
+
if (this.inFlight !== 0)
|
|
158732
|
+
return;
|
|
158733
|
+
const waiters = this.inFlightWaiters.splice(0);
|
|
158734
|
+
for (const waiter of waiters) {
|
|
158735
|
+
waiter();
|
|
158736
|
+
}
|
|
158737
|
+
}
|
|
158631
158738
|
async embed(text, signal) {
|
|
158632
158739
|
if (signal?.aborted)
|
|
158633
158740
|
return null;
|
|
158634
|
-
if (
|
|
158741
|
+
if (this.disposing)
|
|
158635
158742
|
return null;
|
|
158636
|
-
|
|
158743
|
+
this.inFlight += 1;
|
|
158637
158744
|
try {
|
|
158745
|
+
if (!await this.initialize()) {
|
|
158746
|
+
return null;
|
|
158747
|
+
}
|
|
158638
158748
|
const pipeline = this.pipeline;
|
|
158639
158749
|
if (!pipeline) {
|
|
158640
158750
|
return null;
|
|
@@ -158647,6 +158757,8 @@ class LocalEmbeddingProvider {
|
|
|
158647
158757
|
} catch (error51) {
|
|
158648
158758
|
log("[magic-context] embedding failed:", error51);
|
|
158649
158759
|
return null;
|
|
158760
|
+
} finally {
|
|
158761
|
+
this.finishInFlight();
|
|
158650
158762
|
}
|
|
158651
158763
|
}
|
|
158652
158764
|
async embedBatch(texts, signal) {
|
|
@@ -158656,10 +158768,14 @@ class LocalEmbeddingProvider {
|
|
|
158656
158768
|
if (signal?.aborted) {
|
|
158657
158769
|
return Array.from({ length: texts.length }, () => null);
|
|
158658
158770
|
}
|
|
158659
|
-
if (
|
|
158771
|
+
if (this.disposing) {
|
|
158660
158772
|
return Array.from({ length: texts.length }, () => null);
|
|
158661
158773
|
}
|
|
158774
|
+
this.inFlight += 1;
|
|
158662
158775
|
try {
|
|
158776
|
+
if (!await this.initialize()) {
|
|
158777
|
+
return Array.from({ length: texts.length }, () => null);
|
|
158778
|
+
}
|
|
158663
158779
|
const pipeline = this.pipeline;
|
|
158664
158780
|
if (!pipeline) {
|
|
158665
158781
|
return Array.from({ length: texts.length }, () => null);
|
|
@@ -158672,25 +158788,33 @@ class LocalEmbeddingProvider {
|
|
|
158672
158788
|
} catch (error51) {
|
|
158673
158789
|
log("[magic-context] embedding batch failed:", error51);
|
|
158674
158790
|
return Array.from({ length: texts.length }, () => null);
|
|
158791
|
+
} finally {
|
|
158792
|
+
this.finishInFlight();
|
|
158675
158793
|
}
|
|
158676
158794
|
}
|
|
158677
158795
|
async dispose() {
|
|
158678
|
-
if (this.
|
|
158679
|
-
|
|
158680
|
-
}
|
|
158681
|
-
if (!this.pipeline) {
|
|
158682
|
-
this.pipeline = null;
|
|
158683
|
-
this.initPromise = null;
|
|
158684
|
-
return;
|
|
158796
|
+
if (this.disposePromise) {
|
|
158797
|
+
return this.disposePromise;
|
|
158685
158798
|
}
|
|
158686
|
-
|
|
158687
|
-
|
|
158688
|
-
|
|
158689
|
-
|
|
158690
|
-
|
|
158799
|
+
this.disposing = true;
|
|
158800
|
+
this.disposePromise = (async () => {
|
|
158801
|
+
if (this.initPromise) {
|
|
158802
|
+
await this.initPromise;
|
|
158803
|
+
}
|
|
158804
|
+
await this.waitForInFlightToDrain();
|
|
158805
|
+
const pipelineToDispose = this.pipeline;
|
|
158691
158806
|
this.pipeline = null;
|
|
158692
158807
|
this.initPromise = null;
|
|
158693
|
-
|
|
158808
|
+
if (!pipelineToDispose) {
|
|
158809
|
+
return;
|
|
158810
|
+
}
|
|
158811
|
+
try {
|
|
158812
|
+
await pipelineToDispose.dispose?.();
|
|
158813
|
+
} catch (error51) {
|
|
158814
|
+
log("[magic-context] embedding model dispose failed:", error51);
|
|
158815
|
+
}
|
|
158816
|
+
})();
|
|
158817
|
+
return this.disposePromise;
|
|
158694
158818
|
}
|
|
158695
158819
|
isLoaded() {
|
|
158696
158820
|
return this.pipeline !== null;
|
|
@@ -158916,22 +159040,112 @@ var init_embedding_openai = __esm(() => {
|
|
|
158916
159040
|
OPEN_DURATION_MS = 5 * 60000;
|
|
158917
159041
|
});
|
|
158918
159042
|
|
|
158919
|
-
// src/features/magic-context/
|
|
158920
|
-
function
|
|
158921
|
-
|
|
158922
|
-
|
|
159043
|
+
// src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
159044
|
+
function getSaveStatement(db) {
|
|
159045
|
+
let stmt = saveStatements.get(db);
|
|
159046
|
+
if (!stmt) {
|
|
159047
|
+
stmt = db.prepare(`INSERT INTO git_commit_embeddings (sha, embedding, model_id, created_at)
|
|
159048
|
+
VALUES (?, ?, ?, ?)
|
|
159049
|
+
ON CONFLICT(sha) DO UPDATE SET
|
|
159050
|
+
embedding = excluded.embedding,
|
|
159051
|
+
model_id = excluded.model_id,
|
|
159052
|
+
created_at = excluded.created_at`);
|
|
159053
|
+
saveStatements.set(db, stmt);
|
|
158923
159054
|
}
|
|
158924
|
-
|
|
158925
|
-
return typeof candidate.id === "number" && typeof candidate.content === "string";
|
|
159055
|
+
return stmt;
|
|
158926
159056
|
}
|
|
158927
|
-
function
|
|
158928
|
-
let stmt =
|
|
159057
|
+
function getLoadProjectStatement(db) {
|
|
159058
|
+
let stmt = loadProjectStatements.get(db);
|
|
158929
159059
|
if (!stmt) {
|
|
158930
|
-
stmt = db.prepare(
|
|
158931
|
-
|
|
159060
|
+
stmt = db.prepare(`SELECT e.sha AS sha, e.embedding AS embedding, e.model_id AS model_id
|
|
159061
|
+
FROM git_commit_embeddings e
|
|
159062
|
+
JOIN git_commits c ON c.sha = e.sha
|
|
159063
|
+
WHERE c.project_path = ?`);
|
|
159064
|
+
loadProjectStatements.set(db, stmt);
|
|
159065
|
+
}
|
|
159066
|
+
return stmt;
|
|
159067
|
+
}
|
|
159068
|
+
function getLoadUnembeddedStatement(db) {
|
|
159069
|
+
let stmt = loadUnembeddedStatements.get(db);
|
|
159070
|
+
if (!stmt) {
|
|
159071
|
+
stmt = db.prepare(`SELECT c.sha AS sha, c.message AS message
|
|
159072
|
+
FROM git_commits c
|
|
159073
|
+
LEFT JOIN git_commit_embeddings e ON c.sha = e.sha
|
|
159074
|
+
WHERE c.project_path = ? AND e.sha IS NULL
|
|
159075
|
+
ORDER BY c.committed_at DESC
|
|
159076
|
+
LIMIT ?`);
|
|
159077
|
+
loadUnembeddedStatements.set(db, stmt);
|
|
159078
|
+
}
|
|
159079
|
+
return stmt;
|
|
159080
|
+
}
|
|
159081
|
+
function getCountEmbeddedStatement(db) {
|
|
159082
|
+
let stmt = countEmbeddedStatements.get(db);
|
|
159083
|
+
if (!stmt) {
|
|
159084
|
+
stmt = db.prepare(`SELECT COUNT(*) AS count FROM git_commit_embeddings e
|
|
159085
|
+
JOIN git_commits c ON c.sha = e.sha WHERE c.project_path = ?`);
|
|
159086
|
+
countEmbeddedStatements.set(db, stmt);
|
|
159087
|
+
}
|
|
159088
|
+
return stmt;
|
|
159089
|
+
}
|
|
159090
|
+
function getClearProjectStatement(db) {
|
|
159091
|
+
let stmt = clearProjectStatements.get(db);
|
|
159092
|
+
if (!stmt) {
|
|
159093
|
+
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
159094
|
+
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
159095
|
+
clearProjectStatements.set(db, stmt);
|
|
158932
159096
|
}
|
|
158933
159097
|
return stmt;
|
|
158934
159098
|
}
|
|
159099
|
+
function getDistinctModelIdStatement(db) {
|
|
159100
|
+
let stmt = distinctModelIdStatements.get(db);
|
|
159101
|
+
if (!stmt) {
|
|
159102
|
+
stmt = db.prepare(`SELECT DISTINCT e.model_id AS modelId
|
|
159103
|
+
FROM git_commit_embeddings e
|
|
159104
|
+
JOIN git_commits c ON c.sha = e.sha
|
|
159105
|
+
WHERE c.project_path = ?`);
|
|
159106
|
+
distinctModelIdStatements.set(db, stmt);
|
|
159107
|
+
}
|
|
159108
|
+
return stmt;
|
|
159109
|
+
}
|
|
159110
|
+
function saveCommitEmbedding(db, sha, embedding, modelId) {
|
|
159111
|
+
const bytes = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
159112
|
+
getSaveStatement(db).run(sha, bytes, modelId, Date.now());
|
|
159113
|
+
}
|
|
159114
|
+
function loadProjectCommitEmbeddings(db, projectPath) {
|
|
159115
|
+
const rows = getLoadProjectStatement(db).all(projectPath);
|
|
159116
|
+
const map2 = new Map;
|
|
159117
|
+
for (const row of rows) {
|
|
159118
|
+
const buffer2 = row.embedding.buffer.slice(row.embedding.byteOffset, row.embedding.byteOffset + row.embedding.byteLength);
|
|
159119
|
+
map2.set(row.sha, new Float32Array(buffer2));
|
|
159120
|
+
}
|
|
159121
|
+
return map2;
|
|
159122
|
+
}
|
|
159123
|
+
function loadUnembeddedCommits(db, projectPath, limit) {
|
|
159124
|
+
return getLoadUnembeddedStatement(db).all(projectPath, limit);
|
|
159125
|
+
}
|
|
159126
|
+
function countEmbeddedCommits(db, projectPath) {
|
|
159127
|
+
const row = getCountEmbeddedStatement(db).get(projectPath);
|
|
159128
|
+
return row?.count ?? 0;
|
|
159129
|
+
}
|
|
159130
|
+
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
159131
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
159132
|
+
}
|
|
159133
|
+
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
159134
|
+
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
159135
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
159136
|
+
}
|
|
159137
|
+
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements, clearProjectStatements, distinctModelIdStatements;
|
|
159138
|
+
var init_storage_git_commit_embeddings = __esm(() => {
|
|
159139
|
+
saveStatements = new WeakMap;
|
|
159140
|
+
loadProjectStatements = new WeakMap;
|
|
159141
|
+
loadUnembeddedStatements = new WeakMap;
|
|
159142
|
+
countEmbeddedStatements = new WeakMap;
|
|
159143
|
+
clearProjectStatements = new WeakMap;
|
|
159144
|
+
distinctModelIdStatements = new WeakMap;
|
|
159145
|
+
});
|
|
159146
|
+
|
|
159147
|
+
// src/features/magic-context/project-embedding-registry.ts
|
|
159148
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
158935
159149
|
function resolveEmbeddingConfig(config2) {
|
|
158936
159150
|
if (!config2 || config2.provider === "local") {
|
|
158937
159151
|
return {
|
|
@@ -158950,10 +159164,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
158950
159164
|
}
|
|
158951
159165
|
return { provider: "off" };
|
|
158952
159166
|
}
|
|
158953
|
-
function resolveProviderIdentity(config2) {
|
|
158954
|
-
return getEmbeddingProviderIdentity(config2);
|
|
158955
|
-
}
|
|
158956
159167
|
function createProvider(config2) {
|
|
159168
|
+
if (testProviderFactory) {
|
|
159169
|
+
return testProviderFactory(config2);
|
|
159170
|
+
}
|
|
158957
159171
|
if (config2.provider === "off") {
|
|
158958
159172
|
return null;
|
|
158959
159173
|
}
|
|
@@ -158966,129 +159180,221 @@ function createProvider(config2) {
|
|
|
158966
159180
|
}
|
|
158967
159181
|
return new LocalEmbeddingProvider(config2.model);
|
|
158968
159182
|
}
|
|
158969
|
-
function
|
|
158970
|
-
if (
|
|
158971
|
-
return
|
|
159183
|
+
function stableStringify2(value) {
|
|
159184
|
+
if (Array.isArray(value)) {
|
|
159185
|
+
return `[${value.map((entry) => stableStringify2(entry)).join(",")}]`;
|
|
158972
159186
|
}
|
|
158973
|
-
|
|
158974
|
-
|
|
159187
|
+
if (value && typeof value === "object") {
|
|
159188
|
+
const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
|
|
159189
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify2(entry)}`).join(",")}}`;
|
|
159190
|
+
}
|
|
159191
|
+
return JSON.stringify(value);
|
|
159192
|
+
}
|
|
159193
|
+
function sha256Prefix(value, length = 16) {
|
|
159194
|
+
return createHash5("sha256").update(value).digest("hex").slice(0, length);
|
|
158975
159195
|
}
|
|
158976
|
-
function
|
|
158977
|
-
|
|
158978
|
-
|
|
158979
|
-
|
|
158980
|
-
|
|
158981
|
-
|
|
158982
|
-
|
|
159196
|
+
function getRuntimeFingerprint(config2) {
|
|
159197
|
+
if (config2.provider === "off") {
|
|
159198
|
+
return OFF_PROVIDER_IDENTITY;
|
|
159199
|
+
}
|
|
159200
|
+
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
159201
|
+
}
|
|
159202
|
+
function sameFeatures(a, b) {
|
|
159203
|
+
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
159204
|
+
}
|
|
159205
|
+
function snapshotFor(registration) {
|
|
159206
|
+
const providerIsOn = registration.providerIdentity !== OFF_PROVIDER_IDENTITY;
|
|
159207
|
+
const enabled = !registration.observationMode && providerIsOn && registration.features.memoryEnabled;
|
|
159208
|
+
const gitCommitEnabled = !registration.observationMode && providerIsOn && registration.features.gitCommitEnabled;
|
|
159209
|
+
return {
|
|
159210
|
+
projectIdentity: registration.projectIdentity,
|
|
159211
|
+
sourceDirectory: registration.sourceDirectory,
|
|
159212
|
+
providerIdentity: registration.providerIdentity,
|
|
159213
|
+
runtimeFingerprint: registration.runtimeFingerprint,
|
|
159214
|
+
generation: registration.generation,
|
|
159215
|
+
features: { ...registration.features },
|
|
159216
|
+
enabled,
|
|
159217
|
+
gitCommitEnabled,
|
|
159218
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
159219
|
+
};
|
|
159220
|
+
}
|
|
159221
|
+
function disposeProvider(provider) {
|
|
159222
|
+
if (!provider)
|
|
158983
159223
|
return;
|
|
159224
|
+
provider.dispose().catch((error51) => {
|
|
159225
|
+
log("[magic-context] embedding provider dispose failed:", error51);
|
|
159226
|
+
});
|
|
159227
|
+
}
|
|
159228
|
+
function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
159229
|
+
if (storedIds.size === 0)
|
|
159230
|
+
return false;
|
|
159231
|
+
for (const id of storedIds) {
|
|
159232
|
+
if (id === null || id !== currentId) {
|
|
159233
|
+
return true;
|
|
159234
|
+
}
|
|
158984
159235
|
}
|
|
158985
|
-
|
|
158986
|
-
|
|
158987
|
-
|
|
158988
|
-
|
|
158989
|
-
|
|
158990
|
-
});
|
|
159236
|
+
return false;
|
|
159237
|
+
}
|
|
159238
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
159239
|
+
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
159240
|
+
return false;
|
|
158991
159241
|
}
|
|
159242
|
+
let wiped = false;
|
|
159243
|
+
db.transaction(() => {
|
|
159244
|
+
if (features.memoryEnabled) {
|
|
159245
|
+
const memoryIds = getDistinctStoredModelIds(db, projectIdentity);
|
|
159246
|
+
if (anyStoredModelIdIsStale(memoryIds, currentProviderIdentity)) {
|
|
159247
|
+
clearEmbeddingsForProject(db, projectIdentity);
|
|
159248
|
+
invalidateProject(projectIdentity);
|
|
159249
|
+
wiped = true;
|
|
159250
|
+
}
|
|
159251
|
+
}
|
|
159252
|
+
if (features.gitCommitEnabled) {
|
|
159253
|
+
const commitIds = getDistinctCommitEmbeddingModelIds(db, projectIdentity);
|
|
159254
|
+
if (anyStoredModelIdIsStale(commitIds, currentProviderIdentity)) {
|
|
159255
|
+
clearProjectCommitEmbeddings(db, projectIdentity);
|
|
159256
|
+
wiped = true;
|
|
159257
|
+
}
|
|
159258
|
+
}
|
|
159259
|
+
})();
|
|
159260
|
+
return wiped;
|
|
158992
159261
|
}
|
|
158993
|
-
function
|
|
158994
|
-
|
|
159262
|
+
function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, features, sourceDirectory) {
|
|
159263
|
+
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
159264
|
+
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
159265
|
+
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
159266
|
+
const prior = projectRegistrations.get(projectIdentity);
|
|
159267
|
+
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
159268
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
159269
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
159270
|
+
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
159271
|
+
const registration = {
|
|
159272
|
+
projectIdentity,
|
|
159273
|
+
sourceDirectory,
|
|
159274
|
+
config: resolvedConfig,
|
|
159275
|
+
providerIdentity,
|
|
159276
|
+
runtimeFingerprint,
|
|
159277
|
+
provider: canReuseProvider ? prior.provider : null,
|
|
159278
|
+
generation,
|
|
159279
|
+
features: { ...features },
|
|
159280
|
+
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
159281
|
+
observationMode: false
|
|
159282
|
+
};
|
|
159283
|
+
projectRegistrations.set(projectIdentity, registration);
|
|
159284
|
+
if (!canReuseProvider) {
|
|
159285
|
+
disposeProvider(prior?.provider ?? null);
|
|
159286
|
+
}
|
|
159287
|
+
return snapshotFor(registration);
|
|
159288
|
+
}
|
|
159289
|
+
function registerProjectInObservationMode(db, projectIdentity, sourceDirectory, failedConfig, failureSummary) {
|
|
159290
|
+
const prior = projectRegistrations.get(projectIdentity);
|
|
159291
|
+
const runtimeFingerprint = `observation:${sha256Prefix(failureSummary)}`;
|
|
159292
|
+
const generation = prior?.runtimeFingerprint === runtimeFingerprint && prior.observationMode ? prior.generation : ++globalRegistrationGeneration;
|
|
159293
|
+
const registration = {
|
|
159294
|
+
projectIdentity,
|
|
159295
|
+
sourceDirectory,
|
|
159296
|
+
config: resolveEmbeddingConfig(failedConfig),
|
|
159297
|
+
providerIdentity: OFF_PROVIDER_IDENTITY,
|
|
159298
|
+
runtimeFingerprint,
|
|
159299
|
+
provider: null,
|
|
159300
|
+
generation,
|
|
159301
|
+
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
159302
|
+
modelId: "off",
|
|
159303
|
+
observationMode: true
|
|
159304
|
+
};
|
|
159305
|
+
projectRegistrations.set(projectIdentity, registration);
|
|
159306
|
+
disposeProvider(prior?.provider ?? null);
|
|
159307
|
+
return snapshotFor(registration);
|
|
158995
159308
|
}
|
|
158996
|
-
|
|
158997
|
-
const
|
|
158998
|
-
|
|
159309
|
+
function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
159310
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
159311
|
+
return registration ? snapshotFor(registration) : null;
|
|
159312
|
+
}
|
|
159313
|
+
function getOrCreateProjectProvider(registration) {
|
|
159314
|
+
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
158999
159315
|
return null;
|
|
159000
159316
|
}
|
|
159001
|
-
if (
|
|
159317
|
+
if (registration.provider) {
|
|
159318
|
+
return registration.provider;
|
|
159319
|
+
}
|
|
159320
|
+
const provider = createProvider(registration.config);
|
|
159321
|
+
registration.provider = provider;
|
|
159322
|
+
return provider;
|
|
159323
|
+
}
|
|
159324
|
+
async function embedTextForProject(projectIdentity, text, signal) {
|
|
159325
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
159326
|
+
if (!registration)
|
|
159327
|
+
return null;
|
|
159328
|
+
const generation = registration.generation;
|
|
159329
|
+
const modelId = registration.modelId;
|
|
159330
|
+
const provider = getOrCreateProjectProvider(registration);
|
|
159331
|
+
if (!provider)
|
|
159332
|
+
return null;
|
|
159333
|
+
const vector = await provider.embed(text, signal);
|
|
159334
|
+
if (!vector)
|
|
159335
|
+
return null;
|
|
159336
|
+
const current = projectRegistrations.get(projectIdentity);
|
|
159337
|
+
if (!current || current.generation !== generation || current.runtimeFingerprint !== registration.runtimeFingerprint) {
|
|
159002
159338
|
return null;
|
|
159003
159339
|
}
|
|
159004
|
-
return
|
|
159340
|
+
return { vector, modelId, generation };
|
|
159005
159341
|
}
|
|
159006
|
-
async function
|
|
159342
|
+
async function embedBatchForProject(projectIdentity, texts, signal) {
|
|
159007
159343
|
if (texts.length === 0) {
|
|
159008
|
-
|
|
159009
|
-
|
|
159010
|
-
|
|
159011
|
-
|
|
159012
|
-
return Array.from({ length: texts.length }, () => null);
|
|
159344
|
+
const registration2 = projectRegistrations.get(projectIdentity);
|
|
159345
|
+
if (!registration2 || registration2.observationMode)
|
|
159346
|
+
return null;
|
|
159347
|
+
return { vectors: [], modelId: registration2.modelId, generation: registration2.generation };
|
|
159013
159348
|
}
|
|
159014
|
-
|
|
159015
|
-
|
|
159349
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
159350
|
+
if (!registration)
|
|
159351
|
+
return null;
|
|
159352
|
+
const generation = registration.generation;
|
|
159353
|
+
const modelId = registration.modelId;
|
|
159354
|
+
const runtimeFingerprint = registration.runtimeFingerprint;
|
|
159355
|
+
const provider = getOrCreateProjectProvider(registration);
|
|
159356
|
+
if (!provider)
|
|
159357
|
+
return null;
|
|
159358
|
+
const vectors = await provider.embedBatch(texts, signal);
|
|
159359
|
+
const current = projectRegistrations.get(projectIdentity);
|
|
159360
|
+
if (!current || current.generation !== generation || current.runtimeFingerprint !== runtimeFingerprint) {
|
|
159361
|
+
return null;
|
|
159016
159362
|
}
|
|
159017
|
-
return
|
|
159363
|
+
return { vectors, modelId, generation };
|
|
159018
159364
|
}
|
|
159019
|
-
|
|
159020
|
-
if (
|
|
159021
|
-
|
|
159022
|
-
|
|
159023
|
-
|
|
159024
|
-
|
|
159025
|
-
|
|
159026
|
-
|
|
159027
|
-
|
|
159028
|
-
|
|
159029
|
-
|
|
159030
|
-
return 0;
|
|
159031
|
-
const projects = db.prepare(`SELECT m.project_path, MAX(m.updated_at) AS latest
|
|
159032
|
-
FROM memories m
|
|
159033
|
-
WHERE m.status IN ('active', 'permanent')
|
|
159034
|
-
AND m.id NOT IN (SELECT memory_id FROM memory_embeddings)
|
|
159035
|
-
GROUP BY m.project_path
|
|
159036
|
-
ORDER BY latest DESC
|
|
159037
|
-
LIMIT 20`).all();
|
|
159038
|
-
let total = 0;
|
|
159039
|
-
let consecutiveEmpty = 0;
|
|
159040
|
-
outer:
|
|
159041
|
-
for (const project of projects) {
|
|
159042
|
-
while (Date.now() < deadline) {
|
|
159043
|
-
const count = await embedUnembeddedMemoriesForProject(db, project.project_path, config2, batchSize);
|
|
159044
|
-
if (count === 0) {
|
|
159045
|
-
consecutiveEmpty += 1;
|
|
159046
|
-
if (consecutiveEmpty >= SWEEP_MAX_CONSECUTIVE_EMPTY) {
|
|
159047
|
-
log(`[magic-context] embedding sweep: ${SWEEP_MAX_CONSECUTIVE_EMPTY} consecutive empty batches, stopping (total=${total})`);
|
|
159048
|
-
break outer;
|
|
159049
|
-
}
|
|
159050
|
-
break;
|
|
159051
|
-
}
|
|
159052
|
-
consecutiveEmpty = 0;
|
|
159053
|
-
total += count;
|
|
159054
|
-
if (count < batchSize)
|
|
159055
|
-
break;
|
|
159056
|
-
}
|
|
159057
|
-
if (Date.now() >= deadline) {
|
|
159058
|
-
log(`[magic-context] embedding sweep: wall-clock deadline reached after ${((Date.now() - startedAt) / 1000).toFixed(1)}s (total=${total})`);
|
|
159059
|
-
break;
|
|
159060
|
-
}
|
|
159061
|
-
}
|
|
159062
|
-
return total;
|
|
159063
|
-
} finally {
|
|
159064
|
-
sweepInProgress = false;
|
|
159365
|
+
function isUnembeddedMemoryRow(row) {
|
|
159366
|
+
if (row === null || typeof row !== "object")
|
|
159367
|
+
return false;
|
|
159368
|
+
const candidate = row;
|
|
159369
|
+
return typeof candidate.id === "number" && typeof candidate.content === "string";
|
|
159370
|
+
}
|
|
159371
|
+
function getLoadUnembeddedMemoriesStatement(db) {
|
|
159372
|
+
let stmt = loadUnembeddedMemoriesStatements.get(db);
|
|
159373
|
+
if (!stmt) {
|
|
159374
|
+
stmt = db.prepare("SELECT m.id AS id, m.content AS content FROM memories m LEFT JOIN memory_embeddings me ON m.id = me.memory_id WHERE m.project_path = ? AND m.status = 'active' AND me.memory_id IS NULL LIMIT ?");
|
|
159375
|
+
loadUnembeddedMemoriesStatements.set(db, stmt);
|
|
159065
159376
|
}
|
|
159377
|
+
return stmt;
|
|
159066
159378
|
}
|
|
159067
|
-
async function embedUnembeddedMemoriesForProject(db,
|
|
159068
|
-
const
|
|
159069
|
-
|
|
159070
|
-
if (resolvedConfig.provider === "off") {
|
|
159379
|
+
async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize = 10) {
|
|
159380
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
159381
|
+
if (!snapshot?.enabled)
|
|
159071
159382
|
return 0;
|
|
159072
|
-
|
|
159073
|
-
|
|
159074
|
-
|
|
159075
|
-
if (memories.length === 0) {
|
|
159383
|
+
const normalizedBatchSize = Math.max(1, Math.floor(batchSize));
|
|
159384
|
+
const memories = getLoadUnembeddedMemoriesStatement(db).all(projectIdentity, normalizedBatchSize).filter(isUnembeddedMemoryRow);
|
|
159385
|
+
if (memories.length === 0)
|
|
159076
159386
|
return 0;
|
|
159077
|
-
}
|
|
159078
159387
|
try {
|
|
159079
|
-
const
|
|
159080
|
-
|
|
159081
|
-
if (modelId === "off") {
|
|
159388
|
+
const result = await embedBatchForProject(projectIdentity, memories.map((memory) => memory.content));
|
|
159389
|
+
if (!result)
|
|
159082
159390
|
return 0;
|
|
159083
|
-
}
|
|
159084
159391
|
let embeddedCount = 0;
|
|
159085
159392
|
db.transaction(() => {
|
|
159086
159393
|
for (const [index, memory] of memories.entries()) {
|
|
159087
|
-
const embedding =
|
|
159088
|
-
if (!embedding)
|
|
159394
|
+
const embedding = result.vectors[index];
|
|
159395
|
+
if (!embedding)
|
|
159089
159396
|
continue;
|
|
159090
|
-
|
|
159091
|
-
saveEmbedding(db, memory.id, embedding, modelId);
|
|
159397
|
+
saveEmbedding(db, memory.id, embedding, result.modelId);
|
|
159092
159398
|
embeddedCount += 1;
|
|
159093
159399
|
}
|
|
159094
159400
|
})();
|
|
@@ -159098,10 +159404,56 @@ async function embedUnembeddedMemoriesForProject(db, projectPath, config2, batch
|
|
|
159098
159404
|
return 0;
|
|
159099
159405
|
}
|
|
159100
159406
|
}
|
|
159101
|
-
|
|
159102
|
-
|
|
159407
|
+
var OFF_PROVIDER_IDENTITY = "embedding-provider:off", SWEEP_MAX_WALL_CLOCK_MS, projectRegistrations, loadUnembeddedMemoriesStatements, globalRegistrationGeneration = 0, testProviderFactory = null;
|
|
159408
|
+
var init_project_embedding_registry = __esm(() => {
|
|
159409
|
+
init_magic_context();
|
|
159410
|
+
init_logger();
|
|
159411
|
+
init_storage_git_commit_embeddings();
|
|
159412
|
+
init_embedding_cache();
|
|
159413
|
+
init_embedding_identity();
|
|
159414
|
+
init_embedding_local();
|
|
159415
|
+
init_embedding_openai();
|
|
159416
|
+
init_storage_memory_embeddings();
|
|
159417
|
+
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
159418
|
+
projectRegistrations = new Map;
|
|
159419
|
+
loadUnembeddedMemoriesStatements = new WeakMap;
|
|
159420
|
+
});
|
|
159421
|
+
|
|
159422
|
+
// src/features/magic-context/memory/embedding.ts
|
|
159423
|
+
function createProvider2(config2) {
|
|
159424
|
+
if (config2.provider === "off") {
|
|
159425
|
+
return null;
|
|
159426
|
+
}
|
|
159427
|
+
if (config2.provider === "openai-compatible") {
|
|
159428
|
+
return new OpenAICompatibleEmbeddingProvider({
|
|
159429
|
+
endpoint: config2.endpoint,
|
|
159430
|
+
model: config2.model,
|
|
159431
|
+
apiKey: config2.api_key
|
|
159432
|
+
});
|
|
159433
|
+
}
|
|
159434
|
+
return new LocalEmbeddingProvider(config2.model);
|
|
159435
|
+
}
|
|
159436
|
+
function getOrCreateProvider() {
|
|
159437
|
+
if (provider) {
|
|
159438
|
+
return provider;
|
|
159439
|
+
}
|
|
159440
|
+
provider = createProvider2(embeddingConfig);
|
|
159441
|
+
return provider;
|
|
159442
|
+
}
|
|
159443
|
+
function isEmbeddingEnabled() {
|
|
159444
|
+
return embeddingConfig.provider !== "off";
|
|
159445
|
+
}
|
|
159446
|
+
async function embedText(text, signal) {
|
|
159447
|
+
const currentProvider = getOrCreateProvider();
|
|
159448
|
+
if (!currentProvider) {
|
|
159449
|
+
return null;
|
|
159450
|
+
}
|
|
159451
|
+
if (!await currentProvider.initialize()) {
|
|
159452
|
+
return null;
|
|
159453
|
+
}
|
|
159454
|
+
return currentProvider.embed(text, signal);
|
|
159103
159455
|
}
|
|
159104
|
-
var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null,
|
|
159456
|
+
var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMemoriesStatements2, SWEEP_MAX_WALL_CLOCK_MS2;
|
|
159105
159457
|
var init_embedding = __esm(() => {
|
|
159106
159458
|
init_magic_context();
|
|
159107
159459
|
init_logger();
|
|
@@ -159109,13 +159461,14 @@ var init_embedding = __esm(() => {
|
|
|
159109
159461
|
init_embedding_local();
|
|
159110
159462
|
init_embedding_openai();
|
|
159111
159463
|
init_storage_memory_embeddings();
|
|
159464
|
+
init_project_embedding_registry();
|
|
159112
159465
|
DEFAULT_EMBEDDING_CONFIG = {
|
|
159113
159466
|
provider: "local",
|
|
159114
159467
|
model: DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
159115
159468
|
};
|
|
159116
159469
|
embeddingConfig = DEFAULT_EMBEDDING_CONFIG;
|
|
159117
|
-
|
|
159118
|
-
|
|
159470
|
+
loadUnembeddedMemoriesStatements2 = new WeakMap;
|
|
159471
|
+
SWEEP_MAX_WALL_CLOCK_MS2 = 10 * 60 * 1000;
|
|
159119
159472
|
});
|
|
159120
159473
|
|
|
159121
159474
|
// src/features/magic-context/memory/storage-memory-fts.ts
|
|
@@ -159152,46 +159505,6 @@ var init_storage_memory_fts = __esm(() => {
|
|
|
159152
159505
|
searchStatements = new WeakMap;
|
|
159153
159506
|
});
|
|
159154
159507
|
|
|
159155
|
-
// src/features/magic-context/memory/project-identity.ts
|
|
159156
|
-
import { execSync } from "node:child_process";
|
|
159157
|
-
import { createHash as createHash4 } from "node:crypto";
|
|
159158
|
-
import path4 from "node:path";
|
|
159159
|
-
function getRootCommitHash(directory) {
|
|
159160
|
-
try {
|
|
159161
|
-
const hash2 = execSync("git rev-list --max-parents=0 HEAD", {
|
|
159162
|
-
cwd: directory,
|
|
159163
|
-
encoding: "utf-8",
|
|
159164
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
159165
|
-
timeout: GIT_TIMEOUT_MS2
|
|
159166
|
-
}).trim();
|
|
159167
|
-
const firstLine = hash2.split(`
|
|
159168
|
-
`)[0]?.trim();
|
|
159169
|
-
return firstLine && firstLine.length >= 7 ? firstLine : undefined;
|
|
159170
|
-
} catch {
|
|
159171
|
-
return;
|
|
159172
|
-
}
|
|
159173
|
-
}
|
|
159174
|
-
function directoryFallback(directory) {
|
|
159175
|
-
const canonical = path4.resolve(directory);
|
|
159176
|
-
const hash2 = createHash4("md5").update(canonical).digest("hex").slice(0, 12);
|
|
159177
|
-
return `dir:${hash2}`;
|
|
159178
|
-
}
|
|
159179
|
-
function resolveProjectIdentity(directory) {
|
|
159180
|
-
const resolved = path4.resolve(directory);
|
|
159181
|
-
const cached2 = resolvedCache.get(resolved);
|
|
159182
|
-
if (cached2 !== undefined) {
|
|
159183
|
-
return cached2;
|
|
159184
|
-
}
|
|
159185
|
-
const rootHash = getRootCommitHash(resolved);
|
|
159186
|
-
const identity = rootHash ? `git:${rootHash}` : directoryFallback(resolved);
|
|
159187
|
-
resolvedCache.set(resolved, identity);
|
|
159188
|
-
return identity;
|
|
159189
|
-
}
|
|
159190
|
-
var GIT_TIMEOUT_MS2 = 5000, resolvedCache;
|
|
159191
|
-
var init_project_identity = __esm(() => {
|
|
159192
|
-
resolvedCache = new Map;
|
|
159193
|
-
});
|
|
159194
|
-
|
|
159195
159508
|
// src/features/magic-context/compression-depth-storage.ts
|
|
159196
159509
|
function getIncrementDepthStatement(db) {
|
|
159197
159510
|
let stmt = incrementDepthStatements.get(db);
|
|
@@ -160550,6 +160863,52 @@ var init_migrations = __esm(async () => {
|
|
|
160550
160863
|
db.exec("ALTER TABLE session_meta ADD COLUMN deferred_execute_state TEXT");
|
|
160551
160864
|
}
|
|
160552
160865
|
}
|
|
160866
|
+
},
|
|
160867
|
+
{
|
|
160868
|
+
version: 16,
|
|
160869
|
+
description: "Add context-limit cache regression sentinels",
|
|
160870
|
+
up: (db) => {
|
|
160871
|
+
const cols = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
160872
|
+
if (!cols.some((c) => c.name === "observed_safe_input_tokens")) {
|
|
160873
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0");
|
|
160874
|
+
}
|
|
160875
|
+
if (!cols.some((c) => c.name === "cache_alert_sent")) {
|
|
160876
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN cache_alert_sent INTEGER NOT NULL DEFAULT 0");
|
|
160877
|
+
}
|
|
160878
|
+
}
|
|
160879
|
+
},
|
|
160880
|
+
{
|
|
160881
|
+
version: 17,
|
|
160882
|
+
description: "Multi-anchor JSON storage for note-nudge and auto-search-hint persistence",
|
|
160883
|
+
up: (db) => {
|
|
160884
|
+
const cols = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
160885
|
+
if (!cols.some((c) => c.name === "note_nudge_anchors")) {
|
|
160886
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN note_nudge_anchors TEXT NOT NULL DEFAULT '[]'");
|
|
160887
|
+
}
|
|
160888
|
+
if (!cols.some((c) => c.name === "auto_search_hint_decisions")) {
|
|
160889
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]'");
|
|
160890
|
+
}
|
|
160891
|
+
db.exec(`
|
|
160892
|
+
UPDATE session_meta
|
|
160893
|
+
SET note_nudge_anchors = json_array(
|
|
160894
|
+
json_object(
|
|
160895
|
+
'messageId', note_nudge_sticky_message_id,
|
|
160896
|
+
'text', note_nudge_sticky_text
|
|
160897
|
+
)
|
|
160898
|
+
)
|
|
160899
|
+
WHERE COALESCE(note_nudge_sticky_text, '') != ''
|
|
160900
|
+
AND COALESCE(note_nudge_sticky_message_id, '') != ''
|
|
160901
|
+
AND (note_nudge_anchors IS NULL OR note_nudge_anchors = '[]')
|
|
160902
|
+
`);
|
|
160903
|
+
db.exec(`
|
|
160904
|
+
UPDATE session_meta SET note_nudge_anchors = '[]'
|
|
160905
|
+
WHERE note_nudge_anchors IS NULL
|
|
160906
|
+
`);
|
|
160907
|
+
db.exec(`
|
|
160908
|
+
UPDATE session_meta SET auto_search_hint_decisions = '[]'
|
|
160909
|
+
WHERE auto_search_hint_decisions IS NULL
|
|
160910
|
+
`);
|
|
160911
|
+
}
|
|
160553
160912
|
}
|
|
160554
160913
|
];
|
|
160555
160914
|
});
|
|
@@ -161055,6 +161414,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
161055
161414
|
note_nudge_trigger_message_id TEXT DEFAULT '',
|
|
161056
161415
|
note_nudge_sticky_text TEXT DEFAULT '',
|
|
161057
161416
|
note_nudge_sticky_message_id TEXT DEFAULT '',
|
|
161417
|
+
note_nudge_anchors TEXT NOT NULL DEFAULT '[]',
|
|
161418
|
+
auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]',
|
|
161058
161419
|
last_todo_state TEXT DEFAULT '',
|
|
161059
161420
|
todo_synthetic_call_id TEXT DEFAULT '',
|
|
161060
161421
|
todo_synthetic_anchor_message_id TEXT DEFAULT '',
|
|
@@ -161062,6 +161423,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
161062
161423
|
is_subagent INTEGER DEFAULT 0,
|
|
161063
161424
|
last_context_percentage REAL DEFAULT 0,
|
|
161064
161425
|
last_input_tokens INTEGER DEFAULT 0,
|
|
161426
|
+
observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
161427
|
+
cache_alert_sent INTEGER NOT NULL DEFAULT 0,
|
|
161065
161428
|
times_execute_threshold_reached INTEGER DEFAULT 0,
|
|
161066
161429
|
compartment_in_progress INTEGER DEFAULT 0,
|
|
161067
161430
|
historian_failure_count INTEGER DEFAULT 0,
|
|
@@ -161133,12 +161496,16 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
161133
161496
|
ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
|
|
161134
161497
|
ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
|
|
161135
161498
|
ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
|
|
161499
|
+
ensureColumn(db, "session_meta", "note_nudge_anchors", "TEXT NOT NULL DEFAULT '[]'");
|
|
161500
|
+
ensureColumn(db, "session_meta", "auto_search_hint_decisions", "TEXT NOT NULL DEFAULT '[]'");
|
|
161136
161501
|
ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
|
|
161137
161502
|
ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
|
|
161138
161503
|
ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
|
|
161139
161504
|
ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
|
|
161140
161505
|
ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
|
|
161141
161506
|
ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
|
|
161507
|
+
ensureColumn(db, "session_meta", "observed_safe_input_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
161508
|
+
ensureColumn(db, "session_meta", "cache_alert_sent", "INTEGER NOT NULL DEFAULT 0");
|
|
161142
161509
|
ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
|
|
161143
161510
|
ensureColumn(db, "session_meta", "historian_failure_count", "INTEGER DEFAULT 0");
|
|
161144
161511
|
ensureColumn(db, "session_meta", "historian_last_error", "TEXT DEFAULT NULL");
|
|
@@ -161230,7 +161597,9 @@ function healNullIntegerColumns(db) {
|
|
|
161230
161597
|
["system_prompt_tokens", 0],
|
|
161231
161598
|
["conversation_tokens", 0],
|
|
161232
161599
|
["tool_call_tokens", 0],
|
|
161233
|
-
["note_nudge_trigger_pending", 0]
|
|
161600
|
+
["note_nudge_trigger_pending", 0],
|
|
161601
|
+
["observed_safe_input_tokens", 0],
|
|
161602
|
+
["cache_alert_sent", 0]
|
|
161234
161603
|
];
|
|
161235
161604
|
for (const [column, fallback] of columns) {
|
|
161236
161605
|
try {
|
|
@@ -161239,7 +161608,7 @@ function healNullIntegerColumns(db) {
|
|
|
161239
161608
|
}
|
|
161240
161609
|
}
|
|
161241
161610
|
function ensureColumn(db, table, column, definition) {
|
|
161242
|
-
if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'()
|
|
161611
|
+
if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
|
|
161243
161612
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
161244
161613
|
}
|
|
161245
161614
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -161326,7 +161695,7 @@ function isSessionMetaRow(row) {
|
|
|
161326
161695
|
if (row === null || typeof row !== "object")
|
|
161327
161696
|
return false;
|
|
161328
161697
|
const r = row;
|
|
161329
|
-
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);
|
|
161698
|
+
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.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && 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);
|
|
161330
161699
|
}
|
|
161331
161700
|
function getDefaultSessionMeta(sessionId) {
|
|
161332
161701
|
return {
|
|
@@ -161340,6 +161709,8 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
161340
161709
|
isSubagent: false,
|
|
161341
161710
|
lastContextPercentage: 0,
|
|
161342
161711
|
lastInputTokens: 0,
|
|
161712
|
+
observedSafeInputTokens: 0,
|
|
161713
|
+
cacheAlertSent: false,
|
|
161343
161714
|
timesExecuteThresholdReached: 0,
|
|
161344
161715
|
compartmentInProgress: false,
|
|
161345
161716
|
systemPromptHash: "",
|
|
@@ -161352,7 +161723,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
161352
161723
|
}
|
|
161353
161724
|
function ensureSessionMetaRow(db, sessionId) {
|
|
161354
161725
|
const defaults = getDefaultSessionMeta(sessionId);
|
|
161355
|
-
db.prepare("INSERT OR IGNORE INTO session_meta (session_id, harness, 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, cleared_reasoning_through_tag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(sessionId, getHarness(), defaults.lastResponseTime, defaults.cacheTtl, defaults.counter, defaults.lastNudgeTokens, defaults.lastNudgeBand ?? "", defaults.lastTransformError ?? "", defaults.isSubagent ? 1 : 0, defaults.lastContextPercentage, defaults.lastInputTokens, defaults.timesExecuteThresholdReached, defaults.compartmentInProgress ? 1 : 0, defaults.systemPromptHash ?? "", defaults.clearedReasoningThroughTag);
|
|
161726
|
+
db.prepare("INSERT OR IGNORE INTO session_meta (session_id, harness, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, observed_safe_input_tokens, cache_alert_sent, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, cleared_reasoning_through_tag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(sessionId, getHarness(), defaults.lastResponseTime, defaults.cacheTtl, defaults.counter, defaults.lastNudgeTokens, defaults.lastNudgeBand ?? "", defaults.lastTransformError ?? "", defaults.isSubagent ? 1 : 0, defaults.lastContextPercentage, defaults.lastInputTokens, defaults.observedSafeInputTokens, defaults.cacheAlertSent ? 1 : 0, defaults.timesExecuteThresholdReached, defaults.compartmentInProgress ? 1 : 0, defaults.systemPromptHash ?? "", defaults.clearedReasoningThroughTag);
|
|
161356
161727
|
}
|
|
161357
161728
|
function toSessionMeta(row) {
|
|
161358
161729
|
const nudgeBandRaw = typeof row.last_nudge_band === "string" ? row.last_nudge_band : "";
|
|
@@ -161372,6 +161743,8 @@ function toSessionMeta(row) {
|
|
|
161372
161743
|
isSubagent: row.is_subagent === 1,
|
|
161373
161744
|
lastContextPercentage: row.last_context_percentage,
|
|
161374
161745
|
lastInputTokens: row.last_input_tokens,
|
|
161746
|
+
observedSafeInputTokens: numOrZero(row.observed_safe_input_tokens),
|
|
161747
|
+
cacheAlertSent: numOrZero(row.cache_alert_sent) === 1,
|
|
161375
161748
|
timesExecuteThresholdReached: numOrZero(row.times_execute_threshold_reached),
|
|
161376
161749
|
compartmentInProgress: row.compartment_in_progress === 1,
|
|
161377
161750
|
systemPromptHash: String(systemPromptHashRaw),
|
|
@@ -161394,6 +161767,8 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
161394
161767
|
isSubagent: "is_subagent",
|
|
161395
161768
|
lastContextPercentage: "last_context_percentage",
|
|
161396
161769
|
lastInputTokens: "last_input_tokens",
|
|
161770
|
+
observedSafeInputTokens: "observed_safe_input_tokens",
|
|
161771
|
+
cacheAlertSent: "cache_alert_sent",
|
|
161397
161772
|
timesExecuteThresholdReached: "times_execute_threshold_reached",
|
|
161398
161773
|
compartmentInProgress: "compartment_in_progress",
|
|
161399
161774
|
systemPromptHash: "system_prompt_hash",
|
|
@@ -161403,7 +161778,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
161403
161778
|
clearedReasoningThroughTag: "cleared_reasoning_through_tag",
|
|
161404
161779
|
lastTodoState: "last_todo_state"
|
|
161405
161780
|
};
|
|
161406
|
-
BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress"]);
|
|
161781
|
+
BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress", "cacheAlertSent"]);
|
|
161407
161782
|
});
|
|
161408
161783
|
|
|
161409
161784
|
// src/features/magic-context/storage-meta-persisted.ts
|
|
@@ -161437,6 +161812,38 @@ function isPersistedNoteNudgeRow(row) {
|
|
|
161437
161812
|
const r = row;
|
|
161438
161813
|
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";
|
|
161439
161814
|
}
|
|
161815
|
+
function isValidNoteNudgeAnchor(value) {
|
|
161816
|
+
if (value === null || typeof value !== "object")
|
|
161817
|
+
return false;
|
|
161818
|
+
const row = value;
|
|
161819
|
+
return typeof row.messageId === "string" && row.messageId.length > 0 && typeof row.text === "string" && row.text.length > 0;
|
|
161820
|
+
}
|
|
161821
|
+
function isValidAutoSearchHintDecision(value) {
|
|
161822
|
+
if (value === null || typeof value !== "object")
|
|
161823
|
+
return false;
|
|
161824
|
+
const row = value;
|
|
161825
|
+
if (typeof row.messageId !== "string" || row.messageId.length === 0)
|
|
161826
|
+
return false;
|
|
161827
|
+
if (row.decision === "hint") {
|
|
161828
|
+
return typeof row.text === "string" && row.text.length > 0;
|
|
161829
|
+
}
|
|
161830
|
+
if (row.decision === "no-hint") {
|
|
161831
|
+
return typeof row.reason === "string" && AUTO_SEARCH_NO_HINT_REASONS.has(row.reason);
|
|
161832
|
+
}
|
|
161833
|
+
return false;
|
|
161834
|
+
}
|
|
161835
|
+
function parseJsonArray(json2, validator) {
|
|
161836
|
+
if (!json2)
|
|
161837
|
+
return [];
|
|
161838
|
+
try {
|
|
161839
|
+
const parsed = JSON.parse(json2);
|
|
161840
|
+
if (!Array.isArray(parsed))
|
|
161841
|
+
return [];
|
|
161842
|
+
return parsed.filter(validator);
|
|
161843
|
+
} catch {
|
|
161844
|
+
return [];
|
|
161845
|
+
}
|
|
161846
|
+
}
|
|
161440
161847
|
function isPersistedTodoSyntheticAnchorRow(row) {
|
|
161441
161848
|
if (row === null || typeof row !== "object")
|
|
161442
161849
|
return false;
|
|
@@ -161547,7 +161954,7 @@ function getPersistedNoteNudge(db, sessionId) {
|
|
|
161547
161954
|
function setPersistedNoteNudgeTrigger(db, sessionId, triggerMessageId = "") {
|
|
161548
161955
|
db.transaction(() => {
|
|
161549
161956
|
ensureSessionMetaRow(db, sessionId);
|
|
161550
|
-
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 1, note_nudge_trigger_message_id =
|
|
161957
|
+
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 1, note_nudge_trigger_message_id = ? WHERE session_id = ?").run(triggerMessageId, sessionId);
|
|
161551
161958
|
})();
|
|
161552
161959
|
}
|
|
161553
161960
|
function setPersistedNoteNudgeTriggerMessageId(db, sessionId, triggerMessageId) {
|
|
@@ -161556,14 +161963,126 @@ function setPersistedNoteNudgeTriggerMessageId(db, sessionId, triggerMessageId)
|
|
|
161556
161963
|
db.prepare("UPDATE session_meta SET note_nudge_trigger_message_id = ? WHERE session_id = ?").run(triggerMessageId, sessionId);
|
|
161557
161964
|
})();
|
|
161558
161965
|
}
|
|
161559
|
-
function
|
|
161560
|
-
db.
|
|
161966
|
+
function getNoteNudgeAnchors(db, sessionId) {
|
|
161967
|
+
const row = db.prepare("SELECT note_nudge_anchors FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161968
|
+
return parseJsonArray(row?.note_nudge_anchors, isValidNoteNudgeAnchor);
|
|
161969
|
+
}
|
|
161970
|
+
function getAutoSearchHintDecisions(db, sessionId) {
|
|
161971
|
+
const row = db.prepare("SELECT auto_search_hint_decisions FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161972
|
+
return parseJsonArray(row?.auto_search_hint_decisions, isValidAutoSearchHintDecision);
|
|
161973
|
+
}
|
|
161974
|
+
function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, options) {
|
|
161975
|
+
if (options?.ensureRow === false) {
|
|
161976
|
+
const exists = db.prepare("SELECT 1 FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161977
|
+
if (!exists)
|
|
161978
|
+
return true;
|
|
161979
|
+
} else {
|
|
161561
161980
|
ensureSessionMetaRow(db, sessionId);
|
|
161562
|
-
|
|
161563
|
-
|
|
161981
|
+
}
|
|
161982
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
161983
|
+
const row = db.prepare(`SELECT ${column} FROM session_meta WHERE session_id = ?`).get(sessionId);
|
|
161984
|
+
const currentBlob = row?.[column] ?? "[]";
|
|
161985
|
+
const current = parseJsonArray(currentBlob, validator);
|
|
161986
|
+
const next = mutate(current);
|
|
161987
|
+
if (next === null)
|
|
161988
|
+
return true;
|
|
161989
|
+
const nextBlob = stableStringify(next);
|
|
161990
|
+
if (nextBlob === currentBlob)
|
|
161991
|
+
return true;
|
|
161992
|
+
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column} = ?`).run(nextBlob, sessionId, currentBlob);
|
|
161993
|
+
if (result.changes > 0)
|
|
161994
|
+
return true;
|
|
161995
|
+
}
|
|
161996
|
+
sessionLog(sessionId, `${column} CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
161997
|
+
return false;
|
|
161564
161998
|
}
|
|
161565
|
-
function
|
|
161566
|
-
|
|
161999
|
+
function deliverNoteNudgeAtomic(db, sessionId, messageId, text) {
|
|
162000
|
+
let plan = null;
|
|
162001
|
+
const casOk = casUpdateJsonArrayColumn(db, sessionId, "note_nudge_anchors", isValidNoteNudgeAnchor, (current) => {
|
|
162002
|
+
if (current.some((anchor) => anchor.messageId === messageId && anchor.text === text)) {
|
|
162003
|
+
plan = { kind: "already-present" };
|
|
162004
|
+
return null;
|
|
162005
|
+
}
|
|
162006
|
+
if (current.some((anchor) => anchor.messageId === messageId)) {
|
|
162007
|
+
plan = { kind: "conflict" };
|
|
162008
|
+
sessionLog(sessionId, "note-nudge: messageId conflict, refusing append");
|
|
162009
|
+
return null;
|
|
162010
|
+
}
|
|
162011
|
+
plan = { kind: "appended" };
|
|
162012
|
+
return [...current, { messageId, text }];
|
|
162013
|
+
});
|
|
162014
|
+
if (!casOk) {
|
|
162015
|
+
sessionLog(sessionId, `note-nudge: CAS exhausted for ${messageId}; skipping wire append`);
|
|
162016
|
+
return { ok: false, kind: "cas-exhausted" };
|
|
162017
|
+
}
|
|
162018
|
+
const committedPlan = plan;
|
|
162019
|
+
if (!committedPlan) {
|
|
162020
|
+
sessionLog(sessionId, "note-nudge: CAS reported success with no plan staged; treating as failure");
|
|
162021
|
+
return { ok: false, kind: "cas-exhausted" };
|
|
162022
|
+
}
|
|
162023
|
+
if (committedPlan.kind === "conflict") {
|
|
162024
|
+
return { ok: false, kind: "conflict" };
|
|
162025
|
+
}
|
|
162026
|
+
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
162027
|
+
return { ok: true, kind: committedPlan.kind };
|
|
162028
|
+
}
|
|
162029
|
+
function appendAutoSearchHintDecision(db, sessionId, entry) {
|
|
162030
|
+
if (!entry.messageId)
|
|
162031
|
+
return { ok: false, kind: "cas-exhausted" };
|
|
162032
|
+
let staged = null;
|
|
162033
|
+
const casOk = casUpdateJsonArrayColumn(db, sessionId, "auto_search_hint_decisions", isValidAutoSearchHintDecision, (current) => {
|
|
162034
|
+
const existing = current.find((decision) => decision.messageId === entry.messageId);
|
|
162035
|
+
if (existing) {
|
|
162036
|
+
staged = { kind: "already-present", decision: existing };
|
|
162037
|
+
return null;
|
|
162038
|
+
}
|
|
162039
|
+
staged = { kind: "appended", decision: entry };
|
|
162040
|
+
return [...current, entry];
|
|
162041
|
+
});
|
|
162042
|
+
if (!casOk)
|
|
162043
|
+
return { ok: false, kind: "cas-exhausted" };
|
|
162044
|
+
const committed = staged;
|
|
162045
|
+
if (!committed) {
|
|
162046
|
+
sessionLog(sessionId, "auto-search: CAS reported success with no staged outcome");
|
|
162047
|
+
return { ok: false, kind: "cas-exhausted" };
|
|
162048
|
+
}
|
|
162049
|
+
return { ok: true, kind: committed.kind, decision: committed.decision };
|
|
162050
|
+
}
|
|
162051
|
+
function pruneNoteNudgeAnchors(db, sessionId, visibleMessageIds) {
|
|
162052
|
+
let pruned = 0;
|
|
162053
|
+
casUpdateJsonArrayColumn(db, sessionId, "note_nudge_anchors", isValidNoteNudgeAnchor, (current) => {
|
|
162054
|
+
const next = current.filter((anchor) => visibleMessageIds.has(anchor.messageId));
|
|
162055
|
+
pruned = current.length - next.length;
|
|
162056
|
+
return pruned > 0 ? next : null;
|
|
162057
|
+
});
|
|
162058
|
+
return pruned;
|
|
162059
|
+
}
|
|
162060
|
+
function pruneAutoSearchHintDecisions(db, sessionId, visibleMessageIds) {
|
|
162061
|
+
let pruned = 0;
|
|
162062
|
+
casUpdateJsonArrayColumn(db, sessionId, "auto_search_hint_decisions", isValidAutoSearchHintDecision, (current) => {
|
|
162063
|
+
const next = current.filter((decision) => visibleMessageIds.has(decision.messageId));
|
|
162064
|
+
pruned = current.length - next.length;
|
|
162065
|
+
return pruned > 0 ? next : null;
|
|
162066
|
+
});
|
|
162067
|
+
return pruned;
|
|
162068
|
+
}
|
|
162069
|
+
function removeNoteNudgeAnchorByMessageId(db, sessionId, messageId) {
|
|
162070
|
+
let removed = false;
|
|
162071
|
+
const ok = casUpdateJsonArrayColumn(db, sessionId, "note_nudge_anchors", isValidNoteNudgeAnchor, (current) => {
|
|
162072
|
+
const next = current.filter((anchor) => anchor.messageId !== messageId);
|
|
162073
|
+
removed = next.length !== current.length;
|
|
162074
|
+
return removed ? next : null;
|
|
162075
|
+
}, { ensureRow: false });
|
|
162076
|
+
return ok && removed;
|
|
162077
|
+
}
|
|
162078
|
+
function removeAutoSearchHintDecisionByMessageId(db, sessionId, messageId) {
|
|
162079
|
+
let removed = false;
|
|
162080
|
+
const ok = casUpdateJsonArrayColumn(db, sessionId, "auto_search_hint_decisions", isValidAutoSearchHintDecision, (current) => {
|
|
162081
|
+
const next = current.filter((decision) => decision.messageId !== messageId);
|
|
162082
|
+
removed = next.length !== current.length;
|
|
162083
|
+
return removed ? next : null;
|
|
162084
|
+
}, { ensureRow: false });
|
|
162085
|
+
return ok && removed;
|
|
161567
162086
|
}
|
|
161568
162087
|
function getPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
161569
162088
|
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);
|
|
@@ -161645,9 +162164,9 @@ function recordOverflowDetected(db, sessionId, reportedLimit) {
|
|
|
161645
162164
|
db.transaction(() => {
|
|
161646
162165
|
ensureSessionMetaRow(db, sessionId);
|
|
161647
162166
|
if (typeof reportedLimit === "number" && reportedLimit > 0) {
|
|
161648
|
-
db.prepare("UPDATE session_meta SET detected_context_limit = ?, needs_emergency_recovery = 1 WHERE session_id = ?").run(reportedLimit, sessionId);
|
|
162167
|
+
db.prepare("UPDATE session_meta SET detected_context_limit = ?, needs_emergency_recovery = 1, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, sessionId);
|
|
161649
162168
|
} else {
|
|
161650
|
-
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1 WHERE session_id = ?").run(sessionId);
|
|
162169
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(sessionId);
|
|
161651
162170
|
}
|
|
161652
162171
|
})();
|
|
161653
162172
|
}
|
|
@@ -161656,7 +162175,7 @@ function recordDetectedContextLimit(db, sessionId, reportedLimit) {
|
|
|
161656
162175
|
return;
|
|
161657
162176
|
db.transaction(() => {
|
|
161658
162177
|
ensureSessionMetaRow(db, sessionId);
|
|
161659
|
-
db.prepare("UPDATE session_meta SET detected_context_limit =
|
|
162178
|
+
db.prepare("UPDATE session_meta SET detected_context_limit = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, sessionId);
|
|
161660
162179
|
})();
|
|
161661
162180
|
}
|
|
161662
162181
|
function clearEmergencyRecovery(db, sessionId) {
|
|
@@ -161771,9 +162290,18 @@ function getSessionsWithPendingMarker(db) {
|
|
|
161771
162290
|
AND pending_compaction_marker_state != ''`).all();
|
|
161772
162291
|
return rows.map((r) => r.session_id);
|
|
161773
162292
|
}
|
|
162293
|
+
var CAS_RETRY_LIMIT = 5, AUTO_SEARCH_NO_HINT_REASONS;
|
|
161774
162294
|
var init_storage_meta_persisted = __esm(() => {
|
|
161775
162295
|
init_logger();
|
|
161776
162296
|
init_storage_meta_shared();
|
|
162297
|
+
AUTO_SEARCH_NO_HINT_REASONS = new Set([
|
|
162298
|
+
"below-threshold",
|
|
162299
|
+
"timeout",
|
|
162300
|
+
"empty",
|
|
162301
|
+
"error",
|
|
162302
|
+
"stacked",
|
|
162303
|
+
"too-short"
|
|
162304
|
+
]);
|
|
161777
162305
|
});
|
|
161778
162306
|
|
|
161779
162307
|
// src/features/magic-context/resolve-subagent-fallback.ts
|
|
@@ -161797,7 +162325,7 @@ var init_resolve_subagent_fallback = __esm(async () => {
|
|
|
161797
162325
|
|
|
161798
162326
|
// src/features/magic-context/storage-meta-session.ts
|
|
161799
162327
|
function getOrCreateSessionMeta(db, sessionId) {
|
|
161800
|
-
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);
|
|
162328
|
+
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, observed_safe_input_tokens, cache_alert_sent, 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);
|
|
161801
162329
|
if (isSessionMetaRow(result)) {
|
|
161802
162330
|
return toSessionMeta(result);
|
|
161803
162331
|
}
|
|
@@ -162298,12 +162826,12 @@ var init_storage = __esm(async () => {
|
|
|
162298
162826
|
});
|
|
162299
162827
|
|
|
162300
162828
|
// src/shared/models-dev-cache.ts
|
|
162301
|
-
import { createHash as
|
|
162829
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
162302
162830
|
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "node:fs";
|
|
162303
162831
|
import { homedir as homedir9, platform as platform3 } from "node:os";
|
|
162304
162832
|
import { join as join19 } from "node:path";
|
|
162305
162833
|
function hashFast(input) {
|
|
162306
|
-
return
|
|
162834
|
+
return createHash7("sha1").update(input).digest("hex");
|
|
162307
162835
|
}
|
|
162308
162836
|
function getModelsJsonPath() {
|
|
162309
162837
|
const explicit = process.env.OPENCODE_MODELS_PATH?.trim();
|
|
@@ -162410,17 +162938,9 @@ async function refreshModelLimitsFromApi(client) {
|
|
|
162410
162938
|
apiCache = map2;
|
|
162411
162939
|
apiLoadedAt = Date.now();
|
|
162412
162940
|
if (previousSize === null) {
|
|
162413
|
-
recentlySeenApiSizes.add(map2.size);
|
|
162414
162941
|
sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model metadata entries`);
|
|
162415
162942
|
} else if (previousSize !== map2.size) {
|
|
162416
|
-
|
|
162417
|
-
recentlySeenApiSizes.add(map2.size);
|
|
162418
|
-
if (!sizeAlreadySeen) {
|
|
162419
|
-
sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model metadata entries (was ${previousSize})`);
|
|
162420
|
-
} else if (!oscillationLogged) {
|
|
162421
|
-
oscillationLogged = true;
|
|
162422
|
-
sessionLog("global", `models-dev-cache: API count oscillating between ${[...recentlySeenApiSizes].sort((a, b) => a - b).join(" ↔ ")} — likely upstream provider plugin returning slightly different model sets between calls (e.g. github-copilot's /models endpoint toggling model_picker_enabled). Suppressing further size-change logs.`);
|
|
162423
|
-
}
|
|
162943
|
+
sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model metadata entries (was ${previousSize})`);
|
|
162424
162944
|
}
|
|
162425
162945
|
} catch (error51) {
|
|
162426
162946
|
sessionLog("global", "models-dev-cache: API refresh failed:", error51 instanceof Error ? error51.message : String(error51));
|
|
@@ -162440,13 +162960,12 @@ function getModelsDevContextLimit(providerID, modelID) {
|
|
|
162440
162960
|
}
|
|
162441
162961
|
return fileCache.get(key)?.limit;
|
|
162442
162962
|
}
|
|
162443
|
-
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0,
|
|
162963
|
+
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, fileCache = null, fileLastAttempt = 0;
|
|
162444
162964
|
var init_models_dev_cache = __esm(() => {
|
|
162445
162965
|
init_data_path();
|
|
162446
162966
|
init_jsonc_parser();
|
|
162447
162967
|
init_logger();
|
|
162448
162968
|
RELOAD_INTERVAL_MS = 5 * 60 * 1000;
|
|
162449
|
-
recentlySeenApiSizes = new Set;
|
|
162450
162969
|
});
|
|
162451
162970
|
|
|
162452
162971
|
// src/shared/rpc-notifications.ts
|
|
@@ -164340,7 +164859,7 @@ function peekNoteNudgeText(db, sessionId, currentUserMessageId, projectIdentity,
|
|
|
164340
164859
|
const deliveredAt = getPersistedNoteNudgeDeliveredAt(db, sessionId);
|
|
164341
164860
|
if (deliveredAt > 0 && Date.now() - deliveredAt < NOTE_NUDGE_COOLDOWN_MS) {
|
|
164342
164861
|
sessionLog(sessionId, `note-nudge: suppressing — last delivered ${Math.round((Date.now() - deliveredAt) / 1000)}s ago (cooldown ${NOTE_NUDGE_COOLDOWN_MS / 60000}m)`);
|
|
164343
|
-
|
|
164862
|
+
clearNoteNudgeTriggerOnly(db, sessionId);
|
|
164344
164863
|
return null;
|
|
164345
164864
|
}
|
|
164346
164865
|
const notes = getSessionNotes(db, sessionId);
|
|
@@ -164348,7 +164867,7 @@ function peekNoteNudgeText(db, sessionId, currentUserMessageId, projectIdentity,
|
|
|
164348
164867
|
const totalCount = notes.length + readySmartNotes.length;
|
|
164349
164868
|
if (totalCount === 0) {
|
|
164350
164869
|
sessionLog(sessionId, "note-nudge: triggerPending but no notes found, skipping");
|
|
164351
|
-
|
|
164870
|
+
clearNoteNudgeTriggerOnly(db, sessionId);
|
|
164352
164871
|
return null;
|
|
164353
164872
|
}
|
|
164354
164873
|
const lastReadAt = getNoteLastReadAt(db, sessionId);
|
|
@@ -164356,7 +164875,7 @@ function peekNoteNudgeText(db, sessionId, currentUserMessageId, projectIdentity,
|
|
|
164356
164875
|
const mostRecentNoteActivity = maxNoteActivityTime([...notes, ...readySmartNotes]);
|
|
164357
164876
|
if (mostRecentNoteActivity > 0 && lastReadAt > mostRecentNoteActivity) {
|
|
164358
164877
|
sessionLog(sessionId, `note-nudge: suppressing — agent ran ctx_note(read) at ${new Date(lastReadAt).toISOString()} and the read is still visible; no new notes since ${new Date(mostRecentNoteActivity).toISOString()}`);
|
|
164359
|
-
|
|
164878
|
+
clearNoteNudgeTriggerOnly(db, sessionId);
|
|
164360
164879
|
return null;
|
|
164361
164880
|
}
|
|
164362
164881
|
}
|
|
@@ -164381,22 +164900,28 @@ function maxNoteActivityTime(notes) {
|
|
|
164381
164900
|
return max;
|
|
164382
164901
|
}
|
|
164383
164902
|
function markNoteNudgeDelivered(db, sessionId, text, messageId) {
|
|
164384
|
-
|
|
164385
|
-
|
|
164386
|
-
|
|
164903
|
+
if (!messageId) {
|
|
164904
|
+
clearNoteNudgeTriggerAndCooldown(db, sessionId);
|
|
164905
|
+
sessionLog(sessionId, "note-nudge: marked delivered without anchor");
|
|
164906
|
+
return { ok: true, kind: "already-present" };
|
|
164907
|
+
}
|
|
164908
|
+
const outcome = deliverNoteNudgeAtomic(db, sessionId, messageId, text);
|
|
164909
|
+
if (outcome.ok) {
|
|
164910
|
+
recordNoteNudgeDeliveryTime(sessionId);
|
|
164911
|
+
}
|
|
164912
|
+
sessionLog(sessionId, outcome.ok ? `note-nudge: marked delivered, sticky anchor=${messageId} (${outcome.kind})` : `note-nudge: delivery not persisted for anchor=${messageId} (${outcome.kind})`);
|
|
164913
|
+
return outcome;
|
|
164387
164914
|
}
|
|
164388
|
-
function
|
|
164389
|
-
|
|
164390
|
-
|
|
164391
|
-
return null;
|
|
164392
|
-
return { text: state.stickyText, messageId: state.stickyMessageId };
|
|
164915
|
+
function clearNoteNudgeTriggerAndCooldown(db, sessionId) {
|
|
164916
|
+
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
164917
|
+
lastDeliveredAt.delete(sessionId);
|
|
164393
164918
|
}
|
|
164394
|
-
function
|
|
164395
|
-
if (options?.persist !== false) {
|
|
164396
|
-
clearPersistedNoteNudge(db, sessionId);
|
|
164397
|
-
}
|
|
164919
|
+
function resetNoteNudgeCooldownOnly(sessionId) {
|
|
164398
164920
|
lastDeliveredAt.delete(sessionId);
|
|
164399
164921
|
}
|
|
164922
|
+
function clearNoteNudgeTriggerOnly(db, sessionId) {
|
|
164923
|
+
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
164924
|
+
}
|
|
164400
164925
|
var NOTE_NUDGE_COOLDOWN_MS, lastDeliveredAt;
|
|
164401
164926
|
var init_note_nudger = __esm(() => {
|
|
164402
164927
|
init_storage_meta_persisted();
|
|
@@ -164668,7 +165193,8 @@ var init_historian_state_file = __esm(() => {
|
|
|
164668
165193
|
|
|
164669
165194
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
164670
165195
|
async function ensureMemoryEmbeddings(args) {
|
|
164671
|
-
|
|
165196
|
+
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
165197
|
+
if (!snapshot?.enabled) {
|
|
164672
165198
|
return args.existingEmbeddings;
|
|
164673
165199
|
}
|
|
164674
165200
|
const missingMemories = args.memories.filter((memory) => !args.existingEmbeddings.has(memory.id));
|
|
@@ -164676,19 +165202,25 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
164676
165202
|
return args.existingEmbeddings;
|
|
164677
165203
|
}
|
|
164678
165204
|
try {
|
|
164679
|
-
const
|
|
164680
|
-
|
|
165205
|
+
const result = await embedBatchForProject(args.projectIdentity, missingMemories.map((memory) => memory.content));
|
|
165206
|
+
if (!result) {
|
|
165207
|
+
return args.existingEmbeddings;
|
|
165208
|
+
}
|
|
164681
165209
|
const staged = new Map;
|
|
164682
165210
|
args.db.transaction(() => {
|
|
164683
165211
|
for (const [index, memory] of missingMemories.entries()) {
|
|
164684
|
-
const embedding =
|
|
165212
|
+
const embedding = result.vectors[index];
|
|
164685
165213
|
if (!embedding) {
|
|
164686
165214
|
continue;
|
|
164687
165215
|
}
|
|
164688
|
-
saveEmbedding(args.db, memory.id, embedding, modelId);
|
|
165216
|
+
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
164689
165217
|
staged.set(memory.id, embedding);
|
|
164690
165218
|
}
|
|
164691
165219
|
})();
|
|
165220
|
+
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
165221
|
+
if (!currentSnapshot || currentSnapshot.generation !== result.generation) {
|
|
165222
|
+
return args.existingEmbeddings;
|
|
165223
|
+
}
|
|
164692
165224
|
for (const [id, embedding] of staged) {
|
|
164693
165225
|
args.existingEmbeddings.set(id, embedding);
|
|
164694
165226
|
}
|
|
@@ -164732,17 +165264,17 @@ function promoteSessionFactsToMemory(db, sessionId, projectPath, facts) {
|
|
|
164732
165264
|
expiresAt: resolveExpiresAt(fact.category)
|
|
164733
165265
|
};
|
|
164734
165266
|
const memory = insertMemory(db, memoryInput);
|
|
164735
|
-
embedAndStoreMemory(db, sessionId, memory.id, memory.content);
|
|
165267
|
+
embedAndStoreMemory(db, sessionId, projectPath, memory.id, memory.content);
|
|
164736
165268
|
} catch (error51) {
|
|
164737
165269
|
sessionLog(sessionId, `memory promotion failed for fact "${fact.content.slice(0, 60)}":`, error51);
|
|
164738
165270
|
}
|
|
164739
165271
|
}
|
|
164740
165272
|
}
|
|
164741
|
-
async function embedAndStoreMemory(db, sessionId, memoryId, content) {
|
|
165273
|
+
async function embedAndStoreMemory(db, sessionId, projectPath, memoryId, content) {
|
|
164742
165274
|
try {
|
|
164743
|
-
const
|
|
164744
|
-
if (
|
|
164745
|
-
saveEmbedding(db, memoryId,
|
|
165275
|
+
const result = await embedTextForProject(projectPath, content);
|
|
165276
|
+
if (result) {
|
|
165277
|
+
saveEmbedding(db, memoryId, result.vector, result.modelId);
|
|
164746
165278
|
}
|
|
164747
165279
|
} catch (error51) {
|
|
164748
165280
|
sessionLog(sessionId, `memory embedding failed for memory ${memoryId}:`, error51);
|
|
@@ -165344,6 +165876,7 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
165344
165876
|
}
|
|
165345
165877
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
165346
165878
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
165879
|
+
await deps.ensureProjectRegistered?.(deps.directory, db);
|
|
165347
165880
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), validatedPass.facts ?? []);
|
|
165348
165881
|
}
|
|
165349
165882
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
@@ -165446,7 +165979,33 @@ async function executeContextRecompInternal(deps) {
|
|
|
165446
165979
|
let currentStateFilePath;
|
|
165447
165980
|
updateSessionMeta(db, sessionId, { compartmentInProgress: true });
|
|
165448
165981
|
try {
|
|
165449
|
-
|
|
165982
|
+
const protectedTailStart = getProtectedTailStartOrdinal(sessionId);
|
|
165983
|
+
if (protectedTailStart <= 1) {
|
|
165984
|
+
return `## Magic Recomp
|
|
165985
|
+
|
|
165986
|
+
No eligible raw history exists before the protected tail, so nothing was rebuilt.`;
|
|
165987
|
+
}
|
|
165988
|
+
const rawMessageCount = getRawSessionMessageCount(sessionId);
|
|
165989
|
+
const parentSessionResponse = await client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
165990
|
+
const parentSession = normalizeSDKResponse(parentSessionResponse, null, { preferResponseOnMissingData: true });
|
|
165991
|
+
const sessionDirectory = parentSession?.directory ?? directory;
|
|
165992
|
+
const projectPath = directory ? resolveProjectIdentity(directory) : undefined;
|
|
165993
|
+
const memories = projectPath ? getMemoriesByProject(db, projectPath, ["active", "permanent"]) : [];
|
|
165994
|
+
const memoryBlock = renderMemoryBlock(memories) ?? undefined;
|
|
165995
|
+
const existingStaging = getRecompStaging(db, sessionId);
|
|
165996
|
+
let candidateCompartments = existingStaging?.compartments ?? [];
|
|
165997
|
+
let candidateFacts = existingStaging?.facts ?? [];
|
|
165998
|
+
let offset = existingStaging ? existingStaging.lastEndMessage + 1 : 1;
|
|
165999
|
+
let passCount = existingStaging?.passCount ?? 0;
|
|
166000
|
+
let currentTokenBudget = historianChunkTokens;
|
|
166001
|
+
let passAttempt = 1;
|
|
166002
|
+
const resumed = existingStaging !== null;
|
|
166003
|
+
if (resumed) {
|
|
166004
|
+
await sendIgnoredMessage(client, sessionId, `## Magic Recomp — Resumed
|
|
166005
|
+
|
|
166006
|
+
Found ${existingStaging.compartments.length} staged compartment(s) from ${existingStaging.passCount} previous pass(es), covering messages 1-${existingStaging.lastEndMessage}. Resuming from message ${offset}.`, notifParams());
|
|
166007
|
+
}
|
|
166008
|
+
async function promoteAndFinalize(reason) {
|
|
165450
166009
|
if (passCount === 0 || candidateCompartments.length === 0)
|
|
165451
166010
|
return null;
|
|
165452
166011
|
const mergedError = validateStoredCompartments(candidateCompartments);
|
|
@@ -165462,6 +166021,7 @@ async function executeContextRecompInternal(deps) {
|
|
|
165462
166021
|
}
|
|
165463
166022
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
165464
166023
|
if (deps.directory && deps.memoryEnabled !== false && deps.autoPromote !== false) {
|
|
166024
|
+
await deps.ensureProjectRegistered?.(deps.directory, db);
|
|
165465
166025
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), promoted2.facts);
|
|
165466
166026
|
}
|
|
165467
166027
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
@@ -165481,37 +166041,11 @@ async function executeContextRecompInternal(deps) {
|
|
|
165481
166041
|
`Remaining messages ${lastCompartmentEnd2 + 1}-${protectedTailStart - 1} were not rebuilt (${reason}).`
|
|
165482
166042
|
].join(`
|
|
165483
166043
|
`);
|
|
165484
|
-
};
|
|
165485
|
-
const protectedTailStart = getProtectedTailStartOrdinal(sessionId);
|
|
165486
|
-
if (protectedTailStart <= 1) {
|
|
165487
|
-
return `## Magic Recomp
|
|
165488
|
-
|
|
165489
|
-
No eligible raw history exists before the protected tail, so nothing was rebuilt.`;
|
|
165490
|
-
}
|
|
165491
|
-
const rawMessageCount = getRawSessionMessageCount(sessionId);
|
|
165492
|
-
const parentSessionResponse = await client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
165493
|
-
const parentSession = normalizeSDKResponse(parentSessionResponse, null, { preferResponseOnMissingData: true });
|
|
165494
|
-
const sessionDirectory = parentSession?.directory ?? directory;
|
|
165495
|
-
const projectPath = directory ? resolveProjectIdentity(directory) : undefined;
|
|
165496
|
-
const memories = projectPath ? getMemoriesByProject(db, projectPath, ["active", "permanent"]) : [];
|
|
165497
|
-
const memoryBlock = renderMemoryBlock(memories) ?? undefined;
|
|
165498
|
-
const existingStaging = getRecompStaging(db, sessionId);
|
|
165499
|
-
let candidateCompartments = existingStaging?.compartments ?? [];
|
|
165500
|
-
let candidateFacts = existingStaging?.facts ?? [];
|
|
165501
|
-
let offset = existingStaging ? existingStaging.lastEndMessage + 1 : 1;
|
|
165502
|
-
let passCount = existingStaging?.passCount ?? 0;
|
|
165503
|
-
let currentTokenBudget = historianChunkTokens;
|
|
165504
|
-
let passAttempt = 1;
|
|
165505
|
-
const resumed = existingStaging !== null;
|
|
165506
|
-
if (resumed) {
|
|
165507
|
-
await sendIgnoredMessage(client, sessionId, `## Magic Recomp — Resumed
|
|
165508
|
-
|
|
165509
|
-
Found ${existingStaging.compartments.length} staged compartment(s) from ${existingStaging.passCount} previous pass(es), covering messages 1-${existingStaging.lastEndMessage}. Resuming from message ${offset}.`, notifParams());
|
|
165510
166044
|
}
|
|
165511
166045
|
while (offset < protectedTailStart) {
|
|
165512
166046
|
const chunk = readSessionChunk(sessionId, currentTokenBudget, offset, protectedTailStart);
|
|
165513
166047
|
if (!chunk.text || chunk.messageCount === 0 || chunk.endIndex < offset) {
|
|
165514
|
-
const promoted2 = promoteAndFinalize(`remaining messages ${offset}-${protectedTailStart - 1} were too few or all noise to form a historian chunk`);
|
|
166048
|
+
const promoted2 = await promoteAndFinalize(`remaining messages ${offset}-${protectedTailStart - 1} were too few or all noise to form a historian chunk`);
|
|
165515
166049
|
if (promoted2) {
|
|
165516
166050
|
return `## Magic Recomp — Complete
|
|
165517
166051
|
|
|
@@ -165523,7 +166057,7 @@ Recomp stopped because raw history ${offset}-${protectedTailStart - 1} could not
|
|
|
165523
166057
|
}
|
|
165524
166058
|
const chunkCoverageError = validateChunkCoverage(chunk);
|
|
165525
166059
|
if (chunkCoverageError) {
|
|
165526
|
-
const partial2 = promoteAndFinalize(`chunk could not be represented safely: ${chunkCoverageError}`);
|
|
166060
|
+
const partial2 = await promoteAndFinalize(`chunk could not be represented safely: ${chunkCoverageError}`);
|
|
165527
166061
|
if (partial2) {
|
|
165528
166062
|
return `## Magic Recomp — Partial
|
|
165529
166063
|
|
|
@@ -165584,7 +166118,7 @@ Validator result: ${validatedPass.error}`, notifParams());
|
|
|
165584
166118
|
continue;
|
|
165585
166119
|
}
|
|
165586
166120
|
}
|
|
165587
|
-
const partial2 = promoteAndFinalize(`historian failed to validate messages ${chunk.startIndex}-${chunk.endIndex}: ${validatedPass.error}`);
|
|
166121
|
+
const partial2 = await promoteAndFinalize(`historian failed to validate messages ${chunk.startIndex}-${chunk.endIndex}: ${validatedPass.error}`);
|
|
165588
166122
|
if (partial2) {
|
|
165589
166123
|
return `## Magic Recomp — Partial
|
|
165590
166124
|
|
|
@@ -165607,7 +166141,7 @@ Nothing was written.`;
|
|
|
165607
166141
|
saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, candidateFacts);
|
|
165608
166142
|
const nextOffset = (validatedPass.compartments?.[validatedPass.compartments.length - 1]?.endMessage ?? chunk.endIndex) + 1;
|
|
165609
166143
|
if (nextOffset <= offset) {
|
|
165610
|
-
const partial2 = promoteAndFinalize(`historian made no forward progress after messages ${chunk.startIndex}-${chunk.endIndex}`);
|
|
166144
|
+
const partial2 = await promoteAndFinalize(`historian made no forward progress after messages ${chunk.startIndex}-${chunk.endIndex}`);
|
|
165611
166145
|
if (partial2) {
|
|
165612
166146
|
return `## Magic Recomp — Partial
|
|
165613
166147
|
|
|
@@ -165806,7 +166340,7 @@ __export(exports_tui_config, {
|
|
|
165806
166340
|
ensureTuiPluginEntry: () => ensureTuiPluginEntry
|
|
165807
166341
|
});
|
|
165808
166342
|
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
165809
|
-
import { dirname as
|
|
166343
|
+
import { dirname as dirname9, join as join27 } from "node:path";
|
|
165810
166344
|
function isMagicContextEntry(entry) {
|
|
165811
166345
|
if (!entry)
|
|
165812
166346
|
return false;
|
|
@@ -165852,7 +166386,7 @@ function ensureTuiPluginEntry() {
|
|
|
165852
166386
|
plugins.push(PLUGIN_ENTRY);
|
|
165853
166387
|
}
|
|
165854
166388
|
config2.plugin = plugins;
|
|
165855
|
-
mkdirSync9(
|
|
166389
|
+
mkdirSync9(dirname9(configPath), { recursive: true });
|
|
165856
166390
|
writeFileSync8(configPath, `${import_comment_json4.stringify(config2, null, 2)}
|
|
165857
166391
|
`);
|
|
165858
166392
|
log(`[magic-context] updated TUI plugin entry in ${configPath}`);
|
|
@@ -165963,6 +166497,42 @@ function loadConfigFile(configPath) {
|
|
|
165963
166497
|
return null;
|
|
165964
166498
|
}
|
|
165965
166499
|
}
|
|
166500
|
+
function loadConfigFileDetailed(configPath, source) {
|
|
166501
|
+
if (!existsSync3(configPath)) {
|
|
166502
|
+
return null;
|
|
166503
|
+
}
|
|
166504
|
+
let rawText;
|
|
166505
|
+
try {
|
|
166506
|
+
rawText = readFileSync3(configPath, "utf-8");
|
|
166507
|
+
} catch (error51) {
|
|
166508
|
+
return {
|
|
166509
|
+
config: {},
|
|
166510
|
+
warnings: [
|
|
166511
|
+
`${configPath}: failed to read config: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
166512
|
+
],
|
|
166513
|
+
outcome: "project-file-io-error",
|
|
166514
|
+
source
|
|
166515
|
+
};
|
|
166516
|
+
}
|
|
166517
|
+
try {
|
|
166518
|
+
const substituted = substituteConfigVariables({ text: rawText, configPath });
|
|
166519
|
+
return {
|
|
166520
|
+
config: parseJsonc(substituted.text),
|
|
166521
|
+
warnings: substituted.warnings.map((w) => `${configPath}: ${w}`),
|
|
166522
|
+
outcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok",
|
|
166523
|
+
source
|
|
166524
|
+
};
|
|
166525
|
+
} catch (error51) {
|
|
166526
|
+
return {
|
|
166527
|
+
config: {},
|
|
166528
|
+
warnings: [
|
|
166529
|
+
`${configPath}: failed to load config: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
166530
|
+
],
|
|
166531
|
+
outcome: "project-file-parse-error",
|
|
166532
|
+
source
|
|
166533
|
+
};
|
|
166534
|
+
}
|
|
166535
|
+
}
|
|
165966
166536
|
function deepMergeRawConfig(base, override) {
|
|
165967
166537
|
const result = { ...base };
|
|
165968
166538
|
for (const key of Object.keys(override)) {
|
|
@@ -166057,7 +166627,7 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
166057
166627
|
patched.dreamer = dreamer;
|
|
166058
166628
|
return patched;
|
|
166059
166629
|
}
|
|
166060
|
-
function parsePluginConfig(rawConfig) {
|
|
166630
|
+
function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
166061
166631
|
const preMigrationWarnings = [];
|
|
166062
166632
|
const migrated = migrateLegacyExperimental(rawConfig, preMigrationWarnings);
|
|
166063
166633
|
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
@@ -166082,6 +166652,7 @@ function parsePluginConfig(rawConfig) {
|
|
|
166082
166652
|
}
|
|
166083
166653
|
const patched = { ...rawConfig };
|
|
166084
166654
|
for (const key of errorPaths) {
|
|
166655
|
+
recoveredTopLevelKeys.push(key);
|
|
166085
166656
|
const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
|
|
166086
166657
|
if (isAgentConfig) {
|
|
166087
166658
|
delete patched[key];
|
|
@@ -166152,6 +166723,102 @@ function loadPluginConfig(directory) {
|
|
|
166152
166723
|
}
|
|
166153
166724
|
return config2;
|
|
166154
166725
|
}
|
|
166726
|
+
function collectEmptyStringPaths(value, prefix = "") {
|
|
166727
|
+
if (typeof value === "string") {
|
|
166728
|
+
return value === "" && prefix ? [prefix] : [];
|
|
166729
|
+
}
|
|
166730
|
+
if (Array.isArray(value) || value === null || typeof value !== "object") {
|
|
166731
|
+
return [];
|
|
166732
|
+
}
|
|
166733
|
+
const paths = [];
|
|
166734
|
+
for (const [key, child] of Object.entries(value)) {
|
|
166735
|
+
const nextPrefix = prefix ? `${prefix}.${key}` : key;
|
|
166736
|
+
paths.push(...collectEmptyStringPaths(child, nextPrefix));
|
|
166737
|
+
}
|
|
166738
|
+
return paths;
|
|
166739
|
+
}
|
|
166740
|
+
function bindSubstitutionFailures(loaded) {
|
|
166741
|
+
if (!loaded || loaded.warnings.length === 0 || loaded.outcome !== "substitution-failure") {
|
|
166742
|
+
return [];
|
|
166743
|
+
}
|
|
166744
|
+
const emptyPaths = collectEmptyStringPaths(loaded.config);
|
|
166745
|
+
return loaded.warnings.map((message) => {
|
|
166746
|
+
const matchedPath = emptyPaths.find((path) => {
|
|
166747
|
+
const tail = path.split(".").at(-1) ?? path;
|
|
166748
|
+
return message.includes(path) || message.toLowerCase().includes(tail.toLowerCase());
|
|
166749
|
+
});
|
|
166750
|
+
return { keyPath: matchedPath ?? "<unknown>", source: loaded.source, message };
|
|
166751
|
+
});
|
|
166752
|
+
}
|
|
166753
|
+
function combinedOutcome(args) {
|
|
166754
|
+
const sourceOutcomes = Object.values(args.sources);
|
|
166755
|
+
if (sourceOutcomes.includes("project-file-parse-error"))
|
|
166756
|
+
return "project-file-parse-error";
|
|
166757
|
+
if (sourceOutcomes.includes("project-file-io-error"))
|
|
166758
|
+
return "project-file-io-error";
|
|
166759
|
+
if (args.recoveredTopLevelKeys.length > 0)
|
|
166760
|
+
return "schema-recovery";
|
|
166761
|
+
if (args.substitutionFailures.length > 0)
|
|
166762
|
+
return "substitution-failure";
|
|
166763
|
+
return "ok";
|
|
166764
|
+
}
|
|
166765
|
+
function loadPluginConfigDetailed(directory) {
|
|
166766
|
+
const userDetected = detectConfigFile(getUserConfigBasePath());
|
|
166767
|
+
const rootDetected = detectConfigFile(join(directory, CONFIG_FILE_BASENAME));
|
|
166768
|
+
const dotOpenCodeDetected = detectConfigFile(getProjectConfigBasePath(directory));
|
|
166769
|
+
const projectDetected = rootDetected.format !== "none" ? rootDetected : dotOpenCodeDetected;
|
|
166770
|
+
const userLoaded = userDetected.format === "none" ? null : loadConfigFileDetailed(userDetected.path, "user");
|
|
166771
|
+
const projectLoaded = projectDetected.format === "none" ? null : loadConfigFileDetailed(projectDetected.path, "project");
|
|
166772
|
+
const allWarnings = [];
|
|
166773
|
+
let mergedRaw = {};
|
|
166774
|
+
if (userLoaded) {
|
|
166775
|
+
allWarnings.push(...userLoaded.warnings.map((w) => `[user config] ${w}`));
|
|
166776
|
+
mergedRaw = deepMergeRawConfig(mergedRaw, userLoaded.config);
|
|
166777
|
+
}
|
|
166778
|
+
if (projectLoaded) {
|
|
166779
|
+
allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
|
|
166780
|
+
const projectRaw = { ...projectLoaded.config };
|
|
166781
|
+
const strippedUserOnlyFields = getProjectUserOnlyFields(projectRaw);
|
|
166782
|
+
if (strippedUserOnlyFields.length > 0) {
|
|
166783
|
+
for (const key of strippedUserOnlyFields) {
|
|
166784
|
+
delete projectRaw[key];
|
|
166785
|
+
}
|
|
166786
|
+
allWarnings.push(`[project config] Ignoring ${strippedUserOnlyFields.join(", ")} from project config (security: these settings only honor user-level config)`);
|
|
166787
|
+
}
|
|
166788
|
+
mergedRaw = deepMergeRawConfig(mergedRaw, projectRaw);
|
|
166789
|
+
}
|
|
166790
|
+
const recoveredTopLevelKeys = [];
|
|
166791
|
+
const config2 = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
|
|
166792
|
+
if (config2.configWarnings?.length) {
|
|
166793
|
+
allWarnings.push(...config2.configWarnings.map((w) => {
|
|
166794
|
+
if (userLoaded && projectLoaded)
|
|
166795
|
+
return `[config] ${w}`;
|
|
166796
|
+
if (userLoaded)
|
|
166797
|
+
return `[user config] ${w}`;
|
|
166798
|
+
return `[project config] ${w}`;
|
|
166799
|
+
}));
|
|
166800
|
+
}
|
|
166801
|
+
if (allWarnings.length > 0) {
|
|
166802
|
+
config2.configWarnings = allWarnings;
|
|
166803
|
+
} else if ("configWarnings" in config2) {
|
|
166804
|
+
config2.configWarnings = undefined;
|
|
166805
|
+
}
|
|
166806
|
+
const substitutionFailures = [
|
|
166807
|
+
...bindSubstitutionFailures(userLoaded),
|
|
166808
|
+
...bindSubstitutionFailures(projectLoaded)
|
|
166809
|
+
];
|
|
166810
|
+
const sources = {
|
|
166811
|
+
userConfig: userLoaded?.outcome ?? "ok",
|
|
166812
|
+
projectConfig: projectLoaded?.outcome ?? "ok"
|
|
166813
|
+
};
|
|
166814
|
+
return {
|
|
166815
|
+
config: config2,
|
|
166816
|
+
loadOutcome: combinedOutcome({ sources, substitutionFailures, recoveredTopLevelKeys }),
|
|
166817
|
+
sources,
|
|
166818
|
+
substitutionFailures,
|
|
166819
|
+
recoveredTopLevelKeys
|
|
166820
|
+
};
|
|
166821
|
+
}
|
|
166155
166822
|
|
|
166156
166823
|
// src/features/builtin-commands/commands.ts
|
|
166157
166824
|
function getMagicContextBuiltinCommands() {
|
|
@@ -166545,6 +167212,9 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
166545
167212
|
}
|
|
166546
167213
|
}
|
|
166547
167214
|
|
|
167215
|
+
// src/index.ts
|
|
167216
|
+
init_project_identity();
|
|
167217
|
+
|
|
166548
167218
|
// src/features/magic-context/sidekick/agent.ts
|
|
166549
167219
|
init_shared();
|
|
166550
167220
|
init_assistant_message_extractor();
|
|
@@ -167425,10 +168095,10 @@ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:f
|
|
|
167425
168095
|
import { homedir as homedir8 } from "node:os";
|
|
167426
168096
|
import { join as join11 } from "node:path";
|
|
167427
168097
|
var overrideAvailability = null;
|
|
167428
|
-
function parseConfig(
|
|
167429
|
-
if (!existsSync9(
|
|
168098
|
+
function parseConfig(path5) {
|
|
168099
|
+
if (!existsSync9(path5))
|
|
167430
168100
|
return null;
|
|
167431
|
-
return import_comment_json3.parse(readFileSync8(
|
|
168101
|
+
return import_comment_json3.parse(readFileSync8(path5, "utf-8"));
|
|
167432
168102
|
}
|
|
167433
168103
|
function entryMatchesAft(entry) {
|
|
167434
168104
|
const value = Array.isArray(entry) ? entry[0] : entry;
|
|
@@ -167456,9 +168126,9 @@ function getAftAvailability() {
|
|
|
167456
168126
|
const piPaths = [join11(home, ".pi", "agent", "settings.json")];
|
|
167457
168127
|
const checkedPaths = [...opencodePaths, ...piPaths];
|
|
167458
168128
|
let opencode = false;
|
|
167459
|
-
for (const
|
|
168129
|
+
for (const path5 of opencodePaths) {
|
|
167460
168130
|
try {
|
|
167461
|
-
const config2 = parseConfig(
|
|
168131
|
+
const config2 = parseConfig(path5);
|
|
167462
168132
|
if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"])) {
|
|
167463
168133
|
opencode = true;
|
|
167464
168134
|
break;
|
|
@@ -167466,9 +168136,9 @@ function getAftAvailability() {
|
|
|
167466
168136
|
} catch {}
|
|
167467
168137
|
}
|
|
167468
168138
|
let pi = false;
|
|
167469
|
-
for (const
|
|
168139
|
+
for (const path5 of piPaths) {
|
|
167470
168140
|
try {
|
|
167471
|
-
const config2 = parseConfig(
|
|
168141
|
+
const config2 = parseConfig(path5);
|
|
167472
168142
|
if (hasAftAtKeys(config2, ["packages", "extensions"])) {
|
|
167473
168143
|
pi = true;
|
|
167474
168144
|
break;
|
|
@@ -168866,7 +169536,7 @@ init_logger();
|
|
|
168866
169536
|
import { execFile } from "node:child_process";
|
|
168867
169537
|
import { promisify } from "node:util";
|
|
168868
169538
|
var execFileAsync = promisify(execFile);
|
|
168869
|
-
var
|
|
169539
|
+
var GIT_TIMEOUT_MS2 = 1e4;
|
|
168870
169540
|
var DEFAULT_MAX_COMMITS = 5000;
|
|
168871
169541
|
var RECORD_SEPARATOR = "\x1E";
|
|
168872
169542
|
var FIELD_SEPARATOR = "\x1F";
|
|
@@ -168886,7 +169556,7 @@ async function readGitCommits(directory, options = {}) {
|
|
|
168886
169556
|
try {
|
|
168887
169557
|
const result = await execFileAsync("git", args, {
|
|
168888
169558
|
cwd: directory,
|
|
168889
|
-
timeout:
|
|
169559
|
+
timeout: GIT_TIMEOUT_MS2,
|
|
168890
169560
|
maxBuffer: 32 * 1024 * 1024,
|
|
168891
169561
|
encoding: "utf8"
|
|
168892
169562
|
});
|
|
@@ -168944,79 +169614,7 @@ ${body}` : subject;
|
|
|
168944
169614
|
// src/features/magic-context/git-commits/indexer.ts
|
|
168945
169615
|
init_logger();
|
|
168946
169616
|
init_embedding();
|
|
168947
|
-
|
|
168948
|
-
// src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
168949
|
-
var saveStatements = new WeakMap;
|
|
168950
|
-
var loadProjectStatements = new WeakMap;
|
|
168951
|
-
var loadUnembeddedStatements = new WeakMap;
|
|
168952
|
-
var countEmbeddedStatements = new WeakMap;
|
|
168953
|
-
var clearProjectStatements = new WeakMap;
|
|
168954
|
-
function getSaveStatement(db) {
|
|
168955
|
-
let stmt = saveStatements.get(db);
|
|
168956
|
-
if (!stmt) {
|
|
168957
|
-
stmt = db.prepare(`INSERT INTO git_commit_embeddings (sha, embedding, model_id, created_at)
|
|
168958
|
-
VALUES (?, ?, ?, ?)
|
|
168959
|
-
ON CONFLICT(sha) DO UPDATE SET
|
|
168960
|
-
embedding = excluded.embedding,
|
|
168961
|
-
model_id = excluded.model_id,
|
|
168962
|
-
created_at = excluded.created_at`);
|
|
168963
|
-
saveStatements.set(db, stmt);
|
|
168964
|
-
}
|
|
168965
|
-
return stmt;
|
|
168966
|
-
}
|
|
168967
|
-
function getLoadProjectStatement(db) {
|
|
168968
|
-
let stmt = loadProjectStatements.get(db);
|
|
168969
|
-
if (!stmt) {
|
|
168970
|
-
stmt = db.prepare(`SELECT e.sha AS sha, e.embedding AS embedding, e.model_id AS model_id
|
|
168971
|
-
FROM git_commit_embeddings e
|
|
168972
|
-
JOIN git_commits c ON c.sha = e.sha
|
|
168973
|
-
WHERE c.project_path = ?`);
|
|
168974
|
-
loadProjectStatements.set(db, stmt);
|
|
168975
|
-
}
|
|
168976
|
-
return stmt;
|
|
168977
|
-
}
|
|
168978
|
-
function getLoadUnembeddedStatement(db) {
|
|
168979
|
-
let stmt = loadUnembeddedStatements.get(db);
|
|
168980
|
-
if (!stmt) {
|
|
168981
|
-
stmt = db.prepare(`SELECT c.sha AS sha, c.message AS message
|
|
168982
|
-
FROM git_commits c
|
|
168983
|
-
LEFT JOIN git_commit_embeddings e ON c.sha = e.sha
|
|
168984
|
-
WHERE c.project_path = ? AND e.sha IS NULL
|
|
168985
|
-
ORDER BY c.committed_at DESC
|
|
168986
|
-
LIMIT ?`);
|
|
168987
|
-
loadUnembeddedStatements.set(db, stmt);
|
|
168988
|
-
}
|
|
168989
|
-
return stmt;
|
|
168990
|
-
}
|
|
168991
|
-
function getCountEmbeddedStatement(db) {
|
|
168992
|
-
let stmt = countEmbeddedStatements.get(db);
|
|
168993
|
-
if (!stmt) {
|
|
168994
|
-
stmt = db.prepare(`SELECT COUNT(*) AS count FROM git_commit_embeddings e
|
|
168995
|
-
JOIN git_commits c ON c.sha = e.sha WHERE c.project_path = ?`);
|
|
168996
|
-
countEmbeddedStatements.set(db, stmt);
|
|
168997
|
-
}
|
|
168998
|
-
return stmt;
|
|
168999
|
-
}
|
|
169000
|
-
function saveCommitEmbedding(db, sha, embedding, modelId) {
|
|
169001
|
-
const bytes = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
169002
|
-
getSaveStatement(db).run(sha, bytes, modelId, Date.now());
|
|
169003
|
-
}
|
|
169004
|
-
function loadProjectCommitEmbeddings(db, projectPath) {
|
|
169005
|
-
const rows = getLoadProjectStatement(db).all(projectPath);
|
|
169006
|
-
const map2 = new Map;
|
|
169007
|
-
for (const row of rows) {
|
|
169008
|
-
const buffer2 = row.embedding.buffer.slice(row.embedding.byteOffset, row.embedding.byteOffset + row.embedding.byteLength);
|
|
169009
|
-
map2.set(row.sha, new Float32Array(buffer2));
|
|
169010
|
-
}
|
|
169011
|
-
return map2;
|
|
169012
|
-
}
|
|
169013
|
-
function loadUnembeddedCommits(db, projectPath, limit) {
|
|
169014
|
-
return getLoadUnembeddedStatement(db).all(projectPath, limit);
|
|
169015
|
-
}
|
|
169016
|
-
function countEmbeddedCommits(db, projectPath) {
|
|
169017
|
-
const row = getCountEmbeddedStatement(db).get(projectPath);
|
|
169018
|
-
return row?.count ?? 0;
|
|
169019
|
-
}
|
|
169617
|
+
init_storage_git_commit_embeddings();
|
|
169020
169618
|
|
|
169021
169619
|
// src/features/magic-context/git-commits/storage-git-commits.ts
|
|
169022
169620
|
init_logger();
|
|
@@ -169143,7 +169741,7 @@ var EMBED_MAX_PER_SWEEP = 500;
|
|
|
169143
169741
|
var EMBED_SWEEP_MAX_WALL_CLOCK_MS = 5 * 60 * 1000;
|
|
169144
169742
|
var indexInProgress = new Set;
|
|
169145
169743
|
var embedInProgress = new Set;
|
|
169146
|
-
async function indexCommitsForProject(db, projectPath, directory,
|
|
169744
|
+
async function indexCommitsForProject(db, projectPath, directory, options) {
|
|
169147
169745
|
const result = {
|
|
169148
169746
|
scanned: 0,
|
|
169149
169747
|
inserted: 0,
|
|
@@ -169174,22 +169772,24 @@ async function indexCommitsForProject(db, projectPath, directory, embeddingConfi
|
|
|
169174
169772
|
result.inserted = upsert.inserted;
|
|
169175
169773
|
result.updated = upsert.updated;
|
|
169176
169774
|
result.evicted = enforceProjectCap(db, projectPath, options.maxCommits);
|
|
169177
|
-
|
|
169178
|
-
|
|
169775
|
+
const snapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
169776
|
+
if (options.skipEmbed || !snapshot?.gitCommitEnabled) {
|
|
169777
|
+
log(`[git-commits] indexed ${projectPath}: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=0 (embedding skipped: skipEmbed=${options.skipEmbed === true} gitCommitEnabled=${snapshot?.gitCommitEnabled === true})`);
|
|
169179
169778
|
return result;
|
|
169180
169779
|
}
|
|
169181
|
-
result.embedded = await embedUnembeddedCommits(db, projectPath
|
|
169780
|
+
result.embedded = await embedUnembeddedCommits(db, projectPath);
|
|
169182
169781
|
log(`[git-commits] indexed ${projectPath}: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=${result.embedded}`);
|
|
169183
169782
|
return result;
|
|
169184
169783
|
} finally {
|
|
169185
169784
|
indexInProgress.delete(projectPath);
|
|
169186
169785
|
}
|
|
169187
169786
|
}
|
|
169188
|
-
async function embedUnembeddedCommits(db, projectPath
|
|
169787
|
+
async function embedUnembeddedCommits(db, projectPath) {
|
|
169189
169788
|
if (embedInProgress.has(projectPath)) {
|
|
169190
169789
|
return 0;
|
|
169191
169790
|
}
|
|
169192
|
-
|
|
169791
|
+
const snapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
169792
|
+
if (!snapshot?.gitCommitEnabled) {
|
|
169193
169793
|
return 0;
|
|
169194
169794
|
}
|
|
169195
169795
|
embedInProgress.add(projectPath);
|
|
@@ -169203,16 +169803,15 @@ async function embedUnembeddedCommits(db, projectPath, _config) {
|
|
|
169203
169803
|
break;
|
|
169204
169804
|
let embeddedThisBatch = 0;
|
|
169205
169805
|
try {
|
|
169206
|
-
const
|
|
169207
|
-
|
|
169208
|
-
if (modelId === "off")
|
|
169806
|
+
const result = await embedBatchForProject(projectPath, rows.map((row) => row.message));
|
|
169807
|
+
if (!result)
|
|
169209
169808
|
break;
|
|
169210
169809
|
db.transaction(() => {
|
|
169211
169810
|
for (const [index, row] of rows.entries()) {
|
|
169212
|
-
const embedding =
|
|
169811
|
+
const embedding = result.vectors[index];
|
|
169213
169812
|
if (!embedding)
|
|
169214
169813
|
continue;
|
|
169215
|
-
saveCommitEmbedding(db, row.sha, embedding, modelId);
|
|
169814
|
+
saveCommitEmbedding(db, row.sha, embedding, result.modelId);
|
|
169216
169815
|
embeddedThisBatch += 1;
|
|
169217
169816
|
}
|
|
169218
169817
|
})();
|
|
@@ -169238,6 +169837,7 @@ async function embedUnembeddedCommits(db, projectPath, _config) {
|
|
|
169238
169837
|
// src/features/magic-context/git-commits/search-git-commits.ts
|
|
169239
169838
|
init_logger();
|
|
169240
169839
|
init_storage_memory_fts();
|
|
169840
|
+
init_storage_git_commit_embeddings();
|
|
169241
169841
|
var ftsStatements = new WeakMap;
|
|
169242
169842
|
var ftsPlainStatements = new WeakMap;
|
|
169243
169843
|
var getBySHAStatements = new WeakMap;
|
|
@@ -169368,19 +169968,25 @@ function searchGitCommitsSync(db, projectPath, query, options) {
|
|
|
169368
169968
|
});
|
|
169369
169969
|
return results.slice(0, options.limit);
|
|
169370
169970
|
}
|
|
169971
|
+
|
|
169972
|
+
// src/features/magic-context/git-commits/index.ts
|
|
169973
|
+
init_storage_git_commit_embeddings();
|
|
169974
|
+
|
|
169371
169975
|
// src/plugin/dream-timer.ts
|
|
169372
169976
|
init_embedding();
|
|
169373
|
-
init_project_identity();
|
|
169374
169977
|
init_logger();
|
|
169375
169978
|
init_resolve_fallbacks();
|
|
169376
169979
|
await init_storage();
|
|
169377
169980
|
var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
|
|
169378
169981
|
var activeTimer = null;
|
|
169379
169982
|
var registeredProjects = new Map;
|
|
169380
|
-
function startDreamScheduleTimer(args) {
|
|
169983
|
+
async function startDreamScheduleTimer(args) {
|
|
169984
|
+
const db = openDatabase();
|
|
169985
|
+
await args.ensureRegistered(args.directory, db);
|
|
169986
|
+
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
169381
169987
|
const dreamingEnabled = Boolean(args.dreamerConfig?.enabled && args.dreamerConfig.schedule?.trim());
|
|
169382
|
-
const embeddingSweepEnabled =
|
|
169383
|
-
const commitIndexingEnabled =
|
|
169988
|
+
const embeddingSweepEnabled = snapshot?.enabled ?? false;
|
|
169989
|
+
const commitIndexingEnabled = snapshot?.gitCommitEnabled ?? false;
|
|
169384
169990
|
if (!dreamingEnabled && !embeddingSweepEnabled && !commitIndexingEnabled) {
|
|
169385
169991
|
return;
|
|
169386
169992
|
}
|
|
@@ -169412,45 +170018,43 @@ function startDreamScheduleTimer(args) {
|
|
|
169412
170018
|
}
|
|
169413
170019
|
function runTick(origin) {
|
|
169414
170020
|
log(`[dreamer] timer tick (${origin}) — projects=${registeredProjects.size}`);
|
|
169415
|
-
|
|
169416
|
-
|
|
169417
|
-
|
|
169418
|
-
const
|
|
169419
|
-
|
|
169420
|
-
|
|
170021
|
+
(async () => {
|
|
170022
|
+
try {
|
|
170023
|
+
const db = openDatabase();
|
|
170024
|
+
for (const reg of registeredProjects.values()) {
|
|
170025
|
+
await reg.ensureRegistered(reg.directory, db);
|
|
170026
|
+
const memorySnapshot = getProjectEmbeddingSnapshot(reg.projectIdentity);
|
|
170027
|
+
if (memorySnapshot?.enabled) {
|
|
170028
|
+
const embeddedCount = await embedUnembeddedMemoriesForProject(db, reg.projectIdentity);
|
|
169421
170029
|
if (embeddedCount > 0) {
|
|
169422
|
-
log(`[magic-context] proactively embedded ${embeddedCount} ${embeddedCount === 1 ? "memory" : "memories"}
|
|
170030
|
+
log(`[magic-context] proactively embedded ${embeddedCount} ${embeddedCount === 1 ? "memory" : "memories"} for project ${reg.projectIdentity}`);
|
|
169423
170031
|
}
|
|
169424
|
-
}
|
|
169425
|
-
|
|
169426
|
-
|
|
170032
|
+
}
|
|
170033
|
+
await reg.ensureRegistered(reg.directory, db);
|
|
170034
|
+
const gitSnapshot = getProjectEmbeddingSnapshot(reg.projectIdentity);
|
|
170035
|
+
await sweepProject(reg, origin, db, gitSnapshot?.gitCommitEnabled === true);
|
|
169427
170036
|
}
|
|
170037
|
+
} catch (error51) {
|
|
170038
|
+
log("[magic-context] timer-triggered maintenance check failed:", error51);
|
|
169428
170039
|
}
|
|
169429
|
-
|
|
169430
|
-
sweepProject(reg, origin);
|
|
169431
|
-
}
|
|
169432
|
-
} catch (error51) {
|
|
169433
|
-
log("[magic-context] timer-triggered maintenance check failed:", error51);
|
|
169434
|
-
}
|
|
170040
|
+
})();
|
|
169435
170041
|
}
|
|
169436
|
-
async function sweepProject(reg, origin) {
|
|
170042
|
+
async function sweepProject(reg, origin, db = openDatabase(), gitCommitEnabled = getProjectEmbeddingSnapshot(reg.projectIdentity)?.gitCommitEnabled === true) {
|
|
169437
170043
|
const dreamingEnabled = Boolean(reg.dreamerConfig?.enabled && reg.dreamerConfig.schedule?.trim());
|
|
169438
|
-
|
|
169439
|
-
if (commitIndexingEnabled && reg.gitCommitIndexing) {
|
|
170044
|
+
if (gitCommitEnabled && reg.gitCommitIndexing) {
|
|
169440
170045
|
await sweepGitCommits({
|
|
169441
170046
|
directory: reg.directory,
|
|
169442
170047
|
gitCommitIndexing: reg.gitCommitIndexing,
|
|
169443
|
-
|
|
170048
|
+
projectIdentity: reg.projectIdentity,
|
|
170049
|
+
db
|
|
169444
170050
|
});
|
|
169445
170051
|
}
|
|
169446
170052
|
if (!dreamingEnabled || !reg.dreamerConfig?.schedule?.trim()) {
|
|
169447
170053
|
return;
|
|
169448
170054
|
}
|
|
169449
170055
|
try {
|
|
169450
|
-
const db = openDatabase();
|
|
169451
170056
|
log(`[dreamer] timer tick (${origin}) ${reg.directory} — checking schedule window "${reg.dreamerConfig.schedule}"`);
|
|
169452
|
-
|
|
169453
|
-
checkScheduleAndEnqueue(db, reg.dreamerConfig.schedule, registrationIdentity);
|
|
170057
|
+
checkScheduleAndEnqueue(db, reg.dreamerConfig.schedule, reg.projectIdentity);
|
|
169454
170058
|
await processDreamQueue({
|
|
169455
170059
|
db,
|
|
169456
170060
|
client: reg.client,
|
|
@@ -169459,7 +170063,7 @@ async function sweepProject(reg, origin) {
|
|
|
169459
170063
|
maxRuntimeMinutes: reg.dreamerConfig.max_runtime_minutes,
|
|
169460
170064
|
experimentalUserMemories: reg.experimentalUserMemories,
|
|
169461
170065
|
experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
|
|
169462
|
-
projectIdentity:
|
|
170066
|
+
projectIdentity: reg.projectIdentity,
|
|
169463
170067
|
fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
|
|
169464
170068
|
});
|
|
169465
170069
|
} catch (error51) {
|
|
@@ -169467,28 +170071,124 @@ async function sweepProject(reg, origin) {
|
|
|
169467
170071
|
}
|
|
169468
170072
|
}
|
|
169469
170073
|
async function sweepGitCommits(args) {
|
|
169470
|
-
const { directory,
|
|
170074
|
+
const { directory, projectIdentity, db, gitCommitIndexing } = args;
|
|
169471
170075
|
const startedAt = Date.now();
|
|
169472
|
-
log(`[git-commits] sweep starting for ${directory} (sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits}
|
|
170076
|
+
log(`[git-commits] sweep starting for ${directory} (sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits})`);
|
|
169473
170077
|
try {
|
|
169474
|
-
const
|
|
169475
|
-
const projectPath = resolveProjectIdentity(directory);
|
|
169476
|
-
const result = await indexCommitsForProject(db, projectPath, directory, embeddingConfig2, {
|
|
170078
|
+
const result = await indexCommitsForProject(db, projectIdentity, directory, {
|
|
169477
170079
|
sinceDays: gitCommitIndexing.since_days,
|
|
169478
170080
|
maxCommits: gitCommitIndexing.max_commits
|
|
169479
170081
|
});
|
|
169480
170082
|
let drainedEmbeddings = 0;
|
|
169481
|
-
if (
|
|
169482
|
-
drainedEmbeddings = await embedUnembeddedCommits(db,
|
|
170083
|
+
if (result.embedded > 0) {
|
|
170084
|
+
drainedEmbeddings = await embedUnembeddedCommits(db, projectIdentity);
|
|
169483
170085
|
}
|
|
169484
170086
|
const elapsedMs = Date.now() - startedAt;
|
|
169485
|
-
log(`[git-commits] sweep finished for ${
|
|
170087
|
+
log(`[git-commits] sweep finished for ${projectIdentity} in ${elapsedMs}ms: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=${result.embedded} drained=${drainedEmbeddings}`);
|
|
169486
170088
|
} catch (error51) {
|
|
169487
170089
|
const elapsedMs = Date.now() - startedAt;
|
|
169488
170090
|
log(`[git-commits] sweep failed for ${directory} after ${elapsedMs}ms: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
169489
170091
|
}
|
|
169490
170092
|
}
|
|
169491
170093
|
|
|
170094
|
+
// src/plugin/embedding-bootstrap.ts
|
|
170095
|
+
init_embedding();
|
|
170096
|
+
init_embedding_cache();
|
|
170097
|
+
init_project_identity();
|
|
170098
|
+
|
|
170099
|
+
// src/plugin/embedding-bootstrap-helpers.ts
|
|
170100
|
+
init_embedding();
|
|
170101
|
+
init_logger();
|
|
170102
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
170103
|
+
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
170104
|
+
"embedding.api_key",
|
|
170105
|
+
"embedding.endpoint",
|
|
170106
|
+
"embedding.model",
|
|
170107
|
+
"embedding.provider"
|
|
170108
|
+
]);
|
|
170109
|
+
var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experimental"]);
|
|
170110
|
+
var EMBEDDING_WARNING_TERMS = ["api_key", "endpoint", "model", "provider", "embedding"];
|
|
170111
|
+
var loggedFailureSignatures = new Map;
|
|
170112
|
+
function sha256Prefix2(value, length = 16) {
|
|
170113
|
+
return createHash6("sha256").update(value).digest("hex").slice(0, length);
|
|
170114
|
+
}
|
|
170115
|
+
function warningLooksEmbeddingRelated(message) {
|
|
170116
|
+
const lower = message.toLowerCase();
|
|
170117
|
+
return EMBEDDING_WARNING_TERMS.some((term) => lower.includes(term));
|
|
170118
|
+
}
|
|
170119
|
+
function isConfigLoadUntrusted(detailed) {
|
|
170120
|
+
if (detailed.sources.userConfig === "project-file-parse-error" || detailed.sources.userConfig === "project-file-io-error" || detailed.sources.projectConfig === "project-file-parse-error" || detailed.sources.projectConfig === "project-file-io-error") {
|
|
170121
|
+
return true;
|
|
170122
|
+
}
|
|
170123
|
+
for (const failure of detailed.substitutionFailures) {
|
|
170124
|
+
if (EMBEDDING_AFFECTING_KEYS.has(failure.keyPath)) {
|
|
170125
|
+
return true;
|
|
170126
|
+
}
|
|
170127
|
+
if (failure.keyPath === "<unknown>" && warningLooksEmbeddingRelated(failure.message)) {
|
|
170128
|
+
return true;
|
|
170129
|
+
}
|
|
170130
|
+
}
|
|
170131
|
+
for (const recoveredKey of detailed.recoveredTopLevelKeys) {
|
|
170132
|
+
if (EMBEDDING_AFFECTING_TOP_LEVEL_KEYS.has(recoveredKey)) {
|
|
170133
|
+
return true;
|
|
170134
|
+
}
|
|
170135
|
+
}
|
|
170136
|
+
return false;
|
|
170137
|
+
}
|
|
170138
|
+
function describeFailure(detailed) {
|
|
170139
|
+
const parts = [];
|
|
170140
|
+
for (const [source, outcome] of Object.entries(detailed.sources)) {
|
|
170141
|
+
if (outcome !== "ok") {
|
|
170142
|
+
parts.push(`${source}=${outcome}`);
|
|
170143
|
+
}
|
|
170144
|
+
}
|
|
170145
|
+
if (detailed.substitutionFailures.length > 0) {
|
|
170146
|
+
parts.push(`substitution=${detailed.substitutionFailures.map((failure) => `${failure.source}:${failure.keyPath}`).join(",")}`);
|
|
170147
|
+
}
|
|
170148
|
+
if (detailed.recoveredTopLevelKeys.length > 0) {
|
|
170149
|
+
parts.push(`recovered=${detailed.recoveredTopLevelKeys.join(",")}`);
|
|
170150
|
+
}
|
|
170151
|
+
return parts.length > 0 ? parts.join("; ") : detailed.loadOutcome;
|
|
170152
|
+
}
|
|
170153
|
+
function logConfigFailureOnce(projectIdentity, detailed) {
|
|
170154
|
+
const signature = sha256Prefix2(JSON.stringify({
|
|
170155
|
+
outcomes: detailed.sources,
|
|
170156
|
+
substitutions: detailed.substitutionFailures.map((failure) => `${failure.source}:${failure.keyPath}:${failure.message}`).sort(),
|
|
170157
|
+
recoveredTopLevelKeys: [...detailed.recoveredTopLevelKeys].sort()
|
|
170158
|
+
}));
|
|
170159
|
+
const existing = loggedFailureSignatures.get(projectIdentity) ?? new Set;
|
|
170160
|
+
if (existing.has(signature))
|
|
170161
|
+
return;
|
|
170162
|
+
existing.add(signature);
|
|
170163
|
+
loggedFailureSignatures.set(projectIdentity, existing);
|
|
170164
|
+
log(`[mc][embedding] config load untrusted, preserving last-known-good for ${projectIdentity} — ${describeFailure(detailed)}`);
|
|
170165
|
+
}
|
|
170166
|
+
function handleUntrustedLoad(db, projectIdentity, directory, detailed) {
|
|
170167
|
+
const prior = getProjectEmbeddingSnapshot(projectIdentity);
|
|
170168
|
+
if (prior && !prior.runtimeFingerprint.startsWith("observation:")) {
|
|
170169
|
+
logConfigFailureOnce(projectIdentity, detailed);
|
|
170170
|
+
return true;
|
|
170171
|
+
}
|
|
170172
|
+
registerProjectInObservationMode(db, projectIdentity, directory, detailed.config.embedding, describeFailure(detailed));
|
|
170173
|
+
return true;
|
|
170174
|
+
}
|
|
170175
|
+
|
|
170176
|
+
// src/plugin/embedding-bootstrap.ts
|
|
170177
|
+
async function ensureProjectRegisteredFromOpenCodeDirectory(directory, db) {
|
|
170178
|
+
const projectIdentity = resolveProjectIdentity(directory);
|
|
170179
|
+
invalidateProject(projectIdentity);
|
|
170180
|
+
const detailed = loadPluginConfigDetailed(directory);
|
|
170181
|
+
if (isConfigLoadUntrusted(detailed)) {
|
|
170182
|
+
handleUntrustedLoad(db, projectIdentity, directory, detailed);
|
|
170183
|
+
return;
|
|
170184
|
+
}
|
|
170185
|
+
const features = {
|
|
170186
|
+
memoryEnabled: detailed.config.memory.enabled,
|
|
170187
|
+
gitCommitEnabled: detailed.config.experimental.git_commit_indexing.enabled
|
|
170188
|
+
};
|
|
170189
|
+
registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, detailed.config.embedding, features, directory);
|
|
170190
|
+
}
|
|
170191
|
+
|
|
169492
170192
|
// src/plugin/event.ts
|
|
169493
170193
|
function createEventHandler(args) {
|
|
169494
170194
|
return async (input) => {
|
|
@@ -169987,9 +170687,9 @@ function createTagger() {
|
|
|
169987
170687
|
// src/hooks/magic-context/hook.ts
|
|
169988
170688
|
init_magic_context();
|
|
169989
170689
|
init_project_identity();
|
|
170690
|
+
await init_storage();
|
|
169990
170691
|
init_logger();
|
|
169991
170692
|
init_resolve_fallbacks();
|
|
169992
|
-
await init_storage();
|
|
169993
170693
|
|
|
169994
170694
|
// src/hooks/magic-context/command-handler.ts
|
|
169995
170695
|
init_shared();
|
|
@@ -170770,6 +171470,7 @@ function clearSessionTracking(sessionId) {
|
|
|
170770
171470
|
init_overflow_detection();
|
|
170771
171471
|
init_storage_meta_persisted();
|
|
170772
171472
|
init_logger();
|
|
171473
|
+
init_models_dev_cache();
|
|
170773
171474
|
await __promiseAll([
|
|
170774
171475
|
init_storage(),
|
|
170775
171476
|
init_compaction_marker_manager()
|
|
@@ -170872,6 +171573,7 @@ function getMessageRemovedInfo(properties) {
|
|
|
170872
171573
|
|
|
170873
171574
|
// src/hooks/magic-context/event-handler.ts
|
|
170874
171575
|
init_note_nudger();
|
|
171576
|
+
init_send_session_notification();
|
|
170875
171577
|
await init_read_session_chunk();
|
|
170876
171578
|
|
|
170877
171579
|
// src/hooks/magic-context/transform.ts
|
|
@@ -171728,6 +172430,7 @@ async function runCompartmentPhase(args) {
|
|
|
171728
172430
|
fallbackModels: args.fallbackModels,
|
|
171729
172431
|
directory: args.compartmentDirectory,
|
|
171730
172432
|
fallbackModelId: args.fallbackModelId,
|
|
172433
|
+
ensureProjectRegistered: args.ensureProjectRegistered,
|
|
171731
172434
|
getNotificationParams: args.getNotificationParams,
|
|
171732
172435
|
experimentalCompactionMarkers: args.experimentalCompactionMarkers,
|
|
171733
172436
|
experimentalUserMemories: args.experimentalUserMemories,
|
|
@@ -171757,6 +172460,7 @@ async function runCompartmentPhase(args) {
|
|
|
171757
172460
|
fallbackModels: args.fallbackModels,
|
|
171758
172461
|
directory: args.compartmentDirectory,
|
|
171759
172462
|
fallbackModelId: args.fallbackModelId,
|
|
172463
|
+
ensureProjectRegistered: args.ensureProjectRegistered,
|
|
171760
172464
|
getNotificationParams: args.getNotificationParams,
|
|
171761
172465
|
experimentalCompactionMarkers: args.experimentalCompactionMarkers,
|
|
171762
172466
|
experimentalUserMemories: args.experimentalUserMemories,
|
|
@@ -172627,6 +173331,9 @@ function applyContextNudge(messages, nudge, nudgePlacements, sessionId) {
|
|
|
172627
173331
|
}
|
|
172628
173332
|
}
|
|
172629
173333
|
|
|
173334
|
+
// src/hooks/magic-context/auto-search-runner.ts
|
|
173335
|
+
init_embedding();
|
|
173336
|
+
|
|
172630
173337
|
// src/features/magic-context/search.ts
|
|
172631
173338
|
init_logger();
|
|
172632
173339
|
init_memory();
|
|
@@ -172687,6 +173394,7 @@ async function getSemanticScores(args) {
|
|
|
172687
173394
|
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
172688
173395
|
const embeddings = await ensureMemoryEmbeddings({
|
|
172689
173396
|
db: args.db,
|
|
173397
|
+
projectIdentity: args.projectPath,
|
|
172690
173398
|
memories: args.memories,
|
|
172691
173399
|
existingEmbeddings: cachedEmbeddings
|
|
172692
173400
|
});
|
|
@@ -172962,6 +173670,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172962
173670
|
}
|
|
172963
173671
|
|
|
172964
173672
|
// src/hooks/magic-context/auto-search-runner.ts
|
|
173673
|
+
init_storage_meta_persisted();
|
|
172965
173674
|
init_logger();
|
|
172966
173675
|
|
|
172967
173676
|
// src/hooks/magic-context/auto-search-hint.ts
|
|
@@ -173043,7 +173752,6 @@ ${trimmedBody}…
|
|
|
173043
173752
|
}
|
|
173044
173753
|
|
|
173045
173754
|
// src/hooks/magic-context/auto-search-runner.ts
|
|
173046
|
-
var autoSearchByTurn = new Map;
|
|
173047
173755
|
var AUTO_SEARCH_TIMEOUT_MS = 3000;
|
|
173048
173756
|
async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
|
|
173049
173757
|
const controller = new AbortController;
|
|
@@ -173135,66 +173843,101 @@ async function runAutoSearchHint(args) {
|
|
|
173135
173843
|
if (!userMsg || typeof userMsg.info.id !== "string")
|
|
173136
173844
|
return;
|
|
173137
173845
|
const userMsgId = userMsg.info.id;
|
|
173138
|
-
const
|
|
173139
|
-
|
|
173140
|
-
|
|
173846
|
+
const existing = getAutoSearchHintDecisions(db, sessionId);
|
|
173847
|
+
const existingForMessage = existing.find((decision) => decision.messageId === userMsgId);
|
|
173848
|
+
if (existingForMessage) {
|
|
173849
|
+
if (existingForMessage.decision === "hint") {
|
|
173850
|
+
appendReminderToUserMessageById(messages, userMsgId, existingForMessage.text);
|
|
173851
|
+
}
|
|
173141
173852
|
return;
|
|
173142
173853
|
}
|
|
173854
|
+
const writeNoHintAndReconcile = (reason) => {
|
|
173855
|
+
const outcome2 = appendAutoSearchHintDecision(db, sessionId, {
|
|
173856
|
+
messageId: userMsgId,
|
|
173857
|
+
decision: "no-hint",
|
|
173858
|
+
reason
|
|
173859
|
+
});
|
|
173860
|
+
if (!outcome2.ok)
|
|
173861
|
+
return;
|
|
173862
|
+
if (outcome2.kind === "already-present" && outcome2.decision.decision === "hint") {
|
|
173863
|
+
appendReminderToUserMessageById(messages, userMsgId, outcome2.decision.text);
|
|
173864
|
+
}
|
|
173865
|
+
};
|
|
173143
173866
|
const rawPartsText = collectUserPromptParts(userMsg);
|
|
173144
173867
|
if (hasStackedAugmentation(rawPartsText)) {
|
|
173145
173868
|
sessionLog(sessionId, "auto-search: skipping — user message already carries augmentation/hint");
|
|
173146
|
-
|
|
173869
|
+
writeNoHintAndReconcile("stacked");
|
|
173147
173870
|
return;
|
|
173148
173871
|
}
|
|
173149
173872
|
const rawPrompt = extractUserPromptText(userMsg);
|
|
173150
173873
|
if (rawPrompt.length < options.minPromptChars) {
|
|
173151
|
-
|
|
173874
|
+
writeNoHintAndReconcile("too-short");
|
|
173152
173875
|
return;
|
|
173153
173876
|
}
|
|
173154
173877
|
let results;
|
|
173155
173878
|
try {
|
|
173879
|
+
if (options.directory) {
|
|
173880
|
+
await options.ensureProjectRegistered?.(options.directory, db);
|
|
173881
|
+
}
|
|
173882
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(options.projectPath);
|
|
173883
|
+
const memoryEnabled = embeddingSnapshot?.features.memoryEnabled ?? options.memoryEnabled;
|
|
173884
|
+
const embeddingEnabled = embeddingSnapshot ? embeddingSnapshot.enabled || embeddingSnapshot.gitCommitEnabled : options.embeddingEnabled;
|
|
173885
|
+
const gitCommitsEnabled = embeddingSnapshot?.gitCommitEnabled ?? options.gitCommitsEnabled ?? false;
|
|
173156
173886
|
const searchOptions = {
|
|
173157
173887
|
limit: 10,
|
|
173158
|
-
memoryEnabled
|
|
173159
|
-
embeddingEnabled
|
|
173160
|
-
gitCommitsEnabled
|
|
173888
|
+
memoryEnabled,
|
|
173889
|
+
embeddingEnabled,
|
|
173890
|
+
gitCommitsEnabled,
|
|
173891
|
+
embedQuery: async (text, signal) => {
|
|
173892
|
+
const result = await embedTextForProject(options.projectPath, text, signal);
|
|
173893
|
+
return result?.vector ?? null;
|
|
173894
|
+
},
|
|
173895
|
+
isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
|
|
173161
173896
|
visibleMemoryIds: options.visibleMemoryIds ?? null
|
|
173162
173897
|
};
|
|
173163
173898
|
results = await unifiedSearchWithTimeout(db, sessionId, options.projectPath, rawPrompt, searchOptions, AUTO_SEARCH_TIMEOUT_MS);
|
|
173164
173899
|
} catch (error51) {
|
|
173165
173900
|
log(`[auto-search] unified search failed for session ${sessionId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
173166
|
-
|
|
173901
|
+
writeNoHintAndReconcile("error");
|
|
173167
173902
|
return;
|
|
173168
173903
|
}
|
|
173169
173904
|
if (results === null) {
|
|
173170
173905
|
sessionLog(sessionId, `auto-search: timed out after ${AUTO_SEARCH_TIMEOUT_MS}ms, skipping hint for this turn`);
|
|
173171
|
-
|
|
173906
|
+
writeNoHintAndReconcile("timeout");
|
|
173172
173907
|
return;
|
|
173173
173908
|
}
|
|
173174
173909
|
if (results.length === 0) {
|
|
173175
|
-
|
|
173910
|
+
writeNoHintAndReconcile("empty");
|
|
173176
173911
|
return;
|
|
173177
173912
|
}
|
|
173178
173913
|
if (results[0].score < options.scoreThreshold) {
|
|
173179
173914
|
sessionLog(sessionId, `auto-search: top score ${results[0].score.toFixed(3)} below threshold ${options.scoreThreshold}`);
|
|
173180
|
-
|
|
173915
|
+
writeNoHintAndReconcile("below-threshold");
|
|
173181
173916
|
return;
|
|
173182
173917
|
}
|
|
173183
173918
|
const hintText = buildAutoSearchHint(results);
|
|
173184
173919
|
if (!hintText) {
|
|
173185
|
-
|
|
173920
|
+
writeNoHintAndReconcile("empty");
|
|
173186
173921
|
return;
|
|
173187
173922
|
}
|
|
173188
173923
|
const payload = `
|
|
173189
173924
|
|
|
173190
173925
|
${hintText}`;
|
|
173191
|
-
|
|
173192
|
-
|
|
173926
|
+
const outcome = appendAutoSearchHintDecision(db, sessionId, {
|
|
173927
|
+
messageId: userMsgId,
|
|
173928
|
+
decision: "hint",
|
|
173929
|
+
text: payload
|
|
173930
|
+
});
|
|
173931
|
+
if (!outcome.ok) {
|
|
173932
|
+
sessionLog(sessionId, `auto-search: CAS exhausted for ${userMsgId}; skipping wire append`);
|
|
173933
|
+
return;
|
|
173934
|
+
}
|
|
173935
|
+
if (outcome.decision.decision === "hint") {
|
|
173936
|
+
appendReminderToUserMessageById(messages, userMsgId, outcome.decision.text);
|
|
173937
|
+
}
|
|
173193
173938
|
sessionLog(sessionId, `auto-search: attached hint to ${userMsgId} (${results.length} fragments, top score ${results[0].score.toFixed(3)})`);
|
|
173194
173939
|
}
|
|
173195
|
-
function clearAutoSearchForSession(
|
|
173196
|
-
autoSearchByTurn.delete(sessionId);
|
|
173197
|
-
}
|
|
173940
|
+
function clearAutoSearchForSession(_sessionId) {}
|
|
173198
173941
|
|
|
173199
173942
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
173200
173943
|
await __promiseAll([
|
|
@@ -173474,7 +174217,7 @@ function isVisibleNoteReadPart(part) {
|
|
|
173474
174217
|
}
|
|
173475
174218
|
|
|
173476
174219
|
// src/hooks/magic-context/todo-view.ts
|
|
173477
|
-
import { createHash as
|
|
174220
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
173478
174221
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
173479
174222
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
173480
174223
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -173519,7 +174262,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
173519
174262
|
};
|
|
173520
174263
|
}
|
|
173521
174264
|
function computeSyntheticCallId(stateJson) {
|
|
173522
|
-
const hash2 =
|
|
174265
|
+
const hash2 = createHash8("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
173523
174266
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
173524
174267
|
}
|
|
173525
174268
|
function parseTodoState(stateJson) {
|
|
@@ -173793,15 +174536,13 @@ async function runPostTransformPhase(args) {
|
|
|
173793
174536
|
} else {
|
|
173794
174537
|
args.nudgePlacements.clear(args.sessionId);
|
|
173795
174538
|
}
|
|
173796
|
-
|
|
173797
|
-
|
|
173798
|
-
|
|
173799
|
-
|
|
173800
|
-
|
|
173801
|
-
|
|
173802
|
-
|
|
173803
|
-
} else {
|
|
173804
|
-
sessionLog(args.sessionId, `preserving sticky note nudge anchor to avoid cache bust: messageId=${stickyNoteNudge.messageId}`);
|
|
174539
|
+
if (args.fullFeatureMode) {
|
|
174540
|
+
for (const anchor of getNoteNudgeAnchors(args.db, args.sessionId)) {
|
|
174541
|
+
appendReminderToUserMessageById(args.messages, anchor.messageId, anchor.text);
|
|
174542
|
+
}
|
|
174543
|
+
for (const decision of getAutoSearchHintDecisions(args.db, args.sessionId)) {
|
|
174544
|
+
if (decision.decision === "hint") {
|
|
174545
|
+
appendReminderToUserMessageById(args.messages, decision.messageId, decision.text);
|
|
173805
174546
|
}
|
|
173806
174547
|
}
|
|
173807
174548
|
}
|
|
@@ -173811,8 +174552,13 @@ async function runPostTransformPhase(args) {
|
|
|
173811
174552
|
const noteInstruction = `
|
|
173812
174553
|
|
|
173813
174554
|
<instruction name="deferred_notes">${deferredNoteText}</instruction>`;
|
|
173814
|
-
const anchoredMessageId =
|
|
173815
|
-
markNoteNudgeDelivered(args.db, args.sessionId, noteInstruction, anchoredMessageId);
|
|
174555
|
+
const anchoredMessageId = findLastUserMessageId(args.messages);
|
|
174556
|
+
const outcome = markNoteNudgeDelivered(args.db, args.sessionId, noteInstruction, anchoredMessageId);
|
|
174557
|
+
if (anchoredMessageId && outcome.ok) {
|
|
174558
|
+
appendReminderToUserMessageById(args.messages, anchoredMessageId, noteInstruction);
|
|
174559
|
+
} else if (anchoredMessageId && !outcome.ok) {
|
|
174560
|
+
sessionLog(args.sessionId, `note-nudge delivery skipped wire append: ${outcome.kind}`);
|
|
174561
|
+
}
|
|
173816
174562
|
}
|
|
173817
174563
|
if (args.fullFeatureMode) {
|
|
173818
174564
|
const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
@@ -173903,10 +174649,9 @@ async function runPostTransformPhase(args) {
|
|
|
173903
174649
|
enabled: true,
|
|
173904
174650
|
scoreThreshold: args.autoSearch.scoreThreshold,
|
|
173905
174651
|
minPromptChars: args.autoSearch.minPromptChars,
|
|
174652
|
+
directory: args.autoSearch.directory ?? args.sessionDirectory,
|
|
173906
174653
|
projectPath: args.projectPath,
|
|
173907
|
-
|
|
173908
|
-
embeddingEnabled: args.autoSearch.embeddingEnabled,
|
|
173909
|
-
gitCommitsEnabled: args.autoSearch.gitCommitsEnabled,
|
|
174654
|
+
ensureProjectRegistered: args.autoSearch.ensureProjectRegistered,
|
|
173910
174655
|
visibleMemoryIds
|
|
173911
174656
|
}
|
|
173912
174657
|
});
|
|
@@ -173914,6 +174659,19 @@ async function runPostTransformPhase(args) {
|
|
|
173914
174659
|
sessionLog(args.sessionId, "auto-search runner failed:", error51);
|
|
173915
174660
|
}
|
|
173916
174661
|
}
|
|
174662
|
+
if (args.fullFeatureMode && isCacheBustingPass) {
|
|
174663
|
+
const visibleIds = new Set;
|
|
174664
|
+
for (const message of args.messages) {
|
|
174665
|
+
if (typeof message.info?.id === "string") {
|
|
174666
|
+
visibleIds.add(message.info.id);
|
|
174667
|
+
}
|
|
174668
|
+
}
|
|
174669
|
+
const prunedAnchors = pruneNoteNudgeAnchors(args.db, args.sessionId, visibleIds);
|
|
174670
|
+
const prunedDecisions = pruneAutoSearchHintDecisions(args.db, args.sessionId, visibleIds);
|
|
174671
|
+
if (prunedAnchors > 0 || prunedDecisions > 0) {
|
|
174672
|
+
sessionLog(args.sessionId, `sticky-injection GC: pruned ${prunedAnchors} note-nudge anchor(s), ${prunedDecisions} auto-search decision(s)`);
|
|
174673
|
+
}
|
|
174674
|
+
}
|
|
173917
174675
|
return { explicitMaterializedSuccessfully, deferredMaterializedSuccessfully };
|
|
173918
174676
|
}
|
|
173919
174677
|
|
|
@@ -174047,6 +174805,8 @@ function createTransform(deps) {
|
|
|
174047
174805
|
updateSessionMeta(db, sessionId, {
|
|
174048
174806
|
lastContextPercentage: 0,
|
|
174049
174807
|
lastInputTokens: 0,
|
|
174808
|
+
observedSafeInputTokens: 0,
|
|
174809
|
+
cacheAlertSent: false,
|
|
174050
174810
|
clearedReasoningThroughTag: 0
|
|
174051
174811
|
});
|
|
174052
174812
|
clearHistorianFailureState(db, sessionId);
|
|
@@ -174058,7 +174818,9 @@ function createTransform(deps) {
|
|
|
174058
174818
|
...sessionMeta,
|
|
174059
174819
|
lastContextPercentage: 0,
|
|
174060
174820
|
lastInputTokens: 0,
|
|
174061
|
-
clearedReasoningThroughTag: 0
|
|
174821
|
+
clearedReasoningThroughTag: 0,
|
|
174822
|
+
observedSafeInputTokens: 0,
|
|
174823
|
+
cacheAlertSent: false
|
|
174062
174824
|
};
|
|
174063
174825
|
}
|
|
174064
174826
|
}
|
|
@@ -174169,6 +174931,7 @@ function createTransform(deps) {
|
|
|
174169
174931
|
compressorMaxMergeDepth: deps.compressorMaxMergeDepth,
|
|
174170
174932
|
memoryEnabled: deps.memoryConfig?.enabled,
|
|
174171
174933
|
autoPromote: deps.memoryConfig?.autoPromote,
|
|
174934
|
+
ensureProjectRegistered: deps.ensureProjectRegistered,
|
|
174172
174935
|
preserveInjectionCacheUntilConsumed: true,
|
|
174173
174936
|
onCompartmentStatePublished: (sid) => {
|
|
174174
174937
|
deferredHistoryRefreshSessions.add(sid);
|
|
@@ -174353,6 +175116,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
174353
175116
|
compressorCooldownMs: deps.compressorCooldownMs,
|
|
174354
175117
|
memoryEnabled: deps.memoryConfig?.enabled,
|
|
174355
175118
|
autoPromote: deps.memoryConfig?.autoPromote,
|
|
175119
|
+
ensureProjectRegistered: deps.ensureProjectRegistered,
|
|
174356
175120
|
onCompartmentStatePublished: (sid) => {
|
|
174357
175121
|
deferredHistoryRefreshSessions.add(sid);
|
|
174358
175122
|
deferredMaterializationSessions.add(sid);
|
|
@@ -174567,6 +175331,9 @@ function truncateHistorianEmergencyError(error51) {
|
|
|
174567
175331
|
|
|
174568
175332
|
// src/hooks/magic-context/event-handler.ts
|
|
174569
175333
|
var CONTEXT_USAGE_TTL_MS = 60 * 60 * 1000;
|
|
175334
|
+
function formatTokens(value) {
|
|
175335
|
+
return value.toLocaleString();
|
|
175336
|
+
}
|
|
174570
175337
|
function evictExpiredUsageEntries(contextUsageMap) {
|
|
174571
175338
|
const now = Date.now();
|
|
174572
175339
|
for (const [sessionId, entry] of contextUsageMap) {
|
|
@@ -174587,12 +175354,16 @@ function cleanupRemovedMessageState(deps, sessionId, messageId) {
|
|
|
174587
175354
|
clearPersistedNudgePlacement(deps.db, sessionId);
|
|
174588
175355
|
}
|
|
174589
175356
|
sessionLog(sessionId, clearedNudgePlacement ? `event message.removed: cleared nudge anchor for ${messageId}` : `event message.removed: nudge anchor unchanged for ${messageId}`);
|
|
175357
|
+
const removedNoteNudgeAnchor = removeNoteNudgeAnchorByMessageId(deps.db, sessionId, messageId);
|
|
175358
|
+
const removedAutoSearchDecision = removeAutoSearchHintDecisionByMessageId(deps.db, sessionId, messageId);
|
|
174590
175359
|
const persistedNoteNudge = getPersistedNoteNudge(deps.db, sessionId);
|
|
174591
|
-
const
|
|
174592
|
-
if (
|
|
174593
|
-
|
|
175360
|
+
const clearedNoteNudgeTrigger = persistedNoteNudge.triggerMessageId === messageId;
|
|
175361
|
+
if (clearedNoteNudgeTrigger) {
|
|
175362
|
+
clearNoteNudgeTriggerOnly(deps.db, sessionId);
|
|
174594
175363
|
}
|
|
174595
|
-
|
|
175364
|
+
const clearedNoteNudge = removedNoteNudgeAnchor || clearedNoteNudgeTrigger;
|
|
175365
|
+
sessionLog(sessionId, clearedNoteNudge ? `event message.removed: pruned note nudge state for ${messageId}` : `event message.removed: note nudge state unchanged for ${messageId}`);
|
|
175366
|
+
sessionLog(sessionId, removedAutoSearchDecision ? `event message.removed: pruned auto-search decision for ${messageId}` : `event message.removed: auto-search decision unchanged for ${messageId}`);
|
|
174596
175367
|
const persistedStickyTurnReminder = getPersistedStickyTurnReminder(deps.db, sessionId);
|
|
174597
175368
|
const clearedStickyTurnReminder = persistedStickyTurnReminder?.messageId === messageId;
|
|
174598
175369
|
if (clearedStickyTurnReminder) {
|
|
@@ -174678,9 +175449,11 @@ function createEventHandler2(deps) {
|
|
|
174678
175449
|
} else {
|
|
174679
175450
|
clearMessageTokensCache(info.sessionID);
|
|
174680
175451
|
}
|
|
175452
|
+
let messageHadOverflowError = false;
|
|
174681
175453
|
if (info.error !== undefined && info.error !== null) {
|
|
174682
175454
|
const detection = detectOverflow(info.error);
|
|
174683
175455
|
if (detection.isOverflow) {
|
|
175456
|
+
messageHadOverflowError = true;
|
|
174684
175457
|
try {
|
|
174685
175458
|
const metaForOverflow = getOrCreateSessionMeta(deps.db, info.sessionID);
|
|
174686
175459
|
if (metaForOverflow.isSubagent) {
|
|
@@ -174723,12 +175496,33 @@ function createEventHandler2(deps) {
|
|
|
174723
175496
|
}
|
|
174724
175497
|
if (hasUsageTokens) {
|
|
174725
175498
|
const totalInputTokens = (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0);
|
|
174726
|
-
|
|
175499
|
+
let contextLimit = resolveContextLimit(info.providerID, info.modelID, {
|
|
174727
175500
|
db: deps.db,
|
|
174728
175501
|
sessionID: info.sessionID
|
|
174729
175502
|
});
|
|
174730
|
-
|
|
175503
|
+
let percentage = contextLimit > 0 ? totalInputTokens / contextLimit * 100 : 0;
|
|
174731
175504
|
sessionLog(info.sessionID, `event message.updated: totalInputTokens=${totalInputTokens} contextLimit=${contextLimit} percentage=${percentage.toFixed(1)}%`);
|
|
175505
|
+
const sessionMeta = getOrCreateSessionMeta(deps.db, info.sessionID);
|
|
175506
|
+
const observedSafeInputTokens = sessionMeta.observedSafeInputTokens ?? 0;
|
|
175507
|
+
if (percentage > 100 && observedSafeInputTokens > 0 && totalInputTokens <= observedSafeInputTokens * 2) {
|
|
175508
|
+
const oldLimit = contextLimit;
|
|
175509
|
+
if (deps.client) {
|
|
175510
|
+
await refreshModelLimitsFromApi(deps.client);
|
|
175511
|
+
contextLimit = resolveContextLimit(info.providerID, info.modelID, {
|
|
175512
|
+
db: deps.db,
|
|
175513
|
+
sessionID: info.sessionID
|
|
175514
|
+
});
|
|
175515
|
+
if (contextLimit >= totalInputTokens) {
|
|
175516
|
+
percentage = totalInputTokens / contextLimit * 100;
|
|
175517
|
+
sessionLog(info.sessionID, `models-dev-cache: regression recovered for ${info.providerID}/${info.modelID} via refresh (was=${oldLimit}, now=${contextLimit})`);
|
|
175518
|
+
}
|
|
175519
|
+
}
|
|
175520
|
+
if (contextLimit < totalInputTokens && !sessionMeta.cacheAlertSent) {
|
|
175521
|
+
updates.cacheAlertSent = true;
|
|
175522
|
+
const safeTokens = Math.max(observedSafeInputTokens, totalInputTokens);
|
|
175523
|
+
await sendIgnoredMessage(deps.client, info.sessionID, `⚠️ Magic Context: OpenCode reports a context limit of ${formatTokens(contextLimit)} tokens for ${info.providerID}/${info.modelID} but you've successfully sent ${formatTokens(safeTokens)} tokens in this session — the cached limit looks wrong. Restart OpenCode if you suspect this is incorrect.`, deps.getNotificationParams?.(info.sessionID) ?? {});
|
|
175524
|
+
}
|
|
175525
|
+
}
|
|
174732
175526
|
deps.contextUsageMap.set(info.sessionID, {
|
|
174733
175527
|
usage: {
|
|
174734
175528
|
percentage,
|
|
@@ -174739,12 +175533,14 @@ function createEventHandler2(deps) {
|
|
|
174739
175533
|
});
|
|
174740
175534
|
updates.lastContextPercentage = percentage;
|
|
174741
175535
|
updates.lastInputTokens = totalInputTokens;
|
|
175536
|
+
if (!messageHadOverflowError) {
|
|
175537
|
+
updates.observedSafeInputTokens = Math.max(observedSafeInputTokens, totalInputTokens);
|
|
175538
|
+
}
|
|
174742
175539
|
const historianFailureState = getHistorianFailureState(deps.db, info.sessionID);
|
|
174743
175540
|
if (historianFailureState.failureCount > 0 && percentage < 90) {
|
|
174744
175541
|
clearHistorianFailureState(deps.db, info.sessionID);
|
|
174745
175542
|
sessionLog(info.sessionID, `event message.updated: cleared historian failure state at ${percentage.toFixed(1)}%`);
|
|
174746
175543
|
}
|
|
174747
|
-
const sessionMeta = getOrCreateSessionMeta(deps.db, info.sessionID);
|
|
174748
175544
|
const previousPercentage = sessionMeta.lastContextPercentage;
|
|
174749
175545
|
if (!sessionMeta.isSubagent) {
|
|
174750
175546
|
const effectiveExecuteThreshold = resolveExecuteThreshold(deps.config.execute_threshold_percentage ?? 65, modelKey, 65, {
|
|
@@ -174789,10 +175585,6 @@ function createEventHandler2(deps) {
|
|
|
174789
175585
|
deps.nudgePlacements.clear(info.sessionID, { persist: false });
|
|
174790
175586
|
sessionLog(info.sessionID, "event message.removed: cleared in-memory nudge placement cache");
|
|
174791
175587
|
}
|
|
174792
|
-
if (cleanup.clearedNoteNudge) {
|
|
174793
|
-
clearNoteNudgeState(deps.db, info.sessionID, { persist: false });
|
|
174794
|
-
sessionLog(info.sessionID, "event message.removed: cleared in-memory note nudge state");
|
|
174795
|
-
}
|
|
174796
175588
|
const markerState = getPersistedCompactionMarkerState(deps.db, info.sessionID);
|
|
174797
175589
|
if (markerState && (markerState.boundaryMessageId === info.messageID || markerState.summaryMessageId === info.messageID)) {
|
|
174798
175590
|
removeCompactionMarkerForSession(deps.db, info.sessionID);
|
|
@@ -175017,10 +175809,11 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
|
|
|
175017
175809
|
await init_read_session_db();
|
|
175018
175810
|
|
|
175019
175811
|
// src/hooks/magic-context/text-complete.ts
|
|
175020
|
-
var
|
|
175812
|
+
var LEADING_TAG_PREFIX_REGEX = /^(\u00a7\d+\u00a7\s*)+/;
|
|
175813
|
+
var SECTION_CHAR_REGEX = /\u00a7/g;
|
|
175021
175814
|
function createTextCompleteHandler() {
|
|
175022
175815
|
return async (_input, output) => {
|
|
175023
|
-
output.text = output.text.replace(
|
|
175816
|
+
output.text = output.text.replace(LEADING_TAG_PREFIX_REGEX, "").replace(SECTION_CHAR_REGEX, "");
|
|
175024
175817
|
};
|
|
175025
175818
|
}
|
|
175026
175819
|
|
|
@@ -175155,7 +175948,9 @@ function createEventHook(args) {
|
|
|
175155
175948
|
clearHistorianFailureState(args.db, assistantInfo.sessionID);
|
|
175156
175949
|
clearPersistedReasoningWatermark(args.db, assistantInfo.sessionID);
|
|
175157
175950
|
updateSessionMeta(args.db, assistantInfo.sessionID, {
|
|
175158
|
-
clearedReasoningThroughTag: 0
|
|
175951
|
+
clearedReasoningThroughTag: 0,
|
|
175952
|
+
observedSafeInputTokens: 0,
|
|
175953
|
+
cacheAlertSent: false
|
|
175159
175954
|
});
|
|
175160
175955
|
}
|
|
175161
175956
|
}
|
|
@@ -175181,7 +175976,7 @@ function createEventHook(args) {
|
|
|
175181
175976
|
args.deferredMaterializationSessions.delete(sessionId);
|
|
175182
175977
|
args.lastHeuristicsTurnId.delete(sessionId);
|
|
175183
175978
|
args.commitSeenLastPass?.delete(sessionId);
|
|
175184
|
-
|
|
175979
|
+
resetNoteNudgeCooldownOnly(sessionId);
|
|
175185
175980
|
clearAutoSearchForSession(sessionId);
|
|
175186
175981
|
clearSidebarSnapshotCache(sessionId);
|
|
175187
175982
|
clearSessionTracking(sessionId);
|
|
@@ -175229,7 +176024,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
175229
176024
|
}
|
|
175230
176025
|
}
|
|
175231
176026
|
if (typedInput.tool === "ctx_note") {
|
|
175232
|
-
|
|
176027
|
+
clearNoteNudgeTriggerAndCooldown(args.db, typedInput.sessionID);
|
|
175233
176028
|
}
|
|
175234
176029
|
args.toolUsageSinceUserTurn.set(typedInput.sessionID, turnUsage + 1);
|
|
175235
176030
|
};
|
|
@@ -175239,7 +176034,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
175239
176034
|
init_send_session_notification();
|
|
175240
176035
|
|
|
175241
176036
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
175242
|
-
import { createHash as
|
|
176037
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
175243
176038
|
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "node:fs";
|
|
175244
176039
|
import { join as join25 } from "node:path";
|
|
175245
176040
|
|
|
@@ -175620,7 +176415,7 @@ ${items}
|
|
|
175620
176415
|
`);
|
|
175621
176416
|
if (systemContent.length === 0)
|
|
175622
176417
|
return;
|
|
175623
|
-
const currentHash =
|
|
176418
|
+
const currentHash = createHash9("md5").update(systemContent).digest("hex");
|
|
175624
176419
|
if (!sessionMetaEarly) {
|
|
175625
176420
|
return;
|
|
175626
176421
|
}
|
|
@@ -175772,6 +176567,7 @@ function createMagicContextHook(deps) {
|
|
|
175772
176567
|
injectionBudgetTokens: deps.config.memory.injection_budget_tokens,
|
|
175773
176568
|
autoPromote: deps.config.memory.auto_promote ?? true
|
|
175774
176569
|
} : undefined,
|
|
176570
|
+
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
175775
176571
|
getHistorianChunkTokens,
|
|
175776
176572
|
historyBudgetPercentage: deps.config.history_budget_percentage,
|
|
175777
176573
|
executeThresholdPercentage: deps.config.execute_threshold_percentage,
|
|
@@ -175801,9 +176597,8 @@ function createMagicContextHook(deps) {
|
|
|
175801
176597
|
enabled: true,
|
|
175802
176598
|
scoreThreshold: deps.config.experimental.auto_search.score_threshold,
|
|
175803
176599
|
minPromptChars: deps.config.experimental.auto_search.min_prompt_chars,
|
|
175804
|
-
|
|
175805
|
-
|
|
175806
|
-
gitCommitsEnabled: deps.config.experimental?.git_commit_indexing?.enabled === true
|
|
176600
|
+
directory: deps.directory,
|
|
176601
|
+
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
|
|
175807
176602
|
} : undefined,
|
|
175808
176603
|
cavemanTextCompression: ctxReduceEnabled === false && deps.config.experimental?.caveman_text_compression?.enabled === true ? {
|
|
175809
176604
|
enabled: true,
|
|
@@ -175816,6 +176611,8 @@ function createMagicContextHook(deps) {
|
|
|
175816
176611
|
config: deps.config,
|
|
175817
176612
|
tagger: deps.tagger,
|
|
175818
176613
|
db,
|
|
176614
|
+
client: deps.client,
|
|
176615
|
+
getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
175819
176616
|
nudgePlacements,
|
|
175820
176617
|
onSessionCacheInvalidated: (sessionId) => {
|
|
175821
176618
|
clearInjectionCache(sessionId);
|
|
@@ -175901,6 +176698,7 @@ function createMagicContextHook(deps) {
|
|
|
175901
176698
|
historianTwoPass: deps.config.historian?.two_pass === true,
|
|
175902
176699
|
memoryEnabled: deps.config.memory?.enabled,
|
|
175903
176700
|
autoPromote: deps.config.memory?.auto_promote ?? true,
|
|
176701
|
+
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
175904
176702
|
onCompartmentStatePublished: (sid) => {
|
|
175905
176703
|
historyRefreshSessions.add(sid);
|
|
175906
176704
|
pendingMaterializationSessions.add(sid);
|
|
@@ -176333,6 +177131,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
|
|
|
176333
177131
|
sessionId,
|
|
176334
177132
|
usagePercentage: 0,
|
|
176335
177133
|
inputTokens: 0,
|
|
177134
|
+
contextLimit: 0,
|
|
176336
177135
|
systemPromptTokens: 0,
|
|
176337
177136
|
compartmentCount: 0,
|
|
176338
177137
|
factCount: 0,
|
|
@@ -176469,6 +177268,7 @@ ${c.content}
|
|
|
176469
177268
|
measuredToolDefTokens = getMeasuredToolDefinitionTokens(model.providerID, model.modelID, agent) ?? 0;
|
|
176470
177269
|
}
|
|
176471
177270
|
}
|
|
177271
|
+
const contextLimit = activeProviderID && activeModelID ? resolveContextLimit(activeProviderID, activeModelID, { db, sessionID: sessionId }) : 0;
|
|
176472
177272
|
const calibration = resolveModelCalibration(activeProviderID, activeModelID);
|
|
176473
177273
|
const calibrated = calibrateBuckets({
|
|
176474
177274
|
inputTokens,
|
|
@@ -176485,6 +177285,7 @@ ${c.content}
|
|
|
176485
177285
|
sessionId,
|
|
176486
177286
|
usagePercentage,
|
|
176487
177287
|
inputTokens,
|
|
177288
|
+
contextLimit,
|
|
176488
177289
|
systemPromptTokens: calibrated.systemTokens,
|
|
176489
177290
|
compartmentCount,
|
|
176490
177291
|
factCount,
|
|
@@ -176562,7 +177363,7 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config2, liveSess
|
|
|
176562
177363
|
const ops = db.prepare("SELECT tag_id, operation FROM pending_ops WHERE session_id = ?").all(sessionId);
|
|
176563
177364
|
detail.pendingOps = ops.map((o) => ({ tagId: o.tag_id, operation: o.operation }));
|
|
176564
177365
|
} catch {}
|
|
176565
|
-
const contextLimitForTokens = base.usagePercentage > 0 ? Math.round(base.inputTokens / (base.usagePercentage / 100)) : 0;
|
|
177366
|
+
const contextLimitForTokens = base.contextLimit > 0 ? base.contextLimit : base.usagePercentage > 0 ? Math.round(base.inputTokens / (base.usagePercentage / 100)) : 0;
|
|
176566
177367
|
if (config2) {
|
|
176567
177368
|
const pctCfg = config2.execute_threshold_percentage;
|
|
176568
177369
|
const tokensCfg = config2.execute_threshold_tokens;
|
|
@@ -176588,7 +177389,9 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config2, liveSess
|
|
|
176588
177389
|
detail.historyBudgetPercentage = config2.history_budget_percentage;
|
|
176589
177390
|
}
|
|
176590
177391
|
}
|
|
176591
|
-
if (base.
|
|
177392
|
+
if (base.contextLimit > 0) {
|
|
177393
|
+
detail.contextLimit = base.contextLimit;
|
|
177394
|
+
} else if (base.usagePercentage > 0) {
|
|
176592
177395
|
detail.contextLimit = Math.round(base.inputTokens / (base.usagePercentage / 100));
|
|
176593
177396
|
}
|
|
176594
177397
|
detail.cacheTtlMs = parseTtlString(detail.cacheTtl);
|
|
@@ -176688,9 +177491,6 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
176688
177491
|
}
|
|
176689
177492
|
|
|
176690
177493
|
// src/plugin/tool-registry.ts
|
|
176691
|
-
init_magic_context();
|
|
176692
|
-
init_memory();
|
|
176693
|
-
init_embedding();
|
|
176694
177494
|
init_project_identity();
|
|
176695
177495
|
await init_storage();
|
|
176696
177496
|
|
|
@@ -176838,21 +177638,17 @@ function filterByCategory(memories, category) {
|
|
|
176838
177638
|
return memories.filter((memory) => memory.category === category);
|
|
176839
177639
|
}
|
|
176840
177640
|
function queueMemoryEmbedding(args) {
|
|
176841
|
-
|
|
177641
|
+
const snapshot = getProjectEmbeddingSnapshot(args.projectPath);
|
|
177642
|
+
if (!snapshot?.enabled) {
|
|
176842
177643
|
return;
|
|
176843
177644
|
}
|
|
176844
177645
|
(async () => {
|
|
176845
|
-
const
|
|
176846
|
-
if (!
|
|
177646
|
+
const result = await embedTextForProject(args.projectPath, args.content);
|
|
177647
|
+
if (!result) {
|
|
176847
177648
|
sessionLog(args.sessionId, `memory embedding skipped for memory ${args.memoryId}: provider unavailable or embedding generation failed.`);
|
|
176848
177649
|
return;
|
|
176849
177650
|
}
|
|
176850
|
-
|
|
176851
|
-
if (modelId === "off") {
|
|
176852
|
-
sessionLog(args.sessionId, `memory embedding skipped for memory ${args.memoryId}: embedding provider is off.`);
|
|
176853
|
-
return;
|
|
176854
|
-
}
|
|
176855
|
-
saveEmbedding(args.deps.db, args.memoryId, embedding2, modelId);
|
|
177651
|
+
saveEmbedding(args.deps.db, args.memoryId, result.vector, result.modelId);
|
|
176856
177652
|
sessionLog(args.sessionId, `proactively embedded memory ${args.memoryId}.`);
|
|
176857
177653
|
})().catch((error51) => {
|
|
176858
177654
|
sessionLog(args.sessionId, `memory embedding failed for memory ${args.memoryId}:`, error51);
|
|
@@ -176888,13 +177684,15 @@ function createCtxMemoryTool(deps) {
|
|
|
176888
177684
|
reason: tool2.schema.string().optional().describe("Archive reason (optional for archive)")
|
|
176889
177685
|
},
|
|
176890
177686
|
async execute(args, toolContext) {
|
|
176891
|
-
if (!deps.memoryEnabled) {
|
|
176892
|
-
return getDisabledMessage();
|
|
176893
|
-
}
|
|
176894
177687
|
if (toolContext.agent !== DREAMER_AGENT && !allowedActions.includes(args.action)) {
|
|
176895
177688
|
return `Error: Action '${args.action}' is not allowed in this context.`;
|
|
176896
177689
|
}
|
|
176897
177690
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
177691
|
+
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
177692
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
177693
|
+
if (embeddingSnapshot ? !embeddingSnapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
177694
|
+
return getDisabledMessage();
|
|
177695
|
+
}
|
|
176898
177696
|
if (args.action === "write") {
|
|
176899
177697
|
const content = args.content?.trim();
|
|
176900
177698
|
if (!content) {
|
|
@@ -176923,6 +177721,7 @@ function createCtxMemoryTool(deps) {
|
|
|
176923
177721
|
queueMemoryEmbedding({
|
|
176924
177722
|
deps,
|
|
176925
177723
|
sessionId: toolContext.sessionID,
|
|
177724
|
+
projectPath,
|
|
176926
177725
|
memoryId: memory.id,
|
|
176927
177726
|
content
|
|
176928
177727
|
});
|
|
@@ -176968,6 +177767,7 @@ function createCtxMemoryTool(deps) {
|
|
|
176968
177767
|
queueMemoryEmbedding({
|
|
176969
177768
|
deps,
|
|
176970
177769
|
sessionId: toolContext.sessionID,
|
|
177770
|
+
projectPath,
|
|
176971
177771
|
memoryId: memory.id,
|
|
176972
177772
|
content
|
|
176973
177773
|
});
|
|
@@ -177041,6 +177841,7 @@ function createCtxMemoryTool(deps) {
|
|
|
177041
177841
|
queueMemoryEmbedding({
|
|
177042
177842
|
deps,
|
|
177043
177843
|
sessionId: toolContext.sessionID,
|
|
177844
|
+
projectPath,
|
|
177044
177845
|
memoryId: canonicalMemory.id,
|
|
177045
177846
|
content
|
|
177046
177847
|
});
|
|
@@ -177416,6 +178217,7 @@ var CTX_SEARCH_DESCRIPTION = [
|
|
|
177416
178217
|
var DEFAULT_CTX_SEARCH_LIMIT = 10;
|
|
177417
178218
|
// src/tools/ctx-search/tools.ts
|
|
177418
178219
|
init_compartment_storage();
|
|
178220
|
+
init_embedding();
|
|
177419
178221
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
177420
178222
|
await init_inject_compartments();
|
|
177421
178223
|
var VALID_SOURCES = new Set(["memory", "message", "git_commit"]);
|
|
@@ -177514,13 +178316,23 @@ function createCtxSearchTool(deps) {
|
|
|
177514
178316
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, toolContext.sessionID);
|
|
177515
178317
|
const visibleMemoryIds = getVisibleMemoryIds(deps.db, toolContext.sessionID);
|
|
177516
178318
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
178319
|
+
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
178320
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
178321
|
+
const memoryEnabled = embeddingSnapshot?.features.memoryEnabled ?? deps.memoryEnabled;
|
|
178322
|
+
const embeddingEnabled = embeddingSnapshot ? embeddingSnapshot.enabled || embeddingSnapshot.gitCommitEnabled : deps.embeddingEnabled;
|
|
178323
|
+
const gitCommitsEnabled = embeddingSnapshot?.gitCommitEnabled ?? deps.gitCommitsEnabled ?? false;
|
|
177517
178324
|
const results = await unifiedSearch(deps.db, toolContext.sessionID, projectPath, query, {
|
|
177518
178325
|
limit: normalizeLimit3(args.limit),
|
|
177519
|
-
memoryEnabled
|
|
177520
|
-
embeddingEnabled
|
|
178326
|
+
memoryEnabled,
|
|
178327
|
+
embeddingEnabled,
|
|
178328
|
+
embedQuery: async (text, signal) => {
|
|
178329
|
+
const result = await embedTextForProject(projectPath, text, signal);
|
|
178330
|
+
return result?.vector ?? null;
|
|
178331
|
+
},
|
|
178332
|
+
isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
|
|
177521
178333
|
readMessages: deps.readMessages,
|
|
177522
178334
|
maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
|
|
177523
|
-
gitCommitsEnabled
|
|
178335
|
+
gitCommitsEnabled,
|
|
177524
178336
|
sources: normalizeSources(args.sources),
|
|
177525
178337
|
visibleMemoryIds
|
|
177526
178338
|
});
|
|
@@ -177563,10 +178375,6 @@ function normalizeToolArgSchemas(toolDefinition) {
|
|
|
177563
178375
|
// src/plugin/tool-registry.ts
|
|
177564
178376
|
function createToolRegistry(args) {
|
|
177565
178377
|
const { ctx, pluginConfig } = args;
|
|
177566
|
-
const embeddingConfig2 = pluginConfig.embedding ?? {
|
|
177567
|
-
provider: "local",
|
|
177568
|
-
model: DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
177569
|
-
};
|
|
177570
178378
|
if (pluginConfig.enabled !== true) {
|
|
177571
178379
|
return {};
|
|
177572
178380
|
}
|
|
@@ -177583,18 +178391,7 @@ function createToolRegistry(args) {
|
|
|
177583
178391
|
console.warn(`[magic-context] persistent storage unavailable; disabling magic-context tools${reason ? `: ${reason}` : ""}`);
|
|
177584
178392
|
return {};
|
|
177585
178393
|
}
|
|
177586
|
-
|
|
177587
|
-
initializeEmbedding(embeddingConfig2);
|
|
177588
|
-
const launchProjectPath = resolveProjectIdentity(ctx.directory);
|
|
177589
|
-
if (memoryEnabled) {
|
|
177590
|
-
const currentModelId = getEmbeddingModelId();
|
|
177591
|
-
const storedModelId = getStoredModelId(db, launchProjectPath);
|
|
177592
|
-
const hasEmbeddings = db.prepare("SELECT 1 FROM memory_embeddings me JOIN memories m ON me.memory_id = m.id WHERE m.project_path = ? LIMIT 1").get(launchProjectPath) !== null;
|
|
177593
|
-
if (hasEmbeddings && storedModelId !== currentModelId) {
|
|
177594
|
-
clearEmbeddingsForProject(db, launchProjectPath);
|
|
177595
|
-
console.warn(`[magic-context] embedding model changed from ${storedModelId} to ${currentModelId}; cleared embeddings for project ${launchProjectPath}`);
|
|
177596
|
-
}
|
|
177597
|
-
}
|
|
178394
|
+
ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db);
|
|
177598
178395
|
const resolveProjectPath2 = (directory) => resolveProjectIdentity(directory);
|
|
177599
178396
|
const ctxReduceEnabled = pluginConfig.ctx_reduce_enabled !== false;
|
|
177600
178397
|
const allTools = {
|
|
@@ -177611,19 +178408,14 @@ function createToolRegistry(args) {
|
|
|
177611
178408
|
...createCtxSearchTools({
|
|
177612
178409
|
db,
|
|
177613
178410
|
resolveProjectPath: resolveProjectPath2,
|
|
177614
|
-
|
|
177615
|
-
embeddingEnabled: embeddingConfig2.provider !== "off",
|
|
177616
|
-
gitCommitsEnabled: pluginConfig.experimental?.git_commit_indexing?.enabled === true
|
|
178411
|
+
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
|
|
177617
178412
|
}),
|
|
177618
|
-
...
|
|
177619
|
-
|
|
177620
|
-
|
|
177621
|
-
|
|
177622
|
-
|
|
177623
|
-
|
|
177624
|
-
allowedActions: ["write", "delete"]
|
|
177625
|
-
})
|
|
177626
|
-
} : {}
|
|
178413
|
+
...createCtxMemoryTools({
|
|
178414
|
+
db,
|
|
178415
|
+
resolveProjectPath: resolveProjectPath2,
|
|
178416
|
+
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
178417
|
+
allowedActions: ["write", "delete"]
|
|
178418
|
+
})
|
|
177627
178419
|
};
|
|
177628
178420
|
for (const toolDefinition of Object.values(allTools)) {
|
|
177629
178421
|
normalizeToolArgSchemas(toolDefinition);
|
|
@@ -177649,14 +178441,14 @@ import {
|
|
|
177649
178441
|
writeFileSync as writeFileSync7
|
|
177650
178442
|
} from "node:fs";
|
|
177651
178443
|
import { createServer } from "node:http";
|
|
177652
|
-
import { dirname as
|
|
178444
|
+
import { dirname as dirname8 } from "node:path";
|
|
177653
178445
|
|
|
177654
178446
|
// src/shared/rpc-utils.ts
|
|
177655
|
-
import { createHash as
|
|
178447
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
177656
178448
|
import { join as join26 } from "node:path";
|
|
177657
178449
|
function projectHash(directory) {
|
|
177658
178450
|
const normalized = directory.replace(/\/+$/, "");
|
|
177659
|
-
return
|
|
178451
|
+
return createHash10("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
177660
178452
|
}
|
|
177661
178453
|
function rpcPortDir(storageDir, directory) {
|
|
177662
178454
|
return join26(storageDir, "rpc", projectHash(directory));
|
|
@@ -177736,7 +178528,7 @@ class MagicContextRpcServer {
|
|
|
177736
178528
|
this.server = server;
|
|
177737
178529
|
try {
|
|
177738
178530
|
this.warnIfOtherLiveInstance();
|
|
177739
|
-
const dir =
|
|
178531
|
+
const dir = dirname8(this.portFilePath);
|
|
177740
178532
|
mkdirSync8(dir, { recursive: true });
|
|
177741
178533
|
const tmpPath = `${this.portFilePath}.tmp`;
|
|
177742
178534
|
writeFileSync7(tmpPath, JSON.stringify({
|
|
@@ -177884,8 +178676,9 @@ var plugin = async (ctx) => {
|
|
|
177884
178676
|
});
|
|
177885
178677
|
const storageDir = getMagicContextStorageDir();
|
|
177886
178678
|
if (pluginConfig.enabled) {
|
|
177887
|
-
|
|
178679
|
+
const timerRegistration = {
|
|
177888
178680
|
directory: ctx.directory,
|
|
178681
|
+
projectIdentity: resolveProjectIdentity(ctx.directory),
|
|
177889
178682
|
client: ctx.client,
|
|
177890
178683
|
dreamerConfig: pluginConfig.dreamer,
|
|
177891
178684
|
embeddingConfig: pluginConfig.embedding,
|
|
@@ -177903,8 +178696,10 @@ var plugin = async (ctx) => {
|
|
|
177903
178696
|
enabled: true,
|
|
177904
178697
|
since_days: pluginConfig.experimental.git_commit_indexing.since_days,
|
|
177905
178698
|
max_commits: pluginConfig.experimental.git_commit_indexing.max_commits
|
|
177906
|
-
} : undefined
|
|
177907
|
-
|
|
178699
|
+
} : undefined,
|
|
178700
|
+
ensureRegistered: ensureProjectRegisteredFromOpenCodeDirectory
|
|
178701
|
+
};
|
|
178702
|
+
await startDreamScheduleTimer(timerRegistration);
|
|
177908
178703
|
const rpcServer = new MagicContextRpcServer(storageDir, ctx.directory);
|
|
177909
178704
|
registerRpcHandlers(rpcServer, {
|
|
177910
178705
|
directory: ctx.directory,
|
|
@@ -177916,9 +178711,6 @@ var plugin = async (ctx) => {
|
|
|
177916
178711
|
log(`[magic-context] RPC server failed to start: ${err}`);
|
|
177917
178712
|
});
|
|
177918
178713
|
refreshModelLimitsFromApi(ctx.client);
|
|
177919
|
-
setInterval(() => {
|
|
177920
|
-
refreshModelLimitsFromApi(ctx.client);
|
|
177921
|
-
}, 60 * 60 * 1000);
|
|
177922
178714
|
}
|
|
177923
178715
|
if (conflictResult?.hasConflict) {
|
|
177924
178716
|
sendConflictWarning(ctx.client, ctx.directory, conflictResult);
|