Skip to content

Commit 39b5e0a

Browse files
HumanBean17claude
andauthored
fix(cli install): resolve tuple unpacking bug and UX issues (#292)
Fixes #291 - CLI install command bugs: 1. Fix "Index already exists" false positive: - Properly unpack tuple from index_dir_has_existing_artifacts() - Function returns tuple[bool, list[str]], not bool - Prevents always-true condition causing incorrect messages 2. Fix UI visibility on white/light terminal themes: - Add custom questionary styles with bold/blue colors - Selected items now visible on both light and dark backgrounds - Added underline for highlighted items 3. Fix UX confusion with agent host selection: - Changed from pre-selecting ALL hosts to only claude-code - Added help message explaining multi-select behavior - Added confirmation showing what will be deployed 4. Improve scope selection clarity: - Added explanatory notes about project vs user scope - Added confirmation message showing selected scope All 53 installer tests pass. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 017bd12 commit 39b5e0a

1 file changed

Lines changed: 33 additions & 7 deletions

File tree

java_codebase_rag/installer.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,31 @@ def prompt(
119119

120120
# Lazy import questionary only when needed (TTY)
121121
import questionary
122+
from prompt_toolkit.styles import Style
123+
124+
# Custom style for better visibility on both light and dark backgrounds
125+
# Uses bold and darker colors (blue/cyan) which work well on white backgrounds
126+
custom_style = Style(
127+
[
128+
("qmark", "fg:cyan bold"), # Question mark '?'
129+
("question", "bold"), # Question text
130+
("answer", "fg:blue bold"), # Selected answer (darker blue for white bg)
131+
("pointer", "fg:cyan bold"), # Selection pointer '>'
132+
("selected", "fg:blue bold"), # Selected item in checkbox
133+
("highlighted", "fg:blue underline"), # Highlighted item with underline
134+
("instruction", "dim"), # Instruction text
135+
]
136+
)
122137

123138
try:
124139
if prompt_type == "checkbox":
125-
return questionary.checkbox(message, choices=choices).ask()
140+
return questionary.checkbox(message, choices=choices, style=custom_style).ask()
126141
elif prompt_type == "select":
127-
return questionary.select(message, choices=choices).ask()
142+
return questionary.select(message, choices=choices, style=custom_style).ask()
128143
elif prompt_type == "text":
129-
return questionary.text(message, default=default).ask()
144+
return questionary.text(message, default=default, style=custom_style).ask()
130145
elif prompt_type == "confirm":
131-
return questionary.confirm(message).ask()
146+
return questionary.confirm(message, style=custom_style).ask()
132147
else:
133148
raise ValueError(f"Unknown prompt_type: {prompt_type}")
134149
except KeyboardInterrupt:
@@ -287,10 +302,15 @@ def select_hosts(*, non_interactive: bool, cli_agents: list[str] | None) -> list
287302
print(f"Valid agents: {', '.join(HOSTS.keys())}")
288303
raise SystemExit(2)
289304

290-
# Interactive: show checkbox with all hosts pre-selected
305+
# Interactive: show checkbox with claude-code pre-selected (most common)
306+
# Changed from all pre-selected to avoid confusion
291307
host_names = list(HOSTS.keys())
292-
choices = [{"name": name, "value": name, "checked": True} for name in host_names]
308+
choices = [
309+
{"name": name, "value": name, "checked": (name == "claude-code")}
310+
for name in host_names
311+
]
293312

313+
print("Note: You can select multiple agent hosts with Space. Navigate with arrow keys.")
294314
selected = prompt("checkbox", "Select agent hosts to configure:", choices=choices)
295315

296316
if not selected:
@@ -304,6 +324,8 @@ def select_hosts(*, non_interactive: bool, cli_agents: list[str] | None) -> list
304324
else:
305325
raise SystemExit(2)
306326

327+
# Show confirmation of what will be deployed
328+
print(f"Will deploy to: {', '.join(selected)}")
307329
return [HOSTS[name] for name in selected]
308330

309331

@@ -327,6 +349,8 @@ def select_scope(*, non_interactive: bool, cli_scope: str | None) -> Scope:
327349
return "project"
328350

329351
# Interactive: prompt for scope
352+
print("Note: 'project' scope stores configs in the project directory.")
353+
print(" 'user' scope stores configs in your home directory.")
330354
selected = prompt(
331355
"select",
332356
"Select installation scope:",
@@ -336,6 +360,7 @@ def select_scope(*, non_interactive: bool, cli_scope: str | None) -> Scope:
336360
if not selected:
337361
return "project"
338362

363+
print(f"Selected scope: {selected}")
339364
return selected # type: ignore
340365

341366

@@ -746,7 +771,8 @@ def run_init_if_needed(
746771
)
747772
from java_codebase_rag.pipeline import run_build_ast_graph, run_cocoindex_update
748773

749-
if index_dir_has_existing_artifacts(index_dir):
774+
has_existing, _ = index_dir_has_existing_artifacts(index_dir)
775+
if has_existing:
750776
print("Index already exists. Run `java-codebase-rag reprocess` to rebuild.")
751777
return False
752778

0 commit comments

Comments
 (0)