@yul-labs/agent-relay 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 agent-relay contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,395 @@
1
+ # agent-relay
2
+
3
+ > A vendor-agnostic **interactive** LLM coding-agent session orchestrator.
4
+
5
+ `agent-relay` runs a coding agent (**Claude Code**, **Codex**) in its real
6
+ interactive terminal, watches for the approval / choice prompts it raises, and a
7
+ pluggable **Decider** (a rule policy, an LLM, or any function/API) answers them —
8
+ so the agent runs **unattended without you sitting at the keyboard**. Every run
9
+ is tracked as a *session* with a log, and completion is detected so success can
10
+ be judged.
11
+
12
+ This is the core idea: **don't suppress the agent's prompts — let them happen and
13
+ have an LLM/policy answer them**, interactively.
14
+
15
+ - ✅ Drives the **real interactive TUI** of Claude & Codex over a PTY (node-pty)
16
+ - ✅ A **Decider** answers approvals/choices: `rule` (default), `command` (an LLM
17
+ CLI like `claude -p` / `codex exec`), `function`/API, or `always-approve`
18
+ - ✅ Both **Claude and Codex** are first-class and **verified end-to-end**
19
+ - ✅ Vendor-agnostic core: every agent is an `AgentAdapter`; nothing in `core/`
20
+ imports Claude/Codex
21
+ - ✅ Hard timeout, idle timeout, max-interactions, graceful cancel on every run
22
+ - ✅ Deterministic **fake interactive agent** makes the whole loop testable offline
23
+ - ✅ "Done" means **`pnpm typecheck` + `pnpm test` pass** — not "code was written"
24
+
25
+ ---
26
+
27
+ ## Requirements
28
+
29
+ - Node.js **>= 18.19**
30
+ - [pnpm](https://pnpm.io/)
31
+ - [`node-pty`](https://www.npmjs.com/package/node-pty) — installed automatically;
32
+ it ships prebuilt binaries for macOS/Linux. agent-relay self-heals its
33
+ `spawn-helper` permissions at runtime, so it works across install methods.
34
+ - Optional, per adapter:
35
+ - [`claude`](https://www.npmjs.com/package/@anthropic-ai/claude-code) on PATH
36
+ - [`codex`](https://www.npmjs.com/package/@openai/codex) on PATH
37
+
38
+ Designed for **macOS / Linux** CLI use.
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ # Global CLI (once published):
44
+ npm i -g agent-relay # or: pnpm add -g agent-relay
45
+
46
+ # From a local checkout:
47
+ pnpm install
48
+ pnpm build # tsup -> dist/cli.js + dist/index.js + .d.ts
49
+ npm i -g . # install this checkout globally
50
+ ```
51
+
52
+ Run from source without building: `pnpm dev -- <command>`.
53
+
54
+ ## Quick start
55
+
56
+ **Zero-config** — `init` is optional. With no `agent-relay.config.json`, the CLI
57
+ uses built-in defaults and creates its session/log dirs on first run, so you can
58
+ go straight to `npx`:
59
+
60
+ ```bash
61
+ npx agent-relay run --adapter claude --prompt "현재 프로젝트의 타입 오류를 확인하고 수정해줘"
62
+ ```
63
+
64
+ ```bash
65
+ agent-relay init # OPTIONAL: write a config you can edit
66
+ agent-relay adapters # list adapters
67
+ agent-relay doctor # check environment
68
+
69
+ # Deterministic, no real agent:
70
+ agent-relay run --adapter fake --prompt "test task"
71
+
72
+ # Real agents, driven interactively (the decider answers their prompts):
73
+ agent-relay run --adapter codex --prompt "현재 프로젝트의 타입 오류를 확인하고 수정해줘"
74
+ agent-relay run --adapter claude --prompt-file ./examples/task.md
75
+
76
+ agent-relay resume --session-id <sessionId>
77
+ ```
78
+
79
+ Run `agent-relay init` only when you want a config file on disk to customize
80
+ (pick a different default adapter, point the decider at an LLM/local model, or
81
+ change the session/log dirs). Pass `--root /path/to/project` to run against
82
+ another project — the real `claude`/`codex` then loads *that* project's
83
+ `CLAUDE.md`, skills, MCP servers, and hooks natively.
84
+
85
+ ---
86
+
87
+ ## How it works
88
+
89
+ ```
90
+ prompt ──> spawn agent in a PTY (its real TUI) ──> watch terminal output
91
+
92
+ output settles (idle) ▼
93
+ ┌──> prompt detected? ──yes──> Decider.decide()
94
+ │ │
95
+ │ keystrokes <───────────────┘
96
+ │ (Enter / arrow+Enter / y/n / text)
97
+
98
+ └──> no prompt + sustained idle ──> quit cleanly (completed)
99
+ ```
100
+
101
+ 1. The agent is launched **interactively** in a pseudo-terminal under **pure
102
+ autonomy** (the project's concept): Claude with `--dangerously-skip-permissions`,
103
+ Codex with `-s workspace-write -a never`. The agent rarely asks — but the
104
+ prompts that *still* appear (the directory-trust dialog, the occasional choice)
105
+ are what the Decider answers. `approvalPolicy: "gated"` makes the agent ask
106
+ more (Claude `--permission-mode acceptEdits`, Codex `-a on-request`);
107
+ `"readonly"` sandboxes it (Claude `--permission-mode plan`, Codex `-s read-only`).
108
+ 2. When the terminal goes idle, agent-relay strips ANSI and **detects** a prompt:
109
+ a numbered/▶ **menu** (single choice), a **multi-select** menu (checkboxes
110
+ `[ ]`/`[x]`/`◯`/`◉`), a yes/no **approval**, or — opt-in — a free-text **input**
111
+ step. Multi-step flows (menu → menu → input → submit) are handled as a
112
+ sequence: each settled screen is detected, decided, answered, and the consumed
113
+ screen is dropped so the next step is read fresh.
114
+ 3. The **Decider** decides; the keystrokes are written back into the PTY
115
+ (Enter to confirm a pre-selected option, arrow-down+Enter to pick another,
116
+ `y`/`n`, typed text, or — for a multi-select — a single batch that navigates
117
+ with ↑/↓, toggles the chosen rows with SPACE, and submits with `→`).
118
+ 4. When the agent finishes and stays idle for `completionIdleMs` (default 8s,
119
+ tune with `--completion-idle-ms`), the session quits the TUI and is marked
120
+ **completed**. While the agent is *working* (its TUI shows a
121
+ "… esc to interrupt" indicator) the run is **never** treated as done — so a
122
+ multi-minute think/build is not cut short, however long it stays quiet.
123
+
124
+ > Driving a real TUI by scraping its output is inherently heuristic. The detector
125
+ > patterns and keymaps are tuned for the current Claude/Codex TUIs and are
126
+ > configurable per adapter; if a vendor changes its TUI, the patterns may need a
127
+ > tweak. Both agents are verified working today (see Testing).
128
+
129
+ **Multi-step menus** work out of the box for the real agents. A free-text
130
+ **input** step, however, is **opt-in**: the detector only recognizes one when you
131
+ give it an `inputPattern`, and it is **off by default for Claude/Codex** because
132
+ their idle main input box would otherwise be misread as "the agent is asking for
133
+ text". If you enable it, anchor the pattern to an unambiguous prompt phrase
134
+ (e.g. `/enter .*name:/i`, not a bare `/enter/i` that would also fire on
135
+ "Press Enter to continue"). Detection order within a screen is **choice →
136
+ approval → input**.
137
+
138
+ **Multi-select** (checkbox) menus are detected automatically when most rows carry
139
+ a `[ ]`/`[x]`/`◯`/`◉` box. The decider returns `optionIndexes` (the set that
140
+ should end up checked); the keymap then emits ONE batch — navigate ↑/↓, SPACE to
141
+ toggle only the rows that differ, then submit. The submit key defaults to `→`
142
+ (works for the common step-wizard "advance/Submit"); it is the `multiSelectSubmit`
143
+ arg of the keymap, so a TUI that submits with Enter-on-a-Next-row can be retuned.
144
+ The `rule` decider keeps the current selection and submits (no judgment); an LLM
145
+ decider picks the task-relevant rows.
146
+
147
+ ## The Decider
148
+
149
+ The Decider answers every detected prompt. Choose it in config (`decider`) or
150
+ per run:
151
+
152
+ The guiding policy is **proceed by default, redirect only off-task danger**:
153
+ let the agent do its work (so the project actually progresses) and only refuse
154
+ an action that is *both* dangerous *and* unrelated to the task. Judging
155
+ "on-task vs off-task" needs the goal, so it is an **LLM** job — not a regex.
156
+
157
+ | Type | What it does |
158
+ | --- | --- |
159
+ | `rule` (default) | Deterministic & offline, no judgment: **approves** every y/n and **confirms the recommended (first) option** on a menu so the task proceeds. (No label guessing by default — the TUI already pre-selects its affirmative choice.) Opt into `denyPatterns` (`rm -rf`, `sudo`, ...) to make it **label-aware**: deny dangerous approvals and steer menus to a negative option — see the caveat below. |
160
+ | `command` | Delegate to an **LLM CLI** — `claude -p`, `codex exec`, etc. The model gets the **task** and approves on-task work (even risky) while denying off-task danger with a redirect comment. |
161
+ | `api` | Same task-aware policy via an **OpenAI-compatible HTTP endpoint** (llama.cpp / vLLM / Ollama / LM Studio / OpenAI). Works with local open models. |
162
+ | `always-approve` | Approve/confirm everything. Maximum autonomy, no judgment. |
163
+
164
+ ```jsonc
165
+ // agent-relay.config.json — pick ONE "decider":
166
+
167
+ // a) local open model (llama.cpp / vLLM / Ollama, OpenAI-compatible):
168
+ "decider": { "type": "api", "url": "http://localhost:9090/v1/chat/completions", "model": "default", "maxTokens": 1024 }
169
+
170
+ // b) Claude CLI as the decider:
171
+ "decider": { "type": "command", "command": "claude", "args": ["-p"] }
172
+
173
+ // c) Codex CLI as the decider (note: `codex exec` does NOT accept `-a`):
174
+ "decider": { "type": "command", "command": "codex", "args": ["exec", "--skip-git-repo-check", "-s", "read-only"] }
175
+ ```
176
+
177
+ …or **per run, with no config file** — the `--decider*` flags build the same
178
+ override on the fly (great for `npx`):
179
+
180
+ ```bash
181
+ # local open model (api):
182
+ agent-relay run -a claude -p "..." \
183
+ --decider api --decider-url http://localhost:9090/v1/chat/completions \
184
+ --decider-model default --decider-max-tokens 1024
185
+
186
+ # an LLM CLI (command) — pass the WHOLE command line as one quoted string:
187
+ agent-relay run -a claude -p "..." \
188
+ --decider command --decider-command "codex exec --skip-git-repo-check -s read-only"
189
+
190
+ # force a simple policy:
191
+ agent-relay run -a codex -p "..." --decider always-approve
192
+ ```
193
+
194
+ The type is inferred when obvious (`--decider-url` ⇒ `api`, `--decider-command`
195
+ ⇒ `command`), so `--decider` itself is optional in those cases. A `--decider*`
196
+ flag **overrides** `config.decider` for that run; with no flag, the configured
197
+ (or default `rule`) decider is used. Complex command args with shell quoting
198
+ aren't supported on the flag — use a config file for those.
199
+
200
+ All four backends are verified. The task-aware policy is the important part:
201
+ given the task *"delete build/ and node_modules"*, an LLM decider **approves**
202
+ `rm -rf build node_modules` ("directly implements the task"); given the task
203
+ *"fix the README typo"*, it **denies** `rm -rf ~/Documents` ("dangerous and
204
+ off-task") with a redirect comment — the *same* command, opposite decisions.
205
+ The local model + rule deciders have also driven real Claude/Codex sessions
206
+ end-to-end. Embedders can plug any model via a `FunctionDecider`
207
+ (`async (request) => decision`) or the `onApprovalRequest` run-hook.
208
+
209
+ > A denial can carry a redirect `text`; agent-relay types it back to the agent
210
+ > when its TUI next asks "what should I do instead?" (best-effort, TUI-dependent).
211
+
212
+ > **Latency note:** the agent waits at its prompt while the decider thinks, so a
213
+ > slow decider (a large local model can take ~20 s/decision) is fine for menus
214
+ > the agent waits on, but raise `--idle-timeout-ms` for long sessions. The fast
215
+ > `rule` decider is the default for unattended runs.
216
+
217
+ > **Reasoning models:** the `api` decider's `maxTokens` (default **2048**) is a
218
+ > *cap*, not a target — a normal decision still costs only what it needs. But a
219
+ > reasoning model emits a long chain-of-thought before its JSON answer, so a
220
+ > too-small cap truncates it mid-thought (empty `content` → unparseable → safe
221
+ > deny). Keep `--decider-max-tokens` generous (≥1024) for such models; `content`
222
+ > is parsed first, with `reasoning_content` as a fallback.
223
+
224
+ ---
225
+
226
+ ## Commands
227
+
228
+ - **`init`** — write `agent-relay.config.json` + `.agent-relay/{sessions,logs}`.
229
+ - **`adapters`** — list adapters (`claude`, `codex`, `fake`), mode, resume support.
230
+ - **`doctor`** — Node version, config validity, dirs, and whether `claude`/`codex`
231
+ are on PATH (missing CLIs are warnings, never errors).
232
+ - **`run`** — options: `-a/--adapter`, `-p/--prompt`, `-f/--prompt-file`,
233
+ `--cwd`, `--max-turns`, `--timeout-ms`, `--idle-timeout-ms`,
234
+ `--completion-idle-ms`, `--approval <auto|gated|readonly>`, `--ultracode`,
235
+ `--decider*`, `--verbose`, `--max-log-bytes`, `--dry-run`, `--extra <args...>`,
236
+ `--root`. Exit code `0` on `completed`, non-zero otherwise. (`--approval gated`
237
+ keeps the agent asking so the decider answers more; `auto` is pure-autonomy.
238
+ `--ultracode` (Claude) forces Opus and drives `/effort ultracode` in the TUI
239
+ before the task — the full preset, unattended; plain `--effort xhigh` is the
240
+ default otherwise.)
241
+ - **`sessions`** — list recorded sessions with log sizes + total. Prune with
242
+ `sessions --prune --keep <n>` / `--older-than <days>` / `--all` (deletes the
243
+ session JSON **and** its log). Logs accumulate forever otherwise.
244
+ - **`resume`** — continue a prior session with a follow-up prompt:
245
+ `resume --session-id <id> -p "..."`. **Both verified end-to-end** (recall prior
246
+ context + run the follow-up): **Claude** via `--continue`; **Codex** via its
247
+ captured NATIVE session id — `codex resume <id> "<prompt>"` (the codex adapter
248
+ records the rollout UUID from `~/.codex/sessions/…` after each run into the
249
+ session's `sessionRef`; a legacy session with no captured id falls back to
250
+ `resume --last`).
251
+
252
+ ## Configuration
253
+
254
+ `agent-relay init` writes `agent-relay.config.json` (validated by a zod schema;
255
+ see [`agent-relay.config.example.json`](./agent-relay.config.example.json)):
256
+
257
+ ```jsonc
258
+ {
259
+ "defaultAdapter": "claude",
260
+ "sessionsDir": ".agent-relay/sessions",
261
+ "logsDir": ".agent-relay/logs",
262
+ "defaults": {
263
+ "maxTurns": 20, // max interactions (prompts answered) before aborting
264
+ "timeoutMs": 1800000, // hard wall-clock cap
265
+ "idleTimeoutMs": 300000, // abort if no event for this long
266
+ "approvalPolicy": "auto", // "readonly" => sandbox the agent; otherwise it asks and the decider answers
267
+ "sandbox": "workspace-write"
268
+ },
269
+ "decider": { "type": "rule" },
270
+ "hooks": { "onComplete": "echo \"[$AGENT_RELAY_STATUS] $AGENT_RELAY_SESSION_ID\"" },
271
+ "adapters": {
272
+ "claude": { "type": "claude", "mode": "pty", "command": "claude", "args": [] },
273
+ "codex": { "type": "codex", "mode": "pty", "command": "codex", "args": [] },
274
+ "fake": { "type": "fake", "mode": "test" }
275
+ }
276
+ }
277
+ ```
278
+
279
+ - **`decider`** decides every prompt — this is the real approval mechanism (see
280
+ **The Decider**). `approvalPolicy` no longer "approves"; it only selects
281
+ `readonly` (Codex `-s read-only`, Claude `--permission-mode plan`) vs. letting
282
+ the agent ask normally.
283
+ - `adapters.<name>.args` are passed straight through to the underlying CLI
284
+ (after the adapter's own flags, before the prompt) — e.g.
285
+ `adapters.claude.args: ["--effort", "max"]` to set Claude's effort level
286
+ (`low|medium|high|xhigh|max`), or `["--model", "opus"]`. The same flags can be
287
+ set per-run with `--extra` (e.g. `run -a claude -p "..." --extra --effort max`).
288
+ `adapters.<name>.env` injects/overrides spawn env vars — the Claude adapter sets
289
+ `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` by default (override with
290
+ `adapters.claude.env: { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "0" }`).
291
+ - `defaults.completionIdleMs` (or `--completion-idle-ms`) tunes how long the
292
+ finished agent must stay quiet before its TUI is quit (default 8s).
293
+ - For a fully autonomous, no-prompt agent (no decider involvement), set
294
+ `adapters.claude.args: ["--dangerously-skip-permissions"]` /
295
+ `adapters.codex.args: ["--full-auto"]`.
296
+ - **`hooks`** are shell commands run at lifecycle points with `AGENT_RELAY_*`
297
+ env vars (`SESSION_ID`, `STATUS`, `ADAPTER`, `LOG_FILE`, `EXIT_CODE`, `CWD`).
298
+
299
+ > ⚠️ **Safety:** the default `rule` decider **approves everything** so the task
300
+ > can progress (danger-regex blocking is opt-in via `denyPatterns`, and is
301
+ > unreliable on mangled TUI text anyway). For real control, use `approvalPolicy:
302
+ > "readonly"` (sandbox), or an LLM `command`/`api` decider that approves on-task
303
+ > work and denies off-task danger. Don't point an auto-approving run at an
304
+ > untrusted task.
305
+
306
+ ## Sessions, logs, completion
307
+
308
+ - `.agent-relay/sessions/<id>.json` — metadata (prompt, adapter, status, times,
309
+ logFile, exitCode, error, meta). Tiny; list/prune with `agent-relay sessions`.
310
+ - `.agent-relay/logs/<id>.log` — header + one line per event + footer. By default
311
+ the **raw stdout/stderr stream is omitted** (a TUI redraws constantly — it's
312
+ ~98% noise), so a run logs only its meaningful events and stays ~1 KB. Use
313
+ `--verbose` for the full stream when debugging, and `--max-log-bytes` to cap it.
314
+ - Status lifecycle: `created → running → { completed | failed | timeout |
315
+ cancelled | waiting_approval }`. The `CompletionDetector` maps the run to a
316
+ terminal status (timeout/idle → `timeout`, cancel → `cancelled`, success/exit
317
+ 0 → `completed`, else `failed`) and is extensible.
318
+
319
+ ## Architecture
320
+
321
+ ```
322
+ src/core/ types · config(zod) · session · logger · completion · decider ·
323
+ hooks · runner · errors · util/{ansi,line-splitter,which,...}
324
+ src/adapters/ registry · fake-adapter ·
325
+ interactive/ pty-session (the detect→decide→respond loop) · prompt-detector ·
326
+ interactive-adapter · claude-interactive · codex-interactive
327
+ src/commands/ init · adapters · doctor · run · resume
328
+ src/cli.ts commander CLI src/index.ts programmatic API
329
+ ```
330
+
331
+ **Decoupling rule:** `core/` depends only on the `AgentAdapter` interface and
332
+ receives an adapter factory from `adapters/registry.ts`; it never imports a
333
+ vendor adapter. The `Decider` reaches adapters via the run context, so any
334
+ decision backend works with any agent.
335
+
336
+ ```ts
337
+ import { runAgent, createAdapterFactory, RuleDecider } from "agent-relay";
338
+ const outcome = await runAgent({
339
+ config, rootDir: process.cwd(), adapterName: "codex",
340
+ prompt: "Fix the failing test",
341
+ resolveAdapter: createAdapterFactory(),
342
+ decider: new RuleDecider(), // or a CommandDecider / FunctionDecider
343
+ });
344
+ ```
345
+
346
+ ## Testing
347
+
348
+ ```bash
349
+ pnpm typecheck
350
+ pnpm test # 100+ offline, deterministic tests
351
+ ```
352
+
353
+ The default suite is fully offline. Its centerpiece is a **real PTY test**: a
354
+ deterministic fake interactive agent (`tests/fixtures/fake-interactive.cjs`) is
355
+ driven through `runPtySession` and the Decider answers its approval + menu
356
+ prompts — proving the detect → decide → respond → complete loop, plus deny and
357
+ abort paths. A second fixture (`fake-interactive-wizard.cjs`, `tests/wizard.test.ts`)
358
+ drives a **multi-step** flow — menu → menu → free-text input → `[y/n]` submit —
359
+ and asserts each step is detected on its own fresh screen (the per-step buffer
360
+ reset), that a non-sequentially-numbered menu maps to the right keystroke, and
361
+ that the submitted artifact reflects the exact navigated choices. It also covers
362
+ the decider, prompt detector, ANSI cleanup, config, sessions, hooks, completion,
363
+ safety rails, and the commands.
364
+
365
+ ### Real Claude/Codex integration (opt-in)
366
+
367
+ ```bash
368
+ AGENT_RELAY_RUN_REAL_AGENT_TESTS=1 pnpm test
369
+ ```
370
+
371
+ Skipped by default; each adapter self-skips when its CLI is absent; runs in a
372
+ temp dir with a trivial file-creation prompt. **Both Codex and Claude are
373
+ verified** end-to-end: agent-relay drives the real TUI, the rule decider answers
374
+ the trust/permission prompts, and the agent creates the file.
375
+
376
+ ## Remaining TODO / future work
377
+
378
+ - **Structured-interactive backends**: Claude `--input-format stream-json` +
379
+ permission callbacks and Codex `app-server`/`mcp-server` would be more robust
380
+ than PTY scraping for those agents (the "structured-first" path). PTY is the
381
+ universal driver today.
382
+ - **Richer prompt detection / per-agent keymaps** as TUIs evolve.
383
+ - **Native session-id capture in PTY mode** — resume is wired via `--continue` /
384
+ `resume --last` (most-recent in cwd); capturing the real id would allow
385
+ resuming a *specific* older session.
386
+ - Add a `repository` URL to `package.json` before publishing.
387
+
388
+ ## Working in this repo
389
+
390
+ See [`CLAUDE.md`](./CLAUDE.md). `.claude/settings.json` ships a Stop hook that
391
+ runs `pnpm typecheck` and blocks finishing on type errors.
392
+
393
+ ## License
394
+
395
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,38 @@
1
+ {
2
+ "defaultAdapter": "claude",
3
+ "sessionsDir": ".agent-relay/sessions",
4
+ "logsDir": ".agent-relay/logs",
5
+ "defaults": {
6
+ "maxTurns": 20,
7
+ "timeoutMs": 1800000,
8
+ "idleTimeoutMs": 300000,
9
+ "approvalPolicy": "auto",
10
+ "sandbox": "workspace-write",
11
+ "requireApprovalOnRiskyActions": false
12
+ },
13
+ "adapters": {
14
+ "claude": {
15
+ "type": "claude",
16
+ "mode": "pty",
17
+ "command": "claude",
18
+ "args": []
19
+ },
20
+ "codex": {
21
+ "type": "codex",
22
+ "mode": "pty",
23
+ "command": "codex",
24
+ "args": []
25
+ },
26
+ "fake": {
27
+ "type": "fake",
28
+ "mode": "test",
29
+ "args": []
30
+ }
31
+ },
32
+ "decider": {
33
+ "type": "rule"
34
+ },
35
+ "hooks": {
36
+ "onComplete": "echo \"[$AGENT_RELAY_STATUS] $AGENT_RELAY_SESSION_ID\""
37
+ }
38
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node