@hank-warren/pi-statusline 0.7.2 → 0.7.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/CHANGELOG.md +6 -0
- package/cache-celebration.ts +3 -3
- package/celebration-preview.ts +1 -1
- package/celebration-styles.ts +3 -3
- package/index.ts +1 -1
- package/package.json +2 -2
- package/redraw.ts +1 -1
- package/settings-menu.ts +1 -1
- package/settings.ts +17 -7
- package/usage.ts +9 -6
- package/worktrees.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @hank-warren/pi-statusline
|
|
2
2
|
|
|
3
|
+
## 0.7.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d0c46a5: Resolve `auth.json`, the usage cache and `statusline-settings.json` through Pi's agent directory (`PI_CODING_AGENT_DIR`) instead of a hardcoded `~/.pi/agent`. Behaviour is unchanged for a normal install; a session started with a scratch agent dir no longer reads the real credentials or writes the real usage cache. `engines.node` now states Pi's own floor, `>=22.19.0`.
|
|
8
|
+
|
|
3
9
|
## 0.7.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/cache-celebration.ts
CHANGED
|
@@ -2,7 +2,7 @@ export const CACHE_HIT_THRESHOLD = 0.96;
|
|
|
2
2
|
export const CACHE_CELEBRATION_FRAME_INTERVAL_MS = 60;
|
|
3
3
|
export const CACHE_CELEBRATION_DURATION_MS = 2_000;
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
interface CacheUsage {
|
|
6
6
|
input: number;
|
|
7
7
|
cacheRead: number;
|
|
8
8
|
cacheWrite: number;
|
|
@@ -13,11 +13,11 @@ export interface CacheCelebrationSnapshot {
|
|
|
13
13
|
frame: number;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
interface CacheCelebrationTarget {
|
|
17
17
|
start(percent: number): void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
interface CacheCelebrationControllerOptions {
|
|
21
21
|
frameIntervalMs?: number;
|
|
22
22
|
durationMs?: number;
|
|
23
23
|
now?: () => number;
|
package/celebration-preview.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { SettingsListTheme } from "@earendil-works/pi-tui";
|
|
|
7
7
|
/** Percentage shown by the settings-menu preview badge. */
|
|
8
8
|
export const PREVIEW_PERCENT = 96;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
interface CelebrationPreviewOptions {
|
|
11
11
|
frameIntervalMs?: number;
|
|
12
12
|
schedule?: (callback: () => void, intervalMs: number) => unknown;
|
|
13
13
|
cancel?: (handle: unknown) => void;
|
package/celebration-styles.ts
CHANGED
|
@@ -11,13 +11,13 @@ import type { StatuslinePalette } from "./themes.ts";
|
|
|
11
11
|
const RESET = "\x1b[0m";
|
|
12
12
|
const BOLD = "\x1b[1m";
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
interface Rgb {
|
|
15
15
|
r: number;
|
|
16
16
|
g: number;
|
|
17
17
|
b: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const fgCode = ({ r, g, b }: Rgb): string =>
|
|
21
21
|
`\x1b[38;2;${Math.round(r)};${Math.round(g)};${Math.round(b)}m`;
|
|
22
22
|
|
|
23
23
|
/** Parse an SGR true-colour prefix back into channels; anything else reads as white. */
|
|
@@ -68,7 +68,7 @@ function hue(degrees: number): Rgb {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/** Colour every character of `badge` for one frame. */
|
|
71
|
-
|
|
71
|
+
type CelebrationStyle = (badge: string, frame: number, palette: StatuslinePalette) => string;
|
|
72
72
|
|
|
73
73
|
const uniform = (badge: string, colour: Rgb): string => `${BOLD}${fgCode(colour)}${badge}${RESET}`;
|
|
74
74
|
|
package/index.ts
CHANGED
|
@@ -124,7 +124,7 @@ function renderRepository(
|
|
|
124
124
|
return part;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
function renderCacheCelebrationLine(
|
|
128
128
|
summary: string,
|
|
129
129
|
celebration: CacheCelebrationSnapshot,
|
|
130
130
|
palette: StatuslinePalette = DEFAULT_PALETTE,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hank-warren/pi-statusline",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Compact Pi footer statusline with Git/worktree context, token usage, and neon celebrations for exceptional prompt-cache hits.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/hank-warren/pi-extensions/tree/main/packages/pi-statusline#readme",
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
26
|
+
"node": ">=22.19.0"
|
|
27
27
|
},
|
|
28
28
|
"pi": {
|
|
29
29
|
"extensions": [
|
package/redraw.ts
CHANGED
package/settings-menu.ts
CHANGED
package/settings.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, isAbsolute, join } from "node:path";
|
|
4
4
|
import { pid } from "node:process";
|
|
5
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
5
6
|
import {
|
|
6
7
|
type CelebrationStyleName,
|
|
7
8
|
DEFAULT_CELEBRATION_STYLE,
|
|
@@ -34,7 +35,7 @@ export interface StatuslineSettings extends Record<BooleanSettingKey, boolean> {
|
|
|
34
35
|
repoAliases: Record<string, string>;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
function defaultWorktreeRoot(home: string = homedir()): string {
|
|
38
39
|
return join(home || homedir(), "repos", "worktrees");
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -56,8 +57,17 @@ export function defaultSettings(home: string = homedir()): StatuslineSettings {
|
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Where the settings live when the caller names no path.
|
|
62
|
+
*
|
|
63
|
+
* The agent dir, not the home dir: pi honours `PI_CODING_AGENT_DIR`, so a
|
|
64
|
+
* session running against a scratch agent dir must save its statusline settings
|
|
65
|
+
* there rather than into the host's real `~/.pi/agent`. `home` still shapes the
|
|
66
|
+
* settings' *content* (the worktree root default, `~` collapsing) — that is a
|
|
67
|
+
* different thing and keeps its own parameter.
|
|
68
|
+
*/
|
|
69
|
+
export function defaultSettingsPath(): string {
|
|
70
|
+
return join(getAgentDir(), "statusline-settings.json");
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
/** Expand a leading `~` (and `$HOME`) against `home`; other paths are returned as-is. */
|
|
@@ -78,7 +88,7 @@ export function collapseHome(path: string, home: string = homedir()): string {
|
|
|
78
88
|
return path.startsWith(`${base}/`) ? `~/${path.slice(base.length + 1)}` : path;
|
|
79
89
|
}
|
|
80
90
|
|
|
81
|
-
|
|
91
|
+
interface WorktreeRootResult {
|
|
82
92
|
path?: string;
|
|
83
93
|
error?: string;
|
|
84
94
|
}
|
|
@@ -109,7 +119,7 @@ function normalizeAliases(value: unknown): Record<string, string> | undefined {
|
|
|
109
119
|
return aliases;
|
|
110
120
|
}
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
interface NormalizedSettings {
|
|
113
123
|
settings: StatuslineSettings;
|
|
114
124
|
/** Top-level keys this version does not know about, preserved on write. */
|
|
115
125
|
extra: Record<string, unknown>;
|
|
@@ -225,7 +235,7 @@ export function serializeSettings(
|
|
|
225
235
|
return out;
|
|
226
236
|
}
|
|
227
237
|
|
|
228
|
-
|
|
238
|
+
interface SettingsStoreOptions {
|
|
229
239
|
path?: string;
|
|
230
240
|
home?: string;
|
|
231
241
|
}
|
|
@@ -242,7 +252,7 @@ export class SettingsStore {
|
|
|
242
252
|
|
|
243
253
|
constructor(options: SettingsStoreOptions = {}) {
|
|
244
254
|
this.home = options.home ?? homedir();
|
|
245
|
-
this.path = options.path ?? defaultSettingsPath(
|
|
255
|
+
this.path = options.path ?? defaultSettingsPath();
|
|
246
256
|
this.current = defaultSettings(this.home);
|
|
247
257
|
}
|
|
248
258
|
|
package/usage.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
3
|
import { join } from "node:path";
|
|
5
4
|
import { pid } from "node:process";
|
|
5
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Remaining (not used) integer percents per provider window.
|
|
@@ -84,7 +84,7 @@ export const USAGE_RATE_LIMIT_BACKOFF_MS = 15 * 60_000;
|
|
|
84
84
|
* process's fresh values appear within one tick instead of at the next turn.
|
|
85
85
|
* Request volume is unchanged: both throttles still gate every fetch.
|
|
86
86
|
*/
|
|
87
|
-
|
|
87
|
+
const USAGE_TICK_INTERVAL_MS = 10_000;
|
|
88
88
|
const FETCH_TIMEOUT_MS = 10_000;
|
|
89
89
|
const ONE_DAY_SECONDS = 86_400;
|
|
90
90
|
|
|
@@ -283,7 +283,7 @@ type ProviderKey = "claude" | "codex";
|
|
|
283
283
|
const PROVIDER_KEYS = ["claude", "codex"] as const;
|
|
284
284
|
|
|
285
285
|
/** Provider ids whose additional logins (`${base}-${suffix}`) share a meter. */
|
|
286
|
-
|
|
286
|
+
const USAGE_BASE_PROVIDERS: Record<ProviderKey, string> = {
|
|
287
287
|
claude: "anthropic",
|
|
288
288
|
codex: "openai-codex",
|
|
289
289
|
};
|
|
@@ -295,7 +295,7 @@ const PROVIDER_REFRESH_INTERVAL_MS: Record<ProviderKey, number> = {
|
|
|
295
295
|
};
|
|
296
296
|
|
|
297
297
|
/** Credential id polled for each family. */
|
|
298
|
-
|
|
298
|
+
type UsageAccounts = Record<ProviderKey, string>;
|
|
299
299
|
|
|
300
300
|
/** A freshly fetched value together with the boundary it is valid until. */
|
|
301
301
|
interface FetchedUsage<K extends ProviderKey> {
|
|
@@ -477,8 +477,11 @@ export class UsageTracker {
|
|
|
477
477
|
private tickHandle: unknown;
|
|
478
478
|
|
|
479
479
|
constructor(options: UsageTrackerOptions = {}) {
|
|
480
|
-
|
|
481
|
-
|
|
480
|
+
// getAgentDir(), not ~/.pi/agent: pi honours PI_CODING_AGENT_DIR, and a
|
|
481
|
+
// hardcoded home path made a session pointed at another agent dir read the
|
|
482
|
+
// wrong credentials and write its usage cache into the host's real one.
|
|
483
|
+
this.authPath = options.authPath ?? join(getAgentDir(), "auth.json");
|
|
484
|
+
this.cachePath = options.cachePath ?? join(getAgentDir(), "statusline-usage.json");
|
|
482
485
|
this.fetchFn = options.fetchFn ?? ((url, init) => fetch(url, init));
|
|
483
486
|
this.onChange = options.onChange;
|
|
484
487
|
this.now = options.now ?? Date.now;
|