@cortexkit/opencode-magic-context 0.31.2 → 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.
- package/dist/config/schema/magic-context.d.ts +13 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/memory/verification-paths.d.ts +16 -0
- package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/package.json +5 -3
- package/src/tui/entry.mjs +16 -0
- package/src/tui-compiled/badge-contrast.ts +84 -0
- package/src/tui-compiled/data/context-db.ts +353 -0
- package/src/tui-compiled/data/notification-socket.ts +229 -0
- package/src/tui-compiled/index.tsx +1204 -0
- package/src/tui-compiled/slots/sidebar-content.tsx +1052 -0
- package/src/tui-compiled/types/opencode-plugin-tui.d.ts +232 -0
|
@@ -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":"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"}
|
|
@@ -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
|
|
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.
|
|
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,7 +39,7 @@
|
|
|
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",
|
|
@@ -67,7 +69,7 @@
|
|
|
67
69
|
},
|
|
68
70
|
"./tui": {
|
|
69
71
|
"types": "./src/tui/index.tsx",
|
|
70
|
-
"import": "./src/tui/
|
|
72
|
+
"import": "./src/tui/entry.mjs"
|
|
71
73
|
}
|
|
72
74
|
},
|
|
73
75
|
"oc-plugin": [
|
|
@@ -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
|
+
}
|