@cortexkit/opencode-magic-context 0.8.10 → 0.8.12

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
@@ -333,7 +333,7 @@ On startup, Magic Context checks for common configuration problems — OpenCode'
333
333
  A companion desktop app for browsing and managing Magic Context state outside of OpenCode.
334
334
 
335
335
  <p align="center">
336
- <a href="https://github.com/cortexkit/opencode-magic-context/releases/tag/dashboard-v0.2.4"><strong>⬇️ Download for macOS · Windows · Linux</strong></a></p>
336
+ <a href="https://github.com/cortexkit/opencode-magic-context/releases/tag/dashboard-v0.2.6"><strong>⬇️ Download for macOS · Windows · Linux</strong></a></p>
337
337
 
338
338
  **Features:**
339
339
  - **Memory Browser** — search, filter, and edit project memories with category and project filtering
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AA4MA,wBAAsB,SAAS,CAC3B,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,MAAM,CAAC,CA2MjB"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AA4MA,wBAAsB,SAAS,CAC3B,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,MAAM,CAAC,CAuNjB"}
package/dist/cli.js CHANGED
@@ -7851,7 +7851,7 @@ var require_src3 = __commonJS((exports, module) => {
7851
7851
  // src/cli/doctor.ts
7852
7852
  var import_comment_json3 = __toESM(require_src2(), 1);
7853
7853
  import { execSync as execSync2, spawnSync } from "node:child_process";
7854
- import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync, statSync as statSync2, writeFileSync as writeFileSync4 } from "node:fs";
7854
+ import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync, statSync as statSync2, writeFileSync as writeFileSync4 } from "node:fs";
7855
7855
  import { createRequire as createRequire3 } from "node:module";
7856
7856
  import { homedir as homedir5, platform, tmpdir as tmpdir3 } from "node:os";
7857
7857
  import { join as join9 } from "node:path";
@@ -8393,15 +8393,20 @@ function ensureTuiPluginEntry() {
8393
8393
  config = import_comment_json.parse(raw) ?? {};
8394
8394
  }
8395
8395
  const plugins = Array.isArray(config.plugin) ? config.plugin.filter((p) => typeof p === "string") : [];
8396
- if (plugins.some((p) => p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`))) {
8397
- return false;
8396
+ const existingIdx = plugins.findIndex((p) => p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`));
8397
+ if (existingIdx >= 0) {
8398
+ if (plugins[existingIdx] === PLUGIN_ENTRY) {
8399
+ return false;
8400
+ }
8401
+ plugins[existingIdx] = PLUGIN_ENTRY;
8402
+ } else {
8403
+ plugins.push(PLUGIN_ENTRY);
8398
8404
  }
8399
- plugins.push(PLUGIN_ENTRY);
8400
8405
  config.plugin = plugins;
8401
8406
  mkdirSync2(dirname2(configPath), { recursive: true });
8402
8407
  writeFileSync2(configPath, `${import_comment_json.stringify(config, null, 2)}
8403
8408
  `);
8404
- log(`[magic-context] added TUI plugin entry to ${configPath}`);
8409
+ log(`[magic-context] updated TUI plugin entry in ${configPath}`);
8405
8410
  return true;
8406
8411
  } catch (error) {
8407
8412
  log(`[magic-context] failed to update tui.json: ${error instanceof Error ? error.message : String(error)}`);
@@ -10009,13 +10014,13 @@ function getOpenCodeCacheDir2() {
10009
10014
  async function clearPluginCache(force = false) {
10010
10015
  const cacheDir = getOpenCodeCacheDir2();
10011
10016
  const pluginCacheDir = join9(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
10012
- if (!existsSync7(pluginCacheDir)) {
10017
+ if (!existsSync6(pluginCacheDir)) {
10013
10018
  return { action: "not_found", path: pluginCacheDir };
10014
10019
  }
10015
10020
  let cachedVersion;
10016
10021
  try {
10017
10022
  const installedPkgPath = join9(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
10018
- if (existsSync7(installedPkgPath)) {
10023
+ if (existsSync6(installedPkgPath)) {
10019
10024
  const pkg = JSON.parse(readFileSync5(installedPkgPath, "utf-8"));
10020
10025
  if (typeof pkg?.version === "string") {
10021
10026
  cachedVersion = pkg.version;
@@ -10147,7 +10152,7 @@ async function runDoctor(options = {}) {
10147
10152
  } else {
10148
10153
  R2.success(`OpenCode config: ${paths.opencodeConfig}`);
10149
10154
  }
10150
- if (existsSync7(paths.magicContextConfig)) {
10155
+ if (existsSync6(paths.magicContextConfig)) {
10151
10156
  R2.success(`Magic Context config: ${paths.magicContextConfig}`);
10152
10157
  } else {
10153
10158
  R2.warn(`No magic-context.jsonc found — using defaults`);
@@ -10158,13 +10163,22 @@ async function runDoctor(options = {}) {
10158
10163
  const raw = readFileSync5(paths.opencodeConfig, "utf-8");
10159
10164
  const config = import_comment_json3.parse(raw);
10160
10165
  const plugins = Array.isArray(config?.plugin) ? config.plugin : [];
10161
- const hasPlugin = plugins.some((p) => typeof p === "string" && (p === PLUGIN_NAME3 || p.startsWith(`${PLUGIN_NAME3}@`) || p.includes("opencode-magic-context")));
10166
+ const pluginList = plugins.filter((p) => typeof p === "string");
10167
+ const existingIdx = pluginList.findIndex((p) => p === PLUGIN_NAME3 || p.startsWith(`${PLUGIN_NAME3}@`) || p.includes("opencode-magic-context"));
10162
10168
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
10163
- if (hasPlugin) {
10169
+ if (existingIdx >= 0 && pluginList[existingIdx] === PLUGIN_ENTRY_WITH_VERSION2) {
10164
10170
  R2.success(`Plugin registered in ${configName}`);
10171
+ } else if (existingIdx >= 0) {
10172
+ const oldEntry = pluginList[existingIdx];
10173
+ pluginList[existingIdx] = PLUGIN_ENTRY_WITH_VERSION2;
10174
+ config.plugin = pluginList;
10175
+ writeFileSync4(paths.opencodeConfig, `${import_comment_json3.stringify(config, null, 2)}
10176
+ `);
10177
+ R2.success(`Upgraded plugin entry in ${configName}: ${oldEntry} → ${PLUGIN_ENTRY_WITH_VERSION2}`);
10178
+ fixed++;
10165
10179
  } else {
10166
- const updatedPlugins = [...plugins, PLUGIN_ENTRY_WITH_VERSION2];
10167
- config.plugin = updatedPlugins;
10180
+ pluginList.push(PLUGIN_ENTRY_WITH_VERSION2);
10181
+ config.plugin = pluginList;
10168
10182
  writeFileSync4(paths.opencodeConfig, `${import_comment_json3.stringify(config, null, 2)}
10169
10183
  `);
10170
10184
  R2.success(`Added plugin to ${configName}`);
@@ -10198,13 +10212,13 @@ async function runDoctor(options = {}) {
10198
10212
  R2.warn("Restart OpenCode to see the sidebar");
10199
10213
  fixed++;
10200
10214
  } else {
10201
- if (existsSync7(paths.tuiConfig)) {
10215
+ if (existsSync6(paths.tuiConfig)) {
10202
10216
  R2.success("TUI sidebar plugin configured");
10203
10217
  } else {
10204
10218
  R2.success("TUI sidebar plugin configured (tui.json created)");
10205
10219
  }
10206
10220
  }
10207
- if (existsSync7(paths.magicContextConfig)) {
10221
+ if (existsSync6(paths.magicContextConfig)) {
10208
10222
  try {
10209
10223
  const mcRaw = readFileSync5(paths.magicContextConfig, "utf-8");
10210
10224
  const mcConfig = import_comment_json3.parse(mcRaw);
@@ -10234,7 +10248,7 @@ async function runDoctor(options = {}) {
10234
10248
  R2.success("Plugin cache clean (no cached version found)");
10235
10249
  }
10236
10250
  const logPath = join9(tmpdir3(), "magic-context.log");
10237
- if (existsSync7(logPath)) {
10251
+ if (existsSync6(logPath)) {
10238
10252
  const logStat = statSync2(logPath);
10239
10253
  const sizeKb = (logStat.size / 1024).toFixed(0);
10240
10254
  R2.info(`Log file: ${logPath} (${sizeKb} KB)`);
@@ -10242,7 +10256,7 @@ async function runDoctor(options = {}) {
10242
10256
  R2.info(`Log file: ${logPath} (not yet created)`);
10243
10257
  }
10244
10258
  const historianDumpDir = join9(tmpdir3(), "magic-context-historian");
10245
- if (existsSync7(historianDumpDir)) {
10259
+ if (existsSync6(historianDumpDir)) {
10246
10260
  try {
10247
10261
  const dumps = readdirSync2(historianDumpDir).filter((f) => f.endsWith(".xml")).map((f) => ({
10248
10262
  name: f,
@@ -10280,12 +10294,12 @@ async function runDoctor(options = {}) {
10280
10294
 
10281
10295
  // src/cli/setup.ts
10282
10296
  var import_comment_json4 = __toESM(require_src2(), 1);
10283
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
10297
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
10284
10298
  import { dirname as dirname3 } from "node:path";
10285
10299
  var PLUGIN_NAME4 = "@cortexkit/opencode-magic-context";
10286
10300
  var PLUGIN_ENTRY2 = "@cortexkit/opencode-magic-context@latest";
10287
10301
  function ensureDir(dir) {
10288
- if (!existsSync8(dir)) {
10302
+ if (!existsSync7(dir)) {
10289
10303
  mkdirSync3(dir, { recursive: true });
10290
10304
  }
10291
10305
  }
@@ -10349,7 +10363,7 @@ function addPluginToTuiConfig(configPath, format) {
10349
10363
  `);
10350
10364
  }
10351
10365
  function writeMagicContextConfig(configPath, options) {
10352
- const config = (existsSync8(configPath) ? readJsonc(configPath) : null) ?? {};
10366
+ const config = (existsSync7(configPath) ? readJsonc(configPath) : null) ?? {};
10353
10367
  if (!config.$schema) {
10354
10368
  config.$schema = "https://raw.githubusercontent.com/cortexkit/opencode-magic-context/master/assets/magic-context.schema.json";
10355
10369
  }
@@ -10415,7 +10429,7 @@ async function runSetup() {
10415
10429
  R2.warn("You can configure models manually in magic-context.jsonc later");
10416
10430
  }
10417
10431
  const paths = detectConfigPaths();
10418
- const hadExistingSetup = paths.opencodeConfigFormat !== "none" || existsSync8(paths.magicContextConfig) || paths.tuiConfigFormat !== "none";
10432
+ const hadExistingSetup = paths.opencodeConfigFormat !== "none" || existsSync7(paths.magicContextConfig) || paths.tuiConfigFormat !== "none";
10419
10433
  addPluginToOpenCodeConfig(paths.opencodeConfig, paths.opencodeConfigFormat);
10420
10434
  R2.success(`Plugin added to ${paths.opencodeConfig}`);
10421
10435
  R2.info("Disabled built-in compaction (auto=false, prune=false)");
@@ -5,12 +5,14 @@ export type LiveModelBySession = Map<string, {
5
5
  modelID: string;
6
6
  }>;
7
7
  export type VariantBySession = Map<string, string | undefined>;
8
+ export type AgentBySession = Map<string, string>;
8
9
  export type RecentReduceBySession = Map<string, number>;
9
10
  export type ToolUsageSinceUserTurn = Map<string, number>;
10
11
  export type FlushedSessions = Set<string>;
11
12
  export type LastHeuristicsTurnId = Map<string, string>;
12
13
  export type EmergencyNudgeFired = Set<string>;
13
- export declare function getLiveNotificationParams(sessionId: string, liveModelBySession: LiveModelBySession, variantBySession: VariantBySession): {
14
+ export declare function getLiveNotificationParams(sessionId: string, liveModelBySession: LiveModelBySession, variantBySession: VariantBySession, agentBySession?: AgentBySession): {
15
+ agent?: string;
14
16
  variant?: string;
15
17
  providerId?: string;
16
18
  modelId?: string;
@@ -20,12 +22,14 @@ export declare function createChatMessageHook(args: {
20
22
  toolUsageSinceUserTurn: ToolUsageSinceUserTurn;
21
23
  recentReduceBySession: RecentReduceBySession;
22
24
  variantBySession: VariantBySession;
25
+ agentBySession: AgentBySession;
23
26
  flushedSessions: FlushedSessions;
24
27
  lastHeuristicsTurnId: LastHeuristicsTurnId;
25
28
  ctxReduceEnabled?: boolean;
26
29
  }): (input: {
27
30
  sessionID?: string;
28
31
  variant?: string;
32
+ agent?: string;
29
33
  }) => Promise<void>;
30
34
  export declare function createEventHook(args: {
31
35
  eventHandler: (input: {
@@ -44,6 +48,7 @@ export declare function createEventHook(args: {
44
48
  db: Parameters<typeof getOrCreateSessionMeta>[0];
45
49
  liveModelBySession: LiveModelBySession;
46
50
  variantBySession: VariantBySession;
51
+ agentBySession: AgentBySession;
47
52
  recentReduceBySession: RecentReduceBySession;
48
53
  toolUsageSinceUserTurn: ToolUsageSinceUserTurn;
49
54
  emergencyNudgeFired: EmergencyNudgeFired;
@@ -1 +1 @@
1
- {"version":3,"file":"hook-handlers.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/hook-handlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hook-handlers.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/hook-handlers.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import type { Scheduler } from "../../features/magic-context/scheduler";
4
4
  import type { Tagger } from "../../features/magic-context/tagger";
5
5
  import type { PluginContext } from "../../plugin/types";
6
6
  export type { CommandExecuteInput, CommandExecuteOutput } from "./command-handler";
7
+ import type { LiveSessionState } from "./live-session-state";
7
8
  export interface MagicContextDeps {
8
9
  client: PluginContext["client"];
9
10
  directory: string;
@@ -11,6 +12,7 @@ export interface MagicContextDeps {
11
12
  scheduler: Scheduler;
12
13
  onSessionCacheInvalidated?: (sessionId: string) => void;
13
14
  compactionHandler: ReturnType<typeof createCompactionHandler>;
15
+ liveSessionState?: LiveSessionState;
14
16
  config: {
15
17
  protected_tags: number;
16
18
  ctx_reduce_enabled?: boolean;
@@ -71,6 +73,7 @@ export declare function createMagicContextHook(deps: MagicContextDeps): {
71
73
  "chat.message": (input: {
72
74
  sessionID?: string;
73
75
  variant?: string;
76
+ agent?: string;
74
77
  }) => Promise<void>;
75
78
  event: (input: {
76
79
  event: {
@@ -1 +1 @@
1
- {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,aAAa,EAClB,KAAK,cAAc,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAOvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAMxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWxD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAiBnF,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,MAAM,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,4BAA4B,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACxF,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,uBAAuB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9C,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,CAAC,EAAE;YACL,OAAO,EAAE,OAAO,CAAC;YACjB,uBAAuB,EAAE,MAAM,CAAC;SACnC,CAAC;QACF,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,sBAAsB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;QACpE,YAAY,CAAC,EAAE;YACX,kBAAkB,CAAC,EAAE,OAAO,CAAC;YAC7B,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,mBAAmB,EAAE,MAAM,CAAA;aAAE,CAAC;YAClE,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,YAAY,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAA;aAAE,CAAC;SACjF,CAAC;KACL,CAAC;CACL;AAqCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB;;;;;iBAxCT,CAAC;;;;;;;;;;;;iBA3BE,CAAC;eAC5C,CAAC;;mBAsUgB;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE;;;SAa7E"}
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,aAAa,EAClB,KAAK,cAAc,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAOvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAMxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWxD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAUnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQ7D,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,CAAC;IACrB,yBAAyB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,MAAM,EAAE;QACJ,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,4BAA4B,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QACxF,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,uBAAuB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9C,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,CAAC,EAAE;YACL,OAAO,EAAE,OAAO,CAAC;YACjB,uBAAuB,EAAE,MAAM,CAAC;SACnC,CAAC;QACF,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,sBAAsB,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;QACpE,YAAY,CAAC,EAAE;YACX,kBAAkB,CAAC,EAAE,OAAO,CAAC;YAC7B,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,mBAAmB,EAAE,MAAM,CAAA;aAAE,CAAC;YAClE,aAAa,CAAC,EAAE;gBAAE,OAAO,EAAE,OAAO,CAAC;gBAAC,YAAY,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAA;aAAE,CAAC;SACjF,CAAC;KACL,CAAC;CACL;AAqCD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB;;;;;iBAzCjC,CAAC;;;;;;;;;;;;iBAtBrB,CAAC;eAAiB,CAAC;aACnB,CAAH;;mBAuVwB;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE;;;SAa7E"}
@@ -0,0 +1,8 @@
1
+ import type { AgentBySession, LiveModelBySession, VariantBySession } from "./hook-handlers";
2
+ export interface LiveSessionState {
3
+ liveModelBySession: LiveModelBySession;
4
+ variantBySession: VariantBySession;
5
+ agentBySession: AgentBySession;
6
+ }
7
+ export declare function createLiveSessionState(): LiveSessionState;
8
+ //# sourceMappingURL=live-session-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-session-state.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/live-session-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE5F,MAAM,WAAW,gBAAgB;IAC7B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,wBAAgB,sBAAsB,IAAI,gBAAgB,CAMzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAyBlD,QAAA,MAAM,MAAM,EAAE,MA2Ob,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AA0BlD,QAAA,MAAM,MAAM,EAAE,MAiPb,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js CHANGED
@@ -16916,7 +16916,7 @@ function isThinkingPart(part) {
16916
16916
  var encoder, TAG_PREFIX_REGEX;
16917
16917
  var init_tag_content_primitives = __esm(() => {
16918
16918
  encoder = new TextEncoder;
16919
- TAG_PREFIX_REGEX = /^\u00A7\d+\u00A7\s*/;
16919
+ TAG_PREFIX_REGEX = /^(?:\u00A7\d+\u00A7\s*)+/;
16920
16920
  });
16921
16921
 
16922
16922
  // src/hooks/magic-context/tag-part-guards.ts
@@ -28223,15 +28223,20 @@ function ensureTuiPluginEntry() {
28223
28223
  config2 = import_comment_json.parse(raw) ?? {};
28224
28224
  }
28225
28225
  const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p) => typeof p === "string") : [];
28226
- if (plugins.some((p) => p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`))) {
28227
- return false;
28226
+ const existingIdx = plugins.findIndex((p) => p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`));
28227
+ if (existingIdx >= 0) {
28228
+ if (plugins[existingIdx] === PLUGIN_ENTRY) {
28229
+ return false;
28230
+ }
28231
+ plugins[existingIdx] = PLUGIN_ENTRY;
28232
+ } else {
28233
+ plugins.push(PLUGIN_ENTRY);
28228
28234
  }
28229
- plugins.push(PLUGIN_ENTRY);
28230
28235
  config2.plugin = plugins;
28231
28236
  mkdirSync5(dirname2(configPath), { recursive: true });
28232
28237
  writeFileSync3(configPath, `${import_comment_json.stringify(config2, null, 2)}
28233
28238
  `);
28234
- log(`[magic-context] added TUI plugin entry to ${configPath}`);
28239
+ log(`[magic-context] updated TUI plugin entry in ${configPath}`);
28235
28240
  return true;
28236
28241
  } catch (error48) {
28237
28242
  log(`[magic-context] failed to update tui.json: ${error48 instanceof Error ? error48.message : String(error48)}`);
@@ -28839,6 +28844,17 @@ async function runSidekick(deps) {
28839
28844
 
28840
28845
  // src/index.ts
28841
28846
  init_compartment_prompt();
28847
+
28848
+ // src/hooks/magic-context/live-session-state.ts
28849
+ function createLiveSessionState() {
28850
+ return {
28851
+ liveModelBySession: new Map,
28852
+ variantBySession: new Map,
28853
+ agentBySession: new Map
28854
+ };
28855
+ }
28856
+
28857
+ // src/index.ts
28842
28858
  init_conflict_warning_hook();
28843
28859
 
28844
28860
  // src/features/magic-context/dreamer/storage-dream-state.ts
@@ -30246,6 +30262,12 @@ function loadModelsDevLimits() {
30246
30262
  const context = model?.limit?.context;
30247
30263
  if (typeof context === "number" && context > 0) {
30248
30264
  limits.set(`${providerId}/${modelId}`, context);
30265
+ const modes = model?.experimental?.modes;
30266
+ if (modes && typeof modes === "object") {
30267
+ for (const mode of Object.keys(modes)) {
30268
+ limits.set(`${providerId}/${modelId}-${mode}`, context);
30269
+ }
30270
+ }
30249
30271
  }
30250
30272
  }
30251
30273
  }
@@ -30257,7 +30279,7 @@ function loadModelsDevLimits() {
30257
30279
  const configPath = getOpencodeConfigPath();
30258
30280
  if (configPath && existsSync5(configPath)) {
30259
30281
  let raw = readFileSync4(configPath, "utf-8");
30260
- raw = raw.replace(/\/\/.*$/gm, "");
30282
+ raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
30261
30283
  const config2 = JSON.parse(raw);
30262
30284
  if (config2.provider && typeof config2.provider === "object") {
30263
30285
  for (const [providerId, provider2] of Object.entries(config2.provider)) {
@@ -33693,10 +33715,12 @@ var TOOL_HEAVY_TURN_REMINDER_THRESHOLD = 5;
33693
33715
  var TOOL_HEAVY_TURN_REMINDER_TEXT = `
33694
33716
 
33695
33717
  <instruction name="ctx_reduce_turn_cleanup">Also drop via \`ctx_reduce\` things you don't need anymore from the last turn before continuing.</instruction>`;
33696
- function getLiveNotificationParams(sessionId, liveModelBySession, variantBySession) {
33718
+ function getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession) {
33697
33719
  const model = liveModelBySession.get(sessionId);
33698
33720
  const variant = variantBySession.get(sessionId);
33721
+ const agent = agentBySession?.get(sessionId);
33699
33722
  return {
33723
+ ...agent ? { agent } : {},
33700
33724
  ...variant ? { variant } : {},
33701
33725
  ...model ? { providerId: model.providerID, modelId: model.modelID } : {}
33702
33726
  };
@@ -33717,6 +33741,9 @@ function createChatMessageHook(args) {
33717
33741
  args.toolUsageSinceUserTurn.set(sessionId, 0);
33718
33742
  const previousVariant = args.variantBySession.get(sessionId);
33719
33743
  args.variantBySession.set(sessionId, input.variant);
33744
+ if (input.agent) {
33745
+ args.agentBySession.set(sessionId, input.agent);
33746
+ }
33720
33747
  if (previousVariant !== undefined && input.variant !== undefined && previousVariant !== input.variant) {
33721
33748
  sessionLog(sessionId, `variant changed (${previousVariant} -> ${input.variant}), triggering flush`);
33722
33749
  args.flushedSessions.add(sessionId);
@@ -33748,6 +33775,7 @@ function createEventHook(args) {
33748
33775
  if (input.event.type === "session.deleted") {
33749
33776
  args.liveModelBySession.delete(sessionId);
33750
33777
  args.variantBySession.delete(sessionId);
33778
+ args.agentBySession.delete(sessionId);
33751
33779
  args.recentReduceBySession.delete(sessionId);
33752
33780
  args.toolUsageSinceUserTurn.delete(sessionId);
33753
33781
  args.emergencyNudgeFired.delete(sessionId);
@@ -33782,6 +33810,7 @@ function createEventHook(args) {
33782
33810
  try {
33783
33811
  const model = args.liveModelBySession.get(sessionId);
33784
33812
  const variant = args.variantBySession.get(sessionId);
33813
+ const agent = args.agentBySession.get(sessionId);
33785
33814
  const c = args.client;
33786
33815
  if (typeof c.session?.promptAsync !== "function") {
33787
33816
  sessionLog(sessionId, "emergency nudge: promptAsync unavailable");
@@ -33791,6 +33820,7 @@ function createEventHook(args) {
33791
33820
  await c.session.promptAsync({
33792
33821
  path: { id: sessionId },
33793
33822
  body: {
33823
+ ...agent ? { agent } : {},
33794
33824
  ...model ? { model } : {},
33795
33825
  ...variant ? { variant } : {},
33796
33826
  parts: [{ type: "text", text: nudgeText }]
@@ -34299,8 +34329,9 @@ function createMagicContextHook(deps) {
34299
34329
  const flushedSessions = new Set;
34300
34330
  const lastHeuristicsTurnId = new Map;
34301
34331
  const commitSeenLastPass = new Map;
34302
- const variantBySession = new Map;
34303
- const liveModelBySession = new Map;
34332
+ const variantBySession = deps.liveSessionState?.variantBySession ?? new Map;
34333
+ const liveModelBySession = deps.liveSessionState?.liveModelBySession ?? new Map;
34334
+ const agentBySession = deps.liveSessionState?.agentBySession ?? new Map;
34304
34335
  const recentReduceBySession = new Map;
34305
34336
  const toolUsageSinceUserTurn = new Map;
34306
34337
  const ctxReduceEnabled = deps.config.ctx_reduce_enabled !== false;
@@ -34335,7 +34366,7 @@ function createMagicContextHook(deps) {
34335
34366
  historyBudgetPercentage: deps.config.history_budget_percentage,
34336
34367
  executeThresholdPercentage: deps.config.execute_threshold_percentage,
34337
34368
  historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
34338
- getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession),
34369
+ getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
34339
34370
  getModelKey: (sessionId) => {
34340
34371
  const model = liveModelBySession.get(sessionId);
34341
34372
  return resolveModelKey(model?.providerID, model?.modelID);
@@ -34419,11 +34450,11 @@ function createMagicContextHook(deps) {
34419
34450
  const model = liveModelBySession.get(sessionId);
34420
34451
  return model ? `${model.providerID}/${model.modelID}` : undefined;
34421
34452
  })(),
34422
- getNotificationParams: () => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession)
34453
+ getNotificationParams: () => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession)
34423
34454
  }),
34424
34455
  sendNotification: async (sessionId, text, params) => {
34425
34456
  await sendIgnoredMessage(deps.client, sessionId, text, {
34426
- ...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession),
34457
+ ...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
34427
34458
  ...params
34428
34459
  });
34429
34460
  },
@@ -34470,6 +34501,7 @@ function createMagicContextHook(deps) {
34470
34501
  db,
34471
34502
  liveModelBySession,
34472
34503
  variantBySession,
34504
+ agentBySession,
34473
34505
  recentReduceBySession,
34474
34506
  toolUsageSinceUserTurn,
34475
34507
  emergencyNudgeFired,
@@ -34489,6 +34521,7 @@ function createMagicContextHook(deps) {
34489
34521
  toolUsageSinceUserTurn,
34490
34522
  recentReduceBySession,
34491
34523
  variantBySession,
34524
+ agentBySession,
34492
34525
  flushedSessions,
34493
34526
  lastHeuristicsTurnId,
34494
34527
  ctxReduceEnabled
@@ -34509,7 +34542,7 @@ function createMagicContextHook(deps) {
34509
34542
  }
34510
34543
  // src/plugin/hooks/create-session-hooks.ts
34511
34544
  function createSessionHooks(args) {
34512
- const { ctx, pluginConfig } = args;
34545
+ const { ctx, pluginConfig, liveSessionState } = args;
34513
34546
  if (pluginConfig.enabled !== true) {
34514
34547
  return { magicContext: null };
34515
34548
  }
@@ -34525,6 +34558,7 @@ function createSessionHooks(args) {
34525
34558
  tagger,
34526
34559
  scheduler: scheduler2,
34527
34560
  compactionHandler,
34561
+ liveSessionState,
34528
34562
  config: {
34529
34563
  protected_tags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
34530
34564
  ctx_reduce_enabled: pluginConfig.ctx_reduce_enabled,
@@ -34822,8 +34856,9 @@ ${c.content}
34822
34856
  return detail;
34823
34857
  }
34824
34858
  function registerRpcHandlers(rpcServer, args) {
34825
- const { directory, config: config2 } = args;
34859
+ const { directory, config: config2, liveSessionState } = args;
34826
34860
  const rawConfig = config2;
34861
+ const getNotificationParams = (sessionId) => getLiveNotificationParams(sessionId, liveSessionState.liveModelBySession, liveSessionState.variantBySession, liveSessionState.agentBySession);
34827
34862
  rpcServer.handle("sidebar-snapshot", async (params) => {
34828
34863
  const sessionId = String(params.sessionId ?? "");
34829
34864
  const dir = String(params.directory ?? directory);
@@ -34872,9 +34907,9 @@ function registerRpcHandlers(rpcServer, args) {
34872
34907
  tokenBudget: config2.compartment_token_budget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET2,
34873
34908
  historianTimeoutMs: config2.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS2,
34874
34909
  directory,
34875
- getNotificationParams: () => ({})
34910
+ getNotificationParams: () => getNotificationParams(sessionId)
34876
34911
  }).then((result) => {
34877
- sendIgnoredMessage2(args.client, sessionId, result, {}).catch(() => {});
34912
+ sendIgnoredMessage2(args.client, sessionId, result, getNotificationParams(sessionId)).catch(() => {});
34878
34913
  }).catch((error48) => {
34879
34914
  log("[rpc] recomp failed:", error48);
34880
34915
  });
@@ -36233,9 +36268,11 @@ var plugin = async (ctx) => {
36233
36268
  log("[magic-context] no conflicts detected, plugin enabled");
36234
36269
  }
36235
36270
  }
36271
+ const liveSessionState = createLiveSessionState();
36236
36272
  const hooks = createSessionHooks({
36237
36273
  ctx,
36238
- pluginConfig
36274
+ pluginConfig,
36275
+ liveSessionState
36239
36276
  });
36240
36277
  const tools5 = createToolRegistry({
36241
36278
  ctx,
@@ -36263,7 +36300,8 @@ var plugin = async (ctx) => {
36263
36300
  registerRpcHandlers(rpcServer, {
36264
36301
  directory: ctx.directory,
36265
36302
  config: pluginConfig,
36266
- client: ctx.client
36303
+ client: ctx.client,
36304
+ liveSessionState
36267
36305
  });
36268
36306
  rpcServer.start().catch((err) => {
36269
36307
  log(`[magic-context] RPC server failed to start: ${err}`);
@@ -1,8 +1,10 @@
1
1
  import type { MagicContextPluginConfig } from "../../config";
2
+ import type { LiveSessionState } from "../../hooks/magic-context/live-session-state";
2
3
  import type { PluginContext } from "../types";
3
4
  export declare function createSessionHooks(args: {
4
5
  ctx: PluginContext;
5
6
  pluginConfig: MagicContextPluginConfig;
7
+ liveSessionState: LiveSessionState;
6
8
  }): {
7
9
  magicContext: {
8
10
  "experimental.chat.messages.transform": (_input: Record<string, never>, output: {
@@ -23,6 +25,7 @@ export declare function createSessionHooks(args: {
23
25
  "chat.message": (input: {
24
26
  sessionID?: string;
25
27
  variant?: string;
28
+ agent?: string;
26
29
  }) => Promise<void>;
27
30
  event: (input: {
28
31
  event: {
@@ -1 +1 @@
1
- {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;CAC1C;;;;;;qBA6C81B,CAAC;;;;;;;;;;;;qBAT5zB,CAAC;mBAAiB,CAAC;;;;;0BASiwZ,CAAC;;;;;;EADxzZ"}
1
+ {"version":3,"file":"create-session-hooks.d.ts","sourceRoot":"","sources":["../../../src/plugin/hooks/create-session-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAU7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,GAAG,EAAE,aAAa,CAAC;IACnB,YAAY,EAAE,wBAAwB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;;;;;;qBA8CgrB,CAAC;;;;;;;;;;;;qBAR/pB,CAAC;mBAAiB,CAAC;iBACtB,CAAP;;;;;0BAOo0a,CAAC;;;;;;EAD70a"}
@@ -1,4 +1,5 @@
1
1
  import type { MagicContextConfig } from "../config/schema/magic-context";
2
+ import type { LiveSessionState } from "../hooks/magic-context/live-session-state";
2
3
  import type { MagicContextRpcServer } from "../shared/rpc-server";
3
4
  /**
4
5
  * Register all RPC handlers on the server.
@@ -7,5 +8,6 @@ export declare function registerRpcHandlers(rpcServer: MagicContextRpcServer, ar
7
8
  directory: string;
8
9
  config: MagicContextConfig;
9
10
  client: unknown;
11
+ liveSessionState: LiveSessionState;
10
12
  }): void;
11
13
  //# sourceMappingURL=rpc-handlers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/plugin/rpc-handlers.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAKzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAmZlE;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;CACnB,GACF,IAAI,CAmFN"}
1
+ {"version":3,"file":"rpc-handlers.d.ts","sourceRoot":"","sources":["../../src/plugin/rpc-handlers.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAGlF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAmZlE;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;CACtC,GACF,IAAI,CA+FN"}
@@ -1,4 +1,5 @@
1
1
  import type { MagicContextConfig } from "../config/schema/magic-context";
2
+ import type { LiveSessionState } from "../hooks/magic-context/live-session-state";
2
3
  import type { PluginContext } from "./types";
3
4
  /**
4
5
  * Start a server-side consumer that polls plugin_messages for TUI→server
@@ -9,5 +10,6 @@ export declare function startTuiActionConsumer(args: {
9
10
  client: PluginContext["client"];
10
11
  directory: string;
11
12
  config: MagicContextConfig;
13
+ liveSessionState: LiveSessionState;
12
14
  }): (() => void) | undefined;
13
15
  //# sourceMappingURL=tui-action-consumer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tui-action-consumer.d.ts","sourceRoot":"","sources":["../../src/plugin/tui-action-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAMzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ7C;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;CAC9B,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CA+D3B"}
1
+ {"version":3,"file":"tui-action-consumer.d.ts","sourceRoot":"","sources":["../../src/plugin/tui-action-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAKzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAGlF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAQ7C;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,gBAAgB,EAAE,gBAAgB,CAAC;CACtC,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CA2E3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AA0HA;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAShG;AAED,8CAA8C;AAC9C,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C"}
1
+ {"version":3,"file":"models-dev-cache.d.ts","sourceRoot":"","sources":["../../src/shared/models-dev-cache.ts"],"names":[],"mappings":"AA6IA;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAShG;AAED,8CAA8C;AAC9C,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CA+B9C"}
1
+ {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAsC9C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.8.10",
3
+ "version": "0.8.12",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",
@@ -60,7 +60,15 @@ function loadModelsDevLimits(): Map<string, number> {
60
60
  const raw = readFileSync(modelsJsonPath, "utf-8");
61
61
  const data = JSON.parse(raw) as Record<
62
62
  string,
63
- { models?: Record<string, { limit?: { context?: number } }> }
63
+ {
64
+ models?: Record<
65
+ string,
66
+ {
67
+ limit?: { context?: number };
68
+ experimental?: { modes?: Record<string, unknown> };
69
+ }
70
+ >;
71
+ }
64
72
  >;
65
73
 
66
74
  for (const [providerId, provider] of Object.entries(data)) {
@@ -69,6 +77,14 @@ function loadModelsDevLimits(): Map<string, number> {
69
77
  const context = model?.limit?.context;
70
78
  if (typeof context === "number" && context > 0) {
71
79
  limits.set(`${providerId}/${modelId}`, context);
80
+ // OpenCode creates derived model IDs from experimental.modes
81
+ // e.g. gpt-5.4 + modes.fast → gpt-5.4-fast (inherits parent limit)
82
+ const modes = model?.experimental?.modes;
83
+ if (modes && typeof modes === "object") {
84
+ for (const mode of Object.keys(modes)) {
85
+ limits.set(`${providerId}/${modelId}-${mode}`, context);
86
+ }
87
+ }
72
88
  }
73
89
  }
74
90
  }
@@ -88,8 +104,11 @@ function loadModelsDevLimits(): Map<string, number> {
88
104
  const configPath = getOpencodeConfigPath();
89
105
  if (configPath && existsSync(configPath)) {
90
106
  let raw = readFileSync(configPath, "utf-8");
91
- // Strip JSONC comments (single-line only sufficient for OpenCode configs)
92
- raw = raw.replace(/\/\/.*$/gm, "");
107
+ // Strip JSONC single-line comments while preserving // inside strings.
108
+ // Match strings first (to skip them), then match comments outside strings.
109
+ raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) =>
110
+ match.startsWith('"') ? match : "",
111
+ );
93
112
  const config = JSON.parse(raw) as {
94
113
  provider?: Record<
95
114
  string,
@@ -40,16 +40,23 @@ export function ensureTuiPluginEntry(): boolean {
40
40
  ? config.plugin.filter((p): p is string => typeof p === "string")
41
41
  : [];
42
42
 
43
- if (plugins.some((p) => p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`))) {
44
- return false; // Already present
43
+ const existingIdx = plugins.findIndex(
44
+ (p) => p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`),
45
+ );
46
+ if (existingIdx >= 0) {
47
+ if (plugins[existingIdx] === PLUGIN_ENTRY) {
48
+ return false; // Already @latest
49
+ }
50
+ // Upgrade pinned version to @latest
51
+ plugins[existingIdx] = PLUGIN_ENTRY;
52
+ } else {
53
+ plugins.push(PLUGIN_ENTRY);
45
54
  }
46
-
47
- plugins.push(PLUGIN_ENTRY);
48
55
  config.plugin = plugins;
49
56
 
50
57
  mkdirSync(dirname(configPath), { recursive: true });
51
58
  writeFileSync(configPath, `${stringify(config, null, 2)}\n`);
52
- log(`[magic-context] added TUI plugin entry to ${configPath}`);
59
+ log(`[magic-context] updated TUI plugin entry in ${configPath}`);
53
60
  return true;
54
61
  } catch (error) {
55
62
  log(