Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions node_version/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,13 @@ async function checkUrl(

clearTimeout(t);
return { ok: res.ok, msg: `ok (${res.status})` };
} catch (e: any) {
} catch (e: unknown) {
clearTimeout(t);
const message = e instanceof Error ? e.message : String(e);
const name = e instanceof Error ? e.name : "Error";
return {
ok: false,
msg: `failed (${e?.name || "Error"}: ${e?.message || e})`,
msg: `failed (${name}: ${message})`,
};
}
}
Expand Down Expand Up @@ -143,18 +145,20 @@ async function safeReadRepoFiles(
): Promise<RepoReadResult | null> {
try {
return await readRepoSignalFiles(owner, repo);
} catch (e: any) {
console.warn(`Warning: Could not read repo files: ${e?.message || e}`);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic for extracting an error message is repeated in multiple catch blocks throughout this file. To improve maintainability and reduce code duplication, consider creating a utility function. For example:

function getErrorMessage(error: unknown): string {
  if (error instanceof Error) {
    return error.message;
  }
  return String(error);
}

This function could then be called in each catch block, making the code cleaner and easier to maintain.

console.warn(`Warning: Could not read repo files: ${message}`);
return null;
}
}

async function generateWithExit(prompt: string): Promise<string> {
try {
return await generateExplanation(prompt);
} catch (e: any) {
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
console.error("Failed to generate explanation.");
console.error(`error: ${e?.message || e}`);
console.error(`error: ${message}`);
console.error("\nfix:");
console.error("- Ensure GEMINI_API_KEY is set");
console.error("- Or run: explainthisrepo --doctor");
Expand Down Expand Up @@ -220,8 +224,9 @@ Examples:

try {
({ owner, repo } = resolveRepoTarget(repository));
} catch (e: any) {
console.error(`error: ${e.message}`);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
console.error(`error: ${message}`);
process.exit(1);
}

Expand All @@ -240,8 +245,9 @@ Examples:

printStack(report, owner, repo);
return;
} catch (e: any) {
console.error(`error: ${e?.message || e}`);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
console.error(`error: ${message}`);
process.exit(1);
}
}
Expand All @@ -250,9 +256,10 @@ Examples:

try {
repoData = await fetchRepo(owner, repo);
} catch (e: any) {
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
console.error("Failed to fetch repository data.");
console.error(`error: ${e?.message || e}`);
console.error(`error: ${message}`);
console.error("\nfix:");
console.error("- Ensure the repository exists and is public");
console.error("- Or set GITHUB_TOKEN to avoid rate limits");
Expand All @@ -263,8 +270,9 @@ Examples:

try {
readme = await fetchReadme(owner, repo);
} catch (e: any) {
console.warn(`Warning: Could not fetch README: ${e?.message || e}`);
} catch (e: unknown) {
const message = e instanceof Error ? e.message : String(e);
console.warn(`Warning: Could not fetch README: ${message}`);
readme = null;
}

Expand Down
4 changes: 2 additions & 2 deletions node_version/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion node_version/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "explainthisrepo",
"version": "0.4.2",
"version": "0.4.3",
"description": "A CLI developer tool to explain any GitHub repository in plain English",
"license": "MIT",
"type": "module",
Expand Down
28 changes: 16 additions & 12 deletions node_version/prompt.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
function escapeForPromptBlock(input: string): string {
return input.replace(/</g, "&lt;").replace(/>/g, "&gt;");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While escaping < and > is crucial to prevent breaking out of the XML-style blocks, it's also a good practice to escape ampersands (&) to avoid potential misinterpretation by the LLM, as & is used to start character entities (e.g., &lt;). To make this more robust, consider escaping ampersands as well. The order is important: & should be escaped first.

Suggested change
return input.replace(/</g, "&lt;").replace(/>/g, "&gt;");
return input.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

}

export function buildPrompt(
repoName: string,
description: string | null,
Expand All @@ -11,20 +15,20 @@ export function buildPrompt(
Your task is to explain a GitHub repository clearly and concisely for a human reader.

<repository_metadata>
Name: ${repoName}
Description: ${description || "No description provided"}
Name: ${escapeForPromptBlock(repoName)}
Description: ${escapeForPromptBlock(description || "No description provided")}
</repository_metadata>

<readme>
${readme || "No README provided"}
${escapeForPromptBlock(readme || "No README provided")}
</readme>

<repo_structure>
${treeText || "No file tree provided"}
${escapeForPromptBlock(treeText || "No file tree provided")}
</repo_structure>

<code_files>
${filesText || "No code files provided"}
${escapeForPromptBlock(filesText || "No code files provided")}
</code_files>

Instructions:
Expand Down Expand Up @@ -75,12 +79,12 @@ export function buildQuickPrompt(
Write a ONE-SENTENCE plain-English definition of what this GitHub repository is.

<repository_metadata>
Name: ${repoName}
Description: ${description || "No description provided"}
Name: ${escapeForPromptBlock(repoName)}
Description: ${escapeForPromptBlock(description || "No description provided")}
</repository_metadata>

<readme>
${readmeSnippet}
${escapeForPromptBlock(readmeSnippet)}
</readme>

Rules:
Expand Down Expand Up @@ -112,16 +116,16 @@ export function buildSimplePrompt(
Summarize this GitHub repository in a concise bullet-point format.

<repository_metadata>
Name: ${repoName}
Description: ${description || "No description provided"}
Name: ${escapeForPromptBlock(repoName)}
Description: ${escapeForPromptBlock(description || "No description provided")}
</repository_metadata>

<readme>
${readmeContent}
${escapeForPromptBlock(readmeContent)}
</readme>

<repo_structure>
${treeContent}
${escapeForPromptBlock(treeContent)}
</repo_structure>

Output style rules:
Expand Down
6 changes: 0 additions & 6 deletions package-lock.json

This file was deleted.

1 change: 0 additions & 1 deletion package.json

This file was deleted.