@aerode/pish 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,33 +1,79 @@
1
+ <div align="center">
2
+
1
3
  # pish
2
4
 
3
5
  **Your shell, with AI built in.**
4
6
 
5
- pish wraps bash or zsh transparently. Every command you know works exactly as before — zero overhead. When you type something the shell doesn't recognize, an AI agent ([pi](https://github.com/badlogic/pi-mono)) kicks in automatically.
7
+ [![CI](https://github.com/dacapoday/pish/actions/workflows/ci.yml/badge.svg)](https://github.com/dacapoday/pish/actions/workflows/ci.yml)
8
+ [![npm version](https://img.shields.io/npm/v/@aerode/pish?color=cb0000&label=npm)](https://www.npmjs.com/package/@aerode/pish)
9
+ [![Node.js](https://img.shields.io/badge/node-%E2%89%A518-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/)
10
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
11
+
12
+ <br/>
6
13
 
7
- <p align="center">
8
- <img src="pish-example.gif" alt="pish demo" width="600">
14
+ <p>
15
+ <a href="#-features">Features</a> ·
16
+ <a href="#-quick-start">Quick Start</a> ·
17
+ <a href="#-usage">Usage</a> ·
18
+ <a href="#%EF%B8%8F-configuration">Configuration</a> ·
19
+ <a href="#-how-it-works">How It Works</a> ·
20
+ <a href="#-contributing">Contributing</a>
9
21
  </p>
10
22
 
11
- ## How it works
23
+ <br/>
12
24
 
13
- pish runs your shell inside a PTY with lightweight hooks injected via rcfile. Normal commands flow through untouched. Only when `command_not_found` fires does pish intercept — it sends your recent shell history as context to the AI agent, which can read files, run commands, and edit code.
25
+ <img src="pish-example.gif" alt="pish demo" width="640">
14
26
 
15
- ```
16
- You ←→ pish (Node.js) ←→ PTY (bash/zsh + hooks)
17
-
18
- Agent (pi --mode rpc, on demand)
19
-
20
- Renderer → stderr
21
- ```
27
+ </div>
28
+
29
+ ---
30
+
31
+ ## Why pish?
32
+
33
+ You 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?**
34
+
35
+ pish 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/badlogic/pi-mono)) seamlessly steps in — reading files, running commands, and editing code — all without breaking your flow.
36
+
37
+ > **Think of it as autocomplete for intent:** you describe what you want in plain English, and pish makes it happen, right where you are.
38
+
39
+ ## ✨ Features
40
+
41
+ <table>
42
+ <tr>
43
+ <td width="50%">
44
+
45
+ ### 🔄 Transparent Shell Wrapper
46
+ Every alias, function, pipe, redirection, job control, tab completion, and history feature works exactly as in your native bash/zsh.
47
+
48
+ ### 🤖 Automatic AI Agent
49
+ Type anything the shell doesn't recognize — the AI agent activates with your recent shell context, reads files, runs commands, and edits code.
50
+
51
+ ### 🚀 Zero Overhead
52
+ Normal commands never touch the AI. No hooks intercepting your keystrokes, no latency. The agent is on-demand only.
53
+
54
+ </td>
55
+ <td width="50%">
56
+
57
+ ### 🧠 Context-Aware
58
+ The agent automatically sees your recent commands and their outputs — it understands what you've been doing and can pick up where you left off.
59
+
60
+ ### 🔀 Seamless pi TUI
61
+ Type `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.
22
62
 
23
- Agent output goes to **stderr**, never contaminating your shell's stdout. Your prompt, pipes, and redirections work exactly as expected.
63
+ ### Control Commands
64
+ Switch models, adjust thinking levels, and compact context — all without leaving your terminal. Just type `/model`, `/think`, or `/compact`.
24
65
 
25
- ## Quick start
66
+ </td>
67
+ </tr>
68
+ </table>
26
69
 
27
- **Requirements:**
28
- - Node.js ≥ 18
29
- - bash ≥ 4.4 or zsh ≥ 5.0
30
- - [`pi`](https://github.com/badlogic/pi-mono) installed and on PATH
70
+ ## 📦 Quick Start
71
+
72
+ ### Prerequisites
73
+
74
+ - **Node.js** ≥ 18
75
+ - **bash** ≥ 4.4 or **zsh** ≥ 5.0
76
+ - [**pi**](https://github.com/badlogic/pi-mono) installed and on PATH
31
77
 
32
78
  ### Install from npm
33
79
 
@@ -45,7 +91,7 @@ npm run build
45
91
  npm link # makes `pish` available globally
46
92
  ```
47
93
 
48
- ### Run
94
+ ### Launch
49
95
 
50
96
  ```bash
51
97
  pish # start with $SHELL (or bash)
@@ -54,13 +100,13 @@ pish /usr/local/bin/bash # use a specific shell binary
54
100
  pish --pi /path/to/pi # use a specific pi binary
55
101
  ```
56
102
 
57
- ## Usage
103
+ ## 🎯 Usage
58
104
 
59
- ### Normal commands
105
+ ### Normal commands — everything just works
60
106
 
61
- Everything works exactly like your regular shell — aliases, functions, pipes, redirections, job control, history, tab completion.
107
+ Aliases, functions, pipes, redirections, job control, history, tab completion — **all unchanged**. pish adds zero overhead to normal shell operations.
62
108
 
63
- ### AI agent
109
+ ### AI agent — just describe what you want
64
110
 
65
111
  Type anything the shell doesn't recognize. The agent sees your recent commands and their outputs as context:
66
112
 
@@ -68,35 +114,48 @@ Type anything the shell doesn't recognize. The agent sees your recent commands a
68
114
  ❯ find all TODO comments in src/
69
115
  ⠋ Working...
70
116
  $ grep -rn "TODO" src/
71
- ✓ done (2.1s)
117
+ ✓ done (2.1s · 1.2k tokens · $0.003 · claude-sonnet-4-20250514)
72
118
  ```
73
119
 
120
+ The agent can:
121
+ - 📖 Read files and understand project structure
122
+ - ⚡ Run commands to gather information
123
+ - ✏️ Edit code across multiple files
124
+ - 🔍 Debug errors using your recent shell output as context
125
+
74
126
  ### Reverse to pi TUI
75
127
 
76
- Type `pi` with no arguments to open the full pi TUI. Your conversation carries over — the AI remembers everything from the current session. When you exit pi, you're back in pish.
128
+ Type `pi` with no arguments to open the full [pi](https://github.com/badlogic/pi-mono) 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.
129
+
130
+ > **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.
77
131
 
78
132
  ### Control commands
79
133
 
80
- ```
81
- /compact [instructions] # compact agent context
82
- /model provider/model # switch model
83
- /think [level] # set thinking level (none/low/medium/high)
84
- ```
134
+ | Command | Description | Example |
135
+ |---------|-------------|---------|
136
+ | `/compact [instructions]` | Compact agent context | `/compact focus on auth` |
137
+ | `/model [provider/model]` | Switch or query model | `/model anthropic/claude-sonnet-4-20250514` |
138
+ | `/think [level]` | Set thinking level | `/think high` |
85
139
 
86
140
  ### Keyboard shortcuts
87
141
 
88
142
  | Key | Action |
89
143
  |-----|--------|
90
- | `Ctrl+C` | Abort running agent |
91
- | `Ctrl+L` | Clear screen + reset context + reset session |
144
+ | <kbd>Ctrl</kbd>+<kbd>C</kbd> | Abort running agent |
145
+ | <kbd>Ctrl</kbd>+<kbd>L</kbd> | Clear screen + reset context + reset session |
146
+
147
+ ## ⚙️ Configuration
92
148
 
93
- ## Configuration
149
+ Configuration priority: **CLI args > Environment variables > Defaults**
94
150
 
95
- Priority: **CLI > ENV > defaults**
151
+ ### CLI Options
96
152
 
97
153
  ```
98
154
  pish [options] [shell]
99
155
 
156
+ Arguments:
157
+ shell bash, zsh, or full path (default: $SHELL or bash)
158
+
100
159
  Options:
101
160
  -s, --shell <name> Shell name or path
102
161
  --pi <path> Path to pi binary
@@ -105,25 +164,161 @@ Options:
105
164
  -h, --help Show help
106
165
  ```
107
166
 
108
- | Environment variable | Description | Default |
109
- |---------------------|-------------|---------|
167
+ ### Environment Variables
168
+
169
+ | Variable | Description | Default |
170
+ |----------|-------------|---------|
110
171
  | `PISH_SHELL` | Shell name or path | `$SHELL` or `bash` |
111
172
  | `PISH_PI` | Path to pi binary | `pi` |
112
173
  | `PISH_MAX_CONTEXT` | Max history entries sent to AI | `20` |
113
- | `PISH_HEAD_LINES` | Output head lines kept | `50` |
114
- | `PISH_TAIL_LINES` | Output tail lines kept | `30` |
115
- | `PISH_LINE_WIDTH` | Max chars per line | `512` |
116
- | `PISH_TOOL_LINES` | Max tool result lines shown | `10` |
174
+ | `PISH_HEAD_LINES` | Output head lines kept per command | `50` |
175
+ | `PISH_TAIL_LINES` | Output tail lines kept per command | `30` |
176
+ | `PISH_LINE_WIDTH` | Max chars per output line | `512` |
177
+ | `PISH_TOOL_LINES` | Max tool result lines displayed | `10` |
117
178
  | `PISH_LOG` | Event log (`stderr` or file path) | off |
118
179
  | `PISH_DEBUG` | Debug log file path | off |
119
180
  | `PISH_NO_BANNER` | Hide startup banner (set to `1`) | off |
120
181
 
182
+ ## 🏗️ How It Works
183
+
184
+ pish 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.
185
+
186
+ ```
187
+ ┌─────────────────────────────────────────────────────┐
188
+ │ Terminal (stdin/stdout) │
189
+ │ ▲ │
190
+ │ │ │
191
+ │ ▼ │
192
+ │ ┌─────────────────────────────────────────────┐ │
193
+ │ │ pish (Node.js) │ │
194
+ │ │ │ │
195
+ │ │ ┌──────────┐ ┌──────────┐ │ │
196
+ │ │ │ Recorder │◄──│ OSC │ PTY data │ │
197
+ │ │ │ (context)│ │ Parser │◄──────────┐ │ │
198
+ │ │ └────┬─────┘ └──────────┘ │ │ │
199
+ │ │ │ │ │ │
200
+ │ │ ▼ │ │ │
201
+ │ │ ┌──────────┐ ┌───────┴─┐ │ │
202
+ │ │ │ Agent │ pi --mode rpc │ PTY │ │ │
203
+ │ │ │ Manager │◄────────────────►│ bash/zsh│ │ │
204
+ │ │ └────┬─────┘ (on demand) │ +hooks │ │ │
205
+ │ │ │ └────┬────┘ │ │
206
+ │ │ ▼ │ │ │
207
+ │ │ ┌──────────┐ ┌────┴────┐ │ │
208
+ │ │ │ Renderer │──► stderr │ FIFO │ │ │
209
+ │ │ │ (pi-tui) │ (AI output) │ (sync) │ │ │
210
+ │ │ └──────────┘ └─────────┘ │ │
211
+ │ └─────────────────────────────────────────────┘ │
212
+ └─────────────────────────────────────────────────────┘
213
+ ```
214
+
215
+ ### Key design decisions
216
+
217
+ | Decision | Rationale |
218
+ |----------|-----------|
219
+ | Agent output goes to **stderr** | Never contaminates shell stdout — pipes and redirections work perfectly |
220
+ | Normal commands **never touch FIFO** | Zero latency for regular shell operations |
221
+ | Agent spawns **on demand** | No background process until you need it — instant startup |
222
+ | Session persists **across agent restarts** | Your conversation context survives `kill` and `reverse` |
223
+ | Context is **automatically truncated** | Smart head/tail truncation keeps AI context relevant without overwhelming tokens |
224
+
225
+ ### The four signal paths
226
+
227
+ | Path | Trigger | What happens |
228
+ |------|---------|-------------|
229
+ | **Normal command** | `ls`, `git status`, etc. | Flows through PTY untouched. Recorder captures output for context. |
230
+ | **AI agent** | Unknown command like `fix the bug` | CNF fires → FIFO blocks shell → agent runs → PROCEED unblocks |
231
+ | **Reverse pi** | `pi` (no args) | Switches to full pi TUI with session handoff, returns to pish on exit |
232
+ | **Empty line** | Just pressing Enter | No-op, no context captured |
121
233
 
122
- ## Known limitations
234
+ ## 🧪 Testing
123
235
 
124
- - **Bash keywords** — `do something` or `if something` triggers a syntax error instead of the AI agent. Rephrase as `please do something`.
236
+ pish has a comprehensive three-layer test suite:
237
+
238
+ ```bash
239
+ # Run everything
240
+ bash test/run_tests.sh
241
+
242
+ # Unit tests only (~60s, 104 tests covering osc/strip/recorder/agent/config)
243
+ npm run test:unit
244
+
245
+ # Fast scenario tests (~10s, no pi binary needed)
246
+ bash test/run_tests.sh fast
247
+
248
+ # Slow scenario tests (~2min, needs real pi + LLM)
249
+ bash test/run_tests.sh slow
250
+
251
+ # Single test
252
+ bash test/run_tests.sh bash normal_cmd
253
+ ```
254
+
255
+ | Layer | Tests | What it covers | Requires pi? |
256
+ |-------|-------|---------------|-------------|
257
+ | **Unit** | 104 | OSC parsing, ANSI stripping, recorder logic, agent RPC, config loading | No |
258
+ | **Fast scenarios** | 10 × bash/zsh + 3 edge | Shell lifecycle, context capture, truncation, nesting, control commands | No |
259
+ | **Slow scenarios** | 6 × bash/zsh | Real agent interaction, abort, reverse, model switching | Yes |
260
+
261
+ Scenario tests use `expect` scripts to drive real shell sessions, produce JSONL event logs, and verify with assertion-based checks.
262
+
263
+ ## 🤝 Contributing
264
+
265
+ Contributions are welcome! Here's how to get started:
266
+
267
+ ```bash
268
+ git clone https://github.com/dacapoday/pish.git
269
+ cd pish
270
+ npm install
271
+ npm run build
272
+ ```
273
+
274
+ ### Development workflow
275
+
276
+ ```bash
277
+ npm run dev # Watch mode (tsc --watch)
278
+ npm run lint # Biome lint + format check
279
+ npm run test:unit # Quick unit tests
280
+ bash test/run_tests.sh fast # Fast scenario tests
281
+ ```
282
+
283
+ ### Project structure
284
+
285
+ ```
286
+ src/
287
+ ├── main.ts # Entry point: bootstrap + I/O wiring
288
+ ├── app.ts # Core state machine + event dispatch
289
+ ├── config.ts # Unified config (CLI + ENV + defaults)
290
+ ├── recorder.ts # PTY stream → context entries
291
+ ├── agent.ts # pi RPC process management
292
+ ├── hooks.ts # bash/zsh rcfile generation
293
+ ├── render.ts # Agent UI → stderr (Markdown, spinner, status)
294
+ ├── osc.ts # OSC 9154 signal parser
295
+ ├── session.ts # pi session file discovery
296
+ ├── theme.ts # ANSI colors + Markdown theme
297
+ ├── vterm.ts # xterm headless prompt replay
298
+ ├── strip.ts # ANSI stripping + truncation
299
+ └── log.ts # JSON event logging
300
+ ```
301
+
302
+ Before submitting a PR, please:
303
+ 1. Run `npm run lint` to ensure code style
304
+ 2. Run `bash test/run_tests.sh fast` to verify nothing is broken
305
+ 3. Update documentation if behavior changes
306
+
307
+ ## 📋 Known Limitations
308
+
309
+ - **Bash keywords** — `do something` or `if something` triggers a bash syntax error instead of the AI agent. Rephrase as `please do something`.
125
310
  - **CNF returns 0** — `$?` after an agent run is always 0, not 127.
311
+ - **Reverse context** — When switching to pi TUI, shell context history is not transferred (only the agent session carries over).
312
+ - **bash 4.4+ required** — macOS ships bash 3.2; install a newer version via `brew install bash`.
126
313
 
127
- ## License
314
+ ## 📄 License
128
315
 
129
316
  [MIT](LICENSE) © [dacapoday](https://github.com/dacapoday)
317
+
318
+ ---
319
+
320
+ <div align="center">
321
+
322
+ **[⬆ Back to top](#pish)**
323
+
324
+ </div>
package/dist/app.js CHANGED
@@ -228,7 +228,12 @@ export class App {
228
228
  const entries = this.recorder.drain();
229
229
  log('agent', { cmd, context_count: entries.length });
230
230
  const renderer = new StreamRenderer(this.cfg.toolResultLines, this.cfg.spinnerInterval);
231
- this.agentSession = { cmd, startTime: Date.now(), stdinBuffer: [], renderer };
231
+ this.agentSession = {
232
+ cmd,
233
+ startTime: Date.now(),
234
+ stdinBuffer: [],
235
+ renderer,
236
+ };
232
237
  const crashInfo = this.agent.consumeCrashInfo();
233
238
  if (crashInfo) {
234
239
  printNotice(crashInfo);
package/dist/main.js CHANGED
@@ -63,7 +63,7 @@ ptyProcess.onData((data) => app.onPtyData(data));
63
63
  ptyProcess.onExit(({ exitCode }) => app.onPtyExit(exitCode ?? 0));
64
64
  process.stdin.setRawMode?.(true);
65
65
  process.stdin.resume();
66
- process.stdin.on('data', (data) => app.onStdin(data));
66
+ process.stdin.on('data', (data) => app.onStdin(Buffer.from(data)));
67
67
  process.stdout.on('resize', () => {
68
68
  app.onResize(process.stdout.columns || cfg.defaultCols, process.stdout.rows || cfg.defaultRows);
69
69
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerode/pish",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "A shell-first pi coding agent",
5
5
  "license": "MIT",
6
6
  "author": "dacapoday",
@@ -45,13 +45,14 @@
45
45
  "postinstall.sh"
46
46
  ],
47
47
  "dependencies": {
48
- "@mariozechner/pi-tui": "^0.64.0",
48
+ "@mariozechner/pi-tui": "^0.65.0",
49
49
  "@xterm/headless": "^6.0.0",
50
50
  "node-pty": "^1.0.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@biomejs/biome": "^2.4.10",
54
- "@types/node": "^22.0.0",
55
- "typescript": "^5.0.0"
54
+ "@types/node": "^25.5.2",
55
+ "tsx": "^4.21.0",
56
+ "typescript": "^6.0.2"
56
57
  }
57
58
  }