@diegopetrucci/pi-extensions 0.1.71 → 0.1.73

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 (53) hide show
  1. package/README.md +2 -2
  2. package/extensions/agent-workflow-audit/index.ts +41 -8
  3. package/extensions/agent-workflow-audit/package.json +1 -1
  4. package/extensions/annotate-git-diff/README.md +7 -3
  5. package/extensions/annotate-git-diff/git.ts +3 -2
  6. package/extensions/annotate-git-diff/index.ts +366 -81
  7. package/extensions/annotate-git-diff/package.json +2 -2
  8. package/extensions/annotate-git-diff/quiet-glimpse.ts +4 -2
  9. package/extensions/annotate-git-diff/types.ts +6 -0
  10. package/extensions/annotate-git-diff/web/app.js +54 -4
  11. package/extensions/annotate-git-diff/web/index.html +2 -2
  12. package/extensions/annotate-last-message/README.md +9 -1
  13. package/extensions/annotate-last-message/index.ts +53 -13
  14. package/extensions/annotate-last-message/package.json +2 -1
  15. package/extensions/annotate-last-message/quiet-glimpse.ts +4 -2
  16. package/extensions/annotate-last-message/theme.ts +247 -0
  17. package/extensions/annotate-last-message/ui.ts +28 -2
  18. package/extensions/annotate-last-message/web/app.js +351 -162
  19. package/extensions/annotate-last-message/web/index.html +153 -24
  20. package/extensions/annotate-last-message/web/md-renderer.js +458 -0
  21. package/extensions/code-reviewer/index.ts +12 -1
  22. package/extensions/code-reviewer/package.json +2 -1
  23. package/extensions/context-cap/README.md +33 -4
  24. package/extensions/context-cap/index.ts +271 -68
  25. package/extensions/context-cap/package.json +1 -1
  26. package/extensions/context-inspector/README.md +2 -0
  27. package/extensions/context-inspector/index.ts +90 -9
  28. package/extensions/context-inspector/package.json +1 -1
  29. package/extensions/contrarian/index.ts +21 -15
  30. package/extensions/contrarian/package.json +1 -1
  31. package/extensions/dynamic-context-pruning/README.md +17 -5
  32. package/extensions/dynamic-context-pruning/index.ts +17 -4
  33. package/extensions/dynamic-context-pruning/package.json +1 -1
  34. package/extensions/fast/README.md +25 -4
  35. package/extensions/fast/index.ts +4 -4
  36. package/extensions/fast/package.json +1 -1
  37. package/extensions/git-footer/README.md +1 -0
  38. package/extensions/git-footer/package.json +1 -1
  39. package/extensions/librarian/index.ts +7 -0
  40. package/extensions/librarian/package.json +2 -1
  41. package/extensions/minimal-footer/README.md +16 -4
  42. package/extensions/minimal-footer/index.ts +263 -14
  43. package/extensions/minimal-footer/openai-usage.ts +62 -8
  44. package/extensions/minimal-footer/package.json +1 -1
  45. package/extensions/oracle/index.ts +19 -18
  46. package/extensions/oracle/package.json +1 -1
  47. package/extensions/permission-gate/README.md +6 -0
  48. package/extensions/permission-gate/index.ts +37 -16
  49. package/extensions/permission-gate/package.json +1 -1
  50. package/extensions/quiet-tools/README.md +1 -1
  51. package/extensions/quiet-tools/package.json +1 -1
  52. package/extensions/triage-comments/package.json +2 -1
  53. package/package.json +4 -4
@@ -126,6 +126,9 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
126
126
  "us.openai.gpt-6-astra ",
127
127
  "openai.gpt-6-astra ",
128
128
  "gpt-6-astra",
129
+ "global.openai.gpt-6.1-sol ",
130
+ "us.openai.gpt-6.1-sol ",
131
+ "openai.gpt-6.1-sol ",
129
132
  "openai.gpt-5.6-sol",
130
133
  "openai.gpt-5.6-terra",
131
134
  "openai.gpt-5.6-luna",
@@ -157,6 +160,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
157
160
  "azure-openai-responses": [
158
161
  "gpt-6-astra ",
159
162
  "gpt-6-astra",
163
+ "gpt-6.1-sol ",
160
164
  "gpt-6-sol ",
161
165
  "gpt-6-sol",
162
166
  "gpt-5.6-sol",
@@ -236,13 +240,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
236
240
  fireworks: [
237
241
  "accounts/fireworks/models/kimi-k3",
238
242
  "accounts/fireworks/routers/kimi-k3-fast",
239
- "accounts/fireworks/models/deepseek-v4-pro",
240
- "accounts/fireworks/models/kimi-k2p7-code",
241
- "accounts/fireworks/models/glm-5p2",
242
- "accounts/fireworks/routers/glm-5p2-fast",
243
243
  "accounts/fireworks/models/minimax-m3",
244
- "accounts/fireworks/models/kimi-k2p6",
245
- "accounts/fireworks/models/qwen3p7-plus",
246
244
  "accounts/fireworks/models/gpt-oss-120b",
247
245
  ],
248
246
  "github-copilot": [
@@ -254,6 +252,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
254
252
  "claude-opus-4.7",
255
253
  "gpt-6-astra ",
256
254
  "gpt-6-astra",
255
+ "gpt-6.1-sol ",
257
256
  "gpt-6-sol ",
258
257
  "gpt-6-sol",
259
258
  "gpt-5.6-sol",
@@ -341,6 +340,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
341
340
  openai: [
342
341
  "gpt-6-astra ",
343
342
  "gpt-6-astra",
343
+ "gpt-6.1-sol ",
344
344
  "gpt-6-sol ",
345
345
  "gpt-6-sol",
346
346
  "gpt-5.6-sol",
@@ -366,6 +366,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
366
366
  "openai-codex": [
367
367
  "gpt-6-astra ",
368
368
  "gpt-6-astra",
369
+ "gpt-6.1-sol ",
369
370
  "gpt-6-sol ",
370
371
  "gpt-6-sol",
371
372
  "gpt-5.6-sol",
@@ -383,6 +384,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
383
384
  "claude-fable-5",
384
385
  "gpt-6-astra ",
385
386
  "gpt-6-astra",
387
+ "gpt-6.1-sol ",
386
388
  "gpt-6-sol ",
387
389
  "gpt-6-sol",
388
390
  "gpt-5.6-sol",
@@ -421,17 +423,13 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
421
423
  "deepseek-v4-pro",
422
424
  "glm-5.3",
423
425
  "glm-5.2",
424
- "glm-5.1",
425
- "qwen3.7-max",
426
426
  "qwen3.7-plus",
427
- "qwen3.6-plus",
428
427
  "mimo-v2.5-pro",
429
428
  "mimo-v2.5",
430
429
  "minimax-m3",
431
430
  "minimax-m2.7",
432
431
  "kimi-k3",
433
432
  "kimi-k2.7-code",
434
- "kimi-k2.6",
435
433
  "grok-4.7 ",
436
434
  "grok-4.7",
437
435
  "grok-4.6",
@@ -449,6 +447,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
449
447
  "anthropic/claude-opus-4.1",
450
448
  "openai/gpt-6-astra ",
451
449
  "openai/gpt-6-astra",
450
+ "openai/gpt-6.1-sol ",
452
451
  "openai/gpt-6-sol ",
453
452
  "openai/gpt-6-sol",
454
453
  "openai/gpt-5.6-sol-pro",
@@ -537,9 +536,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
537
536
  "gpt-5.4",
538
537
  "gpt-5.3-codex",
539
538
  "kimi-k3",
540
- "deepseek-v4-pro",
541
539
  "glm-5.3",
542
- "kimi-k2.7-code",
543
540
  "deepseek-v4.1-flash",
544
541
  "gpt-5.4-mini",
545
542
  "glm-5.3-flash",
@@ -549,8 +546,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
549
546
  "moonshotai/Kimi-K3",
550
547
  "zai-org/GLM-5.3-Flash",
551
548
  "zai-org/GLM-5.2",
552
- "moonshotai/Kimi-K2.7-Code",
553
- "moonshotai/Kimi-K2.6",
554
549
  "Qwen/Qwen3.7-Max",
555
550
  "Qwen/Qwen3.6-Plus",
556
551
  "MiniMaxAI/MiniMax-M3",
@@ -560,6 +555,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
560
555
  "nvidia/nemotron-3-ultra-550b-a55b",
561
556
  "google/gemma-4-31B-it",
562
557
  ],
558
+ typesafe: [],
563
559
  "vercel-ai-gateway": [
564
560
  "anthropic/claude-opus-5.5 ",
565
561
  "anthropic/claude-opus-5.5",
@@ -573,6 +569,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
573
569
  "anthropic/claude-sonnet-4.6",
574
570
  "openai/gpt-6-astra ",
575
571
  "openai/gpt-6-astra",
572
+ "openai/gpt-6.1-sol ",
576
573
  "openai/gpt-6-sol ",
577
574
  "openai/gpt-6-sol",
578
575
  "openai/gpt-5.6-sol",
@@ -1021,16 +1018,16 @@ function clampThinkingLevel(model: PiModel, requested: ThinkingLevel): ThinkingL
1021
1018
  return "off";
1022
1019
  }
1023
1020
 
1024
- function isGpt56SolModel(model: PiModel | undefined): boolean {
1021
+ function isGptSolModel(model: PiModel | undefined): boolean {
1025
1022
  if (!model) return false;
1026
- return /\bgpt-(?:5\.6|6)-sol\b/i.test(`${model.id} ${model.name ?? ""}`);
1023
+ return /(?:\bgpt-(?:5\.6|6)-sol\b|\bgpt-6\.1-sol(?:\s|$))/i.test(`${model.id} ${model.name ?? ""}`);
1027
1024
  }
1028
1025
 
1029
1026
  function resolveThinkingLevel(
1030
1027
  model: PiModel | undefined,
1031
1028
  override: ThinkingLevel | undefined,
1032
1029
  ): { requested: ThinkingLevel; effective: ThinkingLevel; clamped: boolean } {
1033
- const requested = override ?? (model?.reasoning ? (isGpt56SolModel(model) ? "high" : DEFAULT_THINKING_LEVEL) : "off");
1030
+ const requested = override ?? (model?.reasoning ? (isGptSolModel(model) ? "high" : DEFAULT_THINKING_LEVEL) : "off");
1034
1031
  const effective = model ? clampThinkingLevel(model, requested) : requested;
1035
1032
  return { requested, effective, clamped: effective !== requested };
1036
1033
  }
@@ -1272,7 +1269,10 @@ async function runOracle(
1272
1269
  }
1273
1270
 
1274
1271
  if (event.type === "message_start" && event.message?.role === "assistant") {
1272
+ // A later assistant turn supersedes any earlier tool/intermediate answer.
1273
+ // Keep only the current message so a tool-only final turn cannot return stale text.
1275
1274
  currentText = "";
1275
+ finalOutput = "";
1276
1276
  emit();
1277
1277
  return;
1278
1278
  }
@@ -1285,7 +1285,8 @@ async function runOracle(
1285
1285
 
1286
1286
  if (event.type === "message_end" && event.message?.role === "assistant") {
1287
1287
  const text = extractTextFromContent(event.message.content) || currentText;
1288
- if (text) finalOutput = text;
1288
+ // message_end is authoritative, including an empty tool-only message.
1289
+ finalOutput = text;
1289
1290
  currentText = "";
1290
1291
 
1291
1292
  const stopReason = event.message.stopReason;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-oracle",
3
- "version": "0.1.28",
3
+ "version": "0.1.29",
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",
@@ -25,6 +25,12 @@ Non-Windows and custom/remote `powershell` tools receive the conservative lexica
25
25
 
26
26
  This is a targeted confirmation guard for the command classes listed above, not a shell sandbox or a proof that every unlisted executable/API is harmless.
27
27
 
28
+ ## Pi 0.99 dispatch boundary
29
+
30
+ The policy is deliberately named-tool-only: it checks `bash`, `powershell`, `write`, and `edit` `tool_call` events. Pi 0.99 routes `ctx.executeTool()` calls (including calls made by `codemode`) through the same preflight tool-call pipeline and supplies `parentToolCallId`; the named checks therefore apply to nested calls too. Executed calls (including execution errors and `isError` results) reach the tool-result hook. Preflight-blocked, invalid, and unknown-tool calls instead produce Pi's host error result and, for nested calls, a bounded nested-call record without an after-execution `tool_result` event. Confirmation cancellation, UI failure, and missing UI fail closed.
31
+
32
+ MCP calls also pass through Pi's host pipeline, but arbitrary `mcp__<server>__<tool>` names are outside this extension's existing guarantee. This extension does not authorize arbitrary MCP tools, infer policy from `readOnlyHint`/`destructiveHint` annotations, or provide a universal MCP security sandbox. Any annotation-based or broader MCP policy requires separate human approval. Custom tools, remote/overridden implementations, and later handlers must enforce their own final-input policy.
33
+
28
34
  ## Install
29
35
 
30
36
  ### Standalone npm package
@@ -26,6 +26,17 @@ const MAX_SHELL_TIMEOUT_SECONDS = 2_147_483_647 / 1000;
26
26
  const POWERSHELL_ANALYSIS_TIMEOUT_MS = 5_000;
27
27
 
28
28
  type GuardDecision = { block: true; reason: string } | undefined;
29
+ type ConfirmationContext = {
30
+ hasUI?: boolean;
31
+ signal?: AbortSignal;
32
+ ui?: {
33
+ select(
34
+ prompt: string,
35
+ choices: string[],
36
+ dialogOptions?: { signal?: AbortSignal },
37
+ ): Promise<string | undefined>;
38
+ };
39
+ };
29
40
  type NormalizedPath = {
30
41
  original: string;
31
42
  displayPath: string;
@@ -611,26 +622,40 @@ function validateEditInput(input: unknown): EditInput | undefined {
611
622
  };
612
623
  }
613
624
 
625
+ async function requestConfirmation(prompt: string, ctx: ConfirmationContext): Promise<GuardDecision> {
626
+ if (!ctx.hasUI || !ctx.ui) {
627
+ return { block: true, reason: "Confirmation unavailable (no UI)" };
628
+ }
629
+ if (ctx.signal?.aborted) {
630
+ return { block: true, reason: "Confirmation cancelled" };
631
+ }
632
+
633
+ try {
634
+ const choice = await ctx.ui.select(prompt, ["Yes", "No"], { signal: ctx.signal });
635
+ if (ctx.signal?.aborted) {
636
+ return { block: true, reason: "Confirmation cancelled" };
637
+ }
638
+ return choice === "Yes" ? undefined : { block: true, reason: "Blocked by user" };
639
+ } catch {
640
+ // A dismissed or failed UI must never turn a confirmation failure into an allow.
641
+ return { block: true, reason: "Confirmation unavailable" };
642
+ }
643
+ }
644
+
614
645
  async function confirmProtectedPathAction(
615
646
  toolName: "write" | "edit",
616
647
  normalizedPath: NormalizedPath,
617
- ctx: { hasUI?: boolean; ui?: { select(prompt: string, options: string[]): Promise<string | undefined> } },
648
+ ctx: ConfirmationContext,
618
649
  ): Promise<GuardDecision> {
619
650
  if (!isProtectedPath(normalizedPath)) return undefined;
620
651
  if (!ctx.hasUI || !ctx.ui) {
621
652
  return { block: true, reason: `Protected path blocked (${toolName} without UI confirmation): ${normalizedPath.displayPath}` };
622
653
  }
623
654
 
624
- const choice = await ctx.ui.select(
655
+ return requestConfirmation(
625
656
  `⚠️ Protected path ${toolName} request:\n\n ${normalizedPath.displayPath}\n\nAllow?`,
626
- ["Yes", "No"],
657
+ ctx,
627
658
  );
628
-
629
- if (choice !== "Yes") {
630
- return { block: true, reason: "Blocked by user" };
631
- }
632
-
633
- return undefined;
634
659
  }
635
660
 
636
661
  export default function (pi: ExtensionAPI) {
@@ -643,8 +668,8 @@ export default function (pi: ExtensionAPI) {
643
668
  }
644
669
  const { command } = input;
645
670
 
646
- const isDangerous = shellToolName === "powershell"
647
- ? await hasDangerousPowerShellCommand(pi, command, ctx.signal)
671
+ const isDangerous = shellToolName === "powershell"
672
+ ? await hasDangerousPowerShellCommand(pi, command, ctx.signal)
648
673
  : hasDangerousRecursiveRm(command) || dangerousPatterns.some((pattern) => pattern.test(command));
649
674
 
650
675
  if (isDangerous) {
@@ -652,11 +677,7 @@ export default function (pi: ExtensionAPI) {
652
677
  return { block: true, reason: "Dangerous command blocked (no UI for confirmation)" };
653
678
  }
654
679
 
655
- const choice = await ctx.ui.select(`⚠️ Dangerous command:\n\n ${command}\n\nAllow?`, ["Yes", "No"]);
656
-
657
- if (choice !== "Yes") {
658
- return { block: true, reason: "Blocked by user" };
659
- }
680
+ return requestConfirmation(`⚠️ Dangerous command:\n\n ${command}\n\nAllow?`, ctx);
660
681
  }
661
682
 
662
683
  return undefined;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-permission-gate",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "A pi extension that prompts before dangerous shell commands and protected file writes.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -4,7 +4,7 @@ A pi extension that makes collapsed built-in tool rows much quieter in the TUI.
4
4
 
5
5
  When enabled, each collapsed tool row renders as one invocation line plus a separate `(Ctrl+O to expand)` hint line. Tool output is hidden until expanded. Expanding with `Ctrl+O` still shows pi's full rendered output.
6
6
 
7
- `quiet-tools` only changes the visual renderer. It does not truncate, summarize, or rewrite the actual tool results sent to the model.
7
+ `quiet-tools` only changes the visual renderer. It does not truncate, summarize, or rewrite the actual tool results sent to the model. On Pi 0.99, its replacement definitions retain the upstream schemas, labels, descriptions, exposure/namespace metadata, `outputSchema`, execution function, abort signal, update callback, execution context, details, structured content, error status, and bounded output behavior. Expanded rendering delegates back to Pi's renderer.
8
8
 
9
9
  ## Covered tools
10
10
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-quiet-tools",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "A pi extension that visually compacts collapsed built-in tool rows in the TUI without changing tool results sent to the model.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-triage-comments",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "A pi extension that adds /triage-comments and a read-only triage_comments subagent tool for review-comment triage.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -30,6 +30,7 @@
30
30
  ]
31
31
  },
32
32
  "peerDependencies": {
33
+ "@earendil-works/pi-ai": "*",
33
34
  "@earendil-works/pi-coding-agent": "*",
34
35
  "@earendil-works/pi-tui": "*",
35
36
  "typebox": "*"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-extensions",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
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",
@@ -71,9 +71,9 @@
71
71
  ]
72
72
  },
73
73
  "devDependencies": {
74
- "@earendil-works/pi-ai": "^0.87.1",
75
- "@earendil-works/pi-coding-agent": "^0.87.1",
76
- "@earendil-works/pi-tui": "^0.87.1",
74
+ "@earendil-works/pi-ai": "^1.0.0",
75
+ "@earendil-works/pi-coding-agent": "^1.0.0",
76
+ "@earendil-works/pi-tui": "^1.0.0",
77
77
  "@types/node": "^25.9.1",
78
78
  "husky": "^9.1.7",
79
79
  "typebox": "^1.3.6",