leet2local 0.1.0__tar.gz

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.
Files changed (34) hide show
  1. leet2local-0.1.0/.gitignore +29 -0
  2. leet2local-0.1.0/CHANGELOG.md +23 -0
  3. leet2local-0.1.0/LICENSE +21 -0
  4. leet2local-0.1.0/PKG-INFO +318 -0
  5. leet2local-0.1.0/README.md +279 -0
  6. leet2local-0.1.0/leet2local/__init__.py +1 -0
  7. leet2local-0.1.0/leet2local/auth.py +197 -0
  8. leet2local-0.1.0/leet2local/cli.py +365 -0
  9. leet2local-0.1.0/leet2local/config.py +119 -0
  10. leet2local-0.1.0/leet2local/data/.gitkeep +0 -0
  11. leet2local-0.1.0/leet2local/data/slug_map.json +3964 -0
  12. leet2local-0.1.0/leet2local/fetcher.py +318 -0
  13. leet2local-0.1.0/leet2local/html_parser.py +50 -0
  14. leet2local-0.1.0/leet2local/models.py +71 -0
  15. leet2local-0.1.0/leet2local/queries.py +39 -0
  16. leet2local-0.1.0/leet2local/rate_limiter.py +29 -0
  17. leet2local-0.1.0/leet2local/runner.py +71 -0
  18. leet2local-0.1.0/leet2local/runners/__init__.py +0 -0
  19. leet2local-0.1.0/leet2local/runners/base.py +106 -0
  20. leet2local-0.1.0/leet2local/runners/cpp_runner.py +122 -0
  21. leet2local-0.1.0/leet2local/runners/java_runner.py +129 -0
  22. leet2local-0.1.0/leet2local/runners/javascript_runner.py +66 -0
  23. leet2local-0.1.0/leet2local/runners/python_runner.py +104 -0
  24. leet2local-0.1.0/leet2local/submitter.py +117 -0
  25. leet2local-0.1.0/leet2local/templates/__init__.py +0 -0
  26. leet2local-0.1.0/leet2local/templates/test_runner.cpp.j2 +28 -0
  27. leet2local-0.1.0/leet2local/templates/test_runner.java.j2 +30 -0
  28. leet2local-0.1.0/leet2local/templates/test_runner.js.j2 +19 -0
  29. leet2local-0.1.0/leet2local/templates/test_runner.py.j2 +84 -0
  30. leet2local-0.1.0/pyproject.toml +91 -0
  31. leet2local-0.1.0/templates/test_runner.cpp.j2 +28 -0
  32. leet2local-0.1.0/templates/test_runner.java.j2 +30 -0
  33. leet2local-0.1.0/templates/test_runner.js.j2 +19 -0
  34. leet2local-0.1.0/templates/test_runner.py.j2 +84 -0
@@ -0,0 +1,29 @@
1
+ # Generated problem directories
2
+ leetcode/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.pyo
8
+ *.pyd
9
+ .Python
10
+ *.egg-info/
11
+ dist/
12
+ build/
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # Config (may contain paths; credentials are in keyring, not here)
18
+ .leet2local.toml
19
+
20
+ # Temp harness files
21
+ /tmp/
22
+
23
+ # IDE
24
+ .vscode/settings.json
25
+ .idea/
26
+
27
+ # OS
28
+ .DS_Store
29
+ Thumbs.db
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2024-06-19
9
+
10
+ ### Added
11
+ - `lc fetch <number>` — fetch any LeetCode problem by number; creates a local directory
12
+ with `question.md`, `solution.<ext>`, `test_cases.json`, and `.meta.json`
13
+ - `lc run <number>` — run solution locally against sample test cases using a Jinja2
14
+ test harness subprocess; supports Python, JavaScript, C++, and Java
15
+ - `lc submit <number>` — submit solution to LeetCode and poll for full results including
16
+ runtime percentile, memory percentile, and hidden test count
17
+ - `lc login` — store LeetCode session credentials securely in the OS native keychain
18
+ (Windows Credential Manager / macOS Keychain / libsecret on Linux)
19
+ - `lc config` — view and update TOML configuration; generate `.vscode/tasks.json`
20
+ - Bundled slug fallback map (3963 entries) for offline problem-number-to-slug resolution
21
+ - Multi-language support: Python 3, JavaScript (Node.js), C++ (g++), Java (JDK)
22
+ - Exponential backoff retry on LeetCode rate-limit responses (HTTP 429)
23
+ - Rate limiter with configurable max retries via `.leet2local.toml`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Dhinesh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: leet2local
3
+ Version: 0.1.0
4
+ Summary: Solve LeetCode problems in your local IDE
5
+ Project-URL: Homepage, https://github.com/dhineshtheprogrammer/leet2local
6
+ Project-URL: Repository, https://github.com/dhineshtheprogrammer/leet2local.git
7
+ Project-URL: Bug Tracker, https://github.com/dhineshtheprogrammer/leet2local/issues
8
+ Project-URL: Changelog, https://github.com/dhineshtheprogrammer/leet2local/blob/main/CHANGELOG.md
9
+ Author-email: Dhinesh <dhineshpro33@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,coding-challenges,competitive-programming,interview-prep,leetcode
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Testing
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: beautifulsoup4>=4.12
26
+ Requires-Dist: httpx>=0.28
27
+ Requires-Dist: jinja2>=3.1
28
+ Requires-Dist: keyring>=25.0
29
+ Requires-Dist: markdownify>=0.13
30
+ Requires-Dist: pydantic>=2.7
31
+ Requires-Dist: tenacity>=8.3
32
+ Requires-Dist: tomli-w>=1.0
33
+ Requires-Dist: typer[all]>=0.12
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
36
+ Requires-Dist: pytest>=8.2; extra == 'dev'
37
+ Requires-Dist: ruff>=0.4; extra == 'dev'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # Leet2Local
41
+
42
+ [![PyPI](https://img.shields.io/pypi/v/leet2local)](https://pypi.org/project/leet2local/)
43
+ [![Python](https://img.shields.io/pypi/pyversions/leet2local)](https://pypi.org/project/leet2local/)
44
+ [![CI](https://github.com/dhineshtheprogrammer/leet2local/actions/workflows/ci.yml/badge.svg)](https://github.com/dhineshtheprogrammer/leet2local/actions/workflows/ci.yml)
45
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
46
+
47
+ A CLI tool that brings LeetCode problems into your local IDE. Fetch problem descriptions, solve in your editor, run tests locally, and submit directly to LeetCode — all from the terminal.
48
+
49
+ ```
50
+ lc fetch 1 --lang python
51
+ lc run 1
52
+ lc submit 1
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Features
58
+
59
+ - **Fetch any problem** by number — creates a local directory with the description, code stub, and sample test cases
60
+ - **Run locally** — executes your solution against sample test cases without touching LeetCode servers
61
+ - **Submit remotely** — sends your code to LeetCode and polls for full results including hidden test cases, runtime, and memory percentile
62
+ - **Multi-language** — Python, JavaScript, C++, and Java
63
+ - **VS Code integration** — generates `tasks.json` for keyboard-shortcut access to all commands
64
+ - **Secure auth** — session cookies stored in OS native keychain (Windows Credential Manager / macOS Keychain)
65
+
66
+ ---
67
+
68
+ ## Installation
69
+
70
+ **Requirements:** Python 3.11+
71
+
72
+ ```bash
73
+ pip install leet2local
74
+ ```
75
+
76
+ Or install from source:
77
+
78
+ ```bash
79
+ git clone https://github.com/dhineshtheprogrammer/leet2local.git
80
+ cd Leet2Local
81
+ pip install -e .
82
+ ```
83
+
84
+ For development (includes pytest and ruff):
85
+
86
+ ```bash
87
+ pip install -e ".[dev]"
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Quick Start
93
+
94
+ ### 1. Log in
95
+
96
+ Get your session cookies from your browser after logging in to leetcode.com:
97
+
98
+ 1. Open DevTools → Application → Cookies → `leetcode.com`
99
+ 2. Copy `LEETCODE_SESSION` and `csrftoken`
100
+
101
+ ```bash
102
+ lc login
103
+ ```
104
+
105
+ ### 2. Fetch a problem
106
+
107
+ ```bash
108
+ lc fetch 1 # Two Sum, defaults to Python
109
+ lc fetch 42 --lang cpp # Trapping Rain Water in C++
110
+ ```
111
+
112
+ This creates:
113
+
114
+ ```
115
+ ./leetcode/1-two-sum/
116
+ ├── question.md # Problem description in Markdown
117
+ ├── solution.py # Code stub from LeetCode
118
+ └── test_cases.json # Sample inputs and expected outputs
119
+ ```
120
+
121
+ ### 3. Write your solution
122
+
123
+ Open `solution.py` in your editor and implement the function.
124
+
125
+ ### 4. Run locally
126
+
127
+ ```bash
128
+ lc run 1
129
+ ```
130
+
131
+ ```
132
+ ┌─ Test Results ──────────────────────────────────┐
133
+ │ # │ Status │ Details │
134
+ │ 0 │ PASS │ │
135
+ │ 1 │ PASS │ │
136
+ │ 2 │ FAIL │ got: [] expected: [0, 1] │
137
+ └────────────────────────────────────────────────-┘
138
+ ✗ 1/3 test(s) failed
139
+ ```
140
+
141
+ ### 5. Submit to LeetCode
142
+
143
+ ```bash
144
+ lc submit 1
145
+ ```
146
+
147
+ ```
148
+ ┌─ Accepted ──────────────────────────────────────┐
149
+ │ Runtime: 52 ms (beats 87.3%) │
150
+ │ Memory: 16.4 MB (beats 62.1%) │
151
+ │ Tests: 54/54 │
152
+ └─────────────────────────────────────────────────┘
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Commands
158
+
159
+ | Command | Description |
160
+ |---|---|
161
+ | `lc login` | Store LeetCode session cookies securely |
162
+ | `lc fetch <number> [--lang]` | Fetch problem and create local files |
163
+ | `lc run <number>` | Run solution against sample test cases |
164
+ | `lc submit <number>` | Submit to LeetCode and get full results |
165
+ | `lc config` | Show current configuration |
166
+ | `lc config --set key=value` | Update a config value |
167
+ | `lc config --vscode-init` | Generate `.vscode/tasks.json` |
168
+
169
+ ---
170
+
171
+ ## Language Support
172
+
173
+ | Language | Flag | Runtime Required |
174
+ |---|---|---|
175
+ | Python 3 | `--lang python` | `python` |
176
+ | JavaScript | `--lang javascript` | `node` |
177
+ | C++ | `--lang cpp` | `g++` |
178
+ | Java | `--lang java` | `javac`, `java` |
179
+
180
+ Set your default language so you don't need `--lang` on every fetch:
181
+
182
+ ```bash
183
+ lc config --set settings.default_language=javascript
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Configuration
189
+
190
+ On first run, create `.leet2local.toml` in your project root:
191
+
192
+ ```toml
193
+ [settings]
194
+ default_language = "python" # python | javascript | cpp | java
195
+ problems_dir = "./leetcode" # where problem directories are created
196
+ run_mode = "local" # local | remote
197
+
198
+ [api]
199
+ graphql_endpoint = "https://leetcode.com/graphql"
200
+ request_timeout = 30
201
+ max_retries = 5
202
+
203
+ [runtime]
204
+ python_cmd = "python"
205
+ node_cmd = "node"
206
+ java_cmd = "java"
207
+ javac_cmd = "javac"
208
+ cpp_compiler = "g++"
209
+ runner_timeout = 10 # seconds per test execution
210
+
211
+ [display]
212
+ show_difficulty = true
213
+ show_tags = false # hide tags to avoid spoilers
214
+ syntax_highlight = true
215
+ ```
216
+
217
+ Config is loaded from the nearest `.leet2local.toml` walking up from the current directory, falling back to `~/.config/leet2local/config.toml`.
218
+
219
+ ---
220
+
221
+ ## VS Code Integration
222
+
223
+ Generate keyboard-shortcut tasks:
224
+
225
+ ```bash
226
+ lc config --vscode-init
227
+ ```
228
+
229
+ This creates `.vscode/tasks.json` with three tasks. Add to your `keybindings.json`:
230
+
231
+ ```json
232
+ [
233
+ { "key": "ctrl+shift+r", "command": "workbench.action.tasks.runTask", "args": "LC: Run Local" },
234
+ { "key": "ctrl+shift+s", "command": "workbench.action.tasks.runTask", "args": "LC: Submit" }
235
+ ]
236
+ ```
237
+
238
+ ---
239
+
240
+ ## How It Works
241
+
242
+ ```
243
+ lc fetch 1
244
+ └─ GraphQL: questionList (slug resolution)
245
+ └─ GraphQL: questionData (description, stub, test cases)
246
+ └─ HTML → Markdown (BeautifulSoup + markdownify)
247
+ └─ Write question.md, solution.py, test_cases.json
248
+
249
+ lc run 1
250
+ └─ Read test_cases.json
251
+ └─ Render Jinja2 test harness template
252
+ └─ subprocess → python harness.py
253
+ └─ Parse LEET_PASS / LEET_FAIL / LEET_ERROR output lines
254
+
255
+ lc submit 1
256
+ └─ GraphQL: submitCode mutation → submission_id
257
+ └─ Poll: checkSubmission every 2s
258
+ └─ Display Rich result table
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Project Structure
264
+
265
+ ```
266
+ Leet2Local/
267
+ ├── leet2local/
268
+ │ ├── cli.py # Typer CLI entry point
269
+ │ ├── auth.py # Login, keyring credential storage
270
+ │ ├── fetcher.py # GraphQL client, file creation
271
+ │ ├── runner.py # Local runner dispatcher
272
+ │ ├── submitter.py # Remote submission + polling
273
+ │ ├── html_parser.py # HTML → Markdown conversion
274
+ │ ├── models.py # Pydantic data models
275
+ │ ├── config.py # TOML config management
276
+ │ ├── queries.py # GraphQL query strings
277
+ │ ├── rate_limiter.py # Tenacity retry decorator
278
+ │ └── runners/
279
+ │ ├── base.py # Abstract Runner base class
280
+ │ ├── python_runner.py
281
+ │ ├── javascript_runner.py
282
+ │ ├── cpp_runner.py
283
+ │ └── java_runner.py
284
+ ├── templates/ # Jinja2 test harness templates
285
+ ├── scripts/
286
+ │ └── generate_slug_map.py # Build slug fallback map
287
+ └── tests/
288
+ ```
289
+
290
+ ---
291
+
292
+ ## Limitations
293
+
294
+ - **Sample test cases only** for local runs — hidden test cases require `lc submit`
295
+ - LeetCode's API is unofficial and undocumented; field names may change
296
+ - C++ and Java require the respective compilers installed and on PATH
297
+ - `lc submit` requires a valid session cookie (obtained via `lc login`)
298
+
299
+ ---
300
+
301
+ ## Development
302
+
303
+ ```bash
304
+ # Run tests
305
+ pytest
306
+
307
+ # Lint
308
+ ruff check .
309
+
310
+ # Regenerate slug fallback map (run once, requires internet)
311
+ python scripts/generate_slug_map.py
312
+ ```
313
+
314
+ ---
315
+
316
+ ## License
317
+
318
+ MIT
@@ -0,0 +1,279 @@
1
+ # Leet2Local
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/leet2local)](https://pypi.org/project/leet2local/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/leet2local)](https://pypi.org/project/leet2local/)
5
+ [![CI](https://github.com/dhineshtheprogrammer/leet2local/actions/workflows/ci.yml/badge.svg)](https://github.com/dhineshtheprogrammer/leet2local/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ A CLI tool that brings LeetCode problems into your local IDE. Fetch problem descriptions, solve in your editor, run tests locally, and submit directly to LeetCode — all from the terminal.
9
+
10
+ ```
11
+ lc fetch 1 --lang python
12
+ lc run 1
13
+ lc submit 1
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - **Fetch any problem** by number — creates a local directory with the description, code stub, and sample test cases
21
+ - **Run locally** — executes your solution against sample test cases without touching LeetCode servers
22
+ - **Submit remotely** — sends your code to LeetCode and polls for full results including hidden test cases, runtime, and memory percentile
23
+ - **Multi-language** — Python, JavaScript, C++, and Java
24
+ - **VS Code integration** — generates `tasks.json` for keyboard-shortcut access to all commands
25
+ - **Secure auth** — session cookies stored in OS native keychain (Windows Credential Manager / macOS Keychain)
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ **Requirements:** Python 3.11+
32
+
33
+ ```bash
34
+ pip install leet2local
35
+ ```
36
+
37
+ Or install from source:
38
+
39
+ ```bash
40
+ git clone https://github.com/dhineshtheprogrammer/leet2local.git
41
+ cd Leet2Local
42
+ pip install -e .
43
+ ```
44
+
45
+ For development (includes pytest and ruff):
46
+
47
+ ```bash
48
+ pip install -e ".[dev]"
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Quick Start
54
+
55
+ ### 1. Log in
56
+
57
+ Get your session cookies from your browser after logging in to leetcode.com:
58
+
59
+ 1. Open DevTools → Application → Cookies → `leetcode.com`
60
+ 2. Copy `LEETCODE_SESSION` and `csrftoken`
61
+
62
+ ```bash
63
+ lc login
64
+ ```
65
+
66
+ ### 2. Fetch a problem
67
+
68
+ ```bash
69
+ lc fetch 1 # Two Sum, defaults to Python
70
+ lc fetch 42 --lang cpp # Trapping Rain Water in C++
71
+ ```
72
+
73
+ This creates:
74
+
75
+ ```
76
+ ./leetcode/1-two-sum/
77
+ ├── question.md # Problem description in Markdown
78
+ ├── solution.py # Code stub from LeetCode
79
+ └── test_cases.json # Sample inputs and expected outputs
80
+ ```
81
+
82
+ ### 3. Write your solution
83
+
84
+ Open `solution.py` in your editor and implement the function.
85
+
86
+ ### 4. Run locally
87
+
88
+ ```bash
89
+ lc run 1
90
+ ```
91
+
92
+ ```
93
+ ┌─ Test Results ──────────────────────────────────┐
94
+ │ # │ Status │ Details │
95
+ │ 0 │ PASS │ │
96
+ │ 1 │ PASS │ │
97
+ │ 2 │ FAIL │ got: [] expected: [0, 1] │
98
+ └────────────────────────────────────────────────-┘
99
+ ✗ 1/3 test(s) failed
100
+ ```
101
+
102
+ ### 5. Submit to LeetCode
103
+
104
+ ```bash
105
+ lc submit 1
106
+ ```
107
+
108
+ ```
109
+ ┌─ Accepted ──────────────────────────────────────┐
110
+ │ Runtime: 52 ms (beats 87.3%) │
111
+ │ Memory: 16.4 MB (beats 62.1%) │
112
+ │ Tests: 54/54 │
113
+ └─────────────────────────────────────────────────┘
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Commands
119
+
120
+ | Command | Description |
121
+ |---|---|
122
+ | `lc login` | Store LeetCode session cookies securely |
123
+ | `lc fetch <number> [--lang]` | Fetch problem and create local files |
124
+ | `lc run <number>` | Run solution against sample test cases |
125
+ | `lc submit <number>` | Submit to LeetCode and get full results |
126
+ | `lc config` | Show current configuration |
127
+ | `lc config --set key=value` | Update a config value |
128
+ | `lc config --vscode-init` | Generate `.vscode/tasks.json` |
129
+
130
+ ---
131
+
132
+ ## Language Support
133
+
134
+ | Language | Flag | Runtime Required |
135
+ |---|---|---|
136
+ | Python 3 | `--lang python` | `python` |
137
+ | JavaScript | `--lang javascript` | `node` |
138
+ | C++ | `--lang cpp` | `g++` |
139
+ | Java | `--lang java` | `javac`, `java` |
140
+
141
+ Set your default language so you don't need `--lang` on every fetch:
142
+
143
+ ```bash
144
+ lc config --set settings.default_language=javascript
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Configuration
150
+
151
+ On first run, create `.leet2local.toml` in your project root:
152
+
153
+ ```toml
154
+ [settings]
155
+ default_language = "python" # python | javascript | cpp | java
156
+ problems_dir = "./leetcode" # where problem directories are created
157
+ run_mode = "local" # local | remote
158
+
159
+ [api]
160
+ graphql_endpoint = "https://leetcode.com/graphql"
161
+ request_timeout = 30
162
+ max_retries = 5
163
+
164
+ [runtime]
165
+ python_cmd = "python"
166
+ node_cmd = "node"
167
+ java_cmd = "java"
168
+ javac_cmd = "javac"
169
+ cpp_compiler = "g++"
170
+ runner_timeout = 10 # seconds per test execution
171
+
172
+ [display]
173
+ show_difficulty = true
174
+ show_tags = false # hide tags to avoid spoilers
175
+ syntax_highlight = true
176
+ ```
177
+
178
+ Config is loaded from the nearest `.leet2local.toml` walking up from the current directory, falling back to `~/.config/leet2local/config.toml`.
179
+
180
+ ---
181
+
182
+ ## VS Code Integration
183
+
184
+ Generate keyboard-shortcut tasks:
185
+
186
+ ```bash
187
+ lc config --vscode-init
188
+ ```
189
+
190
+ This creates `.vscode/tasks.json` with three tasks. Add to your `keybindings.json`:
191
+
192
+ ```json
193
+ [
194
+ { "key": "ctrl+shift+r", "command": "workbench.action.tasks.runTask", "args": "LC: Run Local" },
195
+ { "key": "ctrl+shift+s", "command": "workbench.action.tasks.runTask", "args": "LC: Submit" }
196
+ ]
197
+ ```
198
+
199
+ ---
200
+
201
+ ## How It Works
202
+
203
+ ```
204
+ lc fetch 1
205
+ └─ GraphQL: questionList (slug resolution)
206
+ └─ GraphQL: questionData (description, stub, test cases)
207
+ └─ HTML → Markdown (BeautifulSoup + markdownify)
208
+ └─ Write question.md, solution.py, test_cases.json
209
+
210
+ lc run 1
211
+ └─ Read test_cases.json
212
+ └─ Render Jinja2 test harness template
213
+ └─ subprocess → python harness.py
214
+ └─ Parse LEET_PASS / LEET_FAIL / LEET_ERROR output lines
215
+
216
+ lc submit 1
217
+ └─ GraphQL: submitCode mutation → submission_id
218
+ └─ Poll: checkSubmission every 2s
219
+ └─ Display Rich result table
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Project Structure
225
+
226
+ ```
227
+ Leet2Local/
228
+ ├── leet2local/
229
+ │ ├── cli.py # Typer CLI entry point
230
+ │ ├── auth.py # Login, keyring credential storage
231
+ │ ├── fetcher.py # GraphQL client, file creation
232
+ │ ├── runner.py # Local runner dispatcher
233
+ │ ├── submitter.py # Remote submission + polling
234
+ │ ├── html_parser.py # HTML → Markdown conversion
235
+ │ ├── models.py # Pydantic data models
236
+ │ ├── config.py # TOML config management
237
+ │ ├── queries.py # GraphQL query strings
238
+ │ ├── rate_limiter.py # Tenacity retry decorator
239
+ │ └── runners/
240
+ │ ├── base.py # Abstract Runner base class
241
+ │ ├── python_runner.py
242
+ │ ├── javascript_runner.py
243
+ │ ├── cpp_runner.py
244
+ │ └── java_runner.py
245
+ ├── templates/ # Jinja2 test harness templates
246
+ ├── scripts/
247
+ │ └── generate_slug_map.py # Build slug fallback map
248
+ └── tests/
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Limitations
254
+
255
+ - **Sample test cases only** for local runs — hidden test cases require `lc submit`
256
+ - LeetCode's API is unofficial and undocumented; field names may change
257
+ - C++ and Java require the respective compilers installed and on PATH
258
+ - `lc submit` requires a valid session cookie (obtained via `lc login`)
259
+
260
+ ---
261
+
262
+ ## Development
263
+
264
+ ```bash
265
+ # Run tests
266
+ pytest
267
+
268
+ # Lint
269
+ ruff check .
270
+
271
+ # Regenerate slug fallback map (run once, requires internet)
272
+ python scripts/generate_slug_map.py
273
+ ```
274
+
275
+ ---
276
+
277
+ ## License
278
+
279
+ MIT
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"