coding-agent-adapters 0.8.8 → 0.11.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 +130 -5
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# coding-agent-adapters
|
|
2
2
|
|
|
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
|
|
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, Aider, and Hermes Agent.
|
|
4
4
|
|
|
5
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
6
|
|
|
@@ -14,13 +14,14 @@ npm install coding-agent-adapters pty-manager
|
|
|
14
14
|
|
|
15
15
|
```typescript
|
|
16
16
|
import { PTYManager, AdapterRegistry } from 'pty-manager';
|
|
17
|
-
import { ClaudeAdapter, GeminiAdapter, AiderAdapter } from 'coding-agent-adapters';
|
|
17
|
+
import { ClaudeAdapter, GeminiAdapter, AiderAdapter, HermesAdapter } from 'coding-agent-adapters';
|
|
18
18
|
|
|
19
19
|
// Create adapter registry and register the adapters you need
|
|
20
20
|
const registry = new AdapterRegistry();
|
|
21
21
|
registry.register(new ClaudeAdapter());
|
|
22
22
|
registry.register(new GeminiAdapter());
|
|
23
23
|
registry.register(new AiderAdapter());
|
|
24
|
+
registry.register(new HermesAdapter());
|
|
24
25
|
|
|
25
26
|
// Create PTY manager with the registry
|
|
26
27
|
const manager = new PTYManager({ adapters: registry });
|
|
@@ -50,6 +51,7 @@ session.send('Help me refactor this function to use async/await');
|
|
|
50
51
|
| `GeminiAdapter` | Gemini CLI | `gemini` | TUI menus | 3 rules | 300ms |
|
|
51
52
|
| `CodexAdapter` | OpenAI Codex | `codex` | TUI menus | 6 rules | 300ms |
|
|
52
53
|
| `AiderAdapter` | Aider | `aider` | Text `(Y)es/(N)o` | 17 rules | 200ms |
|
|
54
|
+
| `HermesAdapter` | Hermes Agent | `hermes` | TUI prompts | 0 rules | 400ms |
|
|
53
55
|
|
|
54
56
|
## Session Lifecycle Detection
|
|
55
57
|
|
|
@@ -73,6 +75,7 @@ const login = adapter.detectLogin(output);
|
|
|
73
75
|
| Gemini | Google OAuth, API key entry, auth in-progress (ignores "Both keys set" success messages) | `AuthDialog.tsx`, `ApiAuthDialog.tsx`, `AuthInProgress.tsx` |
|
|
74
76
|
| Codex | Device code flow, onboarding auth menu | `auth.rs`, `headless_chatgpt_login.rs` |
|
|
75
77
|
| Aider | API key missing/invalid, OpenRouter OAuth | `onboarding.py`, `models.py` |
|
|
78
|
+
| Hermes | First-run setup gate (`no API keys/providers found`, `Run setup now?`) | `hermes_cli/setup.py`, `hermes_cli/main.py` |
|
|
76
79
|
|
|
77
80
|
### Ready State Detection
|
|
78
81
|
|
|
@@ -84,6 +87,7 @@ Each adapter knows exactly what "ready for input" looks like:
|
|
|
84
87
|
| Gemini | Prompt glyphs (`>`, `!`, `*`, `(r:)`), composer placeholder | `InputPrompt.tsx`, `Composer.tsx` |
|
|
85
88
|
| Codex | `>` glyph, placeholder suggestions | `chat_composer.rs` |
|
|
86
89
|
| Aider | `ask>`, `code>`, `architect>`, `help>`, `multi>`, startup banner | `io.py`, `base_coder.py` |
|
|
90
|
+
| Hermes | Idle `❯` prompt when not working; completion response box | `cli.py`, `agent/display.py` |
|
|
87
91
|
|
|
88
92
|
### Ready Settle Delay
|
|
89
93
|
|
|
@@ -95,6 +99,7 @@ Each adapter sets `readySettleMs` to control how long pty-manager waits after `d
|
|
|
95
99
|
| Gemini CLI | 300ms | Moderate Ink TUI (inherits base default) |
|
|
96
100
|
| Codex | 300ms | Moderate Rust TUI (inherits base default) |
|
|
97
101
|
| Aider | 200ms | Minimal TUI, mostly text output |
|
|
102
|
+
| Hermes Agent | 400ms | Prompt-toolkit UI with spinner + activity feed that settles after render |
|
|
98
103
|
|
|
99
104
|
### Blocking Prompt Detection
|
|
100
105
|
|
|
@@ -106,6 +111,7 @@ Adapters detect prompts that block the session and require user action:
|
|
|
106
111
|
| Gemini | Folder trust, tool execution, validation dialogs, privacy consent |
|
|
107
112
|
| Codex | Directory trust, tool approval, update available, model migration, CWD selection |
|
|
108
113
|
| Aider | File operations, shell commands, git init, pip install, destructive operations |
|
|
114
|
+
| Hermes | Clarify prompts, sudo password prompts, dangerous command approval choices |
|
|
109
115
|
|
|
110
116
|
### Loading / Active-Work Detection
|
|
111
117
|
|
|
@@ -117,6 +123,7 @@ Each adapter implements `detectLoading(output)` to detect when the CLI is active
|
|
|
117
123
|
| Gemini | `esc to cancel`, `Waiting for user confirmation` | `gemini_active_loading_line` |
|
|
118
124
|
| Codex | `esc to interrupt`, `Booting MCP server`, `Searching the web` | `codex_active_status_row`, `codex_active_booting_mcp` |
|
|
119
125
|
| Aider | `Waiting for LLM/<model>`, `Generating commit message with` | `aider_active_waiting_model`, `aider_active_waiting_llm_default` |
|
|
126
|
+
| Hermes | Thinking spinner verb + elapsed time (`deliberating... (2.4s)`), working prompt (`⚕ ❯`) | `HermesAdapter.detectLoading()` |
|
|
120
127
|
|
|
121
128
|
```typescript
|
|
122
129
|
const claude = new ClaudeAdapter();
|
|
@@ -139,6 +146,7 @@ Each adapter implements `detectTaskComplete(output)` to recognize when the CLI h
|
|
|
139
146
|
| Gemini | `◇ Ready` window title, `Type your message` composer | `gemini_ready_title` |
|
|
140
147
|
| Codex | `Worked for 1m 05s` separator + `›` prompt | `codex_completed_worked_for_separator`, `codex_ready_prompt` |
|
|
141
148
|
| Aider | `Aider is waiting for your input`, mode prompts (including plain `>`) with edit/cost markers | `aider_completed_llm_response_ready` |
|
|
149
|
+
| Hermes | Final response box (`╭─ ⚕ Hermes ... ╰`), or tool-feed line + idle prompt | `HermesAdapter.detectTaskComplete()` |
|
|
142
150
|
|
|
143
151
|
```typescript
|
|
144
152
|
const claude = new ClaudeAdapter();
|
|
@@ -160,12 +168,13 @@ Adapters detect when a CLI session has ended:
|
|
|
160
168
|
| Gemini | Folder trust rejection, logout confirmation |
|
|
161
169
|
| Codex | Session end, update completion |
|
|
162
170
|
| Aider | Ctrl+C / KeyboardInterrupt, version update requiring restart |
|
|
171
|
+
| Hermes | `Goodbye! ⚕` |
|
|
163
172
|
|
|
164
173
|
## Auto-Response Rules
|
|
165
174
|
|
|
166
175
|
Adapters include pre-configured rules to automatically handle known prompts. Rules use two response modes depending on the CLI's input style.
|
|
167
176
|
|
|
168
|
-
### TUI Menu CLIs (Gemini, Codex, Claude)
|
|
177
|
+
### TUI Menu CLIs (Gemini, Codex, Claude, Hermes)
|
|
169
178
|
|
|
170
179
|
These CLIs use arrow-key menus rendered with Ink/Ratatui. Rules send key sequences:
|
|
171
180
|
|
|
@@ -200,7 +209,7 @@ aider.autoResponseRules;
|
|
|
200
209
|
|
|
201
210
|
Adapters declare their input style via `usesTuiMenus`. This affects how auto-response rules with no explicit `responseType` are delivered:
|
|
202
211
|
|
|
203
|
-
- `usesTuiMenus: true` (Gemini, Codex, Claude) — defaults to `sendKeys('enter')`
|
|
212
|
+
- `usesTuiMenus: true` (Gemini, Codex, Claude, Hermes) — defaults to `sendKeys('enter')`
|
|
204
213
|
- `usesTuiMenus: false` (Aider) — defaults to `writeRaw(response + '\r')`
|
|
205
214
|
|
|
206
215
|
## Model Recommendations
|
|
@@ -248,6 +257,7 @@ aider.memoryFilePath; // '.aider.conventions.md'
|
|
|
248
257
|
| Gemini | `GEMINI.md` | `.gemini/settings.json` | `.gemini/styles` |
|
|
249
258
|
| Codex | `AGENTS.md` | `.codex/config.json` | `codex.md` |
|
|
250
259
|
| Aider | `.aider.conventions.md` | `.aider.conf.yml` | `.aiderignore` |
|
|
260
|
+
| Hermes | `AGENTS.md` | `cli-config.yaml` | `SOUL.md` |
|
|
251
261
|
|
|
252
262
|
### Writing Memory Files
|
|
253
263
|
|
|
@@ -344,6 +354,7 @@ const writtenFiles = await adapter.writeApprovalConfig('/path/to/workspace', {
|
|
|
344
354
|
| Gemini CLI | `.gemini/settings.json` | `general.defaultApprovalMode`, `tools.allowed`, `tools.exclude` |
|
|
345
355
|
| Codex | `.codex/config.json` | `approval_policy`, `sandbox_mode`, `tools.web_search` |
|
|
346
356
|
| Aider | `.aider.conf.yml` | `yes-always`, `no-auto-commits` |
|
|
357
|
+
| Hermes Agent | none (CLI-managed) | approvals currently handled in-session by Hermes safety prompts |
|
|
347
358
|
|
|
348
359
|
## Preflight Check
|
|
349
360
|
|
|
@@ -396,6 +407,120 @@ const session = await manager.spawn({
|
|
|
396
407
|
});
|
|
397
408
|
```
|
|
398
409
|
|
|
410
|
+
## Claude Hook Telemetry (Optional)
|
|
411
|
+
|
|
412
|
+
Claude Code hooks can emit deterministic lifecycle markers so PTY orchestration does not rely only on screen-text heuristics.
|
|
413
|
+
|
|
414
|
+
`ClaudeAdapter` supports this as an opt-in mode:
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
const session = await manager.spawn({
|
|
418
|
+
name: 'claude-agent',
|
|
419
|
+
type: 'claude',
|
|
420
|
+
workdir: '/project',
|
|
421
|
+
adapterConfig: {
|
|
422
|
+
anthropicKey: process.env.ANTHROPIC_API_KEY,
|
|
423
|
+
claudeHookTelemetry: true,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
When enabled, the adapter sets:
|
|
429
|
+
- `PARALLAX_CLAUDE_HOOK_TELEMETRY=1`
|
|
430
|
+
- `PARALLAX_CLAUDE_HOOK_MARKER_PREFIX=PARALLAX_CLAUDE_HOOK` (or your override)
|
|
431
|
+
|
|
432
|
+
### Marker Protocol
|
|
433
|
+
|
|
434
|
+
Hook scripts should print single-line markers:
|
|
435
|
+
|
|
436
|
+
```text
|
|
437
|
+
PARALLAX_CLAUDE_HOOK {"event":"Notification","notification_type":"permission_prompt","message":"..."}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Supported high-value events:
|
|
441
|
+
- `Notification` (`permission_prompt`, `elicitation_dialog`, `idle_prompt`)
|
|
442
|
+
- `PreToolUse` (includes `tool_name`)
|
|
443
|
+
- `TaskCompleted`
|
|
444
|
+
- `SessionEnd`
|
|
445
|
+
|
|
446
|
+
The adapter consumes these markers in:
|
|
447
|
+
- `detectBlockingPrompt()`
|
|
448
|
+
- `detectLoading()`
|
|
449
|
+
- `detectToolRunning()`
|
|
450
|
+
- `detectTaskComplete()`
|
|
451
|
+
- `detectReady()`
|
|
452
|
+
- `detectExit()`
|
|
453
|
+
|
|
454
|
+
### Generate Hook Config Template
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
const claude = new ClaudeAdapter();
|
|
458
|
+
const protocol = claude.getHookTelemetryProtocol();
|
|
459
|
+
|
|
460
|
+
// protocol.scriptPath
|
|
461
|
+
// protocol.scriptContent
|
|
462
|
+
// protocol.settingsHooks
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
`settingsHooks` is ready to merge into `.claude/settings.json` under `hooks`.
|
|
466
|
+
|
|
467
|
+
## Gemini Hook Telemetry (Optional)
|
|
468
|
+
|
|
469
|
+
Gemini CLI hooks can emit deterministic lifecycle markers so PTY orchestration does not rely only on screen-text heuristics.
|
|
470
|
+
|
|
471
|
+
`GeminiAdapter` supports this as an opt-in mode:
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
const session = await manager.spawn({
|
|
475
|
+
name: 'gemini-agent',
|
|
476
|
+
type: 'gemini',
|
|
477
|
+
workdir: '/project',
|
|
478
|
+
adapterConfig: {
|
|
479
|
+
googleKey: process.env.GEMINI_API_KEY,
|
|
480
|
+
geminiHookTelemetry: true,
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
When enabled, the adapter sets:
|
|
486
|
+
- `PARALLAX_GEMINI_HOOK_TELEMETRY=1`
|
|
487
|
+
- `PARALLAX_GEMINI_HOOK_MARKER_PREFIX=PARALLAX_GEMINI_HOOK` (or your override)
|
|
488
|
+
|
|
489
|
+
### Marker Protocol
|
|
490
|
+
|
|
491
|
+
Gemini hook command output must be valid JSON. The helper script emits marker lines via `systemMessage`:
|
|
492
|
+
|
|
493
|
+
```text
|
|
494
|
+
PARALLAX_GEMINI_HOOK {"event":"BeforeTool","tool_name":"run_shell_command"}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Supported high-value events:
|
|
498
|
+
- `Notification` (`ToolPermission`)
|
|
499
|
+
- `BeforeTool` (includes `tool_name`)
|
|
500
|
+
- `AfterAgent`
|
|
501
|
+
- `SessionEnd`
|
|
502
|
+
|
|
503
|
+
The adapter consumes these markers in:
|
|
504
|
+
- `detectBlockingPrompt()`
|
|
505
|
+
- `detectLoading()`
|
|
506
|
+
- `detectToolRunning()`
|
|
507
|
+
- `detectTaskComplete()`
|
|
508
|
+
- `detectReady()`
|
|
509
|
+
- `detectExit()`
|
|
510
|
+
|
|
511
|
+
### Generate Hook Config Template
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
const gemini = new GeminiAdapter();
|
|
515
|
+
const protocol = gemini.getHookTelemetryProtocol();
|
|
516
|
+
|
|
517
|
+
// protocol.scriptPath
|
|
518
|
+
// protocol.scriptContent
|
|
519
|
+
// protocol.settingsHooks
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
`settingsHooks` is ready to merge into `.gemini/settings.json` under `hooks`.
|
|
523
|
+
|
|
399
524
|
## Creating Custom Adapters
|
|
400
525
|
|
|
401
526
|
Extend `BaseCodingAdapter` to create adapters for other coding CLIs:
|
|
@@ -479,7 +604,7 @@ const allAdapters = createAllAdapters();
|
|
|
479
604
|
const claude = createAdapter('claude');
|
|
480
605
|
|
|
481
606
|
// Available adapter types
|
|
482
|
-
console.log(Object.keys(ADAPTER_TYPES)); // ['claude', 'gemini', 'codex', 'aider']
|
|
607
|
+
console.log(Object.keys(ADAPTER_TYPES)); // ['claude', 'gemini', 'codex', 'aider', 'hermes']
|
|
483
608
|
```
|
|
484
609
|
|
|
485
610
|
## License
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coding-agent-adapters",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI adapters for AI coding agents - Claude Code, Gemini CLI, OpenAI Codex, and
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "CLI adapters for AI coding agents - Claude Code, Gemini CLI, OpenAI Codex, Aider, and Hermes Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"gemini",
|
|
34
34
|
"codex",
|
|
35
35
|
"aider",
|
|
36
|
+
"hermes",
|
|
36
37
|
"ai-agents",
|
|
37
38
|
"coding-agents",
|
|
38
39
|
"pty-manager"
|