From 551f4096e2d0fbfc7a46e7f0d7fcc0d179a837a6 Mon Sep 17 00:00:00 2001 From: EchoTreee <2024140044@mails.szu.edu.cn> Date: Thu, 17 Sep 2026 12:06:51 +0800 Subject: [PATCH] fix: flatten multiline session titles before printing A session title can contain newlines (e.g. a pasted multi-step prompt), so counting lines to decide single-vs-multiple matches miscounted one session as many. Flatten newlines/tabs in titles in both resume and sessions. --- CHANGELOG.md | 1 + codex-switch | 7 ++++++- tests/test_smoke.py | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a7df8a..c7e5166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Corrected +- `resume` and `sessions` now flatten newlines/tabs in session titles before printing, so a single session whose title spans multiple lines is no longer miscounted as multiple matches. - Braced variables next to Chinese punctuation in CLI messages so macOS Bash does not consume part of a UTF-8 character as a variable name and abort. The existing Linux/macOS smoke suite covers these command paths. - Distinguished read-only session lookup from authenticated resume; documented shared-home parallel use as author-reported experience rather than guaranteed isolation or a fixed token lifetime. - Installation instructions now use a clone, as required by the existing installer. diff --git a/codex-switch b/codex-switch index 5175f10..6b514c1 100755 --- a/codex-switch +++ b/codex-switch @@ -247,6 +247,7 @@ rows = cur.execute(""" """).fetchall() print(f"当前 provider:{prov}(* = 与当前 provider 一致;无 * 的会话用 codex resume 可跨 provider 恢复)") for t, mp, tid, title, src in rows: + title = (title or '').replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').strip() mark = "*" if mp == prov else " " print(f"{mark} {t} {mp:<8} {src:<4} {tid} {title[:48]}") con.close() @@ -283,7 +284,11 @@ else: ORDER BY updated_at DESC """, (f"%{kw}%",)).fetchall() for r in rows: - print("\t".join(r)) + rid, title, provider, t = r + title = (title or '').replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').strip() + if len(title) > 60: + title = title[:57] + '...' + print("\t".join((rid, title, provider, t))) con.close() PY )" diff --git a/tests/test_smoke.py b/tests/test_smoke.py index 7f803ce..0b916a1 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -190,6 +190,24 @@ def test_resume_by_session_id(self): "-c", 'model_provider="new-provider"', "-c", 'model="new-model"', ]) + def test_resume_multiline_title_counts_once(self): + self.seed(provider="new-provider", model="new-model") + with closing(sqlite3.connect(self.home / "state_5.sqlite")) as db: + db.execute( + "CREATE TABLE threads " + "(id TEXT, title TEXT, model_provider TEXT, updated_at INTEGER, source TEXT)" + ) + db.executemany("INSERT INTO threads VALUES (?, ?, ?, ?, ?)", [ + ("fixture-multi", "install codex\nstep two\nstep three", "openai", 1700000000, "cli"), + ]) + db.commit() + # 标题含换行时,仍应作为「一条」会话命中,而不是被数成多行 + self.run_cli("resume", "install codex") + self.assertEqual(json.loads(self.calls.read_text()), [ + "resume", "fixture-multi", + "-c", 'model_provider="new-provider"', "-c", 'model="new-model"', + ]) + def test_installer_from_another_directory_and_destination_with_spaces(self): destination = self.base / "custom bin" result = subprocess.run(