@ycodium-ai/plugin-session-import 0.2.2526 → 0.2.2554

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/dist/index.js +577 -26
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -171,6 +171,492 @@ import * as NodeProcess2 from "node:process";
171
171
  import * as NodePath from "node:path";
172
172
  import * as NodeProcess from "node:process";
173
173
 
174
+ // ../../packages/ycodium-jsonl-stream/src/jsonlStream.ts
175
+ var DEFAULT_MAX_RETAINED_CHARS = 8e6;
176
+ var MAX_DEPTH = 128;
177
+ var MAX_KEY_CHARS = 256;
178
+ var MAX_BARE_CHARS = 64;
179
+ var NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/u;
180
+ var OversizedRecordParser = class {
181
+ #fields;
182
+ #budget;
183
+ #retained = 0;
184
+ #malformed = false;
185
+ #done = false;
186
+ #result = void 0;
187
+ #stack = [];
188
+ // 词法状态。
189
+ #inString = false;
190
+ #stringIsKey = false;
191
+ #escape = false;
192
+ #unicodeLeft = 0;
193
+ #unicodeValue = 0;
194
+ #bare = "";
195
+ // 当前字符串的保留规则与累积。
196
+ #strRetain = false;
197
+ #strCap = void 0;
198
+ #strHead = "";
199
+ #strTail = "";
200
+ #strLength = 0;
201
+ #key = "";
202
+ #keyOverflow = false;
203
+ // 值之间的位置。
204
+ #expectKey = false;
205
+ #expectColon = false;
206
+ #expectComma = false;
207
+ #expectValue = true;
208
+ constructor(fields, maxRetainedChars = DEFAULT_MAX_RETAINED_CHARS) {
209
+ this.#fields = fields;
210
+ this.#budget = maxRetainedChars;
211
+ }
212
+ write(chunk) {
213
+ if (this.#malformed) return;
214
+ try {
215
+ this.#consume(chunk);
216
+ } catch (cause) {
217
+ if (cause instanceof MalformedRecord) {
218
+ this.#malformed = true;
219
+ return;
220
+ }
221
+ throw cause;
222
+ }
223
+ }
224
+ /** 完整且合法才返回记录;其余(含空行)返回 `undefined`。 */
225
+ finish() {
226
+ if (this.#malformed) return void 0;
227
+ try {
228
+ if (this.#bare.length > 0) this.#finishBare();
229
+ } catch (cause) {
230
+ if (cause instanceof MalformedRecord) return void 0;
231
+ throw cause;
232
+ }
233
+ if (!this.#done || this.#inString || this.#result === SKIPPED) return void 0;
234
+ return this.#result;
235
+ }
236
+ #fail() {
237
+ throw new MalformedRecord();
238
+ }
239
+ #charge(chars) {
240
+ this.#retained += chars;
241
+ if (this.#retained > this.#budget) this.#fail();
242
+ }
243
+ #consume(chunk) {
244
+ const n = chunk.length;
245
+ let i = 0;
246
+ while (i < n) {
247
+ if (this.#inString) {
248
+ i = this.#consumeString(chunk, i);
249
+ continue;
250
+ }
251
+ const c = chunk.charCodeAt(i);
252
+ if (this.#bare.length > 0) {
253
+ if (isBareChar(c)) {
254
+ if (this.#bare.length >= MAX_BARE_CHARS) this.#fail();
255
+ this.#bare += chunk[i];
256
+ i += 1;
257
+ continue;
258
+ }
259
+ this.#finishBare();
260
+ }
261
+ i += 1;
262
+ if (c === 32 || c === 9 || c === 10 || c === 13) continue;
263
+ if (this.#done) this.#fail();
264
+ switch (c) {
265
+ case 123:
266
+ this.#requireValue();
267
+ this.#openContainer(false);
268
+ break;
269
+ case 91:
270
+ this.#requireValue();
271
+ this.#openContainer(true);
272
+ break;
273
+ case 125:
274
+ this.#closeContainer(false);
275
+ break;
276
+ case 93:
277
+ this.#closeContainer(true);
278
+ break;
279
+ case 44:
280
+ this.#comma();
281
+ break;
282
+ case 58:
283
+ if (!this.#expectColon) this.#fail();
284
+ this.#expectColon = false;
285
+ this.#expectValue = true;
286
+ break;
287
+ case 34:
288
+ this.#openString();
289
+ break;
290
+ default:
291
+ if (isBareChar(c)) {
292
+ this.#requireValue();
293
+ this.#bare = chunk[i - 1] ?? "";
294
+ } else this.#fail();
295
+ }
296
+ }
297
+ }
298
+ #top() {
299
+ return this.#stack[this.#stack.length - 1];
300
+ }
301
+ #requireValue() {
302
+ if (!this.#expectValue) this.#fail();
303
+ this.#expectValue = false;
304
+ }
305
+ /** 当前要读的值(刚要开始)落在什么模式;`isContainer` 决定 scalarOnly 清单项是否适用。 */
306
+ #childMode(isContainer) {
307
+ const parent = this.#top();
308
+ if (parent === void 0) return this.#classify([], isContainer);
309
+ if (parent.mode === "skip") return { mode: "skip", cap: void 0, path: [] };
310
+ if (parent.mode === "keep") return { mode: "keep", cap: parent.cap, path: [] };
311
+ const segment = parent.isArray ? String(parent.index) : parent.key ?? "";
312
+ if (parent.skipValue) return { mode: "skip", cap: void 0, path: [] };
313
+ return this.#classify([...parent.path, segment], isContainer);
314
+ }
315
+ #classify(path, isContainer) {
316
+ let descend = false;
317
+ for (const field of this.#fields) {
318
+ const fieldPath = field.path;
319
+ if (fieldPath.length <= path.length) {
320
+ if (field.scalarOnly === true && (isContainer || fieldPath.length !== path.length)) {
321
+ continue;
322
+ }
323
+ if (matchesPrefix(fieldPath, path, fieldPath.length)) {
324
+ return { mode: "keep", cap: field.maxChars, path };
325
+ }
326
+ } else if (matchesPrefix(fieldPath, path, path.length)) {
327
+ descend = true;
328
+ }
329
+ }
330
+ return { mode: descend ? "descend" : "skip", cap: void 0, path };
331
+ }
332
+ #openContainer(isArray) {
333
+ if (this.#stack.length >= MAX_DEPTH) this.#fail();
334
+ const { mode, cap, path } = this.#childMode(true);
335
+ const keeping = mode !== "skip";
336
+ let target = null;
337
+ if (keeping) {
338
+ this.#charge(16);
339
+ target = isArray ? [] : {};
340
+ }
341
+ this.#stack.push({ isArray, mode, path, cap, target, key: null, skipValue: false, index: 0 });
342
+ this.#expectValue = isArray;
343
+ this.#expectKey = !isArray;
344
+ this.#expectComma = false;
345
+ this.#expectColon = false;
346
+ }
347
+ #closeContainer(isArray) {
348
+ const top = this.#top();
349
+ if (top === void 0 || top.isArray !== isArray) this.#fail();
350
+ if (!this.#expectComma && top.index > 0) this.#fail();
351
+ if (this.#expectColon || !isArray && this.#expectValue) this.#fail();
352
+ this.#stack.pop();
353
+ this.#expectValue = false;
354
+ this.#expectKey = false;
355
+ this.#expectColon = false;
356
+ this.#expectComma = true;
357
+ this.#store(top.target ?? SKIPPED);
358
+ }
359
+ #comma() {
360
+ const top = this.#top();
361
+ if (top === void 0 || !this.#expectComma) this.#fail();
362
+ this.#expectComma = false;
363
+ if (top.isArray) {
364
+ this.#expectValue = true;
365
+ } else {
366
+ this.#expectKey = true;
367
+ }
368
+ }
369
+ /** 一个值读完:交给外层容器,或成为整条记录。 */
370
+ #store(value) {
371
+ const parent = this.#top();
372
+ if (parent === void 0) {
373
+ this.#result = value;
374
+ this.#done = true;
375
+ this.#expectComma = false;
376
+ return;
377
+ }
378
+ this.#expectComma = true;
379
+ if (parent.isArray) {
380
+ parent.index += 1;
381
+ if (parent.target !== null && value !== SKIPPED) {
382
+ parent.target.push(value);
383
+ this.#charge(8);
384
+ }
385
+ return;
386
+ }
387
+ parent.index += 1;
388
+ const key = parent.key;
389
+ parent.key = null;
390
+ parent.skipValue = false;
391
+ if (parent.target !== null && value !== SKIPPED && key !== null) {
392
+ Object.defineProperty(parent.target, key, {
393
+ value,
394
+ enumerable: true,
395
+ writable: true,
396
+ configurable: true
397
+ });
398
+ this.#charge(key.length + 8);
399
+ }
400
+ }
401
+ #openString() {
402
+ const parent = this.#top();
403
+ const asKey = parent !== void 0 && !parent.isArray && this.#expectKey;
404
+ if (!asKey) this.#requireValue();
405
+ this.#inString = true;
406
+ this.#stringIsKey = asKey;
407
+ this.#escape = false;
408
+ this.#unicodeLeft = 0;
409
+ this.#strLength = 0;
410
+ this.#strHead = "";
411
+ this.#strTail = "";
412
+ this.#key = "";
413
+ if (asKey) {
414
+ this.#keyOverflow = false;
415
+ this.#strRetain = true;
416
+ this.#strCap = void 0;
417
+ return;
418
+ }
419
+ const { mode, cap } = this.#childMode(false);
420
+ this.#strRetain = mode === "keep";
421
+ this.#strCap = cap;
422
+ }
423
+ /** 字符串里的一个解码后片段;按保留规则累积。 */
424
+ #append(text) {
425
+ if (text.length === 0) return;
426
+ if (this.#stringIsKey) {
427
+ if (this.#keyOverflow) return;
428
+ this.#key += text;
429
+ if (this.#key.length > MAX_KEY_CHARS) {
430
+ this.#keyOverflow = true;
431
+ this.#key = "";
432
+ }
433
+ return;
434
+ }
435
+ this.#strLength += text.length;
436
+ if (!this.#strRetain) return;
437
+ const cap = this.#strCap;
438
+ if (cap === void 0) {
439
+ this.#strHead += text;
440
+ this.#charge(text.length);
441
+ return;
442
+ }
443
+ if (this.#strHead.length < cap) {
444
+ const room = cap - this.#strHead.length;
445
+ this.#strHead += text.slice(0, room);
446
+ text = text.slice(room);
447
+ if (text.length === 0) return;
448
+ }
449
+ this.#strTail += text;
450
+ if (this.#strTail.length > cap * 2) this.#strTail = this.#strTail.slice(-cap);
451
+ }
452
+ #consumeString(chunk, start) {
453
+ const n = chunk.length;
454
+ let i = start;
455
+ while (i < n) {
456
+ if (this.#unicodeLeft > 0) {
457
+ const digit = hexValue(chunk.charCodeAt(i));
458
+ if (digit < 0) this.#fail();
459
+ this.#unicodeValue = this.#unicodeValue * 16 + digit;
460
+ this.#unicodeLeft -= 1;
461
+ i += 1;
462
+ if (this.#unicodeLeft === 0) this.#append(String.fromCharCode(this.#unicodeValue));
463
+ continue;
464
+ }
465
+ if (this.#escape) {
466
+ this.#escape = false;
467
+ const c2 = chunk[i] ?? "";
468
+ i += 1;
469
+ switch (c2) {
470
+ case '"':
471
+ case "\\":
472
+ case "/":
473
+ this.#append(c2);
474
+ break;
475
+ case "b":
476
+ this.#append("\b");
477
+ break;
478
+ case "f":
479
+ this.#append("\f");
480
+ break;
481
+ case "n":
482
+ this.#append("\n");
483
+ break;
484
+ case "r":
485
+ this.#append("\r");
486
+ break;
487
+ case "t":
488
+ this.#append(" ");
489
+ break;
490
+ case "u":
491
+ this.#unicodeLeft = 4;
492
+ this.#unicodeValue = 0;
493
+ break;
494
+ default:
495
+ this.#fail();
496
+ }
497
+ continue;
498
+ }
499
+ const runStart = i;
500
+ while (i < n) {
501
+ const c2 = chunk.charCodeAt(i);
502
+ if (c2 === 34 || c2 === 92 || c2 < 32) break;
503
+ i += 1;
504
+ }
505
+ if (i > runStart) this.#append(chunk.slice(runStart, i));
506
+ if (i >= n) break;
507
+ const c = chunk.charCodeAt(i);
508
+ i += 1;
509
+ if (c === 92) {
510
+ this.#escape = true;
511
+ } else if (c === 34) {
512
+ this.#inString = false;
513
+ this.#endString();
514
+ return i;
515
+ } else {
516
+ this.#fail();
517
+ }
518
+ }
519
+ return i;
520
+ }
521
+ #endString() {
522
+ if (this.#stringIsKey) {
523
+ const parent = this.#top();
524
+ if (parent === void 0) this.#fail();
525
+ parent.key = this.#key;
526
+ parent.skipValue = this.#keyOverflow;
527
+ this.#key = "";
528
+ this.#expectKey = false;
529
+ this.#expectColon = true;
530
+ return;
531
+ }
532
+ if (!this.#strRetain) {
533
+ this.#store(SKIPPED);
534
+ return;
535
+ }
536
+ const cap = this.#strCap;
537
+ let text = this.#strHead;
538
+ if (cap !== void 0) {
539
+ let tail = this.#strTail;
540
+ if (tail.length > cap) tail = tail.slice(-cap);
541
+ if (this.#strLength > text.length + tail.length) {
542
+ if (isHighSurrogate(text.charCodeAt(text.length - 1))) text = text.slice(0, -1);
543
+ if (isLowSurrogate(tail.charCodeAt(0))) tail = tail.slice(1);
544
+ const omitted = this.#strLength - text.length - tail.length;
545
+ text = `${text}
546
+ [\u2026 ${omitted} chars omitted \u2026]
547
+ ${tail}`;
548
+ } else {
549
+ text = `${text}${tail}`;
550
+ }
551
+ this.#charge(text.length);
552
+ }
553
+ this.#strHead = "";
554
+ this.#strTail = "";
555
+ this.#store(text);
556
+ }
557
+ #finishBare() {
558
+ const text = this.#bare;
559
+ this.#bare = "";
560
+ const { mode } = this.#childMode(false);
561
+ let value;
562
+ if (text === "true") value = true;
563
+ else if (text === "false") value = false;
564
+ else if (text === "null") value = null;
565
+ else if (NUMBER_PATTERN.test(text)) value = Number(text);
566
+ else this.#fail();
567
+ this.#store(mode === "keep" ? value : SKIPPED);
568
+ }
569
+ };
570
+ var SKIPPED = /* @__PURE__ */ Symbol("skipped");
571
+ var MalformedRecord = class extends Error {
572
+ };
573
+ function isBareChar(c) {
574
+ return c >= 48 && c <= 57 || // 0-9
575
+ c >= 97 && c <= 122 || // a-z
576
+ c >= 65 && c <= 90 || // A-Z
577
+ c === 43 || c === 45 || c === 46;
578
+ }
579
+ function hexValue(c) {
580
+ if (c >= 48 && c <= 57) return c - 48;
581
+ if (c >= 97 && c <= 102) return c - 97 + 10;
582
+ if (c >= 65 && c <= 70) return c - 65 + 10;
583
+ return -1;
584
+ }
585
+ var isHighSurrogate = (c) => c >= 55296 && c <= 56319;
586
+ var isLowSurrogate = (c) => c >= 56320 && c <= 57343;
587
+ function matchesPrefix(pattern, path, length) {
588
+ for (let index = 0; index < length; index += 1) {
589
+ const expected = pattern[index];
590
+ if (expected !== "*" && expected !== path[index]) return false;
591
+ }
592
+ return true;
593
+ }
594
+ function jsonlEntryRecord(entry, accepts) {
595
+ if ("oversized" in entry) return entry.oversized;
596
+ if (!accepts(entry.line)) return void 0;
597
+ try {
598
+ return JSON.parse(entry.line);
599
+ } catch {
600
+ return void 0;
601
+ }
602
+ }
603
+ async function* readJsonlEntries(fs, path, options) {
604
+ const decoder = new TextDecoder("utf-8");
605
+ let pieces = [];
606
+ let pending = 0;
607
+ let parser = null;
608
+ const startOversized = () => {
609
+ const next = new OversizedRecordParser(options.fields, options.maxRetainedChars);
610
+ for (const piece of pieces) next.write(piece);
611
+ pieces = [];
612
+ pending = 0;
613
+ return next;
614
+ };
615
+ const append = (text) => {
616
+ if (text.length === 0) return;
617
+ if (parser !== null) {
618
+ parser.write(text);
619
+ return;
620
+ }
621
+ pieces.push(text);
622
+ pending += text.length;
623
+ if (pending > options.maxLineChars) parser = startOversized();
624
+ };
625
+ const takeLine = () => {
626
+ if (parser !== null) {
627
+ const record3 = parser.finish();
628
+ parser = null;
629
+ return { oversized: record3 };
630
+ }
631
+ if (pending === 0) return null;
632
+ let line = pieces.length === 1 ? pieces[0] ?? "" : pieces.join("");
633
+ pieces = [];
634
+ pending = 0;
635
+ if (line.endsWith("\r")) line = line.slice(0, -1);
636
+ return line.length === 0 ? null : { line };
637
+ };
638
+ const feed = function* (text) {
639
+ let from = 0;
640
+ while (from <= text.length) {
641
+ const newline = text.indexOf("\n", from);
642
+ if (newline < 0) {
643
+ append(text.slice(from));
644
+ return;
645
+ }
646
+ append(text.slice(from, newline));
647
+ const entry = takeLine();
648
+ if (entry !== null) yield entry;
649
+ from = newline + 1;
650
+ }
651
+ };
652
+ for await (const chunk of fs.createReadStream(path)) {
653
+ yield* feed(decoder.decode(chunk, { stream: true }));
654
+ }
655
+ yield* feed(decoder.decode());
656
+ const last = takeLine();
657
+ if (last !== null) yield last;
658
+ }
659
+
174
660
  // src/sessionScope.ts
175
661
  var EXTENDED_LENGTH_UNC = "//?/UNC/";
176
662
  var EXTENDED_LENGTH = "//?/";
@@ -199,6 +685,52 @@ var PREVIEW_LIMIT = 200;
199
685
  var MAX_SCANNED_FILES = 200;
200
686
  var MAX_ROWS = 50;
201
687
  var MAX_PARSED_LINE_BYTES = 1e6;
688
+ var TOOL_TEXT_KEEP_CHARS = 64e3;
689
+ var DIGEST_TEXT_KEEP_CHARS = 4096;
690
+ var DIGEST_FIELDS = [
691
+ { path: ["type"] },
692
+ { path: ["cwd"] },
693
+ { path: ["isSidechain"] },
694
+ { path: ["customTitle"] },
695
+ { path: ["aiTitle"] },
696
+ { path: ["message", "model"] },
697
+ { path: ["message", "content"], scalarOnly: true, maxChars: DIGEST_TEXT_KEEP_CHARS },
698
+ { path: ["message", "content", "*", "type"] },
699
+ { path: ["message", "content", "*", "text"], maxChars: DIGEST_TEXT_KEEP_CHARS }
700
+ ];
701
+ var TRANSCRIPT_FIELDS = [
702
+ { path: ["type"] },
703
+ { path: ["uuid"] },
704
+ { path: ["isSidechain"] },
705
+ { path: ["isSideChain"] },
706
+ { path: ["isMeta"] },
707
+ { path: ["parent_tool_use_id"] },
708
+ { path: ["timestamp"] },
709
+ { path: ["model"] },
710
+ { path: ["message", "model"] },
711
+ { path: ["message", "content"], scalarOnly: true },
712
+ { path: ["message", "content", "*", "type"] },
713
+ // 消息正文不截:它就是导入的内容。
714
+ { path: ["message", "content", "*", "text"] },
715
+ { path: ["message", "content", "*", "thinking"], maxChars: TOOL_TEXT_KEEP_CHARS },
716
+ { path: ["message", "content", "*", "id"] },
717
+ { path: ["message", "content", "*", "name"] },
718
+ { path: ["message", "content", "*", "input"], maxChars: TOOL_TEXT_KEEP_CHARS },
719
+ { path: ["message", "content", "*", "tool_use_id"] },
720
+ { path: ["message", "content", "*", "is_error"] },
721
+ { path: ["message", "content", "*", "status"] },
722
+ // tool_result 的 content 可能是字符串,也可能是块数组;块只认文本块。
723
+ {
724
+ path: ["message", "content", "*", "content"],
725
+ scalarOnly: true,
726
+ maxChars: TOOL_TEXT_KEEP_CHARS
727
+ },
728
+ { path: ["message", "content", "*", "content", "*", "type"] },
729
+ {
730
+ path: ["message", "content", "*", "content", "*", "text"],
731
+ maxChars: TOOL_TEXT_KEEP_CHARS
732
+ }
733
+ ];
202
734
  var TRANSCRIPT_SUFFIX = ".jsonl";
203
735
  function truncate(value) {
204
736
  const trimmed = value?.trim() ?? "";
@@ -227,18 +759,17 @@ async function readClaudeTranscriptDigest(fs, filePath) {
227
759
  let aiTitle = null;
228
760
  let turnCount = 0;
229
761
  try {
230
- for await (const line of fs.readLines(filePath)) {
231
- const isUser = line.includes('"type":"user"');
232
- const wantsAssistant = model === null && line.includes('"type":"assistant"');
233
- const isTitle = line.includes('"custom-title"') || line.includes('"ai-title"');
234
- if (!isUser && !wantsAssistant && !isTitle) continue;
235
- if (line.length > MAX_PARSED_LINE_BYTES) continue;
236
- let record3;
237
- try {
238
- record3 = JSON.parse(line);
239
- } catch {
240
- continue;
241
- }
762
+ const entries = readJsonlEntries(fs, filePath, {
763
+ maxLineChars: MAX_PARSED_LINE_BYTES,
764
+ fields: DIGEST_FIELDS
765
+ });
766
+ for await (const entry of entries) {
767
+ const record3 = jsonlEntryRecord(entry, (line) => {
768
+ const isUser = line.includes('"type":"user"');
769
+ const wantsAssistant = model === null && line.includes('"type":"assistant"');
770
+ const isTitle = line.includes('"custom-title"') || line.includes('"ai-title"');
771
+ return isUser || wantsAssistant || isTitle;
772
+ });
242
773
  if (!record3 || typeof record3 !== "object") continue;
243
774
  const typed = record3;
244
775
  if (cwd === null && typeof typed.cwd === "string" && typed.cwd.length > 0) cwd = typed.cwd;
@@ -377,14 +908,16 @@ async function readClaudeSessionRecords(input) {
377
908
  throw new Error(`No transcript file for Claude session ${input.sessionId}.`);
378
909
  }
379
910
  const records = [];
380
- for await (const line of input.fs.readLines(path)) {
381
- if (line.length > MAX_PARSED_LINE_BYTES) continue;
382
- if (!line.includes('"type":"user"') && !line.includes('"type":"assistant"')) continue;
383
- try {
384
- records.push(JSON.parse(line));
385
- } catch {
386
- continue;
387
- }
911
+ const entries = readJsonlEntries(input.fs, path, {
912
+ maxLineChars: MAX_PARSED_LINE_BYTES,
913
+ fields: TRANSCRIPT_FIELDS
914
+ });
915
+ for await (const entry of entries) {
916
+ const record3 = jsonlEntryRecord(
917
+ entry,
918
+ (line) => line.includes('"type":"user"') || line.includes('"type":"assistant"')
919
+ );
920
+ if (record3 !== void 0) records.push(record3);
388
921
  }
389
922
  return records;
390
923
  }
@@ -573,6 +1106,14 @@ var PAGE_LIMIT = 50;
573
1106
  var MAX_PAGES = 10;
574
1107
  var MAX_ROWS2 = 50;
575
1108
  var PREVIEW_LIMIT2 = 200;
1109
+ var MAX_PARSED_LINE_CHARS = 1e6;
1110
+ var ROLLOUT_FIELDS = [
1111
+ { path: ["type"] },
1112
+ { path: ["payload", "id"] },
1113
+ { path: ["payload", "session_id"] },
1114
+ { path: ["payload", "cwd"] },
1115
+ { path: ["payload", "model"] }
1116
+ ];
576
1117
  function truncate2(value) {
577
1118
  const trimmed = value?.trim() ?? "";
578
1119
  if (trimmed.length === 0) return null;
@@ -691,13 +1232,23 @@ async function readRolloutModel(input, rolloutPath, sameDirectory) {
691
1232
  let verified = false;
692
1233
  let model = null;
693
1234
  try {
694
- for await (const line of input.fs.readLines(resolved)) {
695
- if (!line.includes('"session_meta"') && !line.includes('"turn_context"')) continue;
1235
+ const entries = readJsonlEntries(input.fs, resolved, {
1236
+ maxLineChars: MAX_PARSED_LINE_CHARS,
1237
+ fields: ROLLOUT_FIELDS
1238
+ });
1239
+ for await (const entry of entries) {
696
1240
  let record3;
697
- try {
698
- record3 = asRecord(JSON.parse(line));
699
- } catch {
700
- continue;
1241
+ if ("oversized" in entry) {
1242
+ record3 = asRecord(entry.oversized);
1243
+ } else {
1244
+ if (!entry.line.includes('"session_meta"') && !entry.line.includes('"turn_context"')) {
1245
+ continue;
1246
+ }
1247
+ try {
1248
+ record3 = asRecord(JSON.parse(entry.line));
1249
+ } catch {
1250
+ continue;
1251
+ }
701
1252
  }
702
1253
  const payload = asRecord(record3?.payload);
703
1254
  if (!record3 || !payload) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-session-import",
3
- "version": "0.2.2526",
3
+ "version": "0.2.2554",
4
4
  "description": "Brings a session you started in a terminal into Ycodium.",
5
5
  "keywords": [
6
6
  "session-import",
@@ -20,7 +20,8 @@
20
20
  "effect": "4.0.0-beta.103",
21
21
  "esbuild": "0.28.1",
22
22
  "vite-plus": "0.2.2",
23
- "@ycodium-ai/plugin-api": "0.2.2526"
23
+ "@ycodium-ai/plugin-api": "0.2.2554",
24
+ "ycodium-jsonl-stream": "0.0.0"
24
25
  },
25
26
  "ycodium": {
26
27
  "plugin": "./dist/index.js",