@cortexkit/opencode-magic-context 0.31.1 → 0.31.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.
@@ -660,6 +660,11 @@ export interface MagicContextConfig {
660
660
  * of deleting them on success. For short-term inspection/data collection;
661
661
  * kept sessions accumulate until manually cleared. Default false. */
662
662
  keep_subagents: boolean;
663
+ /** Pi-only controls for Magic Context's OpenCode-parity todowrite surface. */
664
+ todowrite: {
665
+ enabled: boolean;
666
+ overlay: boolean;
667
+ };
663
668
  /** Content-aware reclaim of tool output that a later call supersedes, added
664
669
  * to the normal age-based auto-drop: superseded todowrite/ctx_reduce/meta
665
670
  * outputs are dropped, and older edits to a file are compressed to a marker
@@ -1077,6 +1082,10 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
1077
1082
  }>>>;
1078
1083
  temporal_awareness: z.ZodDefault<z.ZodBoolean>;
1079
1084
  keep_subagents: z.ZodDefault<z.ZodBoolean>;
1085
+ todowrite: z.ZodDefault<z.ZodObject<{
1086
+ enabled: z.ZodDefault<z.ZodBoolean>;
1087
+ overlay: z.ZodDefault<z.ZodBoolean>;
1088
+ }, z.core.$strip>>;
1080
1089
  smart_drops: z.ZodDefault<z.ZodBoolean>;
1081
1090
  caveman_text_compression: z.ZodDefault<z.ZodObject<{
1082
1091
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -1202,6 +1211,10 @@ export declare const MagicContextConfigSchema: z.ZodPipe<z.ZodObject<{
1202
1211
  };
1203
1212
  temporal_awareness: boolean;
1204
1213
  keep_subagents: boolean;
1214
+ todowrite: {
1215
+ enabled: boolean;
1216
+ overlay: boolean;
1217
+ };
1205
1218
  smart_drops: boolean;
1206
1219
  caveman_text_compression: {
1207
1220
  enabled: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"magic-context.d.ts","sourceRoot":"","sources":["../../../src/config/schema/magic-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"magic-context.d.ts","sourceRoot":"","sources":["../../../src/config/schema/magic-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EACH,mBAAmB,EAEtB,MAAM,oDAAoD,CAAC;AAG5D,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAOvD,eAAO,MAAM,6BAA6B,2TACkR,CAAC;AAC7T,eAAO,MAAM,4BAA4B,SAAU,CAAC;AACpD,eAAO,MAAM,iCAAiC,OAAO,CAAC;AAEtD,eAAO,MAAM,6BAA6B,4BAA4B,CAAC;AAMvE,eAAO,MAAM,aAAa,sCAAsB,CAAC;AACjD,eAAO,MAAM,kBAAkB;;;EAA8B,CAAC;AAC9D,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE;;iEAEiE;AACjE,eAAO,MAAM,qBAAqB;;;;;;;GAEnB,CAAC;AAChB,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AA6CpE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;iBAEhC,CAAC;AAOH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AA+BpE;;wDAEwD;AACxD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCxB,CAAC;AAEN,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAa/B,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAMpB,CAAC;AACd,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC;AAE/E;;;;2CAI2C;AAC3C,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgBrB,CAAC;AACd,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC;AAgEjF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB;8EAC0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACpE,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4BAA4B,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvF;;uGAEmG;IACnG,wBAAwB,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACxF,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yBAAyB,EAAE,MAAM,CAAC;IAClC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE;QACpB,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,uEAAuE;IACvE,MAAM,EAAE;QACJ,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACxB,CAAC;IACF;;;;;;;OAOG;IACH,uBAAuB,EAAE;QACrB,4EAA4E;QAC5E,OAAO,EAAE,OAAO,CAAC;QACjB;;;;;;;WAOG;QACH,eAAe,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;IACF;;2EAEuE;IACvE,kBAAkB,EAAE,OAAO,CAAC;IAC5B;;;0EAGsE;IACtE,cAAc,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,SAAS,EAAE;QACP,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,OAAO,CAAC;KACpB,CAAC;IACF;;;;;;;+BAO2B;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;OAcG;IACH,wBAAwB,EAAE;QACtB,OAAO,EAAE,OAAO,CAAC;QACjB,oEAAoE;QACpE,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,SAAS,EAAE,eAAe,CAAC;IAC3B,MAAM,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC;QACjB,uBAAuB,EAAE,MAAM,CAAC;QAChC,YAAY,EAAE,OAAO,CAAC;QACtB,mCAAmC,EAAE,MAAM,CAAC;QAC5C;;;;;;uCAM+B;QAC/B,WAAW,EAAE;YACT,OAAO,EAAE,OAAO,CAAC;YACjB,qEAAqE;YACrE,eAAe,EAAE,MAAM,CAAC;YACxB,sEAAsE;YACtE,gBAAgB,EAAE,MAAM,CAAC;SAC5B,CAAC;QACF;;;;mCAI2B;QAC3B,mBAAmB,EAAE;YACjB,OAAO,EAAE,OAAO,CAAC;YACjB,8CAA8C;YAC9C,UAAU,EAAE,MAAM,CAAC;YACnB,mEAAmE;YACnE,WAAW,EAAE,MAAM,CAAC;SACvB,CAAC;KACL,CAAC;IACF,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwU/B,CAAC"}
@@ -1,3 +1,14 @@
1
+ interface VerificationPathsExecOptions {
2
+ cwd: string;
3
+ timeout: number;
4
+ maxBuffer: number;
5
+ encoding: BufferEncoding;
6
+ }
7
+ type VerificationPathsExecResult = {
8
+ stdout: string | Buffer;
9
+ stderr: string | Buffer;
10
+ };
11
+ type VerificationPathsExecFile = (file: string, args: readonly string[], options: VerificationPathsExecOptions) => Promise<VerificationPathsExecResult>;
1
12
  export interface NormalizedVerificationFiles {
2
13
  files: string[];
3
14
  warnings: string[];
@@ -29,4 +40,9 @@ export declare function normalizeVerificationFiles(args: {
29
40
  cwd: string;
30
41
  files: readonly string[];
31
42
  }): Promise<NormalizedVerificationFiles>;
43
+ export declare function __setVerificationPathsTestHooks(hooks: {
44
+ execFile?: VerificationPathsExecFile;
45
+ }): void;
46
+ export declare function __resetVerificationPathsForTests(): void;
47
+ export {};
32
48
  //# sourceMappingURL=verification-paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verification-paths.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/verification-paths.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,2BAA2B;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAiCD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAI5E;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIrE;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIrF;AAED,wBAAsB,wBAAwB,CAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAO7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,2BAA2B,CAC7C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CA6BrC;AAuBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKlF;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAmGvC"}
1
+ {"version":3,"file":"verification-paths.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/verification-paths.ts"],"names":[],"mappings":"AAQA,UAAU,4BAA4B;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;CAC5B;AAED,KAAK,2BAA2B,GAAG;IAC/B,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B,CAAC;AAEF,KAAK,yBAAyB,GAAG,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,4BAA4B,KACpC,OAAO,CAAC,2BAA2B,CAAC,CAAC;AAU1C,MAAM,WAAW,2BAA2B;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAiCD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAI5E;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIrE;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIrF;AAED,wBAAsB,wBAAwB,CAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAO7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,2BAA2B,CAC7C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CA6BrC;AAuBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKlF;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAmGvC;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IACnD,QAAQ,CAAC,EAAE,yBAAyB,CAAC;CACxC,GAAG,IAAI,CAKP;AAED,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD"}
package/dist/index.js CHANGED
@@ -15408,6 +15408,10 @@ var init_magic_context = __esm(() => {
15408
15408
  }).describe("Embedding provider configuration"),
15409
15409
  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 start/end date attributes on compartments. 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).'),
15410
15410
  keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
15411
+ todowrite: exports_external.object({
15412
+ 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."),
15413
+ overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
15414
+ }).default({ enabled: true, overlay: true }).describe("Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart."),
15411
15415
  smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
15412
15416
  caveman_text_compression: exports_external.object({
15413
15417
  enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Active for primary sessions when enabled; never for subagents. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
@@ -170078,7 +170082,7 @@ import path6 from "node:path";
170078
170082
  import { promisify } from "node:util";
170079
170083
  async function runGit(cwd, args) {
170080
170084
  try {
170081
- const result = await execFileAsync("git", [...args], {
170085
+ const result = await execFileForVerificationPaths("git", args, {
170082
170086
  cwd,
170083
170087
  timeout: GIT_TIMEOUT_MS2,
170084
170088
  maxBuffer: 16 * 1024 * 1024,
@@ -170258,9 +170262,10 @@ async function normalizeVerificationFiles(args) {
170258
170262
  gitRoot
170259
170263
  };
170260
170264
  }
170261
- var execFileAsync, GIT_TIMEOUT_MS2 = 1e4;
170265
+ var execFileAsync, GIT_TIMEOUT_MS2 = 1e4, defaultExecFileForVerificationPaths = async (file2, args, options) => await execFileAsync(file2, [...args], options), execFileForVerificationPaths;
170262
170266
  var init_verification_paths = __esm(() => {
170263
170267
  execFileAsync = promisify(execFile);
170268
+ execFileForVerificationPaths = defaultExecFileForVerificationPaths;
170264
170269
  });
170265
170270
 
170266
170271
  // src/features/magic-context/memory/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-magic-context",
3
- "version": "0.31.1",
3
+ "version": "0.31.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",
@@ -25,11 +25,13 @@
25
25
  "files": [
26
26
  "dist",
27
27
  "src/tui",
28
+ "src/tui-compiled",
28
29
  "src/shared",
29
30
  "README.md"
30
31
  ],
31
32
  "scripts": {
32
33
  "build": "bun build src/index.ts --outdir dist --target node --format esm --external @opencode-ai/plugin --external @huggingface/transformers --external onnxruntime-web --external bun:sqlite --external node:sqlite && tsc --emitDeclarationOnly",
34
+ "build:tui": "bun scripts/build-tui.ts",
33
35
  "typecheck": "tsc --noEmit && tsc -p tsconfig.scripts.json",
34
36
  "test": "bun test",
35
37
  "lint": "biome check .",
@@ -37,27 +39,27 @@
37
39
  "format": "biome format --write .",
38
40
  "format:check": "biome format .",
39
41
  "clean": "rm -rf dist",
40
- "prepublishOnly": "bun run build"
42
+ "prepublishOnly": "bun run build && bun run build:tui"
41
43
  },
42
44
  "dependencies": {
43
45
  "@huggingface/transformers": "^4.1.0",
44
46
  "@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
45
47
  "@opencode-ai/plugin": "^1.17.11",
46
48
  "@opencode-ai/sdk": "^1.17.11",
49
+ "@opentui/core": "^0.4.2",
50
+ "@opentui/solid": "^0.4.2",
47
51
  "ai-tokenizer": "^1.0.6",
48
52
  "comment-json": "^5.0.0",
49
53
  "quickjs-emscripten": "^0.32.0",
54
+ "solid-js": "1.9.12",
50
55
  "zod": "^4.1.8"
51
56
  },
52
57
  "devDependencies": {
53
58
  "@biomejs/biome": "^2.5.1",
54
- "@opentui/core": "0.4.3",
55
- "@opentui/solid": "0.4.3",
56
59
  "@types/better-sqlite3": "^7.6.13",
57
60
  "@types/bun": "^1.3.10",
58
61
  "@types/node": "^22.20.0",
59
62
  "bun-types": "^1.3.10",
60
- "solid-js": "1.9.12",
61
63
  "typescript": "^5.8.0"
62
64
  },
63
65
  "exports": {
@@ -67,7 +69,7 @@
67
69
  },
68
70
  "./tui": {
69
71
  "types": "./src/tui/index.tsx",
70
- "import": "./src/tui/index.tsx"
72
+ "import": "./src/tui/entry.mjs"
71
73
  }
72
74
  },
73
75
  "oc-plugin": [
@@ -75,20 +77,6 @@
75
77
  "tui"
76
78
  ],
77
79
  "peerDependencies": {
78
- "@opencode-ai/plugin": ">=1.15.0",
79
- "@opentui/core": ">=0.3.4 <0.5",
80
- "@opentui/solid": ">=0.3.4 <0.5",
81
- "solid-js": ">=1.9.0 <2"
82
- },
83
- "peerDependenciesMeta": {
84
- "@opentui/core": {
85
- "optional": true
86
- },
87
- "@opentui/solid": {
88
- "optional": true
89
- },
90
- "solid-js": {
91
- "optional": true
92
- }
80
+ "@opencode-ai/plugin": ">=1.15.0"
93
81
  }
94
82
  }
@@ -0,0 +1,16 @@
1
+ // Prefer the host OpenTUI runtime registry when it exists. OpenTUI 0.4.x
2
+ // registers these virtual modules process-wide, which lets the precompiled TUI
3
+ // use the host's single Solid/OpenTUI runtime even when this package is loaded
4
+ // from an npm cache under node_modules.
5
+ let mod;
6
+ try {
7
+ await import("opentui:runtime-module:" + encodeURIComponent("@opentui/solid"));
8
+ mod = await import("../tui-compiled/index.tsx");
9
+ } catch {
10
+ // Older hosts and bare Bun do not provide the virtual registry. Falling back
11
+ // to the raw TSX entry keeps development checkouts and OpenTUI 0.3.x hosts
12
+ // working where the Solid transform still applies to this source path.
13
+ mod = await import("./index.tsx");
14
+ }
15
+
16
+ export default mod.default;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Pick the text color for the sidebar header badge (a bold label drawn on a
3
+ * `theme.accent` background).
4
+ *
5
+ * Primary rule (matches AFT's sidebar by construction): paint the theme's own
6
+ * `background` color as the label, the inverse-of-panel look. Because it is a
7
+ * fixed theme token rather than an accent-derived computation, MC's badge and
8
+ * AFT's badge agree on EVERY accent automatically, so the same theme can never
9
+ * make one badge black and the other white (issue #198).
10
+ *
11
+ * Fallback rule (the reason a luminance pick exists at all): `theme.background`
12
+ * can be unusable as a label color in two degenerate cases, where it would
13
+ * render the label invisible on the accent:
14
+ * 1. Transparent background. Themes that respect terminal transparency set
15
+ * `background: "none"`, which resolves to `RGBA(0,0,0,0)`; drawing it as
16
+ * text renders fully transparent and the label disappears (issue #186).
17
+ * 2. Background ~= accent. If the theme's background and accent are nearly the
18
+ * same color, background-on-accent text has no contrast.
19
+ * In either case we fall back to a black/white pick that is guaranteed visible
20
+ * on the always-opaque accent.
21
+ *
22
+ * `RGBA` channels from @opentui/core are normalized 0..1 floats (alpha included).
23
+ * We accept the minimal `{ r, g, b, a? }` shape so this stays a pure, trivially
24
+ * testable function independent of the native color class, and we return the
25
+ * passed-in `background` object unchanged on the primary path so it stays the
26
+ * exact same theme token AFT uses.
27
+ */
28
+
29
+ type Color = { r: number; g: number; b: number; a?: number };
30
+
31
+ // Below this alpha the theme background is too transparent to read as a label on
32
+ // the accent (issue #186: background:"none" resolves to alpha 0).
33
+ const MIN_OPAQUE_ALPHA = 0.5;
34
+
35
+ // If the theme background and accent are within this per-channel distance they
36
+ // are effectively the same color, so background-on-accent text is unreadable.
37
+ const MIN_CHANNEL_DISTANCE = 0.06;
38
+
39
+ // Luminance midpoint for the fallback pick: accents below this keep white text,
40
+ // accents at/above it (light/pastel/near-white) get black. White-biased relative
41
+ // to the strict equal-contrast crossover (~0.179) so saturated mid-tone accents
42
+ // stay white. Only consulted on the degenerate fallback path.
43
+ const LIGHT_ACCENT_LUMINANCE = 0.5;
44
+
45
+ function srgbChannelToLinear(c: number): number {
46
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
47
+ }
48
+
49
+ function relativeLuminance(bg: Color): number {
50
+ return (
51
+ 0.2126 * srgbChannelToLinear(bg.r) +
52
+ 0.7152 * srgbChannelToLinear(bg.g) +
53
+ 0.0722 * srgbChannelToLinear(bg.b)
54
+ );
55
+ }
56
+
57
+ function nearlyEqual(a: Color, b: Color): boolean {
58
+ return (
59
+ Math.abs(a.r - b.r) < MIN_CHANNEL_DISTANCE &&
60
+ Math.abs(a.g - b.g) < MIN_CHANNEL_DISTANCE &&
61
+ Math.abs(a.b - b.b) < MIN_CHANNEL_DISTANCE
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Pure black/white pick by accent luminance. Used as the badge fallback and kept
67
+ * exported for callers that only have the accent.
68
+ */
69
+ export function readableTextColorOn(bg: Color): string {
70
+ return relativeLuminance(bg) < LIGHT_ACCENT_LUMINANCE ? "#ffffff" : "#000000";
71
+ }
72
+
73
+ /**
74
+ * Badge label color on the accent: the theme background (AFT parity) when it is
75
+ * usable, else a guaranteed-visible black/white fallback. Returns the passed-in
76
+ * `background` reference unchanged on the primary path.
77
+ */
78
+ export function badgeTextColor<T extends Color>(accent: T, background: T): T | string {
79
+ const alpha = background.a ?? 1;
80
+ if (alpha >= MIN_OPAQUE_ALPHA && !nearlyEqual(accent, background)) {
81
+ return background;
82
+ }
83
+ return readableTextColorOn(accent);
84
+ }
@@ -0,0 +1,353 @@
1
+ /**
2
+ * TUI data layer — pure RPC client, no direct SQLite access.
3
+ * All data is fetched from the server plugin via HTTP RPC.
4
+ */
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import { MagicContextRpcClient } from "../../shared/rpc-client";
8
+ import type { EmbedDetail, SidebarSnapshot, StatusDetail } from "../../shared/rpc-types";
9
+
10
+ export type { EmbedDetail, SidebarSnapshot, StatusDetail };
11
+
12
+ let rpcClient: MagicContextRpcClient | null = null;
13
+ let rpcGeneration = 0;
14
+
15
+ function getStorageDir(): string {
16
+ // Plugin v0.16+ uses the shared cortexkit/magic-context path so OpenCode
17
+ // and Pi can share state. The TUI just needs to point its RPC client at
18
+ // the same storage directory the server plugin uses for the lock-file
19
+ // discovery convention.
20
+ const dataDir = process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
21
+ return path.join(dataDir, "cortexkit", "magic-context");
22
+ }
23
+
24
+ /** Initialize the RPC client. Call once on TUI startup. */
25
+ export function initRpcClient(directory: string): void {
26
+ const storageDir = getStorageDir();
27
+ // Bump the generation before replacing the client so late notification
28
+ // responses from a disposed client are ignored (the WS socket observes the
29
+ // new generation and abandons its in-flight connect).
30
+ rpcGeneration += 1;
31
+ rpcClient = new MagicContextRpcClient(storageDir, directory);
32
+ }
33
+
34
+ export function getRpcGeneration(): number {
35
+ return rpcGeneration;
36
+ }
37
+
38
+ /** The live RPC client (for the WS notification socket's endpoint discovery).
39
+ * Null before init / after close. */
40
+ export function getRpcClient(): MagicContextRpcClient | null {
41
+ return rpcClient;
42
+ }
43
+
44
+ /** Clean up the RPC client. */
45
+ export function closeRpc(): void {
46
+ // Closing invalidates any already-issued RPC calls; their callbacks must
47
+ // observe the new generation and abandon (the WS socket checks it too).
48
+ rpcGeneration += 1;
49
+ rpcClient?.reset();
50
+ rpcClient = null;
51
+ }
52
+
53
+ const EMPTY_SNAPSHOT: SidebarSnapshot = {
54
+ sessionId: "",
55
+ usagePercentage: 0,
56
+ inputTokens: 0,
57
+ contextLimit: 0,
58
+ systemPromptTokens: 0,
59
+ compartmentCount: 0,
60
+ memoryCount: 0,
61
+ memoryBlockCount: 0,
62
+ pendingOpsCount: 0,
63
+ historianRunning: false,
64
+ compartmentInProgress: false,
65
+ sessionNoteCount: 0,
66
+ readySmartNoteCount: 0,
67
+ cacheTtl: "5m",
68
+ lastDreamerRunAt: null,
69
+ projectIdentity: null,
70
+ compartmentTokens: 0,
71
+ factTokens: 0,
72
+ memoryTokens: 0,
73
+ docsTokens: 0,
74
+ profileTokens: 0,
75
+ conversationTokens: 0,
76
+ toolCallTokens: 0,
77
+ toolDefinitionTokens: 0,
78
+ executeThreshold: 65,
79
+ newWorkTokens: null,
80
+ totalInputTokens: null,
81
+ };
82
+
83
+ /**
84
+ * Per-session client-side sticky cache. Mirrors the server-side cache in
85
+ * `sidebar-snapshot-cache.ts` but covers the cases the server can't:
86
+ * - RPC call fails entirely (timeout, abort, parse error) → server is never reached
87
+ * - RPC server is not yet up (port file missing, retries exhausted)
88
+ * - Server returns an error envelope
89
+ *
90
+ * In all three cases the breakdown bar would otherwise disappear until the
91
+ * next successful refresh. With this cache, the client returns the most
92
+ * recent good snapshot for the same session so the UI stays stable through
93
+ * transient RPC blips. 5-minute staleness ceiling keeps it from showing
94
+ * obviously old data after long disconnects.
95
+ */
96
+ interface CachedSnapshot {
97
+ snapshot: SidebarSnapshot;
98
+ cachedAt: number;
99
+ }
100
+ const STICKY_TTL_MS = 5 * 60 * 1000;
101
+ const STICKY_MAX_ENTRIES = 100;
102
+ const stickySidebarCache = new Map<string, CachedSnapshot>();
103
+
104
+ function rememberSidebarSnapshot(snapshot: SidebarSnapshot): void {
105
+ if (!snapshot.sessionId || snapshot.inputTokens <= 0) return;
106
+ // LRU-style bound: drop the oldest entry once we hit the cap. With a
107
+ // 5-min TTL most stale entries time out naturally; this just prevents
108
+ // unbounded growth across many session switches in a long TUI session.
109
+ if (
110
+ stickySidebarCache.size >= STICKY_MAX_ENTRIES &&
111
+ !stickySidebarCache.has(snapshot.sessionId)
112
+ ) {
113
+ const firstKey = stickySidebarCache.keys().next().value;
114
+ if (firstKey) stickySidebarCache.delete(firstKey);
115
+ }
116
+ stickySidebarCache.set(snapshot.sessionId, {
117
+ snapshot,
118
+ cachedAt: Date.now(),
119
+ });
120
+ }
121
+
122
+ function recallSidebarSnapshot(sessionId: string, fallback: SidebarSnapshot): SidebarSnapshot {
123
+ const cached = stickySidebarCache.get(sessionId);
124
+ if (!cached) return fallback;
125
+ if (Date.now() - cached.cachedAt > STICKY_TTL_MS) {
126
+ stickySidebarCache.delete(sessionId);
127
+ return fallback;
128
+ }
129
+ if (!hasInFlightEvidence(fallback)) {
130
+ stickySidebarCache.delete(sessionId);
131
+ return fallback;
132
+ }
133
+ return cached.snapshot;
134
+ }
135
+
136
+ function hasInFlightEvidence(snapshot: SidebarSnapshot): boolean {
137
+ return (
138
+ snapshot.compartmentInProgress || snapshot.historianRunning || snapshot.pendingOpsCount > 0
139
+ );
140
+ }
141
+
142
+ /** Fetch sidebar snapshot from the server via RPC. */
143
+ export async function loadSidebarSnapshot(
144
+ sessionId: string,
145
+ directory: string,
146
+ ): Promise<SidebarSnapshot> {
147
+ const empty: SidebarSnapshot = { ...EMPTY_SNAPSHOT, sessionId };
148
+ if (!rpcClient) return recallSidebarSnapshot(sessionId, empty);
149
+ try {
150
+ const result = await rpcClient.call<SidebarSnapshot>("sidebar-snapshot", {
151
+ sessionId,
152
+ directory,
153
+ });
154
+ if ((result as unknown as Record<string, unknown>).error) {
155
+ return recallSidebarSnapshot(sessionId, empty);
156
+ }
157
+ // Trust successful server responses. The server has its own sticky
158
+ // sidebar cache (`sidebar-snapshot-cache.ts`) that handles transient
159
+ // zero-token windows by hybriding cached breakdown values into a
160
+ // fresh snapshot, AND clears that cache on `session.deleted`. If the
161
+ // server reaches us with `inputTokens === 0`, that's its considered
162
+ // answer — typically because the session was deleted, reverted, or
163
+ // is brand-new with no responses yet.
164
+ //
165
+ // Falling back to the client cache here would resurrect old token
166
+ // data for a deleted session (the client never sees `session.deleted`
167
+ // events, so its cache TTL is the only expiry). Sticky behavior is
168
+ // owned exclusively by the server side.
169
+ rememberSidebarSnapshot(result);
170
+ return result;
171
+ } catch {
172
+ return recallSidebarSnapshot(sessionId, empty);
173
+ }
174
+ }
175
+
176
+ /** Fetch full status detail from the server via RPC. */
177
+ export async function loadStatusDetail(
178
+ sessionId: string,
179
+ directory: string,
180
+ modelKey?: string,
181
+ ): Promise<StatusDetail> {
182
+ const emptyDetail: StatusDetail = {
183
+ ...EMPTY_SNAPSHOT,
184
+ sessionId,
185
+ tagCounter: 0,
186
+ activeTags: 0,
187
+ droppedTags: 0,
188
+ totalTags: 0,
189
+ activeBytes: 0,
190
+ lastResponseTime: 0,
191
+ lastNudgeTokens: 0,
192
+ lastTransformError: null,
193
+ isSubagent: false,
194
+ pendingOps: [],
195
+ contextLimit: 0,
196
+ cacheTtlMs: 0,
197
+ cacheRemainingMs: 0,
198
+ cacheExpired: false,
199
+ executeThreshold: 65,
200
+ executeThresholdMode: "percentage",
201
+ protectedTagCount: 20,
202
+ historyBudgetPercentage: 0.15,
203
+ historyBlockTokens: 0,
204
+ compressionBudget: null,
205
+ compressionUsage: null,
206
+ toastDurationMs: 5000,
207
+ };
208
+
209
+ if (!rpcClient) return emptyDetail;
210
+ try {
211
+ const result = await rpcClient.call<StatusDetail>("status-detail", {
212
+ sessionId,
213
+ directory,
214
+ modelKey,
215
+ });
216
+ if ((result as unknown as Record<string, unknown>).error) {
217
+ return emptyDetail;
218
+ }
219
+ return result;
220
+ } catch {
221
+ return emptyDetail;
222
+ }
223
+ }
224
+
225
+ const EMPTY_EMBED_DETAIL: EmbedDetail = {
226
+ enabled: false,
227
+ model: "off",
228
+ provider: "off",
229
+ session: { embedded: 0, total: 0 },
230
+ memories: { embedded: 0, total: 0 },
231
+ commits: { embedded: 0, total: 0, gitEnabled: false },
232
+ statusText: "Embedding is off (no provider configured).",
233
+ };
234
+
235
+ /** Fetch embedding coverage status for `/ctx-embed` via RPC. */
236
+ export async function loadEmbedDetail(sessionId: string, directory: string): Promise<EmbedDetail> {
237
+ if (!rpcClient) return EMPTY_EMBED_DETAIL;
238
+ try {
239
+ const result = await rpcClient.call<EmbedDetail>("embed-detail", {
240
+ sessionId,
241
+ directory,
242
+ });
243
+ if ((result as unknown as Record<string, unknown>).error) {
244
+ return EMPTY_EMBED_DETAIL;
245
+ }
246
+ return result;
247
+ } catch {
248
+ return EMPTY_EMBED_DETAIL;
249
+ }
250
+ }
251
+
252
+ /** Get compartment count via RPC. */
253
+ export async function getCompartmentCount(sessionId: string): Promise<number> {
254
+ if (!rpcClient) return 0;
255
+ try {
256
+ const result = await rpcClient.call<{ count: number }>("compartment-count", { sessionId });
257
+ return result.count ?? 0;
258
+ } catch {
259
+ return 0;
260
+ }
261
+ }
262
+
263
+ /** Send recomp request to server via RPC. */
264
+ export async function requestRecomp(sessionId: string): Promise<boolean> {
265
+ if (!rpcClient) return false;
266
+ try {
267
+ const result = await rpcClient.call<{ ok: boolean }>("recomp", { sessionId });
268
+ return result.ok ?? false;
269
+ } catch {
270
+ return false;
271
+ }
272
+ }
273
+
274
+ /** Run `/ctx-session-upgrade` for the session (full recomp + once-per-project
275
+ * memory migration). Fired from the upgrade dialog's "Run upgrade now" action. */
276
+ export async function requestUpgrade(sessionId: string): Promise<boolean> {
277
+ if (!rpcClient) return false;
278
+ try {
279
+ const result = await rpcClient.call<{ ok: boolean }>("upgrade", { sessionId });
280
+ return result.ok ?? false;
281
+ } catch {
282
+ return false;
283
+ }
284
+ }
285
+
286
+ /** Mark the upgrade reminder dismissed (the user made an explicit Confirm/Cancel
287
+ * choice), setting the durable stamp so the FRESH dialog won't re-show. Resume
288
+ * prompts are staging-driven and unaffected. */
289
+ export async function dismissUpgradeReminder(sessionId: string): Promise<boolean> {
290
+ if (!rpcClient) return false;
291
+ try {
292
+ const result = await rpcClient.call<{ ok: boolean }>("dismiss-upgrade-reminder", {
293
+ sessionId,
294
+ });
295
+ return result.ok ?? false;
296
+ } catch {
297
+ return false;
298
+ }
299
+ }
300
+
301
+ /** Resolve global toast duration from server config via RPC. */
302
+ export async function loadToastDurationMs(): Promise<number> {
303
+ if (!rpcClient) return 5000;
304
+ try {
305
+ const result = await rpcClient.call<{ toastDurationMs?: number }>("toast-duration", {});
306
+ return typeof result.toastDurationMs === "number" ? result.toastDurationMs : 5000;
307
+ } catch {
308
+ return 5000;
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Fetch the current startup announcement from the server, if any.
314
+ * Returns `{show: false}` when there's nothing to announce or when the
315
+ * configured ANNOUNCEMENT_VERSION has already been dismissed.
316
+ */
317
+ export interface AnnouncementResponse {
318
+ show: boolean;
319
+ version?: string;
320
+ features?: string[];
321
+ footer?: string;
322
+ }
323
+
324
+ export async function getAnnouncement(): Promise<AnnouncementResponse> {
325
+ if (!rpcClient) return { show: false };
326
+ try {
327
+ const result = await rpcClient.call<{
328
+ show?: boolean;
329
+ version?: string;
330
+ features?: string[];
331
+ footer?: string;
332
+ }>("get-announcement", {});
333
+ return {
334
+ show: result.show === true,
335
+ version: result.version,
336
+ features: Array.isArray(result.features) ? result.features : undefined,
337
+ footer: typeof result.footer === "string" ? result.footer : undefined,
338
+ };
339
+ } catch {
340
+ return { show: false };
341
+ }
342
+ }
343
+
344
+ /** Mark the current ANNOUNCEMENT_VERSION as dismissed on the server. */
345
+ export async function markAnnounced(): Promise<boolean> {
346
+ if (!rpcClient) return false;
347
+ try {
348
+ const result = await rpcClient.call<{ ok?: boolean }>("mark-announced", {});
349
+ return result.ok === true;
350
+ } catch {
351
+ return false;
352
+ }
353
+ }