{"_id":"s-app-scoder-agent","_rev":"2-075f23d07041de599c19696ed369cbae","name":"s-app-scoder-agent","dist-tags":{"latest":"0.3.0"},"versions":{"0.0.0-stage":{"name":"s-app-scoder-agent","version":"0.0.0-stage","_id":"s-app-scoder-agent@0.0.0-stage","stub":true,"maintainers":[{"name":"nbhson43","email":"nbhson43@gmail.com"}],"dist":{"shasum":"baa1e046ca4a44e53db6b24cdcc423ee22134d88","tarball":"https://registry.npmjs.org/s-app-scoder-agent/-/s-app-scoder-agent-0.0.0-stage.tgz","fileCount":2,"integrity":"sha512-aQj8JcxgkKNKjNo8L3lhW4helK3kFypPWY5wTRxN5Lgux4BObVIuVFFNGLATBLD4S7P9l/z948fApfq1dtkcHw==","signatures":[{"sig":"MEUCIGYx2dEEBWeKrgmJLastTxvLckdAo7mm+3LRv7DUWO+pAiEAhpr7IvZ/wmyirHLv1OPQPoy+90A3xWY2puz+44l/xbg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":340},"_npmUser":{"name":"nbhson43","email":"nbhson43@gmail.com"},"description":"Temporary package placeholder for staged publishing","directories":{}},"0.3.0":{"_id":"s-app-scoder-agent@0.3.0","bin":{"scoder":"dist/index.js"},"bugs":{"url":"https://github.com/nbhson/app-scoder-agent/issues"},"dist":{"shasum":"8b128e24f4f1bb0478fb10b3abd114120599134a","tarball":"https://registry.npmjs.org/s-app-scoder-agent/-/s-app-scoder-agent-0.3.0.tgz","fileCount":19,"integrity":"sha512-hlFxwG3fcYvTZoXGNdlcgoCmQfCDorx6bBQpn3GqX1K6Bim4PIeh1yFWMrrwot5FYayZM4Gq8DaHtAJ+IIT4ng==","signatures":[{"sig":"MEUCID90JiIShq9BZ5cFDus6e1OotwuKnv628Dp9jyTTDzKfAiEA8uLU9QDeSribePizOiOTxmiJ0Fv1nVi+q8ZOyRQtVDM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCWAByVAu5VJL07jlWDFkQhzmNJvoXWEkdIUR0EyScgggIgNFw3BhzZJqRiHa9F4o3U6+1HTA8QUfSyswmFaaCF3qg="}],"unpackedSize":133623},"main":"dist/index.js","name":"s-app-scoder-agent","type":"module","engines":{"node":">=18"},"license":"MIT","scripts":{"dev":"tsc --watch","lint":"eslint src/","test":"npm run build && node --test test/*.test.mjs && node test/run-e2e.mjs && node test/run-mcp-test.mjs","build":"tsc","start":"node dist/index.js","coverage":"npm run build && node --test --experimental-test-coverage test/*.test.mjs","typecheck":"tsc --noEmit"},"version":"0.3.0","_npmUser":{"name":"nbhson43","email":"nbhson43@gmail.com"},"homepage":"https://github.com/nbhson/app-scoder-agent#readme","keywords":["cli","agent","ai","coding-agent","llm"],"repository":{"url":"git+https://github.com/nbhson/app-scoder-agent.git","type":"git"},"_npmVersion":"10.9.9","description":"Autonomous coding agent CLI - similar to opencode/cline/claude. Runs tasks until build succeeds.","directories":{},"maintainers":[{"name":"nbhson43","email":"nbhson43@gmail.com"}],"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.13.0","@eslint/js":"^10.0.1","typescript":"^5.6.0","@types/node":"^22.0.0","typescript-eslint":"^8.72.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/s-app-scoder-agent_0.3.0_1793210119110_0.9286346315491988"}}},"time":{"created":"2026-10-28T17:52:10.854Z","modified":"2026-10-28T17:55:19.325Z","0.0.0-stage":"2026-10-28T17:52:10.854Z","0.3.0":"2026-10-28T17:55:19.201Z"},"description":"Autonomous coding agent CLI - similar to opencode/cline/claude. Runs tasks until build succeeds.","maintainers":[{"name":"nbhson43","email":"nbhson43@gmail.com"}],"readme":"# scoder — Autonomous Coding Agent CLI\n\n[![CI](https://github.com/nbhson/app-scoder-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/nbhson/app-scoder-agent/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![node](https://img.shields.io/node/v/app-scoder-agent)](https://www.npmjs.com/package/app-scoder-agent)\n\n**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.\n\n## Installation\n\n**Requirements:** Node.js ≥ 18\n\n### Install from GitHub (current method)\n\nThe package is not yet on the npm registry — install straight from this repo:\n\n```bash\n# Clones, builds (via the prepare script), and installs the `scoder` command globally\nnpm install -g github:nbhson/app-scoder-agent\n```\n\nOr manually from a local clone:\n\n```bash\ngit clone https://github.com/nbhson/app-scoder-agent.git\ncd app-scoder-agent\nnpm install\nnpm run build\nnpm install -g .        # or: npm link\n```\n\n> Upgrading: pull the latest code and re-run `npm install -g .` (or point the global install at the repo again).\n\n### Try without installing\n\n```bash\nnpx github:nbhson/app-scoder-agent \"your task here\"\n```\n\n### From npm (planned)\n\nOnce published to the npm registry, installation will be a one-liner:\n\n```bash\nnpm install -g app-scoder-agent\n# or run ad-hoc:\nnpx app-scoder-agent \"your task\"\n```\n\n## Quick Start\n\n```bash\n# Set your API key\nexport SCODER_API_KEY=sk-...          # any OpenAI-compatible key (OpenAI, Groq, OpenRouter, Ollama, …)\nexport OPENAI_BASE_URL=https://api.openai.com/v1  # optional, for custom endpoints\n\n# Run a task\nscoder \"add a ping function to src/network.ts\"\n\n# Interactive REPL\nscoder\n```\n\n## How It Works\n\n```\nYou (task) → LLM plans → Tools execute code → Build runs → Success? → Done\n                              ↑                  |\n                              └── Build failed? ─┘ (auto-loop)\n```\n\n**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.\n\n## Tool Set\n\n| Tool | Description |\n|------|-------------|\n| `read_file` | Read a file with line numbers |\n| `write_file` | Overwrite/create a file |\n| `edit_file` | Find-and-replace (unique match required) |\n| `list_files` | Recursive directory listing |\n| `run_command` | Execute any shell command (subject to permission policy) |\n\nFile 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`.\n\n## Configuration\n\n### Environment variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `SCODER_API_KEY` | — | API key (required) |\n| `SCODER_MODEL` | `gpt-4o-mini` | Model name |\n| `SCODER_BASE_URL` | `https://api.openai.com/v1` | OpenAI-compatible endpoint |\n| `SCODER_BUILD_CMD` | auto-detected | Build/compile command |\n| `SCODER_MAX_STEPS` | `40` | Max loop iterations before giving up |\n| `SCODER_PERMISSION` | `auto` | Permission mode: `auto` \\| `ask` \\| `readonly` |\n| `SCODER_STREAM` | `1` | `0` to disable streaming LLM output |\n| `SCODER_NO_APIKEY_WARNING` | — | Set to `1` to suppress the apiKey-in-rc warning |\n\n### Per-project config file (.scoderrc.json)\n\nFor 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`):\n\n```json\n{\n  \"baseUrl\": \"https://api.groq.com/openai/v1\",\n  \"apiKey\": \"gsk_...\",\n  \"model\": \"llama-3.3-70b-versatile\"\n}\n```\n\nThen simply run `scoder \"your task\"` — values are picked up automatically.\n\n#### All fields\n\n| Field | Default | Description |\n|---|---|---|\n| `baseUrl` | `https://api.openai.com/v1` | OpenAI-compatible endpoint (must support `/chat/completions` with tool calling) |\n| `apiKey` | — | API key (⚠️ prefer `SCODER_API_KEY` env var, see warning below) |\n| `model` | `gpt-4o-mini` | Model name served by the endpoint |\n| `buildCmd` | auto-detected | Build/compile command (stop condition) |\n| `maxSteps` | `40` | Max autonomous loop iterations |\n| `stream` | `true` | Stream LLM output token-by-token |\n| `provider` | auto-detected | `openai` \\| `anthropic` |\n| `permission` | `auto` | `auto` \\| `ask` \\| `readonly` |\n| `mcpServers` | — | MCP stdio servers (see below) |\n| `permissions` | — | `{ mode, allowCommands, denyCommands }` |\n\n#### Precedence\n\nValues are merged from highest to lowest priority — your `.scoderrc.json` value only applies when no flag/env is set:\n\n1. **CLI flags** — `-m`, `--base-url`, `-k`, `--provider`, `-B`\n2. **Environment variables** — `SCODER_API_KEY` / `OPENAI_API_KEY`, `SCODER_BASE_URL`, `SCODER_MODEL`, …\n3. **`.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\n4. Built-in defaults\n\n> 💡 If your config in `.scoderrc.json` seems ignored, check `echo $SCODER_API_KEY` — env vars override the file.\n\n#### Examples for common providers\n\n```jsonc\n// Local Ollama\n{\n  \"baseUrl\": \"http://localhost:11434/v1\",\n  \"apiKey\": \"ollama\",\n  \"model\": \"qwen2.5-scoder:32b\"\n}\n```\n\n```jsonc\n// DeepSeek\n{\n  \"baseUrl\": \"https://api.deepseek.com/v1\",\n  \"apiKey\": \"sk-...\",\n  \"model\": \"deepseek-chat\"\n}\n```\n\n#### Notes\n\n- Models starting with `claude-`, or a `baseUrl` containing `api.anthropic.com`, automatically switch to the native Anthropic provider — no `provider` field needed.\n- If an `apiKey` is present in the rc file, scoder prints a warning on every run. Silence it with `SCODER_NO_APIKEY_WARNING=1`.\n\n> ⚠️ **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`.\n\n## Permissions & Safety\n\nscoder ships with a layered permission system for `run_command`:\n\n| Mode | Behavior |\n|------|----------|\n| `auto` (default) | Autonomous — runs shell commands without confirmation (original behavior) |\n| `ask` | Prompts before each shell command not covered by `allowCommands` |\n| `readonly` | Shell commands are disabled entirely; the agent can only read/list files. MCP tools are also disabled (they bypass the permission policy) |\n\nLayered checks, in order:\n\n1. **Catastrophic deny list** — `rm -rf /`, `dd of=/dev/...`, fork bombs, `curl | sh`, etc. are **always denied**, in every mode.\n2. **`denyCommands`** (config) — always denied.\n3. **Session allowlist** — commands you approved with `[a] always allow` in this session.\n4. **`allowCommands`** (config) — auto-approved.\n5. **Mode** — `auto` runs everything else; `ask` prompts; `readonly` denies.\n\nIn `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.\n\n## MCP Servers (stdio)\n\nscoder can use tools from [MCP](https://modelcontextprotocol.io) servers configured in `.scoderrc.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\"]\n    },\n    \"github\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-github\"],\n      \"env\": { \"GITHUB_TOKEN\": \"{env:GITHUB_TOKEN}\" }\n    }\n  }\n}\n```\n\n- Tools are exposed to the LLM as `mcp__<server>__<tool>` (no name collisions with built-ins)\n- Servers connect at agent start; a failing server only logs a warning — the agent keeps running with its built-in tools\n- `{env:VAR}` substitution keeps secrets out of config files\n- Built-in tools always take priority over MCP tools with colliding names\n- ⚠️ **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.\n\n## Sessions\n\nEvery 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:\n\n```bash\nscoder list                      # list saved sessions\nscoder resume last               # continue the most recent session\nscoder resume <id> \"follow-up\"   # resume + add a new instruction\n```\n\nSessions older than 7 days are pruned automatically on the next run. Use `--no-save` to disable (e.g. in CI).\n\n## Streaming\n\nLLM 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.\n\n## Logging\n\nEnable a structured JSONL event log with `--log-file` (or `SCODER_LOG_FILE=1`, or `SCODER_LOG_FILE=/path/to/log.jsonl`):\n\n```bash\nscoder --log-file \"fix the failing test\"\ncat .scoder/logs/<session-id>.jsonl | jq 'select(.type == \"error\")'\n```\n\nEvents: `step` (with token usage), `tool` (args, ok, elapsedMs, denied reason), `build`, `finish`. One JSON object per line — pipe to `jq` or any log consumer.\n\n## Reliability\n\nscoder is designed for unattended use. Key guarantees:\n\n- **Request timeouts** — LLM calls have a 120s timeout; on timeout, the agent retries or fails gracefully (never hangs indefinitely).\n- **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`.\n- **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.\n- **Double-build prevention** — when the agent itself runs the build command, scoder reuses that result instead of running the build twice.\n- **Build diff preview** — run `scoder --permission ask` to see a unified diff before every file write/edit.\n\n> **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.\n\n### Auto-detected build commands\n\nscoder detects the build command automatically:\n\n| Project type | Detected command |\n|---|---|\n| `package.json` with `scripts.build` | `npm run build` |\n| `Makefile` | `make` |\n| `go.mod` | `go build ./...` |\n| `Cargo.toml` | `cargo build` |\n| `tsconfig.json` | `npx tsc --noEmit` |\n| `pyproject.toml` | `python -m compileall .` |\n\n## CLI Options\n\n```\nscoder [options] \"<task>\"     Run a task autonomously until the build passes\nscoder                       Start interactive session\nscoder --help | --version     Help and version\n```\n\n| Flag | Description |\n|------|-------------|\n| `-m <model>` | Model to use |\n| `--base-url <url>` | OpenAI-compatible API base URL |\n| `-k <key>` | API key |\n| `-B, --build <cmd>` | Build command (stop condition) |\n| `-d, --dir <path>` | Working directory |\n| `-s, --max-steps <n>` | Max iterations (default 40) |\n| `--permission <mode>` | `auto` \\| `ask` \\| `readonly` shell-command policy (default `auto`) |\n| `-y` | Non-interactive mode (denies commands needing confirmation) |\n| `--provider <name>` | `openai` \\| `anthropic` (env SCODER_PROVIDER; auto-detected) |\n| `--no-save` | Disable session auto-save to `.scoder/sessions/` |\n\n## Examples\n\n```bash\n# Run a task (auto-saves session to .scoder/sessions/)\nscoder -B \"npm test\" \"fix the null pointer in UserService\"\n\n# Resume after a crash or interrupt\nscoder resume last \"now add unit tests for the fix\"\n\n# Interactive mode with permission guard\nscoder --permission ask \"npm install express and wire up a route\"\n\n# Custom LLM (Groq, Ollama, vLLM, OpenRouter…)\nscoder --base-url https://api.groq.com/openai/v1 -k $GROQ_KEY \\\n  \"add input validation to the CLI\"\n\n# Anthropic (auto-detected when model starts with 'claude-')\nscoder -m claude-sonnet-4-5 \"refactor the parser module\"\n\n# CI: non-interactive, no session saving\nscoder --no-save -y \"run the full migration\"\n```\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────┐\n│  CLI (src/index.ts)                         │\n│   arg parsing, REPL, SIGINT handling        │\n└─────────────────┬───────────────────────────┘\n                  │\n┌─────────────────▼───────────────────────────┐\n│  Agent (src/agent.ts)                       │\n│   Closed-loop orchestrator                  │\n│   history trimming, error injection         │\n└───────┬───────────────────────┬─────────────┘\n        │                       │\n┌───────▼───────┐    ┌─────────▼──────────┐\n│  LLM Client   │    │  Tool Registry       │\n│ (src/llm.ts)  │    │ (src/tools.ts)       │\n│ OpenAI compat │    │ read/write/run/list │\n└───────────────┘    └──────────────────────┘\n        │\n        ▼\n┌─────────────────────────────────────────────┐\n│  Build Checker (src/build.ts)               │\n│   run build → exit 0 = stop condition met   │\n└─────────────────────────────────────────────┘\n```\n\n## Integration Testing\n\n```bash\nnpm test          # runs: lint → typecheck → build → 116 unit tests + e2e + MCP smoke\nnpm run lint      # eslint flat config (typescript-eslint + eqeqeq, prefer-const...)\nnpm run typecheck # tsc --noEmit\n```\n\nTest suites (run with `npm test` — auto-discovers `test/*.test.mjs`):\n- `test/permissions.test.mjs` — catastrophic patterns, mode classification, allowlist word-boundary, timeout-denies\n- `test/permission-prompt.test.mjs` — interactive prompt timeout behavior\n- `test/tools.test.mjs` — safePath traversal, symlink escape, file-size cap, write/edit/list\n- `test/core.test.mjs` — unified diff, retry backoff, context trimming\n- `test/config.test.mjs` — env/rc/cli precedence, logFile mapping, permission lists\n- `test/session.test.mjs` — session store, smart prune, resolve\n- `test/anthropic.test.mjs` — message translation + native SSE streaming\n- `test/llm.test.mjs` — OpenAI-compatible chat + SSE streaming + redaction\n- `test/run-e2e.mjs` — closed-loop integration (mock LLM server)\n- `test/run-mcp-test.mjs` — MCP smoke (mock stdio server)\n\nCoverage (lines): **90.3%** overall — see `npm run coverage`.\n\n## Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| `0` | Task completed — build passed |\n| `1` | Build failed after max steps |\n| `2` | Fatal error (no API key, network error, etc.) |\n\n## License\n\nMIT\n","readmeFilename":"README.md","homepage":"https://github.com/nbhson/app-scoder-agent#readme","keywords":["cli","agent","ai","coding-agent","llm"],"repository":{"url":"git+https://github.com/nbhson/app-scoder-agent.git","type":"git"},"bugs":{"url":"https://github.com/nbhson/app-scoder-agent/issues"},"license":"MIT"}