@diegopetrucci/pi-extensions 0.1.53 → 0.1.54
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 +35 -15
- package/extensions/agent-workflow-audit/.pi-fleet-tested-version +1 -1
- package/extensions/agent-workflow-audit/index.ts +12 -0
- 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/git.ts +1 -0
- package/extensions/annotate-git-diff/index.ts +1 -1
- package/extensions/annotate-git-diff/package.json +1 -1
- package/extensions/annotate-git-diff/prompt.ts +2 -1
- package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-last-message/index.ts +1 -1
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/brrr/.pi-fleet-tested-version +1 -1
- package/extensions/brrr/index.ts +4 -3
- 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/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/index.ts +5 -0
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/.pi-fleet-tested-version +1 -1
- package/extensions/contrarian/index.ts +35 -3
- 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/git-footer/.pi-fleet-tested-version +1 -1
- package/extensions/git-footer/index.ts +42 -14
- 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/index.ts +7 -0
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
- package/extensions/minimal-footer/index.ts +132 -72
- 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 +21 -2
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
- package/extensions/permission-gate/index.ts +5 -1
- package/extensions/permission-gate/package.json +1 -1
- package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
- package/extensions/quiet-tools/index.ts +6 -0
- package/extensions/quiet-tools/package.json +1 -1
- package/extensions/review/.pi-fleet-tested-version +1 -1
- package/extensions/review/index.ts +251 -197
- package/extensions/review/package.json +1 -1
- package/extensions/todo/.pi-fleet-tested-version +1 -1
- package/extensions/todo/index.ts +1 -1
- package/extensions/todo/package.json +1 -1
- package/extensions/triage-comments/.pi-fleet-tested-version +1 -1
- package/extensions/triage-comments/index.ts +25 -3
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +6 -5
package/.pi-fleet-tested-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
package/README.md
CHANGED
|
@@ -2,32 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@diegopetrucci/pi-extensions)
|
|
4
4
|
|
|
5
|
-
A collection of [pi](https://
|
|
5
|
+
A collection of [pi](https://pi.dev) agent extensions I made.
|
|
6
|
+
|
|
7
|
+
### Subagents
|
|
8
|
+
|
|
9
|
+
- [`contrarian`](./extensions/contrarian): Adds a read-only contrarian tool that spins up an isolated subprocess to stress-test plans, designs, assumptions, bug hypotheses, and conclusions by steelmanning the strongest opposing case.
|
|
10
|
+
- [`librarian`](./extensions/librarian): Adds a GitHub research scout with a local repo checkout cache disabled by default under the OS user cache directory, toggleable with `/librarian-cache`, configurable subagent model/thinking defaults via `/librarian-config`, and cached repos expiring after 7 days of non-use.
|
|
11
|
+
- [`oracle`](./extensions/oracle): Adds an Amp-style read-only oracle tool that auto-selects the strongest reasoning model on the current provider/subscription, supports persisted `/oracle` model/thinking defaults, requests xhigh reasoning by default and clamps to model capabilities, and shows live status while running.
|
|
12
|
+
|
|
13
|
+
### Providers
|
|
14
|
+
|
|
15
|
+
- [`claude-fast`](./extensions/claude-fast): Adds `/claude-fast` to enable Anthropic Claude Fast mode for supported Claude Opus models by injecting `speed: "fast"`.
|
|
16
|
+
- [`openai-fast`](./extensions/openai-fast): Adds `/fast` to enable OpenAI Codex Fast mode for ChatGPT-auth GPT-5.4 and GPT-5.5 by injecting the priority service tier.
|
|
17
|
+
|
|
18
|
+
### UI
|
|
19
|
+
|
|
20
|
+
- [`git-footer`](./extensions/git-footer): Standalone extension that adds TLH-style git dirty counts, ahead/behind, and optional PR number to pi's built-in footer status area.
|
|
21
|
+
- [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch plus cached git dirty/ahead/PR status and repo on the first line, context/model on the second, optional `DUMB ZONE`, optional `xp` marker, plus OpenAI Codex 5-hour and 7-day usage when available.
|
|
22
|
+
- [`quiet-tools`](./extensions/quiet-tools): Renders collapsed built-in tool rows as a one-line invocation plus an expand hint without changing model-visible tool results; toggle temporarily with `/quiet-tools`.
|
|
23
|
+
|
|
24
|
+
### / Slash commands
|
|
6
25
|
|
|
7
26
|
- [`agent-workflow-audit`](./extensions/agent-workflow-audit): Adds `/agent-workflow-audit`, which runs an isolated repo workflow audit subagent and returns only the final distilled report to the main session.
|
|
8
27
|
- [`annotate-git-diff`](./extensions/annotate-git-diff): Adds `/annotate-git-diff`, a native Glimpse UI for annotating git diffs and appending structured feedback prompts to the editor.
|
|
9
28
|
- [`annotate-last-message`](./extensions/annotate-last-message): Adds `/annotate-last-message`, a native Glimpse UI for annotating the latest assistant reply and sending planning-oriented feedback back through the editor.
|
|
10
|
-
- [`
|
|
11
|
-
- [`
|
|
12
|
-
|
|
13
|
-
|
|
29
|
+
- [`review`](./extensions/review): Adds `/review` and `/end-review` for interactive code reviews of local changes, commits, PRs, and selected paths.
|
|
30
|
+
- [`triage-comments`](./extensions/triage-comments): Adds `/triage-comments` and a read-only `triage_comments` subagent tool that can auto-detect the current branch's PR, filter resolved/outdated inline comments, classify selected review comments with evidence, and suggest handling options without implementing changes
|
|
31
|
+
|
|
32
|
+
### Context management
|
|
33
|
+
|
|
14
34
|
- [`context-cap`](./extensions/context-cap): Caps effective model context windows at 200k tokens by default so pi avoids the `dumb zone`; toggle temporarily with `/context-cap`.
|
|
15
35
|
- [`context-inspector`](./extensions/context-inspector): Adds `/context`, a local self-contained HTML dashboard that breaks down where the current session context is going, with category overview, top offenders, and drilldown search.
|
|
36
|
+
|
|
37
|
+
### Safety
|
|
38
|
+
|
|
39
|
+
- [`confirm-destructive`](./extensions/confirm-destructive): Confirms before destructive session actions like clear, switch, and fork.
|
|
16
40
|
- [`dirty-repo-guard`](./extensions/dirty-repo-guard): Prompts before new sessions, session switches, or forks when the current git repo has uncommitted changes.
|
|
17
|
-
- [`
|
|
41
|
+
- [`permission-gate`](./extensions/permission-gate): Prompts for confirmation before dangerous bash commands like `rm -rf`, `sudo`, and `chmod 777`.
|
|
42
|
+
|
|
43
|
+
### Quality of life
|
|
44
|
+
|
|
45
|
+
- [`brrr`](./extensions/brrr): Sends brrr push notifications when pi finishes an agent turn and is ready for input, with optional macOS idle gating.
|
|
18
46
|
- [`gnosis`](./extensions/gnosis): Exposes the `gn` repo-local knowledge base CLI as an agent tool for searching and recording durable project decisions, constraints, and intent.
|
|
19
47
|
- [`illustrations-to-explain-things`](./extensions/illustrations-to-explain-things): Adds a skill for generating clean, absurd Xiaohei-style article illustrations, shot lists, image edits, and visual metaphors.
|
|
20
48
|
- [`inline-bash`](./extensions/inline-bash): Expands `!{command}` snippets in user prompts by running them through bash before the prompt reaches the agent.
|
|
21
|
-
- [`librarian`](./extensions/librarian): Adds a GitHub research scout with a local repo checkout cache disabled by default under the OS user cache directory, toggleable with `/librarian-cache`, configurable subagent model/thinking defaults via `/librarian-config`, and cached repos expiring after 7 days of non-use.
|
|
22
|
-
- [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch plus cached git dirty/ahead/PR status and repo on the first line, context/model on the second, optional `DUMB ZONE`, optional `xp` marker, plus OpenAI Codex 5-hour and 7-day usage when available.
|
|
23
49
|
- [`notify`](./extensions/notify): Sends configurable terminal, desktop, bell, and sound notifications when pi finishes and is ready for input.
|
|
24
|
-
- [`
|
|
25
|
-
- [`oracle`](./extensions/oracle): Adds an Amp-style read-only oracle tool that auto-selects the strongest reasoning model on the current provider/subscription, supports persisted `/oracle` model/thinking defaults, requests xhigh reasoning by default and clamps to model capabilities, and shows live status while running.
|
|
26
|
-
- [`permission-gate`](./extensions/permission-gate): Prompts for confirmation before dangerous bash commands like `rm -rf`, `sudo`, and `chmod 777`.
|
|
27
|
-
- [`quiet-tools`](./extensions/quiet-tools): Renders collapsed built-in tool rows as a one-line invocation plus an expand hint without changing model-visible tool results; toggle temporarily with `/quiet-tools`.
|
|
28
|
-
- [`review`](./extensions/review): Adds `/review` and `/end-review` for interactive code reviews of local changes, commits, PRs, and selected paths.
|
|
29
|
-
- [`todo`](./extensions/todo): Adds a branch-aware `todo` tool for the agent and a `/todos` viewer for users.
|
|
30
|
-
- [`triage-comments`](./extensions/triage-comments): Adds `/triage-comments` and a read-only `triage_comments` subagent tool that can auto-detect the current branch's PR, filter resolved/outdated inline comments, classify selected review comments with evidence, and suggest handling options without implementing changes.
|
|
50
|
+
- [`todo`](./extensions/todo): Adds a branch-aware `todo` tool for the agent and a `/todos` viewer for users..
|
|
31
51
|
|
|
32
52
|
(For the full list of pi extensions I use, [check out my dotfiles](https://github.com/diegopetrucci/dot/blob/main/.pi/agent/settings.json).)
|
|
33
53
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1103,6 +1103,18 @@ async function runAudit(
|
|
|
1103
1103
|
}
|
|
1104
1104
|
}
|
|
1105
1105
|
|
|
1106
|
+
export const __test__ = {
|
|
1107
|
+
appendRunBoundary,
|
|
1108
|
+
assertToolPathInsideCwd,
|
|
1109
|
+
buildSystemPrompt,
|
|
1110
|
+
buildUserPrompt,
|
|
1111
|
+
createAuditRuntimeGuardExtension,
|
|
1112
|
+
formatToolCall,
|
|
1113
|
+
getBlockedBashReason,
|
|
1114
|
+
parseArgs,
|
|
1115
|
+
renderCollapsedReport,
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1106
1118
|
export default function agentWorkflowAuditExtension(pi: ExtensionAPI) {
|
|
1107
1119
|
pi.registerMessageRenderer(CUSTOM_TYPE, (message, { expanded }, theme) => {
|
|
1108
1120
|
const details = message.details as AuditDetails | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -94,7 +94,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
async function reviewRepository(ctx: ExtensionCommandContext): Promise<void> {
|
|
97
|
-
if (
|
|
97
|
+
if (ctx.mode !== "tui") {
|
|
98
98
|
ctx.ui.notify("annotate-git-diff requires interactive mode.", "error");
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-annotate-git-diff",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
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",
|
|
@@ -43,6 +43,7 @@ function formatLocation(comment: DiffReviewComment, file: ReviewFile | undefined
|
|
|
43
43
|
|
|
44
44
|
export function composeReviewPrompt(files: ReviewFile[], payload: ReviewSubmitPayload): string {
|
|
45
45
|
const fileMap = new Map(files.map((file) => [file.id, file]));
|
|
46
|
+
const comments = payload.comments.filter((comment) => comment.body.trim().length > 0);
|
|
46
47
|
const lines: string[] = [];
|
|
47
48
|
|
|
48
49
|
lines.push("Please address the following feedback");
|
|
@@ -54,7 +55,7 @@ export function composeReviewPrompt(files: ReviewFile[], payload: ReviewSubmitPa
|
|
|
54
55
|
lines.push("");
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
comments.forEach((comment, index) => {
|
|
58
59
|
const file = fileMap.get(comment.fileId);
|
|
59
60
|
lines.push(`${index + 1}. ${formatLocation(comment, file)}`);
|
|
60
61
|
lines.push(` ${comment.body.trim()}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -38,7 +38,7 @@ export function registerAnnotateLastMessageCommand(pi: ExtensionAPI): void {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
async function openAnnotationWindow(ctx: ExtensionCommandContext): Promise<void> {
|
|
41
|
-
if (
|
|
41
|
+
if (ctx.mode !== "tui") {
|
|
42
42
|
ctx.ui.notify("annotate-last-message requires interactive mode.", "error");
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-annotate-last-message",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "A standalone pi extension that adds /annotate-last-message, a native Glimpse UI for annotating the latest assistant reply.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
package/extensions/brrr/index.ts
CHANGED
|
@@ -159,8 +159,9 @@ function extractTextContent(content: unknown): string {
|
|
|
159
159
|
}
|
|
160
160
|
if (typeof part !== "object" || part === null) continue;
|
|
161
161
|
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
162
|
+
const typedPart = part as { type?: unknown; text?: unknown };
|
|
163
|
+
if (typedPart.type !== undefined && typedPart.type !== "text") continue;
|
|
164
|
+
if (typeof typedPart.text === "string") parts.push(typedPart.text);
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
return parts.join("\n");
|
|
@@ -173,7 +174,7 @@ function lastAssistantMessage(messages: readonly unknown[]): string | undefined
|
|
|
173
174
|
if ((message as { role?: unknown }).role !== "assistant") continue;
|
|
174
175
|
|
|
175
176
|
const text = extractTextContent((message as { content?: unknown }).content).trim();
|
|
176
|
-
|
|
177
|
+
return text || undefined;
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1447,6 +1447,11 @@ pre { margin: 0; white-space: pre-wrap; word-break: break-word; color: #cbd5e1;
|
|
|
1447
1447
|
</html>`;
|
|
1448
1448
|
}
|
|
1449
1449
|
|
|
1450
|
+
export const __testing = {
|
|
1451
|
+
analyzeEntries,
|
|
1452
|
+
buildReportData,
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1450
1455
|
export default function contextInspectorExtension(pi: ExtensionAPI) {
|
|
1451
1456
|
pi.registerCommand("context", {
|
|
1452
1457
|
description: "Open a local HTML breakdown of where this session's context is going",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -72,7 +72,20 @@ const COLLAPSED_LINE_LIMIT = 8;
|
|
|
72
72
|
const CONTRARIAN_STATUS_ID = "contrarian";
|
|
73
73
|
const CONTRARIAN_WIDGET_ID = "contrarian";
|
|
74
74
|
const CONTRARIAN_CONFIG_FILE = "contrarian.json";
|
|
75
|
-
const CONTRARIAN_MODEL_PREFERENCES = [
|
|
75
|
+
const CONTRARIAN_MODEL_PREFERENCES = [
|
|
76
|
+
"gpt-5.5",
|
|
77
|
+
"claude-opus-4-8",
|
|
78
|
+
"claude-opus-4.8",
|
|
79
|
+
"claude-sonnet-5-0",
|
|
80
|
+
"claude-sonnet-5.0",
|
|
81
|
+
"claude-sonnet-5",
|
|
82
|
+
"claude-sonnet-4-6",
|
|
83
|
+
"claude-sonnet-4.6",
|
|
84
|
+
"claude-sonnet-4-5",
|
|
85
|
+
"claude-sonnet-4.5",
|
|
86
|
+
"claude-sonnet-4-0",
|
|
87
|
+
"claude-sonnet-4",
|
|
88
|
+
];
|
|
76
89
|
|
|
77
90
|
const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
78
91
|
"amazon-bedrock": [
|
|
@@ -83,6 +96,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
83
96
|
"claude-opus-4-5",
|
|
84
97
|
"claude-opus-4-1",
|
|
85
98
|
"claude-opus-4",
|
|
99
|
+
"claude-sonnet-5",
|
|
86
100
|
"claude-sonnet-4-6",
|
|
87
101
|
"claude-sonnet-4-5",
|
|
88
102
|
"claude-sonnet-4",
|
|
@@ -107,6 +121,9 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
107
121
|
"claude-opus-4.1",
|
|
108
122
|
"claude-opus-4-0",
|
|
109
123
|
"claude-opus-4",
|
|
124
|
+
"claude-sonnet-5-0",
|
|
125
|
+
"claude-sonnet-5.0",
|
|
126
|
+
"claude-sonnet-5",
|
|
110
127
|
"claude-sonnet-4-6",
|
|
111
128
|
"claude-sonnet-4.6",
|
|
112
129
|
"claude-sonnet-4-5",
|
|
@@ -185,6 +202,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
185
202
|
"gpt-5",
|
|
186
203
|
"gemini-3.1-pro-preview",
|
|
187
204
|
"gemini-3-pro-preview",
|
|
205
|
+
"claude-sonnet-5.0",
|
|
206
|
+
"claude-sonnet-5",
|
|
188
207
|
"claude-sonnet-4.6",
|
|
189
208
|
"claude-sonnet-4.5",
|
|
190
209
|
"gemini-2.5-pro",
|
|
@@ -360,6 +379,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
360
379
|
"anthropic/claude-opus-4.6",
|
|
361
380
|
"anthropic/claude-opus-4.5",
|
|
362
381
|
"anthropic/claude-opus-4.1",
|
|
382
|
+
"anthropic/claude-sonnet-5.0",
|
|
383
|
+
"anthropic/claude-sonnet-5",
|
|
363
384
|
"anthropic/claude-sonnet-4.6",
|
|
364
385
|
"openai/gpt-5.5-pro",
|
|
365
386
|
"openai/gpt-5.5",
|
|
@@ -1184,6 +1205,13 @@ function renderCollapsedText(text: string, lineLimit = COLLAPSED_LINE_LIMIT): st
|
|
|
1184
1205
|
return [...lines.slice(0, lineLimit), `... (${lines.length - lineLimit} more lines)`].join("\n");
|
|
1185
1206
|
}
|
|
1186
1207
|
|
|
1208
|
+
export const __test__ = {
|
|
1209
|
+
findAvailableModel,
|
|
1210
|
+
parseModelPreference,
|
|
1211
|
+
resolveThinkingLevel,
|
|
1212
|
+
selectContrarianModel,
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1187
1215
|
export default function contrarianExtension(pi: ExtensionAPI) {
|
|
1188
1216
|
const activeRuns = new Map<string, ContrarianUiRun>();
|
|
1189
1217
|
let preferences: ContrarianPreferences = {};
|
|
@@ -1347,13 +1375,17 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1347
1375
|
parameters: ContrarianParams,
|
|
1348
1376
|
|
|
1349
1377
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
1378
|
+
const rawTask = (params as { task?: unknown }).task;
|
|
1379
|
+
const task = typeof rawTask === "string" ? rawTask.trim() : "";
|
|
1380
|
+
if (!task) throw new Error("Invalid parameters: expected task to be a non-empty string.");
|
|
1381
|
+
|
|
1350
1382
|
const explicitModel = parseModelPreference(params.model);
|
|
1351
1383
|
const defaultModel = parseModelPreference(preferences.model);
|
|
1352
1384
|
const configuredModel = explicitModel.model ?? defaultModel.model;
|
|
1353
1385
|
const configuredThinkingLevel =
|
|
1354
1386
|
params.thinkingLevel ?? explicitModel.thinkingLevel ?? preferences.thinkingLevel ?? defaultModel.thinkingLevel;
|
|
1355
1387
|
const uiRun: ContrarianUiRun = {
|
|
1356
|
-
task
|
|
1388
|
+
task,
|
|
1357
1389
|
includeBash: params.includeBash ?? false,
|
|
1358
1390
|
startedAt: Date.now(),
|
|
1359
1391
|
};
|
|
@@ -1445,7 +1477,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1445
1477
|
uiRun.selection = attempt;
|
|
1446
1478
|
updateContrarianUi(ctx, activeRuns);
|
|
1447
1479
|
|
|
1448
|
-
const result = await runContrarian(attempt, params, signal, handleUpdate, ctx.cwd);
|
|
1480
|
+
const result = await runContrarian(attempt, { ...params, task }, signal, handleUpdate, ctx.cwd);
|
|
1449
1481
|
if (result.ok) {
|
|
1450
1482
|
return {
|
|
1451
1483
|
content: [{ type: "text", text: result.output }],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -31,6 +31,11 @@ type CommandRunner = (
|
|
|
31
31
|
options: { cwd: string; signal: AbortSignal },
|
|
32
32
|
) => Promise<CommandResult>;
|
|
33
33
|
|
|
34
|
+
type RunCommandSafelyResult =
|
|
35
|
+
| { kind: "ok"; result: CommandResult }
|
|
36
|
+
| { kind: "transient" }
|
|
37
|
+
| { kind: "unavailable" };
|
|
38
|
+
|
|
34
39
|
type TimerHandle = unknown;
|
|
35
40
|
|
|
36
41
|
type Clock = {
|
|
@@ -286,6 +291,10 @@ function defaultClock(): Clock {
|
|
|
286
291
|
};
|
|
287
292
|
}
|
|
288
293
|
|
|
294
|
+
function isCommandUnavailableError(error: unknown): boolean {
|
|
295
|
+
return !!error && typeof error === "object" && (error as { code?: unknown }).code === "ENOENT";
|
|
296
|
+
}
|
|
297
|
+
|
|
289
298
|
class GitFooterCache {
|
|
290
299
|
private readonly cwd: () => string;
|
|
291
300
|
private readonly runner: CommandRunner;
|
|
@@ -345,7 +354,7 @@ class GitFooterCache {
|
|
|
345
354
|
const result = await this.fetchGitStatus();
|
|
346
355
|
if (this.disposed) return;
|
|
347
356
|
if (result.kind === "transient") return;
|
|
348
|
-
if (result.kind === "not-a-repo") {
|
|
357
|
+
if (result.kind === "not-a-repo" || result.kind === "unavailable") {
|
|
349
358
|
this.statusSnapshot = undefined;
|
|
350
359
|
this.pullRequestSnapshot = undefined;
|
|
351
360
|
this.lastSeenBranch = undefined;
|
|
@@ -371,8 +380,8 @@ class GitFooterCache {
|
|
|
371
380
|
|
|
372
381
|
const pr = await this.fetchPullRequest();
|
|
373
382
|
if (this.disposed) return;
|
|
374
|
-
if (pr
|
|
375
|
-
else if (
|
|
383
|
+
if (pr.kind === "ok") this.pullRequestSnapshot = pr.pullRequest;
|
|
384
|
+
else if (pr.kind === "not-found" || pr.kind === "unavailable") this.pullRequestSnapshot = undefined;
|
|
376
385
|
|
|
377
386
|
this.emitChangeIfSnapshotsChanged(previousStatusSnapshot, previousPullRequestSnapshot);
|
|
378
387
|
}
|
|
@@ -399,32 +408,40 @@ class GitFooterCache {
|
|
|
399
408
|
| { kind: "ok"; status: GitStatusSnapshot }
|
|
400
409
|
| { kind: "not-a-repo" }
|
|
401
410
|
| { kind: "transient" }
|
|
411
|
+
| { kind: "unavailable" }
|
|
402
412
|
> {
|
|
403
413
|
const result = await this.runCommandSafely("git", GIT_STATUS_ARGS, this.gitTimeoutMs);
|
|
404
|
-
if (
|
|
405
|
-
if (result.exitCode !== 0) return { kind: "not-a-repo" };
|
|
406
|
-
return { kind: "ok", status: parseGitStatusPorcelainV2(result.stdout) };
|
|
414
|
+
if (result.kind !== "ok") return result;
|
|
415
|
+
if (result.result.exitCode !== 0) return { kind: "not-a-repo" };
|
|
416
|
+
return { kind: "ok", status: parseGitStatusPorcelainV2(result.result.stdout) };
|
|
407
417
|
}
|
|
408
418
|
|
|
409
|
-
private async fetchPullRequest(): Promise<
|
|
419
|
+
private async fetchPullRequest(): Promise<
|
|
420
|
+
| { kind: "ok"; pullRequest: PullRequestSnapshot | undefined }
|
|
421
|
+
| { kind: "not-found" }
|
|
422
|
+
| { kind: "transient" }
|
|
423
|
+
| { kind: "unavailable" }
|
|
424
|
+
> {
|
|
410
425
|
const result = await this.runCommandSafely("gh", GH_PR_VIEW_ARGS, this.ghTimeoutMs);
|
|
411
|
-
if (
|
|
412
|
-
|
|
426
|
+
if (result.kind !== "ok") return result;
|
|
427
|
+
if (result.result.exitCode !== 0) return { kind: "not-found" };
|
|
428
|
+
return { kind: "ok", pullRequest: parsePullRequestJson(result.result.stdout) };
|
|
413
429
|
}
|
|
414
430
|
|
|
415
431
|
private async runCommandSafely(
|
|
416
432
|
command: string,
|
|
417
433
|
args: readonly string[],
|
|
418
434
|
timeoutMs: number,
|
|
419
|
-
): Promise<
|
|
420
|
-
if (this.disposed) return
|
|
435
|
+
): Promise<RunCommandSafelyResult> {
|
|
436
|
+
if (this.disposed) return { kind: "transient" };
|
|
421
437
|
const controller = new AbortController();
|
|
422
438
|
this.inflightControllers.add(controller);
|
|
423
439
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
424
440
|
try {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
441
|
+
const result = await this.runner(command, args, { cwd: this.cwd(), signal: controller.signal });
|
|
442
|
+
return { kind: "ok", result };
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return isCommandUnavailableError(error) ? { kind: "unavailable" } : { kind: "transient" };
|
|
428
445
|
} finally {
|
|
429
446
|
clearTimeout(timeoutId);
|
|
430
447
|
this.inflightControllers.delete(controller);
|
|
@@ -478,3 +495,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
478
495
|
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
479
496
|
});
|
|
480
497
|
}
|
|
498
|
+
|
|
499
|
+
export const __testing = {
|
|
500
|
+
GitFooterCache,
|
|
501
|
+
GIT_STATUS_ARGS,
|
|
502
|
+
GH_PR_VIEW_ARGS,
|
|
503
|
+
parseGitStatusPorcelainV2,
|
|
504
|
+
parsePullRequestJson,
|
|
505
|
+
formatGitStatusFooterSegment,
|
|
506
|
+
formatPullRequestFooterSegment,
|
|
507
|
+
formatGitFooterStatus,
|
|
508
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-illustrations-to-explain-things",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
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.
|
|
1
|
+
0.80.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|
|
@@ -777,6 +777,13 @@ function isAbortLikeError(error: unknown): boolean {
|
|
|
777
777
|
return /aborted|cancelled|canceled/i.test(message);
|
|
778
778
|
}
|
|
779
779
|
|
|
780
|
+
export const __test__ = {
|
|
781
|
+
buildLibrarianCandidates,
|
|
782
|
+
findAvailableModel,
|
|
783
|
+
isModelAvailabilityError,
|
|
784
|
+
parseModelPreference,
|
|
785
|
+
};
|
|
786
|
+
|
|
780
787
|
export default function librarianExtension(pi: ExtensionAPI) {
|
|
781
788
|
let cachePreference: CacheMode = DEFAULT_CACHE_MODE;
|
|
782
789
|
let modelPreference: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.80.3
|