explainthisrepo 0.5.1 → 0.6.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/README.md +1 -1
- package/dist/cli.js +13 -3
- package/dist/config.d.ts +4 -0
- package/dist/config.js +33 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +45 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ExplainThisRepo
|
|
2
2
|
|
|
3
|
-
ExplainThisRepo is a CLI that generates plain-English explanations of
|
|
3
|
+
ExplainThisRepo is a CLI that generates plain-English explanations of any codebase (GitHub repositories and local directories) by analyzing project structure, README content, and high signal files.
|
|
4
4
|
|
|
5
5
|
It helps developers quickly understand unfamiliar codebases by deriving architectural explanations from real project structure and code signals, producing a clear, structured `EXPLAIN.md`.
|
|
6
6
|
|
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
import ora from "ora";
|
|
10
|
+
import { runInit } from "./init.js";
|
|
10
11
|
import { fetchRepo, fetchReadme } from "./github.js";
|
|
11
12
|
import { buildPrompt, buildQuickPrompt, buildSimplePrompt } from "./prompt.js";
|
|
12
13
|
import { generateExplanation } from "./generate.js";
|
|
@@ -133,9 +134,9 @@ async function main() {
|
|
|
133
134
|
const program = new Command();
|
|
134
135
|
program
|
|
135
136
|
.name("explainthisrepo")
|
|
136
|
-
.description("
|
|
137
|
+
.description("CLI that generates plain English explanations of any codebase")
|
|
137
138
|
.version(getPkgVersion(), "-v, --version", "Show version")
|
|
138
|
-
.argument("[repository]", "GitHub repository (owner/repo or URL) or local
|
|
139
|
+
.argument("[repository]", "GitHub repository (owner/repo or URL) or local directories")
|
|
139
140
|
.option("--doctor", "Run diagnostics")
|
|
140
141
|
.option("--quick", "Quick summary mode")
|
|
141
142
|
.option("--simple", "Simple summary mode")
|
|
@@ -155,7 +156,16 @@ Examples:
|
|
|
155
156
|
$ explainthisrepo ./path/to/directory
|
|
156
157
|
$ explainthisrepo . --stack
|
|
157
158
|
$ explainthisrepo --doctor`);
|
|
159
|
+
program
|
|
160
|
+
.command("init")
|
|
161
|
+
.description("Initialize configuration with Gemini API key")
|
|
162
|
+
.action(async () => {
|
|
163
|
+
await runInit();
|
|
164
|
+
});
|
|
158
165
|
program.parse(process.argv);
|
|
166
|
+
if (process.argv[2] === "init") {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
159
169
|
const options = program.opts();
|
|
160
170
|
const repository = program.args[0];
|
|
161
171
|
if (options.doctor) {
|
|
@@ -173,7 +183,7 @@ Examples:
|
|
|
173
183
|
process.exit(1);
|
|
174
184
|
}
|
|
175
185
|
if (!repository) {
|
|
176
|
-
program.error("repository argument required");
|
|
186
|
+
program.error("repository argument required (or use `init` to set up API key)");
|
|
177
187
|
}
|
|
178
188
|
const local = fs.existsSync(repository);
|
|
179
189
|
let owner = "";
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const CONFIG_DIR_NAME = "ExplainThisRepo";
|
|
5
|
+
const CONFIG_FILE_NAME = "config.toml";
|
|
6
|
+
export function getConfigPath() {
|
|
7
|
+
if (process.platform === "win32") {
|
|
8
|
+
const appdata = process.env.APPDATA;
|
|
9
|
+
if (!appdata) {
|
|
10
|
+
throw new Error("APPDATA environment variable is not set");
|
|
11
|
+
}
|
|
12
|
+
return path.join(appdata, CONFIG_DIR_NAME, CONFIG_FILE_NAME);
|
|
13
|
+
}
|
|
14
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
15
|
+
const base = xdg ?? path.join(os.homedir(), ".config");
|
|
16
|
+
return path.join(base, "explainthisrepo", CONFIG_FILE_NAME);
|
|
17
|
+
}
|
|
18
|
+
export function ensureConfigDir() {
|
|
19
|
+
const configPath = getConfigPath();
|
|
20
|
+
const dir = path.dirname(configPath);
|
|
21
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
22
|
+
return configPath;
|
|
23
|
+
}
|
|
24
|
+
export function writeConfig(contents) {
|
|
25
|
+
const path = ensureConfigDir();
|
|
26
|
+
fs.writeFileSync(path, contents, { encoding: "utf-8" });
|
|
27
|
+
}
|
|
28
|
+
export function readConfig() {
|
|
29
|
+
const path = getConfigPath();
|
|
30
|
+
if (!fs.existsSync(path))
|
|
31
|
+
return null;
|
|
32
|
+
return fs.readFileSync(path, "utf-8");
|
|
33
|
+
}
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runInit(): Promise<void>;
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import readline from "node:readline";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { writeConfig } from "./config.js";
|
|
5
|
+
const CONFIG_TEMPLATE = `[llm]
|
|
6
|
+
provider = "gemini"
|
|
7
|
+
api_key = "{api_key}"
|
|
8
|
+
`;
|
|
9
|
+
export async function runInit() {
|
|
10
|
+
const err = process.stderr;
|
|
11
|
+
err.write(chalk.yellow("WARNING: input is hidden. Paste your GEMINI_API_KEY and press Enter.\n\n"));
|
|
12
|
+
try {
|
|
13
|
+
const apiKey = (await promptHidden("Gemini API key: ")).trim();
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
err.write(chalk.red("error: API key cannot be empty\n"));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
writeConfig(CONFIG_TEMPLATE.replace("{api_key}", apiKey));
|
|
19
|
+
err.write("\r");
|
|
20
|
+
err.write("\x1b[2K");
|
|
21
|
+
err.write(chalk.green("Configuration written.\n"));
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
err.write(chalk.red("\nInterrupted.\n"));
|
|
26
|
+
process.exit(130);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function promptHidden(label) {
|
|
30
|
+
const err = process.stderr;
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
err.write(label);
|
|
33
|
+
const rl = readline.createInterface({
|
|
34
|
+
input: process.stdin,
|
|
35
|
+
output: undefined,
|
|
36
|
+
terminal: true,
|
|
37
|
+
});
|
|
38
|
+
rl._writeToOutput = () => { };
|
|
39
|
+
rl.question("", (answer) => {
|
|
40
|
+
rl.close();
|
|
41
|
+
err.write("\n");
|
|
42
|
+
resolve(answer);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "explainthisrepo",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.1",
|
|
4
|
+
"description": "CLI that generates plain English explanations of any codebase",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Caleb Wodi <calebwodi33@gmail.com>",
|