agent-sh 0.1.0
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 +659 -0
- package/dist/acp-client.d.ts +76 -0
- package/dist/acp-client.js +507 -0
- package/dist/context-manager.d.ts +45 -0
- package/dist/context-manager.js +405 -0
- package/dist/core.d.ts +41 -0
- package/dist/core.js +76 -0
- package/dist/event-bus.d.ts +140 -0
- package/dist/event-bus.js +79 -0
- package/dist/executor.d.ts +31 -0
- package/dist/executor.js +116 -0
- package/dist/extension-loader.d.ts +16 -0
- package/dist/extension-loader.js +164 -0
- package/dist/extensions/file-autocomplete.d.ts +2 -0
- package/dist/extensions/file-autocomplete.js +63 -0
- package/dist/extensions/shell-recall.d.ts +9 -0
- package/dist/extensions/shell-recall.js +8 -0
- package/dist/extensions/slash-commands.d.ts +2 -0
- package/dist/extensions/slash-commands.js +105 -0
- package/dist/extensions/tui-renderer.d.ts +2 -0
- package/dist/extensions/tui-renderer.js +354 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +159 -0
- package/dist/input-handler.d.ts +48 -0
- package/dist/input-handler.js +302 -0
- package/dist/output-parser.d.ts +55 -0
- package/dist/output-parser.js +166 -0
- package/dist/shell.d.ts +54 -0
- package/dist/shell.js +219 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.js +1 -0
- package/dist/utils/ansi.d.ts +12 -0
- package/dist/utils/ansi.js +23 -0
- package/dist/utils/box-frame.d.ts +21 -0
- package/dist/utils/box-frame.js +60 -0
- package/dist/utils/diff-renderer.d.ts +20 -0
- package/dist/utils/diff-renderer.js +506 -0
- package/dist/utils/diff.d.ts +24 -0
- package/dist/utils/diff.js +122 -0
- package/dist/utils/file-watcher.d.ts +31 -0
- package/dist/utils/file-watcher.js +101 -0
- package/dist/utils/markdown.d.ts +39 -0
- package/dist/utils/markdown.js +248 -0
- package/dist/utils/palette.d.ts +32 -0
- package/dist/utils/palette.js +36 -0
- package/dist/utils/tool-display.d.ts +33 -0
- package/dist/utils/tool-display.js +141 -0
- package/examples/extensions/interactive-prompts.ts +161 -0
- package/examples/extensions/solarized-theme.ts +27 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
# agent-sh
|
|
2
|
+
|
|
3
|
+
Not a shell that lives in an agent — an agent that lives in a shell.
|
|
4
|
+
|
|
5
|
+
agent-sh is a real terminal first. Every keystroke goes to a real PTY. `cd`, pipes, vim, job control — they all just work. But type `>` at the start of a line, and you're talking to an AI agent that has full context of what you've been doing: your working directory, recent commands, their output.
|
|
6
|
+
|
|
7
|
+
The agent connects via the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/), so you can plug in **any** ACP-compatible agent: [pi](https://github.com/svkozak/pi-acp), claude-code, codex, gemini-cli, goose, etc.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
⚡ src $ ls -la # real shell command
|
|
11
|
+
⚡ src $ cd ../tests && npm test # real cd, env, aliases — all just work
|
|
12
|
+
⚡ src $ vim file.ts # opens vim in the same PTY
|
|
13
|
+
⚡ src $ > refactor the auth middleware # → sent to agent via ACP
|
|
14
|
+
⚡ src $ > explain the last error # agent sees your recent commands + output
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Why shell-first?
|
|
18
|
+
|
|
19
|
+
Most AI coding tools are agent-first: the LLM drives the experience and the shell is bolted on. That means no real PTY, no job control, no interactive commands, and fragile `cd` tracking that reimplements what bash gives you for free.
|
|
20
|
+
|
|
21
|
+
agent-sh starts from the opposite end. The shell is the primary interface — it's your terminal, not the agent's. The agent is a tool you reach for when you need it, not the other way around.
|
|
22
|
+
|
|
23
|
+
### Why ACP?
|
|
24
|
+
|
|
25
|
+
The [Agent Client Protocol](https://agentclientprotocol.com/) decouples the shell from any specific agent:
|
|
26
|
+
|
|
27
|
+
- **Pluggable agents** — swap between pi-acp, claude-code, codex with a CLI flag
|
|
28
|
+
- **Standard protocol** — JSON-RPC 2.0 over stdio, well-specified capability negotiation
|
|
29
|
+
- **Agent handles LLM details** — no API keys, tool definitions, or context windows to manage
|
|
30
|
+
- **Terminal delegation** — ACP defines `terminal/create`, `terminal/output`, `terminal/wait_for_exit` — exactly what an agent needs to run commands in your shell
|
|
31
|
+
|
|
32
|
+
## Key Features
|
|
33
|
+
|
|
34
|
+
- **🚀 Instant Start** — Shell starts immediately, no waiting for agent connection
|
|
35
|
+
- **🔄 Smart Connection** — Agent connects asynchronously in the background
|
|
36
|
+
- **⏳ Auto-Wait** — Queries automatically wait for agent to finish connecting
|
|
37
|
+
- **📊 Real-time Streaming** — Agent responses stream live with syntax highlighting
|
|
38
|
+
- **⚡ Zero Latency** — Direct PTY access, full terminal compatibility
|
|
39
|
+
- **🧠 Context Aware** — Agent sees your cwd, recent commands, and their output
|
|
40
|
+
- **🎯 Multiple Agents** — Easy switching between pi-acp, claude, and other ACP agents
|
|
41
|
+
- **🏷️ Agent Info Display** — Shows current agent and model next to the prompt (e.g., `pi (gpt-4o) ●`)
|
|
42
|
+
- **📝 Inline Diff Preview** — File writes show syntax-highlighted diffs inline (Ctrl+O to expand)
|
|
43
|
+
- **💭 Thinking Display** — Toggle agent thinking/reasoning text with Ctrl+T
|
|
44
|
+
- **🎨 Themeable** — Semantic color palette, swappable via extensions
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/guanyilun/agent-sh.git
|
|
50
|
+
cd agent-sh
|
|
51
|
+
npm install
|
|
52
|
+
npm run build
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Requires Node.js 18+ and an ACP-compatible agent installed on your system.
|
|
56
|
+
|
|
57
|
+
## Running agent-sh
|
|
58
|
+
|
|
59
|
+
After building, you can run agent-sh in several ways:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Start with the default agent (pi-acp) - RECOMMENDED
|
|
63
|
+
npm start
|
|
64
|
+
|
|
65
|
+
# Quick shortcuts
|
|
66
|
+
npm run pi # Start with pi-acp
|
|
67
|
+
npm run claude # Start with claude-agent-acp (Anthropic's official Claude agent)
|
|
68
|
+
|
|
69
|
+
# Using the built binary directly
|
|
70
|
+
node dist/index.js --agent <agent-name>
|
|
71
|
+
|
|
72
|
+
# Using npm script with custom agent
|
|
73
|
+
npm start -- --agent <agent-name>
|
|
74
|
+
|
|
75
|
+
# Using npx (if published to npm)
|
|
76
|
+
npx agent-sh --agent <agent-name>
|
|
77
|
+
|
|
78
|
+
# Make the built file executable and run directly
|
|
79
|
+
chmod +x dist/index.js
|
|
80
|
+
./dist/index.js --agent <agent-name>
|
|
81
|
+
|
|
82
|
+
# Using environment variable to set default agent
|
|
83
|
+
AGENT_SH_AGENT=claude-agent-acp npm start
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Install ACP-compatible agents
|
|
87
|
+
|
|
88
|
+
agent-sh requires an ACP-compatible agent. Here are some popular options:
|
|
89
|
+
|
|
90
|
+
| Agent | Install Command | Notes |
|
|
91
|
+
|-------|----------------|-------|
|
|
92
|
+
| **pi-acp** | `npm install -g pi-acp` | **Recommended default** - ACP adapter for pi coding agent |
|
|
93
|
+
| **claude-agent-acp** | `npm install -g @agentclientprotocol/claude-agent-acp` | Anthropic's official ACP Claude agent |
|
|
94
|
+
|
|
95
|
+
**⚠️ Important**: The `claude` CLI tool (Claude Code) does **not** support the ACP protocol. You must use `claude-agent-acp` or `pi-acp` with Anthropic models.
|
|
96
|
+
|
|
97
|
+
**Example: Installing pi-acp**
|
|
98
|
+
```bash
|
|
99
|
+
npm install -g pi-acp
|
|
100
|
+
pi-acp --help # Verify installation
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Usage
|
|
104
|
+
|
|
105
|
+
### Quick Start
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# 1. Install required agents (if not already installed)
|
|
109
|
+
npm install -g pi-acp
|
|
110
|
+
npm install -g @agentclientprotocol/claude-agent-acp
|
|
111
|
+
|
|
112
|
+
# 2. Set required API keys
|
|
113
|
+
export ANTHROPIC_API_KEY="your-anthropic-api-key"
|
|
114
|
+
# Or for OpenAI models with pi-acp:
|
|
115
|
+
# export OPENAI_API_KEY="your-openai-api-key"
|
|
116
|
+
|
|
117
|
+
# 3. Start agent-sh
|
|
118
|
+
npm start
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Common Usage Patterns
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Start with the default agent (pi-acp)
|
|
125
|
+
npm start
|
|
126
|
+
# Shows: pi ● ❯ when entering agent mode
|
|
127
|
+
|
|
128
|
+
# Quick shortcuts
|
|
129
|
+
npm run pi # pi-acp
|
|
130
|
+
npm run claude # claude-agent-acp (Anthropic's official Claude agent)
|
|
131
|
+
|
|
132
|
+
# Start with a specific agent
|
|
133
|
+
npm start -- --agent pi-acp
|
|
134
|
+
|
|
135
|
+
# Pass arguments to the agent (including model)
|
|
136
|
+
npm start -- --agent claude-agent-acp --agent-args "--model claude-3-5-sonnet-20241022"
|
|
137
|
+
# Shows: claude-agent-acp (claude-3-5-sonnet-20241022) ● ❯ when entering agent mode
|
|
138
|
+
|
|
139
|
+
# Use pi-acp with Claude
|
|
140
|
+
npm start -- --agent pi-acp --agent-args "--provider anthropic --model claude-3-5-sonnet-20241022"
|
|
141
|
+
# Shows: pi (claude-3-5-sonnet-20241022) ● ❯
|
|
142
|
+
|
|
143
|
+
# Use pi-acp with OpenAI GPT-4
|
|
144
|
+
export OPENAI_API_KEY="your-openai-key"
|
|
145
|
+
npm start -- --agent pi-acp --agent-args "--provider openai --model gpt-4o"
|
|
146
|
+
# Shows: pi (gpt-4o) ● ❯
|
|
147
|
+
|
|
148
|
+
# Use a different shell
|
|
149
|
+
npm start -- --shell /bin/zsh
|
|
150
|
+
|
|
151
|
+
# Set default agent via environment variable
|
|
152
|
+
AGENT_SH_AGENT=claude-agent-acp npm start
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Common Claude Models
|
|
156
|
+
|
|
157
|
+
**Valid Claude model names** (for use with `--model` parameter):
|
|
158
|
+
- `claude-3-5-sonnet-20241022` (latest Sonnet)
|
|
159
|
+
- `claude-3-5-haiku-20241022` (latest Haiku)
|
|
160
|
+
- `claude-3-opus-20240229` (older Opus)
|
|
161
|
+
- `claude-3-sonnet-20240229` (older Sonnet)
|
|
162
|
+
|
|
163
|
+
**Example with claude-agent-acp**:
|
|
164
|
+
```bash
|
|
165
|
+
export ANTHROPIC_API_KEY="your-key"
|
|
166
|
+
npm start -- --agent claude-agent-acp --agent-args "--model claude-3-5-sonnet-20241022"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Example with pi-acp**:
|
|
170
|
+
```bash
|
|
171
|
+
export ANTHROPIC_API_KEY="your-key"
|
|
172
|
+
npm start -- --agent pi-acp --agent-args "--provider anthropic --model claude-3-5-sonnet-20241022"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Agent environment configuration
|
|
176
|
+
|
|
177
|
+
agent-sh can be configured via environment variables:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Set the default agent to use
|
|
181
|
+
export AGENT_SH_AGENT=pi-acp # Default is pi-acp
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Smart Connection**: agent-sh uses an intelligent connection system where the shell starts immediately and the agent connects in the background. If you send a query before the agent is fully connected, the system automatically waits for connection completion. This provides instant access to the shell while ensuring reliable agent communication.
|
|
185
|
+
|
|
186
|
+
Many ACP agents also require API keys. Set these before starting agent-sh:
|
|
187
|
+
|
|
188
|
+
#### pi-acp configuration
|
|
189
|
+
|
|
190
|
+
pi-acp uses the same environment variables as the [pi](https://github.com/mariozechner/pi-coding-agent) agent:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Anthropic Claude
|
|
194
|
+
export ANTHROPIC_API_KEY="your-anthropic-key"
|
|
195
|
+
|
|
196
|
+
# OpenAI
|
|
197
|
+
export OPENAI_API_KEY="your-openai-key"
|
|
198
|
+
|
|
199
|
+
# Google Gemini
|
|
200
|
+
export GEMINI_API_KEY="your-gemini-key"
|
|
201
|
+
|
|
202
|
+
# Groq
|
|
203
|
+
export GROQ_API_KEY="your-groq-key"
|
|
204
|
+
|
|
205
|
+
# xAI (Grok)
|
|
206
|
+
export XAI_API_KEY="your-xai-key"
|
|
207
|
+
|
|
208
|
+
# OpenRouter
|
|
209
|
+
export OPENROUTER_API_KEY="your-openrouter-key"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
You can also configure pi-acp by passing arguments:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Use Claude 3.5 Sonnet with pi-acp
|
|
216
|
+
npm start -- --agent pi-acp --agent-args "--provider anthropic --model claude-3-5-sonnet-20241022"
|
|
217
|
+
# Shows: pi (claude-3-5-sonnet-20241022) ● ❯
|
|
218
|
+
|
|
219
|
+
# Use GPT-4o with pi-acp
|
|
220
|
+
export OPENAI_API_KEY="your-openai-key"
|
|
221
|
+
npm start -- --agent pi-acp --agent-args "--provider openai --model gpt-4o"
|
|
222
|
+
# Shows: pi (gpt-4o) ● ❯
|
|
223
|
+
|
|
224
|
+
# Enable thinking mode
|
|
225
|
+
npm start -- --agent pi-acp --agent-args "--thinking high"
|
|
226
|
+
|
|
227
|
+
# Limit to read-only tools
|
|
228
|
+
npm start -- --agent pi-acp --agent-args "--tools read,grep,find,ls"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Model Display**: When you specify a model using `--model`, it will be displayed in parentheses next to the agent name when you enter agent mode. This helps you quickly identify which model you're using.
|
|
232
|
+
|
|
233
|
+
For more pi-acp options, run `pi --help` (pi-acp accepts the same arguments).
|
|
234
|
+
|
|
235
|
+
#### Other agent configurations
|
|
236
|
+
|
|
237
|
+
Refer to each agent's documentation for their specific environment variable requirements. Common patterns:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# claude-agent-acp (Anthropic's official Claude agent)
|
|
241
|
+
export ANTHROPIC_API_KEY="your-key"
|
|
242
|
+
|
|
243
|
+
# gemini-cli
|
|
244
|
+
export GOOGLE_API_KEY="your-key"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Tip:** Add these to your `~/.zshrc` or `~/.bashrc` for persistent configuration.
|
|
248
|
+
|
|
249
|
+
### Input modes
|
|
250
|
+
|
|
251
|
+
| Input | Behavior |
|
|
252
|
+
|---|---|
|
|
253
|
+
| `ls -la` | Runs in real shell (PTY), output displayed normally |
|
|
254
|
+
| `cd src && make` | Real shell — cd, env, aliases all just work |
|
|
255
|
+
| `vim file.ts` | Opens vim in the same PTY, no hacks needed |
|
|
256
|
+
| `> refactor this fn` | Sends to agent via ACP, streams response inline |
|
|
257
|
+
| `> /help` | Shows available slash commands |
|
|
258
|
+
| `Ctrl-C` | Standard signal to shell, or cancels active agent response |
|
|
259
|
+
| `Ctrl-O` | Expand/collapse truncated diff preview |
|
|
260
|
+
| `Ctrl-T` | Toggle thinking/reasoning text display |
|
|
261
|
+
| `Escape` | Exit agent input mode (when typing after `>`) |
|
|
262
|
+
|
|
263
|
+
When you type `>` at the start of a line, agent-sh enters **agent input mode** — the prompt changes to show the agent and model information (e.g., `pi (gpt-4o) ● ❯`) and your text is sent to the agent on Enter. The agent's response streams inline in real-time in a bordered box with markdown rendering and syntax highlighting.
|
|
264
|
+
|
|
265
|
+
**Agent Info Display**: When entering agent mode, you'll see the current agent name and model (if specified) next to the prompt, followed by a green dot (●) indicating the connection status. For example:
|
|
266
|
+
- `pi ● ❯` — pi agent without model specified
|
|
267
|
+
- `pi (gpt-4o) ● ❯` — pi agent with gpt-4o model
|
|
268
|
+
- `pi (claude-3-5-sonnet-20241022) ● ❯` — pi agent with Claude Sonnet model
|
|
269
|
+
- `claude-agent-acp (claude-3-5-sonnet-20241022) ● ❯` — Claude agent with Sonnet model
|
|
270
|
+
|
|
271
|
+
### Slash commands
|
|
272
|
+
|
|
273
|
+
| Command | Description |
|
|
274
|
+
|---|---|
|
|
275
|
+
| `/help` | Show available commands |
|
|
276
|
+
| `/clear` | Start a new agent session |
|
|
277
|
+
| `/copy` | Copy last agent response to clipboard |
|
|
278
|
+
| `/compact` | Ask agent to summarize the conversation |
|
|
279
|
+
| `/quit` | Exit agent-sh |
|
|
280
|
+
|
|
281
|
+
Slash commands have tab-completion and arrow-key navigation in agent input mode.
|
|
282
|
+
|
|
283
|
+
### Shell context
|
|
284
|
+
|
|
285
|
+
The agent automatically receives structured context about your shell session with each query, managed by the ContextManager:
|
|
286
|
+
|
|
287
|
+
- **Current working directory** — tracked via OSC 7 escape sequences
|
|
288
|
+
- **Recent commands and output** — truncated summaries of recent shell commands, agent queries, and tool executions
|
|
289
|
+
- **Recall tool** — the agent can run `__shell_recall --search "query"` or `__shell_recall --expand 42` to retrieve full output of any past exchange
|
|
290
|
+
|
|
291
|
+
This means you can run a failing command, then type `> fix this` and the agent knows exactly what happened. For long outputs, the agent sees a truncated summary and can recall the full content on demand.
|
|
292
|
+
|
|
293
|
+
## Architecture
|
|
294
|
+
|
|
295
|
+
agent-sh is an ACP **client**. The agent is a subprocess launched with stdio transport.
|
|
296
|
+
|
|
297
|
+
### Design philosophy: headless core + pluggable frontends
|
|
298
|
+
|
|
299
|
+
The core (`createCore()`) is a frontend-agnostic kernel — it wires up the EventBus, ContextManager, and AcpClient with zero knowledge of terminals, PTYs, or rendering. The interactive terminal (Shell + TUI + extensions) is one frontend built on top.
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
createCore() — frontend-agnostic kernel:
|
|
303
|
+
│ EventBus — typed pub/sub + transform pipelines
|
|
304
|
+
│ ContextManager — exchange recording, context assembly
|
|
305
|
+
│ AcpClient — ACP protocol, terminal execution (yolo by default)
|
|
306
|
+
│
|
|
307
|
+
index.ts — interactive terminal frontend:
|
|
308
|
+
│ Shell — PTY lifecycle (delegates to InputHandler + OutputParser)
|
|
309
|
+
│
|
|
310
|
+
├── Built-in extensions:
|
|
311
|
+
│ tuiRenderer — markdown rendering, inline diffs, thinking display, spinner
|
|
312
|
+
│ slashCommands — /help, /clear, /copy, /compact, /quit
|
|
313
|
+
│ fileAutocomplete — @ file path completion
|
|
314
|
+
│ shellRecall — __shell_recall terminal interception
|
|
315
|
+
│
|
|
316
|
+
├── Shared utilities:
|
|
317
|
+
│ palette — semantic color system (accent, success, warning, error, muted)
|
|
318
|
+
│ diff-renderer — syntax-highlighted diffs (split/unified/summary)
|
|
319
|
+
│ box-frame — bordered TUI panels
|
|
320
|
+
│ tool-display — width-adaptive tool call rendering
|
|
321
|
+
│
|
|
322
|
+
└── User extensions (opt-in, loaded from -e flag / settings.json / extensions dir):
|
|
323
|
+
e.g. interactive-prompts, solarized-theme
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
All components communicate exclusively through typed bus events. AcpClient has no reference to Shell — it emits lifecycle events (`agent:processing-start`, `agent:processing-done`) and Shell subscribes to manage its own state. Input flows the same way: any frontend emits `agent:submit` and the core routes it to the agent.
|
|
327
|
+
|
|
328
|
+
**The core works without any frontend.** This enables:
|
|
329
|
+
|
|
330
|
+
- **Library usage** — `import { createCore } from "agent-sh"` to build WebSocket servers, REST APIs, Electron apps, or test harnesses
|
|
331
|
+
- **Headless mode** — CI, scripting, embedding — no terminal needed
|
|
332
|
+
- **Alternative renderers** — web UI, logging backend, minimal TUI
|
|
333
|
+
- **Custom features** — add commands, autocomplete providers, tool interceptors by writing an extension
|
|
334
|
+
|
|
335
|
+
### We send to the agent
|
|
336
|
+
|
|
337
|
+
| Method | When |
|
|
338
|
+
|---|---|
|
|
339
|
+
| `initialize` | Startup: negotiate capabilities |
|
|
340
|
+
| `session/new` | Create a conversation session |
|
|
341
|
+
| `session/prompt` | User types `> query` — sent with shell context |
|
|
342
|
+
| `session/cancel` | User hits Ctrl-C during agent response |
|
|
343
|
+
|
|
344
|
+
### We handle from the agent
|
|
345
|
+
|
|
346
|
+
| Method | What we do |
|
|
347
|
+
|---|---|
|
|
348
|
+
| `terminal/create` | Execute command in an isolated child process |
|
|
349
|
+
| `terminal/output` | Return captured output for a terminal ID |
|
|
350
|
+
| `terminal/wait_for_exit` | Await command completion, return exit code |
|
|
351
|
+
| `terminal/kill` | Send signal to running command |
|
|
352
|
+
| `terminal/release` | Cleanup terminal session |
|
|
353
|
+
| `fs/read_text_file` | Read file from disk, return content |
|
|
354
|
+
| `fs/write_text_file` | Write file to disk |
|
|
355
|
+
| `session/request_permission` | Prompt user for y/n/allow-all confirmation |
|
|
356
|
+
|
|
357
|
+
### We render from the agent
|
|
358
|
+
|
|
359
|
+
| Update type | What we render |
|
|
360
|
+
|---|---|
|
|
361
|
+
| `agent_message_chunk` | Real-time streaming markdown with syntax highlighting in a bordered box |
|
|
362
|
+
| `agent_thought_chunk` | Thinking spinner (default), or streaming text when toggled on with Ctrl+T |
|
|
363
|
+
| `tool_call` | Yellow header showing what the agent is invoking |
|
|
364
|
+
| `tool_call_update` | Status indicator (✓ or ✗ with exit code) |
|
|
365
|
+
| `file_write` | Inline diff preview in bordered box (Ctrl+O to expand/collapse) |
|
|
366
|
+
|
|
367
|
+
## Project structure
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
agent-sh/
|
|
371
|
+
├── src/
|
|
372
|
+
│ ├── index.ts # Interactive terminal entry point (CLI args, Shell, extensions)
|
|
373
|
+
│ ├── core.ts # createCore() — frontend-agnostic kernel, library entry point
|
|
374
|
+
│ ├── event-bus.ts # Typed EventBus: emit/on, emitPipe, emitPipeAsync
|
|
375
|
+
│ ├── shell.ts # PTY lifecycle + wiring (InputHandler + OutputParser)
|
|
376
|
+
│ ├── input-handler.ts # Keyboard input, agent mode, bus-driven autocomplete
|
|
377
|
+
│ ├── output-parser.ts # OSC parsing, command boundary detection
|
|
378
|
+
│ ├── acp-client.ts # ACP protocol, terminal execution, session management
|
|
379
|
+
│ ├── context-manager.ts # Exchange log, context assembly, recall API
|
|
380
|
+
│ ├── extension-loader.ts # Extension loading (-e, settings.json, extensions dir)
|
|
381
|
+
│ ├── executor.ts # Isolated child process execution
|
|
382
|
+
│ ├── types.ts # Shared type definitions
|
|
383
|
+
│ ├── utils/
|
|
384
|
+
│ │ ├── palette.ts # Semantic color palette (accent/success/warning/error/muted)
|
|
385
|
+
│ │ ├── ansi.ts # ANSI utility functions (visibleLen, stripAnsi)
|
|
386
|
+
│ │ ├── diff.ts # Line-level LCS diff for file change previews
|
|
387
|
+
│ │ ├── diff-renderer.ts# Syntax-highlighted diff display (split/unified/summary)
|
|
388
|
+
│ │ ├── box-frame.ts # Bordered TUI panels (rounded/square/double/heavy)
|
|
389
|
+
│ │ ├── tool-display.ts # Width-adaptive tool call/result rendering
|
|
390
|
+
│ │ ├── file-watcher.ts # File change detection for agent tool writes
|
|
391
|
+
│ │ └── markdown.ts # Streaming markdown → ANSI renderer
|
|
392
|
+
│ └── extensions/
|
|
393
|
+
│ ├── tui-renderer.ts # Terminal rendering (markdown, spinner, tools)
|
|
394
|
+
│ ├── slash-commands.ts # /help, /clear, /copy, /compact, /quit
|
|
395
|
+
│ ├── file-autocomplete.ts # @ file path completion
|
|
396
|
+
│ └── shell-recall.ts # __shell_recall terminal interception
|
|
397
|
+
├── examples/
|
|
398
|
+
│ └── extensions/
|
|
399
|
+
│ ├── interactive-prompts.ts # Example: permission gates (opt-in)
|
|
400
|
+
│ └── solarized-theme.ts # Example: color theme via setPalette()
|
|
401
|
+
├── package.json
|
|
402
|
+
└── tsconfig.json
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Development
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
# Run in development mode (no build step)
|
|
409
|
+
npm run dev
|
|
410
|
+
|
|
411
|
+
# Build
|
|
412
|
+
npm run build
|
|
413
|
+
|
|
414
|
+
# Run the built version (uses default agent pi-acp)
|
|
415
|
+
npm start
|
|
416
|
+
|
|
417
|
+
# Quick shortcuts for different agents
|
|
418
|
+
npm run pi # Start with pi-acp
|
|
419
|
+
npm run claude # Start with claude-agent-acp (Anthropic's official Claude agent)
|
|
420
|
+
|
|
421
|
+
# Debug mode — logs ACP protocol details to stderr
|
|
422
|
+
DEBUG=1 npm start
|
|
423
|
+
|
|
424
|
+
# Test with specific agent
|
|
425
|
+
npm run dev -- --agent pi-acp
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## How it works
|
|
429
|
+
|
|
430
|
+
1. agent-sh spawns a real PTY running your shell (zsh or bash, with your full rc config — oh-my-zsh, p10k, aliases, plugins, PATH) and sets up raw stdin passthrough
|
|
431
|
+
2. It launches the specified ACP agent as a subprocess with stdio transport
|
|
432
|
+
3. All keyboard input goes directly to the PTY — zero latency, full terminal compatibility
|
|
433
|
+
4. **Smart connection**: The agent connects asynchronously in the background while the shell starts immediately
|
|
434
|
+
5. **Auto-wait**: If you send a query before the agent is fully connected, the system automatically waits for connection completion
|
|
435
|
+
6. When you type `>` at the start of a line, agent-sh intercepts and enters agent input mode
|
|
436
|
+
7. On Enter, the query (plus shell context) is sent to the agent via `session/prompt`
|
|
437
|
+
8. The agent's streaming response renders inline in a bordered markdown box with real-time output
|
|
438
|
+
9. If the agent needs to run commands, it calls `terminal/create` and agent-sh executes them in isolated child processes, streaming output back
|
|
439
|
+
10. When the agent finishes, normal shell operation resumes
|
|
440
|
+
|
|
441
|
+
### EventBus
|
|
442
|
+
|
|
443
|
+
All communication between components flows through a typed EventBus. Components emit events (shell commands, agent responses, tool calls) and extensions subscribe to events they care about. The bus supports three modes:
|
|
444
|
+
|
|
445
|
+
- **emit/on** — fire-and-forget notifications (e.g., `agent:response-chunk`)
|
|
446
|
+
- **emitPipe/onPipe** — synchronous transform chains (e.g., `autocomplete:request` where extensions append completion items)
|
|
447
|
+
- **emitPipeAsync/onPipeAsync** — async transform chains (e.g., `permission:request` where extensions prompt the user and return a decision)
|
|
448
|
+
|
|
449
|
+
### Writing extensions
|
|
450
|
+
|
|
451
|
+
An extension is a module that exports a default (or named `activate`) function. It receives an `ExtensionContext` with access to all core services:
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
// my-extension.js
|
|
455
|
+
export default function activate(ctx) {
|
|
456
|
+
// Listen to agent events
|
|
457
|
+
ctx.bus.on("agent:response-done", (e) => {
|
|
458
|
+
console.log(`Agent responded with ${e.response.length} chars`);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// Add a slash command
|
|
462
|
+
ctx.bus.on("command:execute", (e) => {
|
|
463
|
+
if (e.name === "/greet") {
|
|
464
|
+
ctx.bus.emit("ui:info", { message: "Hello from my extension!" });
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
ctx.bus.onPipe("autocomplete:request", (payload) => {
|
|
468
|
+
if (!payload.buffer.startsWith("/g")) return payload;
|
|
469
|
+
return { ...payload, items: [...payload.items, { name: "/greet", description: "Say hello" }] };
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
// Intercept terminal commands
|
|
473
|
+
ctx.bus.onPipe("agent:terminal-intercept", (payload) => {
|
|
474
|
+
if (payload.command !== "my-tool") return payload;
|
|
475
|
+
return { ...payload, intercepted: true, output: "custom output" };
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
The `ExtensionContext` provides:
|
|
481
|
+
|
|
482
|
+
| Property | Type | Description |
|
|
483
|
+
|---|---|---|
|
|
484
|
+
| `bus` | `EventBus` | Subscribe to events, emit events, register pipe handlers |
|
|
485
|
+
| `contextManager` | `ContextManager` | Access exchange history, cwd, search, expand |
|
|
486
|
+
| `getAcpClient` | `() => AcpClient` | Lazy getter for the agent client |
|
|
487
|
+
| `quit` | `() => void` | Exit agent-sh |
|
|
488
|
+
| `setPalette` | `(overrides: Partial<ColorPalette>) => void` | Override color palette slots for theming |
|
|
489
|
+
|
|
490
|
+
### Yolo mode
|
|
491
|
+
|
|
492
|
+
By default, agent-sh runs in **yolo mode** — all tool calls and file writes are auto-approved. This matches pi's design philosophy where the agent operates freely unless you explicitly add permission gates.
|
|
493
|
+
|
|
494
|
+
To add permission prompts, load the example extension:
|
|
495
|
+
```bash
|
|
496
|
+
# One-off
|
|
497
|
+
npm start -- -e ./examples/extensions/interactive-prompts.ts
|
|
498
|
+
|
|
499
|
+
# Permanent: copy to your extensions dir
|
|
500
|
+
cp examples/extensions/interactive-prompts.ts ~/.agent-sh/extensions/
|
|
501
|
+
|
|
502
|
+
# Or add to settings.json
|
|
503
|
+
echo '{ "extensions": ["./examples/extensions/interactive-prompts.ts"] }' > ~/.agent-sh/settings.json
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Theming
|
|
507
|
+
|
|
508
|
+
agent-sh uses a semantic color palette with ~10 base roles (`accent`, `success`, `warning`, `error`, `muted`, plus background variants and style modifiers). Extensions can override any slot via `setPalette()`:
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
// solarized-theme.ts
|
|
512
|
+
export default function activate({ setPalette }) {
|
|
513
|
+
setPalette({
|
|
514
|
+
accent: "\x1b[38;2;38;139;210m", // solarized blue
|
|
515
|
+
success: "\x1b[38;2;133;153;0m", // solarized green
|
|
516
|
+
warning: "\x1b[38;2;181;137;0m", // solarized yellow
|
|
517
|
+
error: "\x1b[38;2;220;50;47m", // solarized red
|
|
518
|
+
muted: "\x1b[38;2;88;110;117m", // solarized base01
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
Load a theme like any other extension:
|
|
524
|
+
```bash
|
|
525
|
+
npm start -- -e ./examples/extensions/solarized-theme.ts
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
A complete example is included at `examples/extensions/solarized-theme.ts`.
|
|
529
|
+
|
|
530
|
+
### Loading extensions
|
|
531
|
+
|
|
532
|
+
Extensions are loaded from three sources (in order, deduplicated):
|
|
533
|
+
|
|
534
|
+
**1. CLI flag (`-e` / `--extensions`)** — npm packages or file paths, repeatable:
|
|
535
|
+
```bash
|
|
536
|
+
npm start -- -e my-ext-package -e ./local-ext.ts
|
|
537
|
+
npm start -- -e my-ext-package,another-package # comma-separated also works
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**2. Settings file** — `~/.agent-sh/settings.json`:
|
|
541
|
+
```json
|
|
542
|
+
{
|
|
543
|
+
"extensions": [
|
|
544
|
+
"my-published-extension",
|
|
545
|
+
"/absolute/path/to/ext.ts",
|
|
546
|
+
"./relative/path/to/ext.js"
|
|
547
|
+
]
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**3. Extensions directory** — files and directories in `~/.agent-sh/extensions/`:
|
|
552
|
+
```bash
|
|
553
|
+
~/.agent-sh/extensions/
|
|
554
|
+
├── my-extension.ts # loaded directly
|
|
555
|
+
├── another.js # JS works too
|
|
556
|
+
└── complex-extension/ # directory with index file
|
|
557
|
+
├── index.ts # entry point (auto-detected)
|
|
558
|
+
└── helpers.ts # supporting modules
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
Extensions can be written in **TypeScript or JavaScript** — `.ts`, `.tsx`, `.mts`, `.js`, `.mjs` are all supported. TS extensions are transpiled at runtime via tsx.
|
|
562
|
+
|
|
563
|
+
Bare names (e.g. `my-ext-package`) resolve as **npm packages** via Node's standard module resolution. Install them globally or locally and reference by name.
|
|
564
|
+
|
|
565
|
+
Errors in extension loading are non-fatal — a `ui:error` is emitted and the next extension continues loading.
|
|
566
|
+
|
|
567
|
+
### Using as a library
|
|
568
|
+
|
|
569
|
+
The core can be imported directly for building custom frontends — no terminal required:
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
import { createCore } from "agent-sh";
|
|
573
|
+
|
|
574
|
+
const core = createCore({ agentCommand: "pi-acp" });
|
|
575
|
+
|
|
576
|
+
// Subscribe to events
|
|
577
|
+
core.bus.on("agent:response-chunk", ({ text }) => process.stdout.write(text));
|
|
578
|
+
core.bus.on("agent:processing-done", () => console.log("\n[done]"));
|
|
579
|
+
|
|
580
|
+
// Handle permissions (auto-approve, or wire to your own UI)
|
|
581
|
+
core.bus.onPipeAsync("permission:request", async (p) => {
|
|
582
|
+
return { ...p, decision: { approved: true } };
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
// Connect and send a query
|
|
586
|
+
await core.start();
|
|
587
|
+
core.bus.emit("agent:submit", { query: "explain this codebase" });
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
This works for WebSocket servers, REST APIs, Electron apps, test harnesses, or any environment where you want agent-sh's context management and ACP integration without the interactive terminal.
|
|
591
|
+
|
|
592
|
+
## Troubleshooting
|
|
593
|
+
|
|
594
|
+
### Agent connection issues
|
|
595
|
+
|
|
596
|
+
**Problem**: "Agent not connected. Please wait a moment and try again."
|
|
597
|
+
|
|
598
|
+
**Solutions**:
|
|
599
|
+
1. **Check agent installation**:
|
|
600
|
+
```bash
|
|
601
|
+
which pi-acp
|
|
602
|
+
which claude-agent-acp
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
2. **Verify ACP compatibility**:
|
|
606
|
+
```bash
|
|
607
|
+
# Test if agent supports ACP protocol
|
|
608
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientInfo":{"name":"test","version":"1.0.0"},"clientCapabilities":{"terminal":true,"fs":{"readTextFile":true,"writeTextFile":true}}}}' | pi-acp
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
3. **Install missing agents**:
|
|
612
|
+
```bash
|
|
613
|
+
npm install -g pi-acp
|
|
614
|
+
npm install -g @agentclientprotocol/claude-agent-acp
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
4. **Check environment variables**:
|
|
618
|
+
```bash
|
|
619
|
+
echo $ANTHROPIC_API_KEY
|
|
620
|
+
echo $OPENAI_API_KEY
|
|
621
|
+
echo $GEMINI_API_KEY
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Common errors
|
|
625
|
+
|
|
626
|
+
**Error**: "claude: command not found"
|
|
627
|
+
- **Cause**: Trying to use `claude` CLI tool which doesn't support ACP
|
|
628
|
+
- **Solution**: Use `claude-agent-acp` or `pi-acp` instead
|
|
629
|
+
|
|
630
|
+
**Error**: "API key not found"
|
|
631
|
+
- **Cause**: Missing required API key environment variable
|
|
632
|
+
- **Solution**: Set the appropriate API key (e.g., `export ANTHROPIC_API_KEY="your-key"`)
|
|
633
|
+
|
|
634
|
+
**Error**: "Invalid model name"
|
|
635
|
+
- **Cause**: Using incorrect model name
|
|
636
|
+
- **Solution**: Use valid model names like `claude-3-5-sonnet-20241022` or `gpt-4o`
|
|
637
|
+
|
|
638
|
+
**Error**: "Agent process exited with code X"
|
|
639
|
+
- **Cause**: Agent crashed or failed to start
|
|
640
|
+
- **Solution**: Check agent installation and API key validity
|
|
641
|
+
|
|
642
|
+
### Debug mode
|
|
643
|
+
|
|
644
|
+
Enable debug mode to see detailed ACP protocol information:
|
|
645
|
+
```bash
|
|
646
|
+
DEBUG=1 npm start -- --agent pi-acp
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Getting help
|
|
650
|
+
|
|
651
|
+
If you encounter issues:
|
|
652
|
+
1. Check the [ACP Protocol Documentation](https://agentclientprotocol.com/)
|
|
653
|
+
2. Verify agent installation: `pi-acp --version` or `claude-agent-acp --version`
|
|
654
|
+
3. Test with different agents to isolate the problem
|
|
655
|
+
4. Check GitHub issues for known problems
|
|
656
|
+
|
|
657
|
+
## License
|
|
658
|
+
|
|
659
|
+
MIT
|