@diegopetrucci/pi-extensions 0.1.81 → 0.1.82
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 +6 -1
- package/extensions/agent-workflow-audit/index.ts +47 -25
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/brrr/index.ts +21 -15
- package/extensions/brrr/package.json +1 -1
- package/extensions/code-reviewer/index.ts +52 -19
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/contrarian/index.ts +17 -17
- package/extensions/contrarian/package.json +1 -1
- package/extensions/developer/.pi-fleet-tested-version +1 -0
- package/extensions/developer/README.md +70 -0
- package/extensions/developer/index.ts +906 -0
- package/extensions/developer/package.json +40 -0
- package/extensions/diff-summarizer/.pi-fleet-tested-version +1 -0
- package/extensions/diff-summarizer/README.md +75 -0
- package/extensions/diff-summarizer/index.ts +1585 -0
- package/extensions/diff-summarizer/package.json +40 -0
- package/extensions/librarian/index.ts +10 -0
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/index.ts +5 -1
- package/extensions/minimal-footer/package.json +1 -1
- package/extensions/notify/index.ts +7 -2
- package/extensions/notify/package.json +1 -1
- package/extensions/oracle/index.ts +17 -17
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/README.md +6 -11
- package/extensions/permission-gate/index.ts +11 -54
- package/extensions/permission-gate/package.json +1 -3
- package/extensions/project-mcp-json/README.md +4 -3
- package/extensions/project-mcp-json/package.json +1 -1
- package/extensions/repo-scout/.pi-fleet-tested-version +1 -0
- package/extensions/repo-scout/README.md +74 -0
- package/extensions/repo-scout/index.ts +1575 -0
- package/extensions/repo-scout/package.json +40 -0
- package/extensions/test-runner/.pi-fleet-tested-version +1 -0
- package/extensions/test-runner/README.md +70 -0
- package/extensions/test-runner/index.ts +798 -0
- package/extensions/test-runner/package.json +40 -0
- package/extensions/triage-comments/index.ts +66 -16
- package/extensions/triage-comments/package.json +1 -1
- package/extensions/web-scout/.pi-fleet-tested-version +1 -0
- package/extensions/web-scout/README.md +67 -0
- package/extensions/web-scout/index.ts +1204 -0
- package/extensions/web-scout/package.json +41 -0
- package/package.json +7 -2
- package/extensions/permission-gate/powershell-safety.ts +0 -1053
package/README.md
CHANGED
|
@@ -8,8 +8,13 @@ A collection of [pi](https://pi.dev) agent extensions I made. (Btw, [I am also b
|
|
|
8
8
|
|
|
9
9
|
- [`code-reviewer`](./extensions/code-reviewer): Adds a `code_reviewer` subagent tool with read-only built-in tools plus configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4) that reviews local changes for ticket fit, diff mismatches, correctness, security, simplicity, and validation gaps without implementing fixes, auto-selects a contrarian-style opposite-provider review model when available, and clamps requested thinking to the chosen model's capabilities.
|
|
10
10
|
- [`contrarian`](./extensions/contrarian): Adds a contrarian tool with read-only built-in tools plus configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4) that spins up an isolated subprocess to stress-test plans, designs, assumptions, bug hypotheses, and conclusions by steelmanning the strongest opposing case.
|
|
11
|
+
- [`developer`](./extensions/developer): Adds a `developer` subagent tool that implements one task in an isolated child agent using the current session model and thinking, with `read`, `write`, `edit`, `grep`, `find`, `ls`, unrestricted `bash`, and configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4); `write`/`edit` are limited to the checkout.
|
|
12
|
+
- [`diff-summarizer`](./extensions/diff-summarizer): Adds a read-only `diff_summarizer` subagent tool that summarizes a diff or the current local changes and highlights review risk using the current session model at `medium` thinking, with `read`, `grep`, `find`, `ls`, guarded read-only `bash` (direct `git`/`gh`/`pwd` only), and configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4).
|
|
11
13
|
- [`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`, cached repos expiring after 7 days of non-use, and configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4).
|
|
12
14
|
- [`oracle`](./extensions/oracle): Adds an Amp-style oracle tool with read-only built-in tools plus configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4) 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.
|
|
15
|
+
- [`repo-scout`](./extensions/repo-scout): Adds a read-only `repo_scout` subagent tool that scans a repository and reports stack, conventions, commands, and hotspots using the current session model at `medium` thinking, with `read`, `grep`, `find`, `ls`, guarded read-only `bash` (direct `git`/`gh`/`pwd` only), and configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4).
|
|
16
|
+
- [`test-runner`](./extensions/test-runner): Adds a `test_runner` subagent tool that runs exact validation shell commands in order in an isolated child agent using the current session model at `low` thinking, stops at the first failure, and reports PASS/FAIL per step; tools are unrestricted `bash` and configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4).
|
|
17
|
+
- [`web-scout`](./extensions/web-scout): Adds a read-only `web_scout` subagent tool that researches a question on the web via the hosted Exa MCP endpoint (no API key required; optional `EXA_API_KEY` for higher limits) and returns citation-backed findings using the current session model at `medium` thinking, with `web_search`, `fetch_url` (http(s) only), `read`, `grep`, `find`, `ls`, and configured MCP tools (run without confirmation, may have side effects, Pi >=1.0.4).
|
|
13
18
|
|
|
14
19
|
### Providers
|
|
15
20
|
|
|
@@ -39,7 +44,7 @@ A collection of [pi](https://pi.dev) agent extensions I made. (Btw, [I am also b
|
|
|
39
44
|
|
|
40
45
|
- [`confirm-destructive`](./extensions/confirm-destructive): Confirms before destructive session actions like clear, switch, and fork.
|
|
41
46
|
- [`dirty-repo-guard`](./extensions/dirty-repo-guard): Prompts before new sessions, session switches, or forks when the current git repo has uncommitted changes.
|
|
42
|
-
- [`permission-gate`](./extensions/permission-gate): Prompts for confirmation before dangerous bash
|
|
47
|
+
- [`permission-gate`](./extensions/permission-gate): Prompts for confirmation before dangerous bash commands and protected `write`/`edit` targets like `.git`, `node_modules`, and secret-bearing `.env` files; rejects named `powershell` tool calls as unsupported.
|
|
43
48
|
|
|
44
49
|
### Quality of life
|
|
45
50
|
|
|
@@ -562,11 +562,39 @@ const SAFE_GIT_BRANCH_FLAGS = new Set([
|
|
|
562
562
|
"--remotes",
|
|
563
563
|
"-v",
|
|
564
564
|
"-vv",
|
|
565
|
+
"--verbose",
|
|
566
|
+
"-l",
|
|
567
|
+
"--list",
|
|
565
568
|
"--show-current",
|
|
569
|
+
"--column",
|
|
570
|
+
"--no-column",
|
|
571
|
+
"--color",
|
|
572
|
+
"--no-color",
|
|
573
|
+
"-i",
|
|
574
|
+
"--ignore-case",
|
|
575
|
+
]);
|
|
576
|
+
const SAFE_GIT_BRANCH_VALUE_FLAGS = new Set([
|
|
577
|
+
"--contains",
|
|
578
|
+
"--no-contains",
|
|
579
|
+
"--merged",
|
|
580
|
+
"--no-merged",
|
|
581
|
+
"--points-at",
|
|
582
|
+
"--sort",
|
|
583
|
+
"--format",
|
|
584
|
+
]);
|
|
585
|
+
// Flags that make `git branch` list instead of create a branch from positional args.
|
|
586
|
+
const GIT_BRANCH_LISTING_FLAGS = new Set([
|
|
587
|
+
"-a",
|
|
588
|
+
"--all",
|
|
589
|
+
"-r",
|
|
590
|
+
"--remotes",
|
|
591
|
+
"-l",
|
|
566
592
|
"--list",
|
|
567
593
|
"--contains",
|
|
594
|
+
"--no-contains",
|
|
568
595
|
"--merged",
|
|
569
596
|
"--no-merged",
|
|
597
|
+
"--points-at",
|
|
570
598
|
]);
|
|
571
599
|
const GH_GLOBAL_OPTIONS_WITH_VALUE = new Set([
|
|
572
600
|
"--repo",
|
|
@@ -970,33 +998,27 @@ function getGitSubcommand(tokens: string[]): {
|
|
|
970
998
|
function isSafeGitBranchCommand(tokens: string[], subcommandIndex: number): boolean {
|
|
971
999
|
const args = tokens.slice(subcommandIndex + 1);
|
|
972
1000
|
if (args.length === 0) return true;
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1001
|
+
let hasListingMode = false;
|
|
1002
|
+
let hasPositional = false;
|
|
1003
|
+
for (const arg of args) {
|
|
1004
|
+
if (!arg.startsWith("-")) {
|
|
1005
|
+
hasPositional = true;
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
1008
|
+
const name = arg.split("=", 1)[0] ?? "";
|
|
1009
|
+
const hasValue = arg.includes("=");
|
|
1010
|
+
if (!hasValue && SAFE_GIT_BRANCH_FLAGS.has(arg)) {
|
|
1011
|
+
if (GIT_BRANCH_LISTING_FLAGS.has(arg)) hasListingMode = true;
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
if (SAFE_GIT_BRANCH_VALUE_FLAGS.has(name)) {
|
|
1015
|
+
if (GIT_BRANCH_LISTING_FLAGS.has(name)) hasListingMode = true;
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
980
1018
|
return false;
|
|
981
1019
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
SAFE_GIT_BRANCH_FLAGS.has(arg) ||
|
|
985
|
-
arg.startsWith("--contains=") ||
|
|
986
|
-
arg.startsWith("--merged=") ||
|
|
987
|
-
arg.startsWith("--no-merged="),
|
|
988
|
-
);
|
|
989
|
-
return (
|
|
990
|
-
hasReadOnlyMode &&
|
|
991
|
-
args.every(
|
|
992
|
-
(arg) =>
|
|
993
|
-
SAFE_GIT_BRANCH_FLAGS.has(arg) ||
|
|
994
|
-
arg.startsWith("--contains=") ||
|
|
995
|
-
arg.startsWith("--merged=") ||
|
|
996
|
-
arg.startsWith("--no-merged=") ||
|
|
997
|
-
!arg.startsWith("-"),
|
|
998
|
-
)
|
|
999
|
-
);
|
|
1020
|
+
if (args.includes("--show-current")) return !hasPositional;
|
|
1021
|
+
return !hasPositional || hasListingMode;
|
|
1000
1022
|
}
|
|
1001
1023
|
|
|
1002
1024
|
function isSafeGitRemoteCommand(tokens: string[], subcommandIndex: number): boolean {
|
package/extensions/brrr/index.ts
CHANGED
|
@@ -66,7 +66,24 @@ function readConfigFile(path: string): Partial<BrrrConfig> {
|
|
|
66
66
|
if (!existsSync(path)) return {};
|
|
67
67
|
|
|
68
68
|
try {
|
|
69
|
-
|
|
69
|
+
const parsed: unknown = JSON.parse(readFileSync(path, "utf-8"));
|
|
70
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
71
|
+
console.error(`Warning: Invalid config in ${path}: expected an object.`);
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fields = parsed as Record<string, unknown>;
|
|
76
|
+
const config: Record<string, unknown> = {};
|
|
77
|
+
for (const [field, defaultValue] of Object.entries(DEFAULT_CONFIG)) {
|
|
78
|
+
if (!Object.hasOwn(fields, field)) continue;
|
|
79
|
+
const value = fields[field];
|
|
80
|
+
if (typeof value === typeof defaultValue || (field === "idleSeconds" && value === null)) {
|
|
81
|
+
config[field] = value;
|
|
82
|
+
} else {
|
|
83
|
+
console.error(`Warning: Invalid config in ${path}: wrong type for ${field}.`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return config as Partial<BrrrConfig>;
|
|
70
87
|
} catch (error) {
|
|
71
88
|
console.error(`Warning: Could not parse ${path}: ${error}`);
|
|
72
89
|
return {};
|
|
@@ -196,15 +213,6 @@ function sessionMessages(sessionManager: SessionMessageSource | undefined): read
|
|
|
196
213
|
.flatMap((entry: SessionEntry) => (entry.type === "message" ? [entry.message] : []));
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
function resolveAssistantMessage(
|
|
200
|
-
sessionManager: SessionMessageSource | undefined,
|
|
201
|
-
fallbackMessages: readonly unknown[],
|
|
202
|
-
): string | undefined {
|
|
203
|
-
return (
|
|
204
|
-
lastAssistantMessage(sessionMessages(sessionManager)) ?? lastAssistantMessage(fallbackMessages)
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
216
|
function truncateMessage(value: string): string {
|
|
209
217
|
const trimmed = value.trim();
|
|
210
218
|
if (trimmed.length <= 800) return trimmed;
|
|
@@ -227,6 +235,7 @@ async function sendBrrr(
|
|
|
227
235
|
|
|
228
236
|
const response = await fetch(webhook, {
|
|
229
237
|
method: "POST",
|
|
238
|
+
redirect: "error",
|
|
230
239
|
headers: {
|
|
231
240
|
"content-type": "application/json",
|
|
232
241
|
accept: "application/json",
|
|
@@ -274,7 +283,7 @@ export default function brrrExtension(pi: ExtensionAPI) {
|
|
|
274
283
|
},
|
|
275
284
|
});
|
|
276
285
|
|
|
277
|
-
pi.on("agent_settled", async (
|
|
286
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
278
287
|
const config = loadConfig(ctx);
|
|
279
288
|
if (!config.enabled) return;
|
|
280
289
|
if (config.onlyWhenInteractive && !ctx.hasUI) return;
|
|
@@ -284,10 +293,7 @@ export default function brrrExtension(pi: ExtensionAPI) {
|
|
|
284
293
|
if (await shouldSkipForIdleThreshold(config.idleSeconds)) return;
|
|
285
294
|
|
|
286
295
|
const assistantMessage = config.includeLastAssistantMessage
|
|
287
|
-
?
|
|
288
|
-
ctx.sessionManager,
|
|
289
|
-
(event as { messages?: readonly unknown[] }).messages ?? [],
|
|
290
|
-
)
|
|
296
|
+
? lastAssistantMessage(sessionMessages(ctx.sessionManager))
|
|
291
297
|
: undefined;
|
|
292
298
|
const message = truncateMessage(assistantMessage || formatTemplate(config.message, ctx.cwd));
|
|
293
299
|
const result = await sendBrrr(webhook, {
|
|
@@ -91,7 +91,7 @@ const AZURE_MODEL_PREFERENCES = [
|
|
|
91
91
|
"gpt-5.5",
|
|
92
92
|
"gpt-5.4-pro",
|
|
93
93
|
"gpt-5.4",
|
|
94
|
-
"gpt-5.3-codex",
|
|
94
|
+
"gpt-5.3-codex ",
|
|
95
95
|
"gpt-5-pro",
|
|
96
96
|
"gpt-5-chat-latest",
|
|
97
97
|
"gpt-5.2-pro",
|
|
@@ -159,7 +159,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
159
159
|
"claude-opus-5.5",
|
|
160
160
|
"claude-opus-5",
|
|
161
161
|
"gpt-5.4",
|
|
162
|
-
"gpt-5.3-codex",
|
|
162
|
+
"gpt-5.3-codex ",
|
|
163
163
|
"grok-4.7 ",
|
|
164
164
|
"grok-4.7",
|
|
165
165
|
"grok-4.6",
|
|
@@ -183,7 +183,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
183
183
|
"claude-opus-5",
|
|
184
184
|
"gpt-5.4-pro",
|
|
185
185
|
"gpt-5.4",
|
|
186
|
-
"gpt-5.3-codex",
|
|
186
|
+
"gpt-5.3-codex ",
|
|
187
187
|
],
|
|
188
188
|
"opencode-go": ["grok-4.7 ", "grok-4.7"],
|
|
189
189
|
openrouter: [
|
|
@@ -225,7 +225,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
225
225
|
"claude-opus-5-5",
|
|
226
226
|
"claude-opus-5",
|
|
227
227
|
"gpt-5.4",
|
|
228
|
-
"gpt-5.3-codex",
|
|
228
|
+
"gpt-5.3-codex ",
|
|
229
229
|
"gpt-5.4-mini",
|
|
230
230
|
],
|
|
231
231
|
openai: [
|
|
@@ -282,7 +282,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
282
282
|
"spacexai/grok-4.7",
|
|
283
283
|
"spacexai/grok-4.6",
|
|
284
284
|
"xai/grok-4.5",
|
|
285
|
-
"google/gemini-3.5-flash",
|
|
285
|
+
"google/gemini-3.5-flash ",
|
|
286
286
|
],
|
|
287
287
|
};
|
|
288
288
|
|
|
@@ -400,11 +400,39 @@ const SAFE_GIT_BRANCH_FLAGS = new Set([
|
|
|
400
400
|
"--remotes",
|
|
401
401
|
"-v",
|
|
402
402
|
"-vv",
|
|
403
|
+
"--verbose",
|
|
404
|
+
"-l",
|
|
405
|
+
"--list",
|
|
403
406
|
"--show-current",
|
|
407
|
+
"--column",
|
|
408
|
+
"--no-column",
|
|
409
|
+
"--color",
|
|
410
|
+
"--no-color",
|
|
411
|
+
"-i",
|
|
412
|
+
"--ignore-case",
|
|
413
|
+
]);
|
|
414
|
+
const SAFE_GIT_BRANCH_VALUE_FLAGS = new Set([
|
|
415
|
+
"--contains",
|
|
416
|
+
"--no-contains",
|
|
417
|
+
"--merged",
|
|
418
|
+
"--no-merged",
|
|
419
|
+
"--points-at",
|
|
420
|
+
"--sort",
|
|
421
|
+
"--format",
|
|
422
|
+
]);
|
|
423
|
+
// Flags that make `git branch` list instead of create a branch from positional args.
|
|
424
|
+
const GIT_BRANCH_LISTING_FLAGS = new Set([
|
|
425
|
+
"-a",
|
|
426
|
+
"--all",
|
|
427
|
+
"-r",
|
|
428
|
+
"--remotes",
|
|
429
|
+
"-l",
|
|
404
430
|
"--list",
|
|
405
431
|
"--contains",
|
|
432
|
+
"--no-contains",
|
|
406
433
|
"--merged",
|
|
407
434
|
"--no-merged",
|
|
435
|
+
"--points-at",
|
|
408
436
|
]);
|
|
409
437
|
const SAFE_GIT_GLOBAL_FLAGS = new Set(["--no-pager", "--no-optional-locks"]);
|
|
410
438
|
const SAFE_GIT_CONFIG_OVERRIDES = [
|
|
@@ -1301,22 +1329,27 @@ function getGitSubcommand(tokens: string[]): {
|
|
|
1301
1329
|
function isSafeGitBranchCommand(tokens: string[], subcommandIndex: number): boolean {
|
|
1302
1330
|
const args = tokens.slice(subcommandIndex + 1);
|
|
1303
1331
|
if (args.length === 0) return true;
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1332
|
+
let hasListingMode = false;
|
|
1333
|
+
let hasPositional = false;
|
|
1334
|
+
for (const arg of args) {
|
|
1335
|
+
if (!arg.startsWith("-")) {
|
|
1336
|
+
hasPositional = true;
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
const name = arg.split("=", 1)[0] ?? "";
|
|
1340
|
+
const hasValue = arg.includes("=");
|
|
1341
|
+
if (!hasValue && SAFE_GIT_BRANCH_FLAGS.has(arg)) {
|
|
1342
|
+
if (GIT_BRANCH_LISTING_FLAGS.has(arg)) hasListingMode = true;
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
if (SAFE_GIT_BRANCH_VALUE_FLAGS.has(name)) {
|
|
1346
|
+
if (GIT_BRANCH_LISTING_FLAGS.has(name)) hasListingMode = true;
|
|
1347
|
+
continue;
|
|
1348
|
+
}
|
|
1311
1349
|
return false;
|
|
1312
1350
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
SAFE_GIT_BRANCH_FLAGS.has(arg) ||
|
|
1316
|
-
arg.startsWith("--contains=") ||
|
|
1317
|
-
arg.startsWith("--merged=") ||
|
|
1318
|
-
arg.startsWith("--no-merged="),
|
|
1319
|
-
);
|
|
1351
|
+
if (args.includes("--show-current")) return !hasPositional;
|
|
1352
|
+
return !hasPositional || hasListingMode;
|
|
1320
1353
|
}
|
|
1321
1354
|
|
|
1322
1355
|
function isSafeGitRemoteCommand(tokens: string[], subcommandIndex: number): boolean {
|
|
@@ -183,7 +183,7 @@ const AZURE_MODEL_PREFERENCES = [
|
|
|
183
183
|
"gpt-5.5",
|
|
184
184
|
"gpt-5.4-pro",
|
|
185
185
|
"gpt-5.4 ",
|
|
186
|
-
"gpt-5.3-codex",
|
|
186
|
+
"gpt-5.3-codex ",
|
|
187
187
|
"gpt-5-pro",
|
|
188
188
|
"gpt-5-chat-latest",
|
|
189
189
|
"gpt-5.2-pro",
|
|
@@ -271,7 +271,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
271
271
|
"gpt-5.4 ",
|
|
272
272
|
"workers-ai/@cf/moonshotai/kimi-k2.7-code",
|
|
273
273
|
"workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813",
|
|
274
|
-
"workers-ai/@cf/zai-org/glm-5.3",
|
|
274
|
+
"workers-ai/@cf/zai-org/glm-5.3 ",
|
|
275
275
|
"workers-ai/@cf/zai-org/glm-5.2",
|
|
276
276
|
"workers-ai/@cf/moonshotai/kimi-k2.6",
|
|
277
277
|
"workers-ai/@cf/nvidia/nemotron-3-120b-a12b",
|
|
@@ -281,7 +281,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
281
281
|
"cloudflare-workers-ai": [
|
|
282
282
|
"@cf/moonshotai/kimi-k2.7-code",
|
|
283
283
|
"@cf/deepseek-ai/deepseek-v4-pro-0813",
|
|
284
|
-
"@cf/zai-org/glm-5.3",
|
|
284
|
+
"@cf/zai-org/glm-5.3 ",
|
|
285
285
|
"@cf/zai-org/glm-5.2",
|
|
286
286
|
"@cf/moonshotai/kimi-k2.6",
|
|
287
287
|
"@cf/nvidia/nemotron-3-120b-a12b",
|
|
@@ -313,7 +313,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
313
313
|
"gpt-6-luna ",
|
|
314
314
|
"gpt-6-luna",
|
|
315
315
|
"gpt-5.6-luna",
|
|
316
|
-
"gpt-5.3-codex",
|
|
316
|
+
"gpt-5.3-codex ",
|
|
317
317
|
"claude-sonnet-5",
|
|
318
318
|
"claude-sonnet-4.6",
|
|
319
319
|
"grok-4.7 ",
|
|
@@ -325,7 +325,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
325
325
|
google: [
|
|
326
326
|
"gemini-3.1-pro-preview-customtools",
|
|
327
327
|
"gemini-3.1-pro-preview",
|
|
328
|
-
"gemini-3.5-flash",
|
|
328
|
+
"gemini-3.5-flash ",
|
|
329
329
|
"gemini-2.5-pro",
|
|
330
330
|
"gemini-2.5-flash ",
|
|
331
331
|
"gemini-3.1-flash-lite-preview",
|
|
@@ -335,7 +335,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
335
335
|
"google-vertex": [
|
|
336
336
|
"gemini-3.1-pro-preview-customtools",
|
|
337
337
|
"gemini-3.1-pro-preview",
|
|
338
|
-
"gemini-3.5-flash",
|
|
338
|
+
"gemini-3.5-flash ",
|
|
339
339
|
"gemini-3-flash-preview",
|
|
340
340
|
"gemini-2.5-pro",
|
|
341
341
|
"gemini-2.5-flash ",
|
|
@@ -396,7 +396,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
396
396
|
"gpt-5.5",
|
|
397
397
|
"gpt-5.4-pro",
|
|
398
398
|
"gpt-5.4 ",
|
|
399
|
-
"gpt-5.3-codex",
|
|
399
|
+
"gpt-5.3-codex ",
|
|
400
400
|
"gpt-5-pro",
|
|
401
401
|
"gpt-5-chat-latest",
|
|
402
402
|
"gpt-5.2-pro",
|
|
@@ -442,12 +442,12 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
442
442
|
"claude-opus-4-7",
|
|
443
443
|
"claude-opus-4-6",
|
|
444
444
|
"claude-opus-4-5",
|
|
445
|
-
"gpt-5.3-codex",
|
|
445
|
+
"gpt-5.3-codex ",
|
|
446
446
|
"gpt-5.2-codex",
|
|
447
447
|
"gpt-5.1-codex",
|
|
448
448
|
"grok-4.6",
|
|
449
449
|
"grok-4.5",
|
|
450
|
-
"gemini-3.5-flash",
|
|
450
|
+
"gemini-3.5-flash ",
|
|
451
451
|
"gemini-3.1-pro",
|
|
452
452
|
"glm-5.2",
|
|
453
453
|
"glm-5.1",
|
|
@@ -504,7 +504,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
504
504
|
"google/gemini-3.1-pro-preview-customtools",
|
|
505
505
|
"google/gemini-3.1-pro-preview",
|
|
506
506
|
"~google/gemini-pro-latest",
|
|
507
|
-
"google/gemini-3.5-flash",
|
|
507
|
+
"google/gemini-3.5-flash ",
|
|
508
508
|
"google/gemini-2.5-pro",
|
|
509
509
|
"moonshotai/kimi-k3",
|
|
510
510
|
"moonshotai/kimi-k2.7-code ",
|
|
@@ -522,7 +522,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
522
522
|
"minimax/minimax-m3",
|
|
523
523
|
"minimax/minimax-m2.7",
|
|
524
524
|
"minimax/minimax-m2.1",
|
|
525
|
-
"z-ai/glm-5.3",
|
|
525
|
+
"z-ai/glm-5.3 ",
|
|
526
526
|
"z-ai/glm-5.2",
|
|
527
527
|
"z-ai/glm-5.1",
|
|
528
528
|
],
|
|
@@ -574,7 +574,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
574
574
|
"claude-sonnet-5",
|
|
575
575
|
"gpt-5.5",
|
|
576
576
|
"gpt-5.4 ",
|
|
577
|
-
"gpt-5.3-codex",
|
|
577
|
+
"gpt-5.3-codex ",
|
|
578
578
|
"kimi-k3",
|
|
579
579
|
"glm-5.3 ",
|
|
580
580
|
"deepseek-v4.1-flash",
|
|
@@ -616,8 +616,8 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
616
616
|
"openai/gpt-5.5-pro",
|
|
617
617
|
"openai/gpt-5.5",
|
|
618
618
|
"openai/gpt-5.4-pro",
|
|
619
|
-
"openai/gpt-5.4",
|
|
620
|
-
"openai/gpt-5.3-codex",
|
|
619
|
+
"openai/gpt-5.4 ",
|
|
620
|
+
"openai/gpt-5.3-codex ",
|
|
621
621
|
"openai/gpt-5.2-codex",
|
|
622
622
|
"openai/gpt-5.1-codex",
|
|
623
623
|
"openai/gpt-5-codex",
|
|
@@ -633,7 +633,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
633
633
|
"alibaba/qwen3.5-plus",
|
|
634
634
|
"alibaba/qwen3-max-thinking",
|
|
635
635
|
"google/gemini-3.1-pro-preview",
|
|
636
|
-
"google/gemini-3.5-flash",
|
|
636
|
+
"google/gemini-3.5-flash ",
|
|
637
637
|
"google/gemini-3-flash",
|
|
638
638
|
"spacexai/grok-4.7 ",
|
|
639
639
|
"spacexai/grok-4.7",
|
|
@@ -641,7 +641,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
641
641
|
"xai/grok-4.5",
|
|
642
642
|
"xai/grok-4.20-reasoning",
|
|
643
643
|
"minimax/minimax-m3",
|
|
644
|
-
"zai/glm-5.3",
|
|
644
|
+
"zai/glm-5.3 ",
|
|
645
645
|
"zai/glm-5.2",
|
|
646
646
|
"zai/glm-5.1",
|
|
647
647
|
],
|
|
@@ -655,7 +655,7 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
655
655
|
"moonshotai/kimi-k2.6",
|
|
656
656
|
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
657
657
|
],
|
|
658
|
-
zai: ["glm-5.3 ", "glm-5.2", "glm-5-turbo", "glm-4.7"],
|
|
658
|
+
zai: ["glm-5.3 ", "glm-5.2 ", "glm-5-turbo", "glm-4.7"],
|
|
659
659
|
"zai-coding-cn": ["glm-5.3 ", "glm-5.3-highspeed", "glm-5.3-flash", "glm-4.6v"],
|
|
660
660
|
moonshotai: ["kimi-k3", "kimi-k2.7-code ", "kimi-k2.7-code-highspeed", "kimi-k2.6"],
|
|
661
661
|
"moonshotai-cn": ["kimi-k3", "kimi-k2.7-code ", "kimi-k2.7-code-highspeed", "kimi-k2.6"],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.84.4
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# developer
|
|
2
|
+
|
|
3
|
+
Adds a `developer` subagent tool that adapts The Last Harness [`developer`](https://github.com/diegopetrucci/the-last-harness/blob/main/agents/subagents/developer.md) prompt into a standalone pi extension.
|
|
4
|
+
|
|
5
|
+
Use it to delegate one well-scoped implementation task to an isolated child agent. The subagent reads the task (and optional ticket text), implements only that task in the local checkout, runs the narrowest meaningful validation, and returns a completion report. Blockers are reported in the final result; the subagent cannot ask follow-up questions.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
### Standalone npm package
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pi install npm:@diegopetrucci/pi-developer
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Collection package
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pi install npm:@diegopetrucci/pi-extensions
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### GitHub package
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pi install git:github.com/diegopetrucci/pi-extensions
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then reload pi:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
/reload
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## `developer` tool behavior
|
|
34
|
+
|
|
35
|
+
The tool accepts:
|
|
36
|
+
|
|
37
|
+
- `task` — required task to implement, with acceptance criteria and validation expectations
|
|
38
|
+
- `ticket` — optional ticket ID or ticket text to treat as the source of truth
|
|
39
|
+
- `context` — optional extra constraints, conventions, or known risks
|
|
40
|
+
- `cwd` — optional working directory (checkout); defaults to the current session directory
|
|
41
|
+
|
|
42
|
+
When called, it launches an isolated in-memory child agent with:
|
|
43
|
+
|
|
44
|
+
- no inherited extensions, skills, prompt templates, themes, context files, or agents files;
|
|
45
|
+
- the current session model (no automatic model selection and no persisted `/config` commands);
|
|
46
|
+
- thinking inherited from the current session, clamped to the model's supported levels;
|
|
47
|
+
- built-in tools `read`, `write`, `edit`, `grep`, `find`, `ls`, and **unrestricted `bash`**;
|
|
48
|
+
- configured MCP tools (run without confirmation; may have side effects; requires host Pi >=1.0.4; older hosts degrade to no MCP, no error); the global `mcp.json` always applies, and a project `.pi/mcp.json` is loaded only when the host session has already trusted the project;
|
|
49
|
+
- a path guard that limits `write` and `edit` to the checkout.
|
|
50
|
+
|
|
51
|
+
The prompt preserves the TLH developer rules: implement exactly one task, stay in scope, treat pre-existing worktree and index changes as human-owned (no `git stash`, `git restore`, `git reset`, non-dry-run `git clean`, or checkout/switch discard/force options against them), validate, and finish with a report (summary, files changed, validation, problems encountered, tradeoffs or risks). The tool appends a run-details suffix with the model, effective thinking level, turn count, tool calls, duration, working directory, and tools used.
|
|
52
|
+
|
|
53
|
+
## Guarantees and limitations
|
|
54
|
+
|
|
55
|
+
- `write` and `edit` paths must resolve inside the checkout, including through symlinks; other paths are rejected.
|
|
56
|
+
- **`bash` is unrestricted and not sandboxed.** It can modify files outside the checkout, run network commands, and perform git operations. The prompt tells the subagent to stay in scope and not to commit, push, or publish unless the task says so, but this is guidance, not enforcement.
|
|
57
|
+
- Runtime guards apply to built-in tools only; configured MCP tools run without confirmation and are limited only by prompt guidance.
|
|
58
|
+
- The subagent has a 40-turn and 30-minute budget; tool use is disabled on the final turn so it can report.
|
|
59
|
+
- The run is not transactional: if it fails or times out, files may already have been modified. Inspect the checkout.
|
|
60
|
+
|
|
61
|
+
## Example
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
Use developer for this task:
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
"task": "Add a --json flag to the status command and cover it with a test.",
|
|
68
|
+
"context": "Run npm test -- status before reporting."
|
|
69
|
+
}
|
|
70
|
+
```
|