@open330/oac 2026.3.1 → 2026.3.3
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 +454 -0
- package/dist/{chunk-PYSJFMKA.js → chunk-GII2GWGO.js} +75 -20
- package/dist/chunk-GII2GWGO.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +10 -9
- package/dist/chunk-PYSJFMKA.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
___ _ ____
|
|
5
|
+
/ _ \ / \ / ___|
|
|
6
|
+
| | | |/ _ \| |
|
|
7
|
+
| |_| / ___ \ |___
|
|
8
|
+
\___/_/ \_\____|
|
|
9
|
+
|
|
10
|
+
O P E N A G E N T C O N T R I B U T I O N
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Put your spare AI tokens to work. Contribute to open source — automatically.**
|
|
14
|
+
|
|
15
|
+
[](https://www.npmjs.com/package/@open330/oac)
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
[](https://nodejs.org/)
|
|
18
|
+
[](https://typescriptlang.org/)
|
|
19
|
+
|
|
20
|
+
[Getting Started](#-getting-started) · [How It Works](#-how-it-works) · [Commands](#-commands) · [Architecture](#-architecture) · [Contributing](#-contributing)
|
|
21
|
+
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## The Problem
|
|
27
|
+
|
|
28
|
+
You pay for AI agent tokens every month. Claude Code, Codex, OpenCode — they all come with token budgets. But most days, you don't use them all. Those leftover tokens? **Wasted.**
|
|
29
|
+
|
|
30
|
+
Meanwhile, thousands of open source repos have TODOs nobody finishes, lint warnings nobody fixes, tests nobody writes, and issues nobody picks up.
|
|
31
|
+
|
|
32
|
+
## The Solution
|
|
33
|
+
|
|
34
|
+
**OAC** bridges the gap. Point it at a repo, and it will:
|
|
35
|
+
|
|
36
|
+
1. **Scan** the codebase for actionable tasks (TODOs, lint issues, missing tests, open GitHub issues)
|
|
37
|
+
2. **Estimate** token costs and pick tasks that fit your remaining budget
|
|
38
|
+
3. **Execute** the work using your AI agent of choice — in parallel, sandboxed environments
|
|
39
|
+
4. **Submit** pull requests, link issues, and track every contribution
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Install globally
|
|
43
|
+
npm install -g @open330/oac
|
|
44
|
+
|
|
45
|
+
# That's it. One command.
|
|
46
|
+
oac run --repo facebook/react --tokens 50000
|
|
47
|
+
|
|
48
|
+
# Or run without installing
|
|
49
|
+
npx @open330/oac run --repo facebook/react --tokens unlimited
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
Scanning facebook/react...
|
|
54
|
+
Found 23 tasks (12 lint fixes, 6 TODOs, 5 test gaps)
|
|
55
|
+
|
|
56
|
+
Budget: 50,000 tokens
|
|
57
|
+
Selected: 8 tasks (est. 42,300 tokens)
|
|
58
|
+
Reserve: 5,000 tokens (10%)
|
|
59
|
+
|
|
60
|
+
[Claude] ████████░░ 4/8 tasks completed
|
|
61
|
+
[Claude] ✔ PR #1847: Fix unused imports in scheduler
|
|
62
|
+
[Claude] ✔ PR #1848: Add tests for reconciler edge case
|
|
63
|
+
[Claude] ⠋ Resolving TODO in ReactFiberHooks.js...
|
|
64
|
+
|
|
65
|
+
─────────────────────────────────────
|
|
66
|
+
Done! 7/8 tasks succeeded
|
|
67
|
+
PRs created: 7
|
|
68
|
+
Tokens used: 38,420 / 50,000
|
|
69
|
+
Contribution logged to .oac/contributions/
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
| | Feature | Description |
|
|
77
|
+
|---|---------|-------------|
|
|
78
|
+
| **Scan** | Task Discovery | Finds TODOs, lint issues, test gaps, dead code, and open GitHub issues |
|
|
79
|
+
| **Budget** | Token Estimation | Per-provider token counting with knapsack-optimized task selection |
|
|
80
|
+
| **Run** | Parallel Execution | Run 2-3 agents simultaneously in isolated git worktrees |
|
|
81
|
+
| **Ship** | PR Automation | Creates PRs, links issues, notifies Linear/Jira via webhooks |
|
|
82
|
+
| **Track** | Contribution Logs | Git-native audit trail in `.oac/` — who contributed what, with how many tokens |
|
|
83
|
+
| **Rank** | Leaderboard | See who's recycling the most tokens across your team |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Quick Start
|
|
88
|
+
|
|
89
|
+
### Prerequisites
|
|
90
|
+
|
|
91
|
+
- **Node.js** >= 22
|
|
92
|
+
- **git** installed
|
|
93
|
+
- At least one AI agent CLI: [Claude Code](https://claude.ai/code), [Codex](https://github.com/openai/codex), or [OpenCode](https://github.com/opencode-ai/opencode)
|
|
94
|
+
|
|
95
|
+
### Install
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# From npm (recommended)
|
|
99
|
+
npm install -g @open330/oac
|
|
100
|
+
|
|
101
|
+
# Or use without installing
|
|
102
|
+
npx @open330/oac --help
|
|
103
|
+
|
|
104
|
+
# From source (for contributors)
|
|
105
|
+
git clone https://github.com/Open330/open-agent-contribution.git
|
|
106
|
+
cd open-agent-contribution
|
|
107
|
+
pnpm install
|
|
108
|
+
pnpm build
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Setup
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Interactive setup wizard
|
|
115
|
+
oac init
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
___ _ ____
|
|
120
|
+
/ _ \ / \ / ___|
|
|
121
|
+
| | | |/ _ \| |
|
|
122
|
+
| |_| / ___ \ |___
|
|
123
|
+
\___/_/ \_\____|
|
|
124
|
+
|
|
125
|
+
Welcome to Open Agent Contribution.
|
|
126
|
+
Let's put your spare tokens to work.
|
|
127
|
+
|
|
128
|
+
? Select your AI providers: › Claude Code, Codex CLI
|
|
129
|
+
? Monthly token budget for OAC: › 100000
|
|
130
|
+
? Add your first repo (owner/repo): › facebook/react
|
|
131
|
+
|
|
132
|
+
✔ Config written to oac.config.ts
|
|
133
|
+
✔ Created .oac/ tracking directory
|
|
134
|
+
Ready! Run 'oac doctor' to verify or 'oac run' to start.
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Verify
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
oac doctor
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
Environment Check
|
|
145
|
+
─────────────────
|
|
146
|
+
[✔] Node.js v24.0.0
|
|
147
|
+
[✔] git v2.43.0
|
|
148
|
+
[✔] GitHub Auth gh authenticated as @jiun
|
|
149
|
+
[✔] Claude CLI v1.0.16
|
|
150
|
+
[✘] Codex CLI not found
|
|
151
|
+
|
|
152
|
+
4/5 checks passed
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Commands
|
|
158
|
+
|
|
159
|
+
| Command | Description |
|
|
160
|
+
|---------|-------------|
|
|
161
|
+
| `oac init` | Interactive setup wizard — creates `oac.config.ts` |
|
|
162
|
+
| `oac doctor` | Verify environment (Node, git, agents, auth) |
|
|
163
|
+
| `oac scan` | Discover tasks in a repo without executing |
|
|
164
|
+
| `oac plan` | Show execution plan with token budget breakdown |
|
|
165
|
+
| `oac run` | Full pipeline: scan → estimate → execute → PR → track |
|
|
166
|
+
| `oac status` | Show running/recent job status |
|
|
167
|
+
| `oac log` | View contribution history |
|
|
168
|
+
| `oac leaderboard` | Show contribution rankings |
|
|
169
|
+
| `oac dashboard` | Launch localhost web dashboard |
|
|
170
|
+
|
|
171
|
+
### `oac run` — The Main Event
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
oac run \
|
|
175
|
+
--repo owner/repo \ # Target repository
|
|
176
|
+
--tokens 50000 \ # Token budget (or "unlimited")
|
|
177
|
+
--provider claude-code \ # AI agent to use
|
|
178
|
+
--concurrency 2 \ # Parallel agents (default: 2)
|
|
179
|
+
--mode new-pr \ # Create PRs (or: direct-commit)
|
|
180
|
+
--dry-run # Preview without executing
|
|
181
|
+
|
|
182
|
+
# Run with unlimited budget (keeps going until rate-limited)
|
|
183
|
+
oac run --repo owner/repo --tokens unlimited --concurrency 3
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `oac scan` — See What's Out There
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
oac scan --repo owner/repo --format table
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
┌─────────┬──────────────────────────────────┬────────┬──────────┬────────────┐
|
|
194
|
+
│ ID │ Title │ Source │ Priority │ Complexity │
|
|
195
|
+
├─────────┼──────────────────────────────────┼────────┼──────────┼────────────┤
|
|
196
|
+
│ a1b2c3 │ Fix unused import in utils.ts │ lint │ 85 │ trivial │
|
|
197
|
+
│ d4e5f6 │ TODO: Add input validation │ todo │ 72 │ simple │
|
|
198
|
+
│ g7h8i9 │ Missing tests for Parser class │ test │ 68 │ moderate │
|
|
199
|
+
│ j0k1l2 │ Remove dead code in legacy/ │ dead │ 45 │ simple │
|
|
200
|
+
│ #142 │ Fix date formatting bug │ issue │ 91 │ moderate │
|
|
201
|
+
└─────────┴──────────────────────────────────┴────────┴──────────┴────────────┘
|
|
202
|
+
5 tasks discovered
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Configuration
|
|
208
|
+
|
|
209
|
+
OAC uses a TypeScript config file:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// oac.config.ts
|
|
213
|
+
export default {
|
|
214
|
+
repos: ['facebook/react', 'vercel/next.js'],
|
|
215
|
+
|
|
216
|
+
provider: {
|
|
217
|
+
id: 'claude-code',
|
|
218
|
+
options: { model: 'opus' },
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
budget: {
|
|
222
|
+
totalTokens: 100_000,
|
|
223
|
+
reservePercent: 0.10,
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
discovery: {
|
|
227
|
+
scanners: {
|
|
228
|
+
lint: true,
|
|
229
|
+
todo: true,
|
|
230
|
+
testGap: true,
|
|
231
|
+
deadCode: false,
|
|
232
|
+
githubIssues: true,
|
|
233
|
+
},
|
|
234
|
+
issueLabels: ['good-first-issue', 'help-wanted', 'bug'],
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
execution: {
|
|
238
|
+
concurrency: 2,
|
|
239
|
+
mode: 'new-pr',
|
|
240
|
+
taskTimeout: 300,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Architecture
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
┌─────────────────────────────────────────────────────┐
|
|
251
|
+
│ oac CLI / Dashboard │
|
|
252
|
+
└────────────────────────┬────────────────────────────┘
|
|
253
|
+
│
|
|
254
|
+
┌──────────▼──────────┐
|
|
255
|
+
│ Core Engine │
|
|
256
|
+
│ (Event Bus + Config)│
|
|
257
|
+
└──┬──┬──┬──┬──┬──┬──┘
|
|
258
|
+
│ │ │ │ │ │
|
|
259
|
+
┌────────────┘ │ │ │ │ └────────────┐
|
|
260
|
+
│ │ │ │ │ │
|
|
261
|
+
┌───▼───┐ ┌───────▼──▼──▼───────┐ ┌───────▼───────┐
|
|
262
|
+
│ Repo │ │ Discovery → Budget │ │ Tracking │
|
|
263
|
+
│Select │ │ → Execution │ │ (.oac/ logs) │
|
|
264
|
+
└───────┘ └─────────┬───────────┘ └───────────────┘
|
|
265
|
+
│
|
|
266
|
+
┌──────▼──────┐
|
|
267
|
+
│ Completion │
|
|
268
|
+
│ (PR + Issue) │
|
|
269
|
+
└──────┬──────┘
|
|
270
|
+
│
|
|
271
|
+
┌─────────▼─────────┐
|
|
272
|
+
│ GitHub / Linear │
|
|
273
|
+
│ / Jira │
|
|
274
|
+
└───────────────────┘
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Packages
|
|
278
|
+
|
|
279
|
+
All packages are published under the `@open330` scope on npm:
|
|
280
|
+
|
|
281
|
+
| Package | npm | Description |
|
|
282
|
+
|---------|-----|-------------|
|
|
283
|
+
| [`@open330/oac`](packages/cli) | [](https://www.npmjs.com/package/@open330/oac) | CLI — the main entry point |
|
|
284
|
+
| [`@open330/oac-core`](packages/core) | [](https://www.npmjs.com/package/@open330/oac-core) | Event bus, config, types, errors |
|
|
285
|
+
| [`@open330/oac-repo`](packages/repo) | [](https://www.npmjs.com/package/@open330/oac-repo) | GitHub repo resolution, cloning, metadata |
|
|
286
|
+
| [`@open330/oac-discovery`](packages/discovery) | [](https://www.npmjs.com/package/@open330/oac-discovery) | Task scanners (lint, TODO, test-gap, issues) |
|
|
287
|
+
| [`@open330/oac-budget`](packages/budget) | [](https://www.npmjs.com/package/@open330/oac-budget) | Token estimation, complexity analysis, planning |
|
|
288
|
+
| [`@open330/oac-execution`](packages/execution) | [](https://www.npmjs.com/package/@open330/oac-execution) | Agent pool, job queue, worktree sandbox |
|
|
289
|
+
| [`@open330/oac-completion`](packages/completion) | [](https://www.npmjs.com/package/@open330/oac-completion) | PR creation, issue linking |
|
|
290
|
+
| [`@open330/oac-tracking`](packages/tracking) | [](https://www.npmjs.com/package/@open330/oac-tracking) | Contribution logs, leaderboard |
|
|
291
|
+
| [`@open330/oac-dashboard`](packages/dashboard) | [](https://www.npmjs.com/package/@open330/oac-dashboard) | Fastify web dashboard with SSE streaming |
|
|
292
|
+
|
|
293
|
+
### Tech Stack
|
|
294
|
+
|
|
295
|
+
| Layer | Technology |
|
|
296
|
+
|-------|-----------|
|
|
297
|
+
| Runtime | Node.js 22+, TypeScript 5.7+, ESM |
|
|
298
|
+
| Build | pnpm workspaces, Turborepo, tsup |
|
|
299
|
+
| CLI | Commander.js, chalk, ora, cli-table3 |
|
|
300
|
+
| Git | simple-git, git worktrees for isolation |
|
|
301
|
+
| GitHub | @octokit/rest |
|
|
302
|
+
| AI Agents | Claude Code (`claude-code`), Codex CLI (`codex`) — pluggable via `AgentProvider` |
|
|
303
|
+
| Dashboard | Fastify + embedded SPA with SSE streaming |
|
|
304
|
+
| Quality | Vitest, Biome |
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Contribution Tracking
|
|
309
|
+
|
|
310
|
+
Every run creates a JSON log in `.oac/contributions/`:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
.oac/
|
|
314
|
+
├── contributions/
|
|
315
|
+
│ ├── 2026-02-17-143052-jiun.json
|
|
316
|
+
│ ├── 2026-02-17-151023-jiun.json
|
|
317
|
+
│ └── 2026-02-18-091500-alice.json
|
|
318
|
+
└── leaderboard.json
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Each log records: who contributed, which tasks, tokens used, PRs created, and execution metrics. The leaderboard aggregates across all contributors.
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
oac leaderboard
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
Contribution Leaderboard
|
|
329
|
+
────────────────────────
|
|
330
|
+
#1 jiun 42 tasks 284,000 tokens 38 PRs merged
|
|
331
|
+
#2 alice 31 tasks 195,000 tokens 27 PRs merged
|
|
332
|
+
#3 bob 18 tasks 122,000 tokens 15 PRs merged
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## How It Works
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
You run `oac run`
|
|
341
|
+
│
|
|
342
|
+
▼
|
|
343
|
+
┌─────────┐ Shallow clone, cache metadata
|
|
344
|
+
│ Repo │────────────────────────────────────┐
|
|
345
|
+
│ Select │ │
|
|
346
|
+
└────┬─────┘ │
|
|
347
|
+
│ │
|
|
348
|
+
▼ ▼
|
|
349
|
+
┌─────────┐ TODO, lint, test-gap, ┌──────────┐
|
|
350
|
+
│ Scan │──── GitHub issues ──────────▶│ Tasks │
|
|
351
|
+
└────┬────┘ └────┬─────┘
|
|
352
|
+
│ │
|
|
353
|
+
▼ ▼
|
|
354
|
+
┌─────────┐ tiktoken counting, ┌──────────┐
|
|
355
|
+
│ Budget │──── knapsack selection ─────▶│ Plan │
|
|
356
|
+
└────┬────┘ (10% reserve) └────┬─────┘
|
|
357
|
+
│ │
|
|
358
|
+
▼ ▼
|
|
359
|
+
┌─────────┐ git worktree per agent ┌──────────┐
|
|
360
|
+
│Execute │──── parallel sandboxes ─────▶│ Results │
|
|
361
|
+
└────┬────┘ └────┬─────┘
|
|
362
|
+
│ │
|
|
363
|
+
▼ ▼
|
|
364
|
+
┌─────────┐ Validate diff, ┌──────────┐
|
|
365
|
+
│Complete │──── create PR, link issue ──▶│ PRs │
|
|
366
|
+
└────┬────┘ └────┬─────┘
|
|
367
|
+
│ │
|
|
368
|
+
▼ ▼
|
|
369
|
+
┌─────────┐ .oac/contributions/ ┌──────────┐
|
|
370
|
+
│ Track │──── JSON audit log ─────────▶│ Done! │
|
|
371
|
+
└─────────┘ └──────────┘
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Supported AI Agents
|
|
377
|
+
|
|
378
|
+
| Agent | Status | Provider ID |
|
|
379
|
+
|-------|--------|-------------|
|
|
380
|
+
| [Claude Code](https://claude.ai/code) | Supported | `claude-code` |
|
|
381
|
+
| [Codex CLI](https://github.com/openai/codex) | Supported | `codex` |
|
|
382
|
+
| [OpenCode](https://github.com/opencode-ai/opencode) | Planned | `opencode` |
|
|
383
|
+
| Custom | Implement `AgentProvider` interface | any string |
|
|
384
|
+
|
|
385
|
+
### Adding a Custom Agent
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import type { AgentProvider } from '@open330/oac-execution';
|
|
389
|
+
|
|
390
|
+
export class MyAgentAdapter implements AgentProvider {
|
|
391
|
+
readonly id = 'my-agent';
|
|
392
|
+
readonly name = 'My Custom Agent';
|
|
393
|
+
|
|
394
|
+
async checkAvailability() { /* ... */ }
|
|
395
|
+
execute(params) { /* ... */ }
|
|
396
|
+
async estimateTokens(params) { /* ... */ }
|
|
397
|
+
async abort(executionId) { /* ... */ }
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Roadmap
|
|
404
|
+
|
|
405
|
+
- [x] **2026.2.17** — Core engine, CLI, 5 scanners, parallel execution, dashboard, npm publish
|
|
406
|
+
- [x] **2026.3.x** — Claude Code + Codex CLI adapters (both supported)
|
|
407
|
+
- [ ] **Next** — OpenCode adapter, multi-agent routing (run multiple agents simultaneously)
|
|
408
|
+
- [ ] **Future** — Linear/Jira webhooks, plugin system, sparse checkout for monorepos
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Contributing
|
|
413
|
+
|
|
414
|
+
We welcome contributions! OAC is designed to contribute to repos — and it can contribute to itself too.
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
# Clone and setup
|
|
418
|
+
git clone https://github.com/Open330/open-agent-contribution.git
|
|
419
|
+
cd open-agent-contribution
|
|
420
|
+
pnpm install
|
|
421
|
+
pnpm build
|
|
422
|
+
|
|
423
|
+
# Run tests
|
|
424
|
+
pnpm test
|
|
425
|
+
|
|
426
|
+
# Lint and format
|
|
427
|
+
pnpm lint
|
|
428
|
+
pnpm format
|
|
429
|
+
|
|
430
|
+
# Or just let OAC contribute to itself
|
|
431
|
+
npx @open330/oac run --repo Open330/open-agent-contribution --tokens unlimited
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Philosophy
|
|
439
|
+
|
|
440
|
+
> **"Don't let your tokens go to waste."**
|
|
441
|
+
|
|
442
|
+
Every month, developers around the world leave millions of AI tokens on the table. OAC turns that idle capacity into real open source contributions — automatically, safely, and transparently.
|
|
443
|
+
|
|
444
|
+
No hosted services. No data collection. No lock-in. Just your machine, your tokens, and your repos.
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
<div align="center">
|
|
449
|
+
|
|
450
|
+
**Built with spare tokens by the [Open330](https://github.com/Open330) community.**
|
|
451
|
+
|
|
452
|
+
[Report Bug](https://github.com/Open330/open-agent-contribution/issues) · [Request Feature](https://github.com/Open330/open-agent-contribution/issues) · [Discussions](https://github.com/Open330/open-agent-contribution/discussions)
|
|
453
|
+
|
|
454
|
+
</div>
|
|
@@ -13,7 +13,7 @@ function createDoctorCommand() {
|
|
|
13
13
|
const globalOptions = getGlobalOptions(cmd);
|
|
14
14
|
const ui = createUi(globalOptions);
|
|
15
15
|
const checks = await runDoctorChecks();
|
|
16
|
-
const allPassed = checks.every((check) => check.status
|
|
16
|
+
const allPassed = checks.every((check) => check.status !== "fail");
|
|
17
17
|
if (globalOptions.json) {
|
|
18
18
|
console.log(
|
|
19
19
|
JSON.stringify(
|
|
@@ -70,7 +70,7 @@ async function runDoctorChecks() {
|
|
|
70
70
|
const codexResult = await runCommand("codex", ["--version"]);
|
|
71
71
|
const codexVersion = extractVersion(codexResult.stdout) ?? "--";
|
|
72
72
|
checks.push({
|
|
73
|
-
id: "codex
|
|
73
|
+
id: "codex",
|
|
74
74
|
name: "Codex CLI",
|
|
75
75
|
requirement: "installed",
|
|
76
76
|
value: codexVersion,
|
|
@@ -92,12 +92,14 @@ async function checkGithubAuth() {
|
|
|
92
92
|
}
|
|
93
93
|
const authResult = await runCommand("gh", ["auth", "status"]);
|
|
94
94
|
if (authResult.ok) {
|
|
95
|
+
const hasRepoScope = authResult.stdout.includes("repo");
|
|
95
96
|
return {
|
|
96
97
|
id: "github-auth",
|
|
97
98
|
name: "GitHub auth",
|
|
98
99
|
requirement: "gh auth status or GITHUB_TOKEN",
|
|
99
100
|
value: "gh auth status",
|
|
100
|
-
status: "pass"
|
|
101
|
+
status: hasRepoScope ? "pass" : "warn",
|
|
102
|
+
message: hasRepoScope ? void 0 : "Missing 'repo' scope \u2014 private repos won't work. Run: gh auth refresh -s repo"
|
|
101
103
|
};
|
|
102
104
|
}
|
|
103
105
|
return {
|
|
@@ -127,8 +129,10 @@ function renderDoctorOutput(ui, checks, allPassed) {
|
|
|
127
129
|
console.log("Checking environment...");
|
|
128
130
|
console.log("");
|
|
129
131
|
for (const check of checks) {
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
+
const iconMap = { pass: ui.green("[OK]"), warn: ui.yellow("[!]"), fail: ui.red("[X]") };
|
|
133
|
+
const statusMap = { pass: ui.green("PASS"), warn: ui.yellow("WARN"), fail: ui.red("FAIL") };
|
|
134
|
+
const icon = iconMap[check.status];
|
|
135
|
+
const status = statusMap[check.status];
|
|
132
136
|
const name = check.name.padEnd(12, " ");
|
|
133
137
|
const requirement = check.requirement.padEnd(30, " ");
|
|
134
138
|
const value = check.value.padEnd(14, " ");
|
|
@@ -136,6 +140,9 @@ function renderDoctorOutput(ui, checks, allPassed) {
|
|
|
136
140
|
if (check.status === "fail" && check.message) {
|
|
137
141
|
console.log(` ${ui.red(check.message)}`);
|
|
138
142
|
}
|
|
143
|
+
if (check.status === "warn" && check.message) {
|
|
144
|
+
console.log(` ${ui.yellow(check.message)}`);
|
|
145
|
+
}
|
|
139
146
|
}
|
|
140
147
|
console.log("");
|
|
141
148
|
if (allPassed) {
|
|
@@ -260,8 +267,8 @@ function createInitCommand() {
|
|
|
260
267
|
message: "Select AI provider(s):",
|
|
261
268
|
choices: [
|
|
262
269
|
{ name: "Claude Code", value: "claude-code", checked: true },
|
|
263
|
-
{ name: "Codex CLI", value: "codex
|
|
264
|
-
{ name: "OpenCode", value: "opencode" }
|
|
270
|
+
{ name: "Codex CLI", value: "codex" },
|
|
271
|
+
{ name: "OpenCode (coming soon)", value: "opencode", disabled: true }
|
|
265
272
|
],
|
|
266
273
|
validate: (value) => value.length > 0 ? true : "Select at least one provider to continue."
|
|
267
274
|
});
|
|
@@ -784,6 +791,21 @@ function ensureGitHubAuth() {
|
|
|
784
791
|
}
|
|
785
792
|
return void 0;
|
|
786
793
|
}
|
|
794
|
+
function checkGitHubScopes(required = ["repo"]) {
|
|
795
|
+
try {
|
|
796
|
+
const output = execFileSync("gh", ["auth", "status"], {
|
|
797
|
+
timeout: 5e3,
|
|
798
|
+
encoding: "utf-8",
|
|
799
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
800
|
+
});
|
|
801
|
+
const scopeMatch = output.match(/Token scopes:\s*'([^']+)'/);
|
|
802
|
+
if (!scopeMatch) return [];
|
|
803
|
+
const scopes = scopeMatch[1].split(",").map((s) => s.trim().replace(/^'|'$/g, ""));
|
|
804
|
+
return required.filter((r) => !scopes.includes(r));
|
|
805
|
+
} catch {
|
|
806
|
+
return [];
|
|
807
|
+
}
|
|
808
|
+
}
|
|
787
809
|
|
|
788
810
|
// src/commands/plan.ts
|
|
789
811
|
import chalk3, { Chalk as Chalk3 } from "chalk";
|
|
@@ -1089,6 +1111,7 @@ import {
|
|
|
1089
1111
|
rankTasks as rankTasks2
|
|
1090
1112
|
} from "@open330/oac-discovery";
|
|
1091
1113
|
import {
|
|
1114
|
+
ClaudeCodeAdapter,
|
|
1092
1115
|
CodexAdapter,
|
|
1093
1116
|
createSandbox,
|
|
1094
1117
|
executeTask as workerExecuteTask
|
|
@@ -1125,9 +1148,28 @@ function createRunCommand() {
|
|
|
1125
1148
|
if (!ghToken && !outputJson) {
|
|
1126
1149
|
console.log(
|
|
1127
1150
|
ui.yellow(
|
|
1128
|
-
"[oac] Warning: GitHub auth not detected. Run `gh auth login` first
|
|
1151
|
+
"[oac] Warning: GitHub auth not detected. Run `gh auth login` first."
|
|
1152
|
+
)
|
|
1153
|
+
);
|
|
1154
|
+
console.log(
|
|
1155
|
+
ui.yellow(
|
|
1156
|
+
"[oac] For private repos, ensure the 'repo' scope: gh auth refresh -s repo"
|
|
1129
1157
|
)
|
|
1130
1158
|
);
|
|
1159
|
+
} else if (ghToken && !outputJson) {
|
|
1160
|
+
const missingScopes = checkGitHubScopes(["repo"]);
|
|
1161
|
+
if (missingScopes.length > 0) {
|
|
1162
|
+
console.log(
|
|
1163
|
+
ui.yellow(
|
|
1164
|
+
`[oac] Warning: GitHub token missing scope(s): ${missingScopes.join(", ")}. Private repos may fail.`
|
|
1165
|
+
)
|
|
1166
|
+
);
|
|
1167
|
+
console.log(
|
|
1168
|
+
ui.yellow(
|
|
1169
|
+
"[oac] Fix with: gh auth refresh -s repo"
|
|
1170
|
+
)
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1131
1173
|
}
|
|
1132
1174
|
if (!outputJson) {
|
|
1133
1175
|
console.log(
|
|
@@ -1219,18 +1261,17 @@ function createRunCommand() {
|
|
|
1219
1261
|
}
|
|
1220
1262
|
return;
|
|
1221
1263
|
}
|
|
1222
|
-
const
|
|
1223
|
-
const codexAvailability = await codexAdapter.checkAvailability();
|
|
1224
|
-
const useRealExecution = providerId.includes("codex") && codexAvailability.available;
|
|
1264
|
+
const { adapter, useRealExecution } = await resolveAdapter(providerId);
|
|
1225
1265
|
if (!outputJson && globalOptions.verbose) {
|
|
1226
|
-
if (useRealExecution) {
|
|
1266
|
+
if (useRealExecution && adapter) {
|
|
1267
|
+
const avail = await adapter.checkAvailability();
|
|
1227
1268
|
console.log(
|
|
1228
1269
|
ui.green(
|
|
1229
|
-
`[oac] Using
|
|
1270
|
+
`[oac] Using ${adapter.name} v${avail.version ?? "unknown"} for execution.`
|
|
1230
1271
|
)
|
|
1231
1272
|
);
|
|
1232
1273
|
} else {
|
|
1233
|
-
console.log(ui.yellow("[oac]
|
|
1274
|
+
console.log(ui.yellow("[oac] No agent CLI available. Using simulated execution."));
|
|
1234
1275
|
}
|
|
1235
1276
|
}
|
|
1236
1277
|
const executionSpinner = createSpinner2(
|
|
@@ -1244,11 +1285,11 @@ function createRunCommand() {
|
|
|
1244
1285
|
async (entry) => {
|
|
1245
1286
|
let execution;
|
|
1246
1287
|
let sandbox;
|
|
1247
|
-
if (useRealExecution) {
|
|
1248
|
-
const result = await
|
|
1288
|
+
if (useRealExecution && adapter) {
|
|
1289
|
+
const result = await executeWithAgent({
|
|
1249
1290
|
task: entry.task,
|
|
1250
1291
|
estimate: entry.estimate,
|
|
1251
|
-
|
|
1292
|
+
adapter,
|
|
1252
1293
|
repoPath: resolvedRepo.localPath,
|
|
1253
1294
|
baseBranch: resolvedRepo.meta.defaultBranch,
|
|
1254
1295
|
timeoutSeconds
|
|
@@ -1447,6 +1488,20 @@ function resolveRepoInput2(repoOption, config) {
|
|
|
1447
1488
|
}
|
|
1448
1489
|
throw new Error("No repository specified. Use --repo or configure repos in oac.config.ts.");
|
|
1449
1490
|
}
|
|
1491
|
+
async function resolveAdapter(providerId) {
|
|
1492
|
+
const normalizedId = providerId === "codex-cli" ? "codex" : providerId;
|
|
1493
|
+
const adapters = {
|
|
1494
|
+
codex: () => new CodexAdapter(),
|
|
1495
|
+
"claude-code": () => new ClaudeCodeAdapter()
|
|
1496
|
+
};
|
|
1497
|
+
const factory = adapters[normalizedId];
|
|
1498
|
+
if (!factory) {
|
|
1499
|
+
return { adapter: null, useRealExecution: false };
|
|
1500
|
+
}
|
|
1501
|
+
const adapter = factory();
|
|
1502
|
+
const availability = await adapter.checkAvailability();
|
|
1503
|
+
return { adapter: availability.available ? adapter : null, useRealExecution: availability.available };
|
|
1504
|
+
}
|
|
1450
1505
|
function resolveProviderId2(providerOption, config) {
|
|
1451
1506
|
const fromFlag = providerOption?.trim();
|
|
1452
1507
|
if (fromFlag) {
|
|
@@ -1516,7 +1571,7 @@ async function estimateTaskMap2(tasks, providerId) {
|
|
|
1516
1571
|
);
|
|
1517
1572
|
return new Map(entries);
|
|
1518
1573
|
}
|
|
1519
|
-
async function
|
|
1574
|
+
async function executeWithAgent(input2) {
|
|
1520
1575
|
const startedAt = Date.now();
|
|
1521
1576
|
const taskSlug = input2.task.id.replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").slice(0, 30);
|
|
1522
1577
|
const branchName = `oac/${Date.now()}-${taskSlug}`;
|
|
@@ -1528,7 +1583,7 @@ async function executeWithCodex(input2) {
|
|
|
1528
1583
|
cleanup: sandbox.cleanup
|
|
1529
1584
|
};
|
|
1530
1585
|
try {
|
|
1531
|
-
const result = await workerExecuteTask(input2.
|
|
1586
|
+
const result = await workerExecuteTask(input2.adapter, input2.task, sandbox, eventBus, {
|
|
1532
1587
|
tokenBudget: input2.estimate.totalEstimatedTokens,
|
|
1533
1588
|
timeoutMs: input2.timeoutSeconds * 1e3
|
|
1534
1589
|
});
|
|
@@ -2282,4 +2337,4 @@ export {
|
|
|
2282
2337
|
createCliProgram,
|
|
2283
2338
|
runCli
|
|
2284
2339
|
};
|
|
2285
|
-
//# sourceMappingURL=chunk-
|
|
2340
|
+
//# sourceMappingURL=chunk-GII2GWGO.js.map
|