@diegopetrucci/pi-extensions 0.1.58 → 0.1.60
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/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/package.json +1 -1
- package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
- package/extensions/annotate-last-message/package.json +1 -1
- 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 +120 -37
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/.pi-fleet-tested-version +1 -1
- package/extensions/confirm-destructive/README.md +1 -1
- package/extensions/confirm-destructive/index.ts +20 -5
- 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/README.md +1 -1
- package/extensions/contrarian/index.ts +175 -32
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/.pi-fleet-tested-version +1 -1
- package/extensions/dirty-repo-guard/README.md +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/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/README.md +1 -1
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/.pi-fleet-tested-version +1 -1
- package/extensions/librarian/index.ts +385 -106
- 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/README.md +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/README.md +1 -1
- package/extensions/oracle/index.ts +176 -33
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
- package/extensions/permission-gate/README.md +1 -1
- package/extensions/permission-gate/index.ts +453 -2
- package/extensions/permission-gate/package.json +1 -1
- 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/index.ts +53 -19
- package/extensions/review/package.json +1 -1
- package/extensions/todo/.pi-fleet-tested-version +1 -1
- package/extensions/todo/README.md +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 +107 -33
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +4 -4
|
@@ -2,8 +2,8 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
import { StringEnum } from "@earendil-works/pi-ai";
|
|
6
|
-
import { getAgentDir, getMarkdownTheme, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { StringEnum, type Usage } from "@earendil-works/pi-ai";
|
|
6
|
+
import { getAgentDir, getMarkdownTheme, type AgentToolResult, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
8
8
|
import { Type } from "typebox";
|
|
9
9
|
|
|
@@ -25,7 +25,14 @@ interface UsageStats {
|
|
|
25
25
|
output: number;
|
|
26
26
|
cacheRead: number;
|
|
27
27
|
cacheWrite: number;
|
|
28
|
+
cacheWrite1h?: number;
|
|
29
|
+
reasoning?: number;
|
|
30
|
+
totalTokens: number;
|
|
28
31
|
cost: number;
|
|
32
|
+
costInput: number;
|
|
33
|
+
costOutput: number;
|
|
34
|
+
costCacheRead: number;
|
|
35
|
+
costCacheWrite: number;
|
|
29
36
|
turns: number;
|
|
30
37
|
contextTokens: number;
|
|
31
38
|
}
|
|
@@ -464,7 +471,6 @@ const PROVIDER_MODEL_PREFERENCES: Record<string, string[]> = {
|
|
|
464
471
|
"moonshotai/kimi-k2.6",
|
|
465
472
|
"z-ai/glm-5.2",
|
|
466
473
|
"minimaxai/minimax-m3",
|
|
467
|
-
"mistralai/mistral-large-3-675b-instruct-2512",
|
|
468
474
|
"openai/gpt-oss-120b",
|
|
469
475
|
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
470
476
|
"nvidia/nemotron-3-nano-30b-a3b",
|
|
@@ -537,12 +543,91 @@ function createEmptyUsage(): UsageStats {
|
|
|
537
543
|
output: 0,
|
|
538
544
|
cacheRead: 0,
|
|
539
545
|
cacheWrite: 0,
|
|
546
|
+
totalTokens: 0,
|
|
540
547
|
cost: 0,
|
|
548
|
+
costInput: 0,
|
|
549
|
+
costOutput: 0,
|
|
550
|
+
costCacheRead: 0,
|
|
551
|
+
costCacheWrite: 0,
|
|
541
552
|
turns: 0,
|
|
542
553
|
contextTokens: 0,
|
|
543
554
|
};
|
|
544
555
|
}
|
|
545
556
|
|
|
557
|
+
function cloneUsageStats(stats: UsageStats): UsageStats {
|
|
558
|
+
return { ...stats };
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function mergeUsageStats(target: UsageStats, source: UsageStats | undefined): UsageStats {
|
|
562
|
+
if (!source) return target;
|
|
563
|
+
target.input += source.input;
|
|
564
|
+
target.output += source.output;
|
|
565
|
+
target.cacheRead += source.cacheRead;
|
|
566
|
+
target.cacheWrite += source.cacheWrite;
|
|
567
|
+
if (source.cacheWrite1h !== undefined) {
|
|
568
|
+
target.cacheWrite1h = (target.cacheWrite1h ?? 0) + source.cacheWrite1h;
|
|
569
|
+
}
|
|
570
|
+
if (source.reasoning !== undefined) {
|
|
571
|
+
target.reasoning = (target.reasoning ?? 0) + source.reasoning;
|
|
572
|
+
}
|
|
573
|
+
target.totalTokens += source.totalTokens;
|
|
574
|
+
target.cost += source.cost;
|
|
575
|
+
target.costInput += source.costInput;
|
|
576
|
+
target.costOutput += source.costOutput;
|
|
577
|
+
target.costCacheRead += source.costCacheRead;
|
|
578
|
+
target.costCacheWrite += source.costCacheWrite;
|
|
579
|
+
target.turns += source.turns;
|
|
580
|
+
target.contextTokens = source.contextTokens || target.contextTokens;
|
|
581
|
+
return target;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function usageStatsToToolUsage(stats: UsageStats): Usage {
|
|
585
|
+
return {
|
|
586
|
+
input: stats.input,
|
|
587
|
+
output: stats.output,
|
|
588
|
+
cacheRead: stats.cacheRead,
|
|
589
|
+
cacheWrite: stats.cacheWrite,
|
|
590
|
+
...(stats.cacheWrite1h !== undefined ? { cacheWrite1h: stats.cacheWrite1h } : {}),
|
|
591
|
+
...(stats.reasoning !== undefined ? { reasoning: stats.reasoning } : {}),
|
|
592
|
+
totalTokens: stats.totalTokens,
|
|
593
|
+
cost: {
|
|
594
|
+
input: stats.costInput,
|
|
595
|
+
output: stats.costOutput,
|
|
596
|
+
cacheRead: stats.costCacheRead,
|
|
597
|
+
cacheWrite: stats.costCacheWrite,
|
|
598
|
+
total: stats.cost,
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function addUsageStats(
|
|
604
|
+
target: UsageStats,
|
|
605
|
+
source: Usage | undefined,
|
|
606
|
+
options: { countTurn?: boolean; updateContextTokens?: boolean } = {},
|
|
607
|
+
): void {
|
|
608
|
+
if (!source) return;
|
|
609
|
+
if (options.countTurn) target.turns += 1;
|
|
610
|
+
target.input += source.input || 0;
|
|
611
|
+
target.output += source.output || 0;
|
|
612
|
+
target.cacheRead += source.cacheRead || 0;
|
|
613
|
+
target.cacheWrite += source.cacheWrite || 0;
|
|
614
|
+
if (source.cacheWrite1h !== undefined) {
|
|
615
|
+
target.cacheWrite1h = (target.cacheWrite1h ?? 0) + source.cacheWrite1h;
|
|
616
|
+
}
|
|
617
|
+
if (source.reasoning !== undefined) {
|
|
618
|
+
target.reasoning = (target.reasoning ?? 0) + source.reasoning;
|
|
619
|
+
}
|
|
620
|
+
target.totalTokens += source.totalTokens || 0;
|
|
621
|
+
target.cost += source.cost?.total || 0;
|
|
622
|
+
target.costInput += source.cost?.input || 0;
|
|
623
|
+
target.costOutput += source.cost?.output || 0;
|
|
624
|
+
target.costCacheRead += source.cost?.cacheRead || 0;
|
|
625
|
+
target.costCacheWrite += source.cost?.cacheWrite || 0;
|
|
626
|
+
if (options.updateContextTokens) {
|
|
627
|
+
target.contextTokens = source.totalTokens || target.contextTokens;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
546
631
|
function getContrarianConfigPath(): string {
|
|
547
632
|
return path.join(getAgentDir(), "extensions", CONTRARIAN_CONFIG_FILE);
|
|
548
633
|
}
|
|
@@ -631,6 +716,7 @@ function formatUsage(stats: UsageStats): string {
|
|
|
631
716
|
if (stats.output) parts.push(`↓${formatTokens(stats.output)}`);
|
|
632
717
|
if (stats.cacheRead) parts.push(`R${formatTokens(stats.cacheRead)}`);
|
|
633
718
|
if (stats.cacheWrite) parts.push(`W${formatTokens(stats.cacheWrite)}`);
|
|
719
|
+
if (stats.reasoning) parts.push(`T${formatTokens(stats.reasoning)}`);
|
|
634
720
|
if (stats.cost) parts.push(`$${stats.cost.toFixed(4)}`);
|
|
635
721
|
if (stats.contextTokens) parts.push(`ctx:${formatTokens(stats.contextTokens)}`);
|
|
636
722
|
return parts.join(" ");
|
|
@@ -1034,6 +1120,7 @@ async function runContrarian(
|
|
|
1034
1120
|
signal: AbortSignal | undefined,
|
|
1035
1121
|
onUpdate: ((result: { content: Array<{ type: "text"; text: string }>; details: ContrarianDetails }) => void) | undefined,
|
|
1036
1122
|
defaultCwd: string,
|
|
1123
|
+
spawnImpl: typeof spawn = spawn,
|
|
1037
1124
|
): Promise<{ ok: true; output: string; details: ContrarianDetails } | { ok: false; error: string; details: ContrarianDetails }> {
|
|
1038
1125
|
const cwd = params.cwd ?? defaultCwd;
|
|
1039
1126
|
const includeBash = params.includeBash ?? false;
|
|
@@ -1085,7 +1172,7 @@ async function runContrarian(
|
|
|
1085
1172
|
let wasAborted = false;
|
|
1086
1173
|
|
|
1087
1174
|
const exitCode = await new Promise<number>((resolve) => {
|
|
1088
|
-
const proc =
|
|
1175
|
+
const proc = spawnImpl(invocation.command, invocation.args, {
|
|
1089
1176
|
cwd,
|
|
1090
1177
|
shell: false,
|
|
1091
1178
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -1123,18 +1210,16 @@ async function runContrarian(
|
|
|
1123
1210
|
const errorMessageField = event.message.errorMessage;
|
|
1124
1211
|
lastErrorMessage = typeof errorMessageField === "string" ? errorMessageField : undefined;
|
|
1125
1212
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
usage.output += messageUsage.output || 0;
|
|
1131
|
-
usage.cacheRead += messageUsage.cacheRead || 0;
|
|
1132
|
-
usage.cacheWrite += messageUsage.cacheWrite || 0;
|
|
1133
|
-
usage.cost += messageUsage.cost?.total || 0;
|
|
1134
|
-
usage.contextTokens = messageUsage.totalTokens || usage.contextTokens;
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1213
|
+
addUsageStats(usage, event.message.usage as Usage | undefined, {
|
|
1214
|
+
countTurn: true,
|
|
1215
|
+
updateContextTokens: true,
|
|
1216
|
+
});
|
|
1137
1217
|
emit();
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
if (event.type === "compaction_end") {
|
|
1222
|
+
addUsageStats(usage, event.result?.usage as Usage | undefined);
|
|
1138
1223
|
}
|
|
1139
1224
|
};
|
|
1140
1225
|
|
|
@@ -1150,26 +1235,53 @@ async function runContrarian(
|
|
|
1150
1235
|
emit();
|
|
1151
1236
|
});
|
|
1152
1237
|
|
|
1238
|
+
let closed = false;
|
|
1239
|
+
let killTimer: ReturnType<typeof setTimeout> | undefined;
|
|
1240
|
+
let abortListener: (() => void) | undefined;
|
|
1241
|
+
|
|
1242
|
+
const childHasExited = () => proc.exitCode !== null || proc.signalCode !== null;
|
|
1243
|
+
const clearEscalation = () => {
|
|
1244
|
+
if (killTimer) {
|
|
1245
|
+
clearTimeout(killTimer);
|
|
1246
|
+
killTimer = undefined;
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
const cleanup = () => {
|
|
1250
|
+
clearEscalation();
|
|
1251
|
+
if (signal && abortListener) {
|
|
1252
|
+
signal.removeEventListener("abort", abortListener);
|
|
1253
|
+
abortListener = undefined;
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
proc.on("exit", () => {
|
|
1258
|
+
clearEscalation();
|
|
1259
|
+
});
|
|
1260
|
+
|
|
1153
1261
|
proc.on("close", (code) => {
|
|
1262
|
+
closed = true;
|
|
1263
|
+
cleanup();
|
|
1154
1264
|
if (buffer.trim()) processLine(buffer);
|
|
1155
1265
|
resolve(code ?? 0);
|
|
1156
1266
|
});
|
|
1157
1267
|
|
|
1158
1268
|
proc.on("error", (error) => {
|
|
1269
|
+
cleanup();
|
|
1159
1270
|
stderr += `${error instanceof Error ? error.message : String(error)}\n`;
|
|
1160
1271
|
resolve(1);
|
|
1161
1272
|
});
|
|
1162
1273
|
|
|
1163
1274
|
if (signal) {
|
|
1164
|
-
|
|
1275
|
+
abortListener = () => {
|
|
1165
1276
|
wasAborted = true;
|
|
1166
1277
|
proc.kill("SIGTERM");
|
|
1167
|
-
|
|
1168
|
-
|
|
1278
|
+
if (closed || childHasExited()) return;
|
|
1279
|
+
killTimer = setTimeout(() => {
|
|
1280
|
+
if (!closed && !childHasExited()) proc.kill("SIGKILL");
|
|
1169
1281
|
}, 5000);
|
|
1170
1282
|
};
|
|
1171
|
-
if (signal.aborted)
|
|
1172
|
-
else signal.addEventListener("abort",
|
|
1283
|
+
if (signal.aborted) abortListener();
|
|
1284
|
+
else signal.addEventListener("abort", abortListener, { once: true });
|
|
1173
1285
|
}
|
|
1174
1286
|
});
|
|
1175
1287
|
|
|
@@ -1178,6 +1290,7 @@ async function runContrarian(
|
|
|
1178
1290
|
details.durationMs = Date.now() - startedAt;
|
|
1179
1291
|
|
|
1180
1292
|
if (wasAborted) {
|
|
1293
|
+
if (details.exitCode === 0) details.exitCode = 1;
|
|
1181
1294
|
return { ok: false, error: "Contrarian was aborted.", details };
|
|
1182
1295
|
}
|
|
1183
1296
|
|
|
@@ -1187,6 +1300,7 @@ async function runContrarian(
|
|
|
1187
1300
|
// so callers can distinguish transient provider errors from a genuinely
|
|
1188
1301
|
// empty response.
|
|
1189
1302
|
if (lastStopReason === "error" || lastStopReason === "aborted") {
|
|
1303
|
+
if (details.exitCode === 0) details.exitCode = 1;
|
|
1190
1304
|
return {
|
|
1191
1305
|
ok: false,
|
|
1192
1306
|
error: formatContrarianModelError(lastStopReason, lastErrorMessage),
|
|
@@ -1203,6 +1317,7 @@ async function runContrarian(
|
|
|
1203
1317
|
}
|
|
1204
1318
|
|
|
1205
1319
|
if (!finalOutput.trim()) {
|
|
1320
|
+
if (details.exitCode === 0) details.exitCode = 1;
|
|
1206
1321
|
return {
|
|
1207
1322
|
ok: false,
|
|
1208
1323
|
error: details.stderr || "Contrarian finished without returning any text.",
|
|
@@ -1223,15 +1338,26 @@ function renderCollapsedText(text: string, lineLimit = COLLAPSED_LINE_LIMIT): st
|
|
|
1223
1338
|
return [...lines.slice(0, lineLimit), `... (${lines.length - lineLimit} more lines)`].join("\n");
|
|
1224
1339
|
}
|
|
1225
1340
|
|
|
1341
|
+
type ContrarianExtensionDeps = {
|
|
1342
|
+
spawnImpl?: typeof spawn;
|
|
1343
|
+
};
|
|
1344
|
+
|
|
1226
1345
|
export const __test__ = {
|
|
1346
|
+
createContrarianExtension,
|
|
1227
1347
|
findAvailableModel,
|
|
1228
1348
|
isModelAvailabilityError,
|
|
1229
1349
|
parseModelPreference,
|
|
1350
|
+
runContrarian,
|
|
1230
1351
|
resolveThinkingLevel,
|
|
1231
1352
|
selectContrarianModel,
|
|
1232
1353
|
};
|
|
1233
1354
|
|
|
1234
1355
|
export default function contrarianExtension(pi: ExtensionAPI) {
|
|
1356
|
+
createContrarianExtension(pi);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
function createContrarianExtension(pi: ExtensionAPI, deps: ContrarianExtensionDeps = {}) {
|
|
1360
|
+
const spawnImpl = deps.spawnImpl ?? spawn;
|
|
1235
1361
|
const activeRuns = new Map<string, ContrarianUiRun>();
|
|
1236
1362
|
let preferences: ContrarianPreferences = {};
|
|
1237
1363
|
|
|
@@ -1377,6 +1503,13 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1377
1503
|
},
|
|
1378
1504
|
});
|
|
1379
1505
|
|
|
1506
|
+
pi.on("tool_result", async (event) => {
|
|
1507
|
+
if (event.toolName !== "contrarian") return undefined;
|
|
1508
|
+
const details = event.details as ContrarianDetails | undefined;
|
|
1509
|
+
if ((details?.exitCode ?? 0) === 0) return undefined;
|
|
1510
|
+
return { isError: true };
|
|
1511
|
+
});
|
|
1512
|
+
|
|
1380
1513
|
pi.registerTool({
|
|
1381
1514
|
name: "contrarian",
|
|
1382
1515
|
label: "Contrarian",
|
|
@@ -1387,9 +1520,10 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1387
1520
|
promptGuidelines: [
|
|
1388
1521
|
"Use contrarian when you need to stress-test a proposal, implementation plan, design, assumption, bug hypothesis, review conclusion, or product direction.",
|
|
1389
1522
|
"Ask contrarian to steelman the strongest opposing case and separate confirmed objections, plausible concerns, and unresolved unknowns.",
|
|
1390
|
-
"Do not use
|
|
1391
|
-
"The contrarian is read-only by default
|
|
1392
|
-
"
|
|
1523
|
+
"Do not use contrarian for routine low-value work; contrarian is slower than the main agent.",
|
|
1524
|
+
"The contrarian tool is read-only by default and only exposes read, grep, find, and ls unless contrarian includeBash is enabled.",
|
|
1525
|
+
"Set contrarian includeBash only when the extra bash inspection tool is genuinely useful; keep contrarian relying on read, grep, find, and ls otherwise.",
|
|
1526
|
+
"The contrarian tool requests high by default for reasoning models; contrarian defaults and explicit thinkingLevel overrides are clamped to the effective model-supported level when the model is matched.",
|
|
1393
1527
|
],
|
|
1394
1528
|
parameters: ContrarianParams,
|
|
1395
1529
|
|
|
@@ -1414,6 +1548,14 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1414
1548
|
try {
|
|
1415
1549
|
const attempts: ContrarianSelection[] = [];
|
|
1416
1550
|
const seen = new Set<string>();
|
|
1551
|
+
const aggregateUsage = createEmptyUsage();
|
|
1552
|
+
const finalizeResult = (
|
|
1553
|
+
result: { content: Array<{ type: "text"; text: string }>; details: ContrarianDetails },
|
|
1554
|
+
): AgentToolResult<ContrarianDetails> => ({
|
|
1555
|
+
...result,
|
|
1556
|
+
details: { ...result.details, usage: cloneUsageStats(aggregateUsage) },
|
|
1557
|
+
usage: usageStatsToToolUsage(aggregateUsage),
|
|
1558
|
+
});
|
|
1417
1559
|
const pushAttempt = (candidate: ContrarianSelection | undefined) => {
|
|
1418
1560
|
if (!candidate) return;
|
|
1419
1561
|
const key = `${candidate.provider}/${candidate.modelId}`.toLowerCase();
|
|
@@ -1455,7 +1597,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1455
1597
|
} else {
|
|
1456
1598
|
const selectionResult = await selectContrarianModel(ctx, configuredThinkingLevel);
|
|
1457
1599
|
if (!selectionResult.ok) {
|
|
1458
|
-
return {
|
|
1600
|
+
return finalizeResult({
|
|
1459
1601
|
content: [{ type: "text", text: selectionResult.error }],
|
|
1460
1602
|
details: {
|
|
1461
1603
|
modelRef: "",
|
|
@@ -1472,7 +1614,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1472
1614
|
durationMs: 0,
|
|
1473
1615
|
cwd: params.cwd ?? ctx.cwd,
|
|
1474
1616
|
},
|
|
1475
|
-
};
|
|
1617
|
+
});
|
|
1476
1618
|
}
|
|
1477
1619
|
for (const candidate of selectionResult.ordered) pushAttempt(candidate);
|
|
1478
1620
|
}
|
|
@@ -1496,25 +1638,26 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1496
1638
|
uiRun.selection = attempt;
|
|
1497
1639
|
updateContrarianUi(ctx, activeRuns);
|
|
1498
1640
|
|
|
1499
|
-
const result = await runContrarian(attempt, { ...params, task }, signal, handleUpdate, ctx.cwd);
|
|
1641
|
+
const result = await runContrarian(attempt, { ...params, task }, signal, handleUpdate, ctx.cwd, spawnImpl);
|
|
1642
|
+
mergeUsageStats(aggregateUsage, result.details.usage);
|
|
1500
1643
|
if (result.ok) {
|
|
1501
|
-
return {
|
|
1644
|
+
return finalizeResult({
|
|
1502
1645
|
content: [{ type: "text", text: result.output }],
|
|
1503
1646
|
details: result.details,
|
|
1504
|
-
};
|
|
1647
|
+
});
|
|
1505
1648
|
}
|
|
1506
1649
|
|
|
1507
1650
|
lastErrorResult = result;
|
|
1508
1651
|
const canFallBack = index < attempts.length - 1 && isModelAvailabilityError(result.error);
|
|
1509
1652
|
if (!canFallBack) {
|
|
1510
|
-
return {
|
|
1653
|
+
return finalizeResult({
|
|
1511
1654
|
content: [{ type: "text", text: result.error }],
|
|
1512
1655
|
details: result.details,
|
|
1513
|
-
};
|
|
1656
|
+
});
|
|
1514
1657
|
}
|
|
1515
1658
|
}
|
|
1516
1659
|
|
|
1517
|
-
return {
|
|
1660
|
+
return finalizeResult({
|
|
1518
1661
|
content: [
|
|
1519
1662
|
{ type: "text", text: lastErrorResult?.error ?? "Contrarian could not select an available model." },
|
|
1520
1663
|
],
|
|
@@ -1534,7 +1677,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1534
1677
|
durationMs: 0,
|
|
1535
1678
|
cwd: params.cwd ?? ctx.cwd,
|
|
1536
1679
|
},
|
|
1537
|
-
};
|
|
1680
|
+
});
|
|
1538
1681
|
} finally {
|
|
1539
1682
|
activeRuns.delete(toolCallId);
|
|
1540
1683
|
updateContrarianUi(ctx, activeRuns);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.82.0
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A small pi extension that prompts before session changes when the current git repo has uncommitted changes.
|
|
4
4
|
|
|
5
|
-
This is copied from the original `dirty-repo-guard.ts` example in [`earendil-works/pi
|
|
5
|
+
This is copied from the original `dirty-repo-guard.ts` example in [`earendil-works/pi`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/extensions/dirty-repo-guard.ts) and kept basically the same.
|
|
6
6
|
|
|
7
7
|
## What it checks
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.82.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.82.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.82.0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.82.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-illustrations-to-explain-things",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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.82.0
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A pi extension that expands inline bash commands in user prompts before they are sent to the agent.
|
|
4
4
|
|
|
5
|
-
This started from the original `inline-bash.ts` example in [`earendil-works/pi
|
|
5
|
+
This started from the original `inline-bash.ts` example in [`earendil-works/pi`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/extensions/inline-bash.ts), with small packaging and safety tweaks.
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.82.0
|