diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 0000000..348557a --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,44 @@ +name: Deploy website to GitHub Pages + +on: + push: + branches: + - master + - main + workflow_dispatch: {} + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./website + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 2198e29..7dab9c9 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ coverage/ # Benchmarks criterion/ + +# JS tooling +node_modules/ diff --git a/website-screenshot.png b/website-screenshot.png new file mode 100644 index 0000000..857a6f5 Binary files /dev/null and b/website-screenshot.png differ diff --git a/website/assets/styles.css b/website/assets/styles.css new file mode 100644 index 0000000..92c5c07 --- /dev/null +++ b/website/assets/styles.css @@ -0,0 +1,283 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); + +:root { + --bg: #0b1221; + --card: #111a2f; + --accent: #4f46e5; + --accent-2: #22d3ee; + --text: #e5e7eb; + --muted: #9ca3af; + --border: #1f2937; + --success: #10b981; + --warning: #fbbf24; + --shadow: 0 20px 60px rgba(0, 0, 0, 0.35); +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + background: radial-gradient(circle at 10% 20%, rgba(79, 70, 229, 0.08), transparent 25%), + radial-gradient(circle at 90% 10%, rgba(34, 211, 238, 0.08), transparent 25%), + var(--bg); + color: var(--text); + line-height: 1.6; +} + +a { + color: var(--accent-2); + text-decoration: none; +} + +a:hover { + color: #67e8f9; +} + +header { + position: sticky; + top: 0; + z-index: 10; + backdrop-filter: blur(12px); + background: rgba(11, 18, 33, 0.7); + border-bottom: 1px solid var(--border); +} + +.nav { + max-width: 1100px; + margin: 0 auto; + padding: 16px 24px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.brand { + display: flex; + align-items: center; + gap: 10px; + font-weight: 700; + letter-spacing: -0.02em; + color: var(--text); +} + +.nav-links { + display: flex; + gap: 18px; + font-weight: 500; +} + +.btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 18px; + border-radius: 999px; + border: 1px solid transparent; + background: var(--accent); + color: white; + font-weight: 600; + box-shadow: var(--shadow); + transition: transform 150ms ease, box-shadow 150ms ease, background 150ms ease; +} + +.btn.secondary { + background: transparent; + border-color: var(--border); + color: var(--text); + box-shadow: none; +} + +.btn:hover { + transform: translateY(-1px); + box-shadow: 0 14px 40px rgba(79, 70, 229, 0.25); +} + +.hero { + max-width: 1100px; + margin: 0 auto; + padding: 80px 24px 60px; + display: grid; + grid-template-columns: 1.1fr 0.9fr; + gap: 28px; + align-items: center; +} + +.pill { + display: inline-flex; + align-items: center; + gap: 10px; + padding: 8px 14px; + border-radius: 999px; + background: rgba(34, 211, 238, 0.12); + color: #a5f3fc; + font-weight: 600; + border: 1px solid rgba(34, 211, 238, 0.35); +} + +h1 { + margin: 18px 0 12px; + font-size: clamp(34px, 4vw, 48px); + letter-spacing: -0.03em; +} + +.subtitle { + color: var(--muted); + font-size: 18px; + margin-bottom: 24px; +} + +.cta-row { + display: flex; + gap: 12px; + flex-wrap: wrap; +} + +.hero-card { + background: linear-gradient(135deg, rgba(79, 70, 229, 0.18), rgba(34, 211, 238, 0.18)); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 16px; + padding: 20px; + box-shadow: var(--shadow); +} + +.metrics { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: 12px; + margin-top: 16px; +} + +.metric { + background: rgba(17, 26, 47, 0.9); + border: 1px solid var(--border); + padding: 14px; + border-radius: 12px; +} + +.metric .value { + font-size: 24px; + font-weight: 700; +} + +.section { + max-width: 1100px; + margin: 0 auto; + padding: 40px 24px 20px; +} + +.section h2 { + margin: 0 0 12px; + font-size: 28px; +} + +.cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 16px; +} + +.card { + background: var(--card); + border: 1px solid var(--border); + border-radius: 16px; + padding: 18px; + box-shadow: var(--shadow); +} + +.card h3 { + margin-top: 0; + margin-bottom: 8px; +} + +.code { + background: #0a0f1c; + border: 1px solid var(--border); + border-radius: 12px; + padding: 12px; + font-family: 'Fira Code', 'SFMono-Regular', Menlo, Monaco, Consolas, monospace; + color: #cbd5e1; + position: relative; +} + +.code button { + position: absolute; + top: 10px; + right: 10px; + background: rgba(255, 255, 255, 0.08); + border: 1px solid var(--border); + color: var(--text); + padding: 6px 10px; + border-radius: 8px; + cursor: pointer; + font-size: 12px; +} + +.grid-2 { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 18px; +} + +.table { + width: 100%; + border-collapse: collapse; + margin-top: 12px; +} + +.table th, +.table td { + border: 1px solid var(--border); + padding: 12px; + text-align: left; +} + +.table th { + background: rgba(255, 255, 255, 0.04); +} + +.badge { + display: inline-block; + padding: 6px 10px; + border-radius: 999px; + font-size: 12px; + background: rgba(79, 70, 229, 0.15); + border: 1px solid rgba(79, 70, 229, 0.4); + color: #c7d2fe; + font-weight: 600; +} + +.footer { + max-width: 1100px; + margin: 20px auto; + padding: 16px 24px 40px; + color: var(--muted); + border-top: 1px solid var(--border); +} + +.banner { + background: linear-gradient(135deg, rgba(79, 70, 229, 0.25), rgba(34, 211, 238, 0.25)); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 16px; + padding: 18px; + box-shadow: var(--shadow); +} + +@media (max-width: 900px) { + .hero { + grid-template-columns: 1fr; + padding-top: 60px; + } + + .nav { + flex-direction: column; + gap: 10px; + } + + .nav-links { + flex-wrap: wrap; + justify-content: center; + } +} diff --git a/website/docs/index.md b/website/docs/index.md new file mode 100644 index 0000000..01eab41 --- /dev/null +++ b/website/docs/index.md @@ -0,0 +1,12 @@ +# oops Documentation Hub + +Welcome to the extended documentation for **oops**, the blazingly fast command-line typo corrector. Use the links below to dive into detailed guides. + +- [Installation](../docs/guides/installation.md) +- [Configuration](../docs/guides/configuration.md) +- [Creating Rules](../docs/guides/creating-rules.md) +- [Migration from thefuck](../docs/guides/migration-from-thefuck.md) +- [Rule Catalog](../docs/guides/rules.md) +- [Architecture Overview](../docs/architecture/overview.md) +- [Shell Integration](../docs/architecture/shell-integration.md) +- [Release Workflow](../docs/releases/QUICK_RELEASE_GUIDE.md) diff --git a/website/index.html b/website/index.html new file mode 100644 index 0000000..cb163ca --- /dev/null +++ b/website/index.html @@ -0,0 +1,255 @@ + + + + + + oops • Blazingly fast command-line typo fixer + + + + +
+ +
+ +
+
+
+
⚡️ Sub-50ms startup • 175+ rules • Single binary
+

Fix your last typo in one keypress.

+

+ oops is a blazingly fast CLI that rewrites your last failed command and executes it instantly. + Works on macOS, Linux, and Windows with Bash, Zsh, Fish, PowerShell, and Tcsh. +

+ +
+
+
~30ms
+
Cold start
+
+
+
175+
+
Rules included
+
+
+
6
+
Shells supported
+
+
+
1
+
Static binary
+
+
+
+
+
+ +
# macOS / Linux (Homebrew)
+brew install animeshkundu/tap/oops
+eval "$(oops --alias)"
+
+
+ +
# Linux (binary)
+curl -LO https://github.com/animeshkundu/oops/releases/latest/download/oops-linux-x86_64
+chmod +x oops-linux-x86_64 && sudo mv oops-linux-x86_64 /usr/local/bin/oops
+eval "$(oops --alias)"
+
+
+ +
# Windows (PowerShell)
+Invoke-WebRequest -Uri "https://github.com/animeshkundu/oops/releases/latest/download/oops-windows-x86_64.exe" -OutFile "$env:USERPROFILE\\bin\\oops.exe"
+[Environment]::SetEnvironmentVariable("Path", $env:Path + ";$env:USERPROFILE\\bin", "User")
+Invoke-Expression (oops --alias | Out-String)
+
+
+
+ +
+

Why switch from thefuck?

+
+
+

Blazing fast

+

Rust binary with <50ms startup. No Python runtime, no cold boot penalty.

+
+
+

Drop-in compatible

+

Same environment variables as thefuck. Use TF_ALIAS=fuck to keep muscle memory.

+
+
+

Huge rule set

+

175+ curated rules covering git, package managers, system ops, containers, and cloud CLIs.

+
+
+

Single static binary

+

Ships as one file for macOS, Linux, Windows. Works in CI, containers, and air‑gapped hosts.

+
+
+ +
+ +
+

Install in one command

+

Pick your platform and paste. Then add shell alias.

+
+
+

macOS / Linux

+
brew install animeshkundu/tap/oops
+eval "$(oops --alias)"
+
+
+

Linux binary

+
curl -LO https://github.com/animeshkundu/oops/releases/latest/download/oops-linux-x86_64
+chmod +x oops-linux-x86_64 && sudo mv oops-linux-x86_64 /usr/local/bin/oops
+eval "$(oops --alias)"
+
+
+

Windows

+
Invoke-WebRequest -Uri "https://github.com/animeshkundu/oops/releases/latest/download/oops-windows-x86_64.exe" -OutFile "$env:USERPROFILE\\bin\\oops.exe"
+[Environment]::SetEnvironmentVariable("Path", $env:Path + ";$env:USERPROFILE\\bin", "User")
+Invoke-Expression (oops --alias | Out-String)
+
+
+
+ +
+

What makes oops delightful

+
+
+ Shells +

5 shells, zero friction

+

Bash, Zsh, Fish, PowerShell, Tcsh. Add eval \"$(oops --alias)\" once and forget it.

+
+
+ UX +

Instant suggestions

+

Type oops after an error to see ranked fixes with arrow-key navigation, or oops -y to auto-run.

+
+
+ Compatibility +

thefuck friendly

+

Environment variables preserved. Alias to fuck with TF_ALIAS=fuck oops --alias.

+
+
+ Performance +

Built for speed

+

Precompiled rules, no runtime deps, optimized fuzzy matching, and static binaries.

+
+
+
+ +
+

Coverage at a glance

+

Highlights from 175+ rules. See full catalog in rules guide.

+
+
+

Git

+
    +
  • Unknown command typos (push/status/checkout)
  • +
  • Set upstream on first push
  • +
  • Add missing files before commit
  • +
  • Fix branch name typos
  • +
+
+
+

Package managers

+
    +
  • brew, apt, yum/dnf, pacman, cargo, npm, pip
  • +
  • Missing sudo, wrong subcommands, typos
  • +
+
+
+

System & shells

+
    +
  • Permission denied → add sudo
  • +
  • cd to missing dir → create it
  • +
  • chmod +x for scripts
  • +
+
+
+

Dev & cloud

+
    +
  • Docker, Kubernetes, Terraform, Maven/Gradle
  • +
  • AWS/Azure CLI command fixes
  • +
+
+
+
+ +
+

Docs & Migration

+
+
+

Full documentation

+

Installation, configuration, shell setup, and every rule explained.

+ Browse docs +
+
+

Migrate from thefuck

+

Keep aliases, env vars, and habits. Learn the differences and why oops is faster.

+ Read migration guide +
+
+

Add or port a rule

+

Step-by-step guide to contribute new corrections with tests.

+ Create rules +
+
+
+ +
+

Community & Support

+
+
+

GitHub Discussions

+

Request rules, share tips, and get help.

+ Join discussions +
+
+

Open an Issue

+

Found a bug or a missing rule? Let us know.

+ Report issue +
+
+

Star the repo

+

Help others discover oops and track releases.

+ Star on GitHub +
+
+
+
+ + + + + +