The /logs endpoint now returns different formats based on Accept headers:
- Browsers (Accept: text/html) get the interactive HTML log viewer
- Agents/fetch requests get raw JSONL when no Accept header includes text/html
- Without a file parameter, agents get a JSON array of available log files
Also improved security: invalid filenames now throw errors (500) instead of silently failing (404).
Enriches webhook logs with sender and ref for better visibility into who triggered events and what they affected (e.g. which branch). PR logs now include the title, comment logs include the first 200 characters of the comment body.
Adds an expandable detail row in the log viewer UI that shows all metadata as key-value pairs when clicked, keeping the summary line clean.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The empty blockquote line after the repo name was rendering as a literal ">" in Discord. Add a trailing space so it renders as a blank line within the blockquote instead.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Use getConfig("dataDir") and ensure directory exists before writing crash log, fixing ENOENT error when spike crashes.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The sha is already encoded in the log filename (releaseSha_timestamp.jsonl), so there's no need to include it per-event. This simplifies the type and storage format.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Move webhook tests to root tests/ dir and restructure to be non-flaky. Setup webhook capture server once via preload, tear down on process exit. Tests now clean up their own PRs in afterEach. Added bridge test to verify Spike PRs create Discord threads. Made Discord client login explicit via startDiscord(). Updated config with new dev Discord channel and Spike username mappings.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implement a centralized logging system with typed events (webhook, PR, comment, review, Discord relay, errors, etc.) that feeds a pub/sub pattern. Events are logged to console (with ANSI colors: green=normal, yellow=skipped, red=errors, cyan=PR#) and persisted to JSONL files organized by git commit SHA.
Restructure server code into src/server/ directory with separate route handlers. Add a new /logs endpoint with an HTML viewer that displays events in a searchable table with type/repo filtering and browser timezone conversion. Remove the old /errors endpoint.
Improvements:
- All webhook handlers, Discord events, and errors now use log() instead of console.* calls
- Error objects are properly serialized to JSONL (message + stack extracted)
- Path traversal vulnerability fixed in readLogFile()
- Failed API calls and caught errors are now always logged
- Graceful error handling with fallbacks where appropriate (e.g., missing Discord users)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Split nested dev/prod config object into a Config type with separate devConfig and prodConfig objects. This makes it clearer which values apply to which environment and ensures both configs match the type.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Each test now creates its own PR and cleans up after itself. Tests no longer depend on shared state or ordering, making them resilient to failures.
Added retry logic to mergePR for Gitea's 404/405 responses while computing mergeability. Used crypto.randomUUID() for unique branch names instead of Date.now() to eliminate collision risk.
Split the monolithic gitea/helpers.ts (which had Discord imports and created circular dependencies) into three focused libs:
1. **gitea/** — Pure API client: fetchPR, fetchReviewComments, convertUsername, threadName. No side effects or external deps.
2. **discord/** — Discord client setup: bot login, event listeners, slash commands. Now isolated from Gitea internals.
3. **bridge/** — New integration layer: webhook handler, DB mappings (Gitea PR ↔ Discord thread), Discord helpers, and createPRComment.
Dependencies now flow one direction: bridge → gitea and bridge → discord. No circular imports.
Added:
- Barrel exports (index.ts) for each lib with public API
- README.md for each lib documenting the barrel exports
- Comprehensive spike README.md with setup guide and architecture explanation
- Integration tests for webhooks (callback-based, no race conditions)
- Unit tests for pure API functions
- CLAUDE.md with links to each lib's README
This architecture makes it possible for AI to understand a lib by reading just its README, keeping context focused and small.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>