@henryqw/pi-footer 2.0.1 → 2.1.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/README.md +4 -3
- package/extensions/footer.ts +36 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ pi install npm:@henryqw/pi-footer
|
|
|
17
17
|
| [`@henryqw/pi-multi-codex`](https://pi.henry.wang/extensions/pi-multi-codex) | Improves | Adds active Codex subscription quota and reset status. |
|
|
18
18
|
| [`@henryqw/pi-open-in`](https://pi.henry.wang/extensions/pi-open-in) | Improves | Adds `/open` and `/set-open-in` commands for editor configuration. |
|
|
19
19
|
| [`@henryqw/pi-pr`](https://pi.henry.wang/extensions/pi-pr) | Improves | Adds current-branch pull-request status. |
|
|
20
|
+
| [`@henryqw/pi-codegraph`](https://pi.henry.wang/extensions/pi-codegraph) | Improves | Shows CodeGraph index and direct tool activity when loaded. |
|
|
20
21
|
|
|
21
22
|
## Use
|
|
22
23
|
|
|
@@ -25,12 +26,12 @@ The footer shows checkout, usage, model, thinking, and extension statuses.
|
|
|
25
26
|
```text
|
|
26
27
|
pi-harness · clear-field-f8d2 [+2 ~3 ?1 ↑2] · PR #123 · approved Codex #1 · 50% · 7d 1d 1h 22m
|
|
27
28
|
↑ 12.4k · ↓ 2.1k · ↺ 84.3% · ⚡ 87.4 t/s · $ 0.127 · ◔ 36.8% gpt-5.6-luna • high
|
|
28
|
-
● 🐴 ponytail: ⚡ FULL
|
|
29
|
+
✓ CG · ● 🐴 ponytail: ⚡ FULL ◷ 12m 34s
|
|
29
30
|
```
|
|
30
31
|
|
|
31
32
|
- The first line shows the repository, branch, Git state, and `pi-pr` pull request status. Linked-worktree branches drop the generated `worktree/` prefix.
|
|
32
33
|
- The second line shows cumulative input tokens, output tokens, latest cache-hit rate, and tokens per second for the most recent assistant response. It also shows estimated cost and context usage. Totals include reported tool usage and finished `pi-subagent` background workflows. The active model and thinking level are right-aligned.
|
|
33
|
-
- The third line shows
|
|
34
|
+
- The third line shows a compact CodeGraph badge first when loaded: `✓ CG` indexed, `● CG` in use, `◐ CG` checking or indexing, `○ CG` missing, `! CG` setup problem, or `? CG` unknown state. Its icon uses the active theme's state color; `CG` remains plain so the badge is readable without color. When pi-codegraph is not loaded, no badge appears. A middle dot separates statuses from different extensions; cumulative agent-work time stays on the right, beneath the active model.
|
|
34
35
|
|
|
35
36
|
Git badges appear only when action is needed:
|
|
36
37
|
|
|
@@ -57,7 +58,7 @@ Unavailable values render as `—` without a misleading percent sign.
|
|
|
57
58
|
|
|
58
59
|
Non-empty statuses from `@henryqw` extensions, currently Codex quota, occupy the right side of the first line.
|
|
59
60
|
|
|
60
|
-
Statuses from
|
|
61
|
+
Statuses from other extensions, including Ponytail and `pi-rewind`, share the left side. They are sorted by key with producer text, spacing, colors, links, and glyphs preserved. Scripted `mcpScript` calls are not visible as individual tool calls, so they do not trigger the `● CG` badge.
|
|
61
62
|
|
|
62
63
|
## Limits and recovery
|
|
63
64
|
|
package/extensions/footer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { getCapabilities, hyperlink, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
5
5
|
import { configuredOpenUri } from "@henryqw/pi-open-in/open-uri";
|
|
6
6
|
|
|
@@ -167,6 +167,26 @@ function rainbow(text: string): string {
|
|
|
167
167
|
return [...text].map((character, index) => color(character, colors[index % colors.length]!)).join("");
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
function isCodegraphCall(toolName: string, args: unknown): boolean {
|
|
171
|
+
if (toolName === "codegraph_explore") return true;
|
|
172
|
+
if (toolName !== "mcp" || !args || typeof args !== "object") return false;
|
|
173
|
+
const { tool, server } = args as { tool?: unknown; server?: unknown };
|
|
174
|
+
return server === "henryqw_pi-codegraph__codegraph" && typeof tool === "string" && tool.startsWith("codegraph_");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function codegraphBadge(status: string, inUse: boolean, theme: Theme): string {
|
|
178
|
+
if (inUse) return `${theme.fg("accent", "●")} CG`;
|
|
179
|
+
switch (status) {
|
|
180
|
+
case "pi-codegraph: indexed": return `${theme.fg("success", "✓")} CG`;
|
|
181
|
+
case "pi-codegraph: missing": return `${theme.fg("dim", "○")} CG`;
|
|
182
|
+
case "pi-codegraph: checking index…":
|
|
183
|
+
case "pi-codegraph: indexing…": return `${theme.fg("warning", "◐")} CG`;
|
|
184
|
+
case "pi-codegraph: prerequisites missing":
|
|
185
|
+
case "pi-codegraph: setup failed": return `${theme.fg("error", "!")} CG`;
|
|
186
|
+
default: return `${theme.fg("warning", "?")} CG`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
170
190
|
export default function footerExtension(pi: ExtensionAPI): void {
|
|
171
191
|
let activeMilliseconds = 0;
|
|
172
192
|
let activeStartedAt: number | undefined;
|
|
@@ -174,6 +194,15 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
174
194
|
let runtimeTimer: ReturnType<typeof setInterval> | undefined;
|
|
175
195
|
let requestRuntimeRender: (() => void) | undefined;
|
|
176
196
|
let refreshGitStatus: (() => Promise<void>) | undefined;
|
|
197
|
+
const activeCodegraphCalls = new Set<string>();
|
|
198
|
+
pi.on("tool_execution_start", (event) => {
|
|
199
|
+
if (!isCodegraphCall(event.toolName, event.args)) return;
|
|
200
|
+
activeCodegraphCalls.add(event.toolCallId);
|
|
201
|
+
requestRuntimeRender?.();
|
|
202
|
+
});
|
|
203
|
+
pi.on("tool_execution_end", (event) => {
|
|
204
|
+
if (activeCodegraphCalls.delete(event.toolCallId)) requestRuntimeRender?.();
|
|
205
|
+
});
|
|
177
206
|
const stopRuntimeTimer = () => {
|
|
178
207
|
if (runtimeTimer === undefined) return;
|
|
179
208
|
clearInterval(runtimeTimer);
|
|
@@ -230,6 +259,7 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
230
259
|
activeStartedAt = undefined;
|
|
231
260
|
promptPaused = false;
|
|
232
261
|
refreshGitStatus = undefined;
|
|
262
|
+
activeCodegraphCalls.clear();
|
|
233
263
|
});
|
|
234
264
|
|
|
235
265
|
pi.on("session_start", async (_event, ctx) => {
|
|
@@ -238,6 +268,7 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
238
268
|
promptPaused = false;
|
|
239
269
|
requestRuntimeRender = undefined;
|
|
240
270
|
refreshGitStatus = undefined;
|
|
271
|
+
activeCodegraphCalls.clear();
|
|
241
272
|
// Latest valid entry wins; stored data is untrusted.
|
|
242
273
|
activeMilliseconds = 0;
|
|
243
274
|
for (const entry of ctx.sessionManager.getEntries()) {
|
|
@@ -346,8 +377,10 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
346
377
|
const openUri = configuredOpenUri(ctx.cwd);
|
|
347
378
|
const extensionStatuses = data.getExtensionStatuses();
|
|
348
379
|
const prStatus = sanitizeStatus(extensionStatuses.get("pi-pr") ?? "");
|
|
380
|
+
const codegraphStatus = extensionStatuses.get("pi-codegraph");
|
|
381
|
+
const codegraph = codegraphStatus === undefined ? "" : codegraphBadge(codegraphStatus, activeCodegraphCalls.size > 0, theme);
|
|
349
382
|
const statuses = [...extensionStatuses]
|
|
350
|
-
.filter(([key]) => key !== "pi-pr")
|
|
383
|
+
.filter(([key]) => key !== "pi-pr" && key !== "pi-codegraph")
|
|
351
384
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
352
385
|
.map(([key, text]) => [key, sanitizeStatus(text)] as const)
|
|
353
386
|
.filter(([, text]) => Boolean(text));
|
|
@@ -385,7 +418,7 @@ export default function footerExtension(pi: ExtensionAPI): void {
|
|
|
385
418
|
const lines = [
|
|
386
419
|
firstLine,
|
|
387
420
|
align(usage, model, width, ellipsis),
|
|
388
|
-
alignRightReserved(externalStatuses.join(" "), runtime, width, ellipsis),
|
|
421
|
+
alignRightReserved([codegraph, ...externalStatuses].filter(Boolean).join(" · "), runtime, width, ellipsis),
|
|
389
422
|
];
|
|
390
423
|
return lines.map((line) => truncateToWidth(line, width, ellipsis));
|
|
391
424
|
},
|