pi-better-openai 0.1.12 → 0.1.14

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 CHANGED
@@ -36,7 +36,7 @@ pi install npm:pi-better-openai
36
36
  Codex pets are an OpenAI Codex app feature, so the floating overlay and pet picker are still controlled by Codex (`Settings → Appearance → Pets` or `/pet`). This extension can also render compatible custom pet spritesheets directly in pi's Better OpenAI footer.
37
37
 
38
38
  ```bash
39
- /pets wake # render the selected pet, or the first ready pet
39
+ /pets wake # render the selected pet, or pick one if none is selected
40
40
  /pets wake <slug> # render a specific ready pet
41
41
  /pets select <slug> # select a ready pet without changing visibility
42
42
  /pets tuck # hide it
package/index.ts CHANGED
@@ -66,7 +66,7 @@ import {
66
66
  listCodexPets,
67
67
  nextAnimationFrameDelayMs,
68
68
  PET_ANIMATION_ROWS,
69
- deleteCodexPetKittyPlacement,
69
+ deleteCodexPetKittyImage,
70
70
  registerOpenAIPets,
71
71
  renderCodexPetFrame,
72
72
  resetCodexPetKittyCache,
@@ -79,7 +79,7 @@ const OPENAI_SETTINGS_COMMAND = "openai-settings";
79
79
  const FLAG = "fast";
80
80
  const PET_RESIZE_FREEZE_MS = 120;
81
81
  const PET_RENDER_CACHE_LIMIT = 48;
82
- const PET_AUTO_VALUE = "first ready pet";
82
+ const PET_EMPTY_VALUE = "not selected";
83
83
  const SERVICE_TIER = "priority";
84
84
  type SettingsPickerItem = {
85
85
  id: string;
@@ -146,15 +146,15 @@ function petSizeCellsForPlacement(placement: PetPlacement, sizeCells: number): n
146
146
 
147
147
  function readyPetPickerValues(pets: CodexPetPackage[]): string[] | undefined {
148
148
  const readyPets = pets.filter((pet) => pet.hasSpritesheet);
149
- return readyPets.length > 0 ? [PET_AUTO_VALUE, ...readyPets.map((pet) => pet.slug)] : undefined;
149
+ return readyPets.length > 0 ? readyPets.map((pet) => pet.slug) : undefined;
150
150
  }
151
151
 
152
152
  function petConfigPickerValue(cfg: ResolvedConfig): string {
153
- return cfg.pets.slug || PET_AUTO_VALUE;
153
+ return cfg.pets.slug || PET_EMPTY_VALUE;
154
154
  }
155
155
 
156
156
  function petSlugFromPickerValue(value: string): string {
157
- return value === PET_AUTO_VALUE ? "" : value;
157
+ return value === PET_EMPTY_VALUE ? "" : value;
158
158
  }
159
159
 
160
160
  function petPickerLookupKey(value: string): string {
@@ -177,9 +177,14 @@ function petPickerDescription(cfg: ResolvedConfig, pets: CodexPetPackage[]): str
177
177
  const readyPets = pets.filter((pet) => pet.hasSpritesheet);
178
178
  if (readyPets.length === 0)
179
179
  return "No ready custom pets found. Use /pets help to create one, then return here.";
180
- const selectedPet = cfg.pets.slug ? findPickerPet(cfg.pets.slug, readyPets) : readyPets[0];
180
+ if (!cfg.pets.slug) {
181
+ const firstPet = readyPets[0];
182
+ const lastPet = readyPets[readyPets.length - 1];
183
+ return `No pet selected. Enter/Space/→ selects ${firstPet.name}; ← selects ${lastPet.name}.`;
184
+ }
185
+ const selectedPet = findPickerPet(cfg.pets.slug, readyPets);
181
186
  const selected = selectedPet
182
- ? `${cfg.pets.slug ? "Selected" : "Auto"}: ${selectedPet.name} (${selectedPet.slug})`
187
+ ? `Selected: ${selectedPet.name} (${selectedPet.slug})`
183
188
  : `Selected: ${cfg.pets.slug}`;
184
189
  return `${selected}. Enter/Space/→ cycles pets; ← cycles back. Preview appears in the footer while this menu is open.`;
185
190
  }
@@ -462,7 +467,7 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
462
467
  function takePetKittyCleanupSequence(): string {
463
468
  if (pendingPetKittyCleanupImageIds.size === 0) return "";
464
469
  const sequence = Array.from(pendingPetKittyCleanupImageIds)
465
- .map((imageId) => deleteCodexPetKittyPlacement(imageId))
470
+ .map((imageId) => deleteCodexPetKittyImage(imageId))
466
471
  .join("");
467
472
  pendingPetKittyCleanupImageIds.clear();
468
473
  return sequence;
@@ -885,7 +890,7 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
885
890
  `Image enabled: ${cfg.image.enabled}`,
886
891
  `Image default save: ${cfg.image.defaultSave}`,
887
892
  `Pet enabled: ${cfg.pets.enabled}`,
888
- `Pet slug: ${cfg.pets.slug || "first ready pet"}`,
893
+ `Pet slug: ${cfg.pets.slug || PET_EMPTY_VALUE}`,
889
894
  `Pet placement: ${cfg.pets.placement}`,
890
895
  `Pet failed tool state: ${cfg.pets.failedToolState}`,
891
896
  `Pet idle emotes: ${cfg.pets.idleEmotes} (${cfg.pets.idleEmoteIntervalMs}ms)`,
@@ -1477,7 +1482,7 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
1477
1482
 
1478
1483
  const next = writePetConfig(ctx, {
1479
1484
  enabled: true,
1480
- ...(slug ? { slug: selectedPet.slug } : {}),
1485
+ slug: selectedPet.slug,
1481
1486
  });
1482
1487
  updateFooter(ctx);
1483
1488
  await refreshPet(ctx, next, true);
@@ -1957,7 +1962,7 @@ export const _test = {
1957
1962
  readRawConfig,
1958
1963
  supportsFast,
1959
1964
  combineInlinePetFooter,
1960
- PET_AUTO_VALUE,
1965
+ PET_EMPTY_VALUE,
1961
1966
  readyPetPickerValues,
1962
1967
  petConfigPickerValue,
1963
1968
  petSlugFromPickerValue,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-openai",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Personal pi extension that improves OpenAI with fast mode, usage stats, and footer polish.",
5
5
  "keywords": [
6
6
  "fast",
package/src/pets.ts CHANGED
@@ -415,6 +415,10 @@ export function deleteCodexPetKittyPlacement(imageId: number): string {
415
415
  return `\x1b_Ga=d,d=i,i=${imageId},p=1,q=2\x1b\\`;
416
416
  }
417
417
 
418
+ export function deleteCodexPetKittyImage(imageId: number): string {
419
+ return `\x1b_Ga=d,d=I,i=${imageId},q=2\x1b\\`;
420
+ }
421
+
418
422
  function placeKittyImage(imageId: number, columns: number, rows: number): string {
419
423
  return `\x1b_Ga=p,i=${imageId},p=1,c=${columns},r=${rows},q=2,C=1\x1b\\`;
420
424
  }
@@ -467,7 +471,12 @@ function renderKittyPetFrame(
467
471
  const upload = frame.kittyUploaded ? "" : encodeKittyRawRgba(frame, frameImageId);
468
472
  frame.kittyUploaded = true;
469
473
  previousKittyFrameByPlacement.set(options.imageId, frameImageId);
470
- const sequence = `${deletePrevious}${deleteCurrent}${upload}${placeKittyImage(frameImageId, columns, rows)}`;
474
+ // Recent pi-tui versions automatically free Kitty image IDs they own on changed lines.
475
+ // Pet frames are managed here and intentionally reused across animation loops, so keep
476
+ // the first Kitty command pointed at a harmless footer-placement ID, not a frame ID.
477
+ const hostCleanupSentinel =
478
+ frameImageId !== options.imageId ? deleteCodexPetKittyPlacement(options.imageId) : "";
479
+ const sequence = `${hostCleanupSentinel}${deletePrevious}${deleteCurrent}${upload}${placeKittyImage(frameImageId, columns, rows)}`;
471
480
  const lines: string[] = [];
472
481
  for (let i = 0; i < rows - 1; i++) lines.push("");
473
482
  const moveUp = rows > 1 ? `\x1b[${rows - 1}A` : "";