Commit Graph
501 Commits
Author SHA1 Message Date
l0ng-ai c70f9e0881 feat(agent-hooks): follow the agent's own cwd for the sidebar git line
Claude Code's EnterWorktree chdirs the agent without any shell cd, so the
sidebar's branch/diff line could not see the move on platforms without the
proc-cwd fallback. Forward the cwd field every Claude Code hook payload
already carries through the OSC 777 sentinel, keep it on the pane's agent
session state, and let it take precedence over the proc probe for the git
line. The claim is released on session-end (and when the agent leaves the
foreground), so an exited agent falls back to the pane's real directory.
2026-07-17 18:01:29 +08:00
l0ng-ai 58d0596015 feat(tab-strip): float the close button over the label instead of reserving a slot
Every chip permanently reserved a 6px gap + 20px slot for a close
button that is invisible until hover, which read as a hole between an
ellipsized label and the chip edge, and wasted label width on crowded
strips. Drop the in-flow slot: the label now runs the full chip width,
and on hover the ✕ floats over its right edge on a solid backing in
the chip's own fill with a short gradient run-in, so covered text
fades out and nothing reflows.

The ⌘N hint badge keeps an in-flow slot: it also shows on unhovered
inactive chips, which are transparent over the window background, so
an overlay has no solid colour to back onto.
2026-07-17 17:56:09 +08:00
l0ng-ai 72056f4195 fix(settings): keep Agents rows aligned and notes terse
The install/uninstall outcome note repeated the agent name and full
target path inside the row's shrink-proof control column; a long path
inflated the column past the 640px content cap and crushed the label
column (min_w_0) to zero width, wrapping the title one character per
line.

- Terse action summaries: "Installed" / "Removed" — the row already
  shows the agent and target path. Codex keeps the feature-flag
  failure advice; the launch-refresh log line carries the agent name
  and target path itself now.
- Control column gets items_end so status, buttons, and note share
  one right edge across all agent rows.
- Note is width-capped (max_w_80) and wraps, so long error text can
  never expand the column again.
- Outdated status text shortened to one word; the Update button says
  what to do.
2026-07-17 17:21:22 +08:00
l0ng-ai 96ff361209 chore(release): v26.7.1 v26.7.1 2026-07-17 16:42:28 +08:00
l0ng-ai f7270f2bc0 Merge pull request #124 from l0ng-ai/feat/duo-logo-refresh
feat(brand): "Duo" logo refresh — mint panes mark across all icon assets
2026-07-17 16:36:50 +08:00
l0ng-ai 6af47dfb53 feat(brand): "Duo" logo refresh — mint panes mark across all icon assets
Replace the orange window-and-cursor identity with the "Duo" mark: two
offset session panes (mint #3FDD8C behind, ink #17171A in front) with a
prompt chevron, on a cream tile following the Big Sur icon grid.

- app-icon.svg is the master; app-icon.png, tty7.icns and favicon.ico
  are re-rendered from it (rsvg-convert + iconutil + PIL)
- logo.svg/logo.png/logo@256.png carry the tile-less transparent mark
- tray.svg redrawn as the same mark in template form: solid front pane
  with the chevron masked out, back pane at partial alpha
- bare (non-bundled) macOS binaries now set the Dock icon at runtime
  via NSApplication.setApplicationIconImage, so cargo dev/run shows the
  logo instead of the generic executable icon
- README version badge and the social preview switch to the new brand
  green; social preview copy re-aligned with the current README slogan
2026-07-17 16:31:41 +08:00
l0ng-ai 55b5d0151f Merge pull request #123 from l0ng-ai/fix/flaky-reap-guard-test
test(daemon): poll for the child's exec before asserting its path
2026-07-17 15:52:35 +08:00
l0ng-ai 4d2094ff90 test(daemon): poll for the child's exec before asserting its path
Command::spawn returns after the fork, possibly before the child has
exec'd sleep; until then /proc/<pid>/exe still points at the test
binary itself, so asserting the basename immediately is a race. This
intermittently failed the Linux CI job on main (runs 29549626571,
29560431777, 29563049775). Poll process_path for up to 5s and carry
the last-seen basename into the failure message.
2026-07-17 15:48:25 +08:00
l0ng-ai 5b67d79805 Merge pull request #122 from l0ng-ai/fix/macos-tray-template-icon
fix(tray): keep the macOS icon a template image in every state
2026-07-17 15:25:42 +08:00
l0ng-ai 3f61bbbc34 fix(tray): keep the macOS icon a template image in every state
The attention state left template mode to carry the amber badge, which
forced the glyph to a hardcoded mid-grey that was illegible on many menu
bar appearances. Drop the badge (and the grey recolor) on macOS: the icon
now stays a template glyph the system recolors for the bar, and agent
status lives in the tooltip and tray menu. Windows/Linux keep the amber
corner badge on their colored icon.
2026-07-17 15:23:58 +08:00
l0ng-ai a31db6aa7f Merge pull request #121 from l0ng-ai/feat/theme-follow-system
feat(theme): follow the OS appearance with separate light/dark themes
2026-07-17 15:16:02 +08:00
l0ng-ai df36292db1 test(config): round-trip follow-system fields; docs + comment fixes from review 2026-07-17 15:11:11 +08:00
l0ng-ai 1cd801e902 feat(theme): follow the OS appearance with separate light/dark themes
Add a "Sync with system" mode: when on, the active theme resolves from
two user-picked slots (theme_preset_light / theme_preset_dark) by the
current OS appearance and switches live when the OS mode flips.

- config: theme_follow_system + theme_preset_light/theme_preset_dark
- theme: effective_preset_id() resolver; release the native appearance
  pin while following (it would blind the OS-appearance reads)
- app: observe_window_appearance re-applies the theme on OS flips;
  set_preset writes the slot matching the current appearance while
  following; explicit set_slot_preset for the Settings cards
- settings: sync switch + one card per slot; the picker panel aims at
  the slot whose card opened it

Closes #107
2026-07-17 14:57:48 +08:00
l0ng-ai 627f5fe174 Merge pull request #119 from l0ng-ai/fix/windows-hook-console-flash
fix(agent-hooks): stop console windows flashing on each Windows hook
2026-07-17 14:34:30 +08:00
l0ng-ai d5c4f347ed Merge pull request #120 from l0ng-ai/feat/tab-mark-unread
feat(tabs): add Mark as Unread to the tab context menu
2026-07-17 14:32:30 +08:00
l0ng-ai 37a894fc49 feat(tabs): add Mark as Unread to the tab context menu 2026-07-17 14:23:47 +08:00
l0ng-ai 2f1978618d refactor(code-panel): per-tab panel state, diff-overlay style
The panel's open files, tree roots/expansion/selection, and visibility now
live on Tab.code (same contract as Tab.diff_overlay): only the active tab's
panel renders, switching tabs shows that tab's own panel (or none), and
closing the tab drops its state. Hiding via Esc keeps the tab's open files.

Shared infrastructure stays app-global: directory-listing and gitignore
caches (path-keyed, tab-agnostic), the LSP registry, and single watchers
over the union of every tab's roots / open files. External-change reloads
and diagnostics now fan out to every buffer of the path across tabs.
2026-07-17 11:18:25 +08:00
l0ng-ai f9ed31c0af refactor(code-panel): full-body overlay instead of docked side columns
The file tree + editor now render as one overlay covering the terminal
(settings/diff-overlay style): toggling never resizes the terminal (no PTY
resize/reflow) and the editor gets the full body width. The tab sidebar stays
visible and switching tabs re-roots the tree; focus follows the panel.

- Merge ToggleFileTree/ToggleEditor into one ToggleCodePanel action (cmd-shift-e,
  Esc closes, palette "Code Panel").
- Add the one on-screen entry point: a title-bar tile next to the overflow
  menu, lit while the overlay is up (present in both tab-bar modes).
- Drop the editor width divider and the file tree's standalone open flag.
2026-07-17 10:52:21 +08:00
l0ng-ai 5d58aae9d1 Merge remote-tracking branch 'origin/main' into worktree-code-panel 2026-07-17 10:26:06 +08:00
l0ng-ai acb461a094 feat(code-panel): local file tree, code editor panel, and LSP client
- File tree (left column): lazy per-directory listing with notify-driven
  refresh, gitignore chain matching (dimmed italics), keyboard nav, inline
  new-file/new-folder/rename, context menu (open / cd / insert path /
  attach-to-agent / copy path / reveal / delete), multi-root from the active
  tab's pane cwds, rows draggable into the terminal as ExternalPaths.
- Code editor (right column): gpui-component CodeEditor mode (tree-sitter
  highlighting, line numbers, folding, find/replace), file tabs with dirty
  markers, cmd-S save, external-change reload with conflict banner, markdown
  preview, soft-wrap toggle.
- LSP: stdio JSON-RPC client per (server, workspace root) for rust-analyzer /
  gopls / pyright / tsserver / clangd; completions, hover, diagnostics,
  same-file cmd-click definitions, F12 cross-file goto, shift-F12 references
  drawer.
2026-07-17 10:25:45 +08:00
l0ng-ai f8baebddfc Merge pull request #118 from l0ng-ai/fix/sidebar-group-worktree
fix(sidebar): group linked worktrees under their main repository
2026-07-17 10:18:56 +08:00
thomasandClaude Opus 4.8 3a70e62078 fix(agent-hooks): stop console windows flashing on each Windows hook
Debug builds are console-subsystem (so println! logging stays visible
while developing the GUI), so every `tty7 agent-hook <agent> <event>`
process Claude Code spawns for a hook gets its own console window. At
end of turn several hooks fire (Stop, SessionEnd, PostToolUse, ...), so
a cluster of terminal windows flashes open and vanishes as each tiny
emitter runs and exits.

The emitter never uses its own console for I/O — stdin is piped and it
writes to the agent's console via AttachConsole — so free the throwaway
console the instant run_agent_hook starts. With no other process
attached, the console and its window are torn down before they can
paint. No-op in release (GUI subsystem, no console) and on Unix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 09:48:24 +08:00
l0ng-ai 09810c3766 fix(sidebar): group linked worktrees under their main repository
The sidebar's repo grouping keyed on the git work-tree root
(rev-parse --show-toplevel), so every linked worktree of one repository
rendered as its own group. Probe the common git dir alongside and derive
a repository home — the main checkout's root — and group on that
instead. Branch and diff state stay cached per work tree, so each row's
branch line is unaffected.
2026-07-17 09:46:30 +08:00
l0ng-ai e1c0ed332e chore(release): v26.7.0 v26.7.0 2026-07-16 23:40:31 +08:00
l0ng-ai bb4d1a6bc9 Merge pull request #117 from l0ng-ai/feat/windows-clipboard-image-paste
feat(terminal): paste clipboard images as a file path off macOS
2026-07-16 23:30:02 +08:00
l0ng-ai 3155540acd Merge main: carry #113 selection-consume into the SYN fallback of paste_clipboard_image 2026-07-16 23:20:43 +08:00
l0ng-aiandl0ng-ai 17097ea207 fix(nightly): upload only packaged artifacts, not dist/ intermediates (#116)
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
2026-07-16 23:15:39 +08:00
thomasandClaude Opus 4.8 ab91f910f3 feat(terminal): paste clipboard images as a file path off macOS
Pasting a screenshot into a coding-agent pane (Claude Code &co.) did
nothing on Windows/Linux. The clipboard-image branch only forwarded SYN
(0x16), relying on the agent to read the OS clipboard itself when it sees
Ctrl+V. That works on macOS, but Claude Code silently drops raw
screenshots off macOS (anthropics/claude-code#26679), so nothing landed.

gpui already hands us the image bytes via ClipboardEntry::Image, so off
macOS we now stage the image to a temp file and paste its shell-escaped
path — the same route drag-and-drop uses, which agents attach reliably.
Windows screenshots arrive as BMP (CF_DIB), which agent vision rejects,
so those are transcoded to PNG; PNG/JPEG/GIF/WebP pass through untouched.
The temp filename is keyed on gpui's content hash so re-pasting one image
reuses a single file. macOS keeps the higher-fidelity SYN path, and a
staging failure there falls back to SYN too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 23:10:27 +08:00
l0ng-ai 89774b1800 Merge pull request #115 from l0ng-ai/feat/windows-agent-detection
feat(agent): detect coding agents on Windows via shell-integration command capture
2026-07-16 22:46:45 +08:00
l0ng-ai e16708956f fix(agent): only apply mark-derived detection when the C capture changes
A stray foreign A/B mark mid-command re-delivers the same capture; when
that capture names no agent (a wrapper script the matcher can't see
through), re-applying its None wiped an identity the sentinel events had
established. Gate the Windows apply on the capture changing, document
the bare-C trade-off (our own PowerShell fallback emits it), and cover
the gate, %0A multi-line decode, and whitespace-only payloads in tests.
2026-07-16 22:41:51 +08:00
l0ng-aiandl0ng-ai 8209fa1823 feat(nightly): unattended nightly build channel with prerelease-aware update check (#114)
* feat(nightly): unattended nightly build channel with prerelease-aware update check

* fix(nightly): upload assets before pruning stale ones; pin nightly-to-nightly no-prompt in tests

---------

Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
2026-07-16 22:40:22 +08:00
thomasandClaude Opus 4.8 6067f6b651 feat(agent): emit hook status events on Windows via ancestor console
The Windows agent status dot (working/waiting/done) never showed because
`write_to_controlling_tty` was a `false` stub on Windows — the hook's OSC
777 sentinel event was never injected into the pane's PTY, so the daemon
never learned the agent's turn state.

The hook has no `/dev/tty` on Windows, and agents (Claude Code, a Node app)
spawn hooks with CREATE_NO_WINDOW, giving the hook its own *hidden* console
— so a naive `CONOUT$` write succeeds into a dead-end buffer. Mirror the
Unix "write the agent's tty" strategy at the console layer: walk up the
parent chain to the shell tty7 spawned (the ancestor whose parent is the
tty7.exe daemon — the process actually on the pane's ConPTY), FreeConsole
off the hidden one, AttachConsole to the shell's, and write CONOUT$ there.
The OSC bytes then flow through ConPTY to the daemon exactly like the
shell-integration marks. Falls back to spraying every ancestor console
when the shell can't be pinned down.

Adds the windows-sys Win32_System_Console feature for Attach/FreeConsole.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 21:16:03 +08:00
l0ng-ai 775f0b7024 feat(agent): detect coding agents on Windows via shell-integration command capture
ConPTY has no foreground process group, so the Unix process-table poll
(pgid -> argv) has no Windows equivalent and foreground_agent was a stub
returning None. Follow Warp's approach instead: the shell integration
captures the submitted command line at preexec and carries it
percent-encoded on the OSC 133;C mark; the daemon detects the agent from
that string.

- shell_integration: all four bodies (zsh/bash/fish/PowerShell) append
  the submitted line to 133;C, truncated to 512 chars and escaped
  (% ESC BEL CR NL). PowerShell guards the surrogate-splitting truncation
  and wraps the emission in try/catch (EscapeDataString throws on lone
  surrogates under .NET Framework / PS 5.1).
- pane: ShellState.command stores the capture (cleared on D only, so a
  stray foreign A/B mid-command can't wipe the chip); on Windows
  apply_signals feeds it through the new detect_from_command_with.
- cli_agent: detect_from_command_with tokenizes a typed command line
  (quotes, & call operator, case-insensitive) and reuses the argv
  detection; base_stem handles backslash paths and .exe/.cmd/.bat/.ps1.
- ForegroundProbes::agent is now Option<Option<CLIAgent>>: None means
  'no process-table view' (native SSH, Windows) and is never applied,
  fixing the 0.5s poll wiping event-branded agents on native-SSH panes.
2026-07-16 20:23:47 +08:00
l0ng-ai 3aeece5598 Merge pull request #113 from l0ng-ai/fix/ctrlc-selection-consumed
fix(terminal): consume the selection on Ctrl+C copy and PTY paste so the next Ctrl+C sends SIGINT
2026-07-16 19:32:41 +08:00
l0ng-ai 606da8ada7 fix(terminal): consume selection on Ctrl+C copy and PTY paste so the next Ctrl+C sends SIGINT 2026-07-16 19:10:36 +08:00
l0ng-ai 98b4282a39 Merge pull request #110 from l0ng-ai/feat/sidebar-repo-grouping
feat(sidebar): group vertical tabs by git repository
2026-07-16 18:26:19 +08:00
l0ng-ai 9bc84679f7 style: wrap the activate_visual listeners to rustfmt width 2026-07-16 18:22:21 +08:00
l0ng-ai 14d5a8bfc3 Merge pull request #112 from l0ng-ai/fix/rustfmt-settings
style: run cargo fmt on settings.rs
2026-07-16 18:22:06 +08:00
l0ng-ai 0f7a0a9461 style: run cargo fmt on settings.rs 2026-07-16 18:21:41 +08:00
l0ng-ai eec003e4e7 feat(sidebar): visual-order ⌘N, persisted groups, deduped headers
Three follow-ups to the repo grouping:

- ⌘N now targets the N-th row as displayed (activate_visual over the
  same sections the render uses), so the badge digits read 1…9 top to
  bottom under grouping instead of scattering tab-vector indices.
- SessionTab persists the sticky sidebar group, so a restored session
  renders grouped on the first frame instead of starting flat and
  reshuffling as git probes land; reopen-closed-tab keeps its group too.
- Same-named repo roots disambiguate their headers by extending parent
  components until distinct (work/app vs fork/app); unique names stay
  short. Grouping/naming logic moved to pure functions with unit tests.
2026-07-16 18:14:08 +08:00
l0ng-ai e5ede1beb7 fix(sidebar): key repo group on first pane; document grouping
The group key now reads the first pane's cwd instead of the focused
pane's, so switching focus between splits in different repos never
relocates the row (the branch line still follows focus). Also documents
the repo-grouped sidebar and the sidebar_grouping setting in
features.md / features.zh-CN.md.
2026-07-16 18:03:31 +08:00
l0ng-ai 4d70cad3aa feat(sidebar): group vertical tabs by git repository
Group the left tab sidebar's rows under a per-repo header, keyed on the
git work-tree root only (not the branch), so a branch switch or an
in-repo cd never relocates a tab — only changing repos does. Non-repo
tabs collect in a trailing Scratch group; the list stays flat when no
tab is in a repo.

Each row is two lines: the title on its own (never crowded out) with the
branch and +N/-N diff on an indented second line. A sticky per-tab group
key holds across an in-flight probe so the list doesn't flicker on a cd.
New sidebar_grouping setting (repo default / none) toggles it.
2026-07-16 17:51:43 +08:00
l0ng-ai 0603aa99b8 Merge pull request #108 from l0ng-ai/feat/settings-sheet-refine
feat(settings): right-align controls with row hover, tighten column, richer theme card
2026-07-16 17:50:43 +08:00
l0ng-ai d0c2777fdd docs(settings): note both hosting caps for settings_row; refresh theme card doc 2026-07-16 17:50:04 +08:00
l0ng-ai d13c7878a9 Merge pull request #109 from l0ng-ai/fix/tray-glyph
fix(tray): redesign macOS menu bar glyph for legibility
2026-07-16 17:48:19 +08:00
l0ng-ai 530be0fe5c fix(tray): redesign macOS menu bar glyph for legibility
The tray reused logo.svg (window outline + title-bar rule + colored
cursor block), which turns to mush at 18pt in template mode: the color
flattens to alpha and the icon reads as a card/wallet, not a terminal.

Replace it with a dedicated tray.svg — a bold window outline with a
prompt chevron and underscore, drawn for menu-bar size. logo.svg is
untouched; the tray was its only code consumer.
2026-07-16 17:46:51 +08:00
l0ng-ai 6ae48ab950 feat(settings): right-align controls with row hover, tighten column, richer theme card 2026-07-16 17:38:20 +08:00
l0ng-ai 4aeed6fa46 Merge pull request #106 from l0ng-ai/feat/theme-background-visuals
feat(theme): render gradient and image backgrounds, global window opacity/blur
2026-07-16 16:44:01 +08:00
l0ng-ai 2dd817d8cd fix(theme): review follow-ups — diff overlay background, hot-reload window effects, docs
- Diff overlay paints the gradient/opacity-aware window background instead
  of the stale representative solid.
- Config hot-reload now re-runs apply_theme with the window (blur flip,
  traffic-light re-pin) and re-syncs the Appearance opacity slider, so
  hand-edits to config.json / theme files take effect fully.
- Document the theme background/window settings in features docs (EN + zh-CN).
2026-07-16 16:30:59 +08:00
l0ng-ai 1a50cf0e60 feat(theme): render gradient and image backgrounds, global window opacity/blur
- Gradient backgrounds (vertical/horizontal two-stop) now actually render;
  previously only the first stop painted as a solid.
- Background images composite over the background fill (cover-fit, per-image
  opacity), under all content.
- Window opacity/blur become global Appearance settings (config overrides
  layered over per-theme defaults), editable for every theme with a
  follow-theme reset; the theme editor gains a background-image picker and
  image-opacity slider.
- The window is created non-opaque and stays that way: on macOS 26 flipping
  a window to transparent after creation never reaches the compositor, so
  translucent themes rendered against black instead of the desktop. Fully
  opaque themes paint alpha-1.0 content, which is visually identical.
- gpui-component's Root no longer paints a second (stale) background layer,
  and the terminal surface no longer repaints the theme background — the
  app root is the single owner, so alpha is applied exactly once.
- to_yaml now serializes background_image, so editing a theme in-app no
  longer silently drops its image.
2026-07-16 16:03:28 +08:00