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 +21 -1
- package/dist/github.d.ts +2 -0
- package/dist/github.js +6 -0
- package/dist/repo_reader.d.ts +8 -0
- package/dist/repo_reader.js +27 -0
- package/dist/stack-detector.d.ts +23 -0
- package/dist/stack-detector.js +54 -0
- package/dist/stack_printer.d.ts +2 -0
- package/dist/stack_printer.js +20 -0
- package/package.json +1 -1
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) ||
|
|
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
|
+
}
|
package/dist/repo_reader.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/repo_reader.js
CHANGED
|
@@ -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,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
|
+
}
|