Terminal-based AI coding agent with interactive TUI for autonomous code generation.
Features: - Interactive TUI with React/Ink - Autonomous agent with tool calls (bash, read, write, edit, glob, grep) - Permission system with pattern-based rules - Session management with auto-compaction - Dual providers: GitHub Copilot and Ollama - MCP server integration - Todo panel and theme system - Streaming responses - GitHub-compatible project context
This commit is contained in:
208
src/services/debugging-service.ts
Normal file
208
src/services/debugging-service.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* Debugging Detection Service
|
||||
*
|
||||
* Detects debugging-related requests and provides debugging context.
|
||||
*/
|
||||
|
||||
import {
|
||||
DEBUGGING_SYSTEM_PROMPT,
|
||||
DEBUGGING_CONTEXT_TEMPLATE,
|
||||
} from "@prompts/system/debugging";
|
||||
|
||||
export interface DebugContext {
|
||||
isDebugging: boolean;
|
||||
errorMessage?: string;
|
||||
location?: string;
|
||||
expected?: string;
|
||||
actual?: string;
|
||||
stackTrace?: string;
|
||||
debugType: DebugType;
|
||||
}
|
||||
|
||||
export type DebugType =
|
||||
| "error"
|
||||
| "bug"
|
||||
| "fix"
|
||||
| "issue"
|
||||
| "crash"
|
||||
| "broken"
|
||||
| "notworking"
|
||||
| "none";
|
||||
|
||||
const DEBUG_KEYWORDS: Record<DebugType, string[]> = {
|
||||
error: [
|
||||
"error",
|
||||
"exception",
|
||||
"throw",
|
||||
"thrown",
|
||||
"stack trace",
|
||||
"stacktrace",
|
||||
"traceback",
|
||||
],
|
||||
bug: ["bug", "buggy", "glitch", "defect"],
|
||||
fix: ["fix", "fixing", "repair", "resolve", "solved"],
|
||||
issue: ["issue", "problem", "trouble", "wrong"],
|
||||
crash: ["crash", "crashed", "crashing", "dies", "killed"],
|
||||
broken: ["broken", "break", "breaks", "broke"],
|
||||
notworking: [
|
||||
"not working",
|
||||
"doesn't work",
|
||||
"doesn't work",
|
||||
"won't work",
|
||||
"isn't working",
|
||||
"stopped working",
|
||||
"no longer works",
|
||||
"fails",
|
||||
"failing",
|
||||
"failed",
|
||||
],
|
||||
none: [],
|
||||
};
|
||||
|
||||
const ERROR_PATTERNS = [
|
||||
// JavaScript/TypeScript errors
|
||||
/(?:TypeError|ReferenceError|SyntaxError|RangeError|Error):\s*.+/i,
|
||||
// Stack trace patterns
|
||||
/at\s+\w+\s+\([^)]+:\d+:\d+\)/,
|
||||
/^\s*at\s+.+\s+\(.+\)$/m,
|
||||
// Common error messages
|
||||
/cannot read propert(?:y|ies) of (?:undefined|null)/i,
|
||||
/is not a function/i,
|
||||
/is not defined/i,
|
||||
/unexpected token/i,
|
||||
/failed to/i,
|
||||
/unable to/i,
|
||||
// Exit codes
|
||||
/exit(?:ed)? (?:with )?(?:code|status) \d+/i,
|
||||
// HTTP errors
|
||||
/(?:4|5)\d{2}\s+(?:error|bad|not found|internal|forbidden)/i,
|
||||
];
|
||||
|
||||
const extractErrorMessage = (input: string): string | undefined => {
|
||||
for (const pattern of ERROR_PATTERNS) {
|
||||
const match = input.match(pattern);
|
||||
if (match) {
|
||||
return match[0];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const extractStackTrace = (input: string): string | undefined => {
|
||||
const lines = input.split("\n");
|
||||
const stackLines: string[] = [];
|
||||
let inStack = false;
|
||||
|
||||
for (const line of lines) {
|
||||
if (/^\s*at\s+/.test(line) || /Error:/.test(line)) {
|
||||
inStack = true;
|
||||
stackLines.push(line);
|
||||
} else if (inStack && line.trim() === "") {
|
||||
break;
|
||||
} else if (inStack) {
|
||||
stackLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return stackLines.length > 0 ? stackLines.join("\n") : undefined;
|
||||
};
|
||||
|
||||
const extractLocation = (input: string): string | undefined => {
|
||||
// Match file:line:column patterns
|
||||
const patterns = [
|
||||
/([a-zA-Z0-9_\-./]+\.[a-zA-Z]+):(\d+)(?::(\d+))?/,
|
||||
/(?:in|at|file)\s+['"]?([^'":\s]+)['"]?\s*(?:line\s*)?(\d+)?/i,
|
||||
];
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const match = input.match(pattern);
|
||||
if (match) {
|
||||
const file = match[1];
|
||||
const line = match[2];
|
||||
const col = match[3];
|
||||
return col ? `${file}:${line}:${col}` : line ? `${file}:${line}` : file;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const detectDebugType = (input: string): DebugType => {
|
||||
const lowerInput = input.toLowerCase();
|
||||
|
||||
for (const [type, keywords] of Object.entries(DEBUG_KEYWORDS)) {
|
||||
if (type === "none") continue;
|
||||
for (const keyword of keywords) {
|
||||
if (lowerInput.includes(keyword)) {
|
||||
return type as DebugType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for error patterns even without keywords
|
||||
if (ERROR_PATTERNS.some((pattern) => pattern.test(input))) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
return "none";
|
||||
};
|
||||
|
||||
export const detectDebuggingRequest = (input: string): DebugContext => {
|
||||
const debugType = detectDebugType(input);
|
||||
|
||||
if (debugType === "none") {
|
||||
return {
|
||||
isDebugging: false,
|
||||
debugType: "none",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isDebugging: true,
|
||||
debugType,
|
||||
errorMessage: extractErrorMessage(input),
|
||||
location: extractLocation(input),
|
||||
stackTrace: extractStackTrace(input),
|
||||
};
|
||||
};
|
||||
|
||||
export const buildDebuggingContext = (context: DebugContext): string => {
|
||||
if (!context.isDebugging) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let debugContext = DEBUGGING_CONTEXT_TEMPLATE.replace(
|
||||
"{{errorMessage}}",
|
||||
context.errorMessage || "Not specified",
|
||||
)
|
||||
.replace("{{location}}", context.location || "Not specified")
|
||||
.replace("{{expected}}", context.expected || "Not specified")
|
||||
.replace("{{actual}}", context.actual || "Not specified");
|
||||
|
||||
if (context.stackTrace) {
|
||||
debugContext += `\n**Stack Trace**:\n\`\`\`\n${context.stackTrace}\n\`\`\`\n`;
|
||||
}
|
||||
|
||||
return debugContext;
|
||||
};
|
||||
|
||||
export const getDebuggingPrompt = (): string => {
|
||||
return DEBUGGING_SYSTEM_PROMPT;
|
||||
};
|
||||
|
||||
export const enhancePromptForDebugging = (
|
||||
basePrompt: string,
|
||||
userInput: string,
|
||||
): { prompt: string; context: DebugContext } => {
|
||||
const context = detectDebuggingRequest(userInput);
|
||||
|
||||
if (!context.isDebugging) {
|
||||
return { prompt: basePrompt, context };
|
||||
}
|
||||
|
||||
const debugPrompt = getDebuggingPrompt();
|
||||
const debugContext = buildDebuggingContext(context);
|
||||
|
||||
const enhancedPrompt = `${basePrompt}\n\n${debugPrompt}\n${debugContext}`;
|
||||
|
||||
return { prompt: enhancedPrompt, context };
|
||||
};
|
||||
Reference in New Issue
Block a user