remcodex 0.1.0-beta.1

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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +331 -0
  3. package/dist/server/src/app.js +186 -0
  4. package/dist/server/src/cli.js +270 -0
  5. package/dist/server/src/controllers/codex-options.controller.js +199 -0
  6. package/dist/server/src/controllers/message.controller.js +21 -0
  7. package/dist/server/src/controllers/project.controller.js +44 -0
  8. package/dist/server/src/controllers/session.controller.js +175 -0
  9. package/dist/server/src/db/client.js +10 -0
  10. package/dist/server/src/db/migrations.js +32 -0
  11. package/dist/server/src/gateways/ws.gateway.js +60 -0
  12. package/dist/server/src/services/codex-app-server-runner.js +363 -0
  13. package/dist/server/src/services/codex-exec-runner.js +147 -0
  14. package/dist/server/src/services/codex-rollout-sync.js +977 -0
  15. package/dist/server/src/services/codex-runner.js +11 -0
  16. package/dist/server/src/services/codex-stream-events.js +478 -0
  17. package/dist/server/src/services/event-store.js +328 -0
  18. package/dist/server/src/services/project-manager.js +130 -0
  19. package/dist/server/src/services/pty-runner.js +72 -0
  20. package/dist/server/src/services/session-manager.js +1586 -0
  21. package/dist/server/src/services/session-timeline-service.js +181 -0
  22. package/dist/server/src/types/codex-launch.js +2 -0
  23. package/dist/server/src/types/models.js +37 -0
  24. package/dist/server/src/utils/ansi.js +143 -0
  25. package/dist/server/src/utils/codex-launch.js +102 -0
  26. package/dist/server/src/utils/codex-quota.js +179 -0
  27. package/dist/server/src/utils/codex-status.js +163 -0
  28. package/dist/server/src/utils/codex-ui-options.js +114 -0
  29. package/dist/server/src/utils/command.js +46 -0
  30. package/dist/server/src/utils/errors.js +16 -0
  31. package/dist/server/src/utils/ids.js +7 -0
  32. package/dist/server/src/utils/node-pty.js +29 -0
  33. package/package.json +36 -0
  34. package/scripts/fix-node-pty-helper.js +36 -0
  35. package/web/api.js +175 -0
  36. package/web/app.js +8082 -0
  37. package/web/components/composer.js +627 -0
  38. package/web/components/session-workbench.js +173 -0
  39. package/web/i18n/index.js +171 -0
  40. package/web/i18n/locales/de.js +50 -0
  41. package/web/i18n/locales/en.js +320 -0
  42. package/web/i18n/locales/es.js +50 -0
  43. package/web/i18n/locales/fr.js +50 -0
  44. package/web/i18n/locales/ja.js +50 -0
  45. package/web/i18n/locales/ko.js +50 -0
  46. package/web/i18n/locales/pt-BR.js +50 -0
  47. package/web/i18n/locales/ru.js +50 -0
  48. package/web/i18n/locales/zh-CN.js +320 -0
  49. package/web/i18n/locales/zh-Hant.js +53 -0
  50. package/web/index.html +23 -0
  51. package/web/message-rich-text.js +218 -0
  52. package/web/session-command-activity.js +980 -0
  53. package/web/session-event-adapter.js +826 -0
  54. package/web/session-timeline-reducer.js +728 -0
  55. package/web/session-timeline-renderer.js +656 -0
  56. package/web/session-ws.js +31 -0
  57. package/web/styles.css +5665 -0
  58. package/web/vendor/markdown-it.js +6969 -0
@@ -0,0 +1,826 @@
1
+ function toIsoTimestamp(value) {
2
+ if (!value) {
3
+ return null;
4
+ }
5
+
6
+ const date = new Date(value);
7
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
8
+ }
9
+
10
+ function safeJsonParse(value) {
11
+ if (typeof value !== "string" || !value.trim()) {
12
+ return null;
13
+ }
14
+
15
+ try {
16
+ return JSON.parse(value);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ function normalizeId(raw, fallbackPrefix = "raw") {
23
+ if (raw?.id) {
24
+ return String(raw.id);
25
+ }
26
+
27
+ const topType = String(raw?.type || "unknown");
28
+ const payloadType = String(raw?.payload?.type || "unknown");
29
+ const timestamp = String(raw?.timestamp || Date.now());
30
+ return `${fallbackPrefix}:${topType}:${payloadType}:${timestamp}`;
31
+ }
32
+
33
+ function pickTurnId(payload) {
34
+ return payload?.turn_id || payload?.turnId || null;
35
+ }
36
+
37
+ function pickCallId(payload) {
38
+ return payload?.call_id || payload?.callId || null;
39
+ }
40
+
41
+ function pickRequestId(payload) {
42
+ return payload?.request_id || payload?.requestId || null;
43
+ }
44
+
45
+ function pickMessageId(payload) {
46
+ return payload?.message_id || payload?.messageId || payload?.id || null;
47
+ }
48
+
49
+ function normalizeMessageContent(content) {
50
+ if (typeof content === "string") {
51
+ return content;
52
+ }
53
+
54
+ if (!Array.isArray(content)) {
55
+ return "";
56
+ }
57
+
58
+ return content
59
+ .map((item) => {
60
+ if (!item || typeof item !== "object") {
61
+ return "";
62
+ }
63
+ return typeof item.text === "string" ? item.text : "";
64
+ })
65
+ .filter(Boolean)
66
+ .join("\n");
67
+ }
68
+
69
+ function normalizeFunctionCallArguments(payload) {
70
+ const parsed = safeJsonParse(payload?.arguments);
71
+ return parsed && typeof parsed === "object" ? parsed : {};
72
+ }
73
+
74
+ function normalizeFunctionCallOutput(payload) {
75
+ const output = typeof payload?.output === "string" ? payload.output : "";
76
+ const rejected = /Rejected\("rejected by user"\)/.test(output);
77
+
78
+ return {
79
+ output,
80
+ rejected,
81
+ raw: payload,
82
+ };
83
+ }
84
+
85
+ function normalizeCustomToolOutput(payload) {
86
+ const output = typeof payload?.output === "string" ? payload.output : "";
87
+ const parsed = safeJsonParse(output);
88
+
89
+ return {
90
+ output,
91
+ parsed,
92
+ raw: payload,
93
+ };
94
+ }
95
+
96
+ function normalizeExecCommandEnd(payload) {
97
+ const command = Array.isArray(payload?.command)
98
+ ? payload.command.join(" ")
99
+ : typeof payload?.command === "string"
100
+ ? payload.command
101
+ : "";
102
+
103
+ return {
104
+ command,
105
+ argv: Array.isArray(payload?.command) ? payload.command : [],
106
+ cwd: payload?.cwd || null,
107
+ stdout: payload?.stdout || "",
108
+ stderr: payload?.stderr || "",
109
+ aggregatedOutput: payload?.aggregated_output || "",
110
+ formattedOutput: payload?.formatted_output || "",
111
+ exitCode:
112
+ typeof payload?.exit_code === "number"
113
+ ? payload.exit_code
114
+ : Number.isFinite(Number(payload?.exit_code))
115
+ ? Number(payload.exit_code)
116
+ : null,
117
+ processId: payload?.process_id || null,
118
+ status: payload?.status || null,
119
+ duration: payload?.duration || null,
120
+ parsedCommand: Array.isArray(payload?.parsed_cmd) ? payload.parsed_cmd : [],
121
+ raw: payload,
122
+ };
123
+ }
124
+
125
+ function normalizePatchEnd(payload) {
126
+ return {
127
+ stdout: payload?.stdout || "",
128
+ stderr: payload?.stderr || "",
129
+ success: typeof payload?.success === "boolean" ? payload.success : null,
130
+ status: payload?.status || null,
131
+ changes: payload?.changes && typeof payload.changes === "object" ? payload.changes : {},
132
+ raw: payload,
133
+ };
134
+ }
135
+
136
+ function normalizeTokenCount(payload) {
137
+ return {
138
+ info: payload?.info || null,
139
+ rateLimits: payload?.rate_limits || null,
140
+ raw: payload,
141
+ };
142
+ }
143
+
144
+ function normalizeDirectSemanticPayload(topType, raw, payload) {
145
+ if (topType === "message.user") {
146
+ return {
147
+ text:
148
+ payload?.text ||
149
+ raw?.text ||
150
+ raw?.content ||
151
+ normalizeMessageContent(payload?.content || raw?.content),
152
+ raw,
153
+ };
154
+ }
155
+
156
+ if (
157
+ topType === "message.assistant.start" ||
158
+ topType === "message.assistant.delta" ||
159
+ topType === "message.assistant.end" ||
160
+ topType === "message.assistant"
161
+ ) {
162
+ const isDelta = topType === "message.assistant.delta";
163
+ return {
164
+ text: isDelta
165
+ ? undefined
166
+ : payload?.text ||
167
+ raw?.text ||
168
+ raw?.content ||
169
+ normalizeMessageContent(payload?.content || raw?.content),
170
+ textDelta:
171
+ payload?.textDelta ||
172
+ payload?.text_delta ||
173
+ raw?.textDelta ||
174
+ raw?.text_delta ||
175
+ payload?.delta ||
176
+ raw?.delta ||
177
+ payload?.text ||
178
+ raw?.text ||
179
+ payload?.content ||
180
+ raw?.content ||
181
+ "",
182
+ raw,
183
+ };
184
+ }
185
+
186
+ if (topType === "reasoning.start" || topType === "reasoning.delta" || topType === "reasoning.end" || topType === "reasoning") {
187
+ const isDelta = topType === "reasoning.delta";
188
+ return {
189
+ summary: payload?.summary || raw?.summary || raw?.text || "",
190
+ text: isDelta
191
+ ? undefined
192
+ : payload?.text ||
193
+ raw?.text ||
194
+ payload?.summary ||
195
+ raw?.summary ||
196
+ "",
197
+ textDelta:
198
+ payload?.textDelta ||
199
+ payload?.text_delta ||
200
+ raw?.textDelta ||
201
+ raw?.text_delta ||
202
+ payload?.delta ||
203
+ raw?.delta ||
204
+ payload?.summary ||
205
+ raw?.summary ||
206
+ payload?.text ||
207
+ raw?.text ||
208
+ "",
209
+ raw,
210
+ };
211
+ }
212
+
213
+ if (topType === "command.start") {
214
+ return {
215
+ command: payload?.command || raw?.command || "",
216
+ cwd: payload?.cwd || raw?.cwd || null,
217
+ justification: payload?.justification || raw?.justification || null,
218
+ sandboxPermissions:
219
+ payload?.sandboxPermissions || raw?.sandboxPermissions || raw?.sandbox_permissions || null,
220
+ raw,
221
+ };
222
+ }
223
+
224
+ if (topType === "command.end") {
225
+ return {
226
+ command: payload?.command || raw?.command || "",
227
+ cwd: payload?.cwd || raw?.cwd || null,
228
+ stdout: payload?.stdout || raw?.stdout || "",
229
+ stderr: payload?.stderr || raw?.stderr || "",
230
+ output: payload?.output || raw?.output || "",
231
+ aggregatedOutput:
232
+ payload?.aggregatedOutput || payload?.aggregated_output || raw?.aggregatedOutput || "",
233
+ formattedOutput:
234
+ payload?.formattedOutput || payload?.formatted_output || raw?.formattedOutput || "",
235
+ exitCode:
236
+ payload?.exitCode ??
237
+ payload?.exit_code ??
238
+ raw?.exitCode ??
239
+ raw?.exit_code ??
240
+ null,
241
+ duration: payload?.duration || raw?.duration || null,
242
+ status: payload?.status || raw?.status || null,
243
+ rejected: payload?.rejected ?? raw?.rejected ?? false,
244
+ raw,
245
+ };
246
+ }
247
+
248
+ if (topType === "command.output.delta") {
249
+ return {
250
+ stream: payload?.stream || raw?.stream || "stdout",
251
+ textDelta:
252
+ payload?.textDelta ||
253
+ payload?.text_delta ||
254
+ raw?.textDelta ||
255
+ raw?.text_delta ||
256
+ payload?.delta ||
257
+ raw?.delta ||
258
+ payload?.text ||
259
+ raw?.text ||
260
+ "",
261
+ raw,
262
+ };
263
+ }
264
+
265
+ if (topType === "patch.start") {
266
+ return {
267
+ input: payload?.input || raw?.input || raw?.patch || "",
268
+ raw,
269
+ };
270
+ }
271
+
272
+ if (topType === "patch.end") {
273
+ return {
274
+ output: payload?.output || raw?.output || "",
275
+ stdout: payload?.stdout || raw?.stdout || "",
276
+ stderr: payload?.stderr || raw?.stderr || "",
277
+ success: payload?.success ?? raw?.success ?? null,
278
+ status: payload?.status || raw?.status || null,
279
+ changes: payload?.changes || raw?.changes || {},
280
+ raw,
281
+ };
282
+ }
283
+
284
+ if (topType === "patch.output.delta") {
285
+ return {
286
+ textDelta:
287
+ payload?.textDelta ||
288
+ payload?.text_delta ||
289
+ raw?.textDelta ||
290
+ raw?.text_delta ||
291
+ payload?.delta ||
292
+ raw?.delta ||
293
+ payload?.text ||
294
+ raw?.text ||
295
+ "",
296
+ raw,
297
+ };
298
+ }
299
+
300
+ if (topType === "approval.requested" || topType === "approval.resolved") {
301
+ return {
302
+ title: payload?.title || raw?.title || "",
303
+ reason: payload?.reason || raw?.reason || "",
304
+ command: payload?.command || raw?.command || "",
305
+ decision: payload?.decision || raw?.decision || null,
306
+ resumable: payload?.resumable ?? raw?.resumable ?? true,
307
+ raw,
308
+ };
309
+ }
310
+
311
+ if (topType === "turn.aborted" || topType === "error") {
312
+ return {
313
+ reason: payload?.reason || raw?.reason || "",
314
+ message: payload?.message || raw?.message || "",
315
+ code: payload?.code || raw?.code || null,
316
+ raw,
317
+ };
318
+ }
319
+
320
+ if (topType === "token_count") {
321
+ return normalizeTokenCount({
322
+ ...raw,
323
+ ...payload,
324
+ rate_limits: payload?.rate_limits || raw?.rate_limits || raw?.rateLimits || null,
325
+ });
326
+ }
327
+
328
+ return payload;
329
+ }
330
+
331
+ export function normalizeRawSessionEvent(raw) {
332
+ if (!raw || typeof raw !== "object") {
333
+ return null;
334
+ }
335
+
336
+ const timestamp = toIsoTimestamp(raw.timestamp);
337
+ const seq =
338
+ typeof raw.seq === "number"
339
+ ? raw.seq
340
+ : Number.isFinite(Number(raw.seq))
341
+ ? Number(raw.seq)
342
+ : 0;
343
+ const topType = String(raw.type || "");
344
+ const payload = raw.payload && typeof raw.payload === "object" ? raw.payload : {};
345
+ const payloadType = String(payload.type || "");
346
+
347
+ const directSemanticKinds = new Set([
348
+ "message.user",
349
+ "message.assistant",
350
+ "message.assistant.start",
351
+ "message.assistant.delta",
352
+ "message.assistant.end",
353
+ "reasoning",
354
+ "reasoning.start",
355
+ "reasoning.delta",
356
+ "reasoning.end",
357
+ "command.start",
358
+ "command.output.delta",
359
+ "command.end",
360
+ "patch.start",
361
+ "patch.output.delta",
362
+ "patch.end",
363
+ "approval.requested",
364
+ "approval.resolved",
365
+ "turn.started",
366
+ "turn.completed",
367
+ "turn.aborted",
368
+ "error",
369
+ "token_count",
370
+ ]);
371
+
372
+ if (directSemanticKinds.has(topType)) {
373
+ const directKindMap = {
374
+ "message.user": "user_message",
375
+ "message.assistant": "assistant_message",
376
+ "message.assistant.start": "assistant_message_start",
377
+ "message.assistant.delta": "assistant_message_delta",
378
+ "message.assistant.end": "assistant_message_end",
379
+ reasoning: "reasoning",
380
+ "reasoning.start": "reasoning_start",
381
+ "reasoning.delta": "reasoning_delta",
382
+ "reasoning.end": "reasoning_end",
383
+ "command.start": "command_start",
384
+ "command.output.delta": "command_output_delta",
385
+ "command.end": "command_end",
386
+ "patch.start": "patch_start",
387
+ "patch.output.delta": "patch_output_delta",
388
+ "patch.end": "patch_end",
389
+ "approval.requested": "approval_requested",
390
+ "approval.resolved": "approval_resolved",
391
+ "turn.started": "turn_started",
392
+ "turn.completed": "turn_completed",
393
+ "turn.aborted": "turn_aborted",
394
+ error: "error",
395
+ token_count: "token_count",
396
+ };
397
+
398
+ return {
399
+ id: normalizeId(raw, "semantic"),
400
+ seq,
401
+ timestamp,
402
+ kind: directKindMap[topType],
403
+ turnId: raw.turnId || payload.turnId || payload.turn_id || null,
404
+ callId: raw.callId || payload.callId || payload.call_id || null,
405
+ requestId: raw.requestId || payload.requestId || payload.request_id || null,
406
+ messageId: raw.messageId || payload.messageId || payload.message_id || null,
407
+ role: raw.role || payload.role || null,
408
+ phase: raw.phase || payload.phase || null,
409
+ payload: normalizeDirectSemanticPayload(topType, raw, payload),
410
+ };
411
+ }
412
+
413
+ if (topType === "session_meta" || topType === "turn_context") {
414
+ return null;
415
+ }
416
+
417
+ if (topType === "response_item") {
418
+ if (payloadType === "message") {
419
+ const role = String(payload.role || "");
420
+ const phase = payload.phase || null;
421
+ const text = normalizeMessageContent(payload.content);
422
+
423
+ if (role === "user") {
424
+ return {
425
+ id: normalizeId(raw, "user"),
426
+ seq,
427
+ timestamp,
428
+ kind: "user_message",
429
+ turnId: pickTurnId(payload),
430
+ callId: null,
431
+ requestId: null,
432
+ messageId: pickMessageId(payload),
433
+ role: "user",
434
+ phase: null,
435
+ payload: {
436
+ text,
437
+ source: "response_item.message",
438
+ raw: payload,
439
+ },
440
+ };
441
+ }
442
+
443
+ if (role === "assistant") {
444
+ return {
445
+ id: normalizeId(raw, "assistant"),
446
+ seq,
447
+ timestamp,
448
+ kind: "assistant_message",
449
+ turnId: pickTurnId(payload),
450
+ callId: null,
451
+ requestId: null,
452
+ messageId: pickMessageId(payload),
453
+ role: "assistant",
454
+ phase: phase || "final_answer",
455
+ payload: {
456
+ text,
457
+ source: "response_item.message",
458
+ raw: payload,
459
+ },
460
+ };
461
+ }
462
+
463
+ return null;
464
+ }
465
+
466
+ if (payloadType === "reasoning") {
467
+ return {
468
+ id: normalizeId(raw, "reasoning"),
469
+ seq,
470
+ timestamp,
471
+ kind: "reasoning",
472
+ turnId: pickTurnId(payload),
473
+ callId: null,
474
+ requestId: null,
475
+ messageId: pickMessageId(payload),
476
+ role: "assistant",
477
+ phase: "commentary",
478
+ payload: {
479
+ summary: payload?.summary || null,
480
+ content: payload?.content || null,
481
+ encryptedContent: payload?.encrypted_content || null,
482
+ raw: payload,
483
+ },
484
+ };
485
+ }
486
+
487
+ if (payloadType === "function_call" && payload?.name === "exec_command") {
488
+ const args = normalizeFunctionCallArguments(payload);
489
+ return {
490
+ id: normalizeId(raw, "command-start"),
491
+ seq,
492
+ timestamp,
493
+ kind: "command_start",
494
+ turnId: pickTurnId(payload) || args.turnId || null,
495
+ callId: pickCallId(payload),
496
+ requestId: pickRequestId(payload) || null,
497
+ messageId: null,
498
+ role: "assistant",
499
+ phase: "commentary",
500
+ payload: {
501
+ name: payload.name,
502
+ command: args.cmd || "",
503
+ sandboxPermissions: args.sandbox_permissions || null,
504
+ justification: args.justification || null,
505
+ cwd: args.cwd || null,
506
+ args,
507
+ raw: payload,
508
+ },
509
+ };
510
+ }
511
+
512
+ if (payloadType === "function_call_output") {
513
+ return {
514
+ id: normalizeId(raw, "command-end"),
515
+ seq,
516
+ timestamp,
517
+ kind: "command_end",
518
+ turnId: pickTurnId(payload),
519
+ callId: pickCallId(payload),
520
+ requestId: pickRequestId(payload),
521
+ messageId: null,
522
+ role: "assistant",
523
+ phase: "commentary",
524
+ payload: normalizeFunctionCallOutput(payload),
525
+ };
526
+ }
527
+
528
+ if (payloadType === "custom_tool_call" && payload?.name === "apply_patch") {
529
+ return {
530
+ id: normalizeId(raw, "patch-start"),
531
+ seq,
532
+ timestamp,
533
+ kind: "patch_start",
534
+ turnId: pickTurnId(payload),
535
+ callId: pickCallId(payload),
536
+ requestId: null,
537
+ messageId: null,
538
+ role: "assistant",
539
+ phase: "commentary",
540
+ payload: {
541
+ name: payload.name,
542
+ status: payload.status || null,
543
+ input: payload.input || "",
544
+ raw: payload,
545
+ },
546
+ };
547
+ }
548
+
549
+ if (payloadType === "custom_tool_call_output") {
550
+ return {
551
+ id: normalizeId(raw, "patch-end"),
552
+ seq,
553
+ timestamp,
554
+ kind: "patch_end",
555
+ turnId: pickTurnId(payload),
556
+ callId: pickCallId(payload),
557
+ requestId: null,
558
+ messageId: null,
559
+ role: "assistant",
560
+ phase: "commentary",
561
+ payload: normalizeCustomToolOutput(payload),
562
+ };
563
+ }
564
+
565
+ return null;
566
+ }
567
+
568
+ if (topType === "event_msg") {
569
+ if (payloadType === "user_message") {
570
+ return {
571
+ id: normalizeId(raw, "user"),
572
+ seq,
573
+ timestamp,
574
+ kind: "user_message",
575
+ turnId: pickTurnId(payload),
576
+ callId: null,
577
+ requestId: null,
578
+ messageId: pickMessageId(payload),
579
+ role: "user",
580
+ phase: null,
581
+ payload: {
582
+ text: payload?.message || "",
583
+ images: Array.isArray(payload?.images) ? payload.images : [],
584
+ localImages: Array.isArray(payload?.local_images) ? payload.local_images : [],
585
+ source: "event_msg.user_message",
586
+ raw: payload,
587
+ },
588
+ };
589
+ }
590
+
591
+ if (payloadType === "agent_message") {
592
+ return {
593
+ id: normalizeId(raw, "assistant"),
594
+ seq,
595
+ timestamp,
596
+ kind: "assistant_message",
597
+ turnId: pickTurnId(payload),
598
+ callId: null,
599
+ requestId: null,
600
+ messageId: pickMessageId(payload),
601
+ role: "assistant",
602
+ phase: payload?.phase || "final_answer",
603
+ payload: {
604
+ text: payload?.message || "",
605
+ memoryCitation: payload?.memory_citation || null,
606
+ source: "event_msg.agent_message",
607
+ raw: payload,
608
+ },
609
+ };
610
+ }
611
+
612
+ if (payloadType === "task_started") {
613
+ return {
614
+ id: normalizeId(raw, "turn-start"),
615
+ seq,
616
+ timestamp,
617
+ kind: "turn_started",
618
+ turnId: pickTurnId(payload),
619
+ callId: null,
620
+ requestId: null,
621
+ messageId: null,
622
+ role: null,
623
+ phase: null,
624
+ payload: {
625
+ modelContextWindow: payload?.model_context_window || null,
626
+ collaborationModeKind: payload?.collaboration_mode_kind || null,
627
+ raw: payload,
628
+ },
629
+ };
630
+ }
631
+
632
+ if (payloadType === "task_complete") {
633
+ return {
634
+ id: normalizeId(raw, "turn-complete"),
635
+ seq,
636
+ timestamp,
637
+ kind: "turn_completed",
638
+ turnId: pickTurnId(payload),
639
+ callId: null,
640
+ requestId: null,
641
+ messageId: null,
642
+ role: null,
643
+ phase: null,
644
+ payload: {
645
+ lastAgentMessage: payload?.last_agent_message || "",
646
+ raw: payload,
647
+ },
648
+ };
649
+ }
650
+
651
+ if (payloadType === "turn_aborted") {
652
+ return {
653
+ id: normalizeId(raw, "turn-aborted"),
654
+ seq,
655
+ timestamp,
656
+ kind: "turn_aborted",
657
+ turnId: pickTurnId(payload),
658
+ callId: null,
659
+ requestId: null,
660
+ messageId: null,
661
+ role: null,
662
+ phase: null,
663
+ payload: {
664
+ reason: payload?.reason || null,
665
+ raw: payload,
666
+ },
667
+ };
668
+ }
669
+
670
+ if (payloadType === "exec_command_end") {
671
+ return {
672
+ id: normalizeId(raw, "command-end"),
673
+ seq,
674
+ timestamp,
675
+ kind: "command_end",
676
+ turnId: pickTurnId(payload),
677
+ callId: pickCallId(payload),
678
+ requestId: null,
679
+ messageId: null,
680
+ role: null,
681
+ phase: null,
682
+ payload: normalizeExecCommandEnd(payload),
683
+ };
684
+ }
685
+
686
+ if (payloadType === "patch_apply_end") {
687
+ return {
688
+ id: normalizeId(raw, "patch-end"),
689
+ seq,
690
+ timestamp,
691
+ kind: "patch_end",
692
+ turnId: pickTurnId(payload),
693
+ callId: pickCallId(payload),
694
+ requestId: null,
695
+ messageId: null,
696
+ role: null,
697
+ phase: null,
698
+ payload: normalizePatchEnd(payload),
699
+ };
700
+ }
701
+
702
+ if (payloadType === "error") {
703
+ return {
704
+ id: normalizeId(raw, "error"),
705
+ seq,
706
+ timestamp,
707
+ kind: "error",
708
+ turnId: pickTurnId(payload),
709
+ callId: pickCallId(payload),
710
+ requestId: pickRequestId(payload),
711
+ messageId: null,
712
+ role: null,
713
+ phase: null,
714
+ payload: {
715
+ message: payload?.message || "",
716
+ code: payload?.codex_error_info || null,
717
+ raw: payload,
718
+ },
719
+ };
720
+ }
721
+
722
+ if (payloadType === "token_count") {
723
+ return {
724
+ id: normalizeId(raw, "token-count"),
725
+ seq,
726
+ timestamp,
727
+ kind: "token_count",
728
+ turnId: pickTurnId(payload),
729
+ callId: null,
730
+ requestId: null,
731
+ messageId: null,
732
+ role: null,
733
+ phase: null,
734
+ payload: normalizeTokenCount(payload),
735
+ };
736
+ }
737
+ }
738
+
739
+ return null;
740
+ }
741
+
742
+ function expandOneShotNormalizedEvent(event) {
743
+ if (!event) {
744
+ return [];
745
+ }
746
+
747
+ if (event.kind === "assistant_message") {
748
+ const messageId = event.messageId || `assistant:${event.id}`;
749
+ const base = {
750
+ ...event,
751
+ messageId,
752
+ };
753
+ return [
754
+ {
755
+ ...base,
756
+ id: `${event.id}:start`,
757
+ kind: "assistant_message_start",
758
+ payload: { raw: event.payload?.raw || event.payload || {} },
759
+ },
760
+ {
761
+ ...base,
762
+ id: `${event.id}:delta`,
763
+ kind: "assistant_message_delta",
764
+ payload: {
765
+ textDelta: event.payload?.text || "",
766
+ raw: event.payload?.raw || event.payload || {},
767
+ },
768
+ },
769
+ {
770
+ ...base,
771
+ id: `${event.id}:end`,
772
+ kind: "assistant_message_end",
773
+ payload: { raw: event.payload?.raw || event.payload || {} },
774
+ },
775
+ ];
776
+ }
777
+
778
+ if (event.kind === "reasoning") {
779
+ const messageId = event.messageId || `reasoning:${event.id}`;
780
+ const reasoningText =
781
+ event.payload?.content || event.payload?.summary || event.payload?.text || "";
782
+ return [
783
+ {
784
+ ...event,
785
+ id: `${event.id}:start`,
786
+ kind: "reasoning_start",
787
+ messageId,
788
+ payload: {
789
+ summary: event.payload?.summary || "",
790
+ raw: event.payload?.raw || event.payload || {},
791
+ },
792
+ },
793
+ {
794
+ ...event,
795
+ id: `${event.id}:delta`,
796
+ kind: "reasoning_delta",
797
+ messageId,
798
+ payload: {
799
+ textDelta: reasoningText,
800
+ summary: event.payload?.summary || "",
801
+ raw: event.payload?.raw || event.payload || {},
802
+ },
803
+ },
804
+ {
805
+ ...event,
806
+ id: `${event.id}:end`,
807
+ kind: "reasoning_end",
808
+ messageId,
809
+ payload: { raw: event.payload?.raw || event.payload || {} },
810
+ },
811
+ ];
812
+ }
813
+
814
+ return [event];
815
+ }
816
+
817
+ export function normalizeRawSessionEvents(list) {
818
+ if (!Array.isArray(list)) {
819
+ return [];
820
+ }
821
+
822
+ return list
823
+ .flatMap((raw) => expandOneShotNormalizedEvent(normalizeRawSessionEvent(raw)))
824
+ .filter(Boolean)
825
+ .sort((a, b) => a.seq - b.seq);
826
+ }