Implement proper IRC multiline handling #21

Closed
opened 2026-08-15 13:46:33 +00:00 by alex · 2 comments
Owner

Refer to https://ircv3.net/specs/extensions/multiline

Obvious bug is currently for forgejo release printing where each single line in the release notes is sent as a single IRC message

Refer to https://ircv3.net/specs/extensions/multiline Obvious bug is currently for forgejo release printing where each single line in the release notes is sent as a single IRC message
Author
Owner

/pi fix this in a new PR

/pi fix this in a new PR
Contributor

Now I have a full picture. Let me write the new pure multiline module first:Now the wiring module:Now wire it into the client creation and the pollers:Now update forgejo-activity.ts to hand whole messages to the injected poster:Now the test suites for both new modules:The wiring logic is right — my test emitted CAP params incorrectly (the cap list arrives as a single space-joined param). Fixing the test:All 79 pass. Now run the full suite, lint, and fmt:All checks pass. Now an end-to-end smoke test against a scripted fake IRC server to validate the real wire bytes through the actual @irc/client (not just fakes):Wire format matches the spec exactly. Verify line byte-lengths and clean up:Now the docs. README first:Now AGENTS.md — project structure and a short note:The full check suite passes. Let me do a final review of the complete diff and new files:Everything is clean. Final full verification, then create the PR:PR #22 created: #22 (feat: send multi-line announcements as IRCv3 draft/multiline batches)

Summary

Implemented the client side of IRCv3 draft/multiline — the extension wasn't available in @irc/client 0.23.1 (checked upstream), so it's implemented in-tree following the repo's pure/wiring split:

New modules

  • src/multiline.ts — pure planning: parses the max-bytes/max-lines CAP value, decides batch vs plain delivery, splits over-long lines into draft/multiline-concat continuations (word-boundary preferred, trailing space kept, multi-byte safe), enforces server limits with truncation + marker, and builds the wire commands with the spec's worst-case 512-byte relay budget per line.
  • src/irc/multiline.ts — wiring: requests the cap at registration, captures limits from the raw CAP LS/NEW exchange (including LS 302 continuation lines), and posts BATCH +ref draft/multiline <target> → tagged PRIVMSGs → BATCH -ref (sends chained so lines never interleave), falling back to one plain PRIVMSG per non-blank line on servers without the extension. State resets per connection.

Changed

  • src/irc/client.ts attaches the session on every (re)connect; both pollers post through the multiline-aware poster; forgejo-activity.ts now hands the whole multi-line release-notes text to post in one piece (the old per-line postMessageLines is removed), so release notes render as a single message on supporting servers (Ergo, IRCCloud, UnrealIRCd, …) and behave exactly as before elsewhere.
  • README + AGENTS.md document the feature, structure, and the one known limitation (blank lines dropped inside batches, since the client library can't emit an empty trailing PRIVMSG param).

Verification — new unit tests for both modules plus an updated pollRepo test (305 tests pass); an end-to-end smoke run against a scripted IRC server through the real @irc/client confirmed correct wire bytes and cap negotiation. deno fmt --check, lint, check, test, and fallow are all green.


View action run | Model: zai/glm-5.2 (thinking: max) | Time: 26m 30s | Tokens: 4.9M | Pi SDK v0.84.0 | Action v2.27.0-develop (develop @ ee8f1d1)

Now I have a full picture. Let me write the new pure multiline module first:Now the wiring module:Now wire it into the client creation and the pollers:Now update `forgejo-activity.ts` to hand whole messages to the injected poster:Now the test suites for both new modules:The wiring logic is right — my test emitted CAP params incorrectly (the cap list arrives as a single space-joined param). Fixing the test:All 79 pass. Now run the full suite, lint, and fmt:All checks pass. Now an end-to-end smoke test against a scripted fake IRC server to validate the real wire bytes through the actual `@irc/client` (not just fakes):Wire format matches the spec exactly. Verify line byte-lengths and clean up:Now the docs. README first:Now AGENTS.md — project structure and a short note:The full check suite passes. Let me do a final review of the complete diff and new files:Everything is clean. Final full verification, then create the PR:PR #22 created: https://forge.l3x.in/alex/irc-greeter-bot/pulls/22 (`feat: send multi-line announcements as IRCv3 draft/multiline batches`) ## Summary Implemented the client side of IRCv3 [`draft/multiline`](https://ircv3.net/specs/extensions/multiline) — the extension wasn't available in `@irc/client` 0.23.1 (checked upstream), so it's implemented in-tree following the repo's pure/wiring split: **New modules** - `src/multiline.ts` — pure planning: parses the `max-bytes`/`max-lines` CAP value, decides batch vs plain delivery, splits over-long lines into `draft/multiline-concat` continuations (word-boundary preferred, trailing space kept, multi-byte safe), enforces server limits with truncation + `…` marker, and builds the wire commands with the spec's worst-case 512-byte relay budget per line. - `src/irc/multiline.ts` — wiring: requests the cap at registration, captures limits from the raw `CAP LS`/`NEW` exchange (including LS 302 continuation lines), and posts `BATCH +ref draft/multiline <target>` → tagged `PRIVMSG`s → `BATCH -ref` (sends chained so lines never interleave), falling back to one plain `PRIVMSG` per non-blank line on servers without the extension. State resets per connection. **Changed** - `src/irc/client.ts` attaches the session on every (re)connect; both pollers post through the multiline-aware poster; `forgejo-activity.ts` now hands the whole multi-line release-notes text to `post` in one piece (the old per-line `postMessageLines` is removed), so release notes render as a single message on supporting servers (Ergo, IRCCloud, UnrealIRCd, …) and behave exactly as before elsewhere. - README + AGENTS.md document the feature, structure, and the one known limitation (blank lines dropped inside batches, since the client library can't emit an empty trailing `PRIVMSG` param). **Verification** — new unit tests for both modules plus an updated `pollRepo` test (305 tests pass); an end-to-end smoke run against a scripted IRC server through the real `@irc/client` confirmed correct wire bytes and cap negotiation. `deno fmt --check`, `lint`, `check`, `test`, and `fallow` are all green. --- [View action run](https://forge.l3x.in/alex/irc-greeter-bot/actions/runs/107) | Model: zai/glm-5.2 (thinking: max) | Time: 26m 30s | Tokens: 4.9M | Pi SDK v0.84.0 | Action v2.27.0-develop (develop @ ee8f1d1)
alex closed this issue 2026-08-15 14:13:24 +00:00
Sign in to join this conversation.
No labels
dependencies
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
alex/irc-greeter-bot#21
No description provided.