@cortexkit/opencode-magic-context 0.30.6 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/agents/magic-context-prompt.d.ts +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +5 -10
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/builtin-commands/commands.d.ts.map +1 -1
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/open-opencode-db.d.ts +3 -1
- package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity.d.ts +18 -5
- package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +13 -2
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/session-project-backfill.d.ts +31 -0
- package/dist/features/magic-context/session-project-backfill.d.ts.map +1 -0
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +26 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage-schema-helpers.d.ts +1 -1
- package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
- package/dist/features/magic-context/storage-v22-backfill-failures.d.ts +3 -1
- package/dist/features/magic-context/storage-v22-backfill-failures.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/transform-decision-log.d.ts +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/features/magic-context/v22-deferred-backfill.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +11 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.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-types.d.ts +10 -2
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts +2 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +11 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -3
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +0 -2
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +0 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +2 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts +16 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +2 -3
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +3 -4
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +3 -3
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +8 -12
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts +13 -0
- package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2021 -660
- package/dist/plugin/hooks/create-session-hooks.d.ts +0 -1
- 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/announcement.d.ts +1 -1
- package/dist/shared/announcement.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +1 -2
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/tag-transcript.d.ts +3 -4
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/tools/ctx-search/constants.d.ts +1 -1
- package/dist/tools/ctx-search/constants.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +1 -1
- 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 +1 -1
- package/src/shared/announcement.ts +5 -4
- package/src/shared/rpc-types.ts +1 -2
- package/src/shared/tag-transcript.ts +3 -4
- package/src/tui/data/context-db.ts +0 -1
- package/src/tui/index.tsx +9 -1
- package/src/tui/slots/sidebar-content.tsx +6 -7
package/dist/index.js
CHANGED
|
@@ -15372,7 +15372,6 @@ var init_magic_context = __esm(() => {
|
|
|
15372
15372
|
enabled: exports_external.boolean().default(true).describe("Enable magic context (default: true)"),
|
|
15373
15373
|
auto_update: exports_external.boolean().optional().describe("Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates."),
|
|
15374
15374
|
language: exports_external.string().trim().toLowerCase().refine((s) => isValidLanguageCode(s), 'language must be a 2-letter ISO 639-1 code (e.g. "tr", "es", "de")').optional().describe("Output language for Magic Context's generated content and guidance, as a " + '2-letter ISO 639-1 code (e.g. "tr", "es", "de", "ja", "pt"). When set, the ' + "historian, dreamer, sidekick, and the agent-guidance block instruct the model to " + "write its PROSE in this language while keeping all structural tokens (XML tags, " + "the five memory category names, code identifiers, file paths) in English. " + "USER-LEVEL ONLY (ignored in project config for security). Unset = today's " + "behavior (model mirrors the conversation; English scaffolding). Changing it " + "triggers one cache re-materialization; existing compartments/memories keep their " + "original language until naturally rewritten."),
|
|
15375
|
-
ctx_reduce_enabled: exports_external.boolean().default(true).describe("When false, ctx_reduce tool is hidden, all nudges disabled, and prompt guidance about ctx_reduce stripped. Heuristic cleanup, compartments, memory, and other features still work. (default: true)"),
|
|
15376
15375
|
historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
|
|
15377
15376
|
dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
|
|
15378
15377
|
cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m").describe('Cache TTL: string (e.g. "5m") or per-model object ({ default: "5m", "model-id": "10m" })'),
|
|
@@ -15411,9 +15410,9 @@ var init_magic_context = __esm(() => {
|
|
|
15411
15410
|
keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
|
|
15412
15411
|
smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
|
|
15413
15412
|
caveman_text_compression: exports_external.object({
|
|
15414
|
-
enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text.
|
|
15413
|
+
enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Active for primary sessions when enabled; never for subagents. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
|
|
15415
15414
|
min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
|
|
15416
|
-
}).default({ enabled: false, min_chars: 500 }).describe("Age-tier caveman compression for long user/assistant text parts.
|
|
15415
|
+
}).default({ enabled: false, min_chars: 500 }).describe("Age-tier caveman compression for long user/assistant text parts. Active for primary sessions when enabled; never for subagents. Oldest 20% of eligible tags (outside protected tail) go to ultra, next 20% to full, next 20% to lite, newest 40% untouched. Graduated from experimental.caveman_text_compression; opt-in, default off (lossy)."),
|
|
15417
15416
|
memory: exports_external.object({
|
|
15418
15417
|
enabled: exports_external.boolean().default(true).describe("Enable cross-session memory (default: true)"),
|
|
15419
15418
|
injection_budget_tokens: exports_external.number().min(500).max(20000).default(4000).describe("Token budget for memory injection on session start (min: 500, max: 20000, default: 4000)"),
|
|
@@ -15446,10 +15445,344 @@ var init_magic_context = __esm(() => {
|
|
|
15446
15445
|
});
|
|
15447
15446
|
});
|
|
15448
15447
|
|
|
15448
|
+
// src/shared/error-message.ts
|
|
15449
|
+
function getErrorMessage(error51) {
|
|
15450
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
15451
|
+
}
|
|
15452
|
+
function readString(value) {
|
|
15453
|
+
if (typeof value === "string" && value.length > 0)
|
|
15454
|
+
return value;
|
|
15455
|
+
if (typeof value === "number")
|
|
15456
|
+
return String(value);
|
|
15457
|
+
return;
|
|
15458
|
+
}
|
|
15459
|
+
function clip(value, max) {
|
|
15460
|
+
if (value.length <= max)
|
|
15461
|
+
return value;
|
|
15462
|
+
return `${value.slice(0, max)}…`;
|
|
15463
|
+
}
|
|
15464
|
+
function describeError(error51) {
|
|
15465
|
+
const stringForm = clip(safeString(error51), 400);
|
|
15466
|
+
if (!(error51 instanceof Error) && !(error51 && typeof error51 === "object")) {
|
|
15467
|
+
return {
|
|
15468
|
+
name: typeof error51,
|
|
15469
|
+
message: "",
|
|
15470
|
+
stringForm,
|
|
15471
|
+
brief: stringForm || "<empty>"
|
|
15472
|
+
};
|
|
15473
|
+
}
|
|
15474
|
+
const obj = error51;
|
|
15475
|
+
const nameFromField = readString(obj.name);
|
|
15476
|
+
const nameFromCtor = error51?.constructor?.name;
|
|
15477
|
+
const name = nameFromField ?? nameFromCtor ?? "Error";
|
|
15478
|
+
const message = readString(obj.message) ?? "";
|
|
15479
|
+
const status = readString(obj.status) ?? readString(obj.statusCode);
|
|
15480
|
+
const code = readString(obj.code);
|
|
15481
|
+
let causeName;
|
|
15482
|
+
const cause = obj.cause;
|
|
15483
|
+
if (cause && typeof cause === "object") {
|
|
15484
|
+
const causeRecord = cause;
|
|
15485
|
+
causeName = readString(causeRecord.name) ?? cause.constructor?.name;
|
|
15486
|
+
}
|
|
15487
|
+
const stack = readString(obj.stack);
|
|
15488
|
+
const stackHead = stack ? stack.split(`
|
|
15489
|
+
`).slice(0, 4).map((l) => l.trim()).filter((l) => l.length > 0).join(" | ") : undefined;
|
|
15490
|
+
const briefParts = [];
|
|
15491
|
+
if (name)
|
|
15492
|
+
briefParts.push(name);
|
|
15493
|
+
if (message)
|
|
15494
|
+
briefParts.push(`message="${clip(message, 200)}"`);
|
|
15495
|
+
if (status)
|
|
15496
|
+
briefParts.push(`status=${status}`);
|
|
15497
|
+
if (code)
|
|
15498
|
+
briefParts.push(`code=${code}`);
|
|
15499
|
+
if (causeName)
|
|
15500
|
+
briefParts.push(`cause=${causeName}`);
|
|
15501
|
+
if (!message && stringForm && stringForm !== name) {
|
|
15502
|
+
briefParts.push(`str="${clip(stringForm, 200)}"`);
|
|
15503
|
+
}
|
|
15504
|
+
const brief = briefParts.join(" ") || stringForm || name;
|
|
15505
|
+
return {
|
|
15506
|
+
name,
|
|
15507
|
+
message,
|
|
15508
|
+
...status ? { status } : {},
|
|
15509
|
+
...code ? { code } : {},
|
|
15510
|
+
...causeName ? { causeName } : {},
|
|
15511
|
+
...stackHead ? { stackHead } : {},
|
|
15512
|
+
stringForm,
|
|
15513
|
+
brief
|
|
15514
|
+
};
|
|
15515
|
+
}
|
|
15516
|
+
function safeString(value) {
|
|
15517
|
+
try {
|
|
15518
|
+
return String(value);
|
|
15519
|
+
} catch {
|
|
15520
|
+
return "<unstringifiable>";
|
|
15521
|
+
}
|
|
15522
|
+
}
|
|
15523
|
+
|
|
15524
|
+
// src/shared/sqlite.ts
|
|
15525
|
+
function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
15526
|
+
const SAVEPOINT = "mc_tx_sp";
|
|
15527
|
+
|
|
15528
|
+
class NodeSqliteDatabase extends DatabaseSync {
|
|
15529
|
+
constructor(filename, options) {
|
|
15530
|
+
const translated = { ...options };
|
|
15531
|
+
if (options && "readonly" in options) {
|
|
15532
|
+
translated.readOnly = options.readonly;
|
|
15533
|
+
delete translated.readonly;
|
|
15534
|
+
}
|
|
15535
|
+
super(typeof filename === "string" ? filename : ":memory:", translated);
|
|
15536
|
+
}
|
|
15537
|
+
prepare(sql) {
|
|
15538
|
+
const stmt = super.prepare(sql);
|
|
15539
|
+
for (const method of ["run", "get", "all"]) {
|
|
15540
|
+
const original = stmt[method].bind(stmt);
|
|
15541
|
+
stmt[method] = (...args) => args.length === 1 && Array.isArray(args[0]) ? original(...args[0]) : original(...args);
|
|
15542
|
+
}
|
|
15543
|
+
return stmt;
|
|
15544
|
+
}
|
|
15545
|
+
transaction(fn) {
|
|
15546
|
+
const self2 = this;
|
|
15547
|
+
const wrapped = function(...args) {
|
|
15548
|
+
const nested = self2.isTransaction === true;
|
|
15549
|
+
self2.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
|
|
15550
|
+
try {
|
|
15551
|
+
const result = fn.apply(this, args);
|
|
15552
|
+
self2.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
|
|
15553
|
+
return result;
|
|
15554
|
+
} catch (error51) {
|
|
15555
|
+
if (nested) {
|
|
15556
|
+
self2.exec(`ROLLBACK TO ${SAVEPOINT}`);
|
|
15557
|
+
self2.exec(`RELEASE ${SAVEPOINT}`);
|
|
15558
|
+
} else {
|
|
15559
|
+
self2.exec("ROLLBACK");
|
|
15560
|
+
}
|
|
15561
|
+
throw error51;
|
|
15562
|
+
}
|
|
15563
|
+
};
|
|
15564
|
+
return wrapped;
|
|
15565
|
+
}
|
|
15566
|
+
}
|
|
15567
|
+
return NodeSqliteDatabase;
|
|
15568
|
+
}
|
|
15569
|
+
var isBun, bunSpec, nodeSpec, sqliteModule, DatabaseImpl, Database;
|
|
15570
|
+
var init_sqlite = __esm(async () => {
|
|
15571
|
+
isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
|
|
15572
|
+
bunSpec = "bun:" + "sqlite";
|
|
15573
|
+
nodeSpec = "node:" + "sqlite";
|
|
15574
|
+
sqliteModule = isBun ? await import(bunSpec) : await import(nodeSpec);
|
|
15575
|
+
DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
15576
|
+
Database = DatabaseImpl;
|
|
15577
|
+
});
|
|
15578
|
+
|
|
15579
|
+
// src/shared/sqlite-helpers.ts
|
|
15580
|
+
function closeQuietly(db) {
|
|
15581
|
+
if (!db)
|
|
15582
|
+
return;
|
|
15583
|
+
try {
|
|
15584
|
+
db.close();
|
|
15585
|
+
} catch {}
|
|
15586
|
+
}
|
|
15587
|
+
|
|
15588
|
+
// src/features/magic-context/compaction-marker.ts
|
|
15589
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
15590
|
+
import { join as join3 } from "node:path";
|
|
15591
|
+
function randomBase62(length) {
|
|
15592
|
+
const chars = [];
|
|
15593
|
+
for (let i = 0;i < length; i++) {
|
|
15594
|
+
chars.push(BASE62_CHARS[Math.floor(Math.random() * BASE62_CHARS.length)]);
|
|
15595
|
+
}
|
|
15596
|
+
return chars.join("");
|
|
15597
|
+
}
|
|
15598
|
+
function generateId(prefix, timestampMs, counter = 0n) {
|
|
15599
|
+
const encoded = BigInt(timestampMs) * 0x1000n + counter;
|
|
15600
|
+
const hex3 = encoded.toString(16).padStart(14, "0");
|
|
15601
|
+
return `${prefix}_${hex3}${randomBase62(14)}`;
|
|
15602
|
+
}
|
|
15603
|
+
function generateMessageId(timestampMs, counter = 0n) {
|
|
15604
|
+
return generateId("msg", timestampMs, counter);
|
|
15605
|
+
}
|
|
15606
|
+
function generatePartId(timestampMs, counter = 0n) {
|
|
15607
|
+
return generateId("prt", timestampMs, counter);
|
|
15608
|
+
}
|
|
15609
|
+
function getOpenCodeDbPath() {
|
|
15610
|
+
return join3(getDataDir(), "opencode", "opencode.db");
|
|
15611
|
+
}
|
|
15612
|
+
function isOpenCodeSchemaCompatible(db, dbPath) {
|
|
15613
|
+
if (cachedSchemaCompatible?.path === dbPath) {
|
|
15614
|
+
return cachedSchemaCompatible.compatible;
|
|
15615
|
+
}
|
|
15616
|
+
try {
|
|
15617
|
+
const messageCols = new Set(db.prepare("PRAGMA table_info(message)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
15618
|
+
const partCols = new Set(db.prepare("PRAGMA table_info(part)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
15619
|
+
const missingMessage = REQUIRED_MESSAGE_COLUMNS.filter((c) => !messageCols.has(c));
|
|
15620
|
+
const missingPart = REQUIRED_PART_COLUMNS.filter((c) => !partCols.has(c));
|
|
15621
|
+
if (missingMessage.length > 0 || missingPart.length > 0) {
|
|
15622
|
+
log(`[magic-context] compaction-marker: OpenCode DB schema missing required columns ` + `(message: [${missingMessage.join(", ")}], part: [${missingPart.join(", ")}]). ` + `Marker injection disabled for this process. ` + `This usually means OpenCode was updated and magic-context is out of date.`);
|
|
15623
|
+
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
15624
|
+
return false;
|
|
15625
|
+
}
|
|
15626
|
+
cachedSchemaCompatible = { path: dbPath, compatible: true };
|
|
15627
|
+
return true;
|
|
15628
|
+
} catch (error51) {
|
|
15629
|
+
log(`[magic-context] compaction-marker: schema probe failed: ${error51 instanceof Error ? error51.message : String(error51)}. ` + `Marker injection disabled until next process restart.`);
|
|
15630
|
+
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
15631
|
+
return false;
|
|
15632
|
+
}
|
|
15633
|
+
}
|
|
15634
|
+
function getWritableOpenCodeDb() {
|
|
15635
|
+
const dbPath = getOpenCodeDbPath();
|
|
15636
|
+
if (cachedWriteDb?.path === dbPath) {
|
|
15637
|
+
return cachedWriteDb.db;
|
|
15638
|
+
}
|
|
15639
|
+
if (cachedWriteDb) {
|
|
15640
|
+
try {
|
|
15641
|
+
closeQuietly(cachedWriteDb.db);
|
|
15642
|
+
} catch {}
|
|
15643
|
+
}
|
|
15644
|
+
if (!existsSync6(dbPath)) {
|
|
15645
|
+
throw new Error(`OpenCode database not found at ${dbPath} (is OpenCode installed?)`);
|
|
15646
|
+
}
|
|
15647
|
+
const db = new Database(dbPath);
|
|
15648
|
+
db.exec("PRAGMA busy_timeout=5000");
|
|
15649
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
15650
|
+
cachedWriteDb = { path: dbPath, db };
|
|
15651
|
+
return db;
|
|
15652
|
+
}
|
|
15653
|
+
function getNonSummaryMessageSortKey(sessionId, messageId) {
|
|
15654
|
+
const db = getWritableOpenCodeDb();
|
|
15655
|
+
const row = db.prepare(`SELECT time_created, id
|
|
15656
|
+
FROM message
|
|
15657
|
+
WHERE session_id = ?
|
|
15658
|
+
AND id = ?
|
|
15659
|
+
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
15660
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
15661
|
+
LIMIT 1`).get(sessionId, messageId);
|
|
15662
|
+
if (typeof row?.time_created !== "number" || typeof row.id !== "string") {
|
|
15663
|
+
return null;
|
|
15664
|
+
}
|
|
15665
|
+
return { id: row.id, timeCreated: row.time_created };
|
|
15666
|
+
}
|
|
15667
|
+
function findBoundaryUserMessage(sessionId, endMessageId) {
|
|
15668
|
+
const db = getWritableOpenCodeDb();
|
|
15669
|
+
const target = getNonSummaryMessageSortKey(sessionId, endMessageId);
|
|
15670
|
+
if (!target)
|
|
15671
|
+
return null;
|
|
15672
|
+
const boundary = db.prepare(`SELECT id, time_created, data
|
|
15673
|
+
FROM message
|
|
15674
|
+
WHERE session_id = ?
|
|
15675
|
+
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
15676
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
15677
|
+
AND COALESCE(json_extract(data, '$.role'), '') = 'user'
|
|
15678
|
+
AND (time_created < ? OR (time_created = ? AND id <= ?))
|
|
15679
|
+
ORDER BY time_created DESC, id DESC
|
|
15680
|
+
LIMIT 1`).get(sessionId, target.timeCreated, target.timeCreated, target.id);
|
|
15681
|
+
if (typeof boundary?.id !== "string" || typeof boundary.time_created !== "number") {
|
|
15682
|
+
return null;
|
|
15683
|
+
}
|
|
15684
|
+
return { id: boundary.id, timeCreated: boundary.time_created };
|
|
15685
|
+
}
|
|
15686
|
+
function compareOpenCodeMessagesByCanonicalOrder(sessionId, leftMessageId, rightMessageId) {
|
|
15687
|
+
const left = getNonSummaryMessageSortKey(sessionId, leftMessageId);
|
|
15688
|
+
const right = getNonSummaryMessageSortKey(sessionId, rightMessageId);
|
|
15689
|
+
if (!left || !right)
|
|
15690
|
+
return null;
|
|
15691
|
+
if (left.timeCreated < right.timeCreated)
|
|
15692
|
+
return -1;
|
|
15693
|
+
if (left.timeCreated > right.timeCreated)
|
|
15694
|
+
return 1;
|
|
15695
|
+
if (left.id < right.id)
|
|
15696
|
+
return -1;
|
|
15697
|
+
if (left.id > right.id)
|
|
15698
|
+
return 1;
|
|
15699
|
+
return 0;
|
|
15700
|
+
}
|
|
15701
|
+
function getOpenCodeMessageById(sessionId, messageId) {
|
|
15702
|
+
const db = getWritableOpenCodeDb();
|
|
15703
|
+
const row = db.prepare(`SELECT id FROM message WHERE session_id = ? AND id = ? LIMIT 1`).get(sessionId, messageId);
|
|
15704
|
+
return row ?? null;
|
|
15705
|
+
}
|
|
15706
|
+
function injectCompactionMarker(args) {
|
|
15707
|
+
const db = getWritableOpenCodeDb();
|
|
15708
|
+
if (!isOpenCodeSchemaCompatible(db, getOpenCodeDbPath())) {
|
|
15709
|
+
return null;
|
|
15710
|
+
}
|
|
15711
|
+
const boundary = args.resolvedBoundary ?? findBoundaryUserMessage(args.sessionId, args.endMessageId);
|
|
15712
|
+
if (!boundary) {
|
|
15713
|
+
log(`[magic-context] compaction-marker: no user message found at or before endMessageId ${args.endMessageId} (ordinal ${args.endOrdinal})`);
|
|
15714
|
+
return null;
|
|
15715
|
+
}
|
|
15716
|
+
const boundaryTime = boundary.timeCreated;
|
|
15717
|
+
const summaryMsgId = generateMessageId(boundaryTime + 1, 1n);
|
|
15718
|
+
const compactionPartId = generatePartId(boundaryTime, 1n);
|
|
15719
|
+
const summaryPartId = generatePartId(boundaryTime + 1, 2n);
|
|
15720
|
+
const summaryMsgData = JSON.stringify({
|
|
15721
|
+
role: "assistant",
|
|
15722
|
+
parentID: boundary.id,
|
|
15723
|
+
summary: true,
|
|
15724
|
+
finish: "stop",
|
|
15725
|
+
mode: "compaction",
|
|
15726
|
+
agent: "compaction",
|
|
15727
|
+
path: { cwd: args.directory, root: args.directory },
|
|
15728
|
+
cost: 0,
|
|
15729
|
+
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
15730
|
+
modelID: "magic-context",
|
|
15731
|
+
providerID: "magic-context",
|
|
15732
|
+
time: { created: boundaryTime + 1 }
|
|
15733
|
+
});
|
|
15734
|
+
try {
|
|
15735
|
+
db.transaction(() => {
|
|
15736
|
+
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(compactionPartId, boundary.id, args.sessionId, boundaryTime, boundaryTime, '{"type":"compaction","auto":true}');
|
|
15737
|
+
db.prepare("INSERT INTO message (id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?)").run(summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, summaryMsgData);
|
|
15738
|
+
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(summaryPartId, summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, JSON.stringify({ type: "text", text: args.summaryText }));
|
|
15739
|
+
})();
|
|
15740
|
+
log(`[magic-context] compaction-marker: injected boundary at user msg ${boundary.id} (ordinal ~${args.endOrdinal}), summary msg ${summaryMsgId}`);
|
|
15741
|
+
return {
|
|
15742
|
+
boundaryMessageId: boundary.id,
|
|
15743
|
+
summaryMessageId: summaryMsgId,
|
|
15744
|
+
compactionPartId,
|
|
15745
|
+
summaryPartId
|
|
15746
|
+
};
|
|
15747
|
+
} catch (error51) {
|
|
15748
|
+
log(`[magic-context] compaction-marker: injection failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
15749
|
+
return null;
|
|
15750
|
+
}
|
|
15751
|
+
}
|
|
15752
|
+
function removeCompactionMarker(state) {
|
|
15753
|
+
try {
|
|
15754
|
+
const db = getWritableOpenCodeDb();
|
|
15755
|
+
db.transaction(() => {
|
|
15756
|
+
db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
|
|
15757
|
+
db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
|
|
15758
|
+
db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
|
|
15759
|
+
})();
|
|
15760
|
+
return true;
|
|
15761
|
+
} catch (error51) {
|
|
15762
|
+
log(`[magic-context] compaction-marker: removal failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
15763
|
+
return false;
|
|
15764
|
+
}
|
|
15765
|
+
}
|
|
15766
|
+
var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", cachedWriteDb = null, REQUIRED_MESSAGE_COLUMNS, REQUIRED_PART_COLUMNS, cachedSchemaCompatible = null;
|
|
15767
|
+
var init_compaction_marker = __esm(async () => {
|
|
15768
|
+
init_data_path();
|
|
15769
|
+
init_logger();
|
|
15770
|
+
await init_sqlite();
|
|
15771
|
+
REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
|
|
15772
|
+
REQUIRED_PART_COLUMNS = [
|
|
15773
|
+
"id",
|
|
15774
|
+
"message_id",
|
|
15775
|
+
"session_id",
|
|
15776
|
+
"time_created",
|
|
15777
|
+
"time_updated",
|
|
15778
|
+
"data"
|
|
15779
|
+
];
|
|
15780
|
+
});
|
|
15781
|
+
|
|
15449
15782
|
// src/features/magic-context/memory/project-identity.ts
|
|
15450
15783
|
import { execFileSync } from "node:child_process";
|
|
15451
15784
|
import { createHash } from "node:crypto";
|
|
15452
|
-
import { statSync as statSync2 } from "node:fs";
|
|
15785
|
+
import { existsSync as existsSync8, realpathSync, statSync as statSync2 } from "node:fs";
|
|
15453
15786
|
import path3 from "node:path";
|
|
15454
15787
|
function asError(error51) {
|
|
15455
15788
|
return error51 instanceof Error ? error51 : undefined;
|
|
@@ -15526,6 +15859,9 @@ function classifyGitError(error51, rawDirectory) {
|
|
|
15526
15859
|
return new ProjectIdentityError("permission_denied", rawDirectory, "Permission denied while spawning git", asError(error51));
|
|
15527
15860
|
}
|
|
15528
15861
|
const stderr = getErrorStderr(error51).toLowerCase();
|
|
15862
|
+
if (stderr.includes("detected dubious ownership")) {
|
|
15863
|
+
return new ProjectIdentityError("dubious_ownership", rawDirectory, "git refused to read the repository because it detected dubious ownership", asError(error51));
|
|
15864
|
+
}
|
|
15529
15865
|
if (stderr.includes("not a git repository") || stderr.includes("does not have any commits yet") || stderr.includes("ambiguous argument 'head'") || stderr.includes("unknown revision or path")) {
|
|
15530
15866
|
return new ProjectIdentityError("not_git_repo", rawDirectory, "Directory has no git root commit; caller may use directory fallback", asError(error51));
|
|
15531
15867
|
}
|
|
@@ -15538,9 +15874,12 @@ function resolveProjectIdentityStrict(directory) {
|
|
|
15538
15874
|
return cached2;
|
|
15539
15875
|
}
|
|
15540
15876
|
assertDirectoryUsable(canonical, directory);
|
|
15877
|
+
if (!hasGitDir(canonical)) {
|
|
15878
|
+
throw new ProjectIdentityError("not_git_repo", directory, "Directory has no git metadata; caller may use directory fallback");
|
|
15879
|
+
}
|
|
15541
15880
|
let output;
|
|
15542
15881
|
try {
|
|
15543
|
-
output =
|
|
15882
|
+
output = execFileSyncForIdentity("git", ["rev-list", "--max-parents=0", "HEAD"], {
|
|
15544
15883
|
cwd: canonical,
|
|
15545
15884
|
encoding: "utf8",
|
|
15546
15885
|
env: { ...process.env, LC_ALL: "C", LANG: "C" },
|
|
@@ -15558,10 +15897,82 @@ function resolveProjectIdentityStrict(directory) {
|
|
|
15558
15897
|
}
|
|
15559
15898
|
const identity = `git:${rootCommit}`;
|
|
15560
15899
|
identityCache.set(canonical, identity);
|
|
15900
|
+
lastKnownGitIdentityCache.set(canonical, identity);
|
|
15901
|
+
transientFailureCooldown.delete(canonical);
|
|
15902
|
+
dubiousOwnershipFallbackDirectories.delete(canonical);
|
|
15903
|
+
transientGitIdentityReuseLoggedDirectories.delete(canonical);
|
|
15561
15904
|
return identity;
|
|
15562
15905
|
}
|
|
15563
15906
|
function shouldUseDirectoryFallback(error51) {
|
|
15564
|
-
return error51.errorClass
|
|
15907
|
+
return error51.errorClass !== "permission_denied";
|
|
15908
|
+
}
|
|
15909
|
+
function getActiveCooldown(canonical) {
|
|
15910
|
+
const until = transientFailureCooldown.get(canonical);
|
|
15911
|
+
if (until === undefined)
|
|
15912
|
+
return;
|
|
15913
|
+
if (nowMs() < until)
|
|
15914
|
+
return until;
|
|
15915
|
+
transientFailureCooldown.delete(canonical);
|
|
15916
|
+
return;
|
|
15917
|
+
}
|
|
15918
|
+
function lastKnownGitIdentity(canonical) {
|
|
15919
|
+
return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical);
|
|
15920
|
+
}
|
|
15921
|
+
function nearestLastKnownGitIdentity(canonical) {
|
|
15922
|
+
const visited = new Set;
|
|
15923
|
+
const walk = (start) => {
|
|
15924
|
+
let current = start;
|
|
15925
|
+
while (!visited.has(current)) {
|
|
15926
|
+
visited.add(current);
|
|
15927
|
+
const cached2 = lastKnownGitIdentity(current);
|
|
15928
|
+
if (cached2 !== undefined)
|
|
15929
|
+
return { identity: cached2, source: current };
|
|
15930
|
+
const parent = path3.dirname(current);
|
|
15931
|
+
if (parent === current)
|
|
15932
|
+
break;
|
|
15933
|
+
current = parent;
|
|
15934
|
+
}
|
|
15935
|
+
return;
|
|
15936
|
+
};
|
|
15937
|
+
const exactOrAncestor = walk(canonical);
|
|
15938
|
+
if (exactOrAncestor)
|
|
15939
|
+
return exactOrAncestor;
|
|
15940
|
+
try {
|
|
15941
|
+
const realCanonical = realpathSync.native(canonical);
|
|
15942
|
+
if (realCanonical !== canonical)
|
|
15943
|
+
return walk(realCanonical);
|
|
15944
|
+
} catch {}
|
|
15945
|
+
return;
|
|
15946
|
+
}
|
|
15947
|
+
function reuseLastKnownGitIdentity(canonical) {
|
|
15948
|
+
const cached2 = nearestLastKnownGitIdentity(canonical);
|
|
15949
|
+
if (cached2 === undefined)
|
|
15950
|
+
return;
|
|
15951
|
+
if (!transientGitIdentityReuseLoggedDirectories.has(canonical)) {
|
|
15952
|
+
transientGitIdentityReuseLoggedDirectories.add(canonical);
|
|
15953
|
+
const sourceNote = cached2.source === canonical ? "" : ` from ancestor ${cached2.source}`;
|
|
15954
|
+
log(`[magic-context] git identity resolution is temporarily unavailable for ${canonical}; reusing the last successful project identity${sourceNote} to avoid splitting project-scoped memory`);
|
|
15955
|
+
}
|
|
15956
|
+
return cached2.identity;
|
|
15957
|
+
}
|
|
15958
|
+
function formatDubiousOwnershipWarning(canonical) {
|
|
15959
|
+
return `Magic Context: git refused to read ${canonical} (dubious ownership — the repo is owned by a different user). Using a directory-based project identity for now, which keeps memory separate from this repo's normal identity. Fix: git config --global --add safe.directory ${canonical}`;
|
|
15960
|
+
}
|
|
15961
|
+
function recordDubiousOwnershipFallback(canonical) {
|
|
15962
|
+
dubiousOwnershipFallbackDirectories.add(canonical);
|
|
15963
|
+
if (dubiousOwnershipLoggedDirectories.has(canonical))
|
|
15964
|
+
return;
|
|
15965
|
+
dubiousOwnershipLoggedDirectories.add(canonical);
|
|
15966
|
+
log(`[magic-context] ${formatDubiousOwnershipWarning(canonical)}`);
|
|
15967
|
+
}
|
|
15968
|
+
function takeDubiousOwnershipProjectIdentityWarning(directory) {
|
|
15969
|
+
const canonical = path3.resolve(directory);
|
|
15970
|
+
if (!dubiousOwnershipFallbackDirectories.has(canonical))
|
|
15971
|
+
return null;
|
|
15972
|
+
if (dubiousOwnershipWarnedDirectories.has(canonical))
|
|
15973
|
+
return null;
|
|
15974
|
+
dubiousOwnershipWarnedDirectories.add(canonical);
|
|
15975
|
+
return formatDubiousOwnershipWarning(canonical);
|
|
15565
15976
|
}
|
|
15566
15977
|
function resolveProjectIdentity(directory) {
|
|
15567
15978
|
const canonical = path3.resolve(directory);
|
|
@@ -15572,27 +15983,74 @@ function resolveProjectIdentity(directory) {
|
|
|
15572
15983
|
}
|
|
15573
15984
|
directoryFallbackCache.delete(canonical);
|
|
15574
15985
|
}
|
|
15986
|
+
if (getActiveCooldown(canonical) !== undefined) {
|
|
15987
|
+
if (hasGitDir(canonical)) {
|
|
15988
|
+
const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
|
|
15989
|
+
if (cachedGitIdentity !== undefined) {
|
|
15990
|
+
return cachedGitIdentity;
|
|
15991
|
+
}
|
|
15992
|
+
}
|
|
15993
|
+
return directoryFallback(canonical);
|
|
15994
|
+
}
|
|
15575
15995
|
try {
|
|
15576
15996
|
return resolveProjectIdentityStrict(directory);
|
|
15577
15997
|
} catch (error51) {
|
|
15578
15998
|
if (error51 instanceof ProjectIdentityError && shouldUseDirectoryFallback(error51)) {
|
|
15579
15999
|
const fallback = directoryFallback(canonical);
|
|
15580
|
-
|
|
16000
|
+
const hasGitMetadata = hasGitDir(canonical);
|
|
16001
|
+
if (!hasGitMetadata) {
|
|
15581
16002
|
directoryFallbackCache.set(canonical, fallback);
|
|
16003
|
+
transientFailureCooldown.delete(canonical);
|
|
16004
|
+
} else {
|
|
16005
|
+
transientFailureCooldown.set(canonical, nowMs() + TRANSIENT_FAILURE_COOLDOWN_MS);
|
|
16006
|
+
const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
|
|
16007
|
+
if (cachedGitIdentity !== undefined) {
|
|
16008
|
+
return cachedGitIdentity;
|
|
16009
|
+
}
|
|
16010
|
+
}
|
|
16011
|
+
if (error51.errorClass === "dubious_ownership") {
|
|
16012
|
+
recordDubiousOwnershipFallback(canonical);
|
|
15582
16013
|
}
|
|
15583
16014
|
return fallback;
|
|
15584
16015
|
}
|
|
15585
16016
|
throw error51;
|
|
15586
16017
|
}
|
|
15587
16018
|
}
|
|
15588
|
-
function
|
|
16019
|
+
function resolveProjectIdentityOrFallback(directory) {
|
|
15589
16020
|
try {
|
|
15590
|
-
|
|
16021
|
+
return resolveProjectIdentity(directory);
|
|
16022
|
+
} catch (error51) {
|
|
16023
|
+
const canonical = path3.resolve(directory);
|
|
16024
|
+
const fallback = directoryFallback(canonical);
|
|
16025
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
16026
|
+
log(`[magic-context] project identity resolution failed for ${canonical}; using directory fallback ${fallback}: ${message}`);
|
|
16027
|
+
return fallback;
|
|
16028
|
+
}
|
|
16029
|
+
}
|
|
16030
|
+
function hasGitDir(canonical) {
|
|
16031
|
+
if (hasGitDirInAncestorChain(canonical)) {
|
|
15591
16032
|
return true;
|
|
16033
|
+
}
|
|
16034
|
+
try {
|
|
16035
|
+
const realCanonical = realpathSync.native(canonical);
|
|
16036
|
+
return realCanonical !== canonical && hasGitDirInAncestorChain(realCanonical);
|
|
15592
16037
|
} catch {
|
|
15593
16038
|
return false;
|
|
15594
16039
|
}
|
|
15595
16040
|
}
|
|
16041
|
+
function hasGitDirInAncestorChain(startDirectory) {
|
|
16042
|
+
let current = startDirectory;
|
|
16043
|
+
while (true) {
|
|
16044
|
+
if (existsSync8(path3.join(current, ".git"))) {
|
|
16045
|
+
return true;
|
|
16046
|
+
}
|
|
16047
|
+
const parent = path3.dirname(current);
|
|
16048
|
+
if (parent === current) {
|
|
16049
|
+
return false;
|
|
16050
|
+
}
|
|
16051
|
+
current = parent;
|
|
16052
|
+
}
|
|
16053
|
+
}
|
|
15596
16054
|
function normalizeStoredProjectPath(rawOrStored) {
|
|
15597
16055
|
if (rawOrStored.startsWith("git:") || rawOrStored.startsWith("dir:")) {
|
|
15598
16056
|
return rawOrStored;
|
|
@@ -15606,10 +16064,19 @@ function normalizeStoredProjectPath(rawOrStored) {
|
|
|
15606
16064
|
function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
|
|
15607
16065
|
return storedProjectPath === projectIdentity || normalizeStoredProjectPath(storedProjectPath) === projectIdentity;
|
|
15608
16066
|
}
|
|
15609
|
-
var GIT_TIMEOUT_MS = 5000, identityCache, directoryFallbackCache, ProjectIdentityError;
|
|
16067
|
+
var GIT_TIMEOUT_MS = 5000, TRANSIENT_FAILURE_COOLDOWN_MS, identityCache, lastKnownGitIdentityCache, directoryFallbackCache, transientFailureCooldown, dubiousOwnershipFallbackDirectories, dubiousOwnershipLoggedDirectories, dubiousOwnershipWarnedDirectories, transientGitIdentityReuseLoggedDirectories, execFileSyncForIdentity, nowMs = () => Date.now(), ProjectIdentityError;
|
|
15610
16068
|
var init_project_identity = __esm(() => {
|
|
16069
|
+
init_logger();
|
|
16070
|
+
TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
|
|
15611
16071
|
identityCache = new Map;
|
|
16072
|
+
lastKnownGitIdentityCache = new Map;
|
|
15612
16073
|
directoryFallbackCache = new Map;
|
|
16074
|
+
transientFailureCooldown = new Map;
|
|
16075
|
+
dubiousOwnershipFallbackDirectories = new Set;
|
|
16076
|
+
dubiousOwnershipLoggedDirectories = new Set;
|
|
16077
|
+
dubiousOwnershipWarnedDirectories = new Set;
|
|
16078
|
+
transientGitIdentityReuseLoggedDirectories = new Set;
|
|
16079
|
+
execFileSyncForIdentity = execFileSync;
|
|
15613
16080
|
ProjectIdentityError = class ProjectIdentityError extends Error {
|
|
15614
16081
|
errorClass;
|
|
15615
16082
|
rawDirectory;
|
|
@@ -15625,6 +16092,80 @@ var init_project_identity = __esm(() => {
|
|
|
15625
16092
|
};
|
|
15626
16093
|
});
|
|
15627
16094
|
|
|
16095
|
+
// src/features/magic-context/session-project-storage.ts
|
|
16096
|
+
function getUpsertSessionProjectStatement(db) {
|
|
16097
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
16098
|
+
if (!stmt) {
|
|
16099
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
16100
|
+
VALUES (?, ?, ?, ?)
|
|
16101
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
16102
|
+
project_path = excluded.project_path,
|
|
16103
|
+
updated_at = excluded.updated_at
|
|
16104
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
16105
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
16106
|
+
}
|
|
16107
|
+
return stmt;
|
|
16108
|
+
}
|
|
16109
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
16110
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
16111
|
+
if (!stmt) {
|
|
16112
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
16113
|
+
SET project_path = ?
|
|
16114
|
+
WHERE session_id = ?
|
|
16115
|
+
AND harness = ?
|
|
16116
|
+
AND project_path <> ?`);
|
|
16117
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
16118
|
+
}
|
|
16119
|
+
return stmt;
|
|
16120
|
+
}
|
|
16121
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
16122
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
16123
|
+
if (!stmt) {
|
|
16124
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
16125
|
+
SET project_path = (
|
|
16126
|
+
SELECT sp.project_path
|
|
16127
|
+
FROM session_projects sp
|
|
16128
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
16129
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
16130
|
+
LIMIT 1
|
|
16131
|
+
)
|
|
16132
|
+
WHERE EXISTS (
|
|
16133
|
+
SELECT 1
|
|
16134
|
+
FROM session_projects sp
|
|
16135
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
16136
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
16137
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
16138
|
+
AND (
|
|
16139
|
+
sp.project_path = ?
|
|
16140
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
16141
|
+
)
|
|
16142
|
+
)`);
|
|
16143
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
16144
|
+
}
|
|
16145
|
+
return stmt;
|
|
16146
|
+
}
|
|
16147
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
16148
|
+
if (!sessionId || !projectPath)
|
|
16149
|
+
return;
|
|
16150
|
+
const harness = getHarness();
|
|
16151
|
+
const now = Date.now();
|
|
16152
|
+
db.transaction(() => {
|
|
16153
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
16154
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
16155
|
+
})();
|
|
16156
|
+
}
|
|
16157
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
16158
|
+
if (!projectPath)
|
|
16159
|
+
return 0;
|
|
16160
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
16161
|
+
}
|
|
16162
|
+
var upsertSessionProjectStatements, repairSessionChunkProjectStatements, repairProjectChunkProjectStatements;
|
|
16163
|
+
var init_session_project_storage = __esm(() => {
|
|
16164
|
+
upsertSessionProjectStatements = new WeakMap;
|
|
16165
|
+
repairSessionChunkProjectStatements = new WeakMap;
|
|
16166
|
+
repairProjectChunkProjectStatements = new WeakMap;
|
|
16167
|
+
});
|
|
16168
|
+
|
|
15628
16169
|
// src/features/magic-context/overflow-detection.ts
|
|
15629
16170
|
function extractErrorMessage(error51) {
|
|
15630
16171
|
if (!error51)
|
|
@@ -16735,78 +17276,14 @@ function removeSystemReminders(text) {
|
|
|
16735
17276
|
}
|
|
16736
17277
|
var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
|
|
16737
17278
|
|
|
16738
|
-
// src/shared/sqlite.ts
|
|
16739
|
-
function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
16740
|
-
const SAVEPOINT = "mc_tx_sp";
|
|
16741
|
-
|
|
16742
|
-
class NodeSqliteDatabase extends DatabaseSync {
|
|
16743
|
-
constructor(filename, options) {
|
|
16744
|
-
const translated = { ...options };
|
|
16745
|
-
if (options && "readonly" in options) {
|
|
16746
|
-
translated.readOnly = options.readonly;
|
|
16747
|
-
delete translated.readonly;
|
|
16748
|
-
}
|
|
16749
|
-
super(typeof filename === "string" ? filename : ":memory:", translated);
|
|
16750
|
-
}
|
|
16751
|
-
prepare(sql) {
|
|
16752
|
-
const stmt = super.prepare(sql);
|
|
16753
|
-
for (const method of ["run", "get", "all"]) {
|
|
16754
|
-
const original = stmt[method].bind(stmt);
|
|
16755
|
-
stmt[method] = (...args) => args.length === 1 && Array.isArray(args[0]) ? original(...args[0]) : original(...args);
|
|
16756
|
-
}
|
|
16757
|
-
return stmt;
|
|
16758
|
-
}
|
|
16759
|
-
transaction(fn) {
|
|
16760
|
-
const self2 = this;
|
|
16761
|
-
const wrapped = function(...args) {
|
|
16762
|
-
const nested = self2.isTransaction === true;
|
|
16763
|
-
self2.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
|
|
16764
|
-
try {
|
|
16765
|
-
const result = fn.apply(this, args);
|
|
16766
|
-
self2.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
|
|
16767
|
-
return result;
|
|
16768
|
-
} catch (error51) {
|
|
16769
|
-
if (nested) {
|
|
16770
|
-
self2.exec(`ROLLBACK TO ${SAVEPOINT}`);
|
|
16771
|
-
self2.exec(`RELEASE ${SAVEPOINT}`);
|
|
16772
|
-
} else {
|
|
16773
|
-
self2.exec("ROLLBACK");
|
|
16774
|
-
}
|
|
16775
|
-
throw error51;
|
|
16776
|
-
}
|
|
16777
|
-
};
|
|
16778
|
-
return wrapped;
|
|
16779
|
-
}
|
|
16780
|
-
}
|
|
16781
|
-
return NodeSqliteDatabase;
|
|
16782
|
-
}
|
|
16783
|
-
var isBun, bunSpec, nodeSpec, sqliteModule, DatabaseImpl, Database;
|
|
16784
|
-
var init_sqlite = __esm(async () => {
|
|
16785
|
-
isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
|
|
16786
|
-
bunSpec = "bun:" + "sqlite";
|
|
16787
|
-
nodeSpec = "node:" + "sqlite";
|
|
16788
|
-
sqliteModule = isBun ? await import(bunSpec) : await import(nodeSpec);
|
|
16789
|
-
DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
16790
|
-
Database = DatabaseImpl;
|
|
16791
|
-
});
|
|
16792
|
-
|
|
16793
|
-
// src/shared/sqlite-helpers.ts
|
|
16794
|
-
function closeQuietly(db) {
|
|
16795
|
-
if (!db)
|
|
16796
|
-
return;
|
|
16797
|
-
try {
|
|
16798
|
-
db.close();
|
|
16799
|
-
} catch {}
|
|
16800
|
-
}
|
|
16801
|
-
|
|
16802
17279
|
// src/hooks/magic-context/read-session-db.ts
|
|
16803
|
-
import { existsSync as
|
|
16804
|
-
import { join as
|
|
16805
|
-
function
|
|
16806
|
-
return
|
|
17280
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
17281
|
+
import { join as join4 } from "node:path";
|
|
17282
|
+
function getOpenCodeDbPath2() {
|
|
17283
|
+
return join4(getDataDir(), "opencode", "opencode.db");
|
|
16807
17284
|
}
|
|
16808
17285
|
function openCodeDbExists() {
|
|
16809
|
-
return
|
|
17286
|
+
return existsSync10(getOpenCodeDbPath2());
|
|
16810
17287
|
}
|
|
16811
17288
|
function closeCachedReadOnlyDb() {
|
|
16812
17289
|
if (!cachedReadOnlyDb) {
|
|
@@ -16821,7 +17298,7 @@ function closeCachedReadOnlyDb() {
|
|
|
16821
17298
|
}
|
|
16822
17299
|
}
|
|
16823
17300
|
function getReadOnlySessionDb() {
|
|
16824
|
-
const dbPath =
|
|
17301
|
+
const dbPath = getOpenCodeDbPath2();
|
|
16825
17302
|
if (cachedReadOnlyDb?.path === dbPath) {
|
|
16826
17303
|
return cachedReadOnlyDb.db;
|
|
16827
17304
|
}
|
|
@@ -152420,6 +152897,15 @@ var init_migrations = __esm(() => {
|
|
|
152420
152897
|
);
|
|
152421
152898
|
`);
|
|
152422
152899
|
}
|
|
152900
|
+
},
|
|
152901
|
+
{
|
|
152902
|
+
version: 50,
|
|
152903
|
+
description: "add durable ctx-wrapup session marker",
|
|
152904
|
+
up(db) {
|
|
152905
|
+
if (tableExists2(db, "session_meta")) {
|
|
152906
|
+
ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
|
|
152907
|
+
}
|
|
152908
|
+
}
|
|
152423
152909
|
}
|
|
152424
152910
|
];
|
|
152425
152911
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -152555,82 +153041,6 @@ var init_project_docs_hash = __esm(() => {
|
|
|
152555
153041
|
docsCache = new Map;
|
|
152556
153042
|
});
|
|
152557
153043
|
|
|
152558
|
-
// src/shared/error-message.ts
|
|
152559
|
-
function getErrorMessage(error51) {
|
|
152560
|
-
return error51 instanceof Error ? error51.message : String(error51);
|
|
152561
|
-
}
|
|
152562
|
-
function readString(value) {
|
|
152563
|
-
if (typeof value === "string" && value.length > 0)
|
|
152564
|
-
return value;
|
|
152565
|
-
if (typeof value === "number")
|
|
152566
|
-
return String(value);
|
|
152567
|
-
return;
|
|
152568
|
-
}
|
|
152569
|
-
function clip(value, max) {
|
|
152570
|
-
if (value.length <= max)
|
|
152571
|
-
return value;
|
|
152572
|
-
return `${value.slice(0, max)}…`;
|
|
152573
|
-
}
|
|
152574
|
-
function describeError(error51) {
|
|
152575
|
-
const stringForm = clip(safeString(error51), 400);
|
|
152576
|
-
if (!(error51 instanceof Error) && !(error51 && typeof error51 === "object")) {
|
|
152577
|
-
return {
|
|
152578
|
-
name: typeof error51,
|
|
152579
|
-
message: "",
|
|
152580
|
-
stringForm,
|
|
152581
|
-
brief: stringForm || "<empty>"
|
|
152582
|
-
};
|
|
152583
|
-
}
|
|
152584
|
-
const obj = error51;
|
|
152585
|
-
const nameFromField = readString(obj.name);
|
|
152586
|
-
const nameFromCtor = error51?.constructor?.name;
|
|
152587
|
-
const name2 = nameFromField ?? nameFromCtor ?? "Error";
|
|
152588
|
-
const message = readString(obj.message) ?? "";
|
|
152589
|
-
const status = readString(obj.status) ?? readString(obj.statusCode);
|
|
152590
|
-
const code = readString(obj.code);
|
|
152591
|
-
let causeName;
|
|
152592
|
-
const cause = obj.cause;
|
|
152593
|
-
if (cause && typeof cause === "object") {
|
|
152594
|
-
const causeRecord = cause;
|
|
152595
|
-
causeName = readString(causeRecord.name) ?? cause.constructor?.name;
|
|
152596
|
-
}
|
|
152597
|
-
const stack = readString(obj.stack);
|
|
152598
|
-
const stackHead = stack ? stack.split(`
|
|
152599
|
-
`).slice(0, 4).map((l) => l.trim()).filter((l) => l.length > 0).join(" | ") : undefined;
|
|
152600
|
-
const briefParts = [];
|
|
152601
|
-
if (name2)
|
|
152602
|
-
briefParts.push(name2);
|
|
152603
|
-
if (message)
|
|
152604
|
-
briefParts.push(`message="${clip(message, 200)}"`);
|
|
152605
|
-
if (status)
|
|
152606
|
-
briefParts.push(`status=${status}`);
|
|
152607
|
-
if (code)
|
|
152608
|
-
briefParts.push(`code=${code}`);
|
|
152609
|
-
if (causeName)
|
|
152610
|
-
briefParts.push(`cause=${causeName}`);
|
|
152611
|
-
if (!message && stringForm && stringForm !== name2) {
|
|
152612
|
-
briefParts.push(`str="${clip(stringForm, 200)}"`);
|
|
152613
|
-
}
|
|
152614
|
-
const brief = briefParts.join(" ") || stringForm || name2;
|
|
152615
|
-
return {
|
|
152616
|
-
name: name2,
|
|
152617
|
-
message,
|
|
152618
|
-
...status ? { status } : {},
|
|
152619
|
-
...code ? { code } : {},
|
|
152620
|
-
...causeName ? { causeName } : {},
|
|
152621
|
-
...stackHead ? { stackHead } : {},
|
|
152622
|
-
stringForm,
|
|
152623
|
-
brief
|
|
152624
|
-
};
|
|
152625
|
-
}
|
|
152626
|
-
function safeString(value) {
|
|
152627
|
-
try {
|
|
152628
|
-
return String(value);
|
|
152629
|
-
} catch {
|
|
152630
|
-
return "<unstringifiable>";
|
|
152631
|
-
}
|
|
152632
|
-
}
|
|
152633
|
-
|
|
152634
153044
|
// src/shared/stable-json.ts
|
|
152635
153045
|
function stableStringify(value, seen = new WeakSet) {
|
|
152636
153046
|
if (value === undefined)
|
|
@@ -152742,12 +153152,12 @@ var init_tool_definition_tokens = __esm(() => {
|
|
|
152742
153152
|
});
|
|
152743
153153
|
|
|
152744
153154
|
// src/features/magic-context/tool-owner-backfill.ts
|
|
152745
|
-
import { existsSync as
|
|
152746
|
-
import { join as
|
|
153155
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
153156
|
+
import { join as join5 } from "node:path";
|
|
152747
153157
|
function resolveOpencodeDbPath() {
|
|
152748
|
-
return
|
|
153158
|
+
return join5(getDataDir(), "opencode", "opencode.db");
|
|
152749
153159
|
}
|
|
152750
|
-
function
|
|
153160
|
+
function ensureBackfillStateTable2(db) {
|
|
152751
153161
|
db.exec(`
|
|
152752
153162
|
CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
|
|
152753
153163
|
session_id TEXT PRIMARY KEY,
|
|
@@ -152763,7 +153173,7 @@ function ensureBackfillStateTable(db) {
|
|
|
152763
153173
|
}
|
|
152764
153174
|
function runToolOwnerBackfill(db) {
|
|
152765
153175
|
const startedAt = performance.now();
|
|
152766
|
-
|
|
153176
|
+
ensureBackfillStateTable2(db);
|
|
152767
153177
|
const result = {
|
|
152768
153178
|
sessionsProcessed: 0,
|
|
152769
153179
|
sessionsSkippedNoOcDb: 0,
|
|
@@ -152780,7 +153190,7 @@ function runToolOwnerBackfill(db) {
|
|
|
152780
153190
|
return result;
|
|
152781
153191
|
}
|
|
152782
153192
|
const opencodeDbPath = resolveOpencodeDbPath();
|
|
152783
|
-
if (!
|
|
153193
|
+
if (!existsSync11(opencodeDbPath)) {
|
|
152784
153194
|
log(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
|
|
152785
153195
|
markAllUnbackfilledSessionsSkipped(db);
|
|
152786
153196
|
result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
|
|
@@ -152803,7 +153213,7 @@ function runToolOwnerBackfill(db) {
|
|
|
152803
153213
|
return result;
|
|
152804
153214
|
}
|
|
152805
153215
|
function isToolOwnerBackfillNeeded(db) {
|
|
152806
|
-
|
|
153216
|
+
ensureBackfillStateTable2(db);
|
|
152807
153217
|
const row = db.prepare(`SELECT 1 AS hit
|
|
152808
153218
|
FROM tags
|
|
152809
153219
|
WHERE type = 'tool' AND tool_owner_message_id IS NULL
|
|
@@ -153004,8 +153414,8 @@ var init_tool_owner_backfill = __esm(() => {
|
|
|
153004
153414
|
});
|
|
153005
153415
|
|
|
153006
153416
|
// src/features/magic-context/storage-db.ts
|
|
153007
|
-
import { chmodSync, copyFileSync, cpSync, existsSync as
|
|
153008
|
-
import { dirname as dirname4, join as
|
|
153417
|
+
import { chmodSync, copyFileSync, cpSync, existsSync as existsSync12, mkdirSync as mkdirSync4, mkdtempSync } from "node:fs";
|
|
153418
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
153009
153419
|
function getSchemaFenceRejection() {
|
|
153010
153420
|
return lastSchemaFenceRejection;
|
|
153011
153421
|
}
|
|
@@ -153024,7 +153434,7 @@ function restrictDatabaseFilePermissions(dbPath) {
|
|
|
153024
153434
|
return;
|
|
153025
153435
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
153026
153436
|
const file2 = `${dbPath}${suffix}`;
|
|
153027
|
-
if (!
|
|
153437
|
+
if (!existsSync12(file2))
|
|
153028
153438
|
continue;
|
|
153029
153439
|
try {
|
|
153030
153440
|
chmodSync(file2, 384);
|
|
@@ -153039,22 +153449,22 @@ function resolveDatabasePath(dbPathOverride) {
|
|
|
153039
153449
|
}
|
|
153040
153450
|
const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
|
|
153041
153451
|
if (testDataDir && !process.env.XDG_DATA_HOME) {
|
|
153042
|
-
const dbDir2 =
|
|
153043
|
-
return { dbDir: dbDir2, dbPath:
|
|
153452
|
+
const dbDir2 = join6(testDataDir, "cortexkit", "magic-context");
|
|
153453
|
+
return { dbDir: dbDir2, dbPath: join6(dbDir2, "context.db") };
|
|
153044
153454
|
}
|
|
153045
153455
|
if (false) {}
|
|
153046
153456
|
const dbDir = getMagicContextStorageDir();
|
|
153047
|
-
return { dbDir, dbPath:
|
|
153457
|
+
return { dbDir, dbPath: join6(dbDir, "context.db") };
|
|
153048
153458
|
}
|
|
153049
153459
|
function getDatabasePath(db) {
|
|
153050
153460
|
return pathByDatabase.get(db) ?? null;
|
|
153051
153461
|
}
|
|
153052
153462
|
function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
153053
|
-
if (
|
|
153463
|
+
if (existsSync12(targetDbPath))
|
|
153054
153464
|
return;
|
|
153055
153465
|
const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
|
|
153056
|
-
const legacyDbPath =
|
|
153057
|
-
if (!
|
|
153466
|
+
const legacyDbPath = join6(legacyDir, "context.db");
|
|
153467
|
+
if (!existsSync12(legacyDbPath))
|
|
153058
153468
|
return;
|
|
153059
153469
|
log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
|
|
153060
153470
|
ensureSecureStorageDir(targetDbDir);
|
|
@@ -153070,8 +153480,8 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
153070
153480
|
}
|
|
153071
153481
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
153072
153482
|
const src = `${legacyDbPath}${suffix}`;
|
|
153073
|
-
const dst =
|
|
153074
|
-
if (
|
|
153483
|
+
const dst = join6(targetDbDir, `context.db${suffix}`);
|
|
153484
|
+
if (existsSync12(src)) {
|
|
153075
153485
|
try {
|
|
153076
153486
|
copyFileSync(src, dst);
|
|
153077
153487
|
} catch (error51) {
|
|
@@ -153079,9 +153489,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
|
|
|
153079
153489
|
}
|
|
153080
153490
|
}
|
|
153081
153491
|
}
|
|
153082
|
-
const legacyModelsDir =
|
|
153083
|
-
const targetModelsDir =
|
|
153084
|
-
if (
|
|
153492
|
+
const legacyModelsDir = join6(legacyDir, "models");
|
|
153493
|
+
const targetModelsDir = join6(targetDbDir, "models");
|
|
153494
|
+
if (existsSync12(legacyModelsDir) && !existsSync12(targetModelsDir)) {
|
|
153085
153495
|
try {
|
|
153086
153496
|
cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
|
|
153087
153497
|
} catch (error51) {
|
|
@@ -153681,6 +154091,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153681
154091
|
force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
|
|
153682
154092
|
emergency_drain_active INTEGER NOT NULL DEFAULT 0,
|
|
153683
154093
|
historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
|
|
154094
|
+
wrapup_in_progress_state TEXT,
|
|
153684
154095
|
cached_m0_materialized_at INTEGER,
|
|
153685
154096
|
cached_m0_session_facts_version INTEGER,
|
|
153686
154097
|
cached_m0_upgrade_state TEXT,
|
|
@@ -153969,6 +154380,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
153969
154380
|
ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
|
|
153970
154381
|
ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
|
|
153971
154382
|
ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
|
|
154383
|
+
ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
|
|
153972
154384
|
ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
|
|
153973
154385
|
ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
|
|
153974
154386
|
ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
|
|
@@ -154147,7 +154559,7 @@ function getDatabasePersistenceError(db) {
|
|
|
154147
154559
|
return null;
|
|
154148
154560
|
return persistenceErrorByDatabase.get(db) ?? null;
|
|
154149
154561
|
}
|
|
154150
|
-
var databases, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION =
|
|
154562
|
+
var databases, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 50, PERMISSIONS_ENFORCEABLE, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
|
|
154151
154563
|
var init_storage_db = __esm(async () => {
|
|
154152
154564
|
init_data_path();
|
|
154153
154565
|
init_logger();
|
|
@@ -154487,6 +154899,147 @@ function resetProtectedTailNoEligibleHead(db, sessionId) {
|
|
|
154487
154899
|
db.prepare("UPDATE session_meta SET recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
|
|
154488
154900
|
})();
|
|
154489
154901
|
}
|
|
154902
|
+
function parseWrapupState(value) {
|
|
154903
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
154904
|
+
return null;
|
|
154905
|
+
try {
|
|
154906
|
+
const parsed = JSON.parse(value);
|
|
154907
|
+
if (!parsed || typeof parsed !== "object")
|
|
154908
|
+
return null;
|
|
154909
|
+
if (typeof parsed.holderId !== "string" || parsed.holderId.length === 0)
|
|
154910
|
+
return null;
|
|
154911
|
+
const numberFields = [
|
|
154912
|
+
"acquiredAt",
|
|
154913
|
+
"expiresAt",
|
|
154914
|
+
"messagesToKeep",
|
|
154915
|
+
"anchorRawMessageCount",
|
|
154916
|
+
"targetEligibleEndOrdinal",
|
|
154917
|
+
"lastCompartmentEnd",
|
|
154918
|
+
"chunkIndex",
|
|
154919
|
+
"expectedChunks",
|
|
154920
|
+
"updatedAt"
|
|
154921
|
+
];
|
|
154922
|
+
for (const field of numberFields) {
|
|
154923
|
+
if (typeof parsed[field] !== "number" || !Number.isFinite(parsed[field]))
|
|
154924
|
+
return null;
|
|
154925
|
+
}
|
|
154926
|
+
return parsed;
|
|
154927
|
+
} catch {
|
|
154928
|
+
return null;
|
|
154929
|
+
}
|
|
154930
|
+
}
|
|
154931
|
+
function readRawWrapupState(db, sessionId) {
|
|
154932
|
+
const row = db.prepare("SELECT wrapup_in_progress_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
154933
|
+
return parseWrapupState(row?.wrapup_in_progress_state);
|
|
154934
|
+
}
|
|
154935
|
+
function getWrapupInProgressState(db, sessionId, now = Date.now()) {
|
|
154936
|
+
const state = readRawWrapupState(db, sessionId);
|
|
154937
|
+
if (!state)
|
|
154938
|
+
return null;
|
|
154939
|
+
if (state.expiresAt > now)
|
|
154940
|
+
return state;
|
|
154941
|
+
try {
|
|
154942
|
+
db.exec("BEGIN IMMEDIATE");
|
|
154943
|
+
} catch {
|
|
154944
|
+
return null;
|
|
154945
|
+
}
|
|
154946
|
+
let finished = false;
|
|
154947
|
+
try {
|
|
154948
|
+
const current = readRawWrapupState(db, sessionId);
|
|
154949
|
+
if (current && current.expiresAt <= now) {
|
|
154950
|
+
db.prepare("UPDATE session_meta SET wrapup_in_progress_state = NULL WHERE session_id = ?").run(sessionId);
|
|
154951
|
+
}
|
|
154952
|
+
db.exec("COMMIT");
|
|
154953
|
+
finished = true;
|
|
154954
|
+
} finally {
|
|
154955
|
+
if (!finished) {
|
|
154956
|
+
try {
|
|
154957
|
+
db.exec("ROLLBACK");
|
|
154958
|
+
} catch {}
|
|
154959
|
+
}
|
|
154960
|
+
}
|
|
154961
|
+
return null;
|
|
154962
|
+
}
|
|
154963
|
+
function isWrapupInProgress(db, sessionId, now = Date.now()) {
|
|
154964
|
+
return getWrapupInProgressState(db, sessionId, now) !== null;
|
|
154965
|
+
}
|
|
154966
|
+
function acquireWrapupInProgress(db, sessionId, state, now = Date.now()) {
|
|
154967
|
+
const acquiredAt = now;
|
|
154968
|
+
const next = {
|
|
154969
|
+
...state,
|
|
154970
|
+
acquiredAt,
|
|
154971
|
+
expiresAt: acquiredAt + WRAPUP_IN_PROGRESS_TTL_MS,
|
|
154972
|
+
updatedAt: acquiredAt
|
|
154973
|
+
};
|
|
154974
|
+
db.exec("BEGIN IMMEDIATE");
|
|
154975
|
+
let finished = false;
|
|
154976
|
+
try {
|
|
154977
|
+
ensureSessionMetaRow(db, sessionId);
|
|
154978
|
+
const current = readRawWrapupState(db, sessionId);
|
|
154979
|
+
if (current && current.expiresAt > now && current.holderId !== state.holderId) {
|
|
154980
|
+
db.exec("COMMIT");
|
|
154981
|
+
finished = true;
|
|
154982
|
+
return { ok: false, state: current };
|
|
154983
|
+
}
|
|
154984
|
+
db.prepare("UPDATE session_meta SET wrapup_in_progress_state = ? WHERE session_id = ?").run(stableStringify(next), sessionId);
|
|
154985
|
+
db.exec("COMMIT");
|
|
154986
|
+
finished = true;
|
|
154987
|
+
return { ok: true, state: next };
|
|
154988
|
+
} finally {
|
|
154989
|
+
if (!finished) {
|
|
154990
|
+
try {
|
|
154991
|
+
db.exec("ROLLBACK");
|
|
154992
|
+
} catch {}
|
|
154993
|
+
}
|
|
154994
|
+
}
|
|
154995
|
+
}
|
|
154996
|
+
function updateWrapupInProgress(db, sessionId, holderId, updates, now = Date.now()) {
|
|
154997
|
+
db.exec("BEGIN IMMEDIATE");
|
|
154998
|
+
let finished = false;
|
|
154999
|
+
try {
|
|
155000
|
+
const current = readRawWrapupState(db, sessionId);
|
|
155001
|
+
if (!current || current.holderId !== holderId || current.expiresAt <= now) {
|
|
155002
|
+
db.exec("ROLLBACK");
|
|
155003
|
+
finished = true;
|
|
155004
|
+
return null;
|
|
155005
|
+
}
|
|
155006
|
+
const next = {
|
|
155007
|
+
...current,
|
|
155008
|
+
...updates,
|
|
155009
|
+
holderId,
|
|
155010
|
+
expiresAt: now + WRAPUP_IN_PROGRESS_TTL_MS,
|
|
155011
|
+
updatedAt: now
|
|
155012
|
+
};
|
|
155013
|
+
db.prepare("UPDATE session_meta SET wrapup_in_progress_state = ? WHERE session_id = ?").run(stableStringify(next), sessionId);
|
|
155014
|
+
db.exec("COMMIT");
|
|
155015
|
+
finished = true;
|
|
155016
|
+
return next;
|
|
155017
|
+
} finally {
|
|
155018
|
+
if (!finished) {
|
|
155019
|
+
try {
|
|
155020
|
+
db.exec("ROLLBACK");
|
|
155021
|
+
} catch {}
|
|
155022
|
+
}
|
|
155023
|
+
}
|
|
155024
|
+
}
|
|
155025
|
+
function releaseWrapupInProgress(db, sessionId, holderId) {
|
|
155026
|
+
db.exec("BEGIN IMMEDIATE");
|
|
155027
|
+
let finished = false;
|
|
155028
|
+
try {
|
|
155029
|
+
const current = readRawWrapupState(db, sessionId);
|
|
155030
|
+
if (current?.holderId === holderId) {
|
|
155031
|
+
db.prepare("UPDATE session_meta SET wrapup_in_progress_state = NULL WHERE session_id = ?").run(sessionId);
|
|
155032
|
+
}
|
|
155033
|
+
db.exec("COMMIT");
|
|
155034
|
+
finished = true;
|
|
155035
|
+
} finally {
|
|
155036
|
+
if (!finished) {
|
|
155037
|
+
try {
|
|
155038
|
+
db.exec("ROLLBACK");
|
|
155039
|
+
} catch {}
|
|
155040
|
+
}
|
|
155041
|
+
}
|
|
155042
|
+
}
|
|
154490
155043
|
function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
|
|
154491
155044
|
if (usagePercentage >= 95)
|
|
154492
155045
|
return Math.min(1e6, Math.max(4 * perRunCap, Math.round(0.5 * usable)));
|
|
@@ -155164,7 +155717,7 @@ function setSessionWorkMetrics(db, sessionId, newWorkTokens, totalInputTokens) {
|
|
|
155164
155717
|
SET new_work_tokens = ?, total_input_tokens = ?
|
|
155165
155718
|
WHERE session_id = ?`).run(Math.max(0, Math.floor(newWorkTokens)), Math.max(0, Math.floor(totalInputTokens)), sessionId);
|
|
155166
155719
|
}
|
|
155167
|
-
var CAS_RETRY_LIMIT = 5, AUTO_SEARCH_NO_HINT_REASONS, DEFAULT_PROTECTED_TAIL_META, DRAIN_WINDOW_MS, EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95, EMERGENCY_DRAIN_EXIT_MARGIN = 10, EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55, EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000, EMERGENCY_DRAIN_MAX_LATCH_MS;
|
|
155720
|
+
var CAS_RETRY_LIMIT = 5, AUTO_SEARCH_NO_HINT_REASONS, DEFAULT_PROTECTED_TAIL_META, DRAIN_WINDOW_MS, WRAPUP_IN_PROGRESS_TTL_MS, EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95, EMERGENCY_DRAIN_EXIT_MARGIN = 10, EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55, EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000, EMERGENCY_DRAIN_MAX_LATCH_MS;
|
|
155168
155721
|
var init_storage_meta_persisted = __esm(() => {
|
|
155169
155722
|
init_logger();
|
|
155170
155723
|
init_storage_meta_shared();
|
|
@@ -155188,6 +155741,7 @@ var init_storage_meta_persisted = __esm(() => {
|
|
|
155188
155741
|
historianDrainFailureAt: 0
|
|
155189
155742
|
};
|
|
155190
155743
|
DRAIN_WINDOW_MS = 10 * 60 * 1000;
|
|
155744
|
+
WRAPUP_IN_PROGRESS_TTL_MS = 5 * 60 * 1000;
|
|
155191
155745
|
EMERGENCY_DRAIN_MAX_LATCH_MS = 30 * 60 * 1000;
|
|
155192
155746
|
});
|
|
155193
155747
|
|
|
@@ -164181,10 +164735,10 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
164181
164735
|
replacer = null;
|
|
164182
164736
|
indent = EMPTY;
|
|
164183
164737
|
};
|
|
164184
|
-
var
|
|
164738
|
+
var join7 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two)), gap) : EMPTY;
|
|
164185
164739
|
var join_content = (inside, value, gap) => {
|
|
164186
164740
|
const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
|
|
164187
|
-
return
|
|
164741
|
+
return join7(comment, inside, gap);
|
|
164188
164742
|
};
|
|
164189
164743
|
var stringify_string = (holder, key, value) => {
|
|
164190
164744
|
const raw = get_raw_string_literal(holder, key);
|
|
@@ -164206,13 +164760,13 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
164206
164760
|
if (i !== 0) {
|
|
164207
164761
|
inside += COMMA;
|
|
164208
164762
|
}
|
|
164209
|
-
const before =
|
|
164763
|
+
const before = join7(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
|
|
164210
164764
|
inside += before || LF + deeper_gap;
|
|
164211
164765
|
inside += stringify(i, value, deeper_gap) || STR_NULL;
|
|
164212
164766
|
inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
|
|
164213
164767
|
after_comma = process_comments(value, AFTER(i), deeper_gap);
|
|
164214
164768
|
}
|
|
164215
|
-
inside +=
|
|
164769
|
+
inside += join7(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
164216
164770
|
return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
|
|
164217
164771
|
};
|
|
164218
164772
|
var object_stringify = (value, gap) => {
|
|
@@ -164233,13 +164787,13 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
164233
164787
|
inside += COMMA;
|
|
164234
164788
|
}
|
|
164235
164789
|
first = false;
|
|
164236
|
-
const before =
|
|
164790
|
+
const before = join7(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
|
|
164237
164791
|
inside += before || LF + deeper_gap;
|
|
164238
164792
|
inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
|
|
164239
164793
|
after_comma = process_comments(value, AFTER(key), deeper_gap);
|
|
164240
164794
|
};
|
|
164241
164795
|
keys.forEach(iteratee);
|
|
164242
|
-
inside +=
|
|
164796
|
+
inside += join7(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
164243
164797
|
return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
|
|
164244
164798
|
};
|
|
164245
164799
|
function stringify(key, holder, gap) {
|
|
@@ -165239,16 +165793,16 @@ var init_compartment_prompt = () => {};
|
|
|
165239
165793
|
|
|
165240
165794
|
// src/shared/opencode-config-dir.ts
|
|
165241
165795
|
import { homedir as homedir6 } from "node:os";
|
|
165242
|
-
import { join as
|
|
165796
|
+
import { join as join11, resolve as resolve3 } from "node:path";
|
|
165243
165797
|
function getCliConfigDir() {
|
|
165244
165798
|
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
165245
165799
|
if (envConfigDir) {
|
|
165246
165800
|
return resolve3(envConfigDir);
|
|
165247
165801
|
}
|
|
165248
165802
|
if (process.platform === "win32") {
|
|
165249
|
-
return
|
|
165803
|
+
return join11(homedir6(), ".config", "opencode");
|
|
165250
165804
|
}
|
|
165251
|
-
return
|
|
165805
|
+
return join11(process.env.XDG_CONFIG_HOME || join11(homedir6(), ".config"), "opencode");
|
|
165252
165806
|
}
|
|
165253
165807
|
function getOpenCodeConfigDir(_options) {
|
|
165254
165808
|
return getCliConfigDir();
|
|
@@ -165257,16 +165811,16 @@ function getOpenCodeConfigPaths(options) {
|
|
|
165257
165811
|
const configDir = getOpenCodeConfigDir(options);
|
|
165258
165812
|
return {
|
|
165259
165813
|
configDir,
|
|
165260
|
-
configJson:
|
|
165261
|
-
configJsonc:
|
|
165262
|
-
packageJson:
|
|
165263
|
-
omoConfig:
|
|
165814
|
+
configJson: join11(configDir, "opencode.json"),
|
|
165815
|
+
configJsonc: join11(configDir, "opencode.jsonc"),
|
|
165816
|
+
packageJson: join11(configDir, "package.json"),
|
|
165817
|
+
omoConfig: join11(configDir, "magic-context.jsonc")
|
|
165264
165818
|
};
|
|
165265
165819
|
}
|
|
165266
165820
|
var init_opencode_config_dir = () => {};
|
|
165267
165821
|
|
|
165268
165822
|
// src/shared/conflict-detector.ts
|
|
165269
|
-
import { join as
|
|
165823
|
+
import { join as join12 } from "node:path";
|
|
165270
165824
|
function detectConflicts(directory) {
|
|
165271
165825
|
const conflicts = {
|
|
165272
165826
|
compactionAuto: false,
|
|
@@ -165323,8 +165877,8 @@ function checkCompaction(directory) {
|
|
|
165323
165877
|
return { auto: true, prune: false };
|
|
165324
165878
|
}
|
|
165325
165879
|
function readProjectCompaction(directory) {
|
|
165326
|
-
const dotOcJsonc =
|
|
165327
|
-
const dotOcJson =
|
|
165880
|
+
const dotOcJsonc = join12(directory, ".opencode", "opencode.jsonc");
|
|
165881
|
+
const dotOcJson = join12(directory, ".opencode", "opencode.json");
|
|
165328
165882
|
const dotOcConfig = readJsoncFile(dotOcJsonc) ?? readJsoncFile(dotOcJson);
|
|
165329
165883
|
if (dotOcConfig?.compaction) {
|
|
165330
165884
|
const c = dotOcConfig.compaction;
|
|
@@ -165332,8 +165886,8 @@ function readProjectCompaction(directory) {
|
|
|
165332
165886
|
return { auto: c.auto === true, prune: c.prune === true, resolved: true };
|
|
165333
165887
|
}
|
|
165334
165888
|
}
|
|
165335
|
-
const rootJsonc =
|
|
165336
|
-
const rootJson =
|
|
165889
|
+
const rootJsonc = join12(directory, "opencode.jsonc");
|
|
165890
|
+
const rootJson = join12(directory, "opencode.json");
|
|
165337
165891
|
const rootConfig = readJsoncFile(rootJsonc) ?? readJsoncFile(rootJson);
|
|
165338
165892
|
if (rootConfig?.compaction) {
|
|
165339
165893
|
const c = rootConfig.compaction;
|
|
@@ -165387,10 +165941,10 @@ function collectPluginEntries(directory) {
|
|
|
165387
165941
|
}
|
|
165388
165942
|
};
|
|
165389
165943
|
for (const configPath of [
|
|
165390
|
-
|
|
165391
|
-
|
|
165392
|
-
|
|
165393
|
-
|
|
165944
|
+
join12(directory, ".opencode", "opencode.jsonc"),
|
|
165945
|
+
join12(directory, ".opencode", "opencode.json"),
|
|
165946
|
+
join12(directory, "opencode.jsonc"),
|
|
165947
|
+
join12(directory, "opencode.json")
|
|
165394
165948
|
]) {
|
|
165395
165949
|
const config2 = readJsoncFile(configPath);
|
|
165396
165950
|
pushFrom(config2?.plugin);
|
|
@@ -165431,7 +165985,7 @@ function readOmoDisabledHooks(directory) {
|
|
|
165431
165985
|
try {
|
|
165432
165986
|
const paths = getOpenCodeConfigPaths({ binary: "opencode" });
|
|
165433
165987
|
for (const name2 of configNames) {
|
|
165434
|
-
const configPath =
|
|
165988
|
+
const configPath = join12(paths.configDir, name2);
|
|
165435
165989
|
const config2 = readJsoncFile(configPath);
|
|
165436
165990
|
if (config2?.disabled_hooks) {
|
|
165437
165991
|
for (const hook of config2.disabled_hooks) {
|
|
@@ -165441,7 +165995,7 @@ function readOmoDisabledHooks(directory) {
|
|
|
165441
165995
|
}
|
|
165442
165996
|
} catch {}
|
|
165443
165997
|
for (const name2 of configNames) {
|
|
165444
|
-
const config2 = readJsoncFile(
|
|
165998
|
+
const config2 = readJsoncFile(join12(directory, name2));
|
|
165445
165999
|
if (config2?.disabled_hooks) {
|
|
165446
166000
|
for (const hook of config2.disabled_hooks) {
|
|
165447
166001
|
disabled.add(hook);
|
|
@@ -165592,28 +166146,28 @@ __export(exports_conflict_warning_hook, {
|
|
|
165592
166146
|
sendConflictWarning: () => sendConflictWarning,
|
|
165593
166147
|
cleanupConflictWarnings: () => cleanupConflictWarnings
|
|
165594
166148
|
});
|
|
165595
|
-
import { existsSync as
|
|
166149
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "node:fs";
|
|
165596
166150
|
import { homedir as homedir7, platform as platform2 } from "node:os";
|
|
165597
|
-
import { join as
|
|
166151
|
+
import { join as join13 } from "node:path";
|
|
165598
166152
|
function getDesktopStatePath() {
|
|
165599
166153
|
const os2 = platform2();
|
|
165600
166154
|
const home = homedir7();
|
|
165601
166155
|
if (os2 === "darwin") {
|
|
165602
|
-
return
|
|
166156
|
+
return join13(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
|
|
165603
166157
|
}
|
|
165604
166158
|
if (os2 === "linux") {
|
|
165605
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ||
|
|
165606
|
-
return
|
|
166159
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || join13(home, ".config");
|
|
166160
|
+
return join13(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
|
|
165607
166161
|
}
|
|
165608
166162
|
if (os2 === "win32") {
|
|
165609
|
-
const appData = process.env.APPDATA ||
|
|
165610
|
-
return
|
|
166163
|
+
const appData = process.env.APPDATA || join13(home, "AppData", "Roaming");
|
|
166164
|
+
return join13(appData, "ai.opencode.desktop", "opencode.global.dat");
|
|
165611
166165
|
}
|
|
165612
166166
|
return null;
|
|
165613
166167
|
}
|
|
165614
166168
|
function readDesktopState(directory) {
|
|
165615
166169
|
const statePath = getDesktopStatePath();
|
|
165616
|
-
if (!statePath || !
|
|
166170
|
+
if (!statePath || !existsSync16(statePath)) {
|
|
165617
166171
|
log(`[magic-context] conflict-warning: Desktop state file not found at ${statePath}`);
|
|
165618
166172
|
return { sessionId: null, sidecarUrl: null };
|
|
165619
166173
|
}
|
|
@@ -165915,196 +166469,6 @@ var init_conflict_warning_hook = __esm(() => {
|
|
|
165915
166469
|
cachedDesktopStateByDir = new Map;
|
|
165916
166470
|
});
|
|
165917
166471
|
|
|
165918
|
-
// src/features/magic-context/compaction-marker.ts
|
|
165919
|
-
import { join as join13 } from "node:path";
|
|
165920
|
-
function randomBase62(length) {
|
|
165921
|
-
const chars = [];
|
|
165922
|
-
for (let i = 0;i < length; i++) {
|
|
165923
|
-
chars.push(BASE62_CHARS[Math.floor(Math.random() * BASE62_CHARS.length)]);
|
|
165924
|
-
}
|
|
165925
|
-
return chars.join("");
|
|
165926
|
-
}
|
|
165927
|
-
function generateId(prefix, timestampMs, counter = 0n) {
|
|
165928
|
-
const encoded = BigInt(timestampMs) * 0x1000n + counter;
|
|
165929
|
-
const hex3 = encoded.toString(16).padStart(14, "0");
|
|
165930
|
-
return `${prefix}_${hex3}${randomBase62(14)}`;
|
|
165931
|
-
}
|
|
165932
|
-
function generateMessageId(timestampMs, counter = 0n) {
|
|
165933
|
-
return generateId("msg", timestampMs, counter);
|
|
165934
|
-
}
|
|
165935
|
-
function generatePartId(timestampMs, counter = 0n) {
|
|
165936
|
-
return generateId("prt", timestampMs, counter);
|
|
165937
|
-
}
|
|
165938
|
-
function getOpenCodeDbPath2() {
|
|
165939
|
-
return join13(getDataDir(), "opencode", "opencode.db");
|
|
165940
|
-
}
|
|
165941
|
-
function isOpenCodeSchemaCompatible(db, dbPath) {
|
|
165942
|
-
if (cachedSchemaCompatible?.path === dbPath) {
|
|
165943
|
-
return cachedSchemaCompatible.compatible;
|
|
165944
|
-
}
|
|
165945
|
-
try {
|
|
165946
|
-
const messageCols = new Set(db.prepare("PRAGMA table_info(message)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
165947
|
-
const partCols = new Set(db.prepare("PRAGMA table_info(part)").all().map((r) => r.name ?? "").filter((n) => n.length > 0));
|
|
165948
|
-
const missingMessage = REQUIRED_MESSAGE_COLUMNS.filter((c) => !messageCols.has(c));
|
|
165949
|
-
const missingPart = REQUIRED_PART_COLUMNS.filter((c) => !partCols.has(c));
|
|
165950
|
-
if (missingMessage.length > 0 || missingPart.length > 0) {
|
|
165951
|
-
log(`[magic-context] compaction-marker: OpenCode DB schema missing required columns ` + `(message: [${missingMessage.join(", ")}], part: [${missingPart.join(", ")}]). ` + `Marker injection disabled for this process. ` + `This usually means OpenCode was updated and magic-context is out of date.`);
|
|
165952
|
-
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
165953
|
-
return false;
|
|
165954
|
-
}
|
|
165955
|
-
cachedSchemaCompatible = { path: dbPath, compatible: true };
|
|
165956
|
-
return true;
|
|
165957
|
-
} catch (error51) {
|
|
165958
|
-
log(`[magic-context] compaction-marker: schema probe failed: ${error51 instanceof Error ? error51.message : String(error51)}. ` + `Marker injection disabled until next process restart.`);
|
|
165959
|
-
cachedSchemaCompatible = { path: dbPath, compatible: false };
|
|
165960
|
-
return false;
|
|
165961
|
-
}
|
|
165962
|
-
}
|
|
165963
|
-
function getWritableOpenCodeDb() {
|
|
165964
|
-
const dbPath = getOpenCodeDbPath2();
|
|
165965
|
-
if (cachedWriteDb?.path === dbPath) {
|
|
165966
|
-
return cachedWriteDb.db;
|
|
165967
|
-
}
|
|
165968
|
-
if (cachedWriteDb) {
|
|
165969
|
-
try {
|
|
165970
|
-
closeQuietly(cachedWriteDb.db);
|
|
165971
|
-
} catch {}
|
|
165972
|
-
}
|
|
165973
|
-
const db = new Database(dbPath);
|
|
165974
|
-
db.exec("PRAGMA busy_timeout=5000");
|
|
165975
|
-
db.exec("PRAGMA journal_mode=WAL");
|
|
165976
|
-
cachedWriteDb = { path: dbPath, db };
|
|
165977
|
-
return db;
|
|
165978
|
-
}
|
|
165979
|
-
function getNonSummaryMessageSortKey(sessionId, messageId) {
|
|
165980
|
-
const db = getWritableOpenCodeDb();
|
|
165981
|
-
const row = db.prepare(`SELECT time_created, id
|
|
165982
|
-
FROM message
|
|
165983
|
-
WHERE session_id = ?
|
|
165984
|
-
AND id = ?
|
|
165985
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
165986
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
165987
|
-
LIMIT 1`).get(sessionId, messageId);
|
|
165988
|
-
if (typeof row?.time_created !== "number" || typeof row.id !== "string") {
|
|
165989
|
-
return null;
|
|
165990
|
-
}
|
|
165991
|
-
return { id: row.id, timeCreated: row.time_created };
|
|
165992
|
-
}
|
|
165993
|
-
function findBoundaryUserMessage(sessionId, endMessageId) {
|
|
165994
|
-
const db = getWritableOpenCodeDb();
|
|
165995
|
-
const target = getNonSummaryMessageSortKey(sessionId, endMessageId);
|
|
165996
|
-
if (!target)
|
|
165997
|
-
return null;
|
|
165998
|
-
const boundary = db.prepare(`SELECT id, time_created, data
|
|
165999
|
-
FROM message
|
|
166000
|
-
WHERE session_id = ?
|
|
166001
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
166002
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
|
|
166003
|
-
AND COALESCE(json_extract(data, '$.role'), '') = 'user'
|
|
166004
|
-
AND (time_created < ? OR (time_created = ? AND id <= ?))
|
|
166005
|
-
ORDER BY time_created DESC, id DESC
|
|
166006
|
-
LIMIT 1`).get(sessionId, target.timeCreated, target.timeCreated, target.id);
|
|
166007
|
-
if (typeof boundary?.id !== "string" || typeof boundary.time_created !== "number") {
|
|
166008
|
-
return null;
|
|
166009
|
-
}
|
|
166010
|
-
return { id: boundary.id, timeCreated: boundary.time_created };
|
|
166011
|
-
}
|
|
166012
|
-
function compareOpenCodeMessagesByCanonicalOrder(sessionId, leftMessageId, rightMessageId) {
|
|
166013
|
-
const left = getNonSummaryMessageSortKey(sessionId, leftMessageId);
|
|
166014
|
-
const right = getNonSummaryMessageSortKey(sessionId, rightMessageId);
|
|
166015
|
-
if (!left || !right)
|
|
166016
|
-
return null;
|
|
166017
|
-
if (left.timeCreated < right.timeCreated)
|
|
166018
|
-
return -1;
|
|
166019
|
-
if (left.timeCreated > right.timeCreated)
|
|
166020
|
-
return 1;
|
|
166021
|
-
if (left.id < right.id)
|
|
166022
|
-
return -1;
|
|
166023
|
-
if (left.id > right.id)
|
|
166024
|
-
return 1;
|
|
166025
|
-
return 0;
|
|
166026
|
-
}
|
|
166027
|
-
function getOpenCodeMessageById(sessionId, messageId) {
|
|
166028
|
-
const db = getWritableOpenCodeDb();
|
|
166029
|
-
const row = db.prepare(`SELECT id FROM message WHERE session_id = ? AND id = ? LIMIT 1`).get(sessionId, messageId);
|
|
166030
|
-
return row ?? null;
|
|
166031
|
-
}
|
|
166032
|
-
function injectCompactionMarker(args) {
|
|
166033
|
-
const db = getWritableOpenCodeDb();
|
|
166034
|
-
if (!isOpenCodeSchemaCompatible(db, getOpenCodeDbPath2())) {
|
|
166035
|
-
return null;
|
|
166036
|
-
}
|
|
166037
|
-
const boundary = args.resolvedBoundary ?? findBoundaryUserMessage(args.sessionId, args.endMessageId);
|
|
166038
|
-
if (!boundary) {
|
|
166039
|
-
log(`[magic-context] compaction-marker: no user message found at or before endMessageId ${args.endMessageId} (ordinal ${args.endOrdinal})`);
|
|
166040
|
-
return null;
|
|
166041
|
-
}
|
|
166042
|
-
const boundaryTime = boundary.timeCreated;
|
|
166043
|
-
const summaryMsgId = generateMessageId(boundaryTime + 1, 1n);
|
|
166044
|
-
const compactionPartId = generatePartId(boundaryTime, 1n);
|
|
166045
|
-
const summaryPartId = generatePartId(boundaryTime + 1, 2n);
|
|
166046
|
-
const summaryMsgData = JSON.stringify({
|
|
166047
|
-
role: "assistant",
|
|
166048
|
-
parentID: boundary.id,
|
|
166049
|
-
summary: true,
|
|
166050
|
-
finish: "stop",
|
|
166051
|
-
mode: "compaction",
|
|
166052
|
-
agent: "compaction",
|
|
166053
|
-
path: { cwd: args.directory, root: args.directory },
|
|
166054
|
-
cost: 0,
|
|
166055
|
-
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
166056
|
-
modelID: "magic-context",
|
|
166057
|
-
providerID: "magic-context",
|
|
166058
|
-
time: { created: boundaryTime + 1 }
|
|
166059
|
-
});
|
|
166060
|
-
try {
|
|
166061
|
-
db.transaction(() => {
|
|
166062
|
-
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(compactionPartId, boundary.id, args.sessionId, boundaryTime, boundaryTime, '{"type":"compaction","auto":true}');
|
|
166063
|
-
db.prepare("INSERT INTO message (id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?)").run(summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, summaryMsgData);
|
|
166064
|
-
db.prepare("INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES (?, ?, ?, ?, ?, ?)").run(summaryPartId, summaryMsgId, args.sessionId, boundaryTime + 1, boundaryTime + 1, JSON.stringify({ type: "text", text: args.summaryText }));
|
|
166065
|
-
})();
|
|
166066
|
-
log(`[magic-context] compaction-marker: injected boundary at user msg ${boundary.id} (ordinal ~${args.endOrdinal}), summary msg ${summaryMsgId}`);
|
|
166067
|
-
return {
|
|
166068
|
-
boundaryMessageId: boundary.id,
|
|
166069
|
-
summaryMessageId: summaryMsgId,
|
|
166070
|
-
compactionPartId,
|
|
166071
|
-
summaryPartId
|
|
166072
|
-
};
|
|
166073
|
-
} catch (error51) {
|
|
166074
|
-
log(`[magic-context] compaction-marker: injection failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
166075
|
-
return null;
|
|
166076
|
-
}
|
|
166077
|
-
}
|
|
166078
|
-
function removeCompactionMarker(state) {
|
|
166079
|
-
try {
|
|
166080
|
-
const db = getWritableOpenCodeDb();
|
|
166081
|
-
db.transaction(() => {
|
|
166082
|
-
db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
|
|
166083
|
-
db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
|
|
166084
|
-
db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
|
|
166085
|
-
})();
|
|
166086
|
-
return true;
|
|
166087
|
-
} catch (error51) {
|
|
166088
|
-
log(`[magic-context] compaction-marker: removal failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
166089
|
-
return false;
|
|
166090
|
-
}
|
|
166091
|
-
}
|
|
166092
|
-
var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", cachedWriteDb = null, REQUIRED_MESSAGE_COLUMNS, REQUIRED_PART_COLUMNS, cachedSchemaCompatible = null;
|
|
166093
|
-
var init_compaction_marker = __esm(async () => {
|
|
166094
|
-
init_data_path();
|
|
166095
|
-
init_logger();
|
|
166096
|
-
await init_sqlite();
|
|
166097
|
-
REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
|
|
166098
|
-
REQUIRED_PART_COLUMNS = [
|
|
166099
|
-
"id",
|
|
166100
|
-
"message_id",
|
|
166101
|
-
"session_id",
|
|
166102
|
-
"time_created",
|
|
166103
|
-
"time_updated",
|
|
166104
|
-
"data"
|
|
166105
|
-
];
|
|
166106
|
-
});
|
|
166107
|
-
|
|
166108
166472
|
// src/features/magic-context/dreamer/task-config.ts
|
|
166109
166473
|
var exports_task_config = {};
|
|
166110
166474
|
__export(exports_task_config, {
|
|
@@ -166979,7 +167343,8 @@ function isNativeRuntimeMissingError(error51) {
|
|
|
166979
167343
|
if (code === "ERR_DLOPEN_FAILED" && lower.includes("onnxruntime")) {
|
|
166980
167344
|
return true;
|
|
166981
167345
|
}
|
|
166982
|
-
|
|
167346
|
+
const mentionsNativeRuntime = lower.includes("onnxruntime-node") || lower.includes("onnxruntime_binding");
|
|
167347
|
+
if (!mentionsNativeRuntime)
|
|
166983
167348
|
return false;
|
|
166984
167349
|
return code === "ERR_MODULE_NOT_FOUND" || name2 === "ResolveMessage" || lower.includes("cannot find package") || lower.includes("cannot find module") || lower.includes("err_module_not_found");
|
|
166985
167350
|
}
|
|
@@ -167124,7 +167489,7 @@ class LocalEmbeddingProvider {
|
|
|
167124
167489
|
} catch (error51) {
|
|
167125
167490
|
if (isNativeRuntimeMissingError(error51)) {
|
|
167126
167491
|
nativeRuntimeMissing = true;
|
|
167127
|
-
log("[magic-context] local
|
|
167492
|
+
log("[magic-context] local embeddings are disabled because the onnxruntime-node native binding is missing or failed to load. Run `npx @cortexkit/magic-context@latest doctor` for repair guidance (use `doctor --force` to reinstall cached plugin packages), or configure an `openai-compatible` embedding HTTP endpoint. Existing memories are unaffected.");
|
|
167128
167493
|
} else {
|
|
167129
167494
|
log("[magic-context] embedding model failed to load:", error51);
|
|
167130
167495
|
}
|
|
@@ -168072,80 +168437,6 @@ var init_embedding_cache = __esm(() => {
|
|
|
168072
168437
|
embeddingCacheTtlMs = DEFAULT_EMBEDDING_CACHE_TTL_MS;
|
|
168073
168438
|
});
|
|
168074
168439
|
|
|
168075
|
-
// src/features/magic-context/session-project-storage.ts
|
|
168076
|
-
function getUpsertSessionProjectStatement(db) {
|
|
168077
|
-
let stmt = upsertSessionProjectStatements.get(db);
|
|
168078
|
-
if (!stmt) {
|
|
168079
|
-
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
168080
|
-
VALUES (?, ?, ?, ?)
|
|
168081
|
-
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
168082
|
-
project_path = excluded.project_path,
|
|
168083
|
-
updated_at = excluded.updated_at
|
|
168084
|
-
WHERE session_projects.project_path <> excluded.project_path`);
|
|
168085
|
-
upsertSessionProjectStatements.set(db, stmt);
|
|
168086
|
-
}
|
|
168087
|
-
return stmt;
|
|
168088
|
-
}
|
|
168089
|
-
function getRepairSessionChunkProjectStatement(db) {
|
|
168090
|
-
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
168091
|
-
if (!stmt) {
|
|
168092
|
-
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
168093
|
-
SET project_path = ?
|
|
168094
|
-
WHERE session_id = ?
|
|
168095
|
-
AND harness = ?
|
|
168096
|
-
AND project_path <> ?`);
|
|
168097
|
-
repairSessionChunkProjectStatements.set(db, stmt);
|
|
168098
|
-
}
|
|
168099
|
-
return stmt;
|
|
168100
|
-
}
|
|
168101
|
-
function getRepairProjectChunkProjectStatement(db) {
|
|
168102
|
-
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
168103
|
-
if (!stmt) {
|
|
168104
|
-
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
168105
|
-
SET project_path = (
|
|
168106
|
-
SELECT sp.project_path
|
|
168107
|
-
FROM session_projects sp
|
|
168108
|
-
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
168109
|
-
AND sp.harness = compartment_chunk_embeddings.harness
|
|
168110
|
-
LIMIT 1
|
|
168111
|
-
)
|
|
168112
|
-
WHERE EXISTS (
|
|
168113
|
-
SELECT 1
|
|
168114
|
-
FROM session_projects sp
|
|
168115
|
-
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
168116
|
-
AND sp.harness = compartment_chunk_embeddings.harness
|
|
168117
|
-
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
168118
|
-
AND (
|
|
168119
|
-
sp.project_path = ?
|
|
168120
|
-
OR compartment_chunk_embeddings.project_path = ?
|
|
168121
|
-
)
|
|
168122
|
-
)`);
|
|
168123
|
-
repairProjectChunkProjectStatements.set(db, stmt);
|
|
168124
|
-
}
|
|
168125
|
-
return stmt;
|
|
168126
|
-
}
|
|
168127
|
-
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
168128
|
-
if (!sessionId || !projectPath)
|
|
168129
|
-
return;
|
|
168130
|
-
const harness = getHarness();
|
|
168131
|
-
const now = Date.now();
|
|
168132
|
-
db.transaction(() => {
|
|
168133
|
-
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
168134
|
-
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
168135
|
-
})();
|
|
168136
|
-
}
|
|
168137
|
-
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
168138
|
-
if (!projectPath)
|
|
168139
|
-
return 0;
|
|
168140
|
-
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
168141
|
-
}
|
|
168142
|
-
var upsertSessionProjectStatements, repairSessionChunkProjectStatements, repairProjectChunkProjectStatements;
|
|
168143
|
-
var init_session_project_storage = __esm(() => {
|
|
168144
|
-
upsertSessionProjectStatements = new WeakMap;
|
|
168145
|
-
repairSessionChunkProjectStatements = new WeakMap;
|
|
168146
|
-
repairProjectChunkProjectStatements = new WeakMap;
|
|
168147
|
-
});
|
|
168148
|
-
|
|
168149
168440
|
// src/features/magic-context/project-embedding-registry.ts
|
|
168150
168441
|
import { createHash as createHash8, randomUUID } from "node:crypto";
|
|
168151
168442
|
function markProjectLoadUntrusted(projectIdentity) {
|
|
@@ -169782,7 +170073,7 @@ function getMemoryVerifications(db, memoryIds) {
|
|
|
169782
170073
|
var MEMORY_VERIFICATION_SENTINEL = "";
|
|
169783
170074
|
// src/features/magic-context/memory/verification-paths.ts
|
|
169784
170075
|
import { execFile } from "node:child_process";
|
|
169785
|
-
import { existsSync as
|
|
170076
|
+
import { existsSync as existsSync17, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
|
|
169786
170077
|
import path6 from "node:path";
|
|
169787
170078
|
import { promisify } from "node:util";
|
|
169788
170079
|
async function runGit(cwd, args) {
|
|
@@ -169807,7 +170098,7 @@ function isWithin(root, candidate) {
|
|
|
169807
170098
|
}
|
|
169808
170099
|
function safeRealpath(value) {
|
|
169809
170100
|
try {
|
|
169810
|
-
return
|
|
170101
|
+
return realpathSync3.native(value);
|
|
169811
170102
|
} catch {
|
|
169812
170103
|
return null;
|
|
169813
170104
|
}
|
|
@@ -169885,7 +170176,7 @@ function verificationFileExists(baseRoot, filePath) {
|
|
|
169885
170176
|
return false;
|
|
169886
170177
|
const root = path6.resolve(baseRoot);
|
|
169887
170178
|
const candidate = path6.resolve(root, filePath);
|
|
169888
|
-
return isWithin(root, candidate) &&
|
|
170179
|
+
return isWithin(root, candidate) && existsSync17(candidate);
|
|
169889
170180
|
}
|
|
169890
170181
|
async function normalizeVerificationFiles(args) {
|
|
169891
170182
|
const cwd = path6.resolve(args.cwd);
|
|
@@ -169918,7 +170209,7 @@ async function normalizeVerificationFiles(args) {
|
|
|
169918
170209
|
warnings.push(`Skipped verification path "${value}" because it is the repo/project root.`);
|
|
169919
170210
|
continue;
|
|
169920
170211
|
}
|
|
169921
|
-
if (
|
|
170212
|
+
if (existsSync17(candidate)) {
|
|
169922
170213
|
try {
|
|
169923
170214
|
if (statSync5(candidate).isDirectory()) {
|
|
169924
170215
|
warnings.push(`Skipped verification path "${value}" because it is a directory.`);
|
|
@@ -169949,7 +170240,7 @@ async function normalizeVerificationFiles(args) {
|
|
|
169949
170240
|
}
|
|
169950
170241
|
normalized.push(tracked);
|
|
169951
170242
|
} else {
|
|
169952
|
-
if (!
|
|
170243
|
+
if (!existsSync17(candidate)) {
|
|
169953
170244
|
warnings.push(`Skipped verification path "${value}" because it does not exist.`);
|
|
169954
170245
|
continue;
|
|
169955
170246
|
}
|
|
@@ -177293,6 +177584,9 @@ function applyDeferredCompactionMarker(db, sessionId, pending, directory) {
|
|
|
177293
177584
|
}
|
|
177294
177585
|
}
|
|
177295
177586
|
function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, directory) {
|
|
177587
|
+
if (getHarness() !== "opencode") {
|
|
177588
|
+
return true;
|
|
177589
|
+
}
|
|
177296
177590
|
const targetEndMessageId = getCompartmentEndMessageIdForOrdinal(db, sessionId, lastCompartmentEnd);
|
|
177297
177591
|
if (!targetEndMessageId) {
|
|
177298
177592
|
sessionLog(sessionId, `compaction-marker: no compartment endMessageId for ordinal ${lastCompartmentEnd}; preserving existing marker`);
|
|
@@ -178934,7 +179228,8 @@ function readCurrentM0SnapshotMarkers(args) {
|
|
|
178934
179228
|
sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
|
|
178935
179229
|
upgradeState: getUpgradeState(args.db, args.sessionId),
|
|
178936
179230
|
systemHash: hard.systemHash,
|
|
178937
|
-
modelKey: hard.modelKey
|
|
179231
|
+
modelKey: hard.modelKey,
|
|
179232
|
+
projectIdentity: args.projectPath ?? null
|
|
178938
179233
|
};
|
|
178939
179234
|
}
|
|
178940
179235
|
function snapshotMarkersFromCachedM0(state) {
|
|
@@ -178967,7 +179262,8 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
178967
179262
|
sessionFactsVersion: state.cachedM0SessionFactsVersion,
|
|
178968
179263
|
upgradeState: state.cachedM0UpgradeState,
|
|
178969
179264
|
systemHash: state.cachedM0SystemHash ?? "",
|
|
178970
|
-
modelKey: state.cachedM0ModelKey ?? ""
|
|
179265
|
+
modelKey: state.cachedM0ModelKey ?? "",
|
|
179266
|
+
projectIdentity: state.cachedM0ProjectIdentity ?? null
|
|
178971
179267
|
};
|
|
178972
179268
|
}
|
|
178973
179269
|
function mustMaterialize(args) {
|
|
@@ -178986,6 +179282,15 @@ function mustMaterialize(args) {
|
|
|
178986
179282
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
|
|
178987
179283
|
return { value: true, reason: "ttl_idle" };
|
|
178988
179284
|
}
|
|
179285
|
+
if (current.projectIdentity !== null) {
|
|
179286
|
+
const cachedProjectIdentity = args.state.cachedM0ProjectIdentity ?? null;
|
|
179287
|
+
if (cachedProjectIdentity === null) {
|
|
179288
|
+
args.state.cachedM0ProjectIdentity = current.projectIdentity;
|
|
179289
|
+
args.db.prepare("UPDATE session_meta SET cached_m0_project_identity = ? WHERE session_id = ?").run(current.projectIdentity, args.sessionId);
|
|
179290
|
+
} else if (cachedProjectIdentity !== current.projectIdentity) {
|
|
179291
|
+
return { value: true, reason: "project_change" };
|
|
179292
|
+
}
|
|
179293
|
+
}
|
|
178989
179294
|
if (current.workspaceFingerprint !== null || (args.state.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
178990
179295
|
if ((args.state.cachedM0WorkspaceFingerprint ?? null) !== current.workspaceFingerprint) {
|
|
178991
179296
|
return { value: true, reason: "project_memory_epoch" };
|
|
@@ -179226,6 +179531,7 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
179226
179531
|
state.cachedM0UpgradeState = markers.upgradeState;
|
|
179227
179532
|
state.cachedM0SystemHash = markers.systemHash;
|
|
179228
179533
|
state.cachedM0ModelKey = markers.modelKey;
|
|
179534
|
+
state.cachedM0ProjectIdentity = markers.projectIdentity;
|
|
179229
179535
|
state.snapshotMarkers = markers;
|
|
179230
179536
|
}
|
|
179231
179537
|
function historySliceTokens(m0Text) {
|
|
@@ -179349,10 +179655,11 @@ function materializeM0(options) {
|
|
|
179349
179655
|
sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
|
|
179350
179656
|
upgradeState: getUpgradeState(options.db, options.sessionId),
|
|
179351
179657
|
systemHash: snapshotMarkers.systemHash,
|
|
179352
|
-
modelKey: snapshotMarkers.modelKey
|
|
179658
|
+
modelKey: snapshotMarkers.modelKey,
|
|
179659
|
+
projectIdentity: projectPath ?? null
|
|
179353
179660
|
};
|
|
179354
179661
|
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
179355
|
-
const stale = memoryEpochStale || current.projectUserProfileVersion !== snapshotMarkers.projectUserProfileVersion || current.maxCompartmentSeq !== snapshotMarkers.maxCompartmentSeq || current.maxMutationId !== snapshotMarkers.maxMutationId || current.maxMemoryMutationId !== snapshotMarkers.maxMemoryMutationId || current.sessionFactsVersion !== snapshotMarkers.sessionFactsVersion || current.upgradeState !== snapshotMarkers.upgradeState;
|
|
179662
|
+
const stale = memoryEpochStale || current.projectUserProfileVersion !== snapshotMarkers.projectUserProfileVersion || current.maxCompartmentSeq !== snapshotMarkers.maxCompartmentSeq || current.maxMutationId !== snapshotMarkers.maxMutationId || current.maxMemoryMutationId !== snapshotMarkers.maxMemoryMutationId || current.sessionFactsVersion !== snapshotMarkers.sessionFactsVersion || current.upgradeState !== snapshotMarkers.upgradeState || (current.projectIdentity ?? null) !== (snapshotMarkers.projectIdentity ?? null);
|
|
179356
179663
|
if (stale) {
|
|
179357
179664
|
options.db.exec("ROLLBACK");
|
|
179358
179665
|
throw new MaterializeContentionError({ reason: "snapshot changed before Phase 3" });
|
|
@@ -179381,7 +179688,8 @@ function materializeM0(options) {
|
|
|
179381
179688
|
sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
|
|
179382
179689
|
upgradeState: snapshotMarkers.upgradeState,
|
|
179383
179690
|
systemHash: snapshotMarkers.systemHash,
|
|
179384
|
-
modelKey: snapshotMarkers.modelKey
|
|
179691
|
+
modelKey: snapshotMarkers.modelKey,
|
|
179692
|
+
projectIdentity: snapshotMarkers.projectIdentity
|
|
179385
179693
|
});
|
|
179386
179694
|
options.db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), options.sessionId);
|
|
179387
179695
|
const baselineEndMessageId = lastCompartmentBoundaryId(compartments);
|
|
@@ -179539,6 +179847,7 @@ function readCachedM0M1Row(db, sessionId) {
|
|
|
179539
179847
|
cached_m0_upgrade_state,
|
|
179540
179848
|
cached_m0_system_hash,
|
|
179541
179849
|
cached_m0_model_key,
|
|
179850
|
+
cached_m0_project_identity,
|
|
179542
179851
|
memory_block_ids
|
|
179543
179852
|
FROM session_meta
|
|
179544
179853
|
WHERE session_id = ?`).get(sessionId);
|
|
@@ -179573,11 +179882,12 @@ function markersFromCachedRow(row) {
|
|
|
179573
179882
|
sessionFactsVersion: row.cached_m0_session_facts_version,
|
|
179574
179883
|
upgradeState: row.cached_m0_upgrade_state,
|
|
179575
179884
|
systemHash: row.cached_m0_system_hash ?? "",
|
|
179576
|
-
modelKey: row.cached_m0_model_key ?? ""
|
|
179885
|
+
modelKey: row.cached_m0_model_key ?? "",
|
|
179886
|
+
projectIdentity: row.cached_m0_project_identity ?? null
|
|
179577
179887
|
};
|
|
179578
179888
|
}
|
|
179579
179889
|
function cachedRowMatchesState(row, state) {
|
|
179580
|
-
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "");
|
|
179890
|
+
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state.cachedM0ProjectIdentity ?? null);
|
|
179581
179891
|
}
|
|
179582
179892
|
function applyCachedRowToState(state, row) {
|
|
179583
179893
|
const markers = markersFromCachedRow(row);
|
|
@@ -179599,6 +179909,7 @@ function applyCachedRowToState(state, row) {
|
|
|
179599
179909
|
state.cachedM0UpgradeState = markers.upgradeState;
|
|
179600
179910
|
state.cachedM0SystemHash = markers.systemHash;
|
|
179601
179911
|
state.cachedM0ModelKey = markers.modelKey;
|
|
179912
|
+
state.cachedM0ProjectIdentity = markers.projectIdentity;
|
|
179602
179913
|
state.snapshotMarkers = markers;
|
|
179603
179914
|
}
|
|
179604
179915
|
function replayCachedM1(state) {
|
|
@@ -180593,6 +180904,43 @@ function semanticSnapBoundary(args) {
|
|
|
180593
180904
|
}
|
|
180594
180905
|
return snapped;
|
|
180595
180906
|
}
|
|
180907
|
+
function snapWrapupBoundaryToUser(args) {
|
|
180908
|
+
const { messages, index, candidate, offset, triggerBudget } = args;
|
|
180909
|
+
if (candidate <= offset)
|
|
180910
|
+
return candidate;
|
|
180911
|
+
const snapTokenLimit = Math.min(Math.max(triggerBudget, 2000), 48000);
|
|
180912
|
+
for (let ordinal = candidate;ordinal >= offset; ordinal -= 1) {
|
|
180913
|
+
const message = messages.find((m) => m.ordinal === ordinal);
|
|
180914
|
+
if (!message)
|
|
180915
|
+
continue;
|
|
180916
|
+
if (message.role !== "user" || !hasMeaningfulUserText(message.parts))
|
|
180917
|
+
continue;
|
|
180918
|
+
const extraTokens = index.rangeTokens(ordinal, candidate);
|
|
180919
|
+
if (extraTokens <= snapTokenLimit)
|
|
180920
|
+
return ordinal;
|
|
180921
|
+
return candidate;
|
|
180922
|
+
}
|
|
180923
|
+
return candidate;
|
|
180924
|
+
}
|
|
180925
|
+
function fenceWrapupBoundaryForToolArcs(args) {
|
|
180926
|
+
let boundary = args.candidate;
|
|
180927
|
+
const maxPasses = args.arcs.length + 1;
|
|
180928
|
+
for (let pass = 0;pass < maxPasses; pass += 1) {
|
|
180929
|
+
let next = boundary;
|
|
180930
|
+
for (const arc of args.arcs) {
|
|
180931
|
+
if (arc.resOrdinal === null) {
|
|
180932
|
+
continue;
|
|
180933
|
+
}
|
|
180934
|
+
if (arc.invOrdinal >= args.lastCompartmentEndOrdinal + 1 && arc.invOrdinal < next && next <= arc.resOrdinal) {
|
|
180935
|
+
next = arc.invOrdinal;
|
|
180936
|
+
}
|
|
180937
|
+
}
|
|
180938
|
+
if (next === boundary)
|
|
180939
|
+
return boundary;
|
|
180940
|
+
boundary = next;
|
|
180941
|
+
}
|
|
180942
|
+
return boundary;
|
|
180943
|
+
}
|
|
180596
180944
|
function applyHeadCap(args) {
|
|
180597
180945
|
const { index, protectedTailStart, offset, arcs, capTokens, recentOpenArcCutoff } = args;
|
|
180598
180946
|
if (offset >= protectedTailStart)
|
|
@@ -180848,6 +181196,124 @@ function resolveBoundaryContext(args) {
|
|
|
180848
181196
|
function resolveOpenCodeProtectedTailBoundary(args) {
|
|
180849
181197
|
return resolveProtectedTailBoundary(resolveBoundaryContext(args));
|
|
180850
181198
|
}
|
|
181199
|
+
function resolveWrapupProtectedTailBoundary(args) {
|
|
181200
|
+
const ctx = resolveBoundaryContext({ ...args, mode: "manual-wrapup" });
|
|
181201
|
+
const createdAt = ctx.createdAt ?? Date.now();
|
|
181202
|
+
const messages = readRawSessionMessages(ctx.sessionId);
|
|
181203
|
+
const absoluteMessageCount = getCachedAbsoluteMessageCount(ctx.sessionId) ?? undefined;
|
|
181204
|
+
const index = buildTrueRawTokenIndex(ctx.sessionId, messages, {
|
|
181205
|
+
providerShapeVersion: ctx.providerShapeVersion,
|
|
181206
|
+
cacheNamespace: ctx.cacheNamespace,
|
|
181207
|
+
absoluteMessageCount,
|
|
181208
|
+
storedTotalForMessage: ctx.storedTokenTotals ? (m) => {
|
|
181209
|
+
const value = ctx.storedTokenTotals?.get(m.id);
|
|
181210
|
+
return value === undefined ? null : value;
|
|
181211
|
+
} : undefined
|
|
181212
|
+
});
|
|
181213
|
+
const rawMessageCount = index.rawMessageCount;
|
|
181214
|
+
const offset = Math.max(1, ctx.lastCompartmentEndOrdinal + 1);
|
|
181215
|
+
const anchorRawMessageCount = Math.max(0, Math.min(rawMessageCount, Math.floor(args.anchorRawMessageCount ?? rawMessageCount)));
|
|
181216
|
+
const usagePercentage = clampPercentage(ctx.usage?.percentage ?? 0);
|
|
181217
|
+
const usageInputTokens = Math.max(0, Math.round(ctx.usage?.inputTokens ?? 0));
|
|
181218
|
+
const rawMessagesAboveLastCompartment = Math.max(0, anchorRawMessageCount - offset + 1);
|
|
181219
|
+
const keep = Math.max(1, Math.floor(args.messagesToKeep));
|
|
181220
|
+
let targetProtectedTailStart = offset;
|
|
181221
|
+
let boundaryReason = "manual-wrapup-empty";
|
|
181222
|
+
if (rawMessageCount === 0 || rawMessagesAboveLastCompartment <= keep) {
|
|
181223
|
+
targetProtectedTailStart = offset;
|
|
181224
|
+
boundaryReason = rawMessageCount === 0 ? "manual-wrapup-empty" : "manual-wrapup-within-keep";
|
|
181225
|
+
} else {
|
|
181226
|
+
targetProtectedTailStart = anchorRawMessageCount - keep + 1;
|
|
181227
|
+
boundaryReason = "manual-wrapup-keep-watermark";
|
|
181228
|
+
const arcs = buildToolArcs(messages);
|
|
181229
|
+
const fenced = fenceWrapupBoundaryForToolArcs({
|
|
181230
|
+
candidate: targetProtectedTailStart,
|
|
181231
|
+
arcs,
|
|
181232
|
+
lastCompartmentEndOrdinal: ctx.lastCompartmentEndOrdinal
|
|
181233
|
+
});
|
|
181234
|
+
if (fenced !== targetProtectedTailStart)
|
|
181235
|
+
boundaryReason = "manual-wrapup-tool-arc";
|
|
181236
|
+
targetProtectedTailStart = fenced;
|
|
181237
|
+
const snapped = snapWrapupBoundaryToUser({
|
|
181238
|
+
messages,
|
|
181239
|
+
index,
|
|
181240
|
+
candidate: targetProtectedTailStart,
|
|
181241
|
+
offset,
|
|
181242
|
+
triggerBudget: ctx.triggerBudget
|
|
181243
|
+
});
|
|
181244
|
+
if (snapped !== targetProtectedTailStart)
|
|
181245
|
+
boundaryReason = "manual-wrapup-user-snap";
|
|
181246
|
+
targetProtectedTailStart = snapped;
|
|
181247
|
+
const refenced = fenceWrapupBoundaryForToolArcs({
|
|
181248
|
+
candidate: targetProtectedTailStart,
|
|
181249
|
+
arcs,
|
|
181250
|
+
lastCompartmentEndOrdinal: ctx.lastCompartmentEndOrdinal
|
|
181251
|
+
});
|
|
181252
|
+
if (refenced !== targetProtectedTailStart)
|
|
181253
|
+
boundaryReason = "manual-wrapup-tool-arc";
|
|
181254
|
+
targetProtectedTailStart = refenced;
|
|
181255
|
+
}
|
|
181256
|
+
targetProtectedTailStart = clampOrdinal(targetProtectedTailStart, rawMessageCount);
|
|
181257
|
+
const target = deriveProtectedTailTokenTarget({
|
|
181258
|
+
contextLimit: ctx.contextLimit,
|
|
181259
|
+
executeThresholdPercentage: ctx.executeThresholdPercentage,
|
|
181260
|
+
usagePercentage,
|
|
181261
|
+
triggerBudget: ctx.triggerBudget
|
|
181262
|
+
});
|
|
181263
|
+
const perRunCap = selectPerRunCap({
|
|
181264
|
+
usagePercentage,
|
|
181265
|
+
N: target.N,
|
|
181266
|
+
contextLimit: ctx.contextLimit,
|
|
181267
|
+
executeThresholdPercentage: ctx.executeThresholdPercentage
|
|
181268
|
+
});
|
|
181269
|
+
const head = applyHeadCap({
|
|
181270
|
+
index,
|
|
181271
|
+
protectedTailStart: targetProtectedTailStart,
|
|
181272
|
+
offset,
|
|
181273
|
+
arcs: buildToolArcs(messages),
|
|
181274
|
+
lastCompartmentEndOrdinal: ctx.lastCompartmentEndOrdinal,
|
|
181275
|
+
capTokens: perRunCap,
|
|
181276
|
+
recentOpenArcCutoff: targetProtectedTailStart
|
|
181277
|
+
});
|
|
181278
|
+
const eligibleEndOrdinal = Math.min(head.eligibleEndOrdinal, targetProtectedTailStart);
|
|
181279
|
+
const rawRangeFingerprint = computeRawRangeFingerprint(messages, offset, eligibleEndOrdinal);
|
|
181280
|
+
const snapshot = {
|
|
181281
|
+
sessionId: ctx.sessionId,
|
|
181282
|
+
mode: "manual-wrapup",
|
|
181283
|
+
offset,
|
|
181284
|
+
offsetMessageId: boundaryMessageId(index, offset),
|
|
181285
|
+
protectedTailStart: targetProtectedTailStart,
|
|
181286
|
+
protectedTailStartMessageId: boundaryMessageId(index, targetProtectedTailStart),
|
|
181287
|
+
eligibleEndOrdinal,
|
|
181288
|
+
eligibleEndMessageId: boundaryMessageId(index, eligibleEndOrdinal - 1),
|
|
181289
|
+
rawMessageCountAtTrigger: rawMessageCount,
|
|
181290
|
+
rawLastMessageIdAtTrigger: boundaryMessageId(index, rawMessageCount),
|
|
181291
|
+
N: keep,
|
|
181292
|
+
usagePercentage,
|
|
181293
|
+
usageInputTokens,
|
|
181294
|
+
usageSource: ctx.usageSource,
|
|
181295
|
+
contextLimit: ctx.contextLimit,
|
|
181296
|
+
executeThresholdPercentage: ctx.executeThresholdPercentage,
|
|
181297
|
+
triggerBudget: ctx.triggerBudget,
|
|
181298
|
+
priorBoundaryOrdinal: ctx.priorBoundaryOrdinal,
|
|
181299
|
+
migrationFloorActive: ctx.migrationFloorActive,
|
|
181300
|
+
emergencyTailScale: ctx.emergencyTailScale,
|
|
181301
|
+
providerShapeVersion: ctx.providerShapeVersion,
|
|
181302
|
+
cacheNamespace: ctx.cacheNamespace,
|
|
181303
|
+
createdAt,
|
|
181304
|
+
rawRangeFingerprint,
|
|
181305
|
+
trueRawEligibleTokens: index.rangeTokens(offset, targetProtectedTailStart),
|
|
181306
|
+
oversizeAtomicUnit: head.oversizeAtomicUnit,
|
|
181307
|
+
boundaryReason
|
|
181308
|
+
};
|
|
181309
|
+
return {
|
|
181310
|
+
snapshot,
|
|
181311
|
+
rawMessagesAboveLastCompartment,
|
|
181312
|
+
anchorRawMessageCount,
|
|
181313
|
+
targetProtectedTailStart,
|
|
181314
|
+
targetEligibleEndOrdinal: targetProtectedTailStart
|
|
181315
|
+
};
|
|
181316
|
+
}
|
|
180851
181317
|
function getRawHistoryEligibility(db, sessionId) {
|
|
180852
181318
|
const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
|
|
180853
181319
|
const offset = Math.max(1, lastCompartmentEnd + 1);
|
|
@@ -183075,7 +183541,7 @@ async function runCompartmentAgent(deps) {
|
|
|
183075
183541
|
currentContextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit
|
|
183076
183542
|
}) : { ok: true };
|
|
183077
183543
|
if (!validation.ok && validation.reason === "stale_snapshot") {
|
|
183078
|
-
const refreshed = resolveOpenCodeProtectedTailBoundary({
|
|
183544
|
+
const refreshed = deps.refreshBoundarySnapshot ? deps.refreshBoundarySnapshot(boundarySnapshot, validation) : resolveOpenCodeProtectedTailBoundary({
|
|
183079
183545
|
db,
|
|
183080
183546
|
sessionId,
|
|
183081
183547
|
mode: "incremental-runner",
|
|
@@ -183088,7 +183554,7 @@ async function runCompartmentAgent(deps) {
|
|
|
183088
183554
|
usageSource: boundarySnapshot.usageSource,
|
|
183089
183555
|
emergencyTailScale: boundarySnapshot.emergencyTailScale
|
|
183090
183556
|
});
|
|
183091
|
-
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
183557
|
+
if (refreshed && hasRunnableCompartmentWindow(refreshed)) {
|
|
183092
183558
|
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
183093
183559
|
boundarySnapshot = refreshed;
|
|
183094
183560
|
validation = { ok: true };
|
|
@@ -183106,7 +183572,8 @@ async function runCompartmentAgent(deps) {
|
|
|
183106
183572
|
if (protectedTailStart <= offset || eligibleEndOrdinal <= offset) {
|
|
183107
183573
|
sessionLog(sessionId, `historian no-op: protectedTailStart=${protectedTailStart} eligibleEnd=${eligibleEndOrdinal} <= offset=${offset} — nothing to compact`);
|
|
183108
183574
|
if (boundarySnapshot.usagePercentage < 80 && !boundarySnapshot.emergencyTailScale) {
|
|
183109
|
-
|
|
183575
|
+
if (!isWrapupInProgress(db, sessionId))
|
|
183576
|
+
clearEmergencyRecovery(db, sessionId);
|
|
183110
183577
|
} else {
|
|
183111
183578
|
const count = recordHighPressureNoEligibleHead(db, boundarySnapshot);
|
|
183112
183579
|
sessionLog(sessionId, `historian high-pressure no-op: recovery remains armed (noEligibleHeadCount=${count})`);
|
|
@@ -183119,7 +183586,7 @@ async function runCompartmentAgent(deps) {
|
|
|
183119
183586
|
}
|
|
183120
183587
|
const perRunCap = selectPerRunCap(boundarySnapshot);
|
|
183121
183588
|
const usable = Math.max(1, Math.round(boundarySnapshot.contextLimit * boundarySnapshot.executeThresholdPercentage / 100));
|
|
183122
|
-
const reserve = reserveProtectedTailDrainTokens({
|
|
183589
|
+
const reserve = deps.forceDrainQuota ? { ok: true, reservation: null } : reserveProtectedTailDrainTokens({
|
|
183123
183590
|
db,
|
|
183124
183591
|
sessionId,
|
|
183125
183592
|
runId: crypto.randomUUID(),
|
|
@@ -183137,12 +183604,14 @@ async function runCompartmentAgent(deps) {
|
|
|
183137
183604
|
}
|
|
183138
183605
|
drainReservation = reserve.reservation;
|
|
183139
183606
|
const chunk = readSessionChunk(sessionId, historianChunkTokens, offset, eligibleEndOrdinal);
|
|
183607
|
+
const forceKeepLastCompartmentForChunk = deps.forceKeepLastCompartment === true && !chunk.hasMore;
|
|
183140
183608
|
telemetry.chunkStartOrdinal = chunk.startIndex;
|
|
183141
183609
|
telemetry.chunkEndOrdinal = chunk.endIndex;
|
|
183142
183610
|
if (!chunk.text || chunk.messageCount === 0) {
|
|
183143
183611
|
sessionLog(sessionId, `historian no-op: chunk empty after filtering (messageCount=${chunk.messageCount}, textLen=${chunk.text?.length ?? 0}) range=${offset}-${eligibleEndOrdinal - 1}`);
|
|
183144
183612
|
if (boundarySnapshot.usagePercentage < 80 && !boundarySnapshot.emergencyTailScale) {
|
|
183145
|
-
|
|
183613
|
+
if (!isWrapupInProgress(db, sessionId))
|
|
183614
|
+
clearEmergencyRecovery(db, sessionId);
|
|
183146
183615
|
} else {
|
|
183147
183616
|
recordHighPressureNoEligibleHead(db, boundarySnapshot);
|
|
183148
183617
|
}
|
|
@@ -183216,7 +183685,7 @@ ${chunkText}`,
|
|
|
183216
183685
|
const BOUNDARY_HEALING_SLACK = 2;
|
|
183217
183686
|
const inEmergency = getOverflowState(db, sessionId).needsEmergencyRecovery;
|
|
183218
183687
|
let persistedCompartments = emittedCompartments;
|
|
183219
|
-
if (!inEmergency && emittedCompartments.length >= 2) {
|
|
183688
|
+
if (!inEmergency && !forceKeepLastCompartmentForChunk && emittedCompartments.length >= 2) {
|
|
183220
183689
|
const lastEmitted = emittedCompartments[emittedCompartments.length - 1];
|
|
183221
183690
|
const lookaheadMargin = chunk.endIndex - lastEmitted.endMessage;
|
|
183222
183691
|
if (lookaheadMargin <= BOUNDARY_HEALING_SLACK) {
|
|
@@ -183240,10 +183709,21 @@ ${chunkText}`,
|
|
|
183240
183709
|
const lastNewEndMessageId = newCompartments[newCompartments.length - 1]?.endMessageId;
|
|
183241
183710
|
const promotionDirectory = sessionDirectory || deps.directory;
|
|
183242
183711
|
const discardedLast = persistedCompartments.length < emittedCompartments.length;
|
|
183712
|
+
const weakLookaheadFinalCompartment = forceKeepLastCompartmentForChunk;
|
|
183713
|
+
const skipUnanchoredPromotion = discardedLast || weakLookaheadFinalCompartment;
|
|
183243
183714
|
const embeddingActive = !!promotionDirectory && deps.memoryEnabled !== false;
|
|
183244
183715
|
const promotionActive = embeddingActive && deps.autoPromote !== false;
|
|
183245
183716
|
const promotionProjectIdentity = promotionDirectory ? resolveProjectIdentity(promotionDirectory) : "";
|
|
183246
|
-
const publishableEvents = (validatedPass.events ?? []).filter((e) =>
|
|
183717
|
+
const publishableEvents = (validatedPass.events ?? []).filter((e) => {
|
|
183718
|
+
if (typeof e.atCompartment !== "number")
|
|
183719
|
+
return !weakLookaheadFinalCompartment;
|
|
183720
|
+
if (e.atCompartment > persistedCompartments.length)
|
|
183721
|
+
return false;
|
|
183722
|
+
if (weakLookaheadFinalCompartment && e.atCompartment >= emittedCompartments.length) {
|
|
183723
|
+
return false;
|
|
183724
|
+
}
|
|
183725
|
+
return true;
|
|
183726
|
+
});
|
|
183247
183727
|
let promotedFactRefs = [];
|
|
183248
183728
|
let persistedIds = [];
|
|
183249
183729
|
const holderId = deps.compartmentLeaseHolderId;
|
|
@@ -183263,7 +183743,7 @@ ${chunkText}`,
|
|
|
183263
183743
|
}
|
|
183264
183744
|
appendCompartments(db, sessionId, persistedCompartments);
|
|
183265
183745
|
persistedIds = getCompartments(db, sessionId).slice(-persistedCompartments.length).map((c) => c.id);
|
|
183266
|
-
if (promotionActive && !
|
|
183746
|
+
if (promotionActive && !skipUnanchoredPromotion) {
|
|
183267
183747
|
promotedFactRefs = promoteSessionFactsDurable(db, sessionId, promotionProjectIdentity, validatedPass.facts ?? []);
|
|
183268
183748
|
}
|
|
183269
183749
|
if (publishableEvents.length > 0) {
|
|
@@ -183278,7 +183758,8 @@ ${chunkText}`,
|
|
|
183278
183758
|
clearHistorianFailureState(db, sessionId);
|
|
183279
183759
|
clearHistorianDrainFailure(db, sessionId);
|
|
183280
183760
|
recordProtectedTailPublicationFloor(db, sessionId, lastCompartmentEnd + 1);
|
|
183281
|
-
|
|
183761
|
+
if (!isWrapupInProgress(db, sessionId))
|
|
183762
|
+
clearEmergencyRecovery(db, sessionId);
|
|
183282
183763
|
drainReservation = null;
|
|
183283
183764
|
if (deferMarkerApplication && lastNewEndMessageId) {
|
|
183284
183765
|
setPendingCompactionMarkerState(db, sessionId, {
|
|
@@ -183350,7 +183831,7 @@ ${chunkText}`,
|
|
|
183350
183831
|
}
|
|
183351
183832
|
})();
|
|
183352
183833
|
}
|
|
183353
|
-
if (deps.experimentalUserMemories === true && !
|
|
183834
|
+
if (deps.experimentalUserMemories === true && !skipUnanchoredPromotion && validatedPass.userObservations && validatedPass.userObservations.length > 0) {
|
|
183354
183835
|
try {
|
|
183355
183836
|
const lastNew = newCompartments[newCompartments.length - 1];
|
|
183356
183837
|
insertUserMemoryCandidates(db, validatedPass.userObservations.map((obs) => ({
|
|
@@ -183364,7 +183845,7 @@ ${chunkText}`,
|
|
|
183364
183845
|
sessionLog(sessionId, "failed to store user memory candidates:", error51);
|
|
183365
183846
|
}
|
|
183366
183847
|
}
|
|
183367
|
-
if (!
|
|
183848
|
+
if (!skipUnanchoredPromotion && promotionProjectIdentity && validatedPass.primerCandidates && validatedPass.primerCandidates.length > 0) {
|
|
183368
183849
|
try {
|
|
183369
183850
|
const firstNew = newCompartments[0];
|
|
183370
183851
|
const lastNew = newCompartments[newCompartments.length - 1];
|
|
@@ -184231,6 +184712,21 @@ function markActiveCompartmentRunPublished(sessionId) {
|
|
|
184231
184712
|
if (activeRun)
|
|
184232
184713
|
activeRun.published = true;
|
|
184233
184714
|
}
|
|
184715
|
+
function registerActiveCompartmentRun(sessionId, promise2, kind = "other") {
|
|
184716
|
+
const activeRun = {
|
|
184717
|
+
promise: Promise.resolve(),
|
|
184718
|
+
published: false,
|
|
184719
|
+
kind
|
|
184720
|
+
};
|
|
184721
|
+
const wrapped = promise2.finally(() => {
|
|
184722
|
+
if (activeRuns.get(sessionId)?.promise === wrapped) {
|
|
184723
|
+
activeRuns.delete(sessionId);
|
|
184724
|
+
}
|
|
184725
|
+
});
|
|
184726
|
+
activeRun.promise = wrapped;
|
|
184727
|
+
activeRuns.set(sessionId, activeRun);
|
|
184728
|
+
return activeRun;
|
|
184729
|
+
}
|
|
184234
184730
|
function withPublishedCallback(deps) {
|
|
184235
184731
|
return {
|
|
184236
184732
|
...deps,
|
|
@@ -184242,8 +184738,12 @@ function withPublishedCallback(deps) {
|
|
|
184242
184738
|
}
|
|
184243
184739
|
function startLeaseRenewal(deps, holderId) {
|
|
184244
184740
|
return setInterval(() => {
|
|
184245
|
-
|
|
184246
|
-
|
|
184741
|
+
try {
|
|
184742
|
+
if (!renewCompartmentLease(deps.db, deps.sessionId, holderId)) {
|
|
184743
|
+
sessionLog(deps.sessionId, "compartment lease renewal failed; publish will be skipped if holder is stale");
|
|
184744
|
+
}
|
|
184745
|
+
} catch (err) {
|
|
184746
|
+
sessionLog(deps.sessionId, `compartment lease renewal threw; publish will be skipped if holder is stale (${err instanceof Error ? err.message : String(err)})`);
|
|
184247
184747
|
}
|
|
184248
184748
|
}, COMPARTMENT_LEASE_RENEWAL_MS);
|
|
184249
184749
|
}
|
|
@@ -184252,6 +184752,11 @@ function startCompartmentAgent(deps) {
|
|
|
184252
184752
|
if (existing) {
|
|
184253
184753
|
return;
|
|
184254
184754
|
}
|
|
184755
|
+
if (isWrapupInProgress(deps.db, deps.sessionId)) {
|
|
184756
|
+
sessionLog(deps.sessionId, "compartment agent skipped: /ctx-wrapup is active");
|
|
184757
|
+
updateSessionMeta(deps.db, deps.sessionId, { compartmentInProgress: false });
|
|
184758
|
+
return;
|
|
184759
|
+
}
|
|
184255
184760
|
const holderId = crypto.randomUUID();
|
|
184256
184761
|
const lease = acquireCompartmentLease(deps.db, deps.sessionId, holderId);
|
|
184257
184762
|
if (!lease) {
|
|
@@ -184259,6 +184764,12 @@ function startCompartmentAgent(deps) {
|
|
|
184259
184764
|
updateSessionMeta(deps.db, deps.sessionId, { compartmentInProgress: false });
|
|
184260
184765
|
return;
|
|
184261
184766
|
}
|
|
184767
|
+
if (isWrapupInProgress(deps.db, deps.sessionId)) {
|
|
184768
|
+
sessionLog(deps.sessionId, "compartment agent skipped: /ctx-wrapup became active");
|
|
184769
|
+
releaseCompartmentLease(deps.db, deps.sessionId, holderId);
|
|
184770
|
+
updateSessionMeta(deps.db, deps.sessionId, { compartmentInProgress: false });
|
|
184771
|
+
return;
|
|
184772
|
+
}
|
|
184262
184773
|
const renewal = startLeaseRenewal(deps, holderId);
|
|
184263
184774
|
let realRunStarted = false;
|
|
184264
184775
|
const runnerDeps = withPublishedCallback({
|
|
@@ -184280,13 +184791,19 @@ function startCompartmentAgent(deps) {
|
|
|
184280
184791
|
activeRuns.delete(deps.sessionId);
|
|
184281
184792
|
}
|
|
184282
184793
|
});
|
|
184283
|
-
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
184794
|
+
activeRuns.set(deps.sessionId, { promise: promise2, published: false, kind: "incremental" });
|
|
184284
184795
|
if (!realRunStarted && activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
184285
184796
|
activeRuns.delete(deps.sessionId);
|
|
184286
184797
|
}
|
|
184287
184798
|
}
|
|
184288
184799
|
async function executeContextRecompWithResult(deps, options = {}) {
|
|
184289
184800
|
const { sessionId } = deps;
|
|
184801
|
+
if (isWrapupInProgress(deps.db, sessionId)) {
|
|
184802
|
+
return {
|
|
184803
|
+
message: "## Magic Recomp — Skipped\n\n/ctx-wrapup is already compacting this session. Wait for it to finish, then try `/ctx-recomp` again.",
|
|
184804
|
+
published: false
|
|
184805
|
+
};
|
|
184806
|
+
}
|
|
184290
184807
|
if (activeRuns.has(sessionId)) {
|
|
184291
184808
|
return {
|
|
184292
184809
|
message: "## Magic Recomp — Skipped\n\nHistorian is already running for this session. Wait for it to finish, then try `/ctx-recomp` again.",
|
|
@@ -184310,7 +184827,7 @@ async function executeContextRecompWithResult(deps, options = {}) {
|
|
|
184310
184827
|
}).catch((err) => {
|
|
184311
184828
|
sessionLog(sessionId, "compartment agent: recomp unhandled rejection:", err);
|
|
184312
184829
|
});
|
|
184313
|
-
activeRuns.set(sessionId, { promise: wrappedPromise, published: false });
|
|
184830
|
+
activeRuns.set(sessionId, { promise: wrappedPromise, published: false, kind: "recomp" });
|
|
184314
184831
|
try {
|
|
184315
184832
|
const message = await promise2;
|
|
184316
184833
|
const published = activeRuns.get(sessionId)?.published === true;
|
|
@@ -184738,6 +185255,13 @@ Recomp crashed: ${String(error51)}`;
|
|
|
184738
185255
|
}
|
|
184739
185256
|
}
|
|
184740
185257
|
async function runManagedUpgrade(ctx, sessionId) {
|
|
185258
|
+
if (isWrapupInProgress(ctx.db, sessionId)) {
|
|
185259
|
+
const message = "/ctx-wrapup is already compacting this session. Wait for it to finish, then try `/ctx-session-upgrade` again.";
|
|
185260
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "skipped", message);
|
|
185261
|
+
return `## Session Upgrade — Skipped
|
|
185262
|
+
|
|
185263
|
+
${message}`;
|
|
185264
|
+
}
|
|
184741
185265
|
setRecompStarting(ctx.liveSessionState, sessionId, "Starting upgrade…", "upgrade");
|
|
184742
185266
|
try {
|
|
184743
185267
|
const compartments = getCompartments(ctx.db, sessionId);
|
|
@@ -184892,13 +185416,14 @@ function shouldShowAnnouncement() {
|
|
|
184892
185416
|
}
|
|
184893
185417
|
return ordering > 0;
|
|
184894
185418
|
}
|
|
184895
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
185419
|
+
var ANNOUNCEMENT_VERSION = "0.31.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
184896
185420
|
var init_announcement = __esm(() => {
|
|
184897
185421
|
init_data_path();
|
|
184898
185422
|
ANNOUNCEMENT_FEATURES = [
|
|
184899
|
-
"
|
|
184900
|
-
"
|
|
184901
|
-
"
|
|
185423
|
+
"New /ctx-wrapup command: compact older history on demand, keeping the newest N messages raw. Run it before switching to a smaller-context model.",
|
|
185424
|
+
"ctx_search now also searches your session notes and smart notes.",
|
|
185425
|
+
"Project identity now survives transient git failures (slow disks, dubious ownership) without splitting your project memory.",
|
|
185426
|
+
"Removed the ctx_reduce_enabled setting; agent-controlled reduction is always on. Caveman text compression is now independent (caveman_text_compression.enabled)."
|
|
184902
185427
|
];
|
|
184903
185428
|
});
|
|
184904
185429
|
|
|
@@ -186326,6 +186851,10 @@ function getMagicContextBuiltinCommands() {
|
|
|
186326
186851
|
template: "ctx-recomp",
|
|
186327
186852
|
description: "Rebuild compartments and facts from raw history (full or <start>-<end> range)"
|
|
186328
186853
|
},
|
|
186854
|
+
"ctx-wrapup": {
|
|
186855
|
+
template: "ctx-wrapup",
|
|
186856
|
+
description: "Compact older live history while keeping the newest messages raw"
|
|
186857
|
+
},
|
|
186329
186858
|
"ctx-session-upgrade": {
|
|
186330
186859
|
template: "ctx-session-upgrade",
|
|
186331
186860
|
description: "Upgrade this session to the latest history format: rebuild compartments and migrate project memories"
|
|
@@ -186349,6 +186878,29 @@ function getMagicContextBuiltinCommands() {
|
|
|
186349
186878
|
};
|
|
186350
186879
|
}
|
|
186351
186880
|
|
|
186881
|
+
// src/features/magic-context/dreamer/open-opencode-db.ts
|
|
186882
|
+
init_logger();
|
|
186883
|
+
await __promiseAll([
|
|
186884
|
+
init_sqlite(),
|
|
186885
|
+
init_compaction_marker()
|
|
186886
|
+
]);
|
|
186887
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
186888
|
+
function openOpenCodeDb() {
|
|
186889
|
+
const dbPath = getOpenCodeDbPath();
|
|
186890
|
+
if (!existsSync7(dbPath)) {
|
|
186891
|
+
log(`[dreamer] OpenCode DB not found at ${dbPath} — skipping OpenCode history scan`);
|
|
186892
|
+
return null;
|
|
186893
|
+
}
|
|
186894
|
+
try {
|
|
186895
|
+
const db = new Database(dbPath, { readonly: true });
|
|
186896
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
186897
|
+
return db;
|
|
186898
|
+
} catch (error51) {
|
|
186899
|
+
log(`[dreamer] failed to open OpenCode DB at ${dbPath}: ${getErrorMessage(error51)}`);
|
|
186900
|
+
return null;
|
|
186901
|
+
}
|
|
186902
|
+
}
|
|
186903
|
+
|
|
186352
186904
|
// src/features/magic-context/dreamer/task-prompts.ts
|
|
186353
186905
|
var DREAMER_SYSTEM_PROMPT = `You are a background maintenance agent for the magic-context system, running during a scheduled dream window. Your task and its full instructions arrive in the message below. Never read or quote secrets from .env, credentials, or key files, and never commit — the user handles git.`;
|
|
186354
186906
|
var PROJECT_MEMORY_TAXONOMY = `## Memory taxonomy (5 categories)
|
|
@@ -186658,6 +187210,192 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
186658
187210
|
// src/index.ts
|
|
186659
187211
|
init_project_identity();
|
|
186660
187212
|
|
|
187213
|
+
// src/features/magic-context/session-project-backfill.ts
|
|
187214
|
+
init_logger();
|
|
187215
|
+
init_project_identity();
|
|
187216
|
+
init_session_project_storage();
|
|
187217
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
187218
|
+
var LEASE_TTL_MS = 10 * 60 * 1000;
|
|
187219
|
+
var SESSION_QUERY_CHUNK_SIZE = 250;
|
|
187220
|
+
var YIELD_EVERY_NEW_DIRECTORIES = 10;
|
|
187221
|
+
function ensureBackfillStateTable(db) {
|
|
187222
|
+
db.exec(`
|
|
187223
|
+
CREATE TABLE IF NOT EXISTS session_project_backfill_state (
|
|
187224
|
+
harness TEXT PRIMARY KEY,
|
|
187225
|
+
status TEXT NOT NULL CHECK (status IN ('running', 'completed')),
|
|
187226
|
+
started_at INTEGER,
|
|
187227
|
+
lease_expires_at INTEGER,
|
|
187228
|
+
completed_at INTEGER
|
|
187229
|
+
);
|
|
187230
|
+
`);
|
|
187231
|
+
}
|
|
187232
|
+
function withImmediateTransaction(db, fn) {
|
|
187233
|
+
db.exec("BEGIN IMMEDIATE");
|
|
187234
|
+
try {
|
|
187235
|
+
const result = fn();
|
|
187236
|
+
db.exec("COMMIT");
|
|
187237
|
+
return result;
|
|
187238
|
+
} catch (error51) {
|
|
187239
|
+
try {
|
|
187240
|
+
db.exec("ROLLBACK");
|
|
187241
|
+
} catch {}
|
|
187242
|
+
throw error51;
|
|
187243
|
+
}
|
|
187244
|
+
}
|
|
187245
|
+
function defaultYieldFn() {
|
|
187246
|
+
return new Promise((resolve2) => setTimeout(resolve2, 0));
|
|
187247
|
+
}
|
|
187248
|
+
function acquireBackfillLease(db, harness, now) {
|
|
187249
|
+
ensureBackfillStateTable(db);
|
|
187250
|
+
return withImmediateTransaction(db, () => {
|
|
187251
|
+
const current = db.prepare(`SELECT harness, status, started_at, lease_expires_at, completed_at
|
|
187252
|
+
FROM session_project_backfill_state
|
|
187253
|
+
WHERE harness = ?`).get(harness);
|
|
187254
|
+
if (current?.status === "completed") {
|
|
187255
|
+
return "already_completed";
|
|
187256
|
+
}
|
|
187257
|
+
if (current?.status === "running" && current.lease_expires_at !== null && current.lease_expires_at > now) {
|
|
187258
|
+
return "blocked_by_lease";
|
|
187259
|
+
}
|
|
187260
|
+
db.prepare(`INSERT INTO session_project_backfill_state(
|
|
187261
|
+
harness,
|
|
187262
|
+
status,
|
|
187263
|
+
started_at,
|
|
187264
|
+
lease_expires_at,
|
|
187265
|
+
completed_at
|
|
187266
|
+
)
|
|
187267
|
+
VALUES (?, 'running', ?, ?, NULL)
|
|
187268
|
+
ON CONFLICT(harness) DO UPDATE SET
|
|
187269
|
+
status = 'running',
|
|
187270
|
+
started_at = excluded.started_at,
|
|
187271
|
+
lease_expires_at = excluded.lease_expires_at,
|
|
187272
|
+
completed_at = NULL`).run(harness, now, now + LEASE_TTL_MS);
|
|
187273
|
+
return "completed";
|
|
187274
|
+
});
|
|
187275
|
+
}
|
|
187276
|
+
function renewBackfillLease(db, harness, now) {
|
|
187277
|
+
ensureBackfillStateTable(db);
|
|
187278
|
+
db.prepare(`UPDATE session_project_backfill_state
|
|
187279
|
+
SET lease_expires_at = ?
|
|
187280
|
+
WHERE harness = ? AND status = 'running'`).run(now + LEASE_TTL_MS, harness);
|
|
187281
|
+
}
|
|
187282
|
+
function markBackfillCompleted(db, harness, now) {
|
|
187283
|
+
ensureBackfillStateTable(db);
|
|
187284
|
+
db.prepare(`INSERT INTO session_project_backfill_state(
|
|
187285
|
+
harness,
|
|
187286
|
+
status,
|
|
187287
|
+
started_at,
|
|
187288
|
+
lease_expires_at,
|
|
187289
|
+
completed_at
|
|
187290
|
+
)
|
|
187291
|
+
VALUES (?, 'completed', ?, NULL, ?)
|
|
187292
|
+
ON CONFLICT(harness) DO UPDATE SET
|
|
187293
|
+
status = 'completed',
|
|
187294
|
+
lease_expires_at = NULL,
|
|
187295
|
+
completed_at = excluded.completed_at`).run(harness, now, now);
|
|
187296
|
+
}
|
|
187297
|
+
function dedupeSessions(sessions) {
|
|
187298
|
+
const sessionsById = new Map;
|
|
187299
|
+
for (const session of sessions) {
|
|
187300
|
+
if (!session.sessionId)
|
|
187301
|
+
continue;
|
|
187302
|
+
const existing = sessionsById.get(session.sessionId);
|
|
187303
|
+
if (!existing) {
|
|
187304
|
+
sessionsById.set(session.sessionId, {
|
|
187305
|
+
sessionId: session.sessionId,
|
|
187306
|
+
directory: session.directory
|
|
187307
|
+
});
|
|
187308
|
+
continue;
|
|
187309
|
+
}
|
|
187310
|
+
if (!existing.directory && session.directory) {
|
|
187311
|
+
sessionsById.set(session.sessionId, {
|
|
187312
|
+
sessionId: session.sessionId,
|
|
187313
|
+
directory: session.directory
|
|
187314
|
+
});
|
|
187315
|
+
}
|
|
187316
|
+
}
|
|
187317
|
+
return [...sessionsById.values()];
|
|
187318
|
+
}
|
|
187319
|
+
function getMappedSessionIds(db, harness, sessions) {
|
|
187320
|
+
const mapped = new Set;
|
|
187321
|
+
for (let index = 0;index < sessions.length; index += SESSION_QUERY_CHUNK_SIZE) {
|
|
187322
|
+
const chunk = sessions.slice(index, index + SESSION_QUERY_CHUNK_SIZE);
|
|
187323
|
+
if (chunk.length === 0)
|
|
187324
|
+
continue;
|
|
187325
|
+
const placeholders = chunk.map(() => "?").join(", ");
|
|
187326
|
+
const rows = db.prepare(`SELECT session_id
|
|
187327
|
+
FROM session_projects
|
|
187328
|
+
WHERE harness = ?
|
|
187329
|
+
AND session_id IN (${placeholders})`).all(harness, ...chunk.map((session) => session.sessionId));
|
|
187330
|
+
for (const row of rows) {
|
|
187331
|
+
mapped.add(row.session_id);
|
|
187332
|
+
}
|
|
187333
|
+
}
|
|
187334
|
+
return mapped;
|
|
187335
|
+
}
|
|
187336
|
+
async function runSessionProjectBackfill(db, sessions, options = {}) {
|
|
187337
|
+
const startedAt = performance.now();
|
|
187338
|
+
const harness = getHarness();
|
|
187339
|
+
const now = options.now ?? Date.now;
|
|
187340
|
+
const resolveIdentity = options.resolveIdentity ?? resolveProjectIdentity;
|
|
187341
|
+
const yieldFn = options.yieldFn ?? defaultYieldFn;
|
|
187342
|
+
const dedupedSessions = dedupeSessions(sessions);
|
|
187343
|
+
const result = {
|
|
187344
|
+
status: "completed",
|
|
187345
|
+
totalSessions: dedupedSessions.length,
|
|
187346
|
+
alreadyMappedSessions: 0,
|
|
187347
|
+
unmappedSessions: 0,
|
|
187348
|
+
backfilledSessions: 0,
|
|
187349
|
+
skippedDeadDirectories: 0,
|
|
187350
|
+
skippedEmptyDirectories: 0,
|
|
187351
|
+
durationMs: 0
|
|
187352
|
+
};
|
|
187353
|
+
const leaseStatus = acquireBackfillLease(db, harness, now());
|
|
187354
|
+
if (leaseStatus !== "completed") {
|
|
187355
|
+
result.status = leaseStatus;
|
|
187356
|
+
result.durationMs = performance.now() - startedAt;
|
|
187357
|
+
return result;
|
|
187358
|
+
}
|
|
187359
|
+
const mappedSessionIds = getMappedSessionIds(db, harness, dedupedSessions);
|
|
187360
|
+
result.alreadyMappedSessions = mappedSessionIds.size;
|
|
187361
|
+
const existenceCache = new Map;
|
|
187362
|
+
const identityCache2 = new Map;
|
|
187363
|
+
let newDirectoryResolutions = 0;
|
|
187364
|
+
for (const session of dedupedSessions) {
|
|
187365
|
+
if (mappedSessionIds.has(session.sessionId)) {
|
|
187366
|
+
continue;
|
|
187367
|
+
}
|
|
187368
|
+
result.unmappedSessions += 1;
|
|
187369
|
+
if (!session.directory) {
|
|
187370
|
+
result.skippedEmptyDirectories += 1;
|
|
187371
|
+
continue;
|
|
187372
|
+
}
|
|
187373
|
+
const stillExists = existenceCache.get(session.directory) ?? existsSync9(session.directory);
|
|
187374
|
+
existenceCache.set(session.directory, stillExists);
|
|
187375
|
+
if (!stillExists) {
|
|
187376
|
+
result.skippedDeadDirectories += 1;
|
|
187377
|
+
continue;
|
|
187378
|
+
}
|
|
187379
|
+
let identity = identityCache2.get(session.directory);
|
|
187380
|
+
if (!identity) {
|
|
187381
|
+
identity = resolveIdentity(session.directory);
|
|
187382
|
+
identityCache2.set(session.directory, identity);
|
|
187383
|
+
newDirectoryResolutions += 1;
|
|
187384
|
+
if (newDirectoryResolutions % YIELD_EVERY_NEW_DIRECTORIES === 0) {
|
|
187385
|
+
renewBackfillLease(db, harness, now());
|
|
187386
|
+
await yieldFn();
|
|
187387
|
+
renewBackfillLease(db, harness, now());
|
|
187388
|
+
}
|
|
187389
|
+
}
|
|
187390
|
+
recordSessionProjectIdentity(db, session.sessionId, identity);
|
|
187391
|
+
result.backfilledSessions += 1;
|
|
187392
|
+
}
|
|
187393
|
+
markBackfillCompleted(db, harness, now());
|
|
187394
|
+
result.durationMs = performance.now() - startedAt;
|
|
187395
|
+
log(`[session-projects] backfilled ${result.backfilledSessions} of ${result.unmappedSessions} unmapped sessions (skipped ${result.skippedDeadDirectories} dead dirs) in ${Math.round(result.durationMs)}ms`);
|
|
187396
|
+
return result;
|
|
187397
|
+
}
|
|
187398
|
+
|
|
186661
187399
|
// src/features/magic-context/sidekick/agent.ts
|
|
186662
187400
|
init_language_directive();
|
|
186663
187401
|
|
|
@@ -186821,7 +187559,7 @@ await init_storage_db();
|
|
|
186821
187559
|
init_logger();
|
|
186822
187560
|
init_project_identity();
|
|
186823
187561
|
import { createHash as createHash5 } from "node:crypto";
|
|
186824
|
-
import { realpathSync } from "node:fs";
|
|
187562
|
+
import { realpathSync as realpathSync2 } from "node:fs";
|
|
186825
187563
|
import path5 from "node:path";
|
|
186826
187564
|
|
|
186827
187565
|
// src/features/magic-context/memory/relocate-memory.ts
|
|
@@ -186855,7 +187593,10 @@ function countFailures(db) {
|
|
|
186855
187593
|
}
|
|
186856
187594
|
function classifyBackfillError(error51) {
|
|
186857
187595
|
if (error51 instanceof ProjectIdentityError) {
|
|
186858
|
-
return {
|
|
187596
|
+
return {
|
|
187597
|
+
errorClass: error51.errorClass === "dubious_ownership" ? "unknown" : error51.errorClass,
|
|
187598
|
+
errorMessage: error51.message
|
|
187599
|
+
};
|
|
186859
187600
|
}
|
|
186860
187601
|
if (error51 instanceof Error) {
|
|
186861
187602
|
return { errorClass: "unknown", errorMessage: error51.message };
|
|
@@ -186875,7 +187616,7 @@ function resolveBackfillIdentity(rawProjectPath) {
|
|
|
186875
187616
|
function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
186876
187617
|
let canonical;
|
|
186877
187618
|
try {
|
|
186878
|
-
canonical =
|
|
187619
|
+
canonical = realpathSync2(rawProjectPath);
|
|
186879
187620
|
} catch {
|
|
186880
187621
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
186881
187622
|
}
|
|
@@ -187048,45 +187789,45 @@ async function runDeferredV22Backfill(db, options = {}) {
|
|
|
187048
187789
|
|
|
187049
187790
|
// src/hooks/auto-update-checker/index.ts
|
|
187050
187791
|
init_logger();
|
|
187051
|
-
import { existsSync as
|
|
187052
|
-
import { dirname as dirname7, join as
|
|
187792
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync9, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
187793
|
+
import { dirname as dirname7, join as join10 } from "node:path";
|
|
187053
187794
|
|
|
187054
187795
|
// src/hooks/auto-update-checker/cache.ts
|
|
187055
187796
|
init_logger();
|
|
187056
187797
|
var import_comment_json2 = __toESM(require_src2(), 1);
|
|
187057
187798
|
import { spawn } from "node:child_process";
|
|
187058
|
-
import { existsSync as
|
|
187059
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
187799
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
187800
|
+
import { basename as basename2, dirname as dirname6, join as join9 } from "node:path";
|
|
187060
187801
|
|
|
187061
187802
|
// src/hooks/auto-update-checker/checker.ts
|
|
187062
187803
|
init_logger();
|
|
187063
187804
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
187064
|
-
import { existsSync as
|
|
187805
|
+
import { existsSync as existsSync13, readFileSync as readFileSync7, renameSync as renameSync2, statSync as statSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
187065
187806
|
import { homedir as homedir5 } from "node:os";
|
|
187066
|
-
import { dirname as dirname5, isAbsolute as isAbsolute3, join as
|
|
187807
|
+
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join8, resolve as resolve2 } from "node:path";
|
|
187067
187808
|
import { fileURLToPath } from "node:url";
|
|
187068
187809
|
|
|
187069
187810
|
// src/hooks/auto-update-checker/constants.ts
|
|
187070
187811
|
import { homedir as homedir4, platform } from "node:os";
|
|
187071
|
-
import { join as
|
|
187812
|
+
import { join as join7 } from "node:path";
|
|
187072
187813
|
var PACKAGE_NAME = "@cortexkit/opencode-magic-context";
|
|
187073
187814
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
187074
187815
|
var NPM_FETCH_TIMEOUT = 1e4;
|
|
187075
187816
|
function getOpenCodeCacheRoot() {
|
|
187076
187817
|
if (platform() === "win32") {
|
|
187077
|
-
return
|
|
187818
|
+
return join7(process.env.LOCALAPPDATA ?? homedir4(), "opencode");
|
|
187078
187819
|
}
|
|
187079
|
-
return
|
|
187820
|
+
return join7(homedir4(), ".cache", "opencode");
|
|
187080
187821
|
}
|
|
187081
187822
|
function getOpenCodeConfigRoot() {
|
|
187082
187823
|
if (platform() === "win32") {
|
|
187083
|
-
return
|
|
187824
|
+
return join7(process.env.APPDATA ?? join7(homedir4(), "AppData", "Roaming"), "opencode");
|
|
187084
187825
|
}
|
|
187085
|
-
return
|
|
187826
|
+
return join7(process.env.XDG_CONFIG_HOME ?? join7(homedir4(), ".config"), "opencode");
|
|
187086
187827
|
}
|
|
187087
|
-
var CACHE_DIR =
|
|
187088
|
-
var USER_OPENCODE_CONFIG =
|
|
187089
|
-
var USER_OPENCODE_CONFIG_JSONC =
|
|
187828
|
+
var CACHE_DIR = join7(getOpenCodeCacheRoot(), "packages");
|
|
187829
|
+
var USER_OPENCODE_CONFIG = join7(getOpenCodeConfigRoot(), "opencode.json");
|
|
187830
|
+
var USER_OPENCODE_CONFIG_JSONC = join7(getOpenCodeConfigRoot(), "opencode.jsonc");
|
|
187090
187831
|
// src/hooks/auto-update-checker/types.ts
|
|
187091
187832
|
init_zod();
|
|
187092
187833
|
var NpmPackageEnvelopeSchema = exports_external.object({
|
|
@@ -187147,8 +187888,8 @@ function extractChannel(version2) {
|
|
|
187147
187888
|
}
|
|
187148
187889
|
function getConfigPaths(directory) {
|
|
187149
187890
|
return [
|
|
187150
|
-
|
|
187151
|
-
|
|
187891
|
+
join8(directory, ".opencode", "opencode.json"),
|
|
187892
|
+
join8(directory, ".opencode", "opencode.jsonc"),
|
|
187152
187893
|
USER_OPENCODE_CONFIG,
|
|
187153
187894
|
USER_OPENCODE_CONFIG_JSONC
|
|
187154
187895
|
];
|
|
@@ -187170,8 +187911,8 @@ function findPackageJsonUp(startPath) {
|
|
|
187170
187911
|
const stat = statSync4(startPath);
|
|
187171
187912
|
let dir = stat.isDirectory() ? startPath : dirname5(startPath);
|
|
187172
187913
|
for (let i = 0;i < 10; i++) {
|
|
187173
|
-
const pkgPath =
|
|
187174
|
-
if (
|
|
187914
|
+
const pkgPath = join8(dir, "package.json");
|
|
187915
|
+
if (existsSync13(pkgPath)) {
|
|
187175
187916
|
try {
|
|
187176
187917
|
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync7(pkgPath, "utf-8")));
|
|
187177
187918
|
if (pkg.success && pkg.data.name === PACKAGE_NAME)
|
|
@@ -187189,7 +187930,7 @@ function findPackageJsonUp(startPath) {
|
|
|
187189
187930
|
function getLocalDevPath(directory) {
|
|
187190
187931
|
for (const configPath of getConfigPaths(directory)) {
|
|
187191
187932
|
try {
|
|
187192
|
-
if (!
|
|
187933
|
+
if (!existsSync13(configPath))
|
|
187193
187934
|
continue;
|
|
187194
187935
|
const rawConfig = parseJsonConfig(readFileSync7(configPath, "utf-8"));
|
|
187195
187936
|
const plugins = getPluginEntries(rawConfig);
|
|
@@ -187235,7 +187976,7 @@ function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
|
|
|
187235
187976
|
function findPluginEntry(directory) {
|
|
187236
187977
|
for (const configPath of getConfigPaths(directory)) {
|
|
187237
187978
|
try {
|
|
187238
|
-
if (!
|
|
187979
|
+
if (!existsSync13(configPath))
|
|
187239
187980
|
continue;
|
|
187240
187981
|
const rawConfig = parseJsonConfig(readFileSync7(configPath, "utf-8"));
|
|
187241
187982
|
const plugins = getPluginEntries(rawConfig);
|
|
@@ -187260,7 +188001,7 @@ function findPluginEntry(directory) {
|
|
|
187260
188001
|
}
|
|
187261
188002
|
var cachedPackageVersion = null;
|
|
187262
188003
|
function getSpecCachePackageJsonPath(spec) {
|
|
187263
|
-
return
|
|
188004
|
+
return join8(CACHE_DIR, spec, "node_modules", PACKAGE_NAME, "package.json");
|
|
187264
188005
|
}
|
|
187265
188006
|
function getCachedVersion(spec) {
|
|
187266
188007
|
if (!spec && cachedPackageVersion)
|
|
@@ -187269,11 +188010,11 @@ function getCachedVersion(spec) {
|
|
|
187269
188010
|
getCurrentRuntimePackageJsonPath(),
|
|
187270
188011
|
spec ? getSpecCachePackageJsonPath(spec) : null,
|
|
187271
188012
|
getSpecCachePackageJsonPath(`${PACKAGE_NAME}@latest`),
|
|
187272
|
-
|
|
188013
|
+
join8(homedir5(), ".cache", "opencode", "node_modules", PACKAGE_NAME, "package.json")
|
|
187273
188014
|
].filter(isString);
|
|
187274
188015
|
for (const packageJsonPath of candidates) {
|
|
187275
188016
|
try {
|
|
187276
|
-
if (!
|
|
188017
|
+
if (!existsSync13(packageJsonPath))
|
|
187277
188018
|
continue;
|
|
187278
188019
|
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync7(packageJsonPath, "utf-8")));
|
|
187279
188020
|
if (pkg.success && pkg.data.version) {
|
|
@@ -187327,8 +188068,8 @@ function stripPackageNameFromPath(pathValue, packageName) {
|
|
|
187327
188068
|
return current;
|
|
187328
188069
|
}
|
|
187329
188070
|
function removeFromPackageLock(installDir, packageName) {
|
|
187330
|
-
const lockPath =
|
|
187331
|
-
if (!
|
|
188071
|
+
const lockPath = join9(installDir, "package-lock.json");
|
|
188072
|
+
if (!existsSync14(lockPath))
|
|
187332
188073
|
return false;
|
|
187333
188074
|
try {
|
|
187334
188075
|
const lock = import_comment_json2.parse(readFileSync8(lockPath, "utf-8"));
|
|
@@ -187354,7 +188095,7 @@ function removeFromPackageLock(installDir, packageName) {
|
|
|
187354
188095
|
}
|
|
187355
188096
|
}
|
|
187356
188097
|
function ensureDependencyVersion(packageJsonPath, packageName, version2) {
|
|
187357
|
-
if (!
|
|
188098
|
+
if (!existsSync14(packageJsonPath))
|
|
187358
188099
|
return false;
|
|
187359
188100
|
try {
|
|
187360
188101
|
const raw = import_comment_json2.parse(readFileSync8(packageJsonPath, "utf-8"));
|
|
@@ -187376,8 +188117,8 @@ function ensureDependencyVersion(packageJsonPath, packageName, version2) {
|
|
|
187376
188117
|
}
|
|
187377
188118
|
}
|
|
187378
188119
|
function removeInstalledPackage(installDir, packageName) {
|
|
187379
|
-
const packageDir =
|
|
187380
|
-
if (!
|
|
188120
|
+
const packageDir = join9(installDir, "node_modules", packageName);
|
|
188121
|
+
if (!existsSync14(packageDir))
|
|
187381
188122
|
return false;
|
|
187382
188123
|
try {
|
|
187383
188124
|
rmSync2(packageDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
@@ -187398,8 +188139,8 @@ function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackage
|
|
|
187398
188139
|
const nodeModulesDir = stripPackageNameFromPath(packageDir, PACKAGE_NAME);
|
|
187399
188140
|
if (nodeModulesDir && basename2(nodeModulesDir) === "node_modules") {
|
|
187400
188141
|
const installDir = dirname6(nodeModulesDir);
|
|
187401
|
-
const packageJsonPath =
|
|
187402
|
-
if (!
|
|
188142
|
+
const packageJsonPath = join9(installDir, "package.json");
|
|
188143
|
+
if (!existsSync14(packageJsonPath)) {
|
|
187403
188144
|
try {
|
|
187404
188145
|
writeFileSync4(packageJsonPath, `${JSON.stringify({ private: true, dependencies: {} }, null, 2)}
|
|
187405
188146
|
`);
|
|
@@ -187413,8 +188154,8 @@ function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackage
|
|
|
187413
188154
|
}
|
|
187414
188155
|
return null;
|
|
187415
188156
|
}
|
|
187416
|
-
const legacyPackageJsonPath =
|
|
187417
|
-
if (
|
|
188157
|
+
const legacyPackageJsonPath = join9(dirname6(CACHE_DIR), "package.json");
|
|
188158
|
+
if (existsSync14(legacyPackageJsonPath)) {
|
|
187418
188159
|
return { installDir: dirname6(CACHE_DIR), packageJsonPath: legacyPackageJsonPath };
|
|
187419
188160
|
}
|
|
187420
188161
|
return null;
|
|
@@ -187538,8 +188279,8 @@ function claimCheckSlot(storageDir, intervalMs) {
|
|
|
187538
188279
|
if (!storageDir)
|
|
187539
188280
|
return true;
|
|
187540
188281
|
try {
|
|
187541
|
-
const file2 =
|
|
187542
|
-
if (
|
|
188282
|
+
const file2 = join10(storageDir, TIMESTAMP_FILENAME);
|
|
188283
|
+
if (existsSync15(file2)) {
|
|
187543
188284
|
try {
|
|
187544
188285
|
const raw = JSON.parse(readFileSync9(file2, "utf-8"));
|
|
187545
188286
|
const last = typeof raw.lastCheckedMs === "number" ? raw.lastCheckedMs : 0;
|
|
@@ -187845,29 +188586,6 @@ function releaseLease(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
|
|
|
187845
188586
|
});
|
|
187846
188587
|
}
|
|
187847
188588
|
|
|
187848
|
-
// src/features/magic-context/dreamer/open-opencode-db.ts
|
|
187849
|
-
init_logger();
|
|
187850
|
-
await __promiseAll([
|
|
187851
|
-
init_sqlite(),
|
|
187852
|
-
init_compaction_marker()
|
|
187853
|
-
]);
|
|
187854
|
-
import { existsSync as existsSync13 } from "node:fs";
|
|
187855
|
-
function openOpenCodeDb() {
|
|
187856
|
-
const dbPath = getOpenCodeDbPath2();
|
|
187857
|
-
if (!existsSync13(dbPath)) {
|
|
187858
|
-
log(`[key-files] OpenCode DB not found at ${dbPath} — skipping`);
|
|
187859
|
-
return null;
|
|
187860
|
-
}
|
|
187861
|
-
try {
|
|
187862
|
-
const db = new Database(dbPath, { readonly: true });
|
|
187863
|
-
db.exec("PRAGMA busy_timeout = 5000");
|
|
187864
|
-
return db;
|
|
187865
|
-
} catch (error51) {
|
|
187866
|
-
log(`[key-files] failed to open OpenCode DB at ${dbPath}: ${getErrorMessage(error51)}`);
|
|
187867
|
-
return null;
|
|
187868
|
-
}
|
|
187869
|
-
}
|
|
187870
|
-
|
|
187871
188589
|
// src/features/magic-context/dreamer/retrospective-orphan-sweep.ts
|
|
187872
188590
|
init_logger();
|
|
187873
188591
|
var RETROSPECTIVE_CHILD_TITLE = "magic-context-dream-retrospective";
|
|
@@ -188290,7 +189008,7 @@ init_task_config();
|
|
|
188290
189008
|
|
|
188291
189009
|
// src/features/magic-context/dreamer/task-executor.ts
|
|
188292
189010
|
import { createHash as createHash10 } from "node:crypto";
|
|
188293
|
-
import { existsSync as
|
|
189011
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
188294
189012
|
|
|
188295
189013
|
// src/agents/dreamer.ts
|
|
188296
189014
|
var DREAMER_AGENT = "dreamer";
|
|
@@ -190377,7 +191095,7 @@ Output exactly JSON: {"met": false}`;
|
|
|
190377
191095
|
|
|
190378
191096
|
// src/features/magic-context/dreamer/maintain-docs-protected-enforcement.ts
|
|
190379
191097
|
init_logger();
|
|
190380
|
-
import { existsSync as
|
|
191098
|
+
import { existsSync as existsSync18, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
|
|
190381
191099
|
import { join as join15 } from "node:path";
|
|
190382
191100
|
|
|
190383
191101
|
// src/features/magic-context/dreamer/protected-regions.ts
|
|
@@ -190481,7 +191199,7 @@ function snapshotMaintainDocsFiles(docsDir) {
|
|
|
190481
191199
|
for (const name2 of MAINTAIN_DOCS_SNAPSHOT_FILES) {
|
|
190482
191200
|
const path8 = join15(docsDir, name2);
|
|
190483
191201
|
try {
|
|
190484
|
-
if (
|
|
191202
|
+
if (existsSync18(path8)) {
|
|
190485
191203
|
snapshot.set(name2, readFileSync11(path8, "utf8"));
|
|
190486
191204
|
}
|
|
190487
191205
|
} catch {}
|
|
@@ -190513,7 +191231,7 @@ init_memory();
|
|
|
190513
191231
|
init_subagent_token_capture();
|
|
190514
191232
|
|
|
190515
191233
|
// src/features/magic-context/dreamer/map-memories-prompt.ts
|
|
190516
|
-
import { existsSync as
|
|
191234
|
+
import { existsSync as existsSync19, statSync as statSync6 } from "node:fs";
|
|
190517
191235
|
import path8 from "node:path";
|
|
190518
191236
|
var MAP_MEMORIES_SYSTEM_PROMPT = `You are a memory mapper for the magic-context system. You map project memories to the repository files that back them.
|
|
190519
191237
|
|
|
@@ -190551,7 +191269,7 @@ function extractMemoryCandidatePaths(content, repoDir) {
|
|
|
190551
191269
|
if (!abs.startsWith(`${root}/`))
|
|
190552
191270
|
continue;
|
|
190553
191271
|
try {
|
|
190554
|
-
if (
|
|
191272
|
+
if (existsSync19(abs) && statSync6(abs).isFile())
|
|
190555
191273
|
found.add(rel);
|
|
190556
191274
|
} catch {}
|
|
190557
191275
|
if (found.size >= MAX_SEED_PATHS_PER_MEMORY)
|
|
@@ -192380,8 +193098,8 @@ async function runAgenticTask(config2, ctx, helpers) {
|
|
|
192380
193098
|
const lastRunAt = getTaskScheduleState(db, projectIdentity, config2.task)?.lastRunAt ?? null;
|
|
192381
193099
|
const maintainDocsSnapshot = task === "maintain-docs" ? snapshotMaintainDocsFiles(docsDir) : undefined;
|
|
192382
193100
|
const existingDocs = task === "maintain-docs" ? {
|
|
192383
|
-
architecture:
|
|
192384
|
-
structure:
|
|
193101
|
+
architecture: existsSync20(`${docsDir}/ARCHITECTURE.md`),
|
|
193102
|
+
structure: existsSync20(`${docsDir}/STRUCTURE.md`)
|
|
192385
193103
|
} : undefined;
|
|
192386
193104
|
const userMemories = task === "curate" ? getActiveUserMemories(db).map((um) => ({ id: um.id, content: um.content })) : undefined;
|
|
192387
193105
|
let curateMemories;
|
|
@@ -194548,6 +195266,17 @@ ${c.content}
|
|
|
194548
195266
|
init_send_session_notification();
|
|
194549
195267
|
var recompConfirmationBySession = new Map;
|
|
194550
195268
|
var RECOMP_CONFIRMATION_WINDOW_MS = 60000;
|
|
195269
|
+
function isSubagentSession(db, sessionId) {
|
|
195270
|
+
const meta3 = getOrCreateSessionMeta(db, sessionId);
|
|
195271
|
+
if (meta3.isSubagent)
|
|
195272
|
+
return true;
|
|
195273
|
+
try {
|
|
195274
|
+
const row = db.prepare("SELECT is_subagent FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
195275
|
+
return row?.is_subagent === 1 || row?.is_subagent === true;
|
|
195276
|
+
} catch {
|
|
195277
|
+
return false;
|
|
195278
|
+
}
|
|
195279
|
+
}
|
|
194551
195280
|
var RECOMP_USAGE = [
|
|
194552
195281
|
"Usage:",
|
|
194553
195282
|
"- `/ctx-recomp` — full rebuild from message 1 to the protected tail",
|
|
@@ -194586,6 +195315,22 @@ ${RECOMP_USAGE}`
|
|
|
194586
195315
|
}
|
|
194587
195316
|
return { kind: "partial", range: { start, end } };
|
|
194588
195317
|
}
|
|
195318
|
+
function parseWrapupArgs(raw) {
|
|
195319
|
+
const trimmed = raw.trim();
|
|
195320
|
+
if (trimmed === "")
|
|
195321
|
+
return { ok: true, messagesToKeep: 20 };
|
|
195322
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
195323
|
+
return {
|
|
195324
|
+
ok: false,
|
|
195325
|
+
message: "Usage: `/ctx-wrapup [messages_to_keep]` where messages_to_keep is a positive integer."
|
|
195326
|
+
};
|
|
195327
|
+
}
|
|
195328
|
+
const messagesToKeep = Number.parseInt(trimmed, 10);
|
|
195329
|
+
if (!Number.isSafeInteger(messagesToKeep) || messagesToKeep <= 0) {
|
|
195330
|
+
return { ok: false, message: "messages_to_keep must be a positive integer." };
|
|
195331
|
+
}
|
|
195332
|
+
return { ok: true, messagesToKeep };
|
|
195333
|
+
}
|
|
194589
195334
|
var SENTINEL_PREFIX = "__CONTEXT_MANAGEMENT_";
|
|
194590
195335
|
var HTTP_SERVER_RESPONSE_TYPE_ID = "~effect/http/HttpServerResponse";
|
|
194591
195336
|
var HTTP_COOKIES_TYPE_ID = "~effect/http/Cookies";
|
|
@@ -194727,6 +195472,7 @@ function createMagicContextCommandHandler(deps) {
|
|
|
194727
195472
|
const isStatusCommand = (command) => command === "ctx-status";
|
|
194728
195473
|
const isFlushCommand = (command) => command === "ctx-flush";
|
|
194729
195474
|
const isRecompCommand = (command) => command === "ctx-recomp";
|
|
195475
|
+
const isWrapupCommand = (command) => command === "ctx-wrapup";
|
|
194730
195476
|
const isAugCommand = (command) => command === "ctx-aug";
|
|
194731
195477
|
const isDreamCommand = (command) => command === "ctx-dream";
|
|
194732
195478
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
@@ -194736,11 +195482,12 @@ function createMagicContextCommandHandler(deps) {
|
|
|
194736
195482
|
const isStatus = isStatusCommand(input.command);
|
|
194737
195483
|
const isFlush = isFlushCommand(input.command);
|
|
194738
195484
|
const isRecomp = isRecompCommand(input.command);
|
|
195485
|
+
const isWrapup = isWrapupCommand(input.command);
|
|
194739
195486
|
const isAug = isAugCommand(input.command);
|
|
194740
195487
|
const isDream = isDreamCommand(input.command);
|
|
194741
195488
|
const isSessionUpgrade = isSessionUpgradeCommand(input.command);
|
|
194742
195489
|
const isEmbed = isEmbedCommand(input.command);
|
|
194743
|
-
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !isEmbed) {
|
|
195490
|
+
if (!isStatus && !isFlush && !isRecomp && !isWrapup && !isAug && !isDream && !isSessionUpgrade && !isEmbed) {
|
|
194744
195491
|
return;
|
|
194745
195492
|
}
|
|
194746
195493
|
const sessionId = input.sessionID;
|
|
@@ -194810,6 +195557,26 @@ Embedding status is unavailable.`;
|
|
|
194810
195557
|
|
|
194811
195558
|
${statusOutput}` : statusOutput;
|
|
194812
195559
|
}
|
|
195560
|
+
if (isWrapup) {
|
|
195561
|
+
const parsed = parseWrapupArgs(input.arguments);
|
|
195562
|
+
if (isSubagentSession(deps.db, sessionId)) {
|
|
195563
|
+
result = `## Magic Wrapup — Skipped
|
|
195564
|
+
|
|
195565
|
+
/ctx-wrapup is only available in primary sessions.`;
|
|
195566
|
+
} else if (!parsed.ok) {
|
|
195567
|
+
result = `## Magic Wrapup — Invalid Arguments
|
|
195568
|
+
|
|
195569
|
+
${parsed.message}`;
|
|
195570
|
+
} else if (!deps.executeWrapup) {
|
|
195571
|
+
result = `## Magic Wrapup
|
|
195572
|
+
|
|
195573
|
+
/ctx-wrapup is unavailable because the historian handler is not configured.`;
|
|
195574
|
+
} else {
|
|
195575
|
+
result = await deps.executeWrapup(sessionId, {
|
|
195576
|
+
messagesToKeep: parsed.messagesToKeep
|
|
195577
|
+
});
|
|
195578
|
+
}
|
|
195579
|
+
}
|
|
194813
195580
|
if (isRecomp) {
|
|
194814
195581
|
const parsedArgs = parseRecompArgs(input.arguments);
|
|
194815
195582
|
if (parsedArgs.kind === "error") {
|
|
@@ -195116,7 +195883,8 @@ var canonicalReasons = new Set([
|
|
|
195116
195883
|
"first_render",
|
|
195117
195884
|
"pressure_refold",
|
|
195118
195885
|
"upgrade_state",
|
|
195119
|
-
"cached_m1_missing"
|
|
195886
|
+
"cached_m1_missing",
|
|
195887
|
+
"project_change"
|
|
195120
195888
|
]);
|
|
195121
195889
|
var piReasonAliases = {
|
|
195122
195890
|
project_memory_change: "project_memory_epoch",
|
|
@@ -196047,35 +196815,31 @@ function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
|
|
|
196047
196815
|
for (const message of messages) {
|
|
196048
196816
|
if (message.info?.role !== "user")
|
|
196049
196817
|
continue;
|
|
196050
|
-
const verdict = verdictFromToolsMap(message.info.tools);
|
|
196051
|
-
|
|
196052
|
-
|
|
196053
|
-
return verdict;
|
|
196054
|
-
}
|
|
196055
|
-
break;
|
|
196818
|
+
const verdict = verdictFromToolsMap(message.info.tools) ?? true;
|
|
196819
|
+
availabilityBySession.set(sessionId, verdict);
|
|
196820
|
+
return verdict;
|
|
196056
196821
|
}
|
|
196057
|
-
availabilityBySession.set(sessionId, true);
|
|
196058
196822
|
return true;
|
|
196059
196823
|
}
|
|
196060
196824
|
function resolveCtxReduceAvailability(sessionId) {
|
|
196061
196825
|
const cached2 = availabilityBySession.get(sessionId);
|
|
196062
196826
|
if (cached2 !== undefined)
|
|
196063
|
-
return cached2;
|
|
196827
|
+
return { callable: cached2, frozen: true };
|
|
196064
196828
|
if (!openCodeDbExists())
|
|
196065
|
-
return true;
|
|
196829
|
+
return { callable: true, frozen: true };
|
|
196066
196830
|
try {
|
|
196067
196831
|
const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
|
|
196068
196832
|
WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
|
|
196069
196833
|
ORDER BY time_created ASC LIMIT 1`).get(sessionId));
|
|
196070
196834
|
if (!row)
|
|
196071
|
-
return true;
|
|
196835
|
+
return { callable: true, frozen: false };
|
|
196072
196836
|
const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools));
|
|
196073
196837
|
const resolved = verdict ?? true;
|
|
196074
196838
|
availabilityBySession.set(sessionId, resolved);
|
|
196075
|
-
return resolved;
|
|
196839
|
+
return { callable: resolved, frozen: true };
|
|
196076
196840
|
} catch (error51) {
|
|
196077
196841
|
sessionLog(sessionId, "ctx_reduce availability read failed (fail-open):", error51);
|
|
196078
|
-
return true;
|
|
196842
|
+
return { callable: true, frozen: false };
|
|
196079
196843
|
}
|
|
196080
196844
|
}
|
|
196081
196845
|
|
|
@@ -197764,6 +198528,7 @@ function containsProbeVerbatim(text, probes) {
|
|
|
197764
198528
|
init_memory();
|
|
197765
198529
|
init_embedding();
|
|
197766
198530
|
init_storage_memory_fts();
|
|
198531
|
+
init_storage_notes();
|
|
197767
198532
|
init_storage_primers();
|
|
197768
198533
|
init_workspaces();
|
|
197769
198534
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
@@ -198167,6 +198932,147 @@ function searchMessages(args) {
|
|
|
198167
198932
|
role: entry.row.role
|
|
198168
198933
|
}));
|
|
198169
198934
|
}
|
|
198935
|
+
var NOTE_SEARCHABLE_STATUSES = ["active", "pending", "ready", "dismissed"];
|
|
198936
|
+
function noteSearchText(note) {
|
|
198937
|
+
const reason = note.readyReason?.trim();
|
|
198938
|
+
return reason ? `${note.content}
|
|
198939
|
+
Reason: ${reason}` : note.content;
|
|
198940
|
+
}
|
|
198941
|
+
function tokenizeKeywordNeedle(text) {
|
|
198942
|
+
const matches = text.toLowerCase().match(/[a-z0-9/._:-]+/g) ?? [];
|
|
198943
|
+
const seen = new Set;
|
|
198944
|
+
const tokens = [];
|
|
198945
|
+
for (const match of matches) {
|
|
198946
|
+
if (match.length <= 1 || !/[a-z0-9]/.test(match) || seen.has(match)) {
|
|
198947
|
+
continue;
|
|
198948
|
+
}
|
|
198949
|
+
seen.add(match);
|
|
198950
|
+
tokens.push(match);
|
|
198951
|
+
}
|
|
198952
|
+
return tokens;
|
|
198953
|
+
}
|
|
198954
|
+
function rankNotesForNeedle(notes, needle) {
|
|
198955
|
+
const normalizedNeedle = needle.trim().toLowerCase();
|
|
198956
|
+
if (normalizedNeedle.length === 0) {
|
|
198957
|
+
return [];
|
|
198958
|
+
}
|
|
198959
|
+
const needleTokens = tokenizeKeywordNeedle(normalizedNeedle);
|
|
198960
|
+
const ranked = [];
|
|
198961
|
+
for (const note of notes) {
|
|
198962
|
+
const text = noteSearchText(note);
|
|
198963
|
+
const normalizedText = text.toLowerCase();
|
|
198964
|
+
const noteTokens = new Set(tokenizeKeywordNeedle(normalizedText));
|
|
198965
|
+
const exact = normalizedText.includes(normalizedNeedle);
|
|
198966
|
+
const matchedTokens = needleTokens.filter((token) => noteTokens.has(token)).length;
|
|
198967
|
+
if (!exact && matchedTokens === 0) {
|
|
198968
|
+
continue;
|
|
198969
|
+
}
|
|
198970
|
+
const coverage = needleTokens.length > 0 ? matchedTokens / needleTokens.length : 0;
|
|
198971
|
+
const score = (exact ? 2 : 0) + coverage + (needleTokens.length > 1 && matchedTokens === needleTokens.length ? 0.5 : 0);
|
|
198972
|
+
ranked.push({ note, score, text });
|
|
198973
|
+
}
|
|
198974
|
+
return ranked.sort((left, right) => {
|
|
198975
|
+
if (right.score !== left.score) {
|
|
198976
|
+
return right.score - left.score;
|
|
198977
|
+
}
|
|
198978
|
+
if (right.note.createdAt !== left.note.createdAt) {
|
|
198979
|
+
return right.note.createdAt - left.note.createdAt;
|
|
198980
|
+
}
|
|
198981
|
+
return left.note.id - right.note.id;
|
|
198982
|
+
});
|
|
198983
|
+
}
|
|
198984
|
+
function searchNotes(args) {
|
|
198985
|
+
if (args.limit <= 0) {
|
|
198986
|
+
return [];
|
|
198987
|
+
}
|
|
198988
|
+
const notes = [
|
|
198989
|
+
...getNotes(args.db, {
|
|
198990
|
+
sessionId: args.sessionId,
|
|
198991
|
+
type: "session",
|
|
198992
|
+
status: NOTE_SEARCHABLE_STATUSES
|
|
198993
|
+
}),
|
|
198994
|
+
...getNotes(args.db, {
|
|
198995
|
+
projectPath: args.projectPath,
|
|
198996
|
+
type: "smart",
|
|
198997
|
+
status: NOTE_SEARCHABLE_STATUSES
|
|
198998
|
+
})
|
|
198999
|
+
];
|
|
199000
|
+
if (notes.length === 0) {
|
|
199001
|
+
return [];
|
|
199002
|
+
}
|
|
199003
|
+
const baseList = rankNotesForNeedle(notes, args.query);
|
|
199004
|
+
const probes = args.probes ?? [];
|
|
199005
|
+
if (probes.length === 0) {
|
|
199006
|
+
const ranked2 = baseList.slice(0, args.limit);
|
|
199007
|
+
return ranked2.map((entry, rank) => ({
|
|
199008
|
+
source: "note",
|
|
199009
|
+
content: previewText(entry.text),
|
|
199010
|
+
score: linearDecayScore(rank, ranked2.length),
|
|
199011
|
+
noteId: entry.note.id,
|
|
199012
|
+
status: entry.note.status,
|
|
199013
|
+
createdAt: entry.note.createdAt,
|
|
199014
|
+
anchorOrdinal: entry.note.anchorOrdinal,
|
|
199015
|
+
sourceSessionId: entry.note.sessionId
|
|
199016
|
+
}));
|
|
199017
|
+
}
|
|
199018
|
+
const queryLists = [];
|
|
199019
|
+
if (baseList.length > 0) {
|
|
199020
|
+
queryLists.push({ rows: baseList, weight: 1 });
|
|
199021
|
+
}
|
|
199022
|
+
const probeWeights = new Map;
|
|
199023
|
+
for (const probe of probes) {
|
|
199024
|
+
const rows = rankNotesForNeedle(notes, probe);
|
|
199025
|
+
if (rows.length === 0) {
|
|
199026
|
+
continue;
|
|
199027
|
+
}
|
|
199028
|
+
const weight = probeDiscriminationWeight(rows.length, notes.length);
|
|
199029
|
+
probeWeights.set(probe, weight);
|
|
199030
|
+
queryLists.push({ rows, weight });
|
|
199031
|
+
}
|
|
199032
|
+
const fused = new Map;
|
|
199033
|
+
for (const list of queryLists) {
|
|
199034
|
+
list.rows.forEach((row, rank) => {
|
|
199035
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
199036
|
+
const existing = fused.get(row.note.id);
|
|
199037
|
+
if (existing) {
|
|
199038
|
+
existing.score += rrf;
|
|
199039
|
+
} else {
|
|
199040
|
+
fused.set(row.note.id, { entry: row, score: rrf });
|
|
199041
|
+
}
|
|
199042
|
+
});
|
|
199043
|
+
}
|
|
199044
|
+
for (const match of fused.values()) {
|
|
199045
|
+
let best = 0;
|
|
199046
|
+
for (const probe of probes) {
|
|
199047
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
199048
|
+
if (weight > best && containsProbeVerbatim(match.entry.text, [probe])) {
|
|
199049
|
+
best = weight;
|
|
199050
|
+
}
|
|
199051
|
+
}
|
|
199052
|
+
if (best > 0) {
|
|
199053
|
+
match.score += best * VERBATIM_RANK_BONUS;
|
|
199054
|
+
}
|
|
199055
|
+
}
|
|
199056
|
+
const ranked = [...fused.values()].sort((left, right) => {
|
|
199057
|
+
if (right.score !== left.score) {
|
|
199058
|
+
return right.score - left.score;
|
|
199059
|
+
}
|
|
199060
|
+
if (right.entry.note.createdAt !== left.entry.note.createdAt) {
|
|
199061
|
+
return right.entry.note.createdAt - left.entry.note.createdAt;
|
|
199062
|
+
}
|
|
199063
|
+
return left.entry.note.id - right.entry.note.id;
|
|
199064
|
+
}).slice(0, args.limit);
|
|
199065
|
+
return ranked.map((entry, rank) => ({
|
|
199066
|
+
source: "note",
|
|
199067
|
+
content: previewText(entry.entry.text),
|
|
199068
|
+
score: linearDecayScore(rank, ranked.length),
|
|
199069
|
+
noteId: entry.entry.note.id,
|
|
199070
|
+
status: entry.entry.note.status,
|
|
199071
|
+
createdAt: entry.entry.note.createdAt,
|
|
199072
|
+
anchorOrdinal: entry.entry.note.anchorOrdinal,
|
|
199073
|
+
sourceSessionId: entry.entry.note.sessionId
|
|
199074
|
+
}));
|
|
199075
|
+
}
|
|
198170
199076
|
function searchCompartmentChunks(args) {
|
|
198171
199077
|
if (!args.queryEmbedding || args.limit <= 0 || !args.modelId || args.modelId === "off")
|
|
198172
199078
|
return [];
|
|
@@ -198252,6 +199158,8 @@ function getSourceBoost(result) {
|
|
|
198252
199158
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
198253
199159
|
case "primer":
|
|
198254
199160
|
return PRIMER_SOURCE_BOOST;
|
|
199161
|
+
case "note":
|
|
199162
|
+
return 1;
|
|
198255
199163
|
}
|
|
198256
199164
|
}
|
|
198257
199165
|
function compareUnifiedResults(left, right) {
|
|
@@ -198275,6 +199183,9 @@ function compareUnifiedResults(left, right) {
|
|
|
198275
199183
|
if (left.source === "primer" && right.source === "primer") {
|
|
198276
199184
|
return right.support - left.support || left.primerId - right.primerId;
|
|
198277
199185
|
}
|
|
199186
|
+
if (left.source === "note" && right.source === "note") {
|
|
199187
|
+
return right.createdAt - left.createdAt || left.noteId - right.noteId;
|
|
199188
|
+
}
|
|
198278
199189
|
return 0;
|
|
198279
199190
|
}
|
|
198280
199191
|
function toGitCommitResult(hit) {
|
|
@@ -198342,11 +199253,11 @@ function searchPrimers(args) {
|
|
|
198342
199253
|
}
|
|
198343
199254
|
function resolveSources(sources) {
|
|
198344
199255
|
if (sources === undefined) {
|
|
198345
|
-
return new Set(["memory", "message", "git_commit", "primer"]);
|
|
199256
|
+
return new Set(["memory", "message", "git_commit", "primer", "note"]);
|
|
198346
199257
|
}
|
|
198347
199258
|
const set2 = new Set;
|
|
198348
199259
|
for (const source of sources) {
|
|
198349
|
-
if (source === "memory" || source === "message" || source === "git_commit" || source === "primer") {
|
|
199260
|
+
if (source === "memory" || source === "message" || source === "git_commit" || source === "primer" || source === "note") {
|
|
198350
199261
|
set2.add(source);
|
|
198351
199262
|
}
|
|
198352
199263
|
}
|
|
@@ -198369,6 +199280,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
198369
199280
|
const runMessages = activeSources.has("message");
|
|
198370
199281
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
198371
199282
|
const runPrimers = activeSources.has("primer") && memoryFeatureEnabled;
|
|
199283
|
+
const runNotes = activeSources.has("note");
|
|
198372
199284
|
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
198373
199285
|
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks || runPrimers) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
198374
199286
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
@@ -198404,7 +199316,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
198404
199316
|
compartments: compartmentResults,
|
|
198405
199317
|
limit: tierLimit
|
|
198406
199318
|
});
|
|
198407
|
-
const [memoryResults, gitCommitResults, primerResults] = await Promise.all([
|
|
199319
|
+
const [memoryResults, gitCommitResults, primerResults, noteResults] = await Promise.all([
|
|
198408
199320
|
runMemory ? searchMemories({
|
|
198409
199321
|
db,
|
|
198410
199322
|
projectPath,
|
|
@@ -198431,9 +199343,23 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
198431
199343
|
limit: tierLimit,
|
|
198432
199344
|
queryEmbedding,
|
|
198433
199345
|
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null
|
|
199346
|
+
})) : Promise.resolve([]),
|
|
199347
|
+
runNotes ? Promise.resolve(searchNotes({
|
|
199348
|
+
db,
|
|
199349
|
+
sessionId,
|
|
199350
|
+
projectPath,
|
|
199351
|
+
query: trimmedQuery,
|
|
199352
|
+
limit: tierLimit,
|
|
199353
|
+
probes: messageProbes
|
|
198434
199354
|
})) : Promise.resolve([])
|
|
198435
199355
|
]);
|
|
198436
|
-
const results = [
|
|
199356
|
+
const results = [
|
|
199357
|
+
...memoryResults,
|
|
199358
|
+
...primerResults,
|
|
199359
|
+
...messageLikeResults,
|
|
199360
|
+
...gitCommitResults,
|
|
199361
|
+
...noteResults
|
|
199362
|
+
].sort(compareUnifiedResults).slice(0, limit);
|
|
198437
199363
|
const countRetrievals = options.countRetrievals ?? true;
|
|
198438
199364
|
if (countRetrievals) {
|
|
198439
199365
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -198506,6 +199432,10 @@ function renderFragment(result, charCap) {
|
|
|
198506
199432
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
198507
199433
|
return truncate(compressed, charCap);
|
|
198508
199434
|
}
|
|
199435
|
+
case "note": {
|
|
199436
|
+
const compressed = cavemanCompress(result.content, "ultra");
|
|
199437
|
+
return truncate(compressed, charCap);
|
|
199438
|
+
}
|
|
198509
199439
|
}
|
|
198510
199440
|
}
|
|
198511
199441
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -199372,6 +200302,13 @@ var degradedCacheCountBySession = new BoundedSessionMap(100);
|
|
|
199372
200302
|
function resetDegradedCacheCount(sessionId) {
|
|
199373
200303
|
degradedCacheCountBySession.delete(sessionId);
|
|
199374
200304
|
}
|
|
200305
|
+
function pendingMarkerCoveredByConsumedBoundary(pending, injection) {
|
|
200306
|
+
if (!injection)
|
|
200307
|
+
return false;
|
|
200308
|
+
if (pending.endMessageId === injection.compartmentEndMessageId)
|
|
200309
|
+
return true;
|
|
200310
|
+
return pending.ordinal <= injection.compartmentEndMessage;
|
|
200311
|
+
}
|
|
199375
200312
|
function clearPendingCompactionMarkerAfterSuccessfulDrain(args) {
|
|
199376
200313
|
if (clearPendingCompactionMarkerStateIf(args.db, args.sessionId, args.pending)) {
|
|
199377
200314
|
return "cleared";
|
|
@@ -199770,24 +200707,29 @@ async function runPostTransformPhase(args) {
|
|
|
199770
200707
|
if (historyWasConsumedThisPass && args.deferredHistoryWasPendingAtPassStart) {
|
|
199771
200708
|
const pending = getPendingCompactionMarkerState(args.db, args.sessionId);
|
|
199772
200709
|
if (pending) {
|
|
199773
|
-
|
|
199774
|
-
|
|
199775
|
-
|
|
199776
|
-
|
|
199777
|
-
|
|
199778
|
-
|
|
199779
|
-
|
|
199780
|
-
|
|
199781
|
-
|
|
199782
|
-
|
|
199783
|
-
|
|
200710
|
+
if (!pendingMarkerCoveredByConsumedBoundary(pending, args.pendingCompartmentInjection)) {
|
|
200711
|
+
suppressV12HistoryDrain = true;
|
|
200712
|
+
sessionLog(args.sessionId, `compaction-marker drain: pending ordinal ${pending.ordinal} is newer than consumed boundary ${args.pendingCompartmentInjection?.compartmentEndMessage ?? "<none>"}; preserving deferred history refresh signal`);
|
|
200713
|
+
} else {
|
|
200714
|
+
const outcome = applyDeferredCompactionMarker(args.db, args.sessionId, pending, args.sessionDirectory);
|
|
200715
|
+
switch (outcome.kind) {
|
|
200716
|
+
case "applied":
|
|
200717
|
+
case "already-current":
|
|
200718
|
+
case "stale-skip":
|
|
200719
|
+
if (clearPendingCompactionMarkerAfterSuccessfulDrain({
|
|
200720
|
+
db: args.db,
|
|
200721
|
+
sessionId: args.sessionId,
|
|
200722
|
+
pending,
|
|
200723
|
+
deferredHistoryRefreshSessions: args.deferredHistoryRefreshSessions
|
|
200724
|
+
}) === "cas-lost-newer-pending") {
|
|
200725
|
+
suppressV12HistoryDrain = true;
|
|
200726
|
+
}
|
|
200727
|
+
break;
|
|
200728
|
+
case "retryable-failure":
|
|
200729
|
+
sessionLog(args.sessionId, "compaction-marker drain: retryable failure; preserving deferred history refresh signal", outcome.error);
|
|
199784
200730
|
suppressV12HistoryDrain = true;
|
|
199785
|
-
|
|
199786
|
-
|
|
199787
|
-
case "retryable-failure":
|
|
199788
|
-
sessionLog(args.sessionId, "compaction-marker drain: retryable failure; preserving deferred history refresh signal", outcome.error);
|
|
199789
|
-
suppressV12HistoryDrain = true;
|
|
199790
|
-
break;
|
|
200731
|
+
break;
|
|
200732
|
+
}
|
|
199791
200733
|
}
|
|
199792
200734
|
}
|
|
199793
200735
|
}
|
|
@@ -199892,6 +200834,16 @@ function getMessageTokensCache(sessionId) {
|
|
|
199892
200834
|
}
|
|
199893
200835
|
return cache;
|
|
199894
200836
|
}
|
|
200837
|
+
function maybeSendProjectIdentityWarning(deps, sessionId, directory, notificationParams) {
|
|
200838
|
+
if (!deps.client)
|
|
200839
|
+
return;
|
|
200840
|
+
const warning = takeDubiousOwnershipProjectIdentityWarning(directory);
|
|
200841
|
+
if (!warning)
|
|
200842
|
+
return;
|
|
200843
|
+
sendIgnoredMessage(deps.client, sessionId, warning, notificationParams).catch((error51) => {
|
|
200844
|
+
sessionLog(sessionId, `project identity warning delivery failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
200845
|
+
});
|
|
200846
|
+
}
|
|
199895
200847
|
function clearMessageTokensCache(sessionId, messageId) {
|
|
199896
200848
|
if (messageId === undefined) {
|
|
199897
200849
|
messageTokensBySession.delete(sessionId);
|
|
@@ -199966,7 +200918,7 @@ function createTransform(deps) {
|
|
|
199966
200918
|
}
|
|
199967
200919
|
const reducedMode = sessionMeta.isSubagent;
|
|
199968
200920
|
const fullFeatureMode = !reducedMode;
|
|
199969
|
-
const
|
|
200921
|
+
const ctxReduceCallable = resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
|
|
199970
200922
|
let sessionDirectory = deps.directory ?? "";
|
|
199971
200923
|
let sessionDirectoryResolvedFromHost = false;
|
|
199972
200924
|
const cachedDirectory = deps.sessionDirectoryBySession?.get(sessionId);
|
|
@@ -200249,8 +201201,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
200249
201201
|
}
|
|
200250
201202
|
}
|
|
200251
201203
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
200252
|
-
const
|
|
201204
|
+
const memoryProjectDirectory = compartmentDirectory || process.cwd();
|
|
201205
|
+
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(memoryProjectDirectory) : undefined;
|
|
201206
|
+
if (deps.memoryConfig?.enabled) {
|
|
201207
|
+
maybeSendProjectIdentityWarning(deps, sessionId, memoryProjectDirectory, notificationParams);
|
|
201208
|
+
}
|
|
200253
201209
|
const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
|
|
201210
|
+
if (sessionDirectory) {
|
|
201211
|
+
maybeSendProjectIdentityWarning(deps, sessionId, sessionDirectory, notificationParams);
|
|
201212
|
+
}
|
|
200254
201213
|
if (sessionProjectIdentity && sessionDirectoryResolvedFromHost && recordedSessionProjectIdentity.get(sessionId) !== sessionProjectIdentity) {
|
|
200255
201214
|
recordSessionProjectIdentity(db, sessionId, sessionProjectIdentity);
|
|
200256
201215
|
recordedSessionProjectIdentity.set(sessionId, sessionProjectIdentity);
|
|
@@ -200308,7 +201267,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
200308
201267
|
const tInitFromDb = performance.now();
|
|
200309
201268
|
deps.tagger.initFromDb(sessionId, db, taggerFloor);
|
|
200310
201269
|
logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
|
|
200311
|
-
const skipPrefixInjection = !
|
|
201270
|
+
const skipPrefixInjection = !ctxReduceCallable;
|
|
200312
201271
|
const result = tagMessages(sessionId, messages, deps.tagger, db, {
|
|
200313
201272
|
skipPrefixInjection
|
|
200314
201273
|
});
|
|
@@ -200365,7 +201324,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
200365
201324
|
}
|
|
200366
201325
|
logTransformTiming(sessionId, "replayReasoningClearing", tReplay);
|
|
200367
201326
|
}
|
|
200368
|
-
if (!
|
|
201327
|
+
if (!reducedMode && deps.cavemanTextCompression?.enabled) {
|
|
200369
201328
|
const tCavemanReplay = performance.now();
|
|
200370
201329
|
const replayedCaveman = replayCavemanCompression(sessionId, db, targets, targetsSliceTags);
|
|
200371
201330
|
if (replayedCaveman > 0) {
|
|
@@ -200495,7 +201454,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
200495
201454
|
projectPath: sessionProjectIdentity,
|
|
200496
201455
|
sessionDirectory,
|
|
200497
201456
|
autoSearch: deps.autoSearch,
|
|
200498
|
-
cavemanTextCompression:
|
|
201457
|
+
cavemanTextCompression: !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
200499
201458
|
smartDrops: deps.smartDrops === true,
|
|
200500
201459
|
resolvedProviderID,
|
|
200501
201460
|
historyRefreshSessions: deps.historyRefreshSessions,
|
|
@@ -200651,7 +201610,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
200651
201610
|
sessionLog(sessionId, "conversation_tokens UPDATE failed:", error51);
|
|
200652
201611
|
}
|
|
200653
201612
|
}
|
|
200654
|
-
if (
|
|
201613
|
+
if (ctxReduceCallable && deps.channel1StateBySession) {
|
|
200655
201614
|
try {
|
|
200656
201615
|
const resolvedExecuteThresholdPct = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
|
|
200657
201616
|
tokensConfig: deps.executeThresholdTokens,
|
|
@@ -201136,6 +202095,343 @@ function createTextCompleteHandler() {
|
|
|
201136
202095
|
};
|
|
201137
202096
|
}
|
|
201138
202097
|
|
|
202098
|
+
// src/hooks/magic-context/wrapup-orchestrator.ts
|
|
202099
|
+
init_compartment_lease();
|
|
202100
|
+
init_compartment_storage();
|
|
202101
|
+
init_logger();
|
|
202102
|
+
init_rpc_notifications();
|
|
202103
|
+
init_send_session_notification();
|
|
202104
|
+
await __promiseAll([
|
|
202105
|
+
init_storage(),
|
|
202106
|
+
init_compartment_runner(),
|
|
202107
|
+
init_compartment_runner_incremental(),
|
|
202108
|
+
init_protected_tail_boundary(),
|
|
202109
|
+
init_recomp_orchestrator()
|
|
202110
|
+
]);
|
|
202111
|
+
import * as crypto3 from "node:crypto";
|
|
202112
|
+
var WAIT_FOR_LEASE_MS = 1000;
|
|
202113
|
+
function sleep2(ms) {
|
|
202114
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
202115
|
+
}
|
|
202116
|
+
function plural(value, word) {
|
|
202117
|
+
return `${value} ${word}${value === 1 ? "" : "s"}`;
|
|
202118
|
+
}
|
|
202119
|
+
function formatAlreadyRunningMessage(state) {
|
|
202120
|
+
if (!state)
|
|
202121
|
+
return "/ctx-wrapup is already running for this session.";
|
|
202122
|
+
const chunk = state.expectedChunks > 0 ? ` chunk ${state.chunkIndex}/${state.expectedChunks}` : "";
|
|
202123
|
+
const through = state.lastCompartmentEnd > 0 ? ` through message ${state.lastCompartmentEnd}` : "";
|
|
202124
|
+
return `/ctx-wrapup is already running for this session${chunk}${through}. Wait for it to finish, then run /ctx-wrapup again if more history remains.`;
|
|
202125
|
+
}
|
|
202126
|
+
function appendFlushHint(ctx, sessionId, message) {
|
|
202127
|
+
if (ctx.hasPendingNaturalBust?.(sessionId))
|
|
202128
|
+
return message;
|
|
202129
|
+
return `${message} If you want it applied on the very next message, run /ctx-flush first.`;
|
|
202130
|
+
}
|
|
202131
|
+
function buildPlan(ctx, sessionId, messagesToKeep, anchorRawMessageCount) {
|
|
202132
|
+
return resolveWrapupProtectedTailBoundary({
|
|
202133
|
+
db: ctx.db,
|
|
202134
|
+
sessionId,
|
|
202135
|
+
mode: "manual-wrapup",
|
|
202136
|
+
contextLimit: ctx.contextLimit,
|
|
202137
|
+
executeThresholdPercentage: ctx.executeThresholdPercentage,
|
|
202138
|
+
usage: null,
|
|
202139
|
+
usageSource: "manual-none",
|
|
202140
|
+
providerShapeVersion: "opencode-v1",
|
|
202141
|
+
cacheNamespace: `opencode:${sessionId}`,
|
|
202142
|
+
messagesToKeep,
|
|
202143
|
+
anchorRawMessageCount
|
|
202144
|
+
});
|
|
202145
|
+
}
|
|
202146
|
+
function emitWrapupProgress(ctx, sessionId, progress) {
|
|
202147
|
+
const current = ctx.liveSessionState.recompProgressBySession.get(sessionId);
|
|
202148
|
+
ctx.liveSessionState.recompProgressBySession.set(sessionId, {
|
|
202149
|
+
sessionId,
|
|
202150
|
+
kind: "wrapup",
|
|
202151
|
+
phase: "recomp",
|
|
202152
|
+
processedMessages: progress.processedMessages ?? current?.processedMessages ?? 0,
|
|
202153
|
+
totalMessages: progress.totalMessages ?? current?.totalMessages ?? 0,
|
|
202154
|
+
passCount: progress.passCount ?? current?.passCount ?? 0,
|
|
202155
|
+
compartmentsCreated: progress.compartmentsCreated ?? current?.compartmentsCreated ?? 0,
|
|
202156
|
+
startedAt: current?.startedAt ?? Date.now(),
|
|
202157
|
+
updatedAt: Date.now(),
|
|
202158
|
+
note: progress.note
|
|
202159
|
+
});
|
|
202160
|
+
}
|
|
202161
|
+
async function waitForExistingIncrementalRun(sessionId) {
|
|
202162
|
+
const active = getActiveCompartmentRun(sessionId);
|
|
202163
|
+
if (!active)
|
|
202164
|
+
return "ok";
|
|
202165
|
+
if (active.kind === "recomp" || active.kind === "wrapup")
|
|
202166
|
+
return "busy";
|
|
202167
|
+
try {
|
|
202168
|
+
await active.promise;
|
|
202169
|
+
} catch {}
|
|
202170
|
+
return "ok";
|
|
202171
|
+
}
|
|
202172
|
+
async function acquireCompartmentLeaseForWrapup(ctx, sessionId, renewWrapupMarker) {
|
|
202173
|
+
const holderId = crypto3.randomUUID();
|
|
202174
|
+
for (;; ) {
|
|
202175
|
+
const active = getActiveCompartmentRun(sessionId);
|
|
202176
|
+
if (active?.kind === "recomp" || active?.kind === "wrapup")
|
|
202177
|
+
return null;
|
|
202178
|
+
if (active) {
|
|
202179
|
+
emitWrapupProgress(ctx, sessionId, { note: "Waiting for the active historian run…" });
|
|
202180
|
+
try {
|
|
202181
|
+
await active.promise;
|
|
202182
|
+
} catch {}
|
|
202183
|
+
continue;
|
|
202184
|
+
}
|
|
202185
|
+
const lease = acquireCompartmentLease(ctx.db, sessionId, holderId);
|
|
202186
|
+
if (lease)
|
|
202187
|
+
return holderId;
|
|
202188
|
+
emitWrapupProgress(ctx, sessionId, { note: "Waiting for the compartment-state lease…" });
|
|
202189
|
+
if (!renewWrapupMarker({}))
|
|
202190
|
+
return null;
|
|
202191
|
+
await sleep2(WAIT_FOR_LEASE_MS);
|
|
202192
|
+
}
|
|
202193
|
+
}
|
|
202194
|
+
async function runOneWrapupIteration(args) {
|
|
202195
|
+
const { ctx, sessionId, plan, messagesToKeep, anchorRawMessageCount } = args;
|
|
202196
|
+
const leaseHolderId = await acquireCompartmentLeaseForWrapup(ctx, sessionId, args.renewWrapupMarker);
|
|
202197
|
+
if (!leaseHolderId)
|
|
202198
|
+
return false;
|
|
202199
|
+
const renewal = setInterval(() => {
|
|
202200
|
+
try {
|
|
202201
|
+
if (!renewCompartmentLease(ctx.db, sessionId, leaseHolderId)) {
|
|
202202
|
+
sessionLog(sessionId, "wrapup: compartment lease renewal failed");
|
|
202203
|
+
}
|
|
202204
|
+
} catch (err) {
|
|
202205
|
+
sessionLog(sessionId, `wrapup: compartment lease renewal threw; continuing (${err instanceof Error ? err.message : String(err)})`);
|
|
202206
|
+
}
|
|
202207
|
+
}, COMPARTMENT_LEASE_RENEWAL_MS);
|
|
202208
|
+
const runCompartmentAgentForWrapup = ctx.runCompartmentAgentForWrapup ?? runCompartmentAgent;
|
|
202209
|
+
const runnerPromise = runCompartmentAgentForWrapup({
|
|
202210
|
+
client: ctx.client,
|
|
202211
|
+
db: ctx.db,
|
|
202212
|
+
sessionId,
|
|
202213
|
+
historianChunkTokens: ctx.historianChunkTokens,
|
|
202214
|
+
historianTimeoutMs: ctx.historianTimeoutMs,
|
|
202215
|
+
boundarySnapshot: plan.snapshot,
|
|
202216
|
+
currentContextLimit: ctx.contextLimit,
|
|
202217
|
+
directory: ctx.directory,
|
|
202218
|
+
fallbackModels: ctx.fallbackModels,
|
|
202219
|
+
fallbackModelId: ctx.fallbackModelId,
|
|
202220
|
+
language: ctx.language,
|
|
202221
|
+
historianTwoPass: ctx.historianTwoPass,
|
|
202222
|
+
memoryEnabled: ctx.memoryEnabled,
|
|
202223
|
+
autoPromote: ctx.autoPromote,
|
|
202224
|
+
ensureProjectRegistered: ctx.ensureProjectRegistered,
|
|
202225
|
+
getNotificationParams: () => ctx.getNotificationParams(sessionId),
|
|
202226
|
+
preserveInjectionCacheUntilConsumed: true,
|
|
202227
|
+
compartmentLeaseHolderId: leaseHolderId,
|
|
202228
|
+
forceDrainQuota: true,
|
|
202229
|
+
forceKeepLastCompartment: true,
|
|
202230
|
+
refreshBoundarySnapshot: () => buildPlan(ctx, sessionId, messagesToKeep, anchorRawMessageCount).snapshot,
|
|
202231
|
+
onCompartmentStatePublished: (sid) => {
|
|
202232
|
+
markActiveCompartmentRunPublished(sid);
|
|
202233
|
+
ctx.liveSessionState.deferredHistoryRefreshSessions.add(sid);
|
|
202234
|
+
ctx.liveSessionState.deferredMaterializationSessions.add(sid);
|
|
202235
|
+
},
|
|
202236
|
+
onDeferredMarkerPending: (sid) => {
|
|
202237
|
+
ctx.liveSessionState.deferredHistoryRefreshSessions.add(sid);
|
|
202238
|
+
}
|
|
202239
|
+
});
|
|
202240
|
+
registerActiveCompartmentRun(sessionId, runnerPromise, "wrapup");
|
|
202241
|
+
try {
|
|
202242
|
+
await runnerPromise;
|
|
202243
|
+
return true;
|
|
202244
|
+
} finally {
|
|
202245
|
+
clearInterval(renewal);
|
|
202246
|
+
releaseCompartmentLease(ctx.db, sessionId, leaseHolderId);
|
|
202247
|
+
}
|
|
202248
|
+
}
|
|
202249
|
+
async function runManagedWrapup(ctx, sessionId, options) {
|
|
202250
|
+
const messagesToKeep = Math.max(1, Math.floor(options.messagesToKeep));
|
|
202251
|
+
setRecompStarting(ctx.liveSessionState, sessionId, "Estimating wrapup…", "wrapup");
|
|
202252
|
+
const existingWrapup = getWrapupInProgressState(ctx.db, sessionId);
|
|
202253
|
+
if (existingWrapup) {
|
|
202254
|
+
const message2 = formatAlreadyRunningMessage(existingWrapup);
|
|
202255
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "skipped", message2);
|
|
202256
|
+
return `## Magic Wrapup — Skipped
|
|
202257
|
+
|
|
202258
|
+
${message2}`;
|
|
202259
|
+
}
|
|
202260
|
+
const initialPlan = buildPlan(ctx, sessionId, messagesToKeep);
|
|
202261
|
+
if (initialPlan.rawMessagesAboveLastCompartment <= messagesToKeep || !hasRunnableCompartmentWindow(initialPlan.snapshot)) {
|
|
202262
|
+
const message2 = `Nothing to wrap up — only ${initialPlan.rawMessagesAboveLastCompartment} messages above the last compartment.`;
|
|
202263
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "done", message2);
|
|
202264
|
+
return message2;
|
|
202265
|
+
}
|
|
202266
|
+
const expectedChunks = Math.max(1, Math.ceil(initialPlan.snapshot.trueRawEligibleTokens / Math.max(1, ctx.historianChunkTokens)));
|
|
202267
|
+
const wrapupHolderId = crypto3.randomUUID();
|
|
202268
|
+
const acquired = acquireWrapupInProgress(ctx.db, sessionId, {
|
|
202269
|
+
holderId: wrapupHolderId,
|
|
202270
|
+
messagesToKeep,
|
|
202271
|
+
anchorRawMessageCount: initialPlan.anchorRawMessageCount,
|
|
202272
|
+
targetEligibleEndOrdinal: initialPlan.targetEligibleEndOrdinal,
|
|
202273
|
+
lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
|
|
202274
|
+
chunkIndex: 0,
|
|
202275
|
+
expectedChunks
|
|
202276
|
+
});
|
|
202277
|
+
if (!acquired.ok) {
|
|
202278
|
+
const message2 = formatAlreadyRunningMessage(acquired.state);
|
|
202279
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "skipped", message2);
|
|
202280
|
+
return `## Magic Wrapup — Skipped
|
|
202281
|
+
|
|
202282
|
+
${message2}`;
|
|
202283
|
+
}
|
|
202284
|
+
const startLastEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
|
|
202285
|
+
const startCompartmentCount = getCompartments(ctx.db, sessionId).length;
|
|
202286
|
+
let chunkIndex = 0;
|
|
202287
|
+
let lastEnd = startLastEnd;
|
|
202288
|
+
let stoppedForFailure = false;
|
|
202289
|
+
let stoppedReason = "";
|
|
202290
|
+
let ownershipLost = false;
|
|
202291
|
+
const ownershipLostReason = "another process took over this session's wrapup.";
|
|
202292
|
+
const markOwnershipLost = () => {
|
|
202293
|
+
if (ownershipLost)
|
|
202294
|
+
return;
|
|
202295
|
+
ownershipLost = true;
|
|
202296
|
+
sessionLog(sessionId, "wrapup: durable marker ownership lost; aborting loop");
|
|
202297
|
+
};
|
|
202298
|
+
const renewWrapupMarker = (updates) => {
|
|
202299
|
+
const updated = updateWrapupInProgress(ctx.db, sessionId, wrapupHolderId, updates);
|
|
202300
|
+
if (!updated) {
|
|
202301
|
+
markOwnershipLost();
|
|
202302
|
+
return false;
|
|
202303
|
+
}
|
|
202304
|
+
return true;
|
|
202305
|
+
};
|
|
202306
|
+
const markerRenewal = setInterval(() => {
|
|
202307
|
+
try {
|
|
202308
|
+
renewWrapupMarker({
|
|
202309
|
+
lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
|
|
202310
|
+
chunkIndex
|
|
202311
|
+
});
|
|
202312
|
+
} catch (err) {
|
|
202313
|
+
sessionLog(sessionId, `wrapup: marker renewal threw; continuing (${err instanceof Error ? err.message : String(err)})`);
|
|
202314
|
+
}
|
|
202315
|
+
}, 60000);
|
|
202316
|
+
markerRenewal.unref?.();
|
|
202317
|
+
try {
|
|
202318
|
+
const activeAtStart = await waitForExistingIncrementalRun(sessionId);
|
|
202319
|
+
if (activeAtStart === "busy") {
|
|
202320
|
+
const message2 = "Another Magic Context rebuild is already running for this session.";
|
|
202321
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "skipped", message2);
|
|
202322
|
+
return `## Magic Wrapup — Skipped
|
|
202323
|
+
|
|
202324
|
+
${message2}`;
|
|
202325
|
+
}
|
|
202326
|
+
try {
|
|
202327
|
+
sendIgnoredMessage(ctx.client, sessionId, `Magic Wrapup started — compacting about ${plural(expectedChunks, "chunk")} of history. This can take a few minutes; the result posts here when done.`, ctx.getNotificationParams(sessionId));
|
|
202328
|
+
} catch {}
|
|
202329
|
+
try {
|
|
202330
|
+
pushNotification("action", { action: "wrapup-progress-kick" }, sessionId);
|
|
202331
|
+
} catch {}
|
|
202332
|
+
if (ownershipLost) {
|
|
202333
|
+
stoppedForFailure = true;
|
|
202334
|
+
stoppedReason = ownershipLostReason;
|
|
202335
|
+
} else {
|
|
202336
|
+
emitWrapupProgress(ctx, sessionId, {
|
|
202337
|
+
processedMessages: Math.max(0, lastEnd),
|
|
202338
|
+
totalMessages: Math.max(0, initialPlan.targetEligibleEndOrdinal - 1),
|
|
202339
|
+
passCount: 0,
|
|
202340
|
+
compartmentsCreated: 0,
|
|
202341
|
+
note: `Eligible ${plural(initialPlan.snapshot.trueRawEligibleTokens, "token")} across about ${plural(expectedChunks, "chunk")}.`
|
|
202342
|
+
});
|
|
202343
|
+
for (;; ) {
|
|
202344
|
+
if (ownershipLost) {
|
|
202345
|
+
stoppedForFailure = true;
|
|
202346
|
+
stoppedReason = ownershipLostReason;
|
|
202347
|
+
break;
|
|
202348
|
+
}
|
|
202349
|
+
if (!renewWrapupMarker({
|
|
202350
|
+
lastCompartmentEnd: getLastCompartmentEndMessage(ctx.db, sessionId),
|
|
202351
|
+
chunkIndex,
|
|
202352
|
+
expectedChunks
|
|
202353
|
+
})) {
|
|
202354
|
+
stoppedForFailure = true;
|
|
202355
|
+
stoppedReason = ownershipLostReason;
|
|
202356
|
+
break;
|
|
202357
|
+
}
|
|
202358
|
+
const plan = buildPlan(ctx, sessionId, messagesToKeep, initialPlan.anchorRawMessageCount);
|
|
202359
|
+
lastEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
|
|
202360
|
+
if (lastEnd + 1 >= plan.targetEligibleEndOrdinal)
|
|
202361
|
+
break;
|
|
202362
|
+
chunkIndex += 1;
|
|
202363
|
+
emitWrapupProgress(ctx, sessionId, {
|
|
202364
|
+
processedMessages: Math.max(0, lastEnd),
|
|
202365
|
+
totalMessages: Math.max(0, plan.targetEligibleEndOrdinal - 1),
|
|
202366
|
+
passCount: chunkIndex - 1,
|
|
202367
|
+
compartmentsCreated: Math.max(0, getCompartments(ctx.db, sessionId).length - startCompartmentCount),
|
|
202368
|
+
note: `Chunk ${chunkIndex}/${expectedChunks}: messages ${plan.snapshot.offset}-${plan.snapshot.eligibleEndOrdinal - 1}…`
|
|
202369
|
+
});
|
|
202370
|
+
if (!renewWrapupMarker({
|
|
202371
|
+
lastCompartmentEnd: lastEnd,
|
|
202372
|
+
chunkIndex,
|
|
202373
|
+
expectedChunks,
|
|
202374
|
+
targetEligibleEndOrdinal: plan.targetEligibleEndOrdinal
|
|
202375
|
+
})) {
|
|
202376
|
+
stoppedForFailure = true;
|
|
202377
|
+
stoppedReason = ownershipLostReason;
|
|
202378
|
+
break;
|
|
202379
|
+
}
|
|
202380
|
+
const beforeEnd = lastEnd;
|
|
202381
|
+
const beforeFailures = getHistorianFailureState(ctx.db, sessionId).failureCount;
|
|
202382
|
+
const ran = await runOneWrapupIteration({
|
|
202383
|
+
ctx,
|
|
202384
|
+
sessionId,
|
|
202385
|
+
plan,
|
|
202386
|
+
messagesToKeep,
|
|
202387
|
+
anchorRawMessageCount: initialPlan.anchorRawMessageCount,
|
|
202388
|
+
renewWrapupMarker
|
|
202389
|
+
});
|
|
202390
|
+
if (!ran) {
|
|
202391
|
+
stoppedForFailure = true;
|
|
202392
|
+
stoppedReason = ownershipLost ? ownershipLostReason : "Another Magic Context rebuild started while wrapup was waiting.";
|
|
202393
|
+
break;
|
|
202394
|
+
}
|
|
202395
|
+
const afterEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
|
|
202396
|
+
const afterFailures = getHistorianFailureState(ctx.db, sessionId).failureCount;
|
|
202397
|
+
if (afterEnd <= beforeEnd) {
|
|
202398
|
+
stoppedForFailure = true;
|
|
202399
|
+
stoppedReason = afterFailures > beforeFailures ? "The historian failed on the current chunk." : "The historian made no forward progress on the current chunk.";
|
|
202400
|
+
break;
|
|
202401
|
+
}
|
|
202402
|
+
lastEnd = afterEnd;
|
|
202403
|
+
emitWrapupProgress(ctx, sessionId, {
|
|
202404
|
+
processedMessages: Math.max(0, lastEnd),
|
|
202405
|
+
totalMessages: Math.max(0, plan.targetEligibleEndOrdinal - 1),
|
|
202406
|
+
passCount: chunkIndex,
|
|
202407
|
+
compartmentsCreated: Math.max(0, getCompartments(ctx.db, sessionId).length - startCompartmentCount),
|
|
202408
|
+
note: `Wrapped through message ${lastEnd}.`
|
|
202409
|
+
});
|
|
202410
|
+
}
|
|
202411
|
+
}
|
|
202412
|
+
} finally {
|
|
202413
|
+
clearInterval(markerRenewal);
|
|
202414
|
+
releaseWrapupInProgress(ctx.db, sessionId, wrapupHolderId);
|
|
202415
|
+
}
|
|
202416
|
+
const finalEnd = getLastCompartmentEndMessage(ctx.db, sessionId);
|
|
202417
|
+
const compartmentsCreated = Math.max(0, getCompartments(ctx.db, sessionId).length - startCompartmentCount);
|
|
202418
|
+
const messagesWrapped = Math.max(0, finalEnd - Math.max(0, startLastEnd));
|
|
202419
|
+
if (stoppedForFailure) {
|
|
202420
|
+
const message2 = `Wrapped up through message ${Math.max(0, finalEnd)} (${plural(messagesWrapped, "message")} into ${plural(compartmentsCreated, "compartment")}). ${stoppedReason} Run /ctx-wrapup again to continue.`;
|
|
202421
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "failed", message2);
|
|
202422
|
+
return `## Magic Wrapup — Partial
|
|
202423
|
+
|
|
202424
|
+
${message2}`;
|
|
202425
|
+
}
|
|
202426
|
+
try {
|
|
202427
|
+
clearEmergencyRecovery(ctx.db, sessionId);
|
|
202428
|
+
} catch {}
|
|
202429
|
+
const base = `Wrapped up ${messagesWrapped} messages into ${compartmentsCreated} compartments. The compacted history is queued and materializes on your next message.`;
|
|
202430
|
+
const message = appendFlushHint(ctx, sessionId, base);
|
|
202431
|
+
setRecompTerminal(ctx.liveSessionState, sessionId, "done", message);
|
|
202432
|
+
return message;
|
|
202433
|
+
}
|
|
202434
|
+
|
|
201139
202435
|
// src/hooks/magic-context/hook.ts
|
|
201140
202436
|
await init_compaction_marker_manager();
|
|
201141
202437
|
|
|
@@ -201474,7 +202770,7 @@ Drop silently — do not narrate it. NEVER drop large ranges blindly (e.g., "1-5
|
|
|
201474
202770
|
Older tool calls may show \`[dropped §N§]\` sentinels; that is normal context management, not a pattern to copy. ALWAYS make fresh real tool calls when you need data again; never fabricate or inline tool output.`;
|
|
201475
202771
|
var CAVEMAN_COMPRESSION_WARNING = `
|
|
201476
202772
|
**BEWARE**: History compression is on; older user AND assistant text — including your own earlier responses — has been deterministically rewritten in a terse caveman style (dropped articles, missing auxiliaries, \`//\` instead of connectives like \`because\`). This is automatic context compression that runs after the fact, not your actual prior wording or the user's. **DO NOT mimic this style in new turns.** Write fresh responses in normal prose. If you notice your output drifting into caveman cadence, that drift is in-context-learning bleeding from the compressed history — consciously revert to full sentences.`;
|
|
201477
|
-
function buildMagicContextSection(_agent, protectedTags,
|
|
202773
|
+
function buildMagicContextSection(_agent, protectedTags, ctxReduceCallable = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true) {
|
|
201478
202774
|
if (subagentMode) {
|
|
201479
202775
|
return `## Magic Context
|
|
201480
202776
|
|
|
@@ -201485,12 +202781,12 @@ When \`surface_condition\` is provided with \`write\`, the note becomes a projec
|
|
|
201485
202781
|
The dreamer evaluates smart note conditions during nightly runs and surfaces them when conditions are met.
|
|
201486
202782
|
Example: \`ctx_note(action="write", content="Implement X because Y", surface_condition="When PR #42 is merged in this repo")\`` : "";
|
|
201487
202783
|
const temporalGuidance = temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE : "";
|
|
201488
|
-
const cavemanWarning = cavemanTextCompressionEnabled
|
|
202784
|
+
const cavemanWarning = cavemanTextCompressionEnabled ? CAVEMAN_COMPRESSION_WARNING : "";
|
|
201489
202785
|
const languageDirective = buildPrimaryLanguageDirective(language);
|
|
201490
202786
|
const languageGuidance = languageDirective ? `
|
|
201491
202787
|
|
|
201492
202788
|
${languageDirective}` : "";
|
|
201493
|
-
if (!
|
|
202789
|
+
if (!ctxReduceCallable) {
|
|
201494
202790
|
return `## Magic Context
|
|
201495
202791
|
|
|
201496
202792
|
${LONG_TERM_PARTNER_FRAME}
|
|
@@ -201503,7 +202799,7 @@ ${BASE_INTRO_NO_REDUCE(memoryEnabled)}${smartNoteGuidance}${temporalGuidance}${c
|
|
|
201503
202799
|
${LONG_TERM_PARTNER_FRAME}
|
|
201504
202800
|
${PARTNER_FRAME_CLOSER_REDUCE}
|
|
201505
202801
|
|
|
201506
|
-
${BASE_INTRO(protectedTags, memoryEnabled)}${smartNoteGuidance}${temporalGuidance}
|
|
202802
|
+
${BASE_INTRO(protectedTags, memoryEnabled)}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}
|
|
201507
202803
|
${GENERIC_SECTION}
|
|
201508
202804
|
|
|
201509
202805
|
Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance.${languageGuidance}`;
|
|
@@ -201556,17 +202852,18 @@ function createSystemPromptHashHandler(deps) {
|
|
|
201556
202852
|
} catch (error51) {
|
|
201557
202853
|
sessionLog(sessionId, "system-prompt-hash session meta load failed:", error51);
|
|
201558
202854
|
}
|
|
201559
|
-
const
|
|
201560
|
-
const
|
|
201561
|
-
const
|
|
201562
|
-
const
|
|
201563
|
-
const
|
|
202855
|
+
const isSubagentSession2 = sessionMetaEarly?.isSubagent === true;
|
|
202856
|
+
const availability = resolveCtxReduceAvailability(sessionId);
|
|
202857
|
+
const ctxReduceCallable = availability.callable;
|
|
202858
|
+
const subagentReduceMode = isSubagentSession2 && ctxReduceCallable;
|
|
202859
|
+
const effectiveCtxReduceEnabled = isSubagentSession2 ? false : ctxReduceCallable;
|
|
202860
|
+
const skipGuidanceForDisabledSubagent = isSubagentSession2 && !ctxReduceCallable;
|
|
201564
202861
|
const fullPrompt = output.system.join(`
|
|
201565
202862
|
`);
|
|
201566
202863
|
if (fullPrompt.length > 0 && !fullPrompt.includes(MAGIC_CONTEXT_MARKER) && !skipGuidanceForDisabledSubagent) {
|
|
201567
202864
|
const guidance = buildMagicContextSection(null, deps.protectedTags, effectiveCtxReduceEnabled, deps.dreamerEnabled, deps.experimentalTemporalAwareness, deps.experimentalCavemanTextCompression, subagentReduceMode, deps.language, deps.memoryEnabled !== false);
|
|
201568
202865
|
output.system.push(guidance);
|
|
201569
|
-
sessionLog(sessionId, `injected generic guidance into system prompt (ctxReduce=${effectiveCtxReduceEnabled}, subagent=${
|
|
202866
|
+
sessionLog(sessionId, `injected generic guidance into system prompt (ctxReduce=${effectiveCtxReduceEnabled}, subagent=${isSubagentSession2}, subagentReduceMode=${subagentReduceMode})`);
|
|
201570
202867
|
}
|
|
201571
202868
|
const isCacheBusting = deps.systemPromptRefreshSessions.has(sessionId);
|
|
201572
202869
|
const DATE_PATTERN = /Today's date: .+/;
|
|
@@ -201593,6 +202890,8 @@ function createSystemPromptHashHandler(deps) {
|
|
|
201593
202890
|
`);
|
|
201594
202891
|
if (systemContent.length === 0)
|
|
201595
202892
|
return;
|
|
202893
|
+
if (!availability.frozen)
|
|
202894
|
+
return;
|
|
201596
202895
|
const currentHash = createHash13("md5").update(systemContent).digest("hex");
|
|
201597
202896
|
if (!sessionMetaEarly) {
|
|
201598
202897
|
return;
|
|
@@ -201781,7 +203080,7 @@ function createMagicContextHook(deps) {
|
|
|
201781
203080
|
notifyMagicContextDisabled(deps.client, reason);
|
|
201782
203081
|
return null;
|
|
201783
203082
|
}
|
|
201784
|
-
const projectPath =
|
|
203083
|
+
const projectPath = resolveProjectIdentityOrFallback(deps.directory);
|
|
201785
203084
|
try {
|
|
201786
203085
|
checkCompactionMarkerConsistency(db);
|
|
201787
203086
|
} catch (error51) {
|
|
@@ -201792,20 +203091,21 @@ function createMagicContextHook(deps) {
|
|
|
201792
203091
|
const historianFallbackModels = resolveFallbackChain(deps.config.historian?.fallback_models);
|
|
201793
203092
|
const historyRefreshSessions = deps.liveSessionState?.historyRefreshSessions ?? new Set;
|
|
201794
203093
|
const deferredHistoryRefreshSessions = deps.liveSessionState?.deferredHistoryRefreshSessions ?? new Set;
|
|
203094
|
+
const systemPromptRefreshSessions = deps.liveSessionState?.systemPromptRefreshSessions ?? new Set;
|
|
203095
|
+
const pendingMaterializationSessions = deps.liveSessionState?.pendingMaterializationSessions ?? new Set;
|
|
203096
|
+
const deferredMaterializationSessions = deps.liveSessionState?.deferredMaterializationSessions ?? new Set;
|
|
201795
203097
|
try {
|
|
201796
203098
|
const sessionsWithPending = getSessionsWithPendingMarker(db);
|
|
201797
203099
|
if (sessionsWithPending.length > 0) {
|
|
201798
203100
|
for (const sid of sessionsWithPending) {
|
|
201799
203101
|
deferredHistoryRefreshSessions.add(sid);
|
|
203102
|
+
deferredMaterializationSessions.add(sid);
|
|
201800
203103
|
}
|
|
201801
203104
|
log(`[magic-context] rehydrated ${sessionsWithPending.length} session(s) with pending compaction-marker drain at hook init`);
|
|
201802
203105
|
}
|
|
201803
203106
|
} catch (error51) {
|
|
201804
203107
|
log("[magic-context] hook init: pending-marker rehydration failed:", error51);
|
|
201805
203108
|
}
|
|
201806
|
-
const systemPromptRefreshSessions = deps.liveSessionState?.systemPromptRefreshSessions ?? new Set;
|
|
201807
|
-
const pendingMaterializationSessions = deps.liveSessionState?.pendingMaterializationSessions ?? new Set;
|
|
201808
|
-
const deferredMaterializationSessions = deps.liveSessionState?.deferredMaterializationSessions ?? new Set;
|
|
201809
203109
|
const lastHeuristicsTurnId = new Map;
|
|
201810
203110
|
const commitSeenLastPass = new Map;
|
|
201811
203111
|
const variantBySession = deps.liveSessionState?.variantBySession ?? new Map;
|
|
@@ -201826,7 +203126,15 @@ function createMagicContextHook(deps) {
|
|
|
201826
203126
|
}
|
|
201827
203127
|
return;
|
|
201828
203128
|
};
|
|
201829
|
-
const
|
|
203129
|
+
const maybeSendProjectIdentitySessionWarning = (sessionId, directory) => {
|
|
203130
|
+
const warning = takeDubiousOwnershipProjectIdentityWarning(directory);
|
|
203131
|
+
if (!warning)
|
|
203132
|
+
return;
|
|
203133
|
+
const notificationParams = getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession, deps.config.toast_duration_ms);
|
|
203134
|
+
sendIgnoredMessage(deps.client, sessionId, warning, notificationParams).catch((error51) => {
|
|
203135
|
+
log(`[magic-context] failed to send project identity warning for ${directory}: ${getErrorMessage(error51)}`);
|
|
203136
|
+
});
|
|
203137
|
+
};
|
|
201830
203138
|
const dreamerRunnable = isDreamerRunnable(deps.config);
|
|
201831
203139
|
const dreamerConfig = dreamerRunnable ? deps.config.dreamer : undefined;
|
|
201832
203140
|
const historianRunnable = isHistorianRunnable(deps.config);
|
|
@@ -201863,6 +203171,23 @@ function createMagicContextHook(deps) {
|
|
|
201863
203171
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
201864
203172
|
getNotificationParams: (sid) => getLiveNotificationParams(sid, liveModelBySession, variantBySession, agentBySession, deps.config.toast_duration_ms)
|
|
201865
203173
|
});
|
|
203174
|
+
const buildManagedWrapupCtx = (sessionId) => ({
|
|
203175
|
+
...buildManagedRecompCtx(sessionId),
|
|
203176
|
+
contextLimit: (() => {
|
|
203177
|
+
const model = resolveLiveModel(sessionId);
|
|
203178
|
+
return model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
|
|
203179
|
+
})(),
|
|
203180
|
+
executeThresholdPercentage: (() => {
|
|
203181
|
+
const model = resolveLiveModel(sessionId);
|
|
203182
|
+
const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
|
|
203183
|
+
return resolveExecuteThresholdDetail(deps.config.execute_threshold_percentage ?? 65, model ? `${model.providerID}/${model.modelID}` : undefined, 65, {
|
|
203184
|
+
tokensConfig: deps.config.execute_threshold_tokens,
|
|
203185
|
+
contextLimit,
|
|
203186
|
+
sessionId
|
|
203187
|
+
}).percentage;
|
|
203188
|
+
})(),
|
|
203189
|
+
hasPendingNaturalBust: (sid) => historyRefreshSessions.has(sid) || systemPromptRefreshSessions.has(sid) || pendingMaterializationSessions.has(sid)
|
|
203190
|
+
});
|
|
201866
203191
|
const executeEmbedHistory = async (sessionId, options) => {
|
|
201867
203192
|
if (deps.config.memory?.enabled === false) {
|
|
201868
203193
|
return "Memory is disabled for this project, so there is no semantic embedding to backfill.";
|
|
@@ -201873,7 +203198,8 @@ function createMagicContextHook(deps) {
|
|
|
201873
203198
|
return "Embedding is already running for this session.";
|
|
201874
203199
|
}
|
|
201875
203200
|
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
201876
|
-
const sessionProjectIdentity =
|
|
203201
|
+
const sessionProjectIdentity = resolveProjectIdentityOrFallback(directory);
|
|
203202
|
+
maybeSendProjectIdentitySessionWarning(sessionId, directory);
|
|
201877
203203
|
embedPauseBySession.delete(sessionId);
|
|
201878
203204
|
const prior = embedRunStateBySession.get(sessionId);
|
|
201879
203205
|
if (prior)
|
|
@@ -201938,13 +203264,15 @@ function createMagicContextHook(deps) {
|
|
|
201938
203264
|
if (ctrl)
|
|
201939
203265
|
ctrl.abort();
|
|
201940
203266
|
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
201941
|
-
const sessionProjectIdentity =
|
|
203267
|
+
const sessionProjectIdentity = resolveProjectIdentityOrFallback(directory);
|
|
203268
|
+
maybeSendProjectIdentitySessionWarning(sessionId, directory);
|
|
201942
203269
|
const cov = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
201943
203270
|
return `Paused at ${cov.session.embedded}/${cov.session.total} compartments embedded.`;
|
|
201944
203271
|
};
|
|
201945
203272
|
const getEmbedStatusText = (sessionId) => {
|
|
201946
203273
|
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
201947
|
-
const sessionProjectIdentity =
|
|
203274
|
+
const sessionProjectIdentity = resolveProjectIdentityOrFallback(directory);
|
|
203275
|
+
maybeSendProjectIdentitySessionWarning(sessionId, directory);
|
|
201948
203276
|
const coverage = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
201949
203277
|
const progress = recompProgressBySession.get(sessionId);
|
|
201950
203278
|
const drainUi = getEmbedDrainUiStatus(sessionId, progress);
|
|
@@ -201967,7 +203295,8 @@ function createMagicContextHook(deps) {
|
|
|
201967
203295
|
try {
|
|
201968
203296
|
await new Promise((resolve4) => setTimeout(resolve4, 0));
|
|
201969
203297
|
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
201970
|
-
const sessionProjectIdentity =
|
|
203298
|
+
const sessionProjectIdentity = resolveProjectIdentityOrFallback(directory);
|
|
203299
|
+
maybeSendProjectIdentitySessionWarning(sessionId, directory);
|
|
201971
203300
|
const coverage = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
201972
203301
|
if (!coverage.enabled)
|
|
201973
203302
|
return;
|
|
@@ -202001,7 +203330,6 @@ function createMagicContextHook(deps) {
|
|
|
202001
203330
|
db,
|
|
202002
203331
|
channel1StateBySession,
|
|
202003
203332
|
protectedTags: deps.config.protected_tags,
|
|
202004
|
-
ctxReduceEnabled,
|
|
202005
203333
|
smartDrops: deps.config.smart_drops === true,
|
|
202006
203334
|
clearReasoningAge: deps.config.clear_reasoning_age ?? 50,
|
|
202007
203335
|
commitClusterTrigger: deps.config.commit_cluster_trigger,
|
|
@@ -202050,7 +203378,7 @@ function createMagicContextHook(deps) {
|
|
|
202050
203378
|
directory: deps.directory,
|
|
202051
203379
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
|
|
202052
203380
|
} : undefined,
|
|
202053
|
-
cavemanTextCompression:
|
|
203381
|
+
cavemanTextCompression: deps.config.caveman_text_compression?.enabled === true ? {
|
|
202054
203382
|
enabled: true,
|
|
202055
203383
|
minChars: deps.config.caveman_text_compression.min_chars ?? 500
|
|
202056
203384
|
} : undefined,
|
|
@@ -202138,6 +203466,7 @@ function createMagicContextHook(deps) {
|
|
|
202138
203466
|
systemPromptRefreshSessions.add(sessionId);
|
|
202139
203467
|
pendingMaterializationSessions.add(sessionId);
|
|
202140
203468
|
},
|
|
203469
|
+
executeWrapup: historianRunnable ? async (sessionId, options) => runManagedWrapup(buildManagedWrapupCtx(sessionId), sessionId, options) : undefined,
|
|
202141
203470
|
executeRecomp: historianRunnable ? async (sessionId, options) => runManagedRecomp(buildManagedRecompCtx(sessionId), sessionId, options) : undefined,
|
|
202142
203471
|
runUpgrade: historianRunnable ? async (sessionId) => runManagedUpgrade(buildManagedRecompCtx(sessionId), sessionId) : undefined,
|
|
202143
203472
|
executeEmbedHistory,
|
|
@@ -202181,7 +203510,6 @@ function createMagicContextHook(deps) {
|
|
|
202181
203510
|
const systemPromptHash = createSystemPromptHashHandler({
|
|
202182
203511
|
db,
|
|
202183
203512
|
protectedTags: deps.config.protected_tags,
|
|
202184
|
-
ctxReduceEnabled,
|
|
202185
203513
|
dreamerEnabled: dreamerRunnable,
|
|
202186
203514
|
memoryEnabled: deps.config.memory?.enabled !== false,
|
|
202187
203515
|
language: deps.config.language,
|
|
@@ -202196,7 +203524,7 @@ function createMagicContextHook(deps) {
|
|
|
202196
203524
|
internalChildSessions,
|
|
202197
203525
|
experimentalUserMemories: userMemoryCollectionEnabled(deps.config.dreamer),
|
|
202198
203526
|
experimentalTemporalAwareness: deps.config.temporal_awareness === true,
|
|
202199
|
-
experimentalCavemanTextCompression:
|
|
203527
|
+
experimentalCavemanTextCompression: deps.config.caveman_text_compression?.enabled === true
|
|
202200
203528
|
});
|
|
202201
203529
|
const systemPromptHashHandler = systemPromptHash.handler;
|
|
202202
203530
|
const eventHook = createEventHook({
|
|
@@ -202215,8 +203543,7 @@ function createMagicContextHook(deps) {
|
|
|
202215
203543
|
lastHeuristicsTurnId,
|
|
202216
203544
|
commitSeenLastPass,
|
|
202217
203545
|
client: deps.client,
|
|
202218
|
-
protectedTags: deps.config.protected_tags
|
|
202219
|
-
ctxReduceEnabled
|
|
203546
|
+
protectedTags: deps.config.protected_tags
|
|
202220
203547
|
});
|
|
202221
203548
|
return {
|
|
202222
203549
|
"experimental.chat.messages.transform": transform2,
|
|
@@ -202231,7 +203558,6 @@ function createMagicContextHook(deps) {
|
|
|
202231
203558
|
systemPromptRefreshSessions,
|
|
202232
203559
|
pendingMaterializationSessions,
|
|
202233
203560
|
lastHeuristicsTurnId,
|
|
202234
|
-
ctxReduceEnabled,
|
|
202235
203561
|
upgradeReminder: historianRunnable ? (sessionId) => maybeSendUpgradeReminder({
|
|
202236
203562
|
client: deps.client,
|
|
202237
203563
|
db,
|
|
@@ -202263,7 +203589,6 @@ function createMagicContextHook(deps) {
|
|
|
202263
203589
|
function buildMagicContextHookConfig(pluginConfig) {
|
|
202264
203590
|
return {
|
|
202265
203591
|
protected_tags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
|
|
202266
|
-
ctx_reduce_enabled: pluginConfig.ctx_reduce_enabled,
|
|
202267
203592
|
cache_ttl: pluginConfig.cache_ttl,
|
|
202268
203593
|
clear_reasoning_age: pluginConfig.clear_reasoning_age,
|
|
202269
203594
|
toast_duration_ms: pluginConfig.toast_duration_ms,
|
|
@@ -202784,7 +204109,6 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
|
|
|
202784
204109
|
contextLimit: 0,
|
|
202785
204110
|
systemPromptTokens: 0,
|
|
202786
204111
|
compartmentCount: 0,
|
|
202787
|
-
factCount: 0,
|
|
202788
204112
|
memoryCount: 0,
|
|
202789
204113
|
memoryBlockCount: 0,
|
|
202790
204114
|
pendingOpsCount: 0,
|
|
@@ -202823,7 +204147,6 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
|
|
|
202823
204147
|
const memoryBlockCount = meta3 ? Number(meta3.memory_block_count ?? 0) : 0;
|
|
202824
204148
|
const compartmentRow = db.prepare("SELECT COUNT(*) as count FROM compartments WHERE session_id = ?").get(sessionId);
|
|
202825
204149
|
const compartmentCount = compartmentRow?.count ?? 0;
|
|
202826
|
-
const factCount = 0;
|
|
202827
204150
|
let memoryCount = 0;
|
|
202828
204151
|
if (projectIdentity) {
|
|
202829
204152
|
const memRow = db.prepare("SELECT COUNT(*) as count FROM memories WHERE project_path = ? AND status = 'active'").get(projectIdentity);
|
|
@@ -202930,7 +204253,6 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
|
|
|
202930
204253
|
contextLimit,
|
|
202931
204254
|
systemPromptTokens: calibrated.systemTokens,
|
|
202932
204255
|
compartmentCount,
|
|
202933
|
-
factCount,
|
|
202934
204256
|
memoryCount,
|
|
202935
204257
|
memoryBlockCount,
|
|
202936
204258
|
pendingOpsCount,
|
|
@@ -203943,8 +205265,8 @@ function createCtxMemoryTool(deps) {
|
|
|
203943
205265
|
}
|
|
203944
205266
|
});
|
|
203945
205267
|
const idList = targets.map((t) => t.memoryId).join(", ");
|
|
203946
|
-
const
|
|
203947
|
-
return args.reason?.trim() ? `Archived ${
|
|
205268
|
+
const plural2 = targets.length > 1 ? "memories" : "memory";
|
|
205269
|
+
return args.reason?.trim() ? `Archived ${plural2} [ID: ${idList}] (${args.reason.trim()}).` : `Archived ${plural2} [ID: ${idList}].`;
|
|
203948
205270
|
}
|
|
203949
205271
|
return "Error: Unknown action.";
|
|
203950
205272
|
}
|
|
@@ -204349,10 +205671,12 @@ Sources (omit for a broad search across all):
|
|
|
204349
205671
|
- memory: curated cross-session project knowledge — rules, constraints, conventions.
|
|
204350
205672
|
- message: the raw conversation behind your compacted history. Hits include message ordinals — expand the surrounding exchange with ctx_expand(start=N-10, end=N+5).
|
|
204351
205673
|
- git_commit: this repository's commit history.
|
|
205674
|
+
- note: parked decisions, follow-ups, and dismissed notes with their recorded text.
|
|
204352
205675
|
|
|
204353
205676
|
Picking sources:
|
|
204354
205677
|
- "when did this change / was this working before" → ["git_commit", "message"]
|
|
204355
205678
|
- "did we discuss this earlier" → ["message"]
|
|
205679
|
+
- "did we decide something about this / leave a follow-up" → ["note"]
|
|
204356
205680
|
- "what's our convention / rule for X" → ["memory"]`;
|
|
204357
205681
|
var DEFAULT_CTX_SEARCH_LIMIT = 10;
|
|
204358
205682
|
// src/tools/ctx-search/tools.ts
|
|
@@ -204364,7 +205688,8 @@ var VALID_SOURCES = new Set([
|
|
|
204364
205688
|
"memory",
|
|
204365
205689
|
"message",
|
|
204366
205690
|
"git_commit",
|
|
204367
|
-
"primer"
|
|
205691
|
+
"primer",
|
|
205692
|
+
"note"
|
|
204368
205693
|
]);
|
|
204369
205694
|
function normalizeLimit3(limit) {
|
|
204370
205695
|
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
@@ -204407,7 +205732,8 @@ function formatAge2(committedAtMs) {
|
|
|
204407
205732
|
const years = Math.floor(days / 365);
|
|
204408
205733
|
return years === 1 ? "1y ago" : `${years}y ago`;
|
|
204409
205734
|
}
|
|
204410
|
-
|
|
205735
|
+
var NOTE_EXPAND_HINT = "Use ctx_expand(start=N-10, end=N) around any note @msg anchor above to read the surrounding conversation context.";
|
|
205736
|
+
function formatResult(result, index, currentSessionId) {
|
|
204411
205737
|
if (result.source === "memory") {
|
|
204412
205738
|
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
204413
205739
|
return [
|
|
@@ -204428,6 +205754,14 @@ function formatResult(result, index) {
|
|
|
204428
205754
|
`[${index}] [primer] score=${result.score.toFixed(2)} id=${result.primerId} support=${result.support} match=${result.matchType}`,
|
|
204429
205755
|
result.content
|
|
204430
205756
|
].join(`
|
|
205757
|
+
`);
|
|
205758
|
+
}
|
|
205759
|
+
if (result.source === "note") {
|
|
205760
|
+
const anchor = result.anchorOrdinal !== null && result.sourceSessionId === currentSessionId ? ` @msg ${result.anchorOrdinal}` : "";
|
|
205761
|
+
return [
|
|
205762
|
+
`[${index}] [note] score=${result.score.toFixed(2)} id=#${result.noteId} status=${result.status} ${formatAge2(result.createdAt)}${anchor}`,
|
|
205763
|
+
result.content
|
|
205764
|
+
].join(`
|
|
204431
205765
|
`);
|
|
204432
205766
|
}
|
|
204433
205767
|
if (result.source === "compartment") {
|
|
@@ -204445,14 +205779,17 @@ function formatResult(result, index) {
|
|
|
204445
205779
|
].join(`
|
|
204446
205780
|
`);
|
|
204447
205781
|
}
|
|
204448
|
-
function formatSearchResults(query, results) {
|
|
205782
|
+
function formatSearchResults(query, results, currentSessionId) {
|
|
204449
205783
|
if (results.length === 0) {
|
|
204450
|
-
return `No results found for "${query}" across memories, primers, git commits, or message history.`;
|
|
205784
|
+
return `No results found for "${query}" across notes, memories, primers, git commits, or message history.`;
|
|
204451
205785
|
}
|
|
204452
|
-
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
205786
|
+
const bodyParts = results.map((result, index) => formatResult(result, index + 1, currentSessionId));
|
|
204453
205787
|
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
204454
205788
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
204455
205789
|
}
|
|
205790
|
+
if (results.some((result) => result.source === "note" && result.anchorOrdinal !== null && result.sourceSessionId === currentSessionId)) {
|
|
205791
|
+
bodyParts.push(NOTE_EXPAND_HINT);
|
|
205792
|
+
}
|
|
204456
205793
|
const body = bodyParts.join(`
|
|
204457
205794
|
|
|
204458
205795
|
`);
|
|
@@ -204466,7 +205803,7 @@ function createCtxSearchTool(deps) {
|
|
|
204466
205803
|
args: {
|
|
204467
205804
|
query: tool5.schema.string().describe("Search query. Matches against memory content, Primers, git commit messages, and raw user/assistant message text."),
|
|
204468
205805
|
limit: tool5.schema.number().optional().describe("Maximum results to return (default: 10)"),
|
|
204469
|
-
sources: tool5.schema.array(tool5.schema.enum(["memory", "message", "git_commit", "primer"])).optional().describe('Optional. Restrict to specific sources. Examples: ["primer"] for standing project explanations, ["git_commit"] for "when did we change X", ["memory"] for naming conventions, ["message"] for "did we discuss this earlier", ["git_commit","message"] for regression hunts. Omit for a broad search across all enabled sources.')
|
|
205806
|
+
sources: tool5.schema.array(tool5.schema.enum(["memory", "message", "git_commit", "primer", "note"])).optional().describe('Optional. Restrict to specific sources. Examples: ["primer"] for standing project explanations, ["git_commit"] for "when did we change X", ["memory"] for naming conventions, ["message"] for "did we discuss this earlier", ["note"] for parked decisions or follow-ups, ["git_commit","message"] for regression hunts. Omit for a broad search across all enabled sources.')
|
|
204470
205807
|
},
|
|
204471
205808
|
async execute(args, toolContext) {
|
|
204472
205809
|
const query = args.query?.trim();
|
|
@@ -204498,7 +205835,7 @@ function createCtxSearchTool(deps) {
|
|
|
204498
205835
|
visibleMemoryIds,
|
|
204499
205836
|
explicitSearch: true
|
|
204500
205837
|
});
|
|
204501
|
-
return formatSearchResults(query, results);
|
|
205838
|
+
return formatSearchResults(query, results, toolContext.sessionID);
|
|
204502
205839
|
}
|
|
204503
205840
|
});
|
|
204504
205841
|
}
|
|
@@ -204555,14 +205892,13 @@ function createToolRegistry(args) {
|
|
|
204555
205892
|
return {};
|
|
204556
205893
|
}
|
|
204557
205894
|
ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db);
|
|
204558
|
-
const resolveProjectPath = (directory) =>
|
|
204559
|
-
const ctxReduceEnabled = pluginConfig.ctx_reduce_enabled !== false;
|
|
205895
|
+
const resolveProjectPath = (directory) => resolveProjectIdentityOrFallback(directory);
|
|
204560
205896
|
const memoryEnabled = pluginConfig.memory?.enabled !== false;
|
|
204561
205897
|
const allTools = {
|
|
204562
|
-
...
|
|
205898
|
+
...createCtxReduceTools({
|
|
204563
205899
|
db,
|
|
204564
205900
|
protectedTags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS
|
|
204565
|
-
})
|
|
205901
|
+
}),
|
|
204566
205902
|
...createCtxExpandTools({ db }),
|
|
204567
205903
|
...createCtxNoteTools({
|
|
204568
205904
|
db,
|
|
@@ -204973,6 +206309,31 @@ var server = async (ctx) => {
|
|
|
204973
206309
|
log(`[v22-backfill] failed to start background runner: ${err}`);
|
|
204974
206310
|
}
|
|
204975
206311
|
}
|
|
206312
|
+
if (pluginConfig.enabled && hooks.magicContext) {
|
|
206313
|
+
setTimeout(() => {
|
|
206314
|
+
try {
|
|
206315
|
+
const db = openDatabase();
|
|
206316
|
+
if (!db || !isDatabasePersisted(db))
|
|
206317
|
+
return;
|
|
206318
|
+
const ocDb = openOpenCodeDb();
|
|
206319
|
+
if (!ocDb)
|
|
206320
|
+
return;
|
|
206321
|
+
try {
|
|
206322
|
+
const sessions = ocDb.prepare("SELECT id, COALESCE(directory, '') AS directory FROM session ORDER BY id ASC").all();
|
|
206323
|
+
runSessionProjectBackfill(db, sessions.map((session) => ({
|
|
206324
|
+
sessionId: session.id,
|
|
206325
|
+
directory: session.directory
|
|
206326
|
+
}))).catch((err) => {
|
|
206327
|
+
log(`[session-projects] background runner failed: ${err}`);
|
|
206328
|
+
});
|
|
206329
|
+
} finally {
|
|
206330
|
+
closeQuietly(ocDb);
|
|
206331
|
+
}
|
|
206332
|
+
} catch (err) {
|
|
206333
|
+
log(`[session-projects] failed to start background runner: ${err}`);
|
|
206334
|
+
}
|
|
206335
|
+
}, 0);
|
|
206336
|
+
}
|
|
204976
206337
|
const storageDir = getMagicContextStorageDir();
|
|
204977
206338
|
let rpcServer = null;
|
|
204978
206339
|
let stopDreamTimerRegistration;
|
|
@@ -204980,7 +206341,7 @@ var server = async (ctx) => {
|
|
|
204980
206341
|
const dreamerRunnable = isDreamerRunnable(pluginConfig);
|
|
204981
206342
|
const timerRegistration = {
|
|
204982
206343
|
directory: ctx.directory,
|
|
204983
|
-
projectIdentity:
|
|
206344
|
+
projectIdentity: resolveProjectIdentityOrFallback(ctx.directory),
|
|
204984
206345
|
client: ctx.client,
|
|
204985
206346
|
dreamerConfig: dreamerRunnable ? pluginConfig.dreamer : undefined,
|
|
204986
206347
|
language: pluginConfig.language,
|