@gajae-code/tui 0.7.9 → 0.7.11
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 +6 -0
- package/package.json +3 -3
- package/src/components/input.ts +2 -1
- package/src/terminal.ts +30 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.7.11] - 2026-07-03
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Kept the terminal stdout error handler armed briefly after TUI shutdown so late `EIO`/closed-PTY errors from SSH or Windows Terminal detach do not crash tmux-backed GJC panes.
|
|
10
|
+
|
|
5
11
|
## [0.7.9] - 2026-07-01
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/tui",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.11",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://gaebal-gajae.dev",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"fmt": "biome format --write ."
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@gajae-code/natives": "0.7.
|
|
42
|
-
"@gajae-code/utils": "0.7.
|
|
41
|
+
"@gajae-code/natives": "0.7.11",
|
|
42
|
+
"@gajae-code/utils": "0.7.11",
|
|
43
43
|
"lru-cache": "11.3.6",
|
|
44
44
|
"marked": "^18.0.3"
|
|
45
45
|
},
|
package/src/components/input.ts
CHANGED
|
@@ -58,7 +58,8 @@ export class Input implements Component, Focusable {
|
|
|
58
58
|
setValue(value: string): void {
|
|
59
59
|
const normalized = value.normalize("NFC");
|
|
60
60
|
this.#value = normalized;
|
|
61
|
-
this.#cursor =
|
|
61
|
+
this.#cursor = normalized.length;
|
|
62
|
+
this.#lastAction = null;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
handleInput(data: string): void {
|
package/src/terminal.ts
CHANGED
|
@@ -167,6 +167,7 @@ export function resolveTerminalRows(
|
|
|
167
167
|
function isWindowsSubsystemForLinux(): boolean {
|
|
168
168
|
return process.platform === "linux" && (!!$env.WSL_DISTRO_NAME || !!$env.WSL_INTEROP);
|
|
169
169
|
}
|
|
170
|
+
const STDOUT_ERROR_HANDLER_GRACE_MS = 250;
|
|
170
171
|
|
|
171
172
|
/**
|
|
172
173
|
* Real terminal using process.stdin/stdout
|
|
@@ -185,6 +186,7 @@ export class ProcessTerminal implements Terminal {
|
|
|
185
186
|
#detachLogPath = $env.PI_TUI_TERMINAL_DETACH_LOG || "";
|
|
186
187
|
#windowsVTInputRestore?: () => void;
|
|
187
188
|
#stdoutErrorHandler?: (err: Error) => void;
|
|
189
|
+
#stdoutErrorHandlerCleanupTimer?: Timer;
|
|
188
190
|
#appearanceCallbacks: Array<(appearance: TerminalAppearance) => void> = [];
|
|
189
191
|
#appearance: TerminalAppearance | undefined;
|
|
190
192
|
#osc11Pending = false;
|
|
@@ -233,10 +235,16 @@ export class ProcessTerminal implements Terminal {
|
|
|
233
235
|
|
|
234
236
|
// Set up resize handler immediately
|
|
235
237
|
process.stdout.on("resize", this.#resizeHandler);
|
|
236
|
-
this.#
|
|
237
|
-
this.#
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
if (this.#stdoutErrorHandlerCleanupTimer) {
|
|
239
|
+
clearTimeout(this.#stdoutErrorHandlerCleanupTimer);
|
|
240
|
+
this.#stdoutErrorHandlerCleanupTimer = undefined;
|
|
241
|
+
}
|
|
242
|
+
if (!this.#stdoutErrorHandler) {
|
|
243
|
+
this.#stdoutErrorHandler = (err: Error) => {
|
|
244
|
+
this.#markUnavailable(err, "stdout-error");
|
|
245
|
+
};
|
|
246
|
+
process.stdout.on("error", this.#stdoutErrorHandler);
|
|
247
|
+
}
|
|
240
248
|
|
|
241
249
|
// Refresh terminal dimensions - they may be stale after suspend/resume
|
|
242
250
|
// (SIGWINCH is lost while process is stopped). Unix only.
|
|
@@ -692,10 +700,7 @@ export class ProcessTerminal implements Terminal {
|
|
|
692
700
|
process.stdout.removeListener("resize", this.#resizeHandler);
|
|
693
701
|
this.#resizeHandler = undefined;
|
|
694
702
|
}
|
|
695
|
-
|
|
696
|
-
process.stdout.removeListener("error", this.#stdoutErrorHandler);
|
|
697
|
-
this.#stdoutErrorHandler = undefined;
|
|
698
|
-
}
|
|
703
|
+
this.#scheduleStdoutErrorHandlerCleanup();
|
|
699
704
|
|
|
700
705
|
// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being
|
|
701
706
|
// re-interpreted after raw mode is disabled. This fixes a race condition
|
|
@@ -708,6 +713,23 @@ export class ProcessTerminal implements Terminal {
|
|
|
708
713
|
}
|
|
709
714
|
}
|
|
710
715
|
|
|
716
|
+
#scheduleStdoutErrorHandlerCleanup(): void {
|
|
717
|
+
if (!this.#stdoutErrorHandler) return;
|
|
718
|
+
if (this.#stdoutErrorHandlerCleanupTimer) clearTimeout(this.#stdoutErrorHandlerCleanupTimer);
|
|
719
|
+
// Terminal restore writes above can fail asynchronously after stop() returns
|
|
720
|
+
// when an SSH/Windows Terminal PTY disappears. Keep the stdout error listener
|
|
721
|
+
// armed briefly so late EIO/EPIPE events mark the terminal unavailable instead
|
|
722
|
+
// of surfacing as uncaught exceptions that kill the tmux pane.
|
|
723
|
+
this.#stdoutErrorHandlerCleanupTimer = setTimeout(() => {
|
|
724
|
+
if (this.#stdoutErrorHandler) {
|
|
725
|
+
process.stdout.removeListener("error", this.#stdoutErrorHandler);
|
|
726
|
+
this.#stdoutErrorHandler = undefined;
|
|
727
|
+
}
|
|
728
|
+
this.#stdoutErrorHandlerCleanupTimer = undefined;
|
|
729
|
+
}, STDOUT_ERROR_HANDLER_GRACE_MS);
|
|
730
|
+
this.#stdoutErrorHandlerCleanupTimer.unref?.();
|
|
731
|
+
}
|
|
732
|
+
|
|
711
733
|
write(data: string): void {
|
|
712
734
|
this.#safeWrite(data);
|
|
713
735
|
if (this.#writeLogPath) {
|