Prevent delayed loop-start message counts from overwriting active Ralph Loop state after the loop has already advanced, so ULW completion can still enter Oracle verification instead of iterating forever.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Cubic AI reviewer flagged the use of the untrusted Host header as the
URL base in startCallbackServer. The server only binds to 127.0.0.1,
so hardcoding "http://127.0.0.1" as the URL base is robust against
malformed or manipulated Host values and matches upstream behavior
prior to the node:http refactor.
The dist-bundle regression tests in
src/shared/dist-bundle-bun-globals.test.ts are guarded by
`test.skipIf(!existsSync("dist/index.js"))` and dist/ is
gitignored, so they silently skipped in CI which ran tests before
the build step. Adding the build step earlier ensures the
regression guard runs and a future raw `Bun.*` leak in the bundle
fails CI.
Existing test only checked `globalThis.Bun` top-level destructures
and `__require` calls. Add two new test cases:
1. Raw Bun runtime API scanner: scans dist/index.js for any
`Bun.<anyMethod>(` or `Bun.<anyMethod>.` call outside shim-safe
patterns (runtime.Bun, globalThis.Bun, typeof Bun, and the
"Bun is not defined" error-message string). Uses a negative
lookbehind so shim indirection (`runtime.Bun.foo`) passes.
2. Node smoke test: imports dist/index.js under
`node --input-type=module` and asserts stderr contains no
`ReferenceError` and no `Bun is not defined`. The existing
case 3 only checked exit code, which masked lazy-evaluation
crashes that fire after import. Reading exports forces lazy
module-level evaluation paths to run.
bun-install.ts streamToText() was reachable from the plugin bundle via
the cli/config-manager barrel re-export. Replace with the WHATWG
standard `new Response(stream).text()` pattern which works
identically in Bun and Node and avoids the last raw Bun.* runtime
call in dist/index.js.
The OAuth callback server was using Bun.serve, which would crash if
mcp-oauth code paths ever entered the plugin bundle. Switch to
node:http.createServer with the same WHATWG behavior:
- Binds to 127.0.0.1, preserves 200/400/404 status codes
- Translates fetch(Request)→Response to (req, res) callback style
- Clears OAuth timeout on success/error/missing-param paths
- Replaces server.stop(true) with server.close() for shutdown
Functional behavior and response bodies unchanged.
isPortAvailable() previously bound a one-shot Bun.serve and stopped it.
That call was reachable from the plugin bundle through
src/shared/index.ts barrel re-export and crashed on Electron.
Switch to node:net.createServer().listen(port, host), which Bun fully
implements as well. Adds a 2s safety timeout and removes both
"error" and "listening" handlers on resolution to prevent listener
leaks. Behavior is bit-equivalent: returns true iff a server can bind
to (host, port) right now.
Test file is fully rewritten away from stale Bun.serve mocking. New
tests exercise: free-port detection via port 0, EADDRINUSE handling
via a real net.createServer blocker, findAvailablePort range
exhaustion, getAvailableServerPort auto-selection, 127.0.0.1 default
hostname binding, and probe-server resource cleanup.