Skip to content

Instantly share code, notes, and snippets.

@dylarcher
Last active January 30, 2026 01:44
Show Gist options
  • Select an option

  • Save dylarcher/d75d71db96591360a69b0e24ce703450 to your computer and use it in GitHub Desktop.

Select an option

Save dylarcher/d75d71db96591360a69b0e24ce703450 to your computer and use it in GitHub Desktop.
Ideal local dev machine setup.

Modern Frontend Development Setup: MacBook M4

This guide outlines a best-practice, modern local machine setup for frontend development on a MacBook M4. It focuses on maximizing productivity, performance, and developer experience.

1. The Foundation: Homebrew

Homebrew is the essential package manager for macOS. It simplifies the installation of almost all the tools we will use.

  • Install Homebrew - Open the built-in Terminal app and run the following command. This will also install the Xcode Command Line Tools (including Git).

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • Follow "Next steps" - After the installation finishes, Homebrew will provide commands to add it to your PATH. This is crucial for it to work correctly.

2. Command Line (CLI) Setup

A robust and efficient terminal environment is key.

Terminal Emulator

The default terminal is functional, but modern alternatives are superior.

  • Warp - (Recommended) A modern, high-performance, Rust-based terminal with AI features, intuitive block-based workflows, and excellent defaults.
  • iTerm2 - A mature, highly customizable alternative.
# Install Warp
brew install --cask warp

# Or install iTerm2
# brew install --cask iterm2

Shell Framework: Oh My Zsh

Zsh is the default shell on macOS. Oh My Zsh is a framework that manages Zsh configuration, themes, and plugins.

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Theme and Fonts: Powerlevel10k

Powerlevel10k is a fast, highly customizable theme.

  1. Install the theme:

    brew install powerlevel10k
    echo "source $(brew --prefix)/share/powerlevel10k/powerlevel10k.zsh-theme" >>~/.zshrc
  2. Configure - Restart your terminal. The configuration wizard (p10k configure) will launch. It will prompt you to install the recommended MesloLGS NF font, which is necessary for icons to display correctly.

Essential Zsh Plugins

Plugins enhance shell functionality. We will install them into the Oh My Zsh custom directory.

  • zsh-autosuggestions (Suggests commands based on history):

    git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
  • zsh-syntax-highlighting (Provides color highlighting for commands):

    git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
  • Activate Plugins - Open your ~/.zshrc file (e.g., using nano ~/.zshrc) and edit the plugins line to include these:

    plugins=(git zsh-autosuggestions zsh-syntax-highlighting)

3. Runtimes and Version Control

Git and GitHub CLI

Git is installed with the Xcode Command Line Tools (via Homebrew). We will also install the GitHub CLI (gh) for interacting with GitHub from the terminal.

brew install gh
gh auth login

Configure your Git identity:

git config --global user.name "User Name"
git config --global user.email "email@address.com"

Node.js Management: nvm

It is crucial to be able to switch between different Node.js versions for different projects. NVM (Node Version Manager) is the standard tool.

  • Install nvm:

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

    NOTE: Restart your terminal after installation.

  • Install Node.js - Install the latest Long-Term Support (LTS) version.

    nvm install --lts
    nvm use --lts

Package Manager: pnpm (or npm, etc.)

While npm (included with Node) and Yarn are common, pnpm is often preferred for its speed and superior efficiency in managing disk space.

brew install pnpm # or "npm", etc.

4. IDE: VSCode (or Cursor, etc.)

Visual Studio Code (VS Code)is the industry standard for frontend development due to its performance, flexibility, and extensive ecosystem.

brew install --cask visual-studio-code # or "cursor", etc.

Essential VS Code Extensions

Install these extensions within VS Code for an optimal workflow:

  • ESLint - Integrates ESLint to identify and fix code quality issues.
  • Prettier - An opinionated code formatter for consistent code style (usually configured to run on save).
  • GitLens - Supercharges Git capabilities, showing blame annotations, history, and visualizations directly in the editor.
  • Live Server - Launches a local development server with live reloading for static pages.
  • Auto Rename Tag - Automatically renames the closing HTML/JSX tag when the opening tag is changed.
  • Path Intellisense - Autocompletes filenames and paths.
  • Tailwind CSS IntelliSense - (If using Tailwind) Provides intelligent suggestions, linting, and previews.
  • GitHub Copilot - (Optional, paid) AI-powered code completion.

5. Essential Utilities

Browsers: google-chrome (and firefox, etc.)

Cross-browser testing is vital.

brew install --cask google-chrome # and "firefox", etc.
  • Use the built-in Safari for Apple ecosystem testing.
  • Install framework-specific browser extensions (React Developer Tools, Vue.js Devtools, etc.).

Containers: OrbStack (or Docker, etc.)

Containers are essential for running databases, backend services, or isolating environments. While Docker Desktop is the standard, OrbStack is highly recommended for macOS as a faster, lighter, and more efficient alternative.

brew install --cask orbstack # or "docker", etc.

API Client: Insomnia (or Postman, etc.)

For testing and debugging APIs.

brew install --cask insomnia # or "postman", etc.

Design: Figma (or Miro, etc.)

For extracting assets and collaborating on designs.

brew install --cask figma # or "miro", etc.

6. Productivity Tools

Spotlight Replacement: Raycast

Raycast is a blazingly fast, extensible launcher. It is highly recommended over Spotlight or Alfred. It can manage windows, clipboard history, snippets, and integrate with tools like GitHub, Jira, and more.

brew install --cask raycast

Window Management: Rectangle

macOS lacks robust window snapping. Rectangle allows you to quickly move and resize windows using keyboard shortcuts.

brew install --cask rectangle
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Optimal M4 Frontend Developer Setup | 2025</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #F0F4F8; /* Light Blue-Gray Background */
}
.chart-container {
position: relative;
width: 100%;
max-width: 600px;
margin-left: auto;
margin-right: auto;
height: 350px;
max-height: 400px;
}
@media (max-width: 768px) {
.chart-container {
height: 300px;
}
}
.kpi-card {
background-color: #ffffff;
border-radius: 0.75rem;
padding: 1.5rem;
text-align: center;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.kpi-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}
.flowchart-step {
background-color: #FFFFFF;
border: 2px solid #FF6B6B; /* Energetic Red */
color: #1A535C; /* Dark Teal */
}
.flowchart-arrow {
color: #FF6B6B; /* Energetic Red */
}
.gemini-feature-card {
background: linear-gradient(135deg, #F7FFF7, #EFFFFE);
}
</style>
</head>
<body class="text-[#1A535C]">
<div class="container mx-auto p-4 md:p-8 max-w-7xl">
<header class="text-center my-8 md:my-12">
<h1 class="text-4xl md:text-6xl font-black text-[#FF6B6B] tracking-tight">The Optimal Frontend Setup</h1>
<h2 class="text-2xl md:text-4xl font-bold text-[#4ECDC4] mt-2">Apple Silicon M4 Edition | 2025</h2>
<p class="max-w-3xl mx-auto mt-4 text-lg text-gray-600">A curated guide to building a high-performance, modern development environment on the latest Apple hardware, focusing on speed, efficiency, and a seamless workflow.</p>
</header>
<main>
<section id="bedrock" class="mb-12 md:mb-20">
<h3 class="text-3xl font-bold text-center mb-8">The Bedrock: Core Command-Line Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 text-center">
<div class="kpi-card">
<div class="text-5xl font-bold text-[#FF6B6B]">1</div>
<h4 class="text-xl font-semibold mt-4 mb-2">Xcode Command Line Tools</h4>
<p class="text-gray-600">The essential first step. Installs compilers and Git, preparing your Mac for development without the full Xcode IDE.</p>
<code class="mt-4 inline-block bg-gray-100 text-sm p-2 rounded">xcode-select --install</code>
</div>
<div class="kpi-card">
<div class="text-5xl font-bold text-[#FF6B6B]">2</div>
<h4 class="text-xl font-semibold mt-4 mb-2">Homebrew Package Manager</h4>
<p class="text-gray-600">The "missing package manager for macOS." Manages all your tools in a clean, isolated `/opt/homebrew` directory.</p>
<code class="mt-4 inline-block bg-gray-100 text-sm p-2 rounded">/bin/bash -c "$(curl...)"</code>
</div>
<div class="kpi-card">
<div class="text-5xl font-bold text-[#FF6B6B]">3</div>
<h4 class="text-xl font-semibold mt-4 mb-2">Git Version Control</h4>
<p class="text-gray-600">Install the latest version via Homebrew to ensure you have the most up-to-date features for version control.</p>
<code class="mt-4 inline-block bg-gray-100 text-sm p-2 rounded">brew install git</code>
</div>
</div>
</section>
<section id="command-center" class="mb-12 md:mb-20">
<h3 class="text-3xl font-bold text-center mb-8">The Command Center: Terminal & Shell</h3>
<div class="bg-white rounded-lg shadow-md p-6 md:p-8 mb-8">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 items-center">
<div>
<h4 class="text-2xl font-bold text-[#FF6B6B] mb-4">Terminal Recommendation: Warp</h4>
<p class="text-gray-600 mb-6">For a 2025 setup, Warp is the recommended terminal. Built in Rust, it's incredibly fast and rethinks the command line with an IDE-style editor, AI assistance, and collaborative features. It represents the future of developer command-line interaction.</p>
<div class="kpi-card !bg-[#F7FFF7] border-l-4 border-[#4ECDC4]">
<h5 class="text-lg font-semibold text-[#1A535C]">Key Feature: AI Integration</h5>
<p class="text-gray-600 mt-2">Generate commands from natural language and debug errors directly in your terminal, a massive productivity boost over traditional emulators.</p>
</div>
</div>
<div class="chart-container h-80 md:h-96">
<canvas id="terminalComparisonChart"></canvas>
</div>
</div>
</div>
<!-- Gemini API Feature -->
<div class="gemini-feature-card rounded-lg shadow-md p-6 md:p-8 border-2 border-[#4ECDC4]">
<h4 class="text-2xl font-bold text-center text-[#1A535C] mb-4">✨ AI Command Generator</h4>
<p class="text-center text-gray-600 mb-6">Describe what you want to do, and let Gemini generate the command for you.</p>
<div class="max-w-2xl mx-auto">
<div class="flex flex-col sm:flex-row gap-2">
<input type="text" id="command-prompt-input" class="flex-grow p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-[#FF6B6B] focus:outline-none" placeholder="e.g., find files larger than 50MB">
<button id="generate-command-btn" class="bg-[#FF6B6B] text-white font-bold py-3 px-6 rounded-md hover:bg-red-500 transition-colors disabled:bg-gray-400">Generate</button>
</div>
<div id="command-output-container" class="mt-4 hidden">
<p class="font-semibold mb-2">Generated Command:</p>
<div class="relative bg-gray-800 text-white p-4 rounded-md font-mono">
<code id="command-output"></code>
<button id="copy-command-btn" class="absolute top-2 right-2 bg-gray-600 hover:bg-gray-500 text-white text-xs py-1 px-2 rounded">Copy</button>
</div>
</div>
<div id="command-loader" class="text-center mt-4 hidden">
<p class="text-gray-600">Generating command...</p>
</div>
<div id="command-error" class="text-center mt-4 text-red-600 hidden"></div>
</div>
</div>
</section>
<section id="stack" class="mb-12 md:mb-20">
<h3 class="text-3xl font-bold text-center mb-8">Managing the Stack: Runtimes & Packages</h3>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
<h4 class="text-2xl font-bold text-[#FF6B6B] mb-4">Package Manager Showdown</h4>
<p class="text-gray-600 mb-6">While `npm` is the default and `yarn` improved on it, `pnpm` is the technical leader for 2025 due to its superior speed and disk efficiency. It avoids duplicating packages by using a global store and linking files.</p>
<div class="chart-container h-80 md:h-96">
<canvas id="packageManagerChart"></canvas>
</div>
</div>
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
<h4 class="text-2xl font-bold text-[#FF6B6B] mb-4">Node.js Version Management</h4>
<p class="text-gray-600 mb-6">Different projects require different Node.js versions. **NVM (Node Version Manager)** is the industry standard for installing and switching between versions seamlessly, preventing conflicts and ensuring project consistency.</p>
<div class="space-y-4">
<div class="kpi-card !bg-[#F7FFF7] !p-4 text-left">
<h5 class="font-bold text-[#1A535C]">Install LTS Version</h5>
<code class="text-sm text-gray-700">nvm install --lts</code>
</div>
<div class="kpi-card !bg-[#F7FFF7] !p-4 text-left">
<h5 class="font-bold text-[#1A535C]">Use Project-Specific Version</h5>
<p class="text-sm text-gray-500 mb-1">Create a `.nvmrc` file in your project root, then run:</p>
<code class="text-sm text-gray-700">nvm use</code>
</div>
<div class="kpi-card !bg-[#F7FFF7] !p-4 text-left">
<h5 class="font-bold text-[#1A535C]">Set Default Version</h5>
<code class="text-sm text-gray-700">nvm alias default lts/*</code>
</div>
</div>
</div>
</div>
</section>
<section id="ide" class="mb-12 md:mb-20">
<h3 class="text-3xl font-bold text-center mb-8">The Workshop: Visual Studio Code</h3>
<p class="max-w-3xl mx-auto text-center text-lg text-gray-600 mb-8">VS Code is the undisputed industry standard. The key is transforming it from a text editor into a development OS with essential extensions that automate quality control and supercharge your workflow.</p>
<div class="bg-white rounded-lg shadow-md p-6 md:p-8">
<h4 class="text-2xl font-bold text-center text-[#FF6B6B] mb-6">Automated Code Quality Workflow</h4>
<div class="flex flex-col md:flex-row items-center justify-center space-y-4 md:space-y-0 md:space-x-4">
<div class="flowchart-step p-4 rounded-lg text-center shadow">
<span class="text-2xl">📝</span>
<h5 class="font-bold">1. Write Code</h5>
<p class="text-sm">In VS Code</p>
</div>
<div class="flowchart-arrow text-4xl font-light transform md:-rotate-0 rotate-90">&rarr;</div>
<div class="flowchart-step p-4 rounded-lg text-center shadow">
<span class="text-2xl">💾</span>
<h5 class="font-bold">2. On Save: Prettier</h5>
<p class="text-sm">Auto-formats code style</p>
</div>
<div class="flowchart-arrow text-4xl font-light transform md:-rotate-0 rotate-90">&rarr;</div>
<div class="flowchart-step p-4 rounded-lg text-center shadow">
<span class="text-2xl"></span>
<h5 class="font-bold">3. On Save: ESLint</h5>
<p class="text-sm">Auto-fixes linting errors</p>
</div>
<div class="flowchart-arrow text-4xl font-light transform md:-rotate-0 rotate-90">&rarr;</div>
<div class="flowchart-step p-4 rounded-lg text-center shadow bg-[#4ECDC4] !border-[#4ECDC4] text-white">
<span class="text-2xl"></span>
<h5 class="font-bold">4. Result</h5>
<p class="text-sm">Clean, consistent code</p>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mt-8">
<div class="kpi-card">
<h4 class="text-xl font-semibold mt-2 mb-2">Prettier</h4>
<p class="text-gray-600">The opinionated code formatter. Ends all debates on style by automatically reformatting your code on save.</p>
</div>
<div class="kpi-card">
<h4 class="text-xl font-semibold mt-2 mb-2">ESLint</h4>
<p class="text-gray-600">Finds and fixes problems in your JavaScript code, catching bugs and enforcing standards before they hit production.</p>
</div>
<div class="kpi-card">
<h4 class="text-xl font-semibold mt-2 mb-2">GitLens</h4>
<p class="text-gray-600">Supercharges the built-in Git capabilities, providing authorship and history insights directly within your editor.</p>
</div>
</div>
</section>
<section id="auxiliary" class="mb-12 md:mb-20">
<h3 class="text-3xl font-bold text-center mb-8">Essential Auxiliary Tooling</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div class="bg-white rounded-lg shadow-md p-6">
<h4 class="text-xl font-bold text-[#FF6B6B] mb-2">Git GUI Client</h4>
<p class="text-gray-600 mb-4">For a high-level view of your repository. Start with the simplicity of **GitHub Desktop**, and graduate to **Sourcetree** for advanced features like interactive rebase.</p>
<div class="chart-container h-64">
<canvas id="gitGuiChart"></canvas>
</div>
</div>
<div class="bg-white rounded-lg shadow-md p-6">
<h4 class="text-xl font-bold text-[#FF6B6B] mb-2">API Client</h4>
<p class="text-gray-600 mb-4">For testing and debugging APIs. **Bruno** is the top 2025 pick for its local-first, privacy-focused approach. **Postman** remains the standard for enterprise collaboration.</p>
<div class="chart-container h-64">
<canvas id="apiClientChart"></canvas>
</div>
</div>
<div class="bg-white rounded-lg shadow-md p-6">
<h4 class="text-xl font-bold text-[#FF6B6B] mb-2">Containerization</h4>
<p class="text-gray-600 mb-4">**Docker Desktop** provides consistent, isolated environments for databases or backend services, running with native performance on Apple Silicon.</p>
<div class="text-center pt-8">
<span class="text-8xl">🐳</span>
<p class="font-bold text-lg mt-4 text-[#1A535C]">Docker for Mac</p>
<p class="text-gray-500">Native `arm64` performance.</p>
</div>
</div>
</div>
</section>
</main>
<footer class="text-center mt-12 md:mt-20 py-8 border-t border-gray-300">
<p class="text-gray-600">Infographic based on the "Optimal Frontend Development Environment for Apple Silicon (M4) in 2025" report.</p>
<p class="text-sm text-gray-500 mt-2">Built with Tailwind CSS & Chart.js. Enhanced with the Gemini API.</p>
</footer>
</div>
<script>
const energeticPalette = {
red: '#FF6B6B',
teal: '#4ECDC4',
darkTeal: '#1A535C',
yellow: '#FFE66D',
background: '#F7FFF7',
gray: '#6c757d'
};
const tooltipPlugin = {
tooltip: {
callbacks: {
title: function(tooltipItems) {
const item = tooltipItems[0];
let label = item.chart.data.labels[item.dataIndex];
if (Array.isArray(label)) {
return label.join(' ');
} else {
return label;
}
}
}
}
};
function wrapLabel(str, maxWidth) {
if (str.length <= maxWidth) {
return str;
}
const words = str.split(' ');
let lines = [];
let currentLine = words[0];
for (let i = 1; i < words.length; i++) {
if ((currentLine + ' ' + words[i]).length > maxWidth) {
lines.push(currentLine);
currentLine = words[i];
} else {
currentLine += ' ' + words[i];
}
}
lines.push(currentLine);
return lines;
}
new Chart(document.getElementById('terminalComparisonChart'), {
type: 'bar',
data: {
labels: ['Performance', 'AI Integration', 'Modern Text Editing', 'Collaboration', wrapLabel('Out-of-the-box Completions', 16)],
datasets: [{
label: 'Warp (Recommended)',
data: [95, 90, 95, 85, 90],
backgroundColor: energeticPalette.red,
borderColor: energeticPalette.red,
borderWidth: 1
}, {
label: 'iTerm2',
data: [75, 40, 30, 20, 30],
backgroundColor: energeticPalette.teal,
borderColor: energeticPalette.teal,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: {
x: {
beginAtZero: true,
max: 100,
grid: { color: 'rgba(0,0,0,0.05)' }
},
y: {
grid: { display: false }
}
},
plugins: {
...tooltipPlugin,
title: { display: true, text: 'Feature Score (Warp vs. iTerm2)', font: { size: 16 }, color: energeticPalette.darkTeal },
legend: { position: 'bottom' }
}
}
});
new Chart(document.getElementById('packageManagerChart'), {
type: 'radar',
data: {
labels: ['Speed', 'Disk Efficiency', 'Monorepo Support', wrapLabel('Prevents Phantom Dependencies', 16)],
datasets: [{
label: 'pnpm (Recommended)',
data: [95, 100, 90, 100],
backgroundColor: 'rgba(255, 107, 107, 0.4)',
borderColor: energeticPalette.red,
pointBackgroundColor: energeticPalette.red,
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: energeticPalette.red
}, {
label: 'Yarn',
data: [80, 50, 85, 50],
backgroundColor: 'rgba(78, 205, 196, 0.4)',
borderColor: energeticPalette.teal,
pointBackgroundColor: energeticPalette.teal,
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: energeticPalette.teal
}, {
label: 'npm',
data: [60, 20, 70, 40],
backgroundColor: 'rgba(255, 230, 109, 0.4)',
borderColor: energeticPalette.yellow,
pointBackgroundColor: energeticPalette.yellow,
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: energeticPalette.yellow
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
r: {
angleLines: { color: 'rgba(0,0,0,0.1)' },
grid: { color: 'rgba(0,0,0,0.1)' },
pointLabels: { font: { size: 12 }, color: energeticPalette.darkTeal },
ticks: { backdropColor: 'transparent', color: energeticPalette.gray },
suggestedMin: 0,
suggestedMax: 100
}
},
plugins: {
...tooltipPlugin,
title: { display: true, text: 'Relative Strengths', font: { size: 16 }, color: energeticPalette.darkTeal },
legend: { position: 'bottom' }
}
}
});
new Chart(document.getElementById('gitGuiChart'), {
type: 'doughnut',
data: {
labels: ['Beginner Friendly (GitHub Desktop)', 'Advanced Features (Sourcetree)'],
datasets: [{
data: [65, 35],
backgroundColor: [energeticPalette.teal, energeticPalette.red],
borderColor: '#F0F4F8',
borderWidth: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
...tooltipPlugin,
title: { display: true, text: 'Recommended Usage Focus', font: { size: 14 }, color: energeticPalette.darkTeal },
legend: { position: 'bottom' }
}
}
});
new Chart(document.getElementById('apiClientChart'), {
type: 'pie',
data: {
labels: ['Local & Privacy-Focused (Bruno)', 'Enterprise & Collaboration (Postman)'],
datasets: [{
data: [55, 45],
backgroundColor: [energeticPalette.red, energeticPalette.yellow],
borderColor: '#F0F4F8',
borderWidth: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
...tooltipPlugin,
title: { display: true, text: 'Choosing Based on Need', font: { size: 14 }, color: energeticPalette.darkTeal },
legend: { position: 'bottom' }
}
}
});
// Gemini API Feature Logic
const commandPromptInput = document.getElementById('command-prompt-input');
const generateBtn = document.getElementById('generate-command-btn');
const commandOutputContainer = document.getElementById('command-output-container');
const commandOutput = document.getElementById('command-output');
const copyBtn = document.getElementById('copy-command-btn');
const loader = document.getElementById('command-loader');
const errorContainer = document.getElementById('command-error');
const apiKey = ""; // API key will be automatically provided by the environment.
const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`;
async function generateCommand() {
const userInput = commandPromptInput.value.trim();
if (!userInput) {
errorContainer.textContent = 'Please enter a description.';
errorContainer.classList.remove('hidden');
return;
}
generateBtn.disabled = true;
loader.classList.remove('hidden');
commandOutputContainer.classList.add('hidden');
errorContainer.classList.add('hidden');
const prompt = `You are an expert command-line assistant for macOS (zsh/bash). Based on the following user request, provide only the single, most appropriate terminal command. Do not add any explanation, preamble, or markdown formatting like \`\`\`bash. Just the raw command text. User request: "${userInput}"`;
const payload = {
contents: [{
parts: [{ text: prompt }]
}]
};
try {
const response = await fetchWithRetry(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`API error: ${response.statusText}`);
}
const result = await response.json();
const text = result?.candidates?.[0]?.content?.parts?.[0]?.text;
if (text) {
commandOutput.textContent = text.trim();
commandOutputContainer.classList.remove('hidden');
} else {
throw new Error('Failed to generate command. The model returned an empty response.');
}
} catch (err) {
errorContainer.textContent = `Error: ${err.message}`;
errorContainer.classList.remove('hidden');
} finally {
generateBtn.disabled = false;
loader.classList.add('hidden');
}
}
async function fetchWithRetry(url, options, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (response.status !== 429) { // Not a rate limiting error
return response;
}
} catch (error) {
if (i === retries - 1) throw error;
}
await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i)));
}
throw new Error('Max retries reached');
}
function copyToClipboard() {
const textToCopy = commandOutput.textContent;
const textArea = document.createElement('textarea');
textArea.value = textToCopy;
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
copyBtn.textContent = 'Copied!';
setTimeout(() => { copyBtn.textContent = 'Copy'; }, 2000);
} catch (err) {
console.error('Failed to copy text: ', err);
copyBtn.textContent = 'Failed!';
setTimeout(() => { copyBtn.textContent = 'Copy'; }, 2000);
}
document.body.removeChild(textArea);
}
generateBtn.addEventListener('click', generateCommand);
copyBtn.addEventListener('click', copyToClipboard);
commandPromptInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
generateCommand();
}
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment