@danypops/pi-jittor 0.2.0 → 0.2.1
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/extension/src/benchmark-tui.ts +27 -12
- package/extension/src/capabilities/codex-recovery.ts +39 -23
- package/extension/src/capabilities/context-hub.ts +1 -5
- package/extension/src/capabilities/local-run-telemetry.ts +14 -10
- package/extension/src/capabilities/provider-response-telemetry.ts +20 -6
- package/extension/src/context-breakdown.ts +60 -29
- package/extension/src/context-report.ts +16 -5
- package/extension/src/context-view.ts +39 -7
- package/extension/src/footer.ts +56 -26
- package/extension/src/index.ts +228 -97
- package/extension/src/service-client.ts +1 -1
- package/extension/src/settings-tui.ts +35 -20
- package/extension/src/settings.ts +13 -10
- package/extension/src/tui.ts +148 -63
- package/extension/src/usage.ts +124 -42
- package/package.json +3 -3
package/extension/src/footer.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
2
|
-
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
|
-
import { ProgressBar } from "malevich-tui-components";
|
|
5
2
|
import {
|
|
6
3
|
FOOTER_BAR_MAX_WIDTH,
|
|
7
4
|
FOOTER_BAR_MIN_WIDTH,
|
|
5
|
+
FOOTER_COMPACTION_BLINK_HALF_PERIOD_MS,
|
|
8
6
|
FOOTER_CONTEXT_ACCENT_FRACTION,
|
|
9
7
|
FOOTER_CONTEXT_ERROR_FRACTION,
|
|
10
|
-
FOOTER_COMPACTION_BLINK_HALF_PERIOD_MS,
|
|
11
8
|
FOOTER_CONTEXT_WARNING_FRACTION,
|
|
12
9
|
FOOTER_WIDE_TERMINAL_WIDTH,
|
|
13
10
|
MILLISECONDS_PER_DAY,
|
|
@@ -15,6 +12,9 @@ import {
|
|
|
15
12
|
MILLISECONDS_PER_MINUTE,
|
|
16
13
|
TELEMETRY_STALE_AFTER_MS,
|
|
17
14
|
} from "@danypops/jittor";
|
|
15
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
17
|
+
import { ProgressBar } from "malevich-tui-components";
|
|
18
18
|
|
|
19
19
|
type FooterColor = "accent" | "dim" | "warning" | "error";
|
|
20
20
|
|
|
@@ -48,19 +48,21 @@ interface FooterContext {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/** A bounded quota is explicitly remaining; unbounded values never receive a fabricated bar. */
|
|
51
|
-
export type ProviderBudget =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
51
|
+
export type ProviderBudget =
|
|
52
|
+
| {
|
|
53
|
+
kind: "bounded";
|
|
54
|
+
label: string;
|
|
55
|
+
remainingFraction: number;
|
|
56
|
+
observedAt?: number;
|
|
57
|
+
resetsAt?: number;
|
|
58
|
+
resetText?: string;
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
kind: "unbounded";
|
|
62
|
+
label: string;
|
|
63
|
+
valueText: string;
|
|
64
|
+
observedAt?: number;
|
|
65
|
+
};
|
|
64
66
|
|
|
65
67
|
export interface CompactionProgress {
|
|
66
68
|
startedAt: number;
|
|
@@ -92,17 +94,25 @@ function footerCwd(cwd: string, home: string | undefined): string {
|
|
|
92
94
|
const resolvedCwd = resolve(cwd);
|
|
93
95
|
const resolvedHome = resolve(home);
|
|
94
96
|
const relativeToHome = relative(resolvedHome, resolvedCwd);
|
|
95
|
-
const inside =
|
|
97
|
+
const inside =
|
|
98
|
+
relativeToHome === "" || (relativeToHome !== ".." && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));
|
|
96
99
|
if (!inside) return cwd;
|
|
97
100
|
return relativeToHome === "" ? "~" : `~${sep}${relativeToHome}`;
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
function sanitize(value: string): string {
|
|
101
|
-
return value
|
|
104
|
+
return value
|
|
105
|
+
.replace(/[\r\n\t]/g, " ")
|
|
106
|
+
.replace(/ +/g, " ")
|
|
107
|
+
.trim();
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
function usageTotals(context: FooterContext): UsageTotals {
|
|
105
|
-
let input = 0,
|
|
111
|
+
let input = 0,
|
|
112
|
+
output = 0,
|
|
113
|
+
cacheRead = 0,
|
|
114
|
+
cacheWrite = 0,
|
|
115
|
+
cost = 0;
|
|
106
116
|
for (const entry of context.sessionManager.getEntries()) {
|
|
107
117
|
if (entry.type !== "message" || entry.message?.role !== "assistant") continue;
|
|
108
118
|
const usage = entry.message.usage;
|
|
@@ -113,7 +123,7 @@ function usageTotals(context: FooterContext): UsageTotals {
|
|
|
113
123
|
cost += usage?.cost?.total ?? 0;
|
|
114
124
|
}
|
|
115
125
|
const prompt = input + cacheRead + cacheWrite;
|
|
116
|
-
return { input, output, cacheRead, cacheWrite, cost, ...(prompt > 0 ? { cacheHit: cacheRead / prompt * 100 } : {}) };
|
|
126
|
+
return { input, output, cacheRead, cacheWrite, cost, ...(prompt > 0 ? { cacheHit: (cacheRead / prompt) * 100 } : {}) };
|
|
117
127
|
}
|
|
118
128
|
|
|
119
129
|
function barWidth(width: number): number {
|
|
@@ -201,7 +211,13 @@ function resetLabel(resetsAt: number | undefined, now: number): string | undefin
|
|
|
201
211
|
* the segment is omitted entirely rather than showing a placeholder that could never resolve.
|
|
202
212
|
* `null` means not known yet but might resolve, which still earns the `?` placeholder.
|
|
203
213
|
*/
|
|
204
|
-
function budgetSegment(
|
|
214
|
+
function budgetSegment(
|
|
215
|
+
budget: ProviderBudget | null | undefined,
|
|
216
|
+
theme: FooterTheme,
|
|
217
|
+
width: number,
|
|
218
|
+
compact: boolean,
|
|
219
|
+
now: number,
|
|
220
|
+
): string | undefined {
|
|
205
221
|
if (budget === undefined) return undefined;
|
|
206
222
|
const w = barWidth(width);
|
|
207
223
|
if (!budget) return `budget ${theme.fg("dim", progressBar(null, w))} ?`;
|
|
@@ -210,8 +226,8 @@ function budgetSegment(budget: ProviderBudget | null | undefined, theme: FooterT
|
|
|
210
226
|
if (budget.kind === "unbounded") return `${budget.label} ${budget.valueText}${staleText}`;
|
|
211
227
|
const remaining = Math.min(1, Math.max(0, budget.remainingFraction));
|
|
212
228
|
const bar = theme.fg(fillColor(1 - remaining), progressBar(remaining, w));
|
|
213
|
-
const value = `${
|
|
214
|
-
const reset = compact ? undefined : resetLabel(budget.resetsAt, now) ?? budget.resetText;
|
|
229
|
+
const value = `${compact ? Math.round(remaining * 100) : (remaining * 100).toFixed(1)}% left`;
|
|
230
|
+
const reset = compact ? undefined : (resetLabel(budget.resetsAt, now) ?? budget.resetText);
|
|
215
231
|
return `${budget.label} ${bar} ${value}${reset ? ` · ${reset}` : ""}${staleText}`;
|
|
216
232
|
}
|
|
217
233
|
|
|
@@ -238,7 +254,12 @@ function repositorySegment(context: FooterContext, footerData: FooterData, theme
|
|
|
238
254
|
return theme.fg("dim", cwd);
|
|
239
255
|
}
|
|
240
256
|
|
|
241
|
-
function modelSegments(
|
|
257
|
+
function modelSegments(
|
|
258
|
+
context: FooterContext,
|
|
259
|
+
footerData: FooterData,
|
|
260
|
+
theme: FooterTheme,
|
|
261
|
+
thinkingLevel: string,
|
|
262
|
+
): { full: string; compact: string } {
|
|
242
263
|
const model = context.model;
|
|
243
264
|
const modelName = theme.bold(model?.id ?? "no-model");
|
|
244
265
|
const provider = model && footerData.getAvailableProviderCount() > 1 ? `(${model.provider}) ` : "";
|
|
@@ -312,7 +333,16 @@ export function installIntegratedFooter(ctx: ExtensionContext, state: Integrated
|
|
|
312
333
|
return {
|
|
313
334
|
invalidate() {},
|
|
314
335
|
render(width: number): string[] {
|
|
315
|
-
return renderFooterLines(
|
|
336
|
+
return renderFooterLines(
|
|
337
|
+
ctx as unknown as FooterContext,
|
|
338
|
+
footerData,
|
|
339
|
+
theme,
|
|
340
|
+
state.providerBudget,
|
|
341
|
+
getThinkingLevel(),
|
|
342
|
+
width,
|
|
343
|
+
Date.now(),
|
|
344
|
+
state.compaction,
|
|
345
|
+
);
|
|
316
346
|
},
|
|
317
347
|
dispose() {
|
|
318
348
|
unsubscribe?.();
|