ghbounty 1.0.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,124 @@
1
+ # ghbounty
2
+
3
+ A GitHub bounty aggregator CLI. Find and track open bounties across GitHub repositories.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g ghbounty
9
+ ```
10
+
11
+ Or run directly:
12
+
13
+ ```bash
14
+ npx ghbounty scan
15
+ ```
16
+
17
+ ## Setup
18
+
19
+ Set a GitHub token for higher API rate limits (optional but recommended):
20
+
21
+ ```bash
22
+ export GITHUB_TOKEN=ghp_your_token_here
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Scan for bounties
28
+
29
+ ```bash
30
+ # Find all open bounties
31
+ ghbounty scan
32
+
33
+ # Filter by minimum amount and language
34
+ ghbounty scan --min 200 --lang typescript
35
+
36
+ # Deep scan (multiple search strategies, finds more results)
37
+ ghbounty scan --deep
38
+
39
+ # Sort by comments (popular/competitive bounties)
40
+ ghbounty scan --sort comments
41
+
42
+ # Output as JSON for scripting
43
+ ghbounty scan --json
44
+
45
+ # Show detailed info for each bounty
46
+ ghbounty scan --detail
47
+ ```
48
+
49
+ ### Watch mode
50
+
51
+ Continuously monitor for new bounties with desktop notifications:
52
+
53
+ ```bash
54
+ # Default: check every 5 minutes
55
+ ghbounty watch
56
+
57
+ # Check every 60 seconds for TypeScript bounties over $500
58
+ ghbounty watch --min 500 --lang typescript --interval 60
59
+
60
+ # Quiet mode: only desktop notifications, no console output
61
+ ghbounty watch --quiet
62
+ ```
63
+
64
+ ### Stats
65
+
66
+ Track your bounty hunting activity:
67
+
68
+ ```bash
69
+ # View stats dashboard
70
+ ghbounty stats
71
+
72
+ # Export stats as JSON
73
+ ghbounty stats --json
74
+
75
+ # Reset all stats
76
+ ghbounty stats --reset
77
+ ```
78
+
79
+ ### Open a bounty
80
+
81
+ ```bash
82
+ ghbounty open https://github.com/org/repo/issues/123
83
+ ```
84
+
85
+ ## How it works
86
+
87
+ 1. **Scan** — Searches GitHub Issues API for bounty-labeled issues (`bounty`, `reward`, `bug bounty`, etc.)
88
+ 2. **Parse** — Extracts dollar amounts from issue titles, labels, and bodies using pattern matching
89
+ 3. **Enrich** — Fetches repository metadata (language, etc.) for each result
90
+ 4. **Display** — Renders a formatted table sorted by bounty value
91
+ 5. **Notify** — Sends macOS desktop notifications for new bounties in watch mode
92
+ 6. **Track** — Persists scan history and stats to `~/.ghbounty/`
93
+
94
+ ## Filters
95
+
96
+ | Flag | Description | Example |
97
+ |------|-------------|---------|
98
+ | `--min <n>` | Minimum bounty amount (USD) | `--min 200` |
99
+ | `--max <n>` | Maximum bounty amount (USD) | `--max 5000` |
100
+ | `--lang <lang>` | Programming language | `--lang rust` |
101
+ | `--sort <field>` | Sort by: `created`, `updated`, `comments` | `--sort comments` |
102
+ | `--limit <n>` | Max results | `--limit 50` |
103
+ | `--deep` | Multi-strategy scan | `--deep` |
104
+
105
+ ## Data storage
106
+
107
+ Stats and seen-bounty tracking are stored in `~/.ghbounty/`:
108
+
109
+ ```
110
+ ~/.ghbounty/
111
+ stats.json — scan history & aggregated stats
112
+ seen.json — URLs of previously seen bounties (for watch mode)
113
+ ```
114
+
115
+ ## Dependencies
116
+
117
+ - **commander** — CLI framework
118
+ - Node.js built-in `fetch` (Node 18+)
119
+
120
+ Zero other runtime dependencies.
121
+
122
+ ## License
123
+
124
+ MIT
@@ -0,0 +1,42 @@
1
+ /**
2
+ * display.ts — Table output formatting for bounty data.
3
+ */
4
+ import type { BountyIssue } from "./scanner.js";
5
+ /**
6
+ * Render a table of bounties.
7
+ */
8
+ export declare function renderTable(bounties: BountyIssue[]): string;
9
+ /**
10
+ * Render a summary header.
11
+ */
12
+ export declare function renderSummary(bounties: BountyIssue[], elapsed: number): string;
13
+ /**
14
+ * Render a detailed view of a single bounty.
15
+ */
16
+ export declare function renderBountyDetail(bounty: BountyIssue): string;
17
+ /**
18
+ * Render stats dashboard.
19
+ */
20
+ export declare function renderStats(stats: {
21
+ totalScans: number;
22
+ totalBountiesFound: number;
23
+ totalValueTracked: number;
24
+ topLanguages: {
25
+ lang: string;
26
+ count: number;
27
+ }[];
28
+ topRepos: {
29
+ repo: string;
30
+ count: number;
31
+ }[];
32
+ lastScanAt: string | null;
33
+ }): string;
34
+ export declare function getSpinnerFrame(tick: number): string;
35
+ /**
36
+ * Render a "no results" message.
37
+ */
38
+ export declare function renderNoResults(options?: {
39
+ language?: string;
40
+ minAmount?: number;
41
+ }): string;
42
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAmHhD;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CA6B3D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,EAAE,MAAM,GACd,MAAM,CAqBR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAgB9D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChD,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,MAAM,CA8BT;AAOD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA0B3F"}
@@ -0,0 +1,249 @@
1
+ /**
2
+ * display.ts — Table output formatting for bounty data.
3
+ */
4
+ const COLUMNS = [
5
+ {
6
+ header: "Amount",
7
+ key: "amountFormatted",
8
+ width: 10,
9
+ align: "right",
10
+ formatter: (v) => colorAmount(v),
11
+ },
12
+ {
13
+ header: "Repository",
14
+ key: "repo",
15
+ width: 30,
16
+ formatter: (v) => truncate(v, 30),
17
+ },
18
+ {
19
+ header: "Title",
20
+ key: "title",
21
+ width: 45,
22
+ formatter: (v) => truncate(v, 45),
23
+ },
24
+ {
25
+ header: "Lang",
26
+ key: "language",
27
+ width: 12,
28
+ formatter: (v) => v || "—",
29
+ },
30
+ {
31
+ header: "Comments",
32
+ key: "comments",
33
+ width: 8,
34
+ align: "right",
35
+ },
36
+ {
37
+ header: "Updated",
38
+ key: "updatedAt",
39
+ width: 12,
40
+ formatter: (v) => formatRelativeDate(v),
41
+ },
42
+ ];
43
+ // ANSI color codes
44
+ const COLORS = {
45
+ reset: "\x1b[0m",
46
+ bold: "\x1b[1m",
47
+ dim: "\x1b[2m",
48
+ green: "\x1b[32m",
49
+ yellow: "\x1b[33m",
50
+ cyan: "\x1b[36m",
51
+ white: "\x1b[37m",
52
+ bgGreen: "\x1b[42m",
53
+ red: "\x1b[31m",
54
+ magenta: "\x1b[35m",
55
+ underline: "\x1b[4m",
56
+ };
57
+ function c(color, text) {
58
+ return `${COLORS[color]}${text}${COLORS.reset}`;
59
+ }
60
+ function colorAmount(amount) {
61
+ if (amount === "TBD")
62
+ return c("dim", amount);
63
+ const num = parseInt(amount.replace(/[$,]/g, ""));
64
+ if (num >= 1000)
65
+ return c("green", c("bold", amount));
66
+ if (num >= 500)
67
+ return c("green", amount);
68
+ if (num >= 100)
69
+ return c("yellow", amount);
70
+ return amount;
71
+ }
72
+ function truncate(str, maxLen) {
73
+ if (!str)
74
+ return "";
75
+ if (str.length <= maxLen)
76
+ return str;
77
+ return str.slice(0, maxLen - 1) + "\u2026";
78
+ }
79
+ function formatRelativeDate(dateStr) {
80
+ const date = new Date(dateStr);
81
+ const now = new Date();
82
+ const diffMs = now.getTime() - date.getTime();
83
+ const diffMins = Math.floor(diffMs / 60000);
84
+ const diffHours = Math.floor(diffMins / 60);
85
+ const diffDays = Math.floor(diffHours / 24);
86
+ if (diffMins < 1)
87
+ return "just now";
88
+ if (diffMins < 60)
89
+ return `${diffMins}m ago`;
90
+ if (diffHours < 24)
91
+ return `${diffHours}h ago`;
92
+ if (diffDays < 7)
93
+ return `${diffDays}d ago`;
94
+ if (diffDays < 30)
95
+ return `${Math.floor(diffDays / 7)}w ago`;
96
+ if (diffDays < 365)
97
+ return `${Math.floor(diffDays / 30)}mo ago`;
98
+ return `${Math.floor(diffDays / 365)}y ago`;
99
+ }
100
+ function pad(str, width, align = "left") {
101
+ // Strip ANSI codes for length calculation
102
+ const stripped = str.replace(/\x1b\[[0-9;]*m/g, "");
103
+ const diff = width - stripped.length;
104
+ if (diff <= 0)
105
+ return str;
106
+ if (align === "right")
107
+ return " ".repeat(diff) + str;
108
+ if (align === "center") {
109
+ const left = Math.floor(diff / 2);
110
+ return " ".repeat(left) + str + " ".repeat(diff - left);
111
+ }
112
+ return str + " ".repeat(diff);
113
+ }
114
+ /**
115
+ * Render a table of bounties.
116
+ */
117
+ export function renderTable(bounties) {
118
+ const lines = [];
119
+ const sep = " ";
120
+ // Header
121
+ const headerLine = COLUMNS.map((col) => c("bold", pad(col.header, col.width, col.align))).join(sep);
122
+ lines.push(headerLine);
123
+ // Separator
124
+ const separatorLine = COLUMNS.map((col) => "\u2500".repeat(col.width)).join(sep);
125
+ lines.push(c("dim", separatorLine));
126
+ // Rows
127
+ for (const bounty of bounties) {
128
+ const cells = COLUMNS.map((col) => {
129
+ let value = bounty[col.key];
130
+ if (col.formatter) {
131
+ value = col.formatter(value, bounty);
132
+ }
133
+ else {
134
+ value = String(value ?? "");
135
+ }
136
+ return pad(value, col.width, col.align);
137
+ });
138
+ lines.push(cells.join(sep));
139
+ }
140
+ return lines.join("\n");
141
+ }
142
+ /**
143
+ * Render a summary header.
144
+ */
145
+ export function renderSummary(bounties, elapsed) {
146
+ const totalBounties = bounties.length;
147
+ const withAmount = bounties.filter((b) => b.amount !== null);
148
+ const totalValue = withAmount.reduce((sum, b) => sum + (b.amount || 0), 0);
149
+ const avgValue = withAmount.length > 0 ? Math.round(totalValue / withAmount.length) : 0;
150
+ const topAmount = withAmount.length > 0 ? withAmount[0].amount : 0;
151
+ const lines = [
152
+ "",
153
+ c("bold", c("cyan", " ghbounty") + " — GitHub Bounty Scanner"),
154
+ c("dim", ` Scanned in ${(elapsed / 1000).toFixed(1)}s`),
155
+ "",
156
+ ` ${c("bold", String(totalBounties))} bounties found | ` +
157
+ `Total: ${c("green", c("bold", "$" + totalValue.toLocaleString()))} | ` +
158
+ `Avg: ${c("yellow", "$" + avgValue.toLocaleString())} | ` +
159
+ `Top: ${c("green", c("bold", "$" + topAmount.toLocaleString()))}`,
160
+ "",
161
+ ];
162
+ return lines.join("\n");
163
+ }
164
+ /**
165
+ * Render a detailed view of a single bounty.
166
+ */
167
+ export function renderBountyDetail(bounty) {
168
+ const lines = [
169
+ "",
170
+ c("bold", ` ${bounty.title}`),
171
+ ` ${c("dim", bounty.repo)} #${bounty.id}`,
172
+ "",
173
+ ` Amount: ${colorAmount(bounty.amountFormatted)}`,
174
+ ` Author: ${bounty.author}`,
175
+ ` Language: ${bounty.language || "Unknown"}`,
176
+ ` Labels: ${bounty.labels.join(", ") || "none"}`,
177
+ ` Comments: ${bounty.comments}`,
178
+ ` Updated: ${formatRelativeDate(bounty.updatedAt)}`,
179
+ ` URL: ${c("underline", c("cyan", bounty.url))}`,
180
+ "",
181
+ ];
182
+ return lines.join("\n");
183
+ }
184
+ /**
185
+ * Render stats dashboard.
186
+ */
187
+ export function renderStats(stats) {
188
+ const lines = [
189
+ "",
190
+ c("bold", c("cyan", " ghbounty") + " — Your Bounty Hunting Stats"),
191
+ "",
192
+ ` Total scans: ${c("bold", String(stats.totalScans))}`,
193
+ ` Bounties found: ${c("bold", String(stats.totalBountiesFound))}`,
194
+ ` Value tracked: ${c("green", c("bold", "$" + stats.totalValueTracked.toLocaleString()))}`,
195
+ ` Last scan: ${stats.lastScanAt ? formatRelativeDate(stats.lastScanAt) : "never"}`,
196
+ "",
197
+ ];
198
+ if (stats.topLanguages.length > 0) {
199
+ lines.push(c("bold", " Top Languages:"));
200
+ for (const { lang, count } of stats.topLanguages.slice(0, 5)) {
201
+ const bar = "\u2588".repeat(Math.min(count, 20));
202
+ lines.push(` ${pad(lang, 15)} ${c("cyan", bar)} ${count}`);
203
+ }
204
+ lines.push("");
205
+ }
206
+ if (stats.topRepos.length > 0) {
207
+ lines.push(c("bold", " Top Repositories:"));
208
+ for (const { repo, count } of stats.topRepos.slice(0, 5)) {
209
+ lines.push(` ${pad(truncate(repo, 35), 37)} ${c("yellow", String(count))} bounties`);
210
+ }
211
+ lines.push("");
212
+ }
213
+ return lines.join("\n");
214
+ }
215
+ /**
216
+ * Render a spinner frame for loading states.
217
+ */
218
+ const SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
219
+ export function getSpinnerFrame(tick) {
220
+ return SPINNER_FRAMES[tick % SPINNER_FRAMES.length];
221
+ }
222
+ /**
223
+ * Render a "no results" message.
224
+ */
225
+ export function renderNoResults(options) {
226
+ const lines = [
227
+ "",
228
+ c("yellow", " No bounties found matching your criteria."),
229
+ "",
230
+ ];
231
+ if (options?.language || options?.minAmount) {
232
+ lines.push(c("dim", " Active filters:"));
233
+ if (options.language) {
234
+ lines.push(c("dim", ` Language: ${options.language}`));
235
+ }
236
+ if (options.minAmount) {
237
+ lines.push(c("dim", ` Min amount: $${options.minAmount}`));
238
+ }
239
+ lines.push("");
240
+ lines.push(c("dim", " Try broadening your search criteria."));
241
+ lines.push("");
242
+ }
243
+ lines.push(c("dim", " Tips:"));
244
+ lines.push(c("dim", " - Set GITHUB_TOKEN for higher API rate limits"));
245
+ lines.push(c("dim", " - Try: ghbounty scan --deep for broader search"));
246
+ lines.push("");
247
+ return lines.join("\n");
248
+ }
249
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ghbounty — GitHub Bounty Aggregator CLI
4
+ *
5
+ * Find and track bounties across GitHub repositories.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}
package/dist/index.js ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ghbounty — GitHub Bounty Aggregator CLI
4
+ *
5
+ * Find and track bounties across GitHub repositories.
6
+ */
7
+ import { Command } from "commander";
8
+ import { scanBounties, deepScan } from "./scanner.js";
9
+ import { notifyBatchBounties } from "./notifier.js";
10
+ import { renderTable, renderSummary, renderNoResults, renderStats, renderBountyDetail, getSpinnerFrame, } from "./display.js";
11
+ import { recordScan, getFormattedStats, loadSeenBounties, saveSeenBounties, resetStats, } from "./store.js";
12
+ const program = new Command();
13
+ program
14
+ .name("ghbounty")
15
+ .description("GitHub bounty aggregator — find and track bounties across GitHub")
16
+ .version("1.0.0");
17
+ // ─── scan command ───────────────────────────────────────────────────────────
18
+ program
19
+ .command("scan")
20
+ .description("Scan GitHub for open bounty issues")
21
+ .option("--min <amount>", "Minimum bounty amount in USD", parseInt)
22
+ .option("--max <amount>", "Maximum bounty amount in USD", parseInt)
23
+ .option("--lang <language>", "Filter by programming language")
24
+ .option("--sort <field>", "Sort by: created, updated, comments", "updated")
25
+ .option("--limit <n>", "Max results to show", parseInt)
26
+ .option("--deep", "Deep scan with multiple search strategies")
27
+ .option("--json", "Output as JSON")
28
+ .option("--detail", "Show detailed view of each bounty")
29
+ .action(async (opts) => {
30
+ const startTime = Date.now();
31
+ // Show scanning indicator
32
+ process.stdout.write("\n Scanning GitHub for bounties");
33
+ const spinnerInterval = setInterval(() => {
34
+ const frame = getSpinnerFrame(Math.floor(Date.now() / 100));
35
+ process.stdout.write(`\r ${frame} Scanning GitHub for bounties...`);
36
+ }, 100);
37
+ try {
38
+ const scanOpts = {
39
+ minAmount: opts.min,
40
+ maxAmount: opts.max,
41
+ language: opts.lang,
42
+ sort: opts.sort,
43
+ limit: opts.limit || 30,
44
+ };
45
+ let bounties;
46
+ if (opts.deep) {
47
+ bounties = await deepScan(scanOpts);
48
+ }
49
+ else {
50
+ bounties = await scanBounties(scanOpts);
51
+ }
52
+ clearInterval(spinnerInterval);
53
+ process.stdout.write("\r" + " ".repeat(60) + "\r"); // Clear spinner line
54
+ const elapsed = Date.now() - startTime;
55
+ if (bounties.length === 0) {
56
+ console.log(renderNoResults({ language: opts.lang, minAmount: opts.min }));
57
+ return;
58
+ }
59
+ // Record stats
60
+ const totalValue = bounties
61
+ .filter((b) => b.amount !== null)
62
+ .reduce((sum, b) => sum + (b.amount || 0), 0);
63
+ recordScan(bounties.length, totalValue, bounties.map((b) => b.language), bounties.map((b) => b.repo));
64
+ if (opts.json) {
65
+ console.log(JSON.stringify(bounties, null, 2));
66
+ return;
67
+ }
68
+ console.log(renderSummary(bounties, elapsed));
69
+ if (opts.detail) {
70
+ for (const bounty of bounties) {
71
+ console.log(renderBountyDetail(bounty));
72
+ }
73
+ }
74
+ else {
75
+ console.log(renderTable(bounties));
76
+ }
77
+ console.log(`\n \x1b[2mTip: Use --detail for full info, or --json for machine-readable output\x1b[0m\n`);
78
+ }
79
+ catch (err) {
80
+ clearInterval(spinnerInterval);
81
+ process.stdout.write("\r" + " ".repeat(60) + "\r");
82
+ console.error(`\n \x1b[31mError:\x1b[0m ${err.message}\n`);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ // ─── watch command ──────────────────────────────────────────────────────────
87
+ program
88
+ .command("watch")
89
+ .description("Continuously monitor for new bounties with desktop notifications")
90
+ .option("--min <amount>", "Minimum bounty amount in USD", parseInt)
91
+ .option("--lang <language>", "Filter by programming language")
92
+ .option("--interval <seconds>", "Check interval in seconds (default: 300)", parseInt)
93
+ .option("--quiet", "Only notify, don't print to console")
94
+ .action(async (opts) => {
95
+ const intervalSec = opts.interval || 300;
96
+ const seen = loadSeenBounties();
97
+ console.log(`\n \x1b[1m\x1b[36mghbounty\x1b[0m — Watch Mode`);
98
+ console.log(` Checking every ${intervalSec}s for new bounties...`);
99
+ if (opts.lang)
100
+ console.log(` Language filter: ${opts.lang}`);
101
+ if (opts.min)
102
+ console.log(` Min amount: $${opts.min}`);
103
+ console.log(` Press Ctrl+C to stop.\n`);
104
+ const check = async () => {
105
+ const timestamp = new Date().toLocaleTimeString();
106
+ try {
107
+ const bounties = await scanBounties({
108
+ minAmount: opts.min,
109
+ language: opts.lang,
110
+ limit: 50,
111
+ });
112
+ const newBounties = bounties.filter((b) => !seen.has(b.url));
113
+ if (newBounties.length > 0) {
114
+ // Mark as seen
115
+ for (const b of newBounties) {
116
+ seen.add(b.url);
117
+ }
118
+ saveSeenBounties(seen);
119
+ // Record stats
120
+ const totalValue = newBounties
121
+ .filter((b) => b.amount !== null)
122
+ .reduce((sum, b) => sum + (b.amount || 0), 0);
123
+ recordScan(newBounties.length, totalValue, newBounties.map((b) => b.language), newBounties.map((b) => b.repo));
124
+ // Notify
125
+ await notifyBatchBounties(newBounties);
126
+ if (!opts.quiet) {
127
+ console.log(` \x1b[32m[${timestamp}]\x1b[0m ${newBounties.length} new bounties found!`);
128
+ console.log(renderTable(newBounties));
129
+ console.log();
130
+ }
131
+ }
132
+ else {
133
+ if (!opts.quiet) {
134
+ process.stdout.write(`\r \x1b[2m[${timestamp}] No new bounties. Next check in ${intervalSec}s...\x1b[0m`);
135
+ }
136
+ }
137
+ }
138
+ catch (err) {
139
+ console.error(`\n \x1b[31m[${timestamp}] Error: ${err.message}\x1b[0m`);
140
+ }
141
+ };
142
+ // Initial check
143
+ await check();
144
+ // Periodic checks
145
+ setInterval(check, intervalSec * 1000);
146
+ });
147
+ // ─── stats command ──────────────────────────────────────────────────────────
148
+ program
149
+ .command("stats")
150
+ .description("Show your bounty hunting statistics")
151
+ .option("--reset", "Reset all stats")
152
+ .option("--json", "Output as JSON")
153
+ .action((opts) => {
154
+ if (opts.reset) {
155
+ resetStats();
156
+ console.log("\n \x1b[32mStats reset successfully.\x1b[0m\n");
157
+ return;
158
+ }
159
+ const stats = getFormattedStats();
160
+ if (opts.json) {
161
+ console.log(JSON.stringify(stats, null, 2));
162
+ return;
163
+ }
164
+ console.log(renderStats(stats));
165
+ });
166
+ // ─── open command (bonus utility) ───────────────────────────────────────────
167
+ program
168
+ .command("open <url>")
169
+ .description("Open a bounty URL in your browser")
170
+ .action((url) => {
171
+ import("node:child_process").then(({ execSync }) => {
172
+ try {
173
+ if (process.platform === "darwin") {
174
+ execSync(`open "${url}"`);
175
+ }
176
+ else if (process.platform === "linux") {
177
+ execSync(`xdg-open "${url}"`);
178
+ }
179
+ else {
180
+ execSync(`start "${url}"`);
181
+ }
182
+ console.log(`\n Opened: ${url}\n`);
183
+ }
184
+ catch {
185
+ console.log(`\n Could not open browser. URL: ${url}\n`);
186
+ }
187
+ });
188
+ });
189
+ program.parse();
190
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * notifier.ts — macOS desktop notifications via osascript.
3
+ */
4
+ import type { BountyIssue } from "./scanner.js";
5
+ /**
6
+ * Send a macOS desktop notification.
7
+ */
8
+ export declare function notify(title: string, message: string, subtitle?: string): Promise<void>;
9
+ /**
10
+ * Notify about a new bounty found.
11
+ */
12
+ export declare function notifyNewBounty(bounty: BountyIssue): Promise<void>;
13
+ /**
14
+ * Notify about multiple new bounties.
15
+ */
16
+ export declare function notifyBatchBounties(bounties: BountyIssue[]): Promise<void>;
17
+ /**
18
+ * Notify about a scan completion.
19
+ */
20
+ export declare function notifyScanComplete(count: number, totalValue: number): Promise<void>;
21
+ //# sourceMappingURL=notifier.d.ts.map