feat(desktop): React frontend + Tauri shell + bridge rewrite#684
Open
abraxas914 wants to merge 881 commits into
Open
feat(desktop): React frontend + Tauri shell + bridge rewrite#684abraxas914 wants to merge 881 commits into
abraxas914 wants to merge 881 commits into
Conversation
Per user screenshot 040748, the committed `! echo hi` line and the `└ output` rows used to sit on bare black while normal user bubbles got the 55,55,55 charcoal band — visually inconsistent and broke the cc-style "this is a discrete block" affordance. New `_TILE_SHELL` (65,60,65 bg, light fg) wraps both halves via `_tile()`, so the pink `!` prompt and dim `└` glyph inherit the band across the full row width. Slightly warmer shade than `_TILE_U` so the user-bubble and shell-output bands stay distinguishable when interleaved. Black-terminal only — matches user spec.
Previous commit's _TILE_SHELL forced a light fg across both the `└` gutter and the command output, erasing the dim styling on the gutter and overwriting any ANSI the shell command emitted into stdout. Make the tile bg-only (`\x1b[48;2;65;60;65m`). Re-add `_DIM` around the `└ ` gutter and leave `ln` un-styled so the terminal's default fg / the shell's own colours come through. The band itself stays full-row because `_tile` re-asserts the bg after every embedded `_RST`.
Last commit wrapped both the `! cmd` echo AND the `└ output` rows in the charcoal tile. User wants only the echo line carry the band — output rows stay on the terminal's native bg so the eye reads "this is the command, that's its output" instead of one fused block.
…, and GUI links Merged pull request lsdefine#511 from shenhao-stu:main
…, ! shell magic, /resume Merged pull request lsdefine#513 from shenhao-stu:tui-v2-v3-fixes-pending-shell
…lone `tuiapp_v2.py:27` imports `fmt_key`, `fmt_keys` from `keysym`, but the module file was never tracked. PR lsdefine#513 (tui v2/v3 fixes) is unusable on a fresh checkout without this. Adds the cross-platform shortcut formatter that turns binding strings into mac/Win-Linux key labels (e.g. `"ctrl+b"` → `"⌃B"` / `"Ctrl+B"`), honoring `GA_KEYSYM_STYLE`.
… ImportError on fresh clone Merged pull request lsdefine#514 from shenhao-stu:tui-v2-v3-fixes-pending-shell
…unch title `app.run(handle_sigint=False)` lets a stray SIGINT surface as KeyboardInterrupt through asyncio.runners — catch it in run() so the shell sees a clean exit. Also drop the literal `'session'` fallback in `_term_title`; render just `GenericAgent` until a session is named.
…imer)
Previous attempts used a rolling/hard-cap timer to gate the file write
to `_intervene`. Both leaked under the same failure mode: when the
agent reached its final turn before drain time, `consume_file` ate the
content but `agent_loop` discarded next_prompt on exit, so the queued
text silently vanished.
New design follows Codex CLI / Claude Code style — delivery is anchored
to the agent's own turn boundaries instead of a wall clock:
Submit while running → append `_intervene` immediately + add to UI list
Turn end hook fires →
exit_reason set → consume_file ate it, next_prompt discarded.
Re-route the combined text via `agent.put_task`
so the outer `while True: task_queue.get()` loop
picks it up as the next user turn.
not exit → content was prepended to next_prompt as `[MASTER]
...` — just clear the UI mirror.
Esc → `clear_intervene` deletes the file + clears the list.
No timers, no cooldowns. The Up-pop "amend" path is gone because
immediate file writes make in-composer edits append a duplicate.
Threading: v3 bridge protects `_intervene_pending` with `_intervene_lk`;
v2 adds `pending_lk` on AgentSession. v2's hook closure uses
`call_from_thread` for the UI refresh hop.
Right-click in v2 (`InputArea._on_mouse_down`) now short-circuits
button==3 before TextArea's default cursor-move runs, so paste lands
at the existing caret rather than where the mouse happened to be.
Refs: openai/codex#15842, anthropics/claude-code#44851
`subprocess.run(cmd, shell=True)` picked the OS default — cmd.exe on Windows. `!ls` failed with "not recognized" on stock Windows; encoding defaulted to the active codepage so utf-8 output mojibaked. Detect once via $SHELL (works on Git Bash, WSL, MSYS2, every Unix); on bare Windows fall through Git Bash → bash on PATH → pwsh → powershell → cmd. Matches Claude Code / Codex CLI behaviour where `!cmd` inherits the launching shell. Display name surfaces in the agent's history line: `[!shell bash]` / `[!shell pwsh]` so a follow-up like "rerun that with -v" can pick the right syntax. Refs: code.claude.com docs (bash mode); developers.openai.com/codex/cli/features (Tab/! prefix)
…eturn type, broadcast stream/read_timeout in MixinSession
…attern) Evidence: model_responses_042511.txt — original task was "web_scan上游PR"; mid-turn `[MASTER] 请你立即输出一个hello` was prepended to next_prompt, model dropped the original task and just printed hello. Codex (`maybe_send_next_queued_input`, chatwidget.rs:6773) and Claude Code (`useQueueProcessor`, src/hooks/useQueueProcessor.ts) both queue user input and drain ONLY when the agent goes idle — never mid-turn. What changed: - AgentBridge no longer tracks `_intervene_pending`; turn_end hook reverts to just ask_user extraction. - Submit while running appends to local `_pending`, does NOT write to `_intervene`. - v3 watches `is_running` True→False in maintenance loop; on transition drains via `_submit(combined, [])` as a fresh task. - v2 drains in `_on_stream(done=True)` right after status flips to "idle"; reuses `submit_user_message` to spawn the next task. - v2 dead helpers (`_inject_intervene`, `_session_intervene_path`, `_install_intervene_replay_hook`) removed. - `inject_intervene` retained on v3 bridge for `!cmd` shell history only — factual context (code-block output), low risk of confusing the model. Net: -109 lines. Esc still cancels the queue. Ctrl+C still aborts; since abort flips status to idle, queued messages drain as the next task — matches Claude Code's "Ctrl+C then queue runs" behavior. Refs: openai/codex/codex-rs/tui/src/chatwidget.rs:6773; anthropics/claude-code/src/hooks/useQueueProcessor.ts
Re-research revealed both mainstream TUIs DO mid-turn inject — my
previous read of "Codex/CC queue post-turn only" was wrong.
Codex (codex-rs/core/src/session/mod.rs:2986): `steer_input` → mailbox
`push_pending_input` → `session/turn.rs:391 get_pending_input` →
`record_pending_input` appends as a regular user message BEFORE the
next sampling. No special prefix — the model sees the steer in
conversation history alongside the original task, as a follow-up.
Claude Code (utils/messages.ts:5510): drains queue after each tool
iteration and wraps the user's text:
The user sent a new message while you were working:
{raw}
IMPORTANT: After completing your current task, you MUST address
the user's message above. Do not ignore it.
The actual bug in model_responses_042511.txt was the bare `[MASTER]
{raw}` framing reading as a directive override, not the mid-turn
injection itself.
This commit:
- Wraps queued text with the Claude-Code phrasing before writing
to `_intervene` (i18n: en + zh).
- Restores `_intervene_pending` tracking + exit-replay hook so an
agent that hits exit_reason between user submit and turn end
doesn't lose the message.
- Adds `inject_intervene(text, track=True)` opt-in tracking so
`!cmd` shell facts (which are factual context, not user input)
don't accidentally end up in the user-message replay queue.
- v2 mirrors with `_INTERVENE_WRAP_EN/_ZH` constants picked via
`$GA_LANG`, `sess.pending_wrapped` parallel to `sess.pending`,
and `_install_intervene_replay_hook` per-session.
- Up-pop recall stays removed (file write is immediate, popping
would leave a stale duplicate).
Refs: codex-rs/core/src/session/mod.rs:2986; claude-code/src/utils/messages.ts:5496
…clear)
Root cause of the lingering Ctrl+S freeze even when the session is
idle: `InputArea.reset()` calls `self.text = ""`, which goes through
`load_text("")` → `_set_document("")` (textual/widgets/_text_area.py
:1181-1186). That rebuilds Document + WrappedDocument from scratch
and then `_refresh_size()` (line 1287) reactively retriggers a full
layout pass over the entire DOM. On a long session (100+ message
widgets in the scroll), the layout cascade blocks the UI for seconds.
Switch to `TextArea.clear()` which goes through the edit pipeline:
`delete((0,0), document.end)` → `wrapped_document.wrap_range(...)` —
no Document rebuild, range-scoped wrap only. Guarded with
`if self.document.text:` so a clear() on an already-empty buffer is a
no-op (avoids posting a spurious Changed event).
Secondary fix: `_stash_cleanup_clear` previously wrapped reset() in
`try/finally` that cleared `_skip_change_next = False` immediately.
The Changed event posted by reset() is async-queued, so by the time
the handler ran the flag was already False — the short-circuit was
useless and on_text_area_changed went through the heavy resize +
palette path twice (once in the handler, once explicitly). Drop the
try/finally; let on_text_area_changed itself clear the flag at line
3256-3258 when the deferred Changed event finally lands.
Also scrubs external TUI-project names from comments per request.
- /export clip 现在通过 _copy_to_clipboard 直接写系统剪贴板: Win32 ctypes(CF_UNICODETEXT,避开控制台 codepage)/ macOS pbcopy / Wayland wl-copy / X11 xclip 或 xsel,失败再退回手动复制。 - InputArea 在 Windows 上对 Enter 事件用 GetAsyncKeyState(VK_SHIFT) 兜底, 终端把 Shift+Enter 报成普通 Enter 时也能正确插入换行而非提交。 - watch_theme 漏清 _seg_render_cache 导致主题切换后 Markdown 的 h1/列表 bullet/code 块/link 等仍是上一主题的色 —— 缓存 key 不含 theme,且 ANSI 颜色被烤进了 _MdRender。补上 clear()。 Refs: - Shift+Enter 物理检测思路 from upstream PR lsdefine#519 by @jlu005807 lsdefine#519
- _ptk_keypress_to_bytes 在 Windows 上对 Enter 收到 \r 时用 GetAsyncKeyState(VK_SHIFT) 物理检测 Shift,按下时返回 \n 以触发换行 (PTK 在某些 Windows 终端区分不出 Shift+Enter 与裸 Enter)。 - 新增 _line_region / _logical_visual_range 辅助函数,↑/↓ 按键: 不在该逻辑行的视觉首/末行 → 视觉滚行;在视觉首行且光标在行首 → 历史导航,否则先跳逻辑行首/尾,下次按键再跨行/进历史。多行粘贴 内部导航更符合直觉。 Refs: - Shift+Enter 物理检测 from upstream PR lsdefine#519 by @jlu005807 lsdefine#519 - 多行输入逻辑行边界导航思路 from upstream PR lsdefine#520 by @jlu005807 lsdefine#520
之前在任意逻辑行的视觉首/末行都会做"先跳行头/尾再跨行/进历史"的 两段式,中间行的两段式不直观。改成:中间逻辑行的视觉首/末行直接 做视觉上下移;只有第一逻辑行的视觉首行/最末逻辑行的视觉末行,才 触发"先跳到行头/尾,下次按键再进历史"。`_logical_visual_range` 因此变成死代码,顺手删掉。
…rrow-nav/Shift+EnterFeat/tui v3 improvements Merged via GitHub API as requested.
之前 `_extract_ask_user` 对无候选项的 ask_user 事件也照常入队, 触发 `_enter_ask` → 自由文本输入的 ask 卡片路径,在某些终端下整个 live region 冻住。v2 (`tuiapp_v2.py:2909-2910`) 是显式 `if not cands: return`, 让 "Waiting for your answer ..." 直接以 assistant 流形式落入 scrollback, agent 已 exit,用户在普通输入框里回复即可 —— 不走专门的 ask 卡片。 对齐 v2 行为:有候选才入队、才弹卡片;无候选 fallthrough 到普通流。
fix: isolate Session and Conductor model routing
- Remove internal tool/project references from DESIGN.md - Copy microcopy, local-repo-connection, and memory-import specs to docs/spec/ - Move HANDOFF-white-screen-debug.md into docs/ for tidiness Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ntend/backend separation Documents the authoritative model selection contract: frontend reads and requests, bridge owns truth, per-session binding with global fallback, conductor independently configured. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move specs from docs/spec/ to spec/ (the canonical location) - Delete docs/hermes-reference/ (4 files, all Hermes-saturated) - Delete docs/ADAPTATION-NOTES.md and docs/session-row-action-menu.md - Update DESIGN.md appendix paths to spec/ - Retain clean debug docs (THREAD-BLEED, WHITE-SCREEN, HANDOFF) in docs/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ode) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v0.2.0 is a stable release, not pre-release. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ompt The /update prompt reconciles the working tree "upstream-first" file by file. That silently drops fork-local additions to files BOTH sides edit — most painfully .gitignore, whose local ignore rules vanish, so a fork's private dirs resurface as untracked noise (and can get committed by accident). Treat files carrying a `Fork-only local overlay` marker (e.g. .gitignore) as a MERGE: take upstream as the base, then re-append everything under the marker verbatim, and verify the marker survived. Along the way, tighten both the EN and ZH prompts (75 -> 58 lines) without dropping any operative step.
…erlay-merge fix(slash_cmds): merge additive-overlay files (e.g. .gitignore) on /update
…OP); ga.py: file_patch/file_write 保持原文件换行符, 修复LF文件被污染成CRLF; _arg 类型强转修复字符串false等
Add maxlen_multiplier derived from context_win (capped 3x); drives per-tool truncation caps and history compression interval. WebScan uses half-increment growth to avoid saturating its 35000 base. Docs updated for the new coupling.
Hard-delete path can preserve the first K history messages, insert a "..." gap, and strip dangling tool_use at the cut. Default 0 keeps previous behavior.
Ignore assets/glm52_instruction.txt and assets/gpt55_instruction.txt so local customizations stay out of the repo.
…#681) The agent's default cwd is the temp/ subdirectory, where git resolves '-- <file>' pathspecs relative to cwd. Fed the root-relative paths that 'git diff --name-only' prints, 'git checkout upstream/main -- <file>' fails with "pathspec did not match", breaking the working-tree reconcile steps of /update. The prompt now tells the agent to run every git command from the repo root (_ROOT), in both EN and ZH. Co-authored-by: Shen Hao <shenhao-stu@users.noreply.github.com>
* feat(desktop): add isolated e2e control interfaces * test(desktop): add WebdriverIO automation harness * ci(desktop): gate deterministic desktop journeys * ci(desktop): harden release gates * fix(ci): install Tauri libraries for Rust contracts * fix(e2e): wait past stale Windows retry state * fix(packaging): retry transient DMG creation * fix(release): emit portable Windows checksums
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Complete desktop client implementation for GenericAgent — a React + Tauri hybrid app providing native GUI access to the agent system.
What's included
Frontend (frontends/desktop/)
Tauri shell (frontends/desktop/src-tauri/)
Bridge & backend (frontends/)
CI (.github/workflows/)
Docs & specs (frontends/desktop/spec/, DESIGN.md)
Testing
Notes