tf-ai 0.1.2 β†’ 0.1.3

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
@@ -54,7 +54,9 @@ To use the `fuck` alias, run the setup command for your shell:
54
54
  ```bash
55
55
  tf-ai --setup
56
56
  ```
57
- Follow the instructions to add the function to your shell profile (PowerShell `$PROFILE`, `.bashrc`, etc).
57
+ Follow the instructions to add the function to your shell profile:
58
+ - **Windows**: PowerShell (`$PROFILE`)
59
+ - **Linux/macOS**: Bash (`.bashrc`) or Zsh (`.zshrc`)
58
60
 
59
61
  ### 2. The "Fuck" Workflow
60
62
 
@@ -70,7 +72,7 @@ PS> fuck
70
72
  πŸ€– tf-ai
71
73
  It looks like you made a typo. 'pussh' is not a valid git command.
72
74
 
73
- πŸ’‘ Suggested command:
75
+ πŸ’‘Suggested command:
74
76
  ➜ git push origin main
75
77
 
76
78
  [Enter] Run [e] Edit [Esc] Cancel
package/dist/index.js CHANGED
@@ -180,6 +180,64 @@ async function analyzeCommandStream(command, output, config, environment, callba
180
180
  return result;
181
181
  }
182
182
 
183
+ // src/shell/context.ts
184
+ import { existsSync as existsSync2 } from "fs";
185
+ import { join as join2 } from "path";
186
+ import { platform } from "os";
187
+ function detectShell() {
188
+ const shell = process.env["SHELL"];
189
+ if (shell) {
190
+ if (shell.includes("bash")) return "bash";
191
+ if (shell.includes("zsh")) return "zsh";
192
+ if (shell.includes("fish")) return "fish";
193
+ }
194
+ if (process.env["PSModulePath"]) {
195
+ return "powershell";
196
+ }
197
+ if (process.env["ComSpec"]?.includes("cmd.exe")) {
198
+ return "cmd";
199
+ }
200
+ return "unknown";
201
+ }
202
+ function detectOS() {
203
+ const os = platform();
204
+ switch (os) {
205
+ case "win32":
206
+ return "windows";
207
+ case "darwin":
208
+ return "macos";
209
+ case "linux":
210
+ return "linux";
211
+ default:
212
+ return "linux";
213
+ }
214
+ }
215
+ function detectProjectType(cwd) {
216
+ if (existsSync2(join2(cwd, ".git"))) {
217
+ return "git";
218
+ }
219
+ if (existsSync2(join2(cwd, "package.json"))) {
220
+ return "nodejs";
221
+ }
222
+ if (existsSync2(join2(cwd, "requirements.txt")) || existsSync2(join2(cwd, "pyproject.toml"))) {
223
+ return "python";
224
+ }
225
+ if (existsSync2(join2(cwd, "Dockerfile"))) {
226
+ return "docker";
227
+ }
228
+ return void 0;
229
+ }
230
+ function detectEnvironment() {
231
+ const cwd = process.cwd();
232
+ const projectType = detectProjectType(cwd);
233
+ return {
234
+ shell: detectShell(),
235
+ os: detectOS(),
236
+ cwd,
237
+ ...projectType ? { projectType } : {}
238
+ };
239
+ }
240
+
183
241
  // src/shell/powershell.ts
184
242
  import { exec } from "child_process";
185
243
  import { promisify } from "util";
@@ -250,62 +308,85 @@ Then reload your profile:
250
308
  };
251
309
  var powershell = new PowerShellAdapter();
252
310
 
253
- // src/shell/context.ts
254
- import { existsSync as existsSync2 } from "fs";
255
- import { join as join2 } from "path";
256
- import { platform } from "os";
257
- function detectShell() {
258
- if (process.env["PSModulePath"]) {
259
- return "powershell";
260
- }
261
- const shell = process.env["SHELL"];
262
- if (shell) {
263
- if (shell.includes("bash")) return "bash";
264
- if (shell.includes("zsh")) return "zsh";
265
- if (shell.includes("fish")) return "fish";
266
- }
267
- if (process.env["ComSpec"]?.includes("cmd.exe")) {
268
- return "cmd";
311
+ // src/shell/bash.ts
312
+ import { exec as exec2 } from "child_process";
313
+ import { promisify as promisify2 } from "util";
314
+ var execAsync2 = promisify2(exec2);
315
+ var BashAdapter = class {
316
+ async getLastCommand() {
317
+ return null;
269
318
  }
270
- return "unknown";
271
- }
272
- function detectOS() {
273
- const os = platform();
274
- switch (os) {
275
- case "win32":
276
- return "windows";
277
- case "darwin":
278
- return "macos";
279
- case "linux":
280
- return "linux";
281
- default:
282
- return "linux";
319
+ async executeCommand(command) {
320
+ try {
321
+ const escapedCommand = command.replace(/'/g, "'\\''");
322
+ const { stdout, stderr } = await execAsync2(
323
+ `bash -c '${escapedCommand}'`,
324
+ { encoding: "utf-8" }
325
+ );
326
+ return {
327
+ output: stdout + stderr,
328
+ exitCode: 0
329
+ };
330
+ } catch (error) {
331
+ const execError = error;
332
+ return {
333
+ output: (execError.stdout ?? "") + (execError.stderr ?? ""),
334
+ exitCode: execError.code ?? 1
335
+ };
336
+ }
283
337
  }
338
+ getSetupInstructions() {
339
+ return `
340
+ # Add this to your .bashrc or .zshrc:
341
+
342
+ function fuck() {
343
+ # Get last command from history (ignores leading spaces)
344
+ # 'fc -ln -1' gets the last command, 'sed' removes leading whitespace
345
+ TF_CMD=$(fc -ln -1 | sed 's/^[[:space:]]*//')
346
+
347
+ if [ -z "$TF_CMD" ]; then
348
+ echo "No command in history"
349
+ return
350
+ fi
351
+
352
+ # Re-execute to capture output (stdout + stderr)
353
+ # We use a subshell to capture combined output
354
+ TF_OUTPUT=$($TF_CMD 2>&1)
355
+
356
+ # Call tf-ai with captured command and output
357
+ tf-ai --command "$TF_CMD" --output "$TF_OUTPUT"
284
358
  }
285
- function detectProjectType(cwd) {
286
- if (existsSync2(join2(cwd, ".git"))) {
287
- return "git";
288
- }
289
- if (existsSync2(join2(cwd, "package.json"))) {
290
- return "nodejs";
291
- }
292
- if (existsSync2(join2(cwd, "requirements.txt")) || existsSync2(join2(cwd, "pyproject.toml"))) {
293
- return "python";
359
+ `.trim();
294
360
  }
295
- if (existsSync2(join2(cwd, "Dockerfile"))) {
296
- return "docker";
361
+ };
362
+ var bash = new BashAdapter();
363
+
364
+ // src/shell/index.ts
365
+ var activeShell = null;
366
+ function getShell() {
367
+ if (activeShell) {
368
+ return activeShell;
369
+ }
370
+ const env = detectEnvironment();
371
+ switch (env.shell) {
372
+ case "powershell":
373
+ activeShell = powershell;
374
+ break;
375
+ case "bash":
376
+ case "zsh":
377
+ activeShell = bash;
378
+ break;
379
+ case "cmd":
380
+ activeShell = powershell;
381
+ break;
382
+ default:
383
+ if (env.os === "windows") {
384
+ activeShell = powershell;
385
+ } else {
386
+ activeShell = bash;
387
+ }
297
388
  }
298
- return void 0;
299
- }
300
- function detectEnvironment() {
301
- const cwd = process.cwd();
302
- const projectType = detectProjectType(cwd);
303
- return {
304
- shell: detectShell(),
305
- os: detectOS(),
306
- cwd,
307
- ...projectType ? { projectType } : {}
308
- };
389
+ return activeShell;
309
390
  }
310
391
 
311
392
  // src/ui/output.ts
@@ -366,7 +447,8 @@ var theme = {
366
447
  // src/ui/output.ts
367
448
  var ICONS = {
368
449
  robot: "\u{1F916}",
369
- lightbulb: "\u{1F4A1}",
450
+ lightbulb: "",
451
+ // note: remember to add space after it if adding icon
370
452
  command: "\u279C",
371
453
  warning: "\u26A0\uFE0F",
372
454
  error: "\u274C",
@@ -387,7 +469,7 @@ function finalizeStreaming() {
387
469
  lastPrintedLength = 0;
388
470
  }
389
471
  function printSuggestion(suggestion) {
390
- console.log(theme.suggestionLabel(`${ICONS.lightbulb} Suggested command:`));
472
+ console.log(theme.suggestionLabel(`${ICONS.lightbulb}Suggested command:`));
391
473
  console.log();
392
474
  console.log(theme.command(` ${ICONS.command} ${suggestion.command} `));
393
475
  console.log();
@@ -410,9 +492,9 @@ function printVerbose(message, verbose) {
410
492
  // src/ui/confirm.ts
411
493
  import * as readline from "readline";
412
494
  import "chalk";
413
- import { exec as exec2 } from "child_process";
414
- import { promisify as promisify2 } from "util";
415
- var execAsync2 = promisify2(exec2);
495
+ import { exec as exec3 } from "child_process";
496
+ import { promisify as promisify3 } from "util";
497
+ var execAsync3 = promisify3(exec3);
416
498
  async function confirmCommand(command) {
417
499
  return new Promise((resolve) => {
418
500
  process.stdout.write(
@@ -475,20 +557,17 @@ Running: ${command}
475
557
  `));
476
558
  console.log(theme.muted("\u2500".repeat(40)));
477
559
  try {
478
- const { stdout, stderr } = await execAsync2(
479
- `powershell -Command "${command.replace(/"/g, '\\"')}"`,
480
- { encoding: "utf-8" }
481
- );
482
- if (stdout) console.log(stdout);
483
- if (stderr) console.error(theme.error(stderr));
560
+ const { output, exitCode } = await getShell().executeCommand(command);
561
+ if (output) console.log(output);
484
562
  console.log(theme.muted("\u2500".repeat(40)));
485
- console.log(theme.success("\u2713 Command completed"));
563
+ if (exitCode === 0) {
564
+ console.log(theme.success("\u2713 Command completed"));
565
+ } else {
566
+ console.log(theme.error(`\u2717 Command failed with exit code ${exitCode}`));
567
+ }
486
568
  } catch (error) {
487
- const execError = error;
488
- if (execError.stdout) console.log(execError.stdout);
489
- if (execError.stderr) console.error(theme.error(execError.stderr));
490
569
  console.log(theme.muted("\u2500".repeat(40)));
491
- console.log(theme.error(`\u2717 Command failed with exit code ${execError.code ?? 1}`));
570
+ console.log(theme.error(`\u2717 Command failed: ${error}`));
492
571
  }
493
572
  }
494
573
 
@@ -537,7 +616,7 @@ var program = new Command();
537
616
  program.name("tf-ai").description("AI-powered terminal assistant that explains errors and suggests fixes").version("1.0.0");
538
617
  program.option("-c, --command <command>", "The command that failed").option("-o, --output <output>", "The output/error from the failed command").option("-e, --explain", "Only explain the error, don't suggest commands").option("-m, --model <model>", "Model to use (e.g., claude-sonnet-4-20250514, gpt-4o)").option("-y, --yes", "Auto-run the suggested command without confirmation").option("-v, --verbose", "Show verbose output").option("--setup", "Show shell setup instructions").action(async (options) => {
539
618
  if (options.setup) {
540
- console.log(powershell.getSetupInstructions());
619
+ console.log(getShell().getSetupInstructions());
541
620
  return;
542
621
  }
543
622
  const configOverrides = {};
@@ -562,7 +641,7 @@ Create a config file at ${CONFIG_FILE} or set the appropriate environment variab
562
641
  let output = options.output ?? "";
563
642
  if (!command) {
564
643
  printVerbose("No command provided, checking shell history...", config.verbose);
565
- const lastCmd = await powershell.getLastCommand();
644
+ const lastCmd = await getShell().getLastCommand();
566
645
  if (lastCmd) {
567
646
  command = lastCmd.command;
568
647
  output = lastCmd.output;
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\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"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/ai/client.ts","../src/ai/prompts.ts","../src/ai/schema.ts","../src/shell/context.ts","../src/shell/powershell.ts","../src/shell/bash.ts","../src/shell/index.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 { getShell, 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(getShell().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 getShell().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 { 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 SHELL env var (Unix-like systems) - Check this FIRST to avoid false positives on Linux\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 PowerShell-specific env var\r\n if (process.env[\"PSModulePath\"]) {\r\n return \"powershell\";\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 { 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 { 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 BashAdapter implements ShellAdapter {\r\n async getLastCommand(): Promise<CommandContext | null> {\r\n // fast, non-interactive history lookup not easily possible in pure node without help from shell\r\n // The user really should use the shell alias/function for full functionality.\r\n // However, we can try to read ~/.bash_history if forced, but that's flaky (timestamps etc).\r\n \r\n // Instead, we rely on the shell wrapper passing the command.\r\n // If called directly without wrapper:\r\n return null; \r\n }\r\n\r\n async executeCommand(command: string): Promise<{ output: string; exitCode: number }> {\r\n try {\r\n // Use bash -c to execute. \r\n // We escape single quotes in the command by replacing ' with '\\''\r\n const escapedCommand = command.replace(/'/g, \"'\\\\''\");\r\n const { stdout, stderr } = await execAsync(\r\n `bash -c '${escapedCommand}'`,\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\n# Add this to your .bashrc or .zshrc:\r\n\r\nfunction fuck() {\r\n # Get last command from history (ignores leading spaces)\r\n # 'fc -ln -1' gets the last command, 'sed' removes leading whitespace\r\n TF_CMD=$(fc -ln -1 | sed 's/^[[:space:]]*//')\r\n \r\n if [ -z \"$TF_CMD\" ]; then\r\n echo \"No command in history\"\r\n return\r\n fi\r\n\r\n # Re-execute to capture output (stdout + stderr)\r\n # We use a subshell to capture combined output\r\n TF_OUTPUT=$($TF_CMD 2>&1)\r\n \r\n # Call tf-ai with captured command and output\r\n tf-ai --command \"$TF_CMD\" --output \"$TF_OUTPUT\"\r\n}\r\n`.trim();\r\n }\r\n}\r\n\r\nexport const bash = new BashAdapter();\r\n","import { detectEnvironment } from \"./context.js\";\r\nimport { PowerShellAdapter, powershell } from \"./powershell.js\";\r\nimport { BashAdapter, bash } from \"./bash.js\";\r\nimport type { ShellAdapter } from \"./types.js\";\r\n\r\nexport { PowerShellAdapter, powershell } from \"./powershell.js\";\r\nexport { BashAdapter, bash } from \"./bash.js\";\r\nexport { detectEnvironment, type EnvironmentContext } from \"./context.js\";\r\nexport type { ShellAdapter, CommandContext } from \"./types.js\";\r\n\r\nlet activeShell: ShellAdapter | null = null;\r\n\r\nexport function getShell(): ShellAdapter {\r\n if (activeShell) {\r\n return activeShell;\r\n }\r\n \r\n const env = detectEnvironment();\r\n \r\n switch (env.shell) {\r\n case \"powershell\":\r\n activeShell = powershell;\r\n break;\r\n case \"bash\":\r\n case \"zsh\":\r\n // Bash adapter works for zsh too for now as they both share 'fc'\r\n activeShell = bash;\r\n break;\r\n case \"cmd\":\r\n // Fallback to powershell for now on Windows if CMD is detected but we want robust features\r\n // Or we could implement CmdAdapter later. For now, defaulting to powershell is safer \r\n // as our powershell adapter uses 'powershell -Command' which works from CMD too.\r\n activeShell = powershell;\r\n break;\r\n default:\r\n // Default fallback based on OS\r\n if (env.os === \"windows\") {\r\n activeShell = powershell;\r\n } else {\r\n activeShell = bash;\r\n }\r\n }\r\n \r\n return activeShell!;\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: \"\", // note: remember to add space after it if adding icon\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\nimport { getShell } from \"../shell/index.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 { output, exitCode } = await getShell().executeCommand(command);\r\n \r\n // Parse stdout/stderr roughly from the combined output if possible, \r\n // but our adapters return combined output mostly.\r\n // For now we just print the output.\r\n if (output) console.log(output);\r\n \r\n console.log(theme.muted(\"─\".repeat(40)));\r\n if (exitCode === 0) {\r\n console.log(theme.success(\"βœ“ Command completed\"));\r\n } else {\r\n console.log(theme.error(`βœ— Command failed with exit code ${exitCode}`));\r\n }\r\n } catch (error) {\r\n console.log(theme.muted(\"─\".repeat(40)));\r\n console.log(theme.error(`βœ— Command failed: ${error}`));\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","exec","promisify","execAsync","promisify","exec"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tf-ai",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "AI-powered terminal assistant that explains errors and suggests fixes",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",