@cortexkit/aft-opencode 0.26.4 → 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 +571 -466
- package/dist/notifications.d.ts +2 -0
- package/dist/notifications.d.ts.map +1 -1
- package/dist/shared/status.d.ts +12 -0
- package/dist/shared/status.d.ts.map +1 -1
- package/dist/tui.js +93 -10
- package/package.json +7 -7
- package/src/shared/status.ts +34 -0
- package/src/tui/index.tsx +35 -2
- package/src/tui/sidebar.tsx +66 -2
package/dist/notifications.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* Messages are identified by markers and cleaned up on subsequent startups
|
|
14
14
|
* when no longer relevant (Desktop only — TUI toasts are inherently transient).
|
|
15
15
|
*/
|
|
16
|
+
import type { BinaryBridge } from "@cortexkit/aft-bridge";
|
|
16
17
|
type SdkMessage = {
|
|
17
18
|
info?: {
|
|
18
19
|
id?: string;
|
|
@@ -50,6 +51,7 @@ export interface ConfigureWarning {
|
|
|
50
51
|
export interface ConfigureWarningOptions {
|
|
51
52
|
client: unknown;
|
|
52
53
|
sessionId: string;
|
|
54
|
+
bridge: Pick<BinaryBridge, "send">;
|
|
53
55
|
storageDir: string;
|
|
54
56
|
pluginVersion: string;
|
|
55
57
|
projectRoot?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAmI1D,KAAK,UAAU,GAAG;IAChB,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpE,CAAC;AAyBF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,CAAC,CAqBvB;AAqED,MAAM,WAAW,mBAAmB;IAClC,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,yBAAyB,GAAG,uBAAuB,GAAG,oBAAoB,CAAC;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3F;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C1F;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CA2Cf;AA4ED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C9E"}
|
package/dist/shared/status.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
export interface StatusCompressionAggregate {
|
|
2
|
+
events: number;
|
|
3
|
+
original_tokens: number;
|
|
4
|
+
compressed_tokens: number;
|
|
5
|
+
savings_tokens: number;
|
|
6
|
+
}
|
|
7
|
+
export interface StatusCompression {
|
|
8
|
+
project: StatusCompressionAggregate;
|
|
9
|
+
session: StatusCompressionAggregate;
|
|
10
|
+
}
|
|
1
11
|
export interface AftStatusSnapshot {
|
|
2
12
|
version: string;
|
|
3
13
|
project_root: string | null;
|
|
@@ -57,6 +67,8 @@ export interface AftStatusSnapshot {
|
|
|
57
67
|
tracked_files: number;
|
|
58
68
|
checkpoints: number;
|
|
59
69
|
};
|
|
70
|
+
/** Compression aggregate passthrough; rendering is added separately. */
|
|
71
|
+
compression?: StatusCompression;
|
|
60
72
|
/**
|
|
61
73
|
* Human-readable explanation for a synthetic snapshot (e.g.
|
|
62
74
|
* `cache_role === "not_initialized"`). When the plugin returns a placeholder
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE;QACR,cAAc,EAAE,OAAO,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,wBAAwB,EAAE,OAAO,CAAC;QAClC,YAAY,EAAE,OAAO,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,YAAY,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IACF,cAAc,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC;IACF,IAAI,EAAE;QACJ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iEAAiE;IACjE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,0BAA0B,CAAC;IACpC,OAAO,EAAE,0BAA0B,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE;QACR,cAAc,EAAE,OAAO,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,wBAAwB,EAAE,OAAO,CAAC;QAClC,YAAY,EAAE,OAAO,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,YAAY,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IACF,cAAc,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC;IACF,IAAI,EAAE;QACJ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iEAAiE;IACjE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,wEAAwE;IACxE,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAqDD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,CAmEpF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAuE3E;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CA0EtE"}
|
package/dist/tui.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createMemo as createMemo2, createSignal as createSignal2, onCleanup as
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@cortexkit/aft-opencode",
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.27.0",
|
|
8
8
|
type: "module",
|
|
9
9
|
description: "OpenCode plugin for Agent File Tools (AFT) \u2014 tree-sitter and lsp powered code analysis",
|
|
10
10
|
main: "dist/index.js",
|
|
@@ -32,7 +32,7 @@ var package_default = {
|
|
|
32
32
|
},
|
|
33
33
|
dependencies: {
|
|
34
34
|
"@clack/prompts": "^1.2.0",
|
|
35
|
-
"@cortexkit/aft-bridge": "0.
|
|
35
|
+
"@cortexkit/aft-bridge": "0.27.0",
|
|
36
36
|
"@opencode-ai/plugin": "^1.15.5",
|
|
37
37
|
"@opencode-ai/sdk": "^1.15.5",
|
|
38
38
|
"comment-json": "^4.6.2",
|
|
@@ -40,11 +40,11 @@ var package_default = {
|
|
|
40
40
|
zod: "^4.1.8"
|
|
41
41
|
},
|
|
42
42
|
optionalDependencies: {
|
|
43
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
44
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
45
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
46
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
47
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
43
|
+
"@cortexkit/aft-darwin-arm64": "0.27.0",
|
|
44
|
+
"@cortexkit/aft-darwin-x64": "0.27.0",
|
|
45
|
+
"@cortexkit/aft-linux-arm64": "0.27.0",
|
|
46
|
+
"@cortexkit/aft-linux-x64": "0.27.0",
|
|
47
|
+
"@cortexkit/aft-win32-x64": "0.27.0"
|
|
48
48
|
},
|
|
49
49
|
devDependencies: {
|
|
50
50
|
"@types/node": "^22.0.0",
|
|
@@ -304,6 +304,24 @@ function readNumber(value, fallback = 0) {
|
|
|
304
304
|
function readOptionalNumber(value) {
|
|
305
305
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
306
306
|
}
|
|
307
|
+
function readCompressionAggregate(value) {
|
|
308
|
+
const aggregate = asRecord(value);
|
|
309
|
+
return {
|
|
310
|
+
events: readNumber(aggregate.events),
|
|
311
|
+
original_tokens: readNumber(aggregate.original_tokens),
|
|
312
|
+
compressed_tokens: readNumber(aggregate.compressed_tokens),
|
|
313
|
+
savings_tokens: readNumber(aggregate.savings_tokens)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function readCompression(value) {
|
|
317
|
+
if (typeof value !== "object" || value === null)
|
|
318
|
+
return;
|
|
319
|
+
const compression = asRecord(value);
|
|
320
|
+
return {
|
|
321
|
+
project: readCompressionAggregate(compression.project),
|
|
322
|
+
session: readCompressionAggregate(compression.session)
|
|
323
|
+
};
|
|
324
|
+
}
|
|
307
325
|
function formatBytes(bytes) {
|
|
308
326
|
if (!Number.isFinite(bytes) || bytes <= 0)
|
|
309
327
|
return "0 B";
|
|
@@ -376,13 +394,14 @@ function coerceAftStatus(response) {
|
|
|
376
394
|
tracked_files: readNumber(session.tracked_files),
|
|
377
395
|
checkpoints: readNumber(session.checkpoints)
|
|
378
396
|
},
|
|
397
|
+
compression: readCompression(response.compression),
|
|
379
398
|
message: readString(response.message, "")
|
|
380
399
|
};
|
|
381
400
|
}
|
|
382
401
|
|
|
383
402
|
// src/tui/sidebar.tsx
|
|
384
403
|
import { createEffect, createMemo, createSignal, on, onCleanup } from "solid-js";
|
|
385
|
-
import { jsxDEV } from "@opentui/solid/jsx-dev-runtime";
|
|
404
|
+
import { jsxDEV, Fragment } from "@opentui/solid/jsx-dev-runtime";
|
|
386
405
|
var SINGLE_BORDER = { type: "single" };
|
|
387
406
|
var REFRESH_DEBOUNCE_MS = 200;
|
|
388
407
|
var POLL_INTERVAL_MS = 1500;
|
|
@@ -406,6 +425,23 @@ function formatCount(n) {
|
|
|
406
425
|
return `${Math.round(n / 1000)}K`;
|
|
407
426
|
return String(n);
|
|
408
427
|
}
|
|
428
|
+
function appendScope(rows, label, scope) {
|
|
429
|
+
const savings = scope.savings_tokens;
|
|
430
|
+
const pct = scope.original_tokens > 0 ? Math.round(savings / scope.original_tokens * 100) : 0;
|
|
431
|
+
rows.push({ kind: "scope", label });
|
|
432
|
+
rows.push({ kind: "stat", label: "Tokens Saved", value: savings.toLocaleString("en-US") });
|
|
433
|
+
rows.push({ kind: "stat", label: "Compression Ratio", value: `${pct}%` });
|
|
434
|
+
}
|
|
435
|
+
function formatCompressionSidebarRows(compression) {
|
|
436
|
+
if (!compression || compression.project.events <= 0)
|
|
437
|
+
return [];
|
|
438
|
+
const rows = [];
|
|
439
|
+
if (compression.session.events > 0) {
|
|
440
|
+
appendScope(rows, "Session", compression.session);
|
|
441
|
+
}
|
|
442
|
+
appendScope(rows, "Project", compression.project);
|
|
443
|
+
return rows;
|
|
444
|
+
}
|
|
409
445
|
function statusDisplay(status) {
|
|
410
446
|
switch (status) {
|
|
411
447
|
case "ready":
|
|
@@ -474,7 +510,7 @@ function getClient(directory) {
|
|
|
474
510
|
return client;
|
|
475
511
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
476
512
|
const dataHome = process.env.XDG_DATA_HOME || `${home}/.local/share`;
|
|
477
|
-
const storageDir = `${dataHome}/
|
|
513
|
+
const storageDir = `${dataHome}/cortexkit/aft`;
|
|
478
514
|
client = new AftRpcClient(storageDir, directory);
|
|
479
515
|
sidebarClients.set(directory, client);
|
|
480
516
|
return client;
|
|
@@ -562,6 +598,7 @@ var SidebarContent = (props) => {
|
|
|
562
598
|
const semanticStatus = () => statusDisplay(s()?.semantic_index?.status ?? "disabled");
|
|
563
599
|
const trigramBytes = () => s()?.disk?.trigram_disk_bytes ?? 0;
|
|
564
600
|
const semanticBytes = () => s()?.disk?.semantic_disk_bytes ?? 0;
|
|
601
|
+
const compressionRows = () => formatCompressionSidebarRows(s()?.compression);
|
|
565
602
|
const degradedReasonLabel = (reason) => {
|
|
566
603
|
if (reason === "home_root") {
|
|
567
604
|
return "project root is your home directory";
|
|
@@ -703,6 +740,26 @@ var SidebarContent = (props) => {
|
|
|
703
740
|
value: formatBytes2(semanticBytes()),
|
|
704
741
|
tone: "muted"
|
|
705
742
|
}, undefined, false, undefined, this),
|
|
743
|
+
compressionRows().length > 0 && /* @__PURE__ */ jsxDEV(Fragment, {
|
|
744
|
+
children: [
|
|
745
|
+
/* @__PURE__ */ jsxDEV(SectionHeader, {
|
|
746
|
+
theme: props.theme,
|
|
747
|
+
title: "Compression"
|
|
748
|
+
}, undefined, false, undefined, this),
|
|
749
|
+
compressionRows().map((row) => row.kind === "scope" ? /* @__PURE__ */ jsxDEV("box", {
|
|
750
|
+
width: "100%",
|
|
751
|
+
children: /* @__PURE__ */ jsxDEV("text", {
|
|
752
|
+
fg: props.theme.text,
|
|
753
|
+
children: row.label
|
|
754
|
+
}, undefined, false, undefined, this)
|
|
755
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(StatRow, {
|
|
756
|
+
theme: props.theme,
|
|
757
|
+
label: row.label,
|
|
758
|
+
value: row.value,
|
|
759
|
+
tone: "muted"
|
|
760
|
+
}, undefined, false, undefined, this))
|
|
761
|
+
]
|
|
762
|
+
}, undefined, true, undefined, this),
|
|
706
763
|
s()?.semantic_index?.status === "failed" && s()?.semantic_index?.error && /* @__PURE__ */ jsxDEV("box", {
|
|
707
764
|
marginTop: 1,
|
|
708
765
|
width: "100%",
|
|
@@ -744,7 +801,7 @@ function getRpcClient(directory) {
|
|
|
744
801
|
return client;
|
|
745
802
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
746
803
|
const dataHome = process.env.XDG_DATA_HOME || `${home}/.local/share`;
|
|
747
|
-
const storageDir = `${dataHome}/
|
|
804
|
+
const storageDir = `${dataHome}/cortexkit/aft`;
|
|
748
805
|
client = new AftRpcClient(storageDir, directory);
|
|
749
806
|
rpcClients.set(directory, client);
|
|
750
807
|
return client;
|
|
@@ -834,6 +891,7 @@ var StatusDialog = (props) => {
|
|
|
834
891
|
}, POLL_INTERVAL_MS2);
|
|
835
892
|
onCleanup2(() => clearInterval(timer));
|
|
836
893
|
const cacheRoleTone = (role) => role === "main" ? "accent" : role === "worktree" ? "warn" : "muted";
|
|
894
|
+
const compressionAggregateRows = () => formatCompressionSidebarRows(status()?.compression);
|
|
837
895
|
return /* @__PURE__ */ jsxDEV2("box", {
|
|
838
896
|
flexDirection: "column",
|
|
839
897
|
width: "100%",
|
|
@@ -1110,6 +1168,31 @@ var StatusDialog = (props) => {
|
|
|
1110
1168
|
]
|
|
1111
1169
|
}, undefined, true, undefined, this)
|
|
1112
1170
|
}, undefined, false, undefined, this) : null,
|
|
1171
|
+
compressionAggregateRows().length > 0 ? /* @__PURE__ */ jsxDEV2("box", {
|
|
1172
|
+
flexDirection: "column",
|
|
1173
|
+
width: "100%",
|
|
1174
|
+
marginTop: 1,
|
|
1175
|
+
children: [
|
|
1176
|
+
/* @__PURE__ */ jsxDEV2("text", {
|
|
1177
|
+
fg: t().text,
|
|
1178
|
+
children: /* @__PURE__ */ jsxDEV2("b", {
|
|
1179
|
+
children: "Compression"
|
|
1180
|
+
}, undefined, false, undefined, this)
|
|
1181
|
+
}, undefined, false, undefined, this),
|
|
1182
|
+
compressionAggregateRows().map((row) => row.kind === "scope" ? /* @__PURE__ */ jsxDEV2("box", {
|
|
1183
|
+
width: "100%",
|
|
1184
|
+
children: /* @__PURE__ */ jsxDEV2("text", {
|
|
1185
|
+
fg: t().text,
|
|
1186
|
+
children: row.label
|
|
1187
|
+
}, undefined, false, undefined, this)
|
|
1188
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV2(R, {
|
|
1189
|
+
theme: t(),
|
|
1190
|
+
label: row.label,
|
|
1191
|
+
value: row.value,
|
|
1192
|
+
tone: "muted"
|
|
1193
|
+
}, undefined, false, undefined, this))
|
|
1194
|
+
]
|
|
1195
|
+
}, undefined, true, undefined, this) : null,
|
|
1113
1196
|
/* @__PURE__ */ jsxDEV2("box", {
|
|
1114
1197
|
marginTop: 1,
|
|
1115
1198
|
justifyContent: "flex-end",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@clack/prompts": "^1.2.0",
|
|
31
|
-
"@cortexkit/aft-bridge": "0.
|
|
31
|
+
"@cortexkit/aft-bridge": "0.27.0",
|
|
32
32
|
"@opencode-ai/plugin": "^1.15.5",
|
|
33
33
|
"@opencode-ai/sdk": "^1.15.5",
|
|
34
34
|
"comment-json": "^4.6.2",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"zod": "^4.1.8"
|
|
37
37
|
},
|
|
38
38
|
"optionalDependencies": {
|
|
39
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
40
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
41
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
42
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
43
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
39
|
+
"@cortexkit/aft-darwin-arm64": "0.27.0",
|
|
40
|
+
"@cortexkit/aft-darwin-x64": "0.27.0",
|
|
41
|
+
"@cortexkit/aft-linux-arm64": "0.27.0",
|
|
42
|
+
"@cortexkit/aft-linux-x64": "0.27.0",
|
|
43
|
+
"@cortexkit/aft-win32-x64": "0.27.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.0.0",
|
package/src/shared/status.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export interface StatusCompressionAggregate {
|
|
2
|
+
events: number;
|
|
3
|
+
original_tokens: number;
|
|
4
|
+
compressed_tokens: number;
|
|
5
|
+
savings_tokens: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface StatusCompression {
|
|
9
|
+
project: StatusCompressionAggregate;
|
|
10
|
+
session: StatusCompressionAggregate;
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
export interface AftStatusSnapshot {
|
|
2
14
|
version: string;
|
|
3
15
|
project_root: string | null;
|
|
@@ -57,6 +69,8 @@ export interface AftStatusSnapshot {
|
|
|
57
69
|
tracked_files: number;
|
|
58
70
|
checkpoints: number;
|
|
59
71
|
};
|
|
72
|
+
/** Compression aggregate passthrough; rendering is added separately. */
|
|
73
|
+
compression?: StatusCompression;
|
|
60
74
|
/**
|
|
61
75
|
* Human-readable explanation for a synthetic snapshot (e.g.
|
|
62
76
|
* `cache_role === "not_initialized"`). When the plugin returns a placeholder
|
|
@@ -91,6 +105,25 @@ function readOptionalNumber(value: unknown): number | null {
|
|
|
91
105
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
92
106
|
}
|
|
93
107
|
|
|
108
|
+
function readCompressionAggregate(value: unknown): StatusCompressionAggregate {
|
|
109
|
+
const aggregate = asRecord(value);
|
|
110
|
+
return {
|
|
111
|
+
events: readNumber(aggregate.events),
|
|
112
|
+
original_tokens: readNumber(aggregate.original_tokens),
|
|
113
|
+
compressed_tokens: readNumber(aggregate.compressed_tokens),
|
|
114
|
+
savings_tokens: readNumber(aggregate.savings_tokens),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function readCompression(value: unknown): StatusCompression | undefined {
|
|
119
|
+
if (typeof value !== "object" || value === null) return undefined;
|
|
120
|
+
const compression = asRecord(value);
|
|
121
|
+
return {
|
|
122
|
+
project: readCompressionAggregate(compression.project),
|
|
123
|
+
session: readCompressionAggregate(compression.session),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
94
127
|
function formatFlag(enabled: boolean): string {
|
|
95
128
|
return enabled ? "enabled" : "disabled";
|
|
96
129
|
}
|
|
@@ -178,6 +211,7 @@ export function coerceAftStatus(response: Record<string, unknown>): AftStatusSna
|
|
|
178
211
|
tracked_files: readNumber(session.tracked_files),
|
|
179
212
|
checkpoints: readNumber(session.checkpoints),
|
|
180
213
|
},
|
|
214
|
+
compression: readCompression(response.compression),
|
|
181
215
|
message: readString(response.message, ""),
|
|
182
216
|
};
|
|
183
217
|
}
|
package/src/tui/index.tsx
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
import type { TuiPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/plugin/tui";
|
|
5
5
|
import { createMemo, createSignal, onCleanup } from "solid-js";
|
|
6
|
+
|
|
6
7
|
import packageJson from "../../package.json";
|
|
7
8
|
import { AftRpcClient } from "../shared/rpc-client";
|
|
8
9
|
import { type AftStatusSnapshot, coerceAftStatus, formatBytes } from "../shared/status";
|
|
9
|
-
import { createAftSidebarSlot } from "./sidebar";
|
|
10
|
+
import { createAftSidebarSlot, formatCompressionSidebarRows } from "./sidebar";
|
|
10
11
|
|
|
11
12
|
// The TUI talks to the server plugin via AftRpcClient. The client reads the
|
|
12
13
|
// JSON port file written by AftRpcServer ({ port, token }) and includes that
|
|
@@ -22,9 +23,14 @@ function getRpcClient(directory: string): AftRpcClient {
|
|
|
22
23
|
let client = rpcClients.get(directory);
|
|
23
24
|
if (client) return client;
|
|
24
25
|
|
|
26
|
+
// v0.27 moved AFT storage to the CortexKit root. The TUI plugin must use
|
|
27
|
+
// the same path as the server plugin (`resolveCortexKitStorageRoot()`),
|
|
28
|
+
// otherwise it polls stale legacy port files written by older versions
|
|
29
|
+
// and never picks up the live RPC server, leaving the sidebar/dialog
|
|
30
|
+
// stuck on the "AFT is starting up" placeholder forever.
|
|
25
31
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
26
32
|
const dataHome = process.env.XDG_DATA_HOME || `${home}/.local/share`;
|
|
27
|
-
const storageDir = `${dataHome}/
|
|
33
|
+
const storageDir = `${dataHome}/cortexkit/aft`;
|
|
28
34
|
|
|
29
35
|
client = new AftRpcClient(storageDir, directory);
|
|
30
36
|
rpcClients.set(directory, client);
|
|
@@ -153,6 +159,11 @@ const StatusDialog = (props: StatusDialogProps) => {
|
|
|
153
159
|
// not_initialized is muted. Matches the sidebar convention.
|
|
154
160
|
const cacheRoleTone = (role: string): "accent" | "warn" | "muted" =>
|
|
155
161
|
role === "main" ? "accent" : role === "worktree" ? "warn" : "muted";
|
|
162
|
+
// Reuse the sidebar's label/value formatter so the dialog and sidebar
|
|
163
|
+
// render identical text (e.g. "Session" / "-174,489 tokens, 59% reduction").
|
|
164
|
+
// The earlier `formatCompressionDialogRows` returned padded strings that
|
|
165
|
+
// looked offset against neighboring sections.
|
|
166
|
+
const compressionAggregateRows = () => formatCompressionSidebarRows(status()?.compression);
|
|
156
167
|
|
|
157
168
|
return (
|
|
158
169
|
<box
|
|
@@ -374,6 +385,28 @@ const StatusDialog = (props: StatusDialogProps) => {
|
|
|
374
385
|
</box>
|
|
375
386
|
) : null}
|
|
376
387
|
|
|
388
|
+
{/* Compression aggregates — tabular layout matching Search/Semantic
|
|
389
|
+
Index. Each scope ("Session", "Project") renders as a subheader
|
|
390
|
+
followed by two <R> rows (Tokens Saved, Compression Ratio) so the
|
|
391
|
+
numbers stay right-aligned under the value column instead of
|
|
392
|
+
crowding the label. */}
|
|
393
|
+
{compressionAggregateRows().length > 0 ? (
|
|
394
|
+
<box flexDirection="column" width="100%" marginTop={1}>
|
|
395
|
+
<text fg={t().text}>
|
|
396
|
+
<b>Compression</b>
|
|
397
|
+
</text>
|
|
398
|
+
{compressionAggregateRows().map((row) =>
|
|
399
|
+
row.kind === "scope" ? (
|
|
400
|
+
<box width="100%">
|
|
401
|
+
<text fg={t().text}>{row.label}</text>
|
|
402
|
+
</box>
|
|
403
|
+
) : (
|
|
404
|
+
<R theme={t()} label={row.label} value={row.value} tone="muted" />
|
|
405
|
+
),
|
|
406
|
+
)}
|
|
407
|
+
</box>
|
|
408
|
+
) : null}
|
|
409
|
+
|
|
377
410
|
{/* Footer */}
|
|
378
411
|
<box marginTop={1} justifyContent="flex-end" width="100%">
|
|
379
412
|
<text fg={t().textMuted}>Enter or Esc to close</text>
|
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
|
|
@@ -357,6 +401,26 @@ const SidebarContent = (props: {
|
|
|
357
401
|
)}
|
|
358
402
|
<StatRow theme={props.theme} label="Disk" value={formatBytes(semanticBytes())} tone="muted" />
|
|
359
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
|
+
|
|
360
424
|
{/* Surface failures clearly so users know to act (install ONNX,
|
|
361
425
|
fix config, etc.) rather than silently leaving the panel "off". */}
|
|
362
426
|
{s()?.semantic_index?.status === "failed" && s()?.semantic_index?.error && (
|