@cortexkit/aft-opencode 0.35.1 → 0.35.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/hooks/auto-update-checker/cache.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 +432 -240
- package/dist/lsp-auto-install.d.ts +30 -0
- package/dist/lsp-auto-install.d.ts.map +1 -1
- package/dist/shared/status.d.ts +23 -0
- package/dist/shared/status.d.ts.map +1 -1
- package/dist/tools/_shared.d.ts +11 -2
- package/dist/tools/_shared.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/semantic.d.ts.map +1 -1
- package/dist/tui.js +116 -1
- package/package.json +8 -8
- package/src/shared/status.ts +72 -0
- package/src/tui/index.tsx +51 -0
- package/src/tui/sidebar.tsx +98 -0
|
@@ -71,6 +71,36 @@ export interface AutoInstallResult {
|
|
|
71
71
|
installsComplete: Promise<void>;
|
|
72
72
|
}
|
|
73
73
|
export declare function abortInFlightAutoInstalls(): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Spawn `npm install --no-save <pkg>@<version>` in the cache dir.
|
|
76
|
+
*
|
|
77
|
+
* Uses `--ignore-scripts` to neutralize lifecycle hooks (the v0.16 audit
|
|
78
|
+
* hardening). Output goes to plugin log.
|
|
79
|
+
*
|
|
80
|
+
* Previously this used `bun add`, but OpenCode runs under whichever runtime
|
|
81
|
+
* the user has installed (Node 22 is common), and bun is not guaranteed to
|
|
82
|
+
* be on PATH. Every install would fail silently with ENOENT, so users
|
|
83
|
+
* without bun saw recurring `lsp_binary_missing` warnings for newer servers
|
|
84
|
+
* like `@vue/language-server` even though `lsp.auto_install` was true.
|
|
85
|
+
* GitHub #46 reported this exact symptom against v0.27.0.
|
|
86
|
+
*
|
|
87
|
+
* npm is guaranteed to be present whenever the plugin runs through OpenCode's
|
|
88
|
+
* normal CLI distribution path, matches Pi's auto-install behavior, and is
|
|
89
|
+
* what OpenCode itself uses for its built-in LSP auto-install.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* Anchor an `npm install --no-save` to `cwd` by writing a minimal package.json.
|
|
93
|
+
*
|
|
94
|
+
* Without a package.json in `cwd`, npm walks UP the directory tree; if any
|
|
95
|
+
* ancestor (e.g. ~/package.json) has one, npm installs into THAT package's
|
|
96
|
+
* node_modules instead, leaving our cache dir's node_modules/<server> missing
|
|
97
|
+
* while still exiting 0. The result is a silent install failure and a recurring
|
|
98
|
+
* lsp_binary_missing warning. The old `bun add` flow created this package.json
|
|
99
|
+
* implicitly; npm needs it written explicitly. GitHub #92.
|
|
100
|
+
*
|
|
101
|
+
* Idempotent: only writes when absent. Failures are non-fatal (logged).
|
|
102
|
+
*/
|
|
103
|
+
export declare function ensureInstallAnchor(cwd: string): void;
|
|
74
104
|
/**
|
|
75
105
|
* Top-level entry point. Returns the list of bin directories that already
|
|
76
106
|
* have an installed binary AND kicks off background installs for missing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lsp-auto-install.d.ts","sourceRoot":"","sources":["../src/lsp-auto-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;
|
|
1
|
+
{"version":3,"file":"lsp-auto-install.d.ts","sourceRoot":"","sources":["../src/lsp-auto-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAsCH,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,kGAAkG;IAClG,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;;;OAOG;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;;;;;;OASG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AA8DD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM/D;AA4DD;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAYrD;AA8TD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,EACzB,SAAS,GAAE,OAAO,KAAa,GAC9B,iBAAiB,CAwEnB"}
|
package/dist/shared/status.d.ts
CHANGED
|
@@ -8,6 +8,23 @@ export interface StatusCompression {
|
|
|
8
8
|
project: StatusCompressionAggregate;
|
|
9
9
|
session: StatusCompressionAggregate;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* The agent status-bar glance — `[AFT E· W· | D· U· C· | T·]`. `errors`/
|
|
13
|
+
* `warnings` are live LSP diagnostics for files touched this session; the
|
|
14
|
+
* Tier-2 trio (`dead_code`/`unused_exports`/`duplicates`) plus `todos` come
|
|
15
|
+
* from the last completed background scan. `tier2_stale` marks those Tier-2
|
|
16
|
+
* counts as predating the latest edit. Null in the snapshot until the Tier-2
|
|
17
|
+
* cache is populated at least once (no fabricated zeros).
|
|
18
|
+
*/
|
|
19
|
+
export interface StatusBar {
|
|
20
|
+
errors: number;
|
|
21
|
+
warnings: number;
|
|
22
|
+
dead_code: number;
|
|
23
|
+
unused_exports: number;
|
|
24
|
+
duplicates: number;
|
|
25
|
+
todos: number;
|
|
26
|
+
tier2_stale: boolean;
|
|
27
|
+
}
|
|
11
28
|
export interface AftStatusSnapshot {
|
|
12
29
|
version: string;
|
|
13
30
|
project_root: string | null;
|
|
@@ -70,6 +87,12 @@ export interface AftStatusSnapshot {
|
|
|
70
87
|
};
|
|
71
88
|
/** Compression aggregate passthrough; rendering is added separately. */
|
|
72
89
|
compression?: StatusCompression;
|
|
90
|
+
/**
|
|
91
|
+
* Agent status-bar counts (E/W/D/U/C/T). Undefined until the Tier-2 cache
|
|
92
|
+
* is populated at least once — the sidebar hides the Code Health section
|
|
93
|
+
* until then so it never shows fabricated zeros.
|
|
94
|
+
*/
|
|
95
|
+
status_bar?: StatusBar;
|
|
73
96
|
/**
|
|
74
97
|
* Human-readable explanation for a synthetic snapshot (e.g.
|
|
75
98
|
* `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,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,gBAAgB,EAAE,MAAM,CAAC;QACzB,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;
|
|
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;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;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,gBAAgB,EAAE,MAAM,CAAC;QACzB,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;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAsED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAKvF;AAED,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/E;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,CAqEpF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CA0F3E;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CA6FtE"}
|
package/dist/tools/_shared.d.ts
CHANGED
|
@@ -120,8 +120,17 @@ export declare function projectRootFor(runtime: ToolRuntime): string;
|
|
|
120
120
|
* approves is byte-for-byte the path the Rust bridge acts on.
|
|
121
121
|
*/
|
|
122
122
|
export declare function resolveProjectRoot(ctx: PluginContext, runtime: ToolRuntime): Promise<string>;
|
|
123
|
-
/**
|
|
124
|
-
*
|
|
123
|
+
/**
|
|
124
|
+
* Expand a leading `~` to the user's home directory. Node's `path.resolve`
|
|
125
|
+
* treats `~` as a literal segment, so `~/foo` would otherwise resolve to
|
|
126
|
+
* `<projectRoot>/~/foo`. Applied before any absolute/relative decision so all
|
|
127
|
+
* file tools (read/write/edit/outline/zoom/delete/refactor/imports/safety)
|
|
128
|
+
* accept `~/...` the same way the search tools already do.
|
|
129
|
+
*/
|
|
130
|
+
export declare function expandTilde(input: string): string;
|
|
131
|
+
/** Resolve a user path exactly as a bridge request will: `~` expands to home,
|
|
132
|
+
* absolute paths are preserved; relative paths are rooted at the
|
|
133
|
+
* session/project root. */
|
|
125
134
|
export declare function resolvePathFromProjectRoot(projectRoot: string, target: string): string;
|
|
126
135
|
export declare function resolvePathArg(ctx: PluginContext, runtime: ToolRuntime, target: string): Promise<string>;
|
|
127
136
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAQhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,GACR,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,OAAO,EACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMpD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASlE,CAAC;AAEF,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AA2BD,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,MAAM,CAsDR;AAsBD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAW3D;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED;;2BAE2B;AAC3B,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtF;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,YAAY,CAEhF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA0BlC;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAE9F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8EjD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,GAAI,IAAI,MAAM,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,MAChD,CAAC;AA0RtC;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAmKjE;AAknCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA0B/E;AAMD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA+FnF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA2HjD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BrD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA4I9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiCjD,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAyFhF"}
|
package/dist/tui.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/tui/index.tsx
|
|
2
2
|
import { createMemo as createMemo2, createSignal as createSignal2, onCleanup as onCleanup2 } from "solid-js";
|
|
3
3
|
// package.json
|
|
4
|
-
var version = "0.35.
|
|
4
|
+
var version = "0.35.3";
|
|
5
5
|
|
|
6
6
|
// src/shared/rpc-client.ts
|
|
7
7
|
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
@@ -343,6 +343,20 @@ function readCompression(value) {
|
|
|
343
343
|
session: readCompressionAggregate(compression.session)
|
|
344
344
|
};
|
|
345
345
|
}
|
|
346
|
+
function readStatusBar(value) {
|
|
347
|
+
if (typeof value !== "object" || value === null)
|
|
348
|
+
return;
|
|
349
|
+
const bar = asRecord(value);
|
|
350
|
+
return {
|
|
351
|
+
errors: readNumber(bar.errors),
|
|
352
|
+
warnings: readNumber(bar.warnings),
|
|
353
|
+
dead_code: readNumber(bar.dead_code),
|
|
354
|
+
unused_exports: readNumber(bar.unused_exports),
|
|
355
|
+
duplicates: readNumber(bar.duplicates),
|
|
356
|
+
todos: readNumber(bar.todos),
|
|
357
|
+
tier2_stale: readBoolean(bar.tier2_stale)
|
|
358
|
+
};
|
|
359
|
+
}
|
|
346
360
|
function formatSemanticIndexStatus(status, stage) {
|
|
347
361
|
if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
|
|
348
362
|
return "Rebuilding (model changed)";
|
|
@@ -430,6 +444,7 @@ function coerceAftStatus(response) {
|
|
|
430
444
|
checkpoints: readNumber(session.checkpoints)
|
|
431
445
|
},
|
|
432
446
|
compression: readCompression(response.compression),
|
|
447
|
+
status_bar: readStatusBar(response.status_bar),
|
|
433
448
|
message: readString(response.message, "")
|
|
434
449
|
};
|
|
435
450
|
}
|
|
@@ -591,6 +606,14 @@ function collapsedCompressionValue(compression) {
|
|
|
591
606
|
const pct = original_tokens > 0 ? Math.round(savings_tokens / original_tokens * 100) : 0;
|
|
592
607
|
return `${formatCount(savings_tokens)} / ${pct}%`;
|
|
593
608
|
}
|
|
609
|
+
function collapsedHealthLights(statusBar) {
|
|
610
|
+
if (!statusBar)
|
|
611
|
+
return null;
|
|
612
|
+
const diagnostics = statusBar.errors > 0 ? "err" : statusBar.warnings > 0 ? "warn" : "ok";
|
|
613
|
+
const code = statusBar.duplicates > 0 ? "warn" : "ok";
|
|
614
|
+
const todos = statusBar.todos > 0 ? "warn" : "ok";
|
|
615
|
+
return { diagnostics, code, todos };
|
|
616
|
+
}
|
|
594
617
|
function resolveTuiStorageDir() {
|
|
595
618
|
return resolveCortexKitStorageRoot();
|
|
596
619
|
}
|
|
@@ -755,6 +778,7 @@ var SidebarContent = (props) => {
|
|
|
755
778
|
const trigramBytes = () => s()?.disk?.trigram_disk_bytes ?? 0;
|
|
756
779
|
const semanticBytes = () => s()?.disk?.semantic_disk_bytes ?? 0;
|
|
757
780
|
const compressionRows = () => formatCompressionSidebarRows(s()?.compression);
|
|
781
|
+
const statusBar = () => s()?.status_bar;
|
|
758
782
|
const degradedReasonLabel = (reason) => {
|
|
759
783
|
if (reason === "home_root") {
|
|
760
784
|
return "project root is your home directory";
|
|
@@ -873,6 +897,28 @@ var SidebarContent = (props) => {
|
|
|
873
897
|
children: "●"
|
|
874
898
|
}, undefined, false, undefined, this)
|
|
875
899
|
}, undefined, false, undefined, this),
|
|
900
|
+
collapsedHealthLights(statusBar()) && /* @__PURE__ */ jsxDEV(CollapsedRow, {
|
|
901
|
+
theme: props.theme,
|
|
902
|
+
label: "Code Health",
|
|
903
|
+
children: /* @__PURE__ */ jsxDEV("box", {
|
|
904
|
+
flexDirection: "row",
|
|
905
|
+
gap: 1,
|
|
906
|
+
children: [
|
|
907
|
+
/* @__PURE__ */ jsxDEV("text", {
|
|
908
|
+
fg: toneColor(props.theme, collapsedHealthLights(statusBar()).diagnostics),
|
|
909
|
+
children: "●"
|
|
910
|
+
}, undefined, false, undefined, this),
|
|
911
|
+
/* @__PURE__ */ jsxDEV("text", {
|
|
912
|
+
fg: toneColor(props.theme, collapsedHealthLights(statusBar()).code),
|
|
913
|
+
children: "●"
|
|
914
|
+
}, undefined, false, undefined, this),
|
|
915
|
+
/* @__PURE__ */ jsxDEV("text", {
|
|
916
|
+
fg: toneColor(props.theme, collapsedHealthLights(statusBar()).todos),
|
|
917
|
+
children: "●"
|
|
918
|
+
}, undefined, false, undefined, this)
|
|
919
|
+
]
|
|
920
|
+
}, undefined, true, undefined, this)
|
|
921
|
+
}, undefined, false, undefined, this),
|
|
876
922
|
collapsedCompressionValue(s()?.compression) && /* @__PURE__ */ jsxDEV(CollapsedRow, {
|
|
877
923
|
theme: props.theme,
|
|
878
924
|
label: "Compression",
|
|
@@ -944,6 +990,38 @@ var SidebarContent = (props) => {
|
|
|
944
990
|
value: formatBytes2(semanticBytes()),
|
|
945
991
|
tone: "muted"
|
|
946
992
|
}, undefined, false, undefined, this),
|
|
993
|
+
statusBar() && /* @__PURE__ */ jsxDEV(Fragment, {
|
|
994
|
+
children: [
|
|
995
|
+
/* @__PURE__ */ jsxDEV(SectionHeader, {
|
|
996
|
+
theme: props.theme,
|
|
997
|
+
title: statusBar().tier2_stale ? "Code Health ~" : "Code Health"
|
|
998
|
+
}, undefined, false, undefined, this),
|
|
999
|
+
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1000
|
+
theme: props.theme,
|
|
1001
|
+
label: "Errors",
|
|
1002
|
+
value: formatCount(statusBar().errors),
|
|
1003
|
+
tone: statusBar().errors > 0 ? "err" : "muted"
|
|
1004
|
+
}, undefined, false, undefined, this),
|
|
1005
|
+
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1006
|
+
theme: props.theme,
|
|
1007
|
+
label: "Warnings",
|
|
1008
|
+
value: formatCount(statusBar().warnings),
|
|
1009
|
+
tone: statusBar().warnings > 0 ? "warn" : "muted"
|
|
1010
|
+
}, undefined, false, undefined, this),
|
|
1011
|
+
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1012
|
+
theme: props.theme,
|
|
1013
|
+
label: "Duplicates",
|
|
1014
|
+
value: formatCount(statusBar().duplicates),
|
|
1015
|
+
tone: "muted"
|
|
1016
|
+
}, undefined, false, undefined, this),
|
|
1017
|
+
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1018
|
+
theme: props.theme,
|
|
1019
|
+
label: "TODOs",
|
|
1020
|
+
value: formatCount(statusBar().todos),
|
|
1021
|
+
tone: "muted"
|
|
1022
|
+
}, undefined, false, undefined, this)
|
|
1023
|
+
]
|
|
1024
|
+
}, undefined, true, undefined, this),
|
|
947
1025
|
compressionRows().length > 0 && /* @__PURE__ */ jsxDEV(Fragment, {
|
|
948
1026
|
children: [
|
|
949
1027
|
/* @__PURE__ */ jsxDEV(SectionHeader, {
|
|
@@ -1433,6 +1511,43 @@ var StatusDialog = (props) => {
|
|
|
1433
1511
|
}, undefined, false, undefined, this))
|
|
1434
1512
|
]
|
|
1435
1513
|
}, undefined, true, undefined, this) : null,
|
|
1514
|
+
status()?.status_bar ? /* @__PURE__ */ jsxDEV2("box", {
|
|
1515
|
+
flexDirection: "column",
|
|
1516
|
+
width: "100%",
|
|
1517
|
+
marginTop: 1,
|
|
1518
|
+
children: [
|
|
1519
|
+
/* @__PURE__ */ jsxDEV2("text", {
|
|
1520
|
+
fg: t().text,
|
|
1521
|
+
children: /* @__PURE__ */ jsxDEV2("b", {
|
|
1522
|
+
children: status().status_bar.tier2_stale ? "Code Health ~" : "Code Health"
|
|
1523
|
+
}, undefined, false, undefined, this)
|
|
1524
|
+
}, undefined, false, undefined, this),
|
|
1525
|
+
/* @__PURE__ */ jsxDEV2(R, {
|
|
1526
|
+
theme: t(),
|
|
1527
|
+
label: "Errors",
|
|
1528
|
+
value: formatCountShort(status().status_bar.errors),
|
|
1529
|
+
tone: status().status_bar.errors > 0 ? "err" : "muted"
|
|
1530
|
+
}, undefined, false, undefined, this),
|
|
1531
|
+
/* @__PURE__ */ jsxDEV2(R, {
|
|
1532
|
+
theme: t(),
|
|
1533
|
+
label: "Warnings",
|
|
1534
|
+
value: formatCountShort(status().status_bar.warnings),
|
|
1535
|
+
tone: status().status_bar.warnings > 0 ? "warn" : "muted"
|
|
1536
|
+
}, undefined, false, undefined, this),
|
|
1537
|
+
/* @__PURE__ */ jsxDEV2(R, {
|
|
1538
|
+
theme: t(),
|
|
1539
|
+
label: "Duplicates",
|
|
1540
|
+
value: formatCountShort(status().status_bar.duplicates),
|
|
1541
|
+
tone: "muted"
|
|
1542
|
+
}, undefined, false, undefined, this),
|
|
1543
|
+
/* @__PURE__ */ jsxDEV2(R, {
|
|
1544
|
+
theme: t(),
|
|
1545
|
+
label: "TODOs",
|
|
1546
|
+
value: formatCountShort(status().status_bar.todos),
|
|
1547
|
+
tone: "muted"
|
|
1548
|
+
}, undefined, false, undefined, this)
|
|
1549
|
+
]
|
|
1550
|
+
}, undefined, true, undefined, this) : null,
|
|
1436
1551
|
/* @__PURE__ */ jsxDEV2("box", {
|
|
1437
1552
|
marginTop: 1,
|
|
1438
1553
|
justifyContent: "flex-end",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.3",
|
|
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",
|
|
@@ -30,19 +30,19 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@clack/prompts": "^1.2.0",
|
|
33
|
-
"@cortexkit/aft-bridge": "0.35.
|
|
33
|
+
"@cortexkit/aft-bridge": "0.35.3",
|
|
34
34
|
"@xterm/headless": "^5.5.0",
|
|
35
35
|
"comment-json": "^4.6.2",
|
|
36
36
|
"undici": "^7.25.0",
|
|
37
37
|
"zod": "^4.1.8"
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
|
-
"@cortexkit/aft-darwin-arm64": "0.35.
|
|
41
|
-
"@cortexkit/aft-darwin-x64": "0.35.
|
|
42
|
-
"@cortexkit/aft-linux-arm64": "0.35.
|
|
43
|
-
"@cortexkit/aft-linux-x64": "0.35.
|
|
44
|
-
"@cortexkit/aft-win32-arm64": "0.35.
|
|
45
|
-
"@cortexkit/aft-win32-x64": "0.35.
|
|
40
|
+
"@cortexkit/aft-darwin-arm64": "0.35.3",
|
|
41
|
+
"@cortexkit/aft-darwin-x64": "0.35.3",
|
|
42
|
+
"@cortexkit/aft-linux-arm64": "0.35.3",
|
|
43
|
+
"@cortexkit/aft-linux-x64": "0.35.3",
|
|
44
|
+
"@cortexkit/aft-win32-arm64": "0.35.3",
|
|
45
|
+
"@cortexkit/aft-win32-x64": "0.35.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@opencode-ai/plugin": "^1.15.11",
|
package/src/shared/status.ts
CHANGED
|
@@ -10,6 +10,24 @@ export interface StatusCompression {
|
|
|
10
10
|
session: StatusCompressionAggregate;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* The agent status-bar glance — `[AFT E· W· | D· U· C· | T·]`. `errors`/
|
|
15
|
+
* `warnings` are live LSP diagnostics for files touched this session; the
|
|
16
|
+
* Tier-2 trio (`dead_code`/`unused_exports`/`duplicates`) plus `todos` come
|
|
17
|
+
* from the last completed background scan. `tier2_stale` marks those Tier-2
|
|
18
|
+
* counts as predating the latest edit. Null in the snapshot until the Tier-2
|
|
19
|
+
* cache is populated at least once (no fabricated zeros).
|
|
20
|
+
*/
|
|
21
|
+
export interface StatusBar {
|
|
22
|
+
errors: number;
|
|
23
|
+
warnings: number;
|
|
24
|
+
dead_code: number;
|
|
25
|
+
unused_exports: number;
|
|
26
|
+
duplicates: number;
|
|
27
|
+
todos: number;
|
|
28
|
+
tier2_stale: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
export interface AftStatusSnapshot {
|
|
14
32
|
version: string;
|
|
15
33
|
project_root: string | null;
|
|
@@ -72,6 +90,12 @@ export interface AftStatusSnapshot {
|
|
|
72
90
|
};
|
|
73
91
|
/** Compression aggregate passthrough; rendering is added separately. */
|
|
74
92
|
compression?: StatusCompression;
|
|
93
|
+
/**
|
|
94
|
+
* Agent status-bar counts (E/W/D/U/C/T). Undefined until the Tier-2 cache
|
|
95
|
+
* is populated at least once — the sidebar hides the Code Health section
|
|
96
|
+
* until then so it never shows fabricated zeros.
|
|
97
|
+
*/
|
|
98
|
+
status_bar?: StatusBar;
|
|
75
99
|
/**
|
|
76
100
|
* Human-readable explanation for a synthetic snapshot (e.g.
|
|
77
101
|
* `cache_role === "not_initialized"`). When the plugin returns a placeholder
|
|
@@ -125,6 +149,23 @@ function readCompression(value: unknown): StatusCompression | undefined {
|
|
|
125
149
|
};
|
|
126
150
|
}
|
|
127
151
|
|
|
152
|
+
function readStatusBar(value: unknown): StatusBar | undefined {
|
|
153
|
+
// Null until Tier-2 is populated — the Rust snapshot emits JSON null, which
|
|
154
|
+
// is not an object, so this returns undefined and the sidebar hides the
|
|
155
|
+
// Code Health section (no fabricated zeros).
|
|
156
|
+
if (typeof value !== "object" || value === null) return undefined;
|
|
157
|
+
const bar = asRecord(value);
|
|
158
|
+
return {
|
|
159
|
+
errors: readNumber(bar.errors),
|
|
160
|
+
warnings: readNumber(bar.warnings),
|
|
161
|
+
dead_code: readNumber(bar.dead_code),
|
|
162
|
+
unused_exports: readNumber(bar.unused_exports),
|
|
163
|
+
duplicates: readNumber(bar.duplicates),
|
|
164
|
+
todos: readNumber(bar.todos),
|
|
165
|
+
tier2_stale: readBoolean(bar.tier2_stale),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
128
169
|
function formatFlag(enabled: boolean): string {
|
|
129
170
|
return enabled ? "enabled" : "disabled";
|
|
130
171
|
}
|
|
@@ -227,6 +268,7 @@ export function coerceAftStatus(response: Record<string, unknown>): AftStatusSna
|
|
|
227
268
|
checkpoints: readNumber(session.checkpoints),
|
|
228
269
|
},
|
|
229
270
|
compression: readCompression(response.compression),
|
|
271
|
+
status_bar: readStatusBar(response.status_bar),
|
|
230
272
|
message: readString(response.message, ""),
|
|
231
273
|
};
|
|
232
274
|
}
|
|
@@ -288,6 +330,21 @@ export function formatStatusDialogMessage(status: AftStatusSnapshot): string {
|
|
|
288
330
|
lines.push(`- storage dir: ${status.storage_dir ?? status.disk.storage_dir}`);
|
|
289
331
|
}
|
|
290
332
|
|
|
333
|
+
if (status.status_bar) {
|
|
334
|
+
const sb = status.status_bar;
|
|
335
|
+
lines.push(
|
|
336
|
+
"",
|
|
337
|
+
`Code Health${sb.tier2_stale ? " (~ stale)" : ""}`,
|
|
338
|
+
`- errors: ${formatCount(sb.errors)}`,
|
|
339
|
+
`- warnings: ${formatCount(sb.warnings)}`,
|
|
340
|
+
// dead code / unused exports hidden until oxc resolver lands (restore both)
|
|
341
|
+
// `- dead code: ${formatCount(sb.dead_code)}`,
|
|
342
|
+
// `- unused exports: ${formatCount(sb.unused_exports)}`,
|
|
343
|
+
`- duplicates: ${formatCount(sb.duplicates)}`,
|
|
344
|
+
`- todos: ${formatCount(sb.todos)}`,
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
291
348
|
lines.push(
|
|
292
349
|
"",
|
|
293
350
|
"Current session",
|
|
@@ -383,6 +440,21 @@ export function formatStatusMarkdown(status: AftStatusSnapshot): string {
|
|
|
383
440
|
lines.push(`- **Storage dir:** \`${status.storage_dir ?? status.disk.storage_dir}\``);
|
|
384
441
|
}
|
|
385
442
|
|
|
443
|
+
if (status.status_bar) {
|
|
444
|
+
const sb = status.status_bar;
|
|
445
|
+
lines.push(
|
|
446
|
+
"",
|
|
447
|
+
`### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`,
|
|
448
|
+
`- **Errors:** ${formatCount(sb.errors)}`,
|
|
449
|
+
`- **Warnings:** ${formatCount(sb.warnings)}`,
|
|
450
|
+
// dead code / unused exports hidden until oxc resolver lands (restore both)
|
|
451
|
+
// `- **Dead code:** ${formatCount(sb.dead_code)}`,
|
|
452
|
+
// `- **Unused exports:** ${formatCount(sb.unused_exports)}`,
|
|
453
|
+
`- **Duplicates:** ${formatCount(sb.duplicates)}`,
|
|
454
|
+
`- **TODOs:** ${formatCount(sb.todos)}`,
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
386
458
|
lines.push(
|
|
387
459
|
"",
|
|
388
460
|
"### Current session",
|
package/src/tui/index.tsx
CHANGED
|
@@ -466,6 +466,57 @@ const StatusDialog = (props: StatusDialogProps) => {
|
|
|
466
466
|
</box>
|
|
467
467
|
) : null}
|
|
468
468
|
|
|
469
|
+
{/* Code Health — the agent status-bar glance (E/W/D/U/C/T), surfaced so
|
|
470
|
+
users see the same view agents get. Hidden until the Tier-2 cache is
|
|
471
|
+
populated (status_bar undefined) so it never shows fabricated zeros.
|
|
472
|
+
A `~` on the header flags the Tier-2 counts as predating the latest
|
|
473
|
+
edit. */}
|
|
474
|
+
{status()?.status_bar ? (
|
|
475
|
+
<box flexDirection="column" width="100%" marginTop={1}>
|
|
476
|
+
<text fg={t().text}>
|
|
477
|
+
<b>{status()!.status_bar!.tier2_stale ? "Code Health ~" : "Code Health"}</b>
|
|
478
|
+
</text>
|
|
479
|
+
<R
|
|
480
|
+
theme={t()}
|
|
481
|
+
label="Errors"
|
|
482
|
+
value={formatCountShort(status()!.status_bar!.errors)}
|
|
483
|
+
tone={status()!.status_bar!.errors > 0 ? "err" : "muted"}
|
|
484
|
+
/>
|
|
485
|
+
<R
|
|
486
|
+
theme={t()}
|
|
487
|
+
label="Warnings"
|
|
488
|
+
value={formatCountShort(status()!.status_bar!.warnings)}
|
|
489
|
+
tone={status()!.status_bar!.warnings > 0 ? "warn" : "muted"}
|
|
490
|
+
/>
|
|
491
|
+
{/* Dead Code / Unused Exports hidden until the oxc resolver lands
|
|
492
|
+
(current scanner over-reports on barrel re-exports). Restore both. */}
|
|
493
|
+
{/* <R
|
|
494
|
+
theme={t()}
|
|
495
|
+
label="Dead Code"
|
|
496
|
+
value={formatCountShort(status()!.status_bar!.dead_code)}
|
|
497
|
+
tone="muted"
|
|
498
|
+
/>
|
|
499
|
+
<R
|
|
500
|
+
theme={t()}
|
|
501
|
+
label="Unused Exports"
|
|
502
|
+
value={formatCountShort(status()!.status_bar!.unused_exports)}
|
|
503
|
+
tone="muted"
|
|
504
|
+
/> */}
|
|
505
|
+
<R
|
|
506
|
+
theme={t()}
|
|
507
|
+
label="Duplicates"
|
|
508
|
+
value={formatCountShort(status()!.status_bar!.duplicates)}
|
|
509
|
+
tone="muted"
|
|
510
|
+
/>
|
|
511
|
+
<R
|
|
512
|
+
theme={t()}
|
|
513
|
+
label="TODOs"
|
|
514
|
+
value={formatCountShort(status()!.status_bar!.todos)}
|
|
515
|
+
tone="muted"
|
|
516
|
+
/>
|
|
517
|
+
</box>
|
|
518
|
+
) : null}
|
|
519
|
+
|
|
469
520
|
{/* Footer */}
|
|
470
521
|
<box marginTop={1} justifyContent="flex-end" width="100%">
|
|
471
522
|
<text fg={t().textMuted}>Enter or Esc to close</text>
|
package/src/tui/sidebar.tsx
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
coerceAftStatus,
|
|
17
17
|
formatSemanticIndexStatus,
|
|
18
18
|
formatSemanticRefreshing,
|
|
19
|
+
type StatusBar,
|
|
19
20
|
type StatusCompression,
|
|
20
21
|
} from "../shared/status";
|
|
21
22
|
import { resolveCortexKitStorageRoot } from "../shared/storage-paths";
|
|
@@ -179,6 +180,34 @@ export function collapsedCompressionValue(
|
|
|
179
180
|
return `${formatCount(savings_tokens)} / ${pct}%`;
|
|
180
181
|
}
|
|
181
182
|
|
|
183
|
+
export type HealthLightTone = "ok" | "warn" | "err";
|
|
184
|
+
|
|
185
|
+
export interface HealthLights {
|
|
186
|
+
// Diagnostics: red if any errors, yellow if any warnings, else green.
|
|
187
|
+
diagnostics: HealthLightTone;
|
|
188
|
+
// Code cruft: yellow if there is any duplicate, green when zero. Never red —
|
|
189
|
+
// cruft is not a build failure. NOTE: dead_code / unused_exports are
|
|
190
|
+
// temporarily excluded from this signal (and the expanded rows below) until
|
|
191
|
+
// the oxc-based resolver lands and makes those counts trustworthy on real
|
|
192
|
+
// TS/JS codebases. Restore them here when that engine ships.
|
|
193
|
+
code: HealthLightTone;
|
|
194
|
+
// TODOs: yellow if any, else green.
|
|
195
|
+
todos: HealthLightTone;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Three traffic lights for the collapsed view, replacing the cramped
|
|
199
|
+
// `E· W· | D· U· C· | T·` string. Returns null until populated.
|
|
200
|
+
export function collapsedHealthLights(statusBar: StatusBar | undefined): HealthLights | null {
|
|
201
|
+
if (!statusBar) return null;
|
|
202
|
+
const diagnostics: HealthLightTone =
|
|
203
|
+
statusBar.errors > 0 ? "err" : statusBar.warnings > 0 ? "warn" : "ok";
|
|
204
|
+
const code: HealthLightTone =
|
|
205
|
+
// statusBar.dead_code > 0 || statusBar.unused_exports > 0 || // restore with oxc engine
|
|
206
|
+
statusBar.duplicates > 0 ? "warn" : "ok";
|
|
207
|
+
const todos: HealthLightTone = statusBar.todos > 0 ? "warn" : "ok";
|
|
208
|
+
return { diagnostics, code, todos };
|
|
209
|
+
}
|
|
210
|
+
|
|
182
211
|
// v0.27 moved AFT storage to the CortexKit root. TUI code must use a
|
|
183
212
|
// lightweight local path helper rather than the shared bridge barrel, which
|
|
184
213
|
// also exports URL-fetch helpers unsuitable for Bun's TUI runtime.
|
|
@@ -426,6 +455,7 @@ const SidebarContent = (props: {
|
|
|
426
455
|
const trigramBytes = () => s()?.disk?.trigram_disk_bytes ?? 0;
|
|
427
456
|
const semanticBytes = () => s()?.disk?.semantic_disk_bytes ?? 0;
|
|
428
457
|
const compressionRows = () => formatCompressionSidebarRows(s()?.compression);
|
|
458
|
+
const statusBar = () => s()?.status_bar;
|
|
429
459
|
|
|
430
460
|
// Degraded-mode reason → human-readable hint. Distinct strings per reason
|
|
431
461
|
// because the UX direction is different: "home_root" tells the user to
|
|
@@ -537,6 +567,19 @@ const SidebarContent = (props: {
|
|
|
537
567
|
<CollapsedRow theme={props.theme} label="Semantic Index">
|
|
538
568
|
<text fg={toneColor(props.theme, semanticStatus().tone)}>●</text>
|
|
539
569
|
</CollapsedRow>
|
|
570
|
+
{collapsedHealthLights(statusBar()) && (
|
|
571
|
+
<CollapsedRow theme={props.theme} label="Code Health">
|
|
572
|
+
<box flexDirection="row" gap={1}>
|
|
573
|
+
<text fg={toneColor(props.theme, collapsedHealthLights(statusBar())!.diagnostics)}>
|
|
574
|
+
●
|
|
575
|
+
</text>
|
|
576
|
+
<text fg={toneColor(props.theme, collapsedHealthLights(statusBar())!.code)}>●</text>
|
|
577
|
+
<text fg={toneColor(props.theme, collapsedHealthLights(statusBar())!.todos)}>
|
|
578
|
+
●
|
|
579
|
+
</text>
|
|
580
|
+
</box>
|
|
581
|
+
</CollapsedRow>
|
|
582
|
+
)}
|
|
540
583
|
{collapsedCompressionValue(s()?.compression) && (
|
|
541
584
|
<CollapsedRow theme={props.theme} label="Compression">
|
|
542
585
|
<text fg={props.theme.textMuted}>
|
|
@@ -614,6 +657,61 @@ const SidebarContent = (props: {
|
|
|
614
657
|
tone="muted"
|
|
615
658
|
/>
|
|
616
659
|
|
|
660
|
+
{/* Code Health — the agent status-bar glance, surfaced for users.
|
|
661
|
+
Hidden until the Tier-2 cache is populated (status_bar undefined),
|
|
662
|
+
so it never shows fabricated zeros. Errors/warnings are live LSP
|
|
663
|
+
diagnostics; D/U/C/T come from the last background scan. A `~` on
|
|
664
|
+
the section header flags the Tier-2 counts as predating the latest
|
|
665
|
+
edit. */}
|
|
666
|
+
{statusBar() && (
|
|
667
|
+
<>
|
|
668
|
+
<SectionHeader
|
|
669
|
+
theme={props.theme}
|
|
670
|
+
title={statusBar()!.tier2_stale ? "Code Health ~" : "Code Health"}
|
|
671
|
+
/>
|
|
672
|
+
<StatRow
|
|
673
|
+
theme={props.theme}
|
|
674
|
+
label="Errors"
|
|
675
|
+
value={formatCount(statusBar()!.errors)}
|
|
676
|
+
tone={statusBar()!.errors > 0 ? "err" : "muted"}
|
|
677
|
+
/>
|
|
678
|
+
<StatRow
|
|
679
|
+
theme={props.theme}
|
|
680
|
+
label="Warnings"
|
|
681
|
+
value={formatCount(statusBar()!.warnings)}
|
|
682
|
+
tone={statusBar()!.warnings > 0 ? "warn" : "muted"}
|
|
683
|
+
/>
|
|
684
|
+
{/* Dead Code / Unused Exports temporarily hidden until the
|
|
685
|
+
oxc-based resolver lands and makes these trustworthy on real
|
|
686
|
+
TS/JS codebases (current tree-sitter scanner over-reports via
|
|
687
|
+
barrel re-export gaps). Restore both rows when that ships. */}
|
|
688
|
+
{/* <StatRow
|
|
689
|
+
theme={props.theme}
|
|
690
|
+
label="Dead Code"
|
|
691
|
+
value={formatCount(statusBar()!.dead_code)}
|
|
692
|
+
tone="muted"
|
|
693
|
+
/>
|
|
694
|
+
<StatRow
|
|
695
|
+
theme={props.theme}
|
|
696
|
+
label="Unused Exports"
|
|
697
|
+
value={formatCount(statusBar()!.unused_exports)}
|
|
698
|
+
tone="muted"
|
|
699
|
+
/> */}
|
|
700
|
+
<StatRow
|
|
701
|
+
theme={props.theme}
|
|
702
|
+
label="Duplicates"
|
|
703
|
+
value={formatCount(statusBar()!.duplicates)}
|
|
704
|
+
tone="muted"
|
|
705
|
+
/>
|
|
706
|
+
<StatRow
|
|
707
|
+
theme={props.theme}
|
|
708
|
+
label="TODOs"
|
|
709
|
+
value={formatCount(statusBar()!.todos)}
|
|
710
|
+
tone="muted"
|
|
711
|
+
/>
|
|
712
|
+
</>
|
|
713
|
+
)}
|
|
714
|
+
|
|
617
715
|
{/* Compression aggregates. Tabular layout matching Search/Semantic
|
|
618
716
|
Index above: each scope ("Session", "Project") renders as a
|
|
619
717
|
subheader followed by two StatRows (Tokens Saved, Compression
|