@diegopetrucci/pi-extensions 0.1.11 → 0.1.13

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  A collection of [pi](https://github.com/badlogic/pi-mono) agent extensions I made:
4
4
 
5
- - [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal two-line layout: branch/repo on the first line, context/model on the second, plus OpenAI Codex 5-hour and 7-day usage when available.
5
+ - [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch/repo on the first line, context/model on the second, optional `DUMB ZONE`, plus OpenAI Codex 5-hour and 7-day usage when available.
6
6
  - [`oracle`](./extensions/oracle): Adds an Amp-style read-only oracle tool that auto-selects the strongest reasoning model on the current provider/subscription, covers pi’s built-in providers with hardcoded rankings, sets reasoning to xhigh by default, and shows live status while running.
7
7
  - [`permission-gate`](./extensions/permission-gate): Prompts for confirmation before dangerous bash commands like `rm -rf`, `sudo`, and `chmod 777`.
8
8
  - [`confirm-destructive`](./extensions/confirm-destructive): Confirms before destructive session actions like clear, switch, and fork.
@@ -21,7 +21,7 @@ pi install npm:@diegopetrucci/pi-extensions
21
21
  Or pin the GitHub package to this release:
22
22
 
23
23
  ```bash
24
- pi install git:github.com/diegopetrucci/pi-extensions@v0.1.11
24
+ pi install git:github.com/diegopetrucci/pi-extensions@v0.1.13
25
25
  ```
26
26
 
27
27
  Or a specific extension:
@@ -9,6 +9,7 @@ It replaces pi's built-in footer with a cleaner two-line layout that focuses on
9
9
  - current git branch
10
10
  - current repo name
11
11
  - current context percentage
12
+ - red `DUMB ZONE` indicator when context usage is above 200k tokens
12
13
  - current model and thinking level
13
14
  - OpenAI Codex 5-hour and 7-day usage when available
14
15
 
@@ -28,6 +29,12 @@ fix/remove-detached-image-tasks SendItToMy
28
29
  44.1% gpt-5.4 high
29
30
  ```
30
31
 
32
+ When context usage is above 200k tokens, the bottom-left line includes a red warning:
33
+
34
+ ```text
35
+ 44.1% · DUMB ZONE
36
+ ```
37
+
31
38
  When using `openai-codex`, the bottom-left line also includes subscription usage:
32
39
 
33
40
  ```text
@@ -62,11 +69,102 @@ Then reload pi:
62
69
  /reload
63
70
  ```
64
71
 
72
+ ## Configuration
73
+
74
+ Config files are merged, with project config overriding global config:
75
+
76
+ - `~/.pi/agent/extensions/minimal-footer.json`
77
+ - `<project>/.pi/minimal-footer.json`
78
+
79
+ A ready-to-copy sample file is included at [`minimal-footer.example.json`](./minimal-footer.example.json).
80
+
81
+ Example:
82
+
83
+ ```json
84
+ {
85
+ "context": {
86
+ "showPercent": true,
87
+ "dumbZone": {
88
+ "enabled": true,
89
+ "thresholdTokens": 200000,
90
+ "label": "DUMB ZONE",
91
+ "color": "error"
92
+ }
93
+ },
94
+ "codexUsage": {
95
+ "enabled": true,
96
+ "cacheTtlMs": 300000,
97
+ "requestTimeoutMs": 10000,
98
+ "windows": {
99
+ "primary": {
100
+ "enabled": true,
101
+ "label": "5h"
102
+ },
103
+ "secondary": {
104
+ "enabled": true,
105
+ "label": "7d"
106
+ }
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ Disable `DUMB ZONE`:
113
+
114
+ ```json
115
+ {
116
+ "context": {
117
+ "dumbZone": {
118
+ "enabled": false
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ Disable OpenAI Codex session-limit usage entirely:
125
+
126
+ ```json
127
+ {
128
+ "codexUsage": {
129
+ "enabled": false
130
+ }
131
+ }
132
+ ```
133
+
134
+ Disable one session-limit window:
135
+
136
+ ```json
137
+ {
138
+ "codexUsage": {
139
+ "windows": {
140
+ "secondary": {
141
+ "enabled": false
142
+ }
143
+ }
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Config fields
149
+
150
+ - `context.showPercent`: show the context percentage
151
+ - `context.dumbZone.enabled`: show `DUMB ZONE` when context tokens exceed the threshold
152
+ - `context.dumbZone.thresholdTokens`: token threshold for `DUMB ZONE`
153
+ - `context.dumbZone.label`: warning text
154
+ - `context.dumbZone.color`: theme color for the warning (`error`, `warning`, `accent`, `text`, or `dim`)
155
+ - `codexUsage.enabled`: show OpenAI Codex session-limit usage when using `openai-codex`
156
+ - `codexUsage.cacheTtlMs`: in-memory usage cache duration
157
+ - `codexUsage.requestTimeoutMs`: usage request timeout
158
+ - `codexUsage.windows.primary.enabled`: show the primary usage window
159
+ - `codexUsage.windows.primary.label`: label for the primary usage window
160
+ - `codexUsage.windows.secondary.enabled`: show the secondary usage window
161
+ - `codexUsage.windows.secondary.label`: label for the secondary usage window
162
+
65
163
  ## What it shows
66
164
 
67
165
  - **Top left:** current git branch
68
166
  - **Top right:** current repo directory name
69
- - **Bottom left:** current context usage percentage
167
+ - **Bottom left:** current context usage percentage, plus red `DUMB ZONE` above 200k context tokens
70
168
  - **Bottom left on `openai-codex`:** current context usage percentage plus 5-hour and 7-day Codex usage
71
169
  - **Bottom right:** model id and thinking level
72
170
 
@@ -79,6 +177,7 @@ This extension also lives inside the broader [`pi-extensions`](../../README.md)
79
177
  - Replaces pi's built-in footer entirely.
80
178
  - Uses pi footer data for git branch updates.
81
179
  - Shows only context percentage, not context window size.
180
+ - Shows `DUMB ZONE` only while context usage is above 200k tokens.
82
181
  - Shows the model id rather than a provider-specific display label.
83
182
  - For `openai-codex`, reads pi's stored OAuth login and fetches usage from ChatGPT's backend usage endpoint.
84
183
  - Usage is cached briefly in memory and refreshed after turns.
@@ -1,6 +1,8 @@
1
- import { basename } from "node:path";
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
2
3
  import {
3
4
  AuthStorage,
5
+ getAgentDir,
4
6
  type ExtensionAPI,
5
7
  type ExtensionContext,
6
8
  } from "@mariozechner/pi-coding-agent";
@@ -12,11 +14,77 @@ import {
12
14
  type UsageSnapshot,
13
15
  } from "./openai-usage";
14
16
 
15
- const USAGE_CACHE_TTL_MS = 5 * 60 * 1000;
16
- const USAGE_REQUEST_TIMEOUT_MS = 10 * 1000;
17
+ const DEFAULT_CONFIG: MinimalFooterConfig = {
18
+ context: {
19
+ showPercent: true,
20
+ dumbZone: {
21
+ enabled: true,
22
+ thresholdTokens: 200_000,
23
+ label: "DUMB ZONE",
24
+ color: "error",
25
+ },
26
+ },
27
+ codexUsage: {
28
+ enabled: true,
29
+ cacheTtlMs: 5 * 60 * 1000,
30
+ requestTimeoutMs: 10 * 1000,
31
+ windows: {
32
+ primary: {
33
+ enabled: true,
34
+ label: "5h",
35
+ },
36
+ secondary: {
37
+ enabled: true,
38
+ label: "7d",
39
+ },
40
+ },
41
+ },
42
+ };
43
+
44
+ const DUMB_ZONE_COLORS = new Set<DumbZoneColor>([
45
+ "error",
46
+ "warning",
47
+ "accent",
48
+ "text",
49
+ "dim",
50
+ ]);
51
+
52
+ type RecursivePartial<T> = {
53
+ [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P];
54
+ };
55
+
56
+ type DumbZoneColor = "error" | "warning" | "accent" | "text" | "dim";
57
+
58
+ interface MinimalFooterConfig {
59
+ context: {
60
+ showPercent: boolean;
61
+ dumbZone: {
62
+ enabled: boolean;
63
+ thresholdTokens: number;
64
+ label: string;
65
+ color: DumbZoneColor;
66
+ };
67
+ };
68
+ codexUsage: {
69
+ enabled: boolean;
70
+ cacheTtlMs: number;
71
+ requestTimeoutMs: number;
72
+ windows: {
73
+ primary: {
74
+ enabled: boolean;
75
+ label: string;
76
+ };
77
+ secondary: {
78
+ enabled: boolean;
79
+ label: string;
80
+ };
81
+ };
82
+ };
83
+ }
17
84
 
18
85
  type UsageSessionState = {
19
86
  authStorage: AuthStorage;
87
+ config: MinimalFooterConfig;
20
88
  snapshot?: UsageSnapshot;
21
89
  lastFetchedAt?: number;
22
90
  loading: boolean;
@@ -25,6 +93,115 @@ type UsageSessionState = {
25
93
  requestRender?: () => void;
26
94
  };
27
95
 
96
+ function readConfigFile(path: string): RecursivePartial<MinimalFooterConfig> {
97
+ if (!existsSync(path)) return {};
98
+
99
+ try {
100
+ return JSON.parse(readFileSync(path, "utf-8")) as RecursivePartial<MinimalFooterConfig>;
101
+ } catch (error) {
102
+ console.error(`Warning: Could not parse ${path}: ${error}`);
103
+ return {};
104
+ }
105
+ }
106
+
107
+ function mergeConfig(
108
+ base: MinimalFooterConfig,
109
+ overrides: RecursivePartial<MinimalFooterConfig>,
110
+ ): MinimalFooterConfig {
111
+ const context = overrides.context;
112
+ const dumbZone = context?.dumbZone;
113
+ const codexUsage = overrides.codexUsage;
114
+ const primaryWindow = codexUsage?.windows?.primary;
115
+ const secondaryWindow = codexUsage?.windows?.secondary;
116
+
117
+ return {
118
+ context: {
119
+ showPercent: normalizeBoolean(context?.showPercent, base.context.showPercent),
120
+ dumbZone: {
121
+ enabled: normalizeBoolean(dumbZone?.enabled, base.context.dumbZone.enabled),
122
+ thresholdTokens: normalizeNonNegativeNumber(
123
+ dumbZone?.thresholdTokens,
124
+ base.context.dumbZone.thresholdTokens,
125
+ ),
126
+ label: normalizeLabel(dumbZone?.label, base.context.dumbZone.label),
127
+ color: normalizeDumbZoneColor(dumbZone?.color, base.context.dumbZone.color),
128
+ },
129
+ },
130
+ codexUsage: {
131
+ enabled: normalizeBoolean(codexUsage?.enabled, base.codexUsage.enabled),
132
+ cacheTtlMs: normalizeNonNegativeNumber(
133
+ codexUsage?.cacheTtlMs,
134
+ base.codexUsage.cacheTtlMs,
135
+ ),
136
+ requestTimeoutMs: normalizePositiveNumber(
137
+ codexUsage?.requestTimeoutMs,
138
+ base.codexUsage.requestTimeoutMs,
139
+ ),
140
+ windows: {
141
+ primary: {
142
+ enabled: normalizeBoolean(
143
+ primaryWindow?.enabled,
144
+ base.codexUsage.windows.primary.enabled,
145
+ ),
146
+ label: normalizeLabel(primaryWindow?.label, base.codexUsage.windows.primary.label),
147
+ },
148
+ secondary: {
149
+ enabled: normalizeBoolean(
150
+ secondaryWindow?.enabled,
151
+ base.codexUsage.windows.secondary.enabled,
152
+ ),
153
+ label: normalizeLabel(secondaryWindow?.label, base.codexUsage.windows.secondary.label),
154
+ },
155
+ },
156
+ },
157
+ };
158
+ }
159
+
160
+ function normalizeBoolean(value: unknown, fallback: boolean): boolean {
161
+ return typeof value === "boolean" ? value : fallback;
162
+ }
163
+
164
+ function normalizeNonNegativeNumber(value: unknown, fallback: number): number {
165
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
166
+ }
167
+
168
+ function normalizePositiveNumber(value: unknown, fallback: number): number {
169
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
170
+ }
171
+
172
+ function normalizeLabel(value: unknown, fallback: string): string {
173
+ return typeof value === "string" && value.trim() ? value.trim() : fallback;
174
+ }
175
+
176
+ function normalizeDumbZoneColor(value: unknown, fallback: DumbZoneColor): DumbZoneColor {
177
+ return DUMB_ZONE_COLORS.has(value as DumbZoneColor) ? (value as DumbZoneColor) : fallback;
178
+ }
179
+
180
+ function findProjectConfigPath(cwd: string): string {
181
+ let current = cwd;
182
+ while (true) {
183
+ const candidate = join(current, ".pi", "minimal-footer.json");
184
+ if (existsSync(candidate)) return candidate;
185
+
186
+ const parent = dirname(current);
187
+ if (parent === current) return join(cwd, ".pi", "minimal-footer.json");
188
+ current = parent;
189
+ }
190
+ }
191
+
192
+ function loadConfig(cwd: string): MinimalFooterConfig {
193
+ const globalConfig = readConfigFile(join(getAgentDir(), "extensions", "minimal-footer.json"));
194
+ const projectConfig = readConfigFile(findProjectConfigPath(cwd));
195
+ return mergeConfig(mergeConfig(DEFAULT_CONFIG, globalConfig), projectConfig);
196
+ }
197
+
198
+ function shouldShowCodexUsage(config: MinimalFooterConfig): boolean {
199
+ return (
200
+ config.codexUsage.enabled &&
201
+ (config.codexUsage.windows.primary.enabled || config.codexUsage.windows.secondary.enabled)
202
+ );
203
+ }
204
+
28
205
  function clearUsageState(state: UsageSessionState): void {
29
206
  state.snapshot = undefined;
30
207
  state.lastFetchedAt = undefined;
@@ -37,7 +214,8 @@ async function refreshUsageIfNeeded(
37
214
  state: UsageSessionState,
38
215
  force = false,
39
216
  ): Promise<void> {
40
- if (!isOpenAICodexProvider(ctx.model?.provider)) {
217
+ const config = state.config;
218
+ if (!shouldShowCodexUsage(config) || !isOpenAICodexProvider(ctx.model?.provider)) {
41
219
  clearUsageState(state);
42
220
  state.requestRender?.();
43
221
  return;
@@ -47,7 +225,7 @@ async function refreshUsageIfNeeded(
47
225
  if (
48
226
  !force &&
49
227
  state.lastFetchedAt &&
50
- now - state.lastFetchedAt < USAGE_CACHE_TTL_MS
228
+ now - state.lastFetchedAt < config.codexUsage.cacheTtlMs
51
229
  ) {
52
230
  return;
53
231
  }
@@ -61,7 +239,7 @@ async function refreshUsageIfNeeded(
61
239
  state.inflight = (async () => {
62
240
  try {
63
241
  const snapshot = await fetchOpenAICodexUsage(state.authStorage, {
64
- timeoutMs: USAGE_REQUEST_TIMEOUT_MS,
242
+ timeoutMs: config.codexUsage.requestTimeoutMs,
65
243
  });
66
244
  if (snapshot) {
67
245
  state.snapshot = snapshot;
@@ -90,6 +268,7 @@ export default function (pi: ExtensionAPI) {
90
268
  pi.on("session_start", (_event, ctx) => {
91
269
  const state: UsageSessionState = {
92
270
  authStorage: AuthStorage.create(),
271
+ config: loadConfig(ctx.cwd),
93
272
  loading: false,
94
273
  };
95
274
  states.set(ctx.sessionManager, state);
@@ -111,10 +290,11 @@ export default function (pi: ExtensionAPI) {
111
290
 
112
291
  const usage = ctx.getContextUsage();
113
292
  const context = usage?.percent == null ? "?" : `${usage.percent.toFixed(1)}%`;
114
- const usageSummary = isOpenAICodexProvider(ctx.model?.provider)
115
- ? formatUsageSummary(state.snapshot)
293
+ const dumbZone = state.config.context.dumbZone;
294
+ const inDumbZone = dumbZone.enabled && (usage?.tokens ?? 0) > dumbZone.thresholdTokens;
295
+ const usageSummary = shouldShowCodexUsage(state.config) && isOpenAICodexProvider(ctx.model?.provider)
296
+ ? formatUsageSummary(state.snapshot, state.config.codexUsage.windows)
116
297
  : undefined;
117
- const contextText = usageSummary ? `${context} · ${usageSummary}` : context;
118
298
 
119
299
  const model = ctx.model?.id ?? "no-model";
120
300
  const thinking = pi.getThinkingLevel();
@@ -122,7 +302,11 @@ export default function (pi: ExtensionAPI) {
122
302
 
123
303
  const branchStyled = theme.fg("dim", branch);
124
304
  const repoStyled = theme.fg("dim", repo);
125
- const contextStyled = theme.fg("dim", contextText);
305
+ const contextParts: string[] = [];
306
+ if (state.config.context.showPercent) contextParts.push(theme.fg("dim", context));
307
+ if (inDumbZone) contextParts.push(theme.fg(dumbZone.color, dumbZone.label));
308
+ if (usageSummary) contextParts.push(theme.fg("dim", usageSummary));
309
+ const contextStyled = contextParts.join(theme.fg("dim", " · "));
126
310
  const modelStyled = theme.fg("dim", modelText);
127
311
 
128
312
  const renderSplitLine = (left: string, right: string): string => {
@@ -0,0 +1,26 @@
1
+ {
2
+ "context": {
3
+ "showPercent": true,
4
+ "dumbZone": {
5
+ "enabled": true,
6
+ "thresholdTokens": 200000,
7
+ "label": "DUMB ZONE",
8
+ "color": "error"
9
+ }
10
+ },
11
+ "codexUsage": {
12
+ "enabled": true,
13
+ "cacheTtlMs": 300000,
14
+ "requestTimeoutMs": 10000,
15
+ "windows": {
16
+ "primary": {
17
+ "enabled": true,
18
+ "label": "5h"
19
+ },
20
+ "secondary": {
21
+ "enabled": true,
22
+ "label": "7d"
23
+ }
24
+ }
25
+ }
26
+ }
@@ -25,6 +25,17 @@ export interface UsageSnapshot {
25
25
  fetchedAt: number;
26
26
  }
27
27
 
28
+ export interface UsageSummaryWindowsConfig {
29
+ primary: {
30
+ enabled: boolean;
31
+ label: string;
32
+ };
33
+ secondary: {
34
+ enabled: boolean;
35
+ label: string;
36
+ };
37
+ }
38
+
28
39
  function normalizeUsedPercent(value?: number): number | undefined {
29
40
  if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
30
41
  return Math.min(100, Math.max(0, value));
@@ -68,15 +79,18 @@ export function isOpenAICodexProvider(provider?: string): boolean {
68
79
  return provider === PROVIDER_ID;
69
80
  }
70
81
 
71
- export function formatUsageSummary(snapshot?: UsageSnapshot): string | undefined {
82
+ export function formatUsageSummary(
83
+ snapshot: UsageSnapshot | undefined,
84
+ windows: UsageSummaryWindowsConfig,
85
+ ): string | undefined {
72
86
  if (!snapshot) return undefined;
73
87
 
74
88
  const primary = formatUsagePercent(snapshot.primary?.usedPercent);
75
89
  const secondary = formatUsagePercent(snapshot.secondary?.usedPercent);
76
90
  const parts: string[] = [];
77
91
 
78
- if (primary) parts.push(`5h ${primary}`);
79
- if (secondary) parts.push(`7d ${secondary}`);
92
+ if (windows.primary.enabled && primary) parts.push(`${windows.primary.label} ${primary}`);
93
+ if (windows.secondary.enabled && secondary) parts.push(`${windows.secondary.label} ${secondary}`);
80
94
 
81
95
  return parts.length > 0 ? parts.join(" · ") : undefined;
82
96
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-minimal-footer",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "A minimal custom footer for pi.",
5
5
  "keywords": ["pi-package", "pi", "terminal", "footer"],
6
6
  "license": "MIT",
@@ -12,6 +12,7 @@
12
12
  "files": [
13
13
  "index.ts",
14
14
  "openai-usage.ts",
15
+ "minimal-footer.example.json",
15
16
  "README.md"
16
17
  ],
17
18
  "publishConfig": {
@@ -27,7 +27,7 @@ By default, the extension:
27
27
  4. tries a provider-specific hardcoded priority list first
28
28
  5. falls back to a heuristic that favors stronger tiers like `opus`, `pro`, newer versions, and penalizes `mini`, `flash`, `haiku`, `spark`, etc.
29
29
 
30
- The hardcoded rankings now cover pi's built-in provider set, including OpenAI/Codex, Anthropic, Google variants, GitHub Copilot, Bedrock, Azure OpenAI Responses, Groq, Hugging Face, Kimi, MiniMax, Mistral, OpenCode, OpenRouter, Vercel AI Gateway, xAI, ZAI, and Cerebras.
30
+ The hardcoded rankings now cover pi's built-in provider set, including OpenAI/Codex, Anthropic, Google variants, GitHub Copilot, Bedrock, Azure OpenAI Responses, Cloudflare, DeepSeek, Fireworks, Groq, Hugging Face, Kimi/Moonshot, MiniMax, Mistral, OpenCode, OpenRouter, Vercel AI Gateway, xAI, ZAI, and Cerebras.
31
31
 
32
32
  If no reasoning model exists on the current provider, it falls back to the best available model on that provider.
33
33
 
@@ -43,7 +43,7 @@ Use `/oracle-model` inside pi to see what it would pick right now.
43
43
 
44
44
  See also:
45
45
  - [Oracle provider matrix](../../docs/oracle-provider-matrix.md)
46
- - [v0.1.5 release notes](../../docs/release-notes-v0.1.5.md)
46
+ - [v0.1.12 release notes](../../docs/release-notes-v0.1.12.md)
47
47
 
48
48
  ## Install
49
49
 
@@ -72,11 +72,16 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
72
72
  "claude-sonnet-4-6",
73
73
  "claude-sonnet-4-5",
74
74
  "claude-sonnet-4",
75
+ "deepseek.v3.2",
75
76
  "deepseek.r1",
76
77
  "kimi-k2.5",
78
+ "minimax-m2.5",
77
79
  "minimax-m2.1",
80
+ "zai.glm-5",
78
81
  ],
79
82
  anthropic: [
83
+ "claude-opus-4-7",
84
+ "claude-opus-4.7",
80
85
  "claude-opus-4-6",
81
86
  "claude-opus-4.6",
82
87
  "claude-opus-4-5",
@@ -94,8 +99,13 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
94
99
  "claude-3-7-sonnet",
95
100
  ],
96
101
  "azure-openai-responses": [
102
+ "gpt-5.5-pro",
103
+ "gpt-5.5",
97
104
  "gpt-5.4-pro",
105
+ "gpt-5.4",
106
+ "gpt-5.3-codex",
98
107
  "gpt-5-pro",
108
+ "gpt-5.2-pro",
99
109
  "gpt-5.2",
100
110
  "gpt-5.2-codex",
101
111
  "gpt-5.1-codex-max",
@@ -106,20 +116,53 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
106
116
  "gpt-5.4-mini",
107
117
  "gpt-5-mini",
108
118
  ],
109
- cerebras: ["zai-glm-4.7", "llama3.1-8b"],
119
+ cerebras: ["gpt-oss-120b", "zai-glm-4.7", "llama3.1-8b"],
120
+ "cloudflare-ai-gateway": [
121
+ "claude-opus-4-7",
122
+ "claude-opus-4-6",
123
+ "claude-opus-4-5",
124
+ "gpt-5.5",
125
+ "gpt-5.4",
126
+ "gpt-5.3-codex",
127
+ "workers-ai/@cf/moonshotai/kimi-k2.6",
128
+ "workers-ai/@cf/nvidia/nemotron-3-120b-a12b",
129
+ "workers-ai/@cf/zai-org/glm-4.7-flash",
130
+ ],
131
+ "cloudflare-workers-ai": [
132
+ "@cf/moonshotai/kimi-k2.6",
133
+ "@cf/nvidia/nemotron-3-120b-a12b",
134
+ "@cf/moonshotai/kimi-k2.5",
135
+ "@cf/openai/gpt-oss-120b",
136
+ "@cf/zai-org/glm-4.7-flash",
137
+ ],
138
+ deepseek: ["deepseek-v4-pro", "deepseek-v4-flash"],
139
+ fireworks: [
140
+ "accounts/fireworks/models/deepseek-v4-pro",
141
+ "accounts/fireworks/models/kimi-k2p6",
142
+ "accounts/fireworks/models/glm-5p1",
143
+ "accounts/fireworks/models/minimax-m2p7",
144
+ "accounts/fireworks/models/qwen3p6-plus",
145
+ "accounts/fireworks/models/gpt-oss-120b",
146
+ ],
110
147
  "github-copilot": [
111
148
  "claude-opus-4.7",
149
+ "claude-opus-4.6",
112
150
  "claude-opus-4.5",
151
+ "gpt-5.5",
152
+ "gpt-5.4",
153
+ "gpt-5.3-codex",
113
154
  "gpt-5.2",
114
155
  "gpt-5.1-codex-max",
115
156
  "gpt-5.1",
116
157
  "gpt-5",
117
- "gpt-5.3-codex",
158
+ "gemini-3.1-pro-preview",
118
159
  "gemini-3-pro-preview",
160
+ "claude-sonnet-4.6",
119
161
  "claude-sonnet-4.5",
120
162
  "gemini-2.5-pro",
121
163
  ],
122
164
  google: [
165
+ "gemini-3.1-pro-preview-customtools",
123
166
  "gemini-3.1-pro-preview",
124
167
  "gemini-3-pro-preview",
125
168
  "gemini-2.5-pro-preview",
@@ -138,6 +181,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
138
181
  "google-gemini-cli": ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-1.5-flash"],
139
182
  "google-vertex": [
140
183
  "gemini-3.1-pro-preview-customtools",
184
+ "gemini-3.1-pro-preview",
141
185
  "gemini-3-pro-preview",
142
186
  "gemini-2.5-pro",
143
187
  "gemini-2.5-flash-lite",
@@ -152,16 +196,23 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
152
196
  ],
153
197
  huggingface: [
154
198
  "zai-org/GLM-5.1",
199
+ "deepseek-ai/DeepSeek-V4-Pro",
200
+ "moonshotai/Kimi-K2.6",
201
+ "MiniMaxAI/MiniMax-M2.7",
202
+ "Qwen/Qwen3.5-397B-A17B",
155
203
  "Qwen/Qwen3-235B-A22B-Thinking-2507",
156
204
  "moonshotai/Kimi-K2.5",
157
205
  "deepseek-ai/DeepSeek-V3.2",
158
206
  "MiniMaxAI/MiniMax-M2.5",
159
207
  "Qwen/Qwen3-Coder-Next",
160
208
  ],
161
- "kimi-coding": ["kimi-k2-thinking"],
162
- minimax: ["MiniMax-M2.7-highspeed"],
163
- "minimax-cn": ["MiniMax-M2.7-highspeed"],
209
+ "kimi-coding": ["k2p6", "kimi-k2-thinking", "kimi-for-coding"],
210
+ minimax: ["MiniMax-M2.7-highspeed", "MiniMax-M2.7"],
211
+ "minimax-cn": ["MiniMax-M2.7-highspeed", "MiniMax-M2.7"],
164
212
  mistral: [
213
+ "mistral-medium-2604",
214
+ "mistral-medium-3.5",
215
+ "mistral-medium-latest",
165
216
  "magistral-medium-latest",
166
217
  "devstral-medium-latest",
167
218
  "mistral-large-latest",
@@ -171,8 +222,13 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
171
222
  "devstral-2512",
172
223
  ],
173
224
  openai: [
225
+ "gpt-5.5-pro",
226
+ "gpt-5.5",
174
227
  "gpt-5.4-pro",
228
+ "gpt-5.4",
229
+ "gpt-5.3-codex",
175
230
  "gpt-5-pro",
231
+ "gpt-5.2-pro",
176
232
  "gpt-5.2",
177
233
  "gpt-5.2-codex",
178
234
  "gpt-5.1-codex-max",
@@ -184,6 +240,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
184
240
  "gpt-5-mini",
185
241
  ],
186
242
  "openai-codex": [
243
+ "gpt-5.5",
187
244
  "gpt-5.4",
188
245
  "gpt-5.3-codex",
189
246
  "gpt-5.2",
@@ -193,41 +250,104 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
193
250
  "big-pickle",
194
251
  ],
195
252
  opencode: [
253
+ "gpt-5.5-pro",
254
+ "gpt-5.5",
255
+ "gpt-5.4-pro",
196
256
  "gpt-5.4",
197
257
  "claude-opus-4-7",
258
+ "claude-opus-4-6",
198
259
  "claude-opus-4-5",
260
+ "gpt-5.3-codex",
199
261
  "gpt-5.2-codex",
200
262
  "gpt-5.1-codex",
263
+ "gemini-3.1-pro",
264
+ "glm-5.1",
201
265
  "glm-5",
266
+ "kimi-k2.6",
202
267
  "kimi-k2.5",
268
+ "qwen3.6-plus",
203
269
  "qwen3.5-plus",
270
+ "minimax-m2.7",
204
271
  "minimax-m2.5-free",
205
272
  ],
206
- "opencode-go": ["qwen3.6-plus", "minimax-m2.7", "mimo-v2-pro", "kimi-k2.5"],
273
+ "opencode-go": [
274
+ "deepseek-v4-pro",
275
+ "glm-5.1",
276
+ "qwen3.6-plus",
277
+ "mimo-v2.5-pro",
278
+ "mimo-v2-pro",
279
+ "minimax-m2.7",
280
+ "kimi-k2.6",
281
+ "kimi-k2.5",
282
+ ],
207
283
  openrouter: [
284
+ "anthropic/claude-opus-4.7",
208
285
  "anthropic/claude-opus-4.6-fast",
286
+ "anthropic/claude-opus-4.6",
209
287
  "anthropic/claude-opus-4.5",
210
288
  "anthropic/claude-opus-4",
289
+ "openai/gpt-5.5-pro",
290
+ "openai/gpt-5.5",
291
+ "openai/gpt-5.4-pro",
292
+ "openai/gpt-5.4",
211
293
  "google/gemini-3.1-pro-preview-customtools",
294
+ "google/gemini-3.1-pro-preview",
212
295
  "google/gemini-2.5-pro",
296
+ "moonshotai/kimi-k2.6",
213
297
  "moonshotai/kimi-k2-thinking",
298
+ "deepseek/deepseek-v4-pro",
214
299
  "deepseek/deepseek-r1",
215
300
  "deepseek/deepseek-v3.2",
301
+ "minimax/minimax-m2.7",
216
302
  "minimax/minimax-m2.1",
303
+ "z-ai/glm-5.1",
217
304
  ],
218
305
  "vercel-ai-gateway": [
306
+ "anthropic/claude-opus-4.7",
219
307
  "anthropic/claude-opus-4.6",
308
+ "anthropic/claude-opus-4.5",
220
309
  "anthropic/claude-opus-4.1",
221
310
  "anthropic/claude-sonnet-4.6",
311
+ "openai/gpt-5.5-pro",
312
+ "openai/gpt-5.5",
313
+ "openai/gpt-5.4-pro",
314
+ "openai/gpt-5.4",
222
315
  "openai/gpt-5.1-codex",
223
316
  "openai/gpt-5-codex",
317
+ "moonshotai/kimi-k2.6",
224
318
  "moonshotai/kimi-k2-thinking",
319
+ "deepseek/deepseek-v4-pro",
225
320
  "deepseek/deepseek-v3.2-thinking",
321
+ "alibaba/qwen3.5-plus",
226
322
  "alibaba/qwen3-max-thinking",
323
+ "google/gemini-3.1-pro-preview",
227
324
  "google/gemini-3-flash",
325
+ "xai/grok-4.3",
326
+ "zai/glm-5.1",
327
+ ],
328
+ xai: [
329
+ "grok-4.3",
330
+ "grok-4.20-0309-reasoning",
331
+ "grok-4-1-fast",
332
+ "grok-4-fast",
333
+ "grok-4",
334
+ "grok-3-mini-latest",
335
+ "grok-3-mini-fast",
336
+ "grok-3-latest",
337
+ ],
338
+ zai: [
339
+ "glm-5.1",
340
+ "glm-5-turbo",
341
+ "glm-5v-turbo",
342
+ "glm-5",
343
+ "glm-4.7",
344
+ "glm-4.7-flash",
345
+ "glm-4.6v",
346
+ "glm-4.5v",
347
+ "glm-4.5-air",
228
348
  ],
229
- xai: ["grok-4-1-fast", "grok-4-fast", "grok-3-mini-latest", "grok-3-mini-fast", "grok-3-latest"],
230
- zai: ["glm-5.1", "glm-5", "glm-4.7-flash", "glm-4.6v", "glm-4.5v", "glm-4.5-air"],
349
+ moonshotai: ["kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
350
+ "moonshotai-cn": ["kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
231
351
  "gemini-cli": ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-1.5-flash"],
232
352
  };
233
353
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-oracle",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "An Amp-style oracle extension for pi that consults the strongest reasoning model on your current provider.",
5
5
  "keywords": ["pi-package", "pi", "oracle", "reasoning", "subagent"],
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-extensions",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "A collection of pi extensions, including a minimal custom footer, an Amp-style oracle, a permission gate for dangerous bash commands, confirm-before-destructive session actions, and terminal notifications when pi is ready for input.",
5
5
  "keywords": ["pi-package", "pi", "terminal", "agent"],
6
6
  "license": "MIT",