@open330/oac 2026.3.0 → 2026.3.2

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 ADDED
@@ -0,0 +1,453 @@
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
+ [![npm](https://img.shields.io/npm/v/@open330/oac?label=npm&color=CB3837&logo=npm)](https://www.npmjs.com/package/@open330/oac)
16
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
17
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
18
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7+-3178C6?logo=typescript&logoColor=white)](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) | [![npm](https://img.shields.io/npm/v/@open330/oac?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac) | CLI — the main entry point |
284
+ | [`@open330/oac-core`](packages/core) | [![npm](https://img.shields.io/npm/v/@open330/oac-core?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-core) | Event bus, config, types, errors |
285
+ | [`@open330/oac-repo`](packages/repo) | [![npm](https://img.shields.io/npm/v/@open330/oac-repo?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-repo) | GitHub repo resolution, cloning, metadata |
286
+ | [`@open330/oac-discovery`](packages/discovery) | [![npm](https://img.shields.io/npm/v/@open330/oac-discovery?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-discovery) | Task scanners (lint, TODO, test-gap, issues) |
287
+ | [`@open330/oac-budget`](packages/budget) | [![npm](https://img.shields.io/npm/v/@open330/oac-budget?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-budget) | Token estimation, complexity analysis, planning |
288
+ | [`@open330/oac-execution`](packages/execution) | [![npm](https://img.shields.io/npm/v/@open330/oac-execution?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-execution) | Agent pool, job queue, worktree sandbox |
289
+ | [`@open330/oac-completion`](packages/completion) | [![npm](https://img.shields.io/npm/v/@open330/oac-completion?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-completion) | PR creation, issue linking |
290
+ | [`@open330/oac-tracking`](packages/tracking) | [![npm](https://img.shields.io/npm/v/@open330/oac-tracking?label=&color=CB3837)](https://www.npmjs.com/package/@open330/oac-tracking) | Contribution logs, leaderboard |
291
+ | [`@open330/oac-dashboard`](packages/dashboard) | [![npm](https://img.shields.io/npm/v/@open330/oac-dashboard?label=&color=CB3837)](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, Codex CLI (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) | Planned | `codex-cli` |
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, Codex adapter, parallel execution, dashboard, npm publish
406
+ - [ ] **Next** — Multi-agent support (Claude Code + Codex + OpenCode simultaneously)
407
+ - [ ] **Future** — Linear/Jira webhooks, plugin system, sparse checkout for monorepos
408
+
409
+ ---
410
+
411
+ ## Contributing
412
+
413
+ We welcome contributions! OAC is designed to contribute to repos — and it can contribute to itself too.
414
+
415
+ ```bash
416
+ # Clone and setup
417
+ git clone https://github.com/Open330/open-agent-contribution.git
418
+ cd open-agent-contribution
419
+ pnpm install
420
+ pnpm build
421
+
422
+ # Run tests
423
+ pnpm test
424
+
425
+ # Lint and format
426
+ pnpm lint
427
+ pnpm format
428
+
429
+ # Or just let OAC contribute to itself
430
+ npx @open330/oac run --repo Open330/open-agent-contribution --tokens unlimited
431
+ ```
432
+
433
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
434
+
435
+ ---
436
+
437
+ ## Philosophy
438
+
439
+ > **"Don't let your tokens go to waste."**
440
+
441
+ 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.
442
+
443
+ No hosted services. No data collection. No lock-in. Just your machine, your tokens, and your repos.
444
+
445
+ ---
446
+
447
+ <div align="center">
448
+
449
+ **Built with spare tokens by the [Open330](https://github.com/Open330) community.**
450
+
451
+ [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)
452
+
453
+ </div>
@@ -764,6 +764,28 @@ import {
764
764
  rankTasks
765
765
  } from "@open330/oac-discovery";
766
766
  import { cloneRepo, resolveRepo } from "@open330/oac-repo";
767
+
768
+ // src/github-auth.ts
769
+ import { execFileSync } from "child_process";
770
+ function ensureGitHubAuth() {
771
+ if (process.env.GITHUB_TOKEN) return process.env.GITHUB_TOKEN;
772
+ if (process.env.GH_TOKEN) return process.env.GH_TOKEN;
773
+ try {
774
+ const token = execFileSync("gh", ["auth", "token"], {
775
+ timeout: 5e3,
776
+ encoding: "utf-8",
777
+ stdio: ["ignore", "pipe", "ignore"]
778
+ }).trim();
779
+ if (token.length > 0) {
780
+ process.env.GITHUB_TOKEN = token;
781
+ return token;
782
+ }
783
+ } catch {
784
+ }
785
+ return void 0;
786
+ }
787
+
788
+ // src/commands/plan.ts
767
789
  import chalk3, { Chalk as Chalk3 } from "chalk";
768
790
  import Table3 from "cli-table3";
769
791
  import { Command as Command5 } from "commander";
@@ -857,6 +879,7 @@ function createPlanCommand() {
857
879
  const totalBudget = resolveBudget(options.tokens, config);
858
880
  const minPriority = config?.discovery.minPriority ?? 20;
859
881
  const scannerSelection = selectScannersFromConfig(config);
882
+ ensureGitHubAuth();
860
883
  const resolveSpinner = createSpinner(outputJson, "Resolving repository...");
861
884
  const resolvedRepo = await resolveRepo(repoInput);
862
885
  resolveSpinner?.succeed(`Resolved ${resolvedRepo.fullName}`);
@@ -1098,6 +1121,14 @@ function createRunCommand() {
1098
1121
  const scannerSelection = selectScannersFromConfig2(config);
1099
1122
  const runStartedAt = Date.now();
1100
1123
  const runId = randomUUID();
1124
+ const ghToken = ensureGitHubAuth();
1125
+ if (!ghToken && !outputJson) {
1126
+ console.log(
1127
+ ui.yellow(
1128
+ "[oac] Warning: GitHub auth not detected. Run `gh auth login` first to enable PR creation."
1129
+ )
1130
+ );
1131
+ }
1101
1132
  if (!outputJson) {
1102
1133
  console.log(
1103
1134
  ui.blue(
@@ -1111,7 +1142,6 @@ function createRunCommand() {
1111
1142
  const cloneSpinner = createSpinner2(outputJson, "Preparing local clone...");
1112
1143
  await cloneRepo2(resolvedRepo);
1113
1144
  cloneSpinner?.succeed(`Repository ready at ${resolvedRepo.localPath}`);
1114
- const ghToken = await resolveGitHubToken(ui, outputJson);
1115
1145
  const scanSpinner = createSpinner2(
1116
1146
  outputJson,
1117
1147
  `Running scanners: ${scannerSelection.enabled.join(", ")}`
@@ -1543,29 +1573,6 @@ async function executeWithCodex(input2) {
1543
1573
  };
1544
1574
  }
1545
1575
  }
1546
- async function resolveGitHubToken(ui, outputJson) {
1547
- if (process.env.GITHUB_TOKEN) {
1548
- return process.env.GITHUB_TOKEN;
1549
- }
1550
- if (process.env.GH_TOKEN) {
1551
- return process.env.GH_TOKEN;
1552
- }
1553
- try {
1554
- const result = await execa("gh", ["auth", "token"], { reject: false, timeout: 5e3 });
1555
- if (result.exitCode === 0 && result.stdout.trim().length > 0) {
1556
- return result.stdout.trim();
1557
- }
1558
- } catch {
1559
- }
1560
- if (!outputJson) {
1561
- console.log(
1562
- ui.yellow(
1563
- "[oac] Warning: GitHub auth not detected. Run `gh auth login` first to enable PR creation."
1564
- )
1565
- );
1566
- }
1567
- return void 0;
1568
- }
1569
1576
  async function createPullRequest(input2) {
1570
1577
  if (!input2.sandbox) {
1571
1578
  return void 0;
@@ -1899,6 +1906,7 @@ function createScanCommand() {
1899
1906
  )
1900
1907
  );
1901
1908
  }
1909
+ ensureGitHubAuth();
1902
1910
  const resolveSpinner = createSpinner3(outputJson, "Resolving repository...");
1903
1911
  const resolvedRepo = await resolveRepo3(repoInput);
1904
1912
  resolveSpinner?.succeed(`Resolved ${resolvedRepo.fullName}`);
@@ -2274,4 +2282,4 @@ export {
2274
2282
  createCliProgram,
2275
2283
  runCli
2276
2284
  };
2277
- //# sourceMappingURL=chunk-ETHH6TEY.js.map
2285
+ //# sourceMappingURL=chunk-PYSJFMKA.js.map