fd2e1d079836553704ea49bd15083faf71dc591f
Clearing out imported sessions was one confirmation dialog per row, which is why it was not worth doing. Holding a row on the import screen now selects it and plain taps add more; Delete and Import act on the whole selection from a bar along the bottom. Submitting hands the work over and puts the screen back as it was: the selection clears, the bar goes, and what says the work is happening is the rows it is happening to -- the one in flight marked with its operation, the rest marked "waiting". Both are inert, so a queued row cannot be tapped into starting a second CLI behind the batch already coming for it. Rows leave as each one lands rather than all at the end, because a finished row still sitting there looks exactly like one that was never imported; the rows below it therefore move, so a row that has just moved ignores taps for half a second. That busy appearance is one composable shared with the session list, which had its own dimmed row and its own word for it. It is a word rather than a bare spinner because deleting and importing differ in kind. Deleting a session can now take the machine's own transcript with it, as a switch in the confirmation and only where the driver keeps a record this app's delete cannot otherwise reach. Off by default, since leaving that copy is what makes an ordinary delete recoverable -- and the paragraph is rewritten rather than appended to when it is on, because the sentence promising the conversation is still there to import again is exactly the one the switch makes false. The server removes the machine's copy first, so a machine it cannot reach leaves the session where it was. `app/ui-sandbox.sh` is how all of this was driven: a second server with its own $HOME, invented transcripts and a two-line `claude`. Against the ordinary server, testing delete deletes somebody's conversation and testing import spends a turn on a real account.
Languages
Rust
54%
Kotlin
43.6%
Shell
2.4%