Skip to content

feat: hosted remote log relay for production debugging#3

Open
NisargIO wants to merge 3 commits into
mainfrom
live-urls
Open

feat: hosted remote log relay for production debugging#3
NisargIO wants to merge 3 commits into
mainfrom
live-urls

Conversation

@NisargIO
Copy link
Copy Markdown
Member

Summary

  • Adds @debug-agent/remote, a Cloudflare Worker + SQLite-backed Durable Object that acts as a hosted NDJSON log relay so production code (no localhost) can push logs to a public URL and the local agent can read them back.
  • Adds a debug-agent remote CLI subcommand (--daemon, --json, interactive) that creates sessions on the Worker and streams logs over SSE parsed from fetch() (no EventSource dep).
  • Updates SKILL.md with a local-vs-remote decision section and remote variants of STEP 0 / STEP 2 / STEP 4 plus a remote API reference table.
  • Drops .wrangler and .dev.vars* into .gitignore. Incidental formatter cleanup on debug-agent-browser lives in its own commit.

Worker design

  • POST /sessions → returns { sessionId, endpoint, streamUrl, expiresAt } using a 21-char nanoid.
  • LogSession Durable Object schedules an alarm at Date.now() + 3_600_000; the alarm handler broadcasts an expired SSE event, closes writers, and calls ctx.storage.deleteAll() (compatibility date 2026-02-24 so the alarm is cleared in the same call).
  • Storage caps enforced on every POST with 413 Payload Too Large: max 10K entries, 10KB per entry, 100MB total.
  • Optional id field on the payload is used for dedup via an indexed entry_id column.
  • SSE: connected → replay buffered log events → replay-complete → live log events broadcast from POST /s/:id.
  • Expired or unknown sessions return 410 Gone.
  • CORS open (*) on every response and OPTIONS * preflight.

Deployed at https://debug-agent-remote.aidenbai.workers.dev.

Test plan

  • wrangler dev — all routes exercised locally (create, ingest, read NDJSON, SSE replay + live, DELETE, dedup, 413 over-size, 410 unknown, CORS preflight).
  • wrangler deploy succeeds; live worker passes the same smoke tests.
  • pnpm build && pnpm test (63/63 tests pass) and pnpm check clean.
  • debug-agent remote --daemon prints session info and exits.
  • debug-agent remote --json streams remote logs as NDJSON to stdout.
  • End-to-end skill workflow validated by debugging a synthetic off-by-one bug entirely through the deployed worker: instrumented HTTP POSTs, fetched logs via curl ENDPOINT, confirmed hypothesis from cited log lines, fixed, re-verified with runId=post-fix logs.

Made with Cursor

NisargIO and others added 3 commits May 15, 2026 23:01
Incidental whitespace/formatting cleanup surfaced by `pnpm check --fix`
while working on remote logging. No behavioral changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Introduces a hosted log relay so production apps can push NDJSON logs to
a public URL and a local debug-agent session can read them back. Solves
the problem that `localhost` endpoints don't work for production bugs.

- New package `@debug-agent/remote`: Cloudflare Worker with a
  SQLite-backed Durable Object (`LogSession`). Each session is created
  by `POST /sessions` (nanoid id), auto-expires after 1 hour via a DO
  alarm that calls `deleteAll()`, and enforces 10K entries / 10KB per
  entry / 100MB total limits with `413 Payload Too Large`. Routes:
  `POST/GET/DELETE /s/:id` and SSE at `GET /s/:id/stream` (replays
  buffered logs then streams live). Returns `410 Gone` for expired or
  unknown sessions. CORS open on every response.
- New `remote` subcommand in `debug-agent` CLI with `--daemon`, `--json`,
  and interactive modes. SSE is parsed manually from `fetch()` — no
  EventSource dep. Default Worker URL is configurable via `--url`.
- Updated SKILL.md with a local-vs-remote decision section and remote
  variants of STEP 0, STEP 2, STEP 4, plus a remote API reference table.

Deployed at https://debug-agent-remote.aidenbai.workers.dev and
end-to-end verified via the debug-agent skill workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
@reactreview
Copy link
Copy Markdown

reactreview Bot commented May 16, 2026

React Review93/100 (unchanged) · 0 ❌ errors · 5 ⚠️ warnings

Copy prompt for agent
Check if these React Review issues are valid. If so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.

Run this before and after your changes to verify the result:
npx react-doctor@latest --verbose --diff

Do not modify the react-doctor configuration unless explicitly asked.
Fix the underlying code issues instead of changing or suppressing the rules.

React Review found 0 errors and 5 warnings. This PR leaves the React health score unchanged.

<file name="packages/debug-agent-remote/src/log-session.ts">

<violation number="1" location="packages/debug-agent-remote/src/log-session.ts:103">
Severity: Warning

await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

Collect the items and use `await Promise.all(items.map(...))` to run independent operations concurrently

Rule: `async-await-in-loop`
</violation>

<violation number="2" location="packages/debug-agent-remote/src/log-session.ts:271">
Severity: Warning

await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

Collect the items and use `await Promise.all(items.map(...))` to run independent operations concurrently

Rule: `async-await-in-loop`
</violation>

</file>

<file name="packages/debug-agent/src/utils/parse-sse-stream.ts">

<violation number="1" location="packages/debug-agent/src/utils/parse-sse-stream.ts:29">
Severity: Warning

await inside a while-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently

Collect the items and use `await Promise.all(items.map(...))` to run independent operations concurrently

Rule: `async-await-in-loop`
</violation>

<violation number="2" location="packages/debug-agent/src/utils/parse-sse-stream.ts:33">
Severity: Warning

array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

Use a `Set` or `Map` for repeated membership tests / keyed lookups — `Array.includes`/`find` is O(n) per call

Rule: `js-set-map-lookups`
</violation>

<violation number="3" location="packages/debug-agent/src/utils/parse-sse-stream.ts:51">
Severity: Warning

array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups

Use a `Set` or `Map` for repeated membership tests / keyed lookups — `Array.includes`/`find` is O(n) per call

Rule: `js-set-map-lookups`
</violation>

</file>

Reviewed by react-review for commit 2bc948a. Configure here.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
debug-agent-website Ready Ready Preview, Comment May 16, 2026 7:03am

bufferedLogs: rows.length,
};

const removeWriter = () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writers in SSE stream endpoint leak memory when clients disconnect after replay without triggering subsequent broadcasts

Fix on Vercel


newlineIndex = buffer.indexOf("\n");
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSE stream parser loses buffered data when stream ends without a terminating empty line

Fix on Vercel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant