mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-21 16:02:20 +00:00
docs(changelog): write up ten fixes that shipped without an entry
This branch carries 114 user-visible fix commits and had added six changelog bullets. Recent releases run between a third and nearly all of their fixes — 26.8.3 wrote up 85 of 251, 26.8.2 wrote up 71 of 74 — so five percent is well under what this project does, and the ones missing are not small. Ten of the largest, in the order someone would care about them: a `kill -9` leaving the server unable to start again and no way to find out why; SIGTERM armed too late to save any pane's screen, so a shutdown or a logout cost every one of them up to thirty seconds; an SFTP download renaming over a file it did not pick, and a dangling symlink reading as a free name; a failed update deleting the only backup and leaving nothing at the install path; `--cwd` naming a directory that does not exist and running the command somewhere else with exit 0; a probe timeout disabling shell integration for a whole host for the life of the daemon; a signalled command reported to agents as an honest exit 1; a refused split leaving a shell nothing holds; a window reshape leaving its old shells running; and three secret-carrying types still reaching the log. No code changes. More to follow — the rest of the list is longer than one sitting.
This commit is contained in:
@@ -153,6 +153,100 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`kill -9` on the server no longer leaves it unable to start again.** A
|
||||
Unix endpoint is a socket *file*; killed uncleanly, the daemon leaves it on
|
||||
disk and `bind` on a path that already exists fails rather than replacing
|
||||
it. Starting again reported only that the server "did not open its endpoints
|
||||
within 10s", with the real reason — `Address already in use` — visible only
|
||||
by running it by hand, and the way out was deleting a file from a temp
|
||||
directory nothing named. The startup path already knew how to probe a stale
|
||||
endpoint and unlink it; it skipped that whenever the recorded daemon was
|
||||
gone, which is exactly the case a SIGKILL, an OOM kill or a lost machine
|
||||
leaves behind.
|
||||
|
||||
- **SIGTERM no longer costs every pane up to 30 seconds of screen.** The
|
||||
daemon blocks SIGTERM and waits for it on a dedicated thread so it can write
|
||||
every pane's scrollback one last time on the way out. It armed that too
|
||||
late: `pthread_sigmask` blocks a signal on the *calling* thread only, and by
|
||||
then other threads were already serving with SIGTERM unblocked, so the
|
||||
kernel could deliver it to one of them and end the process on the spot —
|
||||
no final write, nothing logged. A machine shutting down, a logout, a
|
||||
supervisor stopping the daemon or a plain `kill` all took that path.
|
||||
|
||||
- **A finished SFTP download no longer replaces a file it did not pick.** The
|
||||
panel chooses a free name, downloads to a sibling temp file, then renames
|
||||
onto it — and `rename` replaces whatever it lands on silently. The gap
|
||||
between choosing the name and arriving at it is the whole transfer, and
|
||||
`~/Downloads` is a directory browsers and other tools write to as well. The
|
||||
rename is now refused if anything is sitting there, which costs a retry and
|
||||
numbers the copy the way a second download already does. It asks
|
||||
`symlink_metadata` rather than `metadata`, so a dangling symlink does not
|
||||
read as a free name and get destroyed.
|
||||
|
||||
- **A failed update no longer takes the backup with it.** Replacing the app
|
||||
moves the current bundle into the staging directory and renames the
|
||||
replacement into its place; between those two lines there is no app at all
|
||||
and the copy in the stage is the only one. If the second rename failed the
|
||||
restore was attempted with its result discarded and the stage deleted
|
||||
regardless — so a restore that also failed left nothing at the install path,
|
||||
no backup, and an error naming only the swap. That is a reinstall. The
|
||||
launch-failure path ten lines below already handled this correctly; both
|
||||
arms now agree.
|
||||
|
||||
- **`--cwd` naming a directory that does not exist no longer runs the command
|
||||
somewhere else.** `tty7 run --cwd /nonexistent -- pwd` exited 0 from
|
||||
wherever the CLI happened to be started, so `--cwd ~/porj -- make` built the
|
||||
wrong tree and reported success — and the caller most likely to mistype a
|
||||
path is a script, which has nothing to notice by. Falling back to a
|
||||
directory that resolves is right for a cwd inherited from a shell's OSC 7
|
||||
and wrong for one typed as an instruction. `tty7 new <path>` did the same,
|
||||
rooting the workspace in the CLI's directory and handing back an id as if it
|
||||
had not. Both now refuse before anything is spawned or created, and tell
|
||||
"no such directory" apart from "not a directory".
|
||||
|
||||
- **A slow moment on the first connection no longer disables shell
|
||||
integration for a whole host.** The probe that asks a remote which shell it
|
||||
runs answers "don't know" both for a shell there is no bootstrap for and for
|
||||
a probe that never got asked — the channel would not open, the exec failed,
|
||||
or the five-second read ran out. Either answer was cached process-wide with
|
||||
no expiry and nothing to evict it, so one busy moment on the first pane to a
|
||||
host meant no prompt marks, no directory tracking and no command status for
|
||||
that host for the rest of the daemon's life, with no error and no way to
|
||||
clear it short of restarting — reconnecting did not, because the entry
|
||||
outlives the connection.
|
||||
|
||||
- **A command killed by a signal is no longer reported as having chosen to
|
||||
exit 1.** The pty layer builds a signalled child's status as code 1 and
|
||||
keeps the signal itself in a private field, so a `SIGKILL` and an honest
|
||||
`exit 1` were indistinguishable. That reached the CLI as
|
||||
`"exit_code_known": true` — the field the reference describes as how you
|
||||
tell a real 1 from a stand-in — so an agent was told the opposite of the
|
||||
truth.
|
||||
|
||||
- **A refused split no longer leaves a shell running that nothing holds.**
|
||||
`tty7 split` spawned the shell and only then asked the tree to hold it, so
|
||||
any refusal in between left a pane that `pane ls --all` could see and the
|
||||
tree could not, removable only with `pane close --orphans`. `--ratio nan`
|
||||
was the way in: it cannot be serialised onto the control connection at all,
|
||||
so the link dropped mid-request and the daemon's own "a split ratio must be
|
||||
a finite number" never came back — the caller saw "control connection lost"
|
||||
instead, and the pane was already running.
|
||||
|
||||
- **Reshaping a window no longer leaves its old shells running.** Dropping a
|
||||
pane's view is also what detaching does, so every layout rewrite — a delta
|
||||
for a tab the window had built differently, a rebuild from the machine tree
|
||||
— left shells nobody could reach again. A 150-operation fuzz against an open
|
||||
window showed 31 such rewrites to 2 rebuilds. Panes put down this way are
|
||||
now parked rather than ended, and judged once the mirrors agree.
|
||||
|
||||
- **Three more secret-carrying types are redacted in log output.** The
|
||||
codebase had already decided a secret must not reach a formatter, and three
|
||||
types still derived `Debug`: the keychain writes holding the password or
|
||||
passphrase just typed — returned *beside* an `AuthResponse` built from the
|
||||
same string, so the identical secret was redacted in one and printable in
|
||||
the other — and the attachment token whose own documentation says it goes
|
||||
over no wire and onto no disk. The log file is disk too.
|
||||
|
||||
- **A bad tab address now points at the command that lists them.** Handed
|
||||
something like `@deadbeef`, the CLI said "@7 as numbered by `tty7 ls`" —
|
||||
but `tty7 ls` prints workspaces with a tab *count* and no `@` numbers at
|
||||
|
||||
Reference in New Issue
Block a user