Skip to content

feat(desktop): integrate React Desktop 2.0 - #777

Closed
yiqi-017 wants to merge 902 commits into
lsdefine:mainfrom
abraxas914:main
Closed

feat(desktop): integrate React Desktop 2.0#777
yiqi-017 wants to merge 902 commits into
lsdefine:mainfrom
abraxas914:main

Conversation

@yiqi-017

@yiqi-017 yiqi-017 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • 完整的 Desktop 2.0 垂直集成:React UI + Tauri 原生壳 + Desktop 专用适配服务。
  • 不修改 GenericAgent 核心推理引擎;包含少量桌面后端、共享 frontend 服务逻辑及三平台发布流水线。

Release packages

Scope

核心 agentmain.py、agent loop、memory、tools schema、static v1 均未修改。不过以下三处 Python/原生集成会改变运行行为:

  • desktop_bridge.py(约 line 1830):Desktop 专用 API:会话、模型、上传、记忆导入、服务、用量。对当前 Desktop 2.0 功能基本不可避免。
  • lib.rs(约 line 1438):包内 bridge 启停、端口保护、恢复、GA_ROOT、runtime 迁移。真正可打包运行不可避免。
  • conductor.py(约 line 96):conductor 模型选择、fallback 和运行状态。完整 conductor UI 所需,但可以拆成前置 PR。
  • cost_tracker.py(约 line 141):持久化逐调用 token ledger。用量页面所需,但不是“启动一个前端壳”所必需。
  • Workflow/打包脚本:CI、三平台产物、macOS 不修改签名包。发布 Desktop 所需,不属于业务逻辑。

其中 cost_tracker.py 也被 TUI 使用,是当前 PR 中影响范围最宽、最适合在 maintainer 要求严格拆分时单独拿出的部分。conductor.py 同样不是 Desktop 私有文件。

Test plan

  • Desktop Quality Gates:TypeScript、Vitest、Python 3.10-3.13、Rust production/e2e、browser E2E、Linux Tauri smoke。
  • 标签 desktop-portable-v0.2.2 的 Windows、Linux、macOS 三平台构建和 Release 上传全部成功。

lsdefine and others added 30 commits May 28, 2026 20:03
- /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 到普通流。
…fine#523)

CommonStack (https://commonstack.ai) is an OAI-compatible gateway
aggregating Claude, GPT, Gemini, DeepSeek, MiniMax, Zhipu, xAI,
Moonshot, Qwen and Xiaomi models behind a single key.

Adds it to the configure_mykey wizard as a native_oai entry,
placed alongside other multi-provider relays (openrouter, crs, gmi).
The wizard's existing probe_models() flow fetches the live
/v1/models list at config time; model_choices keeps the same
2-item fallback shape as openrouter.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(tui): drain exit-boundary intervened replay

* refine(tui): soften intervened message prompt
Update WeChat group QR code (group 19 → group 20)
…search nav (lsdefine#554)

* fix(tui): stop CRLF stdout rendering as blank lines (v2)

Windows child stdout is `\r\n`; the streaming path fed it straight to
`Text.from_ansi`, which treats `\r` as a carriage return and erases each
line's text, so a `[Stdout]` block rendered as a run of blank lines until
the turn finished (the done-state Markdown render strips `\r`). Normalise
`\r\n` -> `\n` before `from_ansi`; lone `\r` is kept so progress-bar
overwrites still work.

* fix(tui): stop leaking empty per-session task_dir signal folders

Both v2 and v3 eagerly `os.makedirs` the per-session `_intervene` /
`_keyinfo` signal dir, but the only writer (`_intervene`) already creates
it lazily — so every session that never used intervene left a stale empty
`temp/_tui_v2_<pid>_<id>` / `temp/_tui_v3_<pid>` behind (85+ accumulated).
`consume_file` tolerates a missing dir, so the eager create is redundant.

- Set only the task_dir *path*; let the writer create it on first inject.
- Remove empty dirs on session close (v2 `_cmd_close`), on graceful exit
  (v2 `on_unmount`, v3 `_cleanup`), and sweep stale ones left by crashes
  at startup (v2 `on_mount`, v3 `main`). `os.rmdir` only removes empty
  dirs, so a still-pending `_intervene` is never clobbered.

* fix(tui): repair /continue search box cursor & up-nav loop (v2)

The SearchablePicker swallowed Right while the search Input had focus
(always treating it as "select"), so the caret could never move right in
the query. And Up could leave the list but never return: from the search
box Down entered the list, yet Up at the top row was stuck.

- Right commits the highlight only when the caret is already at end of the
  query; otherwise it moves the caret within the search text.
- Up on the first list row returns focus to the search box (scoped to
  /continue — no-op for ChoiceLists outside a SearchablePicker), clearing
  the highlight so the next Down re-enters at the first row, not the second.
- Up from the search box wraps around to the bottom of the list.
fix: add plugins/__init__.py for proper package recognition
…证后增补验收线/锁边界质疑目标/遗留项如实入报告; TMWebDriver: 修mark_disconnected重复打印
/continue list previews showed JSON debris (e.g. `{`, `" } ]} === Response ===`)
for some sessions. Two causes in _preview_from_file:

1. Models sometimes emit an unclosed <summary>, so the non-greedy DOTALL regex
   pairs it with a far-away </summary> and captures === block headers / JSON
   across rounds. Now only the latest <summary> is used, and it is rejected if
   it looks like such a cross-segment capture (contains `=== `/`"role"` or
   >200 chars) — falling through instead of digging for older summaries.
2. The fallback scanned for the first non-=== line, returning JSON structure
   lines. It now uses the last real user prompt via a new _last_user(), which
   scans Prompt blocks directly (so response-less/aborted sessions still
   preview) and reuses _user_text() to skip tool_result continuations and all
   _INJECT_MARKERS (WORKING MEMORY / SYSTEM TIPS / DANGER ...).

Scanned 261 local logs: garbage previews 26 -> 0.
…ew-garbage

fix(continue): robust session preview for malformed logs
…loop, log name collision fix, checklist poll hard cap
- conductor_im_plugins: 新增 lark.py(飞书收消息插件,无状态轮询)、email.py、_TEMPLATE.py
- wechat.py/config.local.json 经gitignore排除(含个人会话ID)
- conductor.html/py: UI重构(grid/可折叠卡片/console/approvals)、action与pool化重构
- stapp.py: 移除_js_scroll_fix
- ljqCtrl_sop: 补充Click点歪诊断/DPI坐标陷阱/文本输入经验
abraxas914 and others added 29 commits July 17, 2026 16:40
* 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
# Conflicts:
#	.github/workflows/desktop-release-package.yml
#	.gitignore
#	README.md
#	TMWebDriver.py
#	agent_loop.py
#	agentmain.py
#	assets/ga_install.ps1
#	assets/global_mem_insight_template.txt
#	assets/global_mem_insight_template_en.txt
#	assets/tmwd_cdp_bridge/content.js
#	assets/tmwd_cdp_bridge/manifest.json
#	assets/tools_schema.json
#	docs/installation.md
#	docs/installation_zh.md
#	frontends/conductor.html
#	frontends/conductor.py
#	frontends/cost_tracker.py
#	frontends/desktop/.gitignore
#	frontends/desktop/package.json
#	frontends/desktop/packaging/README.md
#	frontends/desktop/src-tauri/Cargo.lock
#	frontends/desktop/src-tauri/Cargo.toml
#	frontends/desktop/src-tauri/capabilities/default.json
#	frontends/desktop/src-tauri/permissions/bridge-commands.toml
#	frontends/desktop/src-tauri/src/lib.rs
#	frontends/desktop/src-tauri/tauri.conf.json
#	frontends/desktop/static/app.js
#	frontends/desktop/static/fallback.html
#	frontends/desktop/static/i18n.js
#	frontends/desktop/static/index.html
#	frontends/desktop/static/loading.html
#	frontends/desktop/static/phosphor-icons.js
#	frontends/desktop/static/styles.css
#	frontends/desktop_bridge.py
#	frontends/stapp.py
#	frontends/wechatapp.py
#	ga.py
#	llmcore.py
#	memory/plan_sop.md
#	memory/tmwebdriver_sop.md
#	mykey_template.py
Upstream versions lack fork-specific enhancements (e2e controls,
image pipeline, token ledger, model routing).  Will cherry-pick
upstream fixes (022299a, 7fede5a, b4597a0) separately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fork's cost_tracker uses append-only ledger with _ledger_fd,
upstream uses a different approach. Restore fork version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat(desktop): integrate React Desktop 2.0 into fork main
fix(packaging): restore curated macOS DMG layout
…ation

feat(desktop): unify recovery UI and slim macOS package
@yiqi-017 yiqi-017 closed this Aug 21, 2026
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.