just-cli 0.3.1__tar.gz → 0.5.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.
- just_cli-0.5.0/.claude/settings.local.json +8 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/.gitignore +4 -1
- just_cli-0.5.0/PKG-INFO +208 -0
- just_cli-0.5.0/README.md +190 -0
- just_cli-0.5.0/docs/images/editor_demo.png +0 -0
- just_cli-0.5.0/docs/images/note_demo.png +0 -0
- just_cli-0.5.0/docs/images/viewer_demo.png +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/pyproject.toml +2 -2
- just_cli-0.5.0/scripts/ai_coding/agents2claude.py +41 -0
- just_cli-0.5.0/scripts/ai_coding/claude2agents.py +41 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/cli.py +33 -12
- just_cli-0.5.0/src/just/commands/archive.py +57 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/ext/add.py +32 -10
- just_cli-0.5.0/src/just/commands/update.py +52 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/extension/generator.py +63 -5
- just_cli-0.5.0/src/just/installers/glab/installer.py +65 -0
- just_cli-0.5.0/src/just/installers/kimi/installer.py +24 -0
- just_cli-0.5.0/src/just/installers/mssh/installer.py +9 -0
- just_cli-0.5.0/src/just/utils/archive/__init__.py +33 -0
- just_cli-0.5.0/src/just/utils/archive/archiver.py +97 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/archive/compression_handler.py +90 -9
- just_cli-0.5.0/src/just/utils/archive/sevenzip_handler.py +88 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/typer_utils.py +35 -7
- just_cli-0.5.0/tests/test_archive_creation.py +372 -0
- just_cli-0.5.0/tests/test_extension/test_extension_add.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/uv.lock +45 -19
- just_cli-0.3.1/.claude/plans/2026-04-18-edit-installer-macos-micro.md +0 -237
- just_cli-0.3.1/.claude/settings.local.json +0 -9
- just_cli-0.3.1/PKG-INFO +0 -210
- just_cli-0.3.1/README.md +0 -192
- just_cli-0.3.1/docs/images/editor_demo.png +0 -0
- just_cli-0.3.1/docs/images/viewer_demo.png +0 -0
- just_cli-0.3.1/src/just/installers/mssh/installer.py +0 -14
- just_cli-0.3.1/src/just/utils/archive/__init__.py +0 -22
- just_cli-0.3.1/src/just/utils/archive/sevenzip_handler.py +0 -44
- {just_cli-0.3.1 → just_cli-0.5.0}/.claude/skills/textual/README.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/.claude/skills/textual/SKILL.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/.claude/skills/textual/guide.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/.claude/skills/textual/quick-reference.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/.github/workflows/publish.yml +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/AGENTS.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/Dockerfile +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/docs/extension_guide.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/scripts/system/linux/proxy/proxy.sh +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/scripts/system/mac/proxy/proxy.sh +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/scripts/system/windows/proxy/proxy.bat +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/scripts/system/windows/proxy/proxy.ps1 +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/download.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/edit.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/ext/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/ext/edit.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/ext/list.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/ext/remove.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/extract.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/install.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/linux.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/note.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/tunnel.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/view.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/commands/workspace.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/config/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/config/config.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/config/utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/extension/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/extension/parser.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/extension/utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/extension/validator.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/AGENTS.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/decorator.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/install_package.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/installers/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/installers/binary_release.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/installers/remote_script.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/package_info.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/source/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/source/base.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/source/http.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/source/local.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/installer/utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/system_probe/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/system_probe/system_info.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/core/system_probe/system_probe.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/AGENTS.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/brew/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/claude-code/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/claude-code/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/cloudflare/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/cloudflare/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/docker/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/docker/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/edit/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/edit/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/gh/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/gh/installer.py +0 -0
- {just_cli-0.3.1/src/just/installers/mssh → just_cli-0.5.0/src/just/installers/glab}/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/miniconda3/installer.py +0 -0
- {just_cli-0.3.1/src/just/installers/nvm → just_cli-0.5.0/src/just/installers/mssh}/__init__.py +0 -0
- {just_cli-0.3.1/src/just/installers/qodercli → just_cli-0.5.0/src/just/installers/nvm}/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/nvm/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/openclaw/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/opencode/installer.py +0 -0
- {just_cli-0.3.1/src/just/installers/tailscale → just_cli-0.5.0/src/just/installers/qodercli}/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/qodercli/installer.py +0 -0
- /just_cli-0.3.1/tests/test_extension/test_extension_add.py → /just_cli-0.5.0/src/just/installers/tailscale/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/tailscale/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/uv/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/installers/uv/installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/tui/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/tui/editor.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/tui/extension.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/tui/markdown.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/tui/note.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/tui/workspace.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/AGENTS.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/__init__.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/archive/extractor.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/archive/format_detect.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/archive/tar_handler.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/archive/zip_handler.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/docker_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/download_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/echo_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/env_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/file_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/format_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/note_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/progress.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/shell_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/system_probe.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/src/just/utils/user_interaction.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/AGENTS.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/requirements.txt +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/run_tests.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_archive_extraction.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_bash_script_installer.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_download.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_extension/README.md +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_extension/test_ext.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_extension.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_file_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_init.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_installer_e2e.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_linux_commands.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_progress_utils.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/test_system_probe.py +0 -0
- {just_cli-0.3.1 → just_cli-0.5.0}/tests/testing.py +0 -0
just_cli-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: just-cli
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Your all-in-one CLI Toolkit
|
|
5
|
+
Author-email: zzzcb <zjxs.zzzcb@gmail.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: httpx
|
|
8
|
+
Requires-Dist: prompt-toolkit>=3.0.0
|
|
9
|
+
Requires-Dist: py7zr
|
|
10
|
+
Requires-Dist: python-dotenv
|
|
11
|
+
Requires-Dist: rich>=14.2.0
|
|
12
|
+
Requires-Dist: textual>=6.4.0
|
|
13
|
+
Requires-Dist: typer>=0.26.0
|
|
14
|
+
Requires-Dist: zstandard
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: loguru; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
<h1 align="center">🛠️ JUST CLI</h1>
|
|
20
|
+
|
|
21
|
+
<p align="center"><strong>The simple stuff should be simple.</strong></p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://pypi.org/project/just-cli/"> <img src="https://img.shields.io/pypi/v/just-cli?color=blue" alt="PyPI"></a>
|
|
25
|
+
<a href="https://pypi.org/project/just-cli/"> <img src="https://img.shields.io/pypi/pyversions/just-cli" alt="Python"></a>
|
|
26
|
+
<img src="https://img.shields.io/badge/license-MIT-purple.svg" alt="License: MIT">
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
Tired of Googling "how to install X" for the 47th time, just to end up copy-pasting from official docs?
|
|
31
|
+
</p>
|
|
32
|
+
<p align="center">
|
|
33
|
+
Tired of copy-pasting giant commands every time, just to change one little parameter?
|
|
34
|
+
</p>
|
|
35
|
+
<p align="center">
|
|
36
|
+
Start using <b>Just</b> — an all-in-one CLI toolkit that makes everyday developer tasks <i>actually simple</i>.
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv tool install just-cli
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or with pip:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install just-cli
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
### 📦 Archive & Extract
|
|
58
|
+
|
|
59
|
+
Create and extract archives with automatic format detection.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Create archives — format is determined by output extension
|
|
63
|
+
just archive mydir -o backup.zip
|
|
64
|
+
just archive mydir -o backup.tar.gz
|
|
65
|
+
just archive mydir -o backup.7z
|
|
66
|
+
just archive myfile.txt -o myfile.txt.gz # single-file compression
|
|
67
|
+
|
|
68
|
+
# Extract archives — magic bytes detection, works even with wrong extensions
|
|
69
|
+
just extract backup.zip
|
|
70
|
+
just extract data.tar.gz -o ./output_dir
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary><strong>Supported formats</strong></summary>
|
|
75
|
+
|
|
76
|
+
| Format | Archive | Extract |
|
|
77
|
+
|--------|:-------:|:-------:|
|
|
78
|
+
| `.zip` | ✅ | ✅ |
|
|
79
|
+
| `.tar` | ✅ | ✅ |
|
|
80
|
+
| `.tar.gz` / `.tgz` | ✅ | ✅ |
|
|
81
|
+
| `.tar.bz2` / `.tbz2` | ✅ | ✅ |
|
|
82
|
+
| `.tar.xz` / `.txz` | ✅ | ✅ |
|
|
83
|
+
| `.tar.zst` / `.tzst` | ✅ | ✅ |
|
|
84
|
+
| `.gz` | ✅ | ✅ |
|
|
85
|
+
| `.bz2` | ✅ | ✅ |
|
|
86
|
+
| `.xz` | ✅ | ✅ |
|
|
87
|
+
| `.zst` | ✅ | ✅ |
|
|
88
|
+
| `.7z` | ✅ | ✅ |
|
|
89
|
+
|
|
90
|
+
</details>
|
|
91
|
+
|
|
92
|
+
### 📥 Download
|
|
93
|
+
|
|
94
|
+
Like `wget` or `curl`, but with auto-resume **by default** and a progress bar.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Filename is automatically extracted from URL, resume is on by default
|
|
98
|
+
just download https://example.com/big-file.zip
|
|
99
|
+
|
|
100
|
+
# Custom headers and output name
|
|
101
|
+
just download https://api.example.com/data -H "Authorization: Bearer token" -o data.json
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 📝 Edit
|
|
105
|
+
|
|
106
|
+
A lightweight TUI text editor built right in.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
just edit README.md
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+

|
|
113
|
+
|
|
114
|
+
### 📖 View
|
|
115
|
+
|
|
116
|
+
Smart file viewer with syntax highlighting, TOC, and structured rendering.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
just view README.md # Markdown
|
|
120
|
+
just view data.json # JSON
|
|
121
|
+
just view config.xml # XML
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+

|
|
125
|
+
|
|
126
|
+
### 🌐 Tunnel
|
|
127
|
+
|
|
128
|
+
Expose your local server to the internet via Cloudflare Tunnel.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
just tunnel http://localhost:8000
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 🐧 File Operations
|
|
135
|
+
|
|
136
|
+
Common file commands, cross-platform, no syntax surprises.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
just cat file.txt
|
|
140
|
+
just ls
|
|
141
|
+
just cp src dst
|
|
142
|
+
just mv old new
|
|
143
|
+
just rm file
|
|
144
|
+
just mkdir dir
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 📒 Notes
|
|
148
|
+
|
|
149
|
+
Quick notes stored in `~/.just/notes`.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
just note
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+

|
|
156
|
+
|
|
157
|
+
### 🧩 Extension System
|
|
158
|
+
|
|
159
|
+
Turn any long command into a reusable, type-safe CLI in 2 steps.
|
|
160
|
+
|
|
161
|
+
**1. Register the base command:**
|
|
162
|
+
```bash
|
|
163
|
+
just ext add docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' f523e75ca4ef
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**2. Define your CLI by marking dynamic parts:**
|
|
167
|
+
```text
|
|
168
|
+
Enter extension commands: just docker ip f523e75ca4ef[container_id:str#The Container ID]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Done.** Now use it:
|
|
172
|
+
```bash
|
|
173
|
+
just docker ip <container_id>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Under the hood, `just` generates a native Python script using typer — with auto-completion, type validation, and help messages. All from simple **string replacement**.
|
|
177
|
+
|
|
178
|
+
### 💿 Installer Framework
|
|
179
|
+
|
|
180
|
+
Automate installation scripts with system probing and binary/archive helpers.
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
@just.installer(check="cloudflared --version")
|
|
184
|
+
def install_cloudflared():
|
|
185
|
+
if just.system.pms.brew.is_available():
|
|
186
|
+
just.execute_commands("brew install cloudflared")
|
|
187
|
+
elif just.system.platform == 'linux':
|
|
188
|
+
just.BinaryInstaller(
|
|
189
|
+
url='https://github.com/cloudflare/cloudflared/releases/.../cloudflared-linux-amd64',
|
|
190
|
+
alias='cloudflared'
|
|
191
|
+
).run()
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Built-in system info:
|
|
195
|
+
- `just.system.platform` → `linux`, `windows`, `darwin`
|
|
196
|
+
- `just.system.arch` → `x86_64`, `aarch64`
|
|
197
|
+
- `just.system.pms` → detects `winget`, `brew`, `apt`, etc.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
Found a bug? Want a new feature?
|
|
204
|
+
Fork it, fix it, ship it. Keep it cool, keep it simple, don't break the *"just works"* vibe.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
[MIT](LICENSE)
|
just_cli-0.5.0/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
<h1 align="center">🛠️ JUST CLI</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center"><strong>The simple stuff should be simple.</strong></p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://pypi.org/project/just-cli/"> <img src="https://img.shields.io/pypi/v/just-cli?color=blue" alt="PyPI"></a>
|
|
7
|
+
<a href="https://pypi.org/project/just-cli/"> <img src="https://img.shields.io/pypi/pyversions/just-cli" alt="Python"></a>
|
|
8
|
+
<img src="https://img.shields.io/badge/license-MIT-purple.svg" alt="License: MIT">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
Tired of Googling "how to install X" for the 47th time, just to end up copy-pasting from official docs?
|
|
13
|
+
</p>
|
|
14
|
+
<p align="center">
|
|
15
|
+
Tired of copy-pasting giant commands every time, just to change one little parameter?
|
|
16
|
+
</p>
|
|
17
|
+
<p align="center">
|
|
18
|
+
Start using <b>Just</b> — an all-in-one CLI toolkit that makes everyday developer tasks <i>actually simple</i>.
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool install just-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or with pip:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install just-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
### 📦 Archive & Extract
|
|
40
|
+
|
|
41
|
+
Create and extract archives with automatic format detection.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Create archives — format is determined by output extension
|
|
45
|
+
just archive mydir -o backup.zip
|
|
46
|
+
just archive mydir -o backup.tar.gz
|
|
47
|
+
just archive mydir -o backup.7z
|
|
48
|
+
just archive myfile.txt -o myfile.txt.gz # single-file compression
|
|
49
|
+
|
|
50
|
+
# Extract archives — magic bytes detection, works even with wrong extensions
|
|
51
|
+
just extract backup.zip
|
|
52
|
+
just extract data.tar.gz -o ./output_dir
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
<details>
|
|
56
|
+
<summary><strong>Supported formats</strong></summary>
|
|
57
|
+
|
|
58
|
+
| Format | Archive | Extract |
|
|
59
|
+
|--------|:-------:|:-------:|
|
|
60
|
+
| `.zip` | ✅ | ✅ |
|
|
61
|
+
| `.tar` | ✅ | ✅ |
|
|
62
|
+
| `.tar.gz` / `.tgz` | ✅ | ✅ |
|
|
63
|
+
| `.tar.bz2` / `.tbz2` | ✅ | ✅ |
|
|
64
|
+
| `.tar.xz` / `.txz` | ✅ | ✅ |
|
|
65
|
+
| `.tar.zst` / `.tzst` | ✅ | ✅ |
|
|
66
|
+
| `.gz` | ✅ | ✅ |
|
|
67
|
+
| `.bz2` | ✅ | ✅ |
|
|
68
|
+
| `.xz` | ✅ | ✅ |
|
|
69
|
+
| `.zst` | ✅ | ✅ |
|
|
70
|
+
| `.7z` | ✅ | ✅ |
|
|
71
|
+
|
|
72
|
+
</details>
|
|
73
|
+
|
|
74
|
+
### 📥 Download
|
|
75
|
+
|
|
76
|
+
Like `wget` or `curl`, but with auto-resume **by default** and a progress bar.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Filename is automatically extracted from URL, resume is on by default
|
|
80
|
+
just download https://example.com/big-file.zip
|
|
81
|
+
|
|
82
|
+
# Custom headers and output name
|
|
83
|
+
just download https://api.example.com/data -H "Authorization: Bearer token" -o data.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 📝 Edit
|
|
87
|
+
|
|
88
|
+
A lightweight TUI text editor built right in.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
just edit README.md
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+

|
|
95
|
+
|
|
96
|
+
### 📖 View
|
|
97
|
+
|
|
98
|
+
Smart file viewer with syntax highlighting, TOC, and structured rendering.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
just view README.md # Markdown
|
|
102
|
+
just view data.json # JSON
|
|
103
|
+
just view config.xml # XML
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
### 🌐 Tunnel
|
|
109
|
+
|
|
110
|
+
Expose your local server to the internet via Cloudflare Tunnel.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
just tunnel http://localhost:8000
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 🐧 File Operations
|
|
117
|
+
|
|
118
|
+
Common file commands, cross-platform, no syntax surprises.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
just cat file.txt
|
|
122
|
+
just ls
|
|
123
|
+
just cp src dst
|
|
124
|
+
just mv old new
|
|
125
|
+
just rm file
|
|
126
|
+
just mkdir dir
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 📒 Notes
|
|
130
|
+
|
|
131
|
+
Quick notes stored in `~/.just/notes`.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
just note
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+

|
|
138
|
+
|
|
139
|
+
### 🧩 Extension System
|
|
140
|
+
|
|
141
|
+
Turn any long command into a reusable, type-safe CLI in 2 steps.
|
|
142
|
+
|
|
143
|
+
**1. Register the base command:**
|
|
144
|
+
```bash
|
|
145
|
+
just ext add docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' f523e75ca4ef
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**2. Define your CLI by marking dynamic parts:**
|
|
149
|
+
```text
|
|
150
|
+
Enter extension commands: just docker ip f523e75ca4ef[container_id:str#The Container ID]
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Done.** Now use it:
|
|
154
|
+
```bash
|
|
155
|
+
just docker ip <container_id>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Under the hood, `just` generates a native Python script using typer — with auto-completion, type validation, and help messages. All from simple **string replacement**.
|
|
159
|
+
|
|
160
|
+
### 💿 Installer Framework
|
|
161
|
+
|
|
162
|
+
Automate installation scripts with system probing and binary/archive helpers.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
@just.installer(check="cloudflared --version")
|
|
166
|
+
def install_cloudflared():
|
|
167
|
+
if just.system.pms.brew.is_available():
|
|
168
|
+
just.execute_commands("brew install cloudflared")
|
|
169
|
+
elif just.system.platform == 'linux':
|
|
170
|
+
just.BinaryInstaller(
|
|
171
|
+
url='https://github.com/cloudflare/cloudflared/releases/.../cloudflared-linux-amd64',
|
|
172
|
+
alias='cloudflared'
|
|
173
|
+
).run()
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Built-in system info:
|
|
177
|
+
- `just.system.platform` → `linux`, `windows`, `darwin`
|
|
178
|
+
- `just.system.arch` → `x86_64`, `aarch64`
|
|
179
|
+
- `just.system.pms` → detects `winget`, `brew`, `apt`, etc.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Contributing
|
|
184
|
+
|
|
185
|
+
Found a bug? Want a new feature?
|
|
186
|
+
Fork it, fix it, ship it. Keep it cool, keep it simple, don't break the *"just works"* vibe.
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
[MIT](LICENSE)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "just-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "Your all-in-one CLI Toolkit"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -14,7 +14,7 @@ dependencies = [
|
|
|
14
14
|
"py7zr",
|
|
15
15
|
"rich>=14.2.0",
|
|
16
16
|
"textual>=6.4.0",
|
|
17
|
-
"typer>=0.
|
|
17
|
+
"typer>=0.26.0",
|
|
18
18
|
"zstandard",
|
|
19
19
|
]
|
|
20
20
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Rename all AGENTS.md files to CLAUDE.md under a given workspace."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def agents_to_claude(workspace: str) -> list[Path]:
|
|
9
|
+
renamed = []
|
|
10
|
+
for dirpath, _, filenames in os.walk(workspace):
|
|
11
|
+
if "AGENTS.md" in filenames:
|
|
12
|
+
old_path = Path(dirpath) / "AGENTS.md"
|
|
13
|
+
new_path = Path(dirpath) / "CLAUDE.md"
|
|
14
|
+
old_path.rename(new_path)
|
|
15
|
+
renamed.append(new_path)
|
|
16
|
+
return renamed
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main() -> None:
|
|
20
|
+
parser = argparse.ArgumentParser(
|
|
21
|
+
description="Rename all AGENTS.md files to CLAUDE.md under a workspace."
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"workspace",
|
|
25
|
+
nargs="?",
|
|
26
|
+
default="./",
|
|
27
|
+
help="Root directory to search (default: current directory)",
|
|
28
|
+
)
|
|
29
|
+
args = parser.parse_args()
|
|
30
|
+
|
|
31
|
+
renamed = agents_to_claude(args.workspace)
|
|
32
|
+
if renamed:
|
|
33
|
+
for path in renamed:
|
|
34
|
+
print(f"Renamed: {path}")
|
|
35
|
+
print(f"\nTotal: {len(renamed)} file(s) renamed.")
|
|
36
|
+
else:
|
|
37
|
+
print("No AGENTS.md files found.")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Rename all CLAUDE.md files to AGENTS.md under a given workspace."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def claude_to_agents(workspace: str) -> list[Path]:
|
|
9
|
+
renamed = []
|
|
10
|
+
for dirpath, _, filenames in os.walk(workspace):
|
|
11
|
+
if "CLAUDE.md" in filenames:
|
|
12
|
+
old_path = Path(dirpath) / "CLAUDE.md"
|
|
13
|
+
new_path = Path(dirpath) / "AGENTS.md"
|
|
14
|
+
old_path.rename(new_path)
|
|
15
|
+
renamed.append(new_path)
|
|
16
|
+
return renamed
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main() -> None:
|
|
20
|
+
parser = argparse.ArgumentParser(
|
|
21
|
+
description="Rename all CLAUDE.md files to AGENTS.md under a workspace."
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"workspace",
|
|
25
|
+
nargs="?",
|
|
26
|
+
default="./",
|
|
27
|
+
help="Root directory to search (default: current directory)",
|
|
28
|
+
)
|
|
29
|
+
args = parser.parse_args()
|
|
30
|
+
|
|
31
|
+
renamed = claude_to_agents(args.workspace)
|
|
32
|
+
if renamed:
|
|
33
|
+
for path in renamed:
|
|
34
|
+
print(f"Renamed: {path}")
|
|
35
|
+
print(f"\nTotal: {len(renamed)} file(s) renamed.")
|
|
36
|
+
else:
|
|
37
|
+
print("No CLAUDE.md files found.")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -9,7 +9,10 @@ from typing import Any, Callable, List, TypeVar, Optional
|
|
|
9
9
|
|
|
10
10
|
from just.core.config import load_env_config, get_command_dir, get_extension_dir, ensure_extensions_dir_exists
|
|
11
11
|
from just.utils import echo
|
|
12
|
-
from just.utils.typer_utils import create_typer_app
|
|
12
|
+
from just.utils.typer_utils import create_typer_app, get_just_version
|
|
13
|
+
|
|
14
|
+
import typer
|
|
15
|
+
from typing import Annotated
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
just_cli = create_typer_app()
|
|
@@ -17,6 +20,27 @@ just_cli = create_typer_app()
|
|
|
17
20
|
T = TypeVar('T')
|
|
18
21
|
|
|
19
22
|
|
|
23
|
+
def _version_callback(value: Optional[bool]):
|
|
24
|
+
if value:
|
|
25
|
+
echo.echo(f"just {get_just_version()}")
|
|
26
|
+
raise SystemExit(0)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@just_cli.callback()
|
|
30
|
+
def _main_callback(
|
|
31
|
+
version: Annotated[
|
|
32
|
+
Optional[bool],
|
|
33
|
+
typer.Option(
|
|
34
|
+
"-v", "--version",
|
|
35
|
+
help="Show version and exit",
|
|
36
|
+
is_eager=True,
|
|
37
|
+
callback=_version_callback,
|
|
38
|
+
),
|
|
39
|
+
] = None,
|
|
40
|
+
):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
20
44
|
def capture_exception(func: Callable[..., T]) -> Callable[..., Optional[T]]:
|
|
21
45
|
@functools.wraps(func)
|
|
22
46
|
def wrapper(*args: Any, **kwargs: Any) -> Optional[T]:
|
|
@@ -32,8 +56,8 @@ def capture_exception(func: Callable[..., T]) -> Callable[..., Optional[T]]:
|
|
|
32
56
|
class SortedGroup(TyperGroup):
|
|
33
57
|
def list_commands(self, ctx):
|
|
34
58
|
return sorted(super().list_commands(ctx))
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
|
|
60
|
+
|
|
37
61
|
def run_just_cli(*args, **kwargs):
|
|
38
62
|
load_env_config()
|
|
39
63
|
just_cli(*args, **kwargs)
|
|
@@ -56,11 +80,11 @@ def load_extensions_dynamically():
|
|
|
56
80
|
extensions_dir = get_extension_dir()
|
|
57
81
|
if not extensions_dir.exists():
|
|
58
82
|
return
|
|
59
|
-
|
|
83
|
+
|
|
60
84
|
import sys
|
|
61
85
|
if str(extensions_dir.parent) not in sys.path:
|
|
62
86
|
sys.path.insert(0, str(extensions_dir.parent))
|
|
63
|
-
|
|
87
|
+
|
|
64
88
|
for root, dirs, files in os.walk(extensions_dir):
|
|
65
89
|
for file in files:
|
|
66
90
|
if not file.startswith('_') and file.endswith(".py"):
|
|
@@ -72,11 +96,10 @@ def load_extensions_dynamically():
|
|
|
72
96
|
echo.warning(f"Failed to load extension {file}: {e}")
|
|
73
97
|
|
|
74
98
|
|
|
75
|
-
|
|
76
99
|
def main():
|
|
77
100
|
# Ensure extensions directory exists
|
|
78
101
|
ensure_extensions_dir_exists()
|
|
79
|
-
|
|
102
|
+
|
|
80
103
|
# Dynamically import all script modules to register their commands
|
|
81
104
|
script_modules = []
|
|
82
105
|
commands_dir = get_command_dir()
|
|
@@ -85,22 +108,20 @@ def main():
|
|
|
85
108
|
missing_packages = []
|
|
86
109
|
for module_name in script_modules:
|
|
87
110
|
try:
|
|
88
|
-
# echo.debug("Importing", module_name)
|
|
89
111
|
importlib.import_module(module_name)
|
|
90
112
|
except ImportError as e:
|
|
91
113
|
traceback.print_exc()
|
|
92
114
|
package_name = e.name
|
|
93
115
|
if package_name not in missing_packages:
|
|
94
116
|
missing_packages.append(package_name)
|
|
95
|
-
# Handle the case where the module cannot be found
|
|
96
117
|
echo.warning(
|
|
97
118
|
f"`{package_name}` is not installed, some sub commands are disabled, "
|
|
98
119
|
f"refer to README.md for instructions."
|
|
99
120
|
)
|
|
100
121
|
continue
|
|
101
|
-
|
|
122
|
+
|
|
102
123
|
# Load extensions from ~/.just/extensions
|
|
103
124
|
load_extensions_dynamically()
|
|
104
|
-
|
|
125
|
+
|
|
105
126
|
# Run the CLI application
|
|
106
|
-
run_just_cli()
|
|
127
|
+
run_just_cli()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from just import Annotated, just_cli, capture_exception
|
|
6
|
+
from just.utils import echo
|
|
7
|
+
from just.utils.archive import archive as archive_create, detect_format_by_extension, ArchiveFormat
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@just_cli.command(name="archive")
|
|
11
|
+
@capture_exception
|
|
12
|
+
def archive_command(
|
|
13
|
+
source: Annotated[str, typer.Argument(
|
|
14
|
+
help="Path to the file or directory to archive"
|
|
15
|
+
)],
|
|
16
|
+
output: Annotated[str, typer.Option(
|
|
17
|
+
"-o", "--output",
|
|
18
|
+
help="Output archive file path (format detected from extension)"
|
|
19
|
+
)],
|
|
20
|
+
) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Create archives and compressed files.
|
|
23
|
+
|
|
24
|
+
Supports: ZIP, TAR (with gz/bz2/xz/zst compression), GZIP, BZIP2, XZ, ZSTD, 7Z
|
|
25
|
+
|
|
26
|
+
Format is automatically determined by the output file extension.
|
|
27
|
+
Single-file formats (gz, bz2, xz, zst) only accept a single file source.
|
|
28
|
+
|
|
29
|
+
Optional dependencies:
|
|
30
|
+
- 7Z support: pip install py7zr
|
|
31
|
+
- ZSTD support: pip install zstandard
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
just archive mydir -o backup.zip # Create ZIP archive
|
|
35
|
+
just archive mydir -o backup.tar.gz # Create tar.gz archive
|
|
36
|
+
just archive myfile.txt -o myfile.txt.gz # Compress single file with gzip
|
|
37
|
+
just archive mydir -o backup.7z # Create 7z archive
|
|
38
|
+
"""
|
|
39
|
+
source_path = Path(source)
|
|
40
|
+
|
|
41
|
+
if not source_path.exists():
|
|
42
|
+
echo.error(f"Source not found: {source}")
|
|
43
|
+
raise typer.Exit(1)
|
|
44
|
+
|
|
45
|
+
fmt = detect_format_by_extension(output)
|
|
46
|
+
if fmt is None or fmt == ArchiveFormat.UNKNOWN:
|
|
47
|
+
echo.error(f"Unknown archive format for output: {output}")
|
|
48
|
+
echo.info("Supported: .zip, .tar, .tar.gz, .tgz, .tar.bz2, .tbz, "
|
|
49
|
+
".tar.xz, .txz, .tar.zst, .tzst, .gz, .bz2, .xz, .zst, .7z")
|
|
50
|
+
raise typer.Exit(1)
|
|
51
|
+
|
|
52
|
+
if fmt == ArchiveFormat.RAR:
|
|
53
|
+
echo.error("RAR format is not supported for archiving")
|
|
54
|
+
raise typer.Exit(1)
|
|
55
|
+
|
|
56
|
+
if not archive_create([str(source_path)], output, base_dir=str(source_path.parent)):
|
|
57
|
+
raise Exception("Failed to create archive")
|