Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.foundation.shell-log

Shell output stored on disk and read in bounded windows.

Every byte read from a shell is appended to ~/.vis/logs/YYYY-MM-DD/shell/<session>/<id>.log, using the UTC start date. The pump keeps only a fixed-size transfer buffer, not a copy of the output. Live views and later reads use the same file.

A chunk is the paging contract for a growing file, key for key: give an offset, get the bytes and the next-offset to continue from; a NEGATIVE offset names LINES from the end instead (-50 is the last 50). Feeding next-offset back in a loop yields the WHOLE stream with no overlap and no gap, which is why there is no dropped count anywhere in this namespace — nothing is dropped, so nothing has to be reported as lost.

is-eof means "you have read everything WRITTEN so far", never "the command finished": the process's own status belongs to its handle, not to a read of its log. is-truncated is a cap on THIS read alone and never on the file.

The log is PERSISTENT and belongs to the SESSION: it outlives the process's exit, a daemon restart, and the turn that started the command. It dies with the session — delete-session-logs! runs where the session record is deleted, and the DB index row is scoped to the session soul, so the database cascade retires it in the same breath.

Bytes on disk, index in the DB. The log never becomes a row: it is an append-only stream read by offset, and sqlite would turn every pump flush into a blob rewrite and every cursor read into a substring over that blob. What the DB carries is the ROW that makes a log FINDABLE without holding a handle — the command, the path, the start/end and the exit — on the extension_aggregate sidecar rail under index-extension-id.

Shell output stored on disk and read in bounded windows.

Every byte read from a shell is appended to
`~/.vis/logs/YYYY-MM-DD/shell/<session>/<id>.log`, using the UTC start date.
The pump keeps only a fixed-size transfer buffer, not a copy of the output.
Live views and later reads use the same file.

A chunk is the paging contract for a growing file, key for key: give an
`offset`, get the bytes and the `next-offset` to continue from; a NEGATIVE
`offset` names LINES from the end instead (`-50` is the last 50). Feeding
`next-offset` back in a loop yields the WHOLE stream with no overlap and no
gap, which is why there is no `dropped` count anywhere in this namespace —
nothing is dropped, so nothing has to be reported as lost.

`is-eof` means "you have read everything WRITTEN so far", never "the command
finished": the process's own status belongs to its handle, not to a read of
its log. `is-truncated` is a cap on THIS read alone and never on the file.

The log is PERSISTENT and belongs to the SESSION: it outlives the process's
exit, a daemon restart, and the turn that started the command. It dies with
the session — [[delete-session-logs!]] runs where the session record is
deleted, and the DB index row is scoped to the session soul, so the database
cascade retires it in the same breath.

Bytes on disk, index in the DB. The log never becomes a row: it is an
append-only stream read by offset, and sqlite would turn every pump flush into
a blob rewrite and every cursor read into a substring over that blob. What
the DB carries is the ROW that makes a log FINDABLE without holding a
handle — the command, the path, the start/end and the exit — on the
`extension_aggregate` sidecar rail under [[index-extension-id]].
raw docstring

close!clj

(close! sink)

Flush and close a sink. Idempotent and never throws — a log that cannot be closed must not take the shell's teardown down with it.

Flush and close a sink. Idempotent and never throws — a log that cannot be
closed must not take the shell's teardown down with it.
sourceraw docstring

default-chunk-bytesclj

Bytes ONE read returns when the caller named no limit. A window, not the file: the rest is one more read away at next-offset.

Bytes ONE read returns when the caller named no limit. A window, not the
file: the rest is one more read away at `next-offset`.
sourceraw docstring

delete-session-logs!clj

(delete-session-logs! session)

Delete a session's shell logs across all date directories.

Delete a session's shell logs across all date directories.
sourceraw docstring

drain!clj

(drain! in sink)

Copy raw bytes from in to sink with a fixed-size transfer buffer.

Each chunk is flushed before the next read so partial lines are visible while the shell runs. No text, lines or output history are retained. Read, write and flush failures propagate to the caller, which owns closing both streams.

Copy raw bytes from `in` to `sink` with a fixed-size transfer buffer.

Each chunk is flushed before the next read so partial lines are visible while
the shell runs. No text, lines or output history are retained. Read, write and
flush failures propagate to the caller, which owns closing both streams.
sourceraw docstring

index!clj

(index! db-info session id data)

Upsert the row that makes ONE log findable by session: the command, the log path, the start, and — once the pump has seen the child die — the end and the exit code. Best effort by construction: the bytes are on disk either way, and an index that throws must never take a running shell with it.

data is engine-shaped (kebab keywords) and reaches the database through [[wire/->wire]], because a row that outlives the process is JSON on disk and wears the wire's snake_case string keys — which is exactly what session-logs reads back.

Upsert the row that makes ONE log findable by session: the command, the
log path, the start, and — once the pump has seen the child die — the end and
the exit code. Best effort by construction: the bytes are on disk either way,
and an index that throws must never take a running shell with it.

`data` is engine-shaped (kebab keywords) and reaches the database through
[[wire/->wire]], because a row that outlives the process is JSON on disk and
wears the wire's snake_case string keys — which is exactly what
[[session-logs]] reads back.
sourceraw docstring

index-extension-idclj

Owner of the shell-log sidecar rows.

Owner of the shell-log sidecar rows.
sourceraw docstring

index-kindclj

kind of a shell-log sidecar row.

`kind` of a shell-log sidecar row.
sourceraw docstring

log-chunk?clj

(log-chunk? x)
source

log-fileclj

(log-file session id)

Newest dated log for session/id, or today's path when none exists. Date discovery preserves lookup across midnight and gateway restarts.

Newest dated log for `session`/`id`, or today's path when none exists.
Date discovery preserves lookup across midnight and gateway restarts.
sourceraw docstring

max-chunk-bytesclj

Ceiling on ONE read, so a caller cannot bill a 40 MiB build log to a single context window by asking for it.

Ceiling on ONE read, so a caller cannot bill a 40 MiB build log to a single
context window by asking for it.
sourceraw docstring

open!clj

(open! session id)

Create (truncating) the log file for session/id and return the sink the pump writes through: {:path :out}. Truncating is the point — a new spawn under an id IS a new shell, and its log starts at offset 0.

Create (truncating) the log file for `session`/`id` and return the sink the
pump writes through: `{:path :out}`. Truncating is the point — a new spawn
under an id IS a new shell, and its log starts at offset 0.
sourceraw docstring

read-chunkclj

(read-chunk id file)
(read-chunk id file {:keys [offset limit lines]})

Read shell id's log file from :offset and answer a [[::log-chunk]].

With no :offset the read is the TAIL — the last default-chunk-bytes — because that is what someone watching a live command wants, and the head is one {:offset 0} away rather than gone. With a POSITIVE offset it reads FORWARD from exactly that byte, which is what a loop feeding next-offset does. A NEGATIVE offset counts LINES back from the end — {:offset -50} is the last 50 lines — and clamps to the start of the window when the log holds fewer, so more tail than exists is the whole log rather than an error.

:lines N is the LINE window: the answer holds at most N lines, and with no :offset it is anchored at the last N — so {:lines 10} is the last ten lines and {:offset next-offset :lines 10} walks the next ten, the two switches a reader of a long log actually reaches for. A NEGATIVE :lines walks the OTHER way: {:offset o :lines -10} is the ten lines ENDING at o, so the window slides back up a log as easily as it slides down, and the :offset it answers is what feeds the read above it. Bytes stay the outer cap: :limit still bounds one read.

A missing file is an empty chunk at offset 0, not an error: a shell that has printed nothing yet and a shell whose log was deleted read alike, and neither is worth an exception.

Read shell `id`'s log `file` from `:offset` and answer a [[::log-chunk]].

With no `:offset` the read is the TAIL — the last [[default-chunk-bytes]] —
because that is what someone watching a live command wants, and the head is
one `{:offset 0}` away rather than gone. With a POSITIVE offset it reads
FORWARD from exactly that byte, which is what a loop feeding `next-offset`
does. A NEGATIVE offset counts LINES back from the end — `{:offset -50}` is
the last 50 lines — and clamps to the start of the window when the log holds
 fewer, so more tail than exists is the whole log rather than an error.

`:lines` N is the LINE window: the answer holds at most N lines, and with no
`:offset` it is anchored at the last N — so `{:lines 10}` is the last ten
lines and `{:offset next-offset :lines 10}` walks the next ten, the two
switches a reader of a long log actually reaches for. A NEGATIVE `:lines`
walks the OTHER way: `{:offset o :lines -10}` is the ten lines ENDING at `o`,
so the window slides back up a log as easily as it slides down, and the
`:offset` it answers is what feeds the read above it. Bytes stay the outer
cap: `:limit` still bounds one read.

A missing file is an empty chunk at offset 0, not an error: a shell that has
printed nothing yet and a shell whose log was deleted read alike, and neither
is worth an exception.
sourceraw docstring

session-dirclj

(session-dir session)

Directory for new shell logs of one session on the current UTC date.

Directory for new shell logs of one session on the current UTC date.
sourceraw docstring

session-logsclj

(session-logs db-info session)

Every indexed shell log of session, newest start first. The answer to "what did that build print" a turn later, with no handle in hand.

Rows are wire-shaped: snake_case string keys, exactly as index! wrote them.

Every indexed shell log of `session`, newest start first. The answer to
"what did that build print" a turn later, with no handle in hand.

Rows are wire-shaped: snake_case string keys, exactly as [[index!]] wrote
them.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close