* feat(switcher): flatten the workspace list, add a create form, sync remote listings on connect
The switcher's left column is now one flat most-recently-used list across
all machines, each row carrying its machine and link state; the per-machine
tree, headers, and the Other Machines band are gone. Machine trouble
(install progress, connect errors, parked routes) moves to contextual
banners under the list, and machine verbs move into each row's menu.
Cmd+Shift+N now opens a create form instead of silently swapping the
workspace: a name prefilled with the usual generated codename, and a host
combobox (searchable dropdown) defaulting to this computer. Creating on a
machine with no live link connects first and completes when the link is up.
Connecting to a machine also mirrors its workspace listing into the local
store, so its workspaces survive a restart without a connection. Mirrored
references are marked synced: launch restore skips them, and their clock
follows the machine only until this client opens them.
* fix(switcher): drop a parked create when its machine's connect is called off
Disconnect clears the in-flight connect, so finish_connect never runs and
the PendingCreate outlived the intent behind it: the next successful
connect to that machine would have silently created a workspace nobody
was waiting for anymore.
---------
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
* fix(settings): split Shell Arguments like a shell, quote them on the way back (#551)
The field split on raw whitespace, so `-c "echo hi"` became four argv
fragments with the quotes still attached, and it silently rewrote config
too: `build_shell_inputs` refilled the field with `args.join(" ")`, which
cannot spell an argument containing a space, so a legal
`"args": ["-c", "echo hi"]` in config.json re-committed as three argv on
the next blur without the user typing anything.
Parse with shell-words rules instead and quote each argument on the
refill, so field text and the argv array round-trip losslessly. An
unbalanced quote cannot become argv at all, so commit refuses it and the
row explains why under the input — the proxy field's pattern. The field
description in en/zh/ja now says quoting works.
Program gets the milder half of the same treatment: a bare command that
detection (a PATH probe) never saw is almost always a typo like `pwsh7`
that today only surfaces when a pane fails to open, so the row warns
under the field. It never refuses — the field stays free-text so a shell
detection missed remains reachable — and anything spelled as a path is
taken at its word. The comparison reuses core's `same_shell_program`, so
"known" here means exactly what the new-tab menu dedup means.
shell-words was already in the tree via portable-pty, so the direct pin
adds no new code.
* fix(settings): split Shell Arguments as argv, not as POSIX source
Review pass over the #551 fix. Splitting with `shell-words` bought the
quoting contract at the price of two silent rewrites of its own, both the
same shape as the bug being fixed: a backslash outside quotes is a POSIX
escape, so `--dir C:\Users\me` committed as `C:Usersme` on the platform
where that is how a path is spelled, and `#` opens a comment, so
`--tag #1 --verbose` committed as one argument. The refill was noisier
than claimed too — `shell_words::join` quotes on `=`, `~`, `*`, `?` and
`[`, so an existing `--color=auto` came back as `'--color=auto'`.
Nothing here is a shell: the field is a text spelling of an argv array
that goes to `CommandBuilder` directly. So split and join are now a local
pair sized to exactly that job — quotes group, `\"` and `\\` inside double
quotes escape, everything else is a character — and the direct
`shell-words` pin goes away again. They are exact inverses, which is what
`config.json` needs, and the test walks the round trip over the cases a
space-join cannot spell plus the two above.
Drops the Program nudge. `shells::inventory()` inserts the *configured*
shell into the inventory it returns, so `pwsh7` is in `self.shells` from
the next refresh onward: the warning could only ever flash between the
commit and the refresh landing, and never appeared at all on a later visit
to Settings. Its test passed because it hand-built an inventory that
version of the value could not be in. Making it true needs core to say
which rows were detected rather than configured, and that is a serialized
protocol struct — too much for a nudge the issue itself called the milder
half.
Refusing the arguments no longer drops the Program typed or picked beside
them: the stored argv stays as it was, which is what "this value was not
saved" already told the user, and the shell picker works again while the
arguments field is mid-edit.
---------
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
38 pages under docs/, written against the source rather than the README:
config keys and their clamps from core::config, default keybindings from
ui::keymap, every CLI verb and flag from tty7-cli, agent aliases and
hook/fork/resume support from core::cli_agent, and Settings paths taken
from the actual en-US strings.
docs/features.md and its zh-CN translation are retired — everything in
them now lives in a page of its own, plus the two things they carried
that nothing else did (IME input, the performance notes). README and
README.zh-CN point at docs/ instead.
Screenshots and videos are placeholders for now: docs/images/placeholder.svg
with a caption naming what each shot should be.
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>