explain-my-error 1.0.7 → 1.0.9
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 +84 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.js +84 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import "dotenv/config";
|
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import { access, readFile, writeFile } from "fs/promises";
|
|
8
|
+
import { createRequire } from "module";
|
|
8
9
|
import { createInterface } from "readline/promises";
|
|
9
10
|
import { Command } from "commander";
|
|
10
11
|
import pc3 from "picocolors";
|
|
@@ -32,15 +33,81 @@ var PRIMARY_GROQ_MODEL = "llama3-70b-8192";
|
|
|
32
33
|
var FALLBACK_GROQ_MODEL = process.env.GROQ_FALLBACK_MODEL ?? "llama-3.3-70b-versatile";
|
|
33
34
|
function extractJson(content) {
|
|
34
35
|
const trimmed = content.trim();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
throw new Error("AI did not return valid JSON.");
|
|
36
|
+
const tryParse = (input) => {
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(input);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
};
|
|
43
|
+
const sanitizeControlCharsInStrings = (input) => {
|
|
44
|
+
let result = "";
|
|
45
|
+
let inString = false;
|
|
46
|
+
let escaping = false;
|
|
47
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
48
|
+
const ch = input[i];
|
|
49
|
+
if (!inString) {
|
|
50
|
+
result += ch;
|
|
51
|
+
if (ch === '"') {
|
|
52
|
+
inString = true;
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (escaping) {
|
|
57
|
+
result += ch;
|
|
58
|
+
escaping = false;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (ch === "\\") {
|
|
62
|
+
result += ch;
|
|
63
|
+
escaping = true;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (ch === '"') {
|
|
67
|
+
result += ch;
|
|
68
|
+
inString = false;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (ch === "\n") {
|
|
72
|
+
result += "\\n";
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (ch === "\r") {
|
|
76
|
+
result += "\\r";
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (ch === " ") {
|
|
80
|
+
result += "\\t";
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const code = ch.charCodeAt(0);
|
|
84
|
+
if (code < 32) {
|
|
85
|
+
result += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
result += ch;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
};
|
|
92
|
+
const direct = tryParse(trimmed);
|
|
93
|
+
if (direct !== null) {
|
|
94
|
+
return direct;
|
|
43
95
|
}
|
|
96
|
+
const match = trimmed.match(/\{[\s\S]*\}/);
|
|
97
|
+
if (!match) {
|
|
98
|
+
throw new Error("AI did not return valid JSON.");
|
|
99
|
+
}
|
|
100
|
+
const extracted = match[0];
|
|
101
|
+
const extractedParsed = tryParse(extracted);
|
|
102
|
+
if (extractedParsed !== null) {
|
|
103
|
+
return extractedParsed;
|
|
104
|
+
}
|
|
105
|
+
const sanitized = sanitizeControlCharsInStrings(extracted);
|
|
106
|
+
const sanitizedParsed = tryParse(sanitized);
|
|
107
|
+
if (sanitizedParsed !== null) {
|
|
108
|
+
return sanitizedParsed;
|
|
109
|
+
}
|
|
110
|
+
throw new Error("AI did not return valid JSON.");
|
|
44
111
|
}
|
|
45
112
|
function stringifyField(value) {
|
|
46
113
|
if (typeof value === "string") {
|
|
@@ -235,6 +302,15 @@ async function runExplainCommand(errorMessage, deps = {}) {
|
|
|
235
302
|
}
|
|
236
303
|
|
|
237
304
|
// src/cli.ts
|
|
305
|
+
var require2 = createRequire(import.meta.url);
|
|
306
|
+
function getCliVersion() {
|
|
307
|
+
try {
|
|
308
|
+
const pkg = require2("../package.json");
|
|
309
|
+
return pkg.version ?? "0.0.0";
|
|
310
|
+
} catch {
|
|
311
|
+
return "0.0.0";
|
|
312
|
+
}
|
|
313
|
+
}
|
|
238
314
|
async function readStdin() {
|
|
239
315
|
if (process.stdin.isTTY) {
|
|
240
316
|
return "";
|
|
@@ -336,7 +412,7 @@ async function runCli(argv = process.argv, deps = {}) {
|
|
|
336
412
|
const ensureApiKeyFn = deps.ensureApiKey ?? (deps.runExplain ? async () => true : ensureGroqApiKey);
|
|
337
413
|
const log = deps.log ?? logger;
|
|
338
414
|
const program = new Command();
|
|
339
|
-
program.name("explain-my-error").description("Explain programming errors with AI").version(
|
|
415
|
+
program.name("explain-my-error").description("Explain programming errors with AI").version(getCliVersion()).addHelpText(
|
|
340
416
|
"after",
|
|
341
417
|
`
|
|
342
418
|
Input modes:
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli-entry.ts","../src/cli.ts","../src/commands/explain.ts","../src/services/ai.ts","../src/types/error.ts","../src/utils/formatter.ts","../src/utils/logger.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { runCli } from \"./cli.js\";\n\nrunCli().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : \"Unexpected CLI failure\";\n process.stderr.write(`${message}\\n`);\n process.exit(1);\n});\n","import { access, readFile, writeFile } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline/promises\";\nimport { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { runExplainCommand } from \"./commands/explain.js\";\nimport { logger } from \"./utils/logger.js\";\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) {\n return \"\";\n }\n\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\").trim();\n}\n\nasync function promptForError(): Promise<string> {\n if (!process.stdin.isTTY) {\n return \"\";\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.info(pc.cyan(\"Paste an error message and press Enter.\"));\n logger.info(pc.dim('Example: TypeError: Cannot read property \"map\" of undefined'));\n while (true) {\n const answer = await rl.question(pc.bold(pc.cyan(\"\\n> Error message: \")));\n const trimmed = answer.trim();\n\n if (trimmed) {\n return trimmed;\n }\n\n logger.warn(\"Error message cannot be empty. Please try again.\");\n }\n } finally {\n rl.close();\n }\n}\n\nasync function upsertEnvVar(filePath: string, key: string, value: string): Promise<void> {\n let existing = \"\";\n try {\n await access(filePath);\n existing = await readFile(filePath, \"utf8\");\n } catch {\n existing = \"\";\n }\n\n const envLine = `${key}=${value}`;\n const keyPattern = new RegExp(`^${key}=.*$`, \"m\");\n let nextContent: string;\n\n if (keyPattern.test(existing)) {\n nextContent = existing.replace(keyPattern, envLine);\n } else if (!existing.trim()) {\n nextContent = `${envLine}\\n`;\n } else {\n const needsTrailingNewline = !existing.endsWith(\"\\n\");\n nextContent = `${existing}${needsTrailingNewline ? \"\\n\" : \"\"}${envLine}\\n`;\n }\n\n await writeFile(filePath, nextContent, \"utf8\");\n}\n\nasync function ensureGroqApiKey(): Promise<boolean> {\n if (process.env.GROQ_API_KEY?.trim()) {\n return true;\n }\n\n if (!process.stdin.isTTY) {\n return false;\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.warn(\"GROQ_API_KEY is missing.\");\n logger.info(pc.cyan(\"Paste your Groq API key to continue.\"));\n\n while (true) {\n const key = (await rl.question(pc.bold(pc.cyan(\"\\n> GROQ_API_KEY: \")))).trim();\n if (!key) {\n logger.warn(\"API key cannot be empty. Please try again.\");\n continue;\n }\n\n process.env.GROQ_API_KEY = key;\n\n const saveAnswer = (\n await rl.question(pc.dim(\"Save this key to .env in current directory? (Y/n): \"))\n )\n .trim()\n .toLowerCase();\n const shouldSave = saveAnswer === \"\" || saveAnswer === \"y\" || saveAnswer === \"yes\";\n\n if (shouldSave) {\n try {\n await upsertEnvVar(\".env\", \"GROQ_API_KEY\", key);\n logger.success(\"Saved GROQ_API_KEY to .env\");\n } catch {\n logger.warn(\"Could not save key to .env, but this session will continue.\");\n }\n }\n\n return true;\n }\n } finally {\n rl.close();\n }\n}\n\ntype CliLogger = {\n warn(message: string): void;\n};\n\ntype RunCliDeps = {\n runExplain?: (errorMessage: string) => Promise<void>;\n readStdin?: () => Promise<string>;\n promptForError?: () => Promise<string>;\n stdinIsTTY?: () => boolean;\n ensureApiKey?: () => Promise<boolean>;\n log?: CliLogger;\n};\n\nexport async function runCli(argv: string[] = process.argv, deps: RunCliDeps = {}): Promise<void> {\n const runExplain = deps.runExplain ?? runExplainCommand;\n const readStdinFn = deps.readStdin ?? readStdin;\n const promptForErrorFn = deps.promptForError ?? promptForError;\n const stdinIsTTY = deps.stdinIsTTY ?? (() => Boolean(process.stdin.isTTY));\n const ensureApiKeyFn =\n deps.ensureApiKey ?? (deps.runExplain ? async () => true : ensureGroqApiKey);\n const log = deps.log ?? logger;\n\n const program = new Command();\n\n program\n .name(\"explain-my-error\")\n .description(\"Explain programming errors with AI\")\n .version(\"1.0.0\")\n .addHelpText(\n \"after\",\n `\nInput modes:\n 1) Interactive (default)\n $ explain-my-error\n $ eme\n\n 2) Inline argument\n $ explain-my-error explain \"TypeError: Cannot read property 'map' of undefined\"\n $ eme explain \"ReferenceError: x is not defined\"\n\n 3) Pipe from files/commands\n $ cat error.txt | explain-my-error\n $ pnpm run build 2>&1 | eme\n`,\n );\n\n program\n .command(\"explain\")\n .description(\"Explain a programming error message\")\n .argument(\"[error...]\", \"Error message to analyze\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ explain-my-error explain \"SyntaxError: Unexpected token }\"\n $ eme explain \"Module not found: Can't resolve 'axios'\"\n $ cat error.txt | explain-my-error explain\n`,\n )\n .action(async (errorParts: string[]) => {\n const inlineError = errorParts.join(\" \").trim();\n const pipedError = inlineError ? \"\" : await readStdinFn();\n const promptedError = !inlineError && !pipedError ? await promptForErrorFn() : \"\";\n const finalError = inlineError || pipedError || promptedError;\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n await runExplain(finalError);\n });\n\n program.action(async () => {\n if (stdinIsTTY()) {\n const promptedError = await promptForErrorFn();\n await runExplain(promptedError);\n return;\n }\n\n const pipedError = await readStdinFn();\n if (!pipedError) {\n log.warn('No input detected. Use: explain-my-error explain \"<error message>\"');\n return;\n }\n\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n\n await runExplain(pipedError);\n });\n\n await program.parseAsync(argv);\n}\n","import ora from \"ora\";\nimport { explainErrorWithAI } from \"../services/ai.js\";\nimport type { ExplainedError } from \"../types/error.js\";\nimport { formatExplainedError } from \"../utils/formatter.js\";\nimport { logger } from \"../utils/logger.js\";\n\ntype SpinnerLike = {\n succeed(text: string): void;\n fail(text: string): void;\n};\n\ntype ExplainLogger = {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n};\n\ntype RunExplainDeps = {\n explainError?: (errorMessage: string) => Promise<ExplainedError>;\n createSpinner?: (text: string) => SpinnerLike;\n formatOutput?: (result: ExplainedError) => string;\n log?: ExplainLogger;\n};\n\nexport async function runExplainCommand(\n errorMessage: string,\n deps: RunExplainDeps = {},\n): Promise<void> {\n const explainError = deps.explainError ?? explainErrorWithAI;\n const createSpinner = deps.createSpinner ?? ((text: string) => ora(text).start());\n const formatOutput = deps.formatOutput ?? formatExplainedError;\n const log = deps.log ?? logger;\n\n if (!errorMessage?.trim()) {\n log.warn(\"Please provide an error message.\");\n return;\n }\n\n const spinner = createSpinner(\"Analyzing your error...\");\n\n try {\n const result = await explainError(errorMessage.trim());\n spinner.succeed(\"Explanation ready.\");\n log.info(\"\");\n log.info(formatOutput(result));\n } catch (error) {\n spinner.fail(\"Could not explain this error.\");\n const message = error instanceof Error ? error.message : \"Unknown error\";\n log.error(message);\n }\n}\n","import axios from \"axios\";\nimport { type ExplainedError, explainedErrorSchema } from \"../types/error.js\";\n\nconst GROQ_API_URL = \"https://api.groq.com/openai/v1/chat/completions\";\nconst PRIMARY_GROQ_MODEL = \"llama3-70b-8192\";\nconst FALLBACK_GROQ_MODEL = process.env.GROQ_FALLBACK_MODEL ?? \"llama-3.3-70b-versatile\";\n\ntype GroqChatResponse = {\n choices?: Array<{ message?: { content?: string } }>;\n};\n\nfunction extractJson(content: string): unknown {\n const trimmed = content.trim();\n\n try {\n return JSON.parse(trimmed);\n } catch {\n const match = trimmed.match(/\\{[\\s\\S]*\\}/);\n if (!match) {\n throw new Error(\"AI did not return valid JSON.\");\n }\n return JSON.parse(match[0]);\n }\n}\n\nfunction stringifyField(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value == null) {\n return \"\";\n }\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nfunction normalizeResponseShape(payload: unknown): unknown {\n if (!payload || typeof payload !== \"object\") {\n return payload;\n }\n\n const data = payload as Record<string, unknown>;\n\n const rawCauses = data.common_causes;\n const commonCauses = Array.isArray(rawCauses)\n ? rawCauses.map((item) => stringifyField(item)).filter(Boolean)\n : stringifyField(rawCauses)\n .split(/\\n|,/)\n .map((item) => item.trim())\n .filter(Boolean);\n\n return {\n title: stringifyField(data.title),\n explanation: stringifyField(data.explanation),\n common_causes: commonCauses,\n fix: stringifyField(data.fix),\n code_example: stringifyField(data.code_example),\n eli5: stringifyField(data.eli5),\n };\n}\n\nexport async function explainErrorWithAI(errorMessage: string): Promise<ExplainedError> {\n const apiKey = process.env.GROQ_API_KEY;\n if (!apiKey) {\n throw new Error(\n [\n \"Missing GROQ_API_KEY environment variable.\",\n \"\",\n \"Quick setup:\",\n \" macOS/Linux (zsh/bash):\",\n ' export GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \" Windows PowerShell:\",\n ' $env:GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \"Then run the CLI again.\",\n ].join(\"\\n\"),\n );\n }\n\n const prompt =\n \"You are a senior software engineer. Explain the programming error and return JSON with fields: title, explanation, common_causes, fix, code_example, eli5.\";\n\n const requestBody = {\n messages: [\n { role: \"system\" as const, content: prompt },\n {\n role: \"user\" as const,\n content: `Error message:\\n${errorMessage}\\n\\nReturn strict JSON only.`,\n },\n ],\n temperature: 0.2,\n };\n\n const requestConfig = {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n };\n\n let response: { data?: GroqChatResponse };\n try {\n response = await axios.post(\n GROQ_API_URL,\n { model: PRIMARY_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } catch (error) {\n if (axios.isAxiosError(error)) {\n const providerMessage =\n typeof error.response?.data?.error?.message === \"string\"\n ? error.response.data.error.message\n : error.message;\n\n const isModelDecommissioned =\n providerMessage.toLowerCase().includes(\"decommissioned\") ||\n providerMessage.toLowerCase().includes(\"no longer supported\");\n\n if (isModelDecommissioned) {\n response = await axios.post(\n GROQ_API_URL,\n { model: FALLBACK_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } else {\n throw new Error(`Groq API request failed: ${providerMessage}`);\n }\n } else {\n throw error;\n }\n }\n\n const content = response.data?.choices?.[0]?.message?.content;\n if (typeof content !== \"string\" || !content.trim()) {\n throw new Error(\"AI response was empty.\");\n }\n\n const parsed = extractJson(content);\n const normalized = normalizeResponseShape(parsed);\n return explainedErrorSchema.parse(normalized);\n}\n","import { z } from \"zod\";\n\nexport const explainedErrorSchema = z.object({\n title: z.string().min(1),\n explanation: z.string().min(1),\n common_causes: z.array(z.string().min(1)).min(1),\n fix: z.string().min(1),\n code_example: z.string().min(1),\n eli5: z.string().min(1),\n});\n\nexport type ExplainedError = z.infer<typeof explainedErrorSchema>;\n","import pc from \"picocolors\";\nimport type { ExplainedError } from \"../types/error.js\";\n\nconst CARD_WIDTH = 72;\n\nfunction line(char = \"-\"): string {\n return char.repeat(CARD_WIDTH);\n}\n\nfunction pad(text: string): string {\n return text.length > CARD_WIDTH - 4 ? `${text.slice(0, CARD_WIDTH - 7)}...` : text;\n}\n\nfunction framedLine(text: string): string {\n return `| ${pad(text).padEnd(CARD_WIDTH - 4)} |`;\n}\n\nfunction block(title: string, body: string): string {\n const rows = body.split(\"\\n\").map((row) => pc.white(row));\n return [pc.cyan(line()), pc.bold(pc.cyan(title)), ...rows, pc.cyan(line())].join(\"\\n\");\n}\n\nexport function formatExplainedError(result: ExplainedError): string {\n const commonCauses = result.common_causes\n .map((cause, index) => pc.white(`${index + 1}. ${cause}`))\n .join(\"\\n\");\n const hero = [\n pc.cyan(line(\"=\")),\n framedLine(pc.bold(pc.cyan(\"EXPLAIN MY ERROR\"))),\n framedLine(pc.dim(\"AI powered debugging for humans\")),\n pc.cyan(line(\"=\")),\n ].join(\"\\n\");\n\n return [\n hero,\n \"\",\n `${pc.bold(pc.cyan(\"ERROR\"))}: ${pc.bold(pc.white(result.title))}`,\n \"\",\n block(\"EXPLANATION\", result.explanation),\n \"\",\n block(\"COMMON CAUSES\", commonCauses),\n \"\",\n `${pc.bold(pc.green(\"FIX\"))}\\n${pc.white(result.fix)}`,\n \"\",\n block(\"CODE EXAMPLE\", result.code_example),\n \"\",\n block(\"ELI5\", result.eli5),\n \"\",\n pc.dim('Tip: run `eme explain \"<error>\"` for quick mode.'),\n ].join(\"\\n\");\n}\n","import pc from \"picocolors\";\n\nexport const logger = {\n info(message: string): void {\n process.stdout.write(`${pc.white(message)}\\n`);\n },\n success(message: string): void {\n process.stdout.write(`${pc.green(`OK: ${message}`)}\\n`);\n },\n warn(message: string): void {\n process.stderr.write(`${pc.yellow(`WARN: ${message}`)}\\n`);\n },\n error(message: string): void {\n process.stderr.write(`${pc.red(`ERROR: ${message}`)}\\n`);\n },\n};\n"],"mappings":"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","names":["pc","pc","pc"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli-entry.ts","../src/cli.ts","../src/commands/explain.ts","../src/services/ai.ts","../src/types/error.ts","../src/utils/formatter.ts","../src/utils/logger.ts"],"sourcesContent":["#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { runCli } from \"./cli.js\";\n\nrunCli().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : \"Unexpected CLI failure\";\n process.stderr.write(`${message}\\n`);\n process.exit(1);\n});\n","import { access, readFile, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { createInterface } from \"node:readline/promises\";\nimport { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { runExplainCommand } from \"./commands/explain.js\";\nimport { logger } from \"./utils/logger.js\";\n\nconst require = createRequire(import.meta.url);\n\nfunction getCliVersion(): string {\n try {\n const pkg = require(\"../package.json\") as { version?: string };\n return pkg.version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) {\n return \"\";\n }\n\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\").trim();\n}\n\nasync function promptForError(): Promise<string> {\n if (!process.stdin.isTTY) {\n return \"\";\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.info(pc.cyan(\"Paste an error message and press Enter.\"));\n logger.info(pc.dim('Example: TypeError: Cannot read property \"map\" of undefined'));\n while (true) {\n const answer = await rl.question(pc.bold(pc.cyan(\"\\n> Error message: \")));\n const trimmed = answer.trim();\n\n if (trimmed) {\n return trimmed;\n }\n\n logger.warn(\"Error message cannot be empty. Please try again.\");\n }\n } finally {\n rl.close();\n }\n}\n\nasync function upsertEnvVar(filePath: string, key: string, value: string): Promise<void> {\n let existing = \"\";\n try {\n await access(filePath);\n existing = await readFile(filePath, \"utf8\");\n } catch {\n existing = \"\";\n }\n\n const envLine = `${key}=${value}`;\n const keyPattern = new RegExp(`^${key}=.*$`, \"m\");\n let nextContent: string;\n\n if (keyPattern.test(existing)) {\n nextContent = existing.replace(keyPattern, envLine);\n } else if (!existing.trim()) {\n nextContent = `${envLine}\\n`;\n } else {\n const needsTrailingNewline = !existing.endsWith(\"\\n\");\n nextContent = `${existing}${needsTrailingNewline ? \"\\n\" : \"\"}${envLine}\\n`;\n }\n\n await writeFile(filePath, nextContent, \"utf8\");\n}\n\nasync function ensureGroqApiKey(): Promise<boolean> {\n if (process.env.GROQ_API_KEY?.trim()) {\n return true;\n }\n\n if (!process.stdin.isTTY) {\n return false;\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.warn(\"GROQ_API_KEY is missing.\");\n logger.info(pc.cyan(\"Paste your Groq API key to continue.\"));\n\n while (true) {\n const key = (await rl.question(pc.bold(pc.cyan(\"\\n> GROQ_API_KEY: \")))).trim();\n if (!key) {\n logger.warn(\"API key cannot be empty. Please try again.\");\n continue;\n }\n\n process.env.GROQ_API_KEY = key;\n\n const saveAnswer = (\n await rl.question(pc.dim(\"Save this key to .env in current directory? (Y/n): \"))\n )\n .trim()\n .toLowerCase();\n const shouldSave = saveAnswer === \"\" || saveAnswer === \"y\" || saveAnswer === \"yes\";\n\n if (shouldSave) {\n try {\n await upsertEnvVar(\".env\", \"GROQ_API_KEY\", key);\n logger.success(\"Saved GROQ_API_KEY to .env\");\n } catch {\n logger.warn(\"Could not save key to .env, but this session will continue.\");\n }\n }\n\n return true;\n }\n } finally {\n rl.close();\n }\n}\n\ntype CliLogger = {\n warn(message: string): void;\n};\n\ntype RunCliDeps = {\n runExplain?: (errorMessage: string) => Promise<void>;\n readStdin?: () => Promise<string>;\n promptForError?: () => Promise<string>;\n stdinIsTTY?: () => boolean;\n ensureApiKey?: () => Promise<boolean>;\n log?: CliLogger;\n};\n\nexport async function runCli(argv: string[] = process.argv, deps: RunCliDeps = {}): Promise<void> {\n const runExplain = deps.runExplain ?? runExplainCommand;\n const readStdinFn = deps.readStdin ?? readStdin;\n const promptForErrorFn = deps.promptForError ?? promptForError;\n const stdinIsTTY = deps.stdinIsTTY ?? (() => Boolean(process.stdin.isTTY));\n const ensureApiKeyFn =\n deps.ensureApiKey ?? (deps.runExplain ? async () => true : ensureGroqApiKey);\n const log = deps.log ?? logger;\n\n const program = new Command();\n\n program\n .name(\"explain-my-error\")\n .description(\"Explain programming errors with AI\")\n .version(getCliVersion())\n .addHelpText(\n \"after\",\n `\nInput modes:\n 1) Interactive (default)\n $ explain-my-error\n $ eme\n\n 2) Inline argument\n $ explain-my-error explain \"TypeError: Cannot read property 'map' of undefined\"\n $ eme explain \"ReferenceError: x is not defined\"\n\n 3) Pipe from files/commands\n $ cat error.txt | explain-my-error\n $ pnpm run build 2>&1 | eme\n`,\n );\n\n program\n .command(\"explain\")\n .description(\"Explain a programming error message\")\n .argument(\"[error...]\", \"Error message to analyze\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ explain-my-error explain \"SyntaxError: Unexpected token }\"\n $ eme explain \"Module not found: Can't resolve 'axios'\"\n $ cat error.txt | explain-my-error explain\n`,\n )\n .action(async (errorParts: string[]) => {\n const inlineError = errorParts.join(\" \").trim();\n const pipedError = inlineError ? \"\" : await readStdinFn();\n const promptedError = !inlineError && !pipedError ? await promptForErrorFn() : \"\";\n const finalError = inlineError || pipedError || promptedError;\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n await runExplain(finalError);\n });\n\n program.action(async () => {\n if (stdinIsTTY()) {\n const promptedError = await promptForErrorFn();\n await runExplain(promptedError);\n return;\n }\n\n const pipedError = await readStdinFn();\n if (!pipedError) {\n log.warn('No input detected. Use: explain-my-error explain \"<error message>\"');\n return;\n }\n\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n\n await runExplain(pipedError);\n });\n\n await program.parseAsync(argv);\n}\n","import ora from \"ora\";\nimport { explainErrorWithAI } from \"../services/ai.js\";\nimport type { ExplainedError } from \"../types/error.js\";\nimport { formatExplainedError } from \"../utils/formatter.js\";\nimport { logger } from \"../utils/logger.js\";\n\ntype SpinnerLike = {\n succeed(text: string): void;\n fail(text: string): void;\n};\n\ntype ExplainLogger = {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n};\n\ntype RunExplainDeps = {\n explainError?: (errorMessage: string) => Promise<ExplainedError>;\n createSpinner?: (text: string) => SpinnerLike;\n formatOutput?: (result: ExplainedError) => string;\n log?: ExplainLogger;\n};\n\nexport async function runExplainCommand(\n errorMessage: string,\n deps: RunExplainDeps = {},\n): Promise<void> {\n const explainError = deps.explainError ?? explainErrorWithAI;\n const createSpinner = deps.createSpinner ?? ((text: string) => ora(text).start());\n const formatOutput = deps.formatOutput ?? formatExplainedError;\n const log = deps.log ?? logger;\n\n if (!errorMessage?.trim()) {\n log.warn(\"Please provide an error message.\");\n return;\n }\n\n const spinner = createSpinner(\"Analyzing your error...\");\n\n try {\n const result = await explainError(errorMessage.trim());\n spinner.succeed(\"Explanation ready.\");\n log.info(\"\");\n log.info(formatOutput(result));\n } catch (error) {\n spinner.fail(\"Could not explain this error.\");\n const message = error instanceof Error ? error.message : \"Unknown error\";\n log.error(message);\n }\n}\n","import axios from \"axios\";\nimport { type ExplainedError, explainedErrorSchema } from \"../types/error.js\";\n\nconst GROQ_API_URL = \"https://api.groq.com/openai/v1/chat/completions\";\nconst PRIMARY_GROQ_MODEL = \"llama3-70b-8192\";\nconst FALLBACK_GROQ_MODEL = process.env.GROQ_FALLBACK_MODEL ?? \"llama-3.3-70b-versatile\";\n\ntype GroqChatResponse = {\n choices?: Array<{ message?: { content?: string } }>;\n};\n\nfunction extractJson(content: string): unknown {\n const trimmed = content.trim();\n\n const tryParse = (input: string): unknown | null => {\n try {\n return JSON.parse(input);\n } catch {\n return null;\n }\n };\n\n const sanitizeControlCharsInStrings = (input: string): string => {\n let result = \"\";\n let inString = false;\n let escaping = false;\n\n for (let i = 0; i < input.length; i += 1) {\n const ch = input[i];\n\n if (!inString) {\n result += ch;\n if (ch === '\"') {\n inString = true;\n }\n continue;\n }\n\n if (escaping) {\n result += ch;\n escaping = false;\n continue;\n }\n\n if (ch === \"\\\\\") {\n result += ch;\n escaping = true;\n continue;\n }\n\n if (ch === '\"') {\n result += ch;\n inString = false;\n continue;\n }\n\n if (ch === \"\\n\") {\n result += \"\\\\n\";\n continue;\n }\n if (ch === \"\\r\") {\n result += \"\\\\r\";\n continue;\n }\n if (ch === \"\\t\") {\n result += \"\\\\t\";\n continue;\n }\n\n const code = ch.charCodeAt(0);\n if (code < 0x20) {\n result += `\\\\u${code.toString(16).padStart(4, \"0\")}`;\n continue;\n }\n\n result += ch;\n }\n\n return result;\n };\n\n const direct = tryParse(trimmed);\n if (direct !== null) {\n return direct;\n }\n\n const match = trimmed.match(/\\{[\\s\\S]*\\}/);\n if (!match) {\n throw new Error(\"AI did not return valid JSON.\");\n }\n\n const extracted = match[0];\n const extractedParsed = tryParse(extracted);\n if (extractedParsed !== null) {\n return extractedParsed;\n }\n\n const sanitized = sanitizeControlCharsInStrings(extracted);\n const sanitizedParsed = tryParse(sanitized);\n if (sanitizedParsed !== null) {\n return sanitizedParsed;\n }\n\n throw new Error(\"AI did not return valid JSON.\");\n}\n\nfunction stringifyField(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value == null) {\n return \"\";\n }\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nfunction normalizeResponseShape(payload: unknown): unknown {\n if (!payload || typeof payload !== \"object\") {\n return payload;\n }\n\n const data = payload as Record<string, unknown>;\n\n const rawCauses = data.common_causes;\n const commonCauses = Array.isArray(rawCauses)\n ? rawCauses.map((item) => stringifyField(item)).filter(Boolean)\n : stringifyField(rawCauses)\n .split(/\\n|,/)\n .map((item) => item.trim())\n .filter(Boolean);\n\n return {\n title: stringifyField(data.title),\n explanation: stringifyField(data.explanation),\n common_causes: commonCauses,\n fix: stringifyField(data.fix),\n code_example: stringifyField(data.code_example),\n eli5: stringifyField(data.eli5),\n };\n}\n\nexport async function explainErrorWithAI(errorMessage: string): Promise<ExplainedError> {\n const apiKey = process.env.GROQ_API_KEY;\n if (!apiKey) {\n throw new Error(\n [\n \"Missing GROQ_API_KEY environment variable.\",\n \"\",\n \"Quick setup:\",\n \" macOS/Linux (zsh/bash):\",\n ' export GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \" Windows PowerShell:\",\n ' $env:GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \"Then run the CLI again.\",\n ].join(\"\\n\"),\n );\n }\n\n const prompt =\n \"You are a senior software engineer. Explain the programming error and return JSON with fields: title, explanation, common_causes, fix, code_example, eli5.\";\n\n const requestBody = {\n messages: [\n { role: \"system\" as const, content: prompt },\n {\n role: \"user\" as const,\n content: `Error message:\\n${errorMessage}\\n\\nReturn strict JSON only.`,\n },\n ],\n temperature: 0.2,\n };\n\n const requestConfig = {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n };\n\n let response: { data?: GroqChatResponse };\n try {\n response = await axios.post(\n GROQ_API_URL,\n { model: PRIMARY_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } catch (error) {\n if (axios.isAxiosError(error)) {\n const providerMessage =\n typeof error.response?.data?.error?.message === \"string\"\n ? error.response.data.error.message\n : error.message;\n\n const isModelDecommissioned =\n providerMessage.toLowerCase().includes(\"decommissioned\") ||\n providerMessage.toLowerCase().includes(\"no longer supported\");\n\n if (isModelDecommissioned) {\n response = await axios.post(\n GROQ_API_URL,\n { model: FALLBACK_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } else {\n throw new Error(`Groq API request failed: ${providerMessage}`);\n }\n } else {\n throw error;\n }\n }\n\n const content = response.data?.choices?.[0]?.message?.content;\n if (typeof content !== \"string\" || !content.trim()) {\n throw new Error(\"AI response was empty.\");\n }\n\n const parsed = extractJson(content);\n const normalized = normalizeResponseShape(parsed);\n return explainedErrorSchema.parse(normalized);\n}\n","import { z } from \"zod\";\n\nexport const explainedErrorSchema = z.object({\n title: z.string().min(1),\n explanation: z.string().min(1),\n common_causes: z.array(z.string().min(1)).min(1),\n fix: z.string().min(1),\n code_example: z.string().min(1),\n eli5: z.string().min(1),\n});\n\nexport type ExplainedError = z.infer<typeof explainedErrorSchema>;\n","import pc from \"picocolors\";\nimport type { ExplainedError } from \"../types/error.js\";\n\nconst CARD_WIDTH = 72;\n\nfunction line(char = \"-\"): string {\n return char.repeat(CARD_WIDTH);\n}\n\nfunction pad(text: string): string {\n return text.length > CARD_WIDTH - 4 ? `${text.slice(0, CARD_WIDTH - 7)}...` : text;\n}\n\nfunction framedLine(text: string): string {\n return `| ${pad(text).padEnd(CARD_WIDTH - 4)} |`;\n}\n\nfunction block(title: string, body: string): string {\n const rows = body.split(\"\\n\").map((row) => pc.white(row));\n return [pc.cyan(line()), pc.bold(pc.cyan(title)), ...rows, pc.cyan(line())].join(\"\\n\");\n}\n\nexport function formatExplainedError(result: ExplainedError): string {\n const commonCauses = result.common_causes\n .map((cause, index) => pc.white(`${index + 1}. ${cause}`))\n .join(\"\\n\");\n const hero = [\n pc.cyan(line(\"=\")),\n framedLine(pc.bold(pc.cyan(\"EXPLAIN MY ERROR\"))),\n framedLine(pc.dim(\"AI powered debugging for humans\")),\n pc.cyan(line(\"=\")),\n ].join(\"\\n\");\n\n return [\n hero,\n \"\",\n `${pc.bold(pc.cyan(\"ERROR\"))}: ${pc.bold(pc.white(result.title))}`,\n \"\",\n block(\"EXPLANATION\", result.explanation),\n \"\",\n block(\"COMMON CAUSES\", commonCauses),\n \"\",\n `${pc.bold(pc.green(\"FIX\"))}\\n${pc.white(result.fix)}`,\n \"\",\n block(\"CODE EXAMPLE\", result.code_example),\n \"\",\n block(\"ELI5\", result.eli5),\n \"\",\n pc.dim('Tip: run `eme explain \"<error>\"` for quick mode.'),\n ].join(\"\\n\");\n}\n","import pc from \"picocolors\";\n\nexport const logger = {\n info(message: string): void {\n process.stdout.write(`${pc.white(message)}\\n`);\n },\n success(message: string): void {\n process.stdout.write(`${pc.green(`OK: ${message}`)}\\n`);\n },\n warn(message: string): void {\n process.stderr.write(`${pc.yellow(`WARN: ${message}`)}\\n`);\n },\n error(message: string): void {\n process.stderr.write(`${pc.red(`ERROR: ${message}`)}\\n`);\n },\n};\n"],"mappings":"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","names":["pc","pc","require","pc"]}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
2
|
import { access, readFile, writeFile } from "fs/promises";
|
|
3
|
+
import { createRequire } from "module";
|
|
3
4
|
import { createInterface } from "readline/promises";
|
|
4
5
|
import { Command } from "commander";
|
|
5
6
|
import pc3 from "picocolors";
|
|
@@ -27,15 +28,81 @@ var PRIMARY_GROQ_MODEL = "llama3-70b-8192";
|
|
|
27
28
|
var FALLBACK_GROQ_MODEL = process.env.GROQ_FALLBACK_MODEL ?? "llama-3.3-70b-versatile";
|
|
28
29
|
function extractJson(content) {
|
|
29
30
|
const trimmed = content.trim();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
throw new Error("AI did not return valid JSON.");
|
|
31
|
+
const tryParse = (input) => {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(input);
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
};
|
|
38
|
+
const sanitizeControlCharsInStrings = (input) => {
|
|
39
|
+
let result = "";
|
|
40
|
+
let inString = false;
|
|
41
|
+
let escaping = false;
|
|
42
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
43
|
+
const ch = input[i];
|
|
44
|
+
if (!inString) {
|
|
45
|
+
result += ch;
|
|
46
|
+
if (ch === '"') {
|
|
47
|
+
inString = true;
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (escaping) {
|
|
52
|
+
result += ch;
|
|
53
|
+
escaping = false;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (ch === "\\") {
|
|
57
|
+
result += ch;
|
|
58
|
+
escaping = true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (ch === '"') {
|
|
62
|
+
result += ch;
|
|
63
|
+
inString = false;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (ch === "\n") {
|
|
67
|
+
result += "\\n";
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (ch === "\r") {
|
|
71
|
+
result += "\\r";
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (ch === " ") {
|
|
75
|
+
result += "\\t";
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const code = ch.charCodeAt(0);
|
|
79
|
+
if (code < 32) {
|
|
80
|
+
result += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
result += ch;
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
87
|
+
const direct = tryParse(trimmed);
|
|
88
|
+
if (direct !== null) {
|
|
89
|
+
return direct;
|
|
38
90
|
}
|
|
91
|
+
const match = trimmed.match(/\{[\s\S]*\}/);
|
|
92
|
+
if (!match) {
|
|
93
|
+
throw new Error("AI did not return valid JSON.");
|
|
94
|
+
}
|
|
95
|
+
const extracted = match[0];
|
|
96
|
+
const extractedParsed = tryParse(extracted);
|
|
97
|
+
if (extractedParsed !== null) {
|
|
98
|
+
return extractedParsed;
|
|
99
|
+
}
|
|
100
|
+
const sanitized = sanitizeControlCharsInStrings(extracted);
|
|
101
|
+
const sanitizedParsed = tryParse(sanitized);
|
|
102
|
+
if (sanitizedParsed !== null) {
|
|
103
|
+
return sanitizedParsed;
|
|
104
|
+
}
|
|
105
|
+
throw new Error("AI did not return valid JSON.");
|
|
39
106
|
}
|
|
40
107
|
function stringifyField(value) {
|
|
41
108
|
if (typeof value === "string") {
|
|
@@ -230,6 +297,15 @@ async function runExplainCommand(errorMessage, deps = {}) {
|
|
|
230
297
|
}
|
|
231
298
|
|
|
232
299
|
// src/cli.ts
|
|
300
|
+
var require2 = createRequire(import.meta.url);
|
|
301
|
+
function getCliVersion() {
|
|
302
|
+
try {
|
|
303
|
+
const pkg = require2("../package.json");
|
|
304
|
+
return pkg.version ?? "0.0.0";
|
|
305
|
+
} catch {
|
|
306
|
+
return "0.0.0";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
233
309
|
async function readStdin() {
|
|
234
310
|
if (process.stdin.isTTY) {
|
|
235
311
|
return "";
|
|
@@ -331,7 +407,7 @@ async function runCli(argv = process.argv, deps = {}) {
|
|
|
331
407
|
const ensureApiKeyFn = deps.ensureApiKey ?? (deps.runExplain ? async () => true : ensureGroqApiKey);
|
|
332
408
|
const log = deps.log ?? logger;
|
|
333
409
|
const program = new Command();
|
|
334
|
-
program.name("explain-my-error").description("Explain programming errors with AI").version(
|
|
410
|
+
program.name("explain-my-error").description("Explain programming errors with AI").version(getCliVersion()).addHelpText(
|
|
335
411
|
"after",
|
|
336
412
|
`
|
|
337
413
|
Input modes:
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/explain.ts","../src/services/ai.ts","../src/types/error.ts","../src/utils/formatter.ts","../src/utils/logger.ts","../src/explain.ts","../src/skills/explainError.skill.ts"],"sourcesContent":["import { access, readFile, writeFile } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline/promises\";\nimport { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { runExplainCommand } from \"./commands/explain.js\";\nimport { logger } from \"./utils/logger.js\";\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) {\n return \"\";\n }\n\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\").trim();\n}\n\nasync function promptForError(): Promise<string> {\n if (!process.stdin.isTTY) {\n return \"\";\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.info(pc.cyan(\"Paste an error message and press Enter.\"));\n logger.info(pc.dim('Example: TypeError: Cannot read property \"map\" of undefined'));\n while (true) {\n const answer = await rl.question(pc.bold(pc.cyan(\"\\n> Error message: \")));\n const trimmed = answer.trim();\n\n if (trimmed) {\n return trimmed;\n }\n\n logger.warn(\"Error message cannot be empty. Please try again.\");\n }\n } finally {\n rl.close();\n }\n}\n\nasync function upsertEnvVar(filePath: string, key: string, value: string): Promise<void> {\n let existing = \"\";\n try {\n await access(filePath);\n existing = await readFile(filePath, \"utf8\");\n } catch {\n existing = \"\";\n }\n\n const envLine = `${key}=${value}`;\n const keyPattern = new RegExp(`^${key}=.*$`, \"m\");\n let nextContent: string;\n\n if (keyPattern.test(existing)) {\n nextContent = existing.replace(keyPattern, envLine);\n } else if (!existing.trim()) {\n nextContent = `${envLine}\\n`;\n } else {\n const needsTrailingNewline = !existing.endsWith(\"\\n\");\n nextContent = `${existing}${needsTrailingNewline ? \"\\n\" : \"\"}${envLine}\\n`;\n }\n\n await writeFile(filePath, nextContent, \"utf8\");\n}\n\nasync function ensureGroqApiKey(): Promise<boolean> {\n if (process.env.GROQ_API_KEY?.trim()) {\n return true;\n }\n\n if (!process.stdin.isTTY) {\n return false;\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.warn(\"GROQ_API_KEY is missing.\");\n logger.info(pc.cyan(\"Paste your Groq API key to continue.\"));\n\n while (true) {\n const key = (await rl.question(pc.bold(pc.cyan(\"\\n> GROQ_API_KEY: \")))).trim();\n if (!key) {\n logger.warn(\"API key cannot be empty. Please try again.\");\n continue;\n }\n\n process.env.GROQ_API_KEY = key;\n\n const saveAnswer = (\n await rl.question(pc.dim(\"Save this key to .env in current directory? (Y/n): \"))\n )\n .trim()\n .toLowerCase();\n const shouldSave = saveAnswer === \"\" || saveAnswer === \"y\" || saveAnswer === \"yes\";\n\n if (shouldSave) {\n try {\n await upsertEnvVar(\".env\", \"GROQ_API_KEY\", key);\n logger.success(\"Saved GROQ_API_KEY to .env\");\n } catch {\n logger.warn(\"Could not save key to .env, but this session will continue.\");\n }\n }\n\n return true;\n }\n } finally {\n rl.close();\n }\n}\n\ntype CliLogger = {\n warn(message: string): void;\n};\n\ntype RunCliDeps = {\n runExplain?: (errorMessage: string) => Promise<void>;\n readStdin?: () => Promise<string>;\n promptForError?: () => Promise<string>;\n stdinIsTTY?: () => boolean;\n ensureApiKey?: () => Promise<boolean>;\n log?: CliLogger;\n};\n\nexport async function runCli(argv: string[] = process.argv, deps: RunCliDeps = {}): Promise<void> {\n const runExplain = deps.runExplain ?? runExplainCommand;\n const readStdinFn = deps.readStdin ?? readStdin;\n const promptForErrorFn = deps.promptForError ?? promptForError;\n const stdinIsTTY = deps.stdinIsTTY ?? (() => Boolean(process.stdin.isTTY));\n const ensureApiKeyFn =\n deps.ensureApiKey ?? (deps.runExplain ? async () => true : ensureGroqApiKey);\n const log = deps.log ?? logger;\n\n const program = new Command();\n\n program\n .name(\"explain-my-error\")\n .description(\"Explain programming errors with AI\")\n .version(\"1.0.0\")\n .addHelpText(\n \"after\",\n `\nInput modes:\n 1) Interactive (default)\n $ explain-my-error\n $ eme\n\n 2) Inline argument\n $ explain-my-error explain \"TypeError: Cannot read property 'map' of undefined\"\n $ eme explain \"ReferenceError: x is not defined\"\n\n 3) Pipe from files/commands\n $ cat error.txt | explain-my-error\n $ pnpm run build 2>&1 | eme\n`,\n );\n\n program\n .command(\"explain\")\n .description(\"Explain a programming error message\")\n .argument(\"[error...]\", \"Error message to analyze\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ explain-my-error explain \"SyntaxError: Unexpected token }\"\n $ eme explain \"Module not found: Can't resolve 'axios'\"\n $ cat error.txt | explain-my-error explain\n`,\n )\n .action(async (errorParts: string[]) => {\n const inlineError = errorParts.join(\" \").trim();\n const pipedError = inlineError ? \"\" : await readStdinFn();\n const promptedError = !inlineError && !pipedError ? await promptForErrorFn() : \"\";\n const finalError = inlineError || pipedError || promptedError;\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n await runExplain(finalError);\n });\n\n program.action(async () => {\n if (stdinIsTTY()) {\n const promptedError = await promptForErrorFn();\n await runExplain(promptedError);\n return;\n }\n\n const pipedError = await readStdinFn();\n if (!pipedError) {\n log.warn('No input detected. Use: explain-my-error explain \"<error message>\"');\n return;\n }\n\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n\n await runExplain(pipedError);\n });\n\n await program.parseAsync(argv);\n}\n","import ora from \"ora\";\nimport { explainErrorWithAI } from \"../services/ai.js\";\nimport type { ExplainedError } from \"../types/error.js\";\nimport { formatExplainedError } from \"../utils/formatter.js\";\nimport { logger } from \"../utils/logger.js\";\n\ntype SpinnerLike = {\n succeed(text: string): void;\n fail(text: string): void;\n};\n\ntype ExplainLogger = {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n};\n\ntype RunExplainDeps = {\n explainError?: (errorMessage: string) => Promise<ExplainedError>;\n createSpinner?: (text: string) => SpinnerLike;\n formatOutput?: (result: ExplainedError) => string;\n log?: ExplainLogger;\n};\n\nexport async function runExplainCommand(\n errorMessage: string,\n deps: RunExplainDeps = {},\n): Promise<void> {\n const explainError = deps.explainError ?? explainErrorWithAI;\n const createSpinner = deps.createSpinner ?? ((text: string) => ora(text).start());\n const formatOutput = deps.formatOutput ?? formatExplainedError;\n const log = deps.log ?? logger;\n\n if (!errorMessage?.trim()) {\n log.warn(\"Please provide an error message.\");\n return;\n }\n\n const spinner = createSpinner(\"Analyzing your error...\");\n\n try {\n const result = await explainError(errorMessage.trim());\n spinner.succeed(\"Explanation ready.\");\n log.info(\"\");\n log.info(formatOutput(result));\n } catch (error) {\n spinner.fail(\"Could not explain this error.\");\n const message = error instanceof Error ? error.message : \"Unknown error\";\n log.error(message);\n }\n}\n","import axios from \"axios\";\nimport { type ExplainedError, explainedErrorSchema } from \"../types/error.js\";\n\nconst GROQ_API_URL = \"https://api.groq.com/openai/v1/chat/completions\";\nconst PRIMARY_GROQ_MODEL = \"llama3-70b-8192\";\nconst FALLBACK_GROQ_MODEL = process.env.GROQ_FALLBACK_MODEL ?? \"llama-3.3-70b-versatile\";\n\ntype GroqChatResponse = {\n choices?: Array<{ message?: { content?: string } }>;\n};\n\nfunction extractJson(content: string): unknown {\n const trimmed = content.trim();\n\n try {\n return JSON.parse(trimmed);\n } catch {\n const match = trimmed.match(/\\{[\\s\\S]*\\}/);\n if (!match) {\n throw new Error(\"AI did not return valid JSON.\");\n }\n return JSON.parse(match[0]);\n }\n}\n\nfunction stringifyField(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value == null) {\n return \"\";\n }\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nfunction normalizeResponseShape(payload: unknown): unknown {\n if (!payload || typeof payload !== \"object\") {\n return payload;\n }\n\n const data = payload as Record<string, unknown>;\n\n const rawCauses = data.common_causes;\n const commonCauses = Array.isArray(rawCauses)\n ? rawCauses.map((item) => stringifyField(item)).filter(Boolean)\n : stringifyField(rawCauses)\n .split(/\\n|,/)\n .map((item) => item.trim())\n .filter(Boolean);\n\n return {\n title: stringifyField(data.title),\n explanation: stringifyField(data.explanation),\n common_causes: commonCauses,\n fix: stringifyField(data.fix),\n code_example: stringifyField(data.code_example),\n eli5: stringifyField(data.eli5),\n };\n}\n\nexport async function explainErrorWithAI(errorMessage: string): Promise<ExplainedError> {\n const apiKey = process.env.GROQ_API_KEY;\n if (!apiKey) {\n throw new Error(\n [\n \"Missing GROQ_API_KEY environment variable.\",\n \"\",\n \"Quick setup:\",\n \" macOS/Linux (zsh/bash):\",\n ' export GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \" Windows PowerShell:\",\n ' $env:GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \"Then run the CLI again.\",\n ].join(\"\\n\"),\n );\n }\n\n const prompt =\n \"You are a senior software engineer. Explain the programming error and return JSON with fields: title, explanation, common_causes, fix, code_example, eli5.\";\n\n const requestBody = {\n messages: [\n { role: \"system\" as const, content: prompt },\n {\n role: \"user\" as const,\n content: `Error message:\\n${errorMessage}\\n\\nReturn strict JSON only.`,\n },\n ],\n temperature: 0.2,\n };\n\n const requestConfig = {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n };\n\n let response: { data?: GroqChatResponse };\n try {\n response = await axios.post(\n GROQ_API_URL,\n { model: PRIMARY_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } catch (error) {\n if (axios.isAxiosError(error)) {\n const providerMessage =\n typeof error.response?.data?.error?.message === \"string\"\n ? error.response.data.error.message\n : error.message;\n\n const isModelDecommissioned =\n providerMessage.toLowerCase().includes(\"decommissioned\") ||\n providerMessage.toLowerCase().includes(\"no longer supported\");\n\n if (isModelDecommissioned) {\n response = await axios.post(\n GROQ_API_URL,\n { model: FALLBACK_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } else {\n throw new Error(`Groq API request failed: ${providerMessage}`);\n }\n } else {\n throw error;\n }\n }\n\n const content = response.data?.choices?.[0]?.message?.content;\n if (typeof content !== \"string\" || !content.trim()) {\n throw new Error(\"AI response was empty.\");\n }\n\n const parsed = extractJson(content);\n const normalized = normalizeResponseShape(parsed);\n return explainedErrorSchema.parse(normalized);\n}\n","import { z } from \"zod\";\n\nexport const explainedErrorSchema = z.object({\n title: z.string().min(1),\n explanation: z.string().min(1),\n common_causes: z.array(z.string().min(1)).min(1),\n fix: z.string().min(1),\n code_example: z.string().min(1),\n eli5: z.string().min(1),\n});\n\nexport type ExplainedError = z.infer<typeof explainedErrorSchema>;\n","import pc from \"picocolors\";\nimport type { ExplainedError } from \"../types/error.js\";\n\nconst CARD_WIDTH = 72;\n\nfunction line(char = \"-\"): string {\n return char.repeat(CARD_WIDTH);\n}\n\nfunction pad(text: string): string {\n return text.length > CARD_WIDTH - 4 ? `${text.slice(0, CARD_WIDTH - 7)}...` : text;\n}\n\nfunction framedLine(text: string): string {\n return `| ${pad(text).padEnd(CARD_WIDTH - 4)} |`;\n}\n\nfunction block(title: string, body: string): string {\n const rows = body.split(\"\\n\").map((row) => pc.white(row));\n return [pc.cyan(line()), pc.bold(pc.cyan(title)), ...rows, pc.cyan(line())].join(\"\\n\");\n}\n\nexport function formatExplainedError(result: ExplainedError): string {\n const commonCauses = result.common_causes\n .map((cause, index) => pc.white(`${index + 1}. ${cause}`))\n .join(\"\\n\");\n const hero = [\n pc.cyan(line(\"=\")),\n framedLine(pc.bold(pc.cyan(\"EXPLAIN MY ERROR\"))),\n framedLine(pc.dim(\"AI powered debugging for humans\")),\n pc.cyan(line(\"=\")),\n ].join(\"\\n\");\n\n return [\n hero,\n \"\",\n `${pc.bold(pc.cyan(\"ERROR\"))}: ${pc.bold(pc.white(result.title))}`,\n \"\",\n block(\"EXPLANATION\", result.explanation),\n \"\",\n block(\"COMMON CAUSES\", commonCauses),\n \"\",\n `${pc.bold(pc.green(\"FIX\"))}\\n${pc.white(result.fix)}`,\n \"\",\n block(\"CODE EXAMPLE\", result.code_example),\n \"\",\n block(\"ELI5\", result.eli5),\n \"\",\n pc.dim('Tip: run `eme explain \"<error>\"` for quick mode.'),\n ].join(\"\\n\");\n}\n","import pc from \"picocolors\";\n\nexport const logger = {\n info(message: string): void {\n process.stdout.write(`${pc.white(message)}\\n`);\n },\n success(message: string): void {\n process.stdout.write(`${pc.green(`OK: ${message}`)}\\n`);\n },\n warn(message: string): void {\n process.stderr.write(`${pc.yellow(`WARN: ${message}`)}\\n`);\n },\n error(message: string): void {\n process.stderr.write(`${pc.red(`ERROR: ${message}`)}\\n`);\n },\n};\n","import { explainErrorWithAI } from \"./services/ai.js\";\nimport type { ExplainedError } from \"./types/error.js\";\n\nexport async function explainError(errorMessage: string): Promise<ExplainedError> {\n return explainErrorWithAI(errorMessage);\n}\n","import { z } from \"zod\";\nimport { explainErrorWithAI } from \"../services/ai.js\";\nimport type { ExplainedError } from \"../types/error.js\";\n\nconst explainErrorSkillInputSchema = z.object({\n error: z.string().min(1, \"error is required\"),\n});\n\nexport type ExplainErrorSkillInput = z.infer<typeof explainErrorSkillInputSchema>;\n\nexport async function runExplainErrorSkill(input: ExplainErrorSkillInput): Promise<ExplainedError> {\n const parsedInput = explainErrorSkillInputSchema.parse(input);\n return explainErrorWithAI(parsedInput.error);\n}\n"],"mappings":"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","names":["pc","pc","explainError","pc","z","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/explain.ts","../src/services/ai.ts","../src/types/error.ts","../src/utils/formatter.ts","../src/utils/logger.ts","../src/explain.ts","../src/skills/explainError.skill.ts"],"sourcesContent":["import { access, readFile, writeFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { createInterface } from \"node:readline/promises\";\nimport { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { runExplainCommand } from \"./commands/explain.js\";\nimport { logger } from \"./utils/logger.js\";\n\nconst require = createRequire(import.meta.url);\n\nfunction getCliVersion(): string {\n try {\n const pkg = require(\"../package.json\") as { version?: string };\n return pkg.version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nasync function readStdin(): Promise<string> {\n if (process.stdin.isTTY) {\n return \"\";\n }\n\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\").trim();\n}\n\nasync function promptForError(): Promise<string> {\n if (!process.stdin.isTTY) {\n return \"\";\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.info(pc.cyan(\"Paste an error message and press Enter.\"));\n logger.info(pc.dim('Example: TypeError: Cannot read property \"map\" of undefined'));\n while (true) {\n const answer = await rl.question(pc.bold(pc.cyan(\"\\n> Error message: \")));\n const trimmed = answer.trim();\n\n if (trimmed) {\n return trimmed;\n }\n\n logger.warn(\"Error message cannot be empty. Please try again.\");\n }\n } finally {\n rl.close();\n }\n}\n\nasync function upsertEnvVar(filePath: string, key: string, value: string): Promise<void> {\n let existing = \"\";\n try {\n await access(filePath);\n existing = await readFile(filePath, \"utf8\");\n } catch {\n existing = \"\";\n }\n\n const envLine = `${key}=${value}`;\n const keyPattern = new RegExp(`^${key}=.*$`, \"m\");\n let nextContent: string;\n\n if (keyPattern.test(existing)) {\n nextContent = existing.replace(keyPattern, envLine);\n } else if (!existing.trim()) {\n nextContent = `${envLine}\\n`;\n } else {\n const needsTrailingNewline = !existing.endsWith(\"\\n\");\n nextContent = `${existing}${needsTrailingNewline ? \"\\n\" : \"\"}${envLine}\\n`;\n }\n\n await writeFile(filePath, nextContent, \"utf8\");\n}\n\nasync function ensureGroqApiKey(): Promise<boolean> {\n if (process.env.GROQ_API_KEY?.trim()) {\n return true;\n }\n\n if (!process.stdin.isTTY) {\n return false;\n }\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n logger.warn(\"GROQ_API_KEY is missing.\");\n logger.info(pc.cyan(\"Paste your Groq API key to continue.\"));\n\n while (true) {\n const key = (await rl.question(pc.bold(pc.cyan(\"\\n> GROQ_API_KEY: \")))).trim();\n if (!key) {\n logger.warn(\"API key cannot be empty. Please try again.\");\n continue;\n }\n\n process.env.GROQ_API_KEY = key;\n\n const saveAnswer = (\n await rl.question(pc.dim(\"Save this key to .env in current directory? (Y/n): \"))\n )\n .trim()\n .toLowerCase();\n const shouldSave = saveAnswer === \"\" || saveAnswer === \"y\" || saveAnswer === \"yes\";\n\n if (shouldSave) {\n try {\n await upsertEnvVar(\".env\", \"GROQ_API_KEY\", key);\n logger.success(\"Saved GROQ_API_KEY to .env\");\n } catch {\n logger.warn(\"Could not save key to .env, but this session will continue.\");\n }\n }\n\n return true;\n }\n } finally {\n rl.close();\n }\n}\n\ntype CliLogger = {\n warn(message: string): void;\n};\n\ntype RunCliDeps = {\n runExplain?: (errorMessage: string) => Promise<void>;\n readStdin?: () => Promise<string>;\n promptForError?: () => Promise<string>;\n stdinIsTTY?: () => boolean;\n ensureApiKey?: () => Promise<boolean>;\n log?: CliLogger;\n};\n\nexport async function runCli(argv: string[] = process.argv, deps: RunCliDeps = {}): Promise<void> {\n const runExplain = deps.runExplain ?? runExplainCommand;\n const readStdinFn = deps.readStdin ?? readStdin;\n const promptForErrorFn = deps.promptForError ?? promptForError;\n const stdinIsTTY = deps.stdinIsTTY ?? (() => Boolean(process.stdin.isTTY));\n const ensureApiKeyFn =\n deps.ensureApiKey ?? (deps.runExplain ? async () => true : ensureGroqApiKey);\n const log = deps.log ?? logger;\n\n const program = new Command();\n\n program\n .name(\"explain-my-error\")\n .description(\"Explain programming errors with AI\")\n .version(getCliVersion())\n .addHelpText(\n \"after\",\n `\nInput modes:\n 1) Interactive (default)\n $ explain-my-error\n $ eme\n\n 2) Inline argument\n $ explain-my-error explain \"TypeError: Cannot read property 'map' of undefined\"\n $ eme explain \"ReferenceError: x is not defined\"\n\n 3) Pipe from files/commands\n $ cat error.txt | explain-my-error\n $ pnpm run build 2>&1 | eme\n`,\n );\n\n program\n .command(\"explain\")\n .description(\"Explain a programming error message\")\n .argument(\"[error...]\", \"Error message to analyze\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ explain-my-error explain \"SyntaxError: Unexpected token }\"\n $ eme explain \"Module not found: Can't resolve 'axios'\"\n $ cat error.txt | explain-my-error explain\n`,\n )\n .action(async (errorParts: string[]) => {\n const inlineError = errorParts.join(\" \").trim();\n const pipedError = inlineError ? \"\" : await readStdinFn();\n const promptedError = !inlineError && !pipedError ? await promptForErrorFn() : \"\";\n const finalError = inlineError || pipedError || promptedError;\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n await runExplain(finalError);\n });\n\n program.action(async () => {\n if (stdinIsTTY()) {\n const promptedError = await promptForErrorFn();\n await runExplain(promptedError);\n return;\n }\n\n const pipedError = await readStdinFn();\n if (!pipedError) {\n log.warn('No input detected. Use: explain-my-error explain \"<error message>\"');\n return;\n }\n\n const hasApiKey = await ensureApiKeyFn();\n if (!hasApiKey) {\n log.warn(\"GROQ_API_KEY is required. Set it and run again.\");\n return;\n }\n\n await runExplain(pipedError);\n });\n\n await program.parseAsync(argv);\n}\n","import ora from \"ora\";\nimport { explainErrorWithAI } from \"../services/ai.js\";\nimport type { ExplainedError } from \"../types/error.js\";\nimport { formatExplainedError } from \"../utils/formatter.js\";\nimport { logger } from \"../utils/logger.js\";\n\ntype SpinnerLike = {\n succeed(text: string): void;\n fail(text: string): void;\n};\n\ntype ExplainLogger = {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n};\n\ntype RunExplainDeps = {\n explainError?: (errorMessage: string) => Promise<ExplainedError>;\n createSpinner?: (text: string) => SpinnerLike;\n formatOutput?: (result: ExplainedError) => string;\n log?: ExplainLogger;\n};\n\nexport async function runExplainCommand(\n errorMessage: string,\n deps: RunExplainDeps = {},\n): Promise<void> {\n const explainError = deps.explainError ?? explainErrorWithAI;\n const createSpinner = deps.createSpinner ?? ((text: string) => ora(text).start());\n const formatOutput = deps.formatOutput ?? formatExplainedError;\n const log = deps.log ?? logger;\n\n if (!errorMessage?.trim()) {\n log.warn(\"Please provide an error message.\");\n return;\n }\n\n const spinner = createSpinner(\"Analyzing your error...\");\n\n try {\n const result = await explainError(errorMessage.trim());\n spinner.succeed(\"Explanation ready.\");\n log.info(\"\");\n log.info(formatOutput(result));\n } catch (error) {\n spinner.fail(\"Could not explain this error.\");\n const message = error instanceof Error ? error.message : \"Unknown error\";\n log.error(message);\n }\n}\n","import axios from \"axios\";\nimport { type ExplainedError, explainedErrorSchema } from \"../types/error.js\";\n\nconst GROQ_API_URL = \"https://api.groq.com/openai/v1/chat/completions\";\nconst PRIMARY_GROQ_MODEL = \"llama3-70b-8192\";\nconst FALLBACK_GROQ_MODEL = process.env.GROQ_FALLBACK_MODEL ?? \"llama-3.3-70b-versatile\";\n\ntype GroqChatResponse = {\n choices?: Array<{ message?: { content?: string } }>;\n};\n\nfunction extractJson(content: string): unknown {\n const trimmed = content.trim();\n\n const tryParse = (input: string): unknown | null => {\n try {\n return JSON.parse(input);\n } catch {\n return null;\n }\n };\n\n const sanitizeControlCharsInStrings = (input: string): string => {\n let result = \"\";\n let inString = false;\n let escaping = false;\n\n for (let i = 0; i < input.length; i += 1) {\n const ch = input[i];\n\n if (!inString) {\n result += ch;\n if (ch === '\"') {\n inString = true;\n }\n continue;\n }\n\n if (escaping) {\n result += ch;\n escaping = false;\n continue;\n }\n\n if (ch === \"\\\\\") {\n result += ch;\n escaping = true;\n continue;\n }\n\n if (ch === '\"') {\n result += ch;\n inString = false;\n continue;\n }\n\n if (ch === \"\\n\") {\n result += \"\\\\n\";\n continue;\n }\n if (ch === \"\\r\") {\n result += \"\\\\r\";\n continue;\n }\n if (ch === \"\\t\") {\n result += \"\\\\t\";\n continue;\n }\n\n const code = ch.charCodeAt(0);\n if (code < 0x20) {\n result += `\\\\u${code.toString(16).padStart(4, \"0\")}`;\n continue;\n }\n\n result += ch;\n }\n\n return result;\n };\n\n const direct = tryParse(trimmed);\n if (direct !== null) {\n return direct;\n }\n\n const match = trimmed.match(/\\{[\\s\\S]*\\}/);\n if (!match) {\n throw new Error(\"AI did not return valid JSON.\");\n }\n\n const extracted = match[0];\n const extractedParsed = tryParse(extracted);\n if (extractedParsed !== null) {\n return extractedParsed;\n }\n\n const sanitized = sanitizeControlCharsInStrings(extracted);\n const sanitizedParsed = tryParse(sanitized);\n if (sanitizedParsed !== null) {\n return sanitizedParsed;\n }\n\n throw new Error(\"AI did not return valid JSON.\");\n}\n\nfunction stringifyField(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value == null) {\n return \"\";\n }\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nfunction normalizeResponseShape(payload: unknown): unknown {\n if (!payload || typeof payload !== \"object\") {\n return payload;\n }\n\n const data = payload as Record<string, unknown>;\n\n const rawCauses = data.common_causes;\n const commonCauses = Array.isArray(rawCauses)\n ? rawCauses.map((item) => stringifyField(item)).filter(Boolean)\n : stringifyField(rawCauses)\n .split(/\\n|,/)\n .map((item) => item.trim())\n .filter(Boolean);\n\n return {\n title: stringifyField(data.title),\n explanation: stringifyField(data.explanation),\n common_causes: commonCauses,\n fix: stringifyField(data.fix),\n code_example: stringifyField(data.code_example),\n eli5: stringifyField(data.eli5),\n };\n}\n\nexport async function explainErrorWithAI(errorMessage: string): Promise<ExplainedError> {\n const apiKey = process.env.GROQ_API_KEY;\n if (!apiKey) {\n throw new Error(\n [\n \"Missing GROQ_API_KEY environment variable.\",\n \"\",\n \"Quick setup:\",\n \" macOS/Linux (zsh/bash):\",\n ' export GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \" Windows PowerShell:\",\n ' $env:GROQ_API_KEY=\"your_groq_api_key\"',\n \"\",\n \"Then run the CLI again.\",\n ].join(\"\\n\"),\n );\n }\n\n const prompt =\n \"You are a senior software engineer. Explain the programming error and return JSON with fields: title, explanation, common_causes, fix, code_example, eli5.\";\n\n const requestBody = {\n messages: [\n { role: \"system\" as const, content: prompt },\n {\n role: \"user\" as const,\n content: `Error message:\\n${errorMessage}\\n\\nReturn strict JSON only.`,\n },\n ],\n temperature: 0.2,\n };\n\n const requestConfig = {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n };\n\n let response: { data?: GroqChatResponse };\n try {\n response = await axios.post(\n GROQ_API_URL,\n { model: PRIMARY_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } catch (error) {\n if (axios.isAxiosError(error)) {\n const providerMessage =\n typeof error.response?.data?.error?.message === \"string\"\n ? error.response.data.error.message\n : error.message;\n\n const isModelDecommissioned =\n providerMessage.toLowerCase().includes(\"decommissioned\") ||\n providerMessage.toLowerCase().includes(\"no longer supported\");\n\n if (isModelDecommissioned) {\n response = await axios.post(\n GROQ_API_URL,\n { model: FALLBACK_GROQ_MODEL, ...requestBody },\n requestConfig,\n );\n } else {\n throw new Error(`Groq API request failed: ${providerMessage}`);\n }\n } else {\n throw error;\n }\n }\n\n const content = response.data?.choices?.[0]?.message?.content;\n if (typeof content !== \"string\" || !content.trim()) {\n throw new Error(\"AI response was empty.\");\n }\n\n const parsed = extractJson(content);\n const normalized = normalizeResponseShape(parsed);\n return explainedErrorSchema.parse(normalized);\n}\n","import { z } from \"zod\";\n\nexport const explainedErrorSchema = z.object({\n title: z.string().min(1),\n explanation: z.string().min(1),\n common_causes: z.array(z.string().min(1)).min(1),\n fix: z.string().min(1),\n code_example: z.string().min(1),\n eli5: z.string().min(1),\n});\n\nexport type ExplainedError = z.infer<typeof explainedErrorSchema>;\n","import pc from \"picocolors\";\nimport type { ExplainedError } from \"../types/error.js\";\n\nconst CARD_WIDTH = 72;\n\nfunction line(char = \"-\"): string {\n return char.repeat(CARD_WIDTH);\n}\n\nfunction pad(text: string): string {\n return text.length > CARD_WIDTH - 4 ? `${text.slice(0, CARD_WIDTH - 7)}...` : text;\n}\n\nfunction framedLine(text: string): string {\n return `| ${pad(text).padEnd(CARD_WIDTH - 4)} |`;\n}\n\nfunction block(title: string, body: string): string {\n const rows = body.split(\"\\n\").map((row) => pc.white(row));\n return [pc.cyan(line()), pc.bold(pc.cyan(title)), ...rows, pc.cyan(line())].join(\"\\n\");\n}\n\nexport function formatExplainedError(result: ExplainedError): string {\n const commonCauses = result.common_causes\n .map((cause, index) => pc.white(`${index + 1}. ${cause}`))\n .join(\"\\n\");\n const hero = [\n pc.cyan(line(\"=\")),\n framedLine(pc.bold(pc.cyan(\"EXPLAIN MY ERROR\"))),\n framedLine(pc.dim(\"AI powered debugging for humans\")),\n pc.cyan(line(\"=\")),\n ].join(\"\\n\");\n\n return [\n hero,\n \"\",\n `${pc.bold(pc.cyan(\"ERROR\"))}: ${pc.bold(pc.white(result.title))}`,\n \"\",\n block(\"EXPLANATION\", result.explanation),\n \"\",\n block(\"COMMON CAUSES\", commonCauses),\n \"\",\n `${pc.bold(pc.green(\"FIX\"))}\\n${pc.white(result.fix)}`,\n \"\",\n block(\"CODE EXAMPLE\", result.code_example),\n \"\",\n block(\"ELI5\", result.eli5),\n \"\",\n pc.dim('Tip: run `eme explain \"<error>\"` for quick mode.'),\n ].join(\"\\n\");\n}\n","import pc from \"picocolors\";\n\nexport const logger = {\n info(message: string): void {\n process.stdout.write(`${pc.white(message)}\\n`);\n },\n success(message: string): void {\n process.stdout.write(`${pc.green(`OK: ${message}`)}\\n`);\n },\n warn(message: string): void {\n process.stderr.write(`${pc.yellow(`WARN: ${message}`)}\\n`);\n },\n error(message: string): void {\n process.stderr.write(`${pc.red(`ERROR: ${message}`)}\\n`);\n },\n};\n","import { explainErrorWithAI } from \"./services/ai.js\";\nimport type { ExplainedError } from \"./types/error.js\";\n\nexport async function explainError(errorMessage: string): Promise<ExplainedError> {\n return explainErrorWithAI(errorMessage);\n}\n","import { z } from \"zod\";\nimport { explainErrorWithAI } from \"../services/ai.js\";\nimport type { ExplainedError } from \"../types/error.js\";\n\nconst explainErrorSkillInputSchema = z.object({\n error: z.string().min(1, \"error is required\"),\n});\n\nexport type ExplainErrorSkillInput = z.infer<typeof explainErrorSkillInputSchema>;\n\nexport async function runExplainErrorSkill(input: ExplainErrorSkillInput): Promise<ExplainedError> {\n const parsedInput = explainErrorSkillInputSchema.parse(input);\n return explainErrorWithAI(parsedInput.error);\n}\n"],"mappings":"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","names":["pc","pc","explainError","require","pc","z","z"]}
|