Commit Graph
1403 Commits
Author SHA1 Message Date
l0ng-ai 455e74dc2c feat(scm): filter changed files and show them as a tree (#950)
* feat(scm): filter changed files and show them as a tree

* test(scm): key the tree test's settle on the panel's own root
2026-09-25 13:53:44 +08:00
575d2cd68e fix(agents): drop the previous session id when the foreground agent changes (#957)
同一 pane 里前台从 Claude 换成 omp,或别的 agent 的 hook 写进这个 TTY 时,旧的 session id 会留在新 agent 上,Fork 就会拿错 id。

Co-authored-by: stevelliu <stevelliu@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 13:52:36 +08:00
l0ng-ai 3a52e34b02 fix(linux): wrap the confirmation dialog's text instead of clipping it (#948)
Linux has no native prompt, so every window.prompt fell through to gpui's
fallback renderer, which sets the message and the detail as unbreakable
single lines in a fixed-width box with overflow hidden. The quit-and-stop
warning was cut off mid-sentence. Install a prompt builder on platforms
without a native dialog that lays the same prompt out as a card whose text
wraps, in the app's own surfaces, with Return taking answer 0 and Escape
the cancel answer.

Claude-Session: https://claude.ai/code/session_01JRqYZ9E153WpSHGS2AW3BM
2026-09-25 13:50:39 +08:00
l0ng-ai f852629ba1 fix(procinfo): read proc_listallpids' answer as a pid count, not bytes (#947)
libproc's proc_listallpids takes its buffer size in bytes but answers
with the number of pids, and the macOS process table read that number
as bytes twice: once sizing the buffer (count / 4 + 64 slots) and once
reading back how much was filled (count / 4 again). On a Mac with ~700
processes only the first ~60 pids reached the table.

The kernel lists its newest processes first, so what survived was
whatever started most recently. A `go run` server launched a moment ago
was in; the pane's shell, started long before, usually was not, and a
walk from a root missing from the table returns nothing: no processes,
no ports, and a probe state of Ok. A freshly built parent/child chain,
which is what a quick check of the probe builds, is exactly the case
that happened to work.

The listing now goes through list_all_pids, which takes the call as a
closure so the size arithmetic is tested off a Mac against an emulation
of libproc's convention.

Claude-Session: https://claude.ai/code/session_01JRqYZ9E153WpSHGS2AW3BM
2026-09-25 13:49:28 +08:00
l0ng-ai 458c923aaa docs: lead with the tour video instead of the old hero screenshot
The README now opens on an animated WebP of the one-minute tour (GitHub
won't play an mp4 inline), linking the full-quality mp4. The docs home
page autoplays the mp4 in the hero slot. The old hero screenshot and the
separate tour poster block are gone.
2026-09-24 08:28:23 +08:00
l0ng-ai 33aa52ca90 style: rustfmt the right panel's tab row height 2026-09-24 08:26:31 +08:00
l0ng-ai fed4aec170 docs: replace placeholder screenshots and add a one-minute tour video
Every placeholder frame in docs/ now shows a real capture of the current
build: 20 screenshots plus two short looping clips (prompt editor, pane
drag). The README and the docs home page link a one-minute tour covering
agent status across repos, one agent driving another through the CLI,
the prompt editor, diffs, pane dragging, and sessions surviving a quit.
2026-09-24 08:18:14 +08:00
l0ng-ai 1ca7268919 feat(ui): blink a working agent's status dot
A working agent's dot now alternates every 600ms between its colour and
a paler, still opaque, blend of it over the dot's ring, so a column of
tabs shows at a glance which agents are still going.

It rides the existing half-second home-cursor tick rather than an
animation: two repaints a second while some tab has a working agent,
and none once no agent is working (the dot settles back on its full
colour with one last frame).
2026-09-23 22:33:23 +08:00
l0ng-ai 90327861c1 fix(panel): shorten the right panel's tab row below the title bar
On Windows and Linux the tabs sit under a full-width title bar, and a
second 40px band left them well down from the window's top. The row is
now the tab's hover pill plus 2px either side.
2026-09-23 22:20:53 +08:00
l0ng-ai 58d69e0fad fix(search): keep the find bar's frame neutral while focused
An accent border over the bar's drop shadow read as a glow; the caret
already says where focus is. A regex error still turns it red.
2026-09-23 22:20:53 +08:00
l0ng-ai c2d4e7f2c8 feat(settings): open settings in a window of its own
Settings used to cover the workspace it was opened from, hiding the
terminal a setting was being tried on. It now opens a separate window.

- The state and page stay on the workspace's Tty7App; a thin
  SettingsWindow view borrows it to draw, observes it to repaint, and
  sets its own rem size. The state is built against the new window, so
  its inputs and subscriptions belong to it.
- Opening again raises the window instead of closing it. Esc, Cmd-W and
  the close button go through close_settings_checked, so unsaved forms
  and theme drafts still prompt; closing hands focus back to the
  workspace window. The window goes when its owner is released.
- open_settings_then / close_settings_then run follow-ups in the right
  window: loading an SSH form happens in the settings window, and
  Connect opens its tab in the workspace window.
- Window opacity, blur and backdrop are pushed to every window, since
  they are now changed from a window that is not the workspace.
- Tests keep the in-window overlay so they can drive settings through
  their single test window.
2026-09-23 22:18:54 +08:00
l0ng-ai 826c42f6bd fix(scm): give the folded History bar air above the window edge
Folded, the history section is the last line in the window and sat flush
against the bottom edge, inside the window's rounded corner. Pad it 2px
above and 4px below; the expanded section is unchanged, so its
commits-per-height pin still holds.
2026-09-23 22:06:38 +08:00
l0ng-ai 0988c57d5c fix(ui): restore the sidebar's rounded-rectangle corners
The v5 restyle turned the tab rows, the search field and the workspace
switcher into full pills, which read too round at this density. Put
back CARD_RADIUS on the rows, rounded_lg on the search field and
rounded_md on the switcher (and its rename field), keeping the 28px
row height. PILL_RADIUS has no users left and goes with them.
2026-09-23 22:02:45 +08:00
l0ng-ai a3d64bfcc9 fix(ui): drop the solid accent from the switcher's picked row
The workspace switcher painted its picked row a hard-coded #1768CF with
white text, in the workspace list, the tab list and the New Workspace
host dropdown. It bypassed the theme and was the loudest block on
screen. Use the popover's neutral selected step and keep each row's own
inks, so a taken-over warning still reads as one.
2026-09-23 21:50:04 +08:00
l0ng-ai 859c286c6a fix(panel): lead the right panel's tab row on Windows
The tabs sat after the row's flex spacer, so they hugged the window
controls instead of opening the row the way they do on macOS.
2026-09-23 21:49:27 +08:00
l0ng-ai ae0d129816 Merge pull request #946 from l0ng-ai/feat/v5-ui-restyle
feat(ui): restyle the workspace after the v5 design
2026-09-23 21:38:10 +08:00
l0ng-ai d18f797a6c Merge pull request #945 from l0ng-ai/fix/942-wsl-files-panel
fix(files): keep a WSL tree in step with its distro (#942)
2026-09-23 21:38:06 +08:00
l0ng-ai 4ff8fe4fb2 Merge pull request #944 from l0ng-ai/fix/bounded-grid-lock
Let go of the grid lock every 64 KB while parsing pane output
2026-09-23 21:38:01 +08:00
l0ng-ai 27406e472d Merge pull request #943 from l0ng-ai/fix/watch-close-off-ui-thread
Stop waiting on remote round trips from the UI thread
2026-09-23 21:37:57 +08:00
l0ng-ai f1648117b7 feat(ui): restyle the workspace after the v5 design
- Rails share the window fill and are separated by a hairline only;
  the current tab is a neutral selected step plus a semibold title
  instead of the blue navigation wash (the unused role is removed).
- Default Light theme takes ink #0F1419 and accent #1F6BF0; the caret
  follows the accent.
- Sidebar: 28px pill rows with 18px avatars (two-line rows keep card
  corners), pill search field and workspace switcher, group headings
  in body ink with the chevron shown only when folded.
- Right panel: word tabs (Info / Changes / Files) with an underline
  bar on a closing hairline. The Changes count is dropped before any
  label is cut, and the panel floor grows with the measured labels so
  the chrome tiles are never pushed off the edge.
- Headings are no longer uppercased; popovers use a 10px radius.
- docs/design-system.md updated to match.
2026-09-23 21:35:28 +08:00
l0ng-ai 1215eba16d fix(ui): drop the trailing tiles while a docked document holds the right edge
On macOS the panel toggle and app menu tiles sat at the end of the terminal
column's strip whenever the detail panel was closed, including when a docked
diff or file column stood to its right, leaving them in the middle of the
window beside the document's header. Hide them while a document is docked and
stop reserving their width for the tab chips.
v26.9.3
2026-09-23 19:28:39 +08:00
l0ng-ai 8fa9651814 fix(files): keep a WSL tree in step with its distro (#942)
Three things went wrong with a Files panel rooted on a distro's \\wsl$
share:

- A drop brought a `name:Zone.Identifier` file along with every
  downloaded file. fs::copy is CopyFileEx on Windows, which copies the
  NTFS alternate data streams, and the share has no streams to keep one
  in, so it lands as a file of its own. A copy onto a WSL share now
  moves the contents only; one onto NTFS still goes through fs::copy
  and keeps the mark.
- A file removed from the shell in the distro stayed in the tree. The
  share accepts a ReadDirectoryChangesW and never reports a change, so
  the watch looked healthy and was deaf. Directories on a WSL share are
  now watched by a notify PollWatcher every 2s instead, made the first
  time one is needed.
- Right-clicking a row did not select it, so nothing marked the row the
  menu was about. A right click now selects the row without opening it.
2026-09-23 19:26:26 +08:00
l0ng-ai d843b82286 chore(release): v26.9.3 2026-09-23 19:21:12 +08:00
l0ng-ai 439f19ff85 Stop waiting on remote round trips from the UI thread
Dropping a RemoteWatch sent WatchClose with a blocking call, and the last
handle is usually let go on the UI thread: from Tty7App::render via
scm_sync_watchers, and from scm_watch_opened when an open lands after its
subscription moved on. Every window froze for a round trip each time, up
to WatchClose's 5 s deadline on a quiet link. Sampling a live instance
caught ~1.1 s of such stalls in 10 s.

- ControlClient::post sends a request without registering for its reply;
  the reader already drops replies nobody is waiting for.
- RemoteWatch::drop posts WatchClose instead of calling it.
- pane_workspace_for built the full SSH spec, keychain lookups included,
  only to strip the secrets again. It now builds it from NoCredentials,
  which takes the securityd trips off pane_liveness::sweep.

Claude-Session: https://claude.ai/code/session_01YX786Hyr4ivijWxv66zVkf
2026-09-23 19:00:54 +08:00
l0ng-ai b75b60e6af Let go of the grid lock every 64 KB while parsing pane output
The reader parsed each batch — and a relink's whole replay, up to 8 MB —
in one hold of the grid lock, and every UI-thread handler that touches
the grid queues on it. Feed the emulator in MAX_LOCKED_FEED slices, the
same bound Alacritty's reader uses.

Claude-Session: https://claude.ai/code/session_01YX786Hyr4ivijWxv66zVkf
2026-09-23 18:46:48 +08:00
l0ng-ai 800c6bf724 Merge pull request #933 from l0ng-ai/feat/comfortable-ui-surfaces
feat(ui): refine panel readability and workspace surfaces
2026-09-23 16:59:54 +08:00
l0ng-ai 7666e2fd83 Merge pull request #941 from l0ng-ai/feat/852-portable-mode
feat(windows): portable mode keeps data beside the executable
2026-09-23 16:58:12 +08:00
l0ng-ai 0b53ff16ef Merge pull request #940 from l0ng-ai/feat/767-prompt-input-new-line
feat(prompt-editor): start input on its own row when the prompt leaves too little room
2026-09-23 16:58:08 +08:00
l0ng-ai 386ccc3d81 Merge pull request #939 from l0ng-ai/feat/720-font-smoothing
feat(fonts): make macOS stroke thickening configurable
2026-09-23 16:58:03 +08:00
l0ng-ai 296a8a3c3f Merge pull request #938 from l0ng-ai/feat/760-stable-workspace-numbers
feat(workspaces): number workspaces in a stable order (#760)
2026-09-23 16:57:59 +08:00
l0ng-ai da6c8624de Merge pull request #937 from l0ng-ai/feat/723-remote-tree-download
feat(file-tree): download a remote file from the tree's context menu
2026-09-23 16:57:54 +08:00
l0ng-ai a012321542 Merge pull request #936 from l0ng-ai/feat/892-741-codebuddy-cursor-hooks
feat(agents): CodeBuddy CLI support and Cursor CLI hooks
2026-09-23 16:57:50 +08:00
l0ng-ai 2eb1a79d76 Merge pull request #935 from l0ng-ai/feat/754-dock-preview-wrap-actions
feat(editor): add ToggleDocumentPreview / ToggleDocumentWrap actions
2026-09-23 16:57:45 +08:00
l0ng-ai 2aa28d3982 Merge pull request #934 from l0ng-ai/feat/867-direct-tab-cycling
feat(tabs): step to the next/previous tab without the switcher (#867)
2026-09-23 16:57:41 +08:00
l0ng-ai 5d861f991f Merge pull request #932 from l0ng-ai/feat/826-sftp-open-at-cwd
feat(sftp): open the Files panel at the shell's current directory
2026-09-23 16:57:36 +08:00
l0ng-ai 3d4c158278 fix(agents): open Cursor turns on beforeSubmitPrompt, count tool calls as activity
The interactive cursor-agent TUI fires beforeSubmitPrompt and stop; only
print mode (-p) lacks them. Mapping postToolUse to prompt-submit froze the
activity counter (opportunistic git refresh, agents --changed), shortened
turn timing and hid tool-less turns. Map it to tool-complete instead.
2026-09-23 16:54:06 +08:00
l0ng-ai 75480cac05 fix(ui): improve panel readability at narrow sizes 2026-09-23 16:51:59 +08:00
l0ng-ai f5a97ed68c feat(windows): portable mode keeps data beside the executable (#852)
A portable ZIP install whose folder has both the .tty7-portable marker
and a data\ folder next to tty7-app.exe now uses <exe dir>\data as its
config directory, so settings, sessions, scrollback and the daemon's
socket travel with the program. --config-dir and TTY7_CONFIG_DIR still
win. The folder is an explicit opt-in because the marker has shipped in
every portable ZIP since the in-app updater arrived: keying on it alone
would move existing users onto an empty directory at their next update.

The portable directory is not the machine's config dir, so a portable
copy never adopts the installed tty7's legacy tree. An updater test pins
that data\ is not a managed root and survives an in-place update.
2026-09-23 15:44:27 +08:00
l0ng-ai 9a01a12852 docs(prompt): describe the input moving below a long prompt (#767) 2026-09-23 15:43:05 +08:00
l0ng-ai 57ca21dd68 feat(workspaces): number workspaces in a stable order (#760)
SelectWorkspace1-9 and the Window menu numbered workspaces by most
recent use, so switching to one moved it to slot 1 and reshuffled the
rest. Number them by the order this client first had them instead
(the append-only views list), skipping synced remote references until
they are opened; opening one moves it to the end so it takes the next
free number. The switcher keeps its MRU list and shows each row's
number.
2026-09-23 15:38:28 +08:00
l0ng-ai 5c3d2a9e8a feat(prompt-editor): start input on its own row when the prompt leaves too little room (#767)
With a long prompt the inline editor started at the prompt's end column,
leaving e.g. 24 of 143 columns for the first row of input. When fewer than
max(20, cols/3) columns remain (and the prompt is at least as wide as what
it left, so a new row actually gains room), the input overlay now starts at
column 0 of the row below the prompt.

The start position is decided by one pure fn, input_start(), and fed to
everything that lays out the input: the overlay rows and overflow shift,
click-to-index mapping, vertical caret movement, the rendered bar, the
completion menu anchor and the IME candidate anchor.
2026-09-23 15:32:26 +08:00
l0ng-ai 592058acc7 feat(fonts): make macOS stroke thickening configurable (#720)
Add a macOS-only `font_thicken` key (default true) and a Settings row
under Appearance > Terminal text. When off, AppleFontSmoothing is pinned
to 0 in this process's NSArgumentDomain before gpui's text system first
reads it, so glyphs render at the face's own weight. The volatile domain
is in-memory only: nothing is persisted and no other app is affected.
gpui caches the preference in a OnceLock, so a change applies after a
restart; no gpui fork change is needed.
2026-09-23 15:23:10 +08:00
l0ng-ai 43d2b902bb feat(file-tree): download a remote file from the tree's context menu
A remote workspace's Files tree took uploads by drag-and-drop but had no
way to bring a file back. Right-click a file -> Download now reads it
through Host::read_file and saves it into this machine's Downloads
folder, named and numbered the way the SFTP panel's Download does.

Capped at the same ~63 MB as uploads (one control frame); an oversized
file is refused up front with the limit and nothing is transferred.
Local trees keep Reveal in that slot; folders are not offered.

Closes #723
2026-09-23 15:22:57 +08:00
l0ng-ai fe7b6e0b76 feat(agents): wire Cursor CLI (cursor-agent) into agent hooks (#741)
Cursor's ~/.cursor/hooks.json is a flat hook map — `command` directly on
each entry under `hooks.<event>` — so it reuses the flat writer Crush
introduced. Two things are Cursor-specific:

- The file needs `"version": 1` at its root or Cursor ignores it. tty7
  now writes it when it creates the file or finds it missing, never
  overwrites a version the user set, and reports a versionless file that
  holds our hooks as Outdated so refresh repairs it.
- Payloads name the session `conversation_id` (only sessionStart repeats
  it as `session_id`), and most events carry `workspace_roots` instead of
  `cwd`. Both are now read as aliases, which is what Copy Session ID and
  resume were missing.

Events: sessionStart, beforeSubmitPrompt, postToolUse, stop, sessionEnd.
cursor-agent does not fire beforeSubmitPrompt today (a known gap on
Cursor's side), so postToolUse also reports prompt-submit: the first tool
call opens the turn and Cursor's stop, which the CLI does fire, closes it.
A turn with no tool calls never shows as working. None of Cursor's
permission hooks are installed, since those would block on the empty
stdout tty7's hook prints.
2026-09-23 15:21:34 +08:00
l0ng-ai 962fd87ea5 feat(tabs): step to the next/previous tab without the switcher (#867)
Add SelectNextTab / SelectPrevTab, which move to the neighbouring tab in
the order the strip or sidebar shows them, wrapping, with no popup.
Defaults: Cmd+Shift+] / Cmd+Shift+[ on macOS, Ctrl+PgDn / Ctrl+PgUp
elsewhere. The tmux preset's prefix n / p now bind these (tmux
next-window semantics) instead of the MRU switcher, which never
auto-committed there.

NextTab / PrevTab keep their config names and Ctrl+Tab, but are labelled
Recent Tab Switcher on the Keybindings page; the palette's Next/Previous
Tab entries now show the SelectNextTab chord they actually run.
2026-09-23 15:20:34 +08:00
l0ng-ai 9f842975ce feat(editor): add ToggleDocumentPreview / ToggleDocumentWrap actions (#754)
The code panel's Preview/Edit and Wrap buttons only toggled state in their
click handlers, so there was no way to reach them from the keyboard. Register
both as actions, unbound by default like ToggleDocumentFill and the
DocumentWidth* actions, list them in the command palette and the Keybindings
page, and route the buttons through the same methods.

Instead of config keys for the initial state, the last-used state is
remembered (editor_soft_wrap / editor_markdown_preview), the way diff_view
and scm_graph_expanded already are. A file opened at a line target always
opens as source so the cursor is visible.
2026-09-23 15:18:58 +08:00
l0ng-ai 60296567f9 feat(ui): unify floating surfaces and soften workspace chrome 2026-09-23 15:17:56 +08:00
l0ng-ai 0d0dc597ee feat(agents): add CodeBuddy CLI integration (#892)
CodeBuddy Code takes Claude Code's hooks as-is: the same nested
`hooks.<Event>[].hooks[{type, command}]` shape in ~/.codebuddy/settings.json
(or $CODEBUDDY_CONFIG_DIR/settings.json), the same event names, and the same
session_id/cwd payload fields. So it rides the shared hook-map installer and
needs no payload aliases.

The event table follows Qoder rather than Claude: CodeBuddy has a
first-class PermissionRequest and Elicitation, so it gets no Notification
hook, and StopFailure ends a turn like Stop. CodeBuddy also emits
SessionStart with source "compact" mid-turn, which is filtered out the same
way Qoder's is so the pane does not drop back to idle.

Detection covers all three npm bins (codebuddy, codebuddy-code, cbc).
Resume is `codebuddy --resume <id>` and fork appends --fork-session; stale
session and worktree flags are dropped from the replayed launch argv, and
--no-session-persistence disables both commands.

Icon, en/ja/zh names and search keywords, and docs are updated.
2026-09-23 15:04:06 +08:00
l0ng-ai d474e4ade3 feat(sftp): open the Files panel at the shell's current directory
Reopening the SFTP panel went back to the last browsed folder; a fresh
open now prefers the pane shell's cwd, falling back to the last browsed
folder, then the login directory. Following a pane switch with the panel
still open keeps each pane's last browsed folder.

Also pin the test config dir in the sftp gpui harness so filtered runs
do not trip the real-config guard, and fix docs/remote/sftp.mdx, which
said the panel opens on the remote home directory.

Closes #826
2026-09-23 15:03:04 +08:00
l0ng-ai d534c085b9 Merge pull request #930 from l0ng-ai/chore/bump-control-dialect
chore(control): bump the dialect to v10 so remote hosts pick up daemon fixes
2026-09-23 12:34:32 +08:00