-
075b0ca
chore: tidy comments and deploy notes
Pablo Murad
-
75b16e4
fix(radio): replace trending with just played
Pablo Murad
-
51c41a7
feat(radio): web station browser, https fallback
Pablo Murad
-
78a5a8d
fix(almanac): keep the city name as typed
Pablo Murad
-
ea7ca52
fix(radio): hide favorites hint for guests
Pablo Murad
-
5cd1176
fix(linecast): pass units via env, show quick failures
Pablo Murad
-
af0255b
docs: bulletin, linecast and radio
Pablo Murad
-
8353830
feat(radio): dispatcher tools
Pablo Murad
-
3e76e46
feat(radio): Hammer FM in bulletin, PETSCII radio
Pablo Murad
-
1975ad8
feat(chat): add /np
Pablo Murad
-
6be1158
feat: show radio and sky activity in presence
Pablo Murad
-
186c1b3
feat(radio): web player pages
Pablo Murad
-
63c1fa1
feat(radio): [o] radio menu and Hammer FM
Pablo Murad
-
f0ffb11
feat(radio): Radio Browser client, ICY titles, favorites
Pablo Murad
-
3c4f97c
build(docker): add linecast to the games image
Pablo Murad
-
2d31598
feat(linecast): [k] sky & almanac menu
Pablo Murad
-
4d0c1a2
feat(linecast): config and launch args
Pablo Murad
-
372227e
feat(doors): forward window resizes to pty doors
Pablo Murad
-
da7486e
feat(door): pty support
Pablo Murad
-
cc927b1
feat: login bulletin and almanac
Pablo Murad
-
1a6bae0
fix(doors): request the pinned host key type from DoorParty
Pablo Murad
-
6055b56
feat(doors): "menu" door opens the server menu
Pablo Murad
-
8bb8b1a
docs: doors, MRC, echomail, rlogin/FTP/PETSCII
Pablo Murad
-
efd8a0c
build(docker): full target with DOSBox
Pablo Murad
-
d321a59
feat: ANSI postcards
Pablo Murad
-
e5d7043
test(bbs): fix wall/about flake
Pablo Murad
-
7812963
test(bbs): wait for the right badges screen
Pablo Murad
-
21dfb32
feat(bbs): badges
Pablo Murad
-
306e7e5
feat(bbs): /:live page
Pablo Murad
-
6b69c6c
feat: PETSCII ports for C64/C128
Pablo Murad
-
cf911a6
feat: read-only anonymous FTP
Pablo Murad
-
869187b
feat(bbs): rlogin listener
Pablo Murad
-
5eed667
feat(bbs): DOVE-Net echomail over QWK
Pablo Murad
-
8801d3f
feat(qwk): QWK/REP packets and FTP client
Pablo Murad
-
8db0138
feat(bbs): fsxNet echomail over binkp
Pablo Murad
-
d098464
style(ftn): gofmt
Pablo Murad
-
a0d8d34
feat(ftn): packets, echomail and binkp
Pablo Murad
-
429d2d8
feat(forum): network fields for echomail
Pablo Murad
-
936071e
feat(bbs): MRC chat
Pablo Murad
-
03e6015
feat(bbs): native, DOS and remote doors
Pablo Murad
-
d5b5efc
feat(door): drop files and socket doors
Pablo Murad
-
75c838e
fix: Lawn Mower URL, CRLF drop files
Pablo Murad
-
43fa37d
docs: forums, telnet, web terminal, CP437, nodes
Pablo Murad
-
26ba449
feat(bbs): node monitor for moderators
Pablo Murad
-
dc5f287
feat(bbs): browser terminal
Pablo Murad
-
86a0080
feat(bbs): telnet listener
Pablo Murad
-
ceb926b
feat(bbs): CP437 for SyncTERM and other BBS terminals
Pablo Murad
-
83e410b
feat(bbs): forums on the menu and the dispatcher
Pablo Murad
-
756b56f
feat(forum): message areas, topics and posts in SQLite
Pablo Murad
-
666da39
feat(community): arrival notices
Pablo Murad
-
b08d1bf
feat(community): last callers
Pablo Murad
-
faf9ce0
refactor(bbs): run sessions over any transport
Pablo Murad
-
dddad0a
feat(chat): keep the chat in the database
Pablo Murad
-
aa2383b
feat(db): open the BBS database in WAL mode with a busy timeout
Pablo Murad
-
8278016
fix(games): message for an empty games folder
Pablo Murad
-
1cea366
feat(games): games folder on the host
Pablo Murad
-
8585ee9
fix(fetchroms): retry on 429 and 5xx
Pablo Murad
-
e027a9d
docs: NES games
Pablo Murad
-
b84d8cb
build(docker): games target
Pablo Murad
-
b845aef
fix(door): absolute drop file path
Pablo Murad
-
a2b5dfa
feat(games): homebrew catalog and downloader
Pablo Murad
-
6cc53f0
feat(bbs): NES games through nesdoor
Pablo Murad
-
68b2ca1
feat(door): run doors over stdio
Pablo Murad
-
1a0487c
feat(http): the card is the default curl report The classic report is 125 columns wide, so in a normal terminal window every row wrapped and the frames fell apart. A request with no view now gets the card, 64 columns wide. The classic report stays one parameter away (?view=v1), and options only it understands (0-3, n, days=) or a PNG still select it. The BBS keeps the classic report when a tool call names no view. Along the way: - the card's title comes from the geocoder ("São Paulo, Brasil", "Tour Eiffel, France") instead of the lower-cased query or bare coordinates - the rain column is padded, so "9%" no longer shifts the wind column - in the browser each emoji takes exactly two cells, as in a terminal, so framed rows keep their right border in line - help page and README describe the new defaultPablo Murad
-
c55f513
feat(http): curl reports dressed as the BBS Framed reports (v1, v2, v2d, v2n, card) now come out in Hammer's look: a "HAMMER" header, double-line frames in the retro palette, and a footer with the tagline and the command that opens the BBS, taken from the new brand block of the configuration (brand.ssh; empty drops it). ?F drops the footer, ?Q drops header and footer, ?T and ?d behave as before. The BBS itself renders directly and is not dressed. Terminals disagree about how wide an emoji is, which pushed the right border of card and v2 rows out of line. Those rows now move the cursor to the frame's last column (CSI n G) before drawing the border. Help pages name this host (brand.host) instead of the upstream one. Long forecast descriptions in v1 are cut at a word ("Patchy rain…" rather than "Patchy rain ne…"), and one that fits exactly no longer gets an ellipsis it does not need. README: independent status line, "How reports look", credits point to the new NOTICE, which keeps the attribution the Apache licence asks for.Pablo Murad
-
477370f
refactor: Hammer stands on its own Removes what still spoke for the project Hammer grew out of: - translations: the upstream author's "Follow" footer and two unused strings that advertised the upstream service, in every language; his name from the translator credits (the volunteers stay) - web page: our title, no third-party social buttons or their scripts - translation page and bash helper: our names, no upstream contacts - sample config: /hammer paths instead of the upstream's - dead files: the SaltStack and systemd recipes for the upstream host, a lolcat wrapper with the upstream author's home path, and an orphan HTML page the static handler would still serve Also fixes a trailing comma in the crk translation metadata.
Pablo Murad
-
5da9678
style: centre the splash prompt and chat title, brighter retro hotkeys Found in screenshots of real sessions: the splash's "press any key" sat at column 0 under centred art, the chat's title and hint did not line up with the art above them, and the retro theme's dark blue hotkey brackets were nearly invisible on a dark background (now light blue).
Pablo Murad
-
85ce72d
feat(bbs): themes per session, ANSI art on screen, modem effect Every interactive session now picks its theme from the profile (or bbs.style.defaultTheme, retro90 by default) at the colour level its terminal reports, and the art shows up: - splash: the Hammer piece at modem speed (bbs.style.baud, 9600 by default), credited from its SAUCE record; any key finishes the drawing - wall, chat, weather, tools and settings: header art above the menu when the terminal is wide and tall enough - goodbye: NO CARRIER, then "see you" - narrower than 80 columns, or no colour: text titles, no art Input is now read by a goroutine per session and handed to nextByte over a channel, so a screen can check for a key without blocking; this is what lets a keypress cut the modem effect short. A status bar pins "nick · N online · theme · connected for" to the last row of menu screens. Settings gains theme and modem-effect entries, saved in the profile. Dumb terminals get the plain theme: ASCII boxes, no colour codes and no cursor movement. README gains a Look and feel section; deploy configs gain bbs.style; .gitattributes marks .ans files as binary.
Pablo Murad
-
98a0bf5
fix(profiles): saving a profile with a nickname lost every change Save tried an INSERT first and fell back to UPDATE on a unique-constraint error. Once profiles had nicknames, SQLite reported the nickname index before the primary key when re-saving an existing profile, Save read that as "nickname taken", and returned without updating. Units, language, cities and every other setting of a keyed user silently stopped being saved. Save now updates an existing row and inserts only new ones; a nickname conflict is reported only when another key really holds the name. A regression test re-saves a profile with its own nickname unchanged. The profiles table also gains theme and fx columns (same in-place migration as nick) for the look-and-feel settings that follow.
Pablo Murad
-
178bc11
feat(art): Hammer's own ANSI art Seven pieces drawn from scratch for the BBS, saved as real .ans files (CP437, iCE colours, SAUCE credited to hammer / hammer bbs) that open in PabloDraw and Moebius: - splash: HAMMER in steel-and-ice block letters with a drop shadow, a hammer struck by lightning, the tagline and art-pack shade bars - wall: THE WALL over a brick wall - chat: speech bubbles - weather: sun behind a rain cloud - tools: open-end spanner and screwdriver - setup: mixing-desk sliders - nocarrier: NO CARRIER over a modem front panel with CD gone dark They are drawn by tools/artgen (go generate ./internal/bbs) on a pixel layer at two pixels per cell (▀ ▄ █), with a chunky block font, gradients and shadows. artgen -png renders previews through the same loader the BBS uses. Third-party art can join them as plain .ans files, with the author's permission.
Pablo Murad
-
46f86dc
feat(ansiart): load and render classic ANSI art A package for .ans files as the art scene makes them: - SAUCE records are parsed (title, author, group, date, width, iCE flag) and stripped with their COMNT block and the ^Z marker. - CP437 is decoded to Unicode; files already in UTF-8 pass through. - The file is played on a virtual 80-column terminal (go-te, already a dependency), so cursor movement, wrapping, bold-as-bright and blink-as-bright-background land where the artist put them. - Render emits the art in any 16-colour palette at the terminal's colour level (truecolor, 256, 16 or none), leaving black backgrounds to the terminal, and Credit builds the attribution line from SAUCE. Canvas draws a grid and encodes it as a real .ans file (CP437, iCE colours, CRLF, SAUCE), which is how Hammer's own art is produced.
Pablo Murad
-
8c4a426
refactor(ui): themes instead of fixed colours The BBS palette lived in constants, so there could only ever be one look. A Theme now carries the colour roles, box glyphs, title decoration, block shadow, hotkey style, menu leader and the 16-colour palette ANSI art is drawn with: - retro90: VGA palette, double-line boxes with block shadows, blue brackets around hotkeys, dotted leaders in menus - modern: rounded boxes, a softer palette and gradient titles on truecolor terminals - plain: ASCII boxes and no escape sequences, for dumb terminals Colour is emitted at the level the terminal supports (truecolor, 256, 16, none), detected from TERM and COLORTERM. Every screen in the bbs package now paints through the session's theme (st.th); menuEntry, settingsEntry, wallLine and colorNick became session methods. Sessions still use the modern theme at 256 colours, so nothing changes visibly yet; picking the theme comes later.
Pablo Murad
-
fe7d2b8
feat(dispatch): who, wall and wall.post; document the community Scripts and agents can now see who is online (`who`), read the wall (`wall count=N`) and post to it (`wall.post text="..."`). Posting needs a key and honours the same cooldown and bans as the menu; a cooldown comes back as rate_limited with retry_after. The chat stays interactive only. README: a Community section (nicknames, who's online, wall, chat, moderation, anonymous read-only) and the bbs.community block in the configuration example. Runbook: how to make your key a moderator.
Pablo Murad
-
08526cf
feat(bbs): wall, who's online and live chat screens Main menu: the title shows how many people are online, the latest one-liners sit above the menu the way a BBS greets you with its wall, and two new entries open the wall [w] and the chat [c]. Wall: the latest lines from everyone with their age and a colour per nickname; post (keys only, with the per-key cooldown), see who is online (where they are, for how long, how many connections), and, for moderators, delete a line by number. Chat: messages scroll above an input line that stays put. The session goroutine owns input and a receiver goroutine draws incoming messages; both write under the session's write lock and the receiver redraws the line being typed after each message. Long input scrolls sideways so one erase always clears it. Commands: /help /who /me /nick /quit, and for moderators /mute /kick /ban /unban. Anonymous visitors read but cannot talk. Ctrl+C leaves the room, not the BBS. `ssh -t host chat` opens the room directly. System events (joins, kicks, renames) are rendered in each reader's language. End-to-end tests drive several real SSH clients: messages crossing between people, escape sequences stripped, flood limit, read-only anonymous, moderator kick, wall cooldown and the online list.
Pablo Murad
-
e063948
feat(bbs): nicknames and community settings Every key now has a nickname, unique regardless of case: - New keys get their SSH user name (ssh pablo@host -> pablo) when it is meaningful and free, otherwise guest-xxxx, widened until free. - Profiles saved before nicknames get one on their next login; the profiles table gains a nick column through an in-place migration. - Settings has a nickname entry with validation (2-16 characters, reserved names refused) and a friendly message when it is taken. - Anonymous sessions get a guest name that is never stored. The unique index is on the column with COLLATE NOCASE rather than an expression: godb's SQLite error parser panics on the message an expression index produces. A new bbs.community block configures moderators (key fingerprints), the wall (lines shown, length, cooldown) and the chat (length, rate). The server builds the presence tracker, wall and chat hub on the profiles database.
Pablo Murad
-
3609e3a
feat(community): presence, one-liner wall and chat hub A terminal-free package for the social side of the BBS: - CleanText strips escape sequences (CSI, OSC and the rest), C0/C1 controls and bidi overrides from anything one user shows another, and cuts it to a width in terminal cells. - Nickname rules, reserved names and guest-xxxx fallbacks. - Presence: who is online, one entry per key, in memory. - Wall: the last one-liners from everyone, a per-key cooldown and pruning, stored in the BBS's SQLite database. - Hub: a chat room with a 100-message in-memory history, per-key rate limit, a bounded queue per member so a slow reader never blocks the room, read-only anonymous members, and moderation (mute, kick, ban, unban) with bans persisted and honoured by the wall too.
Pablo Murad
-
7529ff0
refactor(bbs): split session.go by responsibility, thread-safe writes session.go had grown to ~1,200 lines mixing terminal I/O, the main menu, weather and settings. It is now: - session.go: connection lifecycle, identity, splash, main loop - session_io.go: input, output and screen primitives - menu_main.go, menu_weather.go, menu_settings.go: the menus Functions moved verbatim. The one change in behaviour: writes to the SSH channel and the session error they record are now guarded by a mutex (wmu), with writeLocked for compound updates. This is groundwork for the chat, where incoming messages are drawn from another goroutine while the user types. Existing tests pass unchanged.
Pablo Murad
-
5ed49b8
feat: NDJSON dispatcher, SFTP area, async jobs SSH: one port now answers three ways. An interactive terminal gets the menu; a command (`ssh host hash input=hi`) or a pipe with no terminal gets a newline-delimited JSON dispatcher over a closed vocabulary with declared, validated arguments; the sftp subsystem gets a private per-key file area that tools read with file=NAME. Slow tools (net, links, data, path) can run as background jobs (async=true, then `job id=...` from any connection with the same key). Jobs live in memory. Anonymous sessions are now throwaway identities: defaults for the connection, nothing saved, no file area. Keying them by client IP made everyone behind one NAT share and overwrite each other's settings. HTTP: X-Forwarded-For / X-Real-IP are believed only from trusted proxies (server.trustedProxies, loopback by default), read right to left. Weather requests are rate limited per client IP (429 + Retry-After), dispatcher calls per key, and geocoder calls per UTC day (geo.dailyLookupLimit) to protect the OpenCage quota. OCR is removed everywhere: ocrpdf package, menu entry, config keys, translations and the ocrmypdf/tesseract packages in the Dockerfile. Old configs carrying ocr* keys will fail at startup; use the ones in deploy/. The storage purge is generalised to the file area (sweepStorageLoop). Tests added for the HTTP server, client IP resolution, rate limiting, dispatcher, jobs, file area and the SSH modes end to end. README and the CloudPanel runbook describe the current ports, modes and limits, and `make go-test-zig` runs the cgo tests without a C compiler.
Pablo Murad
-
82964b8
fix(renderer): v2 crashes and mis-drawing, plus test suite The v2 panel crashed on ordinary inputs and drew several things wrong. Crashes fixed: - location names over ~52 characters (negative strings.Repeat); the caption is now cut with an ellipsis and measured in terminal cells - interpolate: infinite recursion on 2 points, NaN spline on width 1 - temperature diagrams with a single data point (division by zero) - rain sparkline narrower than its label, or series shorter than width - invalid timezone in drawDate, nil Options/Location in Render - negative wind bearings and fewer speeds than directions Drawing fixed: - daylight timeline was never drawn and started at UTC midnight; it now follows the sun's elevation from local midnight (covers polar day/night) - frame padding counted bytes, so rows with colour or accents were ragged - caption flags: quiet drops the prefix, no-city drops the city - spline overshoot showed temperatures never forecast and negative rain; interpolation is now clamped to the input range - emoji and wind rows are resampled to the 24 panel slots oneline: the plain emoji profile declared up-to-3-character symbols as one cell wide, and GetEmojiProfile dereferenced a nil options pointer. Adds a v2 test suite (99% coverage) with a regression test per fix.
Pablo Murad
-
a3f8029
Remove GitHub URL from splash and about screens The project repository link no longer appears on the interactive front-end. Drops the attributionURL line from the splash and the about screen, and the now-unused constant. Author attribution and the pablomurad.com invite footer stay.
Pablo Murad
-
0141e77
feat(bbs): anonymous access, IP prefs, storage quota
Pablo Murad
-
b5a7c1f
fix(deploy): docker prod compose, config and runbook
Pablo Murad
-
341444d
chore(deploy): add deployment configs and CloudPanel runbook - deploy/config.yaml: production config (BBS SSH + HTTP weather, ${VAR} secrets) - deploy/hammer.service: systemd unit (dedicated user, CAP_NET_BIND_SERVICE for :22) - deploy/nginx-hammer.conf: reverse proxy for the HTTP weather service - deploy/DEPLOY-CLOUDPANEL.md: step-by-step runbook for the CloudPanel VPS (web via reverse proxy -> 8080, SSH BBS direct on 2323) - .env.example: document GEOLITE2_LICENSE_KEY, symbolic placeholdersPablo Murad
-
e919fa7
docs: remove doc/ folder
Pablo Murad
-
c7f4b20
feat: SSH tools platform, i18n, and build/port/format fixes - BBS front-end: interactive menu, per-key profiles, tool dispatcher - Native tools: net, qr, hash, jq, age, csv, b64, ids (+ optional links, data, path, ocr) - i18n for the BBS menu across all bundled languages - Move BBS SSH port 2222 -> 2323 (2222 already in use; 22 disallowed) - gofmt: reformat cache, ip, location, logging and v2 renderer files - Re-enable the gofmt linter in .golangci.yaml so formatting is enforced - build.sh: fail the build when no fonts are embedded, and warn on partial font sets, to avoid silently shipping a binary with degraded PNG output
Pablo Murad
-
fbb0774
Add .env support and fix startup panics for minimal configs
Pablo Murad
-
da5b12c
Add emoji weather card and redesign the BBS UI
Pablo Murad
-
5b33d57
Initial commit: Hammer
Pablo Murad