promptcase 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
File without changes
@@ -289,21 +289,20 @@ export class ClaudeCaptureService {
289
289
  * Get all prompts from all sources (project transcripts + history),
290
290
  * deduplicated by SHA-256 content hash.
291
291
  *
292
- * Sort order depends on whether this is a backfill or an incremental sync:
292
+ * Two modes:
293
293
  *
294
- * - **Backfill** (`since` is undefined): the daemon's first sync, with no
295
- * prior cursor. We sort **OLDEST FIRST** so that the server inserts
296
- * prompts in chronological order. Since the server's `created_at`
297
- * column defaults to insert time and the dashboard sorts `created_at
298
- * DESC`, the *most recent* prompt in the batch ends up at the top of
299
- * the dashboard matching the user's intuition that "latest shows
300
- * first."
294
+ * 1. **Initial backfill** (no `since` cursor): fetch the **latest** N
295
+ * prompts and sort them **newest first**. The user sees their
296
+ * recent work immediately on the dashboard. We deliberately do NOT
297
+ * walk backwards through older prompts that would push the user's
298
+ * whole history onto the server on first install, which is
299
+ * unnecessary work and can blow past the per-batch payload limit.
300
+ * Anything older than the 100 newest stays local; subsequent
301
+ * syncs only pick up NEW prompts.
301
302
  *
302
- * - **Incremental** (`since` is a date): the daemon's subsequent syncs
303
- * pick up only prompts newer than the cursor. We sort **NEWEST FIRST**
304
- * so that when the cursor advances we always send the freshest
305
- * prompts first (and the new cursor lands on the actual latest
306
- * prompt, not a few-batch-behind one).
303
+ * 2. **Incremental** (`since` is a date): fetch prompts newer than
304
+ * the cursor, sorted **newest first** so the cursor advances to
305
+ * the actual latest prompt.
307
306
  */
308
307
  async getAllPrompts(since, limit = 100) {
309
308
  const sessions = await this.getSessions();
@@ -342,14 +341,10 @@ export class ClaudeCaptureService {
342
341
  seenHashes.add(prompt.hash);
343
342
  allPrompts.push(prompt);
344
343
  }
345
- // Backfill: oldest first (so newest ends up at top of dashboard).
346
- // Incremental: newest first (so the cursor advances to actual latest).
347
- if (since) {
348
- allPrompts.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
349
- }
350
- else {
351
- allPrompts.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
352
- }
344
+ // Sort: newest first in both modes ensures the cursor advances
345
+ // to the actual latest prompt and the server's `created_at` DESC
346
+ // sort puts the latest prompt at the top of the dashboard.
347
+ allPrompts.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
353
348
  return allPrompts.slice(0, limit);
354
349
  }
355
350
  /**
@@ -345,9 +345,18 @@ export class DaemonService {
345
345
  return this.status;
346
346
  }
347
347
  try {
348
- // Get prompts from Claude. Use a timestamp cursor to skip prompts older
349
- // than the last successful sync (server dedups, but skipping locally
350
- // saves bandwidth on subsequent syncs).
348
+ // Get prompts from Claude. The cursor controls which prompts we fetch:
349
+ //
350
+ // - First-ever run (no cursor yet): sync the LATEST 100 prompts so
351
+ // the user sees their recent work immediately. We deliberately
352
+ // do NOT walk backwards through older prompts — that would push
353
+ // the user's whole history onto the server on first install,
354
+ // which is unnecessary work and can blow past the per-batch
355
+ // payload limit. Anything older than the 100 newest stays local.
356
+ //
357
+ // - Subsequent runs (cursor set): fetch prompts newer than the
358
+ // cursor. This is normal incremental mode — only the latest
359
+ // new prompts get synced.
351
360
  const cursorIso = await this.configService.getLastSyncCursor();
352
361
  const since = cursorIso ? new Date(cursorIso) : undefined;
353
362
  const prompts = await this.captureService.getAllPrompts(since, MAX_PROMPTS_PER_SYNC);
@@ -379,12 +388,16 @@ export class DaemonService {
379
388
  const result = await this.apiService.syncPrompts(apiPrompts);
380
389
  this.status.lastSyncAt = new Date();
381
390
  this.status.promptsSynced += result.synced;
382
- // Persist the cursor at the newest prompt we ATTEMPTED to sync (not
383
- // just newly-synced ones). The server's content_hash dedup means we'll
384
- // see `result.synced: 0` on subsequent runs even though the prompts
385
- // are already saved that's normal. We want the cursor to advance
386
- // so the next run only fetches prompts newer than the newest one we've
387
- // seen, regardless of whether they were already on the server.
391
+ // Advance the cursor to the NEWEST prompt in the synced batch. This
392
+ // is correct in both modes:
393
+ //
394
+ // - First backfill: cursor = newest of the 100 batched → next
395
+ // cycle only picks up prompts strictly newer than that.
396
+ // - Incremental: cursor = newest of the new batch.
397
+ //
398
+ // The server's content_hash dedup means we never re-insert a
399
+ // prompt; advancing the cursor just means we don't re-fetch
400
+ // what we already have.
388
401
  if (prompts.length > 0) {
389
402
  const newest = prompts[0].timestamp;
390
403
  await this.configService.setLastSyncCursor(newest.toISOString());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptcase",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "CLI daemon to capture and sync AI prompts to PromptCase web app",
5
5
  "main": "dist/index.js",
6
6
  "bin": {