kx-cli 0.0.8__tar.gz → 0.0.10__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 (106) hide show
  1. {kx_cli-0.0.8/src/kx_cli.egg-info → kx_cli-0.0.10}/PKG-INFO +51 -65
  2. {kx_cli-0.0.8 → kx_cli-0.0.10}/README.md +50 -64
  3. {kx_cli-0.0.8 → kx_cli-0.0.10}/pyproject.toml +1 -1
  4. kx_cli-0.0.10/src/kx/commands/_metadata.py +16 -0
  5. kx_cli-0.0.10/src/kx/commands/annotations.py +12 -0
  6. kx_cli-0.0.10/src/kx/commands/context.py +13 -0
  7. kx_cli-0.0.10/src/kx/commands/contexts.py +28 -0
  8. kx_cli-0.0.10/src/kx/commands/diagnostic.py +396 -0
  9. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/events.py +16 -9
  10. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/labels.py +2 -6
  11. kx_cli-0.0.10/src/kx/commands/metadata_write.py +54 -0
  12. kx_cli-0.0.10/src/kx/commands/scan.py +122 -0
  13. kx_cli-0.0.10/src/kx/commands/top.py +131 -0
  14. kx_cli-0.0.10/src/kx/commands/yaml.py +43 -0
  15. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/config.py +7 -0
  16. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/console.py +202 -57
  17. kx_cli-0.0.10/src/kx/diagnostics.py +738 -0
  18. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/events.py +16 -1
  19. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/graph.py +36 -4
  20. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/index.py +20 -0
  21. kx_cli-0.0.10/src/kx/kubectl.py +64 -0
  22. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/main.py +244 -19
  23. kx_cli-0.0.10/src/kx/scanner.py +99 -0
  24. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/state.py +30 -7
  25. {kx_cli-0.0.8 → kx_cli-0.0.10/src/kx_cli.egg-info}/PKG-INFO +51 -65
  26. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx_cli.egg-info/SOURCES.txt +20 -0
  27. kx_cli-0.0.10/tests/test_annotations.py +54 -0
  28. kx_cli-0.0.10/tests/test_cli_context.py +54 -0
  29. kx_cli-0.0.10/tests/test_cli_label_annotate.py +57 -0
  30. kx_cli-0.0.10/tests/test_cli_top.py +81 -0
  31. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_config.py +34 -0
  32. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_console.py +283 -15
  33. kx_cli-0.0.10/tests/test_context.py +49 -0
  34. kx_cli-0.0.10/tests/test_contexts.py +58 -0
  35. kx_cli-0.0.10/tests/test_diagnostic.py +838 -0
  36. kx_cli-0.0.10/tests/test_diagnostics.py +1165 -0
  37. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_events.py +37 -11
  38. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_index.py +44 -0
  39. kx_cli-0.0.10/tests/test_kubectl.py +87 -0
  40. kx_cli-0.0.10/tests/test_metadata_helper.py +56 -0
  41. kx_cli-0.0.10/tests/test_metadata_write.py +112 -0
  42. kx_cli-0.0.10/tests/test_scan.py +358 -0
  43. kx_cli-0.0.10/tests/test_scanner.py +114 -0
  44. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_state.py +59 -0
  45. kx_cli-0.0.10/tests/test_top.py +234 -0
  46. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_yaml.py +22 -0
  47. kx_cli-0.0.8/src/kx/commands/diagnostic.py +0 -195
  48. kx_cli-0.0.8/src/kx/commands/yaml.py +0 -32
  49. kx_cli-0.0.8/src/kx/diagnostics.py +0 -363
  50. kx_cli-0.0.8/src/kx/kubectl.py +0 -39
  51. kx_cli-0.0.8/tests/test_diagnostic.py +0 -241
  52. kx_cli-0.0.8/tests/test_diagnostics.py +0 -415
  53. {kx_cli-0.0.8 → kx_cli-0.0.10}/LICENSE +0 -0
  54. {kx_cli-0.0.8 → kx_cli-0.0.10}/setup.cfg +0 -0
  55. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/__init__.py +0 -0
  56. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/__init__.py +0 -0
  57. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/back.py +0 -0
  58. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/delete.py +0 -0
  59. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/describe.py +0 -0
  60. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/drop.py +0 -0
  61. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/edit.py +0 -0
  62. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/exec.py +0 -0
  63. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/forward.py +0 -0
  64. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/get.py +0 -0
  65. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/logs.py +0 -0
  66. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/namespace.py +0 -0
  67. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/port_forward.py +0 -0
  68. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/rollout.py +0 -0
  69. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/scale.py +0 -0
  70. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/state.py +0 -0
  71. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/theme.py +0 -0
  72. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/commands/tree.py +0 -0
  73. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/errors.py +0 -0
  74. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/k8s.py +0 -0
  75. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/kinds.py +0 -0
  76. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/refresh.py +0 -0
  77. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/themes.py +0 -0
  78. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx/types.py +0 -0
  79. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx_cli.egg-info/dependency_links.txt +0 -0
  80. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx_cli.egg-info/entry_points.txt +0 -0
  81. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx_cli.egg-info/requires.txt +0 -0
  82. {kx_cli-0.0.8 → kx_cli-0.0.10}/src/kx_cli.egg-info/top_level.txt +0 -0
  83. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_back.py +0 -0
  84. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_cli_get.py +0 -0
  85. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_cli_help.py +0 -0
  86. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_cli_kind_alias.py +0 -0
  87. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_delete.py +0 -0
  88. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_describe.py +0 -0
  89. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_drop.py +0 -0
  90. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_edit.py +0 -0
  91. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_error_handling.py +0 -0
  92. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_exec.py +0 -0
  93. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_forward.py +0 -0
  94. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_get.py +0 -0
  95. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_graph.py +0 -0
  96. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_kinds.py +0 -0
  97. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_labels.py +0 -0
  98. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_logs.py +0 -0
  99. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_namespace.py +0 -0
  100. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_port_forward.py +0 -0
  101. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_refresh.py +0 -0
  102. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_rollout.py +0 -0
  103. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_scale.py +0 -0
  104. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_theme.py +0 -0
  105. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_themes.py +0 -0
  106. {kx_cli-0.0.8 → kx_cli-0.0.10}/tests/test_tree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kx-cli
3
- Version: 0.0.8
3
+ Version: 0.0.10
4
4
  Summary: kubectl wrapper with index-based resource selection
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.11
@@ -70,7 +70,7 @@ With pip:
70
70
  pip install kx-cli
71
71
  ```
72
72
 
73
- As a kubectl plugin via [krew](https://krew.sigs.k8s.io/), where kx is published as `idx` (no Python required; pending krew-index acceptance):
73
+ As a kubectl plugin via [krew](https://krew.sigs.k8s.io/), where kx is published as `idx` (no Python required):
74
74
 
75
75
  ```bash
76
76
  kubectl krew install idx
@@ -88,26 +88,9 @@ pipx run --spec kx-cli kx get pods
88
88
 
89
89
  ## Usage
90
90
 
91
- ### List resources
91
+ `kx get <resource>` fetches resources and assigns each row an index; every other command takes those indexes. Extra flags pass through to kubectl (`-n <namespace>`, selectors, ...), and `--match`/`-m` filters rows by name substring. All-namespace listings (`-A`) are display-only — names aren't unique across namespaces.
92
92
 
93
- ```
94
- kx get <resource> [--match|-m <substring>] [kubectl flags...]
95
- ```
96
-
97
- Fetches resources and assigns index numbers. Any extra flags (e.g. `-n <namespace>`, `-A`) are passed through to kubectl. Use `--match`/`-m` to filter results by name (substring, case-insensitive). All-namespace listings (`-A`) are display-only — rows aren't indexed, since names aren't unique across namespaces; scope to a namespace to select.
98
-
99
- Known kinds can drop the `get`: `kx pods`, `kx deploy -n kube-system`, `kx svc --match api`. This covers the built-in kinds and their kubectl shorthands (`po`, `deploy`, `svc`, `sts`, ...); existing commands take precedence, so `kx ns 3` still switches namespaces (bare `kx ns` lists them). CRDs and other resource types still use `kx get <resource>`. An integer after a kind is an index into the current state: `kx po 3` (or `kx get po 3`) relists just that pod, erroring if index 3 isn't a pod. Multiple indexes work too: `kx po 1 3`.
100
-
101
- ```
102
- $ kx get pods
103
- Pods · default · 3 items
104
- X NAME READY STATUS RESTARTS AGE
105
- 1 api-7d9f4b8c6-xkp2q 1/1 Running 0 2d
106
- 2 worker-6c8b5f7d9-mnt4r 1/1 Running 3 5h
107
- 3 postgres-0 1/1 Running 0 12d
108
- ```
109
-
110
- All subsequent commands reference resources by their `X` index from the last `kx get`.
93
+ Known kinds can drop the `get`: `kx pods`, `kx deploy -n kube-system`, `kx svc --match api` — kubectl shorthands (`po`, `deploy`, `svc`, `sts`, ...) included. An integer after a kind relists just that index: `kx po 3`. CRDs and other resource types still use `kx get <resource>`.
111
94
 
112
95
  Global flags: `--no-color` disables styled output, `-v`/`--version` prints the installed version, and `--help` on any command shows usage, examples, and aliases.
113
96
 
@@ -117,10 +100,15 @@ Global flags: `--no-color` disables styled output, `-v`/`--version` prints the i
117
100
  | Command | Description |
118
101
  |---|---|
119
102
  | `kx get <resource> [--match/-m str] [kubectl flags...]` | List resources and assign index numbers for use with other commands; shorthand: kx <kind> (e.g. kx pods, kx po 3). |
103
+ | `kx top [--match/-m str] [--no-limits] [kubectl flags...]` | List CPU/memory usage for pods in the current namespace and assign index numbers, like kx get; shows usage as a percent of each pod's resource limits unless --no-limits. |
120
104
  | `kx describe <indexes>... [kubectl flags...]` | Show full kubectl describe output for one or more indexed resources. |
121
105
  | `kx events <indexes>...` | Show Kubernetes events for one or more indexed resources. |
122
106
  | `kx logs <index> [kubectl flags...]` | Stream logs for an indexed resource; aggregates across pods for Deployments, StatefulSets, DaemonSets, and Services. |
107
+ | `kx scan [<index>] [--engine str] [--full] [kubectl flags...]` | Scan the unique container images of an indexed workload for vulnerabilities, or the whole namespace when no index is given; prints a severity summary table by default, or the raw scanner output with --full. |
123
108
  | `kx labels <indexes>... [--selector/-s]` | Show labels for one or more indexed resources; --selector formats output as a label selector. |
109
+ | `kx annotations <indexes>...` | Show annotations for one or more indexed resources. |
110
+ | `kx label <index> [<pairs>...] [--remove str] [--overwrite]` | Set or remove labels on an indexed resource. |
111
+ | `kx annotate <index> [<pairs>...] [--remove str] [--overwrite]` | Set or remove annotations on an indexed resource. |
124
112
  | `kx yaml <indexes>... [--show str]` | Print the raw YAML manifest for one or more indexed resources; --show filters to specific top-level fields. |
125
113
  | `kx delete <indexes>... [--yes/-y]` | Delete one or more indexed resources (prompts for confirmation unless --yes). |
126
114
  | `kx edit <index> [kubectl flags...]` | Open an indexed resource in your editor via kubectl edit. |
@@ -129,8 +117,9 @@ Global flags: `--no-color` disables styled output, `-v`/`--version` prints the i
129
117
  | `kx rollout <action> <index>` | Run a rollout action (status, restart, pause, resume, history, undo) on a Deployment, StatefulSet, or DaemonSet. |
130
118
  | `kx scale <index> <replicas>` | Scale an indexed Deployment, StatefulSet, or ReplicaSet to a given replica count. |
131
119
  | `kx port-forward <index> <port> [kubectl flags...]` | Forward a local port to an indexed resource (Pod, Deployment, ReplicaSet, StatefulSet, DaemonSet, Service). |
132
- | `kx diagnostic <index>` | Run read-only health diagnostics on an indexed Deployment, StatefulSet, DaemonSet, or Pod; alias: kx diag. |
120
+ | `kx diagnostic [<index>]` | Diagnose an indexed Deployment, StatefulSet, DaemonSet, Job, CronJob, Service, PersistentVolumeClaim, or Pod, or triage the whole namespace when no index is given; alias: kx diag. |
133
121
  | `kx namespace [<index>]` | List namespaces, or switch to an indexed one; alias: kx ns. |
122
+ | `kx context [<index>]` | List kubeconfig contexts, or switch to an indexed one; alias: kx contexts. |
134
123
  | `kx theme [<name>]` | List available color themes or persist a choice by name or index. |
135
124
  | `kx state [<position>] [--all/-a]` | Show current state, jump to a history position, or list all entries with --all. |
136
125
  | `kx drop <position>` | Remove a history entry by position (shown in kx state --all). |
@@ -138,48 +127,41 @@ Global flags: `--no-color` disables styled output, `-v`/`--version` prints the i
138
127
  | `kx forward` | Navigate to the next kx get result. |
139
128
  <!-- commands-table-end -->
140
129
 
141
- ### Example workflow
130
+ ### Triage a namespace
142
131
 
143
- ```bash
144
- # list deployments, pick index 2
145
- kx get deployments
146
- kx describe 2
147
-
148
- # check events on that deployment
149
- kx events 2
150
-
151
- # drill into a pod
152
- kx get pods
153
- kx logs 1
154
- kx exec 1 # opens bash/sh
155
- kx exec 1 -- env # run a specific command
156
-
157
- # forward local port 8080 to port 80 on a service
158
- kx get services
159
- kx port-forward 2 8080:80
160
-
161
- # navigate history after multiple gets
162
- kx get pods
163
- kx get deployments
164
- kx logs 1 # logs from pod index 1
165
- kx state --all # review full history
166
-
167
- # clean up
168
- kx delete 3
169
- ```
132
+ Bare `kx diag` sweeps the current namespace — Deployments, StatefulSets,
133
+ DaemonSets, Jobs, CronJobs, Services, and PersistentVolumeClaims, plus pods
134
+ nothing owns — and prints a ranked table of what's unhealthy. Findings also
135
+ draw on live resource usage (`kx top`): a pod running hot against its memory
136
+ limit is flagged as an OOMKill risk before it dies. The rows are indexed, so
137
+ `kx diag 1` or `kx logs 2` drill straight in.
170
138
 
171
- ## State
139
+ <div align="center">
140
+ <img src="https://raw.githubusercontent.com/jzills/kx/main/demo/diag.gif" alt="kx diag demo" width="800"/>
141
+ </div>
172
142
 
173
- `kx` maintains a history of up to 10 `kx get` results in `~/.kx/state.json`. A cursor tracks your current position; index-based commands always resolve against the entry at the cursor.
143
+ `kx diag <index>` diagnoses a single resource: a verdict banner, a `SUMMARY`
144
+ of findings (CrashLoopBackOff, image pull failures, OOMKills, unschedulable
145
+ pods, stalled rollouts, missing Service endpoints, Pending PVCs, failed
146
+ CronJob runs, usage near limits), a per-pod status table, recent log tails
147
+ from broken containers, and warning events — one screen instead of four
148
+ kubectl commands.
174
149
 
175
- ```
176
- $ kx get pods # saves a new entry, cursor advances
177
- $ kx get deployments # saves another entry, cursor advances
178
- $ kx logs 1 # resolves index 1 from the pods result
179
- $ kx state --all # lists all history entries and the current position
180
- ```
150
+ ### Scan images for vulnerabilities
151
+
152
+ `kx scan <index>` scans the unique container images of an indexed workload
153
+ (init containers and CronJob job templates included); bare `kx scan` sweeps
154
+ every workload in the namespace. Results come back as a severity summary,
155
+ or the full per-image CVE report with `--full`. Requires
156
+ [Docker Scout](https://docs.docker.com/scout/).
157
+
158
+ <div align="center">
159
+ <img src="https://raw.githubusercontent.com/jzills/kx/main/demo/scan.gif" alt="kx scan demo" width="800"/>
160
+ </div>
161
+
162
+ ## State
181
163
 
182
- Use `kx state <position>` to jump directly to any history entry, and `kx drop <position>` to remove one.
164
+ `kx` maintains a history of up to 10 `kx get` results in `~/.kx/state.json`. A cursor tracks your current position; index-based commands always resolve against the entry at the cursor. `kx state --all` lists the history, `kx state <position>` jumps to an entry, `kx back`/`kx forward` step through it, and `kx drop <position>` removes one.
183
165
 
184
166
  ## Configuration
185
167
 
@@ -194,13 +176,13 @@ Use `kx state <position>` to jump directly to any history entry, and `kx drop <p
194
176
 
195
177
  Styled output is emitted only when stdout is a terminal — piped or redirected output is plain text, so `kx get pods | grep worker` stays clean. The [`NO_COLOR`](https://no-color.org/) convention is honored as well.
196
178
 
197
- ### Themes
179
+ ## Themes
198
180
 
199
- ```bash
200
- kx theme # list available themes (indexed) with a preview of each
201
- kx theme nord # persist a theme to ~/.kx/config.toml
202
- kx theme 3 # same, selecting by index from the kx theme listing
203
- ```
181
+ `kx theme` lists the available themes with a preview of each; `kx theme <name|index>` persists a choice to `~/.kx/config.toml`.
182
+
183
+ <div align="center">
184
+ <img src="https://raw.githubusercontent.com/jzills/kx/main/demo/theme.gif" alt="kx theme demo" width="800"/>
185
+ </div>
204
186
 
205
187
  Prefab themes: `github-dark` (default), `dracula`, `nord`, `gruvbox`, `solarized-dark`, `catppuccin-mocha`, `tokyo-night`, `rose-pine`, `mono`, `light` (for light terminal backgrounds), and `plain` (no styling at all).
206
188
 
@@ -217,3 +199,7 @@ Run the CLI directly:
217
199
  ```bash
218
200
  python -m kx.main --help
219
201
  ```
202
+
203
+ The demo GIFs are rendered from [VHS](https://github.com/charmbracelet/vhs)
204
+ tapes — see [`demo/README.md`](demo/README.md) for seeding the demo namespace
205
+ and re-recording.
@@ -47,7 +47,7 @@ With pip:
47
47
  pip install kx-cli
48
48
  ```
49
49
 
50
- As a kubectl plugin via [krew](https://krew.sigs.k8s.io/), where kx is published as `idx` (no Python required; pending krew-index acceptance):
50
+ As a kubectl plugin via [krew](https://krew.sigs.k8s.io/), where kx is published as `idx` (no Python required):
51
51
 
52
52
  ```bash
53
53
  kubectl krew install idx
@@ -65,26 +65,9 @@ pipx run --spec kx-cli kx get pods
65
65
 
66
66
  ## Usage
67
67
 
68
- ### List resources
68
+ `kx get <resource>` fetches resources and assigns each row an index; every other command takes those indexes. Extra flags pass through to kubectl (`-n <namespace>`, selectors, ...), and `--match`/`-m` filters rows by name substring. All-namespace listings (`-A`) are display-only — names aren't unique across namespaces.
69
69
 
70
- ```
71
- kx get <resource> [--match|-m <substring>] [kubectl flags...]
72
- ```
73
-
74
- Fetches resources and assigns index numbers. Any extra flags (e.g. `-n <namespace>`, `-A`) are passed through to kubectl. Use `--match`/`-m` to filter results by name (substring, case-insensitive). All-namespace listings (`-A`) are display-only — rows aren't indexed, since names aren't unique across namespaces; scope to a namespace to select.
75
-
76
- Known kinds can drop the `get`: `kx pods`, `kx deploy -n kube-system`, `kx svc --match api`. This covers the built-in kinds and their kubectl shorthands (`po`, `deploy`, `svc`, `sts`, ...); existing commands take precedence, so `kx ns 3` still switches namespaces (bare `kx ns` lists them). CRDs and other resource types still use `kx get <resource>`. An integer after a kind is an index into the current state: `kx po 3` (or `kx get po 3`) relists just that pod, erroring if index 3 isn't a pod. Multiple indexes work too: `kx po 1 3`.
77
-
78
- ```
79
- $ kx get pods
80
- Pods · default · 3 items
81
- X NAME READY STATUS RESTARTS AGE
82
- 1 api-7d9f4b8c6-xkp2q 1/1 Running 0 2d
83
- 2 worker-6c8b5f7d9-mnt4r 1/1 Running 3 5h
84
- 3 postgres-0 1/1 Running 0 12d
85
- ```
86
-
87
- All subsequent commands reference resources by their `X` index from the last `kx get`.
70
+ Known kinds can drop the `get`: `kx pods`, `kx deploy -n kube-system`, `kx svc --match api` — kubectl shorthands (`po`, `deploy`, `svc`, `sts`, ...) included. An integer after a kind relists just that index: `kx po 3`. CRDs and other resource types still use `kx get <resource>`.
88
71
 
89
72
  Global flags: `--no-color` disables styled output, `-v`/`--version` prints the installed version, and `--help` on any command shows usage, examples, and aliases.
90
73
 
@@ -94,10 +77,15 @@ Global flags: `--no-color` disables styled output, `-v`/`--version` prints the i
94
77
  | Command | Description |
95
78
  |---|---|
96
79
  | `kx get <resource> [--match/-m str] [kubectl flags...]` | List resources and assign index numbers for use with other commands; shorthand: kx <kind> (e.g. kx pods, kx po 3). |
80
+ | `kx top [--match/-m str] [--no-limits] [kubectl flags...]` | List CPU/memory usage for pods in the current namespace and assign index numbers, like kx get; shows usage as a percent of each pod's resource limits unless --no-limits. |
97
81
  | `kx describe <indexes>... [kubectl flags...]` | Show full kubectl describe output for one or more indexed resources. |
98
82
  | `kx events <indexes>...` | Show Kubernetes events for one or more indexed resources. |
99
83
  | `kx logs <index> [kubectl flags...]` | Stream logs for an indexed resource; aggregates across pods for Deployments, StatefulSets, DaemonSets, and Services. |
84
+ | `kx scan [<index>] [--engine str] [--full] [kubectl flags...]` | Scan the unique container images of an indexed workload for vulnerabilities, or the whole namespace when no index is given; prints a severity summary table by default, or the raw scanner output with --full. |
100
85
  | `kx labels <indexes>... [--selector/-s]` | Show labels for one or more indexed resources; --selector formats output as a label selector. |
86
+ | `kx annotations <indexes>...` | Show annotations for one or more indexed resources. |
87
+ | `kx label <index> [<pairs>...] [--remove str] [--overwrite]` | Set or remove labels on an indexed resource. |
88
+ | `kx annotate <index> [<pairs>...] [--remove str] [--overwrite]` | Set or remove annotations on an indexed resource. |
101
89
  | `kx yaml <indexes>... [--show str]` | Print the raw YAML manifest for one or more indexed resources; --show filters to specific top-level fields. |
102
90
  | `kx delete <indexes>... [--yes/-y]` | Delete one or more indexed resources (prompts for confirmation unless --yes). |
103
91
  | `kx edit <index> [kubectl flags...]` | Open an indexed resource in your editor via kubectl edit. |
@@ -106,8 +94,9 @@ Global flags: `--no-color` disables styled output, `-v`/`--version` prints the i
106
94
  | `kx rollout <action> <index>` | Run a rollout action (status, restart, pause, resume, history, undo) on a Deployment, StatefulSet, or DaemonSet. |
107
95
  | `kx scale <index> <replicas>` | Scale an indexed Deployment, StatefulSet, or ReplicaSet to a given replica count. |
108
96
  | `kx port-forward <index> <port> [kubectl flags...]` | Forward a local port to an indexed resource (Pod, Deployment, ReplicaSet, StatefulSet, DaemonSet, Service). |
109
- | `kx diagnostic <index>` | Run read-only health diagnostics on an indexed Deployment, StatefulSet, DaemonSet, or Pod; alias: kx diag. |
97
+ | `kx diagnostic [<index>]` | Diagnose an indexed Deployment, StatefulSet, DaemonSet, Job, CronJob, Service, PersistentVolumeClaim, or Pod, or triage the whole namespace when no index is given; alias: kx diag. |
110
98
  | `kx namespace [<index>]` | List namespaces, or switch to an indexed one; alias: kx ns. |
99
+ | `kx context [<index>]` | List kubeconfig contexts, or switch to an indexed one; alias: kx contexts. |
111
100
  | `kx theme [<name>]` | List available color themes or persist a choice by name or index. |
112
101
  | `kx state [<position>] [--all/-a]` | Show current state, jump to a history position, or list all entries with --all. |
113
102
  | `kx drop <position>` | Remove a history entry by position (shown in kx state --all). |
@@ -115,48 +104,41 @@ Global flags: `--no-color` disables styled output, `-v`/`--version` prints the i
115
104
  | `kx forward` | Navigate to the next kx get result. |
116
105
  <!-- commands-table-end -->
117
106
 
118
- ### Example workflow
107
+ ### Triage a namespace
119
108
 
120
- ```bash
121
- # list deployments, pick index 2
122
- kx get deployments
123
- kx describe 2
124
-
125
- # check events on that deployment
126
- kx events 2
127
-
128
- # drill into a pod
129
- kx get pods
130
- kx logs 1
131
- kx exec 1 # opens bash/sh
132
- kx exec 1 -- env # run a specific command
133
-
134
- # forward local port 8080 to port 80 on a service
135
- kx get services
136
- kx port-forward 2 8080:80
137
-
138
- # navigate history after multiple gets
139
- kx get pods
140
- kx get deployments
141
- kx logs 1 # logs from pod index 1
142
- kx state --all # review full history
143
-
144
- # clean up
145
- kx delete 3
146
- ```
109
+ Bare `kx diag` sweeps the current namespace — Deployments, StatefulSets,
110
+ DaemonSets, Jobs, CronJobs, Services, and PersistentVolumeClaims, plus pods
111
+ nothing owns — and prints a ranked table of what's unhealthy. Findings also
112
+ draw on live resource usage (`kx top`): a pod running hot against its memory
113
+ limit is flagged as an OOMKill risk before it dies. The rows are indexed, so
114
+ `kx diag 1` or `kx logs 2` drill straight in.
147
115
 
148
- ## State
116
+ <div align="center">
117
+ <img src="https://raw.githubusercontent.com/jzills/kx/main/demo/diag.gif" alt="kx diag demo" width="800"/>
118
+ </div>
149
119
 
150
- `kx` maintains a history of up to 10 `kx get` results in `~/.kx/state.json`. A cursor tracks your current position; index-based commands always resolve against the entry at the cursor.
120
+ `kx diag <index>` diagnoses a single resource: a verdict banner, a `SUMMARY`
121
+ of findings (CrashLoopBackOff, image pull failures, OOMKills, unschedulable
122
+ pods, stalled rollouts, missing Service endpoints, Pending PVCs, failed
123
+ CronJob runs, usage near limits), a per-pod status table, recent log tails
124
+ from broken containers, and warning events — one screen instead of four
125
+ kubectl commands.
151
126
 
152
- ```
153
- $ kx get pods # saves a new entry, cursor advances
154
- $ kx get deployments # saves another entry, cursor advances
155
- $ kx logs 1 # resolves index 1 from the pods result
156
- $ kx state --all # lists all history entries and the current position
157
- ```
127
+ ### Scan images for vulnerabilities
128
+
129
+ `kx scan <index>` scans the unique container images of an indexed workload
130
+ (init containers and CronJob job templates included); bare `kx scan` sweeps
131
+ every workload in the namespace. Results come back as a severity summary,
132
+ or the full per-image CVE report with `--full`. Requires
133
+ [Docker Scout](https://docs.docker.com/scout/).
134
+
135
+ <div align="center">
136
+ <img src="https://raw.githubusercontent.com/jzills/kx/main/demo/scan.gif" alt="kx scan demo" width="800"/>
137
+ </div>
138
+
139
+ ## State
158
140
 
159
- Use `kx state <position>` to jump directly to any history entry, and `kx drop <position>` to remove one.
141
+ `kx` maintains a history of up to 10 `kx get` results in `~/.kx/state.json`. A cursor tracks your current position; index-based commands always resolve against the entry at the cursor. `kx state --all` lists the history, `kx state <position>` jumps to an entry, `kx back`/`kx forward` step through it, and `kx drop <position>` removes one.
160
142
 
161
143
  ## Configuration
162
144
 
@@ -171,13 +153,13 @@ Use `kx state <position>` to jump directly to any history entry, and `kx drop <p
171
153
 
172
154
  Styled output is emitted only when stdout is a terminal — piped or redirected output is plain text, so `kx get pods | grep worker` stays clean. The [`NO_COLOR`](https://no-color.org/) convention is honored as well.
173
155
 
174
- ### Themes
156
+ ## Themes
175
157
 
176
- ```bash
177
- kx theme # list available themes (indexed) with a preview of each
178
- kx theme nord # persist a theme to ~/.kx/config.toml
179
- kx theme 3 # same, selecting by index from the kx theme listing
180
- ```
158
+ `kx theme` lists the available themes with a preview of each; `kx theme <name|index>` persists a choice to `~/.kx/config.toml`.
159
+
160
+ <div align="center">
161
+ <img src="https://raw.githubusercontent.com/jzills/kx/main/demo/theme.gif" alt="kx theme demo" width="800"/>
162
+ </div>
181
163
 
182
164
  Prefab themes: `github-dark` (default), `dracula`, `nord`, `gruvbox`, `solarized-dark`, `catppuccin-mocha`, `tokyo-night`, `rose-pine`, `mono`, `light` (for light terminal backgrounds), and `plain` (no styling at all).
183
165
 
@@ -194,3 +176,7 @@ Run the CLI directly:
194
176
  ```bash
195
177
  python -m kx.main --help
196
178
  ```
179
+
180
+ The demo GIFs are rendered from [VHS](https://github.com/charmbracelet/vhs)
181
+ tapes — see [`demo/README.md`](demo/README.md) for seeding the demo namespace
182
+ and re-recording.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kx-cli"
3
- version = "0.0.8"
3
+ version = "0.0.10"
4
4
  description = "kubectl wrapper with index-based resource selection"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -0,0 +1,16 @@
1
+ import json
2
+
3
+ from kx.kubectl import KubectlServiceProtocol
4
+ from kx.state import StateServiceProtocol
5
+
6
+
7
+ def fetch_metadata_field(
8
+ kubectl: KubectlServiceProtocol,
9
+ state: StateServiceProtocol,
10
+ index: int,
11
+ field: str,
12
+ ) -> dict[str, str]:
13
+ name, namespace, kind = state.fields(index)
14
+ raw = kubectl.run(["get", kind, name, "-n", namespace, "-o", "json"])
15
+ obj = json.loads(raw)
16
+ return obj.get("metadata", {}).get(field) or {}
@@ -0,0 +1,12 @@
1
+ from kx.commands._metadata import fetch_metadata_field
2
+ from kx.kubectl import KubectlServiceProtocol
3
+ from kx.state import StateServiceProtocol
4
+
5
+
6
+ class AnnotationsCommand:
7
+ def __init__(self, state: StateServiceProtocol, kubectl: KubectlServiceProtocol):
8
+ self.state = state
9
+ self.kubectl = kubectl
10
+
11
+ def execute(self, index: int) -> dict[str, str]:
12
+ return fetch_metadata_field(self.kubectl, self.state, index, "annotations")
@@ -0,0 +1,13 @@
1
+ from kx.kubectl import KubectlServiceProtocol
2
+ from kx.state import StateServiceProtocol
3
+
4
+
5
+ class ContextCommand:
6
+ def __init__(self, state: StateServiceProtocol, kubectl: KubectlServiceProtocol):
7
+ self.state = state
8
+ self.kubectl = kubectl
9
+
10
+ def execute(self, index: int) -> str:
11
+ name, _, _ = self.state.fields(index)
12
+ self.kubectl.run(["config", "use-context", name])
13
+ return name
@@ -0,0 +1,28 @@
1
+ from kx.index import IndexServiceProtocol
2
+ from kx.kubectl import KubectlServiceProtocol
3
+ from kx.state import State, StateServiceProtocol
4
+
5
+
6
+ class ContextsCommand:
7
+ def __init__(
8
+ self,
9
+ kubectl: KubectlServiceProtocol,
10
+ state: StateServiceProtocol,
11
+ index: IndexServiceProtocol,
12
+ ):
13
+ self.kubectl = kubectl
14
+ self.state = state
15
+ self.index = index
16
+
17
+ def execute(self) -> str:
18
+ output = self.kubectl.run(["config", "get-contexts"])
19
+ indexed_output, names = self.index.add(output)
20
+ if names:
21
+ current = self.kubectl.current_context()
22
+ self.state.save(
23
+ State(
24
+ resources={name: "Context" for name in names},
25
+ namespace=current,
26
+ )
27
+ )
28
+ return indexed_output