tf-ai 0.1.1 → 0.1.2

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 CHANGED
@@ -1,16 +1,16 @@
1
1
  # tf-ai 🤖
2
2
 
3
- > *The AI-powered successor to `thefuck` explains errors, fixes commands, and troubleshoots your terminal.*
3
+ > *The AI-powered cheap copy of `thefuck`- explains errors, fixes commands, and troubleshoots the terminal.*
4
4
 
5
- **tf-ai** is a smart CLI tool that uses Large Language Models (LLMs) to analyze your terminal commands and their output. It understands your environment (Shell, OS, Project Type) to provide tailored explanations and fixes.
5
+ **tf-ai** is a CLI tool that uses a LLM to analyze your terminal commands and their output.
6
6
 
7
- Run a command, fail, type `fuck`, and let AI handle the rest.
7
+ Run a command, fail, type `fuck`, and let AI give you it's insight.
8
8
 
9
9
  ## ✨ Features
10
10
 
11
11
  - **🧠 Context-Aware Analysis**: Understanding not just *what* failed, but *where* (PowerShell vs Bash, Node.js vs Python project, etc).
12
12
  - **📝 Plain English Explanations**: Deciphers cryptic error codes and log spew into clear, actionable insights.
13
- - **⚡ Real-Time Streaming**: Watch the explanation appear instantly — no waiting for the full response.
13
+ - **⚡ Real-Time Streaming**: It's not 2024 anymore. No waiting for the full response.
14
14
  - **🛠️ Smart Suggestions**: Offers corrected commands that match your specific shell syntax.
15
15
  - **🔌 Provider Agnostic**: Works with Anthropic (Claude), OpenAI (GPT-4), Google (Gemini), or any [Vercel AI SDK](https://sdk.vercel.ai) compatible provider.
16
16
 
@@ -39,7 +39,7 @@ npx tf-ai --help
39
39
  Create `~/.tf-ai/config.json`:
40
40
  ```json
41
41
  {
42
- "model": "claude-3-5-sonnet-latest",
42
+ "model": "gpt-5.2",
43
43
  "confirmBeforeRun": true,
44
44
  "verbose": false
45
45
  }
package/dist/index.js CHANGED
@@ -95,14 +95,15 @@ Given a command and its output, analyze the situation and provide helpful insigh
95
95
  - Or even successful output that the user wants to understand better
96
96
 
97
97
  Your response should:
98
- 1. **Explain** what happened - interpret the output in plain, helpful terms
99
- 2. **Diagnose** the root cause if there's an issue.
98
+ 1. **Explain** what happened
99
+ 2. **Diagnose** the root cause if there's an issue, or at least speculate
100
100
  3. **Suggest a command** (optional) - only if there's a clear action the user can take
101
101
 
102
102
  Guidelines:
103
- - Be concise but thorough (if the problem is complex/deep, you have more leeway)
103
+ - Be concise but thorough (if the problem is complex/deep, you have more leeway and the output can be longer!)
104
104
  - If you suggest a command, explain why / what it will do
105
- - If you're unsure or lacking enough context, say so
105
+ - If you're unsure or lacking enough context, simply say so
106
+ - Apart from deliberate paragraphs, do not needlessly put newlines between sentences.
106
107
  - Tailor suggestions to the user's shell and OS`;
107
108
  function formatUserMessage(command, output, context) {
108
109
  const projectInfo = context.projectType ? `
@@ -386,7 +387,7 @@ function finalizeStreaming() {
386
387
  lastPrintedLength = 0;
387
388
  }
388
389
  function printSuggestion(suggestion) {
389
- console.log(theme.suggestionLabel(`${ICONS.lightbulb} Suggested fix:`));
390
+ console.log(theme.suggestionLabel(`${ICONS.lightbulb} Suggested command:`));
390
391
  console.log();
391
392
  console.log(theme.command(` ${ICONS.command} ${suggestion.command} `));
392
393
  console.log();
@@ -414,17 +415,9 @@ import { promisify as promisify2 } from "util";
414
415
  var execAsync2 = promisify2(exec2);
415
416
  async function confirmCommand(command) {
416
417
  return new Promise((resolve) => {
417
- console.log(theme.muted("Press:"));
418
- console.log(
419
- theme.secondary(" [Enter]") + theme.muted(" Run command")
418
+ process.stdout.write(
419
+ theme.secondary("[Enter]") + theme.muted(" Run ") + theme.secondary("[e]") + theme.muted(" Edit ") + theme.secondary("[Esc/q]") + theme.muted(" Cancel")
420
420
  );
421
- console.log(
422
- theme.secondary(" [e] ") + theme.muted(" Edit command")
423
- );
424
- console.log(
425
- theme.secondary(" [Esc/q]") + theme.muted(" Cancel")
426
- );
427
- console.log();
428
421
  if (process.stdin.isTTY) {
429
422
  process.stdin.setRawMode(true);
430
423
  }
@@ -444,7 +437,7 @@ async function confirmCommand(command) {
444
437
  return;
445
438
  }
446
439
  if (key === "\x1B" || key === "q" || key === "") {
447
- console.log(theme.warning("Cancelled"));
440
+ console.log("\n" + theme.warning("Cancelled"));
448
441
  resolve({ action: "cancel" });
449
442
  return;
450
443
  }
@@ -452,7 +445,7 @@ async function confirmCommand(command) {
452
445
  resolve({ action: "edit" });
453
446
  return;
454
447
  }
455
- console.log(theme.warning("Cancelled"));
448
+ console.log("\n" + theme.warning("Cancelled"));
456
449
  resolve({ action: "cancel" });
457
450
  });
458
451
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/ai/client.ts","../src/ai/prompts.ts","../src/ai/schema.ts","../src/shell/powershell.ts","../src/shell/context.ts","../src/ui/output.ts","../src/ui/theme.ts","../src/ui/confirm.ts","../src/ui/animation.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport { Command } from \"commander\";\r\nimport { loadConfig, validateConfig, CONFIG_FILE } from \"./config.js\";\r\nimport { analyzeCommandStream } from \"./ai/index.js\";\r\nimport { powershell, detectEnvironment } from \"./shell/index.js\";\r\nimport {\r\n printHeader,\r\n printSuggestion,\r\n printError,\r\n printWarning,\r\n printCommand,\r\n printVerbose,\r\n printStreamingExplanation,\r\n finalizeStreaming,\r\n confirmCommand,\r\n editCommand,\r\n runCommand,\r\n createHackingAnimation,\r\n} from \"./ui/index.js\";\r\nimport chalk from \"chalk\";\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name(\"tf-ai\")\r\n .description(\"AI-powered terminal assistant that explains errors and suggests fixes\")\r\n .version(\"1.0.0\");\r\n\r\nprogram\r\n .option(\"-c, --command <command>\", \"The command that failed\")\r\n .option(\"-o, --output <output>\", \"The output/error from the failed command\")\r\n .option(\"-e, --explain\", \"Only explain the error, don't suggest commands\")\r\n .option(\"-m, --model <model>\", \"Model to use (e.g., claude-sonnet-4-20250514, gpt-4o)\")\r\n .option(\"-y, --yes\", \"Auto-run the suggested command without confirmation\")\r\n .option(\"-v, --verbose\", \"Show verbose output\")\r\n .option(\"--setup\", \"Show shell setup instructions\")\r\n .action(async (options: {\r\n command?: string;\r\n output?: string;\r\n explain?: boolean;\r\n model?: string;\r\n yes?: boolean;\r\n verbose?: boolean;\r\n setup?: boolean;\r\n }) => {\r\n // Show setup instructions\r\n if (options.setup) {\r\n console.log(powershell.getSetupInstructions());\r\n return;\r\n }\r\n\r\n // Load and validate config\r\n const configOverrides: Parameters<typeof loadConfig>[0] = {};\r\n if (options.model !== undefined) configOverrides.model = options.model;\r\n if (options.verbose !== undefined) configOverrides.verbose = options.verbose;\r\n if (options.yes !== undefined) configOverrides.confirmBeforeRun = !options.yes;\r\n \r\n const config = loadConfig(configOverrides);\r\n\r\n printVerbose(`Config: ${JSON.stringify(config, null, 2)}`, config.verbose);\r\n\r\n const validation = validateConfig(config);\r\n if (!validation.valid) {\r\n printError(validation.error!);\r\n console.log(`\\nCreate a config file at ${CONFIG_FILE} or set the appropriate environment variable.`);\r\n console.log('\\nExample config.json:');\r\n console.log(JSON.stringify({\r\n model: \"claude-sonnet-4-20250514\",\r\n apiKey: \"your-api-key-here\",\r\n }, null, 2));\r\n process.exit(1);\r\n }\r\n\r\n // Get command to analyze\r\n let command = options.command;\r\n let output = options.output ?? \"\";\r\n\r\n if (!command) {\r\n printVerbose(\"No command provided, checking shell history...\", config.verbose);\r\n const lastCmd = await powershell.getLastCommand();\r\n \r\n if (lastCmd) {\r\n command = lastCmd.command;\r\n output = lastCmd.output;\r\n printCommand(\"Last command\", command);\r\n } else {\r\n printWarning(\"No command provided and couldn't get last command from history.\");\r\n console.log(\"\\nUsage:\");\r\n console.log(\" tf-ai --command 'git pussh' --output 'error message'\");\r\n console.log(\"\\nOr set up the shell integration:\");\r\n console.log(\" tf-ai --setup\");\r\n process.exit(1);\r\n }\r\n } \r\n // Removed \"Analyzing: command\" print\r\n\r\n if (output && config.verbose) {\r\n console.log(\"\\nOutput:\");\r\n console.log(output);\r\n }\r\n\r\n console.log(); // Spacing\r\n const animation = createHackingAnimation(\"Analyzing what happened...\");\r\n animation.start();\r\n \r\n // Detect environment context\r\n const envContext = detectEnvironment();\r\n if (config.verbose) {\r\n printVerbose(`Environment: ${JSON.stringify(envContext, null, 2)}`, true);\r\n }\r\n \r\n try {\r\n let isFirstChunk = true;\r\n const result = await analyzeCommandStream(command, output, config, envContext, {\r\n onExplanationUpdate: (text) => {\r\n if (isFirstChunk) {\r\n animation.stop();\r\n isFirstChunk = false;\r\n }\r\n // Stream using the polished UI function\r\n printStreamingExplanation(text);\r\n },\r\n });\r\n \r\n if (isFirstChunk) {\r\n animation.stop();\r\n }\r\n \r\n finalizeStreaming();\r\n console.log();\r\n\r\n // Handle suggestion\r\n if (result.suggestion && !options.explain) {\r\n printSuggestion(result.suggestion);\r\n\r\n // Ask for confirmation\r\n if (config.confirmBeforeRun) {\r\n const confirmation = await confirmCommand(result.suggestion.command);\r\n\r\n if (confirmation.action === \"run\") {\r\n await runCommand(result.suggestion.command);\r\n } else if (confirmation.action === \"edit\") {\r\n const edited = await editCommand(result.suggestion.command);\r\n if (edited) {\r\n await runCommand(edited);\r\n }\r\n }\r\n } else {\r\n // Auto-run (-y flag)\r\n await runCommand(result.suggestion.command);\r\n }\r\n }\r\n } catch (error) {\r\n animation.stop(); // Stop animation on error\r\n finalizeStreaming(); // Reset streaming state\r\n \r\n const err = error as Error;\r\n printError(`Failed to analyze command: ${err.message}`);\r\n \r\n if (config.verbose && err.stack) {\r\n console.log(err.stack);\r\n }\r\n \r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram.parse();\r\n","import { existsSync, readFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\n\r\nexport interface Config {\r\n /** Model identifier, e.g. \"anthropic/claude-sonnet-4-20250514\" or \"openai/gpt-4o\" */\r\n model: string;\r\n /** Provider to use: anthropic, openai, or google */\r\n provider: \"anthropic\" | \"openai\" | \"google\";\r\n /** API key for the selected provider */\r\n apiKey: string;\r\n /** Whether to ask for confirmation before running suggested commands */\r\n confirmBeforeRun: boolean;\r\n /** Show verbose/debug output */\r\n verbose: boolean;\r\n}\r\n\r\ninterface ConfigFile {\r\n model?: string;\r\n provider?: \"anthropic\" | \"openai\" | \"google\";\r\n apiKey?: string;\r\n confirmBeforeRun?: boolean;\r\n verbose?: boolean;\r\n}\r\n\r\nconst CONFIG_DIR = join(homedir(), \".tf-ai\");\r\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\r\n\r\nfunction loadConfigFile(): ConfigFile {\r\n if (!existsSync(CONFIG_FILE)) {\r\n return {};\r\n }\r\n \r\n try {\r\n const content = readFileSync(CONFIG_FILE, \"utf-8\");\r\n return JSON.parse(content) as ConfigFile;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nfunction detectProvider(model: string): \"anthropic\" | \"openai\" | \"google\" {\r\n if (model.startsWith(\"anthropic/\") || model.includes(\"claude\")) {\r\n return \"anthropic\";\r\n }\r\n if (model.startsWith(\"openai/\") || model.includes(\"gpt\")) {\r\n return \"openai\";\r\n }\r\n if (model.startsWith(\"google/\") || model.includes(\"gemini\")) {\r\n return \"google\";\r\n }\r\n // Default to anthropic\r\n return \"anthropic\";\r\n}\r\n\r\nfunction getApiKey(provider: \"anthropic\" | \"openai\" | \"google\", configKey?: string): string {\r\n // Config file key takes precedence\r\n if (configKey) {\r\n return configKey;\r\n }\r\n \r\n // Then check environment variables\r\n const envVars = {\r\n anthropic: \"ANTHROPIC_API_KEY\",\r\n openai: \"OPENAI_API_KEY\",\r\n google: \"GOOGLE_API_KEY\",\r\n } as const;\r\n \r\n const envVarName = envVars[provider];\r\n const envKey = process.env[envVarName];\r\n if (envKey) {\r\n return envKey;\r\n }\r\n \r\n // Also check generic key\r\n return process.env[\"TF_AI_API_KEY\"] ?? \"\";\r\n}\r\n\r\nexport function loadConfig(overrides?: Partial<Config>): Config {\r\n const file = loadConfigFile();\r\n \r\n // Determine model (priority: override > env > file > default)\r\n const model =\r\n overrides?.model ??\r\n process.env[\"TF_AI_MODEL\"] ??\r\n file.model ??\r\n \"claude-sonnet-4-5-20250929\";\r\n \r\n // Detect provider from model string\r\n const provider = \r\n overrides?.provider ?? \r\n file.provider ?? \r\n detectProvider(model);\r\n \r\n // Get API key\r\n const apiKey = getApiKey(provider, file.apiKey);\r\n \r\n return {\r\n model,\r\n provider,\r\n apiKey,\r\n confirmBeforeRun: overrides?.confirmBeforeRun ?? file.confirmBeforeRun ?? true,\r\n verbose: overrides?.verbose ?? file.verbose ?? false,\r\n };\r\n}\r\n\r\nexport function validateConfig(config: Config): { valid: boolean; error?: string } {\r\n if (!config.apiKey) {\r\n const envVar = {\r\n anthropic: \"ANTHROPIC_API_KEY\",\r\n openai: \"OPENAI_API_KEY\",\r\n google: \"GOOGLE_API_KEY\",\r\n }[config.provider];\r\n \r\n return {\r\n valid: false,\r\n error: `No API key found. Set ${envVar} environment variable or add \"apiKey\" to ${CONFIG_FILE}`,\r\n };\r\n }\r\n \r\n return { valid: true };\r\n}\r\n\r\nexport { CONFIG_DIR, CONFIG_FILE };\r\n","import { streamText, Output } from \"ai\";\r\nimport { anthropic } from \"@ai-sdk/anthropic\";\r\nimport { openai } from \"@ai-sdk/openai\";\r\nimport { google } from \"@ai-sdk/google\";\r\nimport type { Config } from \"../config.js\";\r\nimport { SYSTEM_PROMPT, formatUserMessage } from \"./prompts.js\";\r\nimport { analysisResponseSchema, type AnalysisResponse } from \"./schema.js\";\r\n\r\nexport interface CommandSuggestion {\r\n command: string;\r\n explanation: string;\r\n}\r\n\r\nexport interface AnalysisResult {\r\n explanation: string;\r\n suggestion: CommandSuggestion | undefined;\r\n}\r\n\r\nfunction getModel(config: Config) {\r\n const modelName = config.model.includes(\"/\") \r\n ? config.model.split(\"/\")[1]! \r\n : config.model;\r\n \r\n switch (config.provider) {\r\n case \"anthropic\":\r\n return anthropic(modelName);\r\n case \"openai\":\r\n return openai(modelName);\r\n case \"google\":\r\n return google(modelName);\r\n default:\r\n return anthropic(modelName);\r\n }\r\n}\r\n\r\nimport type { EnvironmentContext } from \"../shell/context.js\";\r\n\r\nexport interface StreamCallbacks {\r\n onExplanationUpdate?: (text: string) => void;\r\n onComplete?: (result: AnalysisResult) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Analyzes a command using streaming structured output.\r\n * Calls onExplanationUpdate as the explanation streams in.\r\n */\r\nexport async function analyzeCommandStream(\r\n command: string,\r\n output: string,\r\n config: Config,\r\n environment: EnvironmentContext,\r\n callbacks: StreamCallbacks = {}\r\n): Promise<AnalysisResult> {\r\n const model = getModel(config);\r\n \r\n const { partialOutputStream } = streamText({\r\n model,\r\n system: SYSTEM_PROMPT,\r\n prompt: formatUserMessage(command, output, environment),\r\n output: Output.object({ schema: analysisResponseSchema }),\r\n });\r\n\r\n let lastExplanation = \"\";\r\n let finalResponse: Partial<AnalysisResponse> = {};\r\n\r\n try {\r\n for await (const partial of partialOutputStream) {\r\n finalResponse = partial;\r\n \r\n // Stream explanation updates\r\n if (partial.explanation && partial.explanation !== lastExplanation) {\r\n lastExplanation = partial.explanation;\r\n callbacks.onExplanationUpdate?.(partial.explanation);\r\n }\r\n }\r\n } catch (error) {\r\n callbacks.onError?.(error as Error);\r\n throw error;\r\n }\r\n\r\n // Build final result\r\n const result: AnalysisResult = {\r\n explanation: finalResponse.explanation ?? \"\",\r\n suggestion: finalResponse.suggestedCommand \r\n ? {\r\n command: finalResponse.suggestedCommand,\r\n explanation: \"\", // Explanation is in the main field\r\n }\r\n : undefined,\r\n };\r\n\r\n callbacks.onComplete?.(result);\r\n return result;\r\n}\r\n\r\n/**\r\n * Non-streaming version for simpler use cases.\r\n */\r\nexport async function analyzeCommand(\r\n command: string,\r\n output: string,\r\n config: Config,\r\n environment: EnvironmentContext\r\n): Promise<AnalysisResult> {\r\n return analyzeCommandStream(command, output, config, environment);\r\n}\r\n","import type { EnvironmentContext } from \"../shell/context.js\";\r\n\r\nexport const SYSTEM_PROMPT = `You are an expert terminal assistant that helps developers understand command output and troubleshoot issues.\r\n\r\nGiven a command and its output, analyze the situation and provide helpful insight. The output could be:\r\n- An error message (syntax error, permission denied, command not found, etc.)\r\n- A warning or unexpected behavior\r\n- A build failure, test failure, or deployment issue\r\n- API/network errors\r\n- Confusing or unclear output that needs explanation\r\n- Or even successful output that the user wants to understand better\r\n\r\nYour response should:\r\n1. **Explain** what happened - interpret the output in plain, helpful terms\r\n2. **Diagnose** the root cause if there's an issue.\r\n3. **Suggest a command** (optional) - only if there's a clear action the user can take\r\n\r\nGuidelines:\r\n- Be concise but thorough (if the problem is complex/deep, you have more leeway)\r\n- If you suggest a command, explain why / what it will do\r\n- If you're unsure or lacking enough context, say so\r\n- Tailor suggestions to the user's shell and OS`;\r\n\r\nexport function formatUserMessage(\r\n command: string, \r\n output: string,\r\n context: EnvironmentContext\r\n): string {\r\n const projectInfo = context.projectType ? `\\n- Project Type: ${context.projectType}` : '';\r\n \r\n return `Command: ${command}\r\n\r\nOutput:\r\n${output || \"(no output)\"}\r\n\r\nEnvironment:\r\n- Shell: ${context.shell}\r\n- OS: ${context.os}\r\n- Working Directory: ${context.cwd}${projectInfo}\r\n\r\nAnalyze this command and its output. Explain what happened and suggest a follow-up action if appropriate.`;\r\n}\r\n","import { z } from \"zod\";\r\n\r\n// Response schema for the AI analysis\r\nexport const analysisResponseSchema = z.object({\r\n explanation: z\r\n .string()\r\n .describe(\r\n \"Clear, helpful explanation of what happened. Interpret the output, diagnose issues, and provide context.\",\r\n ),\r\n suggestedCommand: z\r\n .string()\r\n .nullable()\r\n .describe(\r\n \"A follow-up command the user could run, if applicable. Could be a fix, a next step, or a diagnostic command. Pass null if no command is suggested\",\r\n ),\r\n});\r\n\r\nexport type AnalysisResponse = z.infer<typeof analysisResponseSchema>;\r\n","import { exec } from \"node:child_process\";\r\nimport { promisify } from \"node:util\";\r\nimport type { ShellAdapter, CommandContext } from \"./types.js\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nexport class PowerShellAdapter implements ShellAdapter {\r\n async getLastCommand(): Promise<CommandContext | null> {\r\n // This is called when the user runs tf-ai without explicit --command\r\n // We try to get the last command from PowerShell history\r\n try {\r\n const { stdout } = await execAsync(\r\n 'powershell -Command \"(Get-History -Count 1).CommandLine\"',\r\n { encoding: \"utf-8\" }\r\n );\r\n \r\n const command = stdout.trim();\r\n if (!command) {\r\n return null;\r\n }\r\n \r\n // We can't reliably get the output of the previous command after the fact\r\n // The user should use the shell function which captures output in real-time\r\n return {\r\n command,\r\n output: \"(Output not captured - use the 'fuck' shell function for full functionality)\",\r\n };\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async executeCommand(command: string): Promise<{ output: string; exitCode: number }> {\r\n try {\r\n const { stdout, stderr } = await execAsync(\r\n `powershell -Command \"${command.replace(/\"/g, '\\\\\"')}\"`,\r\n { encoding: \"utf-8\" }\r\n );\r\n return {\r\n output: stdout + stderr,\r\n exitCode: 0,\r\n };\r\n } catch (error) {\r\n const execError = error as { stdout?: string; stderr?: string; code?: number };\r\n return {\r\n output: (execError.stdout ?? \"\") + (execError.stderr ?? \"\"),\r\n exitCode: execError.code ?? 1,\r\n };\r\n }\r\n }\r\n\r\n getSetupInstructions(): string {\r\n return `\r\nAdd this to your PowerShell profile ($PROFILE):\r\n\r\nfunction fuck {\r\n $lastCmd = (Get-History -Count 1).CommandLine\r\n if (-not $lastCmd) {\r\n Write-Host \"No command in history\" -ForegroundColor Red\r\n return\r\n }\r\n \r\n # Re-execute to capture output\r\n $output = try { \r\n Invoke-Expression $lastCmd 2>&1 | Out-String \r\n } catch { \r\n $_.Exception.Message \r\n }\r\n \r\n # Call tf-ai with captured command and output\r\n tf-ai --command $lastCmd --output $output\r\n}\r\n\r\nThen reload your profile:\r\n. $PROFILE\r\n`.trim();\r\n }\r\n}\r\n\r\nexport const powershell = new PowerShellAdapter();\r\n","import { existsSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { platform } from \"node:os\";\r\n\r\nexport interface EnvironmentContext {\r\n shell: \"powershell\" | \"bash\" | \"zsh\" | \"cmd\" | \"fish\" | \"unknown\";\r\n os: \"windows\" | \"macos\" | \"linux\";\r\n cwd: string;\r\n projectType?: \"git\" | \"nodejs\" | \"python\" | \"docker\";\r\n}\r\n\r\nfunction detectShell(): EnvironmentContext[\"shell\"] {\r\n // Check for PowerShell-specific env var\r\n if (process.env[\"PSModulePath\"]) {\r\n return \"powershell\";\r\n }\r\n \r\n // Check SHELL env var (Unix-like systems)\r\n const shell = process.env[\"SHELL\"];\r\n if (shell) {\r\n if (shell.includes(\"bash\")) return \"bash\";\r\n if (shell.includes(\"zsh\")) return \"zsh\";\r\n if (shell.includes(\"fish\")) return \"fish\";\r\n }\r\n \r\n // Check for CMD on Windows\r\n if (process.env[\"ComSpec\"]?.includes(\"cmd.exe\")) {\r\n return \"cmd\";\r\n }\r\n \r\n return \"unknown\";\r\n}\r\n\r\nfunction detectOS(): EnvironmentContext[\"os\"] {\r\n const os = platform();\r\n \r\n switch (os) {\r\n case \"win32\":\r\n return \"windows\";\r\n case \"darwin\":\r\n return \"macos\";\r\n case \"linux\":\r\n return \"linux\";\r\n default:\r\n // Fallback to linux for other Unix-like systems\r\n return \"linux\";\r\n }\r\n}\r\n\r\nfunction detectProjectType(cwd: string): EnvironmentContext[\"projectType\"] {\r\n // Check in order of specificity\r\n if (existsSync(join(cwd, \".git\"))) {\r\n return \"git\";\r\n }\r\n \r\n if (existsSync(join(cwd, \"package.json\"))) {\r\n return \"nodejs\";\r\n }\r\n \r\n if (existsSync(join(cwd, \"requirements.txt\")) || existsSync(join(cwd, \"pyproject.toml\"))) {\r\n return \"python\";\r\n }\r\n \r\n if (existsSync(join(cwd, \"Dockerfile\"))) {\r\n return \"docker\";\r\n }\r\n \r\n return undefined;\r\n}\r\n\r\nexport function detectEnvironment(): EnvironmentContext {\r\n const cwd = process.cwd();\r\n const projectType = detectProjectType(cwd);\r\n \r\n return {\r\n shell: detectShell(),\r\n os: detectOS(),\r\n cwd,\r\n ...(projectType ? { projectType } : {}),\r\n };\r\n}\r\n","import chalk from \"chalk\";\r\nimport type { CommandSuggestion, AnalysisResult } from \"../ai/index.js\";\r\nimport { theme } from \"./theme.js\";\r\n\r\nconst ICONS = {\r\n robot: \"🤖\",\r\n lightbulb: \"💡\",\r\n command: \"➜\",\r\n warning: \"⚠️\",\r\n error: \"❌\",\r\n success: \"✓\",\r\n thinking: \"🧠\",\r\n};\r\n\r\nexport function printHeader(): void {\r\n // Clean header using theme\r\n console.log(theme.header(`\\n${ICONS.robot} tf-ai\\n`));\r\n}\r\n\r\nexport function printExplanation(result: AnalysisResult): void {\r\n if (result.explanation) {\r\n console.log(theme.explanation(result.explanation));\r\n console.log();\r\n }\r\n}\r\n\r\nlet lastPrintedLength = 0;\r\n\r\n/**\r\n * For streaming: prints only the new part of the explanation\r\n */\r\nexport function printStreamingExplanation(fullText: string): void {\r\n if (!fullText) return;\r\n \r\n // Calculate the new chunk to print\r\n const newText = fullText.slice(lastPrintedLength);\r\n \r\n if (newText) {\r\n // Use theme explanation color\r\n process.stdout.write(theme.explanation(newText));\r\n lastPrintedLength = fullText.length;\r\n }\r\n}\r\n\r\n/**\r\n * Finalize streaming output with newline and reset state\r\n */\r\nexport function finalizeStreaming(): void {\r\n console.log(); // New line after streaming completes\r\n lastPrintedLength = 0; // Reset for next run\r\n}\r\n\r\nexport function printSuggestion(suggestion: CommandSuggestion): void {\r\n console.log(theme.suggestionLabel(`${ICONS.lightbulb} Suggested fix:`));\r\n console.log();\r\n // Using theme.command color\r\n console.log(theme.command(` ${ICONS.command} ${suggestion.command} `));\r\n console.log();\r\n}\r\n\r\nexport function printError(message: string): void {\r\n console.error(theme.error(`${ICONS.error} ${message}`));\r\n}\r\n\r\nexport function printWarning(message: string): void {\r\n console.log(theme.warning(`${ICONS.warning} ${message}`));\r\n}\r\n\r\nexport function printSuccess(message: string): void {\r\n console.log(theme.success(`${ICONS.success} ${message}`));\r\n}\r\n\r\nexport function printCommand(label: string, command: string): void {\r\n console.log(theme.muted(`${label}: `) + theme.text(command));\r\n}\r\n\r\nexport function printVerbose(message: string, verbose: boolean): void {\r\n if (verbose) {\r\n console.log(theme.muted(`[debug] ${message}`));\r\n }\r\n}\r\n","import chalk from \"chalk\";\r\n\r\n/**\r\n * Anthropic-Inspired Palette\r\n * Sophisticated, warm, and professional.\r\n */\r\nexport const COLORS = {\r\n stone: \"#F5F2E8\", // Warmest White / Base\r\n warmGray: \"#9E9A95\", // Muted text / Labels\r\n text: \"#E3DCD2\", // Main reading text (Warm Off-White)\r\n coral: \"#D97757\", // Primary Accent (Anthropic-like orange/coral) - Highlights\r\n maple: \"#C8A682\", // Secondary Accent - Interactions\r\n olive: \"#8E9C6D\", // Success\r\n sienna: \"#C1554D\", // Error\r\n charcoal: \"#2D2B29\", // Dark background text if needed\r\n};\r\n\r\n/**\r\n * Semantic Theme Definitions\r\n */\r\nexport const theme = {\r\n // --- Global Roles ---\r\n primary: chalk.hex(COLORS.coral),\r\n secondary: chalk.hex(COLORS.maple),\r\n success: chalk.hex(COLORS.olive),\r\n error: chalk.hex(COLORS.sienna),\r\n warning: chalk.hex(COLORS.maple), // Maple works well for warning too\r\n muted: chalk.hex(COLORS.warmGray),\r\n text: chalk.hex(COLORS.text),\r\n \r\n // --- Component Specifics ---\r\n \r\n // Header / Branding\r\n header: chalk.hex(COLORS.coral).bold,\r\n \r\n // The suggested command to run\r\n command: chalk.hex(COLORS.stone).bold, // Bright, distinct\r\n \r\n // The AI's explanation text\r\n explanation: chalk.hex(COLORS.text),\r\n \r\n // \"Suggested fix:\" label - subtle yet clear\r\n suggestionLabel: chalk.hex(COLORS.maple).bold,\r\n \r\n // Confidence levels\r\n confidenceHigh: chalk.hex(COLORS.olive),\r\n confidenceMedium: chalk.hex(COLORS.maple),\r\n confidenceLow: chalk.hex(COLORS.sienna),\r\n \r\n // --- Animation Colors ---\r\n // Glitch characters\r\n glitch1: chalk.hex(COLORS.coral),\r\n glitch2: chalk.hex(COLORS.maple),\r\n // Base text for \"Analyzing...\"\r\n glitchBase: chalk.hex(COLORS.warmGray),\r\n};\r\n","import * as readline from \"node:readline\";\r\nimport chalk from \"chalk\";\r\nimport { exec } from \"node:child_process\";\r\nimport { promisify } from \"node:util\";\r\nimport { theme } from \"./theme.js\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nexport interface ConfirmResult {\r\n action: \"run\" | \"cancel\" | \"edit\";\r\n editedCommand?: string;\r\n}\r\n\r\nexport async function confirmCommand(command: string): Promise<ConfirmResult> {\r\n return new Promise((resolve) => {\r\n // \"Press:\" is now muted (Warm Gray), not Red/Pink\r\n console.log(theme.muted(\"Press:\"));\r\n \r\n // Keys highlighted in Secondary (Maple) / Accent (Coral)\r\n // Using formatted strings to mix colors\r\n console.log(\r\n theme.secondary(\" [Enter]\") + theme.muted(\" Run command\")\r\n );\r\n console.log(\r\n theme.secondary(\" [e] \") + theme.muted(\" Edit command\")\r\n );\r\n console.log(\r\n theme.secondary(\" [Esc/q]\") + theme.muted(\" Cancel\")\r\n );\r\n console.log();\r\n\r\n // Set up raw mode to capture single keypresses\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n }\r\n process.stdin.resume();\r\n process.stdin.setEncoding(\"utf8\");\r\n\r\n const cleanup = () => {\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n }\r\n process.stdin.pause();\r\n process.stdin.removeAllListeners(\"data\");\r\n };\r\n\r\n process.stdin.once(\"data\", (key: string) => {\r\n cleanup();\r\n\r\n // Enter key\r\n if (key === \"\\r\" || key === \"\\n\") {\r\n resolve({ action: \"run\" });\r\n return;\r\n }\r\n\r\n // Escape or q\r\n if (key === \"\\u001b\" || key === \"q\" || key === \"\\u0003\") {\r\n console.log(theme.warning(\"Cancelled\"));\r\n resolve({ action: \"cancel\" });\r\n return;\r\n }\r\n\r\n // Edit\r\n if (key === \"e\" || key === \"E\") {\r\n resolve({ action: \"edit\" });\r\n return;\r\n }\r\n\r\n // Unknown key - treat as cancel\r\n console.log(theme.warning(\"Cancelled\"));\r\n resolve({ action: \"cancel\" });\r\n });\r\n });\r\n}\r\n\r\nexport async function editCommand(originalCommand: string): Promise<string | null> {\r\n return new Promise((resolve) => {\r\n const rl = readline.createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n\r\n console.log(theme.secondary(\"\\nEdit command (press Enter to confirm, Ctrl+C to cancel):\"));\r\n \r\n rl.question(theme.muted(\"> \"), (answer) => {\r\n rl.close();\r\n const command = answer.trim();\r\n resolve(command || originalCommand);\r\n });\r\n\r\n rl.on(\"close\", () => {\r\n if (!rl.terminal) {\r\n resolve(null);\r\n }\r\n });\r\n });\r\n}\r\n\r\nexport async function runCommand(command: string): Promise<void> {\r\n console.log(theme.secondary(`\\nRunning: ${command}\\n`));\r\n console.log(theme.muted(\"─\".repeat(40)));\r\n \r\n try {\r\n // Run the command and stream output\r\n const { stdout, stderr } = await execAsync(\r\n `powershell -Command \"${command.replace(/\"/g, '\\\\\"')}\"`,\r\n { encoding: \"utf-8\" }\r\n );\r\n \r\n if (stdout) console.log(stdout);\r\n if (stderr) console.error(theme.error(stderr));\r\n \r\n console.log(theme.muted(\"─\".repeat(40)));\r\n console.log(theme.success(\"✓ Command completed\"));\r\n } catch (error) {\r\n const execError = error as { stdout?: string; stderr?: string; code?: number };\r\n if (execError.stdout) console.log(execError.stdout);\r\n if (execError.stderr) console.error(theme.error(execError.stderr));\r\n \r\n console.log(theme.muted(\"─\".repeat(40)));\r\n console.log(theme.error(`✗ Command failed with exit code ${execError.code ?? 1}`));\r\n }\r\n}\r\n","import { theme } from \"./theme.js\";\n\n/**\n * Creates a \"hacking\" style animated text where random characters glitch\n * Refined for subtlety and elegance\n */\nexport function createHackingAnimation(text: string): {\n start: () => void;\n stop: () => void;\n} {\n const glitchChars = ['#', '$', '%', '*', '?', '~', '^', '+', '=', ':'];\n let interval: NodeJS.Timeout | null = null;\n let isRunning = false;\n \n const originalText = text;\n const textArray = text.split('');\n \n function glitchText(): string {\n return textArray.map((char, i) => {\n // Skip spaces\n if (char === ' ') return ' ';\n \n // Random chance to glitch (much lower probability for subtlety: 5%)\n if (Math.random() < 0.05) {\n // Use theme colors for glitches\n return Math.random() > 0.5 \n ? theme.glitch1(glitchChars[Math.floor(Math.random() * glitchChars.length)]!)\n : theme.glitch2(glitchChars[Math.floor(Math.random() * glitchChars.length)]!);\n }\n \n // Base text color\n return theme.glitchBase(char);\n }).join('');\n }\n \n function render() {\n if (!isRunning) return;\n \n // Clear line and print glitched text\n process.stdout.write('\\r' + glitchText());\n }\n \n return {\n start() {\n if (isRunning) return;\n isRunning = true;\n \n // Print initial state\n process.stdout.write(theme.glitchBase(originalText));\n \n // Start glitching at slower intervals (120ms) for elegance\n interval = setInterval(render, 120);\n },\n \n stop() {\n if (!isRunning) return;\n isRunning = false;\n \n if (interval) {\n clearInterval(interval);\n interval = null;\n }\n \n // Clear the line\n process.stdout.write('\\r' + ' '.repeat(originalText.length) + '\\r');\n },\n };\n}\n"],"mappings":"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","names":["existsSync","join","exec","promisify","execAsync","promisify","exec"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/ai/client.ts","../src/ai/prompts.ts","../src/ai/schema.ts","../src/shell/powershell.ts","../src/shell/context.ts","../src/ui/output.ts","../src/ui/theme.ts","../src/ui/confirm.ts","../src/ui/animation.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport { Command } from \"commander\";\r\nimport { loadConfig, validateConfig, CONFIG_FILE } from \"./config.js\";\r\nimport { analyzeCommandStream } from \"./ai/index.js\";\r\nimport { powershell, detectEnvironment } from \"./shell/index.js\";\r\nimport {\r\n printHeader,\r\n printSuggestion,\r\n printError,\r\n printWarning,\r\n printCommand,\r\n printVerbose,\r\n printStreamingExplanation,\r\n finalizeStreaming,\r\n confirmCommand,\r\n editCommand,\r\n runCommand,\r\n createHackingAnimation,\r\n} from \"./ui/index.js\";\r\nimport chalk from \"chalk\";\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name(\"tf-ai\")\r\n .description(\"AI-powered terminal assistant that explains errors and suggests fixes\")\r\n .version(\"1.0.0\");\r\n\r\nprogram\r\n .option(\"-c, --command <command>\", \"The command that failed\")\r\n .option(\"-o, --output <output>\", \"The output/error from the failed command\")\r\n .option(\"-e, --explain\", \"Only explain the error, don't suggest commands\")\r\n .option(\"-m, --model <model>\", \"Model to use (e.g., claude-sonnet-4-20250514, gpt-4o)\")\r\n .option(\"-y, --yes\", \"Auto-run the suggested command without confirmation\")\r\n .option(\"-v, --verbose\", \"Show verbose output\")\r\n .option(\"--setup\", \"Show shell setup instructions\")\r\n .action(async (options: {\r\n command?: string;\r\n output?: string;\r\n explain?: boolean;\r\n model?: string;\r\n yes?: boolean;\r\n verbose?: boolean;\r\n setup?: boolean;\r\n }) => {\r\n // Show setup instructions\r\n if (options.setup) {\r\n console.log(powershell.getSetupInstructions());\r\n return;\r\n }\r\n\r\n // Load and validate config\r\n const configOverrides: Parameters<typeof loadConfig>[0] = {};\r\n if (options.model !== undefined) configOverrides.model = options.model;\r\n if (options.verbose !== undefined) configOverrides.verbose = options.verbose;\r\n if (options.yes !== undefined) configOverrides.confirmBeforeRun = !options.yes;\r\n \r\n const config = loadConfig(configOverrides);\r\n\r\n printVerbose(`Config: ${JSON.stringify(config, null, 2)}`, config.verbose);\r\n\r\n const validation = validateConfig(config);\r\n if (!validation.valid) {\r\n printError(validation.error!);\r\n console.log(`\\nCreate a config file at ${CONFIG_FILE} or set the appropriate environment variable.`);\r\n console.log('\\nExample config.json:');\r\n console.log(JSON.stringify({\r\n model: \"claude-sonnet-4-20250514\",\r\n apiKey: \"your-api-key-here\",\r\n }, null, 2));\r\n process.exit(1);\r\n }\r\n\r\n // Get command to analyze\r\n let command = options.command;\r\n let output = options.output ?? \"\";\r\n\r\n if (!command) {\r\n printVerbose(\"No command provided, checking shell history...\", config.verbose);\r\n const lastCmd = await powershell.getLastCommand();\r\n \r\n if (lastCmd) {\r\n command = lastCmd.command;\r\n output = lastCmd.output;\r\n printCommand(\"Last command\", command);\r\n } else {\r\n printWarning(\"No command provided and couldn't get last command from history.\");\r\n console.log(\"\\nUsage:\");\r\n console.log(\" tf-ai --command 'git pussh' --output 'error message'\");\r\n console.log(\"\\nOr set up the shell integration:\");\r\n console.log(\" tf-ai --setup\");\r\n process.exit(1);\r\n }\r\n } \r\n // Removed \"Analyzing: command\" print\r\n\r\n if (output && config.verbose) {\r\n console.log(\"\\nOutput:\");\r\n console.log(output);\r\n }\r\n\r\n console.log(); // Spacing\r\n const animation = createHackingAnimation(\"Analyzing what happened...\");\r\n animation.start();\r\n \r\n // Detect environment context\r\n const envContext = detectEnvironment();\r\n if (config.verbose) {\r\n printVerbose(`Environment: ${JSON.stringify(envContext, null, 2)}`, true);\r\n }\r\n \r\n try {\r\n let isFirstChunk = true;\r\n const result = await analyzeCommandStream(command, output, config, envContext, {\r\n onExplanationUpdate: (text) => {\r\n if (isFirstChunk) {\r\n animation.stop();\r\n isFirstChunk = false;\r\n }\r\n // Stream using the polished UI function\r\n printStreamingExplanation(text);\r\n },\r\n });\r\n \r\n if (isFirstChunk) {\r\n animation.stop();\r\n }\r\n \r\n finalizeStreaming();\r\n console.log();\r\n\r\n // Handle suggestion\r\n if (result.suggestion && !options.explain) {\r\n printSuggestion(result.suggestion);\r\n\r\n // Ask for confirmation\r\n if (config.confirmBeforeRun) {\r\n const confirmation = await confirmCommand(result.suggestion.command);\r\n\r\n if (confirmation.action === \"run\") {\r\n await runCommand(result.suggestion.command);\r\n } else if (confirmation.action === \"edit\") {\r\n const edited = await editCommand(result.suggestion.command);\r\n if (edited) {\r\n await runCommand(edited);\r\n }\r\n }\r\n } else {\r\n // Auto-run (-y flag)\r\n await runCommand(result.suggestion.command);\r\n }\r\n }\r\n } catch (error) {\r\n animation.stop(); // Stop animation on error\r\n finalizeStreaming(); // Reset streaming state\r\n \r\n const err = error as Error;\r\n printError(`Failed to analyze command: ${err.message}`);\r\n \r\n if (config.verbose && err.stack) {\r\n console.log(err.stack);\r\n }\r\n \r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram.parse();\r\n","import { existsSync, readFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\n\r\nexport interface Config {\r\n /** Model identifier, e.g. \"anthropic/claude-sonnet-4-20250514\" or \"openai/gpt-4o\" */\r\n model: string;\r\n /** Provider to use: anthropic, openai, or google */\r\n provider: \"anthropic\" | \"openai\" | \"google\";\r\n /** API key for the selected provider */\r\n apiKey: string;\r\n /** Whether to ask for confirmation before running suggested commands */\r\n confirmBeforeRun: boolean;\r\n /** Show verbose/debug output */\r\n verbose: boolean;\r\n}\r\n\r\ninterface ConfigFile {\r\n model?: string;\r\n provider?: \"anthropic\" | \"openai\" | \"google\";\r\n apiKey?: string;\r\n confirmBeforeRun?: boolean;\r\n verbose?: boolean;\r\n}\r\n\r\nconst CONFIG_DIR = join(homedir(), \".tf-ai\");\r\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\r\n\r\nfunction loadConfigFile(): ConfigFile {\r\n if (!existsSync(CONFIG_FILE)) {\r\n return {};\r\n }\r\n \r\n try {\r\n const content = readFileSync(CONFIG_FILE, \"utf-8\");\r\n return JSON.parse(content) as ConfigFile;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nfunction detectProvider(model: string): \"anthropic\" | \"openai\" | \"google\" {\r\n if (model.startsWith(\"anthropic/\") || model.includes(\"claude\")) {\r\n return \"anthropic\";\r\n }\r\n if (model.startsWith(\"openai/\") || model.includes(\"gpt\")) {\r\n return \"openai\";\r\n }\r\n if (model.startsWith(\"google/\") || model.includes(\"gemini\")) {\r\n return \"google\";\r\n }\r\n // Default to anthropic\r\n return \"anthropic\";\r\n}\r\n\r\nfunction getApiKey(provider: \"anthropic\" | \"openai\" | \"google\", configKey?: string): string {\r\n // Config file key takes precedence\r\n if (configKey) {\r\n return configKey;\r\n }\r\n \r\n // Then check environment variables\r\n const envVars = {\r\n anthropic: \"ANTHROPIC_API_KEY\",\r\n openai: \"OPENAI_API_KEY\",\r\n google: \"GOOGLE_API_KEY\",\r\n } as const;\r\n \r\n const envVarName = envVars[provider];\r\n const envKey = process.env[envVarName];\r\n if (envKey) {\r\n return envKey;\r\n }\r\n \r\n // Also check generic key\r\n return process.env[\"TF_AI_API_KEY\"] ?? \"\";\r\n}\r\n\r\nexport function loadConfig(overrides?: Partial<Config>): Config {\r\n const file = loadConfigFile();\r\n \r\n // Determine model (priority: override > env > file > default)\r\n const model =\r\n overrides?.model ??\r\n process.env[\"TF_AI_MODEL\"] ??\r\n file.model ??\r\n \"claude-sonnet-4-5-20250929\";\r\n \r\n // Detect provider from model string\r\n const provider = \r\n overrides?.provider ?? \r\n file.provider ?? \r\n detectProvider(model);\r\n \r\n // Get API key\r\n const apiKey = getApiKey(provider, file.apiKey);\r\n \r\n return {\r\n model,\r\n provider,\r\n apiKey,\r\n confirmBeforeRun: overrides?.confirmBeforeRun ?? file.confirmBeforeRun ?? true,\r\n verbose: overrides?.verbose ?? file.verbose ?? false,\r\n };\r\n}\r\n\r\nexport function validateConfig(config: Config): { valid: boolean; error?: string } {\r\n if (!config.apiKey) {\r\n const envVar = {\r\n anthropic: \"ANTHROPIC_API_KEY\",\r\n openai: \"OPENAI_API_KEY\",\r\n google: \"GOOGLE_API_KEY\",\r\n }[config.provider];\r\n \r\n return {\r\n valid: false,\r\n error: `No API key found. Set ${envVar} environment variable or add \"apiKey\" to ${CONFIG_FILE}`,\r\n };\r\n }\r\n \r\n return { valid: true };\r\n}\r\n\r\nexport { CONFIG_DIR, CONFIG_FILE };\r\n","import { streamText, Output } from \"ai\";\r\nimport { anthropic } from \"@ai-sdk/anthropic\";\r\nimport { openai } from \"@ai-sdk/openai\";\r\nimport { google } from \"@ai-sdk/google\";\r\nimport type { Config } from \"../config.js\";\r\nimport { SYSTEM_PROMPT, formatUserMessage } from \"./prompts.js\";\r\nimport { analysisResponseSchema, type AnalysisResponse } from \"./schema.js\";\r\n\r\nexport interface CommandSuggestion {\r\n command: string;\r\n explanation: string;\r\n}\r\n\r\nexport interface AnalysisResult {\r\n explanation: string;\r\n suggestion: CommandSuggestion | undefined;\r\n}\r\n\r\nfunction getModel(config: Config) {\r\n const modelName = config.model.includes(\"/\") \r\n ? config.model.split(\"/\")[1]! \r\n : config.model;\r\n \r\n switch (config.provider) {\r\n case \"anthropic\":\r\n return anthropic(modelName);\r\n case \"openai\":\r\n return openai(modelName);\r\n case \"google\":\r\n return google(modelName);\r\n default:\r\n return anthropic(modelName);\r\n }\r\n}\r\n\r\nimport type { EnvironmentContext } from \"../shell/context.js\";\r\n\r\nexport interface StreamCallbacks {\r\n onExplanationUpdate?: (text: string) => void;\r\n onComplete?: (result: AnalysisResult) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Analyzes a command using streaming structured output.\r\n * Calls onExplanationUpdate as the explanation streams in.\r\n */\r\nexport async function analyzeCommandStream(\r\n command: string,\r\n output: string,\r\n config: Config,\r\n environment: EnvironmentContext,\r\n callbacks: StreamCallbacks = {}\r\n): Promise<AnalysisResult> {\r\n const model = getModel(config);\r\n \r\n const { partialOutputStream } = streamText({\r\n model,\r\n system: SYSTEM_PROMPT,\r\n prompt: formatUserMessage(command, output, environment),\r\n output: Output.object({ schema: analysisResponseSchema }),\r\n });\r\n\r\n let lastExplanation = \"\";\r\n let finalResponse: Partial<AnalysisResponse> = {};\r\n\r\n try {\r\n for await (const partial of partialOutputStream) {\r\n finalResponse = partial;\r\n \r\n // Stream explanation updates\r\n if (partial.explanation && partial.explanation !== lastExplanation) {\r\n lastExplanation = partial.explanation;\r\n callbacks.onExplanationUpdate?.(partial.explanation);\r\n }\r\n }\r\n } catch (error) {\r\n callbacks.onError?.(error as Error);\r\n throw error;\r\n }\r\n\r\n // Build final result\r\n const result: AnalysisResult = {\r\n explanation: finalResponse.explanation ?? \"\",\r\n suggestion: finalResponse.suggestedCommand \r\n ? {\r\n command: finalResponse.suggestedCommand,\r\n explanation: \"\", // Explanation is in the main field\r\n }\r\n : undefined,\r\n };\r\n\r\n callbacks.onComplete?.(result);\r\n return result;\r\n}\r\n\r\n/**\r\n * Non-streaming version for simpler use cases.\r\n */\r\nexport async function analyzeCommand(\r\n command: string,\r\n output: string,\r\n config: Config,\r\n environment: EnvironmentContext\r\n): Promise<AnalysisResult> {\r\n return analyzeCommandStream(command, output, config, environment);\r\n}\r\n","import type { EnvironmentContext } from \"../shell/context.js\";\r\n\r\nexport const SYSTEM_PROMPT = `You are an expert terminal assistant that helps developers understand command output and troubleshoot issues.\r\n\r\nGiven a command and its output, analyze the situation and provide helpful insight. The output could be:\r\n- An error message (syntax error, permission denied, command not found, etc.)\r\n- A warning or unexpected behavior\r\n- A build failure, test failure, or deployment issue\r\n- API/network errors\r\n- Confusing or unclear output that needs explanation\r\n- Or even successful output that the user wants to understand better\r\n\r\nYour response should:\r\n1. **Explain** what happened\r\n2. **Diagnose** the root cause if there's an issue, or at least speculate\r\n3. **Suggest a command** (optional) - only if there's a clear action the user can take\r\n\r\nGuidelines:\r\n- Be concise but thorough (if the problem is complex/deep, you have more leeway and the output can be longer!)\r\n- If you suggest a command, explain why / what it will do\r\n- If you're unsure or lacking enough context, simply say so\r\n- Apart from deliberate paragraphs, do not needlessly put newlines between sentences.\r\n- Tailor suggestions to the user's shell and OS`;\r\n\r\n\r\nexport function formatUserMessage(\r\n command: string, \r\n output: string,\r\n context: EnvironmentContext\r\n): string {\r\n const projectInfo = context.projectType ? `\\n- Project Type: ${context.projectType}` : '';\r\n \r\n return `Command: ${command}\r\n\r\nOutput:\r\n${output || \"(no output)\"}\r\n\r\nEnvironment:\r\n- Shell: ${context.shell}\r\n- OS: ${context.os}\r\n- Working Directory: ${context.cwd}${projectInfo}\r\n\r\nAnalyze this command and its output. Explain what happened and suggest a follow-up action if appropriate.`;\r\n}\r\n","import { z } from \"zod\";\r\n\r\n// Response schema for the AI analysis\r\nexport const analysisResponseSchema = z.object({\r\n explanation: z\r\n .string()\r\n .describe(\r\n \"Clear, helpful explanation of what happened. Interpret the output, diagnose issues, and provide context.\",\r\n ),\r\n suggestedCommand: z\r\n .string()\r\n .nullable()\r\n .describe(\r\n \"A follow-up command the user could run, if applicable. Could be a fix, a next step, or a diagnostic command. Pass null if no command is suggested\",\r\n ),\r\n});\r\n\r\nexport type AnalysisResponse = z.infer<typeof analysisResponseSchema>;\r\n","import { exec } from \"node:child_process\";\r\nimport { promisify } from \"node:util\";\r\nimport type { ShellAdapter, CommandContext } from \"./types.js\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nexport class PowerShellAdapter implements ShellAdapter {\r\n async getLastCommand(): Promise<CommandContext | null> {\r\n // This is called when the user runs tf-ai without explicit --command\r\n // We try to get the last command from PowerShell history\r\n try {\r\n const { stdout } = await execAsync(\r\n 'powershell -Command \"(Get-History -Count 1).CommandLine\"',\r\n { encoding: \"utf-8\" }\r\n );\r\n \r\n const command = stdout.trim();\r\n if (!command) {\r\n return null;\r\n }\r\n \r\n // We can't reliably get the output of the previous command after the fact\r\n // The user should use the shell function which captures output in real-time\r\n return {\r\n command,\r\n output: \"(Output not captured - use the 'fuck' shell function for full functionality)\",\r\n };\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async executeCommand(command: string): Promise<{ output: string; exitCode: number }> {\r\n try {\r\n const { stdout, stderr } = await execAsync(\r\n `powershell -Command \"${command.replace(/\"/g, '\\\\\"')}\"`,\r\n { encoding: \"utf-8\" }\r\n );\r\n return {\r\n output: stdout + stderr,\r\n exitCode: 0,\r\n };\r\n } catch (error) {\r\n const execError = error as { stdout?: string; stderr?: string; code?: number };\r\n return {\r\n output: (execError.stdout ?? \"\") + (execError.stderr ?? \"\"),\r\n exitCode: execError.code ?? 1,\r\n };\r\n }\r\n }\r\n\r\n getSetupInstructions(): string {\r\n return `\r\nAdd this to your PowerShell profile ($PROFILE):\r\n\r\nfunction fuck {\r\n $lastCmd = (Get-History -Count 1).CommandLine\r\n if (-not $lastCmd) {\r\n Write-Host \"No command in history\" -ForegroundColor Red\r\n return\r\n }\r\n \r\n # Re-execute to capture output\r\n $output = try { \r\n Invoke-Expression $lastCmd 2>&1 | Out-String \r\n } catch { \r\n $_.Exception.Message \r\n }\r\n \r\n # Call tf-ai with captured command and output\r\n tf-ai --command $lastCmd --output $output\r\n}\r\n\r\nThen reload your profile:\r\n. $PROFILE\r\n`.trim();\r\n }\r\n}\r\n\r\nexport const powershell = new PowerShellAdapter();\r\n","import { existsSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\nimport { platform } from \"node:os\";\r\n\r\nexport interface EnvironmentContext {\r\n shell: \"powershell\" | \"bash\" | \"zsh\" | \"cmd\" | \"fish\" | \"unknown\";\r\n os: \"windows\" | \"macos\" | \"linux\";\r\n cwd: string;\r\n projectType?: \"git\" | \"nodejs\" | \"python\" | \"docker\";\r\n}\r\n\r\nfunction detectShell(): EnvironmentContext[\"shell\"] {\r\n // Check for PowerShell-specific env var\r\n if (process.env[\"PSModulePath\"]) {\r\n return \"powershell\";\r\n }\r\n \r\n // Check SHELL env var (Unix-like systems)\r\n const shell = process.env[\"SHELL\"];\r\n if (shell) {\r\n if (shell.includes(\"bash\")) return \"bash\";\r\n if (shell.includes(\"zsh\")) return \"zsh\";\r\n if (shell.includes(\"fish\")) return \"fish\";\r\n }\r\n \r\n // Check for CMD on Windows\r\n if (process.env[\"ComSpec\"]?.includes(\"cmd.exe\")) {\r\n return \"cmd\";\r\n }\r\n \r\n return \"unknown\";\r\n}\r\n\r\nfunction detectOS(): EnvironmentContext[\"os\"] {\r\n const os = platform();\r\n \r\n switch (os) {\r\n case \"win32\":\r\n return \"windows\";\r\n case \"darwin\":\r\n return \"macos\";\r\n case \"linux\":\r\n return \"linux\";\r\n default:\r\n // Fallback to linux for other Unix-like systems\r\n return \"linux\";\r\n }\r\n}\r\n\r\nfunction detectProjectType(cwd: string): EnvironmentContext[\"projectType\"] {\r\n // Check in order of specificity\r\n if (existsSync(join(cwd, \".git\"))) {\r\n return \"git\";\r\n }\r\n \r\n if (existsSync(join(cwd, \"package.json\"))) {\r\n return \"nodejs\";\r\n }\r\n \r\n if (existsSync(join(cwd, \"requirements.txt\")) || existsSync(join(cwd, \"pyproject.toml\"))) {\r\n return \"python\";\r\n }\r\n \r\n if (existsSync(join(cwd, \"Dockerfile\"))) {\r\n return \"docker\";\r\n }\r\n \r\n return undefined;\r\n}\r\n\r\nexport function detectEnvironment(): EnvironmentContext {\r\n const cwd = process.cwd();\r\n const projectType = detectProjectType(cwd);\r\n \r\n return {\r\n shell: detectShell(),\r\n os: detectOS(),\r\n cwd,\r\n ...(projectType ? { projectType } : {}),\r\n };\r\n}\r\n","import chalk from \"chalk\";\r\nimport type { CommandSuggestion, AnalysisResult } from \"../ai/index.js\";\r\nimport { theme } from \"./theme.js\";\r\n\r\nconst ICONS = {\r\n robot: \"🤖\",\r\n lightbulb: \"💡\",\r\n command: \"➜\",\r\n warning: \"⚠️\",\r\n error: \"❌\",\r\n success: \"✓\",\r\n thinking: \"🧠\",\r\n};\r\n\r\nexport function printHeader(): void {\r\n // Clean header using theme\r\n console.log(theme.header(`\\n${ICONS.robot} tf-ai\\n`));\r\n}\r\n\r\nexport function printExplanation(result: AnalysisResult): void {\r\n if (result.explanation) {\r\n console.log(theme.explanation(result.explanation));\r\n console.log();\r\n }\r\n}\r\n\r\nlet lastPrintedLength = 0;\r\n\r\n/**\r\n * For streaming: prints only the new part of the explanation\r\n */\r\nexport function printStreamingExplanation(fullText: string): void {\r\n if (!fullText) return;\r\n\r\n // Calculate the new chunk to print\r\n const newText = fullText.slice(lastPrintedLength);\r\n\r\n if (newText) {\r\n // Use theme explanation color\r\n process.stdout.write(theme.explanation(newText));\r\n lastPrintedLength = fullText.length;\r\n }\r\n}\r\n\r\n/**\r\n * Finalize streaming output with newline and reset state\r\n */\r\nexport function finalizeStreaming(): void {\r\n console.log(); // New line after streaming completes\r\n lastPrintedLength = 0; // Reset for next run\r\n}\r\n\r\nexport function printSuggestion(suggestion: CommandSuggestion): void {\r\n console.log(theme.suggestionLabel(`${ICONS.lightbulb} Suggested command:`));\r\n console.log();\r\n // Using theme.command color\r\n console.log(theme.command(` ${ICONS.command} ${suggestion.command} `));\r\n console.log();\r\n}\r\n\r\nexport function printError(message: string): void {\r\n console.error(theme.error(`${ICONS.error} ${message}`));\r\n}\r\n\r\nexport function printWarning(message: string): void {\r\n console.log(theme.warning(`${ICONS.warning} ${message}`));\r\n}\r\n\r\nexport function printSuccess(message: string): void {\r\n console.log(theme.success(`${ICONS.success} ${message}`));\r\n}\r\n\r\nexport function printCommand(label: string, command: string): void {\r\n console.log(theme.muted(`${label}: `) + theme.text(command));\r\n}\r\n\r\nexport function printVerbose(message: string, verbose: boolean): void {\r\n if (verbose) {\r\n console.log(theme.muted(`[debug] ${message}`));\r\n }\r\n}\r\n","import chalk from \"chalk\";\r\n\r\n/**\r\n * Anthropic-Inspired Palette\r\n * Sophisticated, warm, and professional.\r\n */\r\nexport const COLORS = {\r\n stone: \"#F5F2E8\", // Warmest White / Base\r\n warmGray: \"#9E9A95\", // Muted text / Labels\r\n text: \"#E3DCD2\", // Main reading text (Warm Off-White)\r\n coral: \"#D97757\", // Primary Accent (Anthropic-like orange/coral) - Highlights\r\n maple: \"#C8A682\", // Secondary Accent - Interactions\r\n olive: \"#8E9C6D\", // Success\r\n sienna: \"#C1554D\", // Error\r\n charcoal: \"#2D2B29\", // Dark background text if needed\r\n};\r\n\r\n/**\r\n * Semantic Theme Definitions\r\n */\r\nexport const theme = {\r\n // --- Global Roles ---\r\n primary: chalk.hex(COLORS.coral),\r\n secondary: chalk.hex(COLORS.maple),\r\n success: chalk.hex(COLORS.olive),\r\n error: chalk.hex(COLORS.sienna),\r\n warning: chalk.hex(COLORS.maple), // Maple works well for warning too\r\n muted: chalk.hex(COLORS.warmGray),\r\n text: chalk.hex(COLORS.text),\r\n \r\n // --- Component Specifics ---\r\n \r\n // Header / Branding\r\n header: chalk.hex(COLORS.coral).bold,\r\n \r\n // The suggested command to run\r\n command: chalk.hex(COLORS.stone).bold, // Bright, distinct\r\n \r\n // The AI's explanation text\r\n explanation: chalk.hex(COLORS.text),\r\n \r\n // \"Suggested fix:\" label - subtle yet clear\r\n suggestionLabel: chalk.hex(COLORS.maple).bold,\r\n \r\n // Confidence levels\r\n confidenceHigh: chalk.hex(COLORS.olive),\r\n confidenceMedium: chalk.hex(COLORS.maple),\r\n confidenceLow: chalk.hex(COLORS.sienna),\r\n \r\n // --- Animation Colors ---\r\n // Glitch characters\r\n glitch1: chalk.hex(COLORS.coral),\r\n glitch2: chalk.hex(COLORS.maple),\r\n // Base text for \"Analyzing...\"\r\n glitchBase: chalk.hex(COLORS.warmGray),\r\n};\r\n","import * as readline from \"node:readline\";\r\nimport chalk from \"chalk\";\r\nimport { exec } from \"node:child_process\";\r\nimport { promisify } from \"node:util\";\r\nimport { theme } from \"./theme.js\";\r\n\r\nconst execAsync = promisify(exec);\r\n\r\nexport interface ConfirmResult {\r\n action: \"run\" | \"cancel\" | \"edit\";\r\n editedCommand?: string;\r\n}\r\n\r\nexport async function confirmCommand(command: string): Promise<ConfirmResult> {\r\n return new Promise((resolve) => {\r\n // Compact menu on one line\r\n process.stdout.write(\r\n theme.secondary(\"[Enter]\") + theme.muted(\" Run \") +\r\n theme.secondary(\"[e]\") + theme.muted(\" Edit \") +\r\n theme.secondary(\"[Esc/q]\") + theme.muted(\" Cancel\")\r\n );\r\n\r\n // Set up raw mode to capture single keypresses\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(true);\r\n }\r\n process.stdin.resume();\r\n process.stdin.setEncoding(\"utf8\");\r\n\r\n const cleanup = () => {\r\n if (process.stdin.isTTY) {\r\n process.stdin.setRawMode(false);\r\n }\r\n process.stdin.pause();\r\n process.stdin.removeAllListeners(\"data\");\r\n };\r\n\r\n process.stdin.once(\"data\", (key: string) => {\r\n cleanup();\r\n\r\n // Enter key\r\n if (key === \"\\r\" || key === \"\\n\") {\r\n resolve({ action: \"run\" });\r\n return;\r\n }\r\n\r\n // Escape or q\r\n if (key === \"\\u001b\" || key === \"q\" || key === \"\\u0003\") {\r\n console.log(\"\\n\" + theme.warning(\"Cancelled\"));\r\n resolve({ action: \"cancel\" });\r\n return;\r\n }\r\n\r\n // Edit\r\n if (key === \"e\" || key === \"E\") {\r\n resolve({ action: \"edit\" });\r\n return;\r\n }\r\n\r\n // Unknown key - treat as cancel\r\n console.log(\"\\n\" + theme.warning(\"Cancelled\"));\r\n resolve({ action: \"cancel\" });\r\n });\r\n });\r\n}\r\n\r\nexport async function editCommand(originalCommand: string): Promise<string | null> {\r\n return new Promise((resolve) => {\r\n const rl = readline.createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n\r\n console.log(theme.secondary(\"\\nEdit command (press Enter to confirm, Ctrl+C to cancel):\"));\r\n \r\n rl.question(theme.muted(\"> \"), (answer) => {\r\n rl.close();\r\n const command = answer.trim();\r\n resolve(command || originalCommand);\r\n });\r\n\r\n rl.on(\"close\", () => {\r\n if (!rl.terminal) {\r\n resolve(null);\r\n }\r\n });\r\n });\r\n}\r\n\r\nexport async function runCommand(command: string): Promise<void> {\r\n console.log(theme.secondary(`\\nRunning: ${command}\\n`));\r\n console.log(theme.muted(\"─\".repeat(40)));\r\n \r\n try {\r\n // Run the command and stream output\r\n const { stdout, stderr } = await execAsync(\r\n `powershell -Command \"${command.replace(/\"/g, '\\\\\"')}\"`,\r\n { encoding: \"utf-8\" }\r\n );\r\n \r\n if (stdout) console.log(stdout);\r\n if (stderr) console.error(theme.error(stderr));\r\n \r\n console.log(theme.muted(\"─\".repeat(40)));\r\n console.log(theme.success(\"✓ Command completed\"));\r\n } catch (error) {\r\n const execError = error as { stdout?: string; stderr?: string; code?: number };\r\n if (execError.stdout) console.log(execError.stdout);\r\n if (execError.stderr) console.error(theme.error(execError.stderr));\r\n \r\n console.log(theme.muted(\"─\".repeat(40)));\r\n console.log(theme.error(`✗ Command failed with exit code ${execError.code ?? 1}`));\r\n }\r\n}\r\n","import { theme } from \"./theme.js\";\n\n/**\n * Creates a \"hacking\" style animated text where random characters glitch\n * Refined for subtlety and elegance\n */\nexport function createHackingAnimation(text: string): {\n start: () => void;\n stop: () => void;\n} {\n const glitchChars = ['#', '$', '%', '*', '?', '~', '^', '+', '=', ':'];\n let interval: NodeJS.Timeout | null = null;\n let isRunning = false;\n \n const originalText = text;\n const textArray = text.split('');\n \n function glitchText(): string {\n return textArray.map((char, i) => {\n // Skip spaces\n if (char === ' ') return ' ';\n \n // Random chance to glitch (much lower probability for subtlety: 5%)\n if (Math.random() < 0.05) {\n // Use theme colors for glitches\n return Math.random() > 0.5 \n ? theme.glitch1(glitchChars[Math.floor(Math.random() * glitchChars.length)]!)\n : theme.glitch2(glitchChars[Math.floor(Math.random() * glitchChars.length)]!);\n }\n \n // Base text color\n return theme.glitchBase(char);\n }).join('');\n }\n \n function render() {\n if (!isRunning) return;\n \n // Clear line and print glitched text\n process.stdout.write('\\r' + glitchText());\n }\n \n return {\n start() {\n if (isRunning) return;\n isRunning = true;\n \n // Print initial state\n process.stdout.write(theme.glitchBase(originalText));\n \n // Start glitching at slower intervals (120ms) for elegance\n interval = setInterval(render, 120);\n },\n \n stop() {\n if (!isRunning) return;\n isRunning = false;\n \n if (interval) {\n clearInterval(interval);\n interval = null;\n }\n \n // Clear the line\n process.stdout.write('\\r' + ' '.repeat(originalText.length) + '\\r');\n },\n };\n}\n"],"mappings":"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","names":["existsSync","join","exec","promisify","execAsync","promisify","exec"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tf-ai",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "AI-powered terminal assistant that explains errors and suggests fixes",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",