@cortexkit/aft-opencode 0.26.3 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bg-notifications.d.ts +3 -0
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/configure-warnings.d.ts +2 -0
- package/dist/configure-warnings.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +577 -506
- package/dist/notifications.d.ts +21 -0
- package/dist/notifications.d.ts.map +1 -1
- package/dist/shared/last-assistant-model.d.ts +0 -9
- package/dist/shared/last-assistant-model.d.ts.map +1 -1
- package/dist/shared/status.d.ts +20 -0
- package/dist/shared/status.d.ts.map +1 -1
- package/dist/tui.js +113 -12
- package/package.json +7 -7
- package/src/shared/last-assistant-model.ts +23 -2
- package/src/shared/status.ts +43 -0
- package/src/tui/index.tsx +49 -3
- package/src/tui/sidebar.tsx +81 -2
package/src/tui/sidebar.tsx
CHANGED
|
@@ -11,7 +11,7 @@ import type { TuiPluginApi, TuiSlotPlugin, TuiThemeCurrent } from "@opencode-ai/
|
|
|
11
11
|
import { createEffect, createMemo, createSignal, on, onCleanup } from "solid-js";
|
|
12
12
|
|
|
13
13
|
import { AftRpcClient } from "../shared/rpc-client";
|
|
14
|
-
import { type AftStatusSnapshot, coerceAftStatus } from "../shared/status";
|
|
14
|
+
import { type AftStatusSnapshot, coerceAftStatus, type StatusCompression } from "../shared/status";
|
|
15
15
|
|
|
16
16
|
const SINGLE_BORDER = { type: "single" } as any;
|
|
17
17
|
const REFRESH_DEBOUNCE_MS = 200;
|
|
@@ -35,6 +35,46 @@ function formatCount(n: number | null | undefined): string {
|
|
|
35
35
|
return String(n);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/** Tagged rows for the Compression section. Each scope (Session / Project)
|
|
39
|
+
* emits a "scope" header followed by two "stat" rows — Tokens Saved and
|
|
40
|
+
* Compression Ratio — so the renderer can use the same StatRow layout as
|
|
41
|
+
* Search Index / Semantic Index above. Pi's monospace overlay and the
|
|
42
|
+
* OpenCode TUI dialog/sidebar all consume this same shape. */
|
|
43
|
+
export type CompressionRow =
|
|
44
|
+
| { kind: "scope"; label: string }
|
|
45
|
+
| { kind: "stat"; label: string; value: string };
|
|
46
|
+
|
|
47
|
+
function appendScope(
|
|
48
|
+
rows: CompressionRow[],
|
|
49
|
+
label: string,
|
|
50
|
+
scope: {
|
|
51
|
+
events: number;
|
|
52
|
+
original_tokens: number;
|
|
53
|
+
compressed_tokens: number;
|
|
54
|
+
savings_tokens: number;
|
|
55
|
+
},
|
|
56
|
+
): void {
|
|
57
|
+
const savings = scope.savings_tokens;
|
|
58
|
+
const pct = scope.original_tokens > 0 ? Math.round((savings / scope.original_tokens) * 100) : 0;
|
|
59
|
+
rows.push({ kind: "scope", label });
|
|
60
|
+
rows.push({ kind: "stat", label: "Tokens Saved", value: savings.toLocaleString("en-US") });
|
|
61
|
+
rows.push({ kind: "stat", label: "Compression Ratio", value: `${pct}%` });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function formatCompressionSidebarRows(
|
|
65
|
+
compression: StatusCompression | undefined,
|
|
66
|
+
): CompressionRow[] {
|
|
67
|
+
if (!compression || compression.project.events <= 0) return [];
|
|
68
|
+
|
|
69
|
+
const rows: CompressionRow[] = [];
|
|
70
|
+
if (compression.session.events > 0) {
|
|
71
|
+
appendScope(rows, "Session", compression.session);
|
|
72
|
+
}
|
|
73
|
+
appendScope(rows, "Project", compression.project);
|
|
74
|
+
|
|
75
|
+
return rows;
|
|
76
|
+
}
|
|
77
|
+
|
|
38
78
|
// Map index status → (label, theme color name). The label is what we want
|
|
39
79
|
// the user to see; the color encodes severity so the eye lands on warnings.
|
|
40
80
|
function statusDisplay(status: string): { label: string; tone: "ok" | "warn" | "err" | "muted" } {
|
|
@@ -104,7 +144,10 @@ function getClient(directory: string): AftRpcClient {
|
|
|
104
144
|
if (client) return client;
|
|
105
145
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
106
146
|
const dataHome = process.env.XDG_DATA_HOME || `${home}/.local/share`;
|
|
107
|
-
|
|
147
|
+
// v0.27 moved AFT storage to the CortexKit root. Must match the server
|
|
148
|
+
// plugin's `resolveCortexKitStorageRoot()` or the sidebar will poll a
|
|
149
|
+
// stale legacy port file and never connect to the live RPC server.
|
|
150
|
+
const storageDir = `${dataHome}/cortexkit/aft`;
|
|
108
151
|
client = new AftRpcClient(storageDir, directory);
|
|
109
152
|
sidebarClients.set(directory, client);
|
|
110
153
|
return client;
|
|
@@ -225,6 +268,7 @@ const SidebarContent = (props: {
|
|
|
225
268
|
const semanticStatus = () => statusDisplay(s()?.semantic_index?.status ?? "disabled");
|
|
226
269
|
const trigramBytes = () => s()?.disk?.trigram_disk_bytes ?? 0;
|
|
227
270
|
const semanticBytes = () => s()?.disk?.semantic_disk_bytes ?? 0;
|
|
271
|
+
const compressionRows = () => formatCompressionSidebarRows(s()?.compression);
|
|
228
272
|
|
|
229
273
|
// Degraded-mode reason → human-readable hint. Distinct strings per reason
|
|
230
274
|
// because the UX direction is different: "home_root" tells the user to
|
|
@@ -292,6 +336,21 @@ const SidebarContent = (props: {
|
|
|
292
336
|
</box>
|
|
293
337
|
)}
|
|
294
338
|
|
|
339
|
+
{/* Lazy-bridge placeholder. AFT skips spawning the `aft` binary at
|
|
340
|
+
plugin init to keep memory/CPU low on OpenCode Desktop sessions
|
|
341
|
+
that have many projects pinned in the sidebar. The RPC server
|
|
342
|
+
returns a synthetic `cache_role === "not_initialized"` snapshot
|
|
343
|
+
until the first tool call routes through `callBridge()` and warms
|
|
344
|
+
the bridge. Show the explanatory message instead of empty status
|
|
345
|
+
rows so users understand why metrics are blank. */}
|
|
346
|
+
{s()?.cache_role === "not_initialized" && (
|
|
347
|
+
<box marginTop={1} width="100%">
|
|
348
|
+
<text fg={props.theme.textMuted}>
|
|
349
|
+
{s()!.message || "Waiting for first tool call to populate"}
|
|
350
|
+
</text>
|
|
351
|
+
</box>
|
|
352
|
+
)}
|
|
353
|
+
|
|
295
354
|
{/* Search index */}
|
|
296
355
|
<SectionHeader theme={props.theme} title="Search Index" />
|
|
297
356
|
<StatRow
|
|
@@ -342,6 +401,26 @@ const SidebarContent = (props: {
|
|
|
342
401
|
)}
|
|
343
402
|
<StatRow theme={props.theme} label="Disk" value={formatBytes(semanticBytes())} tone="muted" />
|
|
344
403
|
|
|
404
|
+
{/* Compression aggregates. Tabular layout matching Search/Semantic
|
|
405
|
+
Index above: each scope ("Session", "Project") renders as a
|
|
406
|
+
subheader followed by two StatRows (Tokens Saved, Compression
|
|
407
|
+
Ratio). Keeps numbers right-aligned in the value column instead
|
|
408
|
+
of jamming them after the label on the same line. */}
|
|
409
|
+
{compressionRows().length > 0 && (
|
|
410
|
+
<>
|
|
411
|
+
<SectionHeader theme={props.theme} title="Compression" />
|
|
412
|
+
{compressionRows().map((row) =>
|
|
413
|
+
row.kind === "scope" ? (
|
|
414
|
+
<box width="100%">
|
|
415
|
+
<text fg={props.theme.text}>{row.label}</text>
|
|
416
|
+
</box>
|
|
417
|
+
) : (
|
|
418
|
+
<StatRow theme={props.theme} label={row.label} value={row.value} tone="muted" />
|
|
419
|
+
),
|
|
420
|
+
)}
|
|
421
|
+
</>
|
|
422
|
+
)}
|
|
423
|
+
|
|
345
424
|
{/* Surface failures clearly so users know to act (install ONNX,
|
|
346
425
|
fix config, etc.) rather than silently leaving the panel "off". */}
|
|
347
426
|
{s()?.semantic_index?.status === "failed" && s()?.semantic_index?.error && (
|