Skip to content

chore: sync with upstream main (1c25754) - #42

Merged
ayush5harma merged 11 commits into
mainfrom
chore/sync-upstream-2026-10-16
Oct 16, 2026
Merged

ayush5harma merged 11 commits into
mainfrom
chore/sync-upstream-2026-10-16

Conversation

@ayush5harma

Copy link
Copy Markdown
Owner

Merges upstream main 1c25754 (srothgan#445, srothgan#471, srothgan#474, srothgan#476-srothgan#481) into the fork as one merge commit (fork main 292a92e, merge base a187e1c, 48 conflicted files). Policy: one authority per invariant; where upstream now implements what the fork also had, upstream's version stays and the fork copy is deleted; fork-only behaviour is rebuilt on upstream's structure.

Fork features removed or reshaped in favour of upstream

Fork feature Now Why
/diff (fork #15): bridge get_working_diff, own viewer Removed; upstream's Git viewer (srothgan#476) Same feature; upstream reads Git in Rust and also has staged/unstaged views
/diff listing the session's own Edit/Write diffs Dropped (follow-up) Upstream's viewer is Git-only; needs a non-Git source in its worker
Picker keys c / t / d (fork #21, #22) Tab / Ctrl+T / Ctrl+D srothgan#477 makes every printable key search
/resume <id or title> in chat Removed; picker search, or claude-rs resume <title> at launch srothgan#477 made /resume argument-free
Picker 10-session cap, row title order Upstream's: all sessions searchable, name > first prompt > summary One title rule for display and search
Two-row responsive footer (fork #25, #35) Upstream's configurable single row (srothgan#481) Same facts; upstream owns layout and settings
Footer session title, 5h/7d gauges, agent count New footer fields sessionTitle, rateLimits, agents (on by default) Fork-only facts kept inside upstream's model; bar glyphs and bold title dropped
Footer alert wording ("1 permission waiting") Upstream notices (1 PEND. PERM.) Same fact
Markdown list normalisers, line-based list wrapping Upstream markdown/lists.rs (srothgan#478) Same feature; fork code-block and link styles now apply inside lists
"Claude" / "User" role labels Upstream message markers (srothgan#478, srothgan#480) Layout replaced upstream
Raw command markup in resumed history Normalized (/rename x, notices) srothgan#477's transcript_presentation.ts
Welcome crab (srothgan#479 vs fork #37) Fork pixel crab and clock kept; srothgan#479 frames, clock and tests removed Owner's rule: fork animation supersedes; srothgan#479's scheduling fixes ported

Decisions in detail

srothgan#445 session name, srothgan#471 test glob, srothgan#474 triage CI

srothgan#476 /diff: upstream wins, fork copy deleted

  • Deleted the fork's /diff: src/app/diff_view.rs, src/ui/diff_view.rs, the bridge
    get_working_diff command and working_diff event (agent-sdk/src/bridge/git_diff.ts
    and its test, wire.rs, events.rs, client.rs, event_dispatch.rs, logger and command
    parsing), render_raw_unified_diff_window, the native-diff fixture and PTY test.
    Upstream reads Git from Rust and already covers untracked files and repositories with no
    commit, plus staged/unstaged comparisons.
  • DROPPED (owner should know): the fork's /diff also listed the session's own Edit/Write
    diffs, including edits no longer in the working tree. Upstream's viewer is Git-only and
    reads through a worker with Git-backed FileChanges; carrying session diffs needs a
    non-Git source in that worker. Not rebuilt in this sync; follow-up.
  • Kept: the fork closes the diff view when the session is replaced (events/session.rs).

srothgan#477 session picking: upstream structure wins, fork actions rebuilt on it

  • src/app/session_picker.rs and src/ui/session_picker.rs are upstream's (search,
    picker_sessions, selected_session, reconcile_selection, message reader). The fork's
    MAX_PICKER_SESSIONS cap is gone.
  • Rebuilt on it: tags, confirmed delete, compact-first resume, saved sizes, the picker's
    own SDK refresh (list_sessions / sessions_list_failed), the active-session delete
    guard and the list-revision guard. Actions now target the filtered selection.
  • RESHAPED (owner should know): printable keys search under feat(resume): unify session picking and normalize saved history srothgan/claude-code-rust#477, so the fork's c, t,
    d keys moved: Tab = compact-first resume (1 MiB+), Ctrl+T = tag, Ctrl+D = delete
    (still confirmed with y). A paste goes to the tag draft while one is open, else to
    the search.
  • DROPPED: /resume <id or title> from the chat (upstream made /resume argument-free;
    the picker search finds titles). Exact-title resume stays for claude-rs resume <title>
    (bridge resume_session resolution unchanged). The PTY test for chat title resume is
    removed; the launch title test stays.
  • DROPPED: the fork's row title order (summary before first prompt); upstream's
    session_title (name, first prompt, summary, id) is the one rule for display and search.
  • /resume still refreshes the listing when it opens (fork behaviour); the startup picker
    does not, as before.
  • Bridge: transcript_presentation.ts is the one parser of saved records. Deleted the
    fork's copies in history.ts; its "killed" status for a user-stopped background agent
    moved into upstream's taskNotification. The fork's agentLaunchFields stays. The fork
    test that expected raw <command-name> markup on resume is removed (feat(resume): unify session picking and normalize saved history srothgan/claude-code-rust#477 shows /rename x).
  • Docs: /resume row and the "Resuming sessions" section describe the fork keys.

srothgan#478 chat layout and Markdown lists: upstream wins, fork styles hooked in

  • Upstream's message_layout.rs frames all messages; markdown/lists.rs owns list layout.
    Deleted the fork's list normalisers (normalize_list_indentation, indent_line, ...)
    and the fork's wrap_markdown_lines_to_physical_rows (its padded-code fast path went
    with it; performance only). The fork's "Claude"/"User" role labels are gone with feat(chat): unify message layout and stabilize Markdown lists srothgan/claude-code-rust#478.
  • Kept the fork's Markdown style sheet (headings), link shortening and shaded code blocks.
    Lists now use the same style sheet, shorten links through one link_destination_span,
    and draw nested code with the fork's render_code_block (inside lists the code sits four
    columns right of the item text; upstream's list tests updated with that offset).
  • The fork's heading renderer replaces upstream's improved preprocess_markdown; upstream's
    nested-heading pipeline test is kept and passes.
  • Palette: all upstream code moved to the fork's semantic colours (DIM -> tertiary,
    RUST_ORANGE -> accent, USER_MSG_BG -> fill, named ANSI -> theme functions).

srothgan#479 welcome crab: fork animation and clock kept

  • Kept the fork's pixel crab, its elapsed-time connecting loop and startup.timeline as the
    one clock. Deleted upstream's first_connected_at / mark_connected on StartupState,
    its ASCII frames, spinner pacing and its duplicate tests.
  • Carried feat(ui): animate the welcome crab while connecting srothgan/claude-code-rust#479's review fixes onto the fork's code: the hello window is width-aware (a
    narrow terminal holds nothing back), the loop redraws through the window even before the
    motion preference arrives (so the closing draw commits the welcome), it never redraws a
    fullscreen view, and the extra closing draw happens only while the welcome is the whole
    transcript. Ported upstream's tests for these onto the fork's helpers.

srothgan#480 prompt glyph: taken.

srothgan#481 footer: upstream's configurable row wins, fork facts become fields

  • src/ui/footer_rows.rs: upstream's single configurable row is the status row. Deleted the
    fork's two-row responsive identity/location/gauge/alert layout. Upstream's notices
    (N PEND. PERM., N MCP NEEDS AUTH, startup badge) replace the fork's alert wording;
    upstream's [Model] / Context: N% (remaining) formats replace the fork's.
  • RESHAPED: the fork-only facts are new FooterFieldIds in src/app/footer.rs, visible by
    default: sessionTitle (left, last), rateLimits ("Usage: 5h N% 7d M%", right) and
    agents (finished-agent count, right). Context remaining and usage limits keep the fork's
    70%/90% warning/danger colours. The context bar glyphs and the bold title are dropped.
  • Kept around the row: the plan line, the agent shelf and the statusLine command row.
  • Composer style (presentation.composerStyle) and presentation.footer both stay in the
    bridge catalog.
  • Upstream's footer editor tests updated for 11 fields; two async tests box App (the
    fork's larger App exceeds clippy's future-size limit).

Found by the smoke run

  • src/ui/session_picker.rs: a picker error used to be drawn over the description line
    and left its tail on screen; the error now replaces the description (regression test
    added).

Checks (Rust 1.89 via dev-env.sh, Node 24.21.0)

  • cargo fmt --all -- --check: pass.
  • cargo clippy --all-targets --all-features -- -D warnings: pass.
  • cargo test --all-features: pass (lib 2141 passed / 1 ignored; integration suites all
    pass; terminal_resize 65 passed / 1 ignored). Note:
    bridge_shutdown_deadline_covers_a_blocked_stdin_writer failed in five earlier full
    runs while the machine was loaded and passes alone; it is unchanged by the merge and
    fails 1 of 2 full runs on fork main 292a92e too (measured), so it is a pre-existing
    load flake. The final run passed.
  • cargo test --locked --all-features --test terminal_resize -- --test-threads=1: 65 passed,
    1 ignored. No rerun needed for the two known PTY flakes.
  • agent-sdk: npm ci, npm run build, node --test 'dist/**/*.test.js' (580/580),
    npm run lint, npm run knip: all pass.

Smoke (tmux, --model haiku, scratch Git repo /tmp/claude-rs-sync-1016)

  • Welcome: the pixel crab scuttled while connecting and rested once connected.
  • Prompt: "sync smoke ok" answered; the generated session name and Usage: 7d 89% appeared
    in the footer row, with the owner's statusLine row below it.
  • /diff: HEAD comparison listed ? added.txt (+1) and M notes.txt (+1, -1); the patch
    pane followed the selection; Esc returned to chat.
  • /resume: refreshed list with the current session, [saved 657 KiB], search
    (zzz -> "No sessions match"), Ctrl+D on the active session refused; after the fix, a
    Ctrl+D on another session opened the confirmation (cancelled, nothing deleted).
  • /agents: inspector opened ("No subagents yet").
  • Clean exit with Ctrl+Q; no claude-rs or bridge process left; scratch dir and
    ~/.claude-personal/projects/-private-tmp-claude-rs-sync-1016 removed. The trust prompt
    added a trust entry for /private/tmp/claude-rs-sync-1016 to the personal config, left.

ayush5harma and others added 10 commits October 14, 2026 05:09
…#445)

* feat(agent-sdk): send Claude Code's session title to the app

- add the session_title_update session update to types.ts and the Rust
  wire types, read from getSessionInfo().customTitle after every connect,
  replacement and conversation reset, and after each top-level turn when
  it changed
- drop a read that a later read, a replacement or a close superseded, and
  refresh the session list when a turn changed the title
- strip control characters once in the converter, hold the active
  session's title as one Option cleared with its identity and on a
  conversation reset, and name the terminal tab after it
- cover the read rules, resume, a launch-time name, /rename, /clear and a
  conversation reset at the bridge boundary, and the converter and reset
  handling in Rust tests

* feat(ui): show the session name above the composer and in Status

- draw a `──── name ─` rule as the editor's top row when the session has a
  title, cut with an ellipsis to the width, and give it up first on a
  one-row slot
- name the session in the Status tab by the title Claude Code reports
  instead of the listed custom title, keeping the summary fallback
- cover the rule's layout and the Status row in unit tests, and /rename and
  a Status-tab rename against the fake bridge in PTY tests

* fix(agent-sdk): send the new title after a Status-tab rename

- read the title back through getSessionInfo() after rename_session and
  generate_session_title succeed, so the composer rule, tab title and
  Status tab follow a rename made outside a turn
- keep both commands on renameSession() and the SDK's title generation;
  the session list is still emitted as before
- cover a rename and a generated ai-title at the command boundary against
  transcripts read through the SDK

* refactor(app): prefill Status rename and title generation from the live title

- start the rename draft from the title the bridge reported instead of
  the listed session's custom title, which can lag behind it
- describe the session for title generation by that title first, then
  the listed summary and first prompt as before
- the Status tab, the composer rule and both actions now read one title;
  the config tests and the Status-tab PTY test cover the prefill

* docs: describe the session name and who owns it

- add a Session Name section: /rename and the Status tab change it, the
  app shows what the session API reports, including after a reset
- state that Claude Code generates a title only for a session without
  one, and that the API's generated-title fallback shows a name where
  Claude Code's prompt bar shows none
- add a session title owner table: Claude Code persists it, the bridge
  reads and sends it, Rust holds one value that every display reads

* refactor(ui): show the session name only in the Status tab

- remove the composer rule and its layout hookup; no display placement was agreed before it was added
- restore upstream's terminal tab title so it keeps naming the folder
- keep one PTY test proving the Status tab shows the name a /rename reports
- drop the fake bridge's resume title and rename handler that only the removed tests used

* test(agent-sdk): stub the session API instead of writing transcript records

- have the SDK stand-in report titles from its own state through getSessionInfo, so no test writes CLI-private custom-title or ai-title records
- drive every case through the spawned bridge and assert the NDJSON it emits: resume, a launch-time name after the first turn, /rename, the Status rename and title generation, a conversation reset and /clear
- prove a superseded read is dropped with a held read that resolves after a later one starts
- prove a failed read is logged and sends nothing
- merge session_resume.test.ts into session_title.test.ts, since both tested the same title workflow

* refactor(agent-sdk): send the session title after every read

- remove the bridge's sentTitle copy, which mirrored the title Rust already holds
- send whatever each read returns; Rust stores it idempotently and nothing else reacts to a repeat
- keep the titleReads counter so a superseded read is still dropped
- remove the per-turn session-list refresh that depended on change detection
- cite Claude Code 2.1.288, the version bundled with the pinned SDK

* docs: describe the session name by what claude-rs does

- say where the name shows (the Status tab), when it is read, and that it is whatever the SDK session API reports
- state the generated-title fallback as a property of the API and drop claims about how Claude Code keeps titles
- name the SDK as the title's owner and the listing as a separate snapshot refreshed by listSessions
- reword the Rust field comments the same way

* fix: preserve session titles when live reads lag

* test: make SDK bridge fixtures portable

* test: align listed session event assertion

* test: use a stable SDK history fixture path
* test(agent-sdk): keep the SDK resolvable for the bridge version check

- Redirect only ESM imports of @anthropic-ai/claude-agent-sdk to the stub in the contract-test loader.
- Leave require.resolve alone so the bridge version check reads the real installed package.json.
- Fix 16 spawned-bridge tests that failed with "Agent SDK version check failed" and connection_failed.
- Make them runnable by the next commit, which stops the glob from hiding them (srothgan#446).

* fix(agent-sdk): run top-level bridge tests

- Quote the test glob so node expands dist/**/*.test.js instead of sh reading ** as *.
- Run dist/bridge.test.js and dist/bridge.contract.test.js in CI: 500 tests instead of 167.
- Use escaped double quotes so npm on Windows (cmd.exe, which keeps single quotes literal) passes the same pattern.
- Fixes srothgan#446.
* ci(issues): automate triage and duplicate handling

- manage triage labels when issues open, reopen, and close
- restrict triaged and duplicate commands to collaborators with write access
- preserve triage lifecycle for dependency monitor issues
- document commands and add permission, closure, and retry checks

* ci(issues): keep queued triage events and document label owners

- set `queue: max` so pending issue events are no longer replaced by newer ones
- list the files that name `status: triage` in the label rename note
* feat(tui): add fullscreen Git diff viewer

- add /diff with HEAD, staged, and unstaged comparisons
- show an expanded file tree, colored statistics, diffs, and full file contents
- support keyboard navigation, AltGr hunk shortcuts, and responsive footer hints
- preserve selection and pane focus when refreshing changed files
- document controls and add unit and terminal workflow coverage

* chore(build): set Cargo compilation limit to eight jobs

- allow up to eight concurrent Cargo compilation jobs
- document resource tuning and per-command overrides
- explain the separate control for test execution threads
…hgan#477)

* feat(resume): unify session selection in the fullscreen picker

- route /resume through the shared picker and remove inline session arguments
- search sessions by name, ID, and branch without case sensitivity
- preserve selection across metadata refreshes and handle empty results
- improve fork previews with aligned wrapping and a scrollable message reader
- document the workflow and add functional and rendering regression tests

* fix(resume): normalize internal records across history and fork selection

- share transcript classification between resumed history and fork selection
- render saved commands readably and exclude internal records from fork points
- preserve script text, XML, whitespace, and user message boundaries
- cover valid and malformed records with unit and SDK fixture tests
…an#478)

* feat(chat): unify message layout and assistant response ownership

- render full-width gray user cards with shared composer padding
- align assistant text and tools behind a single response marker
- keep empty responses invisible and separate live output from history replay
- centralize response ownership for submitted, queued, and autonomous turns
- add lifecycle and rendering regression coverage

* fix(markdown): preserve list structure through wrapping and streaming

- replace list marker heuristics with parsed nesting and indentation
- preserve paragraph spacing, inline styles, and nested code and tables
- keep rendered and copied text intact across cache splits
- add adversarial coverage for streaming and scrollback commits
* feat(ui): animate the welcome crab while connecting

- change the crab's eyes and legs through four poses while the first session connects, paced by the spinner frame at about 192 ms per pose
- wave and blink once for 1.2 s after the first connection of the process, then settle on the resting pose
- keep the crab still under prefersReducedMotion, on terminals too narrow to show it, for later connections, and once the transcript holds more than the welcome
- hold the welcome back from scrollback until the hello ends and redraw through that window, with one closing draw that commits the rested welcome
- record the first connection in StartupState and cover the poses, hello window, redraw scheduling and reconnection with pinned-clock tests

* docs: describe the welcome crab animation

- say in usage when the crab moves and when it stays still
- list the welcome crab beside the spinners that Reduce motion already covers
…thgan#480)

- render the transcript user-message marker from theme::PROMPT_CHAR instead of a hardcoded ">"
- keep the transcript marker dim so sent messages stay distinct from the orange composer prompt
- update transcript rendering, resume history, and terminal resize tests to the new marker
* feat(footer): add configurable single-row footer

- add General dialog for field visibility, alignment, and ordering
- autosave user layouts with queued edits, reset, and failure recovery
- render independent fields with priority notices and narrow-terminal fitting
- add persistence, keyboard, rendering, and resize regression coverage
- document footer controls and preference storage

* test(agent-sdk): isolate startup failure contract setup

- test missing executable errors without enumerating session history
- verify session-list correlation in the initialization contract
- isolate both bridge fixtures from user profiles and repository state
Merge upstream srothgan#445, srothgan#471, srothgan#474, srothgan#476-srothgan#481 so the fork follows upstream's
structure, keeping one implementation per feature.

- take upstream's /diff viewer, session picker, chat layout, Markdown lists
  and configurable footer; delete the fork's duplicates of them
- rebuild fork-only behaviour on them: picker tags, delete, sizes, refresh
  and compact-first (now Ctrl+T, Ctrl+D, Tab); session name, usage windows
  and finished agents as footer fields; fork code blocks and link styling
  inside lists
- keep the fork's pixel crab and clock, with srothgan#479's scheduling fixes
- move upstream's new code onto the fork's semantic palette
- fix a picker error that left the description's tail on screen
@cr-gpt

cr-gpt Bot commented Oct 16, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

- Windows Clippy rejects them under large_futures (16456 and 16392 bytes
  against the 16384-byte limit); types are larger there than on macOS/Linux
- wrap the LocalSet futures in Box::pin, as the fork's earlier fixes did
@cr-gpt

cr-gpt Bot commented Oct 16, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

@ayush5harma
ayush5harma merged commit 9e58256 into main Oct 16, 2026
42 of 44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants