mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-10-03 16:01:59 +00:00
4e8a76261b01ac1a50c7494afe82e486ea3c6d92
52
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
643e0f7d95 |
feat(agents): add Qoder CN CLI integration (#988)
* feat(agents): add Qoder CN CLI integration * fix(agents): spell Qoder CN's config override QODERCN_CONFIG_DIR The China build of Qoder resolves its configuration through QODERCN_CONFIG_DIR. The first pass invented QODER_CN_CONFIG_DIR instead, so an install that set the real one was treated as unrelocated: hooks went to ~/.qoder-cn and history was scanned from a directory the CLI never writes to. The test that should have caught it set the same invented name, so it only proved the name agreed with itself. Picks up the rest of the review as well — detect the `qoder-cn` dispatcher beside the other two binaries, call it the mainland-China build rather than a different vendor, and drop the QODER_CN_HOOK_EVENTS alias for the table it only pointed at. The serialized enums keep their variants appended; only the independent ALL arrays moved QoderCLICn next to QoderCLI. |
||
|
|
b063ba97a0 |
refactor(settings): fold Window & Tabs into General, drop two settings (#982)
The Window & Tabs page is gone. Its three remaining tab settings (new tab position, tab bar position, auto grouping) are a Tabs group on General, below Startup & restore, so the nav has seven sections. Removed outright: - SSH tab title (`ssh_tab_title`, #726, unreleased). The sidebar already groups SSH tabs under their host, and renaming a tab pins its name. - Open diff preview from sidebar counts (`sidebar_diff_preview`, #247). The sidebar counts and the Info panel's changes row always open the diff overlay; the large-tree stall it worked around is bounded. An old config.json that still carries either key loads as before. The now-unused window settings icon goes with the page. |
||
|
|
fd2c4f7d4e |
feat(panel): Search and GitHub tabs in the right panel (#978)
* feat(panel): add Search and GitHub tabs to the right panel The right panel grows from three tabs to five. Five word labels do not fit the panel's 280px resting width, so the tab row now draws a glyph per tab and names it in a tooltip. Both new panes are placeholders here; the content search and the GitHub issues/PR browser land on top of this. * feat(panel): find in files in the right panel's Search tab The Search tab replaces its placeholder with a content search over the active tab's project -- the same roots the Files tab shows -- on the host that project lives on. Hits arrive as you type (debounced, with a generation counter so a stale answer never lands), grouped by file with a count, each line excerpted with its matches highlighted. Clicking a hit opens the built-in editor at that line and column; Enter searches again. Match-case, whole-word and regex toggles sit at the end of the field, and the tab focuses its field whenever it is brought forward. Host::search_content is new on the Host trait, implemented once in host::content_search (ignore walk + regex) and run by LocalHost directly and by tty7-server over a new SearchContent control request. The walk honours .gitignore with or without a repository, skips dot-entries, binary files and files over 1 MB, and reports a capped search as truncated. The request is gated on a new `content-search` hello feature, so a server that predates it is never sent it; the panel says the server needs updating instead of showing no results. Conformance cases cover local and the stdio server alike. * feat(panel): browse GitHub issues and pull requests in the right panel The GitHub tab follows the focused pane's repository: its root is resolved the way the Source Control tab does, its remotes are read through the Host (the tree may be on another machine), and the github.com remote is bound, upstream over origin in a fork, with a menu to pick another. The list switches between issues and pull requests, open and closed, 50 rows a page with Load more; rows carry a state glyph distinct by shape, labels (click one to filter by it) and relative times. A row opens the detail in place: title, state, author, labels, description and comments as Markdown, and for a pull request its branches, size and changed files. A file opens in the diff overlay through a new supplied-patch DiffSource, so GitHub's patch renders exactly like a local one without a git probe. Read-only, and sign-in reuses the GitHub CLI: GH_TOKEN, GITHUB_TOKEN, then `gh auth token`, found on PATH or at the Homebrew locations a Finder launch cannot see. Signed out, public repositories still work; 401, 403, 404 and rate limits are told apart and explained. Requests go out from this machine over the installer's ureq stack and proxy settings, on threads of their own, cached per repository with background revalidation. Remote images in issue text become links instead of loading, and non-web link targets are disarmed. The Info tab gains a GitHub row that opens the branch on the remote it tracks, or the repository for a branch never pushed. * docs: list ShowRightPanelGitHub with the other panel actions * feat(panel): one-line GitHub rows, a pill for the current tab - GitHub list rows are one line: state glyph, #number, title. Labels and the age of the last update appear on hover, from state rather than a group_hover display switch, which gpui cannot paint. - The current right panel tab sits on the sidebar's selected fill; ink alone could not tell five same-weight glyphs apart. - The GitHub glyph is a 1.8px outline like the other tab icons, not the filled mark. - The detail byline names both times (opened / updated) so it no longer reads as disagreeing with the list's update age. * feat(github): show screenshots pasted into issues Images GitHub hosts itself (github.com/user-attachments, a repo's /assets, *.githubusercontent.com) now render in issue and PR text, each in a paragraph of its own so the text view draws it at its size rather than at line height. Images from any other host stay links, so opening an issue still tells no third party that you read it. gpui held a null HTTP client, so no remote image could load; the app now installs the update check's reqwest client (same user agent and proxy) at launch. * fix(github): load private-repo screenshots, give inline code a neutral fill - Pasted attachments (github.com/user-attachments/assets/<uuid>) want a browser session on a private repository, which an API token is not. The detail and comment requests now ask for the full media type, and each attachment is swapped for the signed private-user-images URL the rendered body_html carries for the same uuid. - Inline code in rendered Markdown (the GitHub tab and the editor's preview) sits on a faint neutral fill instead of the theme accent, which is also the selection colour. Needs gpui-component 6af19d91 for TextViewStyle::inline_code_background. * style(panel): tidy the GitHub and Search tabs' top rows - GitHub drops its heading row on macOS. It existed only to hold the refresh tile, and no other tab has one; refresh now sits with the repository's other actions, in the repo row and a detail's header. - Search's Aa / ab / .* toggles are muted while off instead of body ink. - Search's idle note puts the folder on its own line, spelled ~/…, so the narrow column no longer breaks the path at a slash. * feat(panel): order the right panel's tabs Info, Files, Search, Changes, GitHub Info stays first as the default and the pane's overview; after it come two pairs, the project's files (Files, Search) and its version control from local to remote (Changes, GitHub), where Changes and GitHub were split by the file tabs before. The palette, the Keybindings list and the docs follow the same order. * style(panel): drop the change count from the Changes tab Beside one glyph of five, the number read as a badge on that tab alone, and the Changes tab already leads with the same count under its own heading. right_panel_tabs no longer needs the row's width, which it only measured to decide whether the count fit. * style(icons): fit the GitHub glyph to the other tab icons' size The Lucide mark filled its whole 24px box, edge to edge, where tty7's own icons keep about 3.5px clear, so at 15px it drew a size larger than the four tabs beside it. Scale it to 0.9 about the centre, and raise the stroke to 2.0 so it still renders at the others' 1.8. * style(icons): a simpler GitHub glyph Drop the Lucide mark's tail and redraw the head and legs on tty7's own grid: the same ~15px live area and 1.8 stroke as the other tab icons, no scale transform. The legs keep it reading as the Octocat; a head alone read as any cat. * test(github): find gh on PATH in the blank-variable token test The test placed gh only at /opt/homebrew/bin/gh, which gh_candidates never offers on Windows, so the Windows CI job panicked at unwrap. Put gh on a PATH directory spelled with the platform's exe name instead. * fix(github): close image and link bypasses in the issue Markdown sanitiser Checked against markdown-rs (the parser TextView uses), several inputs got past the line-based rewrite: - is_github_hosted cut the host only at `/`, so `https://evil.io?.githubusercontent.com/x.png` (and `#`, `\`, `/`) counted as GitHub-hosted and was fetched from evil.io. The host now ends at the first of `/?#\` and may hold only DNS characters. - `<img src>` values were written into `` unescaped, so a `)` in the value closed the image and opened a second one from any host. Written destinations are now percent-encoded. - `<image>` (which the HTML parser reads as `<img>`) passed as an ordinary tag and loaded its src. - A kept link target was copied without scanning; when the parser ended the link elsewhere (open title, unbalanced paren) a `` inside it came alive. Markup characters in it are now encoded. - `file:///...` and similar character references passed is_safe_target and decoded to a `file:` link. References are decoded before judging. The rewrite still cannot see every construct the way the parser does (code spans inside tag attributes, fences the parser rejects, multi-line link definitions), so the detail view now also checks the parsed tree: a block containing a non-GitHub image, an unsafe link or definition, or raw `<img>` is drawn as its plain source instead. * fix(github): hide gh's console, bound Retry-After, and reject URL authorities with ?#\ - run gh through proc::output_within with hide_console, so a Windows GUI launch does not flash a console window and stdout is drained while gh runs. - saturating_add a hostile Retry-After instead of overflowing i64. - parse_github_url no longer accepts `https://evil.io#@github.com/o/r`. * fix(search): no panic on an unbounded time budget, and read files through the size cap ContentLimits arrive off the wire on a server; Instant + u64::MAX ms panicked. A file that grew between the size check and the read was read whole; it is now read through a take() at the cap. * fix(panel): keep Load more on an empty filtered page, and drop another host's hits - /issues pages filtered to one kind can come back empty while later pages hold matches; the GitHub list said "No issues" and hid Load more. It now reads on through up to five such pages and keeps Load more offered. - While a new search runs, the previous hits stay on screen; if they came from another host, a click opened their path on the active host. They are now kept only when the host is the same. |
||
|
|
572bfc014b |
feat(ui): v4 redesign, including a rebuilt settings window (#973)
* feat(ui): restyle the right panel after the v4 design - Tab row: 12.5/16rem word tabs 22px in and 18px apart, the current one in body ink at medium weight; no hover pill, no underline bar, no hairline under the row. - Info: Session, Processes and Ports are spaced 16px apart with no rules; 28px medium muted headings, 28px Session rows on a 76px label floor with values in body ink, 26px process rows with a tree elbow for children, and an explicit empty line for Ports. - Files: the search sits in a 28px filled well; tree rows are 26px with a disclosure chevron column, ignored entries dim their icon instead of going italic, and a folder's change dot is 5px. - docs/design-system.md updated to match. * feat(switcher): restyle the workspace switcher after the v4 design - Card: 112px from the top, 12px corners, 48px search row with an esc keycap, 420px body split 340px / preview, 40px footer. - Workspace rows are 52px: a 26px initial disc carrying the link state as a ringed dot (live green, faint when offline, amber while connecting, red on failure), a medium name with its stable number, a machine · path · time line, and the tab count over the state word. - Preview rows are 44px with the sidebar's 18px brand disc, an all-muted branch · diff line, a Current label and a 5px dot that blinks with the sidebar while an agent is working. - Footer: ghost New workspace button and keycap hints for navigate, open and new window; the unused click-for-new-window string is dropped. * feat(scm): restyle the Changes tab after the v4 design - Pinned block keeps 8/10/14 rhythm; branch name medium, 26px sync tile. - Commit message box rests at 56px with a 7px radius. - Split commit control: inverted neutral fill when committable, faint fill otherwise; 6px radius and an inset 0.5px seam. - Change groups sit 16px apart under 22px sentence-case medium headers; file names take width first and directories right-align, eliding from the start. - History: 32px header, 26px rows inset with rounded hover, 1px lines and 7px beads (HEAD filled, others hollow), neutral inks on a single-lane page, age column always shown, faint HEAD pill. * feat(ui): restyle the rail and palette after the v4 design - Default Light/Dark take warm neutrals (#fcfcfb/#1c1c1e, #18181a/#ececed); Git added/modified seeds follow v4 green and amber. - The left rail gets its own tinted fill again (Neutrals.rail, 3% toward the ink) with its own surface ladder; the right panel keeps the content fill. Captions and hairlines are floored on the rail too. - Title bar is 48px; the bar over the terminal centres the active tab's title in caption ink when tabs live in the rail. - Rail header: 26px new-tab and collapse tiles, then the workspace chip and search field (28px, 7px radius). - Groups sit 16px apart under a 22px caption heading with 'branch · +a −d' in tabular numerals. - Rows are 30px (42px with a branch line), 16px avatars, medium weight when current, branch cut from the front, and a trailing 5px status dot (blinks while working, hollow while waiting, unread count as a pill). - docs/design-system.md updated. * docs(design-system): note the commit button's inverted neutral fill * fix(panel): align the right panel's insets with the v4 design - Rows pad 8px inside lists inset 12px, so text sits on a 20px column in every tab and hover fills start 12px in with a 6px radius. Headings, empty states and the Ports line move to the same column. - Tab labels 18px apart; the panel row's chrome tiles are 26px, 4px apart, 12px from the edge. Default panel width 280. - Info: label column floor keeps values at x=88; Ports add tile 22px. - Changes: 8px top gap on macOS, pinned block on 14px edges with the branch at 22, 12px sync glyph, 8px group chevron, 10px status cell, 1px between rows. - History: compact gutter for single-lane pages, filtered rows on the text column, 10px row gap, 24px age floor, header on 20px insets, 4/12 padding when expanded (heights re-counted in commits). - Files: search well at 12px with an 11px glyph, 10px before the tree, 16px indent step, 16px bottom padding. * feat(diff): restyle the diff overlay and commit detail after the v4 design Carry the v4 language into the diff overlay and the commit detail view: 0.5px hairlines at 8% ink, 26px row pills with a 6px radius, the rem type ladder from right_panel.rs, neutral chips instead of accent washes, the shared git_badge for status letters, and tabular figures on counts. Layout, spacing, type and colour only; no behaviour or i18n changes. * feat(ui): restyle the dialogs, notices and home page after the v4 design - New ui::dialog module holds the shared modal chrome, taken from the workspace switcher: a 12px card, a 48px title row with an esc keycap, 18px insets, a 40px hairline footer, 28px borderless field wells on the faint fill, 11.5px medium muted labels, and 18px keycaps. - Buttons: the primary is the inverted neutral fill, the Commit button's paint, instead of the accent. Secondary buttons are transparent with the surface's hover rung. Override on a changed host key stays the one red button. A disabled button sinks to the faint fill and drops its click handler. - SSH sheet: host and fingerprint lines sit in a mono detail well, and keyboard-interactive prompts become field labels. Banners match the sheet's width and card shape. - Worktree prompt: moves to the same card, with the path preview hung off the Name field. - Notice pill: severity moves from a tinted edge to a 6px leading dot. - Home: shortcut rows are 28px with a hover fill and keycap chords, and the remote strip's action uses the secondary button. * fix(panel): start Info and Changes flush under the tab row Their first line is text centred in a 28px row, so the extra 8px step put it visibly lower than the Files tab's search well. Only Files keeps it. * fix(scm): put the commit detail on the right panel's 20px text column * feat(palette): restyle the command palette after the v4 design - Card: the switcher's 12px corner, 112px drop from the top (shorter windows still scale it up), 600px max width. - Search row keeps the list's own field; an esc keycap sits in its trailing corner while the field is empty. - Rows are 32px with an 8px corner, 8px list inset and 10px padding. The keyboard row takes the popover's neutral selected step and a medium title instead of the accent wash, via a palette row element in place of ListItem. - Section headings: 28px, 11.5/16rem medium caption ink, on the rows' text column. Shortcuts are per-key 18px faint keycaps from ui::dialog. - New 40px footer with the switcher's keycap hints (navigate, open). - Empty state: headline in body ink, hint in caption ink. * feat(ui): carry the v4 chrome into panes, the file viewer and SFTP - theme: additive helpers for a device-pixel hairline, tabular figures and an inverted neutral button variant. - Pane splits rest as a device-pixel hairline in the divider tone; hover and drag keep the accent at 1px like the other resize edges. - File viewer header: medium file name, 5px unsaved dot, 26px/6px close tile with its glyph on the content inset, divider hairline under it. Status bar: divider hairline, caption size, tabular line/column. - SFTP browser: file-tree rows (26px, 6px corner, 16px caption glyphs), breadcrumb and notes on the 20px text column, a borderless edit well, inverted OK button, and ink-on-track transfer progress. - Forward rows line up with the process and port rows (text at 20px, 6px corner); Add and Reconnect use the inverted neutral fill. * docs(design-system): note the v4 palette, pane, viewer and SFTP chrome * feat(settings): restyle the settings page after the v4 design - Nav: the rail's tinted fill and surface ladder behind a divider hairline; a 28px filled search well; 28px rows in 7px pills, the current one on the selected rung at medium weight instead of the accent; match counts in muted ink; the modified-only filter toggles like a nav row. - Pages: the title sits in the 48px title-bar band at 16/16rem; group headings are 11.5/16rem medium muted on a 28px line; sections are split by a 0.5px divider with 16px either side. - Rows: labels in body ink at regular weight, descriptions at 12/16rem muted, 28px floor with 8px padding; a search hit wears the faint neutral fill rather than the accent tint. - Controls: text fields and dropdowns are 28px filled pills with no outline; buttons, segmented tracks and steppers are 26px with a 6px radius on the same fill. The one primary action per view (save theme draft, connect, install update) is the inverted neutral fill of the commit button. Switches and sliders keep the accent. - SSH: host list header with 26px tiles and a filled search, 22px group headings, 42px two-line host rows; the form's labels are a muted, right-aligned column level with 28px fields; disclosure headers use a chevron on a 28px band. - Theme cards are filled and unoutlined, taking the selected rung while open; the theme panel keeps the content fill with a divider edge and its title in the title-bar band. Keycaps are filled with no outline and shortcut rows are divided by 0.5px hairlines. - right_panel::SECTION_GAP is now shared; docs/design-system.md updated. * feat(ui): spell tab titles out in full in the rail and title bar The rail's rows and the centred title have room to spare, so they take the whole label from a new full_tab_label rather than tab_label's three-segment cut; only the width they have decides what gets elided. * fix(settings): even out the page rhythm and line up the columns - Nav header: drop the min_h(ROW_H)/min_h(0) pair on the heading, which measured ~46pt taller than it painted and opened a hole under the search. - Page titles sit under the title-bar band, level with the nav heading, instead of jammed against the window's top edge. - Headings get a 22pt group-header row and hug their rows; rules keep more air, so a heading reads as its rows' rather than floating between. - SSH: the host list gives width before the nav, so the nav no longer narrows on that page; its header, search well and detail title run level with the nav's; the empty note starts on the host-title column. - Window & Tabs no longer opens on a stray rule. - Integrations: status leads the buttons on one line, in the meta ink. - Terminal: the shell footnote stays close to its rows. * fix(ui): stop eliding branches that fit, and seat the SCM branch on the text column - elide_tail_clusters returned "…" plus the whole string when nothing needed cutting, so the rail's group header printed …feat/v4-redesign with room to spare. Return the text as-is when it fits. - The group header only reserves the chevron's width when it draws one. - The Changes tab's branch name no longer stacks a small button's padding on the row gap; it starts on the file names' column. * fix(ui): keep a tab's name in place when an inline rename starts gpui-component's Input keeps 12px of inner padding even with appearance(false), so the name jumped sideways as the rail row, the group header and the top-strip chip swapped their label for the field. Claude-Session: https://claude.ai/code/session_01Q9vsQSxAZjkwT7nRAiFF1J * revert(settings): restore the page rhythm from before |
||
|
|
b5cb6efe7a |
style(sidebar): mark pinned groups with ◆ instead of a pin icon, drop the divider (#972)
The pin icon read as a smudge at header size. Kept groups now carry a small ◆ beside their name — every kept group, label groups too, since with the divider gone it is the one thing that tells kept from derived. On a folder group the mark is still the click that unpins it, and the hover button that pins an auto group shows the same character. The divider is no longer drawn at rest. It keeps its (smaller) place in the layout and its recorded bounds, so pinning a header by dragging it up and handing a tab back by dropping it below behave exactly as before, and it still shows as a line while it is the drop target. |
||
|
|
cf0e8f02e6 |
feat(sidebar): pinned groups above auto groups (#962)
* feat(sidebar): keep pinned groups on the workspace and derive the rest Replace the sidebar's hand-made groups with the model from #955: the sidebar groups tabs by repo automatically, and you pin what you want to keep. - Pinned groups (`PinnedGroup`: id, optional name, optional folder, fold) are stored on the workspace in the machine tree, in display order, and a tab points at one by `GroupId`. Everything else is an auto group worked out every frame and never stored: by repo home, or by `user@host` for an SSH pane — native or a shell that ssh'd onward — so `/home/ubuntu` on two machines no longer lands under one header. - A tab whose cwd *enters* a pinned folder joins it (deepest folder wins; a repo home equal to the folder counts, which keeps worktrees with their repo). It is edge-triggered through `EntryWatch`, so a tab dragged out while still inside the folder stays out until it leaves and comes back, and a tab restored at launch is not pulled in by where it already sits. - Groups sync as one `WorkspaceSetGroups` / `GroupsChanged`, pushed only from an edit and adopted from every pull, so a fresh window can never push an empty set over the workspace's. The machine hands tabs naming a dropped group back to auto grouping in the same mutation. Control dialect → v11. - Config: `sidebar_grouping` (three modes) and `sidebar_collapsed_groups` give way to one `sidebar_auto_grouping` toggle; folds live with the workspace. - `tty7 tab ls` reports the pinned group a tab is in (name or folder leaf; JSON carries id, name and folder). * feat(sidebar): draw pinned groups above a divider, with their own gestures The sidebar now reads as two halves: the groups you keep, in the order you put them, then a divider, then the groups it works out (Arc-style). - Pinned headers drag-reorder among themselves (their own reorder surface, so a pinned header cannot be dropped among the derived ones); the order lands on the workspace's group list, not on the tabs. - An auto header carried above the divider is pinned when let go. With nothing pinned yet the divider appears during that drag as a "Drop here to pin" zone, since a hairline at the top of the list is nothing to aim at. - A tab kept in a pinned group and dropped anywhere below the divider goes back to auto grouping; the divider lights to say so. - An empty pinned group stays, with a "+ New Tab" row that opens a tab in its folder (or where ⌘T would, for a label group) and files it there. - Folder groups carry a pin mark that unpins on click and a tooltip with the folder; auto headers show pin and "+" on hover. - Header menus: pinned — Rename, Set Folder… (local workspaces), Use Current Tab's Folder, Clear Folder, New Tab, Unpin (folder groups), Delete. Auto — Pin Group, New Tab. Nothing renames an auto group; nothing pins implicitly. * feat(sidebar): open folders as pinned groups from Finder, the file tree and the palette Every way into a pinned group the design calls for: - Drop a folder from Finder or Explorer onto the sidebar to pin it (a local workspace only — a dropped path is this machine's, and a folder group keeps a directory on the workspace's host). Files are let fall. - "Pin as Group" on a folder in the file tree, on local and remote workspaces alike, since the tree and the group are both on the workspace's host. - Palette "New Group" makes an empty label group and opens its name for typing; "Open Folder as Group…" picks a folder with the system picker, pins it and opens a tab in it. The picker browses this computer, so that one is not offered on a remote workspace. - Tab right-click "Move to Group" lists the pinned groups plus "New Group…", which files the tab in a fresh label group with its name open for typing. Pinning a folder already pinned hands back the group that keeps it rather than making a second one to split its tabs with. * fix(sidebar): let groups that arrive from elsewhere pull no tab into a folder A window draws its first frames before its copy of the workspace's groups lands, so every tab's entry watch recorded "in no folder" — and the groups landing then read as each tab walking into its folder. A restored tab, or one dragged out of its folder group, was pulled back in on every launch. Groups adopted from a pull or from another window's `GroupsChanged` now start every tab's watch over from where it is; only this window's own pin gathers the tabs inside the folder, and says so tab by tab. A tab also goes up with the group it names even when the window does not know that group yet, so a sync in that same gap cannot send every kept tab back to auto grouping. * docs(sidebar): describe pinned and auto groups, and log the change Rewrite the sidebar page's grouping section around "grouped by repo automatically; pin what you want to keep": the divider, folder and label groups, the edge-triggered join, every way to pin, and the header menus. The configuration reference swaps `sidebar_grouping` for `sidebar_auto_grouping`, the CLI reference describes the GROUP column as the pinned group, and the changelog gains an Unreleased entry (#955). * fix(sidebar): file a tab opened by the CLI in a pinned folder into it A tab that reaches a window as TabCreated — from `tty7 tab new` or another window — started its entry watch as a restored tab, so opening one inside a pinned folder left it in the auto group below. It is as new as a tab opened here, and now joins the folder like one; every window that hears of it reaches the same answer. * test(machine): build the group sets in their initializers Clippy's field_reassign_with_default on the two WorkspaceGroups the set-groups test assembles. * fix(sidebar): draw restored tabs in their auto group, and title by repo again Auto groups are not stored, so after a restart every tab sat in Ungrouped until its own repo probe came back, then jumped; before pinned groups the stored repo key put it in place on the first frame. Each tab now carries `last_auto`, the auto group it last resolved to, as a hint: stored with the tab, sent up alongside its group in `TabSetGroup` whenever the live answer moves, and used to draw the tab until the probe answers. The probe always wins and rewrites the hint, and the hint never outranks a pinned group or the folder-entry rule. Another window's hint only fills a gap, so two windows can never bounce a disagreement between them. The workspace's fallback title regained the repo majority it lost: the most common pinned folder first, then the repo most unpinned tabs were last filed under (a worktree counting toward its repo home), then a pane's cwd. * refactor: drop what the new sidebar left unused, and two clippy findings - `TerminalView::native_ssh_cwd` and its helper existed for the sidebar's old folder grouping of native SSH panes; an SSH tab now groups by host, and nothing else read it. - The file tree's context menu takes `cx` instead of `danger` and the new groups flag, back to the argument count it had on main. - A title test builds its workspace in the initializer. |
||
|
|
9f034558c0 |
feat(ssh): switch a port forward off without losing its rule (#953)
A forward could only be removed, so pointing one local port at another remote target meant deleting the rule and retyping the other one (#439). Forward rules gain an `enabled` flag (serde default on, so saved profiles and older peers keep every rule live) and the daemon a SetForwardEnabled op for panes and workspaces. Off releases the listener and keeps the entry; on rebinds it from the rule it was made from, and is refused by name when another switched-on forward of the same owner holds the port. The Ports panel and the Settings rules editor each get a switch; a switch flipped in the panel on a rule from a saved host is written back to that host. Closes #439 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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.
|
||
|
|
9b4dd53547 |
Merge pull request #916 from l0ng-ai/style/sidebar-marks-and-chrome
style(ui): give agent marks their brand colour back, quiet the toolbar |
||
|
|
fea497433d |
style(ui): give agent marks their brand colour back, quiet the toolbar
The sidebar avatar dropped its brand-coloured disc for a flat theme one, which left a column of identical grey marks: hue had been the fast way to tell one agent from another down twenty rows, and the disc was the only thing carrying it. Painting the mark itself restores the reading at a third of the coloured area, so it no longer competes with the status dot beside it — colour says who, the dot says what it wants. `mark_ink` keeps the hue and only lifts a value that cannot be seen on the surface under it, which is Codex and Grok's pure black on a dark theme. The toolbar above it had the opposite problem: `+` and the panel toggle were drawn at `sidebar_foreground`, the rung a tab title uses, so the two controls were the darkest marks in the sidebar. They drop to `muted_foreground`, level with the workspace chip, and the hover fill the variant already carried answers the pointer. The glyphs themselves: the panel icons fill their compartment so they read as a sidebar rather than a split box, and the plus carries a sixth more stroke than the closed shapes beside it — an open form at the family weight reads both larger and fainter, which is what made it the odd one out. Its cap now lands on a half pixel rather than a whole one; the whole-pixel rungs are 10px and 12px in a 16px box, and neither is the size. Claude-Session: https://claude.ai/code/session_01FG2s9mbZu6LbjjmU54X7kt |
||
|
|
fd9f589c80 |
Merge pull request #914 from l0ng-ai/feat/right-panel-refresh
style(ui): unify native colors, icons, and sidebar hierarchy |
||
|
|
6846571142 | Refine native UI hierarchy, icons, and sidebar chrome | ||
|
|
c2d2db2cfc | added support for Crush agent | ||
|
|
9e338b1d60 |
feat(agents): add Qoder CLI integration
Hook events map Qoder's lifecycle to tty7's state machine: session start, prompt submit, permission requests, MCP tool elicitation (an authorized MCP tool can still pause for user input mid-call), tool completion, stop, and session end. Compaction events are filtered out—Qoder emits a session-start after compacting the active turn, which would reset the status line to Idle without this filter, even though the turn is still running. Settings path resolution respects QODER_CONFIG_DIR for local installs, falling back to ~/.qoder/settings.json. Remote targets ignore the override (a local env var must not redirect remote hooks). Session commands support --resume and --fork-session. The resume command strips conflicting flags (--resume, -r, --continue, -c, --session-id, --worktree, --fork-session) from the original launch argv before appending the new session id. The -w/--cwd flags survive (Qoder's -w means --cwd, not --worktree). Both commands require session persistence: when --no-session-persistence is present, there is no saved conversation to reopen, so the commands return None. Tests cover compaction preservation, MCP elicitation state transitions, QODER_CONFIG_DIR's effect on the hook lifecycle (multi-case isolation), resume/fork command generation, worktree flag handling, and persistence requirements. Localization complete for en/ja/zh. Icon embedded, search keywords wired. |
||
|
|
fc94022ed0 |
feat(agent): add TraeCode CLI support (#807)
* feat(agent): add TraeCode CLI support * fix(settings): index TraeCode agent hooks |
||
|
|
2cdc26f357 |
Wire hooks, resume and detection for Kimi Code CLI (#694)
* feat(agents): wire hooks, resume and detection for Kimi Code Kimi Code CLI takes its hooks as [[hooks]] entries in the same config.toml that holds the user's providers and models, so this adds a third install strategy — a format-preserving TOML merge on toml_edit — beside the JSON map merge and the owned files. Like Qwen it reports permission requests first-class, so it gets no Notification hook. Resume rides `kimi --session <id>`; fork stays unwired, Kimi documents none. Closes #693 Signed-off-by: Austin Spraggins <spragginsdesigns@gmail.com> * fix(agents): harden the Kimi Code TOML hook merge and its resume flags The TOML merge strategy the Kimi wiring introduces round-trips a shared config.toml cleanly, but three gaps sat behind it. `hooks_state` counted only the marked entries that still named an event, so a hand-edit that dropped the key off one of nine entries left the remaining eight matching the roster exactly and the file reported Installed with a broken entry in it. Every marked entry now counts, which is what the JSON merge already did and what `refresh_hooks` needs to see. A `hooks = []` spelled as an empty inline array made install fail outright -- toml_edit keeps an empty array and an array of tables apart, but the two say the same thing and neither carries any configuration. It is now promoted rather than refused. Every other wrong-shaped `hooks` key -- a string, a table, a non-empty inline array -- still refuses with the file left byte-for-byte alone. `Stop` is not the only way a Kimi turn ends: its own event reference says `Stop` does not fire on interrupts and `Interrupt` fires instead, and a turn that dies on an error reports `StopFailure`. Without those two an Esc or a failed turn left the pane on "working" for good and `tty7 wait` could only ever time out. Both are observation-only events and report the same end of turn `Stop` does. On resume, `--agent` and `--agent-file` join the stale flags: Kimi rejects either next to `--session` at startup, and resuming rebinds the session agent by itself, so replaying them turned a working resume into a launch error. Tests cover the wrong-shaped `hooks` keys, a config.toml that does not parse on both install and uninstall, a file that does not exist yet, a second install being byte-for-byte the first, mangled and surplus marked entries, an uninstall threading between the user's own entries and the tables after them, and the `--session=<id>`, bare `--session`, `--continue` and `--agent` spellings on the resume path. --------- Signed-off-by: Austin Spraggins <spragginsdesigns@gmail.com> Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
8b5aeb0077 |
Wire hooks, resume and fork for the CLI agents that support them (#666)
* feat(agents): hook, resume and fork support for nine more CLI agents Hooks go from 7 agents to 11. Gemini, Droid and Qwen merge into their own settings.json the way Claude and Codex already do; Goose gets an owned file under the Open Plugins layout it implements. Qwen is the only one of them with a first-class PermissionRequest event, so it needs none of the notification sniffing the others do -- and deliberately gets no Notification hook at all, since that event fires for non-blocking alerts too and would strand a pane on "waiting". Resume goes from 10 agents to 17, fork from 5 to 9. Amp's `threads fork` is a real subcommand that is simply missing from `amp threads --help`. Four detection and replay bugs turned up while checking each CLI: - `python3 -m antigravity`, the documented way to trigger Python's own easter egg, was detected as a coding agent. The `antigravity` binary is the IDE's launcher shim anyway, in the shape of VS Code's `code`, not the terminal agent -- that one is `agy`. - Amp lost every launch flag on resume. It names a thread with a positional argument, so the stale-flag list had nothing to drop and the generic bare-token check rejected the whole tail along with it. - Gemini could be handed a command line it refuses to start from: `--session-id` and `--session-file` are mutually exclusive with `--resume` and were never stripped. - Cursor's `--continue` was not stripped either, leaving it to collide with the injected `--resume <id>`. Brand colours for Aider, Goose, Droid, Vibe, Qwen and Antigravity now come from first-party sources -- logo SVG fills and site CSS variables -- rather than approximations. Qwen ships its real mark instead of the generic bot glyph. Hooks stay unwired for Aider (no lifecycle mechanism exists at all), Cursor (its usable events gate permissions, and tty7's silent hook would read as a failed check and auto-allow the command), Auggie (its command field takes only script paths, needing generated wrappers, and the constraint could not be verified without a billed run), and for Hermes, Amp, Vibe and Antigravity, whose event sets are too thin to report a blocked turn. * fix(agents): strip every session-naming alias before replaying launch flags Goose spells --session-id also as --id, --name as -n, and keeps a legacy --path, all in one exclusive clap group; Qwen rejects --session-id next to --resume; Vibe shortens --continue to -c. Any of these surviving a replay broke the regenerated resume command. Qwen's --no-chat-recording also persists nothing, so it now opts the pane out of resume and fork like Auggie's --dont-save-session. The Qwen icon gains the 24x24 width/height every other agent mark carries. |
||
|
|
3cd90c6ca6 |
feat(ssh): name panes after their host, reach the host form from where you are, and test a connection (#566)
* feat(ssh): name panes after their host and reach the host form from where you are Five gaps in the SSH flow reported in #438, and the two silent no-ops around them. Panes now carry a display name: a saved host's own name, or its address when nobody named it — every host imported from ~/.ssh/config arrives nameless, and each one opened a tab reading "tty7". The name survives a title reset and a dropped link, and `strip_host_prefix` no longer cuts `deploy@10.0.0.5:2222` down to "2222" on its way to the tab strip. The host form is now reachable from the machine in front of you: the switcher's machine menu edits the host it is showing, or offers to save one for a machine reached by address or by ~/.ssh/config alias. A live connection dialled by hand can be kept as a host from the palette, with everything it was dialled with carried over — the one thing that cannot come along is an ad-hoc jump hop, and that is said out loud rather than saved broken. The New Tab menu lists the saved hosts, most-used first, and the typed address route that already understood -p, -J and config aliases. Both were behind the workspace switcher, its host dialog and the settings list. Finally, the three proxy fields are exclusive — map_proxy picks the first one filled and ignores the rest — so the ones that lose now say which field won instead of leaving it to be discovered by connecting. * feat(ssh): test a connection from the host form, and pick a host by name Three things the host form and the New Tab menu were missing. The form gets a Test button. It hands the spec to the daemon, which dials it the way Connect would — proxy, jump host, host key, auth — and drops the connection again, reporting how long it took. A test never rides an existing connection: one would answer for the credentials that connection was made with, so a password typed wrong would come back green. Anything the handshake stops to ask a person is declined on the spot and reported as what it asked for, since a form is nowhere to answer a password prompt and waiting out the two-minute prompt timeout would be a worse answer than "it got that far and wants your password". The result clears the moment a field changes: vouching for a host that was edited since is worse than saying nothing. The Auth row becomes a dropdown. Six methods is more than a segmented control can label without squeezing, and it is the row that stacks first on a narrow page. The New Tab menu scrolls — PopupMenu only does that past 20 items, and every shell on the machine plus a handful of hosts already runs off a short window — and past the five hosts it lists, Find a Host opens a filter box over all of them. * feat(new-tab): put a search box on the New Tab menu The menu is as long as the machine is — nine shells here, and a ~/.ssh/config with two dozen hosts in it is ordinary — so it needed filtering, not a scrollbar and a row leading somewhere else. A PopupMenu cannot hold a text field: it claims the keyboard for its own navigation, and there is no search input anywhere in it. So the New Tab button now opens a popover holding the same searchable list the command palette is built from, with the shells and the hosts under their own headings and one box over both. Typing filters across both groups; typing an address offers to connect to it, the way the palette does. The standalone host picker this replaces is gone with it, and the row that led there — one search reachable from the button beats two behind a menu. * revert(new-tab): put the New Tab menu back to shells only The searchable popover was the wrong shape for a button in the chrome: too big and too heavy next to the tab strip it hangs off. The menu is the plain shell list it was before this branch — byte for byte, so nothing about it needs re-reviewing — and the hosts, the search box and the row leading to a host picker are gone with it. Everything that came along to serve it goes too: the positional NewTabWithShell command, the picker's palette delegate and its compact row metrics, the standalone host palette, and the four strings they needed. Connecting to a saved host is the palette's job again, which is where it was and where it works. * fix(switcher): size and weight the machine glyphs like the icons beside them The two machine icons are drawn by hand; every other glyph in that gutter comes from lucide. Ours were built to a tighter box — ink 19.3 × 17.3 of a 24 grid against lucide's 22 × 20 — so at the same nominal 16pt the local machine rendered 11.5pt of ink beside a 14.7pt globe and read as a size smaller. Both are redrawn to lucide's extents, which also makes them agree with each other. The local machine's glyph was muted while every remote one was full strength, and while its own name was full strength either way. Beside the machine under it that read as a disabled row rather than as the computer you are sitting at. One weight for all of them now; the "Other Machines" globe keeps its dimmer register, which belongs to the muted section label it sits next to. * fix(tabs): only a port stops the host head being cut off a title Teaching `strip_host_prefix` that `deploy@10.0.0.5:2222` is an address and not a titled directory was done by requiring the tail to start with `/` or `~`. Two very common titles do neither. Debian's stock bash title is `\u@\h: \w` — a space after the colon — so `user@host: ~/work` would have stopped being cut at all, and every one of those tabs would have gone from reading `~/work` to `user@host: ~/wo…`. And tty7's own PowerShell integration writes `ann@BOX:C:/src` whenever the cwd is off the home drive, which would have read `ann@BOX:C:/src` rather than `C:/src`. Key on the port instead, which is the thing that actually makes the string an address: a tail of nothing but digits is kept whole, and everything else is the path it always was. The space belongs to the head, so the tail is trimmed on the way out. * fix(ssh): keep a connection test off the cache, off a stale form, and clear about a changed host key Three ways the new Test could answer for something other than the host in front of it. It dialled with `reuse: false` but still took the connection cache's slot lock, which is held for the whole handshake. So a test stalled every Connect to the same host behind a connection it was never going to leave them — and, queued behind a session already dialling, spent its own budget waiting and came back "connection timed out" about a host that answers fine. A test that is not going to touch the cache has no business locking it: it now skips the slot entirely, and only a reusing dial takes the guard it later fills in. The form dropped a test result whenever a typed field changed, on the grounds that the answer was about the host as it was a moment ago — but the authentication method is a dropdown, and changing it left the green line standing under a handshake the form would no longer make. And a host key that has *changed* was reported with the same words as one nobody has accepted yet. Those are not the same news: the first is a new host, the second is the server presenting a different key than the one on file. `SshTestNeed` now tells them apart and each gets its own line, in all three locales. Verified against a live sshd on localhost: refused port and unresolvable name come back in milliseconds with the connect path's own message, a password host comes back `NeedsInput { Password }` in 55 ms rather than waiting out the two-minute prompt timeout, and two tests of the same host back to back no longer serialize. * chore(palette): drop the root flag the New Tab revert left behind `grouped_root` was split out of `quick_connect_root` for the searchable host picker on the New Tab menu, which was taken back out again. Every constructor now sets the two to the same value, so the second one is a field and a doc comment describing a list that does not exist. * docs(changelog): record the SSH host form, pane names and connection test Every user-facing change in this branch: panes named after their host, the host form reached from the switcher and the palette, and Test. --------- Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
bed3c856ed |
fix(panel): redraw the right panel's tab icons and put the tree glyph on the tile ladder (#578)
* fix(panel): redraw the right panel's three tab icons The tiles render at 13px (`TILE_GLYPH`), and at that size the set had three problems, none of them about style: - `info` and `folder-closed` were both a rounded body split by a horizontal rule at nearly the same proportions, so the first and third tile could only be told apart by a notch a pixel and a half wide. - `git-branch` drew its three nodes as filled r=2.5 discs — 2.7px across at render size — which buried the 2.1 strokes between them and left the glyph reading as three dots. - The interior detail was too dense to survive: `info` carried two rules 4.8 units apart and `folder-closed` a divider 3.2 units below its front edge, both under 2.6px once rendered. Same three metaphors, same 2.1 pen, same rounded joins — only the geometry moves. The nodes go hollow so the branch is drawn with one pen rather than two. The crowded interior rules go, which leaves the folder a clean body and makes the notch the thing that separates it from `info`, rather than a second rule at a slightly different height. And each mark grows into the height `panel-right` already occupies beside them: the three had the width of that box and sat two units short of its height, which on a row of tiles reads as three smaller icons rather than as three different ones. Measured as rendered ink, stroke included, on the 24 grid: | glyph | before | after | | ----------------------------------- | ----------- | ----------- | | `panel-right` (unchanged reference) | 19.3 x 19.3 | — | | `info` | 19.3 x 17.3 | 19.3 x 18.1 | | `folder-closed` | 19.3 x 17.3 | 19.3 x 17.7 | | `git-branch` | 18.5 x 17.3 | 18.3 x 18.9 | All three stay centred on 12, 12. * fix(files): size the tree row's glyph off the tile ladder, not the rem one Glyphs in this window come from the pixel ladder in `app.rs` — `TILE_GLYPH` 13 for a chrome tile, `TILE_GLYPH_XS` 11 for the tiles a row reveals on hover — while text comes from the rem ramp. The file tree's leading folder/file mark was the one place drawing its size from gpui-component's rem sizes instead, and those two systems cannot meet: at the default `ui_font_size` of 16 the rem ladder offers `xsmall` 12 and `small` 14 and nothing in between, so the mark was always a step under the tab tiles above it — a speck beside a 14px name — or a step over them, which is a row of content outsizing the navigation that owns it. `ROW_GLYPH` is that size named once, in pixels, next to the panel's type ramp and defined as the tab tile's own glyph, so the two now agree by construction rather than by coincidence. * fix(icons): put the tree's collapsed folder on the set's box `folder.svg` is the one folder the set never squared up. It inks 19.9 x 16.1 where every other mark in the row is 19.3 wide, because its top edge overshoots the box by 0.6 on the right — which also leaves the whole glyph 0.3 off-centre that way, and 0.2 low. Nothing showed while the tree drew it a step under the chrome. It is on `ROW_GLYPH` now, the same 13px as the Files tab tile above it, and it swaps in place with `folder-open` — already on the box — every time a directory opens or closes, so the overhang is a shift in a fixed column rather than a number in a file. Same folder, same 2.8 corners, same 1.7 shoulder: the top edge gives back the 0.6 it overshot and the body takes the 1.2 of height that puts it on 19.3 x 17.3, centred on 12, 12, which is where `folder-open` and the rest of the row already are. --------- Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
3c5f14f71c |
fix(icons): draw the plus on the same optical bound as the rest of the set (#577)
* fix(icons): draw the plus on the same optical bound as the rest of the set Every icon tty7 draws itself sits on one optical bound: 3.4..20.6 of a 24 viewBox, 19.3 units of ink once the round caps are counted. `plus` was the exception at 6..18, 14.1 units — 59% of the box where the rest fill 77-80%, and tighter even than the stock lucide glyph it replaced. That was compensated at the call site instead, by handing the three chrome tiles that carry a `+` a 16px glyph (`TILE_GLYPH_LINE`) where every other tile in the same row gets 13. It worked where it was applied and nowhere else: the port-forward section's `+` sits in a 24px tile, which has no `_LINE` step to grow into, so it rendered at 7.6px of ink against the 10.5px of the icons around it. Redraw the asset onto the bound and the compensation is no longer needed anywhere — the three call sites go back to plain `chrome_tile`, and the 24px tile is fixed for free. Scaling a glyph up buys stroke as well as extent, which is the part that is easy to miss: at 16px the old art also drew 16/13 wider, so moving the `+` to 13px thinned it by a fifth even as it got longer. A cross is two hairlines with no fill to hide behind, so the weight had to come back in the art's own `stroke-width`, and the value is eyeballed rather than derived — 1.0 CSS px reads thin against the closed shapes beside it, 2.0 reads heavy-handed, and 1.75 is where it settled after walking the range on a 2x screen. `TILE_GLYPH_LINE` stays for stock lucide `close`, which has the same tight geometry and is not ours to redraw. * fix(icons): keep the plus's extra weight to the 16/13 the call site was buying The redraw put `plus` on the family's optical bound and then took its `stroke-width` to 3.2308 — 1.75 CSS px at a 13px glyph, settled by eye against `panel-left`, `panel-right` and `ellipsis` in the titlebar row. Those are the three call sites the redraw was checked at, and they are the three whose neighbours are closed shapes carrying solid fills. The other three are not: - Source Control's row strip draws `plus` (Stage) directly beside stock `undo-2` (Discard) at an 11px glyph, and pairs it with stock `minus` (Unstage) one group up. Both stock glyphs stroke 2. At 3.2308 the `+` came out 1.48 CSS px against their 0.92 — the stage button reads as the emphasised one in a strip where nothing is emphasised, and a stage/unstage pair stops looking like a pair. - The switcher's Add SSH Host row draws it at 16px in the same gutter column as `search`, which is ours and strokes 2.1. - Settings → SSH puts it next to stock `search` and stock `ellipsis`. Reading a size heavy is the same failure as reading a size small, so the weight goes to the one value that is derived rather than chosen: 2.1 × 16/13 = 2.5846, the family's own stroke times the scale-up the three chrome tiles were already applying. At `TILE_GLYPH` that renders at 1.4 CSS px, which is exactly what the titlebar `+` has always drawn at — so nothing that was verified on screen moves, and the three tiles that never had a `_LINE` step to grow into stop being overdrawn. The arm ends move to 4.9846..19.0154 to keep the round-cap tips on whole pixels at the new weight; the ink extent is unchanged at 16.6. The test now derives the weight from `panel-left`'s own `stroke-width` instead of carrying an eyeballed band, and checks both arms rather than the vertical one — a cross edited on one axis passed before. --------- Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
657bb4e0b7 | chore(assets): crop the hero screenshot tighter around the window | ||
|
|
6d47406544 |
docs(readme): add a hero screenshot of the workbench (#475)
One 1600x1132 WebP (184 KB), shown at 900 px in both READMEs. Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
2dc6a88af6 |
merge: main into the Source Control branch
Conflicts were the two streams touching the same seams, resolved by taking the newer decision on each side: - main's interface font scale (rems tokens) wins in right_panel.rs; the SCM panel keeps its local px steps until it moves onto that scale, and the now-unused PANEL_TEXT constants are gone. - main's l10n_keys! macro (idents only) means the key list carries no doc comments any more; our SCM keys fold into it, and PanelUntracked stays deleted — its only caller was the panel this branch replaced. - main's Command::localized palette style carries our Git group; ORDER keeps main's visibility and our width. - main's ansi_seed/clear_ink refactor in presets.rs carries the lane colours: lanes() now clears through the same helper semantics uses. - file_tree keeps both: main's drag-and-drop targets and this branch's git decorations per row. - diff_overlay keeps both: main's sidebar-count write-back on snapshot install and this branch's epoch read and untracked preview. - main's window.prompt SSH-close confirmation supersedes the bespoke modal our branch still carried; main's tile-glyph revert stands. - main's two new guards are satisfied: the fourteen SCM actions carry authored names on the Keybindings page (their palette wording, plus a new CmdGitToggleGraph), ja translates ScmDetached, and CmdGroupGit joins the kept-in-English list — Git is a name. 2571 tests, 0 failures. |
||
|
|
ad23a4223b |
fix(icons): a chrome glyph is the size of its neighbours
Every icon in the detail panel's top row is drawn by the same tile at the same 13px, so the sizes looked settled in the code — but each one paints a different amount of the 24 box it lives in. Measured as rendered ink, git-branch was 14.6 wide against folder's 19.9, a 36% spread on a row of five, which is why the Changes tab read a size smaller than the tabs on either side of it. The two folders were also squat, and folder-open — the Reveal button directly under the folder tab — put a second, differently sized folder in the same column. Redraw the three outliers into the box info and panel-right already use: 3.4–20.6 across, 4.4–19.6 down. git-branch stops 4% short of the others on purpose — it is three solid discs, and a filled shape reads heavier than a hairline outline at an equal extent. |
||
|
|
fee48a4c99 |
Merge origin/main into integration/polish
main shipped v26.8.2 and 15 fixes while this branch was open. Resolved: - zh: main's #417 decided the background process is called "server" in Chinese, and that decision is newer than this branch's "服务器" — took it, kept this branch's typographic quotes around {machine}, and whitelisted SettingsServer in the new every-key-is-translated test, since the zh heading is now that English word on its own. - presets.rs: this branch factored main's inline `clear` closure into Theme::clear_ink / ansi_seed; same arithmetic, so kept the methods. #400's border and caret floors and #413's legible-palette flag both survive untouched. - app.rs: took main's Option-typed `alive` argument, kept this branch's note on why a dropped tab is worth a sentence. - README / docs: agent count is now exactly 18 with Oh My Pi, so the precise number replaces both "17" and "~18"; the zh feature doc keeps its translated menu names and gains Oh My Pi in the fork list. Six keys main added are gone because the surfaces that used them were rewritten here: the home screen's relative time now runs to years, hook failures name install vs remove, Full Screen left the View menu on purpose (AppKit adds its own), the SFTP filter says "search files", and the settings index titles its CLI row by its own label. |
||
|
|
3796ec3399 |
fix(completion): stop a rustup flag describing itself
`rustup doc --unstable-book` carried "--unstable-book" as its description, so the menu printed the flag twice and explained nothing. Every sibling reads as the title of what it opens — The Cargo Book, The Rust Reference, The Embedded Rust Book — and rustup's own help calls this one The Unstable Book. Found by sweeping the specs for descriptions that merely repeat their own flag. The other eleven hits are terse but real: docker login --password really is "Password". |
||
|
|
0ab2e47829 |
fix(completion): describe every entry in the specs this machine can verify
Eleven of the twenty-nine tools with undescribed entries are installed here, so their descriptions could be quoted from the tool rather than written from memory. That closes nine more specs completely — rustup, brew, gh, make, pip, pip3, rg, bundle, cmake — and most of npm. Each line comes from the tool: rustup help for the --toolchain and --profile flags and default-host, brew(1) for `edit`, `gh completion` for --shell, make --help for -j, pip help for --files and --index, rg --help for --sort and the --no-pcre2-unicode deprecation, bundle help for `config` and `help`, cmake --help and `cmake -E` for theirs. The five `npm team` subcommands and the `--` separator are read off their usage signatures. Every spec here writes descriptions without a trailing period, so these do too. 194 gaps across 28 specs, now 162 across 19. `npm run --silent` is left alone: npm ships no man page here to quote. |
||
|
|
40698ed344 |
fix(completion): describe cargo add/remove --color like the other 41
Every other --color in the cargo spec reads "Coloring: auto, always, never"; add and remove had none, so the one flag that appears on nearly every cargo subcommand explained itself everywhere except the two newest. The spec's other cargo gaps are left alone on purpose. They are not unwritten text: `cargo tree --no-dev-dependencies`, `--prefix-depth`, `--no-indent` and the `vendor` flags beside them are from the old cargo-tree subcommand and current cargo has no such flags, while `cargo config get` is undescribed in cargo's own help. Writing prose for those would document flags that do not exist. |
||
|
|
50909b0f84 |
fix(completion): finish the descriptions git's completion menu was missing
The README sells "every flag and subcommand with its description", and git — the spec people hit most — had five entries with none: the `blame` subcommand, `bisect help`, and three flags. `blame` sat in the menu as a bare word between neighbours that all explained themselves. Filled from git's own help output rather than written from memory: "Show what revision and author last modified each line of a file", "Print a long usage message", "Dry run", "Prune remotes after fetching", "Read pathspec from file". A sweep of all 97 specs found 194 more gaps in 28 other tools — dotnet 30, yarn 27, bun 22, flutter 18, conda 14, cargo 13 lead it. Not filled here: those need each tool's own help to quote, not invention. |
||
|
|
80e8e09548 |
feat(scm): turn the Changes tab into Source Control and wire the surface up
Renames `RightPanelTab::Changes` to `Scm` in place. `#[serde(rename = "changes")]` works in both directions, so what lands on disk is unchanged and a build from before this commit reads the config back without kicking anyone off the panel they left open — a fourth variant could not do that, and 260px has no room for a fourth tab tile anyway. The action name `ShowRightPanelChanges` stays put because `Config::keybindings` is keyed by it, and every existing custom binding would otherwise be orphaned. The panel body moves to `src/ui/scm/panel.rs` byte for byte; it still renders the flat `git diff HEAD` list. Alongside it the module gets the pieces the rest of the feature is built from: the shared status glyph and colour tables (one definition instead of three that drift), the path and timestamp helpers a 260px column needs, and the panel's state types. Also wires the whole surface: fourteen actions, their key bindings, ten palette commands in a `Git` group of their own, and the translations. `ScmCommit` takes `secondary-enter`, which macOS already gives `ToggleFullscreen`; the two coexist because the commit binding is scoped to the commit box, and `every_default_chord_is_claimed_by_exactly_one_action` now checks uniqueness per context instead of globally, which is the actual invariant gpui enforces. `Config` gains `diff_view` and `scm_graph_expanded`. Both default to what happens today. Two new icons. `git-sync.svg` is deliberately not `refresh.svg`: the panel header already carries a refresh tile, and the same glyph meaning two different things one row apart reads as a bug. Adds `every_action_has_a_binding_arm`, which walks every action in `default_bindings` rather than only the ones shipping a default keystroke. The gap it closes is an action listed in Settings with no `make_binding` arm behind it: the user assigns a key and the key silently does nothing. |
||
|
|
817447bd48 |
feat(agents): recognize Oh My Pi and install its status hooks (#405)
Issue #376 asked for `omp`. Oh My Pi is a fork of Pi (can1357/oh-my-pi, descended from badlogic/pi-mono), but the fork is where the similarity stops for our purposes: it ships one binary of its own — `omp`, the only `bin` in `@oh-my-pi/pi-coding-agent`, and it never installs a `pi` — and it keeps its config under `~/.omp`. A pane running it was therefore not detected at all, and aliasing `omp` onto `CLIAgent::Pi` would have been worse than nothing: the status bridge would land in `~/.pi`, and Resume Session would offer `pi --session <id>` to a binary that spells that flag `--resume`. So it gets its own variant, wired the whole way through: | | | |---|---| | Detection | argv stem `omp`, distinct from `pi` in both directions | | Avatar | its own mark, normalized from the project's `assets/icon.svg` | | Resume | `omp --resume <id>`, opting out on `--no-session` | | Fork | `omp --fork <id>` — a verified fork command, so the menu item appears | | Hooks | Settings → Agents, at `~/.omp/agent/extensions/tty7/index.ts` | The status bridge is the one piece the fork did not change. Oh My Pi inherited Pi's extension contract intact — same default-exported factory, same `session_start` / `agent_start` / `agent_end` / `session_shutdown`, same `ctx.sessionManager.getSessionId()` — so `pi_extension_ts` now takes the agent and substitutes two things, the package it imports the type from and the slug it calls the emitter with. Pi's generated file is byte-identical to before, so no installed bridge goes stale. `--resume`, `-r` and `--session` are three spellings of one flag in Oh My Pi; all three shed when a session command is rebuilt, while `--session-dir` is a different flag and rides along. `fork_command` now honors the same `--no-session` opt-out `resume_command` already did — Oh My Pi rejects `--fork` outright under it, and no existing agent declares an opt-out. Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
b9956ad6af |
feat(switcher): two-column panel with IDEA-style Ctrl+Tab (#380)
* feat(switcher): two-column panel with IDEA-style Ctrl+Tab
The switcher listed workspaces only; reaching a tab inside one meant
opening it first. It is now two columns — workspaces on the left, the
tabs of whichever one the cursor sits on to the right — and Ctrl+Tab
raises it as a most-recently-used tab switcher that commits when the
modifier comes up.
Picking a workspace or a tab now switches this window in place. A second
window is something you ask for, with the platform modifier or "Open in
New Window", rather than what happens by default.
New workspaces get a codename ("amber-yak") instead of inheriting
whatever directory their first shell started in. The generator moves out
of worktree.rs into core::codename so both callers share it.
* fix(switcher): review fixes — platform-gate the Ctrl+Tab key test, park the new-window tab
- The key_intent test asserted only the macOS half of the Tab chord; off
macOS Ctrl *is* the secondary modifier, the raw key falls through on
purpose (the chord arrives as NextTab), and the test now says so
instead of failing there.
- open_at_tab probed a freshly opened window's tabs exactly once, but a
new window hydrates them asynchronously — route through
activate_tree_tab so the pick parks until the tab arrives.
- Escape mid-rename backs out of the rename instead of tearing down the
whole panel.
- A one-tab workspace reads '1 tab', not '1 tabs'.
Claude-Session: https://claude.ai/code/session_01V7xjxdUGWQp93KQDuFuh8d
* style: cargo fmt
Claude-Session: https://claude.ai/code/session_01V7xjxdUGWQp93KQDuFuh8d
---------
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
|
||
|
|
0190036a2e |
chore(ui): remove the Outline right panel (#375)
Removes the Outline right panel and all of its wiring: the `RightPanelTab::Outline` variant, the `ShowRightPanelOutline` action and its handler, the tab-strip button, the palette command, the keymap arm, `render_panel_outline`, `TerminalView::{command_marks, scroll_to_mark}`, the `one_line` helper, and four i18n keys.
An existing config value of "outline" falls back to the default Info tab via `de_lenient`, and a user keybinding naming `ShowRightPanelOutline` degrades to a logged warning rather than breaking the keymap.
Also drops what the removal stranded: `Marks::list` is now `cfg(test)` (its last production caller was `command_marks`), and `icons/list.svg` — the Outline button's icon, with no other user — is gone.
Closes #374
|
||
|
|
3ae340408b |
fix(windows): bundle Microsoft's ConPTY so panes can answer color queries (#360)
* fix(windows): bundle Microsoft's ConPTY so panes can answer color queries
The in-box conhost swallows a pane process's OSC 11 background query: it
never reaches tty7's emulator and no reply is ever written back, so
applications that choose a light or dark UI from the terminal background
render a dark UI under a light theme.
tty7 already answers OSC 10/11/12 from the live theme, so nothing was
missing but a pseudoconsole that forwards the question. Microsoft ships one
as a redistributable, and portable-pty already prefers a sideloaded
conpty.dll over kernel32's, so this is packaging rather than code: the pair
goes beside tty7-app.exe, where the DLL search path finds it.
Measured on Windows 11 26200, same binary, only the pair added beside it:
in-box conhost: the terminal side never sees the query; the client times
out with no reply
bundled ConPTY: the terminal side sees ESC]11;?BEL and a real pane reads
back rgb:efef/f1f1/f5f5 under catppuccin_latte, which is
the preset's exact background
The two files are one supported unit, so the release verifier fails a
package that carries only one, a mismatched pair, or the MIT notice-less
DLL. They also join PORTABLE_MANAGED_ROOTS, without which the updater would
reject every portable archive that contains them; they are deliberately not
required by verify_portable_payload, since tty7 runs without them and a
packaging slip should fail the release rather than a user's update.
build.rs stages the pair beside cargo's output so a development build does
not quietly run on the in-box host, and the daemon logs which pseudoconsole
it got.
Closes #345
* fix(windows): restage the bundled ConPTY when it goes missing
Watching only the vendored sources meant a staged copy that left the target
directory stayed gone: the build script was cached, so it never ran again to
put it back, and the build silently fell back to the in-box conhost. Cargo
treats a rerun-if-changed path that does not exist as changed, so naming the
destinations makes the staging self-healing.
Found by deleting target/debug/conpty.dll and watching the next build not
bring it back.
---------
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
|
||
|
|
6f9324727c |
Merge remote-tracking branch 'origin/main' into feat/remote-workspace
The Pi extension conflicted: main gave it the session-id forwarding doc, this branch had already moved it from `current_exe` to the target machine's binary. Both kept. `a_detached_result_lands_after_its_view_is_dropped` now pumps to a deadline instead of parking once — a `Host` call runs on `HostOps`' own pool rather than gpui's executor, so there is nothing for `run_until_parked` to wait on until the answer has already crossed back. |
||
|
|
6d70939824 |
feat(agents): make Pi a first-class agent with icon and resume (#240)
* feat(agents): make Pi a first-class agent, not a fallback one
Pi panes drew the generic robot glyph every unbranded agent shares, so a
Pi tab was indistinguishable from an Aider or Qwen one in the sidebar,
the tab chip and the tray menu (#225). Auditing the rest of the registry
turned up two more places Pi was on a default rather than handled.
The avatar. Repo practice, from the most recent addition (
|
||
|
|
68683647ee |
feat(remote): build remote panes off the UI thread, and redraw the switcher
Opening, restoring, closing or listing a remote pane each ran a routed, blocking connection straight from a gpui input callback, freezing the whole window for the length of an SSH setup. Pane tree leaves become a PaneSlot that can be Ready or Connecting, so the slot lands in the layout immediately and the wait happens in it. connect_routed now carries the same debug UI-thread guard the Host trait uses, so the class of bug fails loudly instead of shipping. The workspace switcher is redrawn on one alignment axis with one icon size, a guide rail tying a remote machine's rows to it, and the command palette's card geometry. Launch restores only the workspace the user was last in. |
||
|
|
a15f28eb73 |
feat(icons): redraw the bundled icon set to one humanist spec
All 17 tty7-drawn glyphs are redrawn to a single spec: stroke 2.1, round caps and joins, radius 3.4-4.4, a near-square 3.4->20.6 box, and filled nodes at r >= 1.6. Metaphors stay conventional throughout - a magnifier is a magnifier, a folder is a folder - so nothing needs relearning; what changed is how they are drawn. The previous set mixed weights (1.9 with a 2.4 exception for plus), left folder and folder-closed resolving to one identical drawing, and mixed terminal treatments across the row. This one holds every glyph to the same five rules: optical rather than geometric sizing, handles meeting circles on the tangent, even interior spacing, one terminal treatment, and equal apparent area rather than equal bounds. Two notes for future edits, both in the module docs: nothing here relies on partial alpha surviving rasterisation (the dock block is a flat fill), and folder-closed carries an inner rule so it stops sharing art with folder. |
||
|
|
eced0af754 |
feat(agents): give Grok its brand avatar
Grok was drawing the generic robot glyph on a slate disc — the fallback picked back when no usable mark was bundled. xAI publishes its symbol only as a ~2:1 landscape lockup that bleeds off its own canvas; traced and fitted to a 24x24 box it is unreadable as a 16px silhouette, which is what the tab chip and sidebar render. So the bundled mark is lobehub/lobe-icons' square transcription (MIT), drawn for exactly this avatar use. Its notice rides in the SVG. The slate accent goes with it. That mid-tone exists for vendors whose monochrome mark is grey or a gradient (Cursor), because a white field vanishes on a light theme; a black field has no such problem — it stays darker than even the darkest theme background and the white mark carries the badge. Grok brands in black, like Codex, so it keeps that. Adds a guard test: every CLIAgent::icon_path must resolve through the asset source. A brand mark means touching two files, and forgetting the registration costs the agent its avatar silently. |
||
|
|
0ebe68a453 |
feat(ssh): fold port forwarding and SFTP into the detail panel
Both SSH tools floated over the terminal: a tunnel icon and an SFTP icon pinned top-right, opening a 460px popover and a bottom dock. They are pane facts, so they now live where the pane's other facts already are. Port forwarding becomes a Forwards band on the Info tab, under Ports — one says what the pane listens on locally, the other what it routes across the connection. Rows take the panel's language: a mono kind letter, the bound port as the same chip a listening port gets, hover to remove, click to edit. The add form is inline, stacked to fit the column. The list re-lists on the Info tab's existing 2s poll, so a forward that dies remotely turns red on its own. SFTP becomes the Files tab's remote mode: the tab follows the detail pane, showing a local repository tree or that machine's filesystem. Same browsing model as before (breadcrumb, filter, `..`-led list, per-row right-click) relaid out for ~260px — the toolbar collapses to refresh plus a `⋯`, and the permissions column moves into the chmod form, which now names the mode it is editing. The header carries the hostname: the tab swaps between two filesystems as the pane changes, and it can rename and delete. Transfers become a footer on the panel column rather than a tray inside SFTP. It sits below every tab, so reading Info doesn't hide a running upload, and stays pane-scoped rather than aggregating every pane, which would quietly make the panel a window-level transfer centre. Opening the browser gained a step: the shell's cwd needs tty7's shell integration on the remote, which a freshly-connected host rarely has, so it fell through to `/`. A new SftpOp::Realpath resolves the login directory instead. Per-pane positions are recorded on arrival, so a first landing at `/` can no longer be remembered as a preference. With nothing floating over the terminal any more, the ⌘F find bar gets its top-right slot back — it used to be suppressed while those icons were up. |
||
|
|
1ff907f4cf |
feat(icons): draw the detail panel and chrome glyphs to one spec
The detail panel mixed four stock lucide glyphs from four different
weights and frames, and the title bar's "+" and "..." were the stock
thin cross and three stroked r=1 rings sitting next to the app's own
filled dock tiles. Side by side that read as glyphs from unrelated sets.
Thirteen icons now share one spec: stroke 1.9, corner radius 2.6-3.2, a
3.2->20.8 optical span on both axes (circles widen a little, since a
round shape reads smaller at equal geometry), and every node filled
rather than stroked -- a stroked dot hazes over below 16px, which is
where the stock ellipsis and list bullets fell apart. "+" is the one
departure: a bare cross has no enclosing shape to carry weight, so it
runs 2.4 on a tighter span.
Two shapes changed metaphor rather than just proportion: Info drops the
circled "i" -- the most-drawn icon there is, and one that says "help" as
readily as "details" -- for a panel with two lines written in it, a
picture of what the tab opens; Changes drops lucide's long arc slung
between two floating rings for an actual commit graph, which also fixes
the 11px branch mark on every sidebar row.
The override is keyed on the asset *path*, and `icon_named!` derives
`IconName` from those same filenames, so each arm redraws its glyph
app-wide rather than only in the panel. Two consequences are handled
here rather than left to discover:
- `folder` and `file` are redrawn too. Overriding only `folder-open`
would have split the file tree down the middle -- expanded rows on
the new spec, collapsed rows and every file still stock.
- the Settings nav's About row keeps its circled "i", now carried by
its own `circle-info.svg`. There the glyph labels a section, and a
document shape says nothing about *About*.
Because the paths resolve on their own, the glyphs need no call-site
changes: `Icon::new(IconName::Search)` already renders the new art.
Call sites stay on the typed enum rather than stringly paths, which a
rename would break silently.
|
||
|
|
de3896cbdf |
feat(right-panel): redesign the detail panel and chrome icons
Rework the detail panel's four tabs and the window chrome to read as a deliberate, commercial-grade surface while keeping the terminal's calm. - Chrome icons: filled-block panel toggles; Outline gets a list glyph, Changes a git-branch, Info a redrawn mark; glyphs go to 18px on the full foreground instead of the faint 15px secondary tone. - Panel body: labelled Session / Processes / Ports bands, mono values, pid/port pills, status dots on Outline, neutral M/U badges on Changes, live counts in the headers, and roomier rows. Hue only ever lands on the git add / remove / fail semantics, everything else stays neutral grey. - Fixes: the corner "…" no longer jumps a pixel when the panel opens (the top strip mirrors the TitleBar's hidden bottom border); that strip now drags the window and double-click zooms, like the rail's; and the process list stops flickering — the poll guard now spans the whole 2s cycle instead of being restarted by every repaint between ticks. |
||
|
|
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 |
||
|
|
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. |
||
|
|
cd9577c590 |
feat(agents): recognize CLI coding agents + git branch in the sidebar (#85)
* feat(agents): recognize CLI coding agents + show git branch in the sidebar Observe (never wrap) third-party coding agents running in a pane — Claude Code, Codex, Gemini CLI, Aider, Amp, OpenCode and ~10 more — and enrich the UI around them, plus front each sidebar row with its git branch and diff. Detection & identity - Command-based detection over the foreground argv (launcher basename, and interpreter-wrapped `node …/cli.js` / `npx …` forms), with user rules via `agent_commands` in config. Brand avatars on the tab chip and sidebar row. Rich status channel - A per-pane state machine (idle / working / waiting-for-you / done) driven by agent-reported events over an OSC 777 sentinel channel (`tty7://cli-agent`, versioned JSON), sniffed daemon-side and streamed to the client (DaemonMsg::AgentStatus). - `tty7 agent-hook claude <event>` + a palette installer wire Claude Code's lifecycle hooks up; the hook writes the sentinel to the controlling tty (with an ancestor-tty fallback for detached hook processes). - Avatar status dot: working (blue) / waiting (amber) / done (green); an unread finished turn gets a crisp outer ring that clears on focus. Notifications, resume, context feed - "Needs your permission…" the moment an agent blocks; "finished after Ns" per turn, honoring the notify policy (rich turns suppress the coarse exit). - Session resume: restored panes re-launch their conversation (`claude --resume …`), gated by `restore_agent_sessions` (default on). - Palette commands send the current selection or the repo `git diff` to the running agent as a ready-made prompt. Sidebar git line - New `terminal::git_status`: off-thread `git` probe (branch, or short sha when detached; `git diff --numstat HEAD` line counts) with GIT_OPTIONAL_LOCKS=0, refreshed on cwd change or command finish, dropped on a stale cwd via a generation tag. - Each row is avatar + title + `⎇ branch +N −M` (green/red), sized to content; the redundant cwd/"Working…" lines and the aggregate rollup are gone — the status dot and branch line carry it. 672 tests pass. * fix(agents): repair CI and refresh the git line when an agent turn ends - The live PTY detection test used `sh -c 'exec -a codex cat'`, but `exec -a` is a bashism dash (Ubuntu's /bin/sh) rejects — spawn bash. - cargo fmt over cli_agent.rs / view.rs / app.rs. - An agent session is one long foreground command, so the back-to-prompt edge never refreshed the sidebar's branch/diff line while the agent worked — exactly when the working tree changes. poll_agent_status now reports a turn ending (transition into Done) and the poll reprobes git on that edge too. --------- Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
4c2082235d |
revert(branding): restore original terminal-window logo (#59)
The #54 branding refresh replaced the original line-art logo with a heavier Slate-tile + gradient-ring mark. Restore the original assets (rounded terminal window frame, title-bar divider, orange cursor block) across svg/png/icns/ico, reverting to the pre-#54 versions. Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> |
||
|
|
c4bee13d83 |
feat(theme): file-based themes, in-app editor, and a UI/branding refresh (#54)
Replace compiled-in presets + colors.*/ansi_colors.* overrides with a file-based theme system: a serializable seed (bg/fg/accent/cursor/selection + ANSI-16, optional gradient/image/opacity/blur) with all chrome derived, light/dark inferred from luminance behind a WCAG guard, built-ins + user YAML + on-the-fly iTerm2 import via a hot-reloaded registry, and an in-app duplicate-to-edit color editor. Also: prompt-editor shift-click/word-drag selection and cross-platform word keys, ghostty-style tab labels, flat menu highlights, a redesigned app icon, the Background Service -> Daemon rename, and a gated TTY7_PROFILE build-timing probe. |