doppelgangers 0.0.1
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/.husky/pre-commit +21 -0
- package/README.md +87 -0
- package/biome.json +27 -0
- package/dist/build.d.ts +10 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +951 -0
- package/dist/build.js.map +1 -0
- package/dist/embed.d.ts +11 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +147 -0
- package/dist/embed.js.map +1 -0
- package/dist/triage.d.ts +3 -0
- package/dist/triage.d.ts.map +1 -0
- package/dist/triage.js +220 -0
- package/dist/triage.js.map +1 -0
- package/package.json +36 -0
- package/src/build.ts +995 -0
- package/src/embed.ts +182 -0
- package/src/triage.ts +256 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAoC/B,MAAM,UAAU,KAAK,CAAC,OAAqB,EAAQ;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEhD,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC;YACJ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACR,qBAAqB;QACtB,CAAC;IACF,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3D,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAE1D,IAAI,QAAoB,CAAC;IACzB,IAAI,QAAoB,CAAC;IAEzB,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,mCAAmC,eAAe,EAAE,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QACpE,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC3B,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC5B,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC;YACvB,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM,EAAE,IAAI,CAAC,MAAM;SACnB,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC;YACvB,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM,EAAE,IAAI,CAAC,MAAM;SACnB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,sBAAsB,UAAU,CAAC,MAAM,aAAa,CAAC,CAAC;QAClE,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,sBAAsB,UAAU,CAAC,MAAM,aAAa,CAAC,CAAC;QAClE,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAElC,EAAE,CAAC,aAAa,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,wBAAwB,eAAe,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC;IAEhC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,CAAC;IAEnC,MAAM,MAAM,GAAY,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7C,OAAO;YACN,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM;YAC7B,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM;YAC7B,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO;YACnC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO;YACnC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO;YACnC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;SAClE,CAAC;IAAA,CACF,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAEjE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;AAAA,CACnC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAU;IAC/C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA+Sa,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAugBrB,CAAC;AAAA,CACR;AAED,kBAAkB;AAClB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;IACpF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAiB;QAC7B,KAAK,EAAE,kBAAkB;QACzB,MAAM,EAAE,aAAa;QACrB,WAAW,EAAE,kBAAkB;QAC/B,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,GAAG;QACZ,iBAAiB,EAAE,KAAK;KACxB,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;YACpC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAClC,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACjC,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YAC/B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAClC,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,CAAC;AAChB,CAAC"}
|
package/dist/embed.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface EmbedOptions {
|
|
2
|
+
input: string;
|
|
3
|
+
output: string;
|
|
4
|
+
model: string;
|
|
5
|
+
batchSize: number;
|
|
6
|
+
maxChars: number;
|
|
7
|
+
bodyChars: number;
|
|
8
|
+
resume: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function embed(options: EmbedOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=embed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CAChB;AAkCD,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoGhE"}
|
package/dist/embed.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
import path from "path";
|
|
4
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
const buildText = (title, body, maxChars) => {
|
|
6
|
+
const bodyText = (body || "").replace(/\r\n/g, "\n").trim();
|
|
7
|
+
const combined = `${title}\n\n${bodyText}`.trim();
|
|
8
|
+
return combined.slice(0, maxChars);
|
|
9
|
+
};
|
|
10
|
+
const buildSnippet = (body, bodyChars) => {
|
|
11
|
+
if (!body)
|
|
12
|
+
return "";
|
|
13
|
+
return body.replace(/\s+/g, " ").trim().slice(0, bodyChars);
|
|
14
|
+
};
|
|
15
|
+
export async function embed(options) {
|
|
16
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
17
|
+
console.error("OPENAI_API_KEY is required");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const inputPath = path.resolve(options.input);
|
|
21
|
+
const outputPath = path.resolve(options.output);
|
|
22
|
+
const items = JSON.parse(fs.readFileSync(inputPath, "utf8"));
|
|
23
|
+
const existing = new Map();
|
|
24
|
+
if (options.resume && fs.existsSync(outputPath)) {
|
|
25
|
+
const lines = fs.readFileSync(outputPath, "utf8").split("\n").filter(Boolean);
|
|
26
|
+
for (const line of lines) {
|
|
27
|
+
try {
|
|
28
|
+
const item = JSON.parse(line);
|
|
29
|
+
if (item.url)
|
|
30
|
+
existing.set(item.url, item);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// skip invalid lines
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
38
|
+
const outputDir = path.dirname(outputPath);
|
|
39
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
40
|
+
const outputStream = fs.createWriteStream(outputPath, { flags: options.resume ? "a" : "w" });
|
|
41
|
+
const pending = items.filter((item) => item?.url && !existing.has(item.url));
|
|
42
|
+
const total = pending.length;
|
|
43
|
+
let processed = 0;
|
|
44
|
+
const skipped = items.length - pending.length;
|
|
45
|
+
let batchInputs = [];
|
|
46
|
+
let batchMeta = [];
|
|
47
|
+
const createEmbeddings = async (inputs, attempt = 1) => {
|
|
48
|
+
try {
|
|
49
|
+
const response = await client.embeddings.create({
|
|
50
|
+
model: options.model,
|
|
51
|
+
input: inputs,
|
|
52
|
+
});
|
|
53
|
+
return response.data.map((item) => item.embedding);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (attempt >= 5)
|
|
57
|
+
throw error;
|
|
58
|
+
const delay = 1000 * attempt;
|
|
59
|
+
console.warn(`Embedding request failed, retrying in ${delay}ms`, error.message);
|
|
60
|
+
await sleep(delay);
|
|
61
|
+
return createEmbeddings(inputs, attempt + 1);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const flushBatch = async () => {
|
|
65
|
+
if (!batchInputs.length)
|
|
66
|
+
return;
|
|
67
|
+
const embeddings = await createEmbeddings(batchInputs);
|
|
68
|
+
for (let i = 0; i < embeddings.length; i += 1) {
|
|
69
|
+
const meta = batchMeta[i];
|
|
70
|
+
const record = {
|
|
71
|
+
url: meta.url,
|
|
72
|
+
number: meta.number,
|
|
73
|
+
title: meta.title,
|
|
74
|
+
body: meta.body,
|
|
75
|
+
state: meta.state,
|
|
76
|
+
type: meta.type,
|
|
77
|
+
embedding: embeddings[i],
|
|
78
|
+
};
|
|
79
|
+
outputStream.write(`${JSON.stringify(record)}\n`);
|
|
80
|
+
processed += 1;
|
|
81
|
+
if (processed % 50 === 0 || processed === total) {
|
|
82
|
+
console.log(`Embedded ${processed}/${total} items`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
batchInputs = [];
|
|
86
|
+
batchMeta = [];
|
|
87
|
+
};
|
|
88
|
+
for (const item of pending) {
|
|
89
|
+
const title = item.title || "";
|
|
90
|
+
const body = item.body || "";
|
|
91
|
+
const text = buildText(title, body, options.maxChars);
|
|
92
|
+
batchInputs.push(text || title || item.url);
|
|
93
|
+
batchMeta.push({
|
|
94
|
+
url: item.url,
|
|
95
|
+
number: item.number,
|
|
96
|
+
title,
|
|
97
|
+
body: buildSnippet(body, options.bodyChars),
|
|
98
|
+
state: item.state,
|
|
99
|
+
type: item.type,
|
|
100
|
+
});
|
|
101
|
+
if (batchInputs.length >= options.batchSize) {
|
|
102
|
+
await flushBatch();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
await flushBatch();
|
|
106
|
+
outputStream.end();
|
|
107
|
+
console.log(`Done. Embedded ${processed}/${total} PRs, skipped ${skipped}.`);
|
|
108
|
+
}
|
|
109
|
+
// CLI entry point
|
|
110
|
+
if (process.argv[1]?.endsWith("embed.js") || process.argv[1]?.endsWith("embed.ts")) {
|
|
111
|
+
const args = process.argv.slice(2);
|
|
112
|
+
const options = {
|
|
113
|
+
input: "prs.json",
|
|
114
|
+
output: "embeddings.jsonl",
|
|
115
|
+
model: "text-embedding-3-small",
|
|
116
|
+
batchSize: 100,
|
|
117
|
+
maxChars: 4000,
|
|
118
|
+
bodyChars: 2000,
|
|
119
|
+
resume: true,
|
|
120
|
+
};
|
|
121
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
122
|
+
const arg = args[i];
|
|
123
|
+
if (arg === "--input") {
|
|
124
|
+
options.input = args[++i];
|
|
125
|
+
}
|
|
126
|
+
else if (arg === "--output") {
|
|
127
|
+
options.output = args[++i];
|
|
128
|
+
}
|
|
129
|
+
else if (arg === "--model") {
|
|
130
|
+
options.model = args[++i];
|
|
131
|
+
}
|
|
132
|
+
else if (arg === "--batch") {
|
|
133
|
+
options.batchSize = Number(args[++i]);
|
|
134
|
+
}
|
|
135
|
+
else if (arg === "--max-chars") {
|
|
136
|
+
options.maxChars = Number(args[++i]);
|
|
137
|
+
}
|
|
138
|
+
else if (arg === "--body-chars") {
|
|
139
|
+
options.bodyChars = Number(args[++i]);
|
|
140
|
+
}
|
|
141
|
+
else if (arg === "--no-resume") {
|
|
142
|
+
options.resume = false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
embed(options);
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=embed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed.js","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"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"}
|
package/dist/triage.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../src/triage.ts"],"names":[],"mappings":""}
|
package/dist/triage.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import readline from "readline";
|
|
6
|
+
import { build } from "./build.js";
|
|
7
|
+
import { embed } from "./embed.js";
|
|
8
|
+
function parseRepo(repo) {
|
|
9
|
+
const trimmed = repo.replace(/\s+/g, "");
|
|
10
|
+
const match = trimmed.match(/github\.com[/:]([^/]+)\/([^/.]+)(?:\.git)?/i);
|
|
11
|
+
if (match) {
|
|
12
|
+
return { owner: match[1], name: match[2] };
|
|
13
|
+
}
|
|
14
|
+
if (trimmed.includes("/")) {
|
|
15
|
+
const [owner, name] = trimmed.split("/");
|
|
16
|
+
if (owner && name)
|
|
17
|
+
return { owner, name };
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
async function fetchItems(owner, name, state, type, outputPath) {
|
|
22
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
23
|
+
const repoLabel = `${owner}/${name}`;
|
|
24
|
+
const items = [];
|
|
25
|
+
let prCount = 0;
|
|
26
|
+
let issueCount = 0;
|
|
27
|
+
const fetchEndpoint = async (endpoint, itemType) => {
|
|
28
|
+
const jqFilter = itemType === "issue"
|
|
29
|
+
? '.[] | select(.pull_request == null) | {url: .html_url, number: .number, title: .title, body: .body, state: .state, type: "issue"}'
|
|
30
|
+
: '.[] | {url: .html_url, number: .number, title: .title, body: .body, state: .state, type: "pr"}';
|
|
31
|
+
const gh = spawn("gh", ["api", "--paginate", endpoint, "--jq", jqFilter], {
|
|
32
|
+
stdio: ["ignore", "pipe", "inherit"],
|
|
33
|
+
});
|
|
34
|
+
const rl = readline.createInterface({
|
|
35
|
+
input: gh.stdout,
|
|
36
|
+
crlfDelay: Number.POSITIVE_INFINITY,
|
|
37
|
+
});
|
|
38
|
+
const readPromise = (async () => {
|
|
39
|
+
for await (const line of rl) {
|
|
40
|
+
const trimmed = line.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
continue;
|
|
43
|
+
try {
|
|
44
|
+
const item = JSON.parse(trimmed);
|
|
45
|
+
items.push(item);
|
|
46
|
+
if (itemType === "pr")
|
|
47
|
+
prCount++;
|
|
48
|
+
else
|
|
49
|
+
issueCount++;
|
|
50
|
+
const total = prCount + issueCount;
|
|
51
|
+
if (total % 200 === 0) {
|
|
52
|
+
console.log(`[${repoLabel}] Fetched ${prCount} PRs, ${issueCount} issues`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// skip invalid JSON
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
const exitPromise = new Promise((resolve, reject) => {
|
|
61
|
+
gh.on("close", (code) => {
|
|
62
|
+
if (code === 0)
|
|
63
|
+
resolve();
|
|
64
|
+
else
|
|
65
|
+
reject(new Error(`gh api ${endpoint} exited with code ${code}`));
|
|
66
|
+
});
|
|
67
|
+
gh.on("error", reject);
|
|
68
|
+
});
|
|
69
|
+
await Promise.all([readPromise, exitPromise]);
|
|
70
|
+
};
|
|
71
|
+
if (type === "pr" || type === "all") {
|
|
72
|
+
const prEndpoint = `/repos/${owner}/${name}/pulls?state=${state}&per_page=100`;
|
|
73
|
+
await fetchEndpoint(prEndpoint, "pr");
|
|
74
|
+
}
|
|
75
|
+
if (type === "issue" || type === "all") {
|
|
76
|
+
const issueEndpoint = `/repos/${owner}/${name}/issues?state=${state}&per_page=100`;
|
|
77
|
+
await fetchEndpoint(issueEndpoint, "issue");
|
|
78
|
+
}
|
|
79
|
+
fs.writeFileSync(outputPath, JSON.stringify(items, null, 2));
|
|
80
|
+
return { total: items.length, prs: prCount, issues: issueCount };
|
|
81
|
+
}
|
|
82
|
+
async function main() {
|
|
83
|
+
const args = process.argv.slice(2);
|
|
84
|
+
const options = {
|
|
85
|
+
repo: null,
|
|
86
|
+
state: "open",
|
|
87
|
+
type: "all",
|
|
88
|
+
output: "prs.json",
|
|
89
|
+
embeddings: "embeddings.jsonl",
|
|
90
|
+
html: "triage.html",
|
|
91
|
+
model: "text-embedding-3-small",
|
|
92
|
+
batch: 100,
|
|
93
|
+
maxChars: 4000,
|
|
94
|
+
bodyChars: 2000,
|
|
95
|
+
neighbors: 15,
|
|
96
|
+
minDist: 0.1,
|
|
97
|
+
search: false,
|
|
98
|
+
};
|
|
99
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
100
|
+
const arg = args[i];
|
|
101
|
+
if (arg === "--repo") {
|
|
102
|
+
options.repo = args[++i];
|
|
103
|
+
}
|
|
104
|
+
else if (arg === "--state") {
|
|
105
|
+
const val = args[++i];
|
|
106
|
+
if (val !== "open" && val !== "closed" && val !== "all") {
|
|
107
|
+
console.error("--state must be open, closed, or all");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
options.state = val;
|
|
111
|
+
}
|
|
112
|
+
else if (arg === "--type") {
|
|
113
|
+
const val = args[++i];
|
|
114
|
+
if (val !== "pr" && val !== "issue" && val !== "all") {
|
|
115
|
+
console.error("--type must be pr, issue, or all");
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
options.type = val;
|
|
119
|
+
}
|
|
120
|
+
else if (arg === "--output") {
|
|
121
|
+
options.output = args[++i];
|
|
122
|
+
}
|
|
123
|
+
else if (arg === "--embeddings") {
|
|
124
|
+
options.embeddings = args[++i];
|
|
125
|
+
}
|
|
126
|
+
else if (arg === "--html") {
|
|
127
|
+
options.html = args[++i];
|
|
128
|
+
}
|
|
129
|
+
else if (arg === "--model") {
|
|
130
|
+
options.model = args[++i];
|
|
131
|
+
}
|
|
132
|
+
else if (arg === "--batch") {
|
|
133
|
+
options.batch = Number(args[++i]);
|
|
134
|
+
}
|
|
135
|
+
else if (arg === "--max-chars") {
|
|
136
|
+
options.maxChars = Number(args[++i]);
|
|
137
|
+
}
|
|
138
|
+
else if (arg === "--body-chars") {
|
|
139
|
+
options.bodyChars = Number(args[++i]);
|
|
140
|
+
}
|
|
141
|
+
else if (arg === "--neighbors") {
|
|
142
|
+
options.neighbors = Number(args[++i]);
|
|
143
|
+
}
|
|
144
|
+
else if (arg === "--min-dist") {
|
|
145
|
+
options.minDist = Number(args[++i]);
|
|
146
|
+
}
|
|
147
|
+
else if (arg === "--search") {
|
|
148
|
+
options.search = true;
|
|
149
|
+
}
|
|
150
|
+
else if (arg === "--help" || arg === "-h") {
|
|
151
|
+
console.log(`
|
|
152
|
+
doppelgangers - Find duplicate PRs through embedding visualization
|
|
153
|
+
|
|
154
|
+
Usage:
|
|
155
|
+
doppelgangers --repo <owner/repo>
|
|
156
|
+
|
|
157
|
+
Options:
|
|
158
|
+
--repo <url|owner/repo> GitHub repository (required)
|
|
159
|
+
--state <state> Item state: open, closed, or all (default: open)
|
|
160
|
+
--type <type> Item type: pr, issue, or all (default: all)
|
|
161
|
+
--output <path> Output path for items JSON (default: prs.json)
|
|
162
|
+
--embeddings <path> Output path for embeddings (default: embeddings.jsonl)
|
|
163
|
+
--html <path> Output path for HTML viewer (default: triage.html)
|
|
164
|
+
--model <model> OpenAI embedding model (default: text-embedding-3-small)
|
|
165
|
+
--batch <n> Batch size for embeddings (default: 100)
|
|
166
|
+
--max-chars <n> Max chars for embedding input (default: 4000)
|
|
167
|
+
--body-chars <n> Max chars for body snippet (default: 2000)
|
|
168
|
+
--neighbors <n> UMAP neighbors (default: 15)
|
|
169
|
+
--min-dist <n> UMAP min distance (default: 0.1)
|
|
170
|
+
--search Include embeddings for semantic search (increases file size)
|
|
171
|
+
|
|
172
|
+
Environment:
|
|
173
|
+
OPENAI_API_KEY Required for embedding generation
|
|
174
|
+
`);
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (!options.repo) {
|
|
179
|
+
console.error("--repo is required. Use --help for usage.");
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
const repoInfo = parseRepo(options.repo);
|
|
183
|
+
if (!repoInfo) {
|
|
184
|
+
console.error("Could not parse repo. Use https://github.com/org/repo or org/repo");
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
const { owner, name } = repoInfo;
|
|
188
|
+
const typeLabel = options.type === "all" ? "PRs and issues" : options.type === "pr" ? "PRs" : "issues";
|
|
189
|
+
console.log(`Fetching ${options.state} ${typeLabel} for ${owner}/${name}`);
|
|
190
|
+
const outputPath = path.resolve(options.output);
|
|
191
|
+
const result = await fetchItems(owner, name, options.state, options.type, outputPath);
|
|
192
|
+
console.log(`Wrote ${outputPath} (${result.prs} PRs, ${result.issues} issues)`);
|
|
193
|
+
const embedOptions = {
|
|
194
|
+
input: outputPath,
|
|
195
|
+
output: path.resolve(options.embeddings),
|
|
196
|
+
model: options.model,
|
|
197
|
+
batchSize: options.batch,
|
|
198
|
+
maxChars: options.maxChars,
|
|
199
|
+
bodyChars: options.bodyChars,
|
|
200
|
+
resume: false,
|
|
201
|
+
};
|
|
202
|
+
await embed(embedOptions);
|
|
203
|
+
const embeddingsPath = path.resolve(options.embeddings);
|
|
204
|
+
const projectionsPath = embeddingsPath.replace(/\.[^.]+$/, "-projections.json");
|
|
205
|
+
const buildOptions = {
|
|
206
|
+
input: embeddingsPath,
|
|
207
|
+
output: path.resolve(options.html),
|
|
208
|
+
projections: projectionsPath,
|
|
209
|
+
neighbors: options.neighbors,
|
|
210
|
+
minDist: options.minDist,
|
|
211
|
+
includeEmbeddings: options.search,
|
|
212
|
+
};
|
|
213
|
+
build(buildOptions);
|
|
214
|
+
console.log(`Done. Open ${path.resolve(options.html)}`);
|
|
215
|
+
}
|
|
216
|
+
main().catch((error) => {
|
|
217
|
+
console.error(error);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
});
|
|
220
|
+
//# sourceMappingURL=triage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.js","sourceRoot":"","sources":["../src/triage.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "doppelgangers",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Find duplicate PRs through embedding visualization",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"doppelgangers": "./dist/triage.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsgo",
|
|
11
|
+
"dev": "tsgo --watch",
|
|
12
|
+
"check": "biome check --write . && tsgo --noEmit",
|
|
13
|
+
"prepare": "husky"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["github", "pull-request", "triage", "embeddings", "visualization", "umap"],
|
|
16
|
+
"author": "Mario Zechner",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/badlogic/doppelgangers.git"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"openai": "^4.104.0",
|
|
24
|
+
"umap-js": "^1.4.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@biomejs/biome": "2.3.5",
|
|
28
|
+
"@types/node": "^22.10.5",
|
|
29
|
+
"@typescript/native-preview": "7.0.0-dev.20260120.1",
|
|
30
|
+
"husky": "^9.1.7",
|
|
31
|
+
"typescript": "^5.9.2"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=20.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|