@henryqw/pi-footer 5.1.2 → 5.1.4

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 CHANGED
@@ -30,9 +30,10 @@ Select `extensions/footer.ts` for only the footer, or use `pi config` to toggle
30
30
  | Package | Relationship | Purpose |
31
31
  | --- | --- | --- |
32
32
  | [`@henryqw/pi-codegraph`](https://pi.henry.wang/extensions/pi-codegraph) | Improves | Shows CodeGraph index status, quiet setup progress, and direct tool activity when loaded. |
33
- | [`@henryqw/pi-config-store`](https://pi.henry.wang/extensions/pi-config-store) | Required | Owns config-home resolution and storage. |
33
+ | [`@henryqw/pi-config-store`](https://pi.henry.wang/packages/pi-config-store) | Required | Owns config-home resolution and storage. |
34
34
  | [`@henryqw/pi-multi-codex`](https://pi.henry.wang/extensions/pi-multi-codex) | Improves | Adds active Codex subscription quota and reset status. |
35
35
  | [`@henryqw/pi-pr`](https://pi.henry.wang/extensions/pi-pr) | Improves | Adds current-branch pull-request status. |
36
+ | [`@henryqw/pi-subagent`](https://pi.henry.wang/extensions/pi-subagent) | Improves | Adds completed background workflow usage to the token and cost totals. |
36
37
 
37
38
  ## Use
38
39
 
@@ -298,9 +298,11 @@ export default function footerExtension(pi: ExtensionAPI): void {
298
298
  tps = milliseconds >= MIN_TPS_WINDOW_MS ? output / (milliseconds / 1000) : undefined;
299
299
  });
300
300
 
301
- // Session entries are append-only; the leaf also changes on tree navigation.
301
+ // Session entries are append-only; the leaf also changes on tree navigation. The routed model comes from
302
+ // the branch, so the selected model completes the context window identity.
302
303
  let usageKey: string | undefined;
303
304
  let routed: ReturnType<typeof latestResponse>;
305
+ let context: number | null | undefined;
304
306
  let input = 0;
305
307
  let output = 0;
306
308
  let cost = 0;
@@ -352,16 +354,16 @@ export default function footerExtension(pi: ExtensionAPI): void {
352
354
  invalidate() { },
353
355
  render(width: number): string[] {
354
356
  const entries = ctx.sessionManager.getEntries();
355
- const key = `${entries.length}:${ctx.sessionManager.getLeafId()}`;
357
+ const key = `${entries.length}:${ctx.sessionManager.getLeafId()}:${ctx.model?.provider}/${ctx.model?.id}`;
356
358
  if (key !== usageKey) {
357
359
  usageKey = key;
358
360
  computeUsage(entries);
359
361
  routed = latestResponse(ctx);
362
+ context = ctx.getContextUsage()?.percent;
360
363
  }
361
364
 
362
365
  const reportedBranch = data.getGitBranch()?.replace(/^worktree\//, "");
363
366
  const branch = reportedBranch === "detached" && gitSummary.detachedOid ? `@${gitSummary.detachedOid}` : reportedBranch;
364
- const context = ctx.getContextUsage()?.percent;
365
367
  const openUri = configuredOpenUri(ctx.cwd);
366
368
  const extensionStatuses = data.getExtensionStatuses();
367
369
  const prStatus = sanitizeStatus(extensionStatuses.get("pi-pr") ?? "");
@@ -1,3 +1,4 @@
1
+ import { statSync } from "node:fs";
1
2
  import { pathToFileURL } from "node:url";
2
3
  import { type ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
4
  import { type ConfigLoad, registerConfigReporting } from "@henryqw/pi-config-store";
@@ -10,11 +11,31 @@ export function loadOpenInConfig(agentDir?: string): ConfigLoad<OpenInConfig> {
10
11
  return createOpenInConfigStore(agentDir).loadSync();
11
12
  }
12
13
 
14
+ // The footer renders often; reload only when the config file identity changes.
15
+ let cachedCommand: { path: string; key: string | undefined; command: string | undefined } | undefined;
16
+
17
+ function configuredCommand(): string | undefined {
18
+ const store = createOpenInConfigStore();
19
+ let key: string | undefined;
20
+ try {
21
+ const { size, mtimeMs, ctimeMs } = statSync(store.path);
22
+ key = `${size}:${mtimeMs}:${ctimeMs}`;
23
+ } catch (error) {
24
+ // Other stat failures bypass the cache.
25
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") key = "missing";
26
+ }
27
+ if (key === undefined || cachedCommand?.path !== store.path || cachedCommand.key !== key) {
28
+ const loaded = store.loadSync();
29
+ cachedCommand = { path: store.path, key, command: loaded.status === "disabled" ? undefined : loaded.value.command };
30
+ }
31
+ return cachedCommand.command;
32
+ }
33
+
13
34
  /** Runs on every footer render, so it never notifies; the footer and open extensions report issues at session start. */
14
35
  export function configuredOpenUri(path: string): string | undefined {
15
- const loaded = loadOpenInConfig();
16
- if (loaded.status === "disabled") return undefined;
17
- const [executable, ...args] = loaded.value.command.split(/\s+/);
36
+ const command = configuredCommand();
37
+ if (command === undefined) return undefined;
38
+ const [executable, ...args] = command.split(/\s+/);
18
39
  if (executable !== "code") return undefined;
19
40
  const query = args.includes("-n") || args.includes("--new-window") ? "?windowId=_blank" : "";
20
41
  if (path.startsWith("\\\\")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henryqw/pi-footer",
3
- "version": "5.1.2",
3
+ "version": "5.1.4",
4
4
  "description": "Show repository and usage details in the Pi footer and open the current working directory.",
5
5
  "keywords": [
6
6
  "pi-package",