@oh-my-pi/pi-tui 15.13.3 → 16.0.1

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,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.0.1] - 2026-06-15
6
+
7
+ ### Added
8
+
9
+ - Added Zellij and WezTerm pane environment fallbacks for terminal-specific session continuation when no TTY path is available.
10
+
11
+ ### Fixed
12
+
13
+ - Fixed slash command autocomplete acceptance replacing only a stale rendered prefix, which could leave fast-typed characters before `/skills:` completions and corrupt the submitted command ([#1745](https://github.com/can1357/oh-my-pi/issues/1745)).
14
+
5
15
  ## [15.13.1] - 2026-06-15
6
16
 
7
17
  ### Added
@@ -382,7 +392,7 @@
382
392
 
383
393
  ### Changed
384
394
 
385
- - Changed native-scrollback safety defaults to treat unknown POSIX, SSH, and multiplexer-shaped terminals as ED3-risk for passive rendering; checkpoint replay now requires a positive at-tail viewport proof instead of assuming prompt submit makes host scrollback safe.
395
+ - Changed native-scrollback safety defaults to treat unknown POSIX, SSH, and multiplexer-shaped terminals as ED3-risk for passive rendering; checkpoint replay now requires a positive at-tail viewport proof instead of assuming prompt submit makes host scrollback safe ([#1799](https://github.com/can1357/oh-my-pi/issues/1799)).
386
396
  - Changed synchronized-output defaults to a conservative opt-in profile: DEC 2026 paint wrappers stay disabled for remote/multiplexer/VTE/unknown terminals unless explicitly forced, while the autowrap guards remain active.
387
397
 
388
398
  ### Fixed
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-tui",
4
- "version": "15.13.3",
4
+ "version": "16.0.1",
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,8 +37,8 @@
37
37
  "fmt": "biome format --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@oh-my-pi/pi-natives": "15.13.3",
41
- "@oh-my-pi/pi-utils": "15.13.3",
40
+ "@oh-my-pi/pi-natives": "16.0.1",
41
+ "@oh-my-pi/pi-utils": "16.0.1",
42
42
  "lru-cache": "11.5.1",
43
43
  "marked": "^18.0.5"
44
44
  },
@@ -413,27 +413,39 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
413
413
  prefix: string,
414
414
  ): { lines: string[]; cursorLine: number; cursorCol: number } {
415
415
  const currentLine = lines[cursorLine] || "";
416
- const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
416
+ const textBeforeCursor = currentLine.slice(0, cursorCol);
417
417
  const afterCursor = currentLine.slice(cursorCol);
418
418
 
419
- // Check if we're completing a slash command (prefix starts with "/" but NOT a file path)
420
- // Slash commands are at the start of the line and don't contain path separators after the first /
421
- const isSlashCommand = prefix.startsWith("/") && beforePrefix.trim() === "" && !prefix.slice(1).includes("/");
422
- if (isSlashCommand) {
423
- // This is a command name completion
424
- const newLine = `${beforePrefix}/${item.value} ${afterCursor}`;
425
- const newLines = [...lines];
426
- newLines[cursorLine] = newLine;
419
+ const slashStart = textBeforeCursor.indexOf("/");
420
+ const hasOnlyWhitespaceBeforeSlash = slashStart >= 0 && textBeforeCursor.slice(0, slashStart).trim() === "";
427
421
 
428
- return {
429
- lines: newLines,
430
- cursorLine,
431
- cursorCol: beforePrefix.length + item.value.length + 2, // +2 for "/" and space
432
- };
422
+ // Slash command suggestions can be accepted before the debounced refresh
423
+ // catches up to newly typed characters. Replace the live command token,
424
+ // not only the prefix captured when the suggestion list was rendered.
425
+ if (prefix.startsWith("/") && hasOnlyWhitespaceBeforeSlash) {
426
+ const slashPrefix = textBeforeCursor.slice(slashStart);
427
+ if (!slashPrefix.includes(" ") && !slashPrefix.slice(1).includes("/")) {
428
+ const beforeSlash = currentLine.slice(0, slashStart);
429
+ const newLine = `${beforeSlash}/${item.value} ${afterCursor}`;
430
+ const newLines = [...lines];
431
+ newLines[cursorLine] = newLine;
432
+
433
+ return {
434
+ lines: newLines,
435
+ cursorLine,
436
+ cursorCol: beforeSlash.length + item.value.length + 2, // +2 for "/" and space
437
+ };
438
+ }
433
439
  }
434
440
 
441
+ let beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
442
+
435
443
  // Check if we're completing a file attachment (prefix starts with "@")
436
444
  if (prefix.startsWith("@")) {
445
+ const liveAtPrefix = this.#extractAtPrefix(textBeforeCursor);
446
+ if (liveAtPrefix) {
447
+ beforePrefix = currentLine.slice(0, cursorCol - liveAtPrefix.length);
448
+ }
437
449
  // This is a file attachment completion
438
450
  const newLine = `${beforePrefix + item.value} ${afterCursor}`;
439
451
  const newLines = [...lines];
@@ -446,21 +458,10 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
446
458
  };
447
459
  }
448
460
 
449
- // Check if we're in a slash command context (beforePrefix contains "/command ")
450
- const textBeforeCursor = currentLine.slice(0, cursorCol);
451
- if (textBeforeCursor.includes("/") && textBeforeCursor.includes(" ")) {
452
- // This is likely a command argument completion
453
- const newLine = beforePrefix + item.value + afterCursor;
454
- const newLines = [...lines];
455
- newLines[cursorLine] = newLine;
456
-
457
- return {
458
- lines: newLines,
459
- cursorLine,
460
- cursorCol: beforePrefix.length + item.value.length,
461
- };
462
- }
463
-
461
+ // Slash command argument and plain file path completion both fall through
462
+ // to the path-completion tail below — `beforePrefix` already covers the
463
+ // rendered prefix, which preserves earlier arguments (e.g. accepting
464
+ // `package.json` for `/swarm run pac<Tab>` keeps the `run` token intact).
464
465
  // For file paths, complete the path
465
466
  const newLine = beforePrefix + item.value + afterCursor;
466
467
  const newLines = [...lines];
package/src/ttyid.ts CHANGED
@@ -51,15 +51,29 @@ export function getTerminalId(): string | null {
51
51
 
52
52
  // Fallback to terminal-specific env vars
53
53
  // Prefer inner multiplexers over host terminal emulators when stdin has no TTY path.
54
+ const zellijPane = process.env.ZELLIJ_PANE_ID;
55
+ if (zellijPane) {
56
+ // Session names are user-chosen (`zellij -s …`) and the id is used as a
57
+ // breadcrumb filename — normalize path separators like the TTY branch does.
58
+ const zellijSession = process.env.ZELLIJ_SESSION_NAME?.replace(/[\\/]/g, "-");
59
+ return zellijSession ? `zellij-${zellijSession}-${zellijPane}` : `zellij-${zellijPane}`;
60
+ }
61
+
54
62
  const tmuxPane = process.env.TMUX_PANE;
55
63
  if (tmuxPane) return `tmux-${tmuxPane}`;
56
64
 
57
65
  const cmuxSurface = process.env.CMUX_SURFACE_ID;
58
66
  if (cmuxSurface) return `cmux-${cmuxSurface}`;
59
67
 
68
+ // Kitty before WezTerm/others, matching terminal-capabilities.ts detection
69
+ // order. Inherited env makes either order wrong for some nesting; staying
70
+ // consistent with the capability detector keeps the two answers aligned.
60
71
  const kittyId = process.env.KITTY_WINDOW_ID;
61
72
  if (kittyId) return `kitty-${kittyId}`;
62
73
 
74
+ const weztermPane = process.env.WEZTERM_PANE;
75
+ if (weztermPane) return `wezterm-${weztermPane}`;
76
+
63
77
  const terminalSessionId = process.env.TERM_SESSION_ID; // macOS Terminal.app
64
78
  if (terminalSessionId) return `apple-${terminalSessionId}`;
65
79