Skip to content

Commit d8c88bf

Browse files
committed
fix: mobile scrolling (#13) and timestamp preservation for opencode-sync (#29)
1 parent ff4ffa6 commit d8c88bf

7 files changed

Lines changed: 64 additions & 13 deletions

File tree

changelog.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88

99
### Fixed
1010

11+
- Fixed mobile scrolling in session detail view (fixes #13)
12+
- Added `overscroll-contain`, `touch-pan-y`, and `WebkitOverflowScrolling: 'touch'` to messages container
13+
- Session detail uses absolute positioning on mobile with background color to cover session list
14+
- iOS scrolling now works properly within the messages area
15+
16+
- Fixed opencode-sync --force setting wrong dates (fixes #29)
17+
- Plugin was not sending original `createdAt` timestamps from local session/message data
18+
- Convex mutations were not accepting `createdAt` argument, always using `Date.now()`
19+
- Updated opencode-sync-plugin CLI to include `createdAt: data.time?.created` for sessions and messages
20+
- Updated `internal.sessions.upsert` to accept optional `createdAt` and use it for new inserts
21+
- Updated `internal.messages.upsert` to accept optional `createdAt` and use it for new inserts
22+
- Updated HTTP endpoints `/sync/session` and `/sync/message` to pass `createdAt` to mutations
23+
- Sessions and messages now preserve their original timestamps when synced
24+
1125
- Fixed token double-counting bug in message handlers (fixes #32)
1226
- Message handlers (upsert, batchUpsert) were accumulating per-message promptTokens/completionTokens onto the session record
1327
- Since session-level sync already sets these as authoritative absolute values, the accumulation resulted in inflated token totals

convex/http.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ http.route({
126126
completionTokens: body.completionTokens,
127127
cost: body.cost,
128128
durationMs: body.durationMs,
129+
createdAt: body.createdAt, // Original timestamp from source
129130
});
130131

131132
// Schedule embedding generation
@@ -163,6 +164,7 @@ http.route({
163164
durationMs: body.durationMs,
164165
source: body.source, // Pass source for auto-created sessions ("opencode" or "claude-code")
165166
parts: body.parts,
167+
createdAt: body.createdAt, // Original timestamp from source
166168
});
167169

168170
return json({ ok: true, messageId });

convex/messages.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const upsert = internalMutation({
2727
})
2828
)
2929
),
30+
createdAt: v.optional(v.number()), // Original timestamp from source
3031
},
3132
returns: v.id("messages"),
3233
handler: async (ctx, args) => {
@@ -114,7 +115,8 @@ export const upsert = internalMutation({
114115
await Promise.all(existingParts.map((part) => ctx.db.delete(part._id)));
115116
}
116117
} else {
117-
// Create new message
118+
// Create new message - use provided createdAt or current time
119+
const messageCreatedAt = args.createdAt ?? now;
118120
messageId = await ctx.db.insert("messages", {
119121
sessionId,
120122
externalId: args.externalId,
@@ -124,7 +126,7 @@ export const upsert = internalMutation({
124126
promptTokens: args.promptTokens,
125127
completionTokens: args.completionTokens,
126128
durationMs: args.durationMs,
127-
createdAt: now,
129+
createdAt: messageCreatedAt,
128130
});
129131
shouldUpdateSessionStats = true;
130132
}

convex/sessions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ export const upsert = internalMutation({
307307
completionTokens: v.optional(v.number()),
308308
cost: v.optional(v.number()),
309309
durationMs: v.optional(v.number()),
310+
createdAt: v.optional(v.number()), // Original timestamp from source
310311
},
311312
returns: v.id("sessions"),
312313
handler: async (ctx, args) => {
@@ -384,7 +385,8 @@ export const upsert = internalMutation({
384385
return existing._id;
385386
}
386387

387-
// Insert new session
388+
// Insert new session - use provided createdAt or current time
389+
const sessionCreatedAt = args.createdAt ?? now;
388390
return await ctx.db.insert("sessions", {
389391
userId: args.userId,
390392
externalId: args.externalId,
@@ -402,7 +404,7 @@ export const upsert = internalMutation({
402404
isPublic: false,
403405
searchableText: args.title,
404406
messageCount: 0,
405-
createdAt: now,
407+
createdAt: sessionCreatedAt,
406408
updatedAt: now,
407409
});
408410
},

0 commit comments

Comments
 (0)