pi-extended-teams 2.2.8 → 2.2.9
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";
|
|
1
|
+
import { Box, Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";
|
|
2
2
|
import {
|
|
3
3
|
clearGlobalFavoriteModels,
|
|
4
4
|
FAVORITE_MODEL_SLOTS,
|
|
@@ -116,7 +116,7 @@ function padToWidth(value: string, width: number): string {
|
|
|
116
116
|
|
|
117
117
|
function styledTitle(theme: any, label: string, active: boolean): string {
|
|
118
118
|
const title = active ? `▶ ${label}` : ` ${label}`;
|
|
119
|
-
return active ? theme.fg("accent", theme.bold(title)) : theme.fg("muted", title);
|
|
119
|
+
return active ? theme.inverse(theme.fg("accent", theme.bold(title))) : theme.fg("muted", title);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
function defaultTheme(theme: any) {
|
|
@@ -133,12 +133,12 @@ async function loadScopedModels(ctx: any): Promise<AvailableModelOption[]> {
|
|
|
133
133
|
return sortAvailableModels(await getAvailableModels(ctx));
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
async function showFavoriteModelsPicker(ctx: any): Promise<
|
|
136
|
+
async function showFavoriteModelsPicker(ctx: any): Promise<void> {
|
|
137
137
|
const availableModels = await loadScopedModels(ctx);
|
|
138
138
|
const availableSet = new Set(availableModels.map((model) => model.qualified));
|
|
139
|
-
|
|
139
|
+
let draft = cloneFavoriteModels(loadSettings().favoriteModels);
|
|
140
140
|
|
|
141
|
-
return ctx.ui.custom((tui: any, theme: any, _keybindings: any, done: (
|
|
141
|
+
return ctx.ui.custom((tui: any, theme: any, _keybindings: any, done: () => void) => {
|
|
142
142
|
const colors = defaultTheme(theme);
|
|
143
143
|
let selectedSlotIndex = 0;
|
|
144
144
|
let activeColumnIndex = 0;
|
|
@@ -216,11 +216,6 @@ async function showFavoriteModelsPicker(ctx: any): Promise<"saved" | "cancelled"
|
|
|
216
216
|
notice = undefined;
|
|
217
217
|
};
|
|
218
218
|
|
|
219
|
-
const saveAndClose = () => {
|
|
220
|
-
replaceGlobalFavoriteModels(draft);
|
|
221
|
-
done("saved");
|
|
222
|
-
};
|
|
223
|
-
|
|
224
219
|
const moveColumn = (delta: number) => {
|
|
225
220
|
activeColumnIndex = Math.max(0, Math.min(COLUMNS.length - 1, activeColumnIndex + delta));
|
|
226
221
|
};
|
|
@@ -276,35 +271,41 @@ async function showFavoriteModelsPicker(ctx: any): Promise<"saved" | "cancelled"
|
|
|
276
271
|
return levels.map((thinking) => `${thinking === config.thinking ? "›" : " "} ${thinking}`);
|
|
277
272
|
};
|
|
278
273
|
|
|
279
|
-
const columnRows = (title: string, rows: string[],
|
|
280
|
-
return [styledTitle(theme, title, active), ...rows]
|
|
274
|
+
const columnRows = (title: string, rows: string[], active: boolean): string[] => {
|
|
275
|
+
return [styledTitle(theme, title, active), ...rows];
|
|
281
276
|
};
|
|
282
277
|
|
|
283
278
|
const render = (width: number): string[] => {
|
|
284
|
-
const
|
|
279
|
+
const margin = Math.floor(width * 0.1);
|
|
280
|
+
const innerWidth = Math.max(1, width - margin * 2);
|
|
285
281
|
const thinkingWidth = 16;
|
|
286
282
|
const slotWidth = Math.max(28, Math.floor(innerWidth * 0.38));
|
|
287
283
|
const modelWidth = Math.max(28, innerWidth - slotWidth - thinkingWidth - 6);
|
|
288
284
|
const modelRowCount = modelRowsForTerminal();
|
|
289
|
-
const slotRows = columnRows("slots", buildSlotRows(),
|
|
285
|
+
const slotRows = columnRows("slots", buildSlotRows(), activeColumn() === "slots");
|
|
290
286
|
const modelRows = columnRows(
|
|
291
|
-
|
|
287
|
+
"scoped models",
|
|
292
288
|
buildModelRows(modelRowCount),
|
|
293
|
-
modelWidth,
|
|
294
289
|
activeColumn() === "models",
|
|
295
290
|
);
|
|
296
|
-
const thinkingRows = columnRows("thinking", buildThinkingRows(),
|
|
291
|
+
const thinkingRows = columnRows("thinking", buildThinkingRows(), activeColumn() === "thinking");
|
|
297
292
|
const bodyRows = Math.max(slotRows.length, modelRows.length, thinkingRows.length);
|
|
298
293
|
const lines = [
|
|
299
294
|
colors.accent(colors.bold("Agent favorite models")),
|
|
300
295
|
colors.dim(`${availableModels.length} scoped model(s) available from this Pi session · saves to ${globalSettingsPath()}`),
|
|
301
|
-
colors.dim("
|
|
302
|
-
colors.
|
|
296
|
+
colors.dim("←/→: move columns · ↑/↓: change selection · type anywhere to filter model names"),
|
|
297
|
+
colors.success("Changes auto-save · esc/enter: leave · delete: clear slot · ctrl+a: clear all"),
|
|
303
298
|
"",
|
|
304
299
|
];
|
|
305
300
|
|
|
301
|
+
const columns = [slotRows, modelRows, thinkingRows];
|
|
302
|
+
const widths = [slotWidth, modelWidth, thinkingWidth];
|
|
306
303
|
for (let index = 0; index < bodyRows; index += 1) {
|
|
307
|
-
|
|
304
|
+
const cells = columns.map((rows, column) => {
|
|
305
|
+
const cell = padToWidth(rows[index] ?? "", widths[column] - 2);
|
|
306
|
+
return column === activeColumnIndex ? `${colors.accent("▌ ")}${cell}` : ` ${cell}`;
|
|
307
|
+
});
|
|
308
|
+
lines.push(cells.join(" │ "));
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
const config = selectedConfig();
|
|
@@ -316,52 +317,60 @@ async function showFavoriteModelsPicker(ctx: any): Promise<"saved" | "cancelled"
|
|
|
316
317
|
if (config?.model && !availableSet.has(config.model)) {
|
|
317
318
|
lines.push(colors.warning("This saved model is not in the scoped model list for the current session."));
|
|
318
319
|
}
|
|
319
|
-
if (
|
|
320
|
+
if (modelFilter) {
|
|
320
321
|
lines.push(colors.dim(`Filter: ${modelFilter} (backspace clears characters)`));
|
|
321
322
|
}
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
const content = lines.flatMap((line) => wrapTextWithAnsi(line, innerWidth));
|
|
325
|
+
const height = Math.max(1, tui.terminal?.rows ?? 24);
|
|
326
|
+
const top = Math.max(0, Math.floor((height - content.length) / 2));
|
|
327
|
+
return Array.from({ length: height }, (_, index) => `${" ".repeat(margin)}${content[index - top] ?? ""}`);
|
|
324
328
|
};
|
|
325
329
|
|
|
326
330
|
const handleInput = (data: string) => {
|
|
327
|
-
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) {
|
|
328
|
-
done(
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
if (matchesKey(data, Key.enter) || data === "\r" || data === "\n") {
|
|
332
|
-
saveAndClose();
|
|
331
|
+
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.enter) || data === "\r" || data === "\n") {
|
|
332
|
+
done();
|
|
333
333
|
return;
|
|
334
334
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
if (matchesKey(data, Key.right) || data === "l" || data === "L" || matchesKey(data, Key.tab)) {
|
|
335
|
+
const previous = cloneFavoriteModels(draft);
|
|
336
|
+
if (matchesKey(data, Key.right)) {
|
|
340
337
|
moveColumn(1);
|
|
341
|
-
} else if (matchesKey(data, Key.left)
|
|
338
|
+
} else if (matchesKey(data, Key.left)) {
|
|
342
339
|
moveColumn(-1);
|
|
343
|
-
} else if (matchesKey(data, Key.down)
|
|
340
|
+
} else if (matchesKey(data, Key.down)) {
|
|
344
341
|
moveActiveSelection(1);
|
|
345
|
-
} else if (matchesKey(data, Key.up)
|
|
342
|
+
} else if (matchesKey(data, Key.up)) {
|
|
346
343
|
moveActiveSelection(-1);
|
|
347
344
|
} else if (matchesKey(data, Key.delete)) {
|
|
348
345
|
clearSelectedSlot();
|
|
349
346
|
} else if (matchesKey(data, Key.ctrl("a"))) {
|
|
350
347
|
clearAllSlots();
|
|
351
|
-
} else if (
|
|
348
|
+
} else if (matchesKey(data, Key.backspace)) {
|
|
352
349
|
modelFilter = modelFilter.slice(0, -1);
|
|
353
350
|
modelScroll = 0;
|
|
354
|
-
} else if (
|
|
351
|
+
} else if (data.length === 1 && data.charCodeAt(0) >= 32) {
|
|
355
352
|
modelFilter += data;
|
|
356
353
|
modelScroll = 0;
|
|
357
354
|
}
|
|
355
|
+
if (JSON.stringify(draft) !== JSON.stringify(previous)) {
|
|
356
|
+
try {
|
|
357
|
+
replaceGlobalFavoriteModels(draft);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
draft = previous;
|
|
360
|
+
notice = `Could not save changes: ${error instanceof Error ? error.message : String(error)}`;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
358
363
|
tui.requestRender();
|
|
359
364
|
};
|
|
360
365
|
|
|
361
|
-
|
|
366
|
+
// Truncation emits full ANSI resets; repaint the background after each one.
|
|
367
|
+
const box = new Box(0, 0, (text: string) => text.split("\x1b[0m")
|
|
368
|
+
.map(part => theme.bg("toolPendingBg", part)).join("\x1b[0m"));
|
|
369
|
+
box.addChild({ render, invalidate() {} });
|
|
370
|
+
return { render: (width: number) => box.render(width), invalidate: () => box.invalidate(), handleInput };
|
|
362
371
|
}, {
|
|
363
372
|
overlay: true,
|
|
364
|
-
overlayOptions: { width: "
|
|
373
|
+
overlayOptions: { width: "100%", maxHeight: "100%", anchor: "center", margin: 0 },
|
|
365
374
|
});
|
|
366
375
|
}
|
|
367
376
|
|
|
@@ -375,8 +384,7 @@ export function registerFavoriteModelsCommand(pi: any): void {
|
|
|
375
384
|
try {
|
|
376
385
|
if (!action) {
|
|
377
386
|
if (ctx.mode === "tui" && typeof ctx.ui.custom === "function") {
|
|
378
|
-
|
|
379
|
-
if (result === "saved") ctx.ui.notify("Agent favorite models saved.", "info");
|
|
387
|
+
await showFavoriteModelsPicker(ctx);
|
|
380
388
|
return;
|
|
381
389
|
}
|
|
382
390
|
ctx.ui.notify(formatCurrentSettings(), "info");
|