v0.2.0-prerelease — Phase 1: Local Bridge Server
Pre-release
Pre-release
Local HTTP+SSE+Long-Poll bridge with token auth and a 5-rule path-traversal guard.
Repo stays private until v1.0.0.
Built by a 4-agent team (architect / coder / security / tester) with disjoint
file ownership — no merge conflicts, no overlapping writes.
What landed
Contracts (src/contracts/bridge.ts, 426 lines)
BridgeEventSchemazod discriminatedUnion across 10 event kindsPortLockSchema,BridgeStatusSchema,BridgeHealthSchema,BridgeHttpErrorSchemaLongPollRequestSchema(.refineenforcestimeout <= LONG_POLL_CAP_MS = 270000)AuthModuleinterface,BridgeEndpointdiscriminated union (11 variants)BridgeServerOptions/BridgeServerHandlefor the boot API
Server (src/bridge/server.ts 484 + http-helpers.ts 127 lines)
Plain Node http, no Express/Hono. Binds 127.0.0.1 only. 11 endpoints:
GET /health(no auth, liveness)GET /status(auth,BridgeStatus)GET /live.js(no auth, Phase 2 stub)GET /design-system.json(auth, serves.wisp/design-tokens.json)GET /source(auth +guardPath)GET /eventsSSE (auth, 15s keepalive)POST /events(auth, validatesBridgeEventSchema)GET/POST /poll(auth, long-poll with silent cap)POST /annotation(auth, kind-locked)GET /stop(auth, graceful shutdown)
256 KB body cap (413 BODY_TOO_LARGE). Cursor format seq-N-sessionId. Long-poll
silent-clamps oversize timeouts to 270000 ms (no 400 — improves Impeccable).
Port discovery (port-discovery.ts, 123 lines)
findFreePortover 31337..31400 (Improvement #8 vs Impeccables fixed:8400)- Atomic lockfile (
.tmp+ rename, mode 0o600) - Stale-pid detection via
process.kill(pid, 0)
Auth + path guard (src/bridge/auth.ts, 220 lines)
generateTokenUUIDv4validateTokenUUID-format regex + length-mismatch UNAUTHORIZED
(avoids timing leak) + finalcrypto.timingSafeEqualguardPath5-rule pipeline:- reject absolute paths (POSIX + Windows)
- reject any surviving
..segment after normalize path.resolvemust prefix-matchprojectRootrealpathSyncre-check (symlink-escape blocked); ENOENT is OK (caller 404)- hard-deny
/.git/,/node_modules/,/.wisp/sessions/,.env*
Tests (tests/bridge/*.test.ts, 77 passing in 6 files)
auth.test.ts(26) — token generation, validation edge cases, guardPath all 5 rulespath-traversal.test.ts(11) — mixed seps, unicode, mid-segment denies, long pathsport-discovery.test.ts(11) — range/exhaustion/stale-pid/atomic-writelong-poll-slicing.test.ts(6) — fast-path, wake-up, empty timeout, cursor advance,
client-disconnect race, silent-clampserver-smoke.test.ts(21) — auth gating,/sourcetraversal, body validation,
413 cap, SSE keepalive,/stopgraceful
Tooling
.gitattributesnormalizes line endings to LF (Phase 3 needs byte-equivalence
on inject/remove roundtrip)- Version bump to 0.2.0-prerelease in all three manifests
Quality gates
$ npm run check
typecheck: clean
test: 77 passed in 6 files (1.28s)
build: 9.74 kB
$ node dist/index.js doctor
7/7 OK
Next
Phase 2 — Browser Runtime (src/browser/live.js). Vanilla-JS IIFE, state machine
PICKING → CONFIGURING → GENERATING → CYCLING, floating bar, multi-select via
⌘-click-add, parameter sliders binding to CSS vars.