@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 +238 -43
- package/dist/app.js +6 -1
- package/dist/main.js +1 -1
- package/package.json +5 -4
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
|
|
7
|
+
[](https://github.com/dacapoday/pish/actions/workflows/ci.yml)
|
|
8
|
+
[](https://www.npmjs.com/package/@aerode/pish)
|
|
9
|
+
[](https://nodejs.org/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
<br/>
|
|
6
13
|
|
|
7
|
-
<p
|
|
8
|
-
<
|
|
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
|
-
|
|
23
|
+
<br/>
|
|
12
24
|
|
|
13
|
-
pish
|
|
25
|
+
<img src="pish-example.gif" alt="pish demo" width="640">
|
|
14
26
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
+
</td>
|
|
67
|
+
</tr>
|
|
68
|
+
</table>
|
|
26
69
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
|
91
|
-
|
|
|
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
|
-
|
|
149
|
+
Configuration priority: **CLI args > Environment variables > Defaults**
|
|
94
150
|
|
|
95
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
##
|
|
234
|
+
## 🧪 Testing
|
|
123
235
|
|
|
124
|
-
|
|
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 = {
|
|
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.
|
|
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.
|
|
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": "^
|
|
55
|
-
"
|
|
54
|
+
"@types/node": "^25.5.2",
|
|
55
|
+
"tsx": "^4.21.0",
|
|
56
|
+
"typescript": "^6.0.2"
|
|
56
57
|
}
|
|
57
58
|
}
|