Skip to content
AlSh007Public

About

Chrome extension that pushes your accepted LeetCode solutions to GitHub, with optional AI complexity analysis and progressive hints (Groq or OpenAI).

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

LeetCode to GitHub Extension

Automatically push your accepted LeetCode solutions to GitHub with complete formatting preservation!

A Chrome/Chromium (Manifest V3) extension: submit on LeetCode, and once the result is Accepted it commits your solution plus a generated README to a GitHub repo of your choice, one folder per problem.

🎬 Demo

leetcode_extension_v2_ai.mp4

The UI shown in the video is an illustrative recreation, not a screen recording.

✨ Features

  • πŸš€ Automatic Push - Solutions are pushed to GitHub automatically when accepted
  • 🎨 Perfect Formatting - Preserves Python indentation and all code formatting
  • πŸ“ Rich Metadata - Includes problem description, difficulty, tags, and acceptance rate
  • πŸ”„ Complete Capture - Reads the whole Monaco buffer, not just the lines on screen
  • πŸ›‘ Fails Loudly - Refuses to push rather than committing a partial file
  • 🐍 Python-Optimized - Special validation for Python indentation and structure

πŸ“‹ Table of Contents

πŸ”§ Installation

1. Create GitHub Personal Access Token

  1. Go to: GitHub Settings β†’ Tokens
  2. Click "Generate new token" β†’ "Generate new token (classic)"
  3. Give it a name: LeetCode Extension
  4. Select scope: βœ… repo (needed for private repos; public_repo is enough if your solutions repo is public). A fine-grained token with Contents: Read and write on that one repo also works, since the extension only uses GitHub's repository contents API.
  5. Click "Generate token"
  6. COPY THE TOKEN immediately (you won't see it again!)

2. Install the Extension

Create the (empty or existing) repository you want the solutions in first; the extension does not create it.

  1. Open Chrome (or any Chromium browser) and navigate to: chrome://extensions/
  2. Enable "Developer mode" (toggle in top-right corner)
  3. Click "Load unpacked"
  4. Select the leetpush folder
  5. The extension should appear in your extensions list

3. Configure the Extension

  1. Click the extension icon in Chrome toolbar (puzzle piece icon)
  2. Enter your details (they are saved with the Save button):
    • Repository: your-username/repo-name (e.g., john/leetcode-solutions)
    • Token: Paste your GitHub Personal Access Token
    • AI provider + key (optional): pick Groq (free, via console.groq.com) or OpenAI (via platform.openai.com) and paste that provider's key to enable the AI features below. Leave both blank and everything else still works exactly the same.
  3. Click "Save"

βœ… You're all set! The extension is now ready to use.

🎯 Usage

Basic Workflow

  1. Navigate to any LeetCode problem (e.g., https://leetcode.com/problems/two-sum/)
  2. Write your solution in the code editor
  3. Click Submit button (a plain "Run" does nothing)
  4. Wait for "Accepted" result
  5. Done! Check your GitHub repo - the solution is automatically pushed

Monitoring (Optional)

For debugging or to see what's happening:

  1. Open DevTools (press F12)
  2. Go to Console tab
  3. Look for messages starting with [LeetCode Extension]

Expected console output:

[LeetCode Extension] πŸš€ Submit button clicked!
[LeetCode Extension] Code Extraction Summary: {method: "monaco-model-bridge", lines: 15, editorReportedLines: 15, ...}
[LeetCode Extension] Accepted status detected
[LeetCode Extension] Attempting to push to GitHub...
[LeetCode Extension] GitHub push accepted, processing in background...

The push itself runs in the background service worker, so the final confirmation (and any GitHub error) shows up in its console, not the page's - see Troubleshooting:

[LeetCode Extension BG] βœ… GitHub upsert completed successfully!

πŸ“¦ What Gets Pushed?

For each accepted solution, the extension creates a folder in your repository:

Make_Sum_Divisible_by_P/
β”œβ”€β”€ Make_Sum_Divisible_by_P.py
└── README.md

The folder and file names come from the problem title in the page's tab title, with spaces replaced by underscores and characters GitHub paths dislike replaced by _. The extension is picked from the editor's language (.py, .java, .cpp, .js, .ts, .go, .rs, ...). Each push makes two commits through the GitHub API: Add/update README for <folder> and Add/update solution <file>.

Solution File

Your complete code with:

  • βœ… Perfect indentation (especially important for Python!)
  • βœ… All lines in correct order
  • βœ… Proper file extension based on language

README.md

Auto-generated with:

  • Problem title and description
  • Difficulty level (Easy/Medium/Hard)
  • Tags (Array, Dynamic Programming, etc.)
  • Acceptance rate
  • Link to original LeetCode problem
  • Name of the solution file just pushed (the README is regenerated on each push, so it lists the latest file rather than accumulating every language)

Example README:

# Make Sum Divisible by P

Given an array of positive integers nums, remove the smallest subarray...

---

## Metadata

- Language: Python
- Difficulty: Medium
- Acceptance: 25.4%
- Tags: Array, Hash Table, Prefix Sum
- URL: https://leetcode.com/problems/make-sum-divisible-by-p/

## Files

- Make_Sum_Divisible_by_P.py

πŸ€– AI Features (optional)

A small floating spark-icon button ("LeetCode AI Assistant") appears on every LeetCode problem page. Click it to expand a panel with two on-demand tools, powered by whichever provider you picked in the popup - Groq (free tier) or OpenAI:

  • Analyze Complexity β€” reads whatever code is currently in the editor (draft or accepted, via the same Monaco-bridge extraction used for pushes) and returns its time and space complexity in Big-O notation with a short justification.
  • Hint β€” gives a progressive hint for the current problem. Each click escalates: level 1 is a conceptual nudge, level 2 describes the general approach, level 3 adds detail on data structures and edge cases. It's capped at level 3 and never returns code or pseudocode, so it can't spoil the full solution. The level resets automatically when you move to a different problem.

This is entirely optional. If no key is configured for the selected provider, clicking either button just shows "<Provider> API key not set" in the panel β€” GitHub pushing, code extraction, and everything else keep working normally regardless.

πŸ”’ Privacy & Security

  • Your repo name, GitHub token and (optional) AI keys are saved in chrome.storage.sync. That means they are not encrypted by the extension and, if Chrome sync is on, they sync with your Google account across your signed-in browsers. Use a token limited to the one repo (or the minimum scope above) and revoke it if you stop using the extension.
  • The token is only sent to api.github.com; AI keys only to their own provider. Host permissions are limited to leetcode.com, api.github.com, api.groq.com and api.openai.com.
  • The AI features, if enabled, send the problem text and your current code to the selected provider. Nothing is sent to any provider if you leave the keys blank.
  • Never commit a token to this repo (pat.txt and *.pat are git-ignored).

πŸ› Troubleshooting

Code Not Pushing to GitHub

Check the Service Worker console:

  1. Go to chrome://extensions/
  2. Find "LeetCode to GitHub" extension
  3. Click "service worker" (blue link)
  4. Look for error messages starting with [LeetCode Extension BG]

Common issues:

  • ❌ "Repo or token not set" (page console) β†’ Configure extension via popup
  • ❌ GitHub PUT/GET failed (401) β†’ Invalid/expired token, create a new one
  • ❌ GitHub PUT/GET failed (404) β†’ Repository doesn't exist, wrong owner/repo format, or the token can't see it
  • ❌ "No pending submission found" β†’ Must click Submit on this page BEFORE the result is accepted (the Submit click is remembered for 30 seconds)

Only Part of the Code Was Pushed

This was a real bug, fixed in v1.1. Monaco only keeps DOM nodes for the lines currently scrolled into view, and the old extractor scraped those nodes β€” so a file longer than the editor viewport was pushed truncated. v1.1 reads the editor's text model instead, via a MAIN-world bridge, and never scrapes the DOM.

If you are on v1.1 and nothing pushes at all, look for:

[LeetCode Extension] ❌ Could not read the editor buffer: <reason>
Reason Meaning
bridge-not-installed monaco-bridge.js did not load β€” reload the extension and hard-refresh the page
monaco-not-loaded The editor had not mounted yet; resubmit
no-model / empty-model No editor buffer found, or it was blank

The extension deliberately pushes nothing in these cases rather than committing a partial file, because a truncated push looks like a successful one.

Missing Indentation

If Python code has no indentation, check console for:

[LeetCode Extension] ⚠️ WARNING: Python code lacks indentation - may be corrupted!

Solution: Reload the extension:

  1. Go to chrome://extensions/
  2. Click the reload icon ↻ on "LeetCode to GitHub"
  3. Refresh your LeetCode page (Ctrl+Shift+R)

Language Detected as "Comment"

If you see:

[LeetCode Extension] ⚠️ Could not detect language, defaulting to py (Python)

The extension will use .py as default. This is fine if you're coding in Python, otherwise the file gets the wrong extension.

Nothing Happens

Checklist:

  • βœ… Extension is enabled in chrome://extensions/
  • βœ… You clicked Submit button (not just "Run")
  • βœ… Solution got "Accepted" status
  • βœ… Repository and token are configured in extension popup
  • βœ… GitHub repository exists and the token can write to it (see the service worker console for the exact GitHub error)

πŸ”¬ How It Works

Code Extraction

There is one extraction path, and it reads Monaco's text model β€” the editor's own source of truth. It is complete and correctly ordered by construction, regardless of scroll position.

Getting at it takes a bridge. Chrome runs content scripts in an isolated world: they share the page's DOM but get their own JavaScript globals, so content.js cannot see the page's monaco object (nor expando properties that page scripts set on DOM elements). So:

  • monaco-bridge.js is declared with "world": "MAIN" and runs in the page's own context, where monaco is reachable. It listens for a DOM event and writes a JSON snapshot of the model into an inert <script type="application/json"> node.
  • content.js (isolated world) dispatches that event and reads the node. DOM event dispatch is synchronous and crosses the world boundary, so the snapshot is already fresh when dispatchEvent() returns β€” extraction stays a plain synchronous call.

When several Monaco instances are mounted (solution editor, diff views, playground), the bridge prefers a model attached to a visible editor, then the largest.

There is no DOM-scraping fallback, by design. Scraping .view-line nodes only ever yields the lines on screen; committing that is worse than committing nothing, because a truncated file looks like a successful push.

Validation

  • Line Count Cross-Check: Warns if the snapshot disagrees with the model
  • Python Validation: Warns if the code has no indentation or looks suspiciously short
  • Empty Check: Aborts the push if the code or problem title is empty

Push Process

  1. Submit Click: Captures problem metadata
  2. Accepted Detection: Watches the page for an "Accepted" result and reads the Monaco model
  3. Validation: Warns (console only) on a line-count mismatch or Python code with no indentation; refuses to push if the buffer can't be read or is empty
  4. GitHub API: The background service worker creates/updates the solution and README via the contents API (retrying on sha conflicts)
  5. Confirmation: Logs success or the GitHub error in the service worker console

πŸ“ Notes

  • Supported Languages: Python, Java, C/C++, C#, JavaScript, TypeScript, Go, Rust, Kotlin, Swift, Ruby, PHP, Scala, Dart, SQL dialects, Bash, Racket, Erlang and Elixir (the languages the extension recognises and maps to a file extension)
  • File Naming: Problem title with underscores (e.g., Two_Sum.py)
  • Updates: Re-submitting updates the existing file (no duplicates)
  • Privacy: see Privacy & Security

⚠️ Limitations

  • Only https://leetcode.com/* is supported (not leetcode.cn).
  • Pushes only happen for submissions you click Submit on in the current page session; an old accepted submission you merely open will not be pushed.
  • Problem metadata (difficulty, tags, acceptance, description) is read from LeetCode's page markup with best-effort selectors, so it can come back empty or wrong when LeetCode changes its frontend. The code capture does not depend on those selectors.
  • GitHub failures are logged to the service worker console only; there is no in-page notification.
  • The extension is loaded unpacked; it is not published on the Chrome Web Store.

πŸ§ͺ Tests

node test/bridge.test.js

Needs only Node.js, no packages. The tests load monaco-bridge.js and content.js into separate JS contexts sharing one DOM, mirroring Chrome's isolated/MAIN world split, and assert that a 200-line file rendered 20 lines at a time is captured in full. They also cover the hint-level cap and that a failing AI panel doesn't break extraction.

🀝 Contributing

Found a bug or have a suggestion? Feel free to:

  • Report issues
  • Submit pull requests
  • Suggest improvements

πŸ“„ License

This extension is provided as-is for personal use.


Happy Coding! πŸš€

Made with ❀️ for LeetCode enthusiasts

About

Chrome extension that pushes your accepted LeetCode solutions to GitHub, with optional AI complexity analysis and progressive hints (Groq or OpenAI).

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages