s-app-scoder-agent 0.0.0-stage → 0.4.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/LICENSE +21 -0
- package/README.md +368 -2
- package/dist/agent.js +501 -0
- package/dist/build.js +41 -0
- package/dist/config.js +117 -0
- package/dist/constants.js +69 -0
- package/dist/context.js +44 -0
- package/dist/cost.js +141 -0
- package/dist/diff.js +156 -0
- package/dist/index.js +314 -0
- package/dist/llm.js +276 -0
- package/dist/logger.js +78 -0
- package/dist/mcp.js +189 -0
- package/dist/permissions.js +298 -0
- package/dist/provider-anthropic.js +332 -0
- package/dist/retry.js +53 -0
- package/dist/session.js +143 -0
- package/dist/tools.js +361 -0
- package/dist/ui.js +96 -0
- package/dist/version.js +18 -0
- package/package.json +51 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sơn Nguyễn
|
|
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
CHANGED
|
@@ -1,3 +1,369 @@
|
|
|
1
|
-
#
|
|
1
|
+
# scoder — Autonomous Coding Agent CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/nbhson/app-scoder-agent/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/app-scoder-agent)
|
|
6
|
+
|
|
7
|
+
**scoder** is a command-line coding agent that autonomously writes, edits, and builds code until your project compiles without errors. It mirrors the workflow of opencode, cline, and Claude Code, but runs as a single standalone CLI tool.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
**Requirements:** Node.js ≥ 18
|
|
12
|
+
|
|
13
|
+
### Install from GitHub (current method)
|
|
14
|
+
|
|
15
|
+
The package is not yet on the npm registry — install straight from this repo:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Clones, builds (via the prepare script), and installs the `scoder` command globally
|
|
19
|
+
npm install -g github:nbhson/app-scoder-agent
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or manually from a local clone:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git clone https://github.com/nbhson/app-scoder-agent.git
|
|
26
|
+
cd app-scoder-agent
|
|
27
|
+
npm install
|
|
28
|
+
npm run build
|
|
29
|
+
npm install -g . # or: npm link
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> Upgrading: pull the latest code and re-run `npm install -g .` (or point the global install at the repo again).
|
|
33
|
+
|
|
34
|
+
### Try without installing
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx github:nbhson/app-scoder-agent "your task here"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### From npm (planned)
|
|
41
|
+
|
|
42
|
+
Once published to the npm registry, installation will be a one-liner:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install -g app-scoder-agent
|
|
46
|
+
# or run ad-hoc:
|
|
47
|
+
npx app-scoder-agent "your task"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Set your API key
|
|
54
|
+
export SCODER_API_KEY=sk-... # any OpenAI-compatible key (OpenAI, Groq, OpenRouter, Ollama, …)
|
|
55
|
+
export OPENAI_BASE_URL=https://api.openai.com/v1 # optional, for custom endpoints
|
|
56
|
+
|
|
57
|
+
# Run a task
|
|
58
|
+
scoder "add a ping function to src/network.ts"
|
|
59
|
+
|
|
60
|
+
# Interactive REPL
|
|
61
|
+
scoder
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## How It Works
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
You (task) → LLM plans → Tools execute code → Build runs → Success? → Done
|
|
68
|
+
↑ |
|
|
69
|
+
└── Build failed? ─┘ (auto-loop)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Key constraint:** scoder runs autonomously without stopping for confirmation prompts. If the build fails, it reads the error, patches the code, and retries automatically — until the build passes or the max-step limit is reached.
|
|
73
|
+
|
|
74
|
+
## Tool Set
|
|
75
|
+
|
|
76
|
+
| Tool | Description |
|
|
77
|
+
|------|-------------|
|
|
78
|
+
| `read_file` | Read a file with line numbers |
|
|
79
|
+
| `write_file` | Overwrite/create a file |
|
|
80
|
+
| `edit_file` | Find-and-replace (unique match required) |
|
|
81
|
+
| `list_files` | Recursive directory listing |
|
|
82
|
+
| `run_command` | Execute any shell command (subject to permission policy) |
|
|
83
|
+
|
|
84
|
+
File writes (`write_file` / `edit_file`) are symlink-safe: paths are resolved via `realpath` and cannot escape the working directory, even through a malicious symlink. `read_file` refuses files larger than 2MB with guidance to use `grep`/`head`/`tail`.
|
|
85
|
+
|
|
86
|
+
## Configuration
|
|
87
|
+
|
|
88
|
+
### Environment variables
|
|
89
|
+
|
|
90
|
+
| Variable | Default | Description |
|
|
91
|
+
|----------|---------|-------------|
|
|
92
|
+
| `SCODER_API_KEY` | — | API key (required) |
|
|
93
|
+
| `SCODER_MODEL` | `gpt-4o-mini` | Model name |
|
|
94
|
+
| `SCODER_BASE_URL` | `https://api.openai.com/v1` | OpenAI-compatible endpoint |
|
|
95
|
+
| `SCODER_BUILD_CMD` | auto-detected | Build/compile command |
|
|
96
|
+
| `SCODER_MAX_STEPS` | `40` | Max loop iterations before giving up |
|
|
97
|
+
| `SCODER_PERMISSION` | `auto` | Permission mode: `auto` \| `ask` \| `readonly` |
|
|
98
|
+
| `SCODER_STREAM` | `1` | `0` to disable streaming LLM output |
|
|
99
|
+
| `SCODER_NO_APIKEY_WARNING` | — | Set to `1` to suppress the apiKey-in-rc warning |
|
|
100
|
+
|
|
101
|
+
### Per-project config file (.scoderrc.json)
|
|
102
|
+
|
|
103
|
+
For any OpenAI-compatible endpoint, just point `baseUrl`, `apiKey`, and `model` at it — no code changes needed. Create `.scoderrc.json` in your project root (see `.scoderrc.example.json`):
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"baseUrl": "https://api.groq.com/openai/v1",
|
|
108
|
+
"apiKey": "gsk_...",
|
|
109
|
+
"model": "llama-3.3-70b-versatile"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Then simply run `scoder "your task"` — values are picked up automatically.
|
|
114
|
+
|
|
115
|
+
#### All fields
|
|
116
|
+
|
|
117
|
+
| Field | Default | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `baseUrl` | `https://api.openai.com/v1` | OpenAI-compatible endpoint (must support `/chat/completions` with tool calling) |
|
|
120
|
+
| `apiKey` | — | API key (⚠️ prefer `SCODER_API_KEY` env var, see warning below) |
|
|
121
|
+
| `model` | `gpt-4o-mini` | Model name served by the endpoint |
|
|
122
|
+
| `buildCmd` | auto-detected | Build/compile command (stop condition) |
|
|
123
|
+
| `maxSteps` | `40` | Max autonomous loop iterations |
|
|
124
|
+
| `stream` | `true` | Stream LLM output token-by-token |
|
|
125
|
+
| `provider` | auto-detected | `openai` \| `anthropic` |
|
|
126
|
+
| `permission` | `auto` | `auto` \| `ask` \| `readonly` |
|
|
127
|
+
| `mcpServers` | — | MCP stdio servers (see below) |
|
|
128
|
+
| `permissions` | — | `{ mode, allowCommands, denyCommands }` |
|
|
129
|
+
|
|
130
|
+
#### Precedence
|
|
131
|
+
|
|
132
|
+
Values are merged from highest to lowest priority — your `.scoderrc.json` value only applies when no flag/env is set:
|
|
133
|
+
|
|
134
|
+
1. **CLI flags** — `-m`, `--base-url`, `-k`, `--provider`, `-B`
|
|
135
|
+
2. **Environment variables** — `SCODER_API_KEY` / `OPENAI_API_KEY`, `SCODER_BASE_URL`, `SCODER_MODEL`, …
|
|
136
|
+
3. **`.scoderrc.json`** (or `.scoderrc`) in the project root — project-local only; there is no global rc file. For a machine-wide default, set the `SCODER_*` env vars in your shell profile instead
|
|
137
|
+
4. Built-in defaults
|
|
138
|
+
|
|
139
|
+
> 💡 If your config in `.scoderrc.json` seems ignored, check `echo $SCODER_API_KEY` — env vars override the file.
|
|
140
|
+
|
|
141
|
+
#### Examples for common providers
|
|
142
|
+
|
|
143
|
+
```jsonc
|
|
144
|
+
// Local Ollama
|
|
145
|
+
{
|
|
146
|
+
"baseUrl": "http://localhost:11434/v1",
|
|
147
|
+
"apiKey": "ollama",
|
|
148
|
+
"model": "qwen2.5-scoder:32b"
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```jsonc
|
|
153
|
+
// DeepSeek
|
|
154
|
+
{
|
|
155
|
+
"baseUrl": "https://api.deepseek.com/v1",
|
|
156
|
+
"apiKey": "sk-...",
|
|
157
|
+
"model": "deepseek-chat"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Notes
|
|
162
|
+
|
|
163
|
+
- Models starting with `claude-`, or a `baseUrl` containing `api.anthropic.com`, automatically switch to the native Anthropic provider — no `provider` field needed.
|
|
164
|
+
- If an `apiKey` is present in the rc file, scoder prints a warning on every run. Silence it with `SCODER_NO_APIKEY_WARNING=1`.
|
|
165
|
+
|
|
166
|
+
> ⚠️ **Security:** never commit `apiKey` in `.scoderrc.json` — add the file to `.gitignore` and prefer `SCODER_API_KEY` env var or the `-k` flag. A pre-commit check is available at `scripts/check-secrets.mjs`.
|
|
167
|
+
|
|
168
|
+
## Permissions & Safety
|
|
169
|
+
|
|
170
|
+
scoder ships with a layered permission system for `run_command`:
|
|
171
|
+
|
|
172
|
+
| Mode | Behavior |
|
|
173
|
+
|------|----------|
|
|
174
|
+
| `auto` (default) | Autonomous — runs shell commands without confirmation (original behavior) |
|
|
175
|
+
| `ask` | Prompts before each shell command not covered by `allowCommands` |
|
|
176
|
+
| `readonly` | Shell commands are disabled entirely; the agent can only read/list files. MCP tools are also disabled (they bypass the permission policy) |
|
|
177
|
+
|
|
178
|
+
Layered checks, in order:
|
|
179
|
+
|
|
180
|
+
1. **Catastrophic deny list** — `rm -rf /`, `dd of=/dev/...`, fork bombs, `curl | sh`, etc. are **always denied**, in every mode.
|
|
181
|
+
2. **`denyCommands`** (config) — always denied.
|
|
182
|
+
3. **Session allowlist** — commands you approved with `[a] always allow` in this session.
|
|
183
|
+
4. **`allowCommands`** (config) — auto-approved.
|
|
184
|
+
5. **Mode** — `auto` runs everything else; `ask` prompts; `readonly` denies.
|
|
185
|
+
|
|
186
|
+
In `ask` mode the prompt offers `[y] yes / [a] always allow "<prefix>" / [n] no / [q] quit`. With `-y` (non-interactive), commands needing confirmation are denied instead of hanging CI.
|
|
187
|
+
|
|
188
|
+
## MCP Servers (stdio)
|
|
189
|
+
|
|
190
|
+
scoder can use tools from [MCP](https://modelcontextprotocol.io) servers configured in `.scoderrc.json`:
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"mcpServers": {
|
|
195
|
+
"filesystem": {
|
|
196
|
+
"command": "npx",
|
|
197
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
198
|
+
},
|
|
199
|
+
"github": {
|
|
200
|
+
"command": "npx",
|
|
201
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
202
|
+
"env": { "GITHUB_TOKEN": "{env:GITHUB_TOKEN}" }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- Tools are exposed to the LLM as `mcp__<server>__<tool>` (no name collisions with built-ins)
|
|
209
|
+
- Servers connect at agent start; a failing server only logs a warning — the agent keeps running with its built-in tools
|
|
210
|
+
- `{env:VAR}` substitution keeps secrets out of config files
|
|
211
|
+
- Built-in tools always take priority over MCP tools with colliding names
|
|
212
|
+
- ⚠️ **MCP tools bypass the built-in permission system** (no command classification, no diff preview). In `readonly` mode they are therefore disabled entirely; in `auto`/`ask` mode they run unsandboxed — only add MCP servers you trust.
|
|
213
|
+
|
|
214
|
+
## Sessions
|
|
215
|
+
|
|
216
|
+
Every run auto-saves its state (messages, steps, build result) to `.scoder/sessions/<id>.json` after each step. If the run is interrupted (Ctrl+C, crash, max steps), you can continue where it left off:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
scoder list # list saved sessions
|
|
220
|
+
scoder resume last # continue the most recent session
|
|
221
|
+
scoder resume <id> "follow-up" # resume + add a new instruction
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Sessions older than 7 days are pruned automatically on the next run. Use `--no-save` to disable (e.g. in CI).
|
|
225
|
+
|
|
226
|
+
## Streaming
|
|
227
|
+
|
|
228
|
+
LLM output is streamed token-by-token by default (`SCODER_STREAM=0` to disable). If a provider doesn't support streaming, scoder automatically falls back to non-streaming requests.
|
|
229
|
+
|
|
230
|
+
## Logging
|
|
231
|
+
|
|
232
|
+
Enable a structured JSONL event log with `--log-file` (or `SCODER_LOG_FILE=1`, or `SCODER_LOG_FILE=/path/to/log.jsonl`):
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
scoder --log-file "fix the failing test"
|
|
236
|
+
cat .scoder/logs/<session-id>.jsonl | jq 'select(.type == "error")'
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Events: `step` (with token usage), `tool` (args, ok, elapsedMs, denied reason), `build`, `finish`. One JSON object per line — pipe to `jq` or any log consumer.
|
|
240
|
+
|
|
241
|
+
## Reliability
|
|
242
|
+
|
|
243
|
+
scoder is designed for unattended use. Key guarantees:
|
|
244
|
+
|
|
245
|
+
- **Request timeouts** — LLM calls have a 120s timeout; on timeout, the agent retries or fails gracefully (never hangs indefinitely).
|
|
246
|
+
- **SIGINT handling** — pressing Ctrl+C cancels the in-flight LLM request immediately, kills the running shell command (SIGTERM → SIGKILL), saves the session, and exits with status 130. You can resume with `scoder resume last`.
|
|
247
|
+
- **Graceful retries** — transient LLM API failures (HTTP 429/5xx, network errors) are retried with exponential backoff and jitter (up to 3 retries, honoring `Retry-After`). Client errors (401/403/404) fail fast.
|
|
248
|
+
- **Double-build prevention** — when the agent itself runs the build command, scoder reuses that result instead of running the build twice.
|
|
249
|
+
- **Build diff preview** — run `scoder --permission ask` to see a unified diff before every file write/edit.
|
|
250
|
+
|
|
251
|
+
> **Design note:** the build command (stop condition) always runs without a permission prompt, even in `readonly` mode — the agent must be able to verify its stop condition. Builds are invoked as-is from your config (`buildCmd`) or auto-detection, never invented by the LLM. Shell commands *chosen by the LLM* (`run_command` tool) go through the full permission policy above.
|
|
252
|
+
|
|
253
|
+
### Auto-detected build commands
|
|
254
|
+
|
|
255
|
+
scoder detects the build command automatically:
|
|
256
|
+
|
|
257
|
+
| Project type | Detected command |
|
|
258
|
+
|---|---|
|
|
259
|
+
| `package.json` with `scripts.build` | `npm run build` |
|
|
260
|
+
| `Makefile` | `make` |
|
|
261
|
+
| `go.mod` | `go build ./...` |
|
|
262
|
+
| `Cargo.toml` | `cargo build` |
|
|
263
|
+
| `tsconfig.json` | `npx tsc --noEmit` |
|
|
264
|
+
| `pyproject.toml` | `python -m compileall .` |
|
|
265
|
+
|
|
266
|
+
## CLI Options
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
scoder [options] "<task>" Run a task autonomously until the build passes
|
|
270
|
+
scoder Start interactive session
|
|
271
|
+
scoder --help | --version Help and version
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
| Flag | Description |
|
|
275
|
+
|------|-------------|
|
|
276
|
+
| `-m <model>` | Model to use |
|
|
277
|
+
| `--base-url <url>` | OpenAI-compatible API base URL |
|
|
278
|
+
| `-k <key>` | API key |
|
|
279
|
+
| `-B, --build <cmd>` | Build command (stop condition) |
|
|
280
|
+
| `-d, --dir <path>` | Working directory |
|
|
281
|
+
| `-s, --max-steps <n>` | Max iterations (default 40) |
|
|
282
|
+
| `--permission <mode>` | `auto` \| `ask` \| `readonly` shell-command policy (default `auto`) |
|
|
283
|
+
| `-y` | Non-interactive mode (denies commands needing confirmation) |
|
|
284
|
+
| `--provider <name>` | `openai` \| `anthropic` (env SCODER_PROVIDER; auto-detected) |
|
|
285
|
+
| `--no-save` | Disable session auto-save to `.scoder/sessions/` |
|
|
286
|
+
|
|
287
|
+
## Examples
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# Run a task (auto-saves session to .scoder/sessions/)
|
|
291
|
+
scoder -B "npm test" "fix the null pointer in UserService"
|
|
292
|
+
|
|
293
|
+
# Resume after a crash or interrupt
|
|
294
|
+
scoder resume last "now add unit tests for the fix"
|
|
295
|
+
|
|
296
|
+
# Interactive mode with permission guard
|
|
297
|
+
scoder --permission ask "npm install express and wire up a route"
|
|
298
|
+
|
|
299
|
+
# Custom LLM (Groq, Ollama, vLLM, OpenRouter…)
|
|
300
|
+
scoder --base-url https://api.groq.com/openai/v1 -k $GROQ_KEY \
|
|
301
|
+
"add input validation to the CLI"
|
|
302
|
+
|
|
303
|
+
# Anthropic (auto-detected when model starts with 'claude-')
|
|
304
|
+
scoder -m claude-sonnet-4-5 "refactor the parser module"
|
|
305
|
+
|
|
306
|
+
# CI: non-interactive, no session saving
|
|
307
|
+
scoder --no-save -y "run the full migration"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Architecture
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
┌─────────────────────────────────────────────┐
|
|
314
|
+
│ CLI (src/index.ts) │
|
|
315
|
+
│ arg parsing, REPL, SIGINT handling │
|
|
316
|
+
└─────────────────┬───────────────────────────┘
|
|
317
|
+
│
|
|
318
|
+
┌─────────────────▼───────────────────────────┐
|
|
319
|
+
│ Agent (src/agent.ts) │
|
|
320
|
+
│ Closed-loop orchestrator │
|
|
321
|
+
│ history trimming, error injection │
|
|
322
|
+
└───────┬───────────────────────┬─────────────┘
|
|
323
|
+
│ │
|
|
324
|
+
┌───────▼───────┐ ┌─────────▼──────────┐
|
|
325
|
+
│ LLM Client │ │ Tool Registry │
|
|
326
|
+
│ (src/llm.ts) │ │ (src/tools.ts) │
|
|
327
|
+
│ OpenAI compat │ │ read/write/run/list │
|
|
328
|
+
└───────────────┘ └──────────────────────┘
|
|
329
|
+
│
|
|
330
|
+
▼
|
|
331
|
+
┌─────────────────────────────────────────────┐
|
|
332
|
+
│ Build Checker (src/build.ts) │
|
|
333
|
+
│ run build → exit 0 = stop condition met │
|
|
334
|
+
└─────────────────────────────────────────────┘
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Integration Testing
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
npm test # runs: lint → typecheck → build → 116 unit tests + e2e + MCP smoke
|
|
341
|
+
npm run lint # eslint flat config (typescript-eslint + eqeqeq, prefer-const...)
|
|
342
|
+
npm run typecheck # tsc --noEmit
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Test suites (run with `npm test` — auto-discovers `test/*.test.mjs`):
|
|
346
|
+
- `test/permissions.test.mjs` — catastrophic patterns, mode classification, allowlist word-boundary, timeout-denies
|
|
347
|
+
- `test/permission-prompt.test.mjs` — interactive prompt timeout behavior
|
|
348
|
+
- `test/tools.test.mjs` — safePath traversal, symlink escape, file-size cap, write/edit/list
|
|
349
|
+
- `test/core.test.mjs` — unified diff, retry backoff, context trimming
|
|
350
|
+
- `test/config.test.mjs` — env/rc/cli precedence, logFile mapping, permission lists
|
|
351
|
+
- `test/session.test.mjs` — session store, smart prune, resolve
|
|
352
|
+
- `test/anthropic.test.mjs` — message translation + native SSE streaming
|
|
353
|
+
- `test/llm.test.mjs` — OpenAI-compatible chat + SSE streaming + redaction
|
|
354
|
+
- `test/run-e2e.mjs` — closed-loop integration (mock LLM server)
|
|
355
|
+
- `test/run-mcp-test.mjs` — MCP smoke (mock stdio server)
|
|
356
|
+
|
|
357
|
+
Coverage (lines): **90.3%** overall — see `npm run coverage`.
|
|
358
|
+
|
|
359
|
+
## Exit Codes
|
|
360
|
+
|
|
361
|
+
| Code | Meaning |
|
|
362
|
+
|------|---------|
|
|
363
|
+
| `0` | Task completed — build passed |
|
|
364
|
+
| `1` | Build failed after max steps |
|
|
365
|
+
| `2` | Fatal error (no API key, network error, etc.) |
|
|
366
|
+
|
|
367
|
+
## License
|
|
368
|
+
|
|
369
|
+
MIT
|