explainthisrepo 0.10.0 → 0.20.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.
Files changed (41) hide show
  1. package/README.md +13 -3
  2. package/dist/cli.js +40 -383
  3. package/package.json +2 -9
  4. package/dist/config.d.ts +0 -5
  5. package/dist/config.js +0 -46
  6. package/dist/generate.d.ts +0 -1
  7. package/dist/generate.js +0 -15
  8. package/dist/github.d.ts +0 -6
  9. package/dist/github.js +0 -300
  10. package/dist/init.d.ts +0 -1
  11. package/dist/init.js +0 -189
  12. package/dist/local_reader.d.ts +0 -2
  13. package/dist/local_reader.js +0 -77
  14. package/dist/prompt.d.ts +0 -3
  15. package/dist/prompt.js +0 -127
  16. package/dist/providers/anthropic.d.ts +0 -17
  17. package/dist/providers/anthropic.js +0 -68
  18. package/dist/providers/base.d.ts +0 -8
  19. package/dist/providers/base.js +0 -6
  20. package/dist/providers/gemini.d.ts +0 -16
  21. package/dist/providers/gemini.js +0 -47
  22. package/dist/providers/groq.d.ts +0 -17
  23. package/dist/providers/groq.js +0 -70
  24. package/dist/providers/index.d.ts +0 -1
  25. package/dist/providers/index.js +0 -1
  26. package/dist/providers/ollama.d.ts +0 -15
  27. package/dist/providers/ollama.js +0 -82
  28. package/dist/providers/openai.d.ts +0 -17
  29. package/dist/providers/openai.js +0 -57
  30. package/dist/providers/openrouter.d.ts +0 -17
  31. package/dist/providers/openrouter.js +0 -72
  32. package/dist/providers/registry.d.ts +0 -4
  33. package/dist/providers/registry.js +0 -38
  34. package/dist/repo_reader.d.ts +0 -13
  35. package/dist/repo_reader.js +0 -150
  36. package/dist/stack-detector.d.ts +0 -23
  37. package/dist/stack-detector.js +0 -54
  38. package/dist/stack_printer.d.ts +0 -2
  39. package/dist/stack_printer.js +0 -20
  40. package/dist/writer.d.ts +0 -1
  41. package/dist/writer.js +0 -6
package/README.md CHANGED
@@ -28,7 +28,7 @@ Not blind AI summarization.
28
28
 
29
29
  ## Installation
30
30
 
31
- ### Option 1: install with pip (recommended):
31
+ ### Option 1: install with pip (Python source version):
32
32
 
33
33
  Requirements: Python 3.9+
34
34
 
@@ -66,7 +66,7 @@ pip install explainthisrepo[groq]
66
66
 
67
67
  Replace `owner/repo` with the GitHub repository identifier (e.g., `facebook/react`, `torvalds/linux`).
68
68
 
69
- ### Option 2: Install with npm
69
+ ### Option 2: Install with npm (prebuilt binary, no Python required)
70
70
 
71
71
  Install globally and use forever:
72
72
 
@@ -86,6 +86,16 @@ npx explainthisrepo owner/repo
86
86
  # npx explainthisrepo .
87
87
  ```
88
88
 
89
+ ## How it works
90
+
91
+ ExplainThisRepo uses a hybrid architecture:
92
+
93
+ - Python → core implementaion (analysis, prompts, providers, output)
94
+ - npm → ships prebuilt native binaries (no Python required)
95
+ - pip → installs the full Python package
96
+
97
+ > The npm and pip versions run the same core engine.
98
+
89
99
  ### Option 3: Download standalone binary
90
100
 
91
101
  Prebuilt standalone binaries are available for macOS, Linux, and Windows.
@@ -135,7 +145,7 @@ explainthisrepo init
135
145
  # or npx explainthisrepo init
136
146
  ```
137
147
 
138
- > For details about how initialization works, see [INIT.md](INIT.md).
148
+ > For details about how initialization works, see [docs/INIT.md](docs/INIT.md).
139
149
 
140
150
  ## GitHub token Access (Private Repos & Rate Limits)
141
151
 
package/dist/cli.js CHANGED
@@ -1,395 +1,52 @@
1
1
  #!/usr/bin/env node
2
- import os from "node:os";
3
- import process from "node:process";
4
2
  import fs from "node:fs";
5
- import { readFileSync } from "node:fs";
3
+ import { spawnSync } from "node:child_process";
6
4
  import path from "node:path";
5
+ import process from "node:process";
7
6
  import { fileURLToPath } from "node:url";
8
- import { Command } from "commander";
9
- import ora from "ora";
10
- import { runInit } from "./init.js";
11
- import { fetchRepo, fetchReadme } from "./github.js";
12
- import { buildPrompt, buildQuickPrompt, buildSimplePrompt } from "./prompt.js";
13
- import { generateExplanation } from "./generate.js";
14
- import { writeOutput } from "./writer.js";
15
- import { readRepoSignalFiles } from "./repo_reader.js";
16
- import { readLocalRepoSignalFiles } from "./local_reader.js";
17
- import { fetchLanguages } from "./github.js";
18
- import { detectStack } from "./stack-detector.js";
19
- import { printStack } from "./stack_printer.js";
20
- function resolveRepoTarget(target) {
21
- target = target.trim();
22
- if (target.startsWith("https//")) {
23
- target = target.replace("https//", "https://");
24
- }
25
- if (target.startsWith("http//")) {
26
- target = target.replace("http//", "http://");
27
- }
28
- if (target.startsWith("git@github.com:")) {
29
- const p = target.replace("git@github.com:", "");
30
- const [owner, repoRaw] = p.split("/", 2);
31
- if (!owner || !repoRaw)
32
- throw new Error("Invalid GitHub SSH URL");
33
- return { owner, repo: repoRaw.replace(/\.git$/, "") };
34
- }
35
- if (target.startsWith("github.com/")) {
36
- target = "https://" + target;
37
- }
38
- if (target.startsWith("http://") || target.startsWith("https://")) {
39
- const url = new URL(target);
40
- if (!["github.com", "www.github.com"].includes(url.hostname)) {
41
- throw new Error("Only GitHub repository URLs are supported");
42
- }
43
- const parts = url.pathname.split("/").filter(Boolean);
44
- if (parts.length < 2) {
45
- throw new Error("URL must point to a repository");
46
- }
47
- return { owner: parts[0], repo: parts[1].replace(/\.git$/, "") };
48
- }
49
- const parts = target.split("/");
50
- if (parts.length === 2 && parts[0] && parts[1]) {
51
- return { owner: parts[0], repo: parts[1] };
52
- }
53
- throw new Error("Invalid format. Use owner/repo or a GitHub repo URL");
54
- }
55
- function getPkgVersion() {
7
+ function getTargetKey() {
8
+ const platform = process.platform;
9
+ const arch = process.arch;
10
+ const effectivePlatform = platform === "android" ? "linux" : platform;
11
+ if (platform === "darwin" && arch === "x64")
12
+ return "darwin-x64";
13
+ if (platform === "darwin" && arch === "arm64")
14
+ return "darwin-arm64";
15
+ if (platform === "linux" && arch === "x64")
16
+ return "linux-x64";
17
+ if (platform === "linux" && arch === "arm64")
18
+ return "linux-arm64";
19
+ if (platform === "win32" && arch === "x64")
20
+ return "win-x64";
21
+ throw new Error(`Unsupported platform: ${platform} ${arch}`);
22
+ }
23
+ function getBinaryName() {
24
+ return process.platform === "win32" ? "explainthisrepo.exe" : "explainthisrepo";
25
+ }
26
+ function getBinaryPath() {
27
+ const launcherDir = path.dirname(fileURLToPath(import.meta.url));
28
+ const binaryPath = path.join(launcherDir, "native", getTargetKey(), getBinaryName());
29
+ if (!fs.existsSync(binaryPath)) {
30
+ throw new Error(`Bundled binary not found: ${binaryPath}`);
31
+ }
32
+ return binaryPath;
33
+ }
34
+ function main() {
56
35
  try {
57
- const __filename = fileURLToPath(import.meta.url);
58
- const __dirname = path.dirname(__filename);
59
- const pkgPath = path.join(__dirname, "..", "package.json");
60
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
61
- return pkg.version ?? "unknown";
62
- }
63
- catch {
64
- return "unknown";
65
- }
66
- }
67
- function hasEnv(key) {
68
- const v = process.env[key];
69
- return Boolean(v && v.trim());
70
- }
71
- async function checkUrl(url, timeoutMs = 6000) {
72
- const controller = new AbortController();
73
- const t = setTimeout(() => controller.abort(), timeoutMs);
74
- try {
75
- const res = await fetch(url, {
76
- method: "GET",
77
- headers: { "User-Agent": "explainthisrepo" },
78
- signal: controller.signal,
36
+ const binaryPath = getBinaryPath();
37
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
38
+ stdio: "inherit",
39
+ windowsHide: true,
79
40
  });
80
- clearTimeout(t);
81
- return { ok: res.ok, msg: `ok (${res.status})` };
82
- }
83
- catch (e) {
84
- clearTimeout(t);
85
- const message = e instanceof Error ? e.message : String(e);
86
- const name = e instanceof Error ? e.name : "Error";
87
- return { ok: false, msg: `failed (${name}: ${message})` };
88
- }
89
- }
90
- async function runDoctor(llmOverride) {
91
- console.log("explainthisrepo doctor report\n");
92
- console.log(`node: ${process.version}`);
93
- console.log(`os: ${os.type()} ${os.release()}`);
94
- console.log(`platform: ${process.platform} ${process.arch}`);
95
- console.log(`version: ${getPkgVersion()}`);
96
- console.log("\ngithub auth:");
97
- if (hasEnv("GITHUB_TOKEN") || hasEnv("GH_TOKEN")) {
98
- console.log("-token: set");
99
- }
100
- else {
101
- console.log("-token: not set (limited + no private repos)");
102
- }
103
- console.log("\nnetwork checks:");
104
- const gh = await checkUrl("https://api.github.com");
105
- console.log(`- github api: ${gh.msg}`);
106
- console.log("\nprovider diagnostics:");
107
- let providerOk = true;
108
- try {
109
- const { getActiveProvider } = await import("./providers/registry.js");
110
- const provider = await getActiveProvider(llmOverride);
111
- const providerName = provider.name ?? llmOverride ?? "unknown";
112
- console.log(`- active provider: ${providerName}`);
113
- const doctorFn = provider.doctor;
114
- if (typeof doctorFn === "function") {
115
- const result = await doctorFn.call(provider);
116
- if (typeof result === "boolean") {
117
- console.log(`- ${providerName}: ${result ? "ok" : "checks did not pass"}`);
118
- providerOk = result;
119
- }
120
- else if (Array.isArray(result)) {
121
- if (result.length === 0) {
122
- console.log(`- ${providerName}: ok`);
123
- }
124
- else {
125
- for (const line of result) {
126
- console.log(`- ${providerName}: ${line}`);
127
- }
128
- providerOk = false;
129
- }
130
- }
131
- else {
132
- console.log(`- ${providerName}: ok`);
133
- }
41
+ if (result.error) {
42
+ throw result.error;
134
43
  }
135
- else {
136
- console.log(`- ${providerName}: no diagnostics implemented`);
137
- }
138
- }
139
- catch (e) {
140
- const message = e instanceof Error ? e.message : String(e);
141
- if (llmOverride) {
142
- console.log(`- provider '${llmOverride}' could not be resolved`);
143
- console.log("- check that the provider name is correct and properly configured");
144
- }
145
- else {
146
- console.log(`- provider registry error: ${message}`);
147
- console.log("- run `explainthisrepo init` to configure a provider");
148
- }
149
- providerOk = false;
150
- }
151
- return gh.ok && providerOk ? 0 : 1;
152
- }
153
- async function safeReadRepoFiles(owner, repo) {
154
- try {
155
- return await readRepoSignalFiles(owner, repo);
44
+ process.exit(result.status ?? 1);
156
45
  }
157
- catch (e) {
158
- const message = e instanceof Error ? e.message : String(e);
159
- console.warn(`Warning: Could not read repo files: ${message}`);
160
- return null;
161
- }
162
- }
163
- async function generateWithExit(prompt, llm) {
164
- try {
165
- return await generateExplanation(prompt, llm);
166
- }
167
- catch (e) {
168
- const message = e instanceof Error ? e.message : String(e);
169
- console.error("Failed to generate explanation.");
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
170
48
  console.error(`error: ${message}`);
171
- console.error("\nfix:");
172
- console.error("- Check that the provider name is correct (e.g. gemini, openai, ollama, anthropic, openrouter)");
173
- console.error("- Ensure your API key is set for the selected provider");
174
- console.error("- Or run: explainthisrepo --doctor");
175
49
  process.exit(1);
176
50
  }
177
51
  }
178
- async function runAnalysis(repository, options) {
179
- if (options.doctor) {
180
- const code = await runDoctor(options.llm);
181
- process.exit(code);
182
- }
183
- const modeFlags = [
184
- options.quick,
185
- options.simple,
186
- options.detailed,
187
- options.stack,
188
- ].filter(Boolean);
189
- if (modeFlags.length > 1) {
190
- console.error("error: only one mode flag can be used at a time");
191
- process.exit(1);
192
- }
193
- const local = fs.existsSync(repository);
194
- let owner = "";
195
- let repo = "";
196
- let localPath = "";
197
- if (local) {
198
- localPath = path.resolve(repository);
199
- console.log(`Analyzing local directory: ${repository}`);
200
- }
201
- else {
202
- try {
203
- ({ owner, repo } = resolveRepoTarget(repository));
204
- }
205
- catch (e) {
206
- const message = e instanceof Error ? e.message : String(e);
207
- console.error(`error: ${message}`);
208
- process.exit(1);
209
- }
210
- }
211
- if (options.stack) {
212
- let read;
213
- let languages = {};
214
- if (local) {
215
- const spinner = ora("Reading repository files…").start();
216
- try {
217
- read = readLocalRepoSignalFiles(localPath);
218
- spinner.stop();
219
- }
220
- catch (e) {
221
- spinner.stop();
222
- const message = e instanceof Error ? e.message : String(e);
223
- console.error(`error: ${message}`);
224
- process.exit(1);
225
- }
226
- }
227
- else {
228
- const spinner = ora(`Fetching ${owner}/${repo}…`).start();
229
- try {
230
- languages = await fetchLanguages(owner, repo);
231
- read = await readRepoSignalFiles(owner, repo);
232
- spinner.stop();
233
- }
234
- catch (e) {
235
- spinner.stop();
236
- const message = e instanceof Error ? e.message : String(e);
237
- console.error(`error: ${message}`);
238
- process.exit(1);
239
- }
240
- }
241
- const report = detectStack({
242
- languages,
243
- tree: read.tree,
244
- keyFiles: read.keyFiles,
245
- });
246
- const label = local ? repository : owner;
247
- const sublabel = local ? "" : repo;
248
- printStack(report, label, sublabel);
249
- return;
250
- }
251
- let repoData = null;
252
- let readme = null;
253
- if (!local) {
254
- const spinner = ora(`Fetching ${owner}/${repo}…`).start();
255
- try {
256
- repoData = await fetchRepo(owner, repo);
257
- readme = await fetchReadme(owner, repo);
258
- spinner.stop();
259
- }
260
- catch (e) {
261
- spinner.stop();
262
- const message = e instanceof Error ? e.message : String(e);
263
- console.error("Failed to fetch repository data.");
264
- console.error(`error: ${message}`);
265
- console.error("\nfix:");
266
- console.error("- Run explainthisrepo init");
267
- console.error("- Or set GITHUB_TOKEN to avoid rate limits");
268
- process.exit(1);
269
- }
270
- }
271
- if (options.quick) {
272
- let quickReadme = readme;
273
- const repoName = local ? localPath : (repoData?.full_name ?? "");
274
- const description = local
275
- ? null
276
- : (repoData?.description ?? null);
277
- if (local) {
278
- const spinner = ora("Reading repository files…").start();
279
- try {
280
- const read = readLocalRepoSignalFiles(localPath);
281
- spinner.stop();
282
- const readmeKey = Object.keys(read.keyFiles).find((k) => k.toLowerCase().startsWith("readme"));
283
- quickReadme = readmeKey !== undefined ? read.keyFiles[readmeKey] : null;
284
- }
285
- catch (e) {
286
- spinner.stop();
287
- throw e;
288
- }
289
- }
290
- const prompt = buildQuickPrompt(repoName, description, quickReadme);
291
- const spinner = ora("Generating explanation…").start();
292
- const output = await generateWithExit(prompt, options.llm).finally(() => spinner.stop());
293
- console.log("Quick summary 🎉");
294
- console.log(output.trim());
295
- return;
296
- }
297
- if (options.simple) {
298
- let readResult;
299
- const spinner = ora("Reading repository files…").start();
300
- try {
301
- readResult = local
302
- ? readLocalRepoSignalFiles(localPath)
303
- : await safeReadRepoFiles(owner, repo);
304
- spinner.stop();
305
- }
306
- catch (e) {
307
- spinner.stop();
308
- throw e;
309
- }
310
- const prompt = buildSimplePrompt(local ? localPath : (repoData?.full_name ?? ""), local ? null : (repoData?.description ?? null), local ? null : readme, readResult?.treeText ?? null);
311
- const genSpinner = ora("Generating explanation…").start();
312
- const output = await generateWithExit(prompt, options.llm).finally(() => genSpinner.stop());
313
- console.log("Simple summary 🎉");
314
- console.log(output.trim());
315
- return;
316
- }
317
- let readResult;
318
- const readSpinner = ora("Reading repository files…").start();
319
- try {
320
- readResult = local
321
- ? readLocalRepoSignalFiles(localPath)
322
- : await safeReadRepoFiles(owner, repo);
323
- readSpinner.stop();
324
- }
325
- catch (e) {
326
- readSpinner.stop();
327
- throw e;
328
- }
329
- const prompt = buildPrompt(local ? localPath : (repoData?.full_name ?? ""), local ? null : (repoData?.description ?? null), local ? null : readme, options.detailed || false, readResult?.treeText ?? null, readResult?.filesText ?? null);
330
- const genSpinner = ora("Generating explanation…").start();
331
- const output = await generateWithExit(prompt, options.llm).finally(() => genSpinner.stop());
332
- console.log("Writing EXPLAIN.md...");
333
- writeOutput(output);
334
- const wordCount = output.split(/\s+/).filter(Boolean).length;
335
- console.log("EXPLAIN.md generated successfully 🎉");
336
- console.log(`Words: ${wordCount}`);
337
- console.log("Open EXPLAIN.md to read it.");
338
- }
339
- const program = new Command();
340
- program
341
- .name("explainthisrepo")
342
- .description("The fastest way to understand any codebase in plain English")
343
- .version(getPkgVersion(), "-v, --version", "Show version")
344
- .argument("[repository]", "GitHub repository (owner/repo or URL) or local directories")
345
- .option("--doctor", "Run diagnostics")
346
- .option("--quick", "Quick summary mode")
347
- .option("--simple", "Simple summary mode")
348
- .option("--detailed", "Detailed explanation mode")
349
- .option("--stack", "Stack detection mode")
350
- .option("--llm <provider>", "LLM provider to use (e.g. gemini, openai, ollama, anthropic, openrouter). Overrides config default.")
351
- .addHelpText("after", `
352
- Examples:
353
- $ explainthisrepo owner/repo
354
- $ explainthisrepo https://github.com/owner/repo
355
- $ explainthisrepo github.com/owner/repo
356
- $ explainthisrepo git@github.com:owner/repo.git
357
- $ explainthisrepo owner/repo --detailed
358
- $ explainthisrepo owner/repo --quick
359
- $ explainthisrepo owner/repo --simple
360
- $ explainthisrepo owner/repo --stack
361
- $ explainthisrepo owner/repo --llm gemini
362
- $ explainthisrepo owner/repo --llm openai
363
- $ explainthisrepo owner/repo --llm ollama
364
- $ explainthisrepo .
365
- $ explainthisrepo ./path/to/directory
366
- $ explainthisrepo . --stack
367
- $ explainthisrepo --doctor
368
- $ explainthisrepo --doctor --llm gemini
369
- $ explainthisrepo --doctor --llm openai
370
- $ explainthisrepo --doctor --llm ollama
371
- $ explainthisrepo --version
372
- $ GitHub token:
373
- $ Access private repos and higher rate limits
374
- $ Run:
375
- $ explainthisrepo init
376
- $ Or set:
377
- $ GITHUB_TOKEN=ghp_xxx explainthisrepo owner/repo`)
378
- .action(async (repository, options) => {
379
- if (options.doctor) {
380
- const code = await runDoctor(options.llm);
381
- process.exit(code);
382
- }
383
- if (!repository) {
384
- program.error("repository argument required (or use `explainthisrepo init` to configure a provider)");
385
- return;
386
- }
387
- await runAnalysis(repository, options);
388
- });
389
- program
390
- .command("init")
391
- .description("Configure your LLM provider (Gemini, OpenAI, or Ollama)")
392
- .action(async () => {
393
- await runInit();
394
- });
395
- program.parseAsync(process.argv);
52
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "explainthisrepo",
3
- "version": "0.10.0",
3
+ "version": "0.20.1",
4
4
  "description": "The fastest way to understand any codebase in plain English. Not blind AI summarization",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -46,14 +46,7 @@
46
46
  "node": ">=20"
47
47
  },
48
48
  "dependencies": {
49
- "@google/generative-ai": "^0.24.1",
50
- "@iarna/toml": "^2.2.5",
51
- "axios": "^1.13.2",
52
- "commander": "^14.0.3",
53
- "dotenv": "^17.2.3",
54
- "openai": "^4.0.0",
55
- "ora": "^9.3.0",
56
- "toml": "^3.0.0"
49
+ "commander": "^14.0.3"
57
50
  },
58
51
  "devDependencies": {
59
52
  "@types/node": "^22.0.0",
package/dist/config.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export declare function getConfigPath(): string;
2
- export declare function ensureConfigDir(): string;
3
- export declare function writeConfig(contents: string): void;
4
- export declare function readConfig(): string | null;
5
- export declare function loadConfig(): any;
package/dist/config.js DELETED
@@ -1,46 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { parse } from "@iarna/toml";
5
- const CONFIG_DIR_NAME = "ExplainThisRepo";
6
- const CONFIG_FILE_NAME = "config.toml";
7
- export function getConfigPath() {
8
- if (process.platform === "win32") {
9
- const appdata = process.env.APPDATA;
10
- if (!appdata) {
11
- throw new Error("APPDATA environment variable is not set");
12
- }
13
- return path.join(appdata, CONFIG_DIR_NAME, CONFIG_FILE_NAME);
14
- }
15
- const xdg = process.env.XDG_CONFIG_HOME;
16
- const base = xdg ?? path.join(os.homedir(), ".config");
17
- return path.join(base, "explainthisrepo", CONFIG_FILE_NAME);
18
- }
19
- export function ensureConfigDir() {
20
- const configPath = getConfigPath();
21
- const dir = path.dirname(configPath);
22
- fs.mkdirSync(dir, { recursive: true });
23
- return configPath;
24
- }
25
- export function writeConfig(contents) {
26
- const path = ensureConfigDir();
27
- fs.writeFileSync(path, contents, { encoding: "utf-8" });
28
- }
29
- export function readConfig() {
30
- const path = getConfigPath();
31
- if (!fs.existsSync(path))
32
- return null;
33
- return fs.readFileSync(path, "utf-8");
34
- }
35
- export function loadConfig() {
36
- const raw = readConfig();
37
- if (!raw) {
38
- return {};
39
- }
40
- try {
41
- return parse(raw);
42
- }
43
- catch (err) {
44
- throw new Error("Invalid config.toml format");
45
- }
46
- }
@@ -1 +0,0 @@
1
- export declare function generateExplanation(prompt: string, providerOverride?: string): Promise<string>;
package/dist/generate.js DELETED
@@ -1,15 +0,0 @@
1
- import { getActiveProvider } from "./providers/registry.js";
2
- export async function generateExplanation(prompt, providerOverride) {
3
- const provider = getActiveProvider(providerOverride);
4
- try {
5
- const output = await provider.generate(prompt);
6
- if (!output || !output.trim()) {
7
- throw new Error(`${provider.name} returned no output`);
8
- }
9
- return output.trim();
10
- }
11
- catch (err) {
12
- const message = err?.message ? String(err.message) : String(err);
13
- throw new Error(`${provider.name} generation failed: ${message}`);
14
- }
15
- }
package/dist/github.d.ts DELETED
@@ -1,6 +0,0 @@
1
- export type RepoLanguageMap = Record<string, number>;
2
- export declare function fetchRepo(owner: string, repo: string, token?: string): Promise<any>;
3
- export declare function fetchReadme(owner: string, repo: string, token?: string): Promise<string | null>;
4
- export declare function fetchTree(owner: string, repo: string, token?: string): Promise<any[]>;
5
- export declare function fetchFile(owner: string, repo: string, filePath: string, token?: string): Promise<string | null>;
6
- export declare function fetchLanguages(owner: string, repo: string, token?: string): Promise<RepoLanguageMap>;