explainthisrepo 0.1.4 → 0.1.5

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/dist/cli.js CHANGED
@@ -9,6 +9,9 @@ import { buildPrompt, buildSimplePrompt } from "./prompt.js";
9
9
  import { generateExplanation } from "./generate.js";
10
10
  import { writeOutput } from "./writer.js";
11
11
  import { readRepoSignalFiles } from "./repo_reader.js";
12
+ import { fetchLanguages } from "./github.js";
13
+ import { detectStack } from "./stack-detector.js";
14
+ import { printStack } from "./stack_printer.js";
12
15
  function usage() {
13
16
  console.log("usage:");
14
17
  console.log(" explainthisrepo owner/repo");
@@ -90,6 +93,7 @@ async function main() {
90
93
  let detailed = false;
91
94
  let quick = false;
92
95
  let simple = false;
96
+ let stack = false;
93
97
  if (args.length === 2) {
94
98
  if (args[1] === "--detailed")
95
99
  detailed = true;
@@ -97,6 +101,8 @@ async function main() {
97
101
  quick = true;
98
102
  else if (args[1] === "--simple")
99
103
  simple = true;
104
+ else if (args[1] === "--stack")
105
+ stack = true;
100
106
  else {
101
107
  usage();
102
108
  process.exit(1);
@@ -106,7 +112,10 @@ async function main() {
106
112
  usage();
107
113
  process.exit(1);
108
114
  }
109
- if ((quick && simple) || (detailed && simple) || (detailed && quick)) {
115
+ if ((quick && simple) ||
116
+ (detailed && simple) ||
117
+ (detailed && quick) ||
118
+ (stack && (quick || simple || detailed))) {
110
119
  usage();
111
120
  process.exit(1);
112
121
  }
@@ -121,6 +130,17 @@ async function main() {
121
130
  process.exit(1);
122
131
  }
123
132
  console.log(`Fetching ${owner}/${repo}...`);
133
+ if (stack) {
134
+ const languages = await fetchLanguages(owner, repo);
135
+ const read = await readRepoSignalFiles(owner, repo);
136
+ const report = detectStack({
137
+ languages,
138
+ tree: read.tree,
139
+ keyFiles: read.keyFiles,
140
+ });
141
+ printStack(report, owner, repo);
142
+ return;
143
+ }
124
144
  try {
125
145
  const repoData = await fetchRepo(owner, repo);
126
146
  const readme = await fetchReadme(owner, repo);
package/dist/github.d.ts CHANGED
@@ -2,3 +2,5 @@ export declare function fetchRepo(owner: string, repo: string): Promise<any>;
2
2
  export declare function fetchReadme(owner: string, repo: string): Promise<string | null>;
3
3
  export declare function fetchTree(owner: string, repo: string): Promise<any[]>;
4
4
  export declare function fetchFile(owner: string, repo: string, filePath: string): Promise<string>;
5
+ export type RepoLanguageMap = Record<string, number>;
6
+ export declare function fetchLanguages(owner: string, repo: string): Promise<RepoLanguageMap>;
package/dist/github.js CHANGED
@@ -120,3 +120,9 @@ export async function fetchFile(owner, repo, filePath) {
120
120
  return res.data;
121
121
  });
122
122
  }
123
+ export async function fetchLanguages(owner, repo) {
124
+ return requestWithRetry(async () => {
125
+ const res = await github.get(`/repos/${owner}/${repo}/languages`);
126
+ return res.data;
127
+ });
128
+ }
@@ -1,6 +1,14 @@
1
+ type TreeItem = {
2
+ path: string;
3
+ type: "blob" | "tree";
4
+ size?: number;
5
+ };
1
6
  export type RepoReadResult = {
7
+ tree: TreeItem[];
2
8
  treeText: string;
3
9
  filesText: string;
4
10
  selectedFiles: string[];
11
+ keyFiles: Record<string, string>;
5
12
  };
6
13
  export declare function readRepoSignalFiles(owner: string, repo: string): Promise<RepoReadResult>;
14
+ export {};
@@ -113,9 +113,36 @@ export async function readRepoSignalFiles(owner, repo) {
113
113
  catch {
114
114
  }
115
115
  }
116
+ const keyFiles = {};
117
+ const STACK_KEY_FILES = [
118
+ "package.json",
119
+ "pyproject.toml",
120
+ "requirements.txt",
121
+ "go.mod",
122
+ "Cargo.toml",
123
+ "composer.json",
124
+ "pom.xml",
125
+ "build.gradle",
126
+ "Dockerfile",
127
+ "docker-compose.yml",
128
+ "vercel.json",
129
+ "netlify.toml",
130
+ ];
131
+ for (const path of STACK_KEY_FILES) {
132
+ const match = tree.find(t => t.path.toLowerCase() === path.toLowerCase());
133
+ if (!match)
134
+ continue;
135
+ try {
136
+ const content = await fetchFile(owner, repo, path);
137
+ keyFiles[path] = content.slice(0, 20000);
138
+ }
139
+ catch { }
140
+ }
116
141
  return {
142
+ tree,
117
143
  treeText,
118
144
  filesText: fileBlocks.join("\n"),
119
145
  selectedFiles: selected,
146
+ keyFiles,
120
147
  };
121
148
  }
@@ -0,0 +1,23 @@
1
+ import type { RepoLanguageMap } from "./github.js";
2
+ type TreeItem = {
3
+ path: string;
4
+ type: string;
5
+ size?: number;
6
+ };
7
+ type StackInput = {
8
+ languages: RepoLanguageMap;
9
+ tree: TreeItem[];
10
+ keyFiles: Record<string, string>;
11
+ };
12
+ export type StackReport = {
13
+ languages: string[];
14
+ runtimes: string[];
15
+ frontend: string[];
16
+ backend: string[];
17
+ databases: string[];
18
+ tooling: string[];
19
+ infra: string[];
20
+ packageManagers: string[];
21
+ };
22
+ export declare function detectStack(input: StackInput): StackReport;
23
+ export {};
@@ -0,0 +1,54 @@
1
+ export function detectStack(input) {
2
+ const report = {
3
+ languages: [],
4
+ runtimes: [],
5
+ frontend: [],
6
+ backend: [],
7
+ databases: [],
8
+ tooling: [],
9
+ infra: [],
10
+ packageManagers: [],
11
+ };
12
+ const total = Object.values(input.languages).reduce((a, b) => a + b, 0);
13
+ report.languages = Object.entries(input.languages)
14
+ .filter(([_, bytes]) => bytes / total > 0.03)
15
+ .map(([lang]) => lang);
16
+ const paths = input.tree.map(t => t.path.toLowerCase());
17
+ if (paths.includes("dockerfile"))
18
+ report.infra.push("Docker");
19
+ if (paths.includes("vercel.json"))
20
+ report.infra.push("Vercel");
21
+ if (paths.includes("netlify.toml"))
22
+ report.infra.push("Netlify");
23
+ if (paths.some(p => p.startsWith(".github/workflows")))
24
+ report.infra.push("GitHub Actions");
25
+ const pkgRaw = input.keyFiles["package.json"];
26
+ if (pkgRaw) {
27
+ report.runtimes.push("Node.js");
28
+ report.packageManagers.push("npm");
29
+ try {
30
+ const pkg = JSON.parse(pkgRaw);
31
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
32
+ if (deps.react)
33
+ report.frontend.push("React");
34
+ if (deps.next)
35
+ report.frontend.push("Next.js");
36
+ if (deps.express)
37
+ report.backend.push("Express");
38
+ if (deps.fastify)
39
+ report.backend.push("Fastify");
40
+ if (deps.prisma)
41
+ report.databases.push("Prisma");
42
+ if (deps.mongoose)
43
+ report.databases.push("MongoDB");
44
+ if (deps.jest)
45
+ report.tooling.push("Jest");
46
+ if (deps.vite)
47
+ report.tooling.push("Vite");
48
+ if (deps.eslint)
49
+ report.tooling.push("ESLint");
50
+ }
51
+ catch { }
52
+ }
53
+ return report;
54
+ }
@@ -0,0 +1,2 @@
1
+ import type { StackReport } from "./stack-detector.js";
2
+ export declare function printStack(report: StackReport, owner: string, repo: string): void;
@@ -0,0 +1,20 @@
1
+ function section(title, items) {
2
+ if (!items || items.length === 0)
3
+ return;
4
+ console.log(`\n${title}:`);
5
+ for (const item of items) {
6
+ console.log(`- ${item}`);
7
+ }
8
+ }
9
+ export function printStack(report, owner, repo) {
10
+ console.log(`\nStack summary for ${owner}/${repo}`);
11
+ section("Languages", report.languages);
12
+ section("Runtime", report.runtimes);
13
+ section("Frontend", report.frontend);
14
+ section("Backend", report.backend);
15
+ section("Databases / ORM", report.databases);
16
+ section("Tooling", report.tooling);
17
+ section("Infrastructure / Deploy", report.infra);
18
+ section("Package Managers", report.packageManagers);
19
+ console.log("");
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "explainthisrepo",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "ExplainThisRepo is a CLI developer tool to explain any GitHub repository in plain English",
5
5
  "license": "MIT",
6
6
  "type": "module",