@cortexkit/pi-magic-context 0.33.1 → 0.34.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.
@@ -7852,9 +7852,13 @@ var require_src2 = __commonJS((exports, module) => {
7852
7852
  });
7853
7853
 
7854
7854
  // ../plugin/src/config/agent-disable.ts
7855
+ var COMPACTION_ENABLED_PATH = `compaction${"."}enabled`;
7855
7856
  function isDreamerRunnable(config) {
7856
7857
  return !!config.dreamer && config.dreamer.disable !== true;
7857
7858
  }
7859
+ function isCompactionEnabled(config) {
7860
+ return config.compaction?.enabled !== false;
7861
+ }
7858
7862
  function clonePlainObject(value) {
7859
7863
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
7860
7864
  return;
@@ -8296,6 +8300,7 @@ var dubiousOwnershipLoggedDirectories = new Set;
8296
8300
  var dubiousOwnershipWarnedDirectories = new Set;
8297
8301
  var transientGitIdentityReuseLoggedDirectories = new Set;
8298
8302
  var execFileSyncForIdentity = execFileSync;
8303
+ var userHomeDirectoryForIdentity = () => homedir2();
8299
8304
  var nowMs = () => Date.now();
8300
8305
 
8301
8306
  class ProjectIdentityError extends Error {
@@ -8491,9 +8496,12 @@ function recordDubiousOwnershipFallback(canonical) {
8491
8496
  dubiousOwnershipLoggedDirectories.add(canonical);
8492
8497
  log(`[magic-context] ${formatDubiousOwnershipWarning(canonical)}`);
8493
8498
  }
8499
+ function canonicalUserHomeDirectory() {
8500
+ return realpathSync.native(userHomeDirectoryForIdentity());
8501
+ }
8494
8502
  function isUserHomeDirectory(directory) {
8495
8503
  try {
8496
- return realpathSync.native(path.resolve(directory)) === realpathSync.native(homedir2());
8504
+ return realpathSync.native(path.resolve(directory)) === canonicalUserHomeDirectory();
8497
8505
  } catch {
8498
8506
  return false;
8499
8507
  }
@@ -8562,22 +8570,52 @@ function hasGitDir(canonical) {
8562
8570
  return false;
8563
8571
  }
8564
8572
  }
8565
- function hasGitDirInAncestorChain(startDirectory) {
8573
+ function gitRootInAncestorChain(startDirectory) {
8566
8574
  let current = startDirectory;
8567
8575
  while (true) {
8568
8576
  if (existsSync2(path.join(current, ".git"))) {
8569
- return true;
8577
+ try {
8578
+ return realpathSync.native(current);
8579
+ } catch {
8580
+ return path.resolve(current);
8581
+ }
8570
8582
  }
8571
8583
  const parent = path.dirname(current);
8572
8584
  if (parent === current) {
8573
- return false;
8585
+ return null;
8574
8586
  }
8575
8587
  current = parent;
8576
8588
  }
8577
8589
  }
8578
- function resolveProjectIdentityForSession(directory) {
8579
- if (isUserHomeDirectory(directory))
8580
- return;
8590
+ function hasGitDirInAncestorChain(startDirectory) {
8591
+ return gitRootInAncestorChain(startDirectory) !== null;
8592
+ }
8593
+ function gitRootDirectory(canonical) {
8594
+ const direct = gitRootInAncestorChain(canonical);
8595
+ if (direct)
8596
+ return direct;
8597
+ try {
8598
+ const realCanonical = realpathSync.native(canonical);
8599
+ return realCanonical === canonical ? null : gitRootInAncestorChain(realCanonical);
8600
+ } catch {
8601
+ return null;
8602
+ }
8603
+ }
8604
+ function resolveProjectIdentityForSession(directory, allowHomeProject = false) {
8605
+ const canonicalHome = canonicalUserHomeDirectory();
8606
+ const canonicalDirectory = (() => {
8607
+ try {
8608
+ return realpathSync.native(path.resolve(directory));
8609
+ } catch {
8610
+ return path.resolve(directory);
8611
+ }
8612
+ })();
8613
+ const inheritsHomeRepository = gitRootDirectory(canonicalDirectory) === canonicalHome;
8614
+ if (canonicalDirectory === canonicalHome || inheritsHomeRepository) {
8615
+ if (!allowHomeProject)
8616
+ return;
8617
+ return directoryFallback(canonicalHome);
8618
+ }
8581
8619
  return resolveProjectIdentityOrFallback(directory);
8582
8620
  }
8583
8621
  function normalizeStoredProjectPath(rawOrStored) {
@@ -8610,9 +8648,28 @@ function scheduleAfterBootQuiet(task, additionalDelayMs = 0) {
8610
8648
  return timer;
8611
8649
  }
8612
8650
 
8651
+ // ../plugin/src/shared/storage-permissions.ts
8652
+ var enforcePrivateStoragePermissions = true;
8653
+ function setStoragePrivatePermissionEnforcement(enforce) {
8654
+ enforcePrivateStoragePermissions = enforce;
8655
+ }
8656
+ function shouldEnforcePrivateStoragePermissions() {
8657
+ return enforcePrivateStoragePermissions;
8658
+ }
8659
+
8613
8660
  // ../plugin/src/features/magic-context/storage-db.ts
8614
- import { chmodSync, copyFileSync, cpSync, existsSync as existsSync4, mkdirSync as mkdirSync2, mkdtempSync } from "node:fs";
8615
- import { dirname as dirname2, join as join3 } from "node:path";
8661
+ import {
8662
+ chmodSync,
8663
+ copyFileSync,
8664
+ cpSync,
8665
+ existsSync as existsSync4,
8666
+ mkdirSync as mkdirSync2,
8667
+ mkdtempSync,
8668
+ readdirSync,
8669
+ readFileSync as readFileSync2,
8670
+ unlinkSync as unlinkSync2
8671
+ } from "node:fs";
8672
+ import { basename as basename2, dirname as dirname2, join as join3 } from "node:path";
8616
8673
 
8617
8674
  // ../plugin/src/shared/error-message.ts
8618
8675
  function getErrorMessage(error) {
@@ -8690,6 +8747,49 @@ function safeString(value) {
8690
8747
  }
8691
8748
  }
8692
8749
 
8750
+ // ../plugin/src/shared/rpc-utils.ts
8751
+ function isPidAlive(pid) {
8752
+ if (!Number.isInteger(pid) || pid <= 0)
8753
+ return false;
8754
+ try {
8755
+ process.kill(pid, 0);
8756
+ return true;
8757
+ } catch (err) {
8758
+ return err.code === "EPERM";
8759
+ }
8760
+ }
8761
+ function parseRpcPortFile(content, fallbackPid = 0) {
8762
+ const trimmed = content.trim();
8763
+ if (!trimmed)
8764
+ return null;
8765
+ if (trimmed.startsWith("{")) {
8766
+ try {
8767
+ const parsed = JSON.parse(trimmed);
8768
+ const port2 = Number(parsed.port);
8769
+ const pid = Number(parsed.pid);
8770
+ const startedAt = Number(parsed.started_at);
8771
+ if (!isValidPort(port2) || !Number.isInteger(pid) || pid <= 0)
8772
+ return null;
8773
+ return {
8774
+ port: port2,
8775
+ pid,
8776
+ started_at: Number.isFinite(startedAt) ? startedAt : 0,
8777
+ token: typeof parsed.token === "string" ? parsed.token : undefined,
8778
+ instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
8779
+ };
8780
+ } catch {
8781
+ return null;
8782
+ }
8783
+ }
8784
+ const port = Number.parseInt(trimmed, 10);
8785
+ if (!isValidPort(port))
8786
+ return null;
8787
+ return { port, pid: fallbackPid, started_at: 0 };
8788
+ }
8789
+ function isValidPort(port) {
8790
+ return Number.isInteger(port) && port > 0 && port <= 65535;
8791
+ }
8792
+
8693
8793
  // ../plugin/src/shared/sqlite.ts
8694
8794
  var isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
8695
8795
  var bunSpec = "bun:" + "sqlite";
@@ -11433,6 +11533,33 @@ var MIGRATIONS = [
11433
11533
  up(db) {
11434
11534
  installLatestAuthorityTriggers(db);
11435
11535
  }
11536
+ },
11537
+ {
11538
+ version: 72,
11539
+ description: "add per-session compaction mode record column (issue #266)",
11540
+ up(db) {
11541
+ if (tableExists2(db, "session_meta")) {
11542
+ ensureColumn(db, "session_meta", "compaction_mode_record", "TEXT");
11543
+ }
11544
+ }
11545
+ },
11546
+ {
11547
+ version: 73,
11548
+ description: "persist the last successful todowrite permission verdict",
11549
+ up(db) {
11550
+ if (tableExists2(db, "session_meta")) {
11551
+ ensureColumn(db, "session_meta", "todo_permission_denied", "INTEGER NOT NULL DEFAULT 2");
11552
+ }
11553
+ }
11554
+ },
11555
+ {
11556
+ version: 74,
11557
+ description: "persist detected context-limit provenance",
11558
+ up(db) {
11559
+ if (tableExists2(db, "session_meta")) {
11560
+ ensureColumn(db, "session_meta", "detected_context_limit_provenance", "TEXT NOT NULL DEFAULT 'unknown'");
11561
+ }
11562
+ }
11436
11563
  }
11437
11564
  ];
11438
11565
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -144458,30 +144585,40 @@ var persistenceByDatabase = new WeakMap;
144458
144585
  var persistenceErrorByDatabase = new WeakMap;
144459
144586
  var pathByDatabase = new WeakMap;
144460
144587
  var lastSchemaFenceRejection = null;
144588
+ var lastMigrationOnOpenRefusal = null;
144461
144589
  function getSchemaFenceRejection() {
144462
144590
  return lastSchemaFenceRejection;
144463
144591
  }
144464
- var LATEST_SUPPORTED_VERSION = 71;
144592
+ function getMigrationOnOpenRefusal() {
144593
+ return lastMigrationOnOpenRefusal;
144594
+ }
144595
+ var LATEST_SUPPORTED_VERSION = 74;
144465
144596
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
144597
+ var defaultStoragePermissionFs = { chmodSync, mkdirSync: mkdirSync2 };
144598
+ var storagePermissionFs = defaultStoragePermissionFs;
144466
144599
  function ensureSecureStorageDir(dir) {
144467
- mkdirSync2(dir, { recursive: true, mode: 448 });
144600
+ if (!shouldEnforcePrivateStoragePermissions()) {
144601
+ storagePermissionFs.mkdirSync(dir, { recursive: true });
144602
+ return;
144603
+ }
144604
+ storagePermissionFs.mkdirSync(dir, { recursive: true, mode: 448 });
144468
144605
  if (!PERMISSIONS_ENFORCEABLE)
144469
144606
  return;
144470
144607
  try {
144471
- chmodSync(dir, 448);
144608
+ storagePermissionFs.chmodSync(dir, 448);
144472
144609
  } catch (error) {
144473
144610
  log(`[magic-context] could not restrict storage dir permissions on ${dir}: ${getErrorMessage(error)}`);
144474
144611
  }
144475
144612
  }
144476
144613
  function restrictDatabaseFilePermissions(dbPath) {
144477
- if (!PERMISSIONS_ENFORCEABLE)
144614
+ if (!PERMISSIONS_ENFORCEABLE || !shouldEnforcePrivateStoragePermissions())
144478
144615
  return;
144479
144616
  for (const suffix of ["", "-wal", "-shm"]) {
144480
144617
  const file = `${dbPath}${suffix}`;
144481
144618
  if (!existsSync4(file))
144482
144619
  continue;
144483
144620
  try {
144484
- chmodSync(file, 384);
144621
+ storagePermissionFs.chmodSync(file, 384);
144485
144622
  } catch (error) {
144486
144623
  log(`[magic-context] could not restrict DB file permissions on ${file}: ${getErrorMessage(error)}`);
144487
144624
  }
@@ -144551,6 +144688,9 @@ function getPersistedSchemaVersion(db) {
144551
144688
  const row = db.prepare("SELECT MAX(version) AS version FROM schema_migrations").get();
144552
144689
  return row?.version ?? 0;
144553
144690
  }
144691
+ function formatSchemaFenceBootLog(persistedVersion, supportedVersion) {
144692
+ return `[magic-context] storage schema at boot: database=v${persistedVersion}, supported_fence=v${supportedVersion}`;
144693
+ }
144554
144694
  function getRuntimeLatestSupportedVersion(options) {
144555
144695
  if (options?.latestSupportedVersion !== undefined) {
144556
144696
  return options.latestSupportedVersion;
@@ -144567,12 +144707,109 @@ function getRuntimeLatestSupportedVersion(options) {
144567
144707
  function enforceSchemaFence(db, dbPath, latestSupportedVersion) {
144568
144708
  const persistedVersion = getPersistedSchemaVersion(db);
144569
144709
  if (persistedVersion <= latestSupportedVersion) {
144710
+ lastSchemaFenceRejection = null;
144570
144711
  return true;
144571
144712
  }
144572
144713
  lastSchemaFenceRejection = { persistedVersion, supportedVersion: latestSupportedVersion };
144573
144714
  log(`[magic-context] storage fatal: refusing to open ${dbPath}; database schema v${persistedVersion} is newer than this binary supports (max v${latestSupportedVersion}). A pinned or stale plugin is likely sharing this database with a newer instance; update or unpin Magic Context with 'npx @cortexkit/magic-context@latest doctor --force', then restart.`);
144574
144715
  return false;
144575
144716
  }
144717
+ function unreadableDiscovery(path2) {
144718
+ return {
144719
+ state: "unreadable",
144720
+ serverPids: [],
144721
+ staleFiles: [],
144722
+ unreadableFile: path2
144723
+ };
144724
+ }
144725
+ function inspectRpcServerDiscovery(storageDir) {
144726
+ const rpcRoot = join3(storageDir, "rpc");
144727
+ let projectEntries;
144728
+ try {
144729
+ projectEntries = readdirSync(rpcRoot, { withFileTypes: true });
144730
+ } catch (error) {
144731
+ if (error.code === "ENOENT") {
144732
+ return { state: "absent", serverPids: [], staleFiles: [] };
144733
+ }
144734
+ return unreadableDiscovery(rpcRoot);
144735
+ }
144736
+ const portFiles = [];
144737
+ for (const projectEntry of projectEntries) {
144738
+ if (!projectEntry.isDirectory())
144739
+ continue;
144740
+ const projectDir = join3(rpcRoot, projectEntry.name);
144741
+ let entries;
144742
+ try {
144743
+ entries = readdirSync(projectDir);
144744
+ } catch {
144745
+ return unreadableDiscovery(projectDir);
144746
+ }
144747
+ for (const entry of entries) {
144748
+ if (entry === "port" || entry.startsWith("port-") && entry.endsWith(".json")) {
144749
+ portFiles.push(join3(projectDir, entry));
144750
+ }
144751
+ }
144752
+ }
144753
+ if (portFiles.length === 0) {
144754
+ return { state: "absent", serverPids: [], staleFiles: [] };
144755
+ }
144756
+ const pids = new Set;
144757
+ const staleFiles = [];
144758
+ for (const portFile of portFiles) {
144759
+ let raw;
144760
+ try {
144761
+ raw = readFileSync2(portFile, "utf8");
144762
+ } catch {
144763
+ return unreadableDiscovery(portFile);
144764
+ }
144765
+ const filename = basename2(portFile);
144766
+ const pidFromName = /^port-(\d+)/.exec(filename)?.[1];
144767
+ const record = parseRpcPortFile(raw, pidFromName ? Number(pidFromName) : 0);
144768
+ if (!record || !Number.isInteger(record.pid) || record.pid <= 0) {
144769
+ return unreadableDiscovery(portFile);
144770
+ }
144771
+ if (isPidAlive(record.pid))
144772
+ pids.add(record.pid);
144773
+ else
144774
+ staleFiles.push(portFile);
144775
+ }
144776
+ const serverPids = [...pids].sort((a, b) => a - b);
144777
+ if (serverPids.length > 0) {
144778
+ return { state: "live", serverPids, staleFiles };
144779
+ }
144780
+ for (const staleFile of staleFiles) {
144781
+ try {
144782
+ unlinkSync2(staleFile);
144783
+ } catch {
144784
+ return unreadableDiscovery(staleFile);
144785
+ }
144786
+ }
144787
+ return { state: "stale", serverPids: [], staleFiles };
144788
+ }
144789
+ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion) {
144790
+ const persistedVersion = getPersistedSchemaVersion(db);
144791
+ if (persistedVersion >= latestSupportedVersion) {
144792
+ lastMigrationOnOpenRefusal = null;
144793
+ return true;
144794
+ }
144795
+ const discovery = inspectRpcServerDiscovery(dbDir);
144796
+ if (discovery.state === "absent" || discovery.state === "stale") {
144797
+ lastMigrationOnOpenRefusal = null;
144798
+ return true;
144799
+ }
144800
+ lastMigrationOnOpenRefusal = {
144801
+ persistedVersion,
144802
+ supportedVersion: latestSupportedVersion,
144803
+ serverPids: discovery.serverPids,
144804
+ ...discovery.unreadableFile ? { unreadableFile: discovery.unreadableFile } : {}
144805
+ };
144806
+ if (discovery.state === "unreadable") {
144807
+ log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from schema v${persistedVersion} to v${latestSupportedVersion} because RPC discovery file ${discovery.unreadableFile ?? "<unknown>"} is unreadable or invalid, so the absence of a live OpenCode server cannot be proven. Restart OpenCode, remove or repair the named discovery file, then retry this process.`);
144808
+ } else {
144809
+ log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from schema v${persistedVersion} to v${latestSupportedVersion} while live OpenCode server PID(s) ${discovery.serverPids.join(", ")} may still use the old plugin build. Restart OpenCode, then retry this process.`);
144810
+ }
144811
+ return false;
144812
+ }
144576
144813
  var sqlitePragmaConfig = {
144577
144814
  cacheSizeMb: 64,
144578
144815
  mmapSizeMb: 0
@@ -144617,6 +144854,9 @@ function finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion)
144617
144854
  pathByDatabase.set(db, dbPath);
144618
144855
  persistenceByDatabase.set(db, true);
144619
144856
  persistenceErrorByDatabase.delete(db);
144857
+ if (!explicitDbPath) {
144858
+ log(formatSchemaFenceBootLog(getPersistedSchemaVersion(db), latestSupportedVersion));
144859
+ }
144620
144860
  return db;
144621
144861
  }
144622
144862
  function initializeDatabase(db) {
@@ -145217,12 +145457,14 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145217
145457
  note_nudge_anchors TEXT NOT NULL DEFAULT '[]',
145218
145458
  auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]',
145219
145459
  last_todo_state TEXT DEFAULT '',
145460
+ todo_permission_denied INTEGER NOT NULL DEFAULT 2,
145220
145461
  todo_synthetic_call_id TEXT DEFAULT '',
145221
145462
  todo_synthetic_anchor_message_id TEXT DEFAULT '',
145222
145463
  todo_synthetic_state_json TEXT DEFAULT '',
145223
145464
  is_subagent INTEGER DEFAULT 0,
145224
145465
  last_context_percentage REAL DEFAULT 0,
145225
145466
  last_input_tokens INTEGER DEFAULT 0,
145467
+ detected_context_limit_provenance TEXT NOT NULL DEFAULT 'unknown',
145226
145468
  observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0,
145227
145469
  cache_alert_sent INTEGER NOT NULL DEFAULT 0,
145228
145470
  times_execute_threshold_reached INTEGER DEFAULT 0,
@@ -145277,6 +145519,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145277
145519
  emergency_drain_active INTEGER NOT NULL DEFAULT 0,
145278
145520
  historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
145279
145521
  wrapup_in_progress_state TEXT,
145522
+ compaction_mode_record TEXT,
145280
145523
  cached_m0_materialized_at INTEGER,
145281
145524
  cached_m0_session_facts_version INTEGER,
145282
145525
  cached_m0_upgrade_state TEXT,
@@ -145476,6 +145719,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145476
145719
  ensureColumn(db, "session_meta", "note_nudge_anchors", "TEXT NOT NULL DEFAULT '[]'");
145477
145720
  ensureColumn(db, "session_meta", "auto_search_hint_decisions", "TEXT NOT NULL DEFAULT '[]'");
145478
145721
  ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
145722
+ ensureColumn(db, "session_meta", "todo_permission_denied", "INTEGER NOT NULL DEFAULT 2");
145479
145723
  ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
145480
145724
  ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
145481
145725
  ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
@@ -145532,6 +145776,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145532
145776
  ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
145533
145777
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
145534
145778
  ensureColumn(db, "session_meta", "detected_context_limit_model_key", "TEXT");
145779
+ ensureColumn(db, "session_meta", "detected_context_limit_provenance", "TEXT NOT NULL DEFAULT 'unknown'");
145535
145780
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
145536
145781
  ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
145537
145782
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
@@ -145582,6 +145827,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145582
145827
  ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
145583
145828
  ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
145584
145829
  ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
145830
+ ensureColumn(db, "session_meta", "compaction_mode_record", "TEXT");
145585
145831
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
145586
145832
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
145587
145833
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -145721,6 +145967,8 @@ function openDatabase(dbPathOrOptions) {
145721
145967
  const explicitDbPath = options?.dbPath !== undefined;
145722
145968
  const { dbDir, dbPath } = resolveDatabasePath(options?.dbPath);
145723
145969
  const latestSupportedVersion = getRuntimeLatestSupportedVersion(options);
145970
+ lastSchemaFenceRejection = null;
145971
+ lastMigrationOnOpenRefusal = null;
145724
145972
  const existing = databases.get(dbPath);
145725
145973
  if (existing) {
145726
145974
  if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion)) {
@@ -145742,6 +145990,10 @@ function openDatabase(dbPathOrOptions) {
145742
145990
  closeQuietly(db);
145743
145991
  return null;
145744
145992
  }
145993
+ if (!enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)) {
145994
+ closeQuietly(db);
145995
+ return null;
145996
+ }
145745
145997
  initializeDatabase(db);
145746
145998
  runMigrations(db);
145747
145999
  ensureContextStoreUuid(db);
@@ -145757,6 +146009,8 @@ async function openDatabaseAsync(dbPathOrOptions) {
145757
146009
  const explicitDbPath = options?.dbPath !== undefined;
145758
146010
  const { dbDir, dbPath } = resolveDatabasePath(options?.dbPath);
145759
146011
  const latestSupportedVersion = getRuntimeLatestSupportedVersion(options);
146012
+ lastSchemaFenceRejection = null;
146013
+ lastMigrationOnOpenRefusal = null;
145760
146014
  const existing = databases.get(dbPath);
145761
146015
  if (existing) {
145762
146016
  if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion))
@@ -145780,6 +146034,10 @@ async function openDatabaseAsync(dbPathOrOptions) {
145780
146034
  closeQuietly(db);
145781
146035
  return null;
145782
146036
  }
146037
+ if (!enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)) {
146038
+ closeQuietly(db);
146039
+ return null;
146040
+ }
145783
146041
  initializeDatabase(db);
145784
146042
  await runMigrationsWithRetry(db);
145785
146043
  ensureContextStoreUuid(db);
@@ -145801,6 +146059,24 @@ async function openDatabaseAsync(dbPathOrOptions) {
145801
146059
  }
145802
146060
  }
145803
146061
 
146062
+ // ../plugin/src/shared/context-limit-provenance.ts
146063
+ function normalizeContextLimitProvenance(value) {
146064
+ if (value === "prompt_only" || value === "combined")
146065
+ return value;
146066
+ return "unknown";
146067
+ }
146068
+
146069
+ // ../plugin/src/shared/escalation-bands.ts
146070
+ var MAX_EXECUTE_THRESHOLD = 90;
146071
+ var ABSOLUTE_EMERGENCY_PERCENTAGE = 95;
146072
+ function escalationBands(effectiveThresholdPercentage) {
146073
+ const threshold = Number.isFinite(effectiveThresholdPercentage) ? Math.min(effectiveThresholdPercentage, MAX_EXECUTE_THRESHOLD) : 65;
146074
+ return {
146075
+ forceMaterializationPercentage: Math.max(85, threshold + 2),
146076
+ emergencyPercentage: ABSOLUTE_EMERGENCY_PERCENTAGE
146077
+ };
146078
+ }
146079
+
145804
146080
  // ../plugin/src/features/magic-context/storage-meta-shared.ts
145805
146081
  import { Buffer as Buffer2 } from "node:buffer";
145806
146082
  var SESSION_META_SELECT_COLUMNS = [
@@ -146440,6 +146716,45 @@ function releaseWrapupInProgress(db, sessionId, holderId) {
146440
146716
  }
146441
146717
  }
146442
146718
  }
146719
+ var COMPACTION_MODE_RECORD_VALUES = new Set([
146720
+ "on",
146721
+ "off",
146722
+ "on_notice_pending",
146723
+ "off_notice_pending",
146724
+ "off_cleanup_pending"
146725
+ ]);
146726
+ function normalizeCompactionModeRecord(value) {
146727
+ if (value === null || value === undefined)
146728
+ return null;
146729
+ if (typeof value === "string" && COMPACTION_MODE_RECORD_VALUES.has(value)) {
146730
+ return value;
146731
+ }
146732
+ return null;
146733
+ }
146734
+ function resolveCompactionModeRecord(record) {
146735
+ switch (record) {
146736
+ case "on":
146737
+ case "on_notice_pending":
146738
+ return "on";
146739
+ case "off":
146740
+ case "off_notice_pending":
146741
+ case "off_cleanup_pending":
146742
+ return "off";
146743
+ default:
146744
+ return null;
146745
+ }
146746
+ }
146747
+ function getCompactionModeRecord(db, sessionId) {
146748
+ const row = db.prepare("SELECT compaction_mode_record FROM session_meta WHERE session_id = ?").get(sessionId);
146749
+ return normalizeCompactionModeRecord(row?.compaction_mode_record);
146750
+ }
146751
+ function setCompactionModeRecord(db, sessionId, value) {
146752
+ if (value !== null && !COMPACTION_MODE_RECORD_VALUES.has(value)) {
146753
+ throw new Error(`Invalid compaction_mode_record value: ${String(value)} (expected a supported compaction mode record or null)`);
146754
+ }
146755
+ ensureSessionMetaRow(db, sessionId);
146756
+ db.prepare("UPDATE session_meta SET compaction_mode_record = ? WHERE session_id = ?").run(value, sessionId);
146757
+ }
146443
146758
  function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
146444
146759
  if (usagePercentage >= 95)
146445
146760
  return Math.min(1e6, Math.max(4 * perRunCap, Math.round(0.5 * usable)));
@@ -146447,7 +146762,6 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
146447
146762
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
146448
146763
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
146449
146764
  }
146450
- var EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95;
146451
146765
  var EMERGENCY_DRAIN_EXIT_MARGIN = 10;
146452
146766
  var EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55;
146453
146767
  var EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000;
@@ -146482,7 +146796,8 @@ function reserveProtectedTailDrainTokens(args) {
146482
146796
  }
146483
146797
  const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
146484
146798
  let latchActiveSince = meta.emergencyDrainActive;
146485
- if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
146799
+ const { forceMaterializationPercentage } = escalationBands(args.executeThresholdPercentage);
146800
+ if (args.usagePercentage >= forceMaterializationPercentage) {
146486
146801
  if (latchActiveSince <= 0)
146487
146802
  latchActiveSince = now;
146488
146803
  } else if (latchActiveSince > 0) {
@@ -146851,17 +147166,19 @@ function normalizeEmergencyRecoveryOrigin(value) {
146851
147166
  return value === "provider_overflow" || value === "proactive_model_shrink" ? value : null;
146852
147167
  }
146853
147168
  function getOverflowState(db, sessionId, modelKey) {
146854
- const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, needs_emergency_recovery, emergency_recovery_origin FROM session_meta WHERE session_id = ?").get(sessionId);
147169
+ const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, detected_context_limit_provenance, needs_emergency_recovery, emergency_recovery_origin FROM session_meta WHERE session_id = ?").get(sessionId);
146855
147170
  if (!result) {
146856
147171
  return {
146857
147172
  detectedContextLimit: 0,
146858
147173
  detectedContextLimitModelKey: null,
147174
+ detectedContextLimitProvenance: "unknown",
146859
147175
  needsEmergencyRecovery: false,
146860
147176
  emergencyRecoveryOrigin: null
146861
147177
  };
146862
147178
  }
146863
147179
  const storedModelKey = normalizeDetectedLimitModelKey(result.detected_context_limit_model_key);
146864
147180
  const requestedModelKey = normalizeDetectedLimitModelKey(modelKey);
147181
+ const provenance = normalizeContextLimitProvenance(result.detected_context_limit_provenance);
146865
147182
  const limit = typeof result.detected_context_limit === "number" && result.detected_context_limit > 0 ? result.detected_context_limit : 0;
146866
147183
  const modelMatches = limit > 0 && requestedModelKey && storedModelKey ? requestedModelKey === storedModelKey : true;
146867
147184
  const needs = typeof result.needs_emergency_recovery === "number" && result.needs_emergency_recovery > 0;
@@ -146870,11 +147187,12 @@ function getOverflowState(db, sessionId, modelKey) {
146870
147187
  return {
146871
147188
  detectedContextLimit: modelMatches ? limit : 0,
146872
147189
  detectedContextLimitModelKey: storedModelKey,
147190
+ detectedContextLimitProvenance: provenance,
146873
147191
  needsEmergencyRecovery: needs,
146874
147192
  emergencyRecoveryOrigin: recoveryOrigin
146875
147193
  };
146876
147194
  }
146877
- function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow") {
147195
+ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow", provenance = "unknown") {
146878
147196
  emergencyRecoveryArmedSessions.add(sessionId);
146879
147197
  db.transaction(() => {
146880
147198
  ensureSessionMetaRow(db, sessionId);
@@ -146883,7 +147201,7 @@ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin =
146883
147201
  providerOverflowReconfirmedSessions.add(sessionId);
146884
147202
  }
146885
147203
  if (typeof reportedLimit === "number" && reportedLimit > 0) {
146886
- db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), origin, sessionId);
147204
+ db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, detected_context_limit_provenance = ?, needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), normalizeContextLimitProvenance(provenance), origin, sessionId);
146887
147205
  } else {
146888
147206
  db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(origin, sessionId);
146889
147207
  }
@@ -146904,7 +147222,7 @@ function clearEmergencyRecovery(db, sessionId) {
146904
147222
  function clearDetectedContextLimit(db, sessionId) {
146905
147223
  db.transaction(() => {
146906
147224
  ensureSessionMetaRow(db, sessionId);
146907
- db.prepare("UPDATE session_meta SET detected_context_limit = 0, detected_context_limit_model_key = NULL WHERE session_id = ?").run(sessionId);
147225
+ db.prepare("UPDATE session_meta SET detected_context_limit = 0, detected_context_limit_model_key = NULL, detected_context_limit_provenance = 'unknown' WHERE session_id = ?").run(sessionId);
146908
147226
  })();
146909
147227
  }
146910
147228
  function getPersistedCompactionMarkerState(db, sessionId) {
@@ -147169,6 +147487,62 @@ function getRawSessionMessageCountFromDb(db, sessionId) {
147169
147487
  AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
147170
147488
  return typeof row?.count === "number" ? row.count : 0;
147171
147489
  }
147490
+ function isMidTurn(_deps, sessionId) {
147491
+ try {
147492
+ return withReadOnlySessionDb((db) => isMidTurnFromOpenCodeDb(db, sessionId));
147493
+ } catch (error) {
147494
+ log("[magic-context] failed to inspect OpenCode mid-turn state:", error);
147495
+ return false;
147496
+ }
147497
+ }
147498
+ function isMidTurnFromOpenCodeDb(db, sessionId) {
147499
+ const latestAssistant = db.prepare(`SELECT id,
147500
+ json_extract(data, '$.finish') as finish,
147501
+ time_created as timeCreated
147502
+ FROM message
147503
+ WHERE session_id = ?
147504
+ AND json_extract(data, '$.role') = 'assistant'
147505
+ ORDER BY time_created DESC
147506
+ LIMIT 1`).get(sessionId);
147507
+ if (typeof latestAssistant?.id !== "string")
147508
+ return false;
147509
+ if (hasNewerRealUserMessage(db, sessionId, latestAssistant.timeCreated))
147510
+ return false;
147511
+ if (latestAssistant.finish === "tool-calls")
147512
+ return true;
147513
+ const partRows = db.prepare("SELECT data FROM part WHERE session_id = ? AND message_id = ?").all(sessionId, latestAssistant.id);
147514
+ return partRows.some((row) => {
147515
+ if (typeof row.data !== "string" || row.data.length === 0)
147516
+ return false;
147517
+ try {
147518
+ const part = JSON.parse(row.data);
147519
+ return part.type === "tool" && part.providerExecuted !== true;
147520
+ } catch {
147521
+ return false;
147522
+ }
147523
+ });
147524
+ }
147525
+ function hasNewerRealUserMessage(db, sessionId, latestAssistantTimeCreated) {
147526
+ if (typeof latestAssistantTimeCreated !== "number")
147527
+ return false;
147528
+ const row = db.prepare(`SELECT 1 as one
147529
+ FROM message m
147530
+ WHERE m.session_id = ?
147531
+ AND m.time_created > ?
147532
+ AND json_extract(m.data, '$.role') = 'user'
147533
+ AND NOT (
147534
+ EXISTS (SELECT 1 FROM part p WHERE p.message_id = m.id)
147535
+ AND NOT EXISTS (
147536
+ SELECT 1 FROM part p
147537
+ WHERE p.message_id = m.id
147538
+ AND COALESCE(json_extract(p.data, '$.synthetic'), 0) NOT IN (1, 'true')
147539
+ AND json_extract(p.data, '$.metadata.marker.kind') IS NULL
147540
+ AND COALESCE(json_extract(p.data, '$.ignored'), 0) NOT IN (1, 'true')
147541
+ )
147542
+ )
147543
+ LIMIT 1`).get(sessionId, latestAssistantTimeCreated);
147544
+ return row?.one === 1;
147545
+ }
147172
147546
 
147173
147547
  // ../plugin/src/hooks/magic-context/read-session-raw.ts
147174
147548
  function isRawMessageRow(row) {
@@ -148647,7 +149021,7 @@ function escapeXmlContent(s) {
148647
149021
  }
148648
149022
  // ../plugin/src/features/magic-context/project-docs-hash.ts
148649
149023
  import { createHash as createHash5 } from "node:crypto";
148650
- import { lstatSync, readFileSync as readFileSync2, statSync as statSync3 } from "node:fs";
149024
+ import { lstatSync, readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
148651
149025
  import path2 from "node:path";
148652
149026
  var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
148653
149027
  var PROJECT_DOCS_DELIMITER = `
@@ -148721,7 +149095,7 @@ function readCanonicalPieces(projectDirectory, files) {
148721
149095
  if (!safeToRead) {
148722
149096
  continue;
148723
149097
  }
148724
- const canonicalContent = canonicalizeDocContent(readFileSync2(filePath, "utf8"));
149098
+ const canonicalContent = canonicalizeDocContent(readFileSync3(filePath, "utf8"));
148725
149099
  hashPieces.push(`file:${filename}
148726
149100
  ${canonicalContent}`);
148727
149101
  renderedSections.push(`<file name="${escapeXmlAttr(filename)}">
@@ -149168,7 +149542,7 @@ function getMemoryMutationsForRenderByIdentitySet(db, projectPaths, afterId, ren
149168
149542
  }
149169
149543
  visited.add(terminal);
149170
149544
  const next = byTarget.get(terminal);
149171
- if (!next || next.mutationType !== "superseded")
149545
+ if (next?.mutationType !== "superseded")
149172
149546
  break;
149173
149547
  if (depth >= MAX_MEMORY_REPLACEMENT_DEPTH - 1) {
149174
149548
  terminal = null;
@@ -149428,6 +149802,14 @@ function getPendingOpsStatement(db) {
149428
149802
  }
149429
149803
  return stmt;
149430
149804
  }
149805
+ function getClearPendingOpsStatement(db) {
149806
+ let stmt = clearPendingOpsStatements.get(db);
149807
+ if (!stmt) {
149808
+ stmt = db.prepare("DELETE FROM pending_ops WHERE session_id = ?");
149809
+ clearPendingOpsStatements.set(db, stmt);
149810
+ }
149811
+ return stmt;
149812
+ }
149431
149813
  function getRemovePendingOpStatement(db) {
149432
149814
  let stmt = removePendingOpStatements.get(db);
149433
149815
  if (!stmt) {
@@ -149462,6 +149844,9 @@ function getPendingOps(db, sessionId) {
149462
149844
  const rows = getPendingOpsStatement(db).all(sessionId).filter(isPendingOpRow);
149463
149845
  return rows.map(toPendingOp).filter((op) => op !== null);
149464
149846
  }
149847
+ function clearPendingOps(db, sessionId) {
149848
+ getClearPendingOpsStatement(db).run(sessionId);
149849
+ }
149465
149850
  function removePendingOp(db, sessionId, tagId) {
149466
149851
  getRemovePendingOpStatement(db).run(sessionId, tagId);
149467
149852
  }
@@ -150421,76 +150806,6 @@ var ERROR_CLASSES = new Set([
150421
150806
  "permission_denied",
150422
150807
  "unknown"
150423
150808
  ]);
150424
- // ../plugin/src/shared/models-dev-cache.ts
150425
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
150426
- import { join as join5 } from "node:path";
150427
- var MIN_SANE_LIMIT = 20000;
150428
- var MAX_SANE_LIMIT = 3000000;
150429
- function isSaneLimit(limit) {
150430
- return typeof limit === "number" && limit >= MIN_SANE_LIMIT && limit <= MAX_SANE_LIMIT;
150431
- }
150432
- var apiCache = null;
150433
- var persistSeedLoaded = false;
150434
- function persistFilePath() {
150435
- return join5(getMagicContextStorageDir(), `model-context-limits-${getHarness()}.json`);
150436
- }
150437
- function loadPersistedApiCacheOnce() {
150438
- if (persistSeedLoaded || apiCache !== null)
150439
- return;
150440
- persistSeedLoaded = true;
150441
- try {
150442
- const raw = readFileSync3(persistFilePath(), "utf-8");
150443
- const obj = JSON.parse(raw);
150444
- const map = new Map;
150445
- for (const [key, persisted] of Object.entries(obj)) {
150446
- const limit = typeof persisted === "number" ? persisted : persisted.limit;
150447
- const inputLimit = typeof persisted === "number" ? undefined : persisted.inputLimit;
150448
- const vision = typeof persisted === "number" ? false : persisted.vision === true;
150449
- if (isSaneLimit(limit)) {
150450
- map.set(key, {
150451
- limit,
150452
- inputLimit: isSaneLimit(inputLimit) ? inputLimit : undefined,
150453
- vision
150454
- });
150455
- }
150456
- }
150457
- if (map.size > 0) {
150458
- apiCache = map;
150459
- sessionLog("global", `models-dev-cache: seeded ${map.size} entries from persisted cache (cold start)`);
150460
- }
150461
- } catch {}
150462
- }
150463
- function getSdkContextLimit(providerID, modelID) {
150464
- loadPersistedApiCacheOnce();
150465
- const fromApi = lookupLimitWithTagFallback(apiCache, providerID, modelID);
150466
- return isSaneLimit(fromApi) ? fromApi : undefined;
150467
- }
150468
- function modelSupportsVision(providerID, modelID) {
150469
- loadPersistedApiCacheOnce();
150470
- if (!apiCache)
150471
- return false;
150472
- const exact = apiCache.get(`${providerID}/${modelID}`);
150473
- if (exact?.vision === true)
150474
- return true;
150475
- const colon = modelID.lastIndexOf(":");
150476
- return colon > 0 ? apiCache.get(`${providerID}/${modelID.slice(0, colon)}`)?.vision === true : false;
150477
- }
150478
- function lookupLimitWithTagFallback(cache, providerID, modelID) {
150479
- if (!cache)
150480
- return;
150481
- const exact = cache.get(`${providerID}/${modelID}`)?.limit;
150482
- if (typeof exact === "number")
150483
- return exact;
150484
- const colonIdx = modelID.lastIndexOf(":");
150485
- if (colonIdx > 0) {
150486
- const baseModel = modelID.slice(0, colonIdx);
150487
- const fallback = cache.get(`${providerID}/${baseModel}`)?.limit;
150488
- if (typeof fallback === "number")
150489
- return fallback;
150490
- }
150491
- return;
150492
- }
150493
-
150494
150809
  // ../plugin/src/hooks/magic-context/todo-view.ts
150495
150810
  import { createHash as createHash7 } from "node:crypto";
150496
150811
  var TODO_STATUS_PENDING = "pending";
@@ -150948,7 +151263,7 @@ function pruneNestedConfigLeaf(block, relativePath) {
150948
151263
  }
150949
151264
 
150950
151265
  // src/config/index.ts
150951
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
151266
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
150952
151267
 
150953
151268
  // ../plugin/src/config/migrate-dreamer-v2.ts
150954
151269
  var OLD_VERIFY_TASK = "verify";
@@ -165782,7 +166097,7 @@ var AgentOverrideConfigSchema = exports_external.object({
165782
166097
 
165783
166098
  // ../plugin/src/config/schema/magic-context.ts
165784
166099
  var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
165785
- var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.";
166100
+ var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.";
165786
166101
  var DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
165787
166102
  var DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
165788
166103
  var DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
@@ -165880,7 +166195,22 @@ var BaseEmbeddingConfigSchema = exports_external.object({
165880
166195
  input_type: exports_external.string().optional().describe("Default input_type for stored/indexed (passage) embeddings in the request body. Required by some openai-compatible providers (e.g. NVIDIA NIM). Omitted from the request when unset."),
165881
166196
  query_input_type: exports_external.string().optional().describe("Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type."),
165882
166197
  truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
165883
- max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
166198
+ max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted."),
166199
+ local_dtype: exports_external.enum([
166200
+ "auto",
166201
+ "fp32",
166202
+ "fp16",
166203
+ "q8",
166204
+ "int8",
166205
+ "uint8",
166206
+ "q4",
166207
+ "bnb4",
166208
+ "q4f16",
166209
+ "q2",
166210
+ "q2f16",
166211
+ "q1",
166212
+ "q1f16"
166213
+ ]).optional().describe("Local provider only: ONNX model dtype passed to the transformers.js feature-extraction pipeline. Accepts the @huggingface/transformers DataType strings (auto, fp32, fp16, q8, int8, uint8, q4, bnb4, q4f16, q2, q2f16, q1, q1f16). Omitted keeps today's behavior (fp32). A non-default value changes the produced vectors and folds into the embedding model identity, so switching dtype re-embeds rather than mixing vector spaces. Useful for selecting a quantized variant (e.g. q8) of a larger multilingual model to cut memory and CPU cost; see issue #259.")
165884
166214
  }).superRefine((data, ctx) => {
165885
166215
  const validationProvider = data.provider === "synapse" ? data.fallback_provider : data.provider;
165886
166216
  if (validationProvider === "openai-compatible" && !data.endpoint?.trim()) {
@@ -165922,7 +166252,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
165922
166252
  return {
165923
166253
  provider: "local",
165924
166254
  model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
165925
- ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
166255
+ ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {},
166256
+ ...data.local_dtype ? { local_dtype: data.local_dtype } : {}
165926
166257
  };
165927
166258
  }
165928
166259
  if (data.provider === "openai-compatible") {
@@ -165945,6 +166276,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
165945
166276
  });
165946
166277
  var MagicContextConfigSchema = exports_external.object({
165947
166278
  enabled: exports_external.boolean().default(true).describe("Enable magic context (default: true)"),
166279
+ allow_home_project: exports_external.boolean().default(false).describe("Allow Magic Context sessions launched from the exact canonical home directory. The home session uses its deterministic dir: identity so pre-gate memories reconnect. USER-LEVEL ONLY: project config is ignored. The home identity is excluded from registry seed exports, never resolves descendants by containment, and cannot join a workspace."),
165948
166280
  experimental: exports_external.object({
165949
166281
  mural: exports_external.object({
165950
166282
  enabled: exports_external.boolean().default(false),
@@ -165956,15 +166288,19 @@ var MagicContextConfigSchema = exports_external.object({
165956
166288
  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."),
165957
166289
  historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
165958
166290
  dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
165959
- 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" })'),
166291
+ 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", "1h", "30s") or per-model object ({ default: "5m", "model-id": "10m" }). Set to "never" for lanes kept warm by an external keepwarm proxy — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time.'),
166292
+ output_reserve: exports_external.union([
166293
+ exports_external.number().min(0),
166294
+ exports_external.object({ default: exports_external.number().min(0) }).catchall(exports_external.number().min(0))
166295
+ ]).optional().describe('User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.'),
165960
166296
  toast_duration_ms: exports_external.number().min(0).max(60000).default(5000).describe("TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)"),
165961
166297
  execute_threshold_percentage: exports_external.union([
165962
- exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE),
165963
- exports_external.object({ default: exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE) }).catchall(exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE))
165964
- ]).default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE).describe('Context percentage that forces queued operations to execute. Number or per-model object ({ default: 65, "provider/model": 45 }). Values above 80 are rejected because the runtime caps at 80% for cache safety (MAX_EXECUTE_THRESHOLD). Default: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE'),
166298
+ exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE),
166299
+ exports_external.object({ default: exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE) }).catchall(exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE))
166300
+ ]).default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE).describe('Context percentage that forces queued operations to execute. Number or per-model object ({ default: 65, "provider/model": 45 }). Values above 90 are rejected because the runtime caps at 90% of the output-reserved safe window (MAX_EXECUTE_THRESHOLD). Default: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE'),
165965
166301
  execute_threshold_tokens: exports_external.object({
165966
166302
  default: exports_external.number().min(5000).max(2000000).optional()
165967
- }).catchall(exports_external.number().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 80% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
166303
+ }).catchall(exports_external.number().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 90% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
165968
166304
  protected_tags: exports_external.number().min(1).max(100).optional().describe("Number of recent tags to protect from dropping (min: 1, max: 100, default: 20)"),
165969
166305
  clear_reasoning_age: exports_external.number().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
165970
166306
  history_budget_percentage: exports_external.number().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
@@ -165984,6 +166320,9 @@ var MagicContextConfigSchema = exports_external.object({
165984
166320
  cache_size_mb: exports_external.number().min(2).max(2048).default(64).describe("Page-cache size in MiB per connection (PRAGMA cache_size). Larger keeps more hot pages resident, cutting re-reads on repeated full-table scans. (min 2, max 2048, default 64)"),
165985
166321
  mmap_size_mb: exports_external.number().min(0).max(8192).default(0).describe("Memory-mapped I/O size in MiB (PRAGMA mmap_size). 0 disables mmap (SQLite default). Raising it can cut read overhead on large DBs at the cost of address space. (min 0, max 8192, default 0)")
165986
166322
  }).default({ cache_size_mb: 64, mmap_size_mb: 0 }).describe("SQLite connection tuning for Magic Context's own context.db. These are per-connection PRAGMAs applied at open; they do not change the schema or what is stored."),
166323
+ storage: exports_external.object({
166324
+ enforce_private_permissions: exports_external.boolean().default(true).describe("When true (default), Magic Context creates and re-tightens its storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages directory, database, WAL/SHM, cache, and RPC file permissions externally; Magic Context then never chmods or supplies restrictive creation modes. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.")
166325
+ }).default({ enforce_private_permissions: true }).describe("Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; every group member able to read the storage can read all stored session content and memories."),
165987
166326
  embedding: EmbeddingConfigSchema.default({
165988
166327
  provider: "local",
165989
166328
  model: DEFAULT_LOCAL_EMBEDDING_MODEL
@@ -165997,6 +166336,9 @@ var MagicContextConfigSchema = exports_external.object({
165997
166336
  temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add compact date ranges to compartment headings. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
165998
166337
  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."),
165999
166338
  fail_closed_blocking: exports_external.boolean().default(true).describe("When Magic Context cannot operate (schema fence mismatch, storage open/migration failure), block the primary-session prompt with a loud recovery error instead of silently degrading to native compaction. Default true. Set false only to restore the old degrade-silently behavior (not recommended). USER-LEVEL ONLY — ignored in project config for security. Requires a restart."),
166339
+ compaction: exports_external.object({
166340
+ enabled: exports_external.boolean().default(true).describe("When false, Magic Context stops managing the context window and keeps its knowledge layer: memory and docs/user-profile/key-files injection through additive m[0]/m[1], raw-message FTS indexing, dreamer, notes, ctx_search, ctx_expand, ctx_memory, and /ctx-embed remain available. MC's historian/compartment preparation, tagging, markers, pruning, folding, drops, strips, splicing, synthetic context-management todos, temporal markers, nudges, and fail-closed blocking stop; ctx_expand remains a knowledge-surface tool. fail_closed_blocking is inert: a transform failure passes the input messages through without blocking or cancelling. This setting does not enable native compaction: OpenCode's compaction.auto / compaction.prune or Pi's equivalent owns the window, or nothing does. MC's compaction.enabled in magic-context.jsonc is distinct from OpenCode's compaction.auto / compaction.prune in opencode.jsonc; they are different files and different owners. On the first turn after disabling, a long session may trigger one native compaction cycle; MC removes only its own marker boundary, leaves native boundaries and stored compartments intact, and does no pre-trimming mitigation. Marker cleanup is lazy per session, so an unresumed session is cleaned when it is next resumed. If compaction is enabled again, run /ctx-wrapup when the historian is runnable to catch up. OpenCode peer verification against v1.18.4 confirms native compaction covers child sessions: subagents receive additive memory/docs injection and no MC reclaim in this mode, so keep subagent tasks small or leave compaction.enabled on for long subagent runs. If transform_mode is rust, compaction-off resolves to the TypeScript transform and emits one frozen boot warning because there is no Rust reduced-mode contract. This is boot-resolved and requires a process restart; project-tier compaction.enabled is stripped so a cloned repository cannot disable the user's setting. The sidebar reports raw usage as Context: <pct>% · native compaction or Context: <pct>% · no active compaction and does not show an MC execute-threshold fill. /ctx-wrapup, /ctx-recomp, /ctx-flush, and /ctx-session-upgrade refuse without context-management side effects; /ctx-embed remains functional. Raw content hidden by a native boundary before Magic Context's first pass is not retroactively indexed.")
166341
+ }).default({ enabled: true }).describe("Compaction-off mode gate. Default true (MC manages the context window as today). Set compaction.enabled=false to keep the knowledge layer while letting native compaction (or nothing) own the window. Boot-resolved; requires a restart to change."),
166000
166342
  todowrite: exports_external.object({
166001
166343
  enabled: exports_external.boolean().default(true).describe("Pi only: register Magic Context's todowrite task-list tool. Disable if you use your own todo extension. OpenCode ships its own built-in todowrite; this setting has no effect there."),
166002
166344
  overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
@@ -166150,6 +166492,19 @@ function stripUnsafeProjectConfigFields(projectRaw) {
166150
166492
  delete projectRaw.fail_closed_blocking;
166151
166493
  warnings.push("Ignoring fail_closed_blocking from project config (security: only user-level config may disable or force the loud inoperability gate).");
166152
166494
  }
166495
+ if ("allow_home_project" in projectRaw) {
166496
+ delete projectRaw.allow_home_project;
166497
+ warnings.push("Ignoring allow_home_project from project config (security: only user-level config may opt the user's home directory into Magic Context).");
166498
+ }
166499
+ const compaction = projectRaw.compaction;
166500
+ if (isPlainObject3(compaction) && "enabled" in compaction) {
166501
+ delete compaction.enabled;
166502
+ warnings.push("Ignoring compaction.enabled from project config (security: only user-level config may disable Magic Context's context-window management; a cloned repo cannot change how the user's window is owned).");
166503
+ }
166504
+ if ("output_reserve" in projectRaw) {
166505
+ delete projectRaw.output_reserve;
166506
+ warnings.push("Ignoring output_reserve from project config (security: output-token reservation only honors user-level config).");
166507
+ }
166153
166508
  if ("language" in projectRaw) {
166154
166509
  delete projectRaw.language;
166155
166510
  warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
@@ -166158,6 +166513,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
166158
166513
  delete projectRaw.sqlite;
166159
166514
  warnings.push("Ignoring sqlite.* from project config (security: SQLite cache/mmap PRAGMAs apply to the " + "process-global shared database handle; only user-level config may set them).");
166160
166515
  }
166516
+ const storage = projectRaw.storage;
166517
+ if (isPlainObject3(storage) && "enforce_private_permissions" in storage) {
166518
+ delete storage.enforce_private_permissions;
166519
+ warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
166520
+ }
166161
166521
  const pi = projectRaw.pi;
166162
166522
  if (isPlainObject3(pi) && "subagent_extensions" in pi) {
166163
166523
  delete pi.subagent_extensions;
@@ -166496,6 +166856,188 @@ function substituteConfigVariables(input) {
166496
166856
  return { text: output, warnings };
166497
166857
  }
166498
166858
 
166859
+ // ../plugin/src/shared/models-dev-cache.ts
166860
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
166861
+ import { join as join5 } from "node:path";
166862
+
166863
+ // ../plugin/src/shared/harness-provider-map.ts
166864
+ var CANONICAL_TO_PI_PROVIDER = {
166865
+ openai: "openai-codex",
166866
+ google: "google-antigravity"
166867
+ };
166868
+ var PI_TO_CANONICAL_PROVIDER = {
166869
+ "openai-codex": "openai",
166870
+ "google-antigravity": "google"
166871
+ };
166872
+ function remapProviderPrefix(ref, map2) {
166873
+ if (typeof ref !== "string")
166874
+ return ref;
166875
+ const slash = ref.indexOf("/");
166876
+ if (slash <= 0)
166877
+ return ref;
166878
+ const provider = ref.slice(0, slash);
166879
+ const mapped = map2[provider];
166880
+ return mapped ? `${mapped}${ref.slice(slash)}` : ref;
166881
+ }
166882
+ function piModelRefToCanonical(ref) {
166883
+ return remapProviderPrefix(ref, PI_TO_CANONICAL_PROVIDER);
166884
+ }
166885
+ function resolveModelRefForPi(ref) {
166886
+ return remapProviderPrefix(piModelRefToCanonical(ref), CANONICAL_TO_PI_PROVIDER);
166887
+ }
166888
+
166889
+ // ../plugin/src/shared/models-dev-cache.ts
166890
+ var MIN_SANE_LIMIT = 20000;
166891
+ var MAX_SANE_LIMIT = 3000000;
166892
+ function isSaneLimit(limit) {
166893
+ return typeof limit === "number" && limit >= MIN_SANE_LIMIT && limit <= MAX_SANE_LIMIT;
166894
+ }
166895
+ var SEPARATE_OUTPUT_QUOTA_PROVIDERS = new Set(["google", "google-antigravity"]);
166896
+ var MIN_PLAUSIBLE_CONTEXT_LIMIT = 1024;
166897
+ var OUTPUT_RESERVE_CAP_RATIO = 0.25;
166898
+ var outputReserveConfig;
166899
+ var reserveClampLogSeen = new Set;
166900
+ var apiCache = null;
166901
+ var persistSeedLoaded = false;
166902
+ function persistFilePath() {
166903
+ return join5(getMagicContextStorageDir(), `model-context-limits-${getHarness()}.json`);
166904
+ }
166905
+ function loadPersistedApiCacheOnce() {
166906
+ if (persistSeedLoaded || apiCache !== null)
166907
+ return;
166908
+ persistSeedLoaded = true;
166909
+ try {
166910
+ const raw = readFileSync5(persistFilePath(), "utf-8");
166911
+ const obj = JSON.parse(raw);
166912
+ const map2 = new Map;
166913
+ for (const [key, persisted] of Object.entries(obj)) {
166914
+ const limit = typeof persisted === "number" ? persisted : persisted.limit;
166915
+ const contextLimit = typeof persisted === "number" ? undefined : persisted.contextLimit;
166916
+ const inputLimit = typeof persisted === "number" ? undefined : persisted.inputLimit;
166917
+ const outputLimit = typeof persisted === "number" ? undefined : persisted.outputLimit;
166918
+ const vision = typeof persisted === "number" ? false : persisted.vision === true;
166919
+ if (isSaneLimit(contextLimit) || isSaneLimit(limit)) {
166920
+ map2.set(key, {
166921
+ limit: isSaneLimit(limit) ? limit : undefined,
166922
+ contextLimit: isSaneLimit(contextLimit) ? contextLimit : undefined,
166923
+ inputLimit: isSaneLimit(inputLimit) ? inputLimit : undefined,
166924
+ outputLimit: isFinitePositive(outputLimit) ? outputLimit : undefined,
166925
+ vision
166926
+ });
166927
+ }
166928
+ }
166929
+ if (map2.size > 0) {
166930
+ apiCache = map2;
166931
+ sessionLog("global", `models-dev-cache: seeded ${map2.size} entries from persisted cache (cold start)`);
166932
+ }
166933
+ } catch {}
166934
+ }
166935
+ function isFinitePositive(value) {
166936
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
166937
+ }
166938
+ function modelKeyLookupOrder(providerID, modelID) {
166939
+ const full = `${providerID}/${modelID}`;
166940
+ const canonicalFull = piModelRefToCanonical(full);
166941
+ const candidates = [full, canonicalFull, modelID];
166942
+ const colon = modelID.lastIndexOf(":");
166943
+ if (colon > 0) {
166944
+ const bareModel = modelID.slice(0, colon);
166945
+ const providerBare = `${providerID}/${bareModel}`;
166946
+ candidates.push(providerBare, piModelRefToCanonical(providerBare), bareModel);
166947
+ }
166948
+ return [...new Set(candidates)];
166949
+ }
166950
+ function configuredOutputReserve(config2, providerID, modelID) {
166951
+ if (typeof config2 === "number")
166952
+ return Number.isFinite(config2) && config2 >= 0 ? config2 : undefined;
166953
+ if (!config2)
166954
+ return;
166955
+ for (const candidate of modelKeyLookupOrder(providerID, modelID)) {
166956
+ const value = config2[candidate];
166957
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0)
166958
+ return value;
166959
+ }
166960
+ return Number.isFinite(config2.default) && config2.default >= 0 ? config2.default : undefined;
166961
+ }
166962
+ function logReserveClampOnce(key, message) {
166963
+ if (reserveClampLogSeen.has(key))
166964
+ return;
166965
+ reserveClampLogSeen.add(key);
166966
+ sessionLog("global", `models-dev-cache: ${message}`);
166967
+ }
166968
+ function setOutputReserveConfig(config2) {
166969
+ outputReserveConfig = config2;
166970
+ }
166971
+ function resolveLimit(limit, providerID, modelID, reserveConfig = outputReserveConfig) {
166972
+ if (!limit)
166973
+ return;
166974
+ const context = isFinitePositive(limit.context) ? limit.context : undefined;
166975
+ const input = isFinitePositive(limit.input) ? limit.input : undefined;
166976
+ if (input !== undefined && (context === undefined || input < context))
166977
+ return input;
166978
+ if (context === undefined)
166979
+ return;
166980
+ const configuredReserve = configuredOutputReserve(reserveConfig, providerID, modelID);
166981
+ let reserve;
166982
+ if (configuredReserve !== undefined) {
166983
+ reserve = configuredReserve;
166984
+ } else if (SEPARATE_OUTPUT_QUOTA_PROVIDERS.has(providerID)) {
166985
+ reserve = 0;
166986
+ } else {
166987
+ const output = isFinitePositive(limit.output) ? limit.output : 0;
166988
+ const cap = context * OUTPUT_RESERVE_CAP_RATIO;
166989
+ reserve = Math.min(output, cap);
166990
+ if (output > cap) {
166991
+ logReserveClampOnce(`cap|${providerID}/${modelID}|${context}|${output}`, `output reserve capped at 25% for ${providerID}/${modelID}: ${output} → ${cap}`);
166992
+ }
166993
+ }
166994
+ const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, context * 0.5);
166995
+ const maxReserve = Math.max(0, context - floor);
166996
+ if (reserve > maxReserve) {
166997
+ logReserveClampOnce(`floor|${providerID}/${modelID}|${context}|${reserve}`, `output reserve clamped for ${providerID}/${modelID}: ${reserve} → ${maxReserve} (usable floor ${floor})`);
166998
+ reserve = maxReserve;
166999
+ }
167000
+ return Math.floor(context - reserve);
167001
+ }
167002
+ function getSdkContextLimit(providerID, modelID, detectedContextLimit, options) {
167003
+ loadPersistedApiCacheOnce();
167004
+ const metadata = lookupMetadataWithTagFallback(apiCache, providerID, modelID);
167005
+ if (!metadata)
167006
+ return;
167007
+ const rawContext = metadata.contextLimit ?? metadata.limit;
167008
+ const promptOnlyDetected = options?.detectedLimitProvenance === "prompt_only" && isFinitePositive(detectedContextLimit) ? detectedContextLimit : undefined;
167009
+ const context = promptOnlyDetected === undefined && isFinitePositive(detectedContextLimit) && isFinitePositive(rawContext) ? Math.min(rawContext, detectedContextLimit) : promptOnlyDetected === undefined && isFinitePositive(detectedContextLimit) ? detectedContextLimit : rawContext;
167010
+ const inputCandidates = [metadata.inputLimit, promptOnlyDetected].filter(isFinitePositive);
167011
+ const input = inputCandidates.length > 0 ? Math.min(...inputCandidates) : undefined;
167012
+ return resolveLimit({
167013
+ context,
167014
+ input,
167015
+ output: metadata.outputLimit
167016
+ }, providerID, modelID, options?.reservation === "none" ? 0 : undefined);
167017
+ }
167018
+ function modelSupportsVision(providerID, modelID) {
167019
+ loadPersistedApiCacheOnce();
167020
+ if (!apiCache)
167021
+ return false;
167022
+ const exact = apiCache.get(`${providerID}/${modelID}`);
167023
+ if (exact?.vision === true)
167024
+ return true;
167025
+ const colon = modelID.lastIndexOf(":");
167026
+ return colon > 0 ? apiCache.get(`${providerID}/${modelID.slice(0, colon)}`)?.vision === true : false;
167027
+ }
167028
+ function lookupMetadataWithTagFallback(cache, providerID, modelID) {
167029
+ if (!cache)
167030
+ return;
167031
+ const exact = cache.get(`${providerID}/${modelID}`);
167032
+ if (exact)
167033
+ return exact;
167034
+ const colonIdx = modelID.lastIndexOf(":");
167035
+ if (colonIdx > 0) {
167036
+ return cache.get(`${providerID}/${modelID.slice(0, colonIdx)}`);
167037
+ }
167038
+ return;
167039
+ }
167040
+
166499
167041
  // src/config/index.ts
166500
167042
  var import_comment_json = __toESM(require_src2(), 1);
166501
167043
  function getProjectConfigPaths(cwd) {
@@ -166514,7 +167056,7 @@ function resolvePiLegacyFallback(sources) {
166514
167056
  }
166515
167057
  function loadConfigFile(path3, scope) {
166516
167058
  try {
166517
- const rawText = readFileSync5(path3, "utf-8");
167059
+ const rawText = readFileSync6(path3, "utf-8");
166518
167060
  const substituted = substituteConfigVariables({
166519
167061
  text: rawText,
166520
167062
  configPath: path3,
@@ -166699,6 +167241,7 @@ function loadPiConfig(opts = {}) {
166699
167241
  }
166700
167242
  }
166701
167243
  const parsed = parsePiConfig(rawConfig);
167244
+ setOutputReserveConfig(parsed.config.output_reserve);
166702
167245
  warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
166703
167246
  return {
166704
167247
  config: parsed.config,
@@ -166818,6 +167361,7 @@ function loadPiConfigDetailed(opts = {}) {
166818
167361
  }
166819
167362
  const recoveredTopLevelKeys = [];
166820
167363
  const parsed = parsePiConfig(rawConfig, recoveredTopLevelKeys);
167364
+ setOutputReserveConfig(parsed.config.output_reserve);
166821
167365
  warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
166822
167366
  const substitutionFailures = loadedFiles.flatMap(bindSubstitutionFailures);
166823
167367
  const userLoaded = loadedFiles.find((loaded) => loaded.scope === "user");
@@ -166940,9 +167484,6 @@ var existingHashStatements = new WeakMap;
166940
167484
  var existingHashByProjectStatements = new WeakMap;
166941
167485
  var deleteByCompartmentStatements = new WeakMap;
166942
167486
  var insertEmbeddingStatements = new WeakMap;
166943
- var distinctModelStatements = new WeakMap;
166944
- var clearProjectStatements = new WeakMap;
166945
- var clearProjectModelStatements = new WeakMap;
166946
167487
  var searchRowsStatements = new WeakMap;
166947
167488
  var searchRowsByModelStatements = new WeakMap;
166948
167489
  var searchPoolProbeStatements = new WeakMap;
@@ -170209,6 +170750,7 @@ function getEmbeddingProviderIdentity(config2) {
170209
170750
  throw new Error("Unknown embedding provider");
170210
170751
  }
170211
170752
  const truncate = config2.provider === "openai-compatible" ? config2.truncate?.trim() : undefined;
170753
+ const localDtype = config2.provider === "local" && config2.local_dtype && config2.local_dtype !== "fp32" ? config2.local_dtype : undefined;
170212
170754
  const identityInput = config2.provider === "openai-compatible" ? {
170213
170755
  provider: "openai-compatible",
170214
170756
  model: config2.model.trim(),
@@ -170220,7 +170762,8 @@ function getEmbeddingProviderIdentity(config2) {
170220
170762
  provider: "local",
170221
170763
  model: config2.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
170222
170764
  endpoint: "",
170223
- apiKeyPresent: false
170765
+ apiKeyPresent: false,
170766
+ ...localDtype ? { localDtype } : {}
170224
170767
  };
170225
170768
  return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
170226
170769
  }
@@ -170308,6 +170851,7 @@ async function injectWasmOrtForElectron() {
170308
170851
  return false;
170309
170852
  }
170310
170853
  }
170854
+ var DEFAULT_LOCAL_DTYPE = "fp32";
170311
170855
  async function withQuietConsole(fn) {
170312
170856
  const origWarn = console.warn;
170313
170857
  const origError = console.error;
@@ -170384,16 +170928,22 @@ class LocalEmbeddingProvider {
170384
170928
  modelId;
170385
170929
  maxInputTokens;
170386
170930
  model;
170931
+ dtype;
170387
170932
  pipeline = null;
170388
170933
  initPromise = null;
170389
170934
  inFlight = 0;
170390
170935
  disposing = false;
170391
170936
  disposePromise = null;
170392
170937
  inFlightWaiters = [];
170393
- constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
170938
+ constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE) {
170394
170939
  this.model = model;
170395
170940
  this.maxInputTokens = maxInputTokens;
170396
- this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
170941
+ this.dtype = dtype || DEFAULT_LOCAL_DTYPE;
170942
+ this.modelId = getEmbeddingProviderIdentity({
170943
+ provider: "local",
170944
+ model,
170945
+ ...dtype && dtype !== DEFAULT_LOCAL_DTYPE ? { local_dtype: dtype } : {}
170946
+ });
170397
170947
  }
170398
170948
  async initialize() {
170399
170949
  if (this.disposing) {
@@ -170424,11 +170974,15 @@ class LocalEmbeddingProvider {
170424
170974
  }
170425
170975
  const modelCacheDir = join6(getMagicContextStorageDir(), "models");
170426
170976
  try {
170427
- mkdirSync4(modelCacheDir, { recursive: true, mode: 448 });
170428
- if (process.platform !== "win32") {
170429
- try {
170430
- chmodSync2(modelCacheDir, 448);
170431
- } catch {}
170977
+ if (shouldEnforcePrivateStoragePermissions()) {
170978
+ mkdirSync4(modelCacheDir, { recursive: true, mode: 448 });
170979
+ if (process.platform !== "win32") {
170980
+ try {
170981
+ chmodSync2(modelCacheDir, 448);
170982
+ } catch {}
170983
+ }
170984
+ } else {
170985
+ mkdirSync4(modelCacheDir, { recursive: true });
170432
170986
  }
170433
170987
  env.cacheDir = modelCacheDir;
170434
170988
  } catch {
@@ -170444,7 +170998,7 @@ class LocalEmbeddingProvider {
170444
170998
  for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
170445
170999
  try {
170446
171000
  const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
170447
- dtype: "fp32",
171001
+ dtype: this.dtype,
170448
171002
  ...injectedWasmOrt ? { device: "auto" } : {}
170449
171003
  }));
170450
171004
  if (this.disposing) {
@@ -170916,9 +171470,6 @@ var saveStatements = new WeakMap;
170916
171470
  var loadProjectStatements = new WeakMap;
170917
171471
  var loadUnembeddedStatements = new WeakMap;
170918
171472
  var countEmbeddedStatements = new WeakMap;
170919
- var clearProjectStatements2 = new WeakMap;
170920
- var clearProjectModelStatements2 = new WeakMap;
170921
- var distinctModelIdStatements = new WeakMap;
170922
171473
  function getSaveStatement(db) {
170923
171474
  let stmt = saveStatements.get(db);
170924
171475
  if (!stmt) {
@@ -170989,7 +171540,6 @@ function countEmbeddedCommits(db, projectPath, modelId) {
170989
171540
  var insertStatements = new WeakMap;
170990
171541
  var existingShasStatements = new WeakMap;
170991
171542
  var projectCountStatements = new WeakMap;
170992
- var evictStatements = new WeakMap;
170993
171543
  var evictOverflowStatements = new WeakMap;
170994
171544
  var latestCommitTimeStatements = new WeakMap;
170995
171545
  function getInsertStatement(db) {
@@ -171238,7 +171788,6 @@ var deleteEmbeddingStatements = new WeakMap;
171238
171788
  var getStoredModelIdStatements = new WeakMap;
171239
171789
  var clearAllEmbeddingsStatements = new WeakMap;
171240
171790
  var clearModelEmbeddingsStatements = new WeakMap;
171241
- var getDistinctStoredModelIdsStatements = new WeakMap;
171242
171791
  function isEmbeddingBlob(value) {
171243
171792
  return value instanceof Uint8Array || value instanceof ArrayBuffer;
171244
171793
  }
@@ -171516,7 +172065,8 @@ function resolveEmbeddingConfig(config2) {
171516
172065
  model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
171517
172066
  ...config2?.max_input_tokens ? {
171518
172067
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
171519
- } : {}
172068
+ } : {},
172069
+ ...config2?.local_dtype ? { local_dtype: config2.local_dtype } : {}
171520
172070
  };
171521
172071
  }
171522
172072
  if (config2.provider === "openai-compatible") {
@@ -171575,7 +172125,7 @@ function createProvider(config2, context) {
171575
172125
  });
171576
172126
  }
171577
172127
  if (config2.provider === "local") {
171578
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
172128
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
171579
172129
  }
171580
172130
  if (config2.provider === "synapse") {
171581
172131
  const synapse = config2;
@@ -172718,7 +173268,7 @@ function createProvider2(config2) {
172718
173268
  });
172719
173269
  }
172720
173270
  if (config2.provider === "local") {
172721
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
173271
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
172722
173272
  }
172723
173273
  if (config2.provider === "synapse") {
172724
173274
  const synapse = config2;
@@ -172895,7 +173445,8 @@ function configFingerprint(paths) {
172895
173445
  }).join("|");
172896
173446
  }
172897
173447
  async function ensureProjectRegisteredFromPiDirectory(directory, db) {
172898
- const projectIdentity = resolveProjectIdentityForSession(directory);
173448
+ const detailed = loadPiConfigDetailed({ cwd: directory });
173449
+ const projectIdentity = resolveProjectIdentityForSession(directory, detailed.config.allow_home_project);
172899
173450
  if (!projectIdentity)
172900
173451
  return;
172901
173452
  let registrationFingerprints = registrationFingerprintsByDatabase.get(db);
@@ -172906,7 +173457,6 @@ async function ensureProjectRegisteredFromPiDirectory(directory, db) {
172906
173457
  const cached2 = registrationFingerprints.get(projectIdentity);
172907
173458
  if (cached2 && configFingerprint(cached2.paths) === cached2.fingerprint)
172908
173459
  return;
172909
- const detailed = loadPiConfigDetailed({ cwd: directory });
172910
173460
  if (isConfigLoadUntrusted(detailed)) {
172911
173461
  handleUntrustedLoad(db, projectIdentity, directory, detailed);
172912
173462
  return;
@@ -179338,6 +179888,7 @@ function queueEmbedding(args) {
179338
179888
  }
179339
179889
  function createCtxMemoryTool(deps) {
179340
179890
  const dreamerAllowed = deps.allowDreamerActions === true;
179891
+ const resolveProject = deps.resolveProjectIdentity ?? resolveProjectIdentityForSession;
179341
179892
  const description = dreamerAllowed ? `${CTX_MEMORY_DESCRIPTION}
179342
179893
  - list: enumerate stored memories (maintenance sessions).` : CTX_MEMORY_DESCRIPTION;
179343
179894
  return {
@@ -179360,7 +179911,7 @@ function createCtxMemoryTool(deps) {
179360
179911
  if (!dreamerAllowed && DREAMER_ONLY_ACTIONS.has(params.action)) {
179361
179912
  return err2(`Error: Action '${params.action}' is not allowed in this context.`);
179362
179913
  }
179363
- const projectIdentity = resolveProjectIdentityForSession(ctx.cwd);
179914
+ const projectIdentity = resolveProject(ctx.cwd);
179364
179915
  if (!projectIdentity) {
179365
179916
  return err2("Error: Could not resolve project identity for memory action.");
179366
179917
  }
@@ -179730,6 +180281,7 @@ function paginateNewestFirst(notes, limit, offset) {
179730
180281
  return { page, total, footer };
179731
180282
  }
179732
180283
  function createCtxNoteTool(deps) {
180284
+ const resolveProject = deps.resolveProjectIdentity ?? resolveProjectIdentityForSession;
179733
180285
  return {
179734
180286
  name: "ctx_note",
179735
180287
  label: "Magic Context: Notes",
@@ -179761,7 +180313,7 @@ function createCtxNoteTool(deps) {
179761
180313
  if (dreamerEnabled !== true) {
179762
180314
  return err3("Error: Smart notes require dreamer to be enabled. Enable dreamer in magic-context.jsonc to use surface_condition.");
179763
180315
  }
179764
- const projectIdentity = resolveProjectIdentityForSession(ctx.cwd);
180316
+ const projectIdentity = resolveProject(ctx.cwd);
179765
180317
  if (!projectIdentity) {
179766
180318
  return err3("Error: Could not resolve project identity for smart note.");
179767
180319
  }
@@ -179787,7 +180339,7 @@ function createCtxNoteTool(deps) {
179787
180339
  if (typeof params.note_id !== "number") {
179788
180340
  return err3("Error: 'note_id' is required when action is 'dismiss'.");
179789
180341
  }
179790
- const projectIdentity = resolveProjectIdentityForSession(ctx.cwd);
180342
+ const projectIdentity = resolveProject(ctx.cwd);
179791
180343
  if (!projectIdentity) {
179792
180344
  return err3("Error: Could not resolve project identity for note dismiss.");
179793
180345
  }
@@ -179809,7 +180361,7 @@ function createCtxNoteTool(deps) {
179809
180361
  if (!updates.content && !updates.surfaceCondition) {
179810
180362
  return err3("Error: Provide 'content' and/or 'surface_condition' to update.");
179811
180363
  }
179812
- const projectIdentity = resolveProjectIdentityForSession(ctx.cwd);
180364
+ const projectIdentity = resolveProject(ctx.cwd);
179813
180365
  if (!projectIdentity) {
179814
180366
  return err3("Error: Could not resolve project identity for note update.");
179815
180367
  }
@@ -179835,6 +180387,7 @@ function createCtxNoteTool(deps) {
179835
180387
  db: deps.db,
179836
180388
  sessionId,
179837
180389
  cwd: ctx.cwd,
180390
+ resolveProjectIdentity: resolveProject,
179838
180391
  filter: params.filter,
179839
180392
  limit,
179840
180393
  offset
@@ -179858,7 +180411,7 @@ No session notes or smart notes.`);
179858
180411
  };
179859
180412
  }
179860
180413
  function readNotes(args) {
179861
- const projectIdentity = resolveProjectIdentityForSession(args.cwd);
180414
+ const projectIdentity = args.resolveProjectIdentity(args.cwd);
179862
180415
  if (args.filter === undefined) {
179863
180416
  const sessionNotes2 = getNotes(args.db, {
179864
180417
  sessionId: args.sessionId,
@@ -181591,32 +182144,6 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
181591
182144
  // ../plugin/src/features/magic-context/mural/render-trigger.ts
181592
182145
  import { createHash as createHash15 } from "node:crypto";
181593
182146
 
181594
- // ../plugin/src/shared/harness-provider-map.ts
181595
- var CANONICAL_TO_PI_PROVIDER = {
181596
- openai: "openai-codex",
181597
- google: "google-antigravity"
181598
- };
181599
- var PI_TO_CANONICAL_PROVIDER = {
181600
- "openai-codex": "openai",
181601
- "google-antigravity": "google"
181602
- };
181603
- function remapProviderPrefix(ref3, map2) {
181604
- if (typeof ref3 !== "string")
181605
- return ref3;
181606
- const slash = ref3.indexOf("/");
181607
- if (slash <= 0)
181608
- return ref3;
181609
- const provider2 = ref3.slice(0, slash);
181610
- const mapped3 = map2[provider2];
181611
- return mapped3 ? `${mapped3}${ref3.slice(slash)}` : ref3;
181612
- }
181613
- function piModelRefToCanonical(ref3) {
181614
- return remapProviderPrefix(ref3, PI_TO_CANONICAL_PROVIDER);
181615
- }
181616
- function resolveModelRefForPi(ref3) {
181617
- return remapProviderPrefix(piModelRefToCanonical(ref3), CANONICAL_TO_PI_PROVIDER);
181618
- }
181619
-
181620
182147
  // ../plugin/src/features/magic-context/mural/mural-selection.ts
181621
182148
  var DEFAULT_MURAL_MEMORY_BUDGET = 8000;
181622
182149
  function muralOverflowMemories(memories, budgetTokens = DEFAULT_MURAL_MEMORY_BUDGET) {
@@ -181818,6 +182345,8 @@ function naturalLineLengths(entries, roomWidth) {
181818
182345
  let currentCategory = null;
181819
182346
  for (let index = 0;index < entries.length; index++) {
181820
182347
  const entry = entries[index];
182348
+ if (!entry)
182349
+ continue;
181821
182350
  if (entry.category !== currentCategory) {
181822
182351
  currentCategory = entry.category;
181823
182352
  lengths.push(codepoints(` <${entry.category}> `));
@@ -181850,6 +182379,8 @@ function planLines(entries, roomWidth) {
181850
182379
  let currentCategory = null;
181851
182380
  for (let index = 0;index < entries.length; index++) {
181852
182381
  const entry = entries[index];
182382
+ if (!entry)
182383
+ continue;
181853
182384
  if (entry.category !== currentCategory) {
181854
182385
  currentCategory = entry.category;
181855
182386
  lines.push({
@@ -181913,8 +182444,11 @@ function renderLayout(entries, plan, roomWidth, columnCount) {
181913
182444
  const usage = {};
181914
182445
  let filledLineCount = 0;
181915
182446
  for (const [column, columnPlan] of splitPlan(plan, columnCount).entries()) {
182447
+ const columnGrid = grid[column];
182448
+ if (!columnGrid)
182449
+ continue;
181916
182450
  for (const [row, line] of columnPlan.entries()) {
181917
- grid[column][row] = line.text;
182451
+ columnGrid[row] = line.text;
181918
182452
  filledLineCount += 1;
181919
182453
  usage[line.category] = (usage[line.category] ?? 0) + 1;
181920
182454
  const placementLine = row + 1;
@@ -182025,6 +182559,7 @@ function glyph(character) {
182025
182559
  }
182026
182560
  function drawGlyph(pixels, width, height, x, y, character, color) {
182027
182561
  const glyphData = glyph(character);
182562
+ const [red, green, blue] = color;
182028
182563
  for (let row = 0;row < MURAL_CELL_HEIGHT; row++) {
182029
182564
  const pattern2 = glyphData.rows[row] ?? 0;
182030
182565
  for (let column = 0;column < glyphData.width; column++) {
@@ -182035,9 +182570,9 @@ function drawGlyph(pixels, width, height, x, y, character, color) {
182035
182570
  if (px < 0 || py < 0 || px >= width || py >= height)
182036
182571
  continue;
182037
182572
  const offset = (py * width + px) * 3;
182038
- pixels[offset] = color[0];
182039
- pixels[offset + 1] = color[1];
182040
- pixels[offset + 2] = color[2];
182573
+ pixels[offset] = red;
182574
+ pixels[offset + 1] = green;
182575
+ pixels[offset + 2] = blue;
182041
182576
  }
182042
182577
  }
182043
182578
  }
@@ -182049,6 +182584,7 @@ function drawText(pixels, width, height, x, y, text, color) {
182049
182584
  }
182050
182585
  }
182051
182586
  function fillRect(pixels, canvasWidth, canvasHeight, x, y, width, height, color) {
182587
+ const [red, green, blue] = color;
182052
182588
  const left = Math.max(0, x);
182053
182589
  const top = Math.max(0, y);
182054
182590
  const right = Math.min(canvasWidth, x + width);
@@ -182056,9 +182592,9 @@ function fillRect(pixels, canvasWidth, canvasHeight, x, y, width, height, color)
182056
182592
  for (let py = top;py < bottom; py++) {
182057
182593
  for (let px = left;px < right; px++) {
182058
182594
  const offset = (py * canvasWidth + px) * 3;
182059
- pixels[offset] = color[0];
182060
- pixels[offset + 1] = color[1];
182061
- pixels[offset + 2] = color[2];
182595
+ pixels[offset] = red;
182596
+ pixels[offset + 1] = green;
182597
+ pixels[offset + 2] = blue;
182062
182598
  }
182063
182599
  }
182064
182600
  }
@@ -182085,6 +182621,9 @@ function renderMural(entries) {
182085
182621
  });
182086
182622
  const fittingCandidates = candidates2.filter((candidate) => candidate.layout.droppedIds.length === 0);
182087
182623
  const candidatesToCompare = fittingCandidates.length > 0 ? fittingCandidates : candidates2;
182624
+ const firstCandidate = candidatesToCompare[0];
182625
+ if (!firstCandidate)
182626
+ throw new Error("mural layout candidate list is empty");
182088
182627
  const selected = candidatesToCompare.reduce((best, candidate) => {
182089
182628
  if (!best)
182090
182629
  return candidate;
@@ -182095,7 +182634,7 @@ function renderMural(entries) {
182095
182634
  return candidate.tileArea < best.tileArea ? candidate : best;
182096
182635
  }
182097
182636
  return candidate.requestedColumnCount < best.requestedColumnCount ? candidate : best;
182098
- }, candidatesToCompare[0]);
182637
+ }, firstCandidate);
182099
182638
  const { layout, width, height } = selected;
182100
182639
  const pixels = new Uint8Array(width * height * 3).fill(255);
182101
182640
  const contentWidth = layout.columnCount === 0 ? 0 : layout.columnCount * roomWidth * MURAL_CELL_WIDTH + MURAL_COLUMN_GAP * (layout.columnCount - 1) * MURAL_CELL_WIDTH;
@@ -183379,6 +183918,7 @@ function formatSearchResults(query, results, currentSessionId) {
183379
183918
  ${body}`;
183380
183919
  }
183381
183920
  function createCtxSearchTool(deps) {
183921
+ const resolveProject = deps.resolveProjectIdentity ?? resolveProjectIdentityForSession;
183382
183922
  return {
183383
183923
  name: "ctx_search",
183384
183924
  label: "Magic Context: Search",
@@ -183404,7 +183944,7 @@ function createCtxSearchTool(deps) {
183404
183944
  };
183405
183945
  }
183406
183946
  const sessionId = ctx.sessionManager.getSessionId();
183407
- const projectIdentity = resolveProjectIdentityForSession(ctx.cwd);
183947
+ const projectIdentity = resolveProject(ctx.cwd);
183408
183948
  if (!projectIdentity) {
183409
183949
  return {
183410
183950
  content: [
@@ -183529,12 +184069,14 @@ function createTodowriteTool() {
183529
184069
 
183530
184070
  // src/tools/index.ts
183531
184071
  function registerMagicContextTools(pi, opts) {
184072
+ const resolveProjectIdentity2 = opts.resolveProjectIdentity ? (directory) => opts.resolveProjectIdentity?.({ cwd: directory }) : undefined;
183532
184073
  pi.registerTool(createCtxSearchTool({
183533
184074
  db: opts.db,
183534
184075
  ensureProjectRegistered: opts.ensureProjectRegistered,
183535
184076
  memoryEnabled: opts.memoryEnabled,
183536
184077
  embeddingEnabled: opts.embeddingEnabled,
183537
- gitCommitsEnabled: opts.gitCommitsEnabled
184078
+ gitCommitsEnabled: opts.gitCommitsEnabled,
184079
+ resolveProjectIdentity: resolveProjectIdentity2
183538
184080
  }));
183539
184081
  if (opts.memoryToolEnabled !== false) {
183540
184082
  pi.registerTool(createCtxMemoryTool({
@@ -183542,14 +184084,16 @@ function registerMagicContextTools(pi, opts) {
183542
184084
  ensureProjectRegistered: opts.ensureProjectRegistered,
183543
184085
  memoryEnabled: opts.memoryEnabled,
183544
184086
  embeddingEnabled: opts.embeddingEnabled,
183545
- allowDreamerActions: opts.allowDreamerActions ?? false
184087
+ allowDreamerActions: opts.allowDreamerActions ?? false,
184088
+ resolveProjectIdentity: resolveProjectIdentity2
183546
184089
  }));
183547
184090
  }
183548
184091
  if (!opts.sessionScopedToolsDisabled) {
183549
184092
  pi.registerTool(createCtxNoteTool({
183550
184093
  db: opts.db,
183551
184094
  dreamerEnabled: opts.dreamerEnabled ?? false,
183552
- resolveDreamerEnabled: opts.resolveDreamerEnabled
184095
+ resolveDreamerEnabled: opts.resolveDreamerEnabled,
184096
+ resolveProjectIdentity: resolveProjectIdentity2
183553
184097
  }));
183554
184098
  pi.registerTool(createCtxExpandTool({ db: opts.db }));
183555
184099
  }
@@ -183559,7 +184103,7 @@ function registerMagicContextTools(pi, opts) {
183559
184103
  registerTodosCommand(pi);
183560
184104
  }
183561
184105
  }
183562
- if (!opts.sessionScopedToolsDisabled) {
184106
+ if (!opts.sessionScopedToolsDisabled && !opts.compactionOff) {
183563
184107
  pi.registerTool(createCtxReduceTool({
183564
184108
  db: opts.db,
183565
184109
  protectedTags: opts.protectedTags ?? 20,
@@ -183568,4 +184112,4 @@ function registerMagicContextTools(pi, opts) {
183568
184112
  }
183569
184113
  }
183570
184114
 
183571
- export { isDreamerRunnable, migrateMagicContextConfigLocations, ProjectIdentityError, resolveProjectIdentityStrict, resolveProjectIdentity, resolveProjectIdentityForSession, beginBootQuietPeriod, scheduleAfterBootQuiet, Database, closeQuietly, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, estimateTokens, normalizeText, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isRecord, isEditTool, applyEditMarkerToInput, setRawMessageProvider, withRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, clearCompressionDepth, clearCompressionDepthRange, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordSessionProjectIdentity, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, isCompartmentLeaseHeld, persistCachedM0, clearCachedM0M1, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getCompartmentsByEndMessageId, appendCompartments, saveRecompStagingPass, getRecompStaging, clearRecompStaging, getRecompPartialRange, setRecompPartialRange, escapeXmlAttr, escapeXmlContent, getModuleNoteEvaluationBridge, getContextStoreUuid, parseCompartmentOutput, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, sourceNameForMemory, computeWorkspaceEpochFingerprint, bumpEpochsForWorkspaceMembers, readProjectDocsCanonical, copySessionStateForClone, getErrorMessage, describeError, stableStringify, getSchemaFenceRejection, getDatabasePath, setSqlitePragmaConfig, applySqliteTuningPragmas, runSqliteOptimize, openDatabase, openDatabaseAsync, queueM0Mutation, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRender, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationId, getMaxMemoryMutationIdForProjects, loadProtectedTailMeta, markProtectedTailPolicyV3Seeded, recordProtectedTailPublicationFloor, recordProtectedTailNoEligibleHead, getWrapupInProgressState, isWrapupInProgress, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, reserveProtectedTailDrainTokens, clearEmergencyDrainLatch, recordHistorianDrainFailure, clearHistorianDrainFailure, rollbackProtectedTailDrainReservation, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, setChannel2NudgeState, casChannel2NudgeState, getPersistedNoteNudge, setPersistedNoteNudgeTrigger, setPersistedNoteNudgeTriggerMessageId, getNoteNudgeAnchors, getAutoSearchHintDecisions, deliverNoteNudgeAtomic, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, getNoteLastReadAt, getHistorianFailureState, incrementHistorianFailure, clearHistorianFailureState, getOverflowState, recordOverflowDetected, clearEmergencyRecovery, clearDetectedContextLimit, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, getPendingPiCompactionMarkerState, setPendingPiCompactionMarkerState, clearPendingPiCompactionMarkerStateIf, getSessionsWithPendingPiMarker, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, setSessionWorkMetrics, getSessionWorkMetrics, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, retryPendingSessionCleanups, getNotes, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, insertPrimerCandidates, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, recordSubagentInvocation, getLatestHistorianInvocationId, updateTagByteSize, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, updateTagInputByteSize, updateTagTokenCount, getPersistedToolTagAccounting, getAllStatusTagTokenTotalsFlat, updateTagInputTokenCount, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, hasPiFallbackMessageTags, findAdoptableFallbackTags, hasPiFallbackToolOwnerTags, findPiFallbackToolOwnerTags, adoptPiFallbackToolOwnerTag, adoptPiFallbackMessageTag, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTagsForPendingOperations, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, isSaneLimit, getSdkContextLimit, normalizeTodoStateJson, buildSyntheticTodoPart, SYNTH_USER_ID_PREFIX, resolvePiStableId, isMidTurnPi, readPiSessionMessages, findLastModelKeyFromBranch, convertEntriesToRawMessages, withContentLanguageDirective, withMigrationLanguageDirective, buildPrimaryLanguageDirective, piModelRefToCanonical, resolveModelRefForPi, getOpenCodeDbPath2 as getOpenCodeDbPath, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, cosineSimilarity, computeNormalizedHash, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, invalidateMemory, contentSha256, sweepStaleEmbeddingIdentitiesForProject, enqueueShadowEmbeddingItems, getProjectEmbeddingSnapshot, getProjectChunkEmbeddingModelId, getProjectEmbeddingMaxInputTokens, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, computeCueContentHash, getMuralCueState, memoryNeedsCue, setMuralCue, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, insertMemory, getMemoryByHash, getMemoriesByProject, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getAllActiveMemoriesForMigration, getMemoryById, setMemoryClassification, archiveMemory, deleteMemory, getMemoryCount, getMemoryCountsByStatus, promoteSessionFactsDurable, embedPromotedFacts, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, indexCommitsForProject, embedUnembeddedCommits, loadPiConfig, ensureProjectRegisteredFromPiDirectory, resolveMuralWire, updateCompactionMarkerAfterPublication, COMPARTMENT_RENDER_EPOCH, encodeCachedM0UpgradeIdentity, decodeCachedM0UpgradeIdentity, DEFAULT_HISTORY_BUDGET_TOKENS, renderCompartmentAtTier, renderDecayedCompartments, extractM0Block, TEMPORAL_MARKER_PATTERN, temporalMarkerPrefix, clearInjectionCache, getVisibleMemoryIds, renderMemoryBlock, DEFAULT_MEMORY_BUDGET_TOKENS, DEFAULT_USER_PROFILE_BUDGET_TOKENS, trimMemoriesToBudgetV2, trimWorkspaceMemoriesToBudgetV2, trimUserMemoriesToBudget, renderMemoryBlockV2, stripMemoryMuralBlock, unifiedSearch, rememberTodowriteToolCallTodos, parseTodos, setTodoSnapshot, registerTodoOverlay, registerTodoStateLifecycle, registerMagicContextTools };
184115
+ export { COMPACTION_ENABLED_PATH, isDreamerRunnable, isCompactionEnabled, migrateMagicContextConfigLocations, ProjectIdentityError, resolveProjectIdentityStrict, resolveProjectIdentity, resolveProjectIdentityForSession, beginBootQuietPeriod, scheduleAfterBootQuiet, Database, closeQuietly, isMidTurn, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, estimateTokens, normalizeText, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isRecord, isEditTool, applyEditMarkerToInput, setRawMessageProvider, withRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, clearCompressionDepth, clearCompressionDepthRange, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordSessionProjectIdentity, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, isCompartmentLeaseHeld, persistCachedM0, clearCachedM0M1, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getCompartmentsByEndMessageId, appendCompartments, saveRecompStagingPass, getRecompStaging, clearRecompStaging, getRecompPartialRange, setRecompPartialRange, escapeXmlAttr, escapeXmlContent, getModuleNoteEvaluationBridge, getContextStoreUuid, parseCompartmentOutput, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, sourceNameForMemory, computeWorkspaceEpochFingerprint, bumpEpochsForWorkspaceMembers, readProjectDocsCanonical, copySessionStateForClone, getErrorMessage, describeError, setStoragePrivatePermissionEnforcement, stableStringify, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, applySqliteTuningPragmas, runSqliteOptimize, openDatabase, openDatabaseAsync, queueM0Mutation, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRender, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationId, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, loadProtectedTailMeta, markProtectedTailPolicyV3Seeded, recordProtectedTailPublicationFloor, recordProtectedTailNoEligibleHead, getWrapupInProgressState, isWrapupInProgress, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, reserveProtectedTailDrainTokens, clearEmergencyDrainLatch, recordHistorianDrainFailure, clearHistorianDrainFailure, rollbackProtectedTailDrainReservation, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, setChannel2NudgeState, casChannel2NudgeState, getPersistedNoteNudge, setPersistedNoteNudgeTrigger, setPersistedNoteNudgeTriggerMessageId, getNoteNudgeAnchors, getAutoSearchHintDecisions, deliverNoteNudgeAtomic, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, getNoteLastReadAt, getHistorianFailureState, incrementHistorianFailure, clearHistorianFailureState, getOverflowState, recordOverflowDetected, clearEmergencyRecovery, clearDetectedContextLimit, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, getPendingPiCompactionMarkerState, setPendingPiCompactionMarkerState, clearPendingPiCompactionMarkerStateIf, getSessionsWithPendingPiMarker, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, setSessionWorkMetrics, getSessionWorkMetrics, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, retryPendingSessionCleanups, getNotes, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, insertPrimerCandidates, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, recordSubagentInvocation, getLatestHistorianInvocationId, updateTagByteSize, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, updateTagInputByteSize, updateTagTokenCount, getPersistedToolTagAccounting, getAllStatusTagTokenTotalsFlat, updateTagInputTokenCount, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, hasPiFallbackMessageTags, findAdoptableFallbackTags, hasPiFallbackToolOwnerTags, findPiFallbackToolOwnerTags, adoptPiFallbackToolOwnerTag, adoptPiFallbackMessageTag, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTagsForPendingOperations, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, BoundedSessionMap, piModelRefToCanonical, resolveModelRefForPi, isSaneLimit, resolveLimit, getSdkContextLimit, normalizeTodoStateJson, buildSyntheticTodoPart, SYNTH_USER_ID_PREFIX, resolvePiStableId, isMidTurnPi, readPiSessionMessages, findLastModelKeyFromBranch, convertEntriesToRawMessages, withContentLanguageDirective, withMigrationLanguageDirective, buildPrimaryLanguageDirective, getOpenCodeDbPath2 as getOpenCodeDbPath, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, cosineSimilarity, computeNormalizedHash, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, invalidateMemory, contentSha256, sweepStaleEmbeddingIdentitiesForProject, enqueueShadowEmbeddingItems, getProjectEmbeddingSnapshot, getProjectChunkEmbeddingModelId, getProjectEmbeddingMaxInputTokens, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, computeCueContentHash, getMuralCueState, memoryNeedsCue, setMuralCue, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, insertMemory, getMemoryByHash, getMemoriesByProject, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getAllActiveMemoriesForMigration, getMemoryById, setMemoryClassification, archiveMemory, deleteMemory, getMemoryCount, getMemoryCountsByStatus, promoteSessionFactsDurable, embedPromotedFacts, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, indexCommitsForProject, embedUnembeddedCommits, loadPiConfig, ensureProjectRegisteredFromPiDirectory, resolveMuralWire, updateCompactionMarkerAfterPublication, COMPARTMENT_RENDER_EPOCH, encodeCachedM0UpgradeIdentity, decodeCachedM0UpgradeIdentity, DEFAULT_HISTORY_BUDGET_TOKENS, renderCompartmentAtTier, renderDecayedCompartments, extractM0Block, TEMPORAL_MARKER_PATTERN, temporalMarkerPrefix, clearInjectionCache, getVisibleMemoryIds, renderMemoryBlock, DEFAULT_MEMORY_BUDGET_TOKENS, DEFAULT_USER_PROFILE_BUDGET_TOKENS, trimMemoriesToBudgetV2, trimWorkspaceMemoriesToBudgetV2, trimUserMemoriesToBudget, renderMemoryBlockV2, stripMemoryMuralBlock, unifiedSearch, rememberTodowriteToolCallTodos, parseTodos, setTodoSnapshot, registerTodoOverlay, registerTodoStateLifecycle, registerMagicContextTools };