@diegopetrucci/pi-extensions 0.1.69 → 0.1.70

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
@@ -18,7 +18,7 @@ A collection of [pi](https://pi.dev) agent extensions I made. (Btw, [I am also b
18
18
  ### UI
19
19
 
20
20
  - [`git-footer`](./extensions/git-footer): Standalone extension that adds TLH-style git dirty counts, ahead/behind, and optional PR number to pi's built-in footer status area.
21
- - [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch plus cached git dirty/ahead/PR status and repo on the first line, context/model on the second, optional `DUMB ZONE`, optional `xp` marker, plus OpenAI Codex 5-hour and 7-day usage when available.
21
+ - [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch plus cached git dirty/ahead/PR status and repo on the first line, context/model on the second, optional `DUMB ZONE`, optional `xp` marker, plus OpenAI Codex usage windows labeled from their reported durations.
22
22
  - [`quiet-tools`](./extensions/quiet-tools): Renders collapsed built-in tool rows as a one-line invocation plus an expand hint without changing model-visible tool results; toggle temporarily with `/quiet-tools`.
23
23
 
24
24
  ### / Slash commands
@@ -12,7 +12,7 @@ It replaces pi's built-in footer with a cleaner two-line layout that focuses on
12
12
  - current context percentage
13
13
  - red `DUMB ZONE` indicator when context usage is above 200k tokens
14
14
  - current model and thinking level
15
- - OpenAI Codex 5-hour and 7-day usage when available
15
+ - OpenAI Codex usage windows, labeled from the durations reported by OpenAI
16
16
  - `xp` marker when Pi experimental features are enabled
17
17
 
18
18
  ## Layout
@@ -45,12 +45,14 @@ When context usage is above 200k tokens, the bottom-left line includes a red war
45
45
  44.1% · DUMB ZONE
46
46
  ```
47
47
 
48
- When using `openai-codex`, the bottom-left line also includes subscription usage:
48
+ When using `openai-codex`, the bottom-left line also includes subscription usage. A typical account with both windows looks like:
49
49
 
50
50
  ```text
51
51
  44.1% · 5h 12% · 7d 38%
52
52
  ```
53
53
 
54
+ Window labels come from OpenAI's reported durations, so an account that reports only a weekly primary window is shown correctly (for example, `7d 38%`) instead of being assumed to have a 5-hour window.
55
+
54
56
  When `PI_EXPERIMENTAL=1`, the bottom-left line also includes an experimental marker:
55
57
 
56
58
  ```text
@@ -116,11 +118,11 @@ Example:
116
118
  "windows": {
117
119
  "primary": {
118
120
  "enabled": true,
119
- "label": "5h"
121
+ "label": "auto"
120
122
  },
121
123
  "secondary": {
122
124
  "enabled": true,
123
- "label": "7d"
125
+ "label": "auto"
124
126
  }
125
127
  }
126
128
  },
@@ -205,9 +207,9 @@ Disable git dirty/ahead/PR status:
205
207
  - `codexUsage.cacheTtlMs`: in-memory usage cache duration
206
208
  - `codexUsage.requestTimeoutMs`: usage request timeout
207
209
  - `codexUsage.windows.primary.enabled`: show the primary usage window
208
- - `codexUsage.windows.primary.label`: label for the primary usage window
210
+ - `codexUsage.windows.primary.label`: `"auto"` derives the primary label from OpenAI's reported duration; any other value overrides it
209
211
  - `codexUsage.windows.secondary.enabled`: show the secondary usage window
210
- - `codexUsage.windows.secondary.label`: label for the secondary usage window
212
+ - `codexUsage.windows.secondary.label`: `"auto"` derives the secondary label from OpenAI's reported duration; any other value overrides it
211
213
  - `experimentalMarker.enabled`: show the marker when `PI_EXPERIMENTAL=1`
212
214
  - `experimentalMarker.label`: marker text
213
215
  - `experimentalMarker.color`: theme color for the marker (`error`, `warning`, `accent`, `text`, or `dim`)
@@ -221,7 +223,7 @@ Disable git dirty/ahead/PR status:
221
223
  - **Top left:** current git branch plus dirty/ahead/PR status when available
222
224
  - **Top right:** current repo directory name
223
225
  - **Bottom left:** current context usage percentage, plus red `DUMB ZONE` above 200k context tokens
224
- - **Bottom left on `openai-codex`:** current context usage percentage plus 5-hour and 7-day Codex usage
226
+ - **Bottom left on `openai-codex`:** current context usage percentage plus the Codex usage windows reported for the account
225
227
  - **Bottom left with `PI_EXPERIMENTAL=1`:** current context usage percentage plus `xp`
226
228
  - **Bottom right:** model id and thinking level
227
229
 
@@ -237,5 +239,5 @@ This extension also lives inside the broader [`pi-extensions`](../../README.md)
237
239
  - Shows `DUMB ZONE` only while context usage is above 200k tokens.
238
240
  - Shows the model id rather than a provider-specific display label.
239
241
  - Shows `xp` when `PI_EXPERIMENTAL=1`.
240
- - For `openai-codex`, reads pi's stored OAuth login and fetches usage from ChatGPT's backend usage endpoint.
242
+ - For `openai-codex`, reads pi's stored OAuth login and fetches usage from ChatGPT's backend usage endpoint. Window labels are inferred from each window's reported duration; missing or unrecognized durations use neutral `usage` labels rather than guessing from window position.
241
243
  - Usage is cached briefly in memory and refreshed after turns.
@@ -33,11 +33,11 @@ const DEFAULT_CONFIG: MinimalFooterConfig = {
33
33
  windows: {
34
34
  primary: {
35
35
  enabled: true,
36
- label: "5h",
36
+ label: "auto",
37
37
  },
38
38
  secondary: {
39
39
  enabled: true,
40
- label: "7d",
40
+ label: "auto",
41
41
  },
42
42
  },
43
43
  },
@@ -15,11 +15,11 @@
15
15
  "windows": {
16
16
  "primary": {
17
17
  "enabled": true,
18
- "label": "5h"
18
+ "label": "auto"
19
19
  },
20
20
  "secondary": {
21
21
  "enabled": true,
22
- "label": "7d"
22
+ "label": "auto"
23
23
  }
24
24
  }
25
25
  },
@@ -5,6 +5,7 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
5
5
  const PROVIDER_ID = "openai-codex";
6
6
 
7
7
  interface WhamUsageWindow {
8
+ limit_window_seconds?: number;
8
9
  reset_at?: number;
9
10
  used_percent?: number;
10
11
  }
@@ -18,6 +19,7 @@ interface WhamUsageResponse {
18
19
 
19
20
  export interface UsageWindow {
20
21
  usedPercent?: number;
22
+ windowSeconds?: number;
21
23
  resetAt?: number;
22
24
  }
23
25
 
@@ -43,6 +45,11 @@ function normalizeUsedPercent(value?: number): number | undefined {
43
45
  return Math.min(100, Math.max(0, value));
44
46
  }
45
47
 
48
+ function normalizeWindowSeconds(value?: number): number | undefined {
49
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return undefined;
50
+ return value;
51
+ }
52
+
46
53
  function normalizeResetAt(value?: number): number | undefined {
47
54
  if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
48
55
  return value * 1000;
@@ -51,9 +58,10 @@ function normalizeResetAt(value?: number): number | undefined {
51
58
  function parseUsageWindow(window?: WhamUsageWindow): UsageWindow | undefined {
52
59
  if (!window) return undefined;
53
60
  const usedPercent = normalizeUsedPercent(window.used_percent);
61
+ const windowSeconds = normalizeWindowSeconds(window.limit_window_seconds);
54
62
  const resetAt = normalizeResetAt(window.reset_at);
55
- if (usedPercent === undefined && resetAt === undefined) return undefined;
56
- return { usedPercent, resetAt };
63
+ if (usedPercent === undefined && windowSeconds === undefined && resetAt === undefined) return undefined;
64
+ return { usedPercent, windowSeconds, resetAt };
57
65
  }
58
66
 
59
67
  function parseUsageSnapshot(data: WhamUsageResponse): Omit<UsageSnapshot, "fetchedAt"> {
@@ -125,6 +133,36 @@ function formatUsagePercent(value?: number): string | undefined {
125
133
  return `${Math.round(value)}%`;
126
134
  }
127
135
 
136
+ // Primary/secondary describe positions, not fixed periods. Match each reported
137
+ // duration the same way Codex does, allowing small backend rounding differences.
138
+ const KNOWN_WINDOW_LABELS: ReadonlyArray<{ seconds: number; label: string }> = [
139
+ { seconds: 5 * 60 * 60, label: "5h" },
140
+ { seconds: 24 * 60 * 60, label: "1d" },
141
+ { seconds: 7 * 24 * 60 * 60, label: "7d" },
142
+ { seconds: 30 * 24 * 60 * 60, label: "30d" },
143
+ { seconds: 365 * 24 * 60 * 60, label: "365d" },
144
+ ];
145
+
146
+ function isApproximateWindow(actualSeconds: number, expectedSeconds: number): boolean {
147
+ return Math.abs(actualSeconds - expectedSeconds) <= expectedSeconds * 0.05;
148
+ }
149
+
150
+ function formatUsageWindowLabel(
151
+ window: UsageWindow | undefined,
152
+ configuredLabel: string,
153
+ fallbackLabel: string,
154
+ ): string {
155
+ if (configuredLabel.toLowerCase() !== "auto") return configuredLabel;
156
+ const windowSeconds = window?.windowSeconds;
157
+ if (windowSeconds !== undefined) {
158
+ const knownWindow = KNOWN_WINDOW_LABELS.find(({ seconds }) =>
159
+ isApproximateWindow(windowSeconds, seconds)
160
+ );
161
+ if (knownWindow) return knownWindow.label;
162
+ }
163
+ return fallbackLabel;
164
+ }
165
+
128
166
  export function isOpenAICodexProvider(provider?: string): boolean {
129
167
  return provider === PROVIDER_ID;
130
168
  }
@@ -139,8 +177,18 @@ export function formatUsageSummary(
139
177
  const secondary = formatUsagePercent(snapshot.secondary?.usedPercent);
140
178
  const parts: string[] = [];
141
179
 
142
- if (windows.primary.enabled && primary) parts.push(`${windows.primary.label} ${primary}`);
143
- if (windows.secondary.enabled && secondary) parts.push(`${windows.secondary.label} ${secondary}`);
180
+ if (windows.primary.enabled && primary) {
181
+ const label = formatUsageWindowLabel(snapshot.primary, windows.primary.label, "usage");
182
+ parts.push(`${label} ${primary}`);
183
+ }
184
+ if (windows.secondary.enabled && secondary) {
185
+ const label = formatUsageWindowLabel(
186
+ snapshot.secondary,
187
+ windows.secondary.label,
188
+ "secondary usage",
189
+ );
190
+ parts.push(`${label} ${secondary}`);
191
+ }
144
192
 
145
193
  return parts.length > 0 ? parts.join(" · ") : undefined;
146
194
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-minimal-footer",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "A minimal custom footer for pi.",
5
5
  "keywords": [
6
6
  "pi-package",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-extensions",
3
- "version": "0.1.69",
3
+ "version": "0.1.70",
4
4
  "description": "A collection of pi extensions and skills for annotation UIs, context management, workflow audits, contrarian review, review-comment triage, notifications, brrr push alerts, safety guards, GitHub research, repo-local knowledge, todos, tool rendering, model/provider helpers, and Xiaohei-style article illustrations.",
5
5
  "keywords": [
6
6
  "pi-package",