The agent branch grew .text by ~2.8MB (mostly std monomorphization from
the new script/agent modules); none of it executes in serve mode and
anonymous/heap memory is byte-identical to main (716-724KB Private_Dirty
across main, agent-dev, and a build with the agent code compiled out).
The VmHWM delta is file-backed pages of the binary: the kernel maps them
in large readahead/THP chunks around each touched page, so peak RSS
shifts with link layout on every relink. The agent-less test build
measured 4.2MB *below* main while running the identical serve path,
purely from folio/window boundaries moving. At 28000 the gate was
failing on layout noise (28028-28064), not a regression.
Move console message listener registration out of Session initialization
into an explicit `enableConsoleCapture` method. This avoids buffering
console logs when they are not needed.
* Revert "agent: enhance /save progress and verification feedback"
This reverts commit 54f467d1fa.
* Revert "agent: verify synthesized scripts during /save"
This reverts commit b141da30ca.
* agent: extract save helpers to save.zig
Moves pure helper functions related to the `/save` command (parsing,
validation, file writing, prompt shaping) from `Agent.zig` to a
dedicated `save.zig` module.
Introduces a multi-step synthesis process for `/save` that derives a
logical JSON output schema and uses a dry-run runtime to verify
candidate scripts. The LLM can now run and self-correct its scripts
using a new `run_script` tool before finalizing the save.
Rewrite:
- Section headings now describe tasks ("Log in to Hacker News" vs "Driving the browser by hand").
- Section 3 leads with the five login commands; selector-hunting workflow moved to optional subsection at the end.
- Trimmed prereqs (dropped fish variant, $-escape edge cases, long LP_ prefix explanation).
Every working command preserved. Load-bearing callouts in section 3 kept (/waitForSelector doing two jobs, CSS-only selectors).
The agent.md rewrite dropped documentation for several features that still
exist in the code. Restore them and clean up the markdown:
- Re-add /clear and /reset to the meta-commands table
- Re-add waitForState to the browser-tools list and the /save
state-mutating command list
- Re-add --system-prompt and --verbosity (with the --task stderr-pipe
escalation) to the providers section
- Strip trailing whitespace on blank lines; add blank lines before
headings and between lists and following paragraphs
- **New opening.** Direct framing: "lets you drive a headless browser by talking to it."
- **New "How to think about it" section.** Explains the three-layer stack and the one-sentence pitch ("pay for the LLM once, then replay deterministically").
- **New "The REPL is where you build scripts" section.** Positions the REPL as a sandbox with a full sandbox-to-saved-script example.
- **New tips section.** Practical guidance for prompts that produce useful saved scripts (be specific about extracted data, name the page, check the file).
- **Updated Quick start.**
Extracts chat history and arena management into `Conversation.zig`,
the startup banner into `welcome.zig`, and model/config resolution
helpers into `settings.zig` to simplify `Agent.zig`.
The TestHTTPServer leaks a thread for every connection that shuts down. This
commit correctly releases it. It also closes a leaking CDP socket.
Full test went from 20s -> 10s for me
Rather than relying on the frame_arena, use a distinct arena for FormData. This
generally results in tighter memory usage, but more importantly it ensures that
if FormData outlives the frame, we don't get a UAF. This can happen if the
FormData is refernced in v8 and finalized late (e.g. after the frame would
appear to still be needed).
Also, in Frame.submitForm use the explicit acquireRef and releaseRef. This
FormData can [in theory] be passed to JS, via the `formdata` event that we fire.
Replace the monochrome braille logo with a truecolor ANSI-colored
version. Update logo dimensions and row counting logic, and simplify
the welcome banner printing to stream logo lines directly.
Statically assert that the banner fits within 80 columns at compile
time. This removes the need to dynamically measure terminal width
and conditionally hide the logo.
Updates the isocline dependency to use its native hints for Ctrl-D
and Esc. Removes the custom status bar rendering logic, and prints
the active model and effort level at REPL startup instead.
Prints a Braille-art Lightpanda logo alongside the welcome text and
command hints if the terminal is wide enough. Otherwise, falls back
to a text-only layout.
Also exposes `Terminal.displayWidth` to assist with layout calculations.