wtftools 0.0.1__tar.gz → 0.0.2__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 (57) hide show
  1. {wtftools-0.0.1 → wtftools-0.0.2}/CHANGELOG.md +95 -2
  2. {wtftools-0.0.1 → wtftools-0.0.2}/MANIFEST.in +2 -1
  3. wtftools-0.0.2/PKG-INFO +184 -0
  4. wtftools-0.0.2/README.md +145 -0
  5. wtftools-0.0.1/scripts/wtf.bash-completion → wtftools-0.0.2/completions/wtf +25 -6
  6. {wtftools-0.0.1 → wtftools-0.0.2}/pyproject.toml +8 -4
  7. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_audit.py +4 -1
  8. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_audit_extras.py +3 -0
  9. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_colors.py +11 -12
  10. wtftools-0.0.2/tests/test_completion.py +56 -0
  11. wtftools-0.0.1/tests/test_iteration5.py → wtftools-0.0.2/tests/test_conntrack_alert_explain.py +1 -5
  12. wtftools-0.0.2/tests/test_disk_usage.py +194 -0
  13. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_explain_deep.py +2 -2
  14. wtftools-0.0.1/tests/test_iteration10.py → wtftools-0.0.2/tests/test_llm_html_output.py +29 -5
  15. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_main.py +80 -2
  16. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_main_extras.py +0 -3
  17. wtftools-0.0.1/tests/test_iteration2_extras.py → wtftools-0.0.2/tests/test_net_restart_checks.py +1 -6
  18. wtftools-0.0.2/tests/test_port_docker.py +542 -0
  19. wtftools-0.0.1/tests/test_iteration8.py → wtftools-0.0.2/tests/test_probes_smart_diff.py +1 -1
  20. wtftools-0.0.1/tests/test_iteration4.py → wtftools-0.0.2/tests/test_psi_cert_logs_parallel.py +1 -1
  21. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_public_api.py +15 -12
  22. wtftools-0.0.1/tests/test_iteration6.py → wtftools-0.0.2/tests/test_snapshot_docker_ntp.py +12 -7
  23. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_sysinfo.py +1 -0
  24. wtftools-0.0.1/tests/test_iteration3.py → wtftools-0.0.2/tests/test_tcp_services_config.py +1 -1
  25. wtftools-0.0.2/tests/test_temp.py +66 -0
  26. wtftools-0.0.1/tests/test_iteration7.py → wtftools-0.0.2/tests/test_temp_dns_top_ports.py +6 -27
  27. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/colors.py +6 -16
  28. wtftools-0.0.2/wtftools/completion.py +217 -0
  29. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/llm.py +15 -10
  30. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/main.py +338 -57
  31. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/sections.py +95 -27
  32. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/snapshot.py +6 -2
  33. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/sysinfo.py +244 -16
  34. wtftools-0.0.2/wtftools.egg-info/PKG-INFO +184 -0
  35. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools.egg-info/SOURCES.txt +14 -9
  36. wtftools-0.0.1/PKG-INFO +0 -307
  37. wtftools-0.0.1/README.md +0 -267
  38. wtftools-0.0.1/wtftools.egg-info/PKG-INFO +0 -307
  39. {wtftools-0.0.1 → wtftools-0.0.2}/LICENSE +0 -0
  40. {wtftools-0.0.1 → wtftools-0.0.2}/scripts/build-deb.sh +0 -0
  41. {wtftools-0.0.1 → wtftools-0.0.2}/setup.cfg +0 -0
  42. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_config.py +0 -0
  43. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_cron.py +0 -0
  44. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_info.py +0 -0
  45. {wtftools-0.0.1 → wtftools-0.0.2}/tests/test_plain_formats.py +0 -0
  46. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/__init__.py +0 -0
  47. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/__main__.py +0 -0
  48. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/audit.py +0 -0
  49. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/config.py +0 -0
  50. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/cron.py +0 -0
  51. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/events.py +0 -0
  52. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/explain.py +0 -0
  53. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools/info.py +0 -0
  54. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools.egg-info/dependency_links.txt +0 -0
  55. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools.egg-info/entry_points.txt +0 -0
  56. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools.egg-info/requires.txt +0 -0
  57. {wtftools-0.0.1 → wtftools-0.0.2}/wtftools.egg-info/top_level.txt +0 -0
@@ -6,8 +6,102 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.0.2] - 2026-07-01
10
+
11
+ ### Docs
12
+ - README is now a concise landing page (what it is, capabilities, install, a
13
+ linked command reference). The detailed per-command examples moved into
14
+ `docs/AUDIT.md`, `docs/RESOURCES.md`, `docs/OUTPUT.md` and `docs/CONFIG.md`,
15
+ linked from the command tables. Translations mirror the landing README;
16
+ the deep reference pages are English.
17
+
18
+ ### Added
19
+ - `wtf completion [bash|zsh]` — print a shell-completion script to enable
20
+ `<Tab>` completion (`eval "$(wtf completion bash)"`); bare `wtf completion`
21
+ prints setup instructions. The bash script lives in `wtftools/completion.py`
22
+ as the single source of truth; `completions/wtf` is a generated mirror
23
+ (a test guards against drift), installed to bash-completion's system dir.
24
+
25
+ ### Changed — `wtf disk` folder usage
26
+ - `wtf disk <path>` now breaks a directory down by folder size, biggest first
27
+ (like `du -sh <path>/* | sort`), as `# DISK USAGE <path>` rows of
28
+ `path/ size % of analysed root depth` (the depth index is the last
29
+ column). `wtf disk` with no path still shows the per-mount overview, now laid
30
+ out as `full path used/total percent bar` (full mount paths, no
31
+ truncation).
32
+ - `--tree [N]` drills into the N largest folders at each level (bare `--tree` =
33
+ 1 → a single dominant chain); `--depth D` sets how deep (default 3). Output
34
+ is parse-first: `plain` is `bytes<TAB>percent<TAB>abspath<TAB>depth`, `json`
35
+ is a flat `entries` list with absolute `path` + relative `rel`.
36
+ - **Breaking:** `--tree` used to take a PATH (`wtf disk --tree /var`); the path
37
+ is now the positional argument (`wtf disk /var --tree`) and `--tree` is the
38
+ expansion count. The `du` scan timeout was raised (30→120s) so large
39
+ filesystems no longer return an empty result.
40
+
41
+ ### Fixed
42
+ - `wtf ports` and `wtf top` JSON is now an object carrying `schema_version`
43
+ (was a bare array), consistent with `disk`/`net`; `wtf audit` JSON carries
44
+ `schema_version` too.
45
+ - README documentation links are absolute so they resolve on the PyPI project
46
+ page; the translated READMEs no longer link to a non-existent `docs/docs/`
47
+ path.
48
+ - `.deb` install instructions use the actual package name
49
+ (`python3-wtftools_*.deb`).
50
+ - Unexpected errors now print a one-line message instead of dumping a raw
51
+ Python traceback; set `WTFTOOLS_DEBUG=1` or pass `--verbose` for the trace.
52
+ - `requirements.txt` no longer pulls `psutil` — the core install stays
53
+ dependency-free; use `pip install "wtftools[full]"` for psutil.
54
+ - The packaged bash-completion installs as `completions/wtf`, so it is
55
+ auto-loaded system-wide (the previous file name prevented auto-loading; the
56
+ `eval "$(wtf completion bash)"` path was unaffected).
57
+ - The Docker base image is pinned by digest for reproducible builds.
58
+ - Minimum Python raised to 3.9 (`requires-python`): the build needs
59
+ setuptools>=77, which dropped the EOL Python 3.8. The source stays
60
+ 3.8-compatible in style; only the packaged build floor moved.
61
+
62
+ ### Security
63
+ - `wtf explain --llm claude|openai` discloses (to stderr) that the host name
64
+ and audit findings are sent to the vendor, and asks for confirmation on an
65
+ interactive terminal (`--yes` / `WTFTOOLS_LLM_YES=1` to skip). `--llm auto`
66
+ no longer silently escalates to a remote model — it uses local `ollama` only.
67
+ - `wtf audit --format csv` escapes cells beginning with `= + - @` to prevent
68
+ spreadsheet formula injection.
69
+ - Snapshot files and their directory are created `0600`/`0700`, so root's audit
70
+ history is not world-readable on a multi-user host.
71
+ - `wtf crontab -u <user>` validates the username (same rule as positional
72
+ targets) before shelling out to `crontab -l -u`, avoiding argument injection.
73
+
9
74
  ## [0.0.1] - 2026-06-14
10
75
 
76
+ ### Added — port, docker and temperature views
77
+ - `wtf port <N>` (alias of `wtf ports <N>`) — drill into a single port:
78
+ which process holds it (PID, user, command), the exact executable file
79
+ behind it and its working directory, via `lsof` with `/proc` enrichment
80
+ and psutil/`ss` fallbacks. text/plain/json output.
81
+ - `wtf docker [NAME]` — where a container was started from: the compose
82
+ project working directory and config files read from the container's
83
+ labels, plus on-disk sizes (image layers, writable container layer and
84
+ json log). With no name it lists running containers as a table with
85
+ image/container/log size columns and a TOTAL row. Sizes use decimal units
86
+ (1GB = 1000MB) to match `docker container ls --size`. The image total
87
+ dedupes by image id (one image shared by many containers counted once); it is
88
+ the logical unique-images size, and since different images still share base
89
+ layers on disk, the real layer-deduplicated disk is shown alongside it from
90
+ `docker system df`. Container (writable layer) and log totals are exact. Log
91
+ sizes need read access under `/var/lib/docker` (run with `sudo`); otherwise
92
+ the column and its total show `?`, not a misleading `0B`.
93
+ - `wtf temp` (aliases `temps`, `temperature`) — hardware temperatures from
94
+ `/sys/class/hwmon` sensors, sorted hottest-first and colored against the
95
+ configured warn/fail thresholds. text/plain/json output.
96
+
97
+ ### Changed — output
98
+ - Section headers are now plain `# TITLE` lines instead of full-width
99
+ centered box-drawing rules, so the output greps cleanly (`grep '^#'`).
100
+
101
+ ### CI
102
+ - Bumped GitHub Actions to the Node.js 24 majors (checkout v6,
103
+ setup-python v6, action-gh-release v3).
104
+
11
105
  ### Added — per-resource subcommands
12
106
  - `wtf disk` — per-mount usage with inode percent and read-only flags;
13
107
  `--tree [PATH]` lists the largest directories (du-based, `--depth`,
@@ -54,7 +148,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
54
148
  - `wtftools/checks/plugins.py` — discovery / executor / parser for
55
149
  `/etc/wtf/checks.d/` scripts (bash + Python).
56
150
  - `_plugin_to_check` + `_all_check_callables` glue in `wtftools/audit.py`.
57
- - `tests/test_plugins.py`, `tests/test_iteration16.py`.
58
151
  - README's «Plugins» section and QUICKSTART's «Custom checks (plugins)»
59
152
  section.
60
153
 
@@ -127,7 +220,7 @@ Initial public release. Highlights:
127
220
  release workflow.
128
221
  - **724 tests, 92.6 % coverage.**
129
222
 
130
- ### Added — Plugin SDK & docs (final iteration)
223
+ ### Added — Plugin SDK & docs
131
224
  - **`wtftools.plugin_sdk`** — tiny helper module so Python plugins don't have
132
225
  to remember exit codes or hand-roll JSON:
133
226
 
@@ -2,4 +2,5 @@ include README.md
2
2
  include LICENSE
3
3
  include CHANGELOG.md
4
4
  recursive-include wtftools *.py
5
- recursive-include scripts *.sh *.bash-completion
5
+ recursive-include scripts *.sh
6
+ include completions/wtf
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: wtftools
3
+ Version: 0.0.2
4
+ Summary: One command to see what is going on with your Linux server right now.
5
+ Author-email: Aleksandr Pimenov <wachawo@gmail.com>
6
+ Maintainer-email: Aleksandr Pimenov <wachawo@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/wachawo/wtftools
9
+ Project-URL: Repository, https://github.com/wachawo/wtftools.git
10
+ Project-URL: Documentation, https://github.com/wachawo/wtftools#readme
11
+ Project-URL: Bug Reports, https://github.com/wachawo/wtftools/issues
12
+ Keywords: devops,sre,linux,diagnostics,monitoring,cron,system,audit,cli
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Operating System :: POSIX :: Linux
22
+ Classifier: Topic :: System :: Systems Administration
23
+ Classifier: Topic :: System :: Monitoring
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Provides-Extra: full
29
+ Requires-Dist: psutil>=5.9.0; extra == "full"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
33
+ Requires-Dist: coverage>=7.0.0; extra == "dev"
34
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
35
+ Requires-Dist: build>=1.0.0; extra == "dev"
36
+ Requires-Dist: stdeb>=0.10.0; extra == "dev"
37
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # wtftools
41
+
42
+ [![CI](https://github.com/wachawo/wtftools/actions/workflows/ci.yml/badge.svg)](https://github.com/wachawo/wtftools/actions/workflows/ci.yml)
43
+ [![PyPI](https://img.shields.io/pypi/v/wtftools.svg)](https://pypi.org/project/wtftools/)
44
+ [![Downloads](https://img.shields.io/pypi/dm/wtftools.svg)](https://pypi.org/project/wtftools/)
45
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/wachawo/wtftools/blob/main/LICENSE)
46
+ [![Python](https://img.shields.io/pypi/pyversions/wtftools.svg)](https://pypi.org/project/wtftools/)
47
+
48
+ > One command to see what is going on with your Linux server right now.
49
+
50
+ **English** | [Español](https://github.com/wachawo/wtftools/blob/main/docs/README_ES.md) | [Português](https://github.com/wachawo/wtftools/blob/main/docs/README_PT.md) | [Français](https://github.com/wachawo/wtftools/blob/main/docs/README_FR.md) | [Deutsch](https://github.com/wachawo/wtftools/blob/main/docs/README_DE.md) | [Italiano](https://github.com/wachawo/wtftools/blob/main/docs/README_IT.md) | [Русский](https://github.com/wachawo/wtftools/blob/main/docs/README_RU.md) | [中文](https://github.com/wachawo/wtftools/blob/main/docs/README_ZH.md) | [日本語](https://github.com/wachawo/wtftools/blob/main/docs/README_JA.md) | [हिन्दी](https://github.com/wachawo/wtftools/blob/main/docs/README_HI.md) | [한국어](https://github.com/wachawo/wtftools/blob/main/docs/README_KR.md)
51
+
52
+ You log in to a server and something feels wrong. Instead of running ten
53
+ commands (`htop`, `df -h`, `journalctl`, `systemctl --failed`, …) you run one:
54
+
55
+ ```
56
+ $ wtf
57
+ # AUDIT
58
+ [ OK ] uptime 3d 4h 12m
59
+ [ OK ] load average 0.42 0.51 0.55 / 8 CPU
60
+ [ OK ] memory 4.1GB / 16.0GB used (25%)
61
+ [WARN] disk /var 17.0GB / 20.0GB used (85%)
62
+ [FAIL] failed systemd units 1 failed unit(s)
63
+
64
+ Summary: 12 ok · 1 warn · 1 fail · 2 skip
65
+ ```
66
+
67
+ Green is fine, yellow needs a look, red needs fixing. `wtftools` is a
68
+ **read-only, dependency-free CLI** (Python standard library only; `psutil`
69
+ optional) that turns a pile of diagnostic commands into one readable answer —
70
+ and a machine-readable one when you pipe it.
71
+
72
+ ## What it can do
73
+
74
+ - **Health audit** — 35+ checks (disk, memory, swap, load, PSI, OOM kills,
75
+ failed units, cert expiry, SMART, temperatures, DNS, …) as a
76
+ green / yellow / red checklist.
77
+ - **Per-resource views** — ask about one thing at a time, like `show` commands
78
+ on a switch: `wtf disk`, `wtf cpu`, `wtf mem`, `wtf net`, `wtf docker`, …
79
+ - **Incident triage** — `wtf problems`, `wtf events`, `wtf logs`,
80
+ `wtf services <unit>`, `wtf explain` (optionally through a local or hosted LLM).
81
+ - **Trends & alerting** — `wtf daily`, snapshots + `wtf diff`, cron alerts —
82
+ no monitoring stack required.
83
+ - **Scriptable** — `-f json` on every command and `-f plain` (tab-separated) on
84
+ the resource and audit views; the JSON carries a `schema_version` so scripts
85
+ survive upgrades — for grep / awk / jq.
86
+ - **Beginner-friendly** — `--show-commands` prints the classic commands each
87
+ view replaces, so you can learn them by hand.
88
+
89
+ ## Install
90
+
91
+ ```bash
92
+ pipx install wtftools # recommended — works on any modern distro
93
+ pip install wtftools # or classic pip (core, no dependencies)
94
+ pip install wtftools[full] # + psutil for richer process/socket info
95
+ sudo dpkg -i python3-wtftools_*.deb # Debian/Ubuntu package (see Releases)
96
+ ```
97
+
98
+ After install you have the `wtf` command. Enable `<Tab>` completion by adding
99
+ one line to your shell rc:
100
+
101
+ ```bash
102
+ echo 'eval "$(wtf completion bash)"' >> ~/.bashrc # bash
103
+ echo 'eval "$(wtf completion zsh)"' >> ~/.zshrc # zsh
104
+ ```
105
+
106
+ New here? Start with the [5-minute quickstart](https://github.com/wachawo/wtftools/blob/main/docs/QUICKSTART.md).
107
+
108
+ ## Commands
109
+
110
+ Run `wtf <command> --help` for flags. Each command links to its reference page
111
+ with examples.
112
+
113
+ ### Health & monitoring — [docs/AUDIT.md](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md)
114
+
115
+ | command | what it does |
116
+ |---------|--------------|
117
+ | [`wtf` / `wtf audit`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-audit) | green/yellow/red checklist of what is OK and what is not |
118
+ | [`wtf problems`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-problems) | only the WARN+FAIL rows |
119
+ | [`wtf daily`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-daily) | morning check: audit + diff vs last run + events |
120
+ | [`wtf explain`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-explain) | actionable advice per finding; `--llm` to pipe to an LLM |
121
+ | [`wtf events`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-events) | timeline: reboots, OOM kills, failed units, … |
122
+ | [`wtf logs`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-logs) | recent ERROR+ journal entries grouped by service |
123
+ | [`wtf services`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-services) | drill into one unit: state, restarts, ports, journal |
124
+ | [`wtf diff`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-diff) | compare current state to a saved snapshot |
125
+ | [`wtf history`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-history) | list saved audit snapshots |
126
+ | [`wtf crontab`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-crontab) | validate system + per-user crontabs |
127
+ | [`wtf doctor`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-doctor) | self-diagnostic: which tools/files wtf can use |
128
+
129
+ ### Resource views — [docs/RESOURCES.md](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md)
130
+
131
+ | command | what it does |
132
+ |---------|--------------|
133
+ | [`wtf disk [PATH]`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-disk) | mounts overview; with a PATH, the largest folders; `--tree` drills in |
134
+ | [`wtf cpu`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-cpu) | load, iowait, pressure, top CPU consumers |
135
+ | [`wtf mem`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-mem) | RAM/swap, OOM kills, top memory consumers |
136
+ | [`wtf net`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-net) | interfaces, gateway, DNS, errors, listening ports |
137
+ | [`wtf io`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-io) | per-device IO rates, pressure, stuck processes |
138
+ | [`wtf who`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-who) | logged-in users, recent logins, failed auth |
139
+ | [`wtf temp`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-temp) | hardware temperatures from /sys/class/hwmon |
140
+ | [`wtf info`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-info) | one-page snapshot: all of the above at once |
141
+ | [`wtf top`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-top) | focused process top: sort by cpu/rss, filter by user/name |
142
+ | [`wtf ports` / `wtf port N`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-ports) | listening sockets; drill one port to PID, exe, cwd |
143
+ | [`wtf docker [NAME]`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-docker) | container compose dir + image/container/log sizes |
144
+
145
+ ### Output & configuration
146
+
147
+ | command | what it does |
148
+ |---------|--------------|
149
+ | [`wtf config`](https://github.com/wachawo/wtftools/blob/main/docs/CONFIG.md#wtf-config) | show effective config / print a commented example |
150
+ | [`wtf completion`](#install) | print a bash/zsh `<Tab>`-completion script |
151
+ | [machine output](https://github.com/wachawo/wtftools/blob/main/docs/OUTPUT.md) | `plain`/`json` formats and a grep·awk·jq cookbook |
152
+
153
+ `wtftools` absorbs and supersedes
154
+ [`checkcrontab`](https://github.com/wachawo/checkcrontab) — the same cron
155
+ validator now lives at `wtf crontab`.
156
+
157
+ ## Documentation
158
+
159
+ - [QUICKSTART.md](https://github.com/wachawo/wtftools/blob/main/docs/QUICKSTART.md) — 5-minute onboarding and a cheat sheet
160
+ - [AUDIT.md](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md) — health checks, monitoring, exit codes, the full check list
161
+ - [RESOURCES.md](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md) — per-resource views with examples
162
+ - [OUTPUT.md](https://github.com/wachawo/wtftools/blob/main/docs/OUTPUT.md) — `plain`/`json` formats and the scripting cookbook
163
+ - [CONFIG.md](https://github.com/wachawo/wtftools/blob/main/docs/CONFIG.md) — config file, thresholds, ignoring checks
164
+
165
+ ## Compatibility
166
+
167
+ - Python 3.9+
168
+ - Linux (systemd distributions are the happy path; the tool degrades
169
+ gracefully when `systemctl` / `journalctl` / `psutil` are missing)
170
+ - No network access required for the core CLI; optional network only for
171
+ `wtf explain --llm …` and `wtf doctor --check-updates`
172
+
173
+ ## From source
174
+
175
+ ```bash
176
+ git clone https://github.com/wachawo/wtftools
177
+ cd wtftools
178
+ pip install -e .
179
+ python3 wtf.py audit # or run it without installing
180
+ ```
181
+
182
+ ## License
183
+
184
+ MIT
@@ -0,0 +1,145 @@
1
+ # wtftools
2
+
3
+ [![CI](https://github.com/wachawo/wtftools/actions/workflows/ci.yml/badge.svg)](https://github.com/wachawo/wtftools/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/wtftools.svg)](https://pypi.org/project/wtftools/)
5
+ [![Downloads](https://img.shields.io/pypi/dm/wtftools.svg)](https://pypi.org/project/wtftools/)
6
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/wachawo/wtftools/blob/main/LICENSE)
7
+ [![Python](https://img.shields.io/pypi/pyversions/wtftools.svg)](https://pypi.org/project/wtftools/)
8
+
9
+ > One command to see what is going on with your Linux server right now.
10
+
11
+ **English** | [Español](https://github.com/wachawo/wtftools/blob/main/docs/README_ES.md) | [Português](https://github.com/wachawo/wtftools/blob/main/docs/README_PT.md) | [Français](https://github.com/wachawo/wtftools/blob/main/docs/README_FR.md) | [Deutsch](https://github.com/wachawo/wtftools/blob/main/docs/README_DE.md) | [Italiano](https://github.com/wachawo/wtftools/blob/main/docs/README_IT.md) | [Русский](https://github.com/wachawo/wtftools/blob/main/docs/README_RU.md) | [中文](https://github.com/wachawo/wtftools/blob/main/docs/README_ZH.md) | [日本語](https://github.com/wachawo/wtftools/blob/main/docs/README_JA.md) | [हिन्दी](https://github.com/wachawo/wtftools/blob/main/docs/README_HI.md) | [한국어](https://github.com/wachawo/wtftools/blob/main/docs/README_KR.md)
12
+
13
+ You log in to a server and something feels wrong. Instead of running ten
14
+ commands (`htop`, `df -h`, `journalctl`, `systemctl --failed`, …) you run one:
15
+
16
+ ```
17
+ $ wtf
18
+ # AUDIT
19
+ [ OK ] uptime 3d 4h 12m
20
+ [ OK ] load average 0.42 0.51 0.55 / 8 CPU
21
+ [ OK ] memory 4.1GB / 16.0GB used (25%)
22
+ [WARN] disk /var 17.0GB / 20.0GB used (85%)
23
+ [FAIL] failed systemd units 1 failed unit(s)
24
+
25
+ Summary: 12 ok · 1 warn · 1 fail · 2 skip
26
+ ```
27
+
28
+ Green is fine, yellow needs a look, red needs fixing. `wtftools` is a
29
+ **read-only, dependency-free CLI** (Python standard library only; `psutil`
30
+ optional) that turns a pile of diagnostic commands into one readable answer —
31
+ and a machine-readable one when you pipe it.
32
+
33
+ ## What it can do
34
+
35
+ - **Health audit** — 35+ checks (disk, memory, swap, load, PSI, OOM kills,
36
+ failed units, cert expiry, SMART, temperatures, DNS, …) as a
37
+ green / yellow / red checklist.
38
+ - **Per-resource views** — ask about one thing at a time, like `show` commands
39
+ on a switch: `wtf disk`, `wtf cpu`, `wtf mem`, `wtf net`, `wtf docker`, …
40
+ - **Incident triage** — `wtf problems`, `wtf events`, `wtf logs`,
41
+ `wtf services <unit>`, `wtf explain` (optionally through a local or hosted LLM).
42
+ - **Trends & alerting** — `wtf daily`, snapshots + `wtf diff`, cron alerts —
43
+ no monitoring stack required.
44
+ - **Scriptable** — `-f json` on every command and `-f plain` (tab-separated) on
45
+ the resource and audit views; the JSON carries a `schema_version` so scripts
46
+ survive upgrades — for grep / awk / jq.
47
+ - **Beginner-friendly** — `--show-commands` prints the classic commands each
48
+ view replaces, so you can learn them by hand.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ pipx install wtftools # recommended — works on any modern distro
54
+ pip install wtftools # or classic pip (core, no dependencies)
55
+ pip install wtftools[full] # + psutil for richer process/socket info
56
+ sudo dpkg -i python3-wtftools_*.deb # Debian/Ubuntu package (see Releases)
57
+ ```
58
+
59
+ After install you have the `wtf` command. Enable `<Tab>` completion by adding
60
+ one line to your shell rc:
61
+
62
+ ```bash
63
+ echo 'eval "$(wtf completion bash)"' >> ~/.bashrc # bash
64
+ echo 'eval "$(wtf completion zsh)"' >> ~/.zshrc # zsh
65
+ ```
66
+
67
+ New here? Start with the [5-minute quickstart](https://github.com/wachawo/wtftools/blob/main/docs/QUICKSTART.md).
68
+
69
+ ## Commands
70
+
71
+ Run `wtf <command> --help` for flags. Each command links to its reference page
72
+ with examples.
73
+
74
+ ### Health & monitoring — [docs/AUDIT.md](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md)
75
+
76
+ | command | what it does |
77
+ |---------|--------------|
78
+ | [`wtf` / `wtf audit`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-audit) | green/yellow/red checklist of what is OK and what is not |
79
+ | [`wtf problems`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-problems) | only the WARN+FAIL rows |
80
+ | [`wtf daily`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-daily) | morning check: audit + diff vs last run + events |
81
+ | [`wtf explain`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-explain) | actionable advice per finding; `--llm` to pipe to an LLM |
82
+ | [`wtf events`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-events) | timeline: reboots, OOM kills, failed units, … |
83
+ | [`wtf logs`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-logs) | recent ERROR+ journal entries grouped by service |
84
+ | [`wtf services`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-services) | drill into one unit: state, restarts, ports, journal |
85
+ | [`wtf diff`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-diff) | compare current state to a saved snapshot |
86
+ | [`wtf history`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-history) | list saved audit snapshots |
87
+ | [`wtf crontab`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-crontab) | validate system + per-user crontabs |
88
+ | [`wtf doctor`](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md#wtf-doctor) | self-diagnostic: which tools/files wtf can use |
89
+
90
+ ### Resource views — [docs/RESOURCES.md](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md)
91
+
92
+ | command | what it does |
93
+ |---------|--------------|
94
+ | [`wtf disk [PATH]`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-disk) | mounts overview; with a PATH, the largest folders; `--tree` drills in |
95
+ | [`wtf cpu`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-cpu) | load, iowait, pressure, top CPU consumers |
96
+ | [`wtf mem`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-mem) | RAM/swap, OOM kills, top memory consumers |
97
+ | [`wtf net`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-net) | interfaces, gateway, DNS, errors, listening ports |
98
+ | [`wtf io`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-io) | per-device IO rates, pressure, stuck processes |
99
+ | [`wtf who`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-who) | logged-in users, recent logins, failed auth |
100
+ | [`wtf temp`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-temp) | hardware temperatures from /sys/class/hwmon |
101
+ | [`wtf info`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-info) | one-page snapshot: all of the above at once |
102
+ | [`wtf top`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-top) | focused process top: sort by cpu/rss, filter by user/name |
103
+ | [`wtf ports` / `wtf port N`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-ports) | listening sockets; drill one port to PID, exe, cwd |
104
+ | [`wtf docker [NAME]`](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md#wtf-docker) | container compose dir + image/container/log sizes |
105
+
106
+ ### Output & configuration
107
+
108
+ | command | what it does |
109
+ |---------|--------------|
110
+ | [`wtf config`](https://github.com/wachawo/wtftools/blob/main/docs/CONFIG.md#wtf-config) | show effective config / print a commented example |
111
+ | [`wtf completion`](#install) | print a bash/zsh `<Tab>`-completion script |
112
+ | [machine output](https://github.com/wachawo/wtftools/blob/main/docs/OUTPUT.md) | `plain`/`json` formats and a grep·awk·jq cookbook |
113
+
114
+ `wtftools` absorbs and supersedes
115
+ [`checkcrontab`](https://github.com/wachawo/checkcrontab) — the same cron
116
+ validator now lives at `wtf crontab`.
117
+
118
+ ## Documentation
119
+
120
+ - [QUICKSTART.md](https://github.com/wachawo/wtftools/blob/main/docs/QUICKSTART.md) — 5-minute onboarding and a cheat sheet
121
+ - [AUDIT.md](https://github.com/wachawo/wtftools/blob/main/docs/AUDIT.md) — health checks, monitoring, exit codes, the full check list
122
+ - [RESOURCES.md](https://github.com/wachawo/wtftools/blob/main/docs/RESOURCES.md) — per-resource views with examples
123
+ - [OUTPUT.md](https://github.com/wachawo/wtftools/blob/main/docs/OUTPUT.md) — `plain`/`json` formats and the scripting cookbook
124
+ - [CONFIG.md](https://github.com/wachawo/wtftools/blob/main/docs/CONFIG.md) — config file, thresholds, ignoring checks
125
+
126
+ ## Compatibility
127
+
128
+ - Python 3.9+
129
+ - Linux (systemd distributions are the happy path; the tool degrades
130
+ gracefully when `systemctl` / `journalctl` / `psutil` are missing)
131
+ - No network access required for the core CLI; optional network only for
132
+ `wtf explain --llm …` and `wtf doctor --check-updates`
133
+
134
+ ## From source
135
+
136
+ ```bash
137
+ git clone https://github.com/wachawo/wtftools
138
+ cd wtftools
139
+ pip install -e .
140
+ python3 wtf.py audit # or run it without installing
141
+ ```
142
+
143
+ ## License
144
+
145
+ MIT
@@ -1,5 +1,6 @@
1
1
  # bash completion for `wtf` / `wtftools`
2
- # Install: copy to /etc/bash_completion.d/ or `source` from your bashrc.
2
+ # Enable: eval "$(wtf completion bash)" (add that line to ~/.bashrc),
3
+ # or copy this script to /etc/bash_completion.d/wtf
3
4
 
4
5
  _wtf_complete() {
5
6
  local cur prev cmd
@@ -7,7 +8,7 @@ _wtf_complete() {
7
8
  cur="${COMP_WORDS[COMP_CWORD]}"
8
9
  prev="${COMP_WORDS[COMP_CWORD-1]}"
9
10
 
10
- local subcommands="info disk cpu mem net io who daily audit problems crontab doctor services service config logs explain history diff top ports events"
11
+ local subcommands="info disk cpu mem net io who temp temps temperature daily audit problems crontab doctor services service config logs explain history diff top ports port docker events completion"
11
12
  local global_opts="-h --help -V --version -f --format --no-color -v --verbose -q --quiet --config"
12
13
 
13
14
  if [[ $COMP_CWORD -eq 1 ]]; then
@@ -29,10 +30,14 @@ _wtf_complete() {
29
30
  disk)
30
31
  local opts="--tree --depth --top --format --show-commands"
31
32
  case "$prev" in
32
- --tree) COMPREPLY=( $(compgen -d -- "$cur") ); return 0 ;;
33
- --format) COMPREPLY=( $(compgen -W "text plain json" -- "$cur") ); return 0 ;;
33
+ --format) COMPREPLY=( $(compgen -W "text plain json" -- "$cur") ); return 0 ;;
34
+ --tree|--depth|--top) return 0 ;;
34
35
  esac
35
- COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
36
+ if [[ "$cur" == -* ]]; then
37
+ COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
38
+ else
39
+ COMPREPLY=( $(compgen -d -- "$cur") ) # a PATH to break down
40
+ fi
36
41
  ;;
37
42
  cpu|net|io)
38
43
  COMPREPLY=( $(compgen -W "--format --show-commands" -- "$cur") )
@@ -42,6 +47,10 @@ _wtf_complete() {
42
47
  COMPREPLY=( $(compgen -W "--since --format --show-commands" -- "$cur") )
43
48
  [[ "$prev" == "--format" ]] && COMPREPLY=( $(compgen -W "text plain json" -- "$cur") )
44
49
  ;;
50
+ temp|temps|temperature)
51
+ COMPREPLY=( $(compgen -W "--format" -- "$cur") )
52
+ [[ "$prev" == "--format" ]] && COMPREPLY=( $(compgen -W "text plain json" -- "$cur") )
53
+ ;;
45
54
  audit|problems)
46
55
  local opts="--format --strict --exit-zero --check --only --since --list-checks --brief -b --ignore --serial --check-timeout --alert --alert-on --save --output -o"
47
56
  case "$prev" in
@@ -97,7 +106,7 @@ updates reboot cron-daemon crontab docker hw-temp smart dns http-probes tcp-prob
97
106
  esac
98
107
  COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
99
108
  ;;
100
- ports)
109
+ ports|port)
101
110
  local opts="--proto --public-only --format"
102
111
  case "$prev" in
103
112
  --proto) COMPREPLY=( $(compgen -W "tcp udp all" -- "$cur") ); return 0 ;;
@@ -105,6 +114,13 @@ updates reboot cron-daemon crontab docker hw-temp smart dns http-probes tcp-prob
105
114
  esac
106
115
  COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
107
116
  ;;
117
+ docker)
118
+ case "$prev" in
119
+ --format) COMPREPLY=( $(compgen -W "text plain json" -- "$cur") ); return 0 ;;
120
+ esac
121
+ local names=$(docker ps --format '{{.Names}}' 2>/dev/null)
122
+ COMPREPLY=( $(compgen -W "--format $names" -- "$cur") )
123
+ ;;
108
124
  services|service)
109
125
  local opts="-n --lines --format"
110
126
  case "$prev" in
@@ -147,6 +163,9 @@ updates reboot cron-daemon crontab docker hw-temp smart dns http-probes tcp-prob
147
163
  COMPREPLY=( $(compgen -W "--example --format" -- "$cur") )
148
164
  [[ "$prev" == "--format" ]] && COMPREPLY=( $(compgen -W "text json" -- "$cur") )
149
165
  ;;
166
+ completion)
167
+ COMPREPLY=( $(compgen -W "bash zsh" -- "$cur") )
168
+ ;;
150
169
  esac
151
170
  }
152
171
 
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wtftools"
7
- version = "0.0.1"
7
+ version = "0.0.2"
8
8
  description = "One command to see what is going on with your Linux server right now."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = "MIT"
11
11
  license-files = ["LICENSE"]
12
- requires-python = ">=3.8"
12
+ requires-python = ">=3.9"
13
13
  authors = [{ name = "Aleksandr Pimenov", email = "wachawo@gmail.com" }]
14
14
  maintainers = [{ name = "Aleksandr Pimenov", email = "wachawo@gmail.com" }]
15
15
  keywords = ["devops", "sre", "linux", "diagnostics", "monitoring", "cron", "system", "audit", "cli"]
@@ -18,7 +18,6 @@ classifiers = [
18
18
  "Intended Audience :: System Administrators",
19
19
  "Intended Audience :: Developers",
20
20
  "Programming Language :: Python :: 3",
21
- "Programming Language :: Python :: 3.8",
22
21
  "Programming Language :: Python :: 3.9",
23
22
  "Programming Language :: Python :: 3.10",
24
23
  "Programming Language :: Python :: 3.11",
@@ -59,12 +58,14 @@ include = ["wtftools*"]
59
58
  include-package-data = true
60
59
 
61
60
  [tool.setuptools.data-files]
62
- "share/bash-completion/completions" = ["scripts/wtf.bash-completion"]
61
+ "share/bash-completion/completions" = ["completions/wtf"]
63
62
 
64
63
  [tool.black]
65
64
  line-length = 180
66
65
  target-version = ["py38"]
67
66
 
67
+ # Lint/format target stays py38 so the source keeps 3.8-compatible style; the
68
+ # packaged build floor is 3.9 (requires-python) due to build-time setuptools.
68
69
  [tool.ruff]
69
70
  line-length = 180
70
71
  target-version = "py38"
@@ -91,6 +92,9 @@ testpaths = ["tests"]
91
92
  python_files = ["test_*.py"]
92
93
  required_plugins = ["pytest-cov"]
93
94
  addopts = "-v --tb=short --cov=wtftools --cov-report=term-missing --cov-fail-under=80"
95
+ markers = [
96
+ "integration: exercises real host tools (docker/systemctl/smartctl/journalctl, /proc). Runs by default; skip fast local runs with -m 'not integration'.",
97
+ ]
94
98
 
95
99
  [tool.coverage.run]
96
100
  branch = true
@@ -6,6 +6,8 @@ import logging
6
6
  import types
7
7
  from unittest import mock
8
8
 
9
+ import pytest
10
+
9
11
  from wtftools import audit
10
12
 
11
13
 
@@ -39,7 +41,7 @@ def test_check_load_levels(monkeypatch):
39
41
  monkeypatch.setattr(audit.sysinfo, "get_loadavg", lambda: (1.0, 1.0, 1.0))
40
42
  assert audit._check_load().status == "ok"
41
43
  monkeypatch.setattr(audit.sysinfo, "get_loadavg", lambda: (5.0, 5.0, 5.0))
42
- assert audit._check_load().status == "ok" or audit._check_load().status == "warn"
44
+ assert audit._check_load().status == "warn" # 5.0 / 4 CPUs = 1.25x warn band
43
45
  monkeypatch.setattr(audit.sysinfo, "get_loadavg", lambda: (10.0, 10.0, 10.0))
44
46
  assert audit._check_load().status == "fail"
45
47
 
@@ -324,6 +326,7 @@ def test_run_audit_list_outcome(monkeypatch):
324
326
  assert len(results) == 2
325
327
 
326
328
 
329
+ @pytest.mark.integration
327
330
  def test_run_audit_full_runs():
328
331
  # Smoke: real run_audit must not crash on the host running tests
329
332
  results = audit.run_audit()
@@ -2,6 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  """Tests for new audit-module surface: registry, filter, since-hours, run_audit(names)."""
4
4
 
5
+ import pytest
5
6
 
6
7
  from wtftools import audit
7
8
 
@@ -35,6 +36,7 @@ def test_run_audit_with_unknown_name(monkeypatch):
35
36
  assert "unknown" in results[0].message
36
37
 
37
38
 
39
+ @pytest.mark.integration
38
40
  def test_run_audit_full_still_works():
39
41
  results = audit.run_audit()
40
42
  assert len(results) >= 15
@@ -102,6 +104,7 @@ def test_since_hours_used_by_auth(monkeypatch):
102
104
  audit.set_since_hours(24)
103
105
 
104
106
 
107
+ @pytest.mark.integration
105
108
  def test_check_registry_callables():
106
109
  """All registered checks must be callable and not crash on smoke invocation."""
107
110
  for name, fn in audit.CHECK_REGISTRY.items():