diff --git a/Cargo.lock b/Cargo.lock index 8d1db28..5e47fa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -423,7 +423,7 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "paws" -version = "0.3.1" +version = "0.4.0" dependencies = [ "crossterm", "dirs", diff --git a/Cargo.toml b/Cargo.toml index 534b937..7b4bbca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "paws" -version = "0.3.1" +version = "0.4.0" edition = "2021" [dependencies] diff --git a/README.md b/README.md index 88ed39f..4d75d4a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ English | [中文](README.zh.md) # 🐾 Paws -[![CI](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml/badge.svg)](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Works with Kaku, WezTerm & iTerm2](https://img.shields.io/badge/Works_with-Kaku_%7C_WezTerm_%7C_iTerm2-blue)](https://github.com/interesting-vibe-coding/paws/blob/main/docs/iterm2-setup.md) [![Made with Lua & Rust](https://img.shields.io/badge/Made_with-Lua_&_Rust-orange)]() [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/interesting-vibe-coding/paws/pulls) [![GitHub Stars](https://img.shields.io/github/stars/interesting-vibe-coding/paws?style=flat&color=yellow)](https://github.com/interesting-vibe-coding/paws/stargazers) +[![CI](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml/badge.svg)](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Works with Kaku, WezTerm, iTerm2 & tmux](https://img.shields.io/badge/Works_with-Kaku_%7C_WezTerm_%7C_iTerm2_%7C_tmux-blue)](https://github.com/interesting-vibe-coding/paws#install) [![Made with Lua & Rust](https://img.shields.io/badge/Made_with-Lua_&_Rust-orange)]() [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/interesting-vibe-coding/paws/pulls) [![GitHub Stars](https://img.shields.io/github/stars/interesting-vibe-coding/paws?style=flat&color=yellow)](https://github.com/interesting-vibe-coding/paws/stargazers) Play games while your AI agent works. A status HUD tells you when to come back. @@ -53,7 +53,8 @@ cargo install --git https://github.com/interesting-vibe-coding/paws-games --bin Then wire the terminal integration and hooks for your agent (see [`hooks/`](hooks/) for reference configs). - **Kaku:** add [`lua/paws.lua`](lua/paws.lua) to `~/.config/kaku/kaku.lua` before `return config` — reload with CMD+Shift+R - **WezTerm:** add [`lua/paws.lua`](lua/paws.lua) to `~/.config/wezterm/wezterm.lua` — auto-reloads on save -- **iTerm2:** copy [`iterm2/paws.py`](iterm2/paws.py) to `~/.config/iterm2/scripts/AutoLaunch/` and bind 3 keys — see [docs/iterm2-setup.md](docs/iterm2-setup.md) +- **iTerm2:** copy [`iterm2/paws.py`](iterm2/paws.py) to `~/.config/iterm2/scripts/AutoLaunch/` and bind 3 keys — see [setup guide](docs/iterm2-setup.md) +- **tmux:** copy [`tmux/`](tmux/) scripts to `~/.config/paws/` and add 2 lines to `~/.tmux.conf` — see [setup guide](docs/tmux-setup.md) ## Games @@ -65,9 +66,18 @@ Then wire the terminal integration and hooks for your agent (see [`hooks/`](hook Don't see enough? Open **⤓ Install games** in the picker to browse the catalog and install more in place. The catalog is the [paws-games](https://github.com/interesting-vibe-coding/paws-games) plugin library — anyone can contribute a game. +## Terminals + +| Terminal | Integration | Keys | +|----------|-------------|------| +| [Kaku](https://github.com/tw93/kaku) | `lua/paws.lua` → Lua config | CMD+G / CMD+SHIFT+P | +| [WezTerm](https://wezfurlong.org/wezterm/) | `lua/paws.lua` → Lua config | CMD+G / CMD+SHIFT+P | +| [iTerm2](https://iterm2.com) | `iterm2/paws.py` → AutoLaunch script | CMD+G / CMD+SHIFT+P — [setup](docs/iterm2-setup.md) | +| tmux | `tmux/*.sh` → shell scripts | Prefix+g / Prefix+G — [setup](docs/tmux-setup.md) | + ## How it works -Agent hooks write session state to `/tmp/paws-sessions/` → Kaku Lua handles CMD+G (spawns/toggles a tab) → the `paws` host runs the chosen game in a PTY and renders the HUD on the top row. Games are standalone binaries discovered via a [registry](registry.toml). +Agent hooks write session state to `/tmp/paws-sessions/` → the terminal integration handles the key binding (spawns/toggles a window) → the `paws` host runs the chosen game in a PTY and renders the HUD on the top row. Games are standalone binaries discovered via a [registry](registry.toml). For architecture details, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). diff --git a/README.zh.md b/README.zh.md index c27ef8b..c077cde 100644 --- a/README.zh.md +++ b/README.zh.md @@ -4,7 +4,7 @@ # 🐾 Paws -[![CI](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml/badge.svg)](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Works with Kaku, WezTerm & iTerm2](https://img.shields.io/badge/Works_with-Kaku_%7C_WezTerm_%7C_iTerm2-blue)](https://github.com/interesting-vibe-coding/paws/blob/main/docs/iterm2-setup.md) [![Made with Lua & Rust](https://img.shields.io/badge/Made_with-Lua_&_Rust-orange)]() [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/interesting-vibe-coding/paws/pulls) [![GitHub Stars](https://img.shields.io/github/stars/interesting-vibe-coding/paws?style=flat&color=yellow)](https://github.com/interesting-vibe-coding/paws/stargazers) +[![CI](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml/badge.svg)](https://github.com/interesting-vibe-coding/paws/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Works with Kaku, WezTerm, iTerm2 & tmux](https://img.shields.io/badge/Works_with-Kaku_%7C_WezTerm_%7C_iTerm2_%7C_tmux-blue)](https://github.com/interesting-vibe-coding/paws#install) [![Made with Lua & Rust](https://img.shields.io/badge/Made_with-Lua_&_Rust-orange)]() [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/interesting-vibe-coding/paws/pulls) [![GitHub Stars](https://img.shields.io/github/stars/interesting-vibe-coding/paws?style=flat&color=yellow)](https://github.com/interesting-vibe-coding/paws/stargazers) Agent 工作时尽情玩,需要你时一眼就看到。 @@ -53,7 +53,8 @@ cargo install --git https://github.com/interesting-vibe-coding/paws-games --bin 然后配置终端集成,并为你的 Agent 配置 hooks(参考 [`hooks/`](hooks/) 目录)。 - **Kaku:** 将 [`lua/paws.lua`](lua/paws.lua) 添加到 `~/.config/kaku/kaku.lua` 的 `return config` 之前 — 重载需按 CMD+Shift+R - **WezTerm:** 将 [`lua/paws.lua`](lua/paws.lua) 添加到 `~/.config/wezterm/wezterm.lua` — 保存后自动重载 -- **iTerm2:** 将 [`iterm2/paws.py`](iterm2/paws.py) 复制到 `~/.config/iterm2/scripts/AutoLaunch/`,然后绑定 3 个快捷键 — 详见 [docs/iterm2-setup.md](docs/iterm2-setup.md) +- **iTerm2:** 将 [`iterm2/paws.py`](iterm2/paws.py) 复制到 `~/.config/iterm2/scripts/AutoLaunch/`,绑定 3 个快捷键 — 详见[安装指南](docs/iterm2-setup.md) +- **tmux:** 将 [`tmux/`](tmux/) 脚本复制到 `~/.config/paws/`,在 `~/.tmux.conf` 加 2 行 — 详见[安装指南](docs/tmux-setup.md) ## 游戏 diff --git a/docs/tmux-setup.md b/docs/tmux-setup.md new file mode 100644 index 0000000..beff261 --- /dev/null +++ b/docs/tmux-setup.md @@ -0,0 +1,78 @@ +# Paws × tmux setup + +Paws works in any terminal that runs tmux. The integration is two shell scripts +that handle the window-create/toggle behavior — no dependencies beyond tmux itself. + +## What you get + +| Key | Action | +|-----|--------| +| **Prefix+g** | First press: open the game picker in a new window. After that: toggle agent ↔ game. | +| **Prefix+G** | Close the game window and re-open the picker. | + +> **Prefix** is `Ctrl+B` by default. If you've rebound it, use your custom prefix. + +## Install + +### 1. Copy the scripts + +```bash +mkdir -p ~/.config/paws +cp tmux/paws-toggle.sh ~/.config/paws/tmux-toggle.sh +cp tmux/paws-picker.sh ~/.config/paws/tmux-picker.sh +cp tmux/paws.conf ~/.config/paws/paws.conf +chmod +x ~/.config/paws/tmux-toggle.sh ~/.config/paws/tmux-picker.sh +``` + +### 2. Add keybindings to your tmux config + +**Option A — source the provided config file:** + +```bash +echo 'source-file ~/.config/paws/paws.conf' >> ~/.tmux.conf +``` + +**Option B — copy the two lines directly into `~/.tmux.conf`:** + +``` +bind-key g run-shell "$HOME/.config/paws/tmux-toggle.sh" +bind-key G run-shell "$HOME/.config/paws/tmux-picker.sh" +``` + +### 3. Reload tmux config + +```bash +tmux source-file ~/.tmux.conf +``` + +Or press `Prefix+:` and type `source-file ~/.tmux.conf`. + +### 4. Done + +Press **Prefix+g** — the game picker opens in a new tmux window named `paws`. +The HUD on the top row shows your agent sessions. Press **Prefix+g** again to +toggle back to your previous window. + +## How it works + +`tmux-toggle.sh` queries the current window list with `tmux list-windows` to +find a window named `paws`. If one doesn't exist it spawns a new window running +`paws` via a login shell (so `~/.cargo/bin` is on PATH). If you're already on +the paws window it calls `tmux last-window` to jump back. Otherwise it switches +to the paws window. + +No external state file — tmux's own window list is the source of truth. + +## Troubleshooting + +**`paws: command not found`** +The scripts use a login shell (`$SHELL -l`) so `~/.cargo/bin` should be on +PATH. If it's still missing, run `cargo install --path .` from the paws repo +and try again. + +**Prefix+g conflicts with an existing binding** +Change `g` / `G` to any free key in `paws.conf` (or the lines in `~/.tmux.conf`). + +**Game opens in a small pane instead of full window** +Make sure you're not inside a split pane when pressing Prefix+g. The script +creates a new *window* (full screen), not a pane split. diff --git a/skills/paws-install/SKILL.md b/skills/paws-install/SKILL.md index 815f903..31520ca 100644 --- a/skills/paws-install/SKILL.md +++ b/skills/paws-install/SKILL.md @@ -12,12 +12,13 @@ You are installing Paws for the user. Work from a local clone of this repo ## 0. Preconditions - Confirm the terminal is **Kaku** (`which kaku`), **WezTerm** (`which wezterm`), - or **iTerm2** (`ls /Applications/iTerm.app`). All three are supported. - If none is installed, ask the user to install one first and stop. + **iTerm2** (`ls /Applications/iTerm.app`), or **tmux** (`which tmux`). All four + are supported. If none is installed, ask the user to install one first and stop. - Determine the terminal type — it affects Step 2: - Kaku: `~/.config/kaku/kaku.lua` (Lua config) - WezTerm: `~/.config/wezterm/wezterm.lua` (Lua config) - - iTerm2: Python script + manual key bindings (see Step 2b) + - iTerm2: Python AutoLaunch script + manual key bindings (see Step 2b) + - tmux: two shell scripts + two lines in `~/.tmux.conf` (see Step 2c) - Note the repo root (absolute path) — you'll need it for hook paths. **All hook paths in config files must be absolute** — `~` is not expanded by any of the three agents. @@ -84,6 +85,28 @@ Then tell the user to: Full details: [docs/iterm2-setup.md](../../docs/iterm2-setup.md) +## 2c. Install the tmux scripts (tmux only) + +Skip this step if the user is on Kaku, WezTerm, or iTerm2. + +```bash +mkdir -p ~/.config/paws +cp /tmux/paws-toggle.sh ~/.config/paws/tmux-toggle.sh +cp /tmux/paws-picker.sh ~/.config/paws/tmux-picker.sh +cp /tmux/paws.conf ~/.config/paws/paws.conf +chmod +x ~/.config/paws/tmux-toggle.sh ~/.config/paws/tmux-picker.sh +``` + +Add to `~/.tmux.conf`: +``` +source-file ~/.config/paws/paws.conf +``` + +Then reload: `tmux source-file ~/.tmux.conf` + +Keybindings: **Prefix+g** (toggle), **Prefix+G** (reopen picker). +Full details: [docs/tmux-setup.md](../../docs/tmux-setup.md) + ## 3. Wire the agent's state signals (for the status HUD) Paws ships two hook scripts that write session state to `/tmp/paws-sessions/` diff --git a/tmux/paws-picker.sh b/tmux/paws-picker.sh new file mode 100644 index 0000000..65bd0f0 --- /dev/null +++ b/tmux/paws-picker.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Paws 🐾 tmux picker — close the game window and reopen the picker. +# Bind to your prefix key: +# bind-key P run-shell "~/.config/paws/tmux-picker.sh" + +PAWS_WIN=$(tmux list-windows -F '#{window_index}:#{window_name}' \ + | awk -F: '$2=="paws"{print $1}') + +if [ -n "$PAWS_WIN" ]; then + tmux kill-window -t "$PAWS_WIN" +fi + +tmux new-window -n paws "${SHELL:-/bin/zsh} -l -c paws" diff --git a/tmux/paws-toggle.sh b/tmux/paws-toggle.sh new file mode 100644 index 0000000..42e9eeb --- /dev/null +++ b/tmux/paws-toggle.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Paws 🐾 tmux toggle — bind to your prefix key: +# bind-key g run-shell "~/.config/paws/tmux-toggle.sh" +# +# Press Prefix+g: +# - No paws window exists → create one and switch to it +# - Already on the paws window → jump back to previous window +# - On another window → switch to the paws window + +PAWS_WIN=$(tmux list-windows -F '#{window_index}:#{window_name}' \ + | awk -F: '$2=="paws"{print $1}') +CURRENT=$(tmux display-message -p '#{window_name}') + +if [ -z "$PAWS_WIN" ]; then + # Spawn a new login-shell window so ~/.cargo/bin is on PATH + tmux new-window -n paws "${SHELL:-/bin/zsh} -l -c paws" +elif [ "$CURRENT" = "paws" ]; then + tmux last-window +else + tmux select-window -t "$PAWS_WIN" +fi diff --git a/tmux/paws.conf b/tmux/paws.conf new file mode 100644 index 0000000..857d1cc --- /dev/null +++ b/tmux/paws.conf @@ -0,0 +1,12 @@ +# Paws 🐾 tmux keybindings +# Source this from your ~/.tmux.conf: +# source-file ~/.config/paws/paws.conf +# +# Or copy these lines directly into your ~/.tmux.conf. +# Replace $HOME with the absolute path to your home directory if needed. + +# Prefix+g — open game picker / toggle between agent and game +bind-key g run-shell "$HOME/.config/paws/tmux-toggle.sh" + +# Prefix+G — close the game window and reopen the picker +bind-key G run-shell "$HOME/.config/paws/tmux-picker.sh"