pi-extension-utils 0.7.8 → 0.7.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.
@@ -223,8 +223,19 @@ export function paneOverlay(options) {
223
223
  primaryState.cursor = selectableIndex;
224
224
  primaryState.scrollOffset = selectableIndex;
225
225
  };
226
+ let previousPrimaryKeys = [];
226
227
  const computeSelectionFromRows = (primaryRows, bodyHeight) => {
227
228
  applyInitialSelection(primaryRows);
229
+ // The cursor indexes the previous snapshot. Resolve its stable identity
230
+ // before interpreting that index against refreshed or reordered rows.
231
+ if (options.primary.mode === "cursor" && options.primary.selectionKey) {
232
+ const keys = primaryRows.map((row, index) => isSeparatorRow(row) ? undefined : selectionKeyFor(row, index));
233
+ const previousKey = previousPrimaryKeys[primaryState.cursor];
234
+ const nextIndex = previousKey === undefined ? -1 : keys.indexOf(previousKey);
235
+ if (nextIndex >= 0)
236
+ primaryState.cursor = nextIndex;
237
+ previousPrimaryKeys = keys;
238
+ }
228
239
  const primaryMode = options.primary.mode ?? "scroll";
229
240
  let selectedIndex = 0;
230
241
  if (primaryMode === "cursor") {
@@ -256,17 +256,33 @@ function padToWidth(line, width) {
256
256
  }
257
257
  const SYSTEM_REMINDER_MIN_BODY_WIDTH = 76;
258
258
  const SYSTEM_REMINDER_BODY_WIDTH_RATIO = 0.9;
259
+ /**
260
+ * Bordered transcript box for one reminder message.
261
+ *
262
+ * Content and details are fixed for the component's lifetime, so the laid-out lines depend only on
263
+ * width and theme colors. Lines are cached for the last width because the TUI renders every
264
+ * transcript component on each frame and large reminders are expensive to re-wrap. `invalidate()`
265
+ * drops the cache so theme changes take effect on the next render.
266
+ */
259
267
  class SystemReminderComponent {
260
268
  content;
261
269
  details;
262
270
  theme;
271
+ cache;
263
272
  constructor(content, details, theme) {
264
273
  this.content = content;
265
274
  this.details = details;
266
275
  this.theme = theme;
267
276
  }
268
- invalidate() { }
277
+ invalidate() {
278
+ this.cache = undefined;
279
+ }
269
280
  render(width) {
281
+ if (this.cache?.width !== width)
282
+ this.cache = { width, lines: this.layout(width) };
283
+ return this.cache.lines;
284
+ }
285
+ layout(width) {
270
286
  if (width < 3)
271
287
  return [truncateToWidth("System Reminder", width)];
272
288
  const availableBodyWidth = width - 2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-extension-utils",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "description": "Shared Pi extension utilities for coordinated widgets, fullscreen leases, and logging.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -43,10 +43,10 @@
43
43
  "@earendil-works/pi-tui": "*"
44
44
  },
45
45
  "devDependencies": {
46
- "@earendil-works/pi-agent-core": "^0.84.4",
47
- "@earendil-works/pi-ai": "^0.84.4",
48
- "@earendil-works/pi-coding-agent": "^0.84.4",
49
- "@earendil-works/pi-tui": "^0.84.4",
46
+ "@earendil-works/pi-agent-core": "0.87.1",
47
+ "@earendil-works/pi-ai": "0.87.1",
48
+ "@earendil-works/pi-coding-agent": "0.87.1",
49
+ "@earendil-works/pi-tui": "0.87.1",
50
50
  "@types/node": "^24.0.0",
51
51
  "typescript": "^6.0.3"
52
52
  },