From ea3705991433b4730a1ffa88fe7b6f5da86a28b0 Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 13 Aug 2026 14:16:47 +0800 Subject: [PATCH] emrg: TUI status bar shows current version (rant 2026-08-13T14:11:03) --- Agent.md | 2 +- emrg/client/app.py | 28 ++++++++++++++------- tests/test_app_status_left.py | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 tests/test_app_status_left.py diff --git a/Agent.md b/Agent.md index c67ce4e..75a2e4c 100644 --- a/Agent.md +++ b/Agent.md @@ -118,7 +118,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design: pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.port; python -m emrg ``` -Python: `uv run pytest tests/ -v` (764) — import check: `uv run python -c "from emrg.client.app import run_client"` +Python: `uv run pytest tests/ -v` (769) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (231: 44 daemon_client + 19 conn-manager + 22 app-commands + 109 renderer smoke + 15 i18n + 7 integration + 3 commands + 5 build-config + 7 gui-state) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文) Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响) diff --git a/emrg/client/app.py b/emrg/client/app.py index 07385ab..80622bf 100644 --- a/emrg/client/app.py +++ b/emrg/client/app.py @@ -28,6 +28,23 @@ logger = logging.getLogger(__name__) +def _format_status_left(title: str, sid: str, model: str = "") -> str: + """Format left status: version + session title + short ID + model. + + Module-level so it is unit-testable (rant 2026-08-13T14:11:03). + """ + import emrg + ver = getattr(emrg, "__version__", "dev") + parts = [f"v{ver}"] + if title: + parts.append(f"{title} ({sid[:8]})") + else: + parts.append(sid) + if model: + parts.append(f"[{model}]") + return " ".join(parts) + + # ── Clipboard image support (platform-adaptive) ───────────── def _detect_clipboard_image() -> tuple[bool, str | None]: @@ -212,15 +229,8 @@ async def interactive(init_auto_evolve: bool = False): stdin_queue: asyncio.Queue = asyncio.Queue() def _status_left(title: str, sid: str, model: str = "") -> str: - """Format left status: session title + short ID + current model.""" - parts = [] - if title: - parts.append(f"{title} ({sid[:8]})") - else: - parts.append(sid) - if model: - parts.append(f"[{model}]") - return " ".join(parts) + """Format left status: version + session title + short ID + model.""" + return _format_status_left(title, sid, model) busy = False; server_id = ""; need_new_assistant = False; session_title = "" current_model = "" # model name tracked independently of server_id (rant 2026-08-11T20:02:43) diff --git a/tests/test_app_status_left.py b/tests/test_app_status_left.py new file mode 100644 index 0000000..ee78ab8 --- /dev/null +++ b/tests/test_app_status_left.py @@ -0,0 +1,47 @@ +"""Unit tests for app._format_status_left — status bar left section. + +Rant 2026-08-13T14:11:03: TUI status bar left segment must show the current +EMRG version number (e.g. ``v0.2.30 emrg-main (s_260727) [deepseek-v4-flash]``). +The formatter is module-level so it is unit-testable. +""" + +import pytest + + +class TestFormatStatusLeft: + def test_version_prefix(self): + """Left status starts with v.""" + from emrg.client.app import _format_status_left + import emrg + + out = _format_status_left("main", "s_260727", "deepseek-v4-flash") + assert out.startswith(f"v{emrg.__version__} ") + + def test_title_sid_model_layout(self): + """Title (short sid) + [model] follows the version prefix.""" + from emrg.client.app import _format_status_left + + out = _format_status_left("main", "s_260727", "deepseek-v4-flash") + assert "main (s_260727)" in out + assert out.endswith("[deepseek-v4-flash]") + + def test_no_title_uses_sid(self): + """Without a title, the raw short sid is shown.""" + from emrg.client.app import _format_status_left + + out = _format_status_left("", "s_260727", "") + assert out.endswith("s_260727") + + def test_no_model_omits_brackets(self): + """Without a model, no [..] section appears.""" + from emrg.client.app import _format_status_left + + out = _format_status_left("main", "s_260727", "") + assert "[" not in out + + def test_sid_truncated_to_8_chars(self): + """Long session ids are truncated to 8 chars in the title form.""" + from emrg.client.app import _format_status_left + + out = _format_status_left("main", "s_260727abcdef", "") + assert "main (s_260727)" in out