@oh-my-pi/pi-tui 17.2.9 → 17.2.10

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
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [17.2.10] - 2026-08-06
6
+
7
+ ### Fixed
8
+
9
+ - Fixed a startup crash (EIO error) in multiplexer or SSH sessions when a revoked pty leaves stdin.isTTY active.
10
+ - Fixed prompt autocomplete to support Windows drive-absolute paths (e.g., C:/ or C:\).
11
+ - Fixed desktop notifications in systemd, tmux, or SSH-attached Linux sessions when DBUS_SESSION_BUS_ADDRESS is unset.
12
+ - Fixed an issue where Shift+letter and shifted symbol inputs (such as capital letters, ?, and !) were silently dropped on Windows and WSL terminals using ConPTY (e.g., WezTerm).
13
+
5
14
  ## [17.2.9] - 2026-08-05
6
15
 
7
16
  ### Fixed
package/README.md CHANGED
@@ -640,7 +640,7 @@ class MyComponent implements Component {
640
640
  - `wrapTextWithAnsi()` preserves ANSI codes while word-wrapping and trimming line ends
641
641
 
642
642
  ```typescript
643
- import chalk from "chalk";
643
+ import chalk from "@oh-my-pi/pi-utils/chalk";
644
644
 
645
645
  const styled = chalk.red("Hello") + " " + chalk.blue("World");
646
646
  const width = visibleWidth(styled); // 11 (not counting ANSI codes)
@@ -7,10 +7,11 @@ export interface DesktopNotifier {
7
7
  }
8
8
  /**
9
9
  * Whether the current process can reach a freedesktop notification daemon:
10
- * Linux platform + a session bus address in env. Caller is still responsible
11
- * for resolving a delivery binary via {@link resolveDesktopNotifier}.
10
+ * Linux platform plus either a session bus address in env or the
11
+ * systemd user-bus socket at `$XDG_RUNTIME_DIR/bus`. Caller is still responsible for
12
+ * resolving a delivery binary via {@link resolveDesktopNotifier}.
12
13
  */
13
- export declare function hasLinuxDesktopSession(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): boolean;
14
+ export declare function hasLinuxDesktopSession(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv, fileExists?: (path: string) => boolean): boolean;
14
15
  /**
15
16
  * Whether `sendNotification` should also dispatch a D-Bus toast for this
16
17
  * terminal. Returns true only when (1) the chosen `notifyProtocol` is BEL,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-tui",
4
- "version": "17.2.9",
4
+ "version": "17.2.10",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -37,13 +37,10 @@
37
37
  "fmt": "biome format --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@oh-my-pi/pi-natives": "17.2.9",
41
- "@oh-my-pi/pi-utils": "17.2.9",
42
- "lru-cache": "11.5.2",
43
- "marked": "^18.0.6"
40
+ "@oh-my-pi/pi-natives": "17.2.10",
41
+ "@oh-my-pi/pi-utils": "17.2.10"
44
42
  },
45
43
  "devDependencies": {
46
- "chalk": "^5.6.2",
47
44
  "ghostty-web": "^0.4.0"
48
45
  },
49
46
  "engines": {
@@ -687,7 +687,9 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
687
687
  pathPrefix.startsWith("/") ||
688
688
  pathPrefix.startsWith("./") ||
689
689
  pathPrefix.startsWith("../") ||
690
- pathPrefix.startsWith("~/")
690
+ pathPrefix.startsWith("~/") ||
691
+ // Windows drive-absolute paths (C:/Users, C:\Users).
692
+ /^[A-Za-z]:[\\/]/.test(pathPrefix)
691
693
  ) {
692
694
  return pathPrefix;
693
695
  }
@@ -1,5 +1,12 @@
1
- import { LRUCache } from "lru-cache/raw";
2
- import { Lexer, Marked, type Token, Tokenizer, type TokenizerAndRendererExtension, type Tokens } from "marked";
1
+ import { LRUCache } from "@oh-my-pi/pi-utils/lru";
2
+ import {
3
+ Lexer,
4
+ Marked,
5
+ type Token,
6
+ Tokenizer,
7
+ type TokenizerAndRendererExtension,
8
+ type Tokens,
9
+ } from "@oh-my-pi/pi-utils/marked";
3
10
  import { latexToBlock } from "../latex-block";
4
11
  import { inlineMathSpanEnd, isBareMathEnvironment, latexToUnicode } from "../latex-to-unicode";
5
12
  import type { SymbolTheme } from "../symbols";
@@ -20,6 +20,8 @@
20
20
  // iTerm2, WezTerm, …) keep working unchanged and the BEL emission still fires
21
21
  // for tmux `monitor-bell`, X11 urgency hints, and audible-bell handlers.
22
22
 
23
+ import * as fs from "node:fs";
24
+ import * as path from "node:path";
23
25
  import { $which } from "@oh-my-pi/pi-utils";
24
26
  import type { TerminalId, TerminalNotification } from "./terminal-capabilities";
25
27
 
@@ -36,15 +38,19 @@ export interface DesktopNotifier {
36
38
 
37
39
  /**
38
40
  * Whether the current process can reach a freedesktop notification daemon:
39
- * Linux platform + a session bus address in env. Caller is still responsible
40
- * for resolving a delivery binary via {@link resolveDesktopNotifier}.
41
+ * Linux platform plus either a session bus address in env or the
42
+ * systemd user-bus socket at `$XDG_RUNTIME_DIR/bus`. Caller is still responsible for
43
+ * resolving a delivery binary via {@link resolveDesktopNotifier}.
41
44
  */
42
45
  export function hasLinuxDesktopSession(
43
46
  platform: NodeJS.Platform = process.platform,
44
47
  env: NodeJS.ProcessEnv = Bun.env,
48
+ fileExists: (path: string) => boolean = fs.existsSync,
45
49
  ): boolean {
46
50
  if (platform !== "linux") return false;
47
- return Boolean(env.DBUS_SESSION_BUS_ADDRESS);
51
+ if (env.DBUS_SESSION_BUS_ADDRESS) return true;
52
+ const runtimeDir = env.XDG_RUNTIME_DIR;
53
+ return Boolean(runtimeDir && fileExists(path.join(runtimeDir, "bus")));
48
54
  }
49
55
 
50
56
  /**
package/src/terminal.ts CHANGED
@@ -717,10 +717,17 @@ export class ProcessTerminal implements Terminal {
717
717
  // stderr-guard in pi-utils (mirrors openai/codex#24459).
718
718
  suppressTerminalStderr();
719
719
 
720
- // Save previous state and enable raw mode
720
+ // A multiplexer or SSH disconnect can leave isTTY true after its pty has
721
+ // been revoked. Raw mode is then impossible, so take the normal terminal
722
+ // disconnect path rather than letting Bun abort startup with EIO.
721
723
  this.#wasRaw = process.stdin.isRaw || false;
722
724
  if (process.stdin.setRawMode) {
723
- process.stdin.setRawMode(true);
725
+ try {
726
+ process.stdin.setRawMode(true);
727
+ } catch (err) {
728
+ this.#markTerminalDisconnected("stdin raw mode setup failed", err);
729
+ return;
730
+ }
724
731
  }
725
732
  process.stdin.setEncoding("utf8");
726
733
  process.stdin.on("end", this.#stdinEndHandler);
@@ -1100,7 +1107,13 @@ export class ProcessTerminal implements Terminal {
1100
1107
  const reportedFlags = parseInt(match[1]!, 10);
1101
1108
  this.#kittyProtocolActive = true;
1102
1109
  setKittyProtocolActive(true);
1103
- if ((reportedFlags & 2) !== 0) {
1110
+ if (isConPTYHosted()) {
1111
+ // ConPTY (native Windows and WSL) drops Shift+letter keypresses
1112
+ // entirely when flag 4 (report alternate keys) is set. Use flag 1
1113
+ // (disambiguate only), preserving flag 2 if already active.
1114
+ this.#kittyEnableSeq = (reportedFlags & 2) !== 0 ? "\x1b[>3u" : "\x1b[>1u";
1115
+ this.#safeWrite(this.#kittyEnableSeq);
1116
+ } else if ((reportedFlags & 2) !== 0) {
1104
1117
  // Preserve event-type reporting already enabled by a parent app.
1105
1118
  // Push level-2 to keep its shortcuts reporting consistently.
1106
1119
  this.#kittyEnableSeq = "\x1b[>7u";