pi-cc-extensions 0.5.1 → 0.5.3

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.
@@ -320,6 +320,9 @@ const TOOL_MOUSE_DISABLE = "\x1b[?1006l\x1b[?1000l";
320
320
  let toolMouseTui: any = null;
321
321
  let toolMouseUi: any = null;
322
322
  let toolMouseInputUnsubscribe: (() => void) | null = null;
323
+ let toolMouseInputPatchTui: any = null;
324
+ let toolMouseInputPatchOriginalHandle: ((...args: any[]) => any) | null = null;
325
+ let toolMouseInputPatchWrapper: ((...args: any[]) => any) | null = null;
323
326
 
324
327
  function parseSgrMousePackets(data: string): SgrMousePacket[] | null {
325
328
  const pattern = /\x1b\[<(\d+);(\d+);(\d+)([Mm])/g;
@@ -441,6 +444,55 @@ function toggleToolAtMouseClick(tui: any, packet: SgrMousePacket): boolean {
441
444
  return true;
442
445
  }
443
446
 
447
+ /**
448
+ * pi-zentui consumes left-button presses for text selection. Intercept only a
449
+ * tool-row click at the TUI input boundary, before extension listeners run.
450
+ * Keyboard, wheel, drag, release, and non-tool clicks continue through Pi's
451
+ * original dispatcher, preserving pi-zentui's scroll-to-bottom behavior.
452
+ */
453
+ function patchToolMouseInputCapture(tui: any): void {
454
+ if (toolMouseInputPatchTui === tui) return;
455
+
456
+ restoreToolMouseInputCapture();
457
+ const originalHandle = tui?.handleInput;
458
+ if (typeof originalHandle !== "function") return;
459
+
460
+ const wrapper = function (this: any, ...args: any[]): any {
461
+ const data = args[0];
462
+ if (typeof data === "string") {
463
+ const packets = parseSgrMousePackets(data);
464
+ if (packets) {
465
+ for (const packet of packets) {
466
+ if (isSgrLeftPress(packet) && toggleToolAtMouseClick(this, packet)) return;
467
+ }
468
+ }
469
+ }
470
+ return Reflect.apply(originalHandle, this, args);
471
+ };
472
+
473
+ try {
474
+ tui.handleInput = wrapper;
475
+ } catch {
476
+ return;
477
+ }
478
+ toolMouseInputPatchTui = tui;
479
+ toolMouseInputPatchOriginalHandle = originalHandle;
480
+ toolMouseInputPatchWrapper = wrapper;
481
+ }
482
+
483
+ function restoreToolMouseInputCapture(): void {
484
+ if (
485
+ toolMouseInputPatchTui
486
+ && toolMouseInputPatchOriginalHandle
487
+ && toolMouseInputPatchTui.handleInput === toolMouseInputPatchWrapper
488
+ ) {
489
+ toolMouseInputPatchTui.handleInput = toolMouseInputPatchOriginalHandle;
490
+ }
491
+ toolMouseInputPatchTui = null;
492
+ toolMouseInputPatchOriginalHandle = null;
493
+ toolMouseInputPatchWrapper = null;
494
+ }
495
+
444
496
  function handleToolMouseInput(data: string): { consume: true } | undefined {
445
497
  if (!toolMouseTui) return undefined;
446
498
  const packets = parseSgrMousePackets(data);
@@ -471,6 +523,7 @@ function teardownToolMouseInteraction(): void {
471
523
  } catch {
472
524
  // The UI context may already have been reset during /reload.
473
525
  }
526
+ restoreToolMouseInputCapture();
474
527
  toolMouseTui = null;
475
528
  toolMouseUi = null;
476
529
  }
@@ -483,6 +536,7 @@ function installToolMouseInteraction(ctx: any): void {
483
536
  toolMouseUi = ctx.ui;
484
537
  ctx.ui.setWidget(TOOL_MOUSE_WIDGET_KEY, (tui: any) => {
485
538
  toolMouseTui = tui;
539
+ patchToolMouseInputCapture(tui);
486
540
  tui?.terminal?.write?.(TOOL_MOUSE_ENABLE);
487
541
  // Keep the widget visually empty so Pi's default input bar/layout remains.
488
542
  return { render: () => [], invalidate() {} };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cc-extensions",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Personal extensions for the Pi coding agent",
5
5
  "type": "module",
6
6
  "keywords": [