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
31 changes: 31 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Tests

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
smoke:
name: Lua and Python smoke tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Install Lua
run: sudo apt-get update && sudo apt-get install -y lua5.4 python3

- name: Run tests
run: |
set -euo pipefail
lua5.4 scripts/test_settings.lua
lua5.4 scripts/test_history.lua
python3 scripts/test_parse_refs.py
python3 scripts/test_json_extract.py
WEZAI_COMPOSER_TEST=1 python3 plugin/composer.py --self-test
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Other WezTerm defaults to treat carefully when picking shortcuts (non-exhaustive
## Keybinding checklist (before shipping a new shortcut)

1. Check [WezTerm default keys](https://wezterm.org/config/default-keys.html) for conflicts.
2. Prefer `CTRL|SHIFT` + a free letter for catalog scopes (`G` git, `K` kube, `H` history) — **not `T`** (SpawnTab) or **`W`** (CloseCurrentTab).
2. Prefer `CTRL|SHIFT` + a free letter for catalog scopes (`G` git, `K` kube, `H` history, `D` docker) — **not `T`** (SpawnTab) or **`W`** (CloseCurrentTab).
3. Update `settings.lua` defaults, `init.lua` bind site, and README / GUIDE / SPECS tables together.
4. Call out any intentional override of a WezTerm default in those docs.

Expand Down Expand Up @@ -76,7 +76,7 @@ Raise `timeout` to **300–600** for big local GGUFs, or pre-warm (`ollama run

## Related pitfalls

- Plugin modules load via fingerprint scan in `init.lua`. Prefer the **most complete** install (`tf.lua`, `weather.lua`, etc.) so a stale local checkout cannot hide new catalogs.
- After merging catalog work to GitHub installs: users need palette **Update wezai plugin** (or `update_all()` + config reload). Log line should include `tf.lua ok` / `weather.lua ok` when present.
- Plugin modules load via fingerprint scan in `init.lua`. Prefer the **most complete** install (`tf.lua`, `weather.lua`, `docker.lua`, etc.) so a stale local checkout cannot hide new catalogs.
- After merging catalog work to GitHub installs: users need palette **Update wezai plugin** (or `update_all()` + config reload). Log line should include `tf.lua ok` / `weather.lua ok` / `docker.lua ok` when present.
- **Never** call `wezterm.run_child_process` from a module’s main chunk (inside `require`). WezTerm yields in that API, and Lua errors with `attempt to yield across a C-call boundary`, taking down config load. `util.version_label()` must stay file/`require("version")` only.
- Shell vs AI pane, provider contract, and safety rules: see SPECS §4.
79 changes: 74 additions & 5 deletions GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# wezai guide

Practical examples for every major surface: Ask, the palette, `@git`, `@kube`, `@tf`, `@weather`, `@history`, and file edits.
Practical examples for every major surface: Ask, the palette, `@git`, `@kube`, `@tf`, `@docker`, `@weather`, `@history`, and file edits.

---

Expand All @@ -9,14 +9,15 @@ Practical examples for every major surface: Ask, the palette, `@git`, `@kube`, `
| Pane | Role |
|------|------|
| **Left (shell)** | Your real terminal. cwd, git repo, commands you run. Stay focused here. |
| **Right (wezai)** | Output only — answers, diffs, `git status`, terraform validate, weather, progress. Not a shell. While Ask/Edit or a catalog command waits, this pane scrolls a spinner / timed status so it does not look frozen. |
| **Right (wezai)** | Output only — answers, diffs, `git status`, terraform validate, docker ps, weather, progress. Not a shell. While Ask/Edit or a catalog command waits, this pane scrolls a spinner / timed status so it does not look frozen. |

| Entry point | When to use it |
|-------------|----------------|
| `CTRL+I` | Free-form Ask (`@file`, `@dir/`, questions, `#` edits). Composer keeps the AI log visible |
| `CTRL+SHIFT+P` | Palette — jump to any action without typing a full Ask line |
| `CTRL+SHIFT+G` | Same palette, pre-filtered to `@git` |
| `CTRL+SHIFT+K` | Same palette, pre-filtered to `@kube` |
| `CTRL+SHIFT+D` | Same palette, pre-filtered to `@docker` |
| `CTRL+ALT+T` | Same palette, pre-filtered to `@tf` |
| `CTRL+ALT+W` | Same palette, pre-filtered to `@weather` |
| `CTRL+SHIFT+H` | Same palette, pre-filtered to `@history` |
Expand Down Expand Up @@ -105,6 +106,7 @@ Undo: palette → **Undo last edit**.
| `@git:diff` | `@git:diff write a PR summary` |
| `@tf:state` | `@tf:state what’s orphaned?` |
| `@tf:validate` | `@tf:validate why is this failing?` |
| `@docker:ps` | `@docker:ps what’s using port 5432?` |
| `@weather:now` | `@weather should I bring a jacket?` |
| `@dir:.` | `@dir:src what modules exist?` |
| `@history` | `@history what docker commands did I run?` |
Expand All @@ -128,6 +130,7 @@ Type to fuzzy-filter. Labels start with namespaces so filtering is easy:
| `@git:soft` / `@git:rebase` | Soft reset / interactive rebase (any N) |
| `@kube` | All kubectl actions |
| `@tf` | All terraform actions |
| `@docker` | Docker / Compose actions |
| `@weather` | Open-Meteo current / forecast / set zip |
| `@history` | Unique shell history (detected fish/zsh/bash), type to fuzzy-filter |
| `Ask` / `Fix` / `model` | Core helpers |
Expand Down Expand Up @@ -345,6 +348,54 @@ Ask-with-context attach tokens: `@tf:state`, `@tf:validate`, `@tf:output`, `@tf:

---

## `@docker` actions

Open via `CTRL+SHIFT+P` → type `@docker`, or `CTRL+SHIFT+D`, or Ask → `@docker` / `@docker:ps`.

Commands use the **shell pane cwd** for Compose (`docker compose` in that directory). wezai resolves the `docker` binary the same way as kubectl/terraform (Homebrew + login shell), or set `docker.docker = "/usr/bin/docker"`.

**Mutating** actions (`restart`, `rm`, `compose-down`) confirm when `docker.confirm_mutate` is true (default). AI helpers gather read-only context (ps / compose ps / selection) and steer toward logs / inspect — not `rm` / `compose down` unless you asked.

### Show (no model)

These print the command in the wezai pane immediately, then a spinner until docker returns.

| Action | Meaning |
|--------|---------|
| `@docker:ps` | Running containers |
| `@docker:ps-a` | All containers (`ps -a`) |
| `@docker:images` | Local images |
| `@docker:compose-ps` | `docker compose ps` in the shell cwd |
| `@docker:df` | `docker system df` |

### Shell helpers

| Action | Notes |
|--------|--------|
| `@docker:logs` / `logs-f` | Prompt for container; `--tail=N` via `@docker:logs200` |
| `@docker:exec` | `docker exec -it <container> sh` |
| `@docker:compose-up` / `compose-down` | Detached up; down confirms |
| `@docker:compose-logs` | Compose logs `--tail=N` |
| `@docker:pull` | Prompt for image |
| `@docker:restart` / `rm` | Confirm before run |

### AI

| Action | What it does |
|--------|----------------|
| `@docker:diagnose` | Attach `ps -a` + compose ps (+ selection) → diagnose |
| `@docker:explain-sel` | Explain selected docker/compose output |

```
CTRL+SHIFT+D → @docker:ps
CTRL+I → @docker:ps what's using 5432?
CTRL+I → @docker:diagnose (select a crash log first)
```

Ask-with-context attach tokens: `@docker:ps`, `@docker:ps-a`, `@docker:images`, `@docker:compose-ps`, `@docker:df`. Bare `@docker` opens the palette. `@docker should I restart?` attaches `ps`.

---

## `@weather` actions

Open via `CTRL+SHIFT+P` → type `@weather`, or `CTRL+ALT+W`, or Ask → `@weather` / `@weather:now`.
Expand Down Expand Up @@ -402,12 +453,14 @@ Bare `@weather` opens the weather palette. Add a question after `@weather` / `@w

## `@history`

The history palette uses the **detected shell** (fish / zsh / bash) with the same actions on every shell.
The history palette uses the **detected shell** (fish / zsh / bash) with the same actions on those shells.

1. `CTRL+SHIFT+H` (or `CTRL+SHIFT+P` → type `@history`)
2. Type to fuzzy-filter unique commands (newest first)
3. Pick a row → **Run** / **Insert** / **Explain** / **Attach & ask** / **Copy** / **Delete**

PowerShell (and unknown shells) still list scrollback / session events, but histfile search and **Delete** are not offered.

**Search:** the history-scoped palette loads up to `search_n` unique commands (default 12 000) so WezTerm’s fuzzy matcher can reach far back. For the rest of a huge histfile, pick **Search entire history…** and type a query (`fzf -f` if installed, otherwise subsequence matching). The unified `CTRL+SHIFT+P` list stays at `palette_n` (200) recent rows.

**Delete** removes **all copies** of that command, like fish’s history pager:
Expand Down Expand Up @@ -507,7 +560,20 @@ CTRL+I → @tf:generate aws_s3_bucket with versioning enabled

Then write it with `#main.tf …` after reviewing the suggestion.

### “What’s the weather?”
### “What's running locally?”

```
CTRL+SHIFT+D → @docker:ps
CTRL+I → @docker:ps what's using 5432?
```

Or diagnose a crash (select the log first):

```
CTRL+SHIFT+D → @docker:diagnose
```

### “What's the weather?”

```
CTRL+ALT+W → @weather:zip # once — e.g. 90210
Expand All @@ -525,7 +591,7 @@ CTRL+I → @weather should I bring a jacket tonight?
## Safety

- Secrets (API keys, tokens, private keys) are redacted before send / memory
- Risky shell commands confirm before send (includes `terraform apply` / `destroy` / `force-unlock`)
- Risky shell commands confirm before send (includes `terraform apply` / `destroy` / `force-unlock` and `docker rm` / `compose down`)
- `#` / `@@` edits always show a unified diff in the right-hand pane, with Apply/Cancel in a shell split (not a full-window overlay) unless you disable `require_edit_confirm`
- Edit backups are timestamped wezai **dotfiles** (`backup.suffix` / `backup.dir` / `backup.dotfile`); set `backup.enabled = false` to skip writing `.bak` files
- No force-push action in v1
Expand All @@ -540,9 +606,12 @@ CTRL+I → @weather should I bring a jacket tonight?
|---------|-----|
| `no pane cwd` | Focus the **shell** pane, not the wezai pane; then open the palette again |
| Overlay covers the diff / right pane | Edit confirm should split under the shell. Palette → **Update wezai plugin**. Fallback InputSelector (no python3) still covers the tab. |
| Composer/confirm is a full-window overlay | Needs `python3` plus `plugin/composer.py` / `confirm.py`. The AI pane prints a warning; overlay still works. |
| Palette is WezTerm’s, not wezai | Reload config; wezai overrides `CTRL+SHIFT+P`. Or set `keybinding_palette` |
| Empty `@history` | Run commands in fish/zsh/bash first; check `history.tail_bytes` / `search_n`. Bash often needs `histappend` (or a `history -a` in `PROMPT_COMMAND`) so the current session is on disk. |
| `@history` says histfile unsupported | PowerShell (and unknown shells) have no histfile search/delete. Scrollback and session events still list. Use fish/zsh/bash for Delete. |
| No `@tf` in palette | Need wezai ≥ 1.5.0 with `plugin/tf.lua`. Palette → **Update wezai plugin**, then reload. Log should say `tf.lua ok`. Shortcut is `CTRL+ALT+T` (not `CTRL+SHIFT+T`) |
| No `@docker` in palette | Need `plugin/docker.lua`. Palette → **Update wezai plugin**, then reload. Log should say `docker.lua ok`. Shortcut is `CTRL+SHIFT+D`. |
| No `@weather` / “No zip set” | Need `plugin/weather.lua`. Set `@weather:zip 90210` or `WEZAI_WEATHER_ZIP=90210` in `wezai.env`. Shortcut is `CTRL+ALT+W` (not `CTRL+SHIFT+W`) |
| Palette title is `wezai ?` | Stale plugin without `plugin/version.lua`. Palette → **Update wezai plugin**; log should show `wezai v1.12.0…` not `?` |
| Config error `yield across a C-call boundary` | Load-time process spawn (fixed after 1.12.0). Palette is unavailable — `git fetch` in the WezTerm plugin cache (see README Troubleshooting), then reload |
Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# wezai

**wezai** is a WezTerm plugin that puts an AI assistant, a command palette, and git/kube/terraform/weather/history shortcuts next to your shell — without leaving the terminal.
**wezai** is a WezTerm plugin that puts an AI assistant, a command palette, and git/kube/terraform/docker/weather/history shortcuts next to your shell — without leaving the terminal.

> **Alpha software.** wezai is in active development and under heavy testing. Behavior and APIs may change. If you hit a bug or have an idea, please [open an issue](https://github.com/wsams/wezai/issues) — reports are welcome and help shape the project. See [CONTRIBUTING.md](CONTRIBUTING.md) for what to include.

- Ask questions with file, directory, clipboard, git, kube, terraform, weather, and selection context
- Ask questions with file, directory, clipboard, git, kube, terraform, docker, weather, and selection context
- Edit files in one pass (`#path`, legacy `@@path`) with a unified diff confirm and wezai dotfile backups
- CTRL+I composer keeps the AI log visible; `@` / `#` fuzzy-complete cwd paths plus `~/`, `/abs`, `../`; context persists until Compact/Clear
- One palette (`CTRL+SHIFT+P`) for Ask helpers, `@git:…`, `@kube:…`, `@tf:…`, `@weather:…`, and `@history`
- One palette (`CTRL+SHIFT+P`) for Ask helpers, `@git:…`, `@kube:…`, `@tf:…`, `@docker:…`, `@weather:…`, and `@history`

- Shell-aware suggestions, secret redaction, risky-command confirms

Expand Down Expand Up @@ -65,18 +65,20 @@ Do **not** leave `update_all()` / `reload_configuration()` at config file scope
|-----|--------|
| `CTRL+I` | **Ask** — composer under the shell (`@` attach, `#` edit). Esc saves a draft |
| `CTRL+SHIFT+E` | **Ask** with pane scrollback attached as context |
| `CTRL+SHIFT+P` | **Palette** — type `@git`, `@kube`, `@tf`, `@weather`, `@history`, or `Ask` to filter |
| `CTRL+SHIFT+P` | **Palette** — type `@git`, `@kube`, `@tf`, `@docker`, `@weather`, `@history`, or `Ask` to filter |
| `CTRL+SHIFT+G` | Palette scoped to `@git` |
| `CTRL+SHIFT+K` | Palette scoped to `@kube` |
| `CTRL+SHIFT+D` | Palette scoped to `@docker` |
| `CTRL+ALT+T` | Palette scoped to `@tf` (not `CTRL+SHIFT+T` — that is WezTerm’s new tab) |
| `CTRL+ALT+W` | Palette scoped to `@weather` (not `CTRL+SHIFT+W` — that is WezTerm’s close tab) |
| `CTRL+SHIFT+H` | Palette scoped to `@history` (fuzzy unique commands; Delete like fish) |

Stay on your **shell** pane. The right split is **output only** (answers, diffs, git/kube/tf/weather status). Catalog commands print immediately and spin `waiting…` until output arrives, so a slow `@weather:now` does not look frozen. Don’t run git from that pane — wezai always uses your shell’s cwd.
Stay on your **shell** pane. The right split is **output only** (answers, diffs, git/kube/tf/docker/weather status). Catalog commands print immediately and spin `waiting…` until output arrives, so a slow `@weather:now` does not look frozen. Don’t run git from that pane — wezai always uses your shell’s cwd.

```
CTRL+SHIFT+P → type @git:status → Enter
CTRL+SHIFT+P → type @tf:validate → Enter
CTRL+SHIFT+P → type @docker:ps → Enter
CTRL+I → @README.md is this safe? → Enter
CTRL+I → #notes.txt sort the lines → review diff → Apply
CTRL+I → @plugin/ (pins the tree) → how is loading wired?
Expand Down Expand Up @@ -105,6 +107,8 @@ More examples: [GUIDE.md](GUIDE.md).
| `@tf` / `@tf:validate` | Terraform helpers in the shell cwd (`terraform` binary auto-resolved) |
| `@tf:state` in a question | Attach `terraform state list` and ask |
| `@tf:generate …` / `@tf:debug` | AI helpers to generate or debug HCL |
| `@docker` / `@docker:ps` | Local Docker / Compose helpers (`docker` binary auto-resolved) |
| `@docker:ps` in a question | Attach `docker ps` and ask |
| `@weather` / `@weather:now` | Current conditions (Open-Meteo; needs a zip) |
| `@weather:zip 90210` | Save zip from the plugin (`~/.local/share/wezai/weather.json`) |
| `@dir:path` | Directory listing |
Expand All @@ -129,6 +133,7 @@ Most people never need the Lua table. Copy [wezai.env.example](wezai.env.example
| `WEZAI_OLLAMA_PATH` | `ollama_path` | unset |
| `WEZAI_LMS_PATH` | `lms_path` | unset |
| `WEZAI_KUBE_NS` | `kube.namespace` | kubectl current ns |
| `WEZAI_DOCKER_BIN` | `docker.docker` | unset (auto-resolve) |
| `WEZAI_WEATHER_ZIP` | `weather.zip` | unset (`@weather:zip` still works) |
| `WEZAI_WEATHER_COUNTRY` | `weather.country` | `US` |
| `WEZAI_WEATHER_UNITS` | `weather.units` | `auto` |
Expand All @@ -146,6 +151,7 @@ wezai.apply_to_config(config, {
keybinding_history = { key = "h", mods = "CTRL|SHIFT" },
keybinding_git = { key = "g", mods = "CTRL|SHIFT" },
keybinding_kube = { key = "k", mods = "CTRL|SHIFT" },
keybinding_docker = { key = "d", mods = "CTRL|SHIFT" },
keybinding_tf = { key = "t", mods = "CTRL|ALT" },
keybinding_weather = { key = "w", mods = "CTRL|ALT" },

Expand All @@ -155,6 +161,9 @@ wezai.apply_to_config(config, {
-- Optional: absolute terraform if GUI PATH can't find it
tf = { terraform = nil, confirm_mutate = true },

-- Optional: absolute docker if GUI PATH can't find it
docker = { docker = nil, confirm_mutate = true },

-- Optional: ZIP for @weather (Open-Meteo). Prefer WEZAI_WEATHER_ZIP or @weather:zip
-- (saved under ~/.local/share/wezai/weather.json — does not rewrite this file).
weather = { zip = nil, country = "US", units = "auto" },
Expand Down
Loading