Metadata-Version: 2.4
Name: nlsh-cli
Version: 0.1.3
Summary: Turn natural language into shell commands via the DeepSeek API, with a confirm-before-run step.
Project-URL: Homepage, https://github.com/decajoin/nlsh
Project-URL: Repository, https://github.com/decajoin/nlsh
Author: Yiqi Yang
License: MIT
Keywords: cli,deepseek,llm,natural-language,shell,terminal
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Requires-Dist: click<8.2,>=8.0
Requires-Dist: httpx>=0.27
Requires-Dist: prompt-toolkit>=3.0.52
Requires-Dist: rich>=13
Requires-Dist: tomli>=2; python_version < '3.11'
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# nlsh

Describe what you want to do in plain language; `nlsh` asks the DeepSeek API for
the matching shell command, shows it with a short explanation, and waits for your
confirmation before running it.

```
$ nlsh find the 5 largest files under this directory
╭─ proposed command ───────────────────────────────────────╮
│ $ du -ah . | sort -rh | head -n 5                         │
│                                                           │
│ Lists files by size and shows the five largest.          │
╰───────────────────────────────────────────────────────────╯
Run it? [y/n/e] (n):
```

`y` runs it, `n` cancels, `e` opens the command in your `$EDITOR` first.

## Install

Once published to PyPI, install it as a standalone tool (the package is
`nlsh-cli`; the command it installs is `nlsh`):

```sh
uv tool install nlsh-cli     # or: pipx install nlsh-cli
```

### From source

One command sets up the virtual environment and all dependencies from the
lockfile:

```sh
uv sync
```

This creates `.venv/` and installs `nlsh`. Run it with `uv run nlsh ...`, or
activate the env first (`source .venv/bin/activate`) and just call `nlsh`.

Plain pip (no uv) works too:

```sh
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
pip install -e .
```

## Configure

Easiest — store the key interactively (written to `~/.config/nlsh/config.toml`,
mode 0600):

```sh
nlsh config set-key
nlsh config set-model deepseek-v4-pro   # optional, change default model
nlsh config show                        # show resolved config (key masked)
```

Or via environment variable:

```sh
export DEEPSEEK_API_KEY=sk-...
```

or edit `~/.config/nlsh/config.toml` directly:

```toml
api_key  = "sk-..."
model    = "deepseek-v4-flash"        # optional (also: deepseek-v4-pro)
base_url = "https://api.deepseek.com" # optional
```

Resolution order for each setting is: environment variable → config file → default.

## Usage

```sh
nlsh <natural language request>

  -y, --yes        run without confirmation (dangerous commands still prompt)
  -n, --dry-run    only print the command, never run it
      --pro        use the stronger model (deepseek-v4-pro) for this request
  -m, --model ID   override the model id for this request
      --version    show version
```

At the confirmation prompt: `y` runs, `n` cancels, `e` edits first. Commands
that match risky patterns (`rm -rf`, `dd of=/dev/…`, `mkfs`, fork bombs,
`curl … | sh`, `sudo`, …) are flagged in red and require typing the full word
`yes` before they run — even under `--yes`. Multi-stage commands (pipes, `&&`)
are shown with a per-step breakdown.

## Development

```sh
uv sync                 # installs deps + dev tools (pytest, ruff)
uv run pytest -q        # run the test suite
uv run ruff check .     # lint
```

CI (GitHub Actions) runs ruff + pytest across Python 3.9–3.13 and checks the
lockfile on every push and PR.

### Releasing

The version is derived from the git tag by `hatch-vcs`, so a release is just a
tag:

```sh
git tag v0.1.0
git push origin v0.1.0
```

The `Publish` workflow builds the sdist/wheel and uploads them to PyPI via
[Trusted Publishing](https://docs.pypi.org/trusted-publishers/) (configure a
`pypi` environment on the repo and register the workflow as a trusted publisher
— no API token stored).

## How it works

`nlsh` sends your request plus context (OS, shell, current directory) to the
DeepSeek chat API constrained to JSON output, parses `{command, explanation}`,
and runs the chosen command through your `$SHELL` so aliases and the working
directory behave as expected.
