{"_id":"@aerode/pish","_rev":"5-0285b45e242801e9664cf4ca24eed0a8","name":"@aerode/pish","dist-tags":{"latest":"0.10.0"},"versions":{"0.8.0":{"name":"@aerode/pish","version":"0.8.0","keywords":["shell","ai","coding-agent","bash","zsh","pi","cli"],"author":{"name":"dacapoday"},"license":"MIT","_id":"@aerode/pish@0.8.0","maintainers":[{"name":"dacapoday","email":"dacapoday@gmail.com"}],"homepage":"https://github.com/dacapoday/pish","bugs":{"url":"https://github.com/dacapoday/pish/issues"},"bin":{"pish":"dist/main.js"},"dist":{"shasum":"6c097928842b4cb5278c19c970737d43036b0fe9","tarball":"https://registry.npmjs.org/@aerode/pish/-/pish-0.8.0.tgz","fileCount":16,"integrity":"sha512-Oan5NoBNkFukiQAwpLykrOEOB7eduYpyJFmlbZNX5286j/E5XX3rWjxwB5Z+4Aail43PRAE9hb0MMgbcU5Us1g==","signatures":[{"sig":"MEQCIBH4zTa6hK3lJSMwJmjgGcsTbe48WE0capTtZPh66BKwAiBZxjgroZsKMrUzlEWoFeVJrt2kz20BHCS864jxYTSPsw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88028},"type":"module","engines":{"node":">=18"},"gitHead":"d10a643a12820c1d6258e113b1d02b39426f94ce","scripts":{"dev":"tsc --watch","lint":"biome check src/ test/","test":"bash test/run_tests.sh","build":"tsc && tsc -p tsconfig.test.json && chmod +x dist/main.js","clean":"rm -rf dist","start":"node dist/main.js","test:unit":"npx tsx --test test/unit/*.test.ts","postinstall":"sh postinstall.sh"},"_npmUser":{"name":"dacapoday","email":"dacapoday@gmail.com"},"repository":{"url":"git+https://github.com/dacapoday/pish.git","type":"git"},"_npmVersion":"11.9.0","description":"A shell-first pi coding agent","directories":{},"_nodeVersion":"24.14.0","dependencies":{"node-pty":"^1.0.0","@xterm/headless":"^6.0.0","@mariozechner/pi-tui":"^0.64.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.10"},"_npmOperationalInternal":{"tmp":"tmp/pish_0.8.0_1775272412588_0.8246274473655084","host":"s3://npm-registry-packages-npm-production"}},"0.9.1":{"name":"@aerode/pish","version":"0.9.1","keywords":["shell","ai","coding-agent","bash","zsh","pi","cli"],"author":{"name":"dacapoday"},"license":"MIT","_id":"@aerode/pish@0.9.1","maintainers":[{"name":"dacapoday","email":"dacapoday@gmail.com"}],"homepage":"https://github.com/dacapoday/pish","bugs":{"url":"https://github.com/dacapoday/pish/issues"},"bin":{"pish":"dist/main.js"},"dist":{"shasum":"4ec193aab418ac97c806dff804cd9b274763b30d","tarball":"https://registry.npmjs.org/@aerode/pish/-/pish-0.9.1.tgz","fileCount":17,"integrity":"sha512-9bs8wqno0rTXvMcZJgrHlQG4V7kJkkxuMzFR0zlpm1W8yqiFlXcP1mx3LtOIDZuF9qTX3KI8+D4iYW6GqIpz3g==","signatures":[{"sig":"MEUCIFVA75tvwxJpkxMQ7WD+cpWwl4PLER3o0TTiEMcfTYnFAiEAqVyo1CB8j0xfkEERUueh8YOz6EuoRuAxi4l1z4JdfAQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":91118},"type":"module","engines":{"node":">=18"},"gitHead":"e595e38deb88118ad6a409a0f0cc9d536b5be43e","scripts":{"dev":"tsc --watch","lint":"biome check src/ test/","test":"bash test/run_tests.sh","build":"tsc && tsc -p tsconfig.test.json && chmod +x dist/main.js","clean":"rm -rf dist","start":"node dist/main.js","test:unit":"npx tsx --test test/unit/*.test.ts","postinstall":"sh postinstall.sh"},"_npmUser":{"name":"dacapoday","email":"dacapoday@gmail.com"},"repository":{"url":"git+https://github.com/dacapoday/pish.git","type":"git"},"_npmVersion":"11.9.0","description":"A shell-first pi coding agent","directories":{},"_nodeVersion":"24.14.0","dependencies":{"node-pty":"^1.0.0","@xterm/headless":"^6.0.0","@mariozechner/pi-tui":"^0.64.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.10"},"_npmOperationalInternal":{"tmp":"tmp/pish_0.9.1_1775293119029_0.2635518299218451","host":"s3://npm-registry-packages-npm-production"}},"0.9.2":{"name":"@aerode/pish","version":"0.9.2","keywords":["shell","ai","coding-agent","bash","zsh","pi","cli"],"author":{"name":"dacapoday"},"license":"MIT","_id":"@aerode/pish@0.9.2","maintainers":[{"name":"dacapoday","email":"dacapoday@gmail.com"}],"homepage":"https://github.com/dacapoday/pish","bugs":{"url":"https://github.com/dacapoday/pish/issues"},"bin":{"pish":"dist/main.js"},"dist":{"shasum":"5b0b951d1a5f4f9c46e68a06ed2cf547b2486620","tarball":"https://registry.npmjs.org/@aerode/pish/-/pish-0.9.2.tgz","fileCount":17,"integrity":"sha512-56ROUwK8iZ9unzOxYzgIl+GAU3gSlXNfd6bTGtTbyGI5tmx1hvuP4ZZ+GimyQkGnMZjfk+xcJiXL7Lk//o0Q4w==","signatures":[{"sig":"MEYCIQDXe+QGow3+Ghg6D5EqlUr9RtAFdKmngwFXwjxHHKw/fwIhAJng9oR3A/mobXDuEKK1w9qW251saBDVG2bo+FXYUWOV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":100565},"type":"module","engines":{"node":">=18"},"gitHead":"a013a1ad7d8912fbbdef91b93ac44ddeedf2f0b4","scripts":{"dev":"tsc --watch","lint":"biome check src/ test/","test":"bash test/run_tests.sh","build":"tsc && tsc -p tsconfig.test.json && chmod +x dist/main.js","clean":"rm -rf dist","start":"node dist/main.js","test:unit":"npx tsx --test test/unit/*.test.ts","postinstall":"sh postinstall.sh"},"_npmUser":{"name":"dacapoday","email":"dacapoday@gmail.com"},"repository":{"url":"git+https://github.com/dacapoday/pish.git","type":"git"},"_npmVersion":"10.9.7","description":"A shell-first pi coding agent","directories":{},"_nodeVersion":"22.22.2","dependencies":{"node-pty":"^1.0.0","@xterm/headless":"^6.0.0","@mariozechner/pi-tui":"^0.65.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^6.0.2","@types/node":"^25.5.2","@biomejs/biome":"^2.4.10"},"_npmOperationalInternal":{"tmp":"tmp/pish_0.9.2_1775385196285_0.5520670283692422","host":"s3://npm-registry-packages-npm-production"}},"0.9.3":{"name":"@aerode/pish","version":"0.9.3","keywords":["shell","ai","coding-agent","bash","zsh","pi","cli"],"author":{"name":"dacapoday"},"license":"MIT","_id":"@aerode/pish@0.9.3","maintainers":[{"name":"dacapoday","email":"dacapoday@gmail.com"}],"homepage":"https://github.com/dacapoday/pish","bugs":{"url":"https://github.com/dacapoday/pish/issues"},"bin":{"pish":"dist/main.js"},"dist":{"shasum":"337365b128c9508942dec65eb783ff995bbd41f2","tarball":"https://registry.npmjs.org/@aerode/pish/-/pish-0.9.3.tgz","fileCount":17,"integrity":"sha512-pP/cyleVJh4WA8SLHtVWMFM/Q8Ap2Yqi+Dod+O1dHofboQEBvAu0BiDlfYuUfKUHe7v6QzDPiCiBQC82KCE20w==","signatures":[{"sig":"MEUCIHksU+dGI01wj4mVUn8sCxzqQJCddRI5eLHrngr4IZtDAiEAvUI6rB5wilF0a5ACAlblSz45Z1imUqAe4hwDqms5r5E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":100589},"type":"module","engines":{"node":">=18"},"gitHead":"87a56a68f230a40306da22b2c7652131c67d8e72","scripts":{"dev":"tsc --watch","lint":"biome check src/ test/","test":"bash test/run_tests.sh","build":"tsc && tsc -p tsconfig.test.json && chmod +x dist/main.js","clean":"rm -rf dist","start":"node dist/main.js","test:unit":"npx tsx --test test/unit/*.test.ts","postinstall":"sh postinstall.sh"},"_npmUser":{"name":"dacapoday","email":"dacapoday@gmail.com"},"repository":{"url":"git+https://github.com/dacapoday/pish.git","type":"git"},"_npmVersion":"10.9.7","description":"A shell-first pi coding agent","directories":{},"_nodeVersion":"22.22.2","dependencies":{"node-pty":"^1.0.0","@xterm/headless":"^6.0.0","@mariozechner/pi-tui":"^0.65.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^6.0.2","@types/node":"^25.5.2","@biomejs/biome":"^2.4.10"},"_npmOperationalInternal":{"tmp":"tmp/pish_0.9.3_1776222123098_0.34214253986229926","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@aerode/pish","version":"0.10.0","description":"A shell-first pi coding agent","license":"MIT","author":{"name":"dacapoday"},"repository":{"type":"git","url":"git+https://github.com/dacapoday/pish.git"},"homepage":"https://github.com/dacapoday/pish","bugs":{"url":"https://github.com/dacapoday/pish/issues"},"keywords":["shell","ai","coding-agent","bash","zsh","pi","cli"],"engines":{"node":">=18"},"type":"module","bin":{"pish":"dist/main.js"},"scripts":{"postinstall":"sh postinstall.sh","build":"tsc && tsc -p tsconfig.test.json && chmod +x dist/main.js","clean":"rm -rf dist","start":"node dist/main.js","dev":"tsc --watch","lint":"biome check src/ test/","test":"bash test/run_tests.sh","test:unit":"npx tsx --test test/unit/*.test.ts"},"dependencies":{"@earendil-works/pi-tui":"^0.84.0","@xterm/headless":"^6.0.0","node-pty":"^1.0.0"},"devDependencies":{"@biomejs/biome":"^2.4.10","@types/node":"^25.5.2","tsx":"^4.21.0","typescript":"^6.0.2"},"_id":"@aerode/pish@0.10.0","gitHead":"fbe1888e1119870043c7de732fe397b43fe3b56c","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-SyZkv6tSWqb4pCFPfu+8ddBnOOd4EonbRt/EG9VTEPaoEXwEPSb/X6a+eA9ZoPbxVEXXLkNRLF5rTn7DTnDjcw==","shasum":"1bf309ef424386e776a4209c02808023887619eb","tarball":"https://registry.npmjs.org/@aerode/pish/-/pish-0.10.0.tgz","fileCount":17,"unpackedSize":102216,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDOssTcTCgsGGvam0Tx2Gxso4D/sFi+wajSZ35E8CE+TQIgTgOrmScY47ykn/lJpB/9CHPzHvUStLgDwa8OTx29o7o="}]},"_npmUser":{"name":"dacapoday","email":"dacapoday@gmail.com"},"directories":{},"maintainers":[{"name":"dacapoday","email":"dacapoday@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pish_0.10.0_1786086089115_0.09627729133627705"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-04T03:13:32.500Z","modified":"2026-08-07T07:01:29.446Z","0.8.0":"2026-04-04T03:13:32.724Z","0.9.1":"2026-04-04T08:58:39.161Z","0.9.2":"2026-04-05T10:33:16.428Z","0.9.3":"2026-04-15T03:02:03.272Z","0.10.0":"2026-08-07T07:01:29.269Z"},"bugs":{"url":"https://github.com/dacapoday/pish/issues"},"author":{"name":"dacapoday"},"license":"MIT","homepage":"https://github.com/dacapoday/pish","keywords":["shell","ai","coding-agent","bash","zsh","pi","cli"],"repository":{"type":"git","url":"git+https://github.com/dacapoday/pish.git"},"description":"A shell-first pi coding agent","maintainers":[{"name":"dacapoday","email":"dacapoday@gmail.com"}],"readme":"<div align=\"center\">\n\n# pish\n\n**Your shell, with AI built in.**\n\n[![CI](https://github.com/dacapoday/pish/actions/workflows/ci.yml/badge.svg)](https://github.com/dacapoday/pish/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/@aerode/pish?color=cb0000&label=npm)](https://www.npmjs.com/package/@aerode/pish)\n[![Node.js](https://img.shields.io/badge/node-%E2%89%A518-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n<br/>\n\n<p>\n  <a href=\"#-features\">Features</a> ·\n  <a href=\"#-quick-start\">Quick Start</a> ·\n  <a href=\"#-usage\">Usage</a> ·\n  <a href=\"#%EF%B8%8F-configuration\">Configuration</a> ·\n  <a href=\"#-how-it-works\">How It Works</a> ·\n  <a href=\"#-contributing\">Contributing</a>\n</p>\n\n<br/>\n\n<img src=\"pish-example.gif\" alt=\"pish demo\" width=\"640\">\n\n</div>\n\n---\n\n## Why pish?\n\nYou already know your shell. You've built muscle memory for `cd`, `grep`, `git`, pipes, redirections, and a hundred aliases. **Why should talking to AI mean leaving all that behind?**\n\npish doesn't replace your shell — it **is** your shell. Every command you know works exactly as before, with zero overhead. The moment you type something the shell doesn't recognize, an AI coding agent ([pi](https://github.com/earendil-works/pi)) seamlessly steps in — reading files, running commands, and editing code — all without breaking your flow.\n\n> **Think of it as autocomplete for intent:** you describe what you want in plain English, and pish makes it happen, right where you are.\n\n## ✨ Features\n\n<table>\n<tr>\n<td width=\"50%\">\n\n### 🔄 Transparent Shell Wrapper\nEvery alias, function, pipe, redirection, job control, tab completion, and history feature works exactly as in your native bash/zsh.\n\n### 🤖 Automatic AI Agent\nType anything the shell doesn't recognize — the AI agent activates with your recent shell context, reads files, runs commands, and edits code.\n\n### 🚀 Zero Overhead\nNormal commands never touch the AI. No hooks intercepting your keystrokes, no latency. The agent is on-demand only.\n\n</td>\n<td width=\"50%\">\n\n### 🧠 Context-Aware\nThe agent automatically sees your recent commands and their outputs — it understands what you've been doing and can pick up where you left off.\n\n### 🔀 Seamless pi TUI\nType `pi` to switch to the full pi TUI. Your conversation carries over — the AI remembers everything. Exit pi, and you're right back in pish.\n\n### ⚡ Control Commands\nSwitch models, adjust thinking levels, and compact context — all without leaving your terminal. Just type `/model`, `/think`, or `/compact`.\n\n</td>\n</tr>\n</table>\n\n## 📦 Quick Start\n\n### Prerequisites\n\n- **Node.js** ≥ 18\n- **bash** ≥ 4.4 or **zsh** ≥ 5.0\n- [**pi**](https://github.com/earendil-works/pi) installed and on PATH\n\n### Install from npm\n\n```bash\nnpm install -g @aerode/pish\n```\n\n### Install from source\n\n```bash\ngit clone https://github.com/dacapoday/pish.git\ncd pish\nnpm install\nnpm run build\nnpm link          # makes `pish` available globally\n```\n\n### Launch\n\n```bash\npish                            # start with $SHELL (or bash)\npish zsh                        # start with zsh\npish /usr/local/bin/bash        # use a specific shell binary\npish --pi /path/to/pi           # use a specific pi binary\n```\n\n## 🎯 Usage\n\n### Normal commands — everything just works\n\nAliases, functions, pipes, redirections, job control, history, tab completion — **all unchanged**. pish adds zero overhead to normal shell operations.\n\n### AI agent — just describe what you want\n\nType anything the shell doesn't recognize. The agent sees your recent commands and their outputs as context:\n\n```\n❯ find all TODO comments in src/\n⠋ Working...\n  $ grep -rn \"TODO\" src/\n✓ done (2.1s · 1.2k tokens · $0.003 · claude-sonnet-4-20250514)\n```\n\nThe agent can:\n- 📖 Read files and understand project structure\n- ⚡ Run commands to gather information\n- ✏️ Edit code across multiple files\n- 🔍 Debug errors using your recent shell output as context\n\n### Reverse to pi TUI\n\nType `pi` with no arguments to open the full [pi](https://github.com/earendil-works/pi) TUI. Your conversation carries over — the AI remembers everything from the current session. When you exit, you're back in pish with the updated session.\n\n> **Tip:** `pi` with any arguments (e.g. `pi --help`, `pi some-file.txt`) is passed straight through to the original pi binary — only bare `pi` activates the session handoff. You can also use `command pi` to bypass pish entirely.\n\n### Control commands\n\n| Command | Description | Example |\n|---------|-------------|---------|\n| `/compact [instructions]` | Compact agent context | `/compact focus on auth` |\n| `/model [provider/model]` | Switch or query model | `/model anthropic/claude-sonnet-4-20250514` |\n| `/think [level]` | Set thinking level | `/think high` |\n\n### Keyboard shortcuts\n\n| Key | Action |\n|-----|--------|\n| <kbd>Ctrl</kbd>+<kbd>C</kbd> | Abort running agent |\n| <kbd>Ctrl</kbd>+<kbd>L</kbd> | Clear screen + reset context + reset session |\n\n## ⚙️ Configuration\n\nConfiguration priority: **CLI args > Environment variables > Defaults**\n\n### CLI Options\n\n```\npish [options] [shell]\n\nArguments:\n  shell               bash, zsh, or full path (default: $SHELL or bash)\n\nOptions:\n  -s, --shell <name>  Shell name or path\n  --pi <path>         Path to pi binary\n  --no-agent          Disable agent (for debugging)\n  -v, --version       Show version\n  -h, --help          Show help\n```\n\n### Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `PISH_SHELL` | Shell name or path | `$SHELL` or `bash` |\n| `PISH_PI` | Path to pi binary | `pi` |\n| `PISH_MAX_CONTEXT` | Max history entries sent to AI | `20` |\n| `PISH_HEAD_LINES` | Output head lines kept per command | `50` |\n| `PISH_TAIL_LINES` | Output tail lines kept per command | `30` |\n| `PISH_LINE_WIDTH` | Max chars per output line | `512` |\n| `PISH_TOOL_LINES` | Max tool result lines displayed | `10` |\n| `PISH_LOG` | Event log (`stderr` or file path) | off |\n| `PISH_DEBUG` | Debug log file path | off |\n| `PISH_NO_BANNER` | Hide startup banner (set to `1`) | off |\n\n## 🏗️ How It Works\n\npish runs your shell inside a PTY with lightweight hooks injected via a temporary rcfile. An [OSC 9154](https://en.wikipedia.org/wiki/ANSI_escape_code#OSC_(Operating_System_Command)_sequences) signal protocol embedded in the terminal data stream lets pish detect shell events — command execution, prompts, errors — without interfering with normal operation.\n\n```\n┌─────────────────────────────────────────────────────┐\n│  Terminal (stdin/stdout)                            │\n│       ▲                                             │\n│       │                                             │\n│       ▼                                             │\n│  ┌─────────────────────────────────────────────┐    │\n│  │  pish (Node.js)                             │    │\n│  │                                             │    │\n│  │  ┌──────────┐   ┌──────────┐                │    │\n│  │  │ Recorder │◄──│ OSC      │  PTY data      │    │\n│  │  │ (context)│   │ Parser   │◄──────────┐    │    │\n│  │  └────┬─────┘   └──────────┘           │    │    │\n│  │       │                                │    │    │\n│  │       ▼                                │    │    │\n│  │  ┌──────────┐                  ┌───────┴─┐  │    │\n│  │  │ Agent    │  pi --mode rpc   │ PTY     │  │    │\n│  │  │ Manager  │◄────────────────►│ bash/zsh│  │    │\n│  │  └────┬─────┘   (on demand)    │ +hooks  │  │    │\n│  │       │                        └────┬────┘  │    │\n│  │       ▼                             │       │    │\n│  │  ┌──────────┐                  ┌────┴────┐  │    │\n│  │  │ Renderer │──► stderr        │ FIFO    │  │    │\n│  │  │ (pi-tui) │    (AI output)   │ (sync)  │  │    │\n│  │  └──────────┘                  └─────────┘  │    │\n│  └─────────────────────────────────────────────┘    │\n└─────────────────────────────────────────────────────┘\n```\n\n### Key design decisions\n\n| Decision | Rationale |\n|----------|-----------|\n| Agent output goes to **stderr** | Never contaminates shell stdout — pipes and redirections work perfectly |\n| Normal commands **never touch FIFO** | Zero latency for regular shell operations |\n| Agent spawns **on demand** | No background process until you need it — instant startup |\n| Session persists **across agent restarts** | Your conversation context survives `kill` and `reverse` |\n| Context is **automatically truncated** | Smart head/tail truncation keeps AI context relevant without overwhelming tokens |\n\n### The four signal paths\n\n| Path | Trigger | What happens |\n|------|---------|-------------|\n| **Normal command** | `ls`, `git status`, etc. | Flows through PTY untouched. Recorder captures output for context. |\n| **AI agent** | Unknown command like `fix the bug` | CNF fires → FIFO blocks shell → agent runs → PROCEED unblocks |\n| **Reverse pi** | `pi` (no args) | Switches to full pi TUI with session handoff, returns to pish on exit |\n| **Empty line** | Just pressing Enter | No-op, no context captured |\n\n## 🧪 Testing\n\npish has a comprehensive three-layer test suite:\n\n```bash\n# Run everything\nbash test/run_tests.sh\n\n# Unit tests only (~60s, 104 tests covering osc/strip/recorder/agent/config)\nnpm run test:unit\n\n# Fast scenario tests (~10s, no pi binary needed)\nbash test/run_tests.sh fast\n\n# Slow scenario tests (~2min, needs real pi + LLM)\nbash test/run_tests.sh slow\n\n# Single test\nbash test/run_tests.sh bash normal_cmd\n```\n\n| Layer | Tests | What it covers | Requires pi? |\n|-------|-------|---------------|-------------|\n| **Unit** | 104 | OSC parsing, ANSI stripping, recorder logic, agent RPC, config loading | No |\n| **Fast scenarios** | 10 × bash/zsh + 3 edge | Shell lifecycle, context capture, truncation, nesting, control commands | No |\n| **Slow scenarios** | 6 × bash/zsh | Real agent interaction, abort, reverse, model switching | Yes |\n\nScenario tests use `expect` scripts to drive real shell sessions, produce JSONL event logs, and verify with assertion-based checks.\n\n## 🤝 Contributing\n\nContributions are welcome! Here's how to get started:\n\n```bash\ngit clone https://github.com/dacapoday/pish.git\ncd pish\nnpm install\nnpm run build\n```\n\n### Development workflow\n\n```bash\nnpm run dev           # Watch mode (tsc --watch)\nnpm run lint          # Biome lint + format check\nnpm run test:unit     # Quick unit tests\nbash test/run_tests.sh fast   # Fast scenario tests\n```\n\n### Project structure\n\n```\nsrc/\n├── main.ts        # Entry point: bootstrap + I/O wiring\n├── app.ts         # Core state machine + event dispatch\n├── config.ts      # Unified config (CLI + ENV + defaults)\n├── recorder.ts    # PTY stream → context entries\n├── agent.ts       # pi RPC process management\n├── hooks.ts       # bash/zsh rcfile generation\n├── render.ts      # Agent UI → stderr (Markdown, spinner, status)\n├── osc.ts         # OSC 9154 signal parser\n├── session.ts     # pi session file discovery\n├── theme.ts       # ANSI colors + Markdown theme\n├── vterm.ts       # xterm headless prompt replay\n├── strip.ts       # ANSI stripping + truncation\n└── log.ts         # JSON event logging\n```\n\nBefore submitting a PR, please:\n1. Run `npm run lint` to ensure code style\n2. Run `bash test/run_tests.sh fast` to verify nothing is broken\n3. Update documentation if behavior changes\n\n## 📋 Known Limitations\n\n- **Bash keywords** — `do something` or `if something` triggers a bash syntax error instead of the AI agent. Rephrase as `please do something`.\n- **CNF returns 0** — `$?` after an agent run is always 0, not 127.\n- **Reverse context** — When switching to pi TUI, shell context history is not transferred (only the agent session carries over).\n- **bash 4.4+ required** — macOS ships bash 3.2; install a newer version via `brew install bash`.\n\n## 📄 License\n\n[MIT](LICENSE) © [dacapoday](https://github.com/dacapoday)\n\n---\n\n<div align=\"center\">\n\n**[⬆ Back to top](#pish)**\n\n</div>\n","readmeFilename":"README.md"}