@diegopetrucci/pi-extensions 0.1.58 → 0.1.59
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 -31
- 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/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 -32
- 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 +1 -1
|
@@ -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
|
}
|
|
@@ -537,12 +544,91 @@ function createEmptyUsage(): UsageStats {
|
|
|
537
544
|
output: 0,
|
|
538
545
|
cacheRead: 0,
|
|
539
546
|
cacheWrite: 0,
|
|
547
|
+
totalTokens: 0,
|
|
540
548
|
cost: 0,
|
|
549
|
+
costInput: 0,
|
|
550
|
+
costOutput: 0,
|
|
551
|
+
costCacheRead: 0,
|
|
552
|
+
costCacheWrite: 0,
|
|
541
553
|
turns: 0,
|
|
542
554
|
contextTokens: 0,
|
|
543
555
|
};
|
|
544
556
|
}
|
|
545
557
|
|
|
558
|
+
function cloneUsageStats(stats: UsageStats): UsageStats {
|
|
559
|
+
return { ...stats };
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function mergeUsageStats(target: UsageStats, source: UsageStats | undefined): UsageStats {
|
|
563
|
+
if (!source) return target;
|
|
564
|
+
target.input += source.input;
|
|
565
|
+
target.output += source.output;
|
|
566
|
+
target.cacheRead += source.cacheRead;
|
|
567
|
+
target.cacheWrite += source.cacheWrite;
|
|
568
|
+
if (source.cacheWrite1h !== undefined) {
|
|
569
|
+
target.cacheWrite1h = (target.cacheWrite1h ?? 0) + source.cacheWrite1h;
|
|
570
|
+
}
|
|
571
|
+
if (source.reasoning !== undefined) {
|
|
572
|
+
target.reasoning = (target.reasoning ?? 0) + source.reasoning;
|
|
573
|
+
}
|
|
574
|
+
target.totalTokens += source.totalTokens;
|
|
575
|
+
target.cost += source.cost;
|
|
576
|
+
target.costInput += source.costInput;
|
|
577
|
+
target.costOutput += source.costOutput;
|
|
578
|
+
target.costCacheRead += source.costCacheRead;
|
|
579
|
+
target.costCacheWrite += source.costCacheWrite;
|
|
580
|
+
target.turns += source.turns;
|
|
581
|
+
target.contextTokens = source.contextTokens || target.contextTokens;
|
|
582
|
+
return target;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function usageStatsToToolUsage(stats: UsageStats): Usage {
|
|
586
|
+
return {
|
|
587
|
+
input: stats.input,
|
|
588
|
+
output: stats.output,
|
|
589
|
+
cacheRead: stats.cacheRead,
|
|
590
|
+
cacheWrite: stats.cacheWrite,
|
|
591
|
+
...(stats.cacheWrite1h !== undefined ? { cacheWrite1h: stats.cacheWrite1h } : {}),
|
|
592
|
+
...(stats.reasoning !== undefined ? { reasoning: stats.reasoning } : {}),
|
|
593
|
+
totalTokens: stats.totalTokens,
|
|
594
|
+
cost: {
|
|
595
|
+
input: stats.costInput,
|
|
596
|
+
output: stats.costOutput,
|
|
597
|
+
cacheRead: stats.costCacheRead,
|
|
598
|
+
cacheWrite: stats.costCacheWrite,
|
|
599
|
+
total: stats.cost,
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function addUsageStats(
|
|
605
|
+
target: UsageStats,
|
|
606
|
+
source: Usage | undefined,
|
|
607
|
+
options: { countTurn?: boolean; updateContextTokens?: boolean } = {},
|
|
608
|
+
): void {
|
|
609
|
+
if (!source) return;
|
|
610
|
+
if (options.countTurn) target.turns += 1;
|
|
611
|
+
target.input += source.input || 0;
|
|
612
|
+
target.output += source.output || 0;
|
|
613
|
+
target.cacheRead += source.cacheRead || 0;
|
|
614
|
+
target.cacheWrite += source.cacheWrite || 0;
|
|
615
|
+
if (source.cacheWrite1h !== undefined) {
|
|
616
|
+
target.cacheWrite1h = (target.cacheWrite1h ?? 0) + source.cacheWrite1h;
|
|
617
|
+
}
|
|
618
|
+
if (source.reasoning !== undefined) {
|
|
619
|
+
target.reasoning = (target.reasoning ?? 0) + source.reasoning;
|
|
620
|
+
}
|
|
621
|
+
target.totalTokens += source.totalTokens || 0;
|
|
622
|
+
target.cost += source.cost?.total || 0;
|
|
623
|
+
target.costInput += source.cost?.input || 0;
|
|
624
|
+
target.costOutput += source.cost?.output || 0;
|
|
625
|
+
target.costCacheRead += source.cost?.cacheRead || 0;
|
|
626
|
+
target.costCacheWrite += source.cost?.cacheWrite || 0;
|
|
627
|
+
if (options.updateContextTokens) {
|
|
628
|
+
target.contextTokens = source.totalTokens || target.contextTokens;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
546
632
|
function getContrarianConfigPath(): string {
|
|
547
633
|
return path.join(getAgentDir(), "extensions", CONTRARIAN_CONFIG_FILE);
|
|
548
634
|
}
|
|
@@ -631,6 +717,7 @@ function formatUsage(stats: UsageStats): string {
|
|
|
631
717
|
if (stats.output) parts.push(`↓${formatTokens(stats.output)}`);
|
|
632
718
|
if (stats.cacheRead) parts.push(`R${formatTokens(stats.cacheRead)}`);
|
|
633
719
|
if (stats.cacheWrite) parts.push(`W${formatTokens(stats.cacheWrite)}`);
|
|
720
|
+
if (stats.reasoning) parts.push(`T${formatTokens(stats.reasoning)}`);
|
|
634
721
|
if (stats.cost) parts.push(`$${stats.cost.toFixed(4)}`);
|
|
635
722
|
if (stats.contextTokens) parts.push(`ctx:${formatTokens(stats.contextTokens)}`);
|
|
636
723
|
return parts.join(" ");
|
|
@@ -1034,6 +1121,7 @@ async function runContrarian(
|
|
|
1034
1121
|
signal: AbortSignal | undefined,
|
|
1035
1122
|
onUpdate: ((result: { content: Array<{ type: "text"; text: string }>; details: ContrarianDetails }) => void) | undefined,
|
|
1036
1123
|
defaultCwd: string,
|
|
1124
|
+
spawnImpl: typeof spawn = spawn,
|
|
1037
1125
|
): Promise<{ ok: true; output: string; details: ContrarianDetails } | { ok: false; error: string; details: ContrarianDetails }> {
|
|
1038
1126
|
const cwd = params.cwd ?? defaultCwd;
|
|
1039
1127
|
const includeBash = params.includeBash ?? false;
|
|
@@ -1085,7 +1173,7 @@ async function runContrarian(
|
|
|
1085
1173
|
let wasAborted = false;
|
|
1086
1174
|
|
|
1087
1175
|
const exitCode = await new Promise<number>((resolve) => {
|
|
1088
|
-
const proc =
|
|
1176
|
+
const proc = spawnImpl(invocation.command, invocation.args, {
|
|
1089
1177
|
cwd,
|
|
1090
1178
|
shell: false,
|
|
1091
1179
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -1123,18 +1211,16 @@ async function runContrarian(
|
|
|
1123
1211
|
const errorMessageField = event.message.errorMessage;
|
|
1124
1212
|
lastErrorMessage = typeof errorMessageField === "string" ? errorMessageField : undefined;
|
|
1125
1213
|
|
|
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
|
-
|
|
1214
|
+
addUsageStats(usage, event.message.usage as Usage | undefined, {
|
|
1215
|
+
countTurn: true,
|
|
1216
|
+
updateContextTokens: true,
|
|
1217
|
+
});
|
|
1137
1218
|
emit();
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (event.type === "compaction_end") {
|
|
1223
|
+
addUsageStats(usage, event.result?.usage as Usage | undefined);
|
|
1138
1224
|
}
|
|
1139
1225
|
};
|
|
1140
1226
|
|
|
@@ -1150,26 +1236,53 @@ async function runContrarian(
|
|
|
1150
1236
|
emit();
|
|
1151
1237
|
});
|
|
1152
1238
|
|
|
1239
|
+
let closed = false;
|
|
1240
|
+
let killTimer: ReturnType<typeof setTimeout> | undefined;
|
|
1241
|
+
let abortListener: (() => void) | undefined;
|
|
1242
|
+
|
|
1243
|
+
const childHasExited = () => proc.exitCode !== null || proc.signalCode !== null;
|
|
1244
|
+
const clearEscalation = () => {
|
|
1245
|
+
if (killTimer) {
|
|
1246
|
+
clearTimeout(killTimer);
|
|
1247
|
+
killTimer = undefined;
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
const cleanup = () => {
|
|
1251
|
+
clearEscalation();
|
|
1252
|
+
if (signal && abortListener) {
|
|
1253
|
+
signal.removeEventListener("abort", abortListener);
|
|
1254
|
+
abortListener = undefined;
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
proc.on("exit", () => {
|
|
1259
|
+
clearEscalation();
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1153
1262
|
proc.on("close", (code) => {
|
|
1263
|
+
closed = true;
|
|
1264
|
+
cleanup();
|
|
1154
1265
|
if (buffer.trim()) processLine(buffer);
|
|
1155
1266
|
resolve(code ?? 0);
|
|
1156
1267
|
});
|
|
1157
1268
|
|
|
1158
1269
|
proc.on("error", (error) => {
|
|
1270
|
+
cleanup();
|
|
1159
1271
|
stderr += `${error instanceof Error ? error.message : String(error)}\n`;
|
|
1160
1272
|
resolve(1);
|
|
1161
1273
|
});
|
|
1162
1274
|
|
|
1163
1275
|
if (signal) {
|
|
1164
|
-
|
|
1276
|
+
abortListener = () => {
|
|
1165
1277
|
wasAborted = true;
|
|
1166
1278
|
proc.kill("SIGTERM");
|
|
1167
|
-
|
|
1168
|
-
|
|
1279
|
+
if (closed || childHasExited()) return;
|
|
1280
|
+
killTimer = setTimeout(() => {
|
|
1281
|
+
if (!closed && !childHasExited()) proc.kill("SIGKILL");
|
|
1169
1282
|
}, 5000);
|
|
1170
1283
|
};
|
|
1171
|
-
if (signal.aborted)
|
|
1172
|
-
else signal.addEventListener("abort",
|
|
1284
|
+
if (signal.aborted) abortListener();
|
|
1285
|
+
else signal.addEventListener("abort", abortListener, { once: true });
|
|
1173
1286
|
}
|
|
1174
1287
|
});
|
|
1175
1288
|
|
|
@@ -1178,6 +1291,7 @@ async function runContrarian(
|
|
|
1178
1291
|
details.durationMs = Date.now() - startedAt;
|
|
1179
1292
|
|
|
1180
1293
|
if (wasAborted) {
|
|
1294
|
+
if (details.exitCode === 0) details.exitCode = 1;
|
|
1181
1295
|
return { ok: false, error: "Contrarian was aborted.", details };
|
|
1182
1296
|
}
|
|
1183
1297
|
|
|
@@ -1187,6 +1301,7 @@ async function runContrarian(
|
|
|
1187
1301
|
// so callers can distinguish transient provider errors from a genuinely
|
|
1188
1302
|
// empty response.
|
|
1189
1303
|
if (lastStopReason === "error" || lastStopReason === "aborted") {
|
|
1304
|
+
if (details.exitCode === 0) details.exitCode = 1;
|
|
1190
1305
|
return {
|
|
1191
1306
|
ok: false,
|
|
1192
1307
|
error: formatContrarianModelError(lastStopReason, lastErrorMessage),
|
|
@@ -1203,6 +1318,7 @@ async function runContrarian(
|
|
|
1203
1318
|
}
|
|
1204
1319
|
|
|
1205
1320
|
if (!finalOutput.trim()) {
|
|
1321
|
+
if (details.exitCode === 0) details.exitCode = 1;
|
|
1206
1322
|
return {
|
|
1207
1323
|
ok: false,
|
|
1208
1324
|
error: details.stderr || "Contrarian finished without returning any text.",
|
|
@@ -1223,15 +1339,26 @@ function renderCollapsedText(text: string, lineLimit = COLLAPSED_LINE_LIMIT): st
|
|
|
1223
1339
|
return [...lines.slice(0, lineLimit), `... (${lines.length - lineLimit} more lines)`].join("\n");
|
|
1224
1340
|
}
|
|
1225
1341
|
|
|
1342
|
+
type ContrarianExtensionDeps = {
|
|
1343
|
+
spawnImpl?: typeof spawn;
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1226
1346
|
export const __test__ = {
|
|
1347
|
+
createContrarianExtension,
|
|
1227
1348
|
findAvailableModel,
|
|
1228
1349
|
isModelAvailabilityError,
|
|
1229
1350
|
parseModelPreference,
|
|
1351
|
+
runContrarian,
|
|
1230
1352
|
resolveThinkingLevel,
|
|
1231
1353
|
selectContrarianModel,
|
|
1232
1354
|
};
|
|
1233
1355
|
|
|
1234
1356
|
export default function contrarianExtension(pi: ExtensionAPI) {
|
|
1357
|
+
createContrarianExtension(pi);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
function createContrarianExtension(pi: ExtensionAPI, deps: ContrarianExtensionDeps = {}) {
|
|
1361
|
+
const spawnImpl = deps.spawnImpl ?? spawn;
|
|
1235
1362
|
const activeRuns = new Map<string, ContrarianUiRun>();
|
|
1236
1363
|
let preferences: ContrarianPreferences = {};
|
|
1237
1364
|
|
|
@@ -1377,6 +1504,13 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1377
1504
|
},
|
|
1378
1505
|
});
|
|
1379
1506
|
|
|
1507
|
+
pi.on("tool_result", async (event) => {
|
|
1508
|
+
if (event.toolName !== "contrarian") return undefined;
|
|
1509
|
+
const details = event.details as ContrarianDetails | undefined;
|
|
1510
|
+
if ((details?.exitCode ?? 0) === 0) return undefined;
|
|
1511
|
+
return { isError: true };
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1380
1514
|
pi.registerTool({
|
|
1381
1515
|
name: "contrarian",
|
|
1382
1516
|
label: "Contrarian",
|
|
@@ -1387,9 +1521,10 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1387
1521
|
promptGuidelines: [
|
|
1388
1522
|
"Use contrarian when you need to stress-test a proposal, implementation plan, design, assumption, bug hypothesis, review conclusion, or product direction.",
|
|
1389
1523
|
"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
|
-
"
|
|
1524
|
+
"Do not use contrarian for routine low-value work; contrarian is slower than the main agent.",
|
|
1525
|
+
"The contrarian tool is read-only by default and only exposes read, grep, find, and ls unless contrarian includeBash is enabled.",
|
|
1526
|
+
"Set contrarian includeBash only when the extra bash inspection tool is genuinely useful; keep contrarian relying on read, grep, find, and ls otherwise.",
|
|
1527
|
+
"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
1528
|
],
|
|
1394
1529
|
parameters: ContrarianParams,
|
|
1395
1530
|
|
|
@@ -1414,6 +1549,14 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1414
1549
|
try {
|
|
1415
1550
|
const attempts: ContrarianSelection[] = [];
|
|
1416
1551
|
const seen = new Set<string>();
|
|
1552
|
+
const aggregateUsage = createEmptyUsage();
|
|
1553
|
+
const finalizeResult = (
|
|
1554
|
+
result: { content: Array<{ type: "text"; text: string }>; details: ContrarianDetails },
|
|
1555
|
+
): AgentToolResult<ContrarianDetails> => ({
|
|
1556
|
+
...result,
|
|
1557
|
+
details: { ...result.details, usage: cloneUsageStats(aggregateUsage) },
|
|
1558
|
+
usage: usageStatsToToolUsage(aggregateUsage),
|
|
1559
|
+
});
|
|
1417
1560
|
const pushAttempt = (candidate: ContrarianSelection | undefined) => {
|
|
1418
1561
|
if (!candidate) return;
|
|
1419
1562
|
const key = `${candidate.provider}/${candidate.modelId}`.toLowerCase();
|
|
@@ -1455,7 +1598,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1455
1598
|
} else {
|
|
1456
1599
|
const selectionResult = await selectContrarianModel(ctx, configuredThinkingLevel);
|
|
1457
1600
|
if (!selectionResult.ok) {
|
|
1458
|
-
return {
|
|
1601
|
+
return finalizeResult({
|
|
1459
1602
|
content: [{ type: "text", text: selectionResult.error }],
|
|
1460
1603
|
details: {
|
|
1461
1604
|
modelRef: "",
|
|
@@ -1472,7 +1615,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1472
1615
|
durationMs: 0,
|
|
1473
1616
|
cwd: params.cwd ?? ctx.cwd,
|
|
1474
1617
|
},
|
|
1475
|
-
};
|
|
1618
|
+
});
|
|
1476
1619
|
}
|
|
1477
1620
|
for (const candidate of selectionResult.ordered) pushAttempt(candidate);
|
|
1478
1621
|
}
|
|
@@ -1496,25 +1639,26 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1496
1639
|
uiRun.selection = attempt;
|
|
1497
1640
|
updateContrarianUi(ctx, activeRuns);
|
|
1498
1641
|
|
|
1499
|
-
const result = await runContrarian(attempt, { ...params, task }, signal, handleUpdate, ctx.cwd);
|
|
1642
|
+
const result = await runContrarian(attempt, { ...params, task }, signal, handleUpdate, ctx.cwd, spawnImpl);
|
|
1643
|
+
mergeUsageStats(aggregateUsage, result.details.usage);
|
|
1500
1644
|
if (result.ok) {
|
|
1501
|
-
return {
|
|
1645
|
+
return finalizeResult({
|
|
1502
1646
|
content: [{ type: "text", text: result.output }],
|
|
1503
1647
|
details: result.details,
|
|
1504
|
-
};
|
|
1648
|
+
});
|
|
1505
1649
|
}
|
|
1506
1650
|
|
|
1507
1651
|
lastErrorResult = result;
|
|
1508
1652
|
const canFallBack = index < attempts.length - 1 && isModelAvailabilityError(result.error);
|
|
1509
1653
|
if (!canFallBack) {
|
|
1510
|
-
return {
|
|
1654
|
+
return finalizeResult({
|
|
1511
1655
|
content: [{ type: "text", text: result.error }],
|
|
1512
1656
|
details: result.details,
|
|
1513
|
-
};
|
|
1657
|
+
});
|
|
1514
1658
|
}
|
|
1515
1659
|
}
|
|
1516
1660
|
|
|
1517
|
-
return {
|
|
1661
|
+
return finalizeResult({
|
|
1518
1662
|
content: [
|
|
1519
1663
|
{ type: "text", text: lastErrorResult?.error ?? "Contrarian could not select an available model." },
|
|
1520
1664
|
],
|
|
@@ -1534,7 +1678,7 @@ export default function contrarianExtension(pi: ExtensionAPI) {
|
|
|
1534
1678
|
durationMs: 0,
|
|
1535
1679
|
cwd: params.cwd ?? ctx.cwd,
|
|
1536
1680
|
},
|
|
1537
|
-
};
|
|
1681
|
+
});
|
|
1538
1682
|
} finally {
|
|
1539
1683
|
activeRuns.delete(toolCallId);
|
|
1540
1684
|
updateContrarianUi(ctx, activeRuns);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.81.1
|
|
@@ -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.81.1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.81.1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.81.1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.81.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-illustrations-to-explain-things",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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.81.1
|
|
@@ -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.81.1
|