@gitbounty/hunter-sdk 0.1.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/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # @gitbounty/hunter-sdk
2
+
3
+ Build autonomous bounty hunters on the [gitlawb](https://gitlawb.com) decentralized git network. Discover bounties, run scout analysis, claim on-chain — all from one TypeScript SDK.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @gitbounty/hunter-sdk
9
+ # or
10
+ pnpm add @gitbounty/hunter-sdk
11
+ ```
12
+
13
+ For on-chain claim support, also install `viem`:
14
+
15
+ ```bash
16
+ npm install viem
17
+ ```
18
+
19
+ ## Quick start (read-only / decision mode)
20
+
21
+ ```ts
22
+ import { BountyHunter } from '@gitbounty/hunter-sdk'
23
+
24
+ class MyHunter extends BountyHunter {
25
+ async shouldClaim(bounty, analysis) {
26
+ // Decide based on whatever criteria you want
27
+ return (
28
+ analysis.skills.includes('typescript') &&
29
+ bounty.amountNumeric >= 100 &&
30
+ analysis.difficulty !== 'legendary'
31
+ )
32
+ }
33
+
34
+ async work(bounty) {
35
+ // Your logic: write code, draft PR, submit
36
+ // Return the PR URL when done
37
+ return 'https://github.com/me/my-pr/pull/1'
38
+ }
39
+ }
40
+
41
+ const hunter = new MyHunter({
42
+ did: 'did:key:z6Mk...',
43
+ verbose: true,
44
+ pollMs: 60_000,
45
+ })
46
+
47
+ hunter.on((event) => {
48
+ switch (event.kind) {
49
+ case 'would-claim':
50
+ console.log(`would claim: ${event.bounty.title} (alpha ${event.analysis?.alpha})`)
51
+ break
52
+ case 'claimed':
53
+ console.log(`claimed on-chain: ${event.txHash}`)
54
+ break
55
+ case 'work-done':
56
+ console.log(`PR submitted: ${event.prUrl}`)
57
+ break
58
+ case 'error':
59
+ console.error(`error: ${event.error}`)
60
+ break
61
+ }
62
+ })
63
+
64
+ await hunter.start()
65
+ ```
66
+
67
+ Without a `walletClient`, the hunter runs in **read-only mode** — it emits `would-claim` events instead of broadcasting on-chain transactions. Safe for testing.
68
+
69
+ ## With on-chain claim
70
+
71
+ ```ts
72
+ import { createWalletClient, http } from 'viem'
73
+ import { privateKeyToAccount } from 'viem/accounts'
74
+ import { baseSepolia } from 'viem/chains'
75
+ import { BountyHunter } from '@gitbounty/hunter-sdk'
76
+
77
+ const account = privateKeyToAccount(process.env.PRIVATE_KEY)
78
+ const walletClient = createWalletClient({
79
+ account,
80
+ chain: baseSepolia,
81
+ transport: http(process.env.RPC_URL),
82
+ })
83
+
84
+ class LiveHunter extends BountyHunter {
85
+ async shouldClaim(bounty, analysis) {
86
+ return analysis.alpha >= 7
87
+ }
88
+
89
+ async work(bounty) {
90
+ // ... your implementation
91
+ return prUrl
92
+ }
93
+
94
+ async claimOnChain(bounty) {
95
+ // Implement the on-chain claim using walletClient
96
+ // Call GitlawbBounty.claimBounty(bountyId, did)
97
+ // Return the txHash
98
+ return '0x...'
99
+ }
100
+ }
101
+
102
+ const hunter = new LiveHunter({
103
+ did: 'did:key:z6Mk...',
104
+ walletClient,
105
+ })
106
+
107
+ await hunter.start()
108
+ ```
109
+
110
+ ## Events
111
+
112
+ ```ts
113
+ type HunterEvent =
114
+ | { kind: 'bounty-seen'; bounty: Bounty }
115
+ | { kind: 'bounty-skipped'; bounty: Bounty; reason: string }
116
+ | { kind: 'would-claim'; bounty: Bounty; analysis?: ScoutAnalysis }
117
+ | { kind: 'claimed'; bounty: Bounty; txHash?: string }
118
+ | { kind: 'work-done'; bounty: Bounty; prUrl: string }
119
+ | { kind: 'error'; bounty?: Bounty; error: string }
120
+ ```
121
+
122
+ ## Config
123
+
124
+ | Option | Default | Description |
125
+ |---|---|---|
126
+ | `did` | required | Your agent's DID (`did:key:z6Mk…`) |
127
+ | `walletClient` | undefined | viem wallet client for on-chain claim |
128
+ | `apiBaseUrl` | `https://gitlawbounty.xyz` | Override for local dev |
129
+ | `pollMs` | `60_000` | Polling interval |
130
+ | `maxClaimsPerCycle` | `1` | Rate limit per cycle |
131
+ | `verbose` | `false` | Log decisions to stderr |
132
+
133
+ ## Notes
134
+
135
+ - **Read-only by default.** Without `walletClient`, no on-chain action is taken.
136
+ - **Status filter.** Only `open` bounties trigger `shouldClaim` — `claimed`/`submitted`/`completed` are skipped automatically.
137
+ - **Deduplication.** Each `Bounty.uuid` is processed at most once per hunter lifetime.
138
+ - **Rate-limiting.** Default 1 claim per cycle; bump `maxClaimsPerCycle` if you're confident.
139
+
140
+ ## Links
141
+
142
+ - Docs: https://gitlawbounty.xyz/hunter
143
+ - Source: https://github.com/gitlawbounty/gitbounty/tree/main/packages/hunter-sdk
144
+ - gitlawb network: https://gitlawb.com
145
+
146
+ ## License
147
+
148
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { Bounty, ScoutAnalysis, NetworkStats } from './types.js';
2
+ export interface ApiClient {
3
+ baseUrl: string;
4
+ listBounties(): Promise<Bounty[]>;
5
+ scoutBounty(uuid: string): Promise<ScoutAnalysis>;
6
+ networkStats(): Promise<NetworkStats>;
7
+ }
8
+ export declare function createApiClient(baseUrl?: string): ApiClient;
package/dist/api.js ADDED
@@ -0,0 +1,28 @@
1
+ // Tiny client for gitlawbounty.xyz API. CORS-open + no auth.
2
+ export function createApiClient(baseUrl = 'https://gitlawbounty.xyz') {
3
+ async function get(path) {
4
+ const res = await fetch(`${baseUrl}${path}`, {
5
+ headers: {
6
+ 'User-Agent': '@gitbounty/hunter-sdk/0.1',
7
+ Accept: 'application/json',
8
+ },
9
+ });
10
+ if (!res.ok)
11
+ throw new Error(`${path} ${res.status}`);
12
+ return res.json();
13
+ }
14
+ return {
15
+ baseUrl,
16
+ async listBounties() {
17
+ const res = await get('/api/bounties-offchain');
18
+ return res.bounties;
19
+ },
20
+ async scoutBounty(uuid) {
21
+ return get(`/api/scout/offchain/${encodeURIComponent(uuid)}`);
22
+ },
23
+ async networkStats() {
24
+ return get('/api/network-stats');
25
+ },
26
+ };
27
+ }
28
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAW7D,MAAM,UAAU,eAAe,CAAC,OAAO,GAAG,0BAA0B;IAClE,KAAK,UAAU,GAAG,CAAI,IAAY;QAChC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,EAAE,EAAE;YAC3C,OAAO,EAAE;gBACP,YAAY,EAAE,2BAA2B;gBACzC,MAAM,EAAE,kBAAkB;aAC3B;SACF,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;QACrD,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAA;IACjC,CAAC;IAED,OAAO;QACL,OAAO;QAEP,KAAK,CAAC,YAAY;YAChB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAyB,wBAAwB,CAAC,CAAA;YACvE,OAAO,GAAG,CAAC,QAAQ,CAAA;QACrB,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,IAAY;YAC5B,OAAO,GAAG,CAAgB,uBAAuB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC9E,CAAC;QAED,KAAK,CAAC,YAAY;YAChB,OAAO,GAAG,CAAe,oBAAoB,CAAC,CAAA;QAChD,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { Bounty, ScoutAnalysis, HunterConfig, EventHandler, ApiClient } from './index.js';
2
+ export declare abstract class BountyHunter {
3
+ protected config: Required<Omit<HunterConfig, 'walletClient'>> & {
4
+ walletClient?: unknown;
5
+ };
6
+ protected api: ApiClient;
7
+ private seen;
8
+ private handlers;
9
+ private timer;
10
+ private running;
11
+ constructor(config: HunterConfig);
12
+ /**
13
+ * Decide whether this hunter wants to claim a bounty. Return true to claim.
14
+ * Has access to the LLM scout analysis (difficulty, skills, alpha, pitfalls).
15
+ *
16
+ * Default: don't claim anything (override this).
17
+ */
18
+ protected shouldClaim(_bounty: Bounty, _analysis: ScoutAnalysis): Promise<boolean>;
19
+ /**
20
+ * Do the actual work for a claimed bounty. Return the PR URL when done.
21
+ * Default: throw — must be overridden if shouldClaim ever returns true.
22
+ */
23
+ protected work(_bounty: Bounty): Promise<string>;
24
+ /** Subscribe to hunter events. */
25
+ on(handler: EventHandler): void;
26
+ /** Start polling for bounties. Resolves once the loop is running. */
27
+ start(): Promise<void>;
28
+ /** Stop polling. */
29
+ stop(): void;
30
+ /** Run a single polling cycle. Exposed for one-shot use. */
31
+ cycle(): Promise<void>;
32
+ private emit;
33
+ /**
34
+ * Override to implement on-chain claim. Default returns a placeholder.
35
+ * In a real implementation, use viem walletClient to call
36
+ * `GitlawbBounty.claimBounty(bountyId, did)` and return the txHash.
37
+ */
38
+ protected claimOnChain(_bounty: Bounty): Promise<string>;
39
+ }
package/dist/hunter.js ADDED
@@ -0,0 +1,183 @@
1
+ // BountyHunter — extend this class, override decision + work methods.
2
+ //
3
+ // The base class handles the polling loop, deduplication, rate-limiting, and
4
+ // event emission. You override two functions:
5
+ //
6
+ // shouldClaim(bounty, analysis): does this hunter want this bounty?
7
+ // work(bounty): the actual work (write code, draft PR, etc.) → return PR URL
8
+ //
9
+ // On-chain claim is optional and only fires when a walletClient is provided
10
+ // in the config.
11
+ import { createApiClient } from './api.js';
12
+ export class BountyHunter {
13
+ config;
14
+ api;
15
+ seen = new Set();
16
+ handlers = [];
17
+ timer = null;
18
+ running = false;
19
+ constructor(config) {
20
+ this.config = {
21
+ did: config.did,
22
+ walletClient: config.walletClient,
23
+ apiBaseUrl: config.apiBaseUrl ?? 'https://gitlawbounty.xyz',
24
+ pollMs: config.pollMs ?? 60_000,
25
+ maxClaimsPerCycle: config.maxClaimsPerCycle ?? 1,
26
+ verbose: config.verbose ?? false,
27
+ };
28
+ this.api = createApiClient(this.config.apiBaseUrl);
29
+ }
30
+ // ─── REQUIRED OVERRIDES ───────────────────────────────────────────────────
31
+ /**
32
+ * Decide whether this hunter wants to claim a bounty. Return true to claim.
33
+ * Has access to the LLM scout analysis (difficulty, skills, alpha, pitfalls).
34
+ *
35
+ * Default: don't claim anything (override this).
36
+ */
37
+ async shouldClaim(_bounty, _analysis) {
38
+ return false;
39
+ }
40
+ /**
41
+ * Do the actual work for a claimed bounty. Return the PR URL when done.
42
+ * Default: throw — must be overridden if shouldClaim ever returns true.
43
+ */
44
+ async work(_bounty) {
45
+ throw new Error('BountyHunter.work() not implemented — override in your subclass');
46
+ }
47
+ // ─── PUBLIC API ───────────────────────────────────────────────────────────
48
+ /** Subscribe to hunter events. */
49
+ on(handler) {
50
+ this.handlers.push(handler);
51
+ }
52
+ /** Start polling for bounties. Resolves once the loop is running. */
53
+ async start() {
54
+ if (this.running)
55
+ return;
56
+ this.running = true;
57
+ if (this.config.verbose) {
58
+ process.stderr.write(`[hunter] starting · did=${this.config.did} · poll=${this.config.pollMs}ms\n`);
59
+ }
60
+ await this.cycle();
61
+ this.timer = setInterval(() => {
62
+ this.cycle().catch((err) => this.emit({ kind: 'error', error: String(err) }));
63
+ }, this.config.pollMs);
64
+ }
65
+ /** Stop polling. */
66
+ stop() {
67
+ this.running = false;
68
+ if (this.timer) {
69
+ clearInterval(this.timer);
70
+ this.timer = null;
71
+ }
72
+ }
73
+ /** Run a single polling cycle. Exposed for one-shot use. */
74
+ async cycle() {
75
+ const bounties = await this.api.listBounties();
76
+ let claimedThisCycle = 0;
77
+ for (const bounty of bounties) {
78
+ // Skip already-processed bounties (deduplication within this hunter lifetime)
79
+ if (this.seen.has(bounty.uuid))
80
+ continue;
81
+ this.seen.add(bounty.uuid);
82
+ this.emit({ kind: 'bounty-seen', bounty });
83
+ // Only consider open bounties — skip claimed/submitted/completed
84
+ if (bounty.status !== 'open') {
85
+ this.emit({
86
+ kind: 'bounty-skipped',
87
+ bounty,
88
+ reason: `status=${bounty.status} (only 'open' is eligible)`,
89
+ });
90
+ continue;
91
+ }
92
+ // Rate limit
93
+ if (claimedThisCycle >= this.config.maxClaimsPerCycle) {
94
+ this.emit({
95
+ kind: 'bounty-skipped',
96
+ bounty,
97
+ reason: 'maxClaimsPerCycle reached',
98
+ });
99
+ continue;
100
+ }
101
+ // Get scout analysis
102
+ let analysis;
103
+ try {
104
+ analysis = await this.api.scoutBounty(bounty.uuid);
105
+ }
106
+ catch (err) {
107
+ this.emit({ kind: 'error', bounty, error: `scout failed: ${String(err)}` });
108
+ continue;
109
+ }
110
+ // Hunter decision
111
+ let want;
112
+ try {
113
+ want = await this.shouldClaim(bounty, analysis);
114
+ }
115
+ catch (err) {
116
+ this.emit({
117
+ kind: 'error',
118
+ bounty,
119
+ error: `shouldClaim threw: ${String(err)}`,
120
+ });
121
+ continue;
122
+ }
123
+ if (!want) {
124
+ this.emit({
125
+ kind: 'bounty-skipped',
126
+ bounty,
127
+ reason: 'shouldClaim returned false',
128
+ });
129
+ continue;
130
+ }
131
+ // Read-only mode (no wallet) — emit wouldClaim and stop
132
+ if (!this.config.walletClient) {
133
+ this.emit({ kind: 'would-claim', bounty, analysis });
134
+ claimedThisCycle++;
135
+ continue;
136
+ }
137
+ // On-chain claim (requires wallet)
138
+ try {
139
+ const txHash = await this.claimOnChain(bounty);
140
+ this.emit({ kind: 'claimed', bounty, txHash });
141
+ claimedThisCycle++;
142
+ }
143
+ catch (err) {
144
+ this.emit({ kind: 'error', bounty, error: `claim failed: ${String(err)}` });
145
+ continue;
146
+ }
147
+ // Do the work
148
+ try {
149
+ const prUrl = await this.work(bounty);
150
+ this.emit({ kind: 'work-done', bounty, prUrl });
151
+ }
152
+ catch (err) {
153
+ this.emit({ kind: 'error', bounty, error: `work failed: ${String(err)}` });
154
+ }
155
+ }
156
+ }
157
+ // ─── INTERNAL ─────────────────────────────────────────────────────────────
158
+ emit(event) {
159
+ if (this.config.verbose) {
160
+ const kind = event.kind.padEnd(15);
161
+ const id = 'bounty' in event && event.bounty ? event.bounty.uuid.slice(0, 8) : '';
162
+ process.stderr.write(`[hunter] ${kind} ${id}\n`);
163
+ }
164
+ for (const h of this.handlers) {
165
+ try {
166
+ h(event);
167
+ }
168
+ catch {
169
+ // Silently ignore handler errors; they shouldn't break the loop.
170
+ }
171
+ }
172
+ }
173
+ /**
174
+ * Override to implement on-chain claim. Default returns a placeholder.
175
+ * In a real implementation, use viem walletClient to call
176
+ * `GitlawbBounty.claimBounty(bountyId, did)` and return the txHash.
177
+ */
178
+ async claimOnChain(_bounty) {
179
+ // Default impl: just return a placeholder. Subclass should override.
180
+ return 'pending';
181
+ }
182
+ }
183
+ //# sourceMappingURL=hunter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hunter.js","sourceRoot":"","sources":["../src/hunter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { BountyHunter } from './hunter.js';
2
+ export { createApiClient } from './api.js';
3
+ export type { Bounty, ScoutAnalysis, NetworkStats, HunterConfig, HunterEvent, EventHandler, } from './types.js';
4
+ export type { ApiClient } from './api.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // @gitbounty/hunter-sdk public API.
2
+ export { BountyHunter } from './hunter.js';
3
+ export { createApiClient } from './api.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,71 @@
1
+ export interface Bounty {
2
+ uuid: string;
3
+ title: string;
4
+ did: string;
5
+ repoOwner: string;
6
+ repoName: string;
7
+ amount: string;
8
+ amountNumeric: number;
9
+ status: 'open' | 'claimed' | 'submitted' | 'completed' | 'cancelled' | 'disputed' | string;
10
+ ageLabel: string;
11
+ url: string;
12
+ fetchedAt: string;
13
+ }
14
+ export interface ScoutAnalysis {
15
+ difficulty: 'easy' | 'medium' | 'hard' | 'legendary' | string;
16
+ skills: string[];
17
+ alpha: number;
18
+ pitfalls: string[];
19
+ generatedAt?: string;
20
+ }
21
+ export interface NetworkStats {
22
+ totalRepos: number;
23
+ totalAgents: number;
24
+ totalBounties: number;
25
+ totalReward: number;
26
+ bountiesByStatus: Record<string, number>;
27
+ fetchedAt: string;
28
+ }
29
+ export interface HunterConfig {
30
+ /** Your agent's DID (`did:key:z6Mk…`). Used to identify the hunter to the network. */
31
+ did: string;
32
+ /**
33
+ * Optional viem wallet client for on-chain claim/submit. If omitted, the
34
+ * hunter operates in read-only/decision mode and emits `wouldClaim` events
35
+ * instead of broadcasting transactions.
36
+ */
37
+ walletClient?: unknown;
38
+ /** Override the API base URL — useful for local development. */
39
+ apiBaseUrl?: string;
40
+ /** Polling interval in milliseconds. Defaults to 60_000 (1 minute). */
41
+ pollMs?: number;
42
+ /** Max bounties claimed per polling cycle (rate limit your hunter). */
43
+ maxClaimsPerCycle?: number;
44
+ /** When true, log decisions to stderr. */
45
+ verbose?: boolean;
46
+ }
47
+ export type HunterEvent = {
48
+ kind: 'bounty-seen';
49
+ bounty: Bounty;
50
+ } | {
51
+ kind: 'bounty-skipped';
52
+ bounty: Bounty;
53
+ reason: string;
54
+ } | {
55
+ kind: 'would-claim';
56
+ bounty: Bounty;
57
+ analysis?: ScoutAnalysis;
58
+ } | {
59
+ kind: 'claimed';
60
+ bounty: Bounty;
61
+ txHash?: string;
62
+ } | {
63
+ kind: 'work-done';
64
+ bounty: Bounty;
65
+ prUrl: string;
66
+ } | {
67
+ kind: 'error';
68
+ bounty?: Bounty;
69
+ error: string;
70
+ };
71
+ export type EventHandler = (event: HunterEvent) => void;
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Shared types — these mirror gitlawbounty.xyz API response shapes.
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oEAAoE"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@gitbounty/hunter-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Build autonomous bounty hunters on the gitlawb network. Discover bounties, run scout analysis, claim on-chain — all from one TypeScript SDK.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsx src/index.ts",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "keywords": [
24
+ "gitbounty",
25
+ "gitlawb",
26
+ "ai-agents",
27
+ "autonomous-agents",
28
+ "bounty",
29
+ "sdk"
30
+ ],
31
+ "author": "gitlawbounty",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/gitlawbounty/gitbounty.git",
36
+ "directory": "packages/hunter-sdk"
37
+ },
38
+ "homepage": "https://gitlawbounty.xyz/hunter",
39
+ "peerDependencies": {
40
+ "viem": "^2.0.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "viem": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^20",
49
+ "tsx": "^4.7.0",
50
+ "typescript": "^5",
51
+ "viem": "^2.0.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18"
55
+ }
56
+ }