@cortexkit/opencode-magic-context 0.27.1 → 0.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,6 +28,7 @@
28
28
  <a href="#-recall">Recall</a> ·
29
29
  <a href="https://docs.cortexkit.io/magic-context">Docs</a> ·
30
30
  <a href="./CONFIGURATION.md">Configuration</a> ·
31
+ <a href="https://github.com/cortexkit/magic-context/releases?q=dashboard&expanded=true">Dashboard</a> ·
31
32
  <a href="https://discord.gg/DSa65w8wuf">💬 Discord</a>
32
33
  </p>
33
34
 
@@ -87,13 +88,7 @@ The wizard auto-detects which harnesses you have (OpenCode, Pi, or both), adds t
87
88
 
88
89
  **Troubleshooting:** `npx @cortexkit/magic-context@latest doctor` auto-detects your harnesses, checks for conflicts (compaction, OMO hooks, DCP), verifies the plugin and TUI sidebar, runs an integrity check on the database, and fixes what it can. Add `--issue` to file a ready-to-submit bug report.
89
90
 
90
- ### Adding Magic Context to an existing project
91
-
92
- Magic Context is not limited to greenfield work. Run the setup wizard from the root of the project you already use with OpenCode or Pi, then restart the harness in that same directory so the plugin can attach to the existing project identity. From that point forward, new turns are captured automatically and the historian compartmentalizes the active session as it grows.
93
-
94
- Magic Context does **not** retroactively import or reprocess OpenCode or Pi sessions that happened before it was installed. Those past conversations are not backfilled into compartments. What builds up across an existing project from day one includes project memories, dreamer-maintained docs, key files, and other context captured after installation.
95
-
96
- If you want to seed knowledge from older work, add the important facts explicitly with `ctx_memory`, write a short project note in the repo, or keep working in the project and let the historian and dreamer promote recurring facts over time. Use `/ctx-recomp` when you need to rebuild Magic Context compartments from raw message history that Magic Context has captured in that session, such as after upgrading historian rules; it is not an importer for unrelated pre-install OpenCode or Pi sessions. The dashboard can also inspect the shared CortexKit database, memories, compartments, and dreamer runs without starting a coding session.
91
+ Works the same on a brand-new or a long-running project: install, restart the harness, and Magic Context captures context from that point forward. It does not backfill OpenCode or Pi sessions from before it was installed.
97
92
 
98
93
  <details>
99
94
  <summary><strong>Compatibility with other context-management plugins</strong></summary>
@@ -58,6 +58,14 @@ export declare function resolveCortexKitProjectConfigPath(directory: string): st
58
58
  * `.jsonc` and a `.json` candidate; whichever exists migrates, target is always
59
59
  * `.jsonc`. The bare-root project source (`<root>/magic-context.*`) is unique to
60
60
  * Magic Context (AFT never had it) — omitting it would orphan repo-root configs.
61
+ *
62
+ * Project sources are filtered against the user-scope path set: when a session's
63
+ * project directory IS the user config home (e.g. opencode opened in
64
+ * `~/.config/cortexkit`), the bare-root project source `<root>/magic-context.jsonc`
65
+ * resolves to the USER config path. Without this guard the project migration
66
+ * would "migrate" the user's own config into `<root>/.cortexkit/` and rename the
67
+ * original aside, leaving the user on schema defaults (the config-eats-itself
68
+ * bug). A project migration must never touch a user-scope file.
61
69
  */
62
70
  export declare function resolveLegacyConfigSources(directory: string): {
63
71
  user: LegacyConfigSource[];
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-config-location.d.ts","sourceRoot":"","sources":["../../src/config/migrate-config-location.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACvC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC7C,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAoBD,iFAAiF;AACjF,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAED,+EAA+E;AAC/E,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,2DAA2D;AAC3D,wBAAgB,8BAA8B,IAAI,MAAM,CAEvD;AAED,2DAA2D;AAC3D,wBAAgB,iCAAiC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AASD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG;IAC3D,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,OAAO,EAAE,kBAAkB,EAAE,CAAC;CACjC,CAqBA;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,IAAI,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAChD,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACvB;IAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAAC,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAAE,CA0B/D;AAmSD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,0BAA0B,GAAG,yBAAyB,CA0F7F;AAED;;;;;GAKG;AACH,wBAAgB,kCAAkC,CAC9C,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,qBAAqB,GAC/B,MAAM,EAAE,CA6BV"}
1
+ {"version":3,"file":"migrate-config-location.d.ts","sourceRoot":"","sources":["../../src/config/migrate-config-location.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IAClC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACvC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC7C,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAoBD,iFAAiF;AACjF,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAED,+EAA+E;AAC/E,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,2DAA2D;AAC3D,wBAAgB,8BAA8B,IAAI,MAAM,CAEvD;AAED,2DAA2D;AAC3D,wBAAgB,iCAAiC,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AA4BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG;IAC3D,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,OAAO,EAAE,kBAAkB,EAAE,CAAC;CACjC,CAsBA;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,IAAI,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAChD,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACvB;IAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAAC,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAAE,CA0B/D;AAmSD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,0BAA0B,GAAG,yBAAyB,CA0F7F;AAED;;;;;GAKG;AACH,wBAAgB,kCAAkC,CAC9C,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,qBAAqB,GAC/B,MAAM,EAAE,CA6BV"}
@@ -52,6 +52,7 @@ export declare const __test: {
52
52
  getPendingPi(sessionId: string): PendingPiTransformDecision | undefined;
53
53
  reset(): void;
54
54
  setWriterForTests(writer: TransformDecisionWriter | null): void;
55
+ setRetentionForTests(cap: number | null): void;
55
56
  writeRow(dbPath: string, row: TransformDecisionRow): void;
56
57
  findNewestPiAssistantEntryIdAfter: typeof findNewestPiAssistantEntryIdAfter;
57
58
  };
@@ -1 +1 @@
1
- {"version":3,"file":"transform-decision-log.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/transform-decision-log.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transform-decision-log.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/transform-decision-log.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"event-handler.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/event-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAyBvF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAKlE,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,oCAAoC,CAAC;AAqBpF,OAAO,EAAE,KAAK,kBAAkB,EAAsB,MAAM,6BAA6B,CAAC;AAM1F,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD,UAAU,iBAAiB;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAMD,MAAM,WAAW,gBAAgB;IAC7B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,MAAM,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,4BAA4B,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACxF,wBAAwB,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;SAAE,CAAC;QACxF,SAAS,EAAE,cAAc,CAAC;QAC1B,sBAAsB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;KACvE,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IAIf,EAAE,EAAE,OAAO,qBAAqB,EAAE,QAAQ,CAAC;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,sBAAsB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,oBAAoB,EAAE,aAAa,CAAC,CAAC;IACjF,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,kBAAkB,CAAC;IAClE;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvC;AAqID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IACvC,OAAO;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,KAAG,OAAO,CAAC,IAAI,CAAC,CAyfzF"}
1
+ {"version":3,"file":"event-handler.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/event-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAyBvF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAKlE,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,oCAAoC,CAAC;AAwBpF,OAAO,EAAE,KAAK,kBAAkB,EAAsB,MAAM,6BAA6B,CAAC;AAM1F,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD,UAAU,iBAAiB;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAMD,MAAM,WAAW,gBAAgB;IAC7B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,MAAM,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,4BAA4B,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACxF,wBAAwB,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;SAAE,CAAC;QACxF,SAAS,EAAE,cAAc,CAAC;QAC1B,sBAAsB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;KACvE,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IAIf,EAAE,EAAE,OAAO,qBAAqB,EAAE,QAAQ,CAAC;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,sBAAsB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,oBAAoB,EAAE,aAAa,CAAC,CAAC;IACjF,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,kBAAkB,CAAC;IAClE;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvC;AAqID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IACvC,OAAO;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,KAAG,OAAO,CAAC,IAAI,CAAC,CAmgBzF"}
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/transform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/transform.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -151003,7 +151003,7 @@ function enforceSchemaFence(db, dbPath, latestSupportedVersion) {
151003
151003
  return true;
151004
151004
  }
151005
151005
  lastSchemaFenceRejection = { persistedVersion, supportedVersion: latestSupportedVersion };
151006
- log(`[magic-context] storage fatal: refusing to open ${dbPath}; database schema v${persistedVersion} is newer than this binary supports (max v${latestSupportedVersion}). Upgrade Magic Context/OpenCode/Pi before writing to this cache.`);
151006
+ 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.`);
151007
151007
  return false;
151008
151008
  }
151009
151009
  function setSqlitePragmaConfig(config2) {
@@ -165579,8 +165579,13 @@ async function sendSchemaFenceWarning(client, directory, detail) {
165579
165579
  `newer build (OpenCode and Pi share one database). This build only supports`,
165580
165580
  `up to v${detail.supportedVersion}, so it has fail-closed to avoid corrupting the cache.`,
165581
165581
  "",
165582
- "Update Magic Context on this harness (or update OpenCode/Pi) to the latest",
165583
- "version, then restart. Your data is safe nothing is disabled permanently."
165582
+ "This usually means a pinned or stale plugin is sharing the database with a",
165583
+ "newer instance. Update or unpin Magic Context on this harness (or update",
165584
+ "OpenCode/Pi) to the latest version, then restart. The fastest fix is:",
165585
+ "",
165586
+ " npx @cortexkit/magic-context@latest doctor --force",
165587
+ "",
165588
+ "Your data is safe; nothing is disabled permanently."
165584
165589
  ].join(`
165585
165590
  `);
165586
165591
  try {
@@ -176602,6 +176607,14 @@ async function refreshModelLimitsFromApi(client, options) {
176602
176607
  }
176603
176608
  }
176604
176609
  }
176610
+ async function refreshModelLimitsAfterAuthOnce(client) {
176611
+ if (authRewarmDone)
176612
+ return;
176613
+ authRewarmDone = true;
176614
+ const ok = await refreshModelLimitsOnce(client);
176615
+ if (!ok)
176616
+ authRewarmDone = false;
176617
+ }
176605
176618
  async function refreshModelLimitsOnce(client) {
176606
176619
  try {
176607
176620
  const result = await client.config.providers();
@@ -176655,7 +176668,7 @@ function lookupLimitWithTagFallback(cache, providerID, modelID) {
176655
176668
  }
176656
176669
  return;
176657
176670
  }
176658
- var MIN_SANE_LIMIT = 20000, MAX_SANE_LIMIT = 3000000, apiCache = null, apiLoadedAt = 0, persistSeedLoaded = false;
176671
+ var MIN_SANE_LIMIT = 20000, MAX_SANE_LIMIT = 3000000, apiCache = null, apiLoadedAt = 0, persistSeedLoaded = false, authRewarmDone = false;
176659
176672
  var init_models_dev_cache = __esm(() => {
176660
176673
  init_data_path();
176661
176674
  init_logger();
@@ -186475,7 +186488,7 @@ function resolveTuiConfigPath() {
186475
186488
  return jsoncPath;
186476
186489
  if (existsSync19(jsonPath))
186477
186490
  return jsonPath;
186478
- return jsonPath;
186491
+ return jsoncPath;
186479
186492
  }
186480
186493
  function ensureTuiPluginEntry() {
186481
186494
  try {
@@ -186811,7 +186824,18 @@ function legacySourcesForBase(basePath, label) {
186811
186824
  { path: `${basePath}.json`, label: `${label} magic-context.json` }
186812
186825
  ];
186813
186826
  }
186827
+ function userScopeConfigPaths() {
186828
+ return new Set([
186829
+ `${cortexKitUserConfigBasePath()}.jsonc`,
186830
+ `${cortexKitUserConfigBasePath()}.json`,
186831
+ join2(configHome(), "opencode", `${CONFIG_FILE_BASENAME}.jsonc`),
186832
+ join2(configHome(), "opencode", `${CONFIG_FILE_BASENAME}.json`),
186833
+ join2(homeDir(), ".pi", "agent", `${CONFIG_FILE_BASENAME}.jsonc`),
186834
+ join2(homeDir(), ".pi", "agent", `${CONFIG_FILE_BASENAME}.json`)
186835
+ ]);
186836
+ }
186814
186837
  function resolveLegacyConfigSources(directory) {
186838
+ const userPaths = userScopeConfigPaths();
186815
186839
  return {
186816
186840
  user: [
186817
186841
  ...legacySourcesForBase(join2(configHome(), "opencode", CONFIG_FILE_BASENAME), "OpenCode user"),
@@ -186821,7 +186845,7 @@ function resolveLegacyConfigSources(directory) {
186821
186845
  ...legacySourcesForBase(join2(directory, CONFIG_FILE_BASENAME), "project root"),
186822
186846
  ...legacySourcesForBase(join2(directory, ".opencode", CONFIG_FILE_BASENAME), "OpenCode project"),
186823
186847
  ...legacySourcesForBase(join2(directory, ".pi", CONFIG_FILE_BASENAME), "Pi project")
186824
- ]
186848
+ ].filter((source) => !userPaths.has(source.path))
186825
186849
  };
186826
186850
  }
186827
186851
  function resolveLegacyConfigSourcesForHarness(directory, harness) {
@@ -196678,6 +196702,7 @@ var pendingPiDecisionBySession = new Map;
196678
196702
  var lastBoundMessageIdBySession = new Map;
196679
196703
  var scheduledWriteTokensBySession = new Map;
196680
196704
  var writerOverrideForTests = null;
196705
+ var retentionOverrideForTests = null;
196681
196706
  function normalizeMaterializeReason(harness, reason, rematerialized) {
196682
196707
  const raw = typeof reason === "string" ? reason.trim() : "";
196683
196708
  if (raw.length > 0) {
@@ -196778,7 +196803,7 @@ function writeTransformDecisionRow(dbPath, row) {
196778
196803
  WHERE session_id = ? AND harness = ?
196779
196804
  ORDER BY ts_ms DESC, rowid DESC
196780
196805
  LIMIT ?
196781
- )`).run(row.sessionId, row.harness, row.sessionId, row.harness, TRANSFORM_DECISIONS_RETENTION);
196806
+ )`).run(row.sessionId, row.harness, row.sessionId, row.harness, retentionOverrideForTests ?? TRANSFORM_DECISIONS_RETENTION);
196782
196807
  } finally {
196783
196808
  closeQuietly(db);
196784
196809
  }
@@ -197187,6 +197212,7 @@ init_session_project_storage();
197187
197212
  init_storage_meta_persisted();
197188
197213
  await init_storage();
197189
197214
  init_logger();
197215
+ init_models_dev_cache();
197190
197216
 
197191
197217
  // src/hooks/magic-context/boundary-execution.ts
197192
197218
  var FORCE_MATERIALIZE_PERCENTAGE2 = 85;
@@ -201326,6 +201352,18 @@ function findLastAssistantModel2(messages) {
201326
201352
  }
201327
201353
  return null;
201328
201354
  }
201355
+ function findNewestUserModel(messages) {
201356
+ for (let i = messages.length - 1;i >= 0; i--) {
201357
+ const info = messages[i].info;
201358
+ if (info.role !== "user")
201359
+ continue;
201360
+ if (info.model?.providerID && info.model.modelID) {
201361
+ return { providerID: info.model.providerID, modelID: info.model.modelID };
201362
+ }
201363
+ return null;
201364
+ }
201365
+ return null;
201366
+ }
201329
201367
  function createTransform(deps) {
201330
201368
  const loadedSessions = new Set;
201331
201369
  const lastEmergencyNotificationCount = new Map;
@@ -201386,15 +201424,15 @@ function createTransform(deps) {
201386
201424
  const canRunCompartments = fullFeatureMode && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
201387
201425
  const fallbackModelId = deps.getFallbackModelId?.(sessionId);
201388
201426
  const tModelDetect = performance.now();
201427
+ const persistedUsageBeforeResets = loadPersistedUsage(db, sessionId);
201389
201428
  if (deps.liveModelBySession) {
201390
- const lastAssistantModel = findLastAssistantModel2(messages);
201391
- if (lastAssistantModel) {
201392
- const knownModel = deps.liveModelBySession.get(sessionId);
201393
- if (!knownModel) {
201394
- deps.liveModelBySession.set(sessionId, lastAssistantModel);
201395
- } else if (knownModel.providerID !== lastAssistantModel.providerID || knownModel.modelID !== lastAssistantModel.modelID) {
201396
- sessionLog(sessionId, `transform: model change detected (${knownModel.providerID}/${knownModel.modelID} -> ${lastAssistantModel.providerID}/${lastAssistantModel.modelID}), clearing stale context state`);
201397
- deps.liveModelBySession.set(sessionId, lastAssistantModel);
201429
+ const currentOutgoingModel = findNewestUserModel(messages) ?? deps.liveModelBySession.get(sessionId) ?? findLastAssistantModel2(messages);
201430
+ if (currentOutgoingModel) {
201431
+ deps.liveModelBySession.set(sessionId, currentOutgoingModel);
201432
+ const outgoingModelKey = resolveModelKey(currentOutgoingModel.providerID, currentOutgoingModel.modelID);
201433
+ const lastUsageModelKey = persistedUsageBeforeResets?.lastObservedModelKey ?? null;
201434
+ if (lastUsageModelKey != null && outgoingModelKey != null && lastUsageModelKey !== outgoingModelKey) {
201435
+ sessionLog(sessionId, `transform: model change since last usage (${lastUsageModelKey} -> ${outgoingModelKey}), clearing stale per-model state`);
201398
201436
  updateSessionMeta(db, sessionId, {
201399
201437
  lastContextPercentage: 0,
201400
201438
  lastInputTokens: 0,
@@ -201424,7 +201462,6 @@ function createTransform(deps) {
201424
201462
  const tFirstPass = performance.now();
201425
201463
  const isFirstTransformPassForSession = !loadedSessions.has(sessionId);
201426
201464
  loadedSessions.add(sessionId);
201427
- const persistedUsageBeforeFirstPassReset = loadPersistedUsage(db, sessionId);
201428
201465
  const historianFailureState = getHistorianFailureState(db, sessionId);
201429
201466
  if (isFirstTransformPassForSession && sessionMeta) {
201430
201467
  const persistedPct = sessionMeta.lastContextPercentage ?? 0;
@@ -201443,6 +201480,17 @@ function createTransform(deps) {
201443
201480
  let emergencyRecoveryArmed = false;
201444
201481
  if (fullFeatureMode) {
201445
201482
  try {
201483
+ const armModel = deps.liveModelBySession?.get(sessionId);
201484
+ const armModelKey = deps.getModelKey?.(sessionId);
201485
+ const armSnapshot = persistedUsageBeforeResets;
201486
+ const lastMeasuredInput = armSnapshot?.usage.inputTokens ?? sessionMeta?.lastInputTokens ?? 0;
201487
+ const lastMeasuredModelKey = armSnapshot?.lastObservedModelKey ?? null;
201488
+ const armCatalogLimit = armModel ? getSdkContextLimit(armModel.providerID, armModel.modelID) : undefined;
201489
+ if (!sessionMeta?.isSubagent && armModel && typeof armCatalogLimit === "number" && armCatalogLimit > 0 && lastMeasuredInput > armCatalogLimit && lastMeasuredModelKey != null && armModelKey != null && lastMeasuredModelKey !== armModelKey && !getOverflowState(db, sessionId).needsEmergencyRecovery) {
201490
+ sessionLog(sessionId, `transform: last input ${lastMeasuredInput} (model ${lastMeasuredModelKey}) exceeds new model ${armModelKey} catalog limit ${armCatalogLimit}; arming overflow recovery proactively for the shrinking switch`);
201491
+ recordOverflowDetected(db, sessionId, undefined, armModelKey);
201492
+ resetProtectedTailNoEligibleHead(db, sessionId);
201493
+ }
201446
201494
  const overflowState = getOverflowState(db, sessionId);
201447
201495
  emergencyRecoveryArmed = overflowState.needsEmergencyRecovery;
201448
201496
  if (contextUsageEarly.percentage < 80 && !overflowState.needsEmergencyRecovery) {
@@ -201479,7 +201527,7 @@ function createTransform(deps) {
201479
201527
  sessionID: sessionId
201480
201528
  }) : undefined;
201481
201529
  const currentModelKeyForBoundary = deps.getModelKey?.(sessionId);
201482
- const persistedUsageFreshForBoundary = persistedUsageBeforeFirstPassReset && Date.now() - persistedUsageBeforeFirstPassReset.updatedAt <= 10 * 60 * 1000 && (persistedUsageBeforeFirstPassReset.lastObservedModelKey === null || currentModelKeyForBoundary === undefined || persistedUsageBeforeFirstPassReset.lastObservedModelKey === currentModelKeyForBoundary) && (resolvedContextLimit === undefined || persistedUsageBeforeFirstPassReset.lastUsageContextLimit === 0 || persistedUsageBeforeFirstPassReset.lastUsageContextLimit === resolvedContextLimit) ? persistedUsageBeforeFirstPassReset.usage : null;
201530
+ const persistedUsageFreshForBoundary = persistedUsageBeforeResets && Date.now() - persistedUsageBeforeResets.updatedAt <= 10 * 60 * 1000 && (persistedUsageBeforeResets.lastObservedModelKey === null || currentModelKeyForBoundary === undefined || persistedUsageBeforeResets.lastObservedModelKey === currentModelKeyForBoundary) && (resolvedContextLimit === undefined || persistedUsageBeforeResets.lastUsageContextLimit === 0 || persistedUsageBeforeResets.lastUsageContextLimit === resolvedContextLimit) ? persistedUsageBeforeResets.usage : null;
201483
201531
  const boundaryUsageForProtectedTail = persistedUsageFreshForBoundary ?? contextUsageEarly;
201484
201532
  const boundaryUsageSource = persistedUsageFreshForBoundary ? "persisted" : "live";
201485
201533
  const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens, resolvedContextLimit);
@@ -202317,6 +202365,9 @@ function createEventHandler2(deps) {
202317
202365
  }
202318
202366
  if (hasUsageTokens) {
202319
202367
  const totalInputTokens = (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0);
202368
+ if (deps.client) {
202369
+ await refreshModelLimitsAfterAuthOnce(deps.client);
202370
+ }
202320
202371
  let contextLimit = resolveContextLimit(info.providerID, info.modelID, {
202321
202372
  db: deps.db,
202322
202373
  sessionID: info.sessionID
@@ -1 +1 @@
1
- {"version":3,"file":"conflict-warning-hook.d.ts","sourceRoot":"","sources":["../../src/plugin/conflict-warning-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAsLlE;;GAEG;AACH,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,cAAc,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqDf;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAwHf;AAkCD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC1C,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAsEf;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CACxC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACpC,OAAO,CAAC,IAAI,CAAC,CAkFf"}
1
+ {"version":3,"file":"conflict-warning-hook.d.ts","sourceRoot":"","sources":["../../src/plugin/conflict-warning-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAsLlE;;GAEG;AACH,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,cAAc,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqDf;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAwHf;AAkCD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC1C,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAsEf;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CACxC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CA2Cf;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CACzC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACpC,OAAO,CAAC,IAAI,CAAC,CAkFf"}
@@ -59,6 +59,29 @@ export declare function refreshModelLimitsFromApi(client: OpencodeClientLike, op
59
59
  retries?: number;
60
60
  retryDelayMs?: number;
61
61
  }): Promise<void>;
62
+ /**
63
+ * Re-warm the limit cache ONCE per process, after auth is provably live.
64
+ *
65
+ * The startup warm (index.ts) can run before the user's provider auth is
66
+ * loaded. When it does, an auth-conditional limit patch hasn't applied yet, so
67
+ * `config.providers()` returns the RAW catalog limit (e.g. OpenAI gpt-5.5 OAuth
68
+ * is downshifted to a 272k input cap by OpenCode's Codex auth plugin only when
69
+ * `ctx.auth.type === "oauth"`; before auth loads it reports the raw 922k). That
70
+ * too-high value gets cached AND persisted as last-known-good, survives
71
+ * restarts, and the existing recovery only re-resolves a too-LOW limit
72
+ * (overflow / `percentage > 100`), so a too-HIGH one never self-corrects: the
73
+ * sidebar shows huge headroom while the backend rejects at the real cap (#179).
74
+ *
75
+ * The first `message.updated` carrying usage tokens proves a request succeeded,
76
+ * so auth + providers are fully resolved. Re-warming there overwrites any stale
77
+ * pre-auth limit with the live auth-adjusted one. Idempotent and cheap: a single
78
+ * `config.providers()` round-trip, then a no-op for the rest of the process. The
79
+ * latch is set before the await so concurrent `message.updated` events don't
80
+ * stack duplicate warms; a failed warm resets it so a later message retries.
81
+ */
82
+ export declare function refreshModelLimitsAfterAuthOnce(client: OpencodeClientLike): Promise<void>;
83
+ /** Test-only: reset the after-auth re-warm latch between cases. */
84
+ export declare function resetAuthRewarmLatchForTest(): void;
62
85
  /**
63
86
  * Resolve a model's prompt limit from OpenCode's SDK (`config.providers()`),
64
87
  * the single source of truth: it already merges models.dev + compiled-in
@@ -1 +1 @@
1
- {"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAQH,UAAU,kBAAkB;IACxB,MAAM,EAAE;QACJ,SAAS,EAAE,MAAM,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,SAAS,CAAC,EAAE,OAAO,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAChE,CAAC;CACL;AASD,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,eAAO,MAAM,cAAc,UAAY,CAAC;AAExC;;kFAEkF;AAClF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAEtE;AA+HD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,yBAAyB,CAC3C,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC,IAAI,CAAC,CAUf;AA+DD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI1F;AA6BD,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,IAAI,CAI1C;AAED,oDAAoD;AACpD,wBAAgB,sBAAsB,IAAI;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAMA"}
1
+ {"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAQH,UAAU,kBAAkB;IACxB,MAAM,EAAE;QACJ,SAAS,EAAE,MAAM,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,SAAS,CAAC,EAAE,OAAO,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAChE,CAAC;CACL;AASD,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,eAAO,MAAM,cAAc,UAAY,CAAC;AAExC;;kFAEkF;AAClF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAEtE;AA+HD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,yBAAyB,CAC3C,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC,IAAI,CAAC,CAUf;AAKD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,+BAA+B,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/F;AAED,mEAAmE;AACnE,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AA+DD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI1F;AA6BD,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,IAAI,CAI1C;AAED,oDAAoD;AACpD,wBAAgB,sBAAsB,IAAI;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAMA"}
@@ -1 +1 @@
1
- {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkEH;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAqD9C"}
1
+ {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyEH;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAqD9C"}
@@ -3,7 +3,7 @@ export declare function getTuiPreferencesFile(): string;
3
3
  export declare function readTuiPreferencesFile(): Promise<Record<string, unknown>>;
4
4
  export declare function readTuiPreferencesFileSync(): Record<string, unknown>;
5
5
  export declare const PLUGIN_KEY = "magic-context";
6
- export declare const DEFAULT_SLOT_ORDER = 200;
6
+ export declare const DEFAULT_SLOT_ORDER = 170;
7
7
  export interface MagicContextTuiPrefs {
8
8
  forceToTop: boolean;
9
9
  order: number;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Pick a readable text color (black or white) for text drawn ON TOP of a given
3
+ * background color.
4
+ *
5
+ * The sidebar header badge previously drew its label with `fg={theme.background}`
6
+ * on a `theme.accent` background. That breaks for themes that set
7
+ * `background: "none"` (transparent) to respect terminal transparency: the
8
+ * resolved background is `RGBA(0,0,0,0)`, so the badge text renders fully
9
+ * transparent and disappears (issue #186). The badge background (`accent`) is
10
+ * always opaque, so deriving the text color from it is transparency-proof.
11
+ *
12
+ * The pick is WHITE-BIASED off the accent's relative luminance: white for any
13
+ * accent in the dark half (luminance < 0.5), black only for genuinely light
14
+ * accents. A strict "higher-contrast-wins" pick (crossover at luminance 0.179)
15
+ * flips ordinary mid-tone accents to black: a typical orange/amber sidebar
16
+ * accent (luminance ~0.3) reads black ~5:1 vs white ~3.7:1, so contrast-wins
17
+ * picks black even though white at ~3.7:1 is perfectly legible for a short bold
18
+ * label. That looks heavy and clashes with the sibling status badges, so we
19
+ * prefer white across the whole dark half and only fall to black once the accent
20
+ * is actually light (pale/pastel/near-white), where white would be unreadable.
21
+ *
22
+ * `RGBA` channels from @opentui/core are normalized 0..1 floats. We accept the
23
+ * minimal `{ r, g, b }` shape so this stays a pure, trivially testable function
24
+ * independent of the native color class.
25
+ */
26
+ export declare function readableTextColorOn(bg: {
27
+ r: number;
28
+ g: number;
29
+ b: number;
30
+ }): string;
31
+ //# sourceMappingURL=badge-contrast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge-contrast.d.ts","sourceRoot":"","sources":["../../src/tui/badge-contrast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAmBH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEnF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.27.1",
3
+ "version": "0.27.3",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",
@@ -44,9 +44,12 @@
44
44
  "@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
45
45
  "@opencode-ai/plugin": "^1.15.13",
46
46
  "@opencode-ai/sdk": "^1.15.13",
47
+ "@opentui/core": "^0.4.2",
48
+ "@opentui/solid": "^0.4.2",
47
49
  "ai-tokenizer": "^1.0.6",
48
50
  "comment-json": "^4.2.5",
49
51
  "quickjs-emscripten": "^0.32.0",
52
+ "solid-js": "1.9.12",
50
53
  "zod": "^4.1.8"
51
54
  },
52
55
  "devDependencies": {
@@ -6,7 +6,9 @@ import {
6
6
  clearModelsDevCache,
7
7
  getModelsDevCacheState,
8
8
  getSdkContextLimit,
9
+ refreshModelLimitsAfterAuthOnce,
9
10
  refreshModelLimitsFromApi,
11
+ resetAuthRewarmLatchForTest,
10
12
  } from "./models-dev-cache";
11
13
 
12
14
  /**
@@ -198,6 +200,86 @@ describe("models-dev-cache (SDK-only)", () => {
198
200
  });
199
201
  });
200
202
 
203
+ describe("after-auth re-warm (once per process)", () => {
204
+ // The startup warm can run before provider auth is loaded, caching a raw
205
+ // pre-downshift limit (gpt-5.5 922k) that then survives restarts and is
206
+ // never corrected by the too-low-only recovery. The first usage event
207
+ // proves auth is live; one re-warm there overwrites the stale value.
208
+ function makeCountingClient(input: number) {
209
+ let calls = 0;
210
+ return {
211
+ client: {
212
+ config: {
213
+ providers: async () => {
214
+ calls++;
215
+ return {
216
+ data: {
217
+ providers: [
218
+ {
219
+ id: "openai",
220
+ models: { "gpt-5.5": { limit: { input } } },
221
+ },
222
+ ],
223
+ },
224
+ };
225
+ },
226
+ },
227
+ },
228
+ calls: () => calls,
229
+ };
230
+ }
231
+
232
+ test("re-warm overwrites a stale pre-auth limit and runs only once per process", async () => {
233
+ resetAuthRewarmLatchForTest();
234
+ // Pre-auth startup warm cached the raw 922k.
235
+ await refreshModelLimitsFromApi(
236
+ makeClient([{ id: "openai", models: { "gpt-5.5": { limit: { input: 922000 } } } }]),
237
+ );
238
+ expect(getSdkContextLimit("openai", "gpt-5.5")).toBe(922000);
239
+
240
+ // First usage: auth is live, providers() now reports the 272k cap.
241
+ const { client, calls } = makeCountingClient(272000);
242
+ await refreshModelLimitsAfterAuthOnce(client);
243
+ expect(getSdkContextLimit("openai", "gpt-5.5")).toBe(272000);
244
+ expect(calls()).toBe(1);
245
+
246
+ // Subsequent usage events are a no-op (latch held).
247
+ await refreshModelLimitsAfterAuthOnce(client);
248
+ await refreshModelLimitsAfterAuthOnce(client);
249
+ expect(calls()).toBe(1);
250
+ });
251
+
252
+ test("a failed re-warm resets the latch so a later usage event retries", async () => {
253
+ resetAuthRewarmLatchForTest();
254
+ let calls = 0;
255
+ const flaky = {
256
+ config: {
257
+ providers: async () => {
258
+ calls++;
259
+ // First attempt: empty payload (auth still settling) → no warm.
260
+ if (calls === 1) return { data: { providers: [] } };
261
+ return {
262
+ data: {
263
+ providers: [
264
+ {
265
+ id: "openai",
266
+ models: { "gpt-5.5": { limit: { input: 272000 } } },
267
+ },
268
+ ],
269
+ },
270
+ };
271
+ },
272
+ },
273
+ };
274
+ await refreshModelLimitsAfterAuthOnce(flaky);
275
+ expect(getSdkContextLimit("openai", "gpt-5.5")).toBeUndefined();
276
+ // Latch was reset on failure, so the next event retries and succeeds.
277
+ await refreshModelLimitsAfterAuthOnce(flaky);
278
+ expect(getSdkContextLimit("openai", "gpt-5.5")).toBe(272000);
279
+ expect(calls).toBe(2);
280
+ });
281
+ });
282
+
201
283
  describe("startup retry", () => {
202
284
  test("retries when the provider payload is empty, then succeeds", async () => {
203
285
  let calls = 0;
@@ -210,6 +210,41 @@ export async function refreshModelLimitsFromApi(
210
210
  }
211
211
  }
212
212
 
213
+ // Once-per-process latch for the after-auth re-warm below.
214
+ let authRewarmDone = false;
215
+
216
+ /**
217
+ * Re-warm the limit cache ONCE per process, after auth is provably live.
218
+ *
219
+ * The startup warm (index.ts) can run before the user's provider auth is
220
+ * loaded. When it does, an auth-conditional limit patch hasn't applied yet, so
221
+ * `config.providers()` returns the RAW catalog limit (e.g. OpenAI gpt-5.5 OAuth
222
+ * is downshifted to a 272k input cap by OpenCode's Codex auth plugin only when
223
+ * `ctx.auth.type === "oauth"`; before auth loads it reports the raw 922k). That
224
+ * too-high value gets cached AND persisted as last-known-good, survives
225
+ * restarts, and the existing recovery only re-resolves a too-LOW limit
226
+ * (overflow / `percentage > 100`), so a too-HIGH one never self-corrects: the
227
+ * sidebar shows huge headroom while the backend rejects at the real cap (#179).
228
+ *
229
+ * The first `message.updated` carrying usage tokens proves a request succeeded,
230
+ * so auth + providers are fully resolved. Re-warming there overwrites any stale
231
+ * pre-auth limit with the live auth-adjusted one. Idempotent and cheap: a single
232
+ * `config.providers()` round-trip, then a no-op for the rest of the process. The
233
+ * latch is set before the await so concurrent `message.updated` events don't
234
+ * stack duplicate warms; a failed warm resets it so a later message retries.
235
+ */
236
+ export async function refreshModelLimitsAfterAuthOnce(client: OpencodeClientLike): Promise<void> {
237
+ if (authRewarmDone) return;
238
+ authRewarmDone = true;
239
+ const ok = await refreshModelLimitsOnce(client);
240
+ if (!ok) authRewarmDone = false;
241
+ }
242
+
243
+ /** Test-only: reset the after-auth re-warm latch between cases. */
244
+ export function resetAuthRewarmLatchForTest(): void {
245
+ authRewarmDone = false;
246
+ }
247
+
213
248
  /** Single SDK fetch + cache rebuild. Returns true when providers were loaded. */
214
249
  async function refreshModelLimitsOnce(client: OpencodeClientLike): Promise<boolean> {
215
250
  try {
@@ -60,4 +60,47 @@ describe("ensureTuiPluginEntry", () => {
60
60
  expect(entry[0]).toBe("@cortexkit/opencode-magic-context@latest");
61
61
  expect(entry[1]).toEqual({ enabled: true });
62
62
  });
63
+
64
+ it("creates tui.jsonc (not tui.json) on a fresh install", async () => {
65
+ const root = mkdtempSync(join(tmpdir(), "mc-tui-fresh-"));
66
+ roots.push(root);
67
+ process.env.OPENCODE_CONFIG_DIR = root;
68
+
69
+ const { ensureTuiPluginEntry } = await import("./tui-config");
70
+ expect(ensureTuiPluginEntry()).toBe(true);
71
+
72
+ // The new file must be tui.jsonc so a tui.json stub never ends up
73
+ // sitting next to a tui.jsonc the user writes later (#176).
74
+ expect(existsSync(join(root, "tui.jsonc"))).toBe(true);
75
+ expect(existsSync(join(root, "tui.json"))).toBe(false);
76
+ const parsed = JSON.parse(readFileSync(join(root, "tui.jsonc"), "utf-8")) as {
77
+ plugin: unknown[];
78
+ };
79
+ expect(parsed.plugin).toContain("@cortexkit/opencode-magic-context@latest");
80
+ });
81
+
82
+ it("writes into the existing tui.jsonc when both files exist", async () => {
83
+ const root = mkdtempSync(join(tmpdir(), "mc-tui-both-"));
84
+ roots.push(root);
85
+ process.env.OPENCODE_CONFIG_DIR = root;
86
+ // A real user config in tui.jsonc plus a leftover empty tui.json.
87
+ writeFileSync(
88
+ join(root, "tui.jsonc"),
89
+ `${JSON.stringify({ keybinds: { x: "y" } }, null, 2)}\n`,
90
+ );
91
+ writeFileSync(join(root, "tui.json"), "{}\n");
92
+
93
+ const { ensureTuiPluginEntry } = await import("./tui-config");
94
+ expect(ensureTuiPluginEntry()).toBe(true);
95
+
96
+ // The plugin entry must land in tui.jsonc (higher precedence), and the
97
+ // user's keybinds must survive; tui.json must be left untouched.
98
+ const jsonc = JSON.parse(readFileSync(join(root, "tui.jsonc"), "utf-8")) as {
99
+ plugin: unknown[];
100
+ keybinds: Record<string, string>;
101
+ };
102
+ expect(jsonc.plugin).toContain("@cortexkit/opencode-magic-context@latest");
103
+ expect(jsonc.keybinds).toEqual({ x: "y" });
104
+ expect(readFileSync(join(root, "tui.json"), "utf-8")).toBe("{}\n");
105
+ });
63
106
  });
@@ -62,9 +62,16 @@ function resolveTuiConfigPath(): string {
62
62
  const jsoncPath = join(configDir, "tui.jsonc");
63
63
  const jsonPath = join(configDir, "tui.json");
64
64
 
65
+ // OpenCode loads BOTH tui.json and tui.jsonc and merges them (tui.json first,
66
+ // tui.jsonc second, so .jsonc wins overlapping keys; plugin origins are
67
+ // deduped). So an existing tui.jsonc is the higher-precedence, user-facing
68
+ // file — write into it when present. Otherwise update an existing tui.json.
69
+ // For a fresh install create tui.jsonc, not tui.json: it lets the user add
70
+ // comments later and avoids leaving a second, lower-precedence config file
71
+ // alongside a tui.jsonc they create afterward (#176).
65
72
  if (existsSync(jsoncPath)) return jsoncPath;
66
73
  if (existsSync(jsonPath)) return jsonPath;
67
- return jsonPath; // default: create tui.json
74
+ return jsoncPath;
68
75
  }
69
76
 
70
77
  /**
@@ -11,7 +11,7 @@ import { parse, stringify } from "comment-json";
11
11
  // Cross-plugin convention (anthropic-auth / aft / magic-context all mirror it):
12
12
  // - same file name + env override + lookup order,
13
13
  // - byte-identical `computeEffectiveOrder` so the three sort consistently,
14
- // - a coordinated default-order ladder (anthropic-auth 160, AFT 180, MC 200).
14
+ // - a coordinated default-order ladder (anthropic-auth 160, MC 170, AFT 180).
15
15
  //
16
16
  // MC uses `comment-json` (already a dep, Bun-safe) for the WRITE path — a full
17
17
  // parse → mutate-one-key → stringify round-trip that preserves comments and
@@ -64,7 +64,7 @@ export function readTuiPreferencesFileSync(): Record<string, unknown> {
64
64
  }
65
65
 
66
66
  export const PLUGIN_KEY = "magic-context";
67
- export const DEFAULT_SLOT_ORDER = 200;
67
+ export const DEFAULT_SLOT_ORDER = 170;
68
68
 
69
69
  export interface MagicContextTuiPrefs {
70
70
  forceToTop: boolean;
@@ -0,0 +1,45 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { readableTextColorOn } from "./badge-contrast";
3
+
4
+ describe("readableTextColorOn", () => {
5
+ test("dark accent gets white text", () => {
6
+ // A typical dark accent (deep blue/purple) should read as white.
7
+ expect(readableTextColorOn({ r: 0.1, g: 0.1, b: 0.3 })).toBe("#ffffff");
8
+ expect(readableTextColorOn({ r: 0, g: 0, b: 0 })).toBe("#ffffff");
9
+ });
10
+
11
+ test("light accent gets black text", () => {
12
+ // Only accents pale enough that white fails the contrast bar go black.
13
+ expect(readableTextColorOn({ r: 0.9, g: 0.9, b: 0.7 })).toBe("#000000");
14
+ expect(readableTextColorOn({ r: 1, g: 1, b: 1 })).toBe("#000000");
15
+ });
16
+
17
+ test("mid-tone orange accent prefers white (white-bias, matches sibling badges)", () => {
18
+ // A typical orange/amber accent reads white ~4:1 and black ~5:1. A
19
+ // higher-contrast-wins pick would flip it to black (the #186 over-
20
+ // correction); the white bias keeps it white, clearing the bold-text bar.
21
+ expect(readableTextColorOn({ r: 0.69, g: 0.455, b: 0.188 })).toBe("#ffffff");
22
+ expect(readableTextColorOn({ r: 0.741, g: 0.482, b: 0.2 })).toBe("#ffffff");
23
+ });
24
+
25
+ test("pure green is treated as light (white fails the contrast bar)", () => {
26
+ // A saturated green is bright enough that white drops below the bar.
27
+ expect(readableTextColorOn({ r: 0, g: 1, b: 0 })).toBe("#000000");
28
+ });
29
+
30
+ test("pure blue is treated as dark (low luma weight)", () => {
31
+ // Blue contributes little to perceived brightness, so a saturated blue
32
+ // badge needs light text.
33
+ expect(readableTextColorOn({ r: 0, g: 0, b: 1 })).toBe("#ffffff");
34
+ });
35
+
36
+ test("does not depend on the (possibly transparent) background alpha", () => {
37
+ // The helper only reads r/g/b — the regression in #186 was using a
38
+ // background color whose alpha could be 0. Two accents with identical
39
+ // rgb resolve identically regardless of any alpha the caller might pass.
40
+ const a = readableTextColorOn({ r: 0.2, g: 0.2, b: 0.2 });
41
+ const b = readableTextColorOn({ r: 0.2, g: 0.2, b: 0.2 });
42
+ expect(a).toBe(b);
43
+ expect(a).toBe("#ffffff");
44
+ });
45
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Pick a readable text color (black or white) for text drawn ON TOP of a given
3
+ * background color.
4
+ *
5
+ * The sidebar header badge previously drew its label with `fg={theme.background}`
6
+ * on a `theme.accent` background. That breaks for themes that set
7
+ * `background: "none"` (transparent) to respect terminal transparency: the
8
+ * resolved background is `RGBA(0,0,0,0)`, so the badge text renders fully
9
+ * transparent and disappears (issue #186). The badge background (`accent`) is
10
+ * always opaque, so deriving the text color from it is transparency-proof.
11
+ *
12
+ * The pick is WHITE-BIASED off the accent's relative luminance: white for any
13
+ * accent in the dark half (luminance < 0.5), black only for genuinely light
14
+ * accents. A strict "higher-contrast-wins" pick (crossover at luminance 0.179)
15
+ * flips ordinary mid-tone accents to black: a typical orange/amber sidebar
16
+ * accent (luminance ~0.3) reads black ~5:1 vs white ~3.7:1, so contrast-wins
17
+ * picks black even though white at ~3.7:1 is perfectly legible for a short bold
18
+ * label. That looks heavy and clashes with the sibling status badges, so we
19
+ * prefer white across the whole dark half and only fall to black once the accent
20
+ * is actually light (pale/pastel/near-white), where white would be unreadable.
21
+ *
22
+ * `RGBA` channels from @opentui/core are normalized 0..1 floats. We accept the
23
+ * minimal `{ r, g, b }` shape so this stays a pure, trivially testable function
24
+ * independent of the native color class.
25
+ */
26
+
27
+ // Luminance midpoint: accents below this keep white text, accents at/above it
28
+ // (light/pastel/near-white) get black. White-biased relative to the strict
29
+ // equal-contrast crossover (~0.179) so saturated mid-tone accents stay white.
30
+ const LIGHT_ACCENT_LUMINANCE = 0.5;
31
+
32
+ function srgbChannelToLinear(c: number): number {
33
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
34
+ }
35
+
36
+ function relativeLuminance(bg: { r: number; g: number; b: number }): number {
37
+ return (
38
+ 0.2126 * srgbChannelToLinear(bg.r) +
39
+ 0.7152 * srgbChannelToLinear(bg.g) +
40
+ 0.0722 * srgbChannelToLinear(bg.b)
41
+ );
42
+ }
43
+
44
+ export function readableTextColorOn(bg: { r: number; g: number; b: number }): string {
45
+ return relativeLuminance(bg) < LIGHT_ACCENT_LUMINANCE ? "#ffffff" : "#000000";
46
+ }
@@ -2,6 +2,7 @@
2
2
  import { Show, createEffect, createMemo, createSignal, on, onCleanup } from "solid-js"
3
3
  import type { TuiSlotPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/plugin/tui"
4
4
  import packageJson from "../../../package.json"
5
+ import { readableTextColorOn } from '../badge-contrast';
5
6
  import { loadSidebarSnapshot, type SidebarSnapshot } from "../data/context-db"
6
7
  import { formatThresholdPercent } from "../../shared/format-threshold"
7
8
  import {
@@ -694,7 +695,7 @@ const SidebarContent = (props: {
694
695
  onMouseDown={() => props.controller.toggleCollapsed()}
695
696
  >
696
697
  <box paddingLeft={1} paddingRight={1} backgroundColor={props.theme.accent}>
697
- <text fg={props.theme.background}>
698
+ <text fg={readableTextColorOn(props.theme.accent)}>
698
699
  <b>{collapsed() ? "▶ " : "▼ "}{headerLabel()}</b>
699
700
  </text>
700
701
  </box>