nandi/freeqsay-nimpublic Fork 0
b248dcf49f97f0bc4ec74cdc78dfe62d9bf11257
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 · 93 lines · 3.3 KBmarkdown Blame HistoryRaw
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 21h 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 18h ago54just static # fully static binary → ./freeqsay-static
just install: put the static binary on PATH b248dcf nandi 12h ago55just install # static binary → ~/.local/bin/freeqsay
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 21h ago56just test # test suite
57just run <handle> <message> # run from source, no build
58just shot <handle> <message> # gapless termshot png
59just --list # everything else
60```
61
just static: fully static builds through a pinned nimstatic 078b24d nandi 18h ago62`just static` produces a binary with no dynamic dependencies at all — musl
63libc and OpenSSL linked in, nothing dlopen'd — so it runs on any Linux. It
64builds through [nimstatic](https://rickub.com/nandi/nimstatic), pinned in
65`tools/nimstatic` as a [DotSlash](https://dotslash-cli.com) file: the first run
Point the nimstatic pin at a release asset ed15d1f nandi 12h ago66fetches that exact release asset, checks its hash and caches it. A static binary carries no CA store, so set
just static: fully static builds through a pinned nimstatic 078b24d nandi 18h ago67`SSL_CERT_FILE` when resolving handles on a host without one at the default
68path.
69
just install: put the static binary on PATH b248dcf nandi 12h ago70`just install` puts the static build on your PATH as `freeqsay`; it takes a
71directory (`just install ~/bin`) or `PREFIX`, and says so when the target is
72not actually on your PATH. `just uninstall` removes it again.
73
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 21h ago74`nimble build` and `nimble test` work too. `-d:ssl` is set in `config.nims`,
75since handle resolution goes over HTTPS through the stdlib client.
76
77Everything but the HTTP call and JSON parsing is pure Nim with no dependencies:
78SHA-256, HMAC and HKDF live in `freeqsay/sha256`, and the PNG encoder writes
79stored deflate blocks.
80
81## How it works
82
83```
84handle → resolveHandle → did
85did → HKDF-SHA256(avatar-v1) → traits → 16×24 sprite → ANSI
86message → cowsay balloon
87```
88
89`fixtures/avatar-conformance.json` pins the cross-implementation contract:
90canonical seed, traits, and a sprite hash over all four facings. The suite
91replays it, so this port derives byte-identical characters to the Clojure and
92TypeScript implementations — including the sfc32 PRNG, reproduced on `uint32`
93lanes so trait selection matches the JavaScript original bit for bit.