shellscripts 0.23.1__py3-none-any.whl

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. shell_scripts/__init__.py +5 -0
  2. shell_scripts/__main__.py +5 -0
  3. shell_scripts/commands/__init__.py +81 -0
  4. shell_scripts/commands/_dc_common.py +138 -0
  5. shell_scripts/commands/ai_install.py +453 -0
  6. shell_scripts/commands/bin_links.py +78 -0
  7. shell_scripts/commands/claude.py +56 -0
  8. shell_scripts/commands/clean.py +98 -0
  9. shell_scripts/commands/codex.py +107 -0
  10. shell_scripts/commands/copilot.py +54 -0
  11. shell_scripts/commands/dicom2jpg.py +98 -0
  12. shell_scripts/commands/dicomviewer.py +83 -0
  13. shell_scripts/commands/diff_cmd.py +50 -0
  14. shell_scripts/commands/doxygen_cmd.py +159 -0
  15. shell_scripts/commands/edit_cmd.py +50 -0
  16. shell_scripts/commands/gemini.py +54 -0
  17. shell_scripts/commands/kiro.py +54 -0
  18. shell_scripts/commands/opencode.py +54 -0
  19. shell_scripts/commands/pdf_crop.py +520 -0
  20. shell_scripts/commands/pdf_merge.py +180 -0
  21. shell_scripts/commands/pdf_split_by_format.py +243 -0
  22. shell_scripts/commands/pdf_split_by_toc.py +197 -0
  23. shell_scripts/commands/pdf_tiler_090.py +61 -0
  24. shell_scripts/commands/pdf_tiler_100.py +61 -0
  25. shell_scripts/commands/pdf_toc_clean.py +175 -0
  26. shell_scripts/commands/pi.py +61 -0
  27. shell_scripts/commands/req_cmd.py +362 -0
  28. shell_scripts/commands/tests_cmd.py +87 -0
  29. shell_scripts/commands/ubuntu_dark_theme.py +64 -0
  30. shell_scripts/commands/venv_cmd.py +82 -0
  31. shell_scripts/commands/video2h264.py +89 -0
  32. shell_scripts/commands/video2h265.py +87 -0
  33. shell_scripts/commands/view_cmd.py +50 -0
  34. shell_scripts/commands/vscode_cmd.py +42 -0
  35. shell_scripts/commands/vsinsider_cmd.py +42 -0
  36. shell_scripts/config.py +328 -0
  37. shell_scripts/core.py +324 -0
  38. shell_scripts/utils.py +455 -0
  39. shell_scripts/version_check.py +323 -0
  40. shellscripts-0.23.1.dist-info/METADATA +310 -0
  41. shellscripts-0.23.1.dist-info/RECORD +45 -0
  42. shellscripts-0.23.1.dist-info/WHEEL +5 -0
  43. shellscripts-0.23.1.dist-info/entry_points.txt +3 -0
  44. shellscripts-0.23.1.dist-info/licenses/LICENSE +674 -0
  45. shellscripts-0.23.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,323 @@
1
+ #!/usr/bin/env python3
2
+ """@brief Update-check orchestration for shellscripts startup.
3
+
4
+ @details Performs cooldown-gated PyPI registry checks for the startup update
5
+ notification, resolves GitHub release tags for develop upgrades and version
6
+ display, persists cache metadata for every request outcome, and prints
7
+ terminal-visible update or error status lines. Successful requests apply the
8
+ default cooldown. Request errors apply the enlarged cooldown without aborting
9
+ CLI startup continuity.
10
+ @satisfies PRJ-004, DES-002, DES-003, DES-004, DES-005, DES-006, DES-018, DES-019, DES-020, REQ-003, REQ-075, REQ-059, REQ-060, REQ-061
11
+ """
12
+
13
+ import json
14
+ import sys
15
+ import time
16
+ import urllib.error
17
+ import urllib.request
18
+ from datetime import datetime, timezone
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ PROGRAM = "shellscripts"
23
+ OWNER = "Ogekuri"
24
+ REPOSITORY = "shellScripts"
25
+ IDLE_DELAY = 3600
26
+ HTTP_ERROR_IDLE_DELAY = 86400
27
+ HTTP_TIMEOUT = 2
28
+ GITHUB_API_URL = f"https://api.github.com/repos/{OWNER}/{REPOSITORY}/releases/latest"
29
+ PYPI_API_URL = f"https://pypi.org/pypi/{PROGRAM}/json"
30
+ CACHE_DIR = Path.home() / ".cache" / PROGRAM
31
+ IDLE_TIME_FILE = CACHE_DIR / "check_version_idle-time.json"
32
+
33
+ BRIGHT_GREEN = "\033[92m"
34
+ BRIGHT_RED = "\033[91m"
35
+ RESET = "\033[0m"
36
+
37
+
38
+ def _read_idle_config() -> dict[str, object] | None:
39
+ """@brief Load cached cooldown metadata for the version check.
40
+
41
+ @details Reads the cooldown JSON payload from the user cache directory.
42
+ Absent files and unreadable JSON payloads resolve to `None`. Complexity:
43
+ O(1) for fixed-size payload parsing.
44
+ @return {dict[str, object] | None} Cached cooldown payload or `None`.
45
+ @satisfies DES-003, REQ-059
46
+ """
47
+
48
+ if not IDLE_TIME_FILE.exists():
49
+ return None
50
+ try:
51
+ with open(IDLE_TIME_FILE) as f:
52
+ return json.load(f)
53
+ except (json.JSONDecodeError, OSError):
54
+ return None
55
+
56
+
57
+ def _write_idle_config(last_check_ts: float, idle_delay_seconds: int) -> None:
58
+ """@brief Persist cooldown timestamps for the next version-check gate.
59
+
60
+ @details Derives the idle-until timestamp from the supplied delay, writes
61
+ both machine-readable timestamps and UTC-rendered strings, and stores the
62
+ applied delay for downstream inspection. Complexity: O(1).
63
+ @param last_check_ts {float} UNIX timestamp recorded for the current check.
64
+ @param idle_delay_seconds {int} Cooldown duration applied after the check.
65
+ @return {None} No return value.
66
+ @throws {OSError} Propagated when cache directory creation or file write fails.
67
+ @satisfies DES-003, DES-004, DES-005, REQ-061
68
+ """
69
+
70
+ CACHE_DIR.mkdir(parents=True, exist_ok=True)
71
+ idle_until_ts = last_check_ts + idle_delay_seconds
72
+ data = {
73
+ "last_check_timestamp": last_check_ts,
74
+ "last_check_human": datetime.fromtimestamp(
75
+ last_check_ts, tz=timezone.utc
76
+ ).strftime("%Y-%m-%d %H:%M:%S UTC"),
77
+ "idle_delay_seconds": idle_delay_seconds,
78
+ "idle_until_timestamp": idle_until_ts,
79
+ "idle_until_human": datetime.fromtimestamp(
80
+ idle_until_ts, tz=timezone.utc
81
+ ).strftime("%Y-%m-%d %H:%M:%S UTC"),
82
+ }
83
+ with open(IDLE_TIME_FILE, "w") as f:
84
+ json.dump(data, f, indent=2)
85
+
86
+
87
+ def _is_forced_version_check() -> bool:
88
+ """@brief Detect CLI flags that force the version-check HTTP request.
89
+
90
+ @details Evaluates the live process argument vector and returns `True` when
91
+ the current invocation requested `--version` or `--ver`. Complexity: O(N)
92
+ where N is the number of CLI arguments.
93
+ @return {bool} `True` when the request must bypass cooldown gating.
94
+ @satisfies REQ-003, REQ-059
95
+ """
96
+
97
+ return any(arg in ("--version", "--ver") for arg in sys.argv[1:])
98
+
99
+
100
+ def _format_request_error(error: Exception) -> str:
101
+ """@brief Convert a request exception into terminal output detail text.
102
+
103
+ @details Returns a stable, parser-friendly error descriptor for HTTP and
104
+ non-HTTP request failures. HTTP errors preserve the status code. Non-HTTP
105
+ errors expose the exception type and optional message. Complexity: O(1).
106
+ @param error {Exception} Request failure captured during update checking.
107
+ @return {str} Error detail suffix without terminal color codes.
108
+ @satisfies DES-005, DES-006, REQ-061
109
+ """
110
+
111
+ if isinstance(error, urllib.error.HTTPError):
112
+ if error.code in (403, 429):
113
+ return f"rate limit exceeded (HTTP {error.code})"
114
+ return f"HTTP {error.code}"
115
+
116
+ error_type = type(error).__name__
117
+ error_message = str(error).strip()
118
+ if error_message:
119
+ return f"{error_type}: {error_message}"
120
+ return error_type
121
+
122
+
123
+ def _handle_request_error(last_check_ts: float, error: Exception) -> None:
124
+ """@brief Persist cooldown metadata and print the request error line.
125
+
126
+ @details Applies the fixed HTTP-error cooldown, updates the cooldown JSON,
127
+ and emits a bright-red terminal line for the supplied request failure.
128
+ Complexity: O(1) excluding filesystem latency.
129
+ @param last_check_ts {float} UNIX timestamp recorded for the failed check.
130
+ @param error {Exception} Request failure captured during update checking.
131
+ @return {None} No return value.
132
+ @throws {OSError} Propagated when cache directory creation or file write fails.
133
+ @satisfies DES-003, DES-005, DES-006, REQ-061
134
+ """
135
+
136
+ _write_idle_config(last_check_ts, HTTP_ERROR_IDLE_DELAY)
137
+ print(f"{BRIGHT_RED}Update check failed: {_format_request_error(error)}.{RESET}")
138
+
139
+
140
+ def _should_check(force_check: bool = False) -> bool:
141
+ """@brief Evaluate whether the GitHub version-check request should run.
142
+
143
+ @details Forces execution when `force_check` is `True`; otherwise reads the
144
+ cached idle-until timestamp and compares it against the current wall-clock
145
+ time. Complexity: O(1).
146
+ @param force_check {bool} Cooldown-bypass flag derived from CLI arguments.
147
+ @return {bool} `True` when the HTTP request is allowed or forced.
148
+ @satisfies REQ-003, REQ-059
149
+ """
150
+
151
+ if force_check:
152
+ return True
153
+ config = _read_idle_config()
154
+ if config is None:
155
+ return True
156
+ idle_until = config.get("idle_until_timestamp", 0)
157
+ if not isinstance(idle_until, (int, float)):
158
+ return True
159
+ return time.time() >= idle_until
160
+
161
+
162
+ def _parse_version(version_value: str) -> tuple[int, ...]:
163
+ """@brief Convert a semantic-version string into an integer tuple.
164
+
165
+ @details Strips a leading `v` prefix, splits by `.`, and converts each
166
+ segment to `int`. Complexity: O(N) where N is the number of segments.
167
+ @param version_value {str} Raw semantic version token.
168
+ @return {tuple[int, ...]} Parsed numeric version segments.
169
+ @throws {ValueError} Propagated when a segment is not numeric.
170
+ @satisfies PRJ-004
171
+ """
172
+
173
+ return tuple(int(part) for part in version_value.strip().lstrip("v").split("."))
174
+
175
+
176
+ def _compare_versions(current: str, latest: str) -> bool:
177
+ """@brief Compare installed and latest semantic versions.
178
+
179
+ @details Parses both version strings into integer tuples and returns
180
+ `True` only when `latest` is newer than `current`. Invalid inputs collapse
181
+ to `False`. Complexity: O(N).
182
+ @param current {str} Installed package version.
183
+ @param latest {str} Latest GitHub release version.
184
+ @return {bool} `True` when the remote version is newer.
185
+ @satisfies PRJ-004, REQ-060
186
+ """
187
+
188
+ try:
189
+ return _parse_version(latest) > _parse_version(current)
190
+ except (ValueError, AttributeError):
191
+ return False
192
+
193
+
194
+ def _fetch_json_payload(
195
+ url: str, current_version: str, accept_header: str
196
+ ) -> dict[str, Any]:
197
+ """@brief Fetch and decode one JSON payload over HTTP.
198
+
199
+ @details Issues a GET request with caller-supplied `Accept` header and a
200
+ program/version `User-Agent`, then decodes the response body as a JSON
201
+ object. Time complexity O(n) over payload size.
202
+ @param url {str} Remote JSON endpoint URL.
203
+ @param current_version {str} Installed package version used in User-Agent.
204
+ @param accept_header {str} Value of the HTTP `Accept` header.
205
+ @return {dict[str, Any]} Parsed JSON response object.
206
+ @throws {urllib.error.HTTPError} On HTTP error responses.
207
+ @throws {urllib.error.URLError} On connection failures.
208
+ @throws {json.JSONDecodeError} On malformed payload bodies.
209
+ @satisfies DES-018, DES-019
210
+ """
211
+
212
+ request = urllib.request.Request(url)
213
+ request.add_header("Accept", accept_header)
214
+ request.add_header("User-Agent", f"{PROGRAM}/{current_version}")
215
+ with urllib.request.urlopen(request, timeout=HTTP_TIMEOUT) as response:
216
+ return json.loads(response.read().decode())
217
+
218
+
219
+ def fetch_pypi_latest_version(current_version: str) -> str:
220
+ """@brief Resolve the latest published version from the PyPI registry.
221
+
222
+ @details Queries the PyPI JSON API for this program and extracts field
223
+ `info.version`. Complexity O(1) over response object size.
224
+ @param current_version {str} Installed package version used in User-Agent.
225
+ @return {str} Latest published version token (for example `1.2.3`).
226
+ @throws {urllib.error.HTTPError} On HTTP error responses.
227
+ @throws {urllib.error.URLError} On connection failures.
228
+ @throws {json.JSONDecodeError} On malformed payload bodies.
229
+ @throws {KeyError} When `info.version` fields are absent.
230
+ @satisfies DES-018, PRJ-004
231
+ """
232
+
233
+ payload = _fetch_json_payload(
234
+ PYPI_API_URL, current_version, "application/vnd.pypi.simple.v1+json"
235
+ )
236
+ info = payload["info"]
237
+ return str(info["version"])
238
+
239
+
240
+ def fetch_github_latest_release(current_version: str) -> str:
241
+ """@brief Resolve the latest GitHub release tag regardless of its branch.
242
+
243
+ @details Queries the GitHub Releases API `latest` endpoint and extracts
244
+ field `tag_name`, which tracks the newest published tagged release across
245
+ any branch. Complexity O(1) over response object size.
246
+ @param current_version {str} Installed package version used in User-Agent.
247
+ @return {str} Latest release tag token preserving its `v` prefix.
248
+ @throws {urllib.error.HTTPError} On HTTP error responses.
249
+ @throws {urllib.error.URLError} On connection failures.
250
+ @throws {json.JSONDecodeError} On malformed payload bodies.
251
+ @throws {KeyError} When `tag_name` field is absent.
252
+ @satisfies DES-019, REQ-076
253
+ """
254
+
255
+ payload = _fetch_json_payload(
256
+ GITHUB_API_URL, current_version, "application/vnd.github.v3+json"
257
+ )
258
+ return str(payload["tag_name"])
259
+
260
+
261
+ def print_remote_latest_versions(current_version: str) -> None:
262
+ """@brief Print PyPI and GitHub latest-version report lines.
263
+
264
+ @details Emits one `<source> latest: <version>` line per remote source in
265
+ fixed order (PyPI, GitHub). A failed source lookup prints one bright-red
266
+ error line instead of its version line, and the remaining source is still
267
+ processed. Complexity O(1) excluding network latency.
268
+ @param current_version {str} Installed package version used in User-Agent.
269
+ @return {None} Writes two report or error lines to stdout.
270
+ @satisfies REQ-003, REQ-075, DES-020
271
+ """
272
+
273
+ for source_label, fetch_version in (
274
+ ("PyPI", fetch_pypi_latest_version),
275
+ ("GitHub", fetch_github_latest_release),
276
+ ):
277
+ try:
278
+ latest_version = fetch_version(current_version).lstrip("v")
279
+ except Exception as error:
280
+ print(
281
+ f"{BRIGHT_RED}{source_label} latest check failed: "
282
+ f"{_format_request_error(error)}.{RESET}"
283
+ )
284
+ continue
285
+ print(f"{source_label} latest: {latest_version}")
286
+
287
+
288
+ def check_for_updates(current_version: str) -> None:
289
+ """@brief Execute the startup PyPI registry version check.
290
+
291
+ @details Applies cooldown gating unless the current CLI invocation requests
292
+ `--version` or `--ver`, performs the PyPI latest-version HTTP request,
293
+ prints a bright-green update line for newer releases, persists a
294
+ 3600-second success cooldown or an 86400-second request-error cooldown for
295
+ every request outcome, prints bright-red request errors, and suppresses
296
+ propagation of non-HTTP request exceptions. Complexity O(1) excluding
297
+ network latency and JSON parsing.
298
+ @param current_version {str} Installed package version string.
299
+ @return {None} No return value.
300
+ @throws {urllib.error.HTTPError} Internally handled and converted to output.
301
+ @satisfies PRJ-004, DES-004, DES-005, DES-006, DES-018, REQ-003, REQ-059, REQ-060, REQ-061
302
+ """
303
+
304
+ if not _should_check(force_check=_is_forced_version_check()):
305
+ return
306
+
307
+ now = time.time()
308
+
309
+ try:
310
+ latest = fetch_pypi_latest_version(current_version)
311
+
312
+ if latest and _compare_versions(current_version, latest):
313
+ print(
314
+ f"{BRIGHT_GREEN}Versione Disponibile: {latest} | "
315
+ f"Versione Installata: {current_version}{RESET}"
316
+ )
317
+
318
+ _write_idle_config(now, IDLE_DELAY)
319
+
320
+ except urllib.error.HTTPError as error:
321
+ _handle_request_error(now, error)
322
+ except Exception as error:
323
+ _handle_request_error(now, error)
@@ -0,0 +1,310 @@
1
+ Metadata-Version: 2.4
2
+ Name: shellscripts
3
+ Version: 0.23.1
4
+ Summary: Execute useful shell scripts via an uvx-compatible CLI interface.
5
+ Author: Francesco Rolando
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/Ogekuri/shellScripts
8
+ Project-URL: Repository, https://github.com/Ogekuri/shellScripts
9
+ Keywords: shell,scripts,uv,astral,uvx,cli
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Dynamic: license-file
21
+
22
+ > [!CAUTION]
23
+ > ### 🚨 STRICTLY EXPERIMENTAL — PROOF OF CONCEPT (PRE-ALPHA)
24
+ >
25
+ > ![Status: Proof of Concept](https://img.shields.io/badge/Status-Proof_of_Concept-red?style=flat-square) ![Stage: Pre-Alpha](https://img.shields.io/badge/Stage-Pre--Alpha-critical?style=flat-square) ![Maintenance: Personal Use Only](https://img.shields.io/badge/Scope-Personal_Use_Only-important?style=flat-square) ![Issues: Closed](https://img.shields.io/badge/Issues_%26_PRs-Not_Accepted-inactive?style=flat-square)
26
+ >
27
+ > **PLEASE READ CAREFULLY BEFORE USING THIS SOFTWARE:**
28
+ >
29
+ > * **Very Early Stage:** This project is currently a raw **Proof of Concept (PoC)** in a **pre-alpha** state. It is nowhere near production-ready and may contain severe bugs, breaking changes, or incomplete logic.
30
+ > * **Personal Use Only:** This repository is developed, maintained, and shared strictly for **personal use**.
31
+ > * **No Support or Feature Requests:** Please **do not** open issues, bug reports, or feature requests. They will not be addressed or accepted at this stage of development.
32
+ > * **No Warranty:** This software is provided **"AS IS"**, without warranty of any kind, express or implied. You may use it strictly for **testing and evaluation purposes** at your own sole risk.
33
+
34
+ # s/shellScripts (0.23.1)
35
+
36
+ <p align="center">
37
+ <img src="https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python 3.11+">
38
+ <img src="https://img.shields.io/badge/license-GPL--3.0-491?style=flat-square" alt="License: GPL-3.0">
39
+ <img src="https://img.shields.io/badge/platform-Linux-6A7EC2?style=flat-square&logo=terminal&logoColor=white" alt="Platforms">
40
+ <img src="https://img.shields.io/badge/docs-live-b31b1b" alt="Docs">
41
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
42
+ </p>
43
+ <p align="center">
44
+ <strong>Execute useful shell scripts via an uvx-compatible CLI interface.</strong><br>
45
+ <code>shellscripts</code> is a Linux-first command collection for project automation, AI CLI launchers,
46
+ PDF/DICOM utilities, development helpers, and editor integrations, exposed through a single command.
47
+ <br>
48
+ </p>
49
+
50
+
51
+ <p align="center">
52
+ <a href="#quick-start">Quick Start</a> |
53
+ <a href="#feature-highlights">Feature Highlights</a> |
54
+ <a href="#management-commands">Upgrading or Removing</a> |
55
+ <a href="#shell-scripts">Shell Scripts</a>
56
+ </p>
57
+
58
+ <p align="center">
59
+ <br>
60
+ 🚧 <strong>DRAFT:</strong> Proof-of-Concept (PoC) Version 📝 - Work in Progress 🏗️ 🚧<br>
61
+ ⚠️ <strong>IMPORTANT NOTICE</strong>: Created with <a href="https://www.npmjs.com/package/pi-usereq"><strong>PI-useReq/pi-usereq</strong></a> 🤖✨ ⚠️<br>
62
+ <br>
63
+ </p>
64
+
65
+
66
+ ## Feature Highlights
67
+ - Single CLI entrypoint with command dispatch and grouped built-in help (`shellscripts` and alias `s`).
68
+ - AI tooling bootstrap command (`ai-install`) with per-tool selectors for Codex, Copilot, Gemini, OpenCode, Claude, and Kiro.
69
+ - Project-context launchers for AI CLIs (`claude`, `codex`, `copilot`, `gemini`, `kiro`, `opencode`, `pi`) and IDEs (`vscode`, `vsinsider`).
70
+ - PDF workflow commands for crop, merge, split, TOC cleanup, and tiling.
71
+ - DICOM helpers (`dicom2jpg`, `dicomviewer`) and video transcoders (`video2h264`, `video2h265`).
72
+ - Project maintenance and automation commands (`req`, `clean`, `venv`, `tests`, `doxygen`, `ubuntu-dark-theme`).
73
+ - Startup update notification with rate-limited checks against the PyPI registry.
74
+
75
+
76
+ ## Requirements
77
+
78
+ - Python `>=3.11`.
79
+ - Astral `uv` is required for install and runtime flows (`uv tool install`, `uvx`, `uv run`).
80
+ - Git is required for commands that enforce repository-root execution (`claude`, `codex`, `copilot`, `gemini`, `kiro`, `opencode`, `pi`, `clean`, `venv`, `tests`, `doxygen`, `vscode`, `vsinsider`).
81
+ - Command-specific external tools are required only for related commands:
82
+ - `npm` (and `sudo` on non-Windows) for npm-based `ai-install` targets.
83
+ - `req` for the `req` command.
84
+ - `doxygen` (plus optional `make` and `pdflatex`) for `doxygen`.
85
+ - `gs`, `pdfinfo`, `qpdf`, `pdftk`, `plakativ` for PDF commands.
86
+ - `ffmpeg` for `video2h264` and `video2h265`.
87
+ - Java runtime + PixelMed jars (+ `java-wrappers`) for DICOM commands.
88
+
89
+
90
+ ## Quick Start
91
+
92
+ ### Prerequisites
93
+
94
+ - Install `uv`: [https://docs.astral.sh/uv/getting-started/installation/](https://docs.astral.sh/uv/getting-started/installation/)
95
+
96
+
97
+ ### Install / Upgrade
98
+
99
+ Install from PyPI (primary distribution channel):
100
+
101
+ ```bash
102
+ uv tool install shellscripts
103
+ ```
104
+
105
+ Upgrade to the latest published PyPI release:
106
+
107
+ ```bash
108
+ s --upgrade
109
+ ```
110
+
111
+
112
+ ### Run Without Installing (uvx)
113
+
114
+ ```bash
115
+ uvx shellscripts <command> [args...]
116
+ ```
117
+
118
+
119
+ ### Run From a Local Clone
120
+
121
+ ```bash
122
+ ./scripts/s.sh <command> [args...]
123
+ ```
124
+
125
+ or
126
+
127
+ ```bash
128
+ uv run --project . python -m shell_scripts <command> [args...]
129
+ ```
130
+
131
+
132
+ ## Install from GitHub (Alternative)
133
+
134
+ PyPI is the primary distribution channel. As an alternative, the package can be installed from GitHub Releases, which also hosts intermediate and test releases that are not published on PyPI:
135
+
136
+ ```bash
137
+ uv tool install shellscripts --force --from git+https://github.com/Ogekuri/shellScripts.git@vX.Y.Z
138
+ ```
139
+
140
+ Intermediate and test releases are available at: [https://github.com/Ogekuri/shellScripts/releases](https://github.com/Ogekuri/shellScripts/releases).
141
+
142
+ To upgrade to the newest tagged GitHub release, regardless of the branch that carries the tag, use the `--dev` (alias `--develop`) flag together with `--upgrade`:
143
+
144
+ ```bash
145
+ s --upgrade --dev
146
+ # or
147
+ s --upgrade --develop
148
+ ```
149
+
150
+
151
+ ## Management Commands
152
+
153
+ Global syntax:
154
+
155
+ ```bash
156
+ shellscripts [command] [options]
157
+ # or
158
+ s [command] [options]
159
+ ```
160
+
161
+ Built-in management flags:
162
+
163
+ - `--help` : show full help or command help (`shellscripts --help <command>`).
164
+ - `--version` / `--ver` : print the installed version plus the latest versions available on PyPI and GitHub.
165
+ - `--upgrade` : run the configured upgrade command automatically on Linux (installs the latest PyPI release by default), otherwise print the manual command.
166
+ - `--upgrade --dev` / `--upgrade --develop` : upgrade from the latest tagged GitHub release instead of PyPI, regardless of its source branch.
167
+ - `--uninstall` : run configured uninstall command automatically on Linux, otherwise print the manual command.
168
+ - `--write-config` : write the default runtime configuration file.
169
+
170
+ ### Runtime Configuration
171
+
172
+ Generate a default config file:
173
+
174
+ ```bash
175
+ s --write-config
176
+ ```
177
+
178
+ Default location:
179
+
180
+ ```text
181
+ ~/.config/shellScripts/config.json
182
+ ```
183
+
184
+ Top-level configuration keys:
185
+
186
+ - `management`
187
+ - `upgrade`: command string executed by `--upgrade` (PyPI install by default).
188
+ - `upgrade_develop`: command template executed by `--upgrade --dev`; the `{tag}` placeholder is replaced with the latest GitHub release tag.
189
+ - `uninstall`: command string executed by `--uninstall`.
190
+ - `dispatch`
191
+ - `diff`, `edit`, `view`: each command supports `categories` and `fallback` command vectors.
192
+ - `req`
193
+ - `providers`: provider list forwarded to external `req`.
194
+ - `static_checks`: static-check entries forwarded to external `req`.
195
+
196
+
197
+ ## Shell Scripts
198
+
199
+ ### Command List
200
+
201
+ | Command | Purpose |
202
+ |---|---|
203
+ | `ai-install` | Install AI CLIs (all or selected tools). |
204
+ | `claude` | Launch Claude CLI in project context. |
205
+ | `codex` | Launch Codex CLI in project context with auth sync and `CODEX_HOME`. |
206
+ | `copilot` | Launch Copilot CLI in project context. |
207
+ | `gemini` | Launch Gemini CLI in project context. |
208
+ | `kiro` | Launch Kiro CLI in project context. |
209
+ | `opencode` | Launch OpenCode CLI in project context. |
210
+ | `pi` | Launch pi.dev CLI in project context (adds default `--tools` when missing). |
211
+ | `clean` | Find and delete cache directories under the project root (or a passed directory). |
212
+ | `req` | Run useReq bootstrap on current directory, first-level dirs, or recursively. |
213
+ | `venv` | Recreate `.venv` and install `requirements.txt` if present. |
214
+ | `tests` | Ensure/create `.venv` and run pytest (arguments passed through). |
215
+ | `doxygen` | Generate HTML/XML/Markdown docs and optional PDF output. |
216
+ | `vscode` | Open project in VS Code with `CODEX_HOME` set. |
217
+ | `vsinsider` | Open project in VS Code Insiders with `CODEX_HOME` set. |
218
+ | `diff` | Dispatch file differ by MIME/category. |
219
+ | `edit` | Dispatch file editor by MIME/category. |
220
+ | `view` | Dispatch file viewer by MIME/category. |
221
+ | `pdf-crop` | Crop PDF pages with auto or manual bounding boxes. |
222
+ | `pdf-merge` | Merge multiple PDFs preserving/rebuilding bookmarks. |
223
+ | `pdf-split-by-format` | Split PDFs into parts when page format changes. |
224
+ | `pdf-split-by-toc` | Split PDF into chapter files from level-1 TOC entries. |
225
+ | `pdf-tiler-090` | Tile PDF to A4 at 90% scale. |
226
+ | `pdf-tiler-100` | Tile PDF to A4 at original A1 size. |
227
+ | `pdf-toc-clean` | Remove out-of-range TOC entries and write cleaned outputs. |
228
+ | `dicom2jpg` | Convert DICOM images to JPEG (PixelMed). |
229
+ | `dicomviewer` | Launch PixelMed DICOM viewer. |
230
+ | `video2h264` | Convert one video to H.264 MP4 via ffmpeg. |
231
+ | `video2h265` | Convert one video to H.265 MP4 via ffmpeg. |
232
+ | `ubuntu-dark-theme` | Apply GNOME and Qt dark-theme settings. |
233
+
234
+ ### Selected Usage Examples
235
+
236
+ Install all AI CLIs (default behavior):
237
+
238
+ ```bash
239
+ s ai-install
240
+ ```
241
+
242
+ Install only selected AI tools:
243
+
244
+ ```bash
245
+ s ai-install --codex --gemini --claude
246
+ ```
247
+
248
+ Run pi.dev with default tools injected automatically:
249
+
250
+ ```bash
251
+ s pi
252
+ ```
253
+
254
+ Override pi tools explicitly:
255
+
256
+ ```bash
257
+ s pi --tools read,bash,grep,find
258
+ ```
259
+
260
+ Run useReq bootstrap on first-level child directories:
261
+
262
+ ```bash
263
+ s req --dirs
264
+ ```
265
+
266
+ Clean caches without interactive confirmation:
267
+
268
+ ```bash
269
+ s clean --yes
270
+ ```
271
+
272
+ Crop PDF with automatic bbox over a page window:
273
+
274
+ ```bash
275
+ s pdf-crop --in input.pdf --out cropped.pdf --analyze-pages 1-10 --pages 1-
276
+ ```
277
+
278
+ Merge PDFs and choose output file:
279
+
280
+ ```bash
281
+ s pdf-merge -o merged.pdf a.pdf b.pdf c.pdf
282
+ ```
283
+
284
+ Split PDF by TOC chapters:
285
+
286
+ ```bash
287
+ s pdf-split-by-toc document.pdf
288
+ ```
289
+
290
+ Convert a video to H.264 MP4:
291
+
292
+ ```bash
293
+ s video2h264 input.mov
294
+ ```
295
+
296
+ Run tests and pass pytest options:
297
+
298
+ ```bash
299
+ s tests -q -k "pdf"
300
+ ```
301
+
302
+ Open current git project in VS Code / Insiders:
303
+
304
+ ```bash
305
+ s vscode
306
+ s vsinsider
307
+ ```
308
+
309
+
310
+ ## Acknowledgments
@@ -0,0 +1,45 @@
1
+ shell_scripts/__init__.py,sha256=tcta0Vrn-w5n4wRkcb6xWB5jcyslWz3oKUyNDDU4ago,96
2
+ shell_scripts/__main__.py,sha256=-wEmwKTfeY5TphAH82E38XRPoB4KT5QDLDgRZz84PTs,83
3
+ shell_scripts/config.py,sha256=YUs8QWsZ31lJPrMpFqvn7YLQdseQnlaiu7OXcXsKdEw,12640
4
+ shell_scripts/core.py,sha256=rhgy9xduzkujsjD4NRL2AYvtNI3yTVnPThzEAzyMWUM,11204
5
+ shell_scripts/utils.py,sha256=bXSFRszGmkSKkxOUYJwqqVldveI9rrizkEu-nzstoJs,14133
6
+ shell_scripts/version_check.py,sha256=GDE7IwCzt8-UJ0pFAOQzv0dIYUsynYRN1Z1Gz6Mx7Yo,13090
7
+ shell_scripts/commands/__init__.py,sha256=tFiG-epwWLjfwnZ3LEXXULNk8bEquE5_x9uK59uamQo,3696
8
+ shell_scripts/commands/_dc_common.py,sha256=kfUn92r6n8F1w27jy5QDJE_6Kvpvzhq6dUGNs0_GO0U,4695
9
+ shell_scripts/commands/ai_install.py,sha256=BH38g3OXWQ4F60-pzTbt-fY67eFmRSOEzryhpxVSgQw,17011
10
+ shell_scripts/commands/bin_links.py,sha256=7chuWbk1FdnxH9ak_fATdmUSOyzIbg4WmfRPCOw10-U,2425
11
+ shell_scripts/commands/claude.py,sha256=_X76ygt0jnxZyyNoZ8qVhn6r2C0B9mcNIaKd_hLthl4,2049
12
+ shell_scripts/commands/clean.py,sha256=LOK7bVzqpWDvFBMInlu9COtODVmjwOtwCHyMriq7wIk,2552
13
+ shell_scripts/commands/codex.py,sha256=iHg5S_E8QpsGr2qQwucNDw-24-lcPH_FHsaGCxH9hEE,4331
14
+ shell_scripts/commands/copilot.py,sha256=zYGbB33S8B8zWPi8jV-EBWSoxGv0-11K_zGgBkfi7-Y,1954
15
+ shell_scripts/commands/dicom2jpg.py,sha256=YQQHdhwP8yi10UU3qWn4UzbCjSCK6C33bORcNWtXaek,2614
16
+ shell_scripts/commands/dicomviewer.py,sha256=sMnwQGeHf7r8Qo0n8Cf_ZeTmcask3z5bqQZ44mvSMG8,2283
17
+ shell_scripts/commands/diff_cmd.py,sha256=C6R4GiNhgvvlU6drCVCG9-TusLotNNcb9v5wBq10VJw,1828
18
+ shell_scripts/commands/doxygen_cmd.py,sha256=wd4qecljYZ0lVpdu3D1qKf6cD9xNBv36TetfLlvdFJw,5111
19
+ shell_scripts/commands/edit_cmd.py,sha256=WnWVs4Ojq0qN4fw9iqooUqQHK0XIfDUbJBRmI-AMrUE,1827
20
+ shell_scripts/commands/gemini.py,sha256=efvOhfrDu6WkeJZ0WuRu_vp2fbqPkPrp9r6WECQJDxg,1902
21
+ shell_scripts/commands/kiro.py,sha256=NuD2Zx76azDQAWbJ8YcewshEogLmrd-Avu9feisqHys,1871
22
+ shell_scripts/commands/opencode.py,sha256=64I3IHrliAZ7C4jTU4WLxQcJHJohJcKex09yhegWUoc,1900
23
+ shell_scripts/commands/pdf_crop.py,sha256=VliRAMHMjnSQK9mZhNoghftZAVGZeJG6xhrihcuuawQ,15135
24
+ shell_scripts/commands/pdf_merge.py,sha256=vTTlUv8oVYUo9U45b4yUpK4x0unIwctgXV7g5exvihc,5996
25
+ shell_scripts/commands/pdf_split_by_format.py,sha256=kWID9sadX9cf0jMWFqTyCFMRHwAFNZVmnp24IlcN1H8,7573
26
+ shell_scripts/commands/pdf_split_by_toc.py,sha256=I027ldWXat8ODafn3KRD1X52yeUP2xez1PX-kFNptAg,6674
27
+ shell_scripts/commands/pdf_tiler_090.py,sha256=1eLCw9rqGN8LELB5lBvx6xfaTYc4Kci5YDK2EvnHG6E,1781
28
+ shell_scripts/commands/pdf_tiler_100.py,sha256=U-DlX_PJPHL2P2p0wvWMzb-XkxVYn5-Jb1vqlBzIAqA,1805
29
+ shell_scripts/commands/pdf_toc_clean.py,sha256=7GroNjVbOoh184AbYoqXSVdK_RHqA3y5urjkZ4lcJbw,5907
30
+ shell_scripts/commands/pi.py,sha256=Ozo-VKaieQYp1OFiyo2LFsxvpD-XYdO5JpcvTdqDEhQ,2381
31
+ shell_scripts/commands/req_cmd.py,sha256=3zR4FRbZWebQa-csna7qWttVcZsLqAIqiJSjQ4Idtlk,13212
32
+ shell_scripts/commands/tests_cmd.py,sha256=nKfD2sDb06Hy5J93yRH6dP4kSfV1sxLkpHHdTgqLvvw,2672
33
+ shell_scripts/commands/ubuntu_dark_theme.py,sha256=O-Ku_U3ZwFNVBpSHYvsFZSK36SoDhrlFBeWlqD5_GYc,1987
34
+ shell_scripts/commands/venv_cmd.py,sha256=X8phS-K4b0oOGuuwn2u84D1bcQlfo1QpJi1RI3VVe3s,2381
35
+ shell_scripts/commands/video2h264.py,sha256=5Cj4OpDrl1Bm24wGBbzni2So1ELP3Wual3RaB98DQrs,2717
36
+ shell_scripts/commands/video2h265.py,sha256=Sr_UWGz_V77x4anmuy8kiWZv5I_AOFlV0WDnJEToAhk,2675
37
+ shell_scripts/commands/view_cmd.py,sha256=qHEivQHZpZCTE3VSFP1ay2SuqgancQlEKxJcKtyeqNA,1827
38
+ shell_scripts/commands/vscode_cmd.py,sha256=Rkcjt5A1HMzqJoh2Yz9VRGoLP-L3qpRO5hkcSrzOmvA,1461
39
+ shell_scripts/commands/vsinsider_cmd.py,sha256=KTTv1cVpJO-u1ktxOE0W_o4AAmz20pAvkDtyhpU9XBg,1548
40
+ shellscripts-0.23.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
41
+ shellscripts-0.23.1.dist-info/METADATA,sha256=BihFSRKVrmcCCAiiJLu0B5seR0Unkn0W2-WCrrgWo0A,10985
42
+ shellscripts-0.23.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
43
+ shellscripts-0.23.1.dist-info/entry_points.txt,sha256=9ICAgH87fxHBzi3f6JXIVcsPWzAKsCh4_1xS8JThQ0M,85
44
+ shellscripts-0.23.1.dist-info/top_level.txt,sha256=7bDVqjcR5CfCCArCP4X4e9gYJ-ua8z-GfQeHbAo8rCY,14
45
+ shellscripts-0.23.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ s = shell_scripts.core:main
3
+ shellscripts = shell_scripts.core:main