Commit Graph
788 Commits
Author SHA1 Message Date
nianyucatfish e40c0f19cb fix(tui): drain exit-boundary intervened replay (#533)
* fix(tui): drain exit-boundary intervened replay

* refine(tui): soften intervened message prompt
2026-05-29 21:55:50 +08:00
Frank-Gradient 3a4018ff25 feat(wizard): add CommonStack as a unified API gateway provider (#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.
2026-05-29 21:34:10 +08:00
Liang Jiaqing 20fbc5e3cb Update SOP notes and response history window 2026-05-29 21:02:31 +08:00
Liang Jiaqing 7d57e82b36 Refine goal hive master duty delivery quality 2026-05-29 21:00:03 +08:00
Liang Jiaqing c553be0b58 docs: clarify goal hive master instructions 2026-05-28 22:30:16 +08:00
Liang Jiaqing 0dbef3385a Merge PR #526: fix(tui-v3): skip ask card when ask_user has no candidates 2026-05-28 22:28:25 +08:00
yanghang 98a99ed22c fix(tui-v3): skip ask card when ask_user has no candidates (v2 parity)
之前 `_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 到普通流。
2026-05-28 22:18:27 +08:00
LJQ 9e73854f43 Merge PR #525: fix(tui): v2 theme/clipboard/Shift+Enter, v3 arrow-nav/Shift+EnterFeat/tui v3 improvements
Merged via GitHub API as requested.
2026-05-28 21:44:13 +08:00
yanghang a02cff8d03 refine(tui-v3): 行头/行尾跳转仅在首/末逻辑行触发
之前在任意逻辑行的视觉首/末行都会做"先跳行头/尾再跨行/进历史"的
两段式,中间行的两段式不直观。改成:中间逻辑行的视觉首/末行直接
做视觉上下移;只有第一逻辑行的视觉首行/最末逻辑行的视觉末行,才
触发"先跳到行头/尾,下次按键再进历史"。`_logical_visual_range`
因此变成死代码,顺手删掉。
2026-05-28 21:14:48 +08:00
yanghang 8f8166ea18 Merge remote-tracking branch 'upstream/main' into feat/tui-v3-improvements 2026-05-28 21:14:47 +08:00
yanghang 35dc1c0f20 feat(tui-v3): Shift+Enter on Windows + logical-line arrow navigation
- _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 #519 by @jlu005807
  https://github.com/lsdefine/GenericAgent/pull/519
- 多行输入逻辑行边界导航思路 from upstream PR #520 by @jlu005807
  https://github.com/lsdefine/GenericAgent/pull/520
2026-05-28 21:14:34 +08:00
yanghang 3515ac646e fix(tui-v2): clipboard copy + Shift+Enter + theme-switch markdown colors
- /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 #519 by @jlu005807
  https://github.com/lsdefine/GenericAgent/pull/519
2026-05-28 21:14:21 +08:00
Liang Jiaqing 58a56de26f Merge PR #521 2026-05-28 20:03:42 +08:00
Liang Jiaqing a9b5450819 Merge PR #520 2026-05-28 20:03:42 +08:00
Liang Jiaqing b2caa7ac31 Merge PR #515 2026-05-28 20:03:41 +08:00
Shen Hao c19bed94cb fix(tui-v2): Ctrl+S no longer freezes on long sessions (use TextArea.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.
2026-05-28 19:09:21 +08:00
Shen Hao 18f1bcde50 fix(tui): restore mid-turn inject with Claude-Code wrap (not post-turn)
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
2026-05-28 18:47:02 +08:00
Shen Hao d407401993 fix(tui): queued messages drain post-turn, never mid-turn (Codex/CC pattern)
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
2026-05-28 17:24:20 +08:00
Jiaqing Liang db979aafc8 feat: force non-stream mode for reflect/task, fix BaseSession.ask() return type, broadcast stream/read_timeout in MixinSession 2026-05-28 16:15:41 +08:00
Shen Hao f9e5e53247 fix(tui): !cmd runs in user shell, not hardcoded cmd.exe / /bin/sh
`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)
2026-05-28 16:15:37 +08:00
Shen Hao 474b526939 Merge upstream/main (prefer upstream on conflict) 2026-05-28 15:25:29 +08:00
Jiaqing Liang 57b71e995c feat: externalize long user prompts (>1500 chars) to temp file 2026-05-28 15:22:34 +08:00
Jiaqing Liang 26f22072e2 refine goal hive SOP: add master_duty, streamline entry, update goal_mode prompt 2026-05-28 14:43:14 +08:00
jlu005807 b7d413213b refine(tui-v3): remove redundant \n guard, visual row is sufficient 2026-05-28 13:13:56 +08:00
Shen Hao f0eeeee9ed fix(tui): rebuild pending-queue around turn_end hook (drop cooldown timer)
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
2026-05-28 13:09:39 +08:00
jlu005807 4bf95add78 feat(tui-v3): v2-style arrow navigation with logical line boundaries 2026-05-28 12:32:21 +08:00
Shen Hao 5f104d1d30 fix(tui-v3): quiet Ctrl+C exit + drop placeholder session in first-launch 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.
2026-05-28 11:04:02 +08:00
yanghang a69999eb16 Merge remote-tracking branch 'upstream/main' into feat/tui-v3-improvements 2026-05-28 10:23:14 +08:00
LJQ fd884b0651 Merge PR #514: fix(tui-v2): add missing keysym.py — tuiapp_v2 ImportError on fresh clone
Merged pull request #514 from shenhao-stu:tui-v2-v3-fixes-pending-shell
2026-05-28 10:18:14 +08:00
Shen Hao bebc3ba9e8 fix(tui-v2): add missing keysym.py — tuiapp_v2 ImportError on fresh clone
`tuiapp_v2.py:27` imports `fmt_key`, `fmt_keys` from `keysym`, but the
module file was never tracked. PR #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`.
2026-05-28 10:13:21 +08:00
yanghang 274be82bbd Merge remote-tracking branch 'upstream/main' into feat/tui-v3-improvements 2026-05-28 10:13:18 +08:00
LJQ 11a0dfef55 Merge PR #513: fix(tui): v2+v3 bug fixes, pending input queue, ! shell magic, /resume
Merged pull request #513 from shenhao-stu:tui-v2-v3-fixes-pending-shell
2026-05-28 09:01:47 +08:00
LJQ c7f8c056a6 Merge PR #511: Update README with installation, configuration, and GUI links
Merged pull request #511 from shenhao-stu:main
2026-05-28 09:01:39 +08:00
Shen Hao 5f92cd1b80 fix(tui-v3): keep shell └ output rows on bare terminal bg
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.
2026-05-28 04:16:17 +08:00
Shen Hao 8804218d28 fix(tui-v3): keep └ output fg colors — shell tile becomes bg-only
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`.
2026-05-28 04:13:49 +08:00
Shen Hao 14186e50f3 fix(tui-v3): render shell-mode echo + output as full-width charcoal tile
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.
2026-05-28 04:11:24 +08:00
Shen Hao ebb29c57ba fix(tui): v2+v3 bug fixes, pending input queue, ! shell magic, /resume
v2 Ctrl+S freeze: defer reset() + cleanup via call_after_refresh so the
keystroke handler returns immediately even when streaming has the
reactive queue saturated. Added _skip_change_next flag to short-circuit
on_input_area_changed during the deferred clear.

v3 terminal title: route _set_term_title via os.write(1,...) — sys.stdout
gets redirected to sb_agent.log during PTK app run, so OSC 0 escapes
were silently ending up in the log file. Default _session_name = 'session'
for v2 parity, and repaint title on running→idle transition.

v3 input row bg fill: _tile() now pads explicit bg-active spaces to
width — PTK's cell renderer doesn't honour \x1b[K (erase-to-EOL), so
the user bubble's charcoal band used to stop at text length.

v3 /emoji picker: arrow-key menu (mirrors /llm). Pet styles cleaned to
bear (default) + cat + dot + unicode. Bear calm tier restored to ʕ•ᴥ•ʔ.
• used for the calm tier, o for focused — matches user-requested mood
progression. Pet frame rate decoupled from spinner via self._spin // 5.

v3 ask_user "coderun freeze" fix: _tool_status no longer marks an
in-flight ask_user chip as ✓ ok when the stream contains the
"Waiting for your answer ..." marker. Bumped DoneEvent grace from 2 s
to 10 s when the marker is in the stream so a slow ask_user_queue.put
doesn't cause the picker to fall through to _finalize.

v3 /scheduler picker: added pre_checked kwarg to _show_menu so the
running set lands atomically. slash_cmds._match_service relaxed to
path-only matching so directly-launched (`python reflect/foo.py`)
reflect tasks are detected. Running rows highlighted in functional
green. Confirm card accepts ← as cancel (parity with Esc) — same on
v2 ChoiceList.

v3 keybindings: Esc Esc (within 800 ms) → /rewind (handled in
_handle_key so PTK's Esc interception path actually fires).

v3 pending input queue: agent.task_dir wired so ga.turn_end_callback
can consume `<task_dir>/_intervene`. New AgentBridge.inject_intervene
appends to the file (atomic vs read-modify-write), and _drain_pending
routes the combined message either through that hook (mid-turn) or via
put_task (idle). Cooldown 5 s, resets per new pending. ↑ recalls the
last queued message, Esc clears the queue. v2 has equivalent shape:
AgentSession.pending + per-session agent.task_dir + _inject_intervene
+ _poll_pending timer.

! shell magic: prefix `!` enters shell mode — pink border, prompt mark
swaps `❯` → `!`, body strips the leading `!` so the glyph appears
once. Enter runs the rest as `subprocess.run(shell=True, timeout=30)`,
echoes `! cmd` + `└ output` into scrollback, and appends to LLM
history (via _intervene when agent is running, direct backend.history
append when idle — sidesteps the iterator race).

/resume: forwarded as a literal to the agent so GA's _handle_slash_cmd
(agentmain.py:124) can expand it. Added to v3 _cmds() + v2 COMMANDS +
slash_cmds.COMMANDS + i18n + /help + Tips.

Turn marker regex fix: agent_loop.py:52 switches `**LLM Running
(Turn N) ...**` to the short `**Turn N ...**` when task_dir is set.
Extended all v3/v2 turn-marker regexes to match either form.

Cherry-picked upstream fixes:
- PR #466 (8ae3645): _collapse_choice early-return when the
  on_select callback (e.g. /rewind) detaches the anchor widget.
- PR #461 (08f21e8): SelectableStatic.has_valid_selection_parent +
  app-level _is_stale_selectable_mouse_event filter that swallows
  mouse events on detached widgets.
2026-05-28 04:06:28 +08:00
Shen Hao 156802b694 Enhance GETTING_STARTED with installation and config details
Added installation instructions for Windows and Linux, including one-click install options and manual clone instructions. Updated configuration examples and GUI launch commands.
2026-05-27 23:16:36 +08:00
Shen Hao 44b0e0d80d Update roadmap and community GUI links in README 2026-05-27 23:16:09 +08:00
yanghang d9f2293522 Merge remote-tracking branch 'upstream/main' into feat/tui-v3-improvements 2026-05-27 22:43:03 +08:00
Shen HaoandShen Hao 7ccb90d0fa fix(tui): polish tui_v3 Windows UX — 6 issues (#510)
1. _TILE_U: switch tile bg/fg to truecolor (48;2;55;55;55 / 38;2;230;230;230)
   so the file-tree tiles render legibly on Win Terminal dark themes
   instead of a muddy 8-color block.
2. _ticker: tighten the redraw cadence 0.4s -> 0.1s so the spinner and
   status line feel responsive on Windows.
3. terminal title: add _set_term_title() helper and emit OSC 0 on init /
   session new / rename / quit so the tab title tracks the active session.
4. _drain: stream-aware grace window — when the pending stream carries a
   pending ask_user ("Waiting for your answer"), extend the post-done poll
   so the question card is not swallowed before the prompt appears.
5. /emoji command: split _PETS into _PETS_UNICODE / _PETS_ASCII behind a
   module-level _pet_style toggle; add the /emoji dispatch + _cmd_emoji
   handler so users on fonts without emoji can fall back to ASCII pets.

Local-only edits, no cross-module API change; AST parses clean.

Co-authored-by: Shen Hao <shenhao-stu@users.noreply.github.com>
2026-05-27 22:36:38 +08:00
Shen HaoandShen Hao 3621d96224 feat(tui): add /conductor command + tips/i18n polish (#509)
- slash_cmds: register /conductor bundle + prompt_for builder (frontends/conductor.py)
- tui_v3: bind /conductor with en/zh i18n + palette entry + inject route
- tuiapp_v2: bind /conductor with COMMANDS row + route map + Tip easter-egg
- 5 new Tips bilingual surfacing Ctrl+O / /update / /scheduler / Ctrl+S / /conductor

Co-authored-by: Shen Hao <shenhao-stu@users.noreply.github.com>
2026-05-27 22:24:34 +08:00
nianyucatfish 7d001ca8a7 fix(tui_v2): /continue resumes unfinished plan + /stop refills input (#508)
/continue previously pushed plan_scan_baseline past every restored
message, so plan_state.is_active() saw an empty slice and hid the card —
even when the prior session's plan.md still had `[ ]` items the user
wanted to keep working on. `working['in_plan_mode']` isn't replayed by
the log restore either, so the card never came back.

Make the baseline conditional: default to 0 so the scanner walks the
full restored history; only push past it when the restored plan.md is
already all-done, suppressing the stale ✓ card. Resolved-path missing
or empty items naturally fall back to "no card".

/stop now also refills the input box with the just-sent user message,
so an interrupted send is one keystroke from edit-and-resend. Only
when the box is empty (don't clobber a half-typed follow-up). Agent
history is untouched — a resend duplicates the turn in LLM context;
/rewind 1 is the manual escape.

Behaviour matrix (/continue):
  unfinished plan  → baseline=0, scanner finds path, card resumes
  completed plan   → baseline=len(msgs), card stays hidden
  plan.md deleted  → resolve_path None, card stays hidden
  fresh enter_plan_mode after continue → working flag re-arms, normal
2026-05-27 22:05:00 +08:00
yanghang 2b4bfe989e fix(tui_v2): /continue resumes unfinished plan + /stop refills input
/continue previously pushed plan_scan_baseline past every restored
message, so plan_state.is_active() saw an empty slice and hid the card —
even when the prior session's plan.md still had `[ ]` items the user
wanted to keep working on. `working['in_plan_mode']` isn't replayed by
the log restore either, so the card never came back.

Make the baseline conditional: default to 0 so the scanner walks the
full restored history; only push past it when the restored plan.md is
already all-done, suppressing the stale ✓ card. Resolved-path missing
or empty items naturally fall back to "no card".

/stop now also refills the input box with the just-sent user message,
so an interrupted send is one keystroke from edit-and-resend. Only
when the box is empty (don't clobber a half-typed follow-up). Agent
history is untouched — a resend duplicates the turn in LLM context;
/rewind 1 is the manual escape.

Behaviour matrix (/continue):
  unfinished plan  → baseline=0, scanner finds path, card resumes
  completed plan   → baseline=len(msgs), card stays hidden
  plan.md deleted  → resolve_path None, card stays hidden
  fresh enter_plan_mode after continue → working flag re-arms, normal
2026-05-27 22:01:27 +08:00
Shen HaoandShen Hao 91fcdf51b4 fix(tui): slash-cmd polish, bundle i18n sync & settle spinner on abort (#507)
* fix(tui): slash-cmd polish — /scheduler perf, v2 i18n typo, v3 bundle i18n

- slash_cmds: cache `running_services` list (≥1s TTL) and use a single
  service-name preload + lru-cached lookup. /scheduler picker cold path
  ~2.1s → ~1.0s, warm path ~0ms. Cache is invalidated whenever
  `start_service` succeeds so the picker reflects the new state on the
  next open.
- tuiapp_v2: drop the stray space inside `/reload-keys` zh description
  ("重新加载 mykey.py" → "重新加载mykey.py").
- tui_v3: route the remaining slash_cmds-bundle rows (/autorun,
  /morphling, /goal, /hive, /scheduler) through _t() the same way
  /update already was, with matching en/zh entries in _I18N. Keeps the
  v3 command palette fully bilingual.

* tui: settle spinner on abort + DRY-extract annotation helpers

Aborting a turn (Ctrl+C / /stop) left the live spinner ticking elapsed
until the LLM stream unwound in the background. Now we freeze a
`_stop_summary` snapshot the instant the user aborts and flip the line to
a settled "Stopping…", then "Stopped after Xm Ys" once done.

- ChatMessage._stop_summary: abort-time (elapsed, in, out) snapshot
- _mark_stopping(): freeze + repaint every in-flight assistant on /stop
- _stopping_annotation() / _done_annotation() stopped-state branch
- DRY: _fmt_tokens() single source for `↑ N · ↓ M`, _freeze_summary()
  single source for the snapshot tuple (de-dups spinner/done/stopping
  and the two capture paths)
- carries the branch's existing ask_user multi-choice "; ".join collapse

---------

Co-authored-by: Shen Hao <shenhao-stu@users.noreply.github.com>
2026-05-27 21:28:12 +08:00
Liang Jiaqing 49970b539d ljqCtrl: GrabWindow支持str标题+找不到窗口assert报错 2026-05-27 19:29:52 +08:00
Liang Jiaqing 73c0ccc9d9 ljqCtrl: add Activate/GetForeground/Click check; SOP精简39行; ui_detect物理坐标提醒 2026-05-27 19:02:10 +08:00
LJQ a3173b8981 Merge PR #504: fix(tui): /scheduler UX polish — hide cron advisory, ask_user-style confirm, running-state + untick-to-stop
Merged pull request #504 from shenhao-stu:fix/tui-scheduler-ux
2026-05-27 18:47:06 +08:00
LJQ 37c7c528c9 Merge PR #503: feat(slash/update): rework /update into a dual-branch upstream sync
Merged pull request #503 from shenhao-stu:feat/update-prompt-dual-branch
2026-05-27 18:46:59 +08:00
Liang Jiaqing 01f46b75bb refactor: fix_messages rewrite, Click check, ui_detect batch OCR 2026-05-27 16:49:07 +08:00