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 +124 -0
- package/dist/display.d.ts +42 -0
- package/dist/display.d.ts.map +1 -0
- package/dist/display.js +249 -0
- package/dist/display.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/dist/notifier.d.ts +21 -0
- package/dist/notifier.d.ts.map +1 -0
- package/dist/notifier.js +75 -0
- package/dist/notifier.js.map +1 -0
- package/dist/parser.d.ts +27 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +138 -0
- package/dist/parser.js.map +1 -0
- package/dist/scanner.d.ts +45 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +204 -0
- package/dist/scanner.js.map +1 -0
- package/dist/store.d.ts +54 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +107 -0
- package/dist/store.js.map +1 -0
- package/package.json +33 -0
- package/src/display.ts +284 -0
- package/src/index.ts +251 -0
- package/src/notifier.ts +96 -0
- package/src/parser.ts +185 -0
- package/src/scanner.ts +275 -0
- package/src/store.ts +139 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifier.d.ts","sourceRoot":"","sources":["../src/notifier.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD;;GAEG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,WAAW,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
package/dist/notifier.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notifier.ts ā macOS desktop notifications via osascript.
|
|
3
|
+
*/
|
|
4
|
+
import { execFile } from "node:child_process";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
/**
|
|
8
|
+
* Send a macOS desktop notification.
|
|
9
|
+
*/
|
|
10
|
+
export async function notify(title, message, subtitle) {
|
|
11
|
+
if (process.platform !== "darwin") {
|
|
12
|
+
// Fallback: just print to console on non-macOS
|
|
13
|
+
console.log(`\nš ${title}${subtitle ? ` ā ${subtitle}` : ""}`);
|
|
14
|
+
console.log(` ${message}\n`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const parts = [`display notification "${escapeQuotes(message)}"`];
|
|
18
|
+
parts.push(`with title "${escapeQuotes(title)}"`);
|
|
19
|
+
if (subtitle) {
|
|
20
|
+
parts.push(`subtitle "${escapeQuotes(subtitle)}"`);
|
|
21
|
+
}
|
|
22
|
+
parts.push('sound name "Glass"');
|
|
23
|
+
const script = parts.join(" ");
|
|
24
|
+
try {
|
|
25
|
+
await execFileAsync("osascript", ["-e", script]);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Fallback to console if osascript fails
|
|
29
|
+
console.log(`\n[notification] ${title}: ${message}\n`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Notify about a new bounty found.
|
|
34
|
+
*/
|
|
35
|
+
export async function notifyNewBounty(bounty) {
|
|
36
|
+
const amount = bounty.amountFormatted;
|
|
37
|
+
const title = "ghbounty ā New Bounty Found!";
|
|
38
|
+
const subtitle = `${amount} ā ${bounty.repo}`;
|
|
39
|
+
const message = truncate(bounty.title, 100);
|
|
40
|
+
await notify(title, message, subtitle);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Notify about multiple new bounties.
|
|
44
|
+
*/
|
|
45
|
+
export async function notifyBatchBounties(bounties) {
|
|
46
|
+
if (bounties.length === 0)
|
|
47
|
+
return;
|
|
48
|
+
if (bounties.length === 1) {
|
|
49
|
+
await notifyNewBounty(bounties[0]);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const totalValue = bounties.reduce((sum, b) => sum + (b.amount || 0), 0);
|
|
53
|
+
const title = "ghbounty ā New Bounties Found!";
|
|
54
|
+
const subtitle = `${bounties.length} bounties worth $${totalValue.toLocaleString()}+`;
|
|
55
|
+
const topBounty = bounties[0];
|
|
56
|
+
const message = `Top: ${topBounty.amountFormatted} ā ${truncate(topBounty.title, 80)}`;
|
|
57
|
+
await notify(title, message, subtitle);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Notify about a scan completion.
|
|
61
|
+
*/
|
|
62
|
+
export async function notifyScanComplete(count, totalValue) {
|
|
63
|
+
const title = "ghbounty ā Scan Complete";
|
|
64
|
+
const message = `Found ${count} bounties worth $${totalValue.toLocaleString()}+`;
|
|
65
|
+
await notify(title, message);
|
|
66
|
+
}
|
|
67
|
+
function escapeQuotes(str) {
|
|
68
|
+
return str.replace(/"/g, '\\"').replace(/\\/g, "\\\\");
|
|
69
|
+
}
|
|
70
|
+
function truncate(str, maxLen) {
|
|
71
|
+
if (str.length <= maxLen)
|
|
72
|
+
return str;
|
|
73
|
+
return str.slice(0, maxLen - 3) + "...";
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifier.js","sourceRoot":"","sources":["../src/notifier.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parser.ts ā Extracts dollar amounts from issue titles, labels, and bodies.
|
|
3
|
+
*/
|
|
4
|
+
export interface BountyAmount {
|
|
5
|
+
value: number;
|
|
6
|
+
currency: string;
|
|
7
|
+
source: "title" | "label" | "body";
|
|
8
|
+
raw: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ParsedBounty {
|
|
11
|
+
amounts: BountyAmount[];
|
|
12
|
+
bestAmount: number | null;
|
|
13
|
+
hasBounty: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse an issue for bounty amounts.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseIssueBounty(title: string, labels: string[], body: string | null): ParsedBounty;
|
|
19
|
+
/**
|
|
20
|
+
* Check if labels indicate a bounty issue.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isBountyLabel(label: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Format a dollar amount for display.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatAmount(value: number): string;
|
|
27
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;CACb;AA6GD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,EAChB,IAAI,EAAE,MAAM,GAAG,IAAI,GAClB,YAAY,CA2Bd;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parser.ts ā Extracts dollar amounts from issue titles, labels, and bodies.
|
|
3
|
+
*/
|
|
4
|
+
// Patterns that match dollar amounts in various formats
|
|
5
|
+
const DOLLAR_PATTERNS = [
|
|
6
|
+
// $500, $1,000, $1000.00, $50.5k
|
|
7
|
+
/\$\s?([\d,]+(?:\.\d{1,2})?)\s?k?\b/gi,
|
|
8
|
+
// 500 USD, 1000 usd
|
|
9
|
+
/([\d,]+(?:\.\d{1,2})?)\s?(?:USD|usd)\b/g,
|
|
10
|
+
// "500 dollars", "1000 dollar"
|
|
11
|
+
/([\d,]+(?:\.\d{1,2})?)\s?dollars?\b/gi,
|
|
12
|
+
// "bounty: 500", "reward: 1000"
|
|
13
|
+
/(?:bounty|reward|prize|payout)\s*[:=]\s*\$?\s*([\d,]+(?:\.\d{1,2})?)\s?k?\b/gi,
|
|
14
|
+
];
|
|
15
|
+
function parseNumericValue(raw) {
|
|
16
|
+
// Remove dollar sign, commas, and spaces
|
|
17
|
+
let cleaned = raw.replace(/[$,\s]/g, "");
|
|
18
|
+
// Check for "k" suffix (e.g., $5k = $5000)
|
|
19
|
+
const kMatch = cleaned.match(/^([\d.]+)k$/i);
|
|
20
|
+
if (kMatch) {
|
|
21
|
+
return parseFloat(kMatch[1]) * 1000;
|
|
22
|
+
}
|
|
23
|
+
return parseFloat(cleaned);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract bounty amounts from a text string.
|
|
27
|
+
*/
|
|
28
|
+
function extractFromText(text, source) {
|
|
29
|
+
const amounts = [];
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const pattern of DOLLAR_PATTERNS) {
|
|
32
|
+
// Reset lastIndex for global regex
|
|
33
|
+
pattern.lastIndex = 0;
|
|
34
|
+
let match;
|
|
35
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
36
|
+
const raw = match[0];
|
|
37
|
+
const value = parseNumericValue(raw);
|
|
38
|
+
// Skip invalid or already-seen values
|
|
39
|
+
if (isNaN(value) || value <= 0 || value > 1_000_000 || seen.has(value)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
seen.add(value);
|
|
43
|
+
amounts.push({
|
|
44
|
+
value,
|
|
45
|
+
currency: "USD",
|
|
46
|
+
source,
|
|
47
|
+
raw: raw.trim(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return amounts;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract bounty amounts from issue labels.
|
|
55
|
+
* Common patterns: "bounty: $500", "reward-500", "$200", "bounty-200-usd"
|
|
56
|
+
*/
|
|
57
|
+
function extractFromLabels(labels) {
|
|
58
|
+
const amounts = [];
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
for (const label of labels) {
|
|
61
|
+
// Direct dollar label: "$500"
|
|
62
|
+
const dollarMatch = label.match(/\$\s?([\d,]+(?:\.\d{1,2})?)\s?k?/i);
|
|
63
|
+
if (dollarMatch) {
|
|
64
|
+
const value = parseNumericValue(dollarMatch[0]);
|
|
65
|
+
if (!isNaN(value) && value > 0 && value <= 1_000_000 && !seen.has(value)) {
|
|
66
|
+
seen.add(value);
|
|
67
|
+
amounts.push({
|
|
68
|
+
value,
|
|
69
|
+
currency: "USD",
|
|
70
|
+
source: "label",
|
|
71
|
+
raw: dollarMatch[0].trim(),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Bounty label with number: "bounty-500", "reward: 200"
|
|
76
|
+
const bountyMatch = label.match(/(?:bounty|reward|prize)[\s:\-_]+([\d,]+)/i);
|
|
77
|
+
if (bountyMatch) {
|
|
78
|
+
const value = parseFloat(bountyMatch[1].replace(/,/g, ""));
|
|
79
|
+
if (!isNaN(value) && value > 0 && value <= 1_000_000 && !seen.has(value)) {
|
|
80
|
+
seen.add(value);
|
|
81
|
+
amounts.push({
|
|
82
|
+
value,
|
|
83
|
+
currency: "USD",
|
|
84
|
+
source: "label",
|
|
85
|
+
raw: bountyMatch[0].trim(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return amounts;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse an issue for bounty amounts.
|
|
94
|
+
*/
|
|
95
|
+
export function parseIssueBounty(title, labels, body) {
|
|
96
|
+
const titleAmounts = extractFromText(title, "title");
|
|
97
|
+
const labelAmounts = extractFromLabels(labels);
|
|
98
|
+
const bodyAmounts = body ? extractFromText(body, "body") : [];
|
|
99
|
+
const allAmounts = [...titleAmounts, ...labelAmounts, ...bodyAmounts];
|
|
100
|
+
// Deduplicate by value, keeping the highest-priority source (title > label > body)
|
|
101
|
+
const uniqueMap = new Map();
|
|
102
|
+
const priority = { title: 3, label: 2, body: 1 };
|
|
103
|
+
for (const amt of allAmounts) {
|
|
104
|
+
const existing = uniqueMap.get(amt.value);
|
|
105
|
+
if (!existing || priority[amt.source] > priority[existing.source]) {
|
|
106
|
+
uniqueMap.set(amt.value, amt);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const amounts = Array.from(uniqueMap.values()).sort((a, b) => b.value - a.value);
|
|
110
|
+
return {
|
|
111
|
+
amounts,
|
|
112
|
+
bestAmount: amounts.length > 0 ? amounts[0].value : null,
|
|
113
|
+
hasBounty: amounts.length > 0,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if labels indicate a bounty issue.
|
|
118
|
+
*/
|
|
119
|
+
export function isBountyLabel(label) {
|
|
120
|
+
const lower = label.toLowerCase();
|
|
121
|
+
return (lower.includes("bounty") ||
|
|
122
|
+
lower.includes("reward") ||
|
|
123
|
+
lower.includes("prize") ||
|
|
124
|
+
lower.includes("š°") ||
|
|
125
|
+
lower.includes("šµ") ||
|
|
126
|
+
lower.includes("money") ||
|
|
127
|
+
/\$\d+/.test(label));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Format a dollar amount for display.
|
|
131
|
+
*/
|
|
132
|
+
export function formatAmount(value) {
|
|
133
|
+
if (value >= 1000) {
|
|
134
|
+
return `$${value.toLocaleString("en-US")}`;
|
|
135
|
+
}
|
|
136
|
+
return `$${value}`;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scanner.ts ā Uses GitHub API (via native fetch) to search for bounty-labeled issues.
|
|
3
|
+
*/
|
|
4
|
+
export interface BountyIssue {
|
|
5
|
+
id: number;
|
|
6
|
+
title: string;
|
|
7
|
+
url: string;
|
|
8
|
+
repo: string;
|
|
9
|
+
author: string;
|
|
10
|
+
labels: string[];
|
|
11
|
+
amount: number | null;
|
|
12
|
+
amountFormatted: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
comments: number;
|
|
16
|
+
state: string;
|
|
17
|
+
language: string | null;
|
|
18
|
+
body: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface ScanOptions {
|
|
21
|
+
minAmount?: number;
|
|
22
|
+
maxAmount?: number;
|
|
23
|
+
language?: string;
|
|
24
|
+
sort?: "created" | "updated" | "comments";
|
|
25
|
+
order?: "asc" | "desc";
|
|
26
|
+
limit?: number;
|
|
27
|
+
query?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Scan GitHub for bounty issues.
|
|
31
|
+
*/
|
|
32
|
+
export declare function scanBounties(options?: ScanOptions): Promise<BountyIssue[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Get rate limit information.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getRateLimit(): Promise<{
|
|
37
|
+
remaining: number;
|
|
38
|
+
limit: number;
|
|
39
|
+
resetAt: Date;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Scan with multiple search strategies to find more bounties.
|
|
43
|
+
*/
|
|
44
|
+
export declare function deepScan(options?: ScanOptions): Promise<BountyIssue[]>;
|
|
45
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAC1C,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuED;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,EAAE,CAAC,CAmExB;AA+BD;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,IAAI,CAAC;CACf,CAAC,CAOD;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAkDhF"}
|
package/dist/scanner.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scanner.ts ā Uses GitHub API (via native fetch) to search for bounty-labeled issues.
|
|
3
|
+
*/
|
|
4
|
+
import { parseIssueBounty, formatAmount } from "./parser.js";
|
|
5
|
+
const GITHUB_API = "https://api.github.com";
|
|
6
|
+
function getHeaders() {
|
|
7
|
+
const headers = {
|
|
8
|
+
Accept: "application/vnd.github.v3+json",
|
|
9
|
+
"User-Agent": "ghbounty-cli/1.0.0",
|
|
10
|
+
};
|
|
11
|
+
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
|
|
12
|
+
if (token) {
|
|
13
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
14
|
+
}
|
|
15
|
+
return headers;
|
|
16
|
+
}
|
|
17
|
+
async function githubFetch(url) {
|
|
18
|
+
const response = await fetch(url, { headers: getHeaders() });
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
if (response.status === 403) {
|
|
21
|
+
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
22
|
+
if (remaining === "0") {
|
|
23
|
+
const resetTime = response.headers.get("x-ratelimit-reset");
|
|
24
|
+
const resetDate = resetTime
|
|
25
|
+
? new Date(parseInt(resetTime) * 1000)
|
|
26
|
+
: null;
|
|
27
|
+
throw new Error(`GitHub API rate limit exceeded. Resets at ${resetDate?.toLocaleTimeString() ?? "unknown"}. Set GITHUB_TOKEN for higher limits.`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (response.status === 401) {
|
|
31
|
+
throw new Error("GitHub API authentication failed. Check your GITHUB_TOKEN.");
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
return response.json();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a GitHub search query for bounty issues.
|
|
39
|
+
*/
|
|
40
|
+
function buildSearchQuery(options) {
|
|
41
|
+
const parts = [];
|
|
42
|
+
// Base: open issues with bounty-related labels
|
|
43
|
+
parts.push("is:issue");
|
|
44
|
+
parts.push("is:open");
|
|
45
|
+
// Custom query or default bounty search
|
|
46
|
+
if (options.query) {
|
|
47
|
+
parts.push(options.query);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Simple label-based search ā GitHub search doesn't handle complex OR well
|
|
51
|
+
parts.push("label:bounty");
|
|
52
|
+
}
|
|
53
|
+
// Language filter
|
|
54
|
+
if (options.language) {
|
|
55
|
+
parts.push(`language:${options.language}`);
|
|
56
|
+
}
|
|
57
|
+
return parts.join(" ");
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Scan GitHub for bounty issues.
|
|
61
|
+
*/
|
|
62
|
+
export async function scanBounties(options = {}) {
|
|
63
|
+
const query = buildSearchQuery(options);
|
|
64
|
+
const sort = options.sort || "updated";
|
|
65
|
+
const order = options.order || "desc";
|
|
66
|
+
const limit = Math.min(options.limit || 30, 100);
|
|
67
|
+
const searchUrl = `${GITHUB_API}/search/issues?q=${encodeURIComponent(query)}&sort=${sort}&order=${order}&per_page=${limit}`;
|
|
68
|
+
const data = await githubFetch(searchUrl);
|
|
69
|
+
if (!data.items || !Array.isArray(data.items)) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const bounties = [];
|
|
73
|
+
for (const item of data.items) {
|
|
74
|
+
const labels = (item.labels || []).map((l) => l.name || l);
|
|
75
|
+
const repoUrl = item.repository_url || "";
|
|
76
|
+
const repo = repoUrl.replace(`${GITHUB_API}/repos/`, "");
|
|
77
|
+
const parsed = parseIssueBounty(item.title, labels, item.body);
|
|
78
|
+
const bounty = {
|
|
79
|
+
id: item.number,
|
|
80
|
+
title: item.title,
|
|
81
|
+
url: item.html_url,
|
|
82
|
+
repo,
|
|
83
|
+
author: item.user?.login || "unknown",
|
|
84
|
+
labels,
|
|
85
|
+
amount: parsed.bestAmount,
|
|
86
|
+
amountFormatted: parsed.bestAmount
|
|
87
|
+
? formatAmount(parsed.bestAmount)
|
|
88
|
+
: "TBD",
|
|
89
|
+
createdAt: item.created_at,
|
|
90
|
+
updatedAt: item.updated_at,
|
|
91
|
+
comments: item.comments || 0,
|
|
92
|
+
state: item.state,
|
|
93
|
+
language: null, // We'll enrich this if needed
|
|
94
|
+
body: item.body,
|
|
95
|
+
};
|
|
96
|
+
// Apply min/max amount filters
|
|
97
|
+
if (options.minAmount && bounty.amount !== null && bounty.amount < options.minAmount) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (options.maxAmount && bounty.amount !== null && bounty.amount > options.maxAmount) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
bounties.push(bounty);
|
|
104
|
+
}
|
|
105
|
+
// Try to enrich with repo language info
|
|
106
|
+
await enrichLanguageInfo(bounties);
|
|
107
|
+
// Sort by amount descending (null amounts go last)
|
|
108
|
+
bounties.sort((a, b) => {
|
|
109
|
+
if (a.amount === null && b.amount === null)
|
|
110
|
+
return 0;
|
|
111
|
+
if (a.amount === null)
|
|
112
|
+
return 1;
|
|
113
|
+
if (b.amount === null)
|
|
114
|
+
return -1;
|
|
115
|
+
return b.amount - a.amount;
|
|
116
|
+
});
|
|
117
|
+
return bounties;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Enrich bounty issues with repository language information.
|
|
121
|
+
* Uses a cache to avoid redundant API calls.
|
|
122
|
+
*/
|
|
123
|
+
async function enrichLanguageInfo(bounties) {
|
|
124
|
+
const repoCache = new Map();
|
|
125
|
+
const uniqueRepos = [...new Set(bounties.map((b) => b.repo))];
|
|
126
|
+
// Fetch repo info for unique repos (in batches to avoid rate limits)
|
|
127
|
+
const batchSize = 5;
|
|
128
|
+
for (let i = 0; i < uniqueRepos.length; i += batchSize) {
|
|
129
|
+
const batch = uniqueRepos.slice(i, i + batchSize);
|
|
130
|
+
const promises = batch.map(async (repo) => {
|
|
131
|
+
try {
|
|
132
|
+
const data = await githubFetch(`${GITHUB_API}/repos/${repo}`);
|
|
133
|
+
repoCache.set(repo, data.language || null);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
repoCache.set(repo, null);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
await Promise.all(promises);
|
|
140
|
+
}
|
|
141
|
+
// Apply language info
|
|
142
|
+
for (const bounty of bounties) {
|
|
143
|
+
bounty.language = repoCache.get(bounty.repo) ?? null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get rate limit information.
|
|
148
|
+
*/
|
|
149
|
+
export async function getRateLimit() {
|
|
150
|
+
const data = await githubFetch(`${GITHUB_API}/rate_limit`);
|
|
151
|
+
return {
|
|
152
|
+
remaining: data.resources.search.remaining,
|
|
153
|
+
limit: data.resources.search.limit,
|
|
154
|
+
resetAt: new Date(data.resources.search.reset * 1000),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Scan with multiple search strategies to find more bounties.
|
|
159
|
+
*/
|
|
160
|
+
export async function deepScan(options = {}) {
|
|
161
|
+
const queries = [
|
|
162
|
+
'label:bounty',
|
|
163
|
+
'label:"bug bounty"',
|
|
164
|
+
'label:reward',
|
|
165
|
+
'label:š°',
|
|
166
|
+
'"bounty" in:title',
|
|
167
|
+
'"reward" in:title',
|
|
168
|
+
'"$" "bounty" in:body',
|
|
169
|
+
];
|
|
170
|
+
const allBounties = new Map();
|
|
171
|
+
for (const query of queries) {
|
|
172
|
+
try {
|
|
173
|
+
const results = await scanBounties({ ...options, query, limit: 30 });
|
|
174
|
+
for (const bounty of results) {
|
|
175
|
+
const key = bounty.url;
|
|
176
|
+
if (!allBounties.has(key)) {
|
|
177
|
+
allBounties.set(key, bounty);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Continue with next query on failure
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
let bounties = Array.from(allBounties.values());
|
|
186
|
+
// Apply filters again on merged results
|
|
187
|
+
if (options.minAmount) {
|
|
188
|
+
bounties = bounties.filter((b) => b.amount === null || b.amount >= options.minAmount);
|
|
189
|
+
}
|
|
190
|
+
if (options.language) {
|
|
191
|
+
bounties = bounties.filter((b) => b.language?.toLowerCase() === options.language.toLowerCase());
|
|
192
|
+
}
|
|
193
|
+
bounties.sort((a, b) => {
|
|
194
|
+
if (a.amount === null && b.amount === null)
|
|
195
|
+
return 0;
|
|
196
|
+
if (a.amount === null)
|
|
197
|
+
return 1;
|
|
198
|
+
if (b.amount === null)
|
|
199
|
+
return -1;
|
|
200
|
+
return b.amount - a.amount;
|
|
201
|
+
});
|
|
202
|
+
return bounties.slice(0, options.limit || 50);
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* store.ts ā Persistent storage for stats and watch state.
|
|
3
|
+
*/
|
|
4
|
+
interface StatsData {
|
|
5
|
+
totalScans: number;
|
|
6
|
+
totalBountiesFound: number;
|
|
7
|
+
totalValueTracked: number;
|
|
8
|
+
languageCounts: Record<string, number>;
|
|
9
|
+
repoCounts: Record<string, number>;
|
|
10
|
+
lastScanAt: string | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Load stats from disk.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadStats(): StatsData;
|
|
16
|
+
/**
|
|
17
|
+
* Save stats to disk.
|
|
18
|
+
*/
|
|
19
|
+
export declare function saveStats(stats: StatsData): void;
|
|
20
|
+
/**
|
|
21
|
+
* Record a scan result in stats.
|
|
22
|
+
*/
|
|
23
|
+
export declare function recordScan(bountyCount: number, totalValue: number, languages: (string | null)[], repos: string[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Get formatted stats for display.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getFormattedStats(): {
|
|
28
|
+
totalScans: number;
|
|
29
|
+
totalBountiesFound: number;
|
|
30
|
+
totalValueTracked: number;
|
|
31
|
+
topLanguages: {
|
|
32
|
+
lang: string;
|
|
33
|
+
count: number;
|
|
34
|
+
}[];
|
|
35
|
+
topRepos: {
|
|
36
|
+
repo: string;
|
|
37
|
+
count: number;
|
|
38
|
+
}[];
|
|
39
|
+
lastScanAt: string | null;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Load the set of previously seen bounty URLs.
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadSeenBounties(): Set<string>;
|
|
45
|
+
/**
|
|
46
|
+
* Save the set of seen bounty URLs.
|
|
47
|
+
*/
|
|
48
|
+
export declare function saveSeenBounties(seen: Set<string>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Reset all stats.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resetStats(): void;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,UAAU,SAAS;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AA+BD;;GAEG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAErC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAEhD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAC5B,KAAK,EAAE,MAAM,EAAE,GACd,IAAI,CAmBN;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;;;;;;;;;;EAmBhC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,GAAG,CAAC,MAAM,CAAC,CAG9C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAExD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAGjC"}
|