@henryqw/pi-footer 0.5.2 → 0.5.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/README.md +3 -3
- package/extensions/footer.ts +36 -6
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -37,15 +37,15 @@ First line shows repository, branch, and pull request status (`pi-pr`) after cli
|
|
|
37
37
|
|
|
38
38
|
Second line shows cumulative input tokens, output tokens, latest cache-hit rate, tokens per second of the most recent assistant response, estimated cost, and context usage. Unavailable values render as `—` without a misleading percent sign. Active model and thinking level are right-aligned.
|
|
39
39
|
|
|
40
|
-
`off` uses the same dim grey as the model name. Active levels use an ANSI-256 gradient: green `minimal`, yellow-green `low`, lime `medium`, yellow `high`, orange `xhigh`, and red `max`. `ultra` renders as a rainbow when the runtime supplies it. Pi 0.84.
|
|
40
|
+
`off` uses the same dim grey as the model name. Active levels use an ANSI-256 gradient: green `minimal`, yellow-green `low`, lime `medium`, yellow `high`, orange `xhigh`, and red `max`. `ultra` renders as a rainbow when the runtime supplies it. Pi 0.84.4 does not yet accept `ultra`, so that footer path remains unreachable until Pi adds it.
|
|
41
41
|
|
|
42
|
-
Third line shows cumulative agent-work time right-aligned beneath the model. It counts each run from `agent_start` through the final idle `agent_settled`, including automatic retries and auto-compaction inside that run, and excludes idle waits between runs. Standalone `/compact` is excluded because it runs outside the agent-run lifecycle and emits no `agent_start`. The cumulative total is persisted in the session via a `pi-footer:agent-work` custom entry after each finalized run and restored on session resume. Non-empty statuses from `@henryqw` extensions, currently Codex quota, share the left side.
|
|
42
|
+
Third line shows cumulative agent-work time right-aligned beneath the model. It counts each run from `agent_start` through the final idle `agent_settled`, including automatic retries and auto-compaction inside that run, and excludes blocking user-prompt waits and idle waits between runs. Standalone `/compact` is excluded because it runs outside the agent-run lifecycle and emits no `agent_start`. The cumulative total is persisted in the session via a `pi-footer:agent-work` custom entry after each finalized run and restored on session resume. Non-empty statuses from `@henryqw` extensions, currently Codex quota, share the left side.
|
|
43
43
|
|
|
44
44
|
Fourth line renders statuses from all other extensions, including Ponytail and `pi-rewind`. Statuses are sorted by key; producer text, spacing, colors, links, and glyphs are preserved.
|
|
45
45
|
|
|
46
46
|
## Clickable checkout
|
|
47
47
|
|
|
48
|
-
When `pi-open-in.json` command is exactly `code
|
|
48
|
+
When `pi-open-in.json` command is exactly `code` and Pi reports hyperlink support, the accent-colored checkout name is an OSC 8 `vscode://` link to the current path. Other configured commands and terminals with hyperlinks disabled render plain text.
|
|
49
49
|
|
|
50
50
|
Use Pi fullscreen TUI so Pi handles the custom URI:
|
|
51
51
|
|
package/extensions/footer.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { basename, dirname } from "node:path";
|
|
2
2
|
import type { Usage } from "@earendil-works/pi-ai";
|
|
3
3
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { hyperlink, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
4
|
+
import { getCapabilities, hyperlink, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
5
5
|
import { configuredOpenUri } from "@henryqw/pi-open-in/open-uri";
|
|
6
6
|
|
|
7
7
|
const THINKING_COLORS = {
|
|
@@ -63,6 +63,7 @@ function rainbow(text: string): string {
|
|
|
63
63
|
export default function footerExtension(pi: ExtensionAPI): void {
|
|
64
64
|
let activeMilliseconds = 0;
|
|
65
65
|
let activeStartedAt: number | undefined;
|
|
66
|
+
let promptPaused = false;
|
|
66
67
|
let runtimeTimer: ReturnType<typeof setInterval> | undefined;
|
|
67
68
|
let requestRuntimeRender: (() => void) | undefined;
|
|
68
69
|
const stopRuntimeTimer = () => {
|
|
@@ -72,15 +73,31 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
const startActive = () => {
|
|
75
|
-
if (activeStartedAt !== undefined) return;
|
|
76
|
+
if (activeStartedAt !== undefined || promptPaused) return;
|
|
76
77
|
activeStartedAt = performance.now();
|
|
77
78
|
if (requestRuntimeRender) runtimeTimer = setInterval(requestRuntimeRender, 1_000);
|
|
78
79
|
requestRuntimeRender?.();
|
|
79
80
|
};
|
|
80
|
-
const
|
|
81
|
-
if (activeStartedAt === undefined) return
|
|
81
|
+
const pauseActive = () => {
|
|
82
|
+
if (activeStartedAt === undefined) return;
|
|
82
83
|
activeMilliseconds += performance.now() - activeStartedAt;
|
|
83
84
|
activeStartedAt = undefined;
|
|
85
|
+
promptPaused = true;
|
|
86
|
+
stopRuntimeTimer();
|
|
87
|
+
requestRuntimeRender?.();
|
|
88
|
+
};
|
|
89
|
+
const resumeActive = () => {
|
|
90
|
+
if (!promptPaused) return;
|
|
91
|
+
promptPaused = false;
|
|
92
|
+
activeStartedAt = performance.now();
|
|
93
|
+
if (requestRuntimeRender) runtimeTimer = setInterval(requestRuntimeRender, 1_000);
|
|
94
|
+
requestRuntimeRender?.();
|
|
95
|
+
};
|
|
96
|
+
const finalizeActive = (): boolean => {
|
|
97
|
+
if (activeStartedAt === undefined && !promptPaused) return false;
|
|
98
|
+
if (activeStartedAt !== undefined) activeMilliseconds += performance.now() - activeStartedAt;
|
|
99
|
+
activeStartedAt = undefined;
|
|
100
|
+
promptPaused = false;
|
|
84
101
|
stopRuntimeTimer();
|
|
85
102
|
requestRuntimeRender?.();
|
|
86
103
|
return true;
|
|
@@ -89,14 +106,25 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
89
106
|
pi.on("agent_start", (_event) => {
|
|
90
107
|
startActive();
|
|
91
108
|
});
|
|
109
|
+
pi.on("ui_prompt_start", () => {
|
|
110
|
+
pauseActive();
|
|
111
|
+
});
|
|
112
|
+
pi.on("ui_prompt_end", () => {
|
|
113
|
+
resumeActive();
|
|
114
|
+
});
|
|
92
115
|
pi.on("agent_settled", (_event, ctx) => {
|
|
93
116
|
if (ctx.isIdle() && finalizeActive()) pi.appendEntry(AGENT_TIME_ENTRY, activeMilliseconds);
|
|
94
117
|
});
|
|
95
|
-
pi.on("session_shutdown", () =>
|
|
118
|
+
pi.on("session_shutdown", () => {
|
|
119
|
+
stopRuntimeTimer();
|
|
120
|
+
activeStartedAt = undefined;
|
|
121
|
+
promptPaused = false;
|
|
122
|
+
});
|
|
96
123
|
|
|
97
124
|
pi.on("session_start", async (_event, ctx) => {
|
|
98
125
|
stopRuntimeTimer();
|
|
99
126
|
activeStartedAt = undefined;
|
|
127
|
+
promptPaused = false;
|
|
100
128
|
requestRuntimeRender = undefined;
|
|
101
129
|
// Latest valid entry wins; stored data is untrusted.
|
|
102
130
|
activeMilliseconds = 0;
|
|
@@ -215,7 +243,9 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
215
243
|
const runtime = theme.fg("dim", `◷ ${formatDuration(elapsed)}`);
|
|
216
244
|
const identity = branch ? theme.fg("dim", `${repo} · `) : "";
|
|
217
245
|
const checkout = branch ?? repo;
|
|
218
|
-
const checkoutLink = openUri
|
|
246
|
+
const checkoutLink = openUri && getCapabilities().hyperlinks
|
|
247
|
+
? hyperlink(theme.fg("accent", checkout), openUri)
|
|
248
|
+
: theme.fg("dim", checkout);
|
|
219
249
|
const firstLine = prStatus ? `${identity}${checkoutLink} · ${prStatus}` : `${identity}${checkoutLink}`;
|
|
220
250
|
const lines = [
|
|
221
251
|
firstLine,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henryqw/pi-footer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Show concise repository, branch, and usage details in the Pi footer.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"pack:check": "npm pack --dry-run"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@earendil-works/pi-ai": "^0.84.
|
|
28
|
-
"@earendil-works/pi-coding-agent": "^0.84.
|
|
29
|
-
"@earendil-works/pi-tui": "^0.84.
|
|
27
|
+
"@earendil-works/pi-ai": "^0.84.4",
|
|
28
|
+
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
29
|
+
"@earendil-works/pi-tui": "^0.84.4"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|