Skip to content

feat(ai-autopilot): runner start() + reachable preview — boot-and-serve (#137)#138

Merged
suleimansh merged 1 commit into
mainfrom
suleimansh/feat/137-runner-start-preview
Jul 2, 2026
Merged

feat(ai-autopilot): runner start() + reachable preview — boot-and-serve (#137)#138
suleimansh merged 1 commit into
mainfrom
suleimansh/feat/137-runner-start-preview

Conversation

@suleimansh

Copy link
Copy Markdown
Member

Closes #137. Enabler for #109 and the honest completion of the live capstone (#124).

The gap

The runner seam couldn't actually run an app: RunnerSession.exec awaits the process to exit (so a dev server hangs until timeout), and preview() was a stub that formatted a URL with nothing listening behind it. "Produce a running app" was unreachable — #124 proved file-scaffolding, not serving.

What's added

  • RunnerSession.start(command, opts)RunnerProcess { command, exit, stop() } — launch a long-running command (a dev server) in the background, returning immediately. Optional, like preview (presence = capability).
  • PreviewOptions.waitMspreview() waits for the port to accept connections before resolving, so the URL is live on return.
  • start_server runner tool (exposed when the session supports start, and rides the exec toggle).

Implementations

  • LocalRunner (the reference): start spawns in its own process group (detached) so stop() kills the whole tree (the shell and the server it launched), escalating SIGTERM → SIGKILL; dispose() stops any leftover processes; preview polls the port with net.connect.
  • FakeRunner: mirrors start (records calls, controllable process) for tests.

Verified

Real boot-and-serve test (no external infra, no deps): boot a Node HTTP server into a LocalRunner workspace, start it, preview({ waitMs }) waits until reachable, fetch the URL and assert the body (hello from runner), stop it and confirm the port is dead; a separate test asserts dispose stops a still-running process. 213 tests green (204 + 9), typecheck + build clean.

This is the contract each sandboxed adapter in #109 (Docker / WebContainer / Flue) must satisfy; LocalRunner is the reference they mirror.

…ve (#137)

The runner seam could not run an app: exec() awaits the process to exit (a dev
server hangs), and preview() only formatted a URL with nothing behind it. So
'produce a running app' was unreachable.

Add:
- RunnerSession.start(command): launch a long-running command in the background,
  returning a RunnerProcess ({ command, exit, stop() }). Optional, like preview.
- PreviewOptions.waitMs: preview() waits for the port to accept connections
  before returning, so the URL is live on return.
- start_server runner tool (when the session supports start).

LocalRunner implements it for real: start spawns in its own process group so
stop()/dispose() kill the whole tree; preview polls the port. FakeRunner mirrors
it. Proven by a real boot-and-serve test: boot an HTTP server, start it, preview
waits, fetch the URL and assert the body, stop kills it. 213 tests green.

This is the contract each sandboxed adapter in #109 (Docker/WebContainer/Flue)
must satisfy; LocalRunner is the reference.
@suleimansh suleimansh added enhancement New feature or request priority: medium Worth doing, not urgent labels Jul 2, 2026
@suleimansh suleimansh self-assigned this Jul 2, 2026
@suleimansh suleimansh merged commit 7ce5bae into main Jul 2, 2026
2 checks passed
@suleimansh suleimansh deleted the suleimansh/feat/137-runner-start-preview branch July 2, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority: medium Worth doing, not urgent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Runner seam: long-running processes (start) + readiness-checked preview (boot-and-serve)

1 participant