sni-cli 1.1.1__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 (45) hide show
  1. sni_cli-1.1.1/.gitignore +11 -0
  2. sni_cli-1.1.1/LICENSE +21 -0
  3. sni_cli-1.1.1/PKG-INFO +495 -0
  4. sni_cli-1.1.1/README.md +442 -0
  5. sni_cli-1.1.1/install.ps1 +275 -0
  6. sni_cli-1.1.1/install.sh +399 -0
  7. sni_cli-1.1.1/pyproject.toml +104 -0
  8. sni_cli-1.1.1/sni/__init__.py +1 -0
  9. sni_cli-1.1.1/sni/__main__.py +3 -0
  10. sni_cli-1.1.1/sni/cli.py +589 -0
  11. sni_cli-1.1.1/sni/config.py +124 -0
  12. sni_cli-1.1.1/sni/exceptions.py +45 -0
  13. sni_cli-1.1.1/sni/logger.py +14 -0
  14. sni_cli-1.1.1/sni/player.py +148 -0
  15. sni_cli-1.1.1/sni/providers/__init__.py +11 -0
  16. sni_cli-1.1.1/sni/providers/allanime.py +670 -0
  17. sni_cli-1.1.1/sni/providers/animepahe.py +126 -0
  18. sni_cli-1.1.1/sni/providers/base.py +60 -0
  19. sni_cli-1.1.1/sni/providers/cache.py +29 -0
  20. sni_cli-1.1.1/sni/providers/extractors/__init__.py +3 -0
  21. sni_cli-1.1.1/sni/providers/extractors/megacloud.py +80 -0
  22. sni_cli-1.1.1/sni/providers/extractors/vixcloud.py +63 -0
  23. sni_cli-1.1.1/sni/providers/hianime.py +163 -0
  24. sni_cli-1.1.1/sni/providers/registry.py +81 -0
  25. sni_cli-1.1.1/sni/tui/__init__.py +0 -0
  26. sni_cli-1.1.1/sni/tui/app.py +225 -0
  27. sni_cli-1.1.1/sni/tui/bridge.py +98 -0
  28. sni_cli-1.1.1/sni/tui/screens/__init__.py +0 -0
  29. sni_cli-1.1.1/sni/tui/screens/help.py +49 -0
  30. sni_cli-1.1.1/sni/tui/screens/history.py +61 -0
  31. sni_cli-1.1.1/sni/tui/screens/home.py +255 -0
  32. sni_cli-1.1.1/sni/tui/screens/player.py +124 -0
  33. sni_cli-1.1.1/sni/tui/widgets/__init__.py +0 -0
  34. sni_cli-1.1.1/sni/tui/widgets/ascii_art.py +65 -0
  35. sni_cli-1.1.1/sni/tui/widgets/info_box.py +65 -0
  36. sni_cli-1.1.1/sni/ui.py +186 -0
  37. sni_cli-1.1.1/sni/watch_history.py +62 -0
  38. sni_cli-1.1.1/sni/wizard.py +86 -0
  39. sni_cli-1.1.1/tests/__init__.py +0 -0
  40. sni_cli-1.1.1/tests/conftest.py +1 -0
  41. sni_cli-1.1.1/tests/test_allanime_captcha.py +300 -0
  42. sni_cli-1.1.1/tests/test_cache.py +44 -0
  43. sni_cli-1.1.1/tests/test_config.py +106 -0
  44. sni_cli-1.1.1/tests/test_exceptions.py +48 -0
  45. sni_cli-1.1.1/tests/test_providers.py +52 -0
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .env
10
+ config.toml
11
+ !.github/
sni_cli-1.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 smithmx20
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.
sni_cli-1.1.1/PKG-INFO ADDED
@@ -0,0 +1,495 @@
1
+ Metadata-Version: 2.4
2
+ Name: sni-cli
3
+ Version: 1.1.1
4
+ Summary: Stream Ninja Interface — terminal-based anime streaming CLI + TUI
5
+ Project-URL: Homepage, https://github.com/sundeepyt2/SNI
6
+ Project-URL: Source, https://github.com/sundeepyt2/SNI
7
+ Project-URL: Documentation, https://github.com/sundeepyt2/SNI#readme
8
+ Project-URL: Issues, https://github.com/sundeepyt2/SNI/issues
9
+ Project-URL: Changelog, https://github.com/sundeepyt2/SNI/releases
10
+ Author: sundeepyt2
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: allanime,ani-cli,anime,cli,hianime,mpv,streaming,tui
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Environment :: Console :: Curses
17
+ Classifier: Intended Audience :: End Users/Desktop
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: MacOS :: MacOS X
20
+ Classifier: Operating System :: Microsoft :: Windows
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Operating System :: POSIX :: Linux
23
+ Classifier: Programming Language :: Python :: 3
24
+ Classifier: Programming Language :: Python :: 3.10
25
+ Classifier: Programming Language :: Python :: 3.11
26
+ Classifier: Programming Language :: Python :: 3.12
27
+ Classifier: Programming Language :: Python :: 3.13
28
+ Classifier: Topic :: Games/Entertainment
29
+ Classifier: Topic :: Multimedia :: Video
30
+ Classifier: Typing :: Typed
31
+ Requires-Python: >=3.10
32
+ Requires-Dist: beautifulsoup4>=4.12.0
33
+ Requires-Dist: httpx>=0.26.0
34
+ Requires-Dist: pycryptodome>=3.20.0
35
+ Requires-Dist: pydantic>=2.0.0
36
+ Requires-Dist: rich>=13.0.0
37
+ Requires-Dist: textual>=8.0.0
38
+ Requires-Dist: tomli-w>=1.0.0
39
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
40
+ Requires-Dist: typer>=0.9.0
41
+ Provides-Extra: download
42
+ Requires-Dist: aria2p>=0.12.0; extra == 'download'
43
+ Requires-Dist: yt-dlp>=2024.0.0; extra == 'download'
44
+ Provides-Extra: standard
45
+ Requires-Dist: chafa>=1.13.0; extra == 'standard'
46
+ Requires-Dist: python-magic>=0.4.27; extra == 'standard'
47
+ Provides-Extra: test
48
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
49
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
50
+ Requires-Dist: pytest>=7.0.0; extra == 'test'
51
+ Requires-Dist: ruff>=0.1.0; extra == 'test'
52
+ Description-Content-Type: text/markdown
53
+
54
+ # SNI — Stream Ninja Interface
55
+
56
+ A terminal-based anime streaming client inspired by [ani-cli](https://github.com/pystardust/ani-cli). Search, browse, and stream anime from multiple providers directly in your terminal.
57
+
58
+ [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/)
59
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
60
+ [![Platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20macOS%20%7C%20Windows-lightgrey.svg)](#installation)
61
+
62
+ ---
63
+
64
+ ## Features
65
+
66
+ - **Multi-provider support** — HiAnime (sub+dub), AllAnime (sub+dub), Animepahe (sub)
67
+ - **Full TUI mode** — Rich terminal UI built with Textual
68
+ - **Interactive CLI** — fzf-based selection with numbered-input fallback
69
+ - **Watch history** — Resume from where you left off
70
+ - **Episode queuing** — Play ranges (e.g. `sni play "X" -e 1-12`)
71
+ - **mpv/VLC integration** — IPC socket controls (next, prev, reload, quit)
72
+ - **Captcha-bypass built-in** — Cloudflare Worker fallback + browser-cookie injection for AllAnime
73
+ - **Configurable** — TOML config with interactive wizard
74
+ - **Cross-platform** — Linux, macOS, Windows
75
+
76
+ ---
77
+
78
+ ## Installation
79
+
80
+ ### One-command install
81
+
82
+ Pick the command for your OS, paste it into a terminal, and you're done. The installer detects your package manager, installs Python + mpv + fzf if missing, installs SNI, and adds `sni` to your PATH automatically — no manual steps required.
83
+
84
+ #### Linux
85
+
86
+ ```bash
87
+ curl -fsSL https://raw.githubusercontent.com/sundeepyt2/SNI/main/install.sh | bash
88
+ ```
89
+
90
+ #### macOS
91
+
92
+ ```bash
93
+ curl -fsSL https://raw.githubusercontent.com/sundeepyt2/SNI/main/install.sh | bash
94
+ ```
95
+
96
+ (Homebrew will be bootstrapped automatically if missing.)
97
+
98
+ #### Windows (PowerShell)
99
+
100
+ ```powershell
101
+ iex (irm https://raw.githubusercontent.com/sundeepyt2/SNI/main/install.ps1)
102
+ ```
103
+
104
+ If PowerShell blocks the script with an execution-policy error, run this first:
105
+
106
+ ```powershell
107
+ Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
108
+ ```
109
+
110
+ Then re-run the install command.
111
+
112
+ ---
113
+
114
+ ### Install from PyPI
115
+
116
+ Once SNI is published to PyPI (after the v1.1.1 release), you can install it with plain pip — no cloning required:
117
+
118
+ ```bash
119
+ # Linux / macOS
120
+ pip install --user sni-cli
121
+
122
+ # Windows
123
+ pip install sni-cli
124
+ ```
125
+
126
+ > **Why `sni-cli` and not `sni`?** PyPI rejected the bare `sni` name as too similar to existing projects (`sni-auth`, `sni-bin`, `sni-sdk`, `snib`, `snic`, `snid`, ...). The package name on PyPI is `sni-cli`, but the console command is still just `sni` (e.g. `sni play`, `sni tui`, `sni search`).
127
+
128
+ This installs the SNI Python package and the `sni` command, but **does not** install `mpv` or `fzf` — install those separately if you don't have them already:
129
+
130
+ - **Linux**: `sudo apt install mpv fzf` (or your distro's equivalent)
131
+ - **macOS**: `brew install mpv fzf`
132
+ - **Windows**: `winget install mpv.net junegunn.fzf`
133
+
134
+ For a fully-automatic install (including mpv + fzf), use the one-command installers above instead.
135
+
136
+ ---
137
+
138
+ ### Install from a local clone
139
+
140
+ If you've already cloned the repo (or want to hack on SNI), run the installer from the repo root:
141
+
142
+ ```bash
143
+ git clone https://github.com/sundeepyt2/SNI.git
144
+ cd SNI
145
+
146
+ # Linux / macOS:
147
+ ./install.sh
148
+
149
+ # Windows PowerShell:
150
+ .\install.ps1
151
+ ```
152
+
153
+ ---
154
+
155
+ ### What the installer does
156
+
157
+ Both `install.sh` and `install.ps1` perform the same four steps:
158
+
159
+ 1. **Detects your package manager** and installs system dependencies:
160
+ - Linux: `apt` / `dnf` / `pacman` / `zypper` / `apk` — installs `python3`, `python3-pip`, `mpv`, `fzf`, `git`
161
+ - macOS: Homebrew — installs `python@3.12`, `mpv`, `fzf`
162
+ - Windows: `winget` / `scoop` / `choco` (auto-detected) — installs Python, mpv.net, fzf
163
+ 2. **Verifies Python >= 3.10**
164
+ 3. **Installs SNI itself** via `pip install --user .` (no admin/sudo needed)
165
+ 4. **Adds SNI to your PATH** idempotently:
166
+ - Linux/macOS: injects an `export PATH=...` line into your `~/.bashrc` / `~/.zshrc` / `~/.profile` / `~/.config/fish/config.fish` (whichever is appropriate for your shell)
167
+ - Windows: calls `[Environment]::SetEnvironmentVariable("Path", ..., "User")` to persist across reboots
168
+
169
+ The installer is **idempotent** — safe to re-run as many times as you want. It will skip packages that are already installed and won't add duplicate PATH entries.
170
+
171
+ ---
172
+
173
+ ### Manual install (alternative)
174
+
175
+ If you prefer to install everything by hand:
176
+
177
+ #### Linux (Debian/Ubuntu)
178
+
179
+ ```bash
180
+ sudo apt update
181
+ sudo apt install python3 python3-pip mpv fzf git
182
+
183
+ git clone https://github.com/sundeepyt2/SNI.git
184
+ cd SNI
185
+ pip install --user --break-system-packages .
186
+
187
+ # Add ~/.local/bin to PATH (one-time)
188
+ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
189
+ source ~/.bashrc
190
+
191
+ sni --version
192
+ ```
193
+
194
+ #### macOS
195
+
196
+ ```bash
197
+ brew install python@3.12 mpv fzf git
198
+
199
+ git clone https://github.com/sundeepyt2/SNI.git
200
+ cd SNI
201
+ pip3 install --user .
202
+
203
+ # Add ~/Library/Python/3.12/bin to PATH (one-time)
204
+ echo 'export PATH="$HOME/Library/Python/3.12/bin:$PATH"' >> ~/.zshrc
205
+ source ~/.zshrc
206
+
207
+ sni --version
208
+ ```
209
+
210
+ #### Windows
211
+
212
+ ```powershell
213
+ # Install Python from https://python.org (check "Add to PATH")
214
+ # Install mpv from https://sourceforge.net/projects/mpv-player-windows/
215
+ # Install fzf from https://github.com/junegunn/fzf/releases
216
+
217
+ git clone https://github.com/sundeepyt2/SNI.git
218
+ cd SNI
219
+ pip install .
220
+
221
+ sni --version
222
+ ```
223
+
224
+ ---
225
+
226
+ ## First-run setup
227
+
228
+ After installing, run the interactive config wizard to pick your default provider, quality, sub/dub, etc:
229
+
230
+ ```bash
231
+ sni config --interactive
232
+ ```
233
+
234
+ Or just start using SNI directly — sensible defaults are baked in.
235
+
236
+ ---
237
+
238
+ ## Usage
239
+
240
+ ```bash
241
+ # Search and play (interactive)
242
+ sni play "one piece"
243
+
244
+ # Watch with ani-cli like flow (continue/resume support)
245
+ sni watch "naruto"
246
+
247
+ # Play specific episode range
248
+ sni play "attack on titan" -e 1-12
249
+
250
+ # Use a specific provider
251
+ sni play "jujutsu kaisen" -p allanime
252
+
253
+ # Watch dubbed
254
+ sni play "demon slayer" -d
255
+
256
+ # Resume from watch history
257
+ sni watch --resume
258
+
259
+ # Search only
260
+ sni search "spy x family"
261
+
262
+ # Launch full TUI
263
+ sni tui
264
+
265
+ # Configure
266
+ sni config --interactive
267
+ sni config --update quality=720
268
+ sni config --update default_provider=allanime
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Commands
274
+
275
+ | Command | Description |
276
+ |---------|-------------|
277
+ | `sni search <query>` | Search for anime titles |
278
+ | `sni play <query>` | Search and play with interactive flow |
279
+ | `sni watch <query>` | Watch with continue/resume support |
280
+ | `sni tui` | Launch full terminal UI |
281
+ | `sni config` | Manage configuration |
282
+ | `sni config --interactive` | Interactive config wizard |
283
+ | `sni config --cookie-info` | Show how to bypass AllAnime captcha (3 options) |
284
+ | `sni provider list` | List available providers |
285
+ | `sni provider status` | Health-check providers |
286
+
287
+ ---
288
+
289
+ ## Providers
290
+
291
+ | Provider | Sub | Dub | Status |
292
+ |----------|-----|-----|--------|
293
+ | HiAnime | Yes | Yes | Active |
294
+ | AllAnime | Yes | Yes | Active |
295
+ | Animepahe | Yes | No | API deprecated |
296
+
297
+ ---
298
+
299
+ ## Configuration
300
+
301
+ Config file: `~/.config/sni/config.toml` (Linux/macOS) or `%APPDATA%\sni\config.toml` (Windows)
302
+
303
+ ```toml
304
+ [general]
305
+ default_provider = "allanime"
306
+ selector = "fzf"
307
+ icons = true
308
+
309
+ [stream]
310
+ player = "mpv"
311
+ quality = "1080"
312
+ translation_type = "sub"
313
+ auto_next = true
314
+ use_ipc = true
315
+
316
+ [ui]
317
+ show_description = true
318
+ show_score = true
319
+ show_genres = true
320
+
321
+ [providers]
322
+ allanime_cookies = ""
323
+ allanime_cf_worker_url = ""
324
+ ```
325
+
326
+ Run `sni config --interactive` to set up via a guided wizard.
327
+
328
+ ---
329
+
330
+ ## TUI Mode
331
+
332
+ Launch the full terminal UI with:
333
+
334
+ ```bash
335
+ sni tui
336
+ ```
337
+
338
+ ### Keybinds
339
+
340
+ | Key | Action |
341
+ |-----|--------|
342
+ | `/` | Focus search input |
343
+ | `j` / `k` | Navigate up/down |
344
+ | `Enter` | Select / Play |
345
+ | `Escape` | Go back / Close |
346
+ | `?` | Show help |
347
+ | `!` | Player controls |
348
+ | `@` | Watch history |
349
+ | `$` | About |
350
+ | `q` | Quit |
351
+
352
+ ---
353
+
354
+ ## AllAnime captcha fix
355
+
356
+ AllAnime sometimes blocks API requests with a Cloudflare captcha wall (`NEED_CAPTCHA` error). SNI ships with **three** bypass options. Run `sni config --cookie-info` to see them all in a single panel:
357
+
358
+ ### Option 1 — Cloudflare Worker (recommended, most reliable)
359
+
360
+ Deploy the XAN CF Worker (free, takes 2 minutes):
361
+
362
+ 1. Go to https://dash.cloudflare.com → Workers & Pages → Create
363
+ 2. Paste the contents of [`cf-worker/worker.js`](https://github.com/smithmx20/XAN/blob/main/cf-worker/worker.js) from the XAN repo
364
+ 3. Deploy, copy the worker URL (e.g. `https://xan-proxy.you.workers.dev`)
365
+ 4. Save it to SNI:
366
+
367
+ ```bash
368
+ sni config --update allanime_cf_worker_url='https://xan-proxy.you.workers.dev'
369
+ ```
370
+
371
+ The Worker proxies AllAnime API requests through Cloudflare's own IPs, which AllAnime rarely challenges. **This works even on VPN/shared IPs where cookies fail.**
372
+
373
+ ### Option 2 — Browser cookies
374
+
375
+ If your IP isn't already flagged, browser cookies will work:
376
+
377
+ ```bash
378
+ # Option A — config key:
379
+ sni config --update allanime_cookies='k1=v1; k2=v2'
380
+
381
+ # Option B — cookies file (easier to refresh):
382
+ echo 'k1=v1; k2=v2' > ~/.config/sni/allanime_cookies.txt
383
+
384
+ # Option C — one-off flag:
385
+ sni play "one piece" --cookie 'k1=v1; k2=v2'
386
+ ```
387
+
388
+ Get the cookie string from your browser:
389
+ 1. Open https://allanime.day, solve any captcha.
390
+ 2. DevTools → Application → Cookies → allanime.day.
391
+ 3. Copy the full cookie string.
392
+
393
+ ### Option 3 — Switch providers
394
+
395
+ ```bash
396
+ sni play "one piece" -p hianime
397
+ ```
398
+
399
+ ---
400
+
401
+ ## Troubleshooting
402
+
403
+ ### `sni: command not found` after install
404
+
405
+ The installer added SNI to your PATH, but your current shell session hasn't picked it up yet. Fix:
406
+
407
+ - **Linux/macOS**: open a new terminal, or run `source ~/.bashrc` (or `source ~/.zshrc`)
408
+ - **Windows**: open a new PowerShell window
409
+
410
+ Verify with `sni --version`.
411
+
412
+ ### `mpv not found`
413
+
414
+ SNI needs a video player to actually play streams. Install mpv:
415
+
416
+ - **Linux**: `sudo apt install mpv` / `sudo dnf install mpv` / `sudo pacman -S mpv`
417
+ - **macOS**: `brew install mpv`
418
+ - **Windows**: `winget install mpv.net` or download from https://sourceforge.net/projects/mpv-player-windows/
419
+
420
+ ### `fzf not found`
421
+
422
+ fzf is optional — SNI falls back to numbered selection if it's missing. To install:
423
+
424
+ - **Linux**: `sudo apt install fzf` / `sudo dnf install fzf` / `sudo pacman -S fzf`
425
+ - **macOS**: `brew install fzf`
426
+ - **Windows**: `winget install junegunn.fzf`
427
+
428
+ ### AllAnime `NEED_CAPTCHA` error
429
+
430
+ See the [AllAnime captcha fix](#allanime-captcha-fix) section above. TL;DR: deploy the Cloudflare Worker and run `sni config --update allanime_cf_worker_url='https://your-worker.workers.dev'`.
431
+
432
+ ### Python version too old
433
+
434
+ SNI requires Python 3.10 or newer. Check your version with `python3 --version`. If it's older:
435
+
436
+ - **Linux**: install `python3.12` from your package manager (Debian Backports, Ubuntu deadsnakes PPA, etc.)
437
+ - **macOS**: `brew install python@3.12`
438
+ - **Windows**: download from https://python.org
439
+
440
+ ### `pip install` fails with "externally-managed-environment"
441
+
442
+ This happens on Debian 12+ / Fedora 38+ / PEP 668 systems. The installer handles it automatically with `--break-system-packages`. If you're installing manually:
443
+
444
+ ```bash
445
+ pip install --user --break-system-packages .
446
+ ```
447
+
448
+ Or, better, use a virtualenv:
449
+
450
+ ```bash
451
+ python3 -m venv ~/.venvs/sni
452
+ source ~/.venvs/sni/bin/activate
453
+ pip install .
454
+ sni --version
455
+ ```
456
+
457
+ ---
458
+
459
+ ## Uninstall
460
+
461
+ ```bash
462
+ # Remove the Python package
463
+ pip uninstall sni-cli # Linux/macOS
464
+ pip uninstall sni-cli # Windows
465
+
466
+ # Remove config + cookies
467
+ rm -rf ~/.config/sni # Linux/macOS
468
+ Remove-Item -Recurse $env:APPDATA\sni # Windows
469
+
470
+ # Remove PATH entries (search for "sni-path-inject" in your shell rc files)
471
+ # Linux/macOS: edit ~/.bashrc / ~/.zshrc / ~/.profile and delete the marked lines
472
+ # Windows: System Properties → Environment Variables → edit user Path
473
+ ```
474
+
475
+ ---
476
+
477
+ ## Development
478
+
479
+ ```bash
480
+ git clone https://github.com/sundeepyt2/SNI.git
481
+ cd SNI
482
+ pip install --user -e ".[test]"
483
+
484
+ # Run tests
485
+ pytest -q
486
+
487
+ # Lint
488
+ ruff check .
489
+ ```
490
+
491
+ ---
492
+
493
+ ## License
494
+
495
+ MIT License. See [LICENSE](LICENSE) for details.