fix: resolve CI type checking issues
Some checks failed
CI / test (push) Has been cancelled
Shellhist CI / test (push) Has been cancelled
Shellhist CI / build (push) Has been cancelled

- Add return type annotations to __hash__ (-> int) and __eq__ (-> bool) in HistoryEntry
- Add TextIO import and type annotations for file parameters
- Add type ignore comment for fuzzywuzzy import
- Add HistoryEntry import and list type annotations in time_analysis
- Add assert statements for Optional[datetime] timestamps
- Add TypedDict classes for type-safe pattern dictionaries
- Add CommandPattern import and list[CommandPattern] type annotation
- Add -> None return types to all test methods
- Remove unused HistoryEntry import (F401)
This commit is contained in:
2026-01-31 14:19:18 +00:00
parent 32f78c6985
commit 7028371275

View File

@@ -1 +1,159 @@
bmFtZTogQ0kKCm9uOgogIHB1c2g6CiAgICBicmFuY2hlczogW21haW5dCiAgcHVsbF9yZXF1ZXN0OgogICAgYnJhbmNoZXM6IFttYWluXQoKam9iczogCiAgdGVzdDoKICAgIHJ1bnMtb246IHVidW50dS1sYXRlc3QKICAgIHN0ZXBzOgogICAgICAtIHVzZXM6IGFjdGlvbnMvY2hlY2tvdXQdjNFgKICAgICAgdXNlczogYWN0aW9ucy9zZXR1cC1weXRob25fdjUKICAgICAgd2l0aDoKICAgICAgICBweXRob24tdmVyc2lvbjogJzMuMTEnCiAgICAtIHJ1bjogcGlwIGluc3RhbGwgLWUgIltcImRldlwiXSIKICAgIC0gcnVuOiBweXRlc3QgdGVzdHMvIC12CiAgICAtIHJ1bjogcnVmZiBjaGVjayAu
"""Alias suggestion command."""
import os
from typing import Optional
import click
from rich.console import Console
from rich.panel import Panel
from shellhist.core import HistoryLoader
from shellhist.core.patterns import (
detect_command_pairs,
detect_command_triplets,
detect_repetitive_commands,
)
@click.command("suggest-aliases")
@click.option(
"--history",
"-H",
type=str,
help="Path to history file",
)
@click.option(
"--auto-create",
"-a",
is_flag=True,
default=False,
help="Automatically create aliases without prompting",
)
@click.option(
"--dry-run",
"-d",
is_flag=True,
default=False,
help="Show what would be created without making changes",
)
@click.option(
"--shell",
"-s",
type=click.Choice(["bash", "zsh"]),
help="Shell type for parsing",
)
@click.pass_context
def alias_command(
ctx: click.Context,
history: Optional[str],
auto_create: bool,
dry_run: bool,
shell: Optional[str],
) -> None:
"""Generate alias suggestions for detected patterns.
Examples:
\b
shellhist suggest-aliases
shellhist suggest-aliases --auto-create
shellhist suggest-aliases --dry-run
"""
console = Console()
try:
loader = HistoryLoader(history_path=history)
store = loader.load()
if not store.entries:
console.print("[yellow]No entries found in history.[/yellow]")
return
pairs = detect_command_pairs(store, min_frequency=2)
triplets = detect_command_triplets(store, min_frequency=2)
sequences = [
(p.commands, p.frequency)
for p in pairs + triplets
if len(p.commands) >= 2
]
if not sequences:
console.print(
"[yellow]No command sequences found for alias suggestions.[/yellow]"
)
console.print("Try running more commands first.")
return
console.print(f"\n[bold cyan]Detected Command Sequences[/bold cyan]")
for i, (cmds, freq) in enumerate(sequences[:10], 1):
seq = " && ".join(cmds)
console.print(f"{i}. {seq} (frequency: {freq})")
console.print("\n[bold cyan]Suggested Aliases[/bold cyan]")
for i, (cmds, freq) in enumerate(sequences[:10], 1):
alias_name = generate_alias_name(cmds)
alias_cmd = " && ".join(cmds)
alias_str = f"alias {alias_name}='{alias_cmd}'"
panel = Panel(
f"[green]{alias_str}[/green]",
title=f"Alias {i}",
expand=False,
)
console.print(panel)
if not dry_run:
if auto_create:
append_to_shell_file(alias_str)
console.print(f" [green]Created alias '{alias_name}'[/green]")
else:
if click.confirm(f" Create this alias?"):
append_to_shell_file(alias_str)
console.print(f" [green]Created alias '{alias_name}'[/green]")
except FileNotFoundError as e:
console.print(f"[red]Error: {e}[/red]")
ctx.exit(1)
except Exception as e:
console.print(f"[red]Error generating aliases: {e}[/red]")
ctx.exit(1)
def generate_alias_name(commands: list[str]) -> str:
"""Generate a meaningful alias name from command list."""
if not commands:
return "custom"
keywords = []
for cmd in commands:
parts = cmd.split()
if parts:
keywords.append(parts[0])
keywords = [k for k in keywords if k not in ("sudo", "do", "run", "exec")]
if not keywords:
return "custom"
base = "".join(keywords[:3]).lower()
if len(base) > 12:
base = base[:12]
return base
def append_to_shell_file(alias_str: str) -> None:
"""Append alias to shell config file."""
shell = os.environ.get("SHELL", "")
if "zsh" in shell:
rc_file = os.path.expanduser("~/.zshrc")
else:
rc_file = os.path.expanduser("~/.bashrc")
with open(rc_file, "a", encoding="utf-8") as f:
f.write(f"\n{alias_str}\n")