feat(serve): add --stdio flag for NUL-delimited stdin/stdout protocol#24
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new --stdio transport mode to golit serve, enabling a long-running NUL-delimited stdin/stdout request/response protocol while reusing the existing warm engine pool and rendering pipeline.
Changes:
- Add
--stdioflag togolit serve, with--listenmutual exclusion and stdio-default concurrency behavior. - Implement stdio request loop (
runStdio) using NUL (\0) as the frame delimiter. - Add unit + E2E tests covering single/multi request sessions, EOF shutdown, ignore list behavior, and mutual exclusion.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| cmd/golit/stdio.go | Implements NUL-delimited stdin/stdout serving loop for warm SSR. |
| cmd/golit/stdio_test.go | Adds unit/E2E coverage for stdio protocol behavior and lifecycle. |
| cmd/golit/serve.go | Adds --stdio flag parsing, mutual exclusion with --listen, and stdio execution path. |
| cmd/golit/main.go | Updates CLI usage/help text to document --stdio serve mode. |
Comments suppressed due to low confidence (1)
cmd/golit/serve.go:84
- The
--concurrency/-jparsing incrementsiinside the case and again at the end of the case, while theforloop also incrementsi. This causes arguments to be skipped (e.g.,-j 2 --stdiowill likely skip--stdio). Consider refactoring to thei += 2/i++style used elsewhere (or switching this loop to afor i < len(args)form) soiadvances exactly once per consumed token.
case "--concurrency", "-j":
if i+1 < len(args) {
if n, err := strconv.Atoi(args[i+1]); err == nil {
if n < 1 {
return fmt.Errorf("--concurrency value must be a positive integer")
}
concurrency = n
i++
}
}
if concurrency == 0 {
concurrency = runtime.NumCPU()
}
i++
default:
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Adds an alternative transport mode to `golit serve` that uses NUL-delimited stdin/stdout instead of HTTP. The warm engine pool is shared — only the I/O layer changes. golit serve --defs bundles/ --stdio Protocol: write HTML terminated by \0 to stdin, read rendered HTML terminated by \0 from stdout. Process stays alive across requests. Closes cleanly on stdin EOF or SIGTERM. Mutually exclusive with --listen. Defaults to 1 engine worker (sequential requests) but can be overridden with --concurrency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same fix as PR #23 — buildGolit must produce a .exe on Windows or exec.Command cannot find the binary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
projectRoot, buildGolit, and buildTestBundles are now provided by render_test.go (merged via PR #23). Remove the copies from stdio_test.go to fix go vet redeclaration errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zeroedin
force-pushed
the
feat/serve-stdio
branch
from
April 17, 2026 15:50
7c4aa15 to
72488c0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…arsing - Handle render and flush errors on the EOF path in stdio mode instead of silently swallowing them - Remove duplicate cmd.Wait() from E2E test defer (goroutine already calls Wait) - Remove extra i++ in --concurrency/-j case that caused the next flag to be skipped Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--stdioflag togolit servethat replaces HTTP with a NUL-delimited stdin/stdout protocol--listen; defaults to 1 engine worker for sequential stdio requests/healthendpoint needed — pipe liveness is implicit)Protocol
Usage
Relates to #22 — stdio mode closes the gap with lit-ssr-wasm's NUL-delimited protocol while keeping HTTP as the default.
Test plan
TestRunStdio_SingleRequest— basic component rendering via stdioTestRunStdio_MultipleRequests— process stays alive across requestsTestRunStdio_EmptyInput— bare NUL returns bare NULTestRunStdio_EOF— clean shutdown on stdin closeTestRunStdio_PassthroughHTML— plain HTML passes through unchangedTestRunStdio_IgnoredTags—--ignoreworks in stdio modeTestRunStdio_LargePayload— 100 elements in a single requestTestRunStdio_FullDocument— full HTML document renderingTestRunStdio_BrokenStdout— returns error on broken pipeTestRunStdio_PoolReuse— warm pool produces consistent outputTestE2E_ServeStdio— full binary integration test with multi-request sessionTestE2E_ServeStdioMutualExclusion—--stdio+--listenrejected🤖 Generated with Claude Code