@mariozechner/pi-coding-agent 0.56.2 → 0.57.0

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +3 -1
  3. package/dist/core/agent-session.d.ts +1 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +50 -17
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/auth-storage.d.ts +1 -0
  8. package/dist/core/auth-storage.d.ts.map +1 -1
  9. package/dist/core/auth-storage.js +25 -1
  10. package/dist/core/auth-storage.js.map +1 -1
  11. package/dist/core/compaction/utils.d.ts +3 -0
  12. package/dist/core/compaction/utils.d.ts.map +1 -1
  13. package/dist/core/compaction/utils.js +16 -1
  14. package/dist/core/compaction/utils.js.map +1 -1
  15. package/dist/core/extensions/index.d.ts +1 -1
  16. package/dist/core/extensions/index.d.ts.map +1 -1
  17. package/dist/core/extensions/index.js.map +1 -1
  18. package/dist/core/extensions/runner.d.ts +3 -2
  19. package/dist/core/extensions/runner.d.ts.map +1 -1
  20. package/dist/core/extensions/runner.js +32 -0
  21. package/dist/core/extensions/runner.js.map +1 -1
  22. package/dist/core/extensions/types.d.ts +8 -1
  23. package/dist/core/extensions/types.d.ts.map +1 -1
  24. package/dist/core/extensions/types.js.map +1 -1
  25. package/dist/core/package-manager.d.ts.map +1 -1
  26. package/dist/core/package-manager.js +1 -1
  27. package/dist/core/package-manager.js.map +1 -1
  28. package/dist/core/sdk.d.ts.map +1 -1
  29. package/dist/core/sdk.js +7 -0
  30. package/dist/core/sdk.js.map +1 -1
  31. package/dist/core/settings-manager.d.ts +1 -0
  32. package/dist/core/settings-manager.d.ts.map +1 -1
  33. package/dist/core/settings-manager.js +26 -2
  34. package/dist/core/settings-manager.js.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  39. package/dist/modes/interactive/interactive-mode.js +13 -4
  40. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  41. package/dist/modes/rpc/jsonl.d.ts +17 -0
  42. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  43. package/dist/modes/rpc/jsonl.js +49 -0
  44. package/dist/modes/rpc/jsonl.js.map +1 -0
  45. package/dist/modes/rpc/rpc-client.d.ts +1 -1
  46. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  47. package/dist/modes/rpc/rpc-client.js +7 -11
  48. package/dist/modes/rpc/rpc-client.js.map +1 -1
  49. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  50. package/dist/modes/rpc/rpc-mode.js +9 -11
  51. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  52. package/docs/compaction.md +2 -0
  53. package/docs/extensions.md +30 -1
  54. package/docs/rpc.md +40 -3
  55. package/docs/tmux.md +39 -0
  56. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  57. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  58. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  59. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  60. package/examples/extensions/overlay-qa-tests.ts +468 -1
  61. package/examples/extensions/provider-payload.ts +14 -0
  62. package/examples/extensions/with-deps/index.ts +1 -5
  63. package/examples/extensions/with-deps/package-lock.json +2 -2
  64. package/examples/extensions/with-deps/package.json +1 -1
  65. package/package.json +4 -4
@@ -14,10 +14,13 @@
14
14
  * /overlay-maxheight - Test maxHeight truncation
15
15
  * /overlay-sidepanel - Responsive sidepanel (hides when terminal < 100 cols)
16
16
  * /overlay-toggle - Toggle visibility demo (demonstrates OverlayHandle.setHidden)
17
+ * /overlay-passive - Non-capturing overlay demo (passive info panel alongside active overlay)
18
+ * /overlay-focus - Focus cycling and rendering order with non-capturing overlays
19
+ * /overlay-streaming - Multiple input panels with simulated streaming (Tab to cycle focus)
17
20
  */
18
21
 
19
22
  import type { ExtensionAPI, ExtensionCommandContext, Theme } from "@mariozechner/pi-coding-agent";
20
- import type { OverlayAnchor, OverlayHandle, OverlayOptions, TUI } from "@mariozechner/pi-tui";
23
+ import type { Component, OverlayAnchor, OverlayHandle, OverlayOptions, TUI } from "@mariozechner/pi-tui";
21
24
  import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
22
25
  import { spawn } from "child_process";
23
26
 
@@ -256,6 +259,42 @@ export default function (pi: ExtensionAPI) {
256
259
  globalToggleHandle = null;
257
260
  },
258
261
  });
262
+
263
+ // Non-capturing overlay demo - passive info panel that doesn't steal focus
264
+ pi.registerCommand("overlay-passive", {
265
+ description: "Test non-capturing overlay (passive info panel alongside active overlay)",
266
+ handler: async (_args: string, ctx: ExtensionCommandContext) => {
267
+ ctx.ui.setEditorText("");
268
+ await ctx.ui.custom<void>((tui, theme, _kb, done) => new PassiveDemoController(tui, theme, done), {
269
+ overlay: true,
270
+ overlayOptions: { anchor: "center", width: 48 },
271
+ });
272
+ },
273
+ });
274
+
275
+ // Focus cycling demo - demonstrates focus(), unfocus(), isFocused() and rendering order
276
+ pi.registerCommand("overlay-focus", {
277
+ description: "Test focus cycling and rendering order with non-capturing overlays",
278
+ handler: async (_args: string, ctx: ExtensionCommandContext) => {
279
+ ctx.ui.setEditorText("");
280
+ await ctx.ui.custom<void>((tui, theme, _kb, done) => new FocusDemoController(tui, theme, done), {
281
+ overlay: true,
282
+ overlayOptions: { anchor: "bottom-center", width: 55, margin: { bottom: 1 } },
283
+ });
284
+ },
285
+ });
286
+
287
+ // Test multiple input panels with simulated streaming
288
+ pi.registerCommand("overlay-streaming", {
289
+ description: "Multiple input panels with simulated streaming (Tab to cycle focus)",
290
+ handler: async (_args: string, ctx: ExtensionCommandContext) => {
291
+ ctx.ui.setEditorText("");
292
+ await ctx.ui.custom<void>((tui, theme, _kb, done) => new StreamingInputController(tui, theme, done), {
293
+ overlay: true,
294
+ overlayOptions: { anchor: "bottom-center", width: 60, margin: { bottom: 1 } },
295
+ });
296
+ },
297
+ });
259
298
  }
260
299
 
261
300
  function sleep(ms: number): Promise<void> {
@@ -879,3 +918,431 @@ class ToggleDemoComponent extends BaseOverlay {
879
918
  );
880
919
  }
881
920
  }
921
+
922
+ // === Non-capturing passive overlay demo ===
923
+
924
+ class PassiveDemoController extends BaseOverlay {
925
+ focused = false;
926
+ private typed = "";
927
+ private timerComponent: TimerPanel;
928
+ private timerHandle: OverlayHandle | null = null;
929
+ private interval: ReturnType<typeof setInterval> | null = null;
930
+ private inputCount = 0;
931
+ private lastInputDebug = "";
932
+
933
+ constructor(
934
+ private tui: TUI,
935
+ theme: Theme,
936
+ private done: () => void,
937
+ ) {
938
+ super(theme);
939
+ this.timerComponent = new TimerPanel(theme);
940
+ this.timerHandle = this.tui.showOverlay(this.timerComponent, {
941
+ nonCapturing: true,
942
+ anchor: "top-right",
943
+ width: 22,
944
+ margin: { top: 1, right: 2 },
945
+ });
946
+ this.interval = setInterval(() => {
947
+ this.timerComponent.tick();
948
+ this.tui.requestRender();
949
+ }, 1000);
950
+ }
951
+
952
+ handleInput(data: string): void {
953
+ this.inputCount++;
954
+ this.lastInputDebug = `len=${data.length} c0=${data.charCodeAt(0)}`;
955
+ if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
956
+ this.cleanup();
957
+ this.done();
958
+ } else if (matchesKey(data, "backspace")) {
959
+ this.typed = this.typed.slice(0, -1);
960
+ } else if (data.length === 1 && data.charCodeAt(0) >= 32) {
961
+ this.typed += data;
962
+ }
963
+ }
964
+
965
+ render(width: number): string[] {
966
+ const th = this.theme;
967
+ const display = this.typed.length > 0 ? this.typed : th.fg("dim", "(type here)");
968
+ return this.box(
969
+ [
970
+ "",
971
+ ` ${th.fg("dim", `focused=${this.focused} inputs=${this.inputCount}`)}`,
972
+ ` ${th.fg("dim", `last: ${this.lastInputDebug || "none"}`)}`,
973
+ "",
974
+ ` > ${display}`,
975
+ "",
976
+ th.fg("dim", " Type to prove input goes here."),
977
+ th.fg("dim", " Press Esc to close both."),
978
+ "",
979
+ ],
980
+ width,
981
+ "Non-Capturing Demo",
982
+ );
983
+ }
984
+
985
+ private cleanup(): void {
986
+ if (this.interval) {
987
+ clearInterval(this.interval);
988
+ this.interval = null;
989
+ }
990
+ this.timerHandle?.hide();
991
+ this.timerHandle = null;
992
+ }
993
+
994
+ override dispose(): void {
995
+ this.cleanup();
996
+ }
997
+ }
998
+
999
+ class TimerPanel extends BaseOverlay {
1000
+ private seconds = 0;
1001
+
1002
+ tick(): void {
1003
+ this.seconds++;
1004
+ }
1005
+
1006
+ render(width: number): string[] {
1007
+ const th = this.theme;
1008
+ const mins = Math.floor(this.seconds / 60);
1009
+ const secs = this.seconds % 60;
1010
+ const time = `${String(mins).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
1011
+ return this.box([` ${th.fg("accent", time)}`, th.fg("dim", " nonCapturing: true")], width, "Timer");
1012
+ }
1013
+ }
1014
+
1015
+ // === Focus cycling demo ===
1016
+
1017
+ class FocusDemoController extends BaseOverlay {
1018
+ private panels: FocusPanel[] = [];
1019
+ private handles: OverlayHandle[] = [];
1020
+ private focusIndex = -1;
1021
+
1022
+ constructor(
1023
+ private tui: TUI,
1024
+ theme: Theme,
1025
+ private done: () => void,
1026
+ ) {
1027
+ super(theme);
1028
+ const colors = ["error", "success", "accent"] as const;
1029
+ const labels = ["Alpha", "Beta", "Gamma"];
1030
+
1031
+ for (let i = 0; i < 3; i++) {
1032
+ const panel = new FocusPanel(
1033
+ theme,
1034
+ labels[i]!,
1035
+ colors[i]!,
1036
+ () => this.cycleFocus(),
1037
+ () => this.close(),
1038
+ );
1039
+ const handle = this.tui.showOverlay(panel, {
1040
+ nonCapturing: true,
1041
+ row: 2,
1042
+ col: 5 + i * 6,
1043
+ width: 28,
1044
+ });
1045
+ panel.handle = handle;
1046
+ this.panels.push(panel);
1047
+ this.handles.push(handle);
1048
+ }
1049
+ }
1050
+
1051
+ private cycleFocus(): void {
1052
+ if (this.focusIndex >= 0 && this.focusIndex < this.handles.length) {
1053
+ this.handles[this.focusIndex]!.unfocus();
1054
+ }
1055
+ this.focusIndex++;
1056
+ if (this.focusIndex >= this.handles.length) {
1057
+ this.focusIndex = -1;
1058
+ } else {
1059
+ this.handles[this.focusIndex]!.focus();
1060
+ }
1061
+ this.tui.requestRender();
1062
+ }
1063
+
1064
+ private close(): void {
1065
+ for (const handle of this.handles) handle.hide();
1066
+ this.handles = [];
1067
+ this.panels = [];
1068
+ this.done();
1069
+ }
1070
+
1071
+ handleInput(data: string): void {
1072
+ if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
1073
+ this.close();
1074
+ } else if (matchesKey(data, "tab")) {
1075
+ this.cycleFocus();
1076
+ }
1077
+ }
1078
+
1079
+ render(width: number): string[] {
1080
+ const th = this.theme;
1081
+ const focused = this.focusIndex === -1 ? "Controller" : (this.panels[this.focusIndex]?.label ?? "?");
1082
+ return this.box(
1083
+ [
1084
+ "",
1085
+ ` Current focus: ${th.fg("accent", focused)}`,
1086
+ "",
1087
+ " Three overlapping panels above are",
1088
+ ` all ${th.fg("accent", "nonCapturing")}. Press Tab to`,
1089
+ " cycle focus() between them.",
1090
+ "",
1091
+ " Focused panel renders on top",
1092
+ " (focus-based rendering order).",
1093
+ "",
1094
+ th.fg("dim", " Tab = cycle focus | Esc = close"),
1095
+ "",
1096
+ ],
1097
+ width,
1098
+ "Focus Demo",
1099
+ );
1100
+ }
1101
+
1102
+ override dispose(): void {
1103
+ for (const handle of this.handles) handle.hide();
1104
+ }
1105
+ }
1106
+
1107
+ class FocusPanel extends BaseOverlay {
1108
+ handle: OverlayHandle | null = null;
1109
+ readonly label: string;
1110
+
1111
+ constructor(
1112
+ theme: Theme,
1113
+ label: string,
1114
+ private color: "error" | "success" | "accent",
1115
+ private onTab: () => void,
1116
+ private onClose: () => void,
1117
+ ) {
1118
+ super(theme);
1119
+ this.label = label;
1120
+ }
1121
+
1122
+ handleInput(data: string): void {
1123
+ if (matchesKey(data, "tab")) {
1124
+ this.onTab();
1125
+ } else if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
1126
+ this.onClose();
1127
+ }
1128
+ }
1129
+
1130
+ render(width: number): string[] {
1131
+ const th = this.theme;
1132
+ const focused = this.handle?.isFocused() ?? false;
1133
+ const innerW = Math.max(1, width - 2);
1134
+ const border = (c: string) => th.fg(this.color, c);
1135
+ const padLine = (s: string) => truncateToWidth(s, innerW, "...", true);
1136
+ const lines: string[] = [];
1137
+
1138
+ lines.push(border(`╭${"─".repeat(innerW)}╮`));
1139
+ lines.push(border("│") + padLine(` ${th.fg("accent", this.label)}`) + border("│"));
1140
+ lines.push(border("│") + padLine("") + border("│"));
1141
+ if (focused) {
1142
+ lines.push(border("│") + padLine(th.fg("success", " ● FOCUSED")) + border("│"));
1143
+ lines.push(border("│") + padLine(th.fg("dim", " (receiving input)")) + border("│"));
1144
+ } else {
1145
+ lines.push(border("│") + padLine(th.fg("dim", " ○ unfocused")) + border("│"));
1146
+ lines.push(border("│") + padLine(th.fg("dim", " (passive)")) + border("│"));
1147
+ }
1148
+ lines.push(border("│") + padLine("") + border("│"));
1149
+ lines.push(border(`╰${"─".repeat(innerW)}╯`));
1150
+
1151
+ return lines;
1152
+ }
1153
+ }
1154
+
1155
+ // === Streaming input panel test (/overlay-streaming) ===
1156
+
1157
+ class StreamingInputController extends BaseOverlay {
1158
+ private panels: StreamingInputPanel[] = [];
1159
+ private handles: OverlayHandle[] = [];
1160
+ private focusIndex = -1; // -1 = controller focused, 0-2 = panel focused
1161
+ private streamLines: string[] = [];
1162
+ private streamInterval: ReturnType<typeof setInterval> | null = null;
1163
+ private lineCount = 0;
1164
+
1165
+ constructor(
1166
+ private tui: TUI,
1167
+ theme: Theme,
1168
+ private done: () => void,
1169
+ ) {
1170
+ super(theme);
1171
+
1172
+ // Create 3 input panels as non-capturing overlays
1173
+ const colors = ["error", "success", "accent"] as const;
1174
+ const labels = ["Panel A", "Panel B", "Panel C"];
1175
+
1176
+ for (let i = 0; i < 3; i++) {
1177
+ const panel = new StreamingInputPanel(
1178
+ theme,
1179
+ labels[i]!,
1180
+ colors[i]!,
1181
+ () => this.cycleFocus(),
1182
+ () => this.close(),
1183
+ );
1184
+ const handle = this.tui.showOverlay(panel, {
1185
+ nonCapturing: true,
1186
+ row: 1 + i * 9,
1187
+ col: 2,
1188
+ width: 35,
1189
+ });
1190
+ panel.handle = handle;
1191
+ this.panels.push(panel);
1192
+ this.handles.push(handle);
1193
+ }
1194
+
1195
+ // Start with controller focused (focusIndex = -1)
1196
+
1197
+ // Start simulated streaming
1198
+ this.streamInterval = setInterval(() => {
1199
+ this.lineCount++;
1200
+ const timestamp = new Date().toLocaleTimeString();
1201
+ this.streamLines.push(`[${timestamp}] Streaming line ${this.lineCount}...`);
1202
+ if (this.streamLines.length > 8) {
1203
+ this.streamLines.shift();
1204
+ }
1205
+ this.tui.requestRender();
1206
+ }, 500);
1207
+ }
1208
+
1209
+ private cycleFocus(): void {
1210
+ // Unfocus current panel if any
1211
+ if (this.focusIndex >= 0 && this.focusIndex < this.handles.length) {
1212
+ this.handles[this.focusIndex]!.unfocus();
1213
+ }
1214
+
1215
+ // Cycle: -1 (controller) → 0 → 1 → 2 → -1 ...
1216
+ this.focusIndex++;
1217
+ if (this.focusIndex >= this.handles.length) {
1218
+ this.focusIndex = -1; // Back to controller
1219
+ }
1220
+
1221
+ // Focus new panel if any
1222
+ if (this.focusIndex >= 0) {
1223
+ this.handles[this.focusIndex]!.focus();
1224
+ }
1225
+
1226
+ this.tui.requestRender();
1227
+ }
1228
+
1229
+ private close(): void {
1230
+ if (this.streamInterval) {
1231
+ clearInterval(this.streamInterval);
1232
+ this.streamInterval = null;
1233
+ }
1234
+ for (const handle of this.handles) handle.hide();
1235
+ this.handles = [];
1236
+ this.panels = [];
1237
+ this.done();
1238
+ }
1239
+
1240
+ handleInput(data: string): void {
1241
+ if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
1242
+ this.close();
1243
+ } else if (matchesKey(data, "tab")) {
1244
+ this.cycleFocus();
1245
+ }
1246
+ }
1247
+
1248
+ render(width: number): string[] {
1249
+ const th = this.theme;
1250
+ const focusedLabel =
1251
+ this.focusIndex === -1
1252
+ ? th.fg("success", "Controller (this panel)")
1253
+ : (this.panels[this.focusIndex]?.label ?? "?");
1254
+
1255
+ const lines = [
1256
+ "",
1257
+ ` Current focus: ${th.fg("accent", focusedLabel)}`,
1258
+ "",
1259
+ " Simulated streaming output:",
1260
+ th.fg("dim", " ─".repeat((width - 2) / 2)),
1261
+ ];
1262
+
1263
+ for (const line of this.streamLines) {
1264
+ lines.push(` ${th.fg("dim", line)}`);
1265
+ }
1266
+
1267
+ while (lines.length < 12) {
1268
+ lines.push("");
1269
+ }
1270
+
1271
+ lines.push(th.fg("dim", " ─".repeat((width - 2) / 2)));
1272
+ lines.push("");
1273
+ lines.push(` Three ${th.fg("accent", "nonCapturing")} input panels on the left.`);
1274
+ lines.push(" Tab cycles: Controller → Panel A → B → C → Controller");
1275
+ lines.push(" Type in each panel to test input routing.");
1276
+ lines.push("");
1277
+ lines.push(th.fg("dim", " Tab = cycle focus | Esc = close all"));
1278
+ lines.push("");
1279
+
1280
+ return this.box(lines, width, "Streaming + Input Test");
1281
+ }
1282
+
1283
+ override dispose(): void {
1284
+ this.close();
1285
+ }
1286
+ }
1287
+
1288
+ class StreamingInputPanel implements Component {
1289
+ handle: OverlayHandle | null = null;
1290
+ private typed = "";
1291
+ readonly label: string;
1292
+
1293
+ constructor(
1294
+ private theme: Theme,
1295
+ label: string,
1296
+ private color: "error" | "success" | "accent",
1297
+ private onTab: () => void,
1298
+ private onClose: () => void,
1299
+ ) {
1300
+ this.label = label;
1301
+ }
1302
+
1303
+ handleInput(data: string): void {
1304
+ if (matchesKey(data, "tab")) {
1305
+ this.onTab();
1306
+ } else if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
1307
+ this.onClose();
1308
+ } else if (matchesKey(data, "backspace")) {
1309
+ this.typed = this.typed.slice(0, -1);
1310
+ } else if (data.length === 1 && data.charCodeAt(0) >= 32) {
1311
+ this.typed += data;
1312
+ }
1313
+ }
1314
+
1315
+ render(width: number): string[] {
1316
+ const th = this.theme;
1317
+ const focused = this.handle?.isFocused() ?? false;
1318
+ const innerW = Math.max(1, width - 2);
1319
+ const border = (c: string) => th.fg(this.color, c);
1320
+ const padLine = (s: string) => {
1321
+ const w = visibleWidth(s);
1322
+ return s + " ".repeat(Math.max(0, innerW - w));
1323
+ };
1324
+
1325
+ const inputDisplay = this.typed.length > 0 ? this.typed : th.fg("dim", "(type here)");
1326
+ const truncatedInput = truncateToWidth(` > ${inputDisplay}`, innerW, "...", true);
1327
+
1328
+ const lines: string[] = [];
1329
+ lines.push(border(`╭${"─".repeat(innerW)}╮`));
1330
+ lines.push(border("│") + padLine(` ${th.fg("accent", this.label)}`) + border("│"));
1331
+ lines.push(border("│") + padLine("") + border("│"));
1332
+ if (focused) {
1333
+ lines.push(border("│") + padLine(th.fg("success", " ● FOCUSED")) + border("│"));
1334
+ lines.push(border("│") + padLine(th.fg("dim", " (receiving input)")) + border("│"));
1335
+ } else {
1336
+ lines.push(border("│") + padLine(th.fg("dim", " ○ unfocused")) + border("│"));
1337
+ lines.push(border("│") + padLine("") + border("│"));
1338
+ }
1339
+ lines.push(border("│") + padLine(truncatedInput) + border("│"));
1340
+ lines.push(border("│") + padLine("") + border("│"));
1341
+ lines.push(border("│") + padLine(th.fg("dim", " Tab | Esc")) + border("│"));
1342
+ lines.push(border(`╰${"─".repeat(innerW)}╯`));
1343
+
1344
+ return lines;
1345
+ }
1346
+
1347
+ invalidate(): void {}
1348
+ }
@@ -0,0 +1,14 @@
1
+ import { appendFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
4
+
5
+ export default function (pi: ExtensionAPI) {
6
+ const logFile = join(process.cwd(), ".pi", "provider-payload.log");
7
+
8
+ pi.on("before_provider_request", (event) => {
9
+ appendFileSync(logFile, `${JSON.stringify(event.payload, null, 2)}\n\n`, "utf8");
10
+
11
+ // Optional: replace the payload instead of only logging it.
12
+ // return { ...event.payload, temperature: 0 };
13
+ });
14
+ }
@@ -21,11 +21,7 @@ export default function (pi: ExtensionAPI) {
21
21
  execute: async (_toolCallId, params) => {
22
22
  const result = ms(params.duration as ms.StringValue);
23
23
  if (result === undefined) {
24
- return {
25
- content: [{ type: "text", text: `Invalid duration: "${params.duration}"` }],
26
- isError: true,
27
- details: {},
28
- };
24
+ throw new Error(`Invalid duration: "${params.duration}"`);
29
25
  }
30
26
  return {
31
27
  content: [{ type: "text", text: `${params.duration} = ${result} milliseconds` }],
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "1.20.2",
3
+ "version": "1.21.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "1.20.2",
9
+ "version": "1.21.0",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "1.20.2",
4
+ "version": "1.21.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mariozechner/pi-coding-agent",
3
- "version": "0.56.2",
3
+ "version": "0.57.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -40,9 +40,9 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@mariozechner/jiti": "^2.6.2",
43
- "@mariozechner/pi-agent-core": "^0.56.2",
44
- "@mariozechner/pi-ai": "^0.56.2",
45
- "@mariozechner/pi-tui": "^0.56.2",
43
+ "@mariozechner/pi-agent-core": "^0.57.0",
44
+ "@mariozechner/pi-ai": "^0.57.0",
45
+ "@mariozechner/pi-tui": "^0.57.0",
46
46
  "@silvia-odwyer/photon-node": "^0.3.4",
47
47
  "chalk": "^5.5.0",
48
48
  "cli-highlight": "^2.1.11",