dev-null-tty 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.3
2
+ Name: dev-null-tty
3
+ Version: 0.4.0
4
+ Summary: A terminal interface for /dev/null
5
+ Author: Avetis Avo Pisikyan
6
+ Author-email: Avetis Avo Pisikyan <apisikya@gmail.com>
7
+ Requires-Dist: pillow>=11.0.0
8
+ Requires-Dist: textual>=8.2.8
9
+ Requires-Dist: textual-image[textual]>=0.6.6,<0.7
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+
13
+ # dev-null-tty
14
+
15
+ A keyboard-first terminal client for [/dev/null](https://dev-null.sh), built
16
+ with [Textual](https://textual.textualize.io/) and managed with
17
+ [uv](https://docs.astral.sh/uv/).
18
+
19
+ The **Following**, **Latest**, and **Trending** journals load real commits from
20
+ the signed `/api/v1/log/{log}` endpoint after sign-in. Each journal supports
21
+ automatic cursor-based infinite scrolling, with a bottom-right notification
22
+ while another page loads. When a selected commit is clipped, `j` / `k` scroll
23
+ it into view before changing selection; oversized commits scroll through before
24
+ advancing. Guest users can view the profile
25
+ and sign in; journals require an approved device. Signed-in
26
+ users can browse a cursor-paginated notifications inbox, publish commits,
27
+ reply to a commit, or quote it. Opening the notifications inbox marks
28
+ notifications read on /dev/null. Click detected
29
+ HTTP(S) links with the mouse to open them in your default browser. The modal
30
+ composer shows the original commit above the editor for replies and quotes,
31
+ and submits through the signed `POST /api/v1/commits` endpoint. Press
32
+ `Ctrl+P` to submit. Press `Ctrl+V` in the composer to edit the draft in Neovim;
33
+ the text returns to the composer when Neovim exits successfully. Press `Ctrl+Q`
34
+ or `Escape` to close the composer. Typing `@` and part of a username opens a
35
+ server-backed dropdown of matching users; press `Down` to focus it and `Enter`
36
+ to insert the selected username.
37
+ New commits and replies can include up to three JPEG, PNG, or WebP images
38
+ (maximum 10 MB each). Press `Ctrl+F` or select **Find images** to open `fzf`
39
+ with image files under your home directory. Type to filter, use `Up` / `Down`
40
+ to move, `Tab` to select multiple images, and `Enter` to attach them, up to the
41
+ three-image limit. Press `Escape` to cancel. The picker uses a full-screen
42
+ terminal view and returns to the composer when it closes; `fzf` and `find` must
43
+ be installed. Kitty/Ghostty terminals also show an image preview in the picker.
44
+ Press `Ctrl+R` or select **Remove images** to open a preview-enabled `fzf`
45
+ picker of the attached images. Select one or more and press `Enter` to detach
46
+ them; this does not delete the image files. Image previews use
47
+ Kitty's graphics protocol and work in Kitty or Ghostty without an external
48
+ image-rendering command.
49
+ Image uploads use the `/dev/null` CLI signing protocol and require a matching
50
+ GitHub-registered SSH key available through
51
+ `ssh-agent` or as a private key under `~/.ssh/`. Quotes continue to use the
52
+ signed mobile API and do not support image attachments. Journal cards and
53
+ thread commits show a paperclip and attachment count. Journal cards show quoted
54
+ commits as compact, bordered context cards. In a commit thread, quoted replies
55
+ are labeled beside the commenter's name; the replying-to pane also shows the
56
+ quoted author's name and text inline. Quoted text wraps to the available width,
57
+ and deleted or unavailable targets are labeled where previews are shown. In a
58
+ commit thread, press `i` to open
59
+ the current commit's expanded image view. Opening a commit preloads its attached images
60
+ into a bounded in-memory cache for faster browsing. A minimap overlay appears
61
+ in the upper-left corner. The full image initially fits inside the available
62
+ view frame without stretching; zooming moves a frame-sized viewport over it.
63
+ Use `n` / `Ctrl+N` to move to
64
+ the next / previous image (wrapping at either end), `=` / `-` to zoom in / out, and `h` / `j` / `k` / `l`
65
+ to pan while zoomed. A compact square minimap appears while zoomed, showing the
66
+ view position as a dot; the image edge turns red when you reach it. Panning
67
+ allows a small buffer beyond the image edges, and the image-view keybinds remain
68
+ visible while viewing.
69
+ Press `i` again to return to the thread. Images use the
70
+ terminal's supported graphics protocol or a colored-character fallback.
71
+ In the composer, press `Ctrl+I` to open the full-screen viewer for attached
72
+ images. `Ctrl+I` is the only way to toggle the viewer from the composer. The
73
+ highlighted help line shows the active image keybinds. The composer action
74
+ buttons share one row at the bottom.
75
+ Press `Enter` on a selected journal entry to open its full commit and replies.
76
+ Use `j` / `k` to navigate replies; if the selected reply is partly obscured,
77
+ they first scroll it into view. Oversized replies scroll through their remaining
78
+ content before selection advances. Deleted replies remain visible as tombstones
79
+ and cannot be opened or acted on. Press `Enter` to follow a reply into its
80
+ own thread, `u` to move to the parent comment, and `q` or `Escape` to return to
81
+ the previous screen. Commit details show the ancestor and parent-comment
82
+ context in a scrollable pane on the left, and the comment being replied to
83
+ above its replies on the right. Use `Ctrl+J` / `Ctrl+K` or the mouse wheel to
84
+ scroll ancestor history. Use `Alt+J` / `Alt+K` to scroll the replying-to
85
+ commit. Press `Ctrl+R` to reply to the thread's main
86
+ commit or selected comment. Scroll the replies list to load older replies.
87
+
88
+ The profile's **Sign in with GitHub** action starts the documented PKCE
89
+ device authorization flow. To preserve existing sign-ins, the app keeps its
90
+ dedicated Ed25519 keypair under `~/.dev-null-tui/` (directory mode `0700`,
91
+ private key mode `0600`, no passphrase). It opens the authorization page and,
92
+ after approval, signs `POST /api/v1/devices` with the `devnull-api` namespace.
93
+ The verifier and state remain in memory. The private key stays on the device
94
+ and is never included in API requests.
95
+
96
+ Before opening the authorization page, the app registers its per-user XDG
97
+ desktop handler for `devnull://` (no `sudo`). After approval, the handler
98
+ queues the callback for the running TUI, which checks the state before
99
+ redeeming the one-time code. Pasting the full `devnull://auth/callback?...`
100
+ URL remains available if callback handling is unavailable.
101
+
102
+ The device key stays in `~/.dev-null-tui/`. On each launch, the app checks that
103
+ key with a signed `GET /api/v1/me` and restores the profile when the device is
104
+ still approved. A revoked or unapproved key is retained, but the app remains
105
+ signed out so you can authorize a device again.
106
+
107
+ Signed-in journal pages are cached locally under
108
+ `$XDG_CACHE_HOME/dev-null-tui/` (or `~/.cache/dev-null-tui/` when
109
+ `XDG_CACHE_HOME` is unset). Cache files are private to the account and the
110
+ cache directory/file use owner-only permissions. Each journal keeps at most
111
+ one page of commits; cached pages display immediately at startup while the
112
+ active journal refreshes in the background. Other cached journals refresh when
113
+ opened. The last signed-in profile is cached too, so the profile and journal
114
+ cards can render while an existing saved device key is being checked. This
115
+ cached view does not enable signed-in actions until the API confirms the
116
+ device. An explicit authentication rejection clears that account's cached
117
+ profile and journals; missing keys, network errors, and manual logout leave the
118
+ cache intact.
119
+
120
+ **Log out** removes the local private and public key files and clears the
121
+ in-memory session; callback handoff data and the callback-handler registration
122
+ are left untouched. This API does not expose a device-revocation endpoint, so
123
+ use [Settings → Devices](https://dev-null.sh/settings/devices) to revoke the
124
+ device's server-side approval too.
125
+
126
+ The handler can also be registered manually from the command line:
127
+
128
+ ```bash
129
+ uv run dev-null-tty --register-handler
130
+ ```
131
+
132
+ This registers a per-user XDG desktop entry for `devnull://` (no `sudo`). The
133
+ handler queues the callback in `~/.dev-null-tui/` with owner-only permissions;
134
+ the running TUI validates its state and removes the handoff file. Manual paste
135
+ remains available if registration is unavailable.
136
+
137
+ ## Run
138
+
139
+ ```bash
140
+ uv run dev-null-tty
141
+ ```
142
+
143
+ On Omarchy, the app reads the active palette from
144
+ `~/.local/state/omarchy/current/theme/colors.toml` at startup and checks for
145
+ changes while running, applying updates within about half a second. If that
146
+ file is not present, it uses the terminal's ANSI palette. An unreadable or
147
+ invalid palette file is reported instead of silently falling back; an invalid
148
+ live update leaves the current palette in place.
149
+
150
+ Keyboard shortcuts:
151
+
152
+ - `h` / `l` — Previous / next journal
153
+ - `r` — Refresh the active journal
154
+ - `n` — Open notifications
155
+ - `j` / `k` — Next / previous commit or notification
156
+ - `j` / `k` (commit thread) — Next / previous reply
157
+ - `Enter` — Open the selected commit/notification or follow a selected reply
158
+ - `Ctrl+J` / `Ctrl+K` (commit thread) — Scroll ancestor history
159
+ - `Alt+J` / `Alt+K` (commit thread) — Scroll the current commit up / down
160
+ - `i` (commit thread) — Toggle the current commit's image view
161
+ - `Ctrl+I` (composer) — Toggle the attached-image preview while editing
162
+ - `n` / `Ctrl+N` (image view) — Next / previous attached image
163
+ - `=` / `-` (image view) — Zoom in / out
164
+ - `h` / `j` / `k` / `l` (zoomed image) — Pan left / down / up / right
165
+ - `Ctrl+R` — Reply to the thread's main commit or selected comment; choose
166
+ attached images to remove in the composer
167
+ - `s` — Toggle star on the selected commit or thread comment
168
+ - `u` — Move up to the parent comment in a thread
169
+ - `q` (commit thread) — Return to the previous screen
170
+ - `Escape` — Return to the previous screen
171
+ - `Shift+C` — New commit
172
+ - `Shift+Q` — Quote selected commit
173
+ - `Shift+R` — Reply to selected commit
174
+ - `Ctrl+F` (composer) — Find and attach images with `fzf`
175
+ - `Ctrl+V` (composer) — Edit the draft in Neovim
176
+ - `Down` / `Enter` (composer) — Choose and insert a matching `@mention`
177
+ - `Ctrl+P` — Submit the commit, reply, or quote
178
+ - `q` — Quit
179
+
180
+ Journal navigation wraps between Latest, Following, and Trending. Loaded
181
+ journals remain visible when you switch away and refresh as soon as you return
182
+ to them.
183
+
184
+ ## Test
185
+
186
+ ```bash
187
+ uv run pytest
188
+ ```
189
+
190
+ ## Release
191
+
192
+ Configure a PyPI trusted publisher for this GitHub repository using the
193
+ `.github/workflows/publish.yml` workflow and the `pypi` environment. Update the
194
+ version in `pyproject.toml` (and refresh `uv.lock`), then push a matching
195
+ version tag, for example:
196
+
197
+ ```bash
198
+ git tag v0.3.0
199
+ git push origin v0.3.0
200
+ ```
201
+
202
+ The workflow checks that the tag matches the project version, runs the tests,
203
+ builds the wheel and source distribution, and publishes them to PyPI using
204
+ OpenID Connect. No PyPI API token is required.
205
+
206
+ The upstream project is [nunomaduro/dev-null.sh](https://github.com/nunomaduro/dev-null.sh).
@@ -0,0 +1,194 @@
1
+ # dev-null-tty
2
+
3
+ A keyboard-first terminal client for [/dev/null](https://dev-null.sh), built
4
+ with [Textual](https://textual.textualize.io/) and managed with
5
+ [uv](https://docs.astral.sh/uv/).
6
+
7
+ The **Following**, **Latest**, and **Trending** journals load real commits from
8
+ the signed `/api/v1/log/{log}` endpoint after sign-in. Each journal supports
9
+ automatic cursor-based infinite scrolling, with a bottom-right notification
10
+ while another page loads. When a selected commit is clipped, `j` / `k` scroll
11
+ it into view before changing selection; oversized commits scroll through before
12
+ advancing. Guest users can view the profile
13
+ and sign in; journals require an approved device. Signed-in
14
+ users can browse a cursor-paginated notifications inbox, publish commits,
15
+ reply to a commit, or quote it. Opening the notifications inbox marks
16
+ notifications read on /dev/null. Click detected
17
+ HTTP(S) links with the mouse to open them in your default browser. The modal
18
+ composer shows the original commit above the editor for replies and quotes,
19
+ and submits through the signed `POST /api/v1/commits` endpoint. Press
20
+ `Ctrl+P` to submit. Press `Ctrl+V` in the composer to edit the draft in Neovim;
21
+ the text returns to the composer when Neovim exits successfully. Press `Ctrl+Q`
22
+ or `Escape` to close the composer. Typing `@` and part of a username opens a
23
+ server-backed dropdown of matching users; press `Down` to focus it and `Enter`
24
+ to insert the selected username.
25
+ New commits and replies can include up to three JPEG, PNG, or WebP images
26
+ (maximum 10 MB each). Press `Ctrl+F` or select **Find images** to open `fzf`
27
+ with image files under your home directory. Type to filter, use `Up` / `Down`
28
+ to move, `Tab` to select multiple images, and `Enter` to attach them, up to the
29
+ three-image limit. Press `Escape` to cancel. The picker uses a full-screen
30
+ terminal view and returns to the composer when it closes; `fzf` and `find` must
31
+ be installed. Kitty/Ghostty terminals also show an image preview in the picker.
32
+ Press `Ctrl+R` or select **Remove images** to open a preview-enabled `fzf`
33
+ picker of the attached images. Select one or more and press `Enter` to detach
34
+ them; this does not delete the image files. Image previews use
35
+ Kitty's graphics protocol and work in Kitty or Ghostty without an external
36
+ image-rendering command.
37
+ Image uploads use the `/dev/null` CLI signing protocol and require a matching
38
+ GitHub-registered SSH key available through
39
+ `ssh-agent` or as a private key under `~/.ssh/`. Quotes continue to use the
40
+ signed mobile API and do not support image attachments. Journal cards and
41
+ thread commits show a paperclip and attachment count. Journal cards show quoted
42
+ commits as compact, bordered context cards. In a commit thread, quoted replies
43
+ are labeled beside the commenter's name; the replying-to pane also shows the
44
+ quoted author's name and text inline. Quoted text wraps to the available width,
45
+ and deleted or unavailable targets are labeled where previews are shown. In a
46
+ commit thread, press `i` to open
47
+ the current commit's expanded image view. Opening a commit preloads its attached images
48
+ into a bounded in-memory cache for faster browsing. A minimap overlay appears
49
+ in the upper-left corner. The full image initially fits inside the available
50
+ view frame without stretching; zooming moves a frame-sized viewport over it.
51
+ Use `n` / `Ctrl+N` to move to
52
+ the next / previous image (wrapping at either end), `=` / `-` to zoom in / out, and `h` / `j` / `k` / `l`
53
+ to pan while zoomed. A compact square minimap appears while zoomed, showing the
54
+ view position as a dot; the image edge turns red when you reach it. Panning
55
+ allows a small buffer beyond the image edges, and the image-view keybinds remain
56
+ visible while viewing.
57
+ Press `i` again to return to the thread. Images use the
58
+ terminal's supported graphics protocol or a colored-character fallback.
59
+ In the composer, press `Ctrl+I` to open the full-screen viewer for attached
60
+ images. `Ctrl+I` is the only way to toggle the viewer from the composer. The
61
+ highlighted help line shows the active image keybinds. The composer action
62
+ buttons share one row at the bottom.
63
+ Press `Enter` on a selected journal entry to open its full commit and replies.
64
+ Use `j` / `k` to navigate replies; if the selected reply is partly obscured,
65
+ they first scroll it into view. Oversized replies scroll through their remaining
66
+ content before selection advances. Deleted replies remain visible as tombstones
67
+ and cannot be opened or acted on. Press `Enter` to follow a reply into its
68
+ own thread, `u` to move to the parent comment, and `q` or `Escape` to return to
69
+ the previous screen. Commit details show the ancestor and parent-comment
70
+ context in a scrollable pane on the left, and the comment being replied to
71
+ above its replies on the right. Use `Ctrl+J` / `Ctrl+K` or the mouse wheel to
72
+ scroll ancestor history. Use `Alt+J` / `Alt+K` to scroll the replying-to
73
+ commit. Press `Ctrl+R` to reply to the thread's main
74
+ commit or selected comment. Scroll the replies list to load older replies.
75
+
76
+ The profile's **Sign in with GitHub** action starts the documented PKCE
77
+ device authorization flow. To preserve existing sign-ins, the app keeps its
78
+ dedicated Ed25519 keypair under `~/.dev-null-tui/` (directory mode `0700`,
79
+ private key mode `0600`, no passphrase). It opens the authorization page and,
80
+ after approval, signs `POST /api/v1/devices` with the `devnull-api` namespace.
81
+ The verifier and state remain in memory. The private key stays on the device
82
+ and is never included in API requests.
83
+
84
+ Before opening the authorization page, the app registers its per-user XDG
85
+ desktop handler for `devnull://` (no `sudo`). After approval, the handler
86
+ queues the callback for the running TUI, which checks the state before
87
+ redeeming the one-time code. Pasting the full `devnull://auth/callback?...`
88
+ URL remains available if callback handling is unavailable.
89
+
90
+ The device key stays in `~/.dev-null-tui/`. On each launch, the app checks that
91
+ key with a signed `GET /api/v1/me` and restores the profile when the device is
92
+ still approved. A revoked or unapproved key is retained, but the app remains
93
+ signed out so you can authorize a device again.
94
+
95
+ Signed-in journal pages are cached locally under
96
+ `$XDG_CACHE_HOME/dev-null-tui/` (or `~/.cache/dev-null-tui/` when
97
+ `XDG_CACHE_HOME` is unset). Cache files are private to the account and the
98
+ cache directory/file use owner-only permissions. Each journal keeps at most
99
+ one page of commits; cached pages display immediately at startup while the
100
+ active journal refreshes in the background. Other cached journals refresh when
101
+ opened. The last signed-in profile is cached too, so the profile and journal
102
+ cards can render while an existing saved device key is being checked. This
103
+ cached view does not enable signed-in actions until the API confirms the
104
+ device. An explicit authentication rejection clears that account's cached
105
+ profile and journals; missing keys, network errors, and manual logout leave the
106
+ cache intact.
107
+
108
+ **Log out** removes the local private and public key files and clears the
109
+ in-memory session; callback handoff data and the callback-handler registration
110
+ are left untouched. This API does not expose a device-revocation endpoint, so
111
+ use [Settings → Devices](https://dev-null.sh/settings/devices) to revoke the
112
+ device's server-side approval too.
113
+
114
+ The handler can also be registered manually from the command line:
115
+
116
+ ```bash
117
+ uv run dev-null-tty --register-handler
118
+ ```
119
+
120
+ This registers a per-user XDG desktop entry for `devnull://` (no `sudo`). The
121
+ handler queues the callback in `~/.dev-null-tui/` with owner-only permissions;
122
+ the running TUI validates its state and removes the handoff file. Manual paste
123
+ remains available if registration is unavailable.
124
+
125
+ ## Run
126
+
127
+ ```bash
128
+ uv run dev-null-tty
129
+ ```
130
+
131
+ On Omarchy, the app reads the active palette from
132
+ `~/.local/state/omarchy/current/theme/colors.toml` at startup and checks for
133
+ changes while running, applying updates within about half a second. If that
134
+ file is not present, it uses the terminal's ANSI palette. An unreadable or
135
+ invalid palette file is reported instead of silently falling back; an invalid
136
+ live update leaves the current palette in place.
137
+
138
+ Keyboard shortcuts:
139
+
140
+ - `h` / `l` — Previous / next journal
141
+ - `r` — Refresh the active journal
142
+ - `n` — Open notifications
143
+ - `j` / `k` — Next / previous commit or notification
144
+ - `j` / `k` (commit thread) — Next / previous reply
145
+ - `Enter` — Open the selected commit/notification or follow a selected reply
146
+ - `Ctrl+J` / `Ctrl+K` (commit thread) — Scroll ancestor history
147
+ - `Alt+J` / `Alt+K` (commit thread) — Scroll the current commit up / down
148
+ - `i` (commit thread) — Toggle the current commit's image view
149
+ - `Ctrl+I` (composer) — Toggle the attached-image preview while editing
150
+ - `n` / `Ctrl+N` (image view) — Next / previous attached image
151
+ - `=` / `-` (image view) — Zoom in / out
152
+ - `h` / `j` / `k` / `l` (zoomed image) — Pan left / down / up / right
153
+ - `Ctrl+R` — Reply to the thread's main commit or selected comment; choose
154
+ attached images to remove in the composer
155
+ - `s` — Toggle star on the selected commit or thread comment
156
+ - `u` — Move up to the parent comment in a thread
157
+ - `q` (commit thread) — Return to the previous screen
158
+ - `Escape` — Return to the previous screen
159
+ - `Shift+C` — New commit
160
+ - `Shift+Q` — Quote selected commit
161
+ - `Shift+R` — Reply to selected commit
162
+ - `Ctrl+F` (composer) — Find and attach images with `fzf`
163
+ - `Ctrl+V` (composer) — Edit the draft in Neovim
164
+ - `Down` / `Enter` (composer) — Choose and insert a matching `@mention`
165
+ - `Ctrl+P` — Submit the commit, reply, or quote
166
+ - `q` — Quit
167
+
168
+ Journal navigation wraps between Latest, Following, and Trending. Loaded
169
+ journals remain visible when you switch away and refresh as soon as you return
170
+ to them.
171
+
172
+ ## Test
173
+
174
+ ```bash
175
+ uv run pytest
176
+ ```
177
+
178
+ ## Release
179
+
180
+ Configure a PyPI trusted publisher for this GitHub repository using the
181
+ `.github/workflows/publish.yml` workflow and the `pypi` environment. Update the
182
+ version in `pyproject.toml` (and refresh `uv.lock`), then push a matching
183
+ version tag, for example:
184
+
185
+ ```bash
186
+ git tag v0.3.0
187
+ git push origin v0.3.0
188
+ ```
189
+
190
+ The workflow checks that the tag matches the project version, runs the tests,
191
+ builds the wheel and source distribution, and publishes them to PyPI using
192
+ OpenID Connect. No PyPI API token is required.
193
+
194
+ The upstream project is [nunomaduro/dev-null.sh](https://github.com/nunomaduro/dev-null.sh).
@@ -1,10 +1,14 @@
1
1
  [project]
2
2
  name = "dev-null-tty"
3
- version = "0.2.0"
3
+ version = "0.4.0"
4
4
  description = "A terminal interface for /dev/null"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
- dependencies = ["textual>=8.2.8"]
7
+ dependencies = [
8
+ "Pillow>=11.0.0",
9
+ "textual>=8.2.8",
10
+ "textual-image[textual]>=0.6.6,<0.7",
11
+ ]
8
12
 
9
13
  [[project.authors]]
10
14
  name = "Avetis Avo Pisikyan"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dev-null-tty"
3
- version = "0.2.0"
3
+ version = "0.4.0"
4
4
  description = "A terminal interface for /dev/null"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -8,7 +8,9 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.11"
10
10
  dependencies = [
11
+ "Pillow>=11.0.0",
11
12
  "textual>=8.2.8",
13
+ "textual-image[textual]>=0.6.6,<0.7",
12
14
  ]
13
15
 
14
16
  [project.scripts]