@diegopetrucci/pi-extensions 0.1.74 → 0.1.78

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 (108) hide show
  1. package/LICENSE +2 -0
  2. package/README.md +17 -12
  3. package/extensions/agent-workflow-audit/README.md +1 -1
  4. package/extensions/agent-workflow-audit/index.ts +1631 -1009
  5. package/extensions/agent-workflow-audit/package.json +1 -1
  6. package/extensions/annotate-git-diff/README.md +3 -1
  7. package/extensions/annotate-git-diff/clipboard.ts +109 -100
  8. package/extensions/annotate-git-diff/git.ts +846 -768
  9. package/extensions/annotate-git-diff/glimpseui.d.ts +87 -78
  10. package/extensions/annotate-git-diff/index.ts +712 -671
  11. package/extensions/annotate-git-diff/package.json +1 -1
  12. package/extensions/annotate-git-diff/prompt.ts +45 -45
  13. package/extensions/annotate-git-diff/quiet-glimpse.ts +161 -155
  14. package/extensions/annotate-git-diff/review-server.ts +337 -311
  15. package/extensions/annotate-git-diff/types.ts +132 -132
  16. package/extensions/annotate-git-diff/ui.ts +27 -27
  17. package/extensions/annotate-git-diff/watch.ts +74 -74
  18. package/extensions/annotate-git-diff/web/app.js +1947 -1884
  19. package/extensions/annotate-git-diff/web/index.html +5 -6
  20. package/extensions/annotate-last-message/README.md +1 -1
  21. package/extensions/annotate-last-message/glimpseui.d.ts +87 -78
  22. package/extensions/annotate-last-message/index.ts +210 -206
  23. package/extensions/annotate-last-message/package.json +1 -1
  24. package/extensions/annotate-last-message/prompt.ts +87 -66
  25. package/extensions/annotate-last-message/quiet-glimpse.ts +161 -155
  26. package/extensions/annotate-last-message/session.ts +94 -89
  27. package/extensions/annotate-last-message/theme.ts +199 -193
  28. package/extensions/annotate-last-message/types.ts +23 -23
  29. package/extensions/annotate-last-message/ui.ts +27 -25
  30. package/extensions/annotate-last-message/web/app.js +4 -7
  31. package/extensions/annotate-last-message/web/index.html +3 -3
  32. package/extensions/annotate-last-message/web/md-renderer.js +1 -1
  33. package/extensions/brrr/README.md +1 -1
  34. package/extensions/brrr/index.ts +213 -191
  35. package/extensions/brrr/package.json +1 -1
  36. package/extensions/claude-fast/README.md +5 -79
  37. package/extensions/claude-fast/index.ts +31 -289
  38. package/extensions/claude-fast/package.json +2 -3
  39. package/extensions/code-reviewer/README.md +6 -6
  40. package/extensions/code-reviewer/index.ts +1825 -1373
  41. package/extensions/code-reviewer/package.json +1 -1
  42. package/extensions/confirm-destructive/README.md +1 -1
  43. package/extensions/confirm-destructive/index.ts +50 -52
  44. package/extensions/confirm-destructive/package.json +1 -1
  45. package/extensions/context-cap/README.md +9 -9
  46. package/extensions/context-cap/index.ts +313 -305
  47. package/extensions/context-cap/package.json +2 -2
  48. package/extensions/context-inspector/index.ts +1211 -1064
  49. package/extensions/context-inspector/package.json +1 -1
  50. package/extensions/contrarian/README.md +4 -3
  51. package/extensions/contrarian/index.ts +1863 -1737
  52. package/extensions/contrarian/package.json +1 -1
  53. package/extensions/dirty-repo-guard/index.ts +37 -41
  54. package/extensions/dirty-repo-guard/package.json +1 -1
  55. package/extensions/dynamic-context-pruning/README.md +11 -43
  56. package/extensions/dynamic-context-pruning/index.ts +2131 -2105
  57. package/extensions/dynamic-context-pruning/package.json +1 -1
  58. package/extensions/fast/README.md +52 -14
  59. package/extensions/fast/index.ts +513 -317
  60. package/extensions/fast/package.json +1 -1
  61. package/extensions/git-footer/README.md +1 -1
  62. package/extensions/git-footer/index.ts +458 -411
  63. package/extensions/git-footer/package.json +2 -3
  64. package/extensions/gnosis/index.ts +180 -130
  65. package/extensions/gnosis/package.json +1 -1
  66. package/extensions/inline-bash/index.ts +87 -103
  67. package/extensions/inline-bash/package.json +1 -1
  68. package/extensions/librarian/README.md +1 -1
  69. package/extensions/librarian/index.ts +1877 -1419
  70. package/extensions/librarian/package.json +1 -1
  71. package/extensions/minimal-footer/README.md +5 -5
  72. package/extensions/minimal-footer/index.ts +987 -1012
  73. package/extensions/minimal-footer/minimal-footer.example.json +1 -1
  74. package/extensions/minimal-footer/openai-usage.ts +195 -190
  75. package/extensions/minimal-footer/package.json +1 -1
  76. package/extensions/notify/index.ts +222 -230
  77. package/extensions/notify/package.json +1 -1
  78. package/extensions/openai-fast/README.md +5 -73
  79. package/extensions/openai-fast/index.ts +32 -272
  80. package/extensions/openai-fast/package.json +2 -3
  81. package/extensions/oracle/README.md +4 -3
  82. package/extensions/oracle/index.ts +1740 -1627
  83. package/extensions/oracle/package.json +1 -1
  84. package/extensions/permission-gate/README.md +3 -0
  85. package/extensions/permission-gate/index.ts +785 -612
  86. package/extensions/permission-gate/package.json +1 -1
  87. package/extensions/permission-gate/powershell-safety.ts +840 -793
  88. package/extensions/project-mcp-json/.pi-fleet-tested-version +1 -0
  89. package/extensions/project-mcp-json/README.md +199 -0
  90. package/extensions/project-mcp-json/config.ts +564 -0
  91. package/extensions/project-mcp-json/index.ts +119 -0
  92. package/extensions/project-mcp-json/package.json +38 -0
  93. package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
  94. package/extensions/quiet-tools/README.md +30 -19
  95. package/extensions/quiet-tools/index.ts +376 -291
  96. package/extensions/quiet-tools/package.json +2 -2
  97. package/extensions/review/README.md +2 -2
  98. package/extensions/review/index.ts +1745 -1872
  99. package/extensions/review/package.json +1 -1
  100. package/extensions/todo/index.ts +280 -280
  101. package/extensions/todo/package.json +1 -1
  102. package/extensions/triage-comments/README.md +6 -4
  103. package/extensions/triage-comments/index.ts +2620 -1888
  104. package/extensions/triage-comments/package.json +1 -1
  105. package/package.json +9 -6
  106. package/assets/social-preview.png +0 -0
  107. package/extensions/claude-fast/claude-fast.example.json +0 -4
  108. package/extensions/openai-fast/openai-fast.example.json +0 -4
@@ -1,275 +1,35 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import {
4
- CONFIG_DIR_NAME,
5
- getAgentDir,
6
- type ExtensionAPI,
7
- type ExtensionContext,
8
- } from "@earendil-works/pi-coding-agent";
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
2
 
10
3
  const EXTENSION_ID = "openai-fast";
11
- const PROVIDER_ID = "openai-codex";
12
- const API_ID = "openai-codex-responses";
13
- const FAST_SERVICE_TIER = "priority";
14
- const SUPPORTED_MODELS = new Set([
15
- "gpt-5.5",
16
- "gpt-5.6-sol",
17
- "gpt-5.6-terra",
18
- "gpt-5.6-luna",
19
- ]);
20
- const SUPPORTED_MODELS_LABEL = "gpt-5.5, gpt-5.6-sol, gpt-5.6-terra, or gpt-5.6-luna";
21
-
22
- const DEFAULT_CONFIG: OpenAIFastConfig = {
23
- enabled: false,
24
- showStatus: true,
25
- };
26
-
27
- type FastOverride = "auto" | "on" | "off";
28
-
29
- type OpenAIFastConfig = {
30
- /** Default Fast-mode state when there is no session override. */
31
- enabled: boolean;
32
- /** Show a compact `fast` status when Fast mode is active for the current model. */
33
- showStatus: boolean;
34
- };
35
-
36
- type SessionState = {
37
- config: OpenAIFastConfig;
38
- override: FastOverride;
39
- lastInjectedAt?: number;
40
- lastInjectedModel?: string;
41
- };
42
-
43
- type ProjectConfigContext = {
44
- cwd: string;
45
- isProjectTrusted?: () => boolean;
46
- };
47
-
48
- type RecursivePartial<T> = {
49
- [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P];
50
- };
51
-
52
- type PayloadRecord = Record<string, unknown>;
53
-
54
- type Eligibility = {
55
- eligible: boolean;
56
- modelKey: string;
57
- reason?: string;
58
- };
59
-
60
- function readConfigFile(path: string): RecursivePartial<OpenAIFastConfig> {
61
- if (!existsSync(path)) return {};
62
-
63
- try {
64
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
65
- return isPayloadRecord(parsed) ? (parsed as RecursivePartial<OpenAIFastConfig>) : {};
66
- } catch (error) {
67
- console.error(`Warning: Could not parse ${path}: ${error}`);
68
- return {};
69
- }
70
- }
71
-
72
- function normalizeBoolean(value: unknown, fallback: boolean): boolean {
73
- return typeof value === "boolean" ? value : fallback;
74
- }
75
-
76
- function mergeConfig(
77
- base: OpenAIFastConfig,
78
- overrides: RecursivePartial<OpenAIFastConfig>,
79
- ): OpenAIFastConfig {
80
- return {
81
- enabled: normalizeBoolean(overrides.enabled, base.enabled),
82
- showStatus: normalizeBoolean(overrides.showStatus, base.showStatus),
83
- };
84
- }
85
-
86
- function canReadProjectConfig(ctx: ProjectConfigContext): boolean {
87
- return typeof ctx.isProjectTrusted === "function" && ctx.isProjectTrusted();
88
- }
89
-
90
- function findProjectConfigPath(cwd: string): string {
91
- let current = cwd;
92
- while (true) {
93
- const candidate = join(current, CONFIG_DIR_NAME, "openai-fast.json");
94
- if (existsSync(candidate)) return candidate;
95
-
96
- const parent = dirname(current);
97
- if (parent === current) return join(cwd, CONFIG_DIR_NAME, "openai-fast.json");
98
- current = parent;
99
- }
100
- }
101
-
102
- function loadConfig(ctx: ProjectConfigContext): OpenAIFastConfig {
103
- const globalConfig = readConfigFile(join(getAgentDir(), "extensions", "openai-fast.json"));
104
- const projectConfig = canReadProjectConfig(ctx) ? readConfigFile(findProjectConfigPath(ctx.cwd)) : {};
105
- return mergeConfig(mergeConfig(DEFAULT_CONFIG, globalConfig), projectConfig);
106
- }
107
-
108
- function isPayloadRecord(payload: unknown): payload is PayloadRecord {
109
- return typeof payload === "object" && payload !== null && !Array.isArray(payload);
110
- }
111
-
112
- function modelKey(ctx: ExtensionContext): string {
113
- const model = ctx.model;
114
- return model ? `${model.provider}/${model.id}` : "no-model";
115
- }
116
-
117
- function isFastEnabled(state: SessionState): boolean {
118
- if (state.override === "on") return true;
119
- if (state.override === "off") return false;
120
- return state.config.enabled;
121
- }
122
-
123
- function describeMode(state: SessionState): string {
124
- if (state.override === "on") return "on (session override)";
125
- if (state.override === "off") return "off (session override)";
126
- return state.config.enabled ? "on (config default)" : "off (config default)";
127
- }
128
-
129
- function getEligibility(ctx: ExtensionContext): Eligibility {
130
- const model = ctx.model;
131
- if (!model) {
132
- return { eligible: false, modelKey: "no-model", reason: "no model is selected" };
133
- }
134
-
135
- const key = `${model.provider}/${model.id}`;
136
- if (model.provider !== PROVIDER_ID) {
137
- return {
138
- eligible: false,
139
- modelKey: key,
140
- reason: `current provider is ${model.provider}, not ${PROVIDER_ID}`,
141
- };
142
- }
143
-
144
- if (model.api !== API_ID) {
145
- return {
146
- eligible: false,
147
- modelKey: key,
148
- reason: `current API is ${model.api}, not ${API_ID}`,
149
- };
150
- }
151
-
152
- if (!SUPPORTED_MODELS.has(model.id)) {
153
- return {
154
- eligible: false,
155
- modelKey: key,
156
- reason: `Fast mode is only enabled for ${SUPPORTED_MODELS_LABEL}`,
157
- };
158
- }
159
-
160
- if (!ctx.modelRegistry.isUsingOAuth(model)) {
161
- return {
162
- eligible: false,
163
- modelKey: key,
164
- reason: "ChatGPT OAuth auth is required; API-key auth is intentionally not used",
165
- };
166
- }
167
-
168
- return { eligible: true, modelKey: key };
169
- }
170
-
171
- function updateStatus(ctx: ExtensionContext, state: SessionState): void {
172
- if (!ctx.hasUI) return;
173
- if (!state.config.showStatus) {
174
- ctx.ui.setStatus(EXTENSION_ID, undefined);
175
- return;
176
- }
177
-
178
- const eligibility = getEligibility(ctx);
179
- ctx.ui.setStatus(
180
- EXTENSION_ID,
181
- isFastEnabled(state) && eligibility.eligible ? "fast" : undefined,
182
- );
183
- }
184
-
185
- function getStatusMessage(ctx: ExtensionContext, state: SessionState): string {
186
- const enabled = isFastEnabled(state);
187
- const eligibility = getEligibility(ctx);
188
- const active = enabled && eligibility.eligible;
189
- const injected = state.lastInjectedAt
190
- ? ` Last injected for ${state.lastInjectedModel ?? "unknown model"} ${Math.max(0, Math.round((Date.now() - state.lastInjectedAt) / 1000))}s ago.`
191
- : "";
192
-
193
- if (active) {
194
- return `OpenAI Fast mode is ${describeMode(state)} and active for ${eligibility.modelKey}; requests will use service_tier=${FAST_SERVICE_TIER}.${injected}`;
195
- }
196
-
197
- if (enabled) {
198
- return `OpenAI Fast mode is ${describeMode(state)}, but inactive for ${eligibility.modelKey}: ${eligibility.reason}.${injected}`;
199
- }
200
-
201
- return `OpenAI Fast mode is ${describeMode(state)}. Current model: ${eligibility.modelKey}.${injected}`;
202
- }
203
-
204
- function injectFastServiceTier(
205
- payload: unknown,
206
- ctx: ExtensionContext,
207
- state: SessionState,
208
- ): PayloadRecord | undefined {
209
- if (!isFastEnabled(state)) return undefined;
210
- if (!getEligibility(ctx).eligible) return undefined;
211
- if (!isPayloadRecord(payload)) return undefined;
212
- if (payload.model !== ctx.model?.id) return undefined;
213
- if ("service_tier" in payload) return undefined;
214
-
215
- state.lastInjectedAt = Date.now();
216
- state.lastInjectedModel = modelKey(ctx);
217
- return {
218
- ...payload,
219
- service_tier: FAST_SERVICE_TIER,
220
- };
221
- }
222
-
223
- export default function openAIFastExtension(pi: ExtensionAPI) {
224
- const states = new WeakMap<object, SessionState>();
225
-
226
- function getState(ctx: ExtensionContext): SessionState {
227
- let state = states.get(ctx.sessionManager);
228
- if (!state) {
229
- state = {
230
- config: loadConfig(ctx),
231
- override: "auto",
232
- };
233
- states.set(ctx.sessionManager, state);
234
- }
235
- return state;
236
- }
237
-
238
- pi.on("session_start", (_event, ctx) => {
239
- const state: SessionState = {
240
- config: loadConfig(ctx),
241
- override: "auto",
242
- };
243
- states.set(ctx.sessionManager, state);
244
- updateStatus(ctx, state);
245
- });
246
-
247
- pi.on("model_select", (_event, ctx) => {
248
- updateStatus(ctx, getState(ctx));
249
- });
250
-
251
- pi.on("before_provider_request", (event, ctx) => {
252
- const state = getState(ctx);
253
- const nextPayload = injectFastServiceTier(event.payload, ctx, state);
254
- updateStatus(ctx, state);
255
- return nextPayload;
256
- });
257
-
258
- pi.registerCommand("fast", {
259
- description: "Toggle OpenAI Codex Fast mode for ChatGPT-auth GPT-5.5 and GPT-5.6 Codex variants",
260
- getArgumentCompletions: () => null,
261
- handler: async (args, ctx) => {
262
- const state = getState(ctx);
263
- const action = args.trim();
264
-
265
- if (!action) {
266
- state.override = isFastEnabled(state) ? "off" : "on";
267
- updateStatus(ctx, state);
268
- ctx.ui.notify(getStatusMessage(ctx, state), "info");
269
- return;
270
- }
271
-
272
- ctx.ui.notify("Usage: /fast", "warning");
273
- },
274
- });
4
+ const FAST_BETA = "fast-mode-2026-02-01";
5
+ const DEPRECATION_NOTICE =
6
+ "openai-fast is deprecated and no longer changes provider requests. Use the unified fast extension (/fast) instead.";
7
+
8
+ /**
9
+ * Deprecated leftover of the provider-specific Fast stack.
10
+ * The collection loads extensions/fast only. This package keeps the published
11
+ * npm name working. It does not read config, register commands, or inject Fast
12
+ * fields. Startup only clears leftover footer status and the Fast beta header,
13
+ * which /reload otherwise keeps from the previous extension runtime.
14
+ */
15
+ function stripFastBeta(headers: Record<string, string> | undefined): void {
16
+ if (!headers) return;
17
+ for (const key of Object.keys(headers)) {
18
+ if (key.toLowerCase() !== "anthropic-beta") continue;
19
+ const next = headers[key]
20
+ .split(",")
21
+ .map((part) => part.trim())
22
+ .filter((part) => part && part !== FAST_BETA);
23
+ if (next.length === 0) delete headers[key];
24
+ else headers[key] = next.join(",");
25
+ }
26
+ }
27
+
28
+ export default function openAIFastExtension(pi: ExtensionAPI): void {
29
+ pi.on("session_start", (_event, ctx) => {
30
+ stripFastBeta(ctx.model?.headers);
31
+ if (!ctx.hasUI) return;
32
+ ctx.ui.setStatus(EXTENSION_ID, undefined);
33
+ ctx.ui.notify(DEPRECATION_NOTICE, "warning");
34
+ });
275
35
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-openai-fast",
3
- "version": "0.1.17",
4
- "description": "A pi extension that enables OpenAI Codex Fast mode for ChatGPT-auth GPT-5.5 and GPT-5.6 Codex variants by injecting the priority service tier.",
3
+ "version": "0.1.18",
4
+ "description": "Deprecated standalone leftover. Does not change provider requests; use @diegopetrucci/pi-fast.",
5
5
  "keywords": [
6
6
  "pi-package",
7
7
  "pi",
@@ -17,7 +17,6 @@
17
17
  },
18
18
  "files": [
19
19
  "index.ts",
20
- "openai-fast.example.json",
21
20
  "README.md",
22
21
  ".pi-fleet-tested-version"
23
22
  ],
@@ -4,11 +4,11 @@
4
4
 
5
5
  An Amp-style oracle for [pi](https://github.com/earendil-works/pi).
6
6
 
7
- It adds an `oracle` tool that spins up a separate read-only pi subprocess and sends it to the strongest reasoning model available on the **same provider/subscription** the user is currently using.
7
+ It adds an `oracle` tool that spins up a separate pi subprocess with read-only built-in tools and any configured MCP tools, and sends it to the strongest reasoning model available on the **same provider/subscription** the user is currently using.
8
8
 
9
9
  ## What it does
10
10
 
11
- - creates an isolated read-only subprocess
11
+ - creates an isolated subprocess with read-only built-in tools (read, grep, find, ls) and any configured MCP tools
12
12
  - auto-picks the strongest reasoning model on the current provider
13
13
  - uses provider-specific hardcoded rankings first, then a heuristic fallback
14
14
  - requests `xhigh` by default for reasoning models, then clamps to the model-supported thinking level
@@ -110,7 +110,8 @@ When the current Pi session has a non-empty model scope, Oracle limits automatic
110
110
 
111
111
  ## Notes
112
112
 
113
- - The oracle is intentionally **read-only by default**.
113
+ - The oracle subprocess uses read-only built-in tools (read, grep, find, ls) by default, plus any configured MCP tools. It can optionally include bash for non-mutating inspection.
114
+ - Configured MCP tools run without confirmation inside the subprocess and may have side effects — use them only for gathering evidence. MCP access requires host Pi >=1.0.4; older hosts degrade to no MCP, no error.
114
115
  - It is best for review, analysis, planning, debugging, and second opinions.
115
116
  - It is slower than using the main model directly, so it should be used selectively.
116
117
  - While it runs in interactive mode, it adds a footer status line and a widget below the editor.