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