@diegopetrucci/pi-extensions 0.1.65 → 0.1.67
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/.pi-fleet-tested-version +1 -1
- package/README.md +1 -1
- package/extensions/agent-workflow-audit/.pi-fleet-tested-version +1 -1
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/annotate-git-diff/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-git-diff/README.md +3 -0
- package/extensions/annotate-git-diff/index.ts +49 -5
- package/extensions/annotate-git-diff/package.json +2 -1
- package/extensions/annotate-git-diff/quiet-glimpse.ts +24 -3
- package/extensions/annotate-git-diff/review-server.ts +379 -0
- package/extensions/annotate-git-diff/ui.ts +17 -41
- package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-last-message/index.ts +28 -2
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/annotate-last-message/quiet-glimpse.ts +24 -3
- package/extensions/brrr/.pi-fleet-tested-version +1 -1
- package/extensions/brrr/package.json +1 -1
- package/extensions/claude-fast/.pi-fleet-tested-version +1 -1
- package/extensions/claude-fast/package.json +1 -1
- package/extensions/code-reviewer/.pi-fleet-tested-version +1 -1
- package/extensions/code-reviewer/index.ts +3 -1
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/.pi-fleet-tested-version +1 -1
- package/extensions/confirm-destructive/package.json +1 -1
- package/extensions/context-cap/.pi-fleet-tested-version +1 -1
- package/extensions/context-cap/package.json +1 -1
- package/extensions/context-inspector/.pi-fleet-tested-version +1 -1
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/.pi-fleet-tested-version +1 -1
- package/extensions/contrarian/index.ts +50 -28
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/.pi-fleet-tested-version +1 -1
- package/extensions/dirty-repo-guard/package.json +1 -1
- package/extensions/dynamic-context-pruning/.pi-fleet-tested-version +1 -1
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/fast/.pi-fleet-tested-version +1 -1
- package/extensions/fast/package.json +1 -1
- package/extensions/git-footer/.pi-fleet-tested-version +1 -1
- package/extensions/git-footer/package.json +1 -1
- package/extensions/gnosis/.pi-fleet-tested-version +1 -1
- package/extensions/gnosis/package.json +1 -1
- package/extensions/illustrations-to-explain-things/.pi-fleet-tested-version +1 -1
- package/extensions/illustrations-to-explain-things/package.json +1 -1
- package/extensions/inline-bash/.pi-fleet-tested-version +1 -1
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/.pi-fleet-tested-version +1 -1
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
- package/extensions/minimal-footer/package.json +1 -1
- package/extensions/notify/.pi-fleet-tested-version +1 -1
- package/extensions/notify/package.json +1 -1
- package/extensions/openai-fast/.pi-fleet-tested-version +1 -1
- package/extensions/openai-fast/package.json +1 -1
- package/extensions/oracle/.pi-fleet-tested-version +1 -1
- package/extensions/oracle/index.ts +49 -28
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
- package/extensions/permission-gate/README.md +11 -3
- package/extensions/permission-gate/index.ts +70 -7
- package/extensions/permission-gate/package.json +4 -2
- package/extensions/permission-gate/powershell-safety.ts +1006 -0
- package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
- package/extensions/quiet-tools/package.json +1 -1
- package/extensions/review/.pi-fleet-tested-version +1 -1
- package/extensions/review/package.json +1 -1
- package/extensions/todo/.pi-fleet-tested-version +1 -1
- package/extensions/todo/package.json +1 -1
- package/extensions/triage-comments/.pi-fleet-tested-version +1 -1
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-illustrations-to-explain-things",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "A pi skill for generating clean, absurd Xiaohei-style article illustrations, shot lists, and visual metaphors.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-openai-fast",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -115,6 +115,9 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
115
115
|
"claude-opus-4-5",
|
|
116
116
|
"claude-opus-4-1",
|
|
117
117
|
"claude-opus-4",
|
|
118
|
+
"openai.gpt-5.6-sol",
|
|
119
|
+
"openai.gpt-5.6-terra",
|
|
120
|
+
"openai.gpt-5.6-luna",
|
|
118
121
|
"claude-sonnet-5",
|
|
119
122
|
"claude-sonnet-4-6",
|
|
120
123
|
"claude-sonnet-4-5",
|
|
@@ -125,6 +128,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
125
128
|
"minimax-m2.5",
|
|
126
129
|
"minimax-m2.1",
|
|
127
130
|
"zai.glm-5",
|
|
131
|
+
"xai.grok-4.6",
|
|
128
132
|
],
|
|
129
133
|
anthropic: [
|
|
130
134
|
"claude-opus-5",
|
|
@@ -160,6 +164,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
160
164
|
baseten: [
|
|
161
165
|
"moonshotai/Kimi-K3",
|
|
162
166
|
"moonshotai/Kimi-K2.7-Code",
|
|
167
|
+
"zai-org/GLM-5.3",
|
|
163
168
|
"deepseek-ai/DeepSeek-V4-Pro-0813",
|
|
164
169
|
"deepseek-ai/DeepSeek-V4-Pro",
|
|
165
170
|
"zai-org/GLM-5.2",
|
|
@@ -176,62 +181,67 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
176
181
|
"zai-org/GLM-5.2-Fast",
|
|
177
182
|
"zai-org/GLM-4.7",
|
|
178
183
|
],
|
|
179
|
-
cerebras: ["gpt-oss-120b", "
|
|
184
|
+
cerebras: ["gpt-oss-120b", "gemma-4-31b"],
|
|
180
185
|
"cloudflare-ai-gateway": [
|
|
181
186
|
"claude-fable-5",
|
|
182
|
-
"claude-opus-
|
|
183
|
-
"claude-opus-4
|
|
184
|
-
"claude-opus-4
|
|
187
|
+
"claude-opus-5",
|
|
188
|
+
"claude-opus-4.8",
|
|
189
|
+
"claude-opus-4.7",
|
|
190
|
+
"claude-opus-4.6",
|
|
191
|
+
"claude-opus-4.5",
|
|
185
192
|
"gpt-5.5",
|
|
186
193
|
"gpt-5.4",
|
|
187
|
-
"
|
|
194
|
+
"workers-ai/@cf/moonshotai/kimi-k2.7-code",
|
|
195
|
+
"workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813",
|
|
196
|
+
"workers-ai/@cf/zai-org/glm-5.3",
|
|
197
|
+
"workers-ai/@cf/zai-org/glm-5.2",
|
|
188
198
|
"workers-ai/@cf/moonshotai/kimi-k2.6",
|
|
189
199
|
"workers-ai/@cf/nvidia/nemotron-3-120b-a12b",
|
|
200
|
+
"workers-ai/@cf/openai/gpt-oss-120b",
|
|
190
201
|
"workers-ai/@cf/zai-org/glm-4.7-flash",
|
|
191
202
|
],
|
|
192
203
|
"cloudflare-workers-ai": [
|
|
193
204
|
"@cf/moonshotai/kimi-k2.7-code",
|
|
205
|
+
"@cf/deepseek-ai/deepseek-v4-pro-0813",
|
|
206
|
+
"@cf/zai-org/glm-5.3",
|
|
194
207
|
"@cf/zai-org/glm-5.2",
|
|
195
208
|
"@cf/moonshotai/kimi-k2.6",
|
|
196
209
|
"@cf/nvidia/nemotron-3-120b-a12b",
|
|
197
210
|
"@cf/openai/gpt-oss-120b",
|
|
211
|
+
"@cf/qwen/qwen3.8-27b",
|
|
198
212
|
"@cf/qwen/qwen3-30b-a3b-fp8",
|
|
199
213
|
"@cf/zai-org/glm-4.7-flash",
|
|
200
214
|
],
|
|
201
215
|
deepseek: ["deepseek-v4-pro", "deepseek-v4-flash"],
|
|
202
216
|
fireworks: [
|
|
217
|
+
"accounts/fireworks/models/kimi-k3",
|
|
218
|
+
"accounts/fireworks/routers/kimi-k3-fast",
|
|
203
219
|
"accounts/fireworks/models/deepseek-v4-pro",
|
|
204
220
|
"accounts/fireworks/models/kimi-k2p7-code",
|
|
205
|
-
"accounts/fireworks/routers/kimi-k2p7-code-fast",
|
|
206
221
|
"accounts/fireworks/models/glm-5p2",
|
|
207
222
|
"accounts/fireworks/routers/glm-5p2-fast",
|
|
208
223
|
"accounts/fireworks/models/minimax-m3",
|
|
209
224
|
"accounts/fireworks/models/kimi-k2p6",
|
|
210
|
-
"accounts/fireworks/routers/kimi-k2p6-turbo",
|
|
211
|
-
"accounts/fireworks/routers/kimi-k2p6-fast",
|
|
212
|
-
"accounts/fireworks/models/minimax-m2p7",
|
|
213
225
|
"accounts/fireworks/models/qwen3p7-plus",
|
|
214
226
|
"accounts/fireworks/models/gpt-oss-120b",
|
|
215
|
-
"accounts/fireworks/models/gpt-oss-20b",
|
|
216
227
|
],
|
|
217
228
|
"github-copilot": [
|
|
218
229
|
"claude-opus-5",
|
|
219
230
|
"claude-fable-5",
|
|
220
231
|
"claude-opus-4.8",
|
|
221
232
|
"claude-opus-4.7",
|
|
222
|
-
"
|
|
223
|
-
"
|
|
233
|
+
"gpt-6-astra",
|
|
234
|
+
"gpt-5.6-sol",
|
|
235
|
+
"gpt-5.6-terra",
|
|
236
|
+
"gpt-5.6-luna",
|
|
224
237
|
"gpt-5.5",
|
|
225
238
|
"gpt-5.4",
|
|
226
239
|
"gpt-5.3-codex",
|
|
227
|
-
"gpt-5.2-codex",
|
|
228
|
-
"gpt-5.2",
|
|
229
|
-
"gemini-3.1-pro-preview",
|
|
230
240
|
"gemini-3.5-flash",
|
|
231
241
|
"claude-sonnet-5",
|
|
232
242
|
"claude-sonnet-4.6",
|
|
233
|
-
"claude-sonnet-4.5",
|
|
234
243
|
"gpt-5-mini",
|
|
244
|
+
"kimi-k3",
|
|
235
245
|
"kimi-k2.7-code",
|
|
236
246
|
],
|
|
237
247
|
google: [
|
|
@@ -260,7 +270,10 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
260
270
|
"openai/gpt-oss-20b",
|
|
261
271
|
],
|
|
262
272
|
huggingface: [
|
|
273
|
+
"moonshotai/Kimi-K3",
|
|
263
274
|
"zai-org/GLM-5.1",
|
|
275
|
+
"zai-org/GLM-5.3-Flash",
|
|
276
|
+
"deepseek-ai/DeepSeek-V4-Pro-0813",
|
|
264
277
|
"deepseek-ai/DeepSeek-V4-Pro",
|
|
265
278
|
"moonshotai/Kimi-K2.6",
|
|
266
279
|
"MiniMaxAI/MiniMax-M2.7",
|
|
@@ -285,8 +298,10 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
285
298
|
"mistral-medium-2508",
|
|
286
299
|
"mistral-small-2603",
|
|
287
300
|
"devstral-2512",
|
|
301
|
+
"zai-glm-5-2",
|
|
288
302
|
],
|
|
289
303
|
openai: [
|
|
304
|
+
"gpt-6-astra",
|
|
290
305
|
"gpt-5.6-sol",
|
|
291
306
|
"gpt-5.6-terra",
|
|
292
307
|
"gpt-5.6-luna",
|
|
@@ -306,6 +321,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
306
321
|
"gpt-5-mini",
|
|
307
322
|
],
|
|
308
323
|
"openai-codex": [
|
|
324
|
+
"gpt-6-astra",
|
|
309
325
|
"gpt-5.6-sol",
|
|
310
326
|
"gpt-5.6-terra",
|
|
311
327
|
"gpt-5.6-luna",
|
|
@@ -334,6 +350,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
334
350
|
"glm-5.2",
|
|
335
351
|
"glm-5.1",
|
|
336
352
|
"glm-5",
|
|
353
|
+
"kimi-k3",
|
|
337
354
|
"kimi-k2.7-code",
|
|
338
355
|
"kimi-k2.6",
|
|
339
356
|
"kimi-k2.5",
|
|
@@ -344,6 +361,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
344
361
|
],
|
|
345
362
|
"opencode-go": [
|
|
346
363
|
"deepseek-v4-pro",
|
|
364
|
+
"glm-5.3",
|
|
347
365
|
"glm-5.2",
|
|
348
366
|
"glm-5.1",
|
|
349
367
|
"qwen3.7-max",
|
|
@@ -353,6 +371,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
353
371
|
"mimo-v2.5",
|
|
354
372
|
"minimax-m3",
|
|
355
373
|
"minimax-m2.7",
|
|
374
|
+
"kimi-k3",
|
|
356
375
|
"kimi-k2.7-code",
|
|
357
376
|
"kimi-k2.6",
|
|
358
377
|
],
|
|
@@ -361,9 +380,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
361
380
|
"anthropic/claude-fable-5",
|
|
362
381
|
"~anthropic/claude-fable-latest",
|
|
363
382
|
"anthropic/claude-opus-4.8",
|
|
364
|
-
"anthropic/claude-opus-4.8-fast",
|
|
365
383
|
"anthropic/claude-opus-4.7",
|
|
366
|
-
"anthropic/claude-opus-4.7-fast",
|
|
367
384
|
"anthropic/claude-opus-4.6",
|
|
368
385
|
"anthropic/claude-opus-4.5",
|
|
369
386
|
"anthropic/claude-opus-4.1",
|
|
@@ -381,6 +398,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
381
398
|
"~google/gemini-pro-latest",
|
|
382
399
|
"google/gemini-3.5-flash",
|
|
383
400
|
"google/gemini-2.5-pro",
|
|
401
|
+
"moonshotai/kimi-k3",
|
|
384
402
|
"moonshotai/kimi-k2.7-code",
|
|
385
403
|
"~moonshotai/kimi-latest",
|
|
386
404
|
"moonshotai/kimi-k2.6",
|
|
@@ -393,6 +411,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
393
411
|
"minimax/minimax-m3",
|
|
394
412
|
"minimax/minimax-m2.7",
|
|
395
413
|
"minimax/minimax-m2.1",
|
|
414
|
+
"z-ai/glm-5.3",
|
|
396
415
|
"z-ai/glm-5.2",
|
|
397
416
|
"z-ai/glm-5.1",
|
|
398
417
|
],
|
|
@@ -427,6 +446,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
427
446
|
],
|
|
428
447
|
together: [
|
|
429
448
|
"deepseek-ai/DeepSeek-V4-Pro",
|
|
449
|
+
"moonshotai/Kimi-K3",
|
|
450
|
+
"zai-org/GLM-5.3-Flash",
|
|
430
451
|
"zai-org/GLM-5.2",
|
|
431
452
|
"moonshotai/Kimi-K2.7-Code",
|
|
432
453
|
"moonshotai/Kimi-K2.6",
|
|
@@ -459,6 +480,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
459
480
|
"openai/gpt-5.2-codex",
|
|
460
481
|
"openai/gpt-5.1-codex",
|
|
461
482
|
"openai/gpt-5-codex",
|
|
483
|
+
"moonshotai/kimi-k3",
|
|
462
484
|
"moonshotai/kimi-k2.7-code",
|
|
463
485
|
"moonshotai/kimi-k2.7-code-highspeed",
|
|
464
486
|
"moonshotai/kimi-k2.6",
|
|
@@ -476,6 +498,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
476
498
|
"xai/grok-4.5",
|
|
477
499
|
"xai/grok-4.20-reasoning",
|
|
478
500
|
"minimax/minimax-m3",
|
|
501
|
+
"zai/glm-5.3",
|
|
479
502
|
"zai/glm-5.2",
|
|
480
503
|
"zai/glm-5.1",
|
|
481
504
|
],
|
|
@@ -483,21 +506,19 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
483
506
|
"grok-4.6",
|
|
484
507
|
"grok-4.5",
|
|
485
508
|
"grok-4.3",
|
|
486
|
-
"grok-build-0.1",
|
|
487
509
|
],
|
|
488
|
-
xiaomi: ["mimo-v2.5-pro", "mimo-v2.5
|
|
489
|
-
"xiaomi-token-plan-ams": ["mimo-v2.5-pro", "mimo-v2.5"
|
|
490
|
-
"xiaomi-token-plan-cn": ["mimo-v2.5-pro", "mimo-v2.5"
|
|
491
|
-
"xiaomi-token-plan-sgp": ["mimo-v2.5-pro", "mimo-v2.5"
|
|
510
|
+
xiaomi: ["mimo-v2.5-pro-ultraspeed", "mimo-v2.5-pro", "mimo-v2.5"],
|
|
511
|
+
"xiaomi-token-plan-ams": ["mimo-v2.5-pro", "mimo-v2.5"],
|
|
512
|
+
"xiaomi-token-plan-cn": ["mimo-v2.5-pro", "mimo-v2.5"],
|
|
513
|
+
"xiaomi-token-plan-sgp": ["mimo-v2.5-pro", "mimo-v2.5"],
|
|
492
514
|
nvidia: [
|
|
493
515
|
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
494
516
|
"nvidia/nemotron-3-super-120b-a12b",
|
|
517
|
+
"moonshotai/kimi-k3",
|
|
518
|
+
"deepseek-ai/deepseek-v4-pro-0813",
|
|
495
519
|
"moonshotai/kimi-k2.6",
|
|
496
|
-
"z-ai/glm-5.2",
|
|
497
520
|
"minimaxai/minimax-m3",
|
|
498
|
-
"openai/gpt-oss-120b",
|
|
499
521
|
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
500
|
-
"nvidia/nemotron-3-nano-30b-a3b",
|
|
501
522
|
],
|
|
502
523
|
zai: [
|
|
503
524
|
"glm-5.3",
|
|
@@ -512,8 +533,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
512
533
|
"glm-5",
|
|
513
534
|
"glm-4.7",
|
|
514
535
|
],
|
|
515
|
-
moonshotai: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
|
|
516
|
-
"moonshotai-cn": ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
|
|
536
|
+
moonshotai: ["kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
|
|
537
|
+
"moonshotai-cn": ["kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2-thinking-turbo", "kimi-k2-thinking", "kimi-k2.5"],
|
|
517
538
|
};
|
|
518
539
|
|
|
519
540
|
const ORACLE_SYSTEM_PROMPT = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.84.
|
|
1
|
+
0.84.4
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# permission-gate
|
|
2
2
|
|
|
3
|
-
A small pi extension that prompts for confirmation before running potentially dangerous bash commands or writing to protected paths.
|
|
3
|
+
A small pi extension that prompts for confirmation before running potentially dangerous bash or PowerShell commands or writing to protected paths.
|
|
4
4
|
|
|
5
|
-
This
|
|
5
|
+
This started from the original `permission-gate.ts` example in [`earendil-works/pi`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/extensions/permission-gate.ts) and adds conservative shell and path hardening.
|
|
6
6
|
|
|
7
7
|
## What it checks
|
|
8
8
|
|
|
9
9
|
- `rm -rf`
|
|
10
|
+
- PowerShell `Remove-Item -Recurse -Force` and its standard aliases, including module-qualified, interpolated, splatted, and backtick-escaped forms
|
|
10
11
|
- `sudo`
|
|
11
12
|
- `chmod` / `chown` with `777`
|
|
12
13
|
- direct `write` / `edit` calls touching normalized protected paths:
|
|
@@ -18,6 +19,12 @@ Safe `.env` templates/examples such as `.env.example` and `.env.production.templ
|
|
|
18
19
|
|
|
19
20
|
If pi is running without an interactive UI, it blocks matching commands and protected path writes by default.
|
|
20
21
|
|
|
22
|
+
For Pi's built-in local Windows PowerShell tool, commands that pass the fast lexical checks are also parsed with the same PowerShell installation's AST parser before execution. Malformed input, parser failures, `Remove-Item` parameter splatting, command-resolution changes (aliases/modules/providers/direct function or filter definitions), known script/process/job/member invocation wrappers, computed member calls, and analyzer inputs above 16,000 UTF-8 bytes are treated conservatively and require confirmation (or are blocked when no UI is available). Computed targets passed to provider-capable mutation commands also require confirmation because the target could resolve to `Alias:` or `Function:`. Literal quoted/commented examples, including literal here-strings, stay benign. Definitely enabled `-WhatIf` removals (`-WhatIf`, `-WhatIf:$true`, or `-WhatIf:1`) remain non-destructive and are allowed; computed switch values require confirmation.
|
|
23
|
+
|
|
24
|
+
Non-Windows and custom/remote `powershell` tools receive the conservative lexical checks, but only Pi's built-in local Windows tool can be verified with its actual parser. Pi extensions are trusted code: tool overrides, remote operations, spawn hooks, and mutations made by handlers loaded after this gate are outside its boundary and must enforce their own final-input policy.
|
|
25
|
+
|
|
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
|
+
|
|
21
28
|
## Install
|
|
22
29
|
|
|
23
30
|
### Standalone npm package
|
|
@@ -47,6 +54,7 @@ Then reload pi:
|
|
|
47
54
|
## Notes
|
|
48
55
|
|
|
49
56
|
- Hooks the `tool_call` event.
|
|
50
|
-
- Inspects `bash`, `write`, and `edit` tool calls.
|
|
57
|
+
- Inspects `bash`, `powershell`, `write`, and `edit` tool calls.
|
|
58
|
+
- Validates shell timeouts as well as command strings and fails closed on malformed calls.
|
|
51
59
|
- Normalizes relative/absolute paths before matching so traversal tricks do not bypass the guard.
|
|
52
60
|
- Prompts with a simple `Yes` / `No` selector before allowing dangerous commands or protected path writes.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Permission Gate Extension
|
|
3
3
|
*
|
|
4
|
-
* Prompts for confirmation before running potentially dangerous bash
|
|
5
|
-
* or modifying protected paths via write/edit.
|
|
4
|
+
* Prompts for confirmation before running potentially dangerous bash or
|
|
5
|
+
* PowerShell commands, or modifying protected paths via write/edit.
|
|
6
6
|
* Protected paths include exact .git and node_modules path segments plus
|
|
7
7
|
* secret-bearing .env files (excluding example/template variants).
|
|
8
8
|
*/
|
|
@@ -11,10 +11,19 @@ import * as path from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
13
|
|
|
14
|
+
import {
|
|
15
|
+
analyzePowerShellLexically,
|
|
16
|
+
buildPowerShellAstCommand,
|
|
17
|
+
MAX_POWERSHELL_ANALYSIS_SOURCE_BYTES,
|
|
18
|
+
parsePowerShellAstOutput,
|
|
19
|
+
} from "./powershell-safety.ts";
|
|
20
|
+
|
|
14
21
|
const dangerousPatterns = [/\bsudo\b/i, /\b(chmod|chown)\b.*777/i];
|
|
15
22
|
const protectedPathSegments = new Set([".git", "node_modules"]);
|
|
16
23
|
const shellCommandSeparators = new Set([";", "&", "&&", "||", "|", "\n", "(", ")", "{", "}"]);
|
|
17
24
|
const safeEnvSuffixes = new Set(["example", "examples", "template", "templates"]);
|
|
25
|
+
const MAX_SHELL_TIMEOUT_SECONDS = 2_147_483_647 / 1000;
|
|
26
|
+
const POWERSHELL_ANALYSIS_TIMEOUT_MS = 5_000;
|
|
18
27
|
|
|
19
28
|
type GuardDecision = { block: true; reason: string } | undefined;
|
|
20
29
|
type NormalizedPath = {
|
|
@@ -30,6 +39,7 @@ type ShellToken = {
|
|
|
30
39
|
|
|
31
40
|
type WriteInput = { path: string; content: string };
|
|
32
41
|
type EditInput = { path: string; edits: Array<{ oldText: string; newText: string }> };
|
|
42
|
+
type ShellInput = { command: string; timeout?: number };
|
|
33
43
|
|
|
34
44
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
35
45
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -524,6 +534,55 @@ function hasDangerousRecursiveRm(command: string): boolean {
|
|
|
524
534
|
return evaluateTokens(currentCommand);
|
|
525
535
|
}
|
|
526
536
|
|
|
537
|
+
function validateShellInput(input: unknown): ShellInput | undefined {
|
|
538
|
+
if (!isRecord(input) || typeof input.command !== "string" || input.command.trim() === "") return undefined;
|
|
539
|
+
if (
|
|
540
|
+
input.timeout !== undefined &&
|
|
541
|
+
(typeof input.timeout !== "number" ||
|
|
542
|
+
!Number.isFinite(input.timeout) ||
|
|
543
|
+
input.timeout <= 0 ||
|
|
544
|
+
input.timeout > MAX_SHELL_TIMEOUT_SECONDS)
|
|
545
|
+
) {
|
|
546
|
+
return undefined;
|
|
547
|
+
}
|
|
548
|
+
return input.timeout === undefined
|
|
549
|
+
? { command: input.command }
|
|
550
|
+
: { command: input.command, timeout: input.timeout };
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
async function hasDangerousPowerShellCommand(
|
|
554
|
+
pi: ExtensionAPI,
|
|
555
|
+
command: string,
|
|
556
|
+
signal?: AbortSignal,
|
|
557
|
+
): Promise<boolean> {
|
|
558
|
+
// Keep both lexical work and Windows' base64-expanded -Command transport
|
|
559
|
+
// bounded below the platform command-line limit. Oversized input is
|
|
560
|
+
// deliberately treated as requiring confirmation rather than failing open.
|
|
561
|
+
if (Buffer.byteLength(command, "utf8") > MAX_POWERSHELL_ANALYSIS_SOURCE_BYTES) return true;
|
|
562
|
+
|
|
563
|
+
const lexicalAnalysis = analyzePowerShellLexically(command);
|
|
564
|
+
if (lexicalAnalysis.risky) return true;
|
|
565
|
+
|
|
566
|
+
// Pi only exposes its built-in PowerShell tool on Windows. On that platform,
|
|
567
|
+
// ask PowerShell's own parser for the final word so ordinary syntax features
|
|
568
|
+
// (module qualification, interpolation, splatting, and backtick escapes) cannot
|
|
569
|
+
// bypass the fallback lexer. Parser failures and malformed output fail closed.
|
|
570
|
+
if (process.platform !== "win32") return false;
|
|
571
|
+
|
|
572
|
+
try {
|
|
573
|
+
const { getPowerShellConfig } = await import("@earendil-works/pi-coding-agent");
|
|
574
|
+
const config = getPowerShellConfig();
|
|
575
|
+
const result = await pi.exec(config.shell, [...config.args, buildPowerShellAstCommand(command)], {
|
|
576
|
+
timeout: POWERSHELL_ANALYSIS_TIMEOUT_MS,
|
|
577
|
+
signal,
|
|
578
|
+
});
|
|
579
|
+
if (result.code !== 0 || result.killed) return true;
|
|
580
|
+
return parsePowerShellAstOutput(result.stdout).risky;
|
|
581
|
+
} catch {
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
527
586
|
function validateWriteInput(input: unknown): WriteInput | undefined {
|
|
528
587
|
if (!isRecord(input)) return undefined;
|
|
529
588
|
if (typeof input.path !== "string" || typeof input.content !== "string") return undefined;
|
|
@@ -576,13 +635,17 @@ async function confirmProtectedPathAction(
|
|
|
576
635
|
|
|
577
636
|
export default function (pi: ExtensionAPI) {
|
|
578
637
|
pi.on("tool_call", async (event, ctx) => {
|
|
579
|
-
if (event.toolName === "bash") {
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
638
|
+
if (event.toolName === "bash" || event.toolName === "powershell") {
|
|
639
|
+
const shellToolName = event.toolName;
|
|
640
|
+
const input = validateShellInput(event.input);
|
|
641
|
+
if (!input) {
|
|
642
|
+
return { block: true, reason: `Malformed ${shellToolName} command blocked` };
|
|
583
643
|
}
|
|
644
|
+
const { command } = input;
|
|
584
645
|
|
|
585
|
-
|
|
646
|
+
const isDangerous = shellToolName === "powershell"
|
|
647
|
+
? await hasDangerousPowerShellCommand(pi, command, ctx.signal)
|
|
648
|
+
: hasDangerousRecursiveRm(command) || dangerousPatterns.some((pattern) => pattern.test(command));
|
|
586
649
|
|
|
587
650
|
if (isDangerous) {
|
|
588
651
|
if (!ctx.hasUI) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-permission-gate",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A pi extension that prompts before dangerous
|
|
3
|
+
"version": "0.1.14",
|
|
4
|
+
"description": "A pi extension that prompts before dangerous shell commands and protected file writes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
7
7
|
"pi",
|
|
8
8
|
"security",
|
|
9
9
|
"bash",
|
|
10
|
+
"powershell",
|
|
10
11
|
"permissions",
|
|
11
12
|
"file-safety"
|
|
12
13
|
],
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
},
|
|
19
20
|
"files": [
|
|
20
21
|
"index.ts",
|
|
22
|
+
"powershell-safety.ts",
|
|
21
23
|
"README.md",
|
|
22
24
|
".pi-fleet-tested-version"
|
|
23
25
|
],
|