acdev 1.0.5 → 1.0.6
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/.acdev/.env.example +3 -0
- package/README.md +25 -13
- package/bin/acdev.js +20 -10
- package/package.json +1 -1
- package/public/app.js +1167 -124
- package/public/index.html +154 -17
- package/public/styles.css +590 -33
- package/src/agent.js +122 -64
- package/src/config.js +181 -11
- package/src/models.js +230 -39
- package/src/openrouter-auth.js +37 -0
- package/src/server.js +59 -15
package/.acdev/.env.example
CHANGED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
# An API key takes precedence over subscription login:
|
|
14
14
|
# ANTHROPIC_API_KEY=sk-ant-your-key-here
|
|
15
15
|
#
|
|
16
|
+
# OpenRouter (only when llmProvider is "openrouter" in Settings / config.json):
|
|
17
|
+
# OPENROUTER_API_KEY=sk-or-your-openrouter-key
|
|
18
|
+
#
|
|
16
19
|
# Jira Cloud (only when ticketSource is "jira" in Settings / config.json):
|
|
17
20
|
# JIRA_BASE_URL=https://your-domain.atlassian.net
|
|
18
21
|
# JIRA_EMAIL=you@company.com
|
package/README.md
CHANGED
|
@@ -15,9 +15,9 @@ You do **not** need GitHub or Claude tokens before starting `acdev`. The server
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm i -g
|
|
18
|
+
npm i -g acdev
|
|
19
19
|
# or
|
|
20
|
-
npx
|
|
20
|
+
npx acdev
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
From a local clone (development):
|
|
@@ -29,9 +29,9 @@ npm link # optional — makes `acdev` available globally
|
|
|
29
29
|
|
|
30
30
|
## Authentication
|
|
31
31
|
|
|
32
|
-
`acdev` starts even when auth is missing and prints a warning. Configure GitHub and Claude from **Settings → Authentication** in the web UI (tokens are written to `.acdev/.env`, gitignored) or by editing that file directly. Leave a Settings field blank to keep the current secret. Shell environment variables override `.env` on startup; saving in Settings updates the running process immediately so status refreshes without a restart.
|
|
32
|
+
`acdev` starts even when auth is missing and prints a warning. Configure GitHub and your LLM provider (Claude or OpenRouter) from **Settings → Authentication** in the web UI (tokens are written to `.acdev/.env`, gitignored) or by editing that file directly. Leave a Settings field blank to keep the current secret. Shell environment variables override `.env` on startup; saving in Settings updates the running process immediately so status refreshes without a restart.
|
|
33
33
|
|
|
34
|
-
Enqueueing issues, retrying jobs, and applying review feedback require Claude
|
|
34
|
+
Enqueueing issues, retrying jobs, and applying review feedback require the configured LLM provider to be authenticated (Claude or OpenRouter, unless `--stub-agent`). Opening a PR always requires GitHub auth. The Overview banner prompts you when auth is incomplete.
|
|
35
35
|
|
|
36
36
|
`.env` is optional when you already use `gh auth login` and `claude auth login` on the machine.
|
|
37
37
|
|
|
@@ -92,6 +92,12 @@ acdev
|
|
|
92
92
|
|
|
93
93
|
A Claude.ai browser-only subscription does **not** give you an API key. API keys come from the [Claude Console](https://platform.claude.com/) and are billed separately from Pro/Max. To switch back to subscription login, clear the saved API key in Settings (or omit it from `.env`).
|
|
94
94
|
|
|
95
|
+
### OpenRouter (optional LLM provider)
|
|
96
|
+
|
|
97
|
+
In **Settings → Configuration**, set **LLM provider** to **OpenRouter**, then add your API key under **Settings → Authentication → OpenRouter authentication** (or set `OPENROUTER_API_KEY` in `.acdev/.env`). Agent runs still use the Claude Agent SDK, routed through OpenRouter’s Anthropic-compatible API (`ANTHROPIC_BASE_URL=https://openrouter.ai/api`). Choose any model from the OpenRouter dropdown (e.g. `anthropic/claude-sonnet-4`).
|
|
98
|
+
|
|
99
|
+
**Note:** OpenRouter works best with Anthropic models on OpenRouter. Some SDK versions send Anthropic-only beta headers that OpenRouter may reject; if agent runs fail with a `context-management` error, use Claude provider directly or an Anthropic model slug on OpenRouter.
|
|
100
|
+
|
|
95
101
|
## Jira ticket source
|
|
96
102
|
|
|
97
103
|
Tickets can come from **GitHub Issues** or **Jira Cloud**. Switch in **Settings → Ticket source**. The server still requires `gh` auth (PRs); Jira credentials are only required when enqueueing Jira issues.
|
|
@@ -211,14 +217,19 @@ On first run, creates `.acdev/config.json`:
|
|
|
211
217
|
| `close_issue` | Transitions to a Done-category status, or else a Done/Closed/Resolved-like name | Closes the GitHub issue |
|
|
212
218
|
|
|
213
219
|
Legacy Jira configs that only had `enabled` + `targetStatus` (no `action`) still work: when enabled, they migrate to `action: "set_status"`.
|
|
214
|
-
Supported `model` values
|
|
220
|
+
Supported `model` values depend on the selected LLM provider (`llmProvider` in config):
|
|
221
|
+
|
|
222
|
+
- **Claude** (`llmProvider: "claude"`, default) — Claude Agent SDK / Claude Code model ids (aliases like `claude-sonnet-5` / `claude-opus-5` / `sonnet`, or Anthropic API model ids).
|
|
223
|
+
- **OpenRouter** (`llmProvider: "openrouter"`) — OpenRouter model slugs (e.g. `anthropic/claude-sonnet-4`, `openai/gpt-4o`).
|
|
224
|
+
|
|
225
|
+
The Settings model dropdown is populated by `GET /api/models?provider=claude|openrouter`:
|
|
215
226
|
|
|
216
|
-
1. When `ANTHROPIC_API_KEY` (or `ANTHROPIC_AUTH_TOKEN` / `CLAUDE_CODE_OAUTH_TOKEN`) is set — or Claude Code browser login credentials are readable
|
|
217
|
-
2.
|
|
227
|
+
1. **Claude** — When `ANTHROPIC_API_KEY` (or `ANTHROPIC_AUTH_TOKEN` / `CLAUDE_CODE_OAUTH_TOKEN`) is set — or Claude Code browser login credentials are readable — acdev calls Anthropic’s Models API and merges results with curated Claude Code aliases. Otherwise falls back to a curated list (`source: "fallback"`).
|
|
228
|
+
2. **OpenRouter** — When `OPENROUTER_API_KEY` is set, acdev calls `GET https://openrouter.ai/api/v1/models` and merges with curated OpenRouter defaults. Without a key, shows curated OpenRouter models only.
|
|
218
229
|
|
|
219
|
-
Empty or malformed model IDs in an existing config are migrated to `claude-sonnet-5`
|
|
230
|
+
Empty or malformed model IDs in an existing config are migrated to the provider default on load (`claude-sonnet-5` or `anthropic/claude-sonnet-4`). Switching providers in Settings resets the model when the current id is not in the new provider’s curated list.
|
|
220
231
|
|
|
221
|
-
Change via **Settings → Configuration** (`PATCH /api/config`) or `--model`. Takes effect for the next agent run without restart.
|
|
232
|
+
Change provider/model via **Settings → Configuration** (`PATCH /api/config`) or `--model`. Takes effect for the next agent run without restart.
|
|
222
233
|
|
|
223
234
|
Job state is persisted in `.acdev/state.json`.
|
|
224
235
|
|
|
@@ -234,11 +245,12 @@ npm test
|
|
|
234
245
|
|
|
235
246
|
- `bin/acdev.js` — CLI entry; soft-checks `gh` / Claude auth (warns, does not exit). Tokens in `.acdev/.env` are loaded before auth checks. Job APIs reject until auth is OK.
|
|
236
247
|
- `src/claude-auth.js` — Anthropic API key / Claude Code subscription auth detection
|
|
248
|
+
- `src/openrouter-auth.js` — OpenRouter API key detection
|
|
237
249
|
- `src/gh-auth.js` — GitHub CLI auth (`gh auth login` or `GH_TOKEN`)
|
|
238
250
|
- `src/server.js` — Express API, SSE logs, job queue, config + Jira test endpoints
|
|
239
251
|
- `src/git.js` — Worktree lifecycle (`issue-<id>` paths), `feat/`/`fix/` branch naming, diff, push
|
|
240
|
-
- `src/agent.js` — Claude Agent SDK integration
|
|
241
|
-
- `src/models.js` — `GET /api/models` list (Anthropic
|
|
252
|
+
- `src/agent.js` — Claude Agent SDK integration; OpenRouter via Anthropic-compatible routing when `llmProvider` is `openrouter`
|
|
253
|
+
- `src/models.js` — `GET /api/models` list (Anthropic or OpenRouter APIs + curated fallback)
|
|
242
254
|
- `src/github.js` — Issue URL parsing, issue fetch via `gh`, `createPr({ draft })`
|
|
243
255
|
- `src/jira.js` — Jira Cloud parse/fetch/test + issuetype → feat/fix
|
|
244
256
|
- `src/config.js` — Load/save `.acdev/config.json` including ticket source
|
|
@@ -259,8 +271,8 @@ npm test
|
|
|
259
271
|
| `DELETE` | `/api/jobs/:id` | Clear job from history (worktree best-effort); 409 if in-flight |
|
|
260
272
|
| `POST` | `/api/jobs/:id/retry` | Re-queue failed/discarded |
|
|
261
273
|
| `GET` | `/api/config` | Editable config + curated models + Jira status (token masked) |
|
|
262
|
-
| `GET` | `/api/models` | `{ models, selected, source }` — live
|
|
263
|
-
| `PATCH` | `/api/config` | Partial update including `ticketSource`, `jiraBaseUrl`; `jiraEmail
|
|
274
|
+
| `GET` | `/api/models` | `{ models, selected, source, provider }` — live provider list or curated fallback (`?provider=claude\|openrouter`) |
|
|
275
|
+
| `PATCH` | `/api/config` | Partial update including `llmProvider`, `ticketSource`, `jiraBaseUrl`; secrets (`openrouterApiKey`, `jiraEmail`, etc.) → `.env` |
|
|
264
276
|
| `POST` | `/api/jira/test` | Test Jira credentials (`GET /rest/api/3/myself`) |
|
|
265
277
|
|
|
266
278
|
### Branch naming
|
package/bin/acdev.js
CHANGED
|
@@ -4,6 +4,8 @@ import { execSync } from 'node:child_process';
|
|
|
4
4
|
import http from 'node:http';
|
|
5
5
|
import open from 'open';
|
|
6
6
|
import { checkClaudeAuth, formatClaudeAuthError } from '../src/claude-auth.js';
|
|
7
|
+
import { checkOpenRouterAuth, formatOpenRouterAuthError } from '../src/openrouter-auth.js';
|
|
8
|
+
import { isValidLlmProvider } from '../src/models.js';
|
|
7
9
|
import { checkGhAuth, formatGhAuthError } from '../src/gh-auth.js';
|
|
8
10
|
import { loadConfig } from '../src/config.js';
|
|
9
11
|
import { loadEnv } from '../src/env.js';
|
|
@@ -58,7 +60,7 @@ async function main() {
|
|
|
58
60
|
migrateLegacyWorktreesDir(repoRoot);
|
|
59
61
|
loadEnv(repoRoot);
|
|
60
62
|
|
|
61
|
-
// Soft auth: never exit for missing GitHub/
|
|
63
|
+
// Soft auth: never exit for missing GitHub/LLM credentials.
|
|
62
64
|
// Always start the server so Settings can add tokens; job endpoints
|
|
63
65
|
// reject with a clear 4xx until auth is configured.
|
|
64
66
|
const ghAuth = checkGhAuth();
|
|
@@ -66,15 +68,6 @@ async function main() {
|
|
|
66
68
|
console.warn(formatGhAuthError(ghAuth));
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
if (!opts.stubAgent) {
|
|
70
|
-
const claudeAuth = checkClaudeAuth();
|
|
71
|
-
if (!claudeAuth.ok) {
|
|
72
|
-
console.warn(formatClaudeAuthError(claudeAuth));
|
|
73
|
-
}
|
|
74
|
-
} else {
|
|
75
|
-
console.log('✓ Stub agent enabled (Claude auth not required)');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
71
|
const config = loadConfig(repoRoot);
|
|
79
72
|
if (opts.baseBranch) {
|
|
80
73
|
config.baseBranch = opts.baseBranch;
|
|
@@ -83,6 +76,23 @@ async function main() {
|
|
|
83
76
|
config.model = opts.model;
|
|
84
77
|
}
|
|
85
78
|
|
|
79
|
+
if (!opts.stubAgent) {
|
|
80
|
+
const provider = isValidLlmProvider(config.llmProvider) ? config.llmProvider : 'claude';
|
|
81
|
+
if (provider === 'openrouter') {
|
|
82
|
+
const openrouterAuth = checkOpenRouterAuth();
|
|
83
|
+
if (!openrouterAuth.ok) {
|
|
84
|
+
console.warn(formatOpenRouterAuthError(openrouterAuth));
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
const claudeAuth = checkClaudeAuth();
|
|
88
|
+
if (!claudeAuth.ok) {
|
|
89
|
+
console.warn(formatClaudeAuthError(claudeAuth));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
console.log('✓ Stub agent enabled (LLM auth not required)');
|
|
94
|
+
}
|
|
95
|
+
|
|
86
96
|
const store = new Store(repoRoot);
|
|
87
97
|
store.reconcileStaleJobs();
|
|
88
98
|
|