claude-starter 1.3.3 → 1.3.4

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.
Files changed (2) hide show
  1. package/index.js +49 -6
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -202,17 +202,20 @@ function loadSessionQuick(filePath, projectName) {
202
202
  const sessionId = path.basename(filePath, '.jsonl');
203
203
  const stat = fs.statSync(filePath);
204
204
 
205
+ // Use 32KB head buffer (up from 8KB) to handle sessions whose first user
206
+ // message is very large (e.g. pasted code blocks, long queries).
207
+ const HEAD_SIZE = 32768;
205
208
  const fd = fs.openSync(filePath, 'r');
206
- const headBuf = Buffer.alloc(Math.min(8192, stat.size));
209
+ const headBuf = Buffer.alloc(Math.min(HEAD_SIZE, stat.size));
207
210
  fs.readSync(fd, headBuf, 0, headBuf.length, 0);
208
211
 
209
212
  // Read tail with progressive expansion: start at 32KB, grow up to 256KB
210
213
  // until we find a JSON line with a top-level timestamp (to get accurate lastTs).
211
214
  let tailStr = '';
212
- if (stat.size > 8192) {
215
+ if (stat.size > HEAD_SIZE) {
213
216
  const tailSizes = [32768, 65536, 131072, 262144];
214
217
  for (const ts of tailSizes) {
215
- const tailSize = Math.min(ts, stat.size - 8192);
218
+ const tailSize = Math.min(ts, stat.size - HEAD_SIZE);
216
219
  const tailBuf = Buffer.alloc(tailSize);
217
220
  fs.readSync(fd, tailBuf, 0, tailSize, stat.size - tailSize);
218
221
  tailStr = tailBuf.toString('utf-8');
@@ -221,7 +224,7 @@ function loadSessionQuick(filePath, projectName) {
221
224
  try { return !!JSON.parse(line).timestamp; } catch { return false; }
222
225
  });
223
226
  if (hasTopLevelTs) break;
224
- if (tailSize >= stat.size - 8192) break; // already read entire file
227
+ if (tailSize >= stat.size - HEAD_SIZE) break; // already read entire file
225
228
  }
226
229
  }
227
230
  fs.closeSync(fd);
@@ -250,7 +253,42 @@ function loadSessionQuick(filePath, projectName) {
250
253
  userMsgCount++;
251
254
  if (!firstUserMsg) firstUserMsg = extractUserText(d);
252
255
  }
253
- } catch (e) { /* partial line */ }
256
+ } catch (e) {
257
+ // The line was truncated by the head buffer. Try to salvage metadata
258
+ // via regex so we don't lose the session entirely.
259
+ if (!firstTs) {
260
+ const tsMatch = line.match(/"timestamp"\s*:\s*"([^"]+)"/);
261
+ if (tsMatch) firstTs = tsMatch[1];
262
+ }
263
+ if (!version) {
264
+ const vMatch = line.match(/"version"\s*:\s*"([^"]+)"/);
265
+ if (vMatch) version = vMatch[1];
266
+ }
267
+ if (!gitBranch) {
268
+ const bMatch = line.match(/"gitBranch"\s*:\s*"([^"]+)"/);
269
+ if (bMatch) gitBranch = bMatch[1];
270
+ }
271
+ if (!cwd) {
272
+ const cwdMatch = line.match(/"cwd"\s*:\s*"([^"]+)"/);
273
+ if (cwdMatch) cwd = cwdMatch[1];
274
+ }
275
+ // Try to extract user message text from the truncated JSON line.
276
+ // User messages have "type":"user" and text content embedded inside.
277
+ if (!firstUserMsg && /"type"\s*:\s*"user"/.test(line)) {
278
+ userMsgCount++;
279
+ // Match the text field inside message.content (handles both string
280
+ // content and array-of-objects content structures).
281
+ const textMatch = line.match(/"text"\s*:\s*"((?:[^"\\]|\\.)*)/) ||
282
+ line.match(/"content"\s*:\s*"((?:[^"\\]|\\.)*)/);
283
+ if (textMatch) {
284
+ let text = '';
285
+ try { text = JSON.parse('"' + textMatch[1] + '"'); } catch { text = textMatch[1]; }
286
+ if (!text.startsWith('<local-command') && !text.startsWith('<command-')) {
287
+ firstUserMsg = text.substring(0, 200);
288
+ }
289
+ }
290
+ }
291
+ }
254
292
  }
255
293
 
256
294
  if (tailStr) {
@@ -259,7 +297,12 @@ function loadSessionQuick(filePath, projectName) {
259
297
  try {
260
298
  const d = JSON.parse(line);
261
299
  if (d.timestamp) lastTs = d.timestamp;
262
- if (d.type === 'user') userMsgCount++;
300
+ if (d.type === 'user') {
301
+ userMsgCount++;
302
+ // If no real user message was found in the head (all were commands),
303
+ // try to pick one from the tail as a fallback topic.
304
+ if (!firstUserMsg) firstUserMsg = extractUserText(d);
305
+ }
263
306
  if (d.type === 'custom-title' && d.customTitle) customTitle = d.customTitle;
264
307
  } catch (e) { /* partial line */ }
265
308
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-starter",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "A beautiful terminal UI for managing Claude Code sessions — start new or resume past conversations",
5
5
  "main": "index.js",
6
6
  "bin": {