@esso0428/pi-subagents 0.17.22 → 0.17.23

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/CHANGELOG.md CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.17.23] - 2026-10-02
11
+
12
+ ### Fixed
13
+ - **Stopped the agents roster from stealing keys from open modals**: the widget's focus detection used `focused instanceof Editor`, which is always false when the extension resolves its own copy of `@earendil-works/pi-tui` at a different version than pi's host (for example a hoisted peer pinned to an older release). The check silently degraded to "focused is null", so the widget's global `onTerminalInput` listener claimed the keyboard during teardown and transient render states and consumed `↑`/`↓`/`enter`/`escape` from modals such as the `/agents` menus. Focus detection now identifies the prompt editor structurally and fails closed, so the listener only claims input while the editor provably owns it.
14
+
10
15
  ## [0.17.22] - 2026-10-01
11
16
 
12
17
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esso0428/pi-subagents",
3
- "version": "0.17.22",
3
+ "version": "0.17.23",
4
4
  "description": "A pi extension that brings smart Claude Code-style autonomous sub-agents to pi, with npm:pi-subagents-style JSON agent overrides.",
5
5
  "author": "ESSO0428",
6
6
  "repository": {
@@ -5,7 +5,7 @@
5
5
  * Uses the callback form of setWidget for themed rendering.
6
6
  */
7
7
 
8
- import { Editor, isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
8
+ import { isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
9
9
  import type { AgentManager } from "../agent-manager.js";
10
10
  import { getConfig } from "../agent-types.js";
11
11
  import type { AgentInvocation, AgentRecord, SubagentType, WidgetMode } from "../types.js";
@@ -238,6 +238,24 @@ export function describeActivity(activeTools: Map<string, string>, responseText?
238
238
  return "thinking…";
239
239
  }
240
240
 
241
+ /**
242
+ * Structural check for pi's prompt editor.
243
+ *
244
+ * `instanceof Editor` is unusable here: an extension can resolve its own copy
245
+ * of `@earendil-works/pi-tui` at a different version than the host's, and the
246
+ * two `Editor` class objects are then unrelated identities, so the check is
247
+ * always false. Modals opened with `ctx.ui.custom()` — including the `/agents`
248
+ * menus — focus a plain `{ render, invalidate, handleInput }` object instead,
249
+ * so the editor's text-buffer methods identify it across pi-tui copies.
250
+ */
251
+ function isPromptEditor(component: unknown): boolean {
252
+ if (typeof component !== "object" || component === null) return false;
253
+ const candidate = component as { getText?: unknown; setText?: unknown; submitValue?: unknown };
254
+ return typeof candidate.getText === "function"
255
+ && typeof candidate.setText === "function"
256
+ && typeof candidate.submitValue === "function";
257
+ }
258
+
241
259
  // ---- Widget manager ----
242
260
 
243
261
  export class AgentWidget {
@@ -373,10 +391,17 @@ export class AgentWidget {
373
391
  return [...running, ...queued, ...finished];
374
392
  }
375
393
 
376
- /** True when pi's prompt editor owns the keyboard. */
394
+ /**
395
+ * True when pi's prompt editor owns the keyboard.
396
+ *
397
+ * Deliberately fails closed: an unknown or absent focus target means the
398
+ * widget does not own the keyboard, so its global terminal listener stays out
399
+ * of the way. The previous `focused == null` fallback claimed input during
400
+ * teardown and transient render states, which let roster navigation swallow
401
+ * ↑/↓/enter/escape from an open modal.
402
+ */
377
403
  private editorHasFocus(): boolean {
378
- const focused = (this.tui as { focusedComponent?: unknown } | undefined)?.focusedComponent;
379
- return focused == null || focused instanceof Editor;
404
+ return isPromptEditor((this.tui as { focusedComponent?: unknown } | undefined)?.focusedComponent);
380
405
  }
381
406
 
382
407
  private selectedIndexOf(records: readonly AgentRecord[]): number {