kokoirc 0.2.2 → 0.2.4

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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -40
  3. package/docs/commands/clear.md +26 -0
  4. package/docs/commands/image.md +47 -0
  5. package/docs/commands/invite.md +23 -0
  6. package/docs/commands/kill.md +24 -0
  7. package/docs/commands/names.md +25 -0
  8. package/docs/commands/oper.md +24 -0
  9. package/docs/commands/preview.md +31 -0
  10. package/docs/commands/quote.md +29 -0
  11. package/docs/commands/server.md +6 -0
  12. package/docs/commands/stats.md +31 -0
  13. package/docs/commands/topic.md +12 -6
  14. package/docs/commands/version.md +23 -0
  15. package/docs/commands/wallops.md +24 -0
  16. package/package.json +46 -3
  17. package/src/app/App.tsx +11 -1
  18. package/src/core/commands/help-formatter.ts +1 -1
  19. package/src/core/commands/helpers.ts +3 -1
  20. package/src/core/commands/registry.ts +251 -6
  21. package/src/core/config/defaults.ts +11 -0
  22. package/src/core/config/loader.ts +5 -0
  23. package/src/core/constants.ts +3 -0
  24. package/src/core/image-preview/cache.ts +108 -0
  25. package/src/core/image-preview/detect.ts +105 -0
  26. package/src/core/image-preview/encode.ts +116 -0
  27. package/src/core/image-preview/fetch.ts +174 -0
  28. package/src/core/image-preview/index.ts +6 -0
  29. package/src/core/image-preview/render.ts +222 -0
  30. package/src/core/image-preview/stdin-guard.ts +33 -0
  31. package/src/core/init.ts +2 -1
  32. package/src/core/irc/antiflood.ts +2 -1
  33. package/src/core/irc/client.ts +3 -2
  34. package/src/core/irc/events.ts +121 -47
  35. package/src/core/irc/netsplit.ts +2 -1
  36. package/src/core/scripts/api.ts +3 -2
  37. package/src/core/state/store.ts +261 -3
  38. package/src/core/storage/index.ts +2 -2
  39. package/src/core/storage/writer.ts +12 -10
  40. package/src/core/theme/renderer.tsx +29 -1
  41. package/src/core/utils/id.ts +2 -0
  42. package/src/types/config.ts +14 -0
  43. package/src/types/index.ts +1 -2
  44. package/src/ui/chat/ChatView.tsx +11 -5
  45. package/src/ui/chat/MessageLine.tsx +18 -1
  46. package/src/ui/input/CommandInput.tsx +2 -1
  47. package/src/ui/layout/AppLayout.tsx +3 -1
  48. package/src/ui/overlay/ImagePreview.tsx +77 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kofany
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,23 +2,20 @@
2
2
 
3
3
  A modern terminal IRC client built with [OpenTUI](https://github.com/anomalyco/opentui), React, and Bun. Inspired by irssi, designed for the future.
4
4
 
5
- ```
6
- ┌─ Buffers ─┬─────────────────────────────────────────┬─ Users ──┐
7
- IRCnet │ 12:34:05 <kofany> hey everyone │ @kofany │
8
- │ #chat │ 12:34:08 <alice> welcome back! │ +alice │
9
- │ #dev │ 12:34:12 * kofany waves │ bob │
10
- │ #music │ 12:34:15 <bob> what's new? │ charlie │
11
- │ │ │ │
12
- │ ├──────────────────────────────────────────┤ │
13
- │ │ [IRCnet❱ /msg alice check this out │ │
14
- │ ├──────────────────────────────────────────┤ │
15
- │ │ 12:34 | kofany(+i) | #chat(+nt) | lag:2 │ │
16
- └───────────┴──────────────────────────────────────────┴──────────┘
17
- ```
5
+ **[Documentation](https://kofany.github.io/kokoIRC/)** | **[GitHub](https://github.com/kofany/kokoIRC)**
6
+
7
+ ![Splash screen](docs/screenshots/splash.png)
8
+
9
+ ![Chat view with multiple networks](docs/screenshots/chat.png)
10
+
11
+ ![Help command list](docs/screenshots/help.png)
12
+
13
+ ![Configuration and settings](docs/screenshots/config.png)
18
14
 
19
15
  ## Features
20
16
 
21
17
  - **Full IRC protocol** — channels, queries, CTCP, SASL, TLS, channel modes, ban lists
18
+ - **Inline image preview** — kitty, iTerm2, sixel, and Unicode fallback with tmux support
22
19
  - **irssi-style navigation** — `Esc+1-9` window switching, `/commands`, aliases
23
20
  - **Mouse support** — click buffers/nicks, drag to resize sidepanels
24
21
  - **Netsplit detection** — batches join/part floods into single events
@@ -35,17 +32,31 @@ A modern terminal IRC client built with [OpenTUI](https://github.com/anomalyco/o
35
32
 
36
33
  ## Install
37
34
 
35
+ ### From npm
36
+
38
37
  ```bash
39
- git clone https://github.com/kofany/OpenIRC.git
40
- cd OpenIRC
41
- bun install
38
+ # Global install (adds `kokoirc` to your PATH)
39
+ bun install -g kokoirc
40
+
41
+ # Then run from anywhere
42
+ kokoirc
43
+ ```
44
+
45
+ ```bash
46
+ # Local install (in a project)
47
+ bun add kokoirc
48
+ bunx kokoirc
42
49
  ```
43
50
 
44
- ## Usage
51
+ ### From source
45
52
 
46
53
  ```bash
54
+ git clone https://github.com/kofany/kokoIRC.git
55
+ cd kokoIRC
56
+ bun install
57
+
47
58
  # Run directly
48
- bun run src/index.tsx
59
+ bun run start
49
60
 
50
61
  # Or build a standalone binary
51
62
  bun run build
@@ -74,10 +85,17 @@ address = "irc.libera.chat"
74
85
  port = 6697
75
86
  tls = true
76
87
  autoconnect = true
77
- channels = ["#kokoirc"]
88
+ channels = ["#kokoirc", "#secret mykey"] # "channel key" syntax for keyed channels
89
+ autosendcmd = "MSG NickServ identify pass; WAIT 2000; MODE $N +i"
78
90
  # sasl_user = "mynick"
79
91
  # sasl_pass = "hunter2"
80
92
 
93
+ [image_preview]
94
+ enabled = true
95
+ max_width = 800
96
+ max_height = 400
97
+ protocol = "auto" # "auto", "kitty", "iterm2", "sixel", "unicode"
98
+
81
99
  [logging]
82
100
  enabled = true
83
101
  encrypt = false # AES-256-GCM (key auto-generated in ~/.kokoirc/.env)
@@ -91,16 +109,19 @@ j = "/join"
91
109
 
92
110
  ## Commands
93
111
 
94
- 33 built-in commands. Type `/help` for the full list, `/help <command>` for details.
112
+ 44 built-in commands. Type `/help` for the full list, `/help <command>` for details.
95
113
 
96
114
  | Category | Commands |
97
115
  |----------|----------|
98
116
  | Connection | `/connect`, `/disconnect`, `/quit`, `/server` |
99
- | Channel | `/join`, `/part`, `/close`, `/topic`, `/list` |
100
- | Messaging | `/msg`, `/me`, `/notice`, `/action`, `/slap` |
101
- | Moderation | `/kick`, `/ban`, `/unban`, `/kb`, `/mode` |
117
+ | Channel | `/join`, `/part`, `/close`, `/clear`, `/topic`, `/names`, `/invite`, `/list` |
118
+ | Messaging | `/msg`, `/me`, `/notice`, `/action`, `/slap`, `/wallops` |
119
+ | Moderation | `/kick`, `/ban`, `/unban`, `/kb`, `/kill`, `/mode` |
102
120
  | Nick/Ops | `/nick`, `/op`, `/deop`, `/voice`, `/devoice` |
121
+ | Media | `/image`, `/preview` |
103
122
  | User | `/whois`, `/wii`, `/ignore`, `/unignore` |
123
+ | Info | `/version`, `/stats` |
124
+ | Server | `/quote` (`/raw`), `/oper` |
104
125
  | Config | `/set`, `/alias`, `/unalias`, `/reload` |
105
126
  | Logging | `/log status`, `/log search <query>` |
106
127
  | Scripts | `/script load`, `/script unload`, `/script list` |
@@ -191,25 +212,32 @@ Messages are stored in `~/.kokoirc/logs.db` (SQLite WAL mode). The log system su
191
212
 
192
213
  ```
193
214
  src/
194
- ├── index.tsx # Entry point — creates OpenTUI renderer
215
+ ├── index.tsx # Entry point — creates OpenTUI renderer
195
216
  ├── app/
196
- │ └── App.tsx # Lifecycle: config → storage → theme → connect
217
+ │ └── App.tsx # Lifecycle: config → storage → theme → connect
197
218
  ├── core/
198
- │ ├── irc/ # IRC client, event binding, middlewares
199
- │ ├── state/ # Zustand store (UI-agnostic)
200
- │ ├── commands/ # Command registry and parser
201
- │ ├── config/ # TOML loader, defaults, merge logic
202
- │ ├── storage/ # SQLite logging, encryption, queries
203
- │ ├── scripts/ # Script loader, API, event bus
204
- └── theme/ # Format string parser, theme loader
205
- ├── ui/ # React components (no IRC imports)
206
- │ ├── AppLayout.tsx # 3-column layout with resizable panels
207
- │ ├── ChatView.tsx # Message scrollback
208
- ├── BufferList.tsx # Left sidebar
209
- ├── NickList.tsx # Right sidebar
210
- │ ├── CommandInput.tsx # Input line with prompt
211
- └── StatusLine.tsx # Status bar
212
- └── types/ # TypeScript definitions
219
+ │ ├── init.ts # Application initialization
220
+ │ ├── constants.ts # Global constants
221
+ │ ├── irc/ # IRC client, event binding, middlewares
222
+ │ ├── state/ # Zustand store (UI-agnostic)
223
+ │ ├── commands/ # Command registry, parser, help system
224
+ │ ├── config/ # TOML loader, defaults, merge logic
225
+ ├── storage/ # SQLite logging, encryption, queries
226
+ ├── scripts/ # Script loader, API, event bus
227
+ │ ├── theme/ # Format string parser, theme loader
228
+ │ ├── image-preview/ # Inline image display (kitty, iTerm2, sixel)
229
+ └── utils/ # Message ID generator
230
+ ├── ui/ # React components (no IRC imports)
231
+ │ ├── layout/ # AppLayout, TopicBar
232
+ ├── chat/ # ChatView, MessageLine
233
+ │ ├── input/ # CommandInput
234
+ │ ├── sidebar/ # BufferList, NickList
235
+ │ ├── statusbar/ # StatusLine
236
+ │ ├── overlay/ # ImagePreview
237
+ │ ├── splash/ # SplashScreen
238
+ │ ├── hooks/ # useStatusbarColors
239
+ │ └── ErrorBoundary.tsx # React error boundary
240
+ └── types/ # TypeScript definitions
213
241
  ```
214
242
 
215
243
  The UI layer never imports from `core/irc/` — all communication goes through the Zustand store. This keeps the architecture clean and makes it possible to drive the same store from a web frontend.
@@ -0,0 +1,26 @@
1
+ ---
2
+ category: Channel
3
+ description: Clear current buffer's messages
4
+ ---
5
+
6
+ # /clear
7
+
8
+ ## Syntax
9
+
10
+ /clear
11
+
12
+ ## Description
13
+
14
+ Clears all messages from the current buffer's display. This is a visual-only
15
+ operation — chat logs in the database are not affected. Messages remain
16
+ searchable via `/log search`.
17
+
18
+ Works on any buffer type: channels, queries, and server buffers.
19
+
20
+ ## Examples
21
+
22
+ /clear
23
+
24
+ ## See Also
25
+
26
+ /close, /log
@@ -0,0 +1,47 @@
1
+ ---
2
+ category: Media
3
+ description: Manage image preview cache
4
+ ---
5
+
6
+ # /image
7
+
8
+ ## Syntax
9
+
10
+ /image [stats|clear]
11
+
12
+ ## Description
13
+
14
+ Manage the image preview cache. Without arguments, shows current status.
15
+
16
+ All image preview settings are persistent via `/set`:
17
+
18
+ /set image_preview.enabled true|false
19
+ /set image_preview.protocol auto|kitty|iterm2|sixel|symbols
20
+ /set image_preview.max_width 0
21
+ /set image_preview.cache_max_mb 100
22
+
23
+ ## Subcommands
24
+
25
+ ### stats
26
+
27
+ Show cache file count and disk usage.
28
+
29
+ /image stats
30
+
31
+ ### clear
32
+
33
+ Delete all cached images.
34
+
35
+ /image clear
36
+
37
+ ## Examples
38
+
39
+ /image
40
+ /image stats
41
+ /image clear
42
+ /set image_preview.enabled false
43
+ /set image_preview.protocol kitty
44
+
45
+ ## See Also
46
+
47
+ /preview, /set
@@ -0,0 +1,23 @@
1
+ ---
2
+ category: Channel
3
+ description: Invite a user to a channel
4
+ ---
5
+
6
+ # /invite
7
+
8
+ ## Syntax
9
+
10
+ /invite <nick> [channel]
11
+
12
+ ## Description
13
+
14
+ Invite a user to join a channel. Without a channel argument, invites to the current channel. You typically need channel operator status to send invites.
15
+
16
+ ## Examples
17
+
18
+ /invite friend # invite to current channel
19
+ /invite friend #secret # invite to #secret
20
+
21
+ ## See Also
22
+
23
+ /kick, /ban
@@ -0,0 +1,24 @@
1
+ ---
2
+ category: Moderation
3
+ description: Disconnect a user from the network
4
+ ---
5
+
6
+ # /kill
7
+
8
+ ## Syntax
9
+
10
+ /kill <nick> [reason]
11
+
12
+ ## Description
13
+
14
+ Forcefully disconnect a user from the IRC network. This is an operator-only
15
+ command. If no reason is given, the target's nick is used as the reason.
16
+
17
+ ## Examples
18
+
19
+ /kill spammer Spamming is not allowed
20
+ /kill baduser
21
+
22
+ ## See Also
23
+
24
+ /oper, /kick, /ban
@@ -0,0 +1,25 @@
1
+ ---
2
+ category: Channel
3
+ description: List users in a channel
4
+ ---
5
+
6
+ # /names
7
+
8
+ ## Syntax
9
+
10
+ /names [channel]
11
+
12
+ ## Description
13
+
14
+ Display the list of users in a channel. Without arguments, lists users in the current channel. Also sends a NAMES request to the server to refresh the nick list panel.
15
+
16
+ The output shows each user with their mode prefix (@, +, etc.) and a total user count.
17
+
18
+ ## Examples
19
+
20
+ /names # list users in current channel
21
+ /names #help # list users in #help
22
+
23
+ ## See Also
24
+
25
+ /who, /whois
@@ -0,0 +1,24 @@
1
+ ---
2
+ category: Server
3
+ description: Authenticate as an IRC operator
4
+ ---
5
+
6
+ # /oper
7
+
8
+ ## Syntax
9
+
10
+ /oper <name> <password>
11
+
12
+ ## Description
13
+
14
+ Authenticate as an IRC operator. Requires valid operator credentials
15
+ configured on the server. Once authenticated, you gain access to
16
+ operator commands like /kill and /wallops.
17
+
18
+ ## Examples
19
+
20
+ /oper admin secretpass
21
+
22
+ ## See Also
23
+
24
+ /kill, /wallops
@@ -0,0 +1,31 @@
1
+ ---
2
+ category: Media
3
+ description: Preview an image URL in the terminal
4
+ ---
5
+
6
+ # /preview
7
+
8
+ ## Syntax
9
+
10
+ /preview <url>
11
+
12
+ ## Description
13
+
14
+ Fetches an image URL and displays it as a popup overlay in the terminal.
15
+ Supports direct image links (jpg, png, gif, webp) and pages with og:image
16
+ metadata (imgur, imgbb, etc.).
17
+
18
+ The display protocol is auto-detected based on your terminal:
19
+ kitty, iTerm2, sixel, or Unicode half-block fallback.
20
+ Works through tmux with DCS passthrough.
21
+
22
+ Press any key or click to dismiss the preview.
23
+
24
+ ## Examples
25
+
26
+ /preview https://i.imgur.com/abc123.jpg
27
+ /preview https://imgur.com/gallery/xyz
28
+
29
+ ## See Also
30
+
31
+ /image
@@ -0,0 +1,29 @@
1
+ ---
2
+ category: Server
3
+ description: Send a raw IRC command
4
+ ---
5
+
6
+ # /quote
7
+
8
+ ## Syntax
9
+
10
+ /quote <raw command>
11
+
12
+ ## Description
13
+
14
+ Send a raw IRC command directly to the server. This is useful for
15
+ commands not yet implemented, testing, or advanced protocol interaction.
16
+
17
+ ## Aliases
18
+
19
+ /raw
20
+
21
+ ## Examples
22
+
23
+ /quote VERSION
24
+ /raw LUSERS
25
+ /quote PRIVMSG #channel :hello
26
+
27
+ ## See Also
28
+
29
+ /stats
@@ -39,6 +39,12 @@ Add a new server to the configuration.
39
39
  - `-label=<name>` — Display name
40
40
  - `-password=<pass>` — Server password (saved to .env)
41
41
  - `-sasl=<user>:<pass>` — SASL auth (saved to .env)
42
+ - `-autosendcmd=<cmds>` — Commands to run on connect, before autojoin (must be last flag)
43
+
44
+ Autosendcmd uses erssi-style syntax: commands separated by `;`, with `WAIT <ms>`
45
+ for delays. `$N` is replaced with your nick.
46
+
47
+ /server add libera irc.libera.chat:6697 -tls -autosendcmd=MSG NickServ identify pass; WAIT 2000; MODE $N +i
42
48
 
43
49
  ### remove
44
50
 
@@ -0,0 +1,31 @@
1
+ ---
2
+ category: Info
3
+ description: Request server statistics
4
+ ---
5
+
6
+ # /stats
7
+
8
+ ## Syntax
9
+
10
+ /stats [type] [server]
11
+
12
+ ## Description
13
+
14
+ Request statistics from the IRC server. Common stat types include:
15
+
16
+ - `u` — server uptime
17
+ - `m` — command usage counts
18
+ - `o` — configured operators
19
+ - `l` — connection information
20
+
21
+ If no type is given, the server may return a summary or help text.
22
+
23
+ ## Examples
24
+
25
+ /stats
26
+ /stats u
27
+ /stats o irc.libera.chat
28
+
29
+ ## See Also
30
+
31
+ /quote
@@ -7,18 +7,24 @@ description: Set or view channel topic
7
7
 
8
8
  ## Syntax
9
9
 
10
- /topic [channel] <text>
10
+ /topic
11
+ /topic <text>
12
+ /topic <channel>
13
+ /topic <channel> <text>
11
14
 
12
15
  ## Description
13
16
 
14
- Set the topic for a channel. With just text, sets the topic for the
15
- current channel. Specify a channel name to set a different channel's topic.
17
+ View or set the channel topic.
18
+
19
+ Without arguments, displays the current topic for the active channel. With only a channel name, requests the topic from the server. With text, sets the topic on the active channel (or on the specified channel).
16
20
 
17
21
  ## Examples
18
22
 
19
- /topic Welcome to the channel!
20
- /topic #linux Welcome to #linux
23
+ /topic # show current topic
24
+ /topic #help # request topic for #help
25
+ /topic Welcome to the channel # set topic on current channel
26
+ /topic #help Welcome! # set topic on #help
21
27
 
22
28
  ## See Also
23
29
 
24
- /join, /mode
30
+ /mode, /names
@@ -0,0 +1,23 @@
1
+ ---
2
+ category: Info
3
+ description: Query server or user client version
4
+ ---
5
+
6
+ # /version
7
+
8
+ ## Syntax
9
+
10
+ /version [nick]
11
+
12
+ ## Description
13
+
14
+ Without arguments, queries the IRC server version. With a nick, sends a CTCP VERSION request to that user to find out what client they are using. The reply is displayed in the active buffer.
15
+
16
+ ## Examples
17
+
18
+ /version # query server version
19
+ /version someone # query someone's client version
20
+
21
+ ## See Also
22
+
23
+ /whois
@@ -0,0 +1,24 @@
1
+ ---
2
+ category: Messaging
3
+ description: Send a message to all IRC operators
4
+ ---
5
+
6
+ # /wallops
7
+
8
+ ## Syntax
9
+
10
+ /wallops <message>
11
+
12
+ ## Description
13
+
14
+ Send a message to all connected IRC operators. This is an operator-only
15
+ command typically used for server-wide announcements among staff.
16
+
17
+ ## Examples
18
+
19
+ /wallops Server maintenance in 10 minutes
20
+ /wallops New oper guidelines posted on the wiki
21
+
22
+ ## See Also
23
+
24
+ /oper, /quote
package/package.json CHANGED
@@ -1,7 +1,46 @@
1
1
  {
2
2
  "name": "kokoirc",
3
- "version": "0.2.2",
4
- "description": "Terminal IRC client built with OpenTUI and React",
3
+ "version": "0.2.4",
4
+ "description": "Modern terminal IRC client with inline image preview, SASL, scripting, encrypted logging, and theming — built with OpenTUI, React, and Bun",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "kofany",
8
+ "url": "https://github.com/kofany"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/kofany/kokoIRC.git"
13
+ },
14
+ "homepage": "https://kofany.github.io/kokoIRC/",
15
+ "bugs": {
16
+ "url": "https://github.com/kofany/kokoIRC/issues"
17
+ },
18
+ "keywords": [
19
+ "irc",
20
+ "irc-client",
21
+ "terminal",
22
+ "tui",
23
+ "cli",
24
+ "client",
25
+ "chat",
26
+ "opentui",
27
+ "react",
28
+ "bun",
29
+ "sasl",
30
+ "sixel",
31
+ "image-preview",
32
+ "theming",
33
+ "scripting",
34
+ "sqlite",
35
+ "encrypted-logging"
36
+ ],
37
+ "engines": {
38
+ "bun": ">=1.2.0"
39
+ },
40
+ "os": [
41
+ "darwin",
42
+ "linux"
43
+ ],
5
44
  "module": "src/index.tsx",
6
45
  "type": "module",
7
46
  "bin": {
@@ -17,11 +56,13 @@
17
56
  "start": "bun run src/index.tsx",
18
57
  "dev": "bun --watch run src/index.tsx",
19
58
  "test": "bun test",
20
- "build": "bun build --compile src/index.tsx --outfile openirc"
59
+ "build": "bun build --compile src/index.tsx --outfile openirc",
60
+ "docs:build": "bun run docs/build.ts"
21
61
  },
22
62
  "devDependencies": {
23
63
  "@types/bun": "^1.3.9",
24
64
  "@types/react": "^19.2.14",
65
+ "@types/sharp": "^0.32.0",
25
66
  "typescript": "^5.9.3"
26
67
  },
27
68
  "imports": {
@@ -32,6 +73,8 @@
32
73
  "@opentui/react": "^0.1.83",
33
74
  "kofany-irc-framework": "^4.14.1",
34
75
  "react": "^19.2.4",
76
+ "sharp": "^0.34.5",
77
+ "sixel": "^0.16.0",
35
78
  "smol-toml": "^1.6.0",
36
79
  "zustand": "^5.0.11"
37
80
  }
package/src/app/App.tsx CHANGED
@@ -10,6 +10,7 @@ import { initHomeDir } from "@/core/init"
10
10
  import { autoloadScripts } from "@/core/scripts/manager"
11
11
  import { initStorage, shutdownStorage } from "@/core/storage"
12
12
  import { BufferType, ActivityLevel, makeBufferId, getSortGroup } from "@/types"
13
+ import { nextMsgId } from "@/core/utils/id"
13
14
  import { SplashScreen } from "@/ui/splash/SplashScreen"
14
15
  import { AppLayout } from "@/ui/layout/AppLayout"
15
16
  import { TopicBar } from "@/ui/layout/TopicBar"
@@ -18,6 +19,7 @@ import { NickList } from "@/ui/sidebar/NickList"
18
19
  import { ChatView } from "@/ui/chat/ChatView"
19
20
  import { CommandInput } from "@/ui/input/CommandInput"
20
21
  import { StatusLine } from "@/ui/statusbar/StatusLine"
22
+ import { ImagePreview } from "@/ui/overlay/ImagePreview"
21
23
 
22
24
  export function App() {
23
25
  const renderer = useRenderer()
@@ -37,6 +39,13 @@ export function App() {
37
39
  return
38
40
  }
39
41
 
42
+ // Dismiss image preview on any keypress
43
+ if (useStore.getState().imagePreview) {
44
+ useStore.getState().hideImagePreview()
45
+ key.preventDefault()
46
+ return
47
+ }
48
+
40
49
  // Track standalone Escape keypresses for Esc+N prefix
41
50
  if (key.name === "escape" && !key.ctrl && !key.shift) {
42
51
  escPressedAt.current = Date.now()
@@ -152,7 +161,7 @@ export function App() {
152
161
  type: BufferType.Server,
153
162
  name: "Status",
154
163
  messages: [{
155
- id: crypto.randomUUID(),
164
+ id: nextMsgId(),
156
165
  timestamp: new Date(),
157
166
  type: "event" as const,
158
167
  text: "Welcome to kokoIRC. Type /connect to connect to a server.",
@@ -200,6 +209,7 @@ export function App() {
200
209
  nicklist={<NickList />}
201
210
  input={<CommandInput />}
202
211
  statusline={statusbarEnabled ? <StatusLine /> : undefined}
212
+ overlay={<ImagePreview />}
203
213
  />
204
214
  )
205
215
  }