Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/claude_statusbar/render_thin.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,19 @@ def _displacement_suffix() -> str:
cmd = sl.get("command")
if not isinstance(cmd, str) or not cmd.strip():
return ""
name = Path(cmd.strip().split()[0]).name
if "claude_statusbar" in cmd:
# `<python> -m claude_statusbar.cli render` — ours, just not via the
# console script. See setup._invokes_our_module.
return ""
# Split on both separators rather than via Path: a `C:\...\cs.EXE` entry
# must still reduce to its basename when this code runs on POSIX (CI, and
# a settings.json synced off a Windows box), where PosixPath keeps the
# whole backslash string as one `.name`.
name = cmd.strip().split()[0].replace("\\", "/").rsplit("/", 1)[-1].lower()
for _ext in (".exe", ".cmd", ".bat"):
if name.endswith(_ext):
name = name[: -len(_ext)]
break
if name in _OUR_BINARY_NAMES:
return ""
# ANSI red. Kept short so it doesn't blow up the bar on narrow terminals.
Expand Down
25 changes: 24 additions & 1 deletion src/claude_statusbar/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,27 @@ def _statusline_config(fast: bool = False, refresh_interval: int = DEFAULT_REFRE
}


def _invokes_our_module(cmd: str) -> bool:
"""True for ``<python> -m claude_statusbar.cli render``.

A legitimate way to run us that skips pip's console-script launcher. On
Windows that launcher spawns a second process, roughly doubling status-line
latency (~0.9s vs ~0.44s per render on a conda install), so users on slow
Python startups may prefer the module form. Recognise it as ours rather
than reporting it as a foreign tool.
"""
return "claude_statusbar" in cmd
Comment thread
coderabbitai[bot] marked this conversation as resolved.


def _is_our_statusline(entry: object) -> bool:
"""Return True if the existing statusLine entry already points at our CLI."""
if not isinstance(entry, dict):
return False
cmd = entry.get("command")
if not isinstance(cmd, str) or not cmd.strip():
return False
if _invokes_our_module(cmd):
return True
name = _normalize_command_name(Path(cmd.strip().split()[0]).name) # strip args + path + .exe shim
return name in OUR_COMMAND_NAMES

Expand Down Expand Up @@ -158,7 +172,9 @@ def _existing_uses_render(existing) -> bool:
if not isinstance(cmd, str):
return False
parts = cmd.strip().split()
return len(parts) >= 2 and parts[1] == "render"
# `cs render`, and the module form `<python> -m claude_statusbar.cli render`
# — in both, `render` is the last token.
return len(parts) >= 2 and parts[-1] == "render"


def ensure_statusline_configured(fast: Optional[bool] = None) -> Tuple[bool, str]:
Expand Down Expand Up @@ -218,6 +234,13 @@ def ensure_statusline_configured(fast: Optional[bool] = None) -> Tuple[bool, str
effective_refresh = DEFAULT_REFRESH_INTERVAL
desired = _statusline_config(fast=effective_fast, refresh_interval=effective_refresh)

# The module form is a deliberate choice (see `_invokes_our_module`), not
# drift — the daily repair pass must not rewrite it back to the console
# script. Keep the command, still refresh refreshInterval.
existing_cmd = existing.get("command")
if isinstance(existing_cmd, str) and _invokes_our_module(existing_cmd):
desired["command"] = existing_cmd
Comment on lines +241 to +242

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Honor explicit --setup --inline requests.

This runs even when fast=False, so an existing python -m claude_statusbar.cli render command is preserved and the explicit inline request becomes a no-op. Preserve the module form only during the fast is None daily-repair path.

Proposed fix
-    if isinstance(existing_cmd, str) and _invokes_our_module(existing_cmd):
+    if fast is None and isinstance(existing_cmd, str) and _invokes_our_module(existing_cmd):
         desired["command"] = existing_cmd
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if isinstance(existing_cmd, str) and _invokes_our_module(existing_cmd):
desired["command"] = existing_cmd
if fast is None and isinstance(existing_cmd, str) and _invokes_our_module(existing_cmd):
desired["command"] = existing_cmd
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/claude_statusbar/setup.py` around lines 241 - 242, Update the
existing-command preservation logic around _invokes_our_module so it only
retains the module-form command when fast is None, the daily-repair path. Ensure
explicit --setup --inline requests with fast=False proceed to write the inline
command instead of becoming a no-op.


if (existing.get("command") != desired["command"]
or existing.get("refreshInterval") != desired["refreshInterval"]):
settings["statusLine"] = desired
Expand Down
64 changes: 64 additions & 0 deletions tests/test_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,3 +1098,67 @@ def test_windows_identity_false_when_no_shell_available(monkeypatch):
)

assert _d._process_is_our_daemon(4242) is False


MODULE_STATUSLINE = "C:/Users/x/miniconda3/python.exe -m claude_statusbar.cli render"


def test_module_invocation_counts_as_ours():
"""`<python> -m claude_statusbar.cli render` skips pip's console-script
launcher, which on Windows spawns a second process and roughly doubles
per-render latency. It must not be mistaken for a foreign tool."""
assert _is_our_statusline({"type": "command", "command": MODULE_STATUSLINE}) is True

from claude_statusbar.setup import _existing_uses_render
assert _existing_uses_render({"command": MODULE_STATUSLINE}) is True


def test_daily_repair_does_not_rewrite_module_invocation(monkeypatch, tmp_path):
"""The once-a-day auto-repair pass would otherwise replace a deliberate
module invocation with the console script every single day."""
from claude_statusbar import setup as _setup

settings = tmp_path / "settings.json"
settings.write_text(json.dumps({
"statusLine": {"type": "command", "command": MODULE_STATUSLINE,
"refreshInterval": 1},
}), encoding="utf-8")
monkeypatch.setattr(_setup, "SETTINGS_PATH", settings)

changed, msg = _setup.ensure_statusline_configured()

assert changed is False, msg
after = json.loads(settings.read_text(encoding="utf-8"))
assert after["statusLine"]["command"] == MODULE_STATUSLINE


def test_displacement_warning_silent_for_module_invocation(monkeypatch, tmp_path):
settings = tmp_path / "settings.json"
settings.write_text(json.dumps({
"statusLine": {"type": "command", "command": MODULE_STATUSLINE},
}), encoding="utf-8")
monkeypatch.setattr(render_thin, "_USER_SETTINGS", settings)

assert render_thin._displacement_suffix() == ""
Comment on lines +1135 to +1142

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject foreign commands that merely contain the module name.

_displacement_suffix() currently treats any command containing claude_statusbar as owned. A foreign command such as python -m claude_statusbar_wrapper render would therefore suppress the warning. Add a negative regression test and require the exact module invocation, consistent with _invokes_our_module().

🧰 Tools
🪛 ast-grep (0.44.1)

[info] 1136-1138: use jsonify instead of json.dumps for JSON output
Context: json.dumps({
"statusLine": {"type": "command", "command": MODULE_STATUSLINE},
})
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_daemon.py` around lines 1135 - 1142, Update _displacement_suffix()
to recognize only the exact module invocation defined by _invokes_our_module(),
rather than any command containing the module name. Extend
test_displacement_warning_silent_for_module_invocation with a foreign command
such as python -m claude_statusbar_wrapper render and assert that the
displacement warning is not suppressed.



def test_displacement_warning_silent_for_windows_exe_shim(monkeypatch, tmp_path):
"""pip writes `cs.EXE` on Windows; case + extension must not read as foreign."""
settings = tmp_path / "settings.json"
settings.write_text(json.dumps({
"statusLine": {"type": "command",
"command": r"C:\Users\x\Scripts\cs.EXE render"},
}), encoding="utf-8")
monkeypatch.setattr(render_thin, "_USER_SETTINGS", settings)

assert render_thin._displacement_suffix() == ""


def test_displacement_warning_still_fires_for_foreign_tool(monkeypatch, tmp_path):
settings = tmp_path / "settings.json"
settings.write_text(json.dumps({
"statusLine": {"type": "command", "command": "starship prompt"},
}), encoding="utf-8")
monkeypatch.setattr(render_thin, "_USER_SETTINGS", settings)

assert "starship" in render_thin._displacement_suffix()
Loading