nandi/freeqsay-nimpublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/freeqsay-nim.git
git clone ssh://git@rickub.com/nandi/freeqsay-nim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

README.md · 89 lines · 3.0 KBmarkdown Blame HistoryRaw
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 6h ago1# freeqsay
2
3Cowsay with your FreeqWorld face. Written in Nim — a port of the
4[Clojure/Jolt implementation](https://gitlab.com/nandithebull/freeqsay), which
5is itself a port of the original TypeScript.
6
7```bash
8freeqsay <handle> <message>
9```
10
11Resolves a Bluesky handle → DID, derives the deterministic `avatar-v1` character,
12and prints a cowsay balloon above truecolor ANSI art.
13
14## Usage
15
16```bash
17freeqsay jay.bsky.team hello from the timeline
18freeqsay @pfrazee.com "ships free software"
19echo "piped in" | freeqsay jay.bsky.team
20
21# wrap width, thought bubble, scale
22freeqsay someone.bsky.social -W 20 short lines
23freeqsay jay.bsky.team --think hmm
24freeqsay jay.bsky.team --scale 3 big face says hi
25
26# raw DID (no network)
27freeqsay did:plc:ewvi7nmzuoqusbcablsm7c4h offline ok
28```
29
30Without a built binary, run it straight from the source tree:
31
32```bash
33nim r -d:ssl src/freeqsay.nim jay.bsky.team hello world
34```
35
36## Library
37
38```nim
39import freeqsay
40
41echo freeqsay("jay.bsky.team", "hello").output
42```
43
44Modules: `freeqsay/say` (balloon + face), `freeqsay/avatar` (traits and the
4516×24 sprite), `freeqsay/ansi` (truecolor half-block rendering), `freeqsay/png`
46(RGBA → PNG), `freeqsay/resolve` (handle → DID), `freeqsay/balloon`,
47`freeqsay/sha256` (SHA-256 / HMAC / HKDF). Importing `freeqsay` re-exports all
48of them.
49
50## Development
51
52```bash
53just build # optimized binary → ./freeqsay
just static: fully static builds through a pinned nimstatic 078b24d nandi 3h ago54just static # fully static binary → ./freeqsay-static
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 6h ago55just test # test suite
56just run <handle> <message> # run from source, no build
57just shot <handle> <message> # gapless termshot png
58just --list # everything else
59```
60
just static: fully static builds through a pinned nimstatic 078b24d nandi 3h ago61`just static` produces a binary with no dynamic dependencies at all — musl
62libc and OpenSSL linked in, nothing dlopen'd — so it runs on any Linux. It
63builds through [nimstatic](https://rickub.com/nandi/nimstatic), pinned in
64`tools/nimstatic` as a [DotSlash](https://dotslash-cli.com) file: the first run
65fetches that exact build, checks its hash and caches it, and the URL names a
66commit so it cannot move. A static binary carries no CA store, so set
67`SSL_CERT_FILE` when resolving handles on a host without one at the default
68path.
69
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 6h ago70`nimble build` and `nimble test` work too. `-d:ssl` is set in `config.nims`,
71since handle resolution goes over HTTPS through the stdlib client.
72
73Everything but the HTTP call and JSON parsing is pure Nim with no dependencies:
74SHA-256, HMAC and HKDF live in `freeqsay/sha256`, and the PNG encoder writes
75stored deflate blocks.
76
77## How it works
78
79```
80handle → resolveHandle → did
81did → HKDF-SHA256(avatar-v1) → traits → 16×24 sprite → ANSI
82message → cowsay balloon
83```
84
85`fixtures/avatar-conformance.json` pins the cross-implementation contract:
86canonical seed, traits, and a sprite hash over all four facings. The suite
87replays it, so this port derives byte-identical characters to the Clojure and
88TypeScript implementations — including the sfc32 PRNG, reproduced on `uint32`
89lanes so trait selection matches the JavaScript original bit for bit.