Commit Graph
100 Commits
Author SHA1 Message Date
jjbrunton dcf57273e2 Disable unavailable subreddits after Reddit 404 2026-08-08 22:53:24 +01:00
jjbrunton 664aa5c098 fix: clarify deferred post listing logs 2026-08-08 22:44:00 +01:00
jjbrunton f88d4af146 feat: log subreddit screening outcomes 2026-08-08 22:39:15 +01:00
jjbrunton 53e9a44a5c fix: back off after Reddit access denials 2026-08-08 22:37:19 +01:00
jjbrunton e8b730b592 feat: add agent API and operational analytics 2026-08-08 22:08:14 +01:00
jjbrunton 720ea0652a Install native build tools in container 2026-08-08 21:12:30 +01:00
jjbrunton 5a5a30a1d4 Improve messaging and dashboard reliability 2026-08-08 21:09:20 +01:00
jjbrunton 345ec99348 Improve Reddit chat and media reliability 2026-08-08 20:37:25 +01:00
jjbrunton a44768c089 fix: separate Reddit and Matrix runtime identities 2026-08-08 20:25:06 +01:00
jjbrunton 5623100e93 fix: verify stored sessions from a Reddit page 2026-08-08 20:22:45 +01:00
jjbrunton 8df2d648dd fix: open the dedicated Reddit Chat host 2026-08-08 20:20:03 +01:00
jjbrunton 48492d5238 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/browser/client.ts
#	src/services/reddit-session-importer.ts
#	src/web/routes/conversations.ts
2026-08-08 20:17:19 +01:00
jjbrunton 0e8ba713a8 Merge concurrent Reddit account support 2026-08-08 20:15:22 +01:00
jjbrunton 1833e94a10 Reduce Reddit profile screening requests 2026-08-08 20:11:03 +01:00
jjbrunton 3d015c4e80 Sanitize realtime log metadata 2026-08-08 19:46:51 +01:00
jjbrunton 492efe0f8a Bind Reddit and Matrix session identities 2026-08-08 19:43:35 +01:00
jjbrunton 34ae532cdd Fix chat visibility and conversation sync 2026-08-08 19:29:40 +01:00
jjbrunton f4e8fdc42f Improve seller account filtering 2026-08-08 19:15:05 +01:00
jjbrunton 16a31335d0 feat: support concurrent Reddit accounts 2026-08-08 19:00:38 +01:00
jjbrunton d819a0f1e6 feat: track received image outcomes 2026-08-08 18:53:11 +01:00
jjbrunton 50de1c180d Respect Reddit rate limit delays 2026-08-08 18:34:37 +01:00
jjbrunton 7bcdbe236a Filter unattributed successful messages 2026-08-08 18:28:46 +01:00
jjbrunton 2c100d72b6 feat: persist settings and enrich conversation context 2026-08-08 18:18:28 +01:00
jjbrunton a36723a325 chore: remove retired native login paths 2026-08-08 16:55:04 +01:00
jjbrunton ea92a1a92b fix(auth): unify imported sessions with account gating 2026-08-08 16:53:55 +01:00
jjbrunton 654bbda457 feat(dashboard): add full-size media preview 2026-08-08 16:49:18 +01:00
jjbrunton c483c7b8be feat: replace browser login with imported Reddit sessions 2026-08-08 16:48:59 +01:00
jjbrunton 2b0545afcf Merge branch 'codex/react-auth-cutover' into main (superseded implementation already integrated) 2026-08-08 16:47:14 +01:00
jjbrunton ab2e5cc4ce Merge branch 'codex/react-realtime-complete' into main (superseded implementation already integrated) 2026-08-08 16:47:13 +01:00
jjbrunton 9e317ecf62 Merge branch 'codex/react-parity' into main (changes already integrated) 2026-08-08 16:46:44 +01:00
jjbrunton 0aaaeb6b7f Merge branch 'codex/react-docs' into main (changes already integrated) 2026-08-08 16:46:44 +01:00
jjbrunton de6b8999b7 Merge branch 'codex/react-settings' into main (changes already integrated) 2026-08-08 16:46:43 +01:00
jjbrunton 4d18a3a9a2 Merge branch 'codex/react-performance-ops' into main (changes already integrated) 2026-08-08 16:46:43 +01:00
jjbrunton 14c6fe76c5 Merge branch 'codex/react-media' into main (changes already integrated) 2026-08-08 16:46:42 +01:00
jjbrunton 80417cac06 Merge branch 'codex/react-conversations' into main (changes already integrated) 2026-08-08 16:46:42 +01:00
jjbrunton 2196149c79 Merge branch 'codex/react-sse-adapter' into main (changes already integrated) 2026-08-08 16:46:41 +01:00
jjbrunton 9d9506e0cd Merge branch 'codex/react-events' into main (changes already integrated) 2026-08-08 16:46:41 +01:00
jjbrunton 0a7717910a Merge branch 'codex/react-contracts' into main (changes already integrated) 2026-08-08 16:46:40 +01:00
jjbrunton baf673904c Merge branch 'codex/react-foundation' into main (changes already integrated) 2026-08-08 16:46:39 +01:00
jjbrunton 50985b52f1 Merge branch 'codex/native-login-handoff' into main
# Conflicts:
#	public/index.html
#	src/bootstrap.ts
#	src/services/chat/service.ts
#	tests/chat-service-username-persist.test.ts
2026-08-08 16:46:16 +01:00
jjbrunton dbb1842ef4 Use native Chrome for Reddit login handoff 2026-08-08 16:16:11 +01:00
jjbrunton ec0cd1318b feat(dashboard): complete React cutover 2026-08-08 16:11:57 +01:00
jjbrunton 2c533fa52a Verify Reddit identity before Matrix capture 2026-08-08 16:03:54 +01:00
jjbrunton 2fd92bf82c Gate bot logic on full account authentication 2026-08-08 16:01:06 +01:00
jjbrunton d5f0175dc2 feat(web): wire domain events into realtime stream 2026-08-08 16:00:17 +01:00
jjbrunton 8c8ff11fd7 feat(web): publish bot control transitions 2026-08-08 15:51:58 +01:00
jjbrunton ad770a792a feat: secure React dashboard cutover 2026-08-08 15:51:06 +01:00
jjbrunton a51e0b6b31 feat(web): share realtime hub across domain events 2026-08-08 15:46:25 +01:00
jjbrunton 8b1ec85f1d feat: secure React dashboard cutover 2026-08-08 15:46:11 +01:00
jjbrunton 66a1146562 feat(dashboard): activate routed media filters 2026-08-08 15:43:53 +01:00
jjbrunton d108903174 Harden dashboard realtime state and controls 2026-08-08 15:41:58 +01:00
jjbrunton 4b3f00729f feat(dashboard): close legacy parity gaps 2026-08-08 15:41:34 +01:00
jjbrunton 4db6de8bf5 Stop Matrix refresh loop when login is unavailable 2026-08-08 15:41:02 +01:00
jjbrunton 92287c0a9a Stop Matrix refresh loop when login is unavailable 2026-08-08 15:40:55 +01:00
jjbrunton 0fecd426f4 feat(dashboard): close legacy parity gaps 2026-08-08 15:40:08 +01:00
jjbrunton 64d29e1241 Harden dashboard realtime state and controls 2026-08-08 15:38:11 +01:00
jjbrunton 12a853fa42 docs: describe React dashboard migration state 2026-08-08 15:32:38 +01:00
jjbrunton 8824da3f15 docs: describe React dashboard migration state 2026-08-08 15:32:16 +01:00
jjbrunton 720e5e3e34 test: include shared contract suite in root gate 2026-08-08 15:31:44 +01:00
jjbrunton 674cd89cd7 Use full Chrome for interactive Reddit login 2026-08-08 15:30:24 +01:00
jjbrunton 70d62b2da3 feat(dashboard): route settings and access 2026-08-08 15:26:40 +01:00
jjbrunton 79de6aa2a1 feat: add settings and access dashboard slice 2026-08-08 15:25:34 +01:00
jjbrunton e4dd4ad4da feat: add settings and access dashboard slice 2026-08-08 15:24:47 +01:00
jjbrunton dcf2a1200c Clear stale Chromium profile locks on startup 2026-08-08 15:22:20 +01:00
jjbrunton 364b4db200 docs: document dashboard auth and typed events 2026-08-08 15:20:31 +01:00
jjbrunton 271f2d1fb5 Handle non-string image content types 2026-08-08 15:18:28 +01:00
jjbrunton 51438aa5db Keep x11vnc alive for remote login 2026-08-08 15:16:51 +01:00
jjbrunton 89f7376b1b fix(dashboard): deduplicate realtime log replay 2026-08-08 15:15:54 +01:00
jjbrunton e003b0d8b2 feat(dashboard): route performance and operations 2026-08-08 15:11:48 +01:00
jjbrunton 5917b63755 feat(dashboard): add performance and operations slices 2026-08-08 15:10:52 +01:00
jjbrunton c7dec45abe feat(dashboard): add performance and operations slices 2026-08-08 15:06:44 +01:00
jjbrunton 20fa83f245 feat(dashboard): route conversations and media 2026-08-08 15:06:19 +01:00
jjbrunton 768470204b feat: add private media dashboard slice 2026-08-08 15:05:30 +01:00
jjbrunton 8d4eae7ab5 feat(dashboard): add conversations workspace 2026-08-08 15:05:08 +01:00
jjbrunton e5dda8f9c3 feat: add private media dashboard slice 2026-08-08 15:04:25 +01:00
jjbrunton 4c20a83c89 feat(dashboard): add conversations workspace 2026-08-08 15:04:04 +01:00
jjbrunton 40e5f4c818 chore(deps): apply audited dependency fixes 2026-08-08 15:02:23 +01:00
jjbrunton 9919b12aab feat(web): bridge logs to typed event stream 2026-08-08 15:00:02 +01:00
jjbrunton d6d29badcd feat(dashboard): align contracts and production build 2026-08-08 14:58:27 +01:00
jjbrunton 69d560d5c5 feat(web): add Express SSE event adapter 2026-08-08 14:56:37 +01:00
jjbrunton 10412876f1 feat(web): add Express SSE event adapter 2026-08-08 14:56:04 +01:00
jjbrunton 9f4f198800 fix: align realtime event contracts 2026-08-08 14:54:09 +01:00
jjbrunton 51e3e28a9b feat(dashboard): add React foundation and overview 2026-08-08 14:53:53 +01:00
jjbrunton aef4cbb656 fix: align realtime event contracts 2026-08-08 14:53:47 +01:00
jjbrunton 28fcb3ea99 feat(dashboard): add React foundation and overview 2026-08-08 14:52:39 +01:00
jjbrunton 59c3a61a88 feat: add shared dashboard API contracts 2026-08-08 14:52:06 +01:00
jjbrunton 6f803245d4 feat: add shared dashboard API contracts 2026-08-08 14:50:58 +01:00
jjbrunton 939cf408a0 feat(web): add typed realtime event core 2026-08-08 14:50:15 +01:00
jjbrunton 3c4cfd7411 feat(web): add typed realtime event core 2026-08-08 14:49:38 +01:00
jjbrunton 78e84fe36b Fix noVNC WebSocket routing 2026-08-08 14:48:58 +01:00
jjbrunton 316dc3dd3e Show Reddit recovery status in dashboard 2026-08-08 14:42:19 +01:00
jjbrunton d2b3a1b31d Retry Matrix capture after chat login redirect 2026-08-08 14:34:10 +01:00
jjbrunton bffda95251 Improve remote Matrix token refresh 2026-08-08 14:30:40 +01:00
jjbruntonandClaude Opus 4.7 b9df8459e3 Atomic chat-cache writes + stop tests clobbering prod cache
Three intertwined fixes for the torn-write that corrupted the prod
data/chat-cache.json mid-session:

  - ChatCache.save / persistCooldown now write via temp file + rename.
    rename(2) is atomic on the same filesystem, so a crashed or
    concurrent writer can never leave NULs in the middle of the file.
    A small serialising write queue stops two concurrent saves from
    racing to the same temp name.

  - ChatCache throws if constructed without a filePath under NODE_ENV=test.
    The old default (./data/chat-cache.json) silently routed test
    writes into the production cache — exactly how the corruption
    happened. Future test that forgets to pass a tmp path fails loudly
    instead of stomping data.

  - Cooldown / delta-media / username-persist tests now pass an
    explicit tmp ChatCache so the new guard is satisfied.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:48:33 +01:00
jjbruntonandClaude Opus 4.7 71548ec2ad Resolve invitees via /state and accept 'invite' membership
For chats where we sent an opening message but the recipient never
accepted, /sync drops the room with no heroes and the recipient is
in state as m.room.member with membership:'invite' — not 'join'.
chat.reddit.com's web UI labels these rooms with the invitee anyway,
because it reads the full room state.

  - roomToActiveChat now accepts 'invite' membership in addition to
    'join' when scanning member-join state events.
  - enrichUsernames pass 2 hits /_matrix/client/v3/rooms/{id}/state
    first (cheap, returns all member events including invites) and
    only falls back to /messages history if /state yields nothing.
  - Added MatrixClient.getRoomFullState to back that lookup.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:41:31 +01:00
jjbruntonandClaude Opus 4.7 cf7fc41761 Fix username resolver: use www.reddit.com, not api.reddit.com
api.reddit.com/api/user_data_by_account_ids returns 404 without an
OAuth token — which is why every chat in the dashboard sat on
t2_xxx or unknown. The same path on www.reddit.com (with a .json
suffix) is served unauthenticated and returns the expected user
map. Switch the resolver to that host so enrichUsernames actually
succeeds.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:30:01 +01:00
jjbruntonandClaude Opus 4.7 01ea8fd36b Mine t2 IDs from timeline events and /messages history
Reddit's homeserver does not expose /_matrix/client/v3/rooms/{id}/joined_members
(it returns 'page not found'), so the previous fallback was always a 404.
Two replacements:

  - roomToActiveChat: include timeline event senders as candidate MXIDs
    alongside heroes / member-join state. /sync omits heroes for idle
    rooms but always carries full sender MXIDs in any timeline events
    it does return, so we recover a t2 ID whenever the delta sees a
    message.

  - enrichUsernames: split into three passes — apply known mappings
    first (so re-created delta chats get upgraded without a restart),
    then page /messages 'b' once per still-unknown room to mine a t2
    from the recipient's history, then resolve any remaining raw t2s
    via the bulk user_data endpoint. Failed history lookups are cached
    in unresolvableRooms so we don't retry every sync.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:15:27 +01:00
jjbruntonandClaude Opus 4.7 1df7b680ee Stop re-attempting /joined_members on rooms we can't read
Reddit's homeserver returns 404 from /_matrix/client/v3/rooms/{id}/joined_members
for rooms we've left, been kicked from, or never fully joined — which is
roughly every chat that wasn't accepted by the recipient. The previous
enrichUsernames pass retried these on every delta sync, flooding the
dashboard log with debug-level 404s. Track failures in an in-memory
unresolvable set so each room is tried at most once per process.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:06:33 +01:00
jjbruntonandClaude Opus 4.7 ad5c63fc50 Fall back to /joined_members when delta sync omits the other party
Reddit's homeserver sometimes returns a room in /sync with no
m.heroes and no joined m.room.member state events, leaving us with
no t2 ID to resolve and the chat stuck on 'unknown'. enrichUsernames
now hits /_matrix/client/v3/rooms/{roomId}/joined_members for any
chat whose username is 'unknown' or a bare MXID, stamps the t2 ID,
and lets the existing resolver fill in the real Reddit username.

Also treats a cached 'unknown' username as stale in roomToActiveChat
so subsequent deltas re-attempt the lookup instead of pinning it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 23:01:06 +01:00
jjbruntonandClaude Opus 4.7 2edbc7dbf7 Resolve t2 usernames after every delta sync
enrichUsernames() was only invoked once at startup, so any rooms that
arrived via a later delta /sync stayed pinned to their raw t2_xxx
identifier — which the dashboard then rendered as a bare Matrix-style
ID. Call enrichUsernames() at the tail of syncOnce so new rooms get
resolved to real Reddit usernames before the UI reads them.

Also pass the unformatted username to openConversation() and format
the modal title in the frontend, so lookups by username keep working
after the display sanitisation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 22:52:04 +01:00