Activity Overview
Commits and releases over time
- Commits
- Releases
- Authors
Repository Explorer
No repositories match that filter.
117 commits in all time
Jun 20, 2026 09:34 – Sep 18, 2026 09:34 UTC
feat: identify nodekit via user-agent
Every outbound request went out as Go's default "Go-http-client/1.1", which tells a node operator reading their algod access log, or the GitHub release API, nothing about what is calling them. Send "Nodekit v<version>" instead, built from the version the linker stamps into main so that releases can be told apart. The shared HttpPkg wrapper covers the release checks, the catchpoint lookup, the short links and the upgrade download; the generated algod client gets the header through a request editor, since api/lf.go is overwritten by `make generate`.
b3e885bf
pull/200/head
8/179 ++ 7 --
fix: keep crash output at every level, --level panic included
An entry with no readable level was dropped once the floor passed error, which is the one place the exemption had to hold: a runtime panic is written by the Go runtime and not through logrus, so it carries no level field, and `logs --level panic` on a node that died of a nil dereference answered with nothing at all while the default warn view showed the dump. The floor now never judges a line it could not read a level from, which is what the command's help has been promising. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
94ef4392
pull/193/head
4/41 ++ 20 --
docs: record the truncation Follow cannot see
Size against offset only catches a truncation that is still visible when the poll arrives. A file emptied and written back past the old offset inside one interval never looks short, and the next drain reads new bytes at a stale position: the prefix is lost and a pending fragment of the old file is spliced onto what followed. Polling has no way to close that. Nothing separates a truncate-and-regrow from an append once the inode is unchanged and the length has recovered, so the alternative is a different mechanism rather than a better check. The window is one interval wide, algod rotates by renaming, and tail -F has the same hole; it is left open on purpose, and now says so. The truncation test slept to stay out of that window without explaining which window, which read as timing noise rather than as the point. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
8e061361
pull/193/head
2/21 ++ 1 --
docs: add the generated man page for logs
Every other registered top-level command has one, and the README's command list is where the published docs link from. Generated with cobra/doc and put through the same banner substitution the existing pages carry, checked by regenerating nodekit_restart.md and diffing it against the committed copy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMKTAqwAPrGqB8hvgmBWu5
f21b7562
pull/193/head
2/51 ++ 0 --
fix: finish the log permission message and split off --file
The message broke off at "adding your account to the 'algorand' group after", and it blamed the algod data directory's ownership for every permission failure, including one on a file the user named with --file. It now finishes the instruction, and a file the user chose gets a message that only says which path could not be read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
5c0e8388
pull/193/head
2/14 ++ 3 --
fix: resume follow at the start of a line algod was still writing
Scan reported the live log's size as the follow offset, but a log caught mid-write ends mid-line: the scan shows that fragment, and Follow then resumed past it, so the remainder of the line arrived as a line of its own and the entry algod was writing never appeared whole. The offset is now rounded back to the last line boundary, within one read buffer, so the completed entry is delivered once the newline lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
bac25c1a
pull/193/head
2/102 ++ 8 --
fix: report an archive that cannot be read instead of dropping it
ArchiveFiles skipped every path os.Stat failed on, permission denied included. With a separate LogArchiveDir the user cannot enter, the archive was removed before the scan ever saw it, so nothing recorded it as skipped and no warning was printed: the command reported a complete history it had never read, which is the one failure this package works to avoid. Only absence is skipped now. Anything else keeps the path and lets the read path fail on it, which puts it in ScanResult.Skipped and gets it warned about -- the same choice PruneSources already makes, for the same reason. An archive whose age could not be read sorts last, so it cannot reorder the history around it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
cb861914
pull/193/head
2/57 ++ 5 --
fix: quote a field name that would split the rendered line
Render's one-line guarantee was only half enforced. Values were escaped and keys were concatenated raw, but a field name is decoded from the same JSON object the value is, and an object key may hold anything a JSON string can. A key carrying a newline split one entry across two physical lines, which is the defect the value quoting was there to prevent. The predicate moves into quoteIfNeeded and both halves of the pair go through it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
74f32c3c
pull/193/head
2/40 ++ 17 --
fix: compare and merge every field of the algod config
IsEqual and MergeAlgodConfigs still handled only the two P2P flags, so the log fields added for the logs command were invisible to both: two configs differing only in BaseLoggerDebugLevel, LogSizeLimit or a log path compared equal, and a value passed through the merge was dropped before anything could write it. Both now cover every field, through a pair of generic helpers rather than a block each, and a reflection-driven test fails on the next field added to Config that either of them forgets. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
ec09f55a
pull/193/head
2/101 ++ 29 --
fix: stop --all warning that the view of the log is incomplete
--all names no level. It asks for whatever the log holds, and the log holds everything the node wrote, so nothing the user asked for is missing from it. Measuring the request against the node's floor anyway meant --all asked for trace, which no algod writes, and every node with a configured BaseLoggerDebugLevel was reported as withholding something -- on the one run where the request was for all of it. The warning stays for a level the user named and the node never writes, which is what it is for. A node genuinely holding levels back is still explained by reportEmptyLogResult, at the point where that leaves nothing to show and the reason matters. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy (cherry picked from commit 88bc94234b130effa60ab076a647f35d33e2e359)
b862a3fa
pull/193/head
2/55 ++ 4 --
docs: state that --since bounds the region read
The decision record still listed stopping the backward walk early on --since as deliberately deferred, on the grounds that it would change what the flag means for entries Keep never drops on time. Three optimizations went in since and do exactly that: the walk stops once a chunk's oldest line is older than the bound, a forward stream bisects to the first entry at or after it, and an archive written entirely before it is not opened at all, which is the only way to skip a compressed one. Reviewers of #193 read the record against the code and found the contradiction three times over, once per site. The record was the stale half. --since bounds the region of the history that is read, and an entry whose timestamp cannot be read is shown when it falls in that region: a panic dump belongs to the moment the lines around it were written, and one from two hours ago is not part of the last fifteen minutes. Written down as a decision, with the reasoning alongside the cost the three optimizations avoid, and cross-referenced from each of them and from Filter.Keep. The sentence in sinceOffset calling its answer "never a filter" was the specific claim that had stopped being true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMKTAqwAPrGqB8hvgmBWu5
f4a403f5
pull/193/head
4/27 ++ 5 --
fix: parse in full when --filter text contains <, > or &
The prescreen searches the undecoded line for the filter text verbatim, which is only sound for bytes JSON never rewrites. Quotes, backslashes and non-ASCII were excluded on that basis; `<`, `>` and `&` were not, and they should have been. logrus writes its JSON through Go's encoder with HTML escaping left on, so where the decoded message holds one of those characters the line holds \u003c, \u003e or \u0026. `nodekit logs --filter '<nil>'` therefore found nothing, however many entries said <nil>. Those three bytes now fall through to the full parse, along with the rest of the text the raw search cannot be trusted on. The corpus line and the two filters added to the one-sided prescreen test fail without the fix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMKTAqwAPrGqB8hvgmBWu5
849f4add
pull/193/head
2/16 ++ 3 --
fix: keep a field value from breaking an entry across two lines
A string field was quoted only when it held a space or an equals sign, so a value carrying a newline and neither was written out raw and split one entry over two lines, which is exactly what Render promises not to do and what makes the output greppable. Nothing algod writes reaches this today: a stack trace goes into the message, where collapseNewlines handles it, and the one structurally multi-line field is built by a telemetry hook on a copy of the entry that never reaches the file. The guarantee is Render's own, though, and --file points the command at whatever file the user names, so the test now covers control characters, quotes and backslashes alike -- %q escapes them together and the guarantee stops depending on the producer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
49da6a08
pull/193/head
2/35 ++ 2 --
docs: say that --follow starts from the newest ten
The Long text and the man page said every matching entry is shown, while --follow quietly switched the default to ten so a long backlog would not scroll past before the stream began. The exception is now written down in both places and in the flag's own help, since the behaviour is the one tail -f has and worth keeping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
c06f179e
pull/193/head
2/6 ++ 2 --
fix: bound the reader against a shrinking file and a runaway line
Two problems in reader.go, both raised in review of #193. The backward walk sized the file, then read chunks of it with ReadAt and ignored the count returned. A file truncated in place or replaced by a shorter one after that stat hands back a short read with io.EOF, leaving the tail of the buffer zeroed; those NUL bytes were then split into lines, parsed as entries and charged against the scan budget. The walk now takes only the bytes actually read, and drops the carry from the chunk above with them, since the two halves no longer abut and splicing them would invent a line neither file contains. Follow read its lines with ReadBytes, which accumulates until it finds the delimiter. The cap below it only ever saw a line that had already been buffered whole, so a runaway line was bounded by the writer rather than by us. It now reads the way forEachLine does, keeping at most maxLineBytes across ErrBufferFull and discarding the rest, which is where ParseLine would have sent it anyway. The stale-size test fails without the first fix, emitting a 384-byte entry of NULs. The follow test does not discriminate on output, since the old path arrived at the same truncation by a more expensive route; it guards the part of the rewrite that could go wrong, that the discarded remainder does not disturb the line after it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMKTAqwAPrGqB8hvgmBWu5
61fdb59e
pull/193/head
2/87 ++ 16 --
fix: do not file a callback error under Skipped
streamOne returns a failure to read the file and a failure inside the caller's callback down one path, and behind the live log streamSources treated both as an unreadable archive. A callback that failed while an archive was open had its error recorded as the archive's, and the scan carried on into the newer files and returned nil. That lost a cancellation or a closed pipe outright, and reported a hole in a history that had been read perfectly well. The n > 0 path has always returned the callback's error directly; the two halves of Scan disagreed about their own contract. Callback errors are tagged so they can be told apart and returned. The existing test passed a single live source, so the branch that swallowed them had never been read by it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PqPSx1wqM8rMdo4EHPa4jy
a7a87320
pull/193/head
2/48 ++ 1 --