Skip to content

feat: Extend zev with the history flag that allows users to reuse previously selected commands from the local history#1

Open
0xironclad wants to merge 1 commit intomarqbritt:mainfrom
0xironclad:feat/command-history
Open

feat: Extend zev with the history flag that allows users to reuse previously selected commands from the local history#1
0xironclad wants to merge 1 commit intomarqbritt:mainfrom
0xironclad:feat/command-history

Conversation

@0xironclad
Copy link

No description provided.

…viously selected commands from the local history
Copilot AI review requested due to automatic review settings February 11, 2026 01:04
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new “selected command history” feature to zev, enabling users to browse previously selected command suggestions from local storage via a new CLI flag.

Changes:

  • Introduces a selected_command_history module (types/repository/service/UI) that persists selected commands to a local file and renders an interactive selector.
  • Records selections when the user chooses a command from zev’s suggestions (including the original query).
  • Adds --history / -H to the CLI help and routes the new flag to the history UI.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/zev/utils.py Updates CLI help text to document the new history flag.
src/zev/selected_command_history/ui.py New interactive Questionary UI for browsing selected command history.
src/zev/selected_command_history/types.py New Pydantic model representing a selected command entry.
src/zev/selected_command_history/service.py New service for recording and retrieving selected command history.
src/zev/selected_command_history/repository.py New file-backed repository implementation for persistence.
src/zev/selected_command_history/config.py Defines the default history file location.
src/zev/selected_command_history/init.py Exposes selected-command history types/service.
src/zev/main.py Adds --history routing to the new UI and passes original query into selection flow.
src/zev/command_selector.py Records selected commands into the new history store.
src/zev/command_history.py Passes original query through when reusing “recent query” history.
.gitignore Broadens egg-info ignore patterns.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

self._encoding = encoding
self._ensure_file_exists()

def _ensure_file_exists(self) -> None:
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Path.touch() will fail if the parent directory doesn't exist. Since create_repository() accepts an arbitrary file_path, consider ensuring self._file_path.parent.mkdir(parents=True, exist_ok=True) before touching the file so the repository works with non-home paths (e.g., during tests or future config changes).

Suggested change
def _ensure_file_exists(self) -> None:
def _ensure_file_exists(self) -> None:
# Ensure the parent directory exists before creating the file,
# so arbitrary file paths with non-existent parents work correctly.
self._file_path.parent.mkdir(parents=True, exist_ok=True)

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +88
if command == "--history" or command == "-H":
show_selected_command_history()
return True
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

args[0] is lowercased (command = args[0].lower()), so passing -H becomes -h and this branch will never match. As a result, zev -H will trigger the help case instead of history. Consider preserving the original case for short flags, or compare against the lowercased value and choose a non-conflicting short option (or switch to argparse).

Copilot uses AI. Check for mistakes.
"""Get command history, most recent first."""
entries = self._repository.get_all()
entries.reverse()
if limit:
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

if limit: treats 0 as "no limit" and returns the full history. If limit is intended to be an optional int, consider using if limit is not None: (and possibly validating that limit >= 0) so limit=0 correctly returns an empty list.

Suggested change
if limit:
if limit is not None:
if limit < 0:
raise ValueError("limit must be a non-negative integer or None")

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +41
def _display_history_selector(
entries: list[SelectedCommandEntry],
show_limit: int,
) -> Optional[SelectedCommandEntry]:
"""Display the history selection menu."""
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The return type is annotated as Optional[SelectedCommandEntry], but this function can also return the string values "show_more"/"Cancel" (via the questionary.select(...).ask() result). Update the annotation (e.g., SelectedCommandEntry | Literal["Cancel"] | None) and/or normalize the return value so callers don't need to handle mixed types.

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +70
def _display_full_history(entries: list[SelectedCommandEntry]) -> Optional[SelectedCommandEntry]:
"""Display all history entries."""
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

This function can return the string "Cancel" (based on the choice value), but the return type is Optional[SelectedCommandEntry]. Align the type annotation with actual return values (or map "Cancel" to None) to avoid mixed-type control flow.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +58
try:
entries.append(SelectedCommandEntry.model_validate_json(line))
except Exception:
continue
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Catching Exception here will also swallow unexpected errors beyond JSON/validation problems, making file corruption or other issues hard to diagnose. Consider catching the specific exceptions raised by model_validate_json (e.g., pydantic.ValidationError / ValueError) and optionally surfacing/logging a warning when a line is skipped.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant