29 KiB
2026.07.26 - Fix Wikipedia article links using wrong space encoding. (0.43.2)
- Fixed Wikipedia article links in
!wpresponses using+instead of_for spaces (e.g.CLever+Audio+Plug-in→CLever_Audio_Plug-in). Thewp_url_encode()function was used for both API query parameters (where+is correct) and article title URLs (where Wikipedia expects_). Addedwp_url_encode_title()that encodes spaces as underscores for use in article link construction, and switched all article link encodings to use it.
2026.07.26 - Improved Wikipedia results formatting and article extracts. (0.43.1)
- Changed multi-result mode from a single pipe-separated message to individual messages: each result is now sent as its own IRC message (
Title — snippet) followed by a separate "Read full article: LINK" message. This makes results easier to read in busy channels and ensures each article link is immediately visible. - Removed numbering from multi-result messages (was
1. Title — ..., now justTitle — ...). - Changed single-result extract to show the first chapter instead of only the introductory paragraph: removed
exintro=truefrom the Extracts API URL so the API returns the full article content up to the character limit. - Increased the extract character limit from 500 to 800 characters (
exchars=800) to show more article content per result. - Added truncation indicator ("...") appended to single-result extracts when the text reaches 790+ characters (near the
excharslimit). - Added "Read full article: LINK" follow-up message to every single-result response (previously only sent the bare URL as a second message, now uses the "Read full article: " prefix).
2026.07.26 - Wikipedia search command. (0.43.0)
- Added
!wp <search terms>command: searches Wikipedia using the MediaWiki API (action=query&list=search) and displays results. Accepts multiple keywords (e.g.!wp quantum physics). Rate-limited viarate_limit_check(). - Single-result mode: when the search returns exactly one article, fetches the first chapter via the Extracts API (
action=query&prop=extracts, up to 800 characters) and sends the article title, intro text, and a "Read full article: LINK" message. Appends "..." if the extract was truncated. - Multi-result mode: when the search returns 2–5 articles, sends a compact numbered list with short snippets (truncated to 60 chars) separated by pipes. Each result is followed by a "Read full article: LINK" message. Appends "..." if the result list was truncated.
- Added self-contained JSON parser helpers:
wp_json_get_string()extracts string values by key,wp_json_next_array_item()iterates JSON array objects,wp_decode_json_string()handles JSON escape sequences including\uXXXXUnicode. - Added
wp_url_encode()for percent-encoding search queries and article titles in API URLs (RFC 3986 compliant, spaces as+). - Added
wp_codepoint_to_utf8()to encode Unicode code points as UTF-8 bytes (handles U+0000 through U+10FFFF). - Added
wp_strip_html()to remove HTML tags from Wikipedia search result snippets, andwp_collapse_spaces()to normalize whitespace. - Added
wp_hex_digit()to convert hexadecimal characters to numeric values. - Added
WITH_WPCMake feature toggle (ON by default) with compile definitionHAS_CMD_WP. - Added
!wpto the!helpcommand listing. - Added comprehensive doc comments to all nine functions in
cmd_wp.h.
2026.07.25 - Comprehensive flood protection: per-poll limits, userhost rate limiting, outgoing throttle. (0.42.0)
- Added
MAX_LINES_PER_POLL = 50constant and per-poll line counting inirc_feed(): the bot now drops excess lines when a single poll iteration delivers more than 50 complete IRC messages, preventing burst flooding from overwhelming the bot or triggering IRC server excess flood disconnects. - Added
poll_lines_leftcounter toSessionstruct, reset at the start of each poll cycle inmain()before callingirc_feed(). - Changed
RateLimitEntryto track byuser@hostinstead of nick: the rate limiter now keys on the full userhost extracted from the IRC prefix (nick!user@host) rather than the nick alone, preventing trivial bypass via nick cycling. Addeduserhost[128]field replacing the oldnick[32]field. - Added
current_userhost[128]global variable, parsed from the IRC message prefix inirc_handle()before dispatching to command handlers. Updatedrate_limit_check()signature to accept the userhost parameter. - Added violation tracking to
RateLimitEntrywith aviolationscounter: repeated rate limit hits from the same userhost increment the counter, enabling future escalating penalties (warnings at three violations, kick requests at 5). - Increased
RATE_LIMIT_MAXfrom 8 to 32, expanding the rate limit tracking buffer to handle more concurrent users without evicting entries. - Added outgoing message throttle to
net_send(): usesclock_gettime(CLOCK_MONOTONIC)timestamp tracking to enforce a minimumOUTGOING_DELAY_MS = 100millisecond delay between consecutive sends, preventing the bot from flooding the IRC server with rapid bursts. - Added 200ms inter-line delay in
!gitlogoutput (cmd_gitlog.h): each commit line is now separated by a 200msnanosleep()to avoid triggering IRC server flood protection on multi-commit responses. - Added 150ms inter-chunk delay in AI response delivery (
ai.h): multi-chunk AI answers now have a 150ms pause between chunks to pace outgoing traffic. - Added
AI_COOLDOWN_SECS = 5constant: after an AI query completes, a 5-second cooldown prevents immediate re-submission, reducing unnecessary load. Addedlast_ai_completiontimestamp tracked inai.hand checked inai_ask(). - Added rate limiting to casual chat and greeting responses (
cmd_greeting_or_chat.h): therate_limit_check()call now gates hardcoded greeting matches (hi, hey, hello, etc.) in addition to AI-forwarded messages. - Limited
tell_deliver()toTELL_DELIVER_MAX = 5messages per nick per delivery: excess pending messages remain in the database for the next time the user speaks, preventing a single user from triggering a flood of delivery messages. - Updated all 19 command header files to pass
current_userhostto the updatedrate_limit_check()signature.
2026.07.25 - Welcome message for new users, channel tracking docs. (0.41.2)
- Added a welcome message when users join a channel:
handle_join()now sends"Welcome, <nick>!"to the channel for non-bot users. The bot's own joins are silently ignored to avoid echo loops. - Added
src_nickparameter tohandle_join()to identify the joining user; the call site inirc_handle()was updated to passsrc_nick. - Added doc comments to
chans[](global channel tracking array) andnchans(count of tracked channels) inirc.h. - Added doc comments to
yt_url_encode()incmd_yt.hdescribing percent-encoding behavior, parameters, and return value.
2026.07.25 - Decode Unicode escapes in !yt responses. (0.41.1)
- Fixed
!ytdisplaying raw JSON Unicode escape sequences (e.g.\u0027instead of') in video titles and channel names. YouTube's oEmbed API returns non-ASCII characters as\uXXXXescapes, which were previously passed through as-is. - Added
yt_hex_digit()to convert a hex character to its numeric value. - Added
yt_codepoint_to_utf8()to encode a Unicode code point as UTF-8 bytes (handles U+0000 through U+10FFFF, producing 1-4 bytes). - Added
yt_decode_unicode_escapes()to scan a string for\uXXXXsequences and replace each with the corresponding UTF-8 bytes in-place. Safe for in-place modification because UTF-8 output is always shorter than the 6-byte escape. - Both title and author fields are now decoded after extraction from the JSON response.
- Added doc comments to all three new helper functions.
2026.07.25 - YouTube title lookup command, json_find docs. (0.41.0)
- Added
!yt <url>command: fetches the title and channel name of a YouTube video using the YouTube oEmbed API (https://www.youtube.com/oembed). The video URL is percent-encoded via a newyt_url_encode()helper before being passed as a query parameter. The JSON response is parsed fortitleandauthor_namefields using the existingjson_find()helper, and the result is formatted as"Title — Channel". - Added
WITH_YTCMake feature toggle (ON by default) with compile definitionHAS_CMD_YT. - Added
!ytto the!helpcommand listing. - Added comprehensive doc comments to
yt_url_encode()andcmd_yt()incmd_yt.h, and tojson_find()inzynk.c. - Updated README.md: added YouTube title lookup to the feature summary, features list, feature toggles table, minimal build command, and IRC commands utilities table.
2026.07.24 - Reduced MAX_HISTORY, moved LOAD_FUNC macro, added irc_reply docs. (0.40.9)
- Reduced
MAX_HISTORYfrom 100 to 12 to decrease AI context memory usage. - Moved
LOAD_FUNCmacro fromzynk.htodb.hfor better code organization (closer to its usage in sqlite_init_lib). - Added comprehensive doc comment to
irc_reply()function describing its nick-prefixing behavior for channel messages. - Reordered includes in
zynk.cto alphabetical order.
2026.07.24 - Nick-prefixed channel replies for all non-admin commands. (0.40.8)
- Added
irc_reply(): a new IRC response helper that automatically prepends the sender's nick to channel messages (e.g."nick: pong!"), while leaving private-message responses unmodified. This makes it clear which user the bot is addressing in busy channels. - Converted all non-admin command handlers to use
irc_reply()instead of rawirc_msg():!ping,!zynk,!weather,!forecast,!stock,!calc,!time,!seen,!tell,!gitlog,!changelog,!ai,!uptime,!version,!help, greeting/chat responses, and the"Not implemented..."fallback for unknown!commands. - Converted AI async responses (
ai_check_completion()) to useirc_reply(), so AI answers delivered after the original query also show the requesting user's nick. - Converted AI error messages in
ai_ask()(rate-limit busy, fork failure, start failure) to useirc_reply(). - Removed redundant manual nick prefixes from commands that already embedded the sender's nick in their response text:
!ping("nick: pong!"),!calc("nick: result"),!time("nick: 2026-07-24 ..."),!uptime("nick: up 3d ..."), and greeting/chat responses ("Hi, nick!"→"nick: Hi!"). - Admin commands (
!quit,!reload,!restart,!rebuild,!code) are intentionally excluded - these are privileged operations where the nick prefix adds no value. - The
tell_deliver()function retains its own existing format and was not modified.
2026.07.24 - Secure file ops, TLS hardening, input validation, security docs. (0.40.7)
- Added
secure_state_open(): hardened file open with O_CLOEXEC, O_NOFOLLOW, mode 0600, regular-file and ownership checks. Prevents symlink attacks, TOCTOU races, and world-writable temp files. - Replaced all
fopen()calls for temp state files (/tmp/zynk_reload,/tmp/zynk_code_restart,/tmp/zynk_make_err,/tmp/zynk_rebuild_err) withsecure_state_open()+fdopen()across hot reload, compile-restart, and rebuild paths. - Hardened TLS initialization: enforces minimum TLS 1.2 (
SSL_CTX_set_min_proto_version), disables compression (SSL_OP_NO_COMPRESSION), and checks the return value ofSSL_CTX_set_default_verify_paths()instead of ignoring failures. - CMake compiler/linker hardening: added
-Wformat=2 -Wstrict-prototypes -fstack-protector-strong,_FORTIFY_SOURCE=3for release builds, and RELRO + noexecstack linker flags. Fixed_FORTIFY_SOURCEredefinition warning on musl/Alpine by undefining before redefining viaSHELL:prefix. - Added
!calcinput validation: rejects expressions longer than 256 chars and disallows non-numeric characters (only digits,.,(),+-*/^%, and whitespace are permitted). - Added
!stocksymbol validation: rejects symbols containing characters other than alphanumerics,.,-,^, or=. - Fixed
!quit,!reload,!restartto require channel context - these commands now reject DM usage with a clear error instead of silently passing the op check. - Fixed log timestamp format:
%y(2-digit year) →%Y(4-digit year). - Fixed
asprintfreturn value check in!forecasterror paths (avoids using a potentially NULL error string). - Fixed
!reloadfork-in-place mode: only saves TLS session state whenexec_new=1, since fork-in-place inherits the live socket. - Cleaned up the reload state file on failure and in fork child for fork-in-place mode to avoid stale files.
- Fixed git SSH→HTTPS URL conversion in
!gitlogand!changelog:host:pathnow correctly becomeshost/pathinstead ofhostpath. - AI plan mode (
!aiwithout explicit agent) no longer passes--dangerously-skip-permissions. - Added IRC buffer overflow protection: lines exceeding
RBUF_SZare dropped instead of truncating. - Added doc comments to
ZYNK_RELOAD_FILE,secure_state_open(),RateLimitEntry, andrate_limits.
2026.07.24 - Strip trailing space from wttr.in weather descriptions. (0.40.6)
- Fixed trailing space in weather descriptions from wttr.in (e.g.
"Partly Cloudy "→"Partly Cloudy"), which caused a stray space before the closing parenthesis in!forecast fulloutput (e.g.(Partly Cloudy )instead of(Partly Cloudy)). Applied the same fix to the non-fullcondfield used by!forecastand!weather.
2026.07.23 - Full forecast mode, 24h sunrise/moon times, startup version. (0.40.5)
- Added
fullkeyword to!forecast:!forecast frankfurt fullshows per-day detail lines with weather description, sunrise/sunset, and moonrise/moonset in 24-hour format, sent as separate IRC messages. - Added
to_24h()helper to convert wttr.in's 12-hour AM/PM astronomy times to 24-hour format. - Fixed the missing first letter of weather descriptions in full mode (
"value": "offset was 11 instead of 10). - Startup message now includes the version:
[zynk 0.40.5] starting up. - Added doc comments to
to_24h(),find_day_obj(), and other forecast helper functions. - Fixed "Not implemented..." fallback to only trigger on
!followed by a letter (e.g.!foo), so bare!or!!!no longer produce the message.
2026.07.23 - Raise AI code mode limit, simplify plan mode prompt. (0.40.4)
- Increased AI code mode response limit back to 2000 chars (was reduced to 1000 in 0.40.3, but code changes need more room).
- Simplified the AI plan mode system prompt further: removed the explicit "tell them you are in plan mode" instruction, keeping it to a short "You are in plan mode. Answer briefly." directive.
- Fixed
!gitlogdefault count in README.md from 5 to 1 (matching the actualGITLOG_COUNTvalue set in 0.38.2). - Re-aligned the utility command table in README.md for cleaner formatting.
- Minor grammar and punctuation fixes across older changelog entries.
2026.07.23 - Simplify CMake feature loop, adjust AI response limits. (0.40.3)
- Refactored CMake feature configuration: merged the two separate
foreachloops (one for building_cmd_defsand one for printing status) into a single loop, removing redundant iteration. Improved the status banner formatting for clearer feature configuration output. - Reduced AI code mode response limit from 2000 to 1000 chars to keep IRC replies concise.
- Increased AI plan mode response limit from 800 to 1000 chars, giving slightly more room for explanations.
- Simplified AI plan mode system prompts description for clarity.
- Fixed a minor whitespace alignment in the README.md command table.
2026.07.23 - Show commit date/time in !gitlog output. (0.40.2)
!gitlognow shows the commit date and time in[YYYY-MM-DD HH:MM:SS]format at the beginning of each commit line (e.g.[2026-07-22 14:30:15] 184d4c4 Fix whitespace...).
2026.07.23 - Fix !zynk key-value timestamps to use localtime. (0.40.1)
- Fixed
!zynk key = valuestoring UTC timestamps instead of localtime:db_set()and thezynktable default useddatetime('now')which returns UTC, causing!zynk <key>to display a timestamp offset by the server's timezone difference. Changed todatetime('now','localtime')so timestamps match the system's local time. - Also fixed
db_rotate_history()(used by AI query context) and thetelltable default to use localtime.
2026.07.23 - Commit links for !gitlog, full changelog link for !changelog, CMake, multi-file refactor. (0.40.0)
!gitlognow shows a link to each commit in the repository (e.g.184d4c4 Fix whitespace... - https://...), using the git remote URL converted from SSH/SCP to HTTPS.!changelognow shows a "Full changelog: " link to CHANGELOG.md in the repository as the last message.- Removed
fullkeyword from!gitlogand!changelog(previously showed full commit messages and complete changelog entries). - Switched the build system from Make to CMake with feature toggles (
-DWITH_<FEATURE>=ON/OFF). - Refactored a single-file codebase into dedicated header files: each command now lives in its own
cmd_*.hfile, with separate modules for database (db.h), IRC protocol (irc.h), networking (net.h), TLS (tls.h), and AI (ai.h). - Updated README.md to reflect the simplified
!gitlogand!changelogsyntax and the new CMake build instructions.
2026.07.22 - Fix whitespace collapsing in !ai, !gitlog, !changelog responses. (0.39.1)
- Fixed
collapse_spaces()to treat tabs, newlines, and carriage returns as whitespace (not just spaces), collapsing any run of mixed whitespace into a single space. collapse_spaces()now strips leading and trailing whitespace from output.- Added
collapse_spaces()call to!airesponses (afterstrip_ai_phrases()). - Added
collapse_spaces()call to!changelog fullentries before sending. - Fixed
!gitlog fulloutput still containing multiple spaces from git's tab-delimited commit fields.
2026.07.21 - Hot reload preserves IRC session (nick, channels, voice). (0.39.0)
reload_do()now accepts anexec_newparameter: when 0 (!reload/!restart), the child inherits the socket fd and SSL context directly and continues the event loop without reconnecting; when 1 (!rebuild/!code), the old fork+exec path is used.- Removed
irc_part_all()from the reload path - the bot no longer parts channels on reload, so voice mode (+v) and channel presence are preserved. - Reset
pending_ai_pid/pending_ai_idin the fork child to avoid the stale state from orphaned AI processes. !reloadand!restartnow keep the bot's IRC session alive (no nick collision, no rejoin, no lost voice).!rebuild/!codestill do a clean QUIT+exec since the binary changed.
2026.07.21 - Strip opencode header from !ai responses. (0.38.3)
- Added
strip_opencode_header(): removes the opencode header line (e.g.> plan · big-pickle) and any trailing blank lines from AI responses before sending to IRC. - Pipeline order: format strip → header strip → phrase strip, so ANSI codes are cleaned up first and the
>prefix is reliably detected.
2026.07.21 - Full mode for !gitlog/!changelog, optional pull for !rebuild. (0.38.2)
- Added optional
fullkeyword to!gitlogand!changelog:!gitlog 5 fullshows full commit messages (author, date, body),!changelog 5 fullshows the complete entry text including bullet points. !gitlogfull mode collapses multiple spaces and strips leading whitespace from each commit block for cleaner IRC output.- Changed
!rebuildto skipgit pullby default; passpullto pull before rebuilding (e.g.!rebuild pull). - Changed the default count
GITLOG_COUNTfor!gitlogfrom 5 to 1 andCHANGELOG_COUNTfor!changelogfrom 5 to 1. - Reduced
GITLOG_MAXfrom 10 to 5. - Updated
!helptext to reflect new[full]and[pull]arguments. - Updated README.md with
fulloption for!gitlog/!changelogandpulloption for!rebuild.
2026.07.21 - Exempt ops from rate limiting. (0.38.1)
- Op users in channels are now exempt from rate limiting:
rate_limit_check()callschan_is_op()and allows ops through immediately. - Removed unused
AI_REPLY_MAXconstant.
2026.07.21 - Add !changelog command. (0.38.0)
- Added
!changelog [count]command: displays the latest changelog entries fromCHANGELOG.md. Defaults to five entries (CHANGELOG_COUNT), accepts 1-10 as count. Each entry title (date line) is sent as a separate IRC message with a 200ms delay to avoid IRC server flood protection. - Reduced
GITLOG_MAXandCHANGELOG_MAXfrom 20 to 10. - Updated
!helpto list!changelog. - Updated README.md with
!changelogdocumentation and corrected max values.
2026.07.20 - Add !rebuild command. (0.37.0)
- Added
!rebuildcommand (ops only, channels): runsgit pull,make clean, andmakein sequence, then triggers a hot reload if all steps succeed. If any step fails, the error output from the build is reported to the channel. - Updated
!helpto list!rebuild. - Updated README.md with
!rebuilddocumentation in the Admin (Ops Only) section.
2026.07.20 - Fix !seen showing UTC instead of local time. (0.36.1)
- Fixed
!seencommand storing UTC timestamps instead of local time:seen_update()useddatetime('now')which returns UTC, causing!seen <nick>to display a time offset by the server's timezone difference (e.g., 16:00 instead of 18:00 on a UTC+2 system). Changed todatetime('now','localtime')so seen timestamps match the system's local time.
2026.07.20 - Add !gitlog command. (0.36.0)
- Added
!gitlog [count]command: displays recent git commits of the zynk project usinggit log --oneline. Defaults to 5 commits (GITLOG_COUNT), accepts 1-20 as count. Each commit is sent as a separate IRC message. - Updated
!helpto list!gitlog. - Updated README.md with
!gitlogdocumentation andgitas a requirement. - Added detailed doc comment to
cmd_gitlog()matching the style of all other function documentation in zynk.c.
2026.07.20 - Remove timezone abbreviation from !time response. (0.35.6)
!timenow outputs date and time only (YYYY-MM-DD HH:MM:SS) without the timezone abbreviation, keeping IRC responses shorter and cleaner.- Removed 60 lines of dead timezone abbreviation-matching code from
tz_format()(previously mapped 45 IANA timezone names to abbreviations like CEST, EDT, JST, etc.). - Updated README.md output format to reflect the change.
- Added
tzdatato README.md requirements as optional (without it,!timefalls back to 45 built-in timezones).
2026.07.20 - Fix !time to work without tzdata. (0.35.5)
- Rewrote
!timeto try the systemlocaltime_r()first, then fall back to a built-in timezone table with 45 IANA zones and simplified DST rules when the system can't resolve timezones (e.g. notzdatainstalled). This means!time Australia/Sydneynow shows the correct AEST / AEDT even on minimal systems. - Added doc comments to all undocumented functions in zynk.c:
seen_update,seen_lookup,tell_add,tell_deliver,valid_irc_word,normalize_city,collapse_spaces,cmd_reload,cmd_time,cmd_seen,cmd_tell,cmd_greeting_or_chat,tz_lookup,tz_format. - Added full list of built-in timezones to README.md (all 45 entries from
tz_table) with region, offset, and DST status.
2026.07.20 - Update README with !calc pi() docs and date requirement. (0.35.4)
- Added
pi()constants section to README.md with examples (!calc pi(),!calc pi()*2,!calc pi()^2). - Added
dateto the list of system requirements in README.md.
2026.07.20 - Add pi() to !calc. (0.35.3)
- Added
pi()function support to!calc: bc -l does not definepi()on all systems, socmd_calcnow prepends api()definition before evaluating expressions.!calc pi(),!calc pi()*2,!calc pi()^2etc. all work.
2026.07.20 - Fix !time timezone conversion bug. (0.35.2)
- Fixed
!timecommand:setenv("TZ",...) + localtime()was not reliably converting to the requested timezone. Replaced withTZ=... dateviapopen(), which handles all IANA timezone names correctly (e.g.!time Australia/Sydneynow shows 11:15 AEST instead of UTC).
2026.07.20 - Fix !calc not working (bc stdin not connected). (0.35.1)
- Fixed
!calccommand: the expression was never piped tobc's stdin, causing empty output and a "no result" error for every expression. Added a second pipe to feed the expression intobcbefore reading the result.
2026.07.20 - Calculator, time, seen, and tell commands. (0.35.0)
- Added
!calc <expression>command: evaluate math expressions viabc -l(supports arithmetic, powers, trigonometry, logarithms, variables, and multi-statement expressions). - Added
!time [timezone]command: display the current time in any IANA timezone (e.g.!time US/Pacific,!time Europe/Berlin). - Added
!seen <nick>command: track and query when users were last seen (auto-updated on PRIVMSG, PART, and QUIT). - Added
!tell <nick> <message>command: leave offline messages for users, delivered automatically when they next speak. - Added
seenandtelltables to the SQLite database for persistent user tracking and message storage. - Updated
!helpto list all new commands. - Updated README.md with detailed documentation for all commands, including
!calcexpression syntax and!timetimezone examples.
2026.07.20 - Disabled stripping feature from 0.34.4 because it needs more testing. (0.34.5)
- Disabled
strip_opencode_header()(introduced in 0.34.4) as it requires further testing.
2026.07.20 - Strip opencode header from AI responses. (0.34.4)
- Added
strip_opencode_header()to remove the opencode model/agent header line from AI responses before sending them to IRC.
2026.07.19 - Show full AI error output on failure. (0.34.3)
- AI error messages now include the actual opencode output instead of a generic "(opencode exited with error)" message.
- Captured stderr from opencode (previously sent to /dev/null) so error details are no longer lost.
2026.07.19 - Collapsed double spaces in !forecast and !stock responses (0.34.2)
- Collapsed double spaces in
!forecastand!stockresponses (e.g., when weather condition is empty).
2026.07.19 - Fix !weather returning HTML. (0.34.1)
- Fixed
!weathercommand returning<!DOCTYPE html>instead of weather data: wttr.in now returns HTML when it detects a browser User-Agent, so replaced the fake Firefox UA string withzynk/VERSION. - Fixed
!forecastshowing all days as Sunday on musl libc (Alpine Linux):strptimeon musl does not computetm_wday, so addedmktime()to normalize the struct before formatting.
2026.07.19 - Uptime command, remove !hello. (0.34.0)
- Added
!uptimecommand: displays bot uptime in a human-readable format (days/hours/minutes/seconds). - Removed
!hellocommand.
2026.07.19 - Hot reload re-registration fix, !hello, docs. (0.33.1)
- Fixed hot reload: after TLS session restore, the bot now re-sends PASS/NICK/USER to re-register with the IRC server, fixing the issue where channels were never re-joined after
!reloador!restart. - Added
!hellocommand: responds with a greeting and the user's nick. - Added atomic build target in Makefile: compiles to a temp file and moves into place to avoid partial binaries on failure.
- Added comprehensive doc comments to all major functions in zynk.c.
2026.07.19 - Hot reload, stock quotes, and auto-recompile. (0.33.0)
- Added hot reload:
!reloadand!restartcommands (ops) save TLS session state, fork a new process with the inherited socket, and resume without dropping from IRC. - Added
!stock <SYMBOL>[,SYMBOL...]command to fetch real-time stock quotes from Yahoo Finance (up to 3 symbols). - Added auto-compile and restart on
!codechanges: when the AI code change response is received, the bot runsmakeand reloads on success. - Added User-Agent header to curl requests to avoid being blocked by servers that reject the default curl agent.
- Increased curl read buffer from 2 KiB to 32 KiB to handle larger API responses.
- Improved
!forecastJSON parsing: returns a descriptive error message on parse failure instead of silently returning nothing. - Increased AI_TIMEOUT from 240s to 600s and AI_REPLY_MAX from 400 to 2048 chars for longer AI interactions.
2026.07.16 - Security hardening.
- Fixed buffer overflow in ai_child_task: plen unsigned underflow when history entries exceed prefix buffer size, causing out-of-bounds writes via snprintf.
- Fixed IRC injection in handle_nick_change: validate new nick for CRLF and control characters before storing in op cache.
- Fixed control char leak in irc_msg: drop the message on strdup failure instead of sending unsanitized input on the wire.
- Fixed CRLF/control char injection in -pass argument: reject passwords containing control characters at startup.
2026.07.15 - Numerous optimizations and fixes.
- Fixed DB/TLS resource cleanup on partial startup failures and normal shutdown.
- Fixed net_send() stack over-read risk when vsnprintf() truncates.
- Fixed curl/opencode pipe readers so oversized output cannot deadlock the bot.
- Fixed !code AI agent propagation into the forked child.
- Added CR/LF rejection for startup IRC args to prevent local IRC command injection.
- Normalized weather/forecast city input before building wttr.in URLs.
- Fixed IRC op cache bugs around nick changes and long NAMES entries.
- Added !version command to report the bot's version via IRC.
- Fixed the malformed VERSION macro definition to ensure successful builds.
- Added !help command to list available bot commands.
- Added -opencode command-line option to set the path to the opencode binary, overriding OPENCODE_BIN.
- Hardened IRC sending: strip control characters from messages and sanitize targets to prevent IRC injection.
- Sanitized JOIN/NICK targets and PONG payload to avoid injection via CR/LF or control chars.
- Validated -opencode path at startup to reject control characters.