coding-agent-adapters 0.2.13 → 0.2.15
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 +137 -85
- package/dist/index.cjs +406 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -4
- package/dist/index.d.ts +45 -4
- package/dist/index.js +406 -23
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
CLI adapters for AI coding agents. Works with [pty-manager](https://www.npmjs.com/package/pty-manager) to spawn and manage coding agents like Claude Code, Gemini CLI, OpenAI Codex, and Aider.
|
|
4
4
|
|
|
5
|
+
Each adapter provides source-derived detection patterns for the full session lifecycle: login/auth, blocking prompts, ready state, exit conditions, and auto-response rules — all based on deep analysis of each CLI's open-source codebase.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -42,12 +44,122 @@ session.send('Help me refactor this function to use async/await');
|
|
|
42
44
|
|
|
43
45
|
## Available Adapters
|
|
44
46
|
|
|
45
|
-
| Adapter | CLI | Type |
|
|
46
|
-
|
|
47
|
-
| `ClaudeAdapter` | Claude Code | `claude` |
|
|
48
|
-
| `GeminiAdapter` | Gemini CLI | `gemini` |
|
|
49
|
-
| `CodexAdapter` | OpenAI Codex | `codex` |
|
|
50
|
-
| `AiderAdapter` | Aider | `aider` | `
|
|
47
|
+
| Adapter | CLI | Type | Input Style | Auto-Response Rules |
|
|
48
|
+
|---------|-----|------|-------------|---------------------|
|
|
49
|
+
| `ClaudeAdapter` | Claude Code | `claude` | TUI menus | 5 rules |
|
|
50
|
+
| `GeminiAdapter` | Gemini CLI | `gemini` | TUI menus | 3 rules |
|
|
51
|
+
| `CodexAdapter` | OpenAI Codex | `codex` | TUI menus | 6 rules |
|
|
52
|
+
| `AiderAdapter` | Aider | `aider` | Text `(Y)es/(N)o` | 17 rules |
|
|
53
|
+
|
|
54
|
+
## Session Lifecycle Detection
|
|
55
|
+
|
|
56
|
+
Each adapter implements detection for every stage of a CLI session:
|
|
57
|
+
|
|
58
|
+
### Login / Auth Detection
|
|
59
|
+
|
|
60
|
+
Adapters detect various auth states and methods:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const adapter = new GeminiAdapter();
|
|
64
|
+
const login = adapter.detectLogin(output);
|
|
65
|
+
// { required: true, type: 'browser', url: 'https://...', instructions: '...' }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
| Adapter | Auth Types | Source Files |
|
|
69
|
+
|---------|-----------|-------------|
|
|
70
|
+
| Claude | API key, OAuth browser | CLI runtime |
|
|
71
|
+
| Gemini | Google OAuth, API key entry, auth in-progress | `AuthDialog.tsx`, `ApiAuthDialog.tsx`, `AuthInProgress.tsx` |
|
|
72
|
+
| Codex | Device code flow, onboarding auth menu | `auth.rs`, `headless_chatgpt_login.rs` |
|
|
73
|
+
| Aider | API key missing/invalid, OpenRouter OAuth | `onboarding.py`, `models.py` |
|
|
74
|
+
|
|
75
|
+
### Ready State Detection
|
|
76
|
+
|
|
77
|
+
Each adapter knows exactly what "ready for input" looks like:
|
|
78
|
+
|
|
79
|
+
| Adapter | Ready Indicators | Source |
|
|
80
|
+
|---------|-----------------|--------|
|
|
81
|
+
| Claude | `$` prompt | CLI runtime |
|
|
82
|
+
| Gemini | Prompt glyphs (`>`, `!`, `*`, `(r:)`), composer placeholder | `InputPrompt.tsx`, `Composer.tsx` |
|
|
83
|
+
| Codex | `>` glyph, placeholder suggestions | `chat_composer.rs` |
|
|
84
|
+
| Aider | `ask>`, `code>`, `architect>`, `help>`, `multi>`, startup banner | `io.py`, `base_coder.py` |
|
|
85
|
+
|
|
86
|
+
### Blocking Prompt Detection
|
|
87
|
+
|
|
88
|
+
Adapters detect prompts that block the session and require user action:
|
|
89
|
+
|
|
90
|
+
| Adapter | Detected Prompts |
|
|
91
|
+
|---------|-----------------|
|
|
92
|
+
| Claude | Permission requests, update notices |
|
|
93
|
+
| Gemini | Folder trust, tool execution, validation dialogs, privacy consent |
|
|
94
|
+
| Codex | Directory trust, tool approval, update available, model migration, CWD selection |
|
|
95
|
+
| Aider | File operations, shell commands, git init, pip install, destructive operations |
|
|
96
|
+
|
|
97
|
+
### Exit Detection
|
|
98
|
+
|
|
99
|
+
Adapters detect when a CLI session has ended:
|
|
100
|
+
|
|
101
|
+
| Adapter | Exit Conditions |
|
|
102
|
+
|---------|----------------|
|
|
103
|
+
| Claude | Base exit detection |
|
|
104
|
+
| Gemini | Folder trust rejection, logout confirmation |
|
|
105
|
+
| Codex | Session end, update completion |
|
|
106
|
+
| Aider | Ctrl+C / KeyboardInterrupt, version update requiring restart |
|
|
107
|
+
|
|
108
|
+
## Auto-Response Rules
|
|
109
|
+
|
|
110
|
+
Adapters include pre-configured rules to automatically handle known prompts. Rules use two response modes depending on the CLI's input style.
|
|
111
|
+
|
|
112
|
+
### TUI Menu CLIs (Gemini, Codex, Claude)
|
|
113
|
+
|
|
114
|
+
These CLIs use arrow-key menus rendered with Ink/Ratatui. Rules send key sequences:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const codex = new CodexAdapter();
|
|
118
|
+
codex.autoResponseRules;
|
|
119
|
+
// [
|
|
120
|
+
// { pattern: /update.?available/i, responseType: 'keys', keys: ['down', 'enter'], once: true, ... },
|
|
121
|
+
// { pattern: /trust.?this.?directory/i, responseType: 'keys', keys: ['enter'], once: true, ... },
|
|
122
|
+
// { pattern: /model.?migration/i, responseType: 'keys', keys: ['enter'], once: true, ... },
|
|
123
|
+
// ...
|
|
124
|
+
// ]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Text Prompt CLIs (Aider)
|
|
128
|
+
|
|
129
|
+
Aider uses plain text `(Y)es/(N)o` prompts via `io.py`. Rules send typed text:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const aider = new AiderAdapter();
|
|
133
|
+
aider.autoResponseRules;
|
|
134
|
+
// [
|
|
135
|
+
// { pattern: /allow collection of anonymous analytics/i, response: 'n', responseType: 'text', once: true, ... },
|
|
136
|
+
// { pattern: /add .+ to the chat\?/i, response: 'y', responseType: 'text', ... },
|
|
137
|
+
// { pattern: /create new file\?/i, response: 'y', responseType: 'text', ... },
|
|
138
|
+
// { pattern: /run shell commands?\?/i, response: 'y', responseType: 'text', ... },
|
|
139
|
+
// ...17 rules total
|
|
140
|
+
// ]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### The `usesTuiMenus` Flag
|
|
144
|
+
|
|
145
|
+
Adapters declare their input style via `usesTuiMenus`. This affects how auto-response rules with no explicit `responseType` are delivered:
|
|
146
|
+
|
|
147
|
+
- `usesTuiMenus: true` (Gemini, Codex, Claude) — defaults to `sendKeys('enter')`
|
|
148
|
+
- `usesTuiMenus: false` (Aider) — defaults to `writeRaw(response + '\r')`
|
|
149
|
+
|
|
150
|
+
## Model Recommendations
|
|
151
|
+
|
|
152
|
+
Each adapter provides model recommendations based on available credentials:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const aider = new AiderAdapter();
|
|
156
|
+
|
|
157
|
+
aider.getRecommendedModels({ anthropicKey: 'sk-ant-...' });
|
|
158
|
+
// { powerful: 'anthropic/claude-sonnet-4-20250514', fast: 'anthropic/claude-haiku-4-5-20251001' }
|
|
159
|
+
|
|
160
|
+
aider.getRecommendedModels({ googleKey: 'AIza...' });
|
|
161
|
+
// { powerful: 'gemini/gemini-3-pro', fast: 'gemini/gemini-3-flash' }
|
|
162
|
+
```
|
|
51
163
|
|
|
52
164
|
## Preflight Check
|
|
53
165
|
|
|
@@ -60,9 +172,9 @@ import { checkAdapters, checkAllAdapters, printMissingAdapters } from 'coding-ag
|
|
|
60
172
|
const results = await checkAdapters(['claude', 'aider']);
|
|
61
173
|
for (const result of results) {
|
|
62
174
|
if (result.installed) {
|
|
63
|
-
console.log(
|
|
175
|
+
console.log(`${result.adapter} v${result.version}`);
|
|
64
176
|
} else {
|
|
65
|
-
console.log(
|
|
177
|
+
console.log(`${result.adapter} - Install: ${result.installCommand}`);
|
|
66
178
|
}
|
|
67
179
|
}
|
|
68
180
|
|
|
@@ -73,24 +185,6 @@ const allResults = await checkAllAdapters();
|
|
|
73
185
|
await printMissingAdapters(['claude', 'gemini']);
|
|
74
186
|
```
|
|
75
187
|
|
|
76
|
-
Each adapter also provides installation info:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
import { ClaudeAdapter } from 'coding-agent-adapters';
|
|
80
|
-
|
|
81
|
-
const claude = new ClaudeAdapter();
|
|
82
|
-
console.log(claude.installation);
|
|
83
|
-
// {
|
|
84
|
-
// command: 'npm install -g @anthropic-ai/claude-code',
|
|
85
|
-
// alternatives: ['npx @anthropic-ai/claude-code', 'brew install claude-code'],
|
|
86
|
-
// docsUrl: 'https://docs.anthropic.com/en/docs/claude-code',
|
|
87
|
-
// minVersion: '1.0.0'
|
|
88
|
-
// }
|
|
89
|
-
|
|
90
|
-
// Get formatted instructions
|
|
91
|
-
console.log(claude.getInstallInstructions());
|
|
92
|
-
```
|
|
93
|
-
|
|
94
188
|
## Passing Credentials
|
|
95
189
|
|
|
96
190
|
You can pass API keys either via environment variables or through `adapterConfig`:
|
|
@@ -112,93 +206,51 @@ const session = await manager.spawn({
|
|
|
112
206
|
workdir: '/project',
|
|
113
207
|
adapterConfig: {
|
|
114
208
|
anthropicKey: 'sk-ant-...',
|
|
209
|
+
openaiKey: 'sk-...',
|
|
210
|
+
googleKey: 'AIza...',
|
|
115
211
|
},
|
|
116
212
|
});
|
|
117
213
|
```
|
|
118
214
|
|
|
119
|
-
## Adapter Features
|
|
120
|
-
|
|
121
|
-
### Auto-Response Rules
|
|
122
|
-
|
|
123
|
-
Each adapter includes auto-response rules for common prompts (updates, telemetry, etc.):
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
const claude = new ClaudeAdapter();
|
|
127
|
-
console.log(claude.autoResponseRules);
|
|
128
|
-
// [
|
|
129
|
-
// { pattern: /update available.*\[y\/n\]/i, response: 'n', ... },
|
|
130
|
-
// { pattern: /telemetry.*\[y\/n\]/i, response: 'n', ... },
|
|
131
|
-
// ...
|
|
132
|
-
// ]
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Blocking Prompt Detection
|
|
136
|
-
|
|
137
|
-
Adapters detect blocking prompts that require user intervention:
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
session.on('blocking_prompt', (promptInfo, autoResponded) => {
|
|
141
|
-
if (!autoResponded) {
|
|
142
|
-
console.log(`User action required: ${promptInfo.type}`);
|
|
143
|
-
console.log(promptInfo.instructions);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Login Detection
|
|
149
|
-
|
|
150
|
-
Adapters detect when authentication is required:
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
session.on('login_required', (instructions, url) => {
|
|
154
|
-
console.log('Authentication required:', instructions);
|
|
155
|
-
if (url) {
|
|
156
|
-
console.log('Open:', url);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
```
|
|
160
|
-
|
|
161
215
|
## Creating Custom Adapters
|
|
162
216
|
|
|
163
217
|
Extend `BaseCodingAdapter` to create adapters for other coding CLIs:
|
|
164
218
|
|
|
165
219
|
```typescript
|
|
166
220
|
import { BaseCodingAdapter } from 'coding-agent-adapters';
|
|
167
|
-
import type { SpawnConfig, ParsedOutput, LoginDetection } from 'pty-manager';
|
|
221
|
+
import type { SpawnConfig, ParsedOutput, LoginDetection, AutoResponseRule } from 'pty-manager';
|
|
168
222
|
|
|
169
223
|
export class CursorAdapter extends BaseCodingAdapter {
|
|
170
224
|
readonly adapterType = 'cursor';
|
|
171
225
|
readonly displayName = 'Cursor';
|
|
172
226
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
227
|
+
// Set to false if the CLI uses text prompts instead of TUI menus
|
|
228
|
+
override readonly usesTuiMenus = false;
|
|
176
229
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
230
|
+
readonly autoResponseRules: AutoResponseRule[] = [
|
|
231
|
+
{ pattern: /accept terms/i, type: 'tos', response: 'y', responseType: 'text', description: 'Accept TOS', safe: true, once: true },
|
|
232
|
+
];
|
|
180
233
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
234
|
+
getCommand(): string { return 'cursor'; }
|
|
235
|
+
getArgs(config: SpawnConfig): string[] { return ['--cli']; }
|
|
236
|
+
getEnv(config: SpawnConfig): Record<string, string> { return {}; }
|
|
184
237
|
|
|
185
238
|
detectLogin(output: string): LoginDetection {
|
|
186
|
-
|
|
239
|
+
if (/login required/i.test(output)) {
|
|
240
|
+
return { required: true, type: 'browser' };
|
|
241
|
+
}
|
|
187
242
|
return { required: false };
|
|
188
243
|
}
|
|
189
244
|
|
|
190
245
|
detectReady(output: string): boolean {
|
|
191
|
-
return
|
|
246
|
+
return /cursor>\s*$/m.test(output);
|
|
192
247
|
}
|
|
193
248
|
|
|
194
249
|
parseOutput(output: string): ParsedOutput | null {
|
|
195
|
-
|
|
196
|
-
return null;
|
|
250
|
+
return { type: 'response', content: output.trim(), isComplete: true, isQuestion: output.includes('?') };
|
|
197
251
|
}
|
|
198
252
|
|
|
199
|
-
getPromptPattern(): RegExp {
|
|
200
|
-
return /cursor>\s*$/;
|
|
201
|
-
}
|
|
253
|
+
getPromptPattern(): RegExp { return /cursor>\s*$/; }
|
|
202
254
|
}
|
|
203
255
|
```
|
|
204
256
|
|