embedding/embedding.go:
- Remove EmbedBatch() (never called in production, test updated to use Embed)
- Remove padID field (written but never read)
embedding/index.go:
- Remove Index.mu mutex (Index is immutable after construction)
skills/skills.go:
- Remove Index.All() (never called)
- Remove Index.Reload() (never called)
virtfs/decl.go:
- Remove RemoveNode() NodeOption (never used)
- Remove RenameNode() NodeOption (never used)
- Remove Alias() NodeOption (aliases set directly on struct)
virtfs/tree.go:
- Remove Tree.Data field (never used)
- Remove Tree.Mount() (never called in production)
- Remove Tree.Child() (never called in production)
- Remove Tree.Children() (never called in production)
- Replace indexOf() with strings.IndexByte
Tests updated to directly manipulate internal children map where needed.
Each('peer', ...) creates a named directory whose children come from
Bindings(). Previously, listDir and findChild only checked Bindings
for template names like {foo}. Now they also handle directories that
have Bindings but no Children.
This fixes the peer/ directory in olliesrv which was listing empty
even though peers were configured via peeradd.
Added test for the non-template Each pattern.
Read, Write, and Rdwr are the three atomic 9P operations:
- Read: non-blocking read
- Write: non-blocking write (fire-and-forget)
- Rdwr: atomic write-then-read (blocking, produces result)
BlockOnce and Stream are special cases of Read.
Rdwr is its own primitive — not a variant of either.
Same pattern as BlockOnce: framework handles the blocking loop.
readFn takes a base string, returns (data, nextBase, error).
signal fires when new data may be available.
Chat stream handlers now use Stream(a.ChatRead, a.ChatSignal).
StreamRaw retained for custom handlers.
streamChat() in support.go is now dead code (replaced by ChatRead).
BlockOnce now takes a value-reader and a signal source. The framework
handles the blocking loop: read → compare hash to base → if different
return → else wait on signal or timeout.
On timeout (ctx.Done), returns empty (not error) so clients re-open
cleanly.
BlockOnceRaw retained for queue-style handlers (bypass/pending,
proc/wait) that manage their own blocking.
EventValue adapter wraps a <-chan Event into BlockOnce-compatible
(readFn, signalFn) pair via a thin goroutine.
Wire context cancellation through the toolsrv 9P server so that
canceling a CallTool context properly terminates the running tool.
Changes:
- virtfs: Add Close() to File interface with CloseFn for Request handlers
- toolsrv/p9.go: Handle requests concurrently to allow Tclunk during
blocking Twrite; call entry.Close() in handleClunk
- toolsrv/internal/server/proc.go: Check ctx.Done() while waiting for
tool completion in NewProc
- Integration tests for context cancellation chain
The cancellation chain: client cancels ctx → fid.Close() → Tclunk →
handleClunk calls entry.Close() → closeFn cancels reqCtx → NewProc
sees ctx.Done() and returns ctx.Err()
The with* functional options and newTree constructor were private and
only used in two places (builder and tests). Replaced with direct
field assignment on &Tree{} literals. Less abstraction, same behavior.
Each() now returns []FsNodeDecl directly. The Binding type was a
redundant subset of FsNodeDecl with a slightly different Remove
signature. Dynamic entries are now expressed uniformly — Remove,
Rename, Children, Aliases all live on FsNodeDecl like everything else.
Also added: Alias() and RenameNode() options, DirNode accepts
[]FsNodeDecl for passing pre-built child slices.