@diegopetrucci/pi-extensions 0.1.57 → 0.1.58

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.
Files changed (66) hide show
  1. package/extensions/agent-workflow-audit/index.ts +8 -1
  2. package/extensions/agent-workflow-audit/package.json +4 -0
  3. package/extensions/annotate-git-diff/package.json +5 -2
  4. package/extensions/annotate-last-message/package.json +4 -1
  5. package/extensions/brrr/README.md +2 -2
  6. package/extensions/brrr/package.json +5 -1
  7. package/extensions/claude-fast/package.json +5 -1
  8. package/extensions/code-reviewer/index.ts +9 -2
  9. package/extensions/code-reviewer/package.json +5 -1
  10. package/extensions/confirm-destructive/package.json +4 -0
  11. package/extensions/context-cap/package.json +4 -0
  12. package/extensions/context-inspector/package.json +5 -1
  13. package/extensions/contrarian/index.ts +24 -9
  14. package/extensions/contrarian/package.json +5 -1
  15. package/extensions/dirty-repo-guard/package.json +4 -0
  16. package/extensions/dynamic-context-pruning/package.json +3 -0
  17. package/extensions/git-footer/package.json +4 -0
  18. package/extensions/gnosis/package.json +4 -0
  19. package/extensions/illustrations-to-explain-things/package.json +3 -0
  20. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/01-two-breakpoints.webp +0 -0
  21. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/02-minimum-loop.webp +0 -0
  22. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/03-sort-by-purpose.webp +0 -0
  23. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/04-one-fish-many-uses.webp +0 -0
  24. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/05-handoff-path.webp +0 -0
  25. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/06-three-sources.webp +0 -0
  26. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/07-three-content-jobs.webp +0 -0
  27. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/08-handoff-copy-toolbox.webp +0 -0
  28. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/09-common-pits-no-title.webp +0 -0
  29. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/10-information-well.webp +0 -0
  30. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/11-idea-press.webp +0 -0
  31. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/12-content-fermentation.webp +0 -0
  32. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/13-system-bearing.webp +0 -0
  33. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/14-trust-bridge.webp +0 -0
  34. package/extensions/inline-bash/package.json +4 -0
  35. package/extensions/librarian/index.ts +8 -1
  36. package/extensions/librarian/package.json +4 -0
  37. package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
  38. package/extensions/minimal-footer/index.ts +2 -5
  39. package/extensions/minimal-footer/openai-usage.ts +58 -11
  40. package/extensions/minimal-footer/package.json +5 -1
  41. package/extensions/notify/README.md +2 -2
  42. package/extensions/notify/package.json +5 -1
  43. package/extensions/openai-fast/package.json +5 -1
  44. package/extensions/oracle/index.ts +24 -9
  45. package/extensions/oracle/package.json +5 -1
  46. package/extensions/permission-gate/package.json +5 -1
  47. package/extensions/quiet-tools/package.json +4 -0
  48. package/extensions/review/package.json +5 -1
  49. package/extensions/todo/package.json +4 -0
  50. package/extensions/triage-comments/index.ts +8 -1
  51. package/extensions/triage-comments/package.json +4 -0
  52. package/package.json +10 -6
  53. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/01-two-breakpoints.png +0 -0
  54. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/02-minimum-loop.png +0 -0
  55. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/03-sort-by-purpose.png +0 -0
  56. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/04-one-fish-many-uses.png +0 -0
  57. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/05-handoff-path.png +0 -0
  58. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/06-three-sources.png +0 -0
  59. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/07-three-content-jobs.png +0 -0
  60. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/08-handoff-copy-toolbox.png +0 -0
  61. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/09-common-pits-no-title.png +0 -0
  62. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/10-information-well.png +0 -0
  63. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/11-idea-press.png +0 -0
  64. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/12-content-fermentation.png +0 -0
  65. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/13-system-bearing.png +0 -0
  66. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/14-trust-bridge.png +0 -0
@@ -69,6 +69,13 @@ type ParsedArgs = {
69
69
  error?: string;
70
70
  };
71
71
 
72
+ type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
73
+
74
+ function getModelRuntimeOption(ctx: { modelRegistry?: unknown }): Pick<CreateAgentSessionOptions, "modelRuntime"> {
75
+ const modelRuntime = (ctx.modelRegistry as { runtime?: CreateAgentSessionOptions["modelRuntime"] } | undefined)?.runtime;
76
+ return modelRuntime ? { modelRuntime } : {};
77
+ }
78
+
72
79
  function parseArgs(args: string): ParsedArgs {
73
80
  const parts = args.trim().split(/\s+/).filter(Boolean);
74
81
  const focusParts: string[] = [];
@@ -1013,7 +1020,7 @@ async function runAudit(
1013
1020
  const tools = options.planOnly ? ["read", "grep", "find", "ls"] : ["read", "grep", "find", "ls", "bash"];
1014
1021
  const created = await createAgentSession({
1015
1022
  cwd,
1016
- modelRegistry: ctx.modelRegistry,
1023
+ ...getModelRuntimeOption(ctx),
1017
1024
  resourceLoader,
1018
1025
  settingsManager: isolatedSettingsManager,
1019
1026
  sessionManager: SessionManager.inMemory(cwd),
@@ -32,5 +32,9 @@
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "*",
34
34
  "@earendil-works/pi-tui": "*"
35
+ },
36
+ "type": "module",
37
+ "engines": {
38
+ "node": ">=22.19.0"
35
39
  }
36
40
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-annotate-git-diff",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "A standalone pi extension that adds /annotate-git-diff, a native Glimpse UI for annotating git diffs and sending feedback to the editor.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -46,5 +46,8 @@
46
46
  "glimpseui": "^0.8.1",
47
47
  "monaco-editor": "0.52.2"
48
48
  },
49
- "type": "module"
49
+ "type": "module",
50
+ "engines": {
51
+ "node": ">=22.19.0"
52
+ }
50
53
  }
@@ -41,5 +41,8 @@
41
41
  "dependencies": {
42
42
  "glimpseui": "^0.8.1"
43
43
  },
44
- "type": "module"
44
+ "type": "module",
45
+ "engines": {
46
+ "node": ">=22.19.0"
47
+ }
45
48
  }
@@ -1,6 +1,6 @@
1
1
  # brrr
2
2
 
3
- A pi extension that sends [brrr](https://brrr.now) push notifications when pi finishes an agent turn and is ready for input.
3
+ A pi extension that sends [brrr](https://brrr.now) push notifications when pi has fully settled and is ready for input.
4
4
 
5
5
  ## Install
6
6
 
@@ -81,6 +81,6 @@ Example:
81
81
 
82
82
  ## Notes
83
83
 
84
- - Hooks the `agent_end` event.
84
+ - Hooks the `agent_settled` event so automatic retries, compaction retries, and queued follow-ups do not trigger intermediate notifications.
85
85
  - The extension sends directly to the brrr webhook; it does not require the `brrr` CLI at runtime.
86
86
  - By default, notifications are skipped unless the Mac has been idle for at least 20 seconds.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-brrr",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "A pi extension that sends brrr push notifications when pi is ready for input.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -31,5 +31,9 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-claude-fast",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "A pi extension that enables Anthropic Claude Fast mode for supported Claude Opus models by injecting speed=fast.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -31,5 +31,9 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -220,7 +220,13 @@ type ModelRegistryContext = {
220
220
  modelRegistry: { getAvailable(): PiModel[] | Promise<PiModel[]> };
221
221
  };
222
222
 
223
- type CreateAgentSessionModel = NonNullable<Parameters<typeof createAgentSession>[0]>["model"];
223
+ type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
224
+ type CreateAgentSessionModel = CreateAgentSessionOptions["model"];
225
+
226
+ function getModelRuntimeOption(ctx: { modelRegistry?: unknown }): Pick<CreateAgentSessionOptions, "modelRuntime"> {
227
+ const modelRuntime = (ctx.modelRegistry as { runtime?: CreateAgentSessionOptions["modelRuntime"] } | undefined)?.runtime;
228
+ return modelRuntime ? { modelRuntime } : {};
229
+ }
224
230
 
225
231
  const MODEL_AVAILABILITY_ERROR_PATTERN =
226
232
  /\b(?:404|403|not[_ ]?found(?:[_ ]?error)?|model[_ ]?not[_ ]?found(?:[_ ]?error)?|no such model|unknown model|does not exist|is not available|not available|model[_ ]?not[_ ]?available|unsupported model|invalid model|forbidden|access[ _-]?denied|permission[ _-]?denied|not[ _-]?entitled|do(?:es)? not have access)\b/i;
@@ -1076,6 +1082,7 @@ export const __test__ = {
1076
1082
  buildSafeGitCommand,
1077
1083
  formatToolCall,
1078
1084
  getBlockedBashReason,
1085
+ isModelAvailabilityError,
1079
1086
  normalizeThinkingLevel,
1080
1087
  resolveThinkingLevel,
1081
1088
  selectCodeReviewerModel,
@@ -1181,7 +1188,7 @@ export default function codeReviewerExtension(pi: ExtensionAPI) {
1181
1188
  try {
1182
1189
  const created = await createAgentSession({
1183
1190
  cwd,
1184
- modelRegistry: ctx.modelRegistry,
1191
+ ...getModelRuntimeOption(ctx),
1185
1192
  resourceLoader,
1186
1193
  settingsManager: isolatedSettingsManager,
1187
1194
  sessionManager: SessionManager.inMemory(cwd),
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-code-reviewer",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "A standalone pi extension that adds a read-only code_reviewer subagent tool for isolated code reviews.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -31,5 +31,9 @@
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*",
33
33
  "typebox": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -29,5 +29,9 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@earendil-works/pi-coding-agent": "*"
32
+ },
33
+ "type": "module",
34
+ "engines": {
35
+ "node": ">=22.19.0"
32
36
  }
33
37
  }
@@ -30,5 +30,9 @@
30
30
  "peerDependencies": {
31
31
  "@earendil-works/pi-ai": "*",
32
32
  "@earendil-works/pi-coding-agent": "*"
33
+ },
34
+ "type": "module",
35
+ "engines": {
36
+ "node": ">=22.19.0"
33
37
  }
34
38
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-context-inspector",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "A pi extension that opens a local HTML dashboard explaining where the current session context is going.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -30,5 +30,9 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*"
33
+ },
34
+ "type": "module",
35
+ "engines": {
36
+ "node": ">=22.19.0"
33
37
  }
34
38
  }
@@ -247,7 +247,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
247
247
  "MiniMaxAI/MiniMax-M2.5",
248
248
  "Qwen/Qwen3-Coder-Next",
249
249
  ],
250
- "kimi-coding": ["k2p7", "kimi-k2-thinking", "kimi-for-coding"],
250
+ "kimi-coding": ["k3", "kimi-for-coding", "kimi-for-coding-highspeed"],
251
251
  minimax: ["MiniMax-M3", "MiniMax-M2.7-highspeed", "MiniMax-M2.7"],
252
252
  "minimax-cn": ["MiniMax-M3", "MiniMax-M2.7-highspeed", "MiniMax-M2.7"],
253
253
  mistral: [
@@ -375,17 +375,35 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
375
375
  "z-ai/glm-5.2",
376
376
  "z-ai/glm-5.1",
377
377
  ],
378
+ "qwen-token-plan": [
379
+ "qwen3.8-max-preview",
380
+ "qwen3.7-max",
381
+ "qwen3.7-plus",
382
+ "qwen3.6-plus",
383
+ "deepseek-v4-pro",
384
+ "glm-5.2",
385
+ "kimi-k2.7-code",
386
+ "minimax-m2.5",
387
+ ],
388
+ "qwen-token-plan-cn": [
389
+ "qwen3.8-max-preview",
390
+ "qwen3.7-max",
391
+ "qwen3.7-plus",
392
+ "qwen3.6-plus",
393
+ "deepseek-v4-pro",
394
+ "glm-5.2",
395
+ "kimi-k2.7-code",
396
+ "minimax-m2.5",
397
+ ],
378
398
  together: [
379
399
  "deepseek-ai/DeepSeek-V4-Pro",
380
400
  "zai-org/GLM-5.2",
381
- "zai-org/GLM-5.1",
382
401
  "moonshotai/Kimi-K2.7-Code",
383
402
  "moonshotai/Kimi-K2.6",
384
403
  "Qwen/Qwen3.7-Max",
385
404
  "Qwen/Qwen3.6-Plus",
386
405
  "MiniMaxAI/MiniMax-M3",
387
406
  "MiniMaxAI/MiniMax-M2.7",
388
- "Qwen/Qwen3.5-397B-A17B",
389
407
  "openai/gpt-oss-120b",
390
408
  "openai/gpt-oss-20b",
391
409
  "nvidia/nemotron-3-ultra-550b-a55b",
@@ -433,13 +451,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
433
451
  ],
434
452
  xai: [
435
453
  "grok-4.5",
436
- "grok-4.20-0309-reasoning",
437
- "grok-4.20-0309-non-reasoning",
438
454
  "grok-4.3",
439
455
  "grok-build-0.1",
440
- "grok-code-fast-1",
441
- "grok-3-fast",
442
- "grok-3",
443
456
  ],
444
457
  xiaomi: ["mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", "mimo-v2-omni", "mimo-v2-flash"],
445
458
  "xiaomi-token-plan-ams": ["mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro"],
@@ -450,7 +463,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
450
463
  "nvidia/nemotron-3-super-120b-a12b",
451
464
  "moonshotai/kimi-k2.6",
452
465
  "z-ai/glm-5.2",
453
- "qwen/qwen3.5-122b-a10b",
466
+ "minimaxai/minimax-m3",
467
+ "mistralai/mistral-large-3-675b-instruct-2512",
454
468
  "openai/gpt-oss-120b",
455
469
  "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
456
470
  "nvidia/nemotron-3-nano-30b-a3b",
@@ -1211,6 +1225,7 @@ function renderCollapsedText(text: string, lineLimit = COLLAPSED_LINE_LIMIT): st
1211
1225
 
1212
1226
  export const __test__ = {
1213
1227
  findAvailableModel,
1228
+ isModelAvailabilityError,
1214
1229
  parseModelPreference,
1215
1230
  resolveThinkingLevel,
1216
1231
  selectContrarianModel,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-contrarian",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "A read-only contrarian subagent extension for pi that stress-tests plans, designs, assumptions, and conclusions.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -33,5 +33,9 @@
33
33
  "@earendil-works/pi-coding-agent": "*",
34
34
  "@earendil-works/pi-tui": "*",
35
35
  "typebox": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
@@ -29,5 +29,9 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@earendil-works/pi-coding-agent": "*"
32
+ },
33
+ "type": "module",
34
+ "engines": {
35
+ "node": ">=22.19.0"
32
36
  }
33
37
  }
@@ -30,5 +30,8 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*"
33
+ },
34
+ "engines": {
35
+ "node": ">=22.19.0"
33
36
  }
34
37
  }
@@ -31,5 +31,9 @@
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*",
33
33
  "@earendil-works/pi-tui": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -33,5 +33,9 @@
33
33
  "@earendil-works/pi-ai": "*",
34
34
  "@earendil-works/pi-coding-agent": "*",
35
35
  "typebox": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
@@ -27,5 +27,8 @@
27
27
  "skills": [
28
28
  "skills"
29
29
  ]
30
+ },
31
+ "engines": {
32
+ "node": ">=22.19.0"
30
33
  }
31
34
  }
@@ -30,5 +30,9 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*"
33
+ },
34
+ "type": "module",
35
+ "engines": {
36
+ "node": ">=22.19.0"
33
37
  }
34
38
  }
@@ -39,6 +39,13 @@ type PiModel = {
39
39
  thinkingLevelMap?: ThinkingLevelMap;
40
40
  };
41
41
 
42
+ type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
43
+
44
+ function getModelRuntimeOption(ctx: { modelRegistry?: unknown }): Pick<CreateAgentSessionOptions, "modelRuntime"> {
45
+ const modelRuntime = (ctx.modelRegistry as { runtime?: CreateAgentSessionOptions["modelRuntime"] } | undefined)?.runtime;
46
+ return modelRuntime ? { modelRuntime } : {};
47
+ }
48
+
42
49
  const DEFAULT_CACHE_MODE: CacheMode = "disabled";
43
50
  const DEFAULT_THINKING_LEVEL: ThinkingLevel = "low";
44
51
  const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const;
@@ -1145,7 +1152,7 @@ export default function librarianExtension(pi: ExtensionAPI) {
1145
1152
 
1146
1153
  const created = await createAgentSession({
1147
1154
  cwd: workspace,
1148
- modelRegistry: ctx.modelRegistry,
1155
+ ...getModelRuntimeOption(ctx),
1149
1156
  resourceLoader,
1150
1157
  sessionManager: SessionManager.inMemory(workspace),
1151
1158
  model: candidate.model,
@@ -33,5 +33,9 @@
33
33
  "@earendil-works/pi-coding-agent": "*",
34
34
  "@earendil-works/pi-tui": "*",
35
35
  "typebox": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
@@ -1 +1 @@
1
- 0.80.6
1
+ 0.81.1
@@ -2,7 +2,6 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { spawn } from "node:child_process";
3
3
  import { basename, dirname, join } from "node:path";
4
4
  import {
5
- AuthStorage,
6
5
  CONFIG_DIR_NAME,
7
6
  getAgentDir,
8
7
  type ExtensionAPI,
@@ -14,7 +13,7 @@ import {
14
13
  formatUsageSummary,
15
14
  isOpenAICodexProvider,
16
15
  type UsageSnapshot,
17
- } from "./openai-usage";
16
+ } from "./openai-usage.ts";
18
17
 
19
18
 
20
19
  const DEFAULT_CONFIG: MinimalFooterConfig = {
@@ -108,7 +107,6 @@ interface MinimalFooterConfig {
108
107
  }
109
108
 
110
109
  type UsageSessionState = {
111
- authStorage: AuthStorage;
112
110
  config: MinimalFooterConfig;
113
111
  snapshot?: UsageSnapshot;
114
112
  lastFetchedAt?: number;
@@ -857,7 +855,7 @@ async function refreshUsageIfNeeded(
857
855
  state.requestRender?.();
858
856
  state.inflight = (async () => {
859
857
  try {
860
- const snapshot = await fetchOpenAICodexUsage(state.authStorage, {
858
+ const snapshot = await fetchOpenAICodexUsage(ctx.modelRegistry, {
861
859
  timeoutMs: config.codexUsage.requestTimeoutMs,
862
860
  });
863
861
  if (snapshot) {
@@ -908,7 +906,6 @@ export default function (pi: ExtensionAPI) {
908
906
 
909
907
  pi.on("session_start", (_event, ctx) => {
910
908
  const state: UsageSessionState = {
911
- authStorage: AuthStorage.create(),
912
909
  config: loadConfig(ctx),
913
910
  loading: false,
914
911
  };
@@ -1,4 +1,6 @@
1
- import { AuthStorage } from "@earendil-works/pi-coding-agent";
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
2
4
 
3
5
  const PROVIDER_ID = "openai-codex";
4
6
 
@@ -61,10 +63,58 @@ function parseUsageSnapshot(data: WhamUsageResponse): Omit<UsageSnapshot, "fetch
61
63
  };
62
64
  }
63
65
 
64
- function getOAuthAccountId(authStorage: AuthStorage): string | undefined {
65
- const credential = authStorage.get(PROVIDER_ID);
66
- if (!credential || credential.type !== "oauth") return undefined;
67
- const accountId = (credential as { accountId?: unknown }).accountId;
66
+ function isRecord(value: unknown): value is Record<string, unknown> {
67
+ return typeof value === "object" && value !== null;
68
+ }
69
+
70
+ function readStoredProviderCredential(providerId: string): unknown {
71
+ try {
72
+ const data = JSON.parse(readFileSync(join(getAgentDir(), "auth.json"), "utf-8")) as unknown;
73
+ if (!isRecord(data)) return undefined;
74
+ return data[providerId];
75
+ } catch {
76
+ return undefined;
77
+ }
78
+ }
79
+
80
+ async function getAccessToken(authSource: unknown): Promise<string | undefined> {
81
+ if (isRecord(authSource) && typeof authSource.getProviderAuth === "function") {
82
+ const result = await (authSource as {
83
+ getProviderAuth(providerId: string): Promise<unknown>;
84
+ }).getProviderAuth(PROVIDER_ID);
85
+ if (isRecord(result) && isRecord(result.auth) && typeof result.auth.apiKey === "string") {
86
+ return result.auth.apiKey;
87
+ }
88
+ }
89
+
90
+ if (isRecord(authSource) && typeof authSource.getApiKey === "function") {
91
+ const token = await (authSource as {
92
+ getApiKey(providerId: string, options: { includeFallback: boolean }): Promise<unknown>;
93
+ }).getApiKey(PROVIDER_ID, { includeFallback: false });
94
+ return typeof token === "string" ? token : undefined;
95
+ }
96
+
97
+ const credential = readStoredProviderCredential(PROVIDER_ID);
98
+ if (!isRecord(credential) || credential.type !== "oauth") return undefined;
99
+ return typeof credential.access === "string" ? credential.access : undefined;
100
+ }
101
+
102
+ function getOAuthAccountId(authSource: unknown): string | undefined {
103
+ let credential: unknown;
104
+
105
+ if (
106
+ isRecord(authSource) &&
107
+ typeof authSource.getApiKey === "function" &&
108
+ typeof authSource.get === "function"
109
+ ) {
110
+ if (typeof authSource.reload === "function") authSource.reload();
111
+ credential = (authSource as { get(providerId: string): unknown }).get(PROVIDER_ID);
112
+ } else {
113
+ credential = readStoredProviderCredential(PROVIDER_ID);
114
+ }
115
+
116
+ if (!isRecord(credential) || credential.type !== "oauth") return undefined;
117
+ const accountId = credential.accountId;
68
118
  return typeof accountId === "string" && accountId.trim()
69
119
  ? accountId.trim()
70
120
  : undefined;
@@ -96,16 +146,13 @@ export function formatUsageSummary(
96
146
  }
97
147
 
98
148
  export async function fetchOpenAICodexUsage(
99
- authStorage: AuthStorage,
149
+ authSource: unknown,
100
150
  options?: { timeoutMs?: number },
101
151
  ): Promise<UsageSnapshot | undefined> {
102
- const accessToken = await authStorage.getApiKey(PROVIDER_ID, {
103
- includeFallback: false,
104
- });
152
+ const accessToken = await getAccessToken(authSource);
105
153
  if (!accessToken) return undefined;
106
154
 
107
- authStorage.reload();
108
- const accountId = getOAuthAccountId(authStorage);
155
+ const accountId = getOAuthAccountId(authSource);
109
156
  const controller = new AbortController();
110
157
  const timeoutMs = options?.timeoutMs ?? 10_000;
111
158
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-minimal-footer",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "A minimal custom footer for pi.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -33,5 +33,9 @@
33
33
  "peerDependencies": {
34
34
  "@earendil-works/pi-coding-agent": "*",
35
35
  "@earendil-works/pi-tui": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
@@ -1,6 +1,6 @@
1
1
  # notify
2
2
 
3
- A pi extension that sends notifications when the agent finishes and is waiting for input.
3
+ A pi extension that sends notifications when the agent has fully settled and is waiting for input.
4
4
 
5
5
  This started from the original `notify.ts` example in [`earendil-works/pi-mono`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/examples/extensions/notify.ts), but now supports multiple notification channels and JSON configuration.
6
6
 
@@ -137,7 +137,7 @@ You can also customize the sound backend and options if needed.
137
137
 
138
138
  ## Notes
139
139
 
140
- - Hooks the `agent_end` event.
140
+ - Hooks the `agent_settled` event so automatic retries, compaction retries, and queued follow-ups do not trigger intermediate notifications.
141
141
  - Default message is `Pi` / `Ready for input`.
142
142
  - Terminal, desktop, bell, and sound channels can be enabled independently.
143
143
  - To opt into sound playback, set `channels.sound` to `true`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-notify",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "A pi extension that sends a notification when the agent is ready for input.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -30,5 +30,9 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*"
33
+ },
34
+ "type": "module",
35
+ "engines": {
36
+ "node": ">=22.19.0"
33
37
  }
34
38
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-openai-fast",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A pi extension that enables OpenAI Codex Fast mode for ChatGPT-auth GPT-5.4, GPT-5.5, and GPT-5.6 Codex variants by injecting the priority service tier.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -31,5 +31,9 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -231,7 +231,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
231
231
  "MiniMaxAI/MiniMax-M2.5",
232
232
  "Qwen/Qwen3-Coder-Next",
233
233
  ],
234
- "kimi-coding": ["k2p7", "kimi-k2-thinking", "kimi-for-coding"],
234
+ "kimi-coding": ["k3", "kimi-for-coding", "kimi-for-coding-highspeed"],
235
235
  minimax: ["MiniMax-M3", "MiniMax-M2.7-highspeed", "MiniMax-M2.7"],
236
236
  "minimax-cn": ["MiniMax-M3", "MiniMax-M2.7-highspeed", "MiniMax-M2.7"],
237
237
  mistral: [
@@ -359,17 +359,35 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
359
359
  "z-ai/glm-5.2",
360
360
  "z-ai/glm-5.1",
361
361
  ],
362
+ "qwen-token-plan": [
363
+ "qwen3.8-max-preview",
364
+ "qwen3.7-max",
365
+ "qwen3.7-plus",
366
+ "qwen3.6-plus",
367
+ "deepseek-v4-pro",
368
+ "glm-5.2",
369
+ "kimi-k2.7-code",
370
+ "minimax-m2.5",
371
+ ],
372
+ "qwen-token-plan-cn": [
373
+ "qwen3.8-max-preview",
374
+ "qwen3.7-max",
375
+ "qwen3.7-plus",
376
+ "qwen3.6-plus",
377
+ "deepseek-v4-pro",
378
+ "glm-5.2",
379
+ "kimi-k2.7-code",
380
+ "minimax-m2.5",
381
+ ],
362
382
  together: [
363
383
  "deepseek-ai/DeepSeek-V4-Pro",
364
384
  "zai-org/GLM-5.2",
365
- "zai-org/GLM-5.1",
366
385
  "moonshotai/Kimi-K2.7-Code",
367
386
  "moonshotai/Kimi-K2.6",
368
387
  "Qwen/Qwen3.7-Max",
369
388
  "Qwen/Qwen3.6-Plus",
370
389
  "MiniMaxAI/MiniMax-M3",
371
390
  "MiniMaxAI/MiniMax-M2.7",
372
- "Qwen/Qwen3.5-397B-A17B",
373
391
  "openai/gpt-oss-120b",
374
392
  "openai/gpt-oss-20b",
375
393
  "nvidia/nemotron-3-ultra-550b-a55b",
@@ -417,13 +435,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
417
435
  ],
418
436
  xai: [
419
437
  "grok-4.5",
420
- "grok-4.20-0309-reasoning",
421
- "grok-4.20-0309-non-reasoning",
422
438
  "grok-4.3",
423
439
  "grok-build-0.1",
424
- "grok-code-fast-1",
425
- "grok-3-fast",
426
- "grok-3",
427
440
  ],
428
441
  xiaomi: ["mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro", "mimo-v2-omni", "mimo-v2-flash"],
429
442
  "xiaomi-token-plan-ams": ["mimo-v2.5-pro", "mimo-v2.5", "mimo-v2-pro"],
@@ -434,7 +447,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
434
447
  "nvidia/nemotron-3-super-120b-a12b",
435
448
  "moonshotai/kimi-k2.6",
436
449
  "z-ai/glm-5.2",
437
- "qwen/qwen3.5-122b-a10b",
450
+ "minimaxai/minimax-m3",
451
+ "mistralai/mistral-large-3-675b-instruct-2512",
438
452
  "openai/gpt-oss-120b",
439
453
  "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
440
454
  "nvidia/nemotron-3-nano-30b-a3b",
@@ -1125,6 +1139,7 @@ function renderCollapsedText(text: string, lineLimit = COLLAPSED_LINE_LIMIT): st
1125
1139
 
1126
1140
  export const __test__ = {
1127
1141
  findAvailableModel,
1142
+ isModelAvailabilityError,
1128
1143
  parseModelPreference,
1129
1144
  resolveThinkingLevel,
1130
1145
  selectOracleModel,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-oracle",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "An Amp-style oracle extension for pi that consults the strongest reasoning model on your current provider.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -34,5 +34,9 @@
34
34
  "@earendil-works/pi-coding-agent": "*",
35
35
  "@earendil-works/pi-tui": "*",
36
36
  "typebox": "*"
37
+ },
38
+ "type": "module",
39
+ "engines": {
40
+ "node": ">=22.19.0"
37
41
  }
38
42
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-permission-gate",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "A pi extension that prompts before dangerous bash commands and protected file writes.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -31,5 +31,9 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -31,5 +31,9 @@
31
31
  "peerDependencies": {
32
32
  "@earendil-works/pi-coding-agent": "*",
33
33
  "@earendil-works/pi-tui": "*"
34
+ },
35
+ "type": "module",
36
+ "engines": {
37
+ "node": ">=22.19.0"
34
38
  }
35
39
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-review",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "A standalone pi extension that adds /review and /end-review commands adapted from mitsuhiko/agent-stuff.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -33,5 +33,9 @@
33
33
  "peerDependencies": {
34
34
  "@earendil-works/pi-coding-agent": "*",
35
35
  "@earendil-works/pi-tui": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
@@ -33,5 +33,9 @@
33
33
  "@earendil-works/pi-coding-agent": "*",
34
34
  "@earendil-works/pi-tui": "*",
35
35
  "typebox": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
@@ -91,6 +91,13 @@ const MUTATING_GH_API_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
91
91
 
92
92
  type TriageStatus = "running" | "done" | "error" | "aborted";
93
93
 
94
+ type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
95
+
96
+ function getModelRuntimeOption(ctx: { modelRegistry?: unknown }): Pick<CreateAgentSessionOptions, "modelRuntime"> {
97
+ const modelRuntime = (ctx.modelRegistry as { runtime?: CreateAgentSessionOptions["modelRuntime"] } | undefined)?.runtime;
98
+ return modelRuntime ? { modelRuntime } : {};
99
+ }
100
+
94
101
  type ToolCall = {
95
102
  id: string;
96
103
  name: string;
@@ -2035,7 +2042,7 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
2035
2042
 
2036
2043
  const created = await createAgentSession({
2037
2044
  cwd,
2038
- modelRegistry: ctx.modelRegistry,
2045
+ ...getModelRuntimeOption(ctx),
2039
2046
  resourceLoader,
2040
2047
  settingsManager: isolatedSettingsManager,
2041
2048
  sessionManager: SessionManager.inMemory(cwd),
@@ -33,5 +33,9 @@
33
33
  "@earendil-works/pi-coding-agent": "*",
34
34
  "@earendil-works/pi-tui": "*",
35
35
  "typebox": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-extensions",
3
- "version": "0.1.57",
3
+ "version": "0.1.58",
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",
@@ -17,7 +17,8 @@
17
17
  "ci": "npm run preflight:install-state && npm run typecheck && npm test",
18
18
  "preflight:install-state": "node scripts/check-install-state.mjs",
19
19
  "test": "node --test test/*.test.mjs",
20
- "typecheck": "npx tsc --noEmit --module NodeNext --moduleResolution NodeNext --target ES2022 --skipLibCheck $(git ls-files '*.ts')"
20
+ "typecheck": "tsc -p tsconfig.json",
21
+ "prepare-release": "node scripts/prepare-release.mjs"
21
22
  },
22
23
  "files": [
23
24
  "extensions",
@@ -71,9 +72,9 @@
71
72
  ]
72
73
  },
73
74
  "devDependencies": {
74
- "@earendil-works/pi-ai": "^0.80.6",
75
- "@earendil-works/pi-coding-agent": "^0.80.6",
76
- "@earendil-works/pi-tui": "^0.80.6",
75
+ "@earendil-works/pi-ai": "^0.81.1",
76
+ "@earendil-works/pi-coding-agent": "^0.81.1",
77
+ "@earendil-works/pi-tui": "^0.81.1",
77
78
  "@types/node": "^25.9.1",
78
79
  "husky": "^9.1.7",
79
80
  "typebox": "^1.3.6",
@@ -85,6 +86,9 @@
85
86
  "monaco-editor": "0.52.2"
86
87
  },
87
88
  "overrides": {
88
- "protobufjs": "^7.6.4"
89
+ "protobufjs": "^7.6.5"
90
+ },
91
+ "engines": {
92
+ "node": ">=22.19.0"
89
93
  }
90
94
  }