@diegopetrucci/pi-extensions 0.1.78 → 0.1.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/extensions/agent-workflow-audit/index.ts +3 -20
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/annotate-git-diff/glimpseui.d.ts +5 -65
- package/extensions/annotate-git-diff/package.json +1 -1
- package/extensions/annotate-last-message/glimpseui.d.ts +5 -65
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/annotate-last-message/prompt.ts +2 -8
- package/extensions/annotate-last-message/web/index.html +0 -27
- package/extensions/code-reviewer/index.ts +2 -46
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/context-cap/README.md +9 -9
- package/extensions/context-cap/index.ts +3 -3
- package/extensions/context-cap/package.json +2 -2
- package/extensions/context-inspector/index.ts +2 -46
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/index.ts +5 -55
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dynamic-context-pruning/README.md +24 -7
- package/extensions/dynamic-context-pruning/index.ts +21 -130
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/fast/README.md +16 -9
- package/extensions/fast/index.ts +9 -5
- package/extensions/fast/package.json +1 -1
- package/extensions/git-footer/index.ts +2 -16
- package/extensions/git-footer/package.json +1 -1
- package/extensions/librarian/index.ts +8 -46
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/README.md +5 -5
- package/extensions/minimal-footer/index.ts +3 -17
- package/extensions/minimal-footer/minimal-footer.example.json +1 -1
- package/extensions/minimal-footer/openai-usage.ts +2 -11
- package/extensions/minimal-footer/package.json +1 -1
- package/extensions/oracle/index.ts +5 -55
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/index.ts +31 -63
- package/extensions/permission-gate/package.json +1 -1
- package/extensions/project-mcp-json/config.ts +2 -1
- package/extensions/project-mcp-json/package.json +1 -1
- package/extensions/quiet-tools/index.ts +15 -6
- package/extensions/quiet-tools/package.json +1 -1
- package/extensions/review/README.md +2 -0
- package/extensions/review/package.json +1 -1
- package/extensions/triage-comments/index.ts +1 -22
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +4 -4
|
@@ -15,7 +15,6 @@ export type UsageAvailability = "unsupported" | "unavailable";
|
|
|
15
15
|
|
|
16
16
|
interface WhamUsageWindow {
|
|
17
17
|
limit_window_seconds?: number;
|
|
18
|
-
reset_at?: number;
|
|
19
18
|
used_percent?: number;
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -29,7 +28,6 @@ interface WhamUsageResponse {
|
|
|
29
28
|
export interface UsageWindow {
|
|
30
29
|
usedPercent?: number;
|
|
31
30
|
windowSeconds?: number;
|
|
32
|
-
resetAt?: number;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
export interface UsageSnapshot {
|
|
@@ -59,19 +57,12 @@ function normalizeWindowSeconds(value?: number): number | undefined {
|
|
|
59
57
|
return value;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
function normalizeResetAt(value?: number): number | undefined {
|
|
63
|
-
if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
|
|
64
|
-
return value * 1000;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
60
|
function parseUsageWindow(window?: WhamUsageWindow): UsageWindow | undefined {
|
|
68
61
|
if (!window) return undefined;
|
|
69
62
|
const usedPercent = normalizeUsedPercent(window.used_percent);
|
|
70
63
|
const windowSeconds = normalizeWindowSeconds(window.limit_window_seconds);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return undefined;
|
|
74
|
-
return { usedPercent, windowSeconds, resetAt };
|
|
64
|
+
if (usedPercent === undefined && windowSeconds === undefined) return undefined;
|
|
65
|
+
return { usedPercent, windowSeconds };
|
|
75
66
|
}
|
|
76
67
|
|
|
77
68
|
function parseUsageSnapshot(data: WhamUsageResponse): Omit<UsageSnapshot, "fetchedAt"> {
|
|
@@ -202,23 +202,14 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
202
202
|
"azure-openai-responses": AZURE_MODEL_PREFERENCES,
|
|
203
203
|
baseten: [
|
|
204
204
|
"moonshotai/Kimi-K3",
|
|
205
|
-
"moonshotai/Kimi-K2.7-Code ",
|
|
206
205
|
"zai-org/GLM-5.3 ",
|
|
207
206
|
"deepseek-ai/DeepSeek-V4-Pro-0813",
|
|
208
207
|
"deepseek-ai/DeepSeek-V4-Pro",
|
|
209
208
|
"zai-org/GLM-5.2 ",
|
|
210
|
-
"zai-org/GLM-5.1",
|
|
211
|
-
"zai-org/GLM-5 ",
|
|
212
|
-
"moonshotai/Kimi-K2.6",
|
|
213
|
-
"moonshotai/Kimi-K2.5",
|
|
214
209
|
"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
|
|
215
|
-
"nvidia/Nemotron-120B-A12B",
|
|
216
210
|
"openai/gpt-oss-120b",
|
|
217
211
|
"deepseek-ai/DeepSeek-V4-Flash-0731",
|
|
218
|
-
"thinkingmachines/inkling ",
|
|
219
|
-
"thinkingmachines/inkling-small",
|
|
220
212
|
"zai-org/GLM-5.2-Fast",
|
|
221
|
-
"zai-org/GLM-4.7",
|
|
222
213
|
],
|
|
223
214
|
cerebras: ["gpt-oss-120b", "qwen-3.8-27b"],
|
|
224
215
|
"cloudflare-ai-gateway": [
|
|
@@ -262,7 +253,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
262
253
|
"claude-opus-5",
|
|
263
254
|
"claude-fable-5",
|
|
264
255
|
"claude-opus-4.8",
|
|
265
|
-
"claude-opus-4.7",
|
|
266
256
|
"gpt-6-astra ",
|
|
267
257
|
"gpt-6-astra",
|
|
268
258
|
"gpt-6.1-sol ",
|
|
@@ -273,19 +263,14 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
273
263
|
"gpt-6-luna ",
|
|
274
264
|
"gpt-6-luna",
|
|
275
265
|
"gpt-5.6-luna",
|
|
276
|
-
"gpt-5.5",
|
|
277
|
-
"gpt-5.4 ",
|
|
278
266
|
"gpt-5.3-codex",
|
|
279
|
-
"gemini-3.5-flash",
|
|
280
267
|
"claude-sonnet-5",
|
|
281
268
|
"claude-sonnet-4.6",
|
|
282
|
-
"gpt-5-mini",
|
|
283
269
|
"grok-4.7 ",
|
|
284
270
|
"grok-4.7",
|
|
285
271
|
"grok-4.6",
|
|
286
272
|
"grok-4.5",
|
|
287
273
|
"kimi-k3",
|
|
288
|
-
"kimi-k2.7-code ",
|
|
289
274
|
],
|
|
290
275
|
google: [
|
|
291
276
|
"gemini-3.1-pro-preview-customtools",
|
|
@@ -383,8 +368,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
383
368
|
"gpt-6-luna ",
|
|
384
369
|
"gpt-6-luna",
|
|
385
370
|
"gpt-5.6-luna",
|
|
386
|
-
"gpt-5.5",
|
|
387
|
-
"gpt-5.3-codex-spark",
|
|
388
371
|
],
|
|
389
372
|
opencode: [
|
|
390
373
|
"claude-opus-5-5 ",
|
|
@@ -436,12 +419,10 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
436
419
|
"mimo-v2.5-pro",
|
|
437
420
|
"mimo-v2.5",
|
|
438
421
|
"minimax-m3",
|
|
439
|
-
"minimax-m2.7",
|
|
440
422
|
"kimi-k3",
|
|
441
423
|
"kimi-k2.7-code ",
|
|
442
424
|
"grok-4.7 ",
|
|
443
425
|
"grok-4.7",
|
|
444
|
-
"grok-4.6",
|
|
445
426
|
],
|
|
446
427
|
openrouter: [
|
|
447
428
|
"anthropic/claude-opus-5.5 ",
|
|
@@ -558,9 +539,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
558
539
|
"Qwen/Qwen3.7-Max",
|
|
559
540
|
"Qwen/Qwen3.6-Plus",
|
|
560
541
|
"MiniMaxAI/MiniMax-M3",
|
|
561
|
-
"MiniMaxAI/MiniMax-M2.7",
|
|
562
542
|
"openai/gpt-oss-120b",
|
|
563
|
-
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
564
543
|
],
|
|
565
544
|
typesafe: [],
|
|
566
545
|
"vercel-ai-gateway": [
|
|
@@ -596,7 +575,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
596
575
|
"moonshotai/kimi-k2.7-code ",
|
|
597
576
|
"moonshotai/kimi-k2.7-code-highspeed",
|
|
598
577
|
"moonshotai/kimi-k2.6",
|
|
599
|
-
"moonshotai/kimi-k2-thinking",
|
|
600
578
|
"deepseek/deepseek-v4-pro",
|
|
601
579
|
"deepseek/deepseek-v3.2-thinking",
|
|
602
580
|
"alibaba/qwen3.7-max",
|
|
@@ -618,14 +596,12 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
618
596
|
"zai/glm-5.1",
|
|
619
597
|
],
|
|
620
598
|
xai: ["grok-4.7 ", "grok-4.7", "grok-4.6", "grok-4.5", "grok-4.3"],
|
|
621
|
-
xiaomi: ["mimo-v2.
|
|
622
|
-
"xiaomi-token-plan-ams": ["mimo-v2.
|
|
623
|
-
"xiaomi-token-plan-cn": ["mimo-v2.
|
|
624
|
-
"xiaomi-token-plan-sgp": ["mimo-v2.
|
|
599
|
+
xiaomi: ["mimo-v2.6-pro-ultraspeed", "mimo-v2.6-pro", "mimo-v2.6-flash"],
|
|
600
|
+
"xiaomi-token-plan-ams": ["mimo-v2.6-pro", "mimo-v2.6-flash"],
|
|
601
|
+
"xiaomi-token-plan-cn": ["mimo-v2.6-pro", "mimo-v2.6-flash"],
|
|
602
|
+
"xiaomi-token-plan-sgp": ["mimo-v2.6-pro", "mimo-v2.6-flash"],
|
|
625
603
|
nvidia: [
|
|
626
604
|
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
627
|
-
"nvidia/nemotron-3-super-120b-a12b",
|
|
628
|
-
"moonshotai/kimi-k3",
|
|
629
605
|
"moonshotai/kimi-k2.6",
|
|
630
606
|
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
631
607
|
],
|
|
@@ -1810,8 +1786,7 @@ function createOracleExtension(pi: ExtensionAPI, deps: OracleExtensionDeps = {})
|
|
|
1810
1786
|
onUpdate?.(partial);
|
|
1811
1787
|
};
|
|
1812
1788
|
|
|
1813
|
-
let
|
|
1814
|
-
for (let index = 0; index < attempts.length; index++) {
|
|
1789
|
+
for (let index = 0; ; index++) {
|
|
1815
1790
|
const previous = index > 0 ? attempts[index - 1] : undefined;
|
|
1816
1791
|
const attempt = previous
|
|
1817
1792
|
? withFallbackReason(attempts[index], previous)
|
|
@@ -1835,7 +1810,6 @@ function createOracleExtension(pi: ExtensionAPI, deps: OracleExtensionDeps = {})
|
|
|
1835
1810
|
});
|
|
1836
1811
|
}
|
|
1837
1812
|
|
|
1838
|
-
lastErrorResult = result;
|
|
1839
1813
|
const canFallBack = index < attempts.length - 1 && isModelAvailabilityError(result.error);
|
|
1840
1814
|
if (!canFallBack) {
|
|
1841
1815
|
return finalizeResult({
|
|
@@ -1844,30 +1818,6 @@ function createOracleExtension(pi: ExtensionAPI, deps: OracleExtensionDeps = {})
|
|
|
1844
1818
|
});
|
|
1845
1819
|
}
|
|
1846
1820
|
}
|
|
1847
|
-
|
|
1848
|
-
return finalizeResult({
|
|
1849
|
-
content: [
|
|
1850
|
-
{
|
|
1851
|
-
type: "text",
|
|
1852
|
-
text: lastErrorResult?.error ?? "Oracle could not select an available model.",
|
|
1853
|
-
},
|
|
1854
|
-
],
|
|
1855
|
-
details: lastErrorResult?.details ?? {
|
|
1856
|
-
modelRef: "",
|
|
1857
|
-
provider: ctx.model?.provider ?? "unknown",
|
|
1858
|
-
modelId: "",
|
|
1859
|
-
modelName: undefined,
|
|
1860
|
-
thinkingLevel: configuredThinkingLevel ?? DEFAULT_THINKING_LEVEL,
|
|
1861
|
-
autoSelected: true,
|
|
1862
|
-
selectionReason: "No authenticated models were available to run the oracle.",
|
|
1863
|
-
includeBash: params.includeBash ?? false,
|
|
1864
|
-
usage: createEmptyUsage(),
|
|
1865
|
-
stderr: "",
|
|
1866
|
-
exitCode: 1,
|
|
1867
|
-
durationMs: 0,
|
|
1868
|
-
cwd: params.cwd ?? ctx.cwd,
|
|
1869
|
-
},
|
|
1870
|
-
});
|
|
1871
1821
|
} finally {
|
|
1872
1822
|
activeRuns.delete(toolCallId);
|
|
1873
1823
|
updateOracleUi(ctx, activeRuns);
|
|
@@ -77,17 +77,9 @@ function normalizeWindowsShellPathLocal(filePath: string): string {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
* Mirrors Pi's normalizePath (dist/utils/paths.js).
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* normalizeUnicodeSpaces — replace Unicode space characters with ASCII space.
|
|
84
|
-
* stripAtPrefix — strip a leading "@" path sigil.
|
|
85
|
-
* expandTilde — expand "~"/"~/" to homedir (default true).
|
|
86
|
-
*
|
|
87
|
-
* On win32, Git Bash / WSL drive-path normalisation always runs (not gated
|
|
88
|
-
* by expandTilde); only the tilde expansion itself is gated by expandTilde.
|
|
89
|
-
* Always resolves "file://" URLs via fileURLToPath; throws for non-local hosts
|
|
90
|
-
* (e.g. file://hostname/…) or invalid URLs.
|
|
80
|
+
* Mirrors Pi's normalizePath (dist/utils/paths.js). On win32, Git Bash / WSL
|
|
81
|
+
* drive-path normalisation always runs; only tilde expansion is gated by
|
|
82
|
+
* expandTilde.
|
|
91
83
|
*/
|
|
92
84
|
function normalizePath(
|
|
93
85
|
input: string,
|
|
@@ -797,6 +789,28 @@ async function confirmProtectedPathAction(
|
|
|
797
789
|
);
|
|
798
790
|
}
|
|
799
791
|
|
|
792
|
+
async function confirmLexicalOrResolvedPath(
|
|
793
|
+
toolName: "write" | "edit",
|
|
794
|
+
normalizedPath: NormalizedPath,
|
|
795
|
+
ctx: ConfirmationContext & { cwd?: string },
|
|
796
|
+
): Promise<GuardDecision> {
|
|
797
|
+
// Monotonic hardening: also check via Pi-style path resolution against ctx.cwd.
|
|
798
|
+
// OR logic: protected if EITHER the lexical check OR the Pi-resolved check matches.
|
|
799
|
+
// When only the Pi-resolved check catches a path, show the resolved absolute path in
|
|
800
|
+
// the reason so the user understands why the plain-looking path is protected.
|
|
801
|
+
const lexicalProtected = isProtectedPath(normalizedPath);
|
|
802
|
+
const piResult = checkPiResolvedPath(normalizedPath.original, ctx.cwd ?? process.cwd());
|
|
803
|
+
const piAlsoProtected = piResult.status === "protected" || piResult.status === "error";
|
|
804
|
+
const displaySuffix = lexicalProtected
|
|
805
|
+
? undefined
|
|
806
|
+
: piResult.status === "protected"
|
|
807
|
+
? ` (resolves to ${piResult.resolvedPath})`
|
|
808
|
+
: piResult.status === "error"
|
|
809
|
+
? " (path could not be resolved)"
|
|
810
|
+
: undefined;
|
|
811
|
+
return confirmProtectedPathAction(toolName, normalizedPath, ctx, piAlsoProtected, displaySuffix);
|
|
812
|
+
}
|
|
813
|
+
|
|
800
814
|
export default function (pi: ExtensionAPI) {
|
|
801
815
|
pi.on("tool_call", async (event, ctx) => {
|
|
802
816
|
if (event.toolName === "bash" || event.toolName === "powershell") {
|
|
@@ -824,60 +838,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
824
838
|
return undefined;
|
|
825
839
|
}
|
|
826
840
|
|
|
827
|
-
if (event.toolName === "write") {
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
// Monotonic hardening: also check via Pi-style path resolution against ctx.cwd.
|
|
833
|
-
// OR logic: protected if EITHER the lexical check OR the Pi-resolved check matches.
|
|
834
|
-
// When only the Pi-resolved check catches a path, show the resolved absolute path in
|
|
835
|
-
// the reason so the user understands why the plain-looking path is protected.
|
|
836
|
-
const lexicalProtected = isProtectedPath(normalizedPath);
|
|
837
|
-
const piResult = checkPiResolvedPath(normalizedPath.original, ctx.cwd ?? process.cwd());
|
|
838
|
-
const piAlsoProtected = piResult.status === "protected" || piResult.status === "error";
|
|
839
|
-
const displaySuffix = lexicalProtected
|
|
840
|
-
? undefined
|
|
841
|
-
: piResult.status === "protected"
|
|
842
|
-
? ` (resolves to ${piResult.resolvedPath})`
|
|
843
|
-
: piResult.status === "error"
|
|
844
|
-
? " (path could not be resolved)"
|
|
845
|
-
: undefined;
|
|
846
|
-
return confirmProtectedPathAction(
|
|
847
|
-
"write",
|
|
848
|
-
normalizedPath,
|
|
849
|
-
ctx,
|
|
850
|
-
piAlsoProtected,
|
|
851
|
-
displaySuffix,
|
|
852
|
-
);
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
if (event.toolName === "edit") {
|
|
856
|
-
const normalizedPath = validateEditInput(event.input);
|
|
841
|
+
if (event.toolName === "write" || event.toolName === "edit") {
|
|
842
|
+
const toolName = event.toolName;
|
|
843
|
+
const normalizedPath =
|
|
844
|
+
toolName === "write" ? validateWriteInput(event.input) : validateEditInput(event.input);
|
|
857
845
|
if (!normalizedPath) {
|
|
858
|
-
return { block: true, reason:
|
|
846
|
+
return { block: true, reason: `Malformed ${toolName} input blocked` };
|
|
859
847
|
}
|
|
860
|
-
|
|
861
|
-
// OR logic: protected if EITHER the lexical check OR the Pi-resolved check matches.
|
|
862
|
-
// When only the Pi-resolved check catches a path, show the resolved absolute path in
|
|
863
|
-
// the reason so the user understands why the plain-looking path is protected.
|
|
864
|
-
const lexicalProtected = isProtectedPath(normalizedPath);
|
|
865
|
-
const piResult = checkPiResolvedPath(normalizedPath.original, ctx.cwd ?? process.cwd());
|
|
866
|
-
const piAlsoProtected = piResult.status === "protected" || piResult.status === "error";
|
|
867
|
-
const displaySuffix = lexicalProtected
|
|
868
|
-
? undefined
|
|
869
|
-
: piResult.status === "protected"
|
|
870
|
-
? ` (resolves to ${piResult.resolvedPath})`
|
|
871
|
-
: piResult.status === "error"
|
|
872
|
-
? " (path could not be resolved)"
|
|
873
|
-
: undefined;
|
|
874
|
-
return confirmProtectedPathAction(
|
|
875
|
-
"edit",
|
|
876
|
-
normalizedPath,
|
|
877
|
-
ctx,
|
|
878
|
-
piAlsoProtected,
|
|
879
|
-
displaySuffix,
|
|
880
|
-
);
|
|
848
|
+
return confirmLexicalOrResolvedPath(toolName, normalizedPath, ctx);
|
|
881
849
|
}
|
|
882
850
|
|
|
883
851
|
return undefined;
|
|
@@ -224,7 +224,8 @@ export function parseMcpJson(text: string, env: Record<string, string> = {}): Pa
|
|
|
224
224
|
|
|
225
225
|
let root: unknown;
|
|
226
226
|
try {
|
|
227
|
-
|
|
227
|
+
const jsonText = text.startsWith("\uFEFF") ? text.slice(1) : text;
|
|
228
|
+
root = JSON.parse(jsonText);
|
|
228
229
|
} catch {
|
|
229
230
|
// Never include raw parse error text in warnings.
|
|
230
231
|
warnings.push("project-mcp-json: .mcp.json could not be parsed as JSON; skipping all servers");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-project-mcp-json",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A pi extension that reads Claude Code-style .mcp.json files and registers the configured servers with pi.registerMcpServer.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -162,12 +162,22 @@ function formatPathArg(args: unknown, theme: RenderTheme, placeholder = "..."):
|
|
|
162
162
|
return path ? theme.fg("accent", shortenPath(path)) : theme.fg("toolOutput", placeholder);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
function parseReadLineNumber(value: unknown): number | undefined {
|
|
166
|
+
if (typeof value === "string" && value.trim() !== "") value = Number(value);
|
|
167
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
165
170
|
function formatReadLineRange(args: unknown, theme: RenderTheme): string {
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
+
const record = asRecord(args);
|
|
172
|
+
const offset = record?.offset;
|
|
173
|
+
const limit = record?.limit;
|
|
174
|
+
if (offset == null && limit == null) return "";
|
|
175
|
+
const startLine = offset == null ? 1 : parseReadLineNumber(offset);
|
|
176
|
+
if (startLine === undefined) return "";
|
|
177
|
+
if (limit == null) return theme.fg("warning", `:${startLine}`);
|
|
178
|
+
const count = parseReadLineNumber(limit);
|
|
179
|
+
if (count === undefined) return "";
|
|
180
|
+
const endLine = startLine + count - 1;
|
|
171
181
|
return theme.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
|
|
172
182
|
}
|
|
173
183
|
|
|
@@ -418,7 +428,6 @@ export const __testing = {
|
|
|
418
428
|
formatMcpCallLine,
|
|
419
429
|
createQuietResolver,
|
|
420
430
|
QuietCallRenderComponent,
|
|
421
|
-
QuietResultRenderComponent,
|
|
422
431
|
QuietToolsDelegateToDefault,
|
|
423
432
|
};
|
|
424
433
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-quiet-tools",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "A pi extension that visually compacts collapsed built-in tool rows and MCP tool rows in the TUI without changing tool results sent to the model.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -29,7 +29,9 @@ Then reload pi:
|
|
|
29
29
|
|
|
30
30
|
## Notes
|
|
31
31
|
|
|
32
|
+
- `/review` requires interactive mode (TUI); `/end-review` requires a UI.
|
|
32
33
|
- This fork adds loop fixing, custom review instructions persisted in the session, a blocking-findings parser, and `/end-review` handoff modes (return only, return and summarize, or return and fix findings). Loop fixing cycles until the parser reports no blocking findings: tagged P0–P2 items, or a "needs attention" verdict when no priority tags are present. Commit review is excluded from loop fixing.
|
|
34
|
+
- Loop fixing always uses Empty branch mode and skips the Empty branch / Current session choice.
|
|
33
35
|
- PR review requires `gh` access and a clean working tree for tracked files.
|
|
34
36
|
- If the project is trusted and a `REVIEW_GUIDELINES.md` file exists next to the repo's `<pi-config-dir>` directory, its contents are appended to the review prompt. `<pi-config-dir>` is Pi's runtime config directory name (`CONFIG_DIR_NAME`; `.pi` by default).
|
|
35
37
|
|
|
@@ -272,8 +272,6 @@ type ToolCall = {
|
|
|
272
272
|
id: string;
|
|
273
273
|
name: string;
|
|
274
274
|
args: unknown;
|
|
275
|
-
startedAt: number;
|
|
276
|
-
endedAt?: number;
|
|
277
275
|
isError?: boolean;
|
|
278
276
|
};
|
|
279
277
|
|
|
@@ -580,12 +578,6 @@ function addAssistantMessageUsage(total: Usage, message: unknown): void {
|
|
|
580
578
|
addUsage(total, assistant.usage as Usage);
|
|
581
579
|
}
|
|
582
580
|
|
|
583
|
-
function aggregateAssistantUsage(messages: unknown[]): Usage {
|
|
584
|
-
const total = createEmptyUsage();
|
|
585
|
-
for (const message of messages) addAssistantMessageUsage(total, message);
|
|
586
|
-
return total;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
581
|
function addSessionEventUsage(total: Usage, event: unknown): void {
|
|
590
582
|
const sessionEvent = event as { type?: string; message?: unknown; result?: { usage?: Usage } };
|
|
591
583
|
if (sessionEvent?.type === "message_end")
|
|
@@ -736,12 +728,6 @@ function getReadPathCandidates(resolved: string): string[] {
|
|
|
736
728
|
];
|
|
737
729
|
}
|
|
738
730
|
|
|
739
|
-
function resolveToolPath(cwd: string, rawPath: string | undefined): string {
|
|
740
|
-
const input = rawPath?.trim() || ".";
|
|
741
|
-
const normalized = input.startsWith("@") ? input.slice(1) : input;
|
|
742
|
-
return path.isAbsolute(normalized) ? path.resolve(normalized) : path.resolve(cwd, normalized);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
731
|
async function assertToolPathInsideCwd(
|
|
746
732
|
cwd: string,
|
|
747
733
|
rawPath: unknown,
|
|
@@ -754,11 +740,6 @@ async function assertToolPathInsideCwd(
|
|
|
754
740
|
// where realpath fails and the lexical fallback starts with the alias prefix.
|
|
755
741
|
const root = await fs.realpath(cwd).catch(() => path.resolve(cwd));
|
|
756
742
|
const lexicalCwd = path.resolve(cwd);
|
|
757
|
-
const resolved = resolveToolPath(cwd, rawPath);
|
|
758
|
-
const realPath = await fs.realpath(resolved).catch(() => resolved);
|
|
759
|
-
if (!isInside(root, realPath) && !isInside(lexicalCwd, realPath))
|
|
760
|
-
return `${toolName} is limited to the local checkout: ${realPath}`;
|
|
761
|
-
// Pi-effective path check (monotonic: block if either resolution is outside).
|
|
762
743
|
// For the read tool, also check Pi's resolveReadPathAsync fallback variants so
|
|
763
744
|
// a missing file whose variant resolves outside is not silently allowed.
|
|
764
745
|
try {
|
|
@@ -2654,7 +2635,7 @@ export const __test__ = {
|
|
|
2654
2635
|
parseSelectionList,
|
|
2655
2636
|
parseTriageCommandArgs,
|
|
2656
2637
|
prepareArguments,
|
|
2657
|
-
|
|
2638
|
+
createEmptyUsage,
|
|
2658
2639
|
addSessionEventUsage,
|
|
2659
2640
|
inspectFinalAssistant,
|
|
2660
2641
|
classifyRunFailure,
|
|
@@ -2841,7 +2822,6 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
|
|
|
2841
2822
|
id: event.toolCallId,
|
|
2842
2823
|
name: event.toolName,
|
|
2843
2824
|
args: event.args,
|
|
2844
|
-
startedAt: Date.now(),
|
|
2845
2825
|
});
|
|
2846
2826
|
if (details.toolCalls.length > MAX_TOOL_CALLS_TO_KEEP) {
|
|
2847
2827
|
details.toolCalls.splice(0, details.toolCalls.length - MAX_TOOL_CALLS_TO_KEEP);
|
|
@@ -2851,7 +2831,6 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
|
|
|
2851
2831
|
case "tool_execution_end": {
|
|
2852
2832
|
const call = details.toolCalls.find((item) => item.id === event.toolCallId);
|
|
2853
2833
|
if (call) {
|
|
2854
|
-
call.endedAt = Date.now();
|
|
2855
2834
|
call.isError = event.isError;
|
|
2856
2835
|
}
|
|
2857
2836
|
emit();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-extensions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.80",
|
|
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",
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
]
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@earendil-works/pi-ai": "^1.0
|
|
78
|
-
"@earendil-works/pi-coding-agent": "^1.0
|
|
79
|
-
"@earendil-works/pi-tui": "^1.0
|
|
77
|
+
"@earendil-works/pi-ai": "^1.4.0",
|
|
78
|
+
"@earendil-works/pi-coding-agent": "^1.4.0",
|
|
79
|
+
"@earendil-works/pi-tui": "^1.4.0",
|
|
80
80
|
"@types/node": "^25.9.1",
|
|
81
81
|
"oxfmt": "0.67.0",
|
|
82
82
|
"typebox": "^1.3.6",
|