@lvce-editor/chat-debug-view 10.0.0 → 10.3.0

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.
@@ -1315,6 +1315,9 @@ const listChatViewEvents$1 = async sessionId => {
1315
1315
  const loadSelectedEvent$1 = async (sessionId, eventId, type) => {
1316
1316
  return invoke$1('ChatStorage.loadSelectedEvent', sessionId, eventId, type);
1317
1317
  };
1318
+ const registerUpdateListener = async (sessionId, rpcId, uid) => {
1319
+ return invoke$1('ChatStorage.registerUpdateListener', sessionId, rpcId, uid);
1320
+ };
1318
1321
 
1319
1322
  const appendStoredEventForTest = async (state, event) => {
1320
1323
  await appendEvent(event);
@@ -2217,6 +2220,8 @@ const createDefaultState = () => {
2217
2220
  largeBreakpoint: 900,
2218
2221
  mediumBreakpoint: 600,
2219
2222
  platform: 0,
2223
+ previewTextCursorColumnIndex: null,
2224
+ previewTextCursorRowIndex: null,
2220
2225
  sashPointerActive: false,
2221
2226
  selectedEvent: null,
2222
2227
  selectedEventId: null,
@@ -2230,11 +2235,17 @@ const createDefaultState = () => {
2230
2235
  sortDescending: false,
2231
2236
  tableColumns: createTableColumns(),
2232
2237
  tableColumnWidths: defaultTableColumnWidths,
2238
+ tableDeltaY: 0,
2239
+ tableMaxLineY: 0,
2240
+ tableMinLineY: 0,
2233
2241
  tableResizerDownId: 0,
2242
+ tableScrollBarHandleOffset: 0,
2243
+ tableScrollBarPointerActive: false,
2234
2244
  tableWidth: defaultTableWidth,
2235
2245
  timelineEndSeconds: '',
2236
2246
  timelineEvents: [],
2237
2247
  timelineFilterDescription: '',
2248
+ timelineHeight: 81,
2238
2249
  timelineHoverPercent: null,
2239
2250
  timelineHoverSeconds: '',
2240
2251
  timelineInfo: emptyTimelineInfo,
@@ -2282,7 +2293,7 @@ const RenderFocusContext = 4;
2282
2293
  const RenderFocus = 5;
2283
2294
 
2284
2295
  const diff = (oldState, newState) => {
2285
- if (oldState.categoryFilters !== newState.categoryFilters || oldState.detailTabs !== newState.detailTabs || oldState.errorMessage !== newState.errorMessage || oldState.events !== newState.events || oldState.filterValue !== newState.filterValue || oldState.sessionId !== newState.sessionId || oldState.showEventStreamFinishedEvents !== newState.showEventStreamFinishedEvents || oldState.showInputEvents !== newState.showInputEvents || oldState.showResponsePartEvents !== newState.showResponsePartEvents || oldState.sortColumn !== newState.sortColumn || oldState.sortDescending !== newState.sortDescending || oldState.tableColumnWidths !== newState.tableColumnWidths || oldState.tableWidth !== newState.tableWidth || oldState.timelineEndSeconds !== newState.timelineEndSeconds || oldState.timelineHoverPercent !== newState.timelineHoverPercent || oldState.timelineHoverSeconds !== newState.timelineHoverSeconds || oldState.timelineSelectionActive !== newState.timelineSelectionActive || oldState.timelineSelectionAnchorSeconds !== newState.timelineSelectionAnchorSeconds || oldState.timelineSelectionFocusSeconds !== newState.timelineSelectionFocusSeconds || oldState.timelineStartSeconds !== newState.timelineStartSeconds || oldState.useDevtoolsLayout !== newState.useDevtoolsLayout || oldState.tableColumns !== newState.tableColumns || oldState.selectedEvent !== newState.selectedEvent || oldState.selectedEventIndex !== newState.selectedEventIndex || oldState.focus !== newState.focus || oldState.width !== newState.width || oldState.uid !== newState.uid) {
2296
+ if (oldState.categoryFilters !== newState.categoryFilters || oldState.detailTabs !== newState.detailTabs || oldState.errorMessage !== newState.errorMessage || oldState.events !== newState.events || oldState.filterValue !== newState.filterValue || oldState.previewTextCursorColumnIndex !== newState.previewTextCursorColumnIndex || oldState.previewTextCursorRowIndex !== newState.previewTextCursorRowIndex || oldState.sessionId !== newState.sessionId || oldState.showEventStreamFinishedEvents !== newState.showEventStreamFinishedEvents || oldState.showInputEvents !== newState.showInputEvents || oldState.showResponsePartEvents !== newState.showResponsePartEvents || oldState.sortColumn !== newState.sortColumn || oldState.sortDescending !== newState.sortDescending || oldState.tableColumnWidths !== newState.tableColumnWidths || oldState.tableDeltaY !== newState.tableDeltaY || oldState.tableMaxLineY !== newState.tableMaxLineY || oldState.tableMinLineY !== newState.tableMinLineY || oldState.tableWidth !== newState.tableWidth || oldState.timelineEndSeconds !== newState.timelineEndSeconds || oldState.timelineHeight !== newState.timelineHeight || oldState.timelineHoverPercent !== newState.timelineHoverPercent || oldState.timelineHoverSeconds !== newState.timelineHoverSeconds || oldState.timelineSelectionActive !== newState.timelineSelectionActive || oldState.timelineSelectionAnchorSeconds !== newState.timelineSelectionAnchorSeconds || oldState.timelineSelectionFocusSeconds !== newState.timelineSelectionFocusSeconds || oldState.timelineStartSeconds !== newState.timelineStartSeconds || oldState.useDevtoolsLayout !== newState.useDevtoolsLayout || oldState.tableColumns !== newState.tableColumns || oldState.selectedEvent !== newState.selectedEvent || oldState.selectedEventIndex !== newState.selectedEventIndex || oldState.focus !== newState.focus || oldState.width !== newState.width || oldState.uid !== newState.uid) {
2286
2297
  return [RenderIncremental, RenderCss];
2287
2298
  }
2288
2299
  return [];
@@ -2373,6 +2384,76 @@ const mergeToolExecutionEvents = (startedEvent, finishedEvent, type = mergedEven
2373
2384
  return mergedEvent;
2374
2385
  };
2375
2386
 
2387
+ const requestEventTypes = new Set(['request', 'ai-request']);
2388
+ const responseEventTypes = new Set(['response', 'ai-response-success']);
2389
+ const getPairId = event => {
2390
+ const {
2391
+ request_id: requestIdSnake,
2392
+ requestId,
2393
+ requestID,
2394
+ turn_id: turnIdSnake,
2395
+ turnId
2396
+ } = event;
2397
+ if (typeof requestId === 'string' || typeof requestId === 'number') {
2398
+ return requestId;
2399
+ }
2400
+ if (typeof requestIdSnake === 'string' || typeof requestIdSnake === 'number') {
2401
+ return requestIdSnake;
2402
+ }
2403
+ if (typeof requestID === 'string' || typeof requestID === 'number') {
2404
+ return requestID;
2405
+ }
2406
+ if (typeof turnId === 'string' || typeof turnId === 'number') {
2407
+ return turnId;
2408
+ }
2409
+ if (typeof turnIdSnake === 'string' || typeof turnIdSnake === 'number') {
2410
+ return turnIdSnake;
2411
+ }
2412
+ const {
2413
+ body,
2414
+ request,
2415
+ response,
2416
+ value
2417
+ } = event;
2418
+ const bodyPairId = body?.requestId ?? body?.request_id ?? body?.requestID ?? body?.turnId ?? body?.turn_id;
2419
+ if (typeof bodyPairId === 'string' || typeof bodyPairId === 'number') {
2420
+ return bodyPairId;
2421
+ }
2422
+ const requestPairId = request?.requestId ?? request?.request_id ?? request?.requestID ?? request?.turnId ?? request?.turn_id;
2423
+ if (typeof requestPairId === 'string' || typeof requestPairId === 'number') {
2424
+ return requestPairId;
2425
+ }
2426
+ const valuePairId = value?.requestId ?? value?.request_id ?? value?.requestID ?? value?.turnId ?? value?.turn_id;
2427
+ if (typeof valuePairId === 'string' || typeof valuePairId === 'number') {
2428
+ return valuePairId;
2429
+ }
2430
+ const responsePairId = response?.requestId ?? response?.request_id ?? response?.requestID ?? response?.turnId ?? response?.turn_id;
2431
+ if (typeof responsePairId === 'string' || typeof responsePairId === 'number') {
2432
+ return responsePairId;
2433
+ }
2434
+ return undefined;
2435
+ };
2436
+ const mergeRequestResponseEvents = (startedEvent, finishedEvent) => {
2437
+ return {
2438
+ ...mergeToolExecutionEvents(startedEvent, finishedEvent, startedEvent.type),
2439
+ requestEvent: startedEvent,
2440
+ responseEvent: finishedEvent
2441
+ };
2442
+ };
2443
+ const isMatchingRequestResponsePair = (startedEvent, finishedEvent) => {
2444
+ if (!requestEventTypes.has(startedEvent.type) || !responseEventTypes.has(finishedEvent.type)) {
2445
+ return false;
2446
+ }
2447
+ if (startedEvent.sessionId !== finishedEvent.sessionId) {
2448
+ return false;
2449
+ }
2450
+ const startedPairId = getPairId(startedEvent);
2451
+ const finishedPairId = getPairId(finishedEvent);
2452
+ if (startedPairId !== undefined && finishedPairId !== undefined) {
2453
+ return startedPairId === finishedPairId;
2454
+ }
2455
+ return startedEvent.type === 'ai-request' && finishedEvent.type === 'ai-response-success';
2456
+ };
2376
2457
  const isMatchingHandleSubmitPair = (startedEvent, finishedEvent) => {
2377
2458
  return startedEvent.type === handleSubmitEventType && finishedEvent.type === sseResponseCompletedEventType && startedEvent.sessionId === finishedEvent.sessionId;
2378
2459
  };
@@ -2386,6 +2467,11 @@ const collapseToolExecutionEvents = events => {
2386
2467
  i++;
2387
2468
  continue;
2388
2469
  }
2470
+ if (nextEvent && isMatchingRequestResponsePair(event, nextEvent)) {
2471
+ collapsedEvents.push(mergeRequestResponseEvents(event, nextEvent));
2472
+ i++;
2473
+ continue;
2474
+ }
2389
2475
  if (nextEvent && isMatchingHandleSubmitPair(event, nextEvent)) {
2390
2476
  collapsedEvents.push(mergeToolExecutionEvents(event, nextEvent, handleSubmitEventType));
2391
2477
  i++;
@@ -2555,6 +2641,9 @@ const hasErrorStatus = event => {
2555
2641
  const {
2556
2642
  status
2557
2643
  } = event;
2644
+ if (status === 'error') {
2645
+ return true;
2646
+ }
2558
2647
  if (isErrorStatusCode(status)) {
2559
2648
  return true;
2560
2649
  }
@@ -2631,6 +2720,129 @@ const loadSelectedEvent = async (_databaseName, _dataBaseVersion, _eventStoreNam
2631
2720
  return loadSelectedEvent$1(sessionId, eventId, type);
2632
2721
  };
2633
2722
 
2723
+ const mergeSelectedEventDetails = (selectedEvent, selectedEventDetails) => {
2724
+ if (!selectedEventDetails) {
2725
+ return selectedEvent;
2726
+ }
2727
+ const {
2728
+ requestEvent,
2729
+ responseEvent
2730
+ } = selectedEvent;
2731
+ if (!requestEvent || !responseEvent || typeof requestEvent !== 'object' || typeof responseEvent !== 'object') {
2732
+ return selectedEventDetails;
2733
+ }
2734
+ const selectedEventDetailsType = selectedEventDetails.type;
2735
+ const resolvedResponseEvent = selectedEventDetailsType === 'response' || selectedEventDetailsType === 'ai-response-success' ? selectedEventDetails : responseEvent;
2736
+ return {
2737
+ ...selectedEventDetails,
2738
+ ...selectedEvent,
2739
+ requestEvent: {
2740
+ ...requestEvent,
2741
+ ...selectedEventDetails
2742
+ },
2743
+ responseEvent: resolvedResponseEvent
2744
+ };
2745
+ };
2746
+
2747
+ const devtoolsTableHeaderHeight = 24;
2748
+ const devtoolsTableRowHeight = 24;
2749
+ const devtoolsTableScrollBarWidth = 12;
2750
+ const devtoolsTableSummaryHeight = 24;
2751
+ const minimumDevtoolsTableScrollBarHeight = 20;
2752
+
2753
+ const devtoolsRootGap = 4;
2754
+ const devtoolsTopHeight = 28;
2755
+ const devtoolsTimelineHeight = 88;
2756
+ const getTableBodyY = (state, hasTimeline) => {
2757
+ const {
2758
+ y
2759
+ } = state;
2760
+ return y + viewPadding + devtoolsTopHeight + devtoolsRootGap + (hasTimeline ? devtoolsTimelineHeight : 0) + devtoolsTableHeaderHeight;
2761
+ };
2762
+
2763
+ const getTableBodyHeight = (state, eventCount) => {
2764
+ if (eventCount === 0) {
2765
+ return 0;
2766
+ }
2767
+ const tableBodyY = getTableBodyY(state, true);
2768
+ return Math.max(0, state.height - (tableBodyY - state.y) - viewPadding - devtoolsTableSummaryHeight);
2769
+ };
2770
+ const getVisibleRowCount = tableBodyHeight => {
2771
+ if (tableBodyHeight <= 0) {
2772
+ return 0;
2773
+ }
2774
+ return Math.max(1, Math.ceil(tableBodyHeight / devtoolsTableRowHeight));
2775
+ };
2776
+ const getMaxDeltaY = (eventCount, tableBodyHeight) => {
2777
+ return Math.max(eventCount * devtoolsTableRowHeight - tableBodyHeight, 0);
2778
+ };
2779
+ const clampTableDeltaY = (deltaY, eventCount, tableBodyHeight) => {
2780
+ const maxDeltaY = getMaxDeltaY(eventCount, tableBodyHeight);
2781
+ if (deltaY < 0) {
2782
+ return 0;
2783
+ }
2784
+ if (deltaY > maxDeltaY) {
2785
+ return maxDeltaY;
2786
+ }
2787
+ return deltaY;
2788
+ };
2789
+ const getScrollBarHeight = (eventCount, tableBodyHeight) => {
2790
+ if (eventCount === 0 || tableBodyHeight <= 0) {
2791
+ return 0;
2792
+ }
2793
+ const contentHeight = eventCount * devtoolsTableRowHeight;
2794
+ if (contentHeight <= tableBodyHeight) {
2795
+ return 0;
2796
+ }
2797
+ return Math.max(minimumDevtoolsTableScrollBarHeight, Math.floor(tableBodyHeight * tableBodyHeight / contentHeight));
2798
+ };
2799
+ const getScrollBarOffset = (deltaY, maxDeltaY, tableBodyHeight, scrollBarHeight) => {
2800
+ if (maxDeltaY <= 0 || scrollBarHeight <= 0 || tableBodyHeight <= scrollBarHeight) {
2801
+ return 0;
2802
+ }
2803
+ return Math.round(deltaY / maxDeltaY * (tableBodyHeight - scrollBarHeight));
2804
+ };
2805
+ const applyVirtualTableState = state => {
2806
+ const currentEvents = getCurrentEvents$2(state);
2807
+ const tableBodyHeight = getTableBodyHeight(state, currentEvents.length);
2808
+ const deltaY = clampTableDeltaY(state.tableDeltaY, currentEvents.length, tableBodyHeight);
2809
+ const minLineY = Math.floor(deltaY / devtoolsTableRowHeight);
2810
+ const visibleRowCount = getVisibleRowCount(tableBodyHeight);
2811
+ const maxLineY = Math.min(currentEvents.length, minLineY + visibleRowCount);
2812
+ return {
2813
+ ...state,
2814
+ tableDeltaY: deltaY,
2815
+ tableMaxLineY: maxLineY,
2816
+ tableMinLineY: minLineY
2817
+ };
2818
+ };
2819
+ const setTableDeltaY = (state, deltaY) => {
2820
+ return applyVirtualTableState({
2821
+ ...state,
2822
+ tableDeltaY: deltaY
2823
+ });
2824
+ };
2825
+ const withSelectedEventVisible = state => {
2826
+ if (state.selectedEventIndex === null || state.selectedEventIndex < 0) {
2827
+ return applyVirtualTableState(state);
2828
+ }
2829
+ const currentEvents = getCurrentEvents$2(state);
2830
+ const tableBodyHeight = getTableBodyHeight(state, currentEvents.length);
2831
+ const visibleRowCount = getVisibleRowCount(tableBodyHeight);
2832
+ if (visibleRowCount === 0) {
2833
+ return applyVirtualTableState(state);
2834
+ }
2835
+ const minLineY = Math.floor(state.tableDeltaY / devtoolsTableRowHeight);
2836
+ const maxLineY = minLineY + visibleRowCount;
2837
+ if (state.selectedEventIndex < minLineY) {
2838
+ return setTableDeltaY(state, state.selectedEventIndex * devtoolsTableRowHeight);
2839
+ }
2840
+ if (state.selectedEventIndex >= maxLineY) {
2841
+ return setTableDeltaY(state, (state.selectedEventIndex + 1) * devtoolsTableRowHeight - tableBodyHeight);
2842
+ }
2843
+ return applyVirtualTableState(state);
2844
+ };
2845
+
2634
2846
  const svgWidthRegex = /\bwidth=["']([\d.]+)(?:px)?["']/i;
2635
2847
  const svgHeightRegex = /\bheight=["']([\d.]+)(?:px)?["']/i;
2636
2848
  const svgViewBoxRegex = /\bviewBox=["'][^"']*?([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)["']/i;
@@ -2774,14 +2986,16 @@ const selectEventAtIndex = async (state, selectedEventIndex, dependencies = sele
2774
2986
  };
2775
2987
  }
2776
2988
  const selectedEventDetails = await dependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
2777
- const resolvedSelectedEvent = await withPreparedSelectedEventPreview(selectedEventDetails ?? selectedEvent);
2778
- return {
2989
+ const resolvedSelectedEvent = await withPreparedSelectedEventPreview(mergeSelectedEventDetails(selectedEvent, selectedEventDetails));
2990
+ return withSelectedEventVisible({
2779
2991
  ...state,
2780
2992
  detailTabs: createDetailTabs(selectedDetailTab, resolvedSelectedEvent),
2993
+ previewTextCursorColumnIndex: null,
2994
+ previewTextCursorRowIndex: null,
2781
2995
  selectedEvent: resolvedSelectedEvent,
2782
2996
  selectedEventId: selectedEvent.eventId,
2783
2997
  selectedEventIndex
2784
- };
2998
+ });
2785
2999
  };
2786
3000
 
2787
3001
  const focusIndex = async (state, index) => {
@@ -2879,35 +3093,33 @@ const show2 = async (uid, menuId, x, y, args) => {
2879
3093
  await showContextMenu2(uid, menuId, x, y, args);
2880
3094
  };
2881
3095
 
2882
- const devtoolsTableHeaderHeight = 24;
2883
- const devtoolsTableRowHeight = 24;
2884
-
2885
- const devtoolsRootGap = 4;
2886
- const devtoolsTopHeight = 28;
2887
- const devtoolsTimelineHeight = 88;
2888
- const getTableBodyY = (state, hasTimeline) => {
2889
- return state.y + viewPadding + devtoolsTopHeight + devtoolsRootGap + (hasTimeline ? devtoolsTimelineHeight : 0) + devtoolsTableHeaderHeight;
2890
- };
2891
-
2892
3096
  const getTableBodyEventIndex = (state, eventX, eventY) => {
2893
- if (!state.useDevtoolsLayout) {
3097
+ const {
3098
+ tableMaxLineY,
3099
+ tableMinLineY,
3100
+ tableWidth,
3101
+ useDevtoolsLayout,
3102
+ width,
3103
+ x
3104
+ } = state;
3105
+ if (!useDevtoolsLayout) {
2894
3106
  return -1;
2895
3107
  }
2896
3108
  const currentEvents = getCurrentEvents$1(state);
2897
3109
  if (currentEvents.length === 0) {
2898
3110
  return -1;
2899
3111
  }
2900
- const tableX = state.x + leftPadding;
2901
- const tableWidth = clampTableWidth(state.width, state.tableWidth);
3112
+ const tableX = x + leftPadding;
3113
+ const tableWidthNew = clampTableWidth(width, tableWidth);
2902
3114
  const hasTimeline = currentEvents.length > 0;
2903
3115
  const tableBodyY = getTableBodyY(state, hasTimeline);
2904
3116
  const relativeX = eventX - tableX;
2905
3117
  const relativeY = eventY - tableBodyY;
2906
- if (relativeX < 0 || relativeX >= tableWidth || relativeY < 0) {
3118
+ if (relativeX < 0 || relativeX >= tableWidthNew || relativeY < 0) {
2907
3119
  return -1;
2908
3120
  }
2909
- const eventIndex = Math.floor(relativeY / devtoolsTableRowHeight);
2910
- if (eventIndex < 0 || eventIndex >= currentEvents.length) {
3121
+ const eventIndex = tableMinLineY + Math.floor(relativeY / devtoolsTableRowHeight);
3122
+ if (eventIndex < tableMinLineY || eventIndex >= tableMaxLineY || eventIndex >= currentEvents.length) {
2911
3123
  return -1;
2912
3124
  }
2913
3125
  return eventIndex;
@@ -3120,6 +3332,8 @@ const restoreSelectedEvent = async state => {
3120
3332
  if (state.selectedEventId === null) {
3121
3333
  return {
3122
3334
  ...state,
3335
+ previewTextCursorColumnIndex: null,
3336
+ previewTextCursorRowIndex: null,
3123
3337
  selectedEvent: null,
3124
3338
  selectedEventIndex: null
3125
3339
  };
@@ -3129,6 +3343,8 @@ const restoreSelectedEvent = async state => {
3129
3343
  if (selectedEventIndex === -1) {
3130
3344
  return {
3131
3345
  ...state,
3346
+ previewTextCursorColumnIndex: null,
3347
+ previewTextCursorRowIndex: null,
3132
3348
  selectedEvent: null,
3133
3349
  selectedEventId: null,
3134
3350
  selectedEventIndex: null
@@ -3138,15 +3354,19 @@ const restoreSelectedEvent = async state => {
3138
3354
  if (!selectedEvent || typeof selectedEvent.eventId !== 'number') {
3139
3355
  return {
3140
3356
  ...state,
3357
+ previewTextCursorColumnIndex: null,
3358
+ previewTextCursorRowIndex: null,
3141
3359
  selectedEvent: null,
3142
3360
  selectedEventId: null,
3143
3361
  selectedEventIndex: null
3144
3362
  };
3145
3363
  }
3146
3364
  const selectedEventDetails = await loadEventsDependencies.loadSelectedEvent(state.databaseName, state.dataBaseVersion, state.eventStoreName, state.sessionId, state.sessionIdIndexName, selectedEvent.eventId, selectedEvent.type);
3147
- const resolvedSelectedEvent = selectedEventDetails ? await withPreparedSelectedEventPreview(selectedEventDetails) : null;
3365
+ const resolvedSelectedEvent = await withPreparedSelectedEventPreview(mergeSelectedEventDetails(selectedEvent, selectedEventDetails));
3148
3366
  return {
3149
3367
  ...state,
3368
+ previewTextCursorColumnIndex: null,
3369
+ previewTextCursorRowIndex: null,
3150
3370
  selectedEvent: resolvedSelectedEvent,
3151
3371
  selectedEventId: selectedEvent.eventId,
3152
3372
  selectedEventIndex
@@ -3162,7 +3382,7 @@ const loadEventsForSessionId = async (state, sessionId) => {
3162
3382
  } = state;
3163
3383
  const result = await loadEventsDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
3164
3384
  if (result.type === 'error') {
3165
- return getStateWithTimelineInfo({
3385
+ return applyVirtualTableState(getStateWithTimelineInfo({
3166
3386
  ...state,
3167
3387
  errorMessage: getFailedToLoadMessage(sessionId, result.error),
3168
3388
  events: [],
@@ -3171,13 +3391,13 @@ const loadEventsForSessionId = async (state, sessionId) => {
3171
3391
  selectedEventId: null,
3172
3392
  selectedEventIndex: null,
3173
3393
  sessionId
3174
- });
3394
+ }));
3175
3395
  }
3176
3396
  const {
3177
3397
  events
3178
3398
  } = result;
3179
3399
  if (events.length === 0) {
3180
- return getStateWithTimelineInfo({
3400
+ return applyVirtualTableState(getStateWithTimelineInfo({
3181
3401
  ...state,
3182
3402
  errorMessage: getSessionNotFoundMessage(sessionId),
3183
3403
  events: [],
@@ -3186,7 +3406,7 @@ const loadEventsForSessionId = async (state, sessionId) => {
3186
3406
  selectedEventId: null,
3187
3407
  selectedEventIndex: null,
3188
3408
  sessionId
3189
- });
3409
+ }));
3190
3410
  }
3191
3411
  const nextState = getStateWithTimelineInfo({
3192
3412
  ...state,
@@ -3195,7 +3415,8 @@ const loadEventsForSessionId = async (state, sessionId) => {
3195
3415
  initial: false,
3196
3416
  sessionId
3197
3417
  });
3198
- return restoreSelectedEvent(nextState);
3418
+ const restoredState = await restoreSelectedEvent(nextState);
3419
+ return withSelectedEventVisible(restoredState);
3199
3420
  };
3200
3421
 
3201
3422
  const loadEventsFromUri = async state => {
@@ -3228,6 +3449,8 @@ const handleClickRefresh = async state => {
3228
3449
  const handleCloseDetails = state => {
3229
3450
  return {
3230
3451
  ...state,
3452
+ previewTextCursorColumnIndex: null,
3453
+ previewTextCursorRowIndex: null,
3231
3454
  selectedEvent: null,
3232
3455
  selectedEventId: null,
3233
3456
  selectedEventIndex: null
@@ -3311,12 +3534,12 @@ const getPreservedSelectedEventIndex$1 = (oldState, newState) => {
3311
3534
  const withPreservedSelection$1 = (state, nextState) => {
3312
3535
  const nextStateWithTimelineInfo = getStateWithTimelineInfo(nextState);
3313
3536
  const selectedEventIndex = getPreservedSelectedEventIndex$1(state, nextStateWithTimelineInfo);
3314
- return {
3537
+ return withSelectedEventVisible({
3315
3538
  ...nextStateWithTimelineInfo,
3316
3539
  selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
3317
3540
  selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
3318
3541
  selectedEventIndex
3319
- };
3542
+ });
3320
3543
  };
3321
3544
 
3322
3545
  const handleEventCategoryFilter = (state, value, ctrlKey = false, metaKey = false) => {
@@ -3423,12 +3646,14 @@ const parseSelectedEventIndex = value => {
3423
3646
  const withPreservedSelection = (state, nextState) => {
3424
3647
  const nextStateWithTimelineInfo = getStateWithTimelineInfo(nextState);
3425
3648
  const selectedEventIndex = getPreservedSelectedEventIndex(state, nextStateWithTimelineInfo);
3426
- return {
3649
+ return withSelectedEventVisible({
3427
3650
  ...nextStateWithTimelineInfo,
3651
+ previewTextCursorColumnIndex: selectedEventIndex === null ? null : state.previewTextCursorColumnIndex,
3652
+ previewTextCursorRowIndex: selectedEventIndex === null ? null : state.previewTextCursorRowIndex,
3428
3653
  selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
3429
3654
  selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
3430
3655
  selectedEventIndex
3431
- };
3656
+ });
3432
3657
  };
3433
3658
  const handleInput = (state, name, value, checked) => {
3434
3659
  if (name === Filter) {
@@ -3473,22 +3698,26 @@ const handleInput = (state, name, value, checked) => {
3473
3698
  if (name === UseDevtoolsLayout) {
3474
3699
  const useDevtoolsLayout = getBoolean(checked);
3475
3700
  const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex(state) : null;
3476
- return {
3701
+ return applyVirtualTableState({
3477
3702
  ...state,
3703
+ previewTextCursorColumnIndex: useDevtoolsLayout && selectedEventIndex !== null ? state.previewTextCursorColumnIndex : null,
3704
+ previewTextCursorRowIndex: useDevtoolsLayout && selectedEventIndex !== null ? state.previewTextCursorRowIndex : null,
3478
3705
  selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
3479
3706
  selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
3480
3707
  selectedEventIndex,
3481
3708
  useDevtoolsLayout
3482
- };
3709
+ });
3483
3710
  }
3484
3711
  if (name === SelectedEventIndex) {
3485
3712
  const selectedEventIndex = parseSelectedEventIndex(value);
3486
- return {
3713
+ return withSelectedEventVisible({
3487
3714
  ...state,
3715
+ previewTextCursorColumnIndex: selectedEventIndex === null ? null : state.previewTextCursorColumnIndex,
3716
+ previewTextCursorRowIndex: selectedEventIndex === null ? null : state.previewTextCursorRowIndex,
3488
3717
  selectedEvent: selectedEventIndex === null ? null : state.selectedEvent,
3489
3718
  selectedEventId: selectedEventIndex === null ? null : state.selectedEventId,
3490
3719
  selectedEventIndex
3491
- };
3720
+ });
3492
3721
  }
3493
3722
  if (name === TimelineStartSeconds) {
3494
3723
  const nextState = {
@@ -3512,12 +3741,14 @@ const handleInput = (state, name, value, checked) => {
3512
3741
  return withPreservedSelection(state, nextState);
3513
3742
  }
3514
3743
  if (name === CloseDetails) {
3515
- return {
3744
+ return applyVirtualTableState({
3516
3745
  ...state,
3746
+ previewTextCursorColumnIndex: null,
3747
+ previewTextCursorRowIndex: null,
3517
3748
  selectedEvent: null,
3518
3749
  selectedEventId: null,
3519
3750
  selectedEventIndex: null
3520
- };
3751
+ });
3521
3752
  }
3522
3753
  if (name === DetailTab) {
3523
3754
  if (!isDetailTab(value)) {
@@ -3535,1382 +3766,1607 @@ const handleInput = (state, name, value, checked) => {
3535
3766
  return state;
3536
3767
  };
3537
3768
 
3538
- const handleSashPointerDown = (state, eventX, eventY) => {
3539
- if (state.sashPointerActive) {
3540
- return state;
3769
+ const getListFilesPreviewEvent = (event, name) => {
3770
+ if (name !== 'list_files') {
3771
+ return undefined;
3541
3772
  }
3542
- return {
3543
- ...state,
3544
- sashPointerActive: true
3545
- };
3546
- };
3547
-
3548
- const handleSashPointerMove = (state, eventX, eventY) => {
3549
- if (!state.sashPointerActive) {
3550
- return state;
3773
+ const {
3774
+ result
3775
+ } = event;
3776
+ if (typeof result !== 'object' || result === null) {
3777
+ return undefined;
3551
3778
  }
3552
- return {
3553
- ...state,
3554
- tableWidth: getTableWidthFromClientX(state.x, state.width, eventX)
3555
- };
3779
+ const {
3780
+ entries
3781
+ } = result;
3782
+ if (entries !== undefined) {
3783
+ return entries;
3784
+ }
3785
+ return result;
3556
3786
  };
3557
3787
 
3558
- const handleSashPointerUp = (state, eventX, eventY) => {
3559
- if (!state.sashPointerActive) {
3560
- return state;
3788
+ const getPreviewName = event => {
3789
+ if (typeof event.name === 'string' && event.name) {
3790
+ return event.name;
3561
3791
  }
3562
- return {
3563
- ...state,
3564
- sashPointerActive: false
3565
- };
3792
+ if (typeof event.toolName === 'string' && event.toolName) {
3793
+ return event.toolName;
3794
+ }
3795
+ return undefined;
3566
3796
  };
3567
3797
 
3568
- const FocusChatDebugTable = 221_139;
3569
-
3570
- const handleTableFocus = state => {
3571
- return {
3572
- ...state,
3573
- focus: FocusChatDebugTable
3574
- };
3798
+ const hasOwn = (event, key) => {
3799
+ return Object.hasOwn(event, key);
3575
3800
  };
3576
3801
 
3577
- const handleTableHeaderClick = (state, value) => {
3578
- if (!isTableColumn(value)) {
3579
- return state;
3802
+ const shouldIncludeArguments = (event, name) => {
3803
+ if (!hasOwn(event, 'arguments')) {
3804
+ return false;
3580
3805
  }
3581
- const sortDescending = state.sortColumn === value ? !state.sortDescending : false;
3582
- const nextState = {
3583
- ...state,
3584
- sortColumn: value,
3585
- sortDescending
3586
- };
3587
- return withPreservedSelection$1(state, nextState);
3588
- };
3589
-
3590
- const getTableResizerId = name => {
3591
- switch (name) {
3592
- case 'ResizerOne':
3593
- return 1;
3594
- case 'ResizerTwo':
3595
- return 2;
3596
- default:
3597
- return 0;
3806
+ if (name === 'getWorkspaceUri') {
3807
+ return false;
3598
3808
  }
3599
- };
3600
- const handleTableResizerPointerDown = (state, name, clientX) => {
3601
- return {
3602
- ...state,
3603
- tableResizerDownId: getTableResizerId(name)
3604
- };
3809
+ return true;
3605
3810
  };
3606
3811
 
3607
- const handleTableResizerPointerMove = (state, clientX) => {
3608
- if (!state.tableResizerDownId) {
3609
- return state;
3812
+ const getPayloadEvent = event => {
3813
+ const {
3814
+ requestEvent
3815
+ } = event;
3816
+ if (requestEvent && typeof requestEvent === 'object' && typeof requestEvent.type === 'string') {
3817
+ const mergedRequestEvent = requestEvent;
3818
+ if (mergedRequestEvent.body !== undefined) {
3819
+ return mergedRequestEvent.body;
3820
+ }
3821
+ if (mergedRequestEvent.value !== undefined) {
3822
+ return mergedRequestEvent.value;
3823
+ }
3824
+ if (hasOwn(mergedRequestEvent, 'arguments')) {
3825
+ return mergedRequestEvent.arguments;
3826
+ }
3827
+ return requestEvent;
3610
3828
  }
3611
- return {
3612
- ...state,
3613
- tableColumnWidths: getResizedTableColumnWidths(state.width, state.tableWidth, getVisibleTableColumns(state.tableColumns), state.tableColumnWidths, state.x, clientX, state.tableResizerDownId)
3614
- };
3615
- };
3616
-
3617
- const handleTableResizerPointerUp = state => {
3618
- if (!state.tableResizerDownId) {
3619
- return state;
3829
+ const name = getPreviewName(event);
3830
+ if (name === 'list_files' && hasOwn(event, 'arguments')) {
3831
+ return event.arguments;
3620
3832
  }
3621
- return {
3622
- ...state,
3623
- tableResizerDownId: 0
3833
+ const payloadEvent = {
3834
+ ...(name === undefined ? {} : {
3835
+ name
3836
+ }),
3837
+ ...(shouldIncludeArguments(event, name) ? {
3838
+ arguments: event.arguments
3839
+ } : {}),
3840
+ ...(hasOwn(event, 'result') ? {
3841
+ result: event.result
3842
+ } : {})
3624
3843
  };
3625
- };
3626
-
3627
- const handleTableRowCopy = async (state, eventIndex) => {
3628
- const currentEvents = getCurrentEvents$1(state);
3629
- const event = currentEvents[eventIndex];
3630
- if (!event) {
3631
- return state;
3844
+ if (Object.keys(payloadEvent).length > 0) {
3845
+ return payloadEvent;
3632
3846
  }
3633
- const text = JSON.stringify(event, null, 2);
3634
- await writeClipBoardText(text);
3635
- return state;
3847
+ return event;
3636
3848
  };
3637
3849
 
3638
- const handleTimelineContextMenu = state => {
3639
- return state;
3850
+ const isChatMessageAddedEvent = event => {
3851
+ return event.type === 'chat-message-added';
3640
3852
  };
3641
3853
 
3642
- const clearTimelineSelectionState = state => {
3643
- return getStateWithTimelineInfo({
3644
- ...state,
3645
- timelineSelectionActive: false,
3646
- timelineSelectionAnchorSeconds: '',
3647
- timelineSelectionFocusSeconds: ''
3648
- });
3854
+ const isChatMessageUpdatedEvent = event => {
3855
+ return event.type === 'chat-message-updated';
3649
3856
  };
3650
3857
 
3651
- const parseTimelineRangePreset = value => {
3652
- if (!value) {
3653
- return {
3654
- timelineEndSeconds: '',
3655
- timelineStartSeconds: ''
3656
- };
3858
+ const getResponseContentText = content => {
3859
+ if (!content || typeof content !== 'object') {
3860
+ return undefined;
3657
3861
  }
3658
- const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
3659
- return {
3660
- timelineEndSeconds,
3661
- timelineStartSeconds
3662
- };
3663
- };
3664
- const handleTimelineStartSeconds = (state, value) => {
3665
- const nextState = {
3666
- ...state,
3667
- timelineStartSeconds: value
3668
- };
3669
- return withPreservedSelection$1(state, nextState);
3862
+ if (Array.isArray(content)) {
3863
+ const [firstContentItem] = content;
3864
+ if (!firstContentItem || typeof firstContentItem !== 'object') {
3865
+ return undefined;
3866
+ }
3867
+ const {
3868
+ text
3869
+ } = firstContentItem;
3870
+ return typeof text === 'string' ? text : undefined;
3871
+ }
3872
+ const {
3873
+ text
3874
+ } = content;
3875
+ return typeof text === 'string' ? text : undefined;
3670
3876
  };
3671
- const handleTimelineEndSeconds = (state, value) => {
3672
- const nextState = {
3673
- ...state,
3674
- timelineEndSeconds: value
3675
- };
3676
- return withPreservedSelection$1(state, nextState);
3877
+ const getSseResponseCompletedPreviewText = event => {
3878
+ if (event.type !== 'sse-response-completed') {
3879
+ return undefined;
3880
+ }
3881
+ const {
3882
+ value
3883
+ } = event;
3884
+ if (!value || typeof value !== 'object') {
3885
+ return undefined;
3886
+ }
3887
+ const {
3888
+ response
3889
+ } = value;
3890
+ if (!response || typeof response !== 'object') {
3891
+ return undefined;
3892
+ }
3893
+ const {
3894
+ output
3895
+ } = response;
3896
+ if (!Array.isArray(output) || output.length === 0) {
3897
+ return undefined;
3898
+ }
3899
+ const [firstOutput] = output;
3900
+ if (!firstOutput || typeof firstOutput !== 'object') {
3901
+ return undefined;
3902
+ }
3903
+ const {
3904
+ content
3905
+ } = firstOutput;
3906
+ return getResponseContentText(content);
3677
3907
  };
3678
- const handleTimelineRangePreset = (state, value) => {
3679
- const nextState = {
3680
- ...state,
3681
- ...parseTimelineRangePreset(value)
3682
- };
3683
- return withPreservedSelection$1(state, nextState);
3908
+ const getPreviewMessageText = event => {
3909
+ if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
3910
+ return event.text;
3911
+ }
3912
+ const sseResponseCompletedPreviewText = getSseResponseCompletedPreviewText(event);
3913
+ if (sseResponseCompletedPreviewText !== undefined) {
3914
+ return sseResponseCompletedPreviewText;
3915
+ }
3916
+ if (!isChatMessageAddedEvent(event)) {
3917
+ return undefined;
3918
+ }
3919
+ const {
3920
+ message
3921
+ } = event;
3922
+ if (!message || typeof message !== 'object') {
3923
+ return undefined;
3924
+ }
3925
+ if (!Object.hasOwn(message, 'text')) {
3926
+ return undefined;
3927
+ }
3928
+ const {
3929
+ text
3930
+ } = message;
3931
+ if (typeof text !== 'string') {
3932
+ return undefined;
3933
+ }
3934
+ return text;
3684
3935
  };
3685
3936
 
3686
- const handleTimelineDoubleClick = state => {
3687
- const nextState = handleTimelineRangePreset(state, '');
3688
- return clearTimelineSelectionState(nextState);
3937
+ const getReadFilePreviewText = (event, name) => {
3938
+ if (name !== 'read_file') {
3939
+ return undefined;
3940
+ }
3941
+ const {
3942
+ result
3943
+ } = event;
3944
+ if (typeof result !== 'string') {
3945
+ return undefined;
3946
+ }
3947
+ return result;
3689
3948
  };
3690
3949
 
3691
- const trailingZeroFractionRegex = /\.0+$/;
3692
- const trailingFractionZeroRegex = /(\.\d*?)0+$/;
3693
- const formatTimelinePresetValue = value => {
3694
- return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
3950
+ const getWriteFilePreviewText = (event, name) => {
3951
+ if (name !== 'write_file') {
3952
+ return undefined;
3953
+ }
3954
+ const {
3955
+ arguments: toolArguments
3956
+ } = event;
3957
+ if (typeof toolArguments !== 'object' || toolArguments === null || !Object.hasOwn(toolArguments, 'content')) {
3958
+ return undefined;
3959
+ }
3960
+ const {
3961
+ content
3962
+ } = toolArguments;
3963
+ if (typeof content !== 'string') {
3964
+ return undefined;
3965
+ }
3966
+ return content;
3695
3967
  };
3696
3968
 
3697
- const getTimelineEventX = (state, eventX) => {
3698
- return state.x + eventX;
3969
+ const getPreviewEvent = event => {
3970
+ const selectedEventPreview = getSelectedEventPreview(event);
3971
+ if (selectedEventPreview !== undefined) {
3972
+ return selectedEventPreview;
3973
+ }
3974
+ const previewMessageText = getPreviewMessageText(event);
3975
+ if (previewMessageText !== undefined) {
3976
+ return previewMessageText;
3977
+ }
3978
+ const name = getPreviewName(event);
3979
+ const writeFilePreviewText = getWriteFilePreviewText(event, name);
3980
+ if (writeFilePreviewText !== undefined) {
3981
+ return writeFilePreviewText;
3982
+ }
3983
+ const readFilePreviewText = getReadFilePreviewText(event, name);
3984
+ if (readFilePreviewText !== undefined) {
3985
+ return readFilePreviewText;
3986
+ }
3987
+ const listFilesPreviewEvent = getListFilesPreviewEvent(event, name);
3988
+ if (listFilesPreviewEvent !== undefined) {
3989
+ return listFilesPreviewEvent;
3990
+ }
3991
+ return getPayloadEvent(event);
3699
3992
  };
3700
3993
 
3701
- const getTimelineLeft = state => {
3702
- return state.x + viewPadding + timelineHorizontalPadding;
3994
+ const previewTextRowHeight = 20;
3995
+ const defaultPreviewTextColumnWidth = 9;
3996
+ const clamp = (value, min, max) => {
3997
+ return Math.min(Math.max(value, min), max);
3703
3998
  };
3704
- const getTimelineWidth = state => {
3705
- return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
3706
- };
3707
-
3708
- const getTimelineDurationSeconds = events => {
3709
- const eventsWithTime = getEventsWithTime(events);
3710
- if (eventsWithTime.length === 0) {
3711
- return 0;
3712
- }
3713
- const baseTime = eventsWithTime[0].time;
3714
- const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
3715
- return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
3999
+ const getPreviewTextCursorFromPoint = (value, x, y) => {
4000
+ const lines = value.split('\n');
4001
+ const rowIndex = clamp(Math.floor(Math.max(y, 0) / previewTextRowHeight), 0, Math.max(lines.length - 1, 0));
4002
+ const line = lines[rowIndex] || '';
4003
+ const columnIndex = clamp(Math.floor(Math.max(x, 0) / defaultPreviewTextColumnWidth), 0, line.length);
4004
+ return {
4005
+ columnIndex,
4006
+ rowIndex
4007
+ };
3716
4008
  };
3717
-
3718
- const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
3719
- if (timelineWidth <= 0) {
3720
- return undefined;
3721
- }
3722
- const durationSeconds = getTimelineDurationSeconds(events);
3723
- const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
3724
- const ratio = relativeX / timelineWidth;
3725
- return formatTimelinePresetValue(durationSeconds * ratio);
4009
+ const getPreviewTextCursorStyle = cursor => {
4010
+ return `height: ${previewTextRowHeight}px; left: ${cursor.columnIndex * defaultPreviewTextColumnWidth}px; top: ${cursor.rowIndex * previewTextRowHeight}px; width: 0px;`;
3726
4011
  };
3727
4012
 
3728
- const Start = 'TimelineSelectionStartHandle';
3729
- const End = 'TimelineSelectionEndHandle';
3730
-
3731
- const getResizeState = (state, name) => {
3732
- if (state.timelineInfo.startSeconds === null || state.timelineInfo.endSeconds === null) {
3733
- return undefined;
3734
- }
3735
- if (name === Start) {
3736
- return getStateWithTimelineInfo({
3737
- ...state,
3738
- timelineSelectionActive: true,
3739
- timelineSelectionAnchorSeconds: formatTimelinePresetValue(state.timelineInfo.endSeconds),
3740
- timelineSelectionFocusSeconds: formatTimelinePresetValue(state.timelineInfo.startSeconds)
3741
- });
4013
+ const hasNumberedTextPreview = (state, previewEvent) => {
4014
+ if (typeof previewEvent !== 'string') {
4015
+ return false;
3742
4016
  }
3743
- if (name === End) {
3744
- return getStateWithTimelineInfo({
3745
- ...state,
3746
- timelineSelectionActive: true,
3747
- timelineSelectionAnchorSeconds: formatTimelinePresetValue(state.timelineInfo.startSeconds),
3748
- timelineSelectionFocusSeconds: formatTimelinePresetValue(state.timelineInfo.endSeconds)
3749
- });
4017
+ if (previewEvent === ImageCouldNotBeLoaded) {
4018
+ return false;
3750
4019
  }
3751
- return undefined;
4020
+ return !state.selectedEvent || !isChatMessageUpdatedEvent(state.selectedEvent);
3752
4021
  };
3753
- const handleTimelinePointerDown = (state, name, eventX) => {
3754
- const resizeState = getResizeState(state, name);
3755
- if (resizeState) {
3756
- return resizeState;
4022
+ const handlePreviewTextPointerDown = (state, x, y) => {
4023
+ if (!state.selectedEvent) {
4024
+ return state;
3757
4025
  }
3758
- const timelineLeft = getTimelineLeft(state);
3759
- const timelineWidth = getTimelineWidth(state);
3760
- const clientX = getTimelineEventX(state, eventX);
3761
- const seconds = getTimelineSecondsFromClientX(state.timelineEvents, clientX, timelineLeft, timelineWidth);
3762
- if (seconds === undefined) {
4026
+ const previewEvent = getPreviewEvent(state.selectedEvent);
4027
+ if (!hasNumberedTextPreview(state, previewEvent)) {
3763
4028
  return state;
3764
4029
  }
3765
- const timelineHoverPercent = getSelectionPercent(Number.parseFloat(seconds), state.timelineInfo.durationSeconds);
3766
- return getStateWithTimelineInfo({
4030
+ const cursor = getPreviewTextCursorFromPoint(previewEvent, x, y);
4031
+ if (state.previewTextCursorColumnIndex === cursor.columnIndex && state.previewTextCursorRowIndex === cursor.rowIndex) {
4032
+ return state;
4033
+ }
4034
+ return {
3767
4035
  ...state,
3768
- timelineHoverPercent,
3769
- timelineHoverSeconds: seconds,
3770
- timelineSelectionActive: true,
3771
- timelineSelectionAnchorSeconds: seconds,
3772
- timelineSelectionFocusSeconds: seconds
3773
- });
4036
+ previewTextCursorColumnIndex: cursor.columnIndex,
4037
+ previewTextCursorRowIndex: cursor.rowIndex
4038
+ };
3774
4039
  };
3775
4040
 
3776
- const handleTimelinePointerLeave = state => {
3777
- if (state.timelineHoverPercent === null && state.timelineHoverSeconds === '') {
4041
+ const handleSashPointerDown = (state, eventX, eventY) => {
4042
+ if (state.sashPointerActive) {
3778
4043
  return state;
3779
4044
  }
3780
4045
  return {
3781
4046
  ...state,
3782
- timelineHoverPercent: null,
3783
- timelineHoverSeconds: ''
4047
+ sashPointerActive: true
3784
4048
  };
3785
4049
  };
3786
4050
 
3787
- const handleTimelinePointerMove = (state, eventX) => {
3788
- const timelineLeft = getTimelineLeft(state);
3789
- const timelineWidth = getTimelineWidth(state);
3790
- const clientX = getTimelineEventX(state, eventX);
3791
- const seconds = getTimelineSecondsFromClientX(state.timelineEvents, clientX, timelineLeft, timelineWidth);
3792
- if (seconds === undefined) {
4051
+ const handleSashPointerMove = (state, eventX, eventY) => {
4052
+ if (!state.sashPointerActive) {
3793
4053
  return state;
3794
4054
  }
3795
- const timelineHoverPercent = getSelectionPercent(Number.parseFloat(seconds), state.timelineInfo.durationSeconds);
3796
- if (!state.timelineSelectionActive) {
3797
- return {
3798
- ...state,
3799
- timelineHoverPercent,
3800
- timelineHoverSeconds: seconds
3801
- };
3802
- }
3803
- return getStateWithTimelineInfo({
4055
+ return {
3804
4056
  ...state,
3805
- timelineHoverPercent,
3806
- timelineHoverSeconds: seconds,
3807
- timelineSelectionFocusSeconds: seconds
3808
- });
4057
+ tableWidth: getTableWidthFromClientX(state.x, state.width, eventX)
4058
+ };
3809
4059
  };
3810
4060
 
3811
- const handleTimelinePointerUp = (state, eventX) => {
3812
- if (!state.timelineSelectionActive) {
4061
+ const handleSashPointerUp = (state, eventX, eventY) => {
4062
+ if (!state.sashPointerActive) {
3813
4063
  return state;
3814
4064
  }
3815
- const timelineLeft = getTimelineLeft(state);
3816
- const timelineWidth = getTimelineWidth(state);
3817
- const clientX = getTimelineEventX(state, eventX);
3818
- const focusSeconds = getTimelineSecondsFromClientX(state.timelineEvents, clientX, timelineLeft, timelineWidth);
3819
- if (focusSeconds === undefined) {
3820
- return clearTimelineSelectionState(state);
3821
- }
3822
- const timelineHoverPercent = getSelectionPercent(Number.parseFloat(focusSeconds), state.timelineInfo.durationSeconds);
3823
- const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
3824
- const focus = Number.parseFloat(focusSeconds);
3825
- const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
3826
- const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
3827
- const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
3828
- return clearTimelineSelectionState({
3829
- ...nextState,
3830
- timelineHoverPercent,
3831
- timelineHoverSeconds: focusSeconds
3832
- });
4065
+ return {
4066
+ ...state,
4067
+ sashPointerActive: false
4068
+ };
3833
4069
  };
3834
4070
 
3835
- const setUseDevtoolsLayout = (state, checked) => {
3836
- const useDevtoolsLayout = getBoolean(checked);
3837
- const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
4071
+ const FocusChatDebugTable = 221_139;
4072
+
4073
+ const handleTableFocus = state => {
3838
4074
  return {
3839
4075
  ...state,
3840
- selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
3841
- selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
3842
- selectedEventIndex,
3843
- useDevtoolsLayout
4076
+ focus: FocusChatDebugTable
3844
4077
  };
3845
4078
  };
3846
4079
 
3847
- const handleShowEventStreamFinishedEvents = (state, checked) => {
4080
+ const handleTableHeaderClick = (state, value) => {
4081
+ const {
4082
+ sortColumn,
4083
+ sortDescending
4084
+ } = state;
4085
+ if (!isTableColumn(value)) {
4086
+ return state;
4087
+ }
4088
+ const newSortDescending = sortColumn === value ? !sortDescending : false;
3848
4089
  const nextState = {
3849
4090
  ...state,
3850
- showEventStreamFinishedEvents: getBoolean(checked)
4091
+ sortColumn: value,
4092
+ sortDescending: newSortDescending
3851
4093
  };
3852
4094
  return withPreservedSelection$1(state, nextState);
3853
4095
  };
3854
- const handleShowInputEvents = (state, checked) => {
3855
- const nextState = {
4096
+
4097
+ const getTableResizerId = name => {
4098
+ switch (name) {
4099
+ case 'ResizerOne':
4100
+ return 1;
4101
+ case 'ResizerTwo':
4102
+ return 2;
4103
+ default:
4104
+ return 0;
4105
+ }
4106
+ };
4107
+ const handleTableResizerPointerDown = (state, name, clientX) => {
4108
+ return {
3856
4109
  ...state,
3857
- showInputEvents: getBoolean(checked)
4110
+ tableResizerDownId: getTableResizerId(name)
3858
4111
  };
3859
- return withPreservedSelection$1(state, nextState);
3860
4112
  };
3861
- const handleShowResponsePartEvents = (state, checked) => {
3862
- const nextState = {
4113
+
4114
+ const handleTableResizerPointerMove = (state, clientX) => {
4115
+ if (!state.tableResizerDownId) {
4116
+ return state;
4117
+ }
4118
+ return {
3863
4119
  ...state,
3864
- showResponsePartEvents: getBoolean(checked)
4120
+ tableColumnWidths: getResizedTableColumnWidths(state.width, state.tableWidth, getVisibleTableColumns(state.tableColumns), state.tableColumnWidths, state.x, clientX, state.tableResizerDownId)
3865
4121
  };
3866
- return withPreservedSelection$1(state, nextState);
3867
4122
  };
3868
4123
 
3869
- const loadContent = async (state, savedState) => {
3870
- await getPreference('chatDebug.autoRefresh');
3871
- const nextState = await loadEventsFromUri(restoreSavedState(state, savedState));
4124
+ const handleTableResizerPointerUp = state => {
4125
+ if (!state.tableResizerDownId) {
4126
+ return state;
4127
+ }
3872
4128
  return {
3873
- ...nextState,
3874
- categoryFilters: createCategoryFilters(getSelectedEventCategoryFilters(nextState.categoryFilters)),
3875
- detailTabs: createDetailTabs(getSelectedDetailTab(nextState.detailTabs), nextState.selectedEvent),
3876
- tableColumns: createTableColumns()
4129
+ ...state,
4130
+ tableResizerDownId: 0
3877
4131
  };
3878
4132
  };
3879
4133
 
3880
- // cspell:ignore liga calt
3881
-
3882
- const getCss = state => {
3883
- const hasSelectedEvent = !!state.selectedEvent;
3884
- const tableWidth = hasSelectedEvent ? clampTableWidth(state.width, state.tableWidth) : getMainWidth(state.width);
3885
- const detailsWidth = hasSelectedEvent ? getDetailsWidth(state.width, state.tableWidth) : 0;
3886
- const topSize = state.width >= state.largeBreakpoint ? 30 : state.width >= state.mediumBreakpoint ? 60 : 60;
3887
- const tableColumnLayout = getTableColumnLayout(tableWidth, getVisibleTableColumns(state.tableColumns), state.tableColumnWidths);
3888
- const [tableColZeroWidth = 0, tableColOneWidth = 0, tableColTwoWidth = 0] = tableColumnLayout.visibleColumnWidths;
3889
- const resizerOneLeft = tableColumnLayout.resizerLefts[0] ?? 0;
3890
- const resizerTwoLeft = tableColumnLayout.resizerLefts[1] ?? 0;
3891
- const {
3892
- selectionEndPercent,
3893
- selectionStartPercent
3894
- } = state.timelineInfo;
3895
- return `
3896
- .ChatDebugView {
3897
- --ChatDebugViewTableHeaderHeight: ${devtoolsTableHeaderHeight}px;
3898
- --ChatDebugViewTableColZeroWidth: ${tableColZeroWidth}px;
3899
- --ChatDebugViewTableColOneWidth: ${tableColOneWidth}px;
3900
- --ChatDebugViewTableColTwoWidth: ${tableColTwoWidth}px;
3901
- --ChatDebugViewDetailsWidth: ${detailsWidth}px;
3902
- --ChatDebugViewDurationColumnWidth: ${state.tableColumnWidths.duration}px;
3903
- --ChatDebugViewTableRowHeight: ${devtoolsTableRowHeight}px;
3904
- --ResizerOneLeft: ${resizerOneLeft}px;
3905
- --ResizerTwoLeft: ${resizerTwoLeft}px;
3906
- --ChatDebugViewSashWidth: ${sashWidth}px;
3907
- --ChatDebugViewTableWidth: ${tableWidth}px;
3908
- --ChatDebugViewTimelineCursorGuideLeft: ${state.timelineHoverPercent ?? 0}%;
3909
- --ChatDebugViewTimelineSelectionEndLeft: ${selectionEndPercent ?? 0}%;
3910
- --ChatDebugViewTimelineSelectionStartLeft: ${selectionStartPercent ?? 0}%;
3911
- --ChatDebugViewTopSize: ${topSize}px;
3912
- --ChatDebugViewTypeColumnWidth: ${state.tableColumnWidths.type}px;
3913
- padding: ${viewPadding}px;
3914
- }
3915
-
3916
- `;
4134
+ const handleTableRowCopy = async (state, eventIndex) => {
4135
+ const currentEvents = getCurrentEvents$1(state);
4136
+ const event = currentEvents[eventIndex];
4137
+ if (!event) {
4138
+ return state;
4139
+ }
4140
+ const text = JSON.stringify(event, null, 2);
4141
+ await writeClipBoardText(text);
4142
+ return state;
3917
4143
  };
3918
4144
 
3919
- const renderCss = (oldState, newState) => {
3920
- const css = getCss(newState);
3921
- return [SetCss, newState.uid, css];
4145
+ const getHandleOffsetAndPercent = (tableBodyHeight, scrollBarHeight, relativeY) => {
4146
+ const halfScrollBarHeight = scrollBarHeight / 2;
4147
+ if (relativeY <= halfScrollBarHeight) {
4148
+ return {
4149
+ handleOffset: relativeY,
4150
+ percent: 0
4151
+ };
4152
+ }
4153
+ if (relativeY <= tableBodyHeight - halfScrollBarHeight) {
4154
+ return {
4155
+ handleOffset: halfScrollBarHeight,
4156
+ percent: (relativeY - halfScrollBarHeight) / Math.max(1, tableBodyHeight - scrollBarHeight)
4157
+ };
4158
+ }
4159
+ return {
4160
+ handleOffset: scrollBarHeight - tableBodyHeight + relativeY,
4161
+ percent: 1
4162
+ };
3922
4163
  };
3923
-
3924
- const mergeClassNames = (...classNames) => {
3925
- return classNames.filter(Boolean).join(' ');
4164
+ const handleTableScrollBarPointerDown = (state, eventY) => {
4165
+ const currentEvents = getCurrentEvents$2(state);
4166
+ const tableBodyHeight = getTableBodyHeight(state, currentEvents.length);
4167
+ const scrollBarHeight = getScrollBarHeight(currentEvents.length, tableBodyHeight);
4168
+ if (tableBodyHeight === 0 || scrollBarHeight === 0) {
4169
+ return state;
4170
+ }
4171
+ const relativeY = eventY - getTableBodyY(state, currentEvents.length > 0);
4172
+ const {
4173
+ handleOffset,
4174
+ percent
4175
+ } = getHandleOffsetAndPercent(tableBodyHeight, scrollBarHeight, relativeY);
4176
+ const maxDeltaY = getMaxDeltaY(currentEvents.length, tableBodyHeight);
4177
+ const nextState = setTableDeltaY(state, percent * maxDeltaY);
4178
+ return {
4179
+ ...nextState,
4180
+ tableScrollBarHandleOffset: handleOffset,
4181
+ tableScrollBarPointerActive: true
4182
+ };
3926
4183
  };
3927
4184
 
3928
- const text = data => {
4185
+ const handleTableScrollBarPointerMove = (state, eventY) => {
4186
+ if (!state.tableScrollBarPointerActive) {
4187
+ return state;
4188
+ }
4189
+ const currentEvents = getCurrentEvents$2(state);
4190
+ const tableBodyHeight = getTableBodyHeight(state, currentEvents.length);
4191
+ const scrollBarHeight = getScrollBarHeight(currentEvents.length, tableBodyHeight);
4192
+ if (tableBodyHeight === 0 || scrollBarHeight === 0) {
4193
+ return state;
4194
+ }
4195
+ const relativeY = eventY - getTableBodyY(state, currentEvents.length > 0);
4196
+ const nextHandleTop = Math.max(0, Math.min(tableBodyHeight - scrollBarHeight, relativeY - state.tableScrollBarHandleOffset));
4197
+ const percent = nextHandleTop / Math.max(1, tableBodyHeight - scrollBarHeight);
4198
+ const maxDeltaY = getMaxDeltaY(currentEvents.length, tableBodyHeight);
4199
+ const nextState = setTableDeltaY(state, percent * maxDeltaY);
3929
4200
  return {
3930
- childCount: 0,
3931
- text: data,
3932
- type: Text
4201
+ ...nextState,
4202
+ tableScrollBarPointerActive: true
3933
4203
  };
3934
4204
  };
3935
4205
 
3936
- const SetText = 1;
3937
- const Replace = 2;
3938
- const SetAttribute = 3;
3939
- const RemoveAttribute = 4;
3940
- const Add = 6;
3941
- const NavigateChild = 7;
3942
- const NavigateParent = 8;
3943
- const RemoveChild = 9;
3944
- const NavigateSibling = 10;
3945
- const SetReferenceNodeUid = 11;
4206
+ const handleTableScrollBarPointerUp = state => {
4207
+ if (!state.tableScrollBarPointerActive && state.tableScrollBarHandleOffset === 0) {
4208
+ return state;
4209
+ }
4210
+ return {
4211
+ ...state,
4212
+ tableScrollBarHandleOffset: 0,
4213
+ tableScrollBarPointerActive: false
4214
+ };
4215
+ };
3946
4216
 
3947
- const isKey = key => {
3948
- return key !== 'type' && key !== 'childCount';
4217
+ const handleTableWheel = (state, deltaY) => {
4218
+ return setTableDeltaY(state, state.tableDeltaY + deltaY);
3949
4219
  };
3950
4220
 
3951
- const getKeys = node => {
3952
- const keys = Object.keys(node).filter(isKey);
3953
- return keys;
4221
+ const handleTimelineContextMenu = state => {
4222
+ return state;
3954
4223
  };
3955
4224
 
3956
- const arrayToTree = nodes => {
3957
- const result = [];
3958
- let i = 0;
3959
- while (i < nodes.length) {
3960
- const node = nodes[i];
3961
- const {
3962
- children,
3963
- nodesConsumed
3964
- } = getChildrenWithCount(nodes, i + 1, node.childCount || 0);
3965
- result.push({
3966
- node,
3967
- children
3968
- });
3969
- i += 1 + nodesConsumed;
3970
- }
3971
- return result;
4225
+ const clearTimelineSelectionState = state => {
4226
+ return getStateWithTimelineInfo({
4227
+ ...state,
4228
+ timelineSelectionActive: false,
4229
+ timelineSelectionAnchorSeconds: '',
4230
+ timelineSelectionFocusSeconds: ''
4231
+ });
3972
4232
  };
3973
- const getChildrenWithCount = (nodes, startIndex, childCount) => {
3974
- if (childCount === 0) {
4233
+
4234
+ const parseTimelineRangePreset = value => {
4235
+ if (!value) {
3975
4236
  return {
3976
- children: [],
3977
- nodesConsumed: 0
4237
+ timelineEndSeconds: '',
4238
+ timelineStartSeconds: ''
3978
4239
  };
3979
4240
  }
3980
- const children = [];
3981
- let i = startIndex;
3982
- let remaining = childCount;
3983
- let totalConsumed = 0;
3984
- while (remaining > 0 && i < nodes.length) {
3985
- const node = nodes[i];
3986
- const nodeChildCount = node.childCount || 0;
3987
- const {
3988
- children: nodeChildren,
3989
- nodesConsumed
3990
- } = getChildrenWithCount(nodes, i + 1, nodeChildCount);
3991
- children.push({
3992
- node,
3993
- children: nodeChildren
3994
- });
3995
- const nodeSize = 1 + nodesConsumed;
3996
- i += nodeSize;
3997
- totalConsumed += nodeSize;
3998
- remaining--;
3999
- }
4241
+ const [timelineStartSeconds = '', timelineEndSeconds = ''] = value.split(':', 2);
4000
4242
  return {
4001
- children,
4002
- nodesConsumed: totalConsumed
4243
+ timelineEndSeconds,
4244
+ timelineStartSeconds
4245
+ };
4246
+ };
4247
+ const handleTimelineStartSeconds = (state, value) => {
4248
+ const nextState = {
4249
+ ...state,
4250
+ timelineStartSeconds: value
4251
+ };
4252
+ return withPreservedSelection$1(state, nextState);
4253
+ };
4254
+ const handleTimelineEndSeconds = (state, value) => {
4255
+ const nextState = {
4256
+ ...state,
4257
+ timelineEndSeconds: value
4003
4258
  };
4259
+ return withPreservedSelection$1(state, nextState);
4260
+ };
4261
+ const handleTimelineRangePreset = (state, value) => {
4262
+ const nextState = {
4263
+ ...state,
4264
+ ...parseTimelineRangePreset(value)
4265
+ };
4266
+ return withPreservedSelection$1(state, nextState);
4004
4267
  };
4005
4268
 
4006
- const compareNodes = (oldNode, newNode) => {
4007
- const patches = [];
4008
- // Check if node type changed - return null to signal incompatible nodes
4009
- // (caller should handle this with a Replace operation)
4010
- if (oldNode.type !== newNode.type) {
4011
- return null;
4012
- }
4013
- // Handle reference nodes - special handling for uid changes
4014
- if (oldNode.type === Reference) {
4015
- if (oldNode.uid !== newNode.uid) {
4016
- patches.push({
4017
- type: SetReferenceNodeUid,
4018
- uid: newNode.uid
4019
- });
4020
- }
4021
- return patches;
4022
- }
4023
- // Handle text nodes
4024
- if (oldNode.type === Text && newNode.type === Text) {
4025
- if (oldNode.text !== newNode.text) {
4026
- patches.push({
4027
- type: SetText,
4028
- value: newNode.text
4029
- });
4030
- }
4031
- return patches;
4032
- }
4033
- // Compare attributes
4034
- const oldKeys = getKeys(oldNode);
4035
- const newKeys = getKeys(newNode);
4036
- // Check for attribute changes
4037
- for (const key of newKeys) {
4038
- if (oldNode[key] !== newNode[key]) {
4039
- patches.push({
4040
- type: SetAttribute,
4041
- key,
4042
- value: newNode[key]
4043
- });
4044
- }
4045
- }
4046
- // Check for removed attributes
4047
- for (const key of oldKeys) {
4048
- if (!(key in newNode)) {
4049
- patches.push({
4050
- type: RemoveAttribute,
4051
- key
4052
- });
4053
- }
4269
+ const handleTimelineDoubleClick = state => {
4270
+ const nextState = handleTimelineRangePreset(state, '');
4271
+ return clearTimelineSelectionState(nextState);
4272
+ };
4273
+
4274
+ const trailingZeroFractionRegex = /\.0+$/;
4275
+ const trailingFractionZeroRegex = /(\.\d*?)0+$/;
4276
+ const formatTimelinePresetValue = value => {
4277
+ return value.toFixed(3).replace(trailingZeroFractionRegex, '').replace(trailingFractionZeroRegex, '$1');
4278
+ };
4279
+
4280
+ const getTimelineEventX = eventX => {
4281
+ return eventX;
4282
+ };
4283
+
4284
+ const getTimelineLeft = state => {
4285
+ return state.x + viewPadding + timelineHorizontalPadding;
4286
+ };
4287
+ const getTimelineWidth = state => {
4288
+ return Math.max(0, getMainWidth(state.width) - timelineHorizontalPadding * 2);
4289
+ };
4290
+
4291
+ const getTimelineDurationSeconds = events => {
4292
+ const eventsWithTime = getEventsWithTime(events);
4293
+ if (eventsWithTime.length === 0) {
4294
+ return 0;
4054
4295
  }
4055
- return patches;
4296
+ const baseTime = eventsWithTime[0].time;
4297
+ const lastTime = eventsWithTime.at(-1)?.time ?? baseTime;
4298
+ return roundSeconds(Math.max(0, lastTime - baseTime) / 1000);
4056
4299
  };
4057
4300
 
4058
- const treeToArray = node => {
4059
- const result = [node.node];
4060
- for (const child of node.children) {
4061
- result.push(...treeToArray(child));
4301
+ const getTimelineSecondsFromClientX = (events, eventX, timelineLeft, timelineWidth) => {
4302
+ if (timelineWidth <= 0) {
4303
+ return undefined;
4062
4304
  }
4063
- return result;
4305
+ const durationSeconds = getTimelineDurationSeconds(events);
4306
+ const relativeX = Math.min(Math.max(eventX - timelineLeft, 0), timelineWidth);
4307
+ const ratio = relativeX / timelineWidth;
4308
+ return formatTimelinePresetValue(durationSeconds * ratio);
4064
4309
  };
4065
4310
 
4066
- const diffChildren = (oldChildren, newChildren, patches) => {
4067
- const maxLength = Math.max(oldChildren.length, newChildren.length);
4068
- // Track where we are: -1 means at parent, >= 0 means at child index
4069
- let currentChildIndex = -1;
4070
- // Collect indices of children to remove (we'll add these patches at the end in reverse order)
4071
- const indicesToRemove = [];
4072
- for (let i = 0; i < maxLength; i++) {
4073
- const oldNode = oldChildren[i];
4074
- const newNode = newChildren[i];
4075
- if (!oldNode && !newNode) {
4076
- continue;
4077
- }
4078
- if (!oldNode) {
4079
- // Add new node - we should be at the parent
4080
- if (currentChildIndex >= 0) {
4081
- // Navigate back to parent
4082
- patches.push({
4083
- type: NavigateParent
4084
- });
4085
- currentChildIndex = -1;
4086
- }
4087
- // Flatten the entire subtree so renderInternal can handle it
4088
- const flatNodes = treeToArray(newNode);
4089
- patches.push({
4090
- type: Add,
4091
- nodes: flatNodes
4092
- });
4093
- } else if (newNode) {
4094
- // Compare nodes to see if we need any patches
4095
- const nodePatches = compareNodes(oldNode.node, newNode.node);
4096
- // If nodePatches is null, the node types are incompatible - need to replace
4097
- if (nodePatches === null) {
4098
- // Navigate to this child
4099
- if (currentChildIndex === -1) {
4100
- patches.push({
4101
- type: NavigateChild,
4102
- index: i
4103
- });
4104
- currentChildIndex = i;
4105
- } else if (currentChildIndex !== i) {
4106
- patches.push({
4107
- type: NavigateSibling,
4108
- index: i
4109
- });
4110
- currentChildIndex = i;
4111
- }
4112
- // Replace the entire subtree
4113
- const flatNodes = treeToArray(newNode);
4114
- patches.push({
4115
- type: Replace,
4116
- nodes: flatNodes
4117
- });
4118
- // After replace, we're at the new element (same position)
4119
- continue;
4120
- }
4121
- // Check if we need to recurse into children
4122
- const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
4123
- // Only navigate to this element if we need to do something
4124
- if (nodePatches.length > 0 || hasChildrenToCompare) {
4125
- // Navigate to this child if not already there
4126
- if (currentChildIndex === -1) {
4127
- patches.push({
4128
- type: NavigateChild,
4129
- index: i
4130
- });
4131
- currentChildIndex = i;
4132
- } else if (currentChildIndex !== i) {
4133
- patches.push({
4134
- type: NavigateSibling,
4135
- index: i
4136
- });
4137
- currentChildIndex = i;
4138
- }
4139
- // Apply node patches (these apply to the current element, not children)
4140
- if (nodePatches.length > 0) {
4141
- patches.push(...nodePatches);
4142
- }
4143
- // Compare children recursively
4144
- if (hasChildrenToCompare) {
4145
- diffChildren(oldNode.children, newNode.children, patches);
4146
- }
4147
- }
4148
- } else {
4149
- // Remove old node - collect the index for later removal
4150
- indicesToRemove.push(i);
4151
- }
4311
+ const Start = 'TimelineSelectionStartHandle';
4312
+ const End = 'TimelineSelectionEndHandle';
4313
+
4314
+ const getResizeState = (state, name) => {
4315
+ if (state.timelineInfo.startSeconds === null || state.timelineInfo.endSeconds === null) {
4316
+ return undefined;
4152
4317
  }
4153
- // Navigate back to parent if we ended at a child
4154
- if (currentChildIndex >= 0) {
4155
- patches.push({
4156
- type: NavigateParent
4318
+ if (name === Start) {
4319
+ return getStateWithTimelineInfo({
4320
+ ...state,
4321
+ timelineSelectionActive: true,
4322
+ timelineSelectionAnchorSeconds: formatTimelinePresetValue(state.timelineInfo.endSeconds),
4323
+ timelineSelectionFocusSeconds: formatTimelinePresetValue(state.timelineInfo.startSeconds)
4157
4324
  });
4158
- currentChildIndex = -1;
4159
4325
  }
4160
- // Add remove patches in reverse order (highest index first)
4161
- // This ensures indices remain valid as we remove
4162
- for (let j = indicesToRemove.length - 1; j >= 0; j--) {
4163
- patches.push({
4164
- type: RemoveChild,
4165
- index: indicesToRemove[j]
4326
+ if (name === End) {
4327
+ return getStateWithTimelineInfo({
4328
+ ...state,
4329
+ timelineSelectionActive: true,
4330
+ timelineSelectionAnchorSeconds: formatTimelinePresetValue(state.timelineInfo.startSeconds),
4331
+ timelineSelectionFocusSeconds: formatTimelinePresetValue(state.timelineInfo.endSeconds)
4166
4332
  });
4167
4333
  }
4334
+ return undefined;
4168
4335
  };
4169
- const diffTrees = (oldTree, newTree, patches, path) => {
4170
- // At the root level (path.length === 0), we're already AT the element
4171
- // So we compare the root node directly, then compare its children
4172
- if (path.length === 0 && oldTree.length === 1 && newTree.length === 1) {
4173
- const oldNode = oldTree[0];
4174
- const newNode = newTree[0];
4175
- // Compare root nodes
4176
- const nodePatches = compareNodes(oldNode.node, newNode.node);
4177
- // If nodePatches is null, the root node types are incompatible - need to replace
4178
- if (nodePatches === null) {
4179
- const flatNodes = treeToArray(newNode);
4180
- patches.push({
4181
- type: Replace,
4182
- nodes: flatNodes
4183
- });
4184
- return;
4185
- }
4186
- if (nodePatches.length > 0) {
4187
- patches.push(...nodePatches);
4188
- }
4189
- // Compare children
4190
- if (oldNode.children.length > 0 || newNode.children.length > 0) {
4191
- diffChildren(oldNode.children, newNode.children, patches);
4192
- }
4193
- } else {
4194
- // Non-root level or multiple root elements - use the regular comparison
4195
- diffChildren(oldTree, newTree, patches);
4196
- }
4336
+ const handleTimelinePointerDown = (state, name, eventX) => {
4337
+ const resizeState = getResizeState(state, name);
4338
+ if (resizeState) {
4339
+ return resizeState;
4340
+ }
4341
+ const timelineLeft = getTimelineLeft(state);
4342
+ const timelineWidth = getTimelineWidth(state);
4343
+ const clientX = getTimelineEventX(eventX);
4344
+ const seconds = getTimelineSecondsFromClientX(state.timelineEvents, clientX, timelineLeft, timelineWidth);
4345
+ if (seconds === undefined) {
4346
+ return state;
4347
+ }
4348
+ const timelineHoverPercent = getSelectionPercent(Number.parseFloat(seconds), state.timelineInfo.durationSeconds);
4349
+ return getStateWithTimelineInfo({
4350
+ ...state,
4351
+ timelineHoverPercent,
4352
+ timelineHoverSeconds: seconds,
4353
+ timelineSelectionActive: true,
4354
+ timelineSelectionAnchorSeconds: seconds,
4355
+ timelineSelectionFocusSeconds: seconds
4356
+ });
4197
4357
  };
4198
4358
 
4199
- const removeTrailingNavigationPatches = patches => {
4200
- // Find the last non-navigation patch
4201
- let lastNonNavigationIndex = -1;
4202
- for (let i = patches.length - 1; i >= 0; i--) {
4203
- const patch = patches[i];
4204
- if (patch.type !== NavigateChild && patch.type !== NavigateParent && patch.type !== NavigateSibling) {
4205
- lastNonNavigationIndex = i;
4206
- break;
4207
- }
4359
+ const handleTimelinePointerLeave = state => {
4360
+ if (state.timelineHoverPercent === null && state.timelineHoverSeconds === '') {
4361
+ return state;
4208
4362
  }
4209
- // Return patches up to and including the last non-navigation patch
4210
- return lastNonNavigationIndex === -1 ? [] : patches.slice(0, lastNonNavigationIndex + 1);
4363
+ return {
4364
+ ...state,
4365
+ timelineHoverPercent: null,
4366
+ timelineHoverSeconds: ''
4367
+ };
4211
4368
  };
4212
4369
 
4213
- const diffTree = (oldNodes, newNodes) => {
4214
- // Step 1: Convert flat arrays to tree structures
4215
- const oldTree = arrayToTree(oldNodes);
4216
- const newTree = arrayToTree(newNodes);
4217
- // Step 3: Compare the trees
4218
- const patches = [];
4219
- diffTrees(oldTree, newTree, patches, []);
4220
- // Remove trailing navigation patches since they serve no purpose
4221
- return removeTrailingNavigationPatches(patches);
4370
+ const handleTimelinePointerMove = (state, eventX) => {
4371
+ const timelineLeft = getTimelineLeft(state);
4372
+ const timelineWidth = getTimelineWidth(state);
4373
+ const clientX = getTimelineEventX(eventX);
4374
+ const seconds = getTimelineSecondsFromClientX(state.timelineEvents, clientX, timelineLeft, timelineWidth);
4375
+ if (seconds === undefined) {
4376
+ return state;
4377
+ }
4378
+ const timelineHoverPercent = getSelectionPercent(Number.parseFloat(seconds), state.timelineInfo.durationSeconds);
4379
+ if (!state.timelineSelectionActive) {
4380
+ return {
4381
+ ...state,
4382
+ timelineHoverPercent,
4383
+ timelineHoverSeconds: seconds
4384
+ };
4385
+ }
4386
+ return getStateWithTimelineInfo({
4387
+ ...state,
4388
+ timelineHoverPercent,
4389
+ timelineHoverSeconds: seconds,
4390
+ timelineSelectionFocusSeconds: seconds
4391
+ });
4222
4392
  };
4223
4393
 
4224
- const ChatDebugView = 'ChatDebugView';
4225
- const ChatDebugViewDevtools = 'ChatDebugView--devtools';
4226
- const ChatDebugViewDetails = 'ChatDebugViewDetails';
4227
- const ChatDebugViewDetailsBottom = 'ChatDebugViewDetailsBottom';
4228
- const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
4229
- const EditorContainer = 'EditorContainer';
4230
- const PanelTab = 'PanelTab';
4231
- const PanelTabSelected = 'PanelTabSelected';
4232
- const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
4233
- const ChatDebugViewDetailsTop = 'ChatDebugViewDetailsTop';
4234
- const ChatDebugViewDevtoolsSplit = 'ChatDebugViewDevtoolsSplit';
4235
- const ChatDebugViewEmpty = 'ChatDebugViewEmpty';
4236
- const ChatDebugViewError = 'ChatDebugViewError';
4237
- const EditorContent = 'EditorContent';
4238
- const EditorInput = 'EditorInput';
4239
- const EditorLayers = 'EditorLayers';
4240
- const EditorRow = 'EditorRow';
4241
- const EditorRows = 'EditorRows';
4242
- const EditorSelection = 'EditorSelection';
4243
- const EditorSelections = 'Selections';
4244
- const EditorViewlet = 'Viewlet Editor';
4245
- const ChatDebugViewEventLineNumber = 'ChatDebugViewEventLineNumber';
4246
- const Gutter = 'Gutter';
4247
- const TableRowSelected = 'TableRowSelected';
4248
- const ChatDebugViewEvents = 'ChatDebugViewEvents';
4249
- const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
4250
- const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
4251
- const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
4252
- const ChatDebugViewHeaderCell = 'TableCell';
4253
- const ChatDebugViewImagePreview = 'ChatDebugViewImagePreview';
4254
- const ChatDebugViewImagePreviewImageWrapper = 'ChatDebugViewImagePreviewImageWrapper';
4255
- const ChatDebugViewImagePreviewImage = 'ChatDebugViewImagePreviewImage';
4256
- const ChatDebugViewImagePreviewLabel = 'ChatDebugViewImagePreviewLabel';
4257
- const ChatDebugViewRefreshButton = 'ChatDebugViewRefreshButton';
4258
- const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
4259
- const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
4260
- const ChatDebugViewQuickFilters = 'ChatDebugViewQuickFilters';
4261
- const Sash = 'Sash';
4262
- const ChatDebugViewSashLine = 'ChatDebugViewSashLine';
4263
- const Table = 'Table';
4264
- const TableBody = 'TableBody';
4265
- const TableSummary = 'TableSummary';
4266
- const TableWrapper = 'TableWrapper';
4267
- const TableWrapperWrapper = 'TableWrapperWrapper';
4268
- const FocusOutline = 'FocusOutline';
4269
- const Resizer = 'Resizer';
4270
- const ResizerInner = 'ResizerInner';
4271
- const ResizerOne = 'ResizerOne';
4272
- const ResizerTwo = 'ResizerTwo';
4273
- const TableHead = 'TableHead';
4274
- const Resizers = 'Resizers';
4275
- const TableCol = 'TableCol';
4276
- const TableRow = 'TableRow';
4277
- const TableRowOdd = 'TableRowOdd';
4278
- const TableRowEven = 'TableRowEven';
4279
- const ChatDebugViewTimeline = 'ChatDebugViewTimeline';
4280
- const ChatDebugViewTimelineBadge = 'ChatDebugViewTimelineBadge';
4281
- const ChatDebugViewTimelineBadges = 'ChatDebugViewTimelineBadges';
4282
- const ChatDebugViewTimelineBucket = 'ChatDebugViewTimelineBucket';
4283
- const ChatDebugViewTimelineBucketBar = 'ChatDebugViewTimelineBucketBar';
4284
- const ChatDebugViewTimelineBucketBarSelected = 'ChatDebugViewTimelineBucketBarSelected';
4285
- const ChatDebugViewTimelineBucketSelected = 'ChatDebugViewTimelineBucketSelected';
4286
- const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
4287
- const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
4288
- const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
4289
- const ChatDebugViewTimelineCursorGuide = 'ChatDebugViewTimelineCursorGuide';
4290
- const ChatDebugViewTimelineCursorGuideVisible = 'ChatDebugViewTimelineCursorGuideVisible';
4291
- const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
4292
- const ChatDebugViewTimelineSelectionHandle = 'ChatDebugViewTimelineSelectionHandle';
4293
- const ChatDebugViewTimelineSelectionHandleEnd = 'ChatDebugViewTimelineSelectionHandleEnd';
4294
- const ChatDebugViewTimelineSelectionHandleStart = 'ChatDebugViewTimelineSelectionHandleStart';
4295
- const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
4296
- const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
4297
- const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
4298
- const ChatDebugViewTimelineSelectionOverlay = 'ChatDebugViewTimelineSelectionOverlay';
4299
- const ChatDebugViewTimelineSelectionRange = 'ChatDebugViewTimelineSelectionRange';
4300
- const ChatDebugViewTimelineTop = 'ChatDebugViewTimelineTop';
4301
- const ChatDebugViewTiming = 'ChatDebugViewTiming';
4302
- const ChatDebugViewTimingLabel = 'ChatDebugViewTimingLabel';
4303
- const ChatDebugViewTimingPreview = 'ChatDebugViewTimingPreview';
4304
- const ChatDebugViewTimingPreviewMarker = 'ChatDebugViewTimingPreviewMarker';
4305
- const ChatDebugViewTimingPreviewMarkerEnd = 'ChatDebugViewTimingPreviewMarkerEnd';
4306
- const ChatDebugViewTimingPreviewMarkerStart = 'ChatDebugViewTimingPreviewMarkerStart';
4307
- const ChatDebugViewTimingPreviewRail = 'ChatDebugViewTimingPreviewRail';
4308
- const ChatDebugViewTimingPreviewSegment = 'ChatDebugViewTimingPreviewSegment';
4309
- const ChatDebugViewTimingPreviewTrack = 'ChatDebugViewTimingPreviewTrack';
4310
- const ChatDebugViewTimingPreviewTrackOverlay = 'ChatDebugViewTimingPreviewTrackOverlay';
4311
- const ChatDebugViewTimingRow = 'ChatDebugViewTimingRow';
4312
- const ChatDebugViewTimingValue = 'ChatDebugViewTimingValue';
4313
- const ChatDebugViewTop = 'ChatDebugViewTop';
4314
- const ChatDebugViewTopDevtools = 'ChatDebugViewTop--devtools';
4315
- const TableCell = 'TableCell';
4316
- const ChatDebugViewColumnFixed = 'ChatDebugViewColumnFixed';
4317
- const ChatDebugViewCellDuration = 'ChatDebugViewCellDuration';
4318
- const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
4319
- const InputBox = 'InputBox';
4320
- const TokenBoolean = 'Token TokenBoolean';
4321
- const TokenKey = 'Token TokenKey';
4322
- const TokenNumeric = 'Token TokenNumeric';
4323
- const TokenString = 'Token TokenString';
4324
- const TokenText = 'Token TokenText';
4394
+ const handleTimelinePointerUp = (state, eventX) => {
4395
+ if (!state.timelineSelectionActive) {
4396
+ return state;
4397
+ }
4398
+ const timelineLeft = getTimelineLeft(state);
4399
+ const timelineWidth = getTimelineWidth(state);
4400
+ const clientX = getTimelineEventX(eventX);
4401
+ const focusSeconds = getTimelineSecondsFromClientX(state.timelineEvents, clientX, timelineLeft, timelineWidth);
4402
+ if (focusSeconds === undefined) {
4403
+ return clearTimelineSelectionState(state);
4404
+ }
4405
+ const timelineHoverPercent = getSelectionPercent(Number.parseFloat(focusSeconds), state.timelineInfo.durationSeconds);
4406
+ const anchor = Number.parseFloat(state.timelineSelectionAnchorSeconds);
4407
+ const focus = Number.parseFloat(focusSeconds);
4408
+ const startSeconds = formatTimelinePresetValue(Math.min(anchor, focus));
4409
+ const endSeconds = formatTimelinePresetValue(Math.max(anchor, focus));
4410
+ const nextState = handleTimelineRangePreset(state, `${startSeconds}:${endSeconds}`);
4411
+ return clearTimelineSelectionState({
4412
+ ...nextState,
4413
+ timelineHoverPercent,
4414
+ timelineHoverSeconds: focusSeconds
4415
+ });
4416
+ };
4325
4417
 
4326
- const debugErrorRootNode = {
4327
- childCount: 1,
4328
- className: ChatDebugView,
4329
- type: Div
4418
+ const setUseDevtoolsLayout = (state, checked) => {
4419
+ const useDevtoolsLayout = getBoolean(checked);
4420
+ const selectedEventIndex = useDevtoolsLayout ? getSelectedEventIndex$1(state) : null;
4421
+ return applyVirtualTableState({
4422
+ ...state,
4423
+ previewTextCursorColumnIndex: useDevtoolsLayout && selectedEventIndex !== null ? state.previewTextCursorColumnIndex : null,
4424
+ previewTextCursorRowIndex: useDevtoolsLayout && selectedEventIndex !== null ? state.previewTextCursorRowIndex : null,
4425
+ selectedEvent: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEvent : null,
4426
+ selectedEventId: useDevtoolsLayout && selectedEventIndex !== null ? state.selectedEventId : null,
4427
+ selectedEventIndex,
4428
+ useDevtoolsLayout
4429
+ });
4330
4430
  };
4331
- const debugErrorMessageNode = {
4332
- childCount: 1,
4333
- className: ChatDebugViewError,
4334
- type: Div
4431
+
4432
+ const handleShowEventStreamFinishedEvents = (state, checked) => {
4433
+ const nextState = {
4434
+ ...state,
4435
+ showEventStreamFinishedEvents: getBoolean(checked)
4436
+ };
4437
+ return withPreservedSelection$1(state, nextState);
4335
4438
  };
4336
- const getDebugErrorDom = errorMessage => {
4337
- return [debugErrorRootNode, debugErrorMessageNode, text(errorMessage)];
4439
+ const handleShowInputEvents = (state, checked) => {
4440
+ const nextState = {
4441
+ ...state,
4442
+ showInputEvents: getBoolean(checked)
4443
+ };
4444
+ return withPreservedSelection$1(state, nextState);
4445
+ };
4446
+ const handleShowResponsePartEvents = (state, checked) => {
4447
+ const nextState = {
4448
+ ...state,
4449
+ showResponsePartEvents: getBoolean(checked)
4450
+ };
4451
+ return withPreservedSelection$1(state, nextState);
4338
4452
  };
4339
4453
 
4340
- const HandleEventCategoryFilter = 4;
4341
- const HandleFilterInput = 5;
4342
- const SelectDetailTab = 6;
4343
- const HandleEventRowClickAt = 7;
4344
- const HandleHeaderContextMenu = 8;
4345
- const HandleSashPointerDown = 9;
4346
- const HandleSashPointerMove = 10;
4347
- const HandleSashPointerUp = 11;
4348
- const HandleTableResizerPointerDown = 12;
4349
- const HandleTableResizerPointerMove = 13;
4350
- const HandleTableResizerPointerUp = 14;
4351
- const HandleTableBodyContextMenu = 15;
4352
- const HandleDetailsContextMenu = 16;
4353
- const HandleTimelinePointerDown = 17;
4354
- const HandleTimelinePointerMove = 18;
4355
- const HandleTimelinePointerUp = 19;
4356
- const HandleTimelineDoubleClick = 20;
4357
- const HandleTableHeaderClick = 21;
4358
- const HandleTimelineRangePreset = 22;
4359
- const HandleCloseDetails = 23;
4360
- const HandleClickRefresh = 24;
4361
- const HandleDetailsTopContextMenu = 25;
4362
- const HandleTimelineContextMenu = 26;
4363
- const HandleTimelinePointerLeave = 27;
4364
- const HandleEventRowClick = 28;
4365
- const HandleTableFocus = 29;
4366
- const HandleDetailTabsFocus = 30;
4454
+ const rpcId = 'handleStorageWorkerUpdate';
4455
+ const handleStorageWorkerUpdate = async uid => {
4456
+ await invoke('Viewlet.executeViewletCommand', uid, 'ChatDebug.handleClickRefresh');
4457
+ };
4367
4458
 
4368
- const getFilterInputDom = (filterValue, useDevtoolsLayout) => {
4369
- return {
4370
- autocomplete: 'off',
4371
- childCount: 0,
4372
- className: useDevtoolsLayout ? mergeClassNames(InputBox, ChatDebugViewFilterInput, ChatDebugViewFilterInputDevtools) : mergeClassNames(InputBox, ChatDebugViewFilterInput),
4373
- inputType: 'search',
4374
- name: Filter,
4375
- onInput: HandleFilterInput,
4376
- placeholder: filterEvents(),
4377
- type: Input,
4378
- value: filterValue
4379
- };
4459
+ const loadContentDependencies = loadEventsDependencies;
4460
+ loadContentDependencies.registerUpdateListener = registerUpdateListener;
4461
+ const loadContent = async (state, savedState) => {
4462
+ await getPreference('chatDebug.autoRefresh');
4463
+ const nextState = await loadEventsFromUri(restoreSavedState(state, savedState));
4464
+ if (nextState.sessionId) {
4465
+ try {
4466
+ await loadContentDependencies.registerUpdateListener(nextState.sessionId, rpcId, nextState.uid);
4467
+ } catch {
4468
+ // ignore
4469
+ }
4470
+ }
4471
+ return applyVirtualTableState({
4472
+ ...nextState,
4473
+ categoryFilters: createCategoryFilters(getSelectedEventCategoryFilters(nextState.categoryFilters)),
4474
+ detailTabs: createDetailTabs(getSelectedDetailTab(nextState.detailTabs), nextState.selectedEvent),
4475
+ tableColumns: createTableColumns()
4476
+ });
4380
4477
  };
4381
4478
 
4382
- const getQuickFilterDom = categoryFilter => {
4479
+ // cspell:ignore liga calt
4480
+
4481
+ const getCss = state => {
4482
+ const hasSelectedEvent = !!state.selectedEvent;
4483
+ const tableWidth = hasSelectedEvent ? clampTableWidth(state.width, state.tableWidth) : getMainWidth(state.width);
4484
+ const currentEvents = getCurrentEvents$2(state);
4485
+ const tableBodyHeight = getTableBodyHeight(state, currentEvents.length);
4486
+ const scrollBarHeight = getScrollBarHeight(currentEvents.length, tableBodyHeight);
4487
+ const maxDeltaY = getMaxDeltaY(currentEvents.length, tableBodyHeight);
4488
+ const showScrollBar = scrollBarHeight > 0;
4489
+ const scrollBarOffset = getScrollBarOffset(state.tableDeltaY, maxDeltaY, tableBodyHeight, scrollBarHeight);
4490
+ const tableContentWidth = Math.max(0, tableWidth - (showScrollBar ? devtoolsTableScrollBarWidth : 0));
4491
+ const detailsWidth = hasSelectedEvent ? getDetailsWidth(state.width, state.tableWidth) : 0;
4492
+ const topSize = state.width >= state.largeBreakpoint ? 30 : state.width >= state.mediumBreakpoint ? 60 : 60;
4493
+ const tableColumnLayout = getTableColumnLayout(tableContentWidth, getVisibleTableColumns(state.tableColumns), state.tableColumnWidths);
4494
+ const [tableColZeroWidth = 0, tableColOneWidth = 0, tableColTwoWidth = 0] = tableColumnLayout.visibleColumnWidths;
4495
+ const resizerOneLeft = tableColumnLayout.resizerLefts[0] ?? 0;
4496
+ const resizerTwoLeft = tableColumnLayout.resizerLefts[1] ?? 0;
4383
4497
  const {
4384
- isSelected,
4385
- label,
4386
- name
4387
- } = categoryFilter;
4388
- return [{
4389
- ariaSelected: isSelected,
4390
- childCount: 1,
4391
- className: mergeClassNames(ChatDebugViewQuickFilterPill, isSelected ? ChatDebugViewQuickFilterPillSelected : ''),
4392
- name,
4393
- onClick: HandleEventCategoryFilter,
4394
- role: Option,
4395
- type: Button$1
4396
- }, text(label)];
4397
- };
4498
+ selectionEndPercent,
4499
+ selectionStartPercent
4500
+ } = state.timelineInfo;
4501
+ return `
4502
+ .ChatDebugView {
4503
+ --ChatDebugViewTableBodyHeight: ${tableBodyHeight}px;
4504
+ --ChatDebugViewTableHeaderHeight: ${devtoolsTableHeaderHeight}px;
4505
+ --ChatDebugViewTableColZeroWidth: ${tableColZeroWidth}px;
4506
+ --ChatDebugViewTableColOneWidth: ${tableColOneWidth}px;
4507
+ --ChatDebugViewTableColTwoWidth: ${tableColTwoWidth}px;
4508
+ --ChatDebugViewDetailsWidth: ${detailsWidth}px;
4509
+ --ChatDebugViewDurationColumnWidth: ${state.tableColumnWidths.duration}px;
4510
+ --ChatDebugViewTableRowHeight: ${devtoolsTableRowHeight}px;
4511
+ --ChatDebugViewTableScrollBarHeight: ${scrollBarHeight}px;
4512
+ --ChatDebugViewTableScrollBarOffset: ${scrollBarOffset}px;
4513
+ --ChatDebugViewTableScrollBarWidth: ${showScrollBar ? devtoolsTableScrollBarWidth : 0}px;
4514
+ --ResizerOneLeft: ${resizerOneLeft}px;
4515
+ --ResizerTwoLeft: ${resizerTwoLeft}px;
4516
+ --ChatDebugViewSashWidth: ${sashWidth}px;
4517
+ --ChatDebugViewTableWidth: ${tableWidth}px;
4518
+ --ChatDebugViewTimelineHeight: ${state.timelineHeight}px;
4519
+ --ChatDebugViewTimelineCursorGuideLeft: ${state.timelineHoverPercent ?? 0}%;
4520
+ --ChatDebugViewTimelineSelectionEndLeft: ${selectionEndPercent ?? 0}%;
4521
+ --ChatDebugViewTimelineSelectionStartLeft: ${selectionStartPercent ?? 0}%;
4522
+ --ChatDebugViewTopSize: ${topSize}px;
4523
+ --ChatDebugViewTypeColumnWidth: ${state.tableColumnWidths.type}px;
4524
+ padding: ${viewPadding}px;
4525
+ padding-right: 0;
4526
+ }
4398
4527
 
4399
- // cspell:ignore multiselectable
4400
- const getQuickFilterNodes = categoryFilters => {
4401
- return [{
4402
- 'aria-multiselectable': true,
4403
- childCount: categoryFilters.length,
4404
- className: ChatDebugViewQuickFilters,
4405
- onClick: HandleEventCategoryFilter,
4406
- role: ListBox,
4407
- type: Div
4408
- }, ...categoryFilters.flatMap(getQuickFilterDom)];
4409
- };
4528
+ .TableWrapper {
4529
+ height: calc(var(--ChatDebugViewTableHeaderHeight) + var(--ChatDebugViewTableBodyHeight));
4530
+ overflow: hidden;
4531
+ position: relative;
4532
+ }
4410
4533
 
4411
- const refreshButtonDom = [{
4412
- 'aria-label': refreshEvents$1(),
4413
- childCount: 1,
4414
- className: ChatDebugViewRefreshButton,
4415
- name: Refresh,
4416
- onClick: HandleClickRefresh,
4417
- type: Button$1,
4418
- value: Refresh
4419
- }, text(refresh$1())];
4420
- const getRefreshButtonDom = () => {
4421
- return refreshButtonDom;
4422
- };
4534
+ .Table {
4535
+ width: calc(100% - var(--ChatDebugViewTableScrollBarWidth));
4536
+ }
4423
4537
 
4424
- const getDebugViewTopDom = (filterValue, useDevtoolsLayout, categoryFilters) => {
4425
- const refreshButtonDom = getRefreshButtonDom();
4426
- if (useDevtoolsLayout) {
4427
- const quickFilterNodes = getQuickFilterNodes(categoryFilters);
4428
- return [{
4429
- childCount: 2 + (quickFilterNodes.length > 0 ? 1 : 0),
4430
- className: mergeClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
4431
- onContextMenu: HandleHeaderContextMenu,
4432
- type: Search
4433
- }, getFilterInputDom(filterValue, true), ...quickFilterNodes, ...refreshButtonDom];
4434
- }
4435
- return [{
4436
- childCount: 2,
4437
- className: ChatDebugViewTop,
4438
- onContextMenu: HandleHeaderContextMenu,
4439
- type: Search
4440
- }, getFilterInputDom(filterValue, false), ...refreshButtonDom];
4441
- };
4538
+ .ChatDebugViewTimeline {
4539
+ contain: strict;
4540
+ display: flex;
4541
+ flex-direction: column;
4542
+ gap: 8px;
4543
+ height: var(--ChatDebugViewTimelineHeight);
4544
+ }
4442
4545
 
4443
- const detailsCloseButtonDom = [{
4444
- 'aria-label': closeDetails(),
4445
- childCount: 1,
4446
- className: ChatDebugViewDetailsClose,
4447
- name: CloseDetails,
4448
- onChange: HandleCloseDetails,
4449
- onClick: HandleCloseDetails,
4450
- type: Button$1,
4451
- value: 'close'
4452
- }, {
4453
- childCount: 0,
4454
- className: 'MaskIcon MaskIconClose',
4455
- type: Div
4456
- }];
4457
- const getDetailsCloseButtonDom = () => {
4458
- return detailsCloseButtonDom;
4459
- };
4546
+ .ChatDebugViewTimelineInteractive {
4547
+ flex: 1;
4548
+ min-height: 0;
4549
+ position: relative;
4550
+ }
4460
4551
 
4461
- const getEditorSelectionDom = () => {
4462
- return [{
4463
- childCount: 1,
4464
- className: EditorSelections,
4465
- type: Div
4466
- }, {
4467
- childCount: 0,
4468
- className: EditorSelection,
4469
- style: 'height: 20px; left: 0px; top: 20px; width: 0px;',
4470
- type: Div
4471
- }];
4472
- };
4473
- const getGutterDom = (lineData, showLineNumbers) => {
4474
- const gutterNodes = showLineNumbers ? lineData.flatMap((_, index) => {
4475
- return [{
4476
- childCount: 1,
4477
- className: ChatDebugViewEventLineNumber,
4478
- type: Span
4479
- }, text(String(index + 1))];
4480
- }) : [];
4481
- return [{
4482
- childCount: showLineNumbers ? lineData.length : 0,
4483
- className: Gutter,
4484
- type: Div
4485
- }, ...gutterNodes];
4552
+ .TableScrollBar {
4553
+ background: rgba(255, 255, 255, 0.06);
4554
+ border-radius: 999px;
4555
+ height: var(--ChatDebugViewTableBodyHeight);
4556
+ position: absolute;
4557
+ right: 0;
4558
+ top: var(--ChatDebugViewTableHeaderHeight);
4559
+ width: var(--ChatDebugViewTableScrollBarWidth);
4560
+ }
4561
+
4562
+ .TableScrollBarThumb {
4563
+ background: rgba(255, 255, 255, 0.22);
4564
+ border-radius: 999px;
4565
+ height: var(--ChatDebugViewTableScrollBarHeight);
4566
+ left: 2px;
4567
+ position: absolute;
4568
+ top: var(--ChatDebugViewTableScrollBarOffset);
4569
+ width: calc(100% - 4px);
4570
+ }
4571
+
4572
+ `;
4486
4573
  };
4487
- const getEditorRowDom = line => {
4488
- return [{
4489
- childCount: line.childCount,
4490
- className: EditorRow,
4491
- type: Div
4492
- }, ...line.nodes];
4574
+
4575
+ const renderCss = (oldState, newState) => {
4576
+ const css = getCss(newState);
4577
+ return [SetCss, newState.uid, css];
4493
4578
  };
4494
- const getEditorRowsDom = lineData => {
4495
- return [{
4496
- childCount: lineData.length,
4497
- className: EditorRows,
4498
- type: Div
4499
- }, ...lineData.flatMap(getEditorRowDom)];
4579
+
4580
+ const mergeClassNames = (...classNames) => {
4581
+ return classNames.filter(Boolean).join(' ');
4500
4582
  };
4501
- const getEditorDom = (lineData, showLineNumbers = true) => {
4502
- return [{
4503
- childCount: 1,
4504
- className: EditorContainer,
4505
- type: Div
4506
- }, {
4507
- childCount: 2,
4508
- className: EditorViewlet,
4509
- role: 'code',
4510
- type: Div
4511
- }, ...getGutterDom(lineData, showLineNumbers), {
4512
- childCount: 2,
4513
- className: EditorContent,
4514
- type: Div
4515
- }, {
4516
- 'aria-autocomplete': 'list',
4517
- 'aria-multiline': true,
4518
- 'aria-roledescription': 'editor',
4519
- autocapitalize: 'off',
4520
- autocomplete: 'off',
4521
- autocorrect: 'off',
4583
+
4584
+ const text = data => {
4585
+ return {
4522
4586
  childCount: 0,
4523
- className: EditorInput,
4524
- name: 'editor',
4525
- role: 'textbox',
4526
- spellcheck: false,
4527
- type: TextArea,
4528
- wrap: 'off'
4529
- }, {
4530
- childCount: 2,
4531
- className: EditorLayers,
4532
- type: Div
4533
- }, ...getEditorSelectionDom(), ...getEditorRowsDom(lineData)];
4587
+ text: data,
4588
+ type: Text
4589
+ };
4534
4590
  };
4535
4591
 
4536
- const isDigit = character => {
4537
- return character !== undefined && character >= '0' && character <= '9';
4592
+ const SetText = 1;
4593
+ const Replace = 2;
4594
+ const SetAttribute = 3;
4595
+ const RemoveAttribute = 4;
4596
+ const Add = 6;
4597
+ const NavigateChild = 7;
4598
+ const NavigateParent = 8;
4599
+ const RemoveChild = 9;
4600
+ const NavigateSibling = 10;
4601
+ const SetReferenceNodeUid = 11;
4602
+
4603
+ const isKey = key => {
4604
+ return key !== 'type' && key !== 'childCount';
4538
4605
  };
4539
- const isWhitespace = character => {
4540
- return character === ' ' || character === '\n' || character === '\r' || character === '\t';
4606
+
4607
+ const getKeys = node => {
4608
+ const keys = Object.keys(node).filter(isKey);
4609
+ return keys;
4541
4610
  };
4542
- const getNumberEnd = (json, start) => {
4543
- let i = start;
4544
- if (json[i] === '-') {
4545
- i++;
4611
+
4612
+ const arrayToTree = nodes => {
4613
+ const result = [];
4614
+ let i = 0;
4615
+ while (i < nodes.length) {
4616
+ const node = nodes[i];
4617
+ const {
4618
+ children,
4619
+ nodesConsumed
4620
+ } = getChildrenWithCount(nodes, i + 1, node.childCount || 0);
4621
+ result.push({
4622
+ node,
4623
+ children
4624
+ });
4625
+ i += 1 + nodesConsumed;
4546
4626
  }
4547
- if (json[i] === '0') {
4548
- i++;
4549
- } else {
4550
- if (!isDigit(json[i])) {
4551
- return start;
4552
- }
4553
- while (isDigit(json[i])) {
4554
- i++;
4555
- }
4556
- }
4557
- if (json[i] === '.') {
4558
- const decimalStart = i;
4559
- i++;
4560
- if (!isDigit(json[i])) {
4561
- return decimalStart;
4562
- }
4563
- while (isDigit(json[i])) {
4564
- i++;
4565
- }
4627
+ return result;
4628
+ };
4629
+ const getChildrenWithCount = (nodes, startIndex, childCount) => {
4630
+ if (childCount === 0) {
4631
+ return {
4632
+ children: [],
4633
+ nodesConsumed: 0
4634
+ };
4566
4635
  }
4567
- if (json[i] === 'e' || json[i] === 'E') {
4568
- const exponentStart = i;
4569
- i++;
4570
- if (json[i] === '+' || json[i] === '-') {
4571
- i++;
4572
- }
4573
- if (!isDigit(json[i])) {
4574
- return exponentStart;
4575
- }
4576
- while (isDigit(json[i])) {
4577
- i++;
4578
- }
4636
+ const children = [];
4637
+ let i = startIndex;
4638
+ let remaining = childCount;
4639
+ let totalConsumed = 0;
4640
+ while (remaining > 0 && i < nodes.length) {
4641
+ const node = nodes[i];
4642
+ const nodeChildCount = node.childCount || 0;
4643
+ const {
4644
+ children: nodeChildren,
4645
+ nodesConsumed
4646
+ } = getChildrenWithCount(nodes, i + 1, nodeChildCount);
4647
+ children.push({
4648
+ node,
4649
+ children: nodeChildren
4650
+ });
4651
+ const nodeSize = 1 + nodesConsumed;
4652
+ i += nodeSize;
4653
+ totalConsumed += nodeSize;
4654
+ remaining--;
4579
4655
  }
4580
- return i;
4656
+ return {
4657
+ children,
4658
+ nodesConsumed: totalConsumed
4659
+ };
4581
4660
  };
4582
- const forEachTokenSegment = (json, onToken) => {
4583
- let i = 0;
4584
- while (i < json.length) {
4585
- const character = json[i];
4586
- if (character === '"') {
4587
- const start = i;
4588
- i++;
4589
- while (i < json.length) {
4590
- const currentCharacter = json[i];
4591
- if (currentCharacter === '\\') {
4592
- i += 2;
4593
- continue;
4594
- }
4595
- if (currentCharacter === '"') {
4596
- i++;
4597
- break;
4598
- }
4599
- i++;
4600
- }
4601
- let lookAheadIndex = i;
4602
- while (lookAheadIndex < json.length && isWhitespace(json[lookAheadIndex])) {
4603
- lookAheadIndex++;
4604
- }
4605
- const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
4606
- onToken(className, json.slice(start, i));
4607
- continue;
4608
- }
4609
- const numberEnd = getNumberEnd(json, i);
4610
- if (numberEnd > i) {
4611
- onToken(TokenNumeric, json.slice(i, numberEnd));
4612
- i = numberEnd;
4613
- continue;
4661
+
4662
+ const compareNodes = (oldNode, newNode) => {
4663
+ const patches = [];
4664
+ // Check if node type changed - return null to signal incompatible nodes
4665
+ // (caller should handle this with a Replace operation)
4666
+ if (oldNode.type !== newNode.type) {
4667
+ return null;
4668
+ }
4669
+ // Handle reference nodes - special handling for uid changes
4670
+ if (oldNode.type === Reference) {
4671
+ if (oldNode.uid !== newNode.uid) {
4672
+ patches.push({
4673
+ type: SetReferenceNodeUid,
4674
+ uid: newNode.uid
4675
+ });
4614
4676
  }
4615
- if (json.startsWith('true', i)) {
4616
- onToken(TokenBoolean, 'true');
4617
- i += 4;
4618
- continue;
4677
+ return patches;
4678
+ }
4679
+ // Handle text nodes
4680
+ if (oldNode.type === Text && newNode.type === Text) {
4681
+ if (oldNode.text !== newNode.text) {
4682
+ patches.push({
4683
+ type: SetText,
4684
+ value: newNode.text
4685
+ });
4619
4686
  }
4620
- if (json.startsWith('false', i)) {
4621
- onToken(TokenBoolean, 'false');
4622
- i += 5;
4623
- continue;
4687
+ return patches;
4688
+ }
4689
+ // Compare attributes
4690
+ const oldKeys = getKeys(oldNode);
4691
+ const newKeys = getKeys(newNode);
4692
+ // Check for attribute changes
4693
+ for (const key of newKeys) {
4694
+ if (oldNode[key] !== newNode[key]) {
4695
+ patches.push({
4696
+ type: SetAttribute,
4697
+ key,
4698
+ value: newNode[key]
4699
+ });
4624
4700
  }
4625
- if (json.startsWith('null', i)) {
4626
- onToken(TokenBoolean, 'null');
4627
- i += 4;
4628
- continue;
4701
+ }
4702
+ // Check for removed attributes
4703
+ for (const key of oldKeys) {
4704
+ if (!(key in newNode)) {
4705
+ patches.push({
4706
+ type: RemoveAttribute,
4707
+ key
4708
+ });
4629
4709
  }
4630
- onToken(TokenText, character);
4631
- i++;
4632
4710
  }
4711
+ return patches;
4633
4712
  };
4634
4713
 
4635
- const getJsonLines = value => {
4636
- const json = JSON.stringify(value, null, 2);
4637
- if (!json) {
4638
- return [[{
4639
- className: TokenText,
4640
- value: String(json)
4641
- }]];
4714
+ const treeToArray = node => {
4715
+ const result = [node.node];
4716
+ for (const child of node.children) {
4717
+ result.push(...treeToArray(child));
4642
4718
  }
4643
- const lines = [];
4644
- let currentLine = [];
4645
- const pushLineSegment = (className, lineValue) => {
4646
- if (!lineValue) {
4647
- return;
4648
- }
4649
- const lastSegment = currentLine.at(-1);
4650
- if (lastSegment && lastSegment.className === className) {
4651
- lastSegment.value += lineValue;
4652
- return;
4653
- }
4654
- currentLine.push({
4655
- className,
4656
- value: lineValue
4657
- });
4658
- };
4659
- forEachTokenSegment(json, (className, segmentValue) => {
4660
- let start = 0;
4661
- for (let i = 0; i < segmentValue.length; i++) {
4662
- if (segmentValue[i] === '\n') {
4663
- pushLineSegment(className, segmentValue.slice(start, i));
4664
- lines.push(currentLine);
4665
- currentLine = [];
4666
- start = i + 1;
4667
- }
4668
- }
4669
- pushLineSegment(className, segmentValue.slice(start));
4670
- });
4671
- lines.push(currentLine);
4672
- return lines;
4673
- };
4674
- const getLineContentNodes = line => {
4675
- return line.flatMap(segment => {
4676
- return [{
4677
- childCount: 1,
4678
- className: segment.className,
4679
- type: Span
4680
- }, text(segment.value)];
4681
- });
4682
- };
4683
- const isChatViewEvent = value => {
4684
- return typeof value === 'object' && value !== null && typeof value.type === 'string';
4685
- };
4686
- const getEventNode = value => {
4687
- const renderedValue = isChatViewEvent(value) ? {
4688
- ...value,
4689
- type: getEventTypeLabel(value)
4690
- } : value;
4691
- const lines = getJsonLines(renderedValue);
4692
- const lineData = lines.map(line => {
4693
- const lineContentNodes = getLineContentNodes(line);
4694
- return {
4695
- childCount: lineContentNodes.length / 2,
4696
- nodes: lineContentNodes
4697
- };
4698
- });
4699
- return getEditorDom(lineData);
4719
+ return result;
4700
4720
  };
4701
4721
 
4702
- const getPanelId = detailTab => {
4703
- return `ChatDebugViewDetailsPanel-${detailTab}`;
4722
+ const diffChildren = (oldChildren, newChildren, patches) => {
4723
+ const maxLength = Math.max(oldChildren.length, newChildren.length);
4724
+ // Track where we are: -1 means at parent, >= 0 means at child index
4725
+ let currentChildIndex = -1;
4726
+ // Collect indices of children to remove (we'll add these patches at the end in reverse order)
4727
+ const indicesToRemove = [];
4728
+ for (let i = 0; i < maxLength; i++) {
4729
+ const oldNode = oldChildren[i];
4730
+ const newNode = newChildren[i];
4731
+ if (!oldNode && !newNode) {
4732
+ continue;
4733
+ }
4734
+ if (!oldNode) {
4735
+ // Add new node - we should be at the parent
4736
+ if (currentChildIndex >= 0) {
4737
+ // Navigate back to parent
4738
+ patches.push({
4739
+ type: NavigateParent
4740
+ });
4741
+ currentChildIndex = -1;
4742
+ }
4743
+ // Flatten the entire subtree so renderInternal can handle it
4744
+ const flatNodes = treeToArray(newNode);
4745
+ patches.push({
4746
+ type: Add,
4747
+ nodes: flatNodes
4748
+ });
4749
+ } else if (newNode) {
4750
+ // Compare nodes to see if we need any patches
4751
+ const nodePatches = compareNodes(oldNode.node, newNode.node);
4752
+ // If nodePatches is null, the node types are incompatible - need to replace
4753
+ if (nodePatches === null) {
4754
+ // Navigate to this child
4755
+ if (currentChildIndex === -1) {
4756
+ patches.push({
4757
+ type: NavigateChild,
4758
+ index: i
4759
+ });
4760
+ currentChildIndex = i;
4761
+ } else if (currentChildIndex !== i) {
4762
+ patches.push({
4763
+ type: NavigateSibling,
4764
+ index: i
4765
+ });
4766
+ currentChildIndex = i;
4767
+ }
4768
+ // Replace the entire subtree
4769
+ const flatNodes = treeToArray(newNode);
4770
+ patches.push({
4771
+ type: Replace,
4772
+ nodes: flatNodes
4773
+ });
4774
+ // After replace, we're at the new element (same position)
4775
+ continue;
4776
+ }
4777
+ // Check if we need to recurse into children
4778
+ const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
4779
+ // Only navigate to this element if we need to do something
4780
+ if (nodePatches.length > 0 || hasChildrenToCompare) {
4781
+ // Navigate to this child if not already there
4782
+ if (currentChildIndex === -1) {
4783
+ patches.push({
4784
+ type: NavigateChild,
4785
+ index: i
4786
+ });
4787
+ currentChildIndex = i;
4788
+ } else if (currentChildIndex !== i) {
4789
+ patches.push({
4790
+ type: NavigateSibling,
4791
+ index: i
4792
+ });
4793
+ currentChildIndex = i;
4794
+ }
4795
+ // Apply node patches (these apply to the current element, not children)
4796
+ if (nodePatches.length > 0) {
4797
+ patches.push(...nodePatches);
4798
+ }
4799
+ // Compare children recursively
4800
+ if (hasChildrenToCompare) {
4801
+ diffChildren(oldNode.children, newNode.children, patches);
4802
+ }
4803
+ }
4804
+ } else {
4805
+ // Remove old node - collect the index for later removal
4806
+ indicesToRemove.push(i);
4807
+ }
4808
+ }
4809
+ // Navigate back to parent if we ended at a child
4810
+ if (currentChildIndex >= 0) {
4811
+ patches.push({
4812
+ type: NavigateParent
4813
+ });
4814
+ currentChildIndex = -1;
4815
+ }
4816
+ // Add remove patches in reverse order (highest index first)
4817
+ // This ensures indices remain valid as we remove
4818
+ for (let j = indicesToRemove.length - 1; j >= 0; j--) {
4819
+ patches.push({
4820
+ type: RemoveChild,
4821
+ index: indicesToRemove[j]
4822
+ });
4823
+ }
4824
+ };
4825
+ const diffTrees = (oldTree, newTree, patches, path) => {
4826
+ // At the root level (path.length === 0), we're already AT the element
4827
+ // So we compare the root node directly, then compare its children
4828
+ if (path.length === 0 && oldTree.length === 1 && newTree.length === 1) {
4829
+ const oldNode = oldTree[0];
4830
+ const newNode = newTree[0];
4831
+ // Compare root nodes
4832
+ const nodePatches = compareNodes(oldNode.node, newNode.node);
4833
+ // If nodePatches is null, the root node types are incompatible - need to replace
4834
+ if (nodePatches === null) {
4835
+ const flatNodes = treeToArray(newNode);
4836
+ patches.push({
4837
+ type: Replace,
4838
+ nodes: flatNodes
4839
+ });
4840
+ return;
4841
+ }
4842
+ if (nodePatches.length > 0) {
4843
+ patches.push(...nodePatches);
4844
+ }
4845
+ // Compare children
4846
+ if (oldNode.children.length > 0 || newNode.children.length > 0) {
4847
+ diffChildren(oldNode.children, newNode.children, patches);
4848
+ }
4849
+ } else {
4850
+ // Non-root level or multiple root elements - use the regular comparison
4851
+ diffChildren(oldTree, newTree, patches);
4852
+ }
4853
+ };
4854
+
4855
+ const removeTrailingNavigationPatches = patches => {
4856
+ // Find the last non-navigation patch
4857
+ let lastNonNavigationIndex = -1;
4858
+ for (let i = patches.length - 1; i >= 0; i--) {
4859
+ const patch = patches[i];
4860
+ if (patch.type !== NavigateChild && patch.type !== NavigateParent && patch.type !== NavigateSibling) {
4861
+ lastNonNavigationIndex = i;
4862
+ break;
4863
+ }
4864
+ }
4865
+ // Return patches up to and including the last non-navigation patch
4866
+ return lastNonNavigationIndex === -1 ? [] : patches.slice(0, lastNonNavigationIndex + 1);
4867
+ };
4868
+
4869
+ const diffTree = (oldNodes, newNodes) => {
4870
+ // Step 1: Convert flat arrays to tree structures
4871
+ const oldTree = arrayToTree(oldNodes);
4872
+ const newTree = arrayToTree(newNodes);
4873
+ // Step 3: Compare the trees
4874
+ const patches = [];
4875
+ diffTrees(oldTree, newTree, patches, []);
4876
+ // Remove trailing navigation patches since they serve no purpose
4877
+ return removeTrailingNavigationPatches(patches);
4878
+ };
4879
+
4880
+ const ChatDebugView = 'ChatDebugView';
4881
+ const ChatDebugViewDevtools = 'ChatDebugView--devtools';
4882
+ const ChatDebugViewDetails = 'ChatDebugViewDetails';
4883
+ const ChatDebugViewDetailsBottom = 'ChatDebugViewDetailsBottom';
4884
+ const ChatDebugViewDetailsClose = 'ChatDebugViewDetailsClose';
4885
+ const EditorContainer = 'EditorContainer';
4886
+ const PanelTab = 'PanelTab';
4887
+ const PanelTabSelected = 'PanelTabSelected';
4888
+ const ChatDebugViewDetailsTabs = 'ChatDebugViewDetailsTabs';
4889
+ const ChatDebugViewDetailsTop = 'ChatDebugViewDetailsTop';
4890
+ const ChatDebugViewDevtoolsSplit = 'ChatDebugViewDevtoolsSplit';
4891
+ const ChatDebugViewEmpty = 'ChatDebugViewEmpty';
4892
+ const ChatDebugViewError = 'ChatDebugViewError';
4893
+ const EditorContent = 'EditorContent';
4894
+ const EditorInput = 'EditorInput';
4895
+ const EditorLayers = 'EditorLayers';
4896
+ const EditorRow = 'EditorRow';
4897
+ const EditorRows = 'EditorRows';
4898
+ const EditorSelection = 'EditorSelection';
4899
+ const EditorSelections = 'Selections';
4900
+ const EditorViewlet = 'Viewlet Editor';
4901
+ const ChatDebugViewEventLineNumber = 'ChatDebugViewEventLineNumber';
4902
+ const Gutter = 'Gutter';
4903
+ const TableRowSelected = 'TableRowSelected';
4904
+ const ChatDebugViewEvents = 'ChatDebugViewEvents';
4905
+ const ChatDebugViewEventsFullWidth = 'ChatDebugViewEventsFullWidth';
4906
+ const ChatDebugViewFilterInput = 'ChatDebugViewFilterInput';
4907
+ const ChatDebugViewFilterInputDevtools = 'ChatDebugViewFilterInput--devtools';
4908
+ const ChatDebugViewHeaderCell = 'TableCell';
4909
+ const ChatDebugViewImagePreview = 'ChatDebugViewImagePreview';
4910
+ const ChatDebugViewImagePreviewImageWrapper = 'ChatDebugViewImagePreviewImageWrapper';
4911
+ const ChatDebugViewImagePreviewImage = 'ChatDebugViewImagePreviewImage';
4912
+ const ChatDebugViewImagePreviewLabel = 'ChatDebugViewImagePreviewLabel';
4913
+ const ChatDebugViewRefreshButton = 'ChatDebugViewRefreshButton';
4914
+ const ChatDebugViewQuickFilterPill = 'ChatDebugViewQuickFilterPill';
4915
+ const ChatDebugViewQuickFilterPillSelected = 'ChatDebugViewQuickFilterPillSelected';
4916
+ const ChatDebugViewQuickFilters = 'ChatDebugViewQuickFilters';
4917
+ const Sash = 'Sash';
4918
+ const Table = 'Table';
4919
+ const TableBody = 'TableBody';
4920
+ const TableSummary = 'TableSummary';
4921
+ const TableScrollBar = 'TableScrollBar';
4922
+ const TableScrollBarThumb = 'TableScrollBarThumb';
4923
+ const TableWrapper = 'TableWrapper';
4924
+ const TableWrapperWrapper = 'TableWrapperWrapper';
4925
+ const FocusOutline = 'FocusOutline';
4926
+ const Resizer = 'Resizer';
4927
+ const ResizerInner = 'ResizerInner';
4928
+ const ResizerOne = 'ResizerOne';
4929
+ const ResizerTwo = 'ResizerTwo';
4930
+ const TableHead = 'TableHead';
4931
+ const Resizers = 'Resizers';
4932
+ const TableCol = 'TableCol';
4933
+ const TableRow = 'TableRow';
4934
+ const TableRowOdd = 'TableRowOdd';
4935
+ const TableRowEven = 'TableRowEven';
4936
+ const ChatDebugViewTimeline = 'ChatDebugViewTimeline';
4937
+ const ChatDebugViewTimelineBadge = 'ChatDebugViewTimelineBadge';
4938
+ const ChatDebugViewTimelineBadges = 'ChatDebugViewTimelineBadges';
4939
+ const ChatDebugViewTimelineBucket = 'ChatDebugViewTimelineBucket';
4940
+ const ChatDebugViewTimelineBucketBar = 'ChatDebugViewTimelineBucketBar';
4941
+ const ChatDebugViewTimelineBucketBarSelected = 'ChatDebugViewTimelineBucketBarSelected';
4942
+ const ChatDebugViewTimelineBucketSelected = 'ChatDebugViewTimelineBucketSelected';
4943
+ const ChatDebugViewTimelineBucketUnit = 'ChatDebugViewTimelineBucketUnit';
4944
+ const ChatDebugViewTimelineBucketUnitEmpty = 'ChatDebugViewTimelineBucketUnitEmpty';
4945
+ const ChatDebugViewTimelineBuckets = 'ChatDebugViewTimelineBuckets';
4946
+ const ChatDebugViewTimelineCursorGuide = 'ChatDebugViewTimelineCursorGuide';
4947
+ const ChatDebugViewTimelineCursorGuideVisible = 'ChatDebugViewTimelineCursorGuideVisible';
4948
+ const ChatDebugViewTimelineInteractive = 'ChatDebugViewTimelineInteractive';
4949
+ const ChatDebugViewTimelineSelectionHandle = 'ChatDebugViewTimelineSelectionHandle';
4950
+ const ChatDebugViewTimelineSelectionHandleEnd = 'ChatDebugViewTimelineSelectionHandleEnd';
4951
+ const ChatDebugViewTimelineSelectionHandleStart = 'ChatDebugViewTimelineSelectionHandleStart';
4952
+ const ChatDebugViewTimelineSelectionMarker = 'ChatDebugViewTimelineSelectionMarker';
4953
+ const ChatDebugViewTimelineSelectionMarkerEnd = 'ChatDebugViewTimelineSelectionMarkerEnd';
4954
+ const ChatDebugViewTimelineSelectionMarkerStart = 'ChatDebugViewTimelineSelectionMarkerStart';
4955
+ const ChatDebugViewTimelineSelectionOverlay = 'ChatDebugViewTimelineSelectionOverlay';
4956
+ const ChatDebugViewTimelineSelectionRange = 'ChatDebugViewTimelineSelectionRange';
4957
+ const ChatDebugViewTiming = 'ChatDebugViewTiming';
4958
+ const ChatDebugViewTimingLabel = 'ChatDebugViewTimingLabel';
4959
+ const ChatDebugViewTimingPreview = 'ChatDebugViewTimingPreview';
4960
+ const ChatDebugViewTimingPreviewMarker = 'ChatDebugViewTimingPreviewMarker';
4961
+ const ChatDebugViewTimingPreviewMarkerEnd = 'ChatDebugViewTimingPreviewMarkerEnd';
4962
+ const ChatDebugViewTimingPreviewMarkerStart = 'ChatDebugViewTimingPreviewMarkerStart';
4963
+ const ChatDebugViewTimingPreviewRail = 'ChatDebugViewTimingPreviewRail';
4964
+ const ChatDebugViewTimingPreviewSegment = 'ChatDebugViewTimingPreviewSegment';
4965
+ const ChatDebugViewTimingPreviewTrack = 'ChatDebugViewTimingPreviewTrack';
4966
+ const ChatDebugViewTimingPreviewTrackOverlay = 'ChatDebugViewTimingPreviewTrackOverlay';
4967
+ const ChatDebugViewTimingRow = 'ChatDebugViewTimingRow';
4968
+ const ChatDebugViewTimingValue = 'ChatDebugViewTimingValue';
4969
+ const ChatDebugViewTop = 'ChatDebugViewTop';
4970
+ const ChatDebugViewTopDevtools = 'ChatDebugViewTop--devtools';
4971
+ const TableCell = 'TableCell';
4972
+ const ChatDebugViewCellDuration = 'ChatDebugViewCellDuration';
4973
+ const ChatDebugViewCellStatusError = 'ChatDebugViewCellStatusError';
4974
+ const InputBox = 'InputBox';
4975
+ const TokenBoolean = 'Token TokenBoolean';
4976
+ const TokenKey = 'Token TokenKey';
4977
+ const TokenNumeric = 'Token TokenNumeric';
4978
+ const TokenString = 'Token TokenString';
4979
+ const TokenText = 'Token TokenText';
4980
+
4981
+ const debugErrorRootNode = {
4982
+ childCount: 1,
4983
+ className: ChatDebugView,
4984
+ type: Div
4985
+ };
4986
+ const debugErrorMessageNode = {
4987
+ childCount: 1,
4988
+ className: ChatDebugViewError,
4989
+ type: Div
4990
+ };
4991
+ const getDebugErrorDom = errorMessage => {
4992
+ return [debugErrorRootNode, debugErrorMessageNode, text(errorMessage)];
4993
+ };
4994
+
4995
+ const HandleEventCategoryFilter = 4;
4996
+ const HandleFilterInput = 5;
4997
+ const SelectDetailTab = 6;
4998
+ const HandleEventRowClickAt = 7;
4999
+ const HandleHeaderContextMenu = 8;
5000
+ const HandleSashPointerDown = 9;
5001
+ const HandleSashPointerMove = 10;
5002
+ const HandleSashPointerUp = 11;
5003
+ const HandleTableResizerPointerDown = 12;
5004
+ const HandleTableResizerPointerMove = 13;
5005
+ const HandleTableResizerPointerUp = 14;
5006
+ const HandleTableBodyContextMenu = 15;
5007
+ const HandleDetailsContextMenu = 16;
5008
+ const HandleTimelinePointerDown = 17;
5009
+ const HandleTimelinePointerMove = 18;
5010
+ const HandleTimelinePointerUp = 19;
5011
+ const HandleTimelineDoubleClick = 20;
5012
+ const HandleTableHeaderClick = 21;
5013
+ const HandleTimelineRangePreset = 22;
5014
+ const HandleCloseDetails = 23;
5015
+ const HandleClickRefresh = 24;
5016
+ const HandleDetailsTopContextMenu = 25;
5017
+ const HandleTimelineContextMenu = 26;
5018
+ const HandleTimelinePointerLeave = 27;
5019
+ const HandleEventRowClick = 28;
5020
+ const HandleTableFocus = 29;
5021
+ const HandleDetailTabsFocus = 30;
5022
+ const HandlePreviewTextPointerDown = 31;
5023
+ const HandleTableScrollBarPointerDown = 32;
5024
+ const HandleTableScrollBarPointerMove = 33;
5025
+ const HandleTableScrollBarPointerUp = 34;
5026
+ const HandleTableWheel = 35;
5027
+
5028
+ const getFilterInputDom = (filterValue, useDevtoolsLayout) => {
5029
+ return {
5030
+ autocomplete: 'off',
5031
+ childCount: 0,
5032
+ className: useDevtoolsLayout ? mergeClassNames(InputBox, ChatDebugViewFilterInput, ChatDebugViewFilterInputDevtools) : mergeClassNames(InputBox, ChatDebugViewFilterInput),
5033
+ inputType: 'search',
5034
+ name: Filter,
5035
+ onInput: HandleFilterInput,
5036
+ placeholder: filterEvents(),
5037
+ type: Input,
5038
+ value: filterValue
5039
+ };
5040
+ };
5041
+
5042
+ const getQuickFilterDom = categoryFilter => {
5043
+ const {
5044
+ isSelected,
5045
+ label,
5046
+ name
5047
+ } = categoryFilter;
5048
+ return [{
5049
+ ariaSelected: isSelected,
5050
+ childCount: 1,
5051
+ className: mergeClassNames(ChatDebugViewQuickFilterPill, isSelected ? ChatDebugViewQuickFilterPillSelected : ''),
5052
+ name,
5053
+ onClick: HandleEventCategoryFilter,
5054
+ role: Option,
5055
+ type: Button$1
5056
+ }, text(label)];
4704
5057
  };
4705
5058
 
4706
- const getPreviewName = event => {
4707
- if (typeof event.name === 'string' && event.name) {
4708
- return event.name;
4709
- }
4710
- if (typeof event.toolName === 'string' && event.toolName) {
4711
- return event.toolName;
4712
- }
4713
- return undefined;
5059
+ // cspell:ignore multiselectable
5060
+ const getQuickFilterNodes = categoryFilters => {
5061
+ return [{
5062
+ 'aria-multiselectable': true,
5063
+ childCount: categoryFilters.length,
5064
+ className: ChatDebugViewQuickFilters,
5065
+ onClick: HandleEventCategoryFilter,
5066
+ role: ListBox,
5067
+ type: Div
5068
+ }, ...categoryFilters.flatMap(getQuickFilterDom)];
4714
5069
  };
4715
5070
 
4716
- const hasOwn = (event, key) => {
4717
- return Object.hasOwn(event, key);
5071
+ const refreshButtonDom = [{
5072
+ 'aria-label': refreshEvents$1(),
5073
+ childCount: 1,
5074
+ className: ChatDebugViewRefreshButton,
5075
+ name: Refresh,
5076
+ onClick: HandleClickRefresh,
5077
+ type: Button$1,
5078
+ value: Refresh
5079
+ }, text(refresh$1())];
5080
+ const getRefreshButtonDom = () => {
5081
+ return refreshButtonDom;
4718
5082
  };
4719
5083
 
4720
- const shouldIncludeArguments = (event, name) => {
4721
- if (!hasOwn(event, 'arguments')) {
4722
- return false;
4723
- }
4724
- if (name === 'getWorkspaceUri') {
4725
- return false;
5084
+ const getDebugViewTopDom = (filterValue, useDevtoolsLayout, categoryFilters) => {
5085
+ const refreshButtonDom = getRefreshButtonDom();
5086
+ if (useDevtoolsLayout) {
5087
+ const quickFilterNodes = getQuickFilterNodes(categoryFilters);
5088
+ return [{
5089
+ childCount: 2 + (quickFilterNodes.length > 0 ? 1 : 0),
5090
+ className: mergeClassNames(ChatDebugViewTop, ChatDebugViewTopDevtools),
5091
+ onContextMenu: HandleHeaderContextMenu,
5092
+ type: Search
5093
+ }, getFilterInputDom(filterValue, true), ...quickFilterNodes, ...refreshButtonDom];
4726
5094
  }
4727
- return true;
5095
+ return [{
5096
+ childCount: 2,
5097
+ className: ChatDebugViewTop,
5098
+ onContextMenu: HandleHeaderContextMenu,
5099
+ type: Search
5100
+ }, getFilterInputDom(filterValue, false), ...refreshButtonDom];
4728
5101
  };
4729
5102
 
4730
- const getPayloadEvent = event => {
4731
- const name = getPreviewName(event);
4732
- if (name === 'list_files' && hasOwn(event, 'arguments')) {
4733
- return event.arguments;
4734
- }
4735
- const payloadEvent = {
4736
- ...(name === undefined ? {} : {
4737
- name
4738
- }),
4739
- ...(shouldIncludeArguments(event, name) ? {
4740
- arguments: event.arguments
4741
- } : {}),
4742
- ...(hasOwn(event, 'result') ? {
4743
- result: event.result
4744
- } : {})
4745
- };
4746
- if (Object.keys(payloadEvent).length > 0) {
4747
- return payloadEvent;
4748
- }
4749
- return event;
5103
+ const detailsCloseButtonDom = [{
5104
+ 'aria-label': closeDetails(),
5105
+ childCount: 1,
5106
+ className: ChatDebugViewDetailsClose,
5107
+ name: CloseDetails,
5108
+ onChange: HandleCloseDetails,
5109
+ onClick: HandleCloseDetails,
5110
+ type: Button$1,
5111
+ value: 'close'
5112
+ }, {
5113
+ childCount: 0,
5114
+ className: 'MaskIcon MaskIconClose',
5115
+ type: Div
5116
+ }];
5117
+ const getDetailsCloseButtonDom = () => {
5118
+ return detailsCloseButtonDom;
4750
5119
  };
4751
5120
 
4752
- const getListFilesPreviewEvent = (event, name) => {
4753
- if (name !== 'list_files') {
4754
- return undefined;
4755
- }
4756
- const {
4757
- result
4758
- } = event;
4759
- if (typeof result !== 'object' || result === null) {
4760
- return undefined;
4761
- }
4762
- const {
4763
- entries,
4764
- error
4765
- } = result;
4766
- if (entries !== undefined) {
4767
- return entries;
4768
- }
4769
- return error;
5121
+ const defaultEditorCursor = {
5122
+ columnIndex: 0,
5123
+ rowIndex: 1
4770
5124
  };
4771
-
4772
- const isChatMessageAddedEvent = event => {
4773
- return event.type === 'chat-message-added';
5125
+ const getEditorSelectionDom = (cursor = defaultEditorCursor) => {
5126
+ const hasCursor = cursor !== null;
5127
+ return [{
5128
+ childCount: hasCursor ? 1 : 0,
5129
+ className: EditorSelections,
5130
+ type: Div
5131
+ }, ...(hasCursor ? [{
5132
+ childCount: 0,
5133
+ className: EditorSelection,
5134
+ style: getPreviewTextCursorStyle(cursor),
5135
+ type: Div
5136
+ }] : [])];
4774
5137
  };
4775
-
4776
- const isChatMessageUpdatedEvent = event => {
4777
- return event.type === 'chat-message-updated';
5138
+ const getGutterDom = (lineData, showLineNumbers) => {
5139
+ const gutterNodes = showLineNumbers ? lineData.flatMap((_, index) => {
5140
+ return [{
5141
+ childCount: 1,
5142
+ className: ChatDebugViewEventLineNumber,
5143
+ type: Span
5144
+ }, text(String(index + 1))];
5145
+ }) : [];
5146
+ return [{
5147
+ childCount: showLineNumbers ? lineData.length : 0,
5148
+ className: Gutter,
5149
+ type: Div
5150
+ }, ...gutterNodes];
4778
5151
  };
4779
-
4780
- const getResponseContentText = content => {
4781
- if (!content || typeof content !== 'object') {
4782
- return undefined;
4783
- }
4784
- if (Array.isArray(content)) {
4785
- const [firstContentItem] = content;
4786
- if (!firstContentItem || typeof firstContentItem !== 'object') {
4787
- return undefined;
4788
- }
4789
- const {
4790
- text
4791
- } = firstContentItem;
4792
- return typeof text === 'string' ? text : undefined;
4793
- }
4794
- const {
4795
- text
4796
- } = content;
4797
- return typeof text === 'string' ? text : undefined;
5152
+ const getEditorRowDom = line => {
5153
+ return [{
5154
+ childCount: line.childCount,
5155
+ className: EditorRow,
5156
+ type: Div
5157
+ }, ...line.nodes];
4798
5158
  };
4799
- const getSseResponseCompletedPreviewText = event => {
4800
- if (event.type !== 'sse-response-completed') {
4801
- return undefined;
4802
- }
4803
- const {
4804
- value
4805
- } = event;
4806
- if (!value || typeof value !== 'object') {
4807
- return undefined;
4808
- }
4809
- const {
4810
- response
4811
- } = value;
4812
- if (!response || typeof response !== 'object') {
4813
- return undefined;
4814
- }
4815
- const {
4816
- output
4817
- } = response;
4818
- if (!Array.isArray(output) || output.length === 0) {
4819
- return undefined;
4820
- }
4821
- const [firstOutput] = output;
4822
- if (!firstOutput || typeof firstOutput !== 'object') {
4823
- return undefined;
4824
- }
4825
- const {
4826
- content
4827
- } = firstOutput;
4828
- return getResponseContentText(content);
5159
+ const getEditorRowsDom = lineData => {
5160
+ return [{
5161
+ childCount: lineData.length,
5162
+ className: EditorRows,
5163
+ type: Div
5164
+ }, ...lineData.flatMap(getEditorRowDom)];
4829
5165
  };
4830
- const getPreviewMessageText = event => {
4831
- if (isChatMessageUpdatedEvent(event) && typeof event.text === 'string') {
4832
- return event.text;
4833
- }
4834
- const sseResponseCompletedPreviewText = getSseResponseCompletedPreviewText(event);
4835
- if (sseResponseCompletedPreviewText !== undefined) {
4836
- return sseResponseCompletedPreviewText;
4837
- }
4838
- if (!isChatMessageAddedEvent(event)) {
4839
- return undefined;
4840
- }
4841
- const {
4842
- message
4843
- } = event;
4844
- if (!message || typeof message !== 'object') {
4845
- return undefined;
4846
- }
4847
- if (!Object.hasOwn(message, 'text')) {
4848
- return undefined;
4849
- }
4850
- const {
4851
- text
4852
- } = message;
4853
- if (typeof text !== 'string') {
4854
- return undefined;
4855
- }
4856
- return text;
5166
+ const getEditorDom = (lineData, showLineNumbers = true, cursor = defaultEditorCursor, onPointerDown) => {
5167
+ return [{
5168
+ childCount: 1,
5169
+ className: EditorContainer,
5170
+ type: Div
5171
+ }, {
5172
+ childCount: 2,
5173
+ className: EditorViewlet,
5174
+ role: 'code',
5175
+ type: Div
5176
+ }, ...getGutterDom(lineData, showLineNumbers), {
5177
+ childCount: 2,
5178
+ className: EditorContent,
5179
+ onPointerDown,
5180
+ type: Div
5181
+ }, {
5182
+ 'aria-autocomplete': 'list',
5183
+ 'aria-multiline': true,
5184
+ 'aria-roledescription': 'editor',
5185
+ autocapitalize: 'off',
5186
+ autocomplete: 'off',
5187
+ autocorrect: 'off',
5188
+ childCount: 0,
5189
+ className: EditorInput,
5190
+ name: 'editor',
5191
+ role: 'textbox',
5192
+ spellcheck: false,
5193
+ type: TextArea,
5194
+ wrap: 'off'
5195
+ }, {
5196
+ childCount: 2,
5197
+ className: EditorLayers,
5198
+ type: Div
5199
+ }, ...getEditorSelectionDom(cursor), ...getEditorRowsDom(lineData)];
4857
5200
  };
4858
5201
 
4859
- const getReadFilePreviewText = (event, name) => {
4860
- if (name !== 'read_file') {
4861
- return undefined;
5202
+ const isDigit = character => {
5203
+ return character !== undefined && character >= '0' && character <= '9';
5204
+ };
5205
+ const isWhitespace = character => {
5206
+ return character === ' ' || character === '\n' || character === '\r' || character === '\t';
5207
+ };
5208
+ const getNumberEnd = (json, start) => {
5209
+ let i = start;
5210
+ if (json[i] === '-') {
5211
+ i++;
4862
5212
  }
4863
- const {
4864
- result
4865
- } = event;
4866
- if (typeof result !== 'string') {
4867
- return undefined;
5213
+ if (json[i] === '0') {
5214
+ i++;
5215
+ } else {
5216
+ if (!isDigit(json[i])) {
5217
+ return start;
5218
+ }
5219
+ while (isDigit(json[i])) {
5220
+ i++;
5221
+ }
4868
5222
  }
4869
- return result;
4870
- };
4871
-
4872
- const getWriteFilePreviewText = (event, name) => {
4873
- if (name !== 'write_file') {
4874
- return undefined;
5223
+ if (json[i] === '.') {
5224
+ const decimalStart = i;
5225
+ i++;
5226
+ if (!isDigit(json[i])) {
5227
+ return decimalStart;
5228
+ }
5229
+ while (isDigit(json[i])) {
5230
+ i++;
5231
+ }
4875
5232
  }
4876
- const {
4877
- arguments: toolArguments
4878
- } = event;
4879
- if (typeof toolArguments !== 'object' || toolArguments === null || !Object.hasOwn(toolArguments, 'content')) {
4880
- return undefined;
5233
+ if (json[i] === 'e' || json[i] === 'E') {
5234
+ const exponentStart = i;
5235
+ i++;
5236
+ if (json[i] === '+' || json[i] === '-') {
5237
+ i++;
5238
+ }
5239
+ if (!isDigit(json[i])) {
5240
+ return exponentStart;
5241
+ }
5242
+ while (isDigit(json[i])) {
5243
+ i++;
5244
+ }
4881
5245
  }
4882
- const {
4883
- content
4884
- } = toolArguments;
4885
- if (typeof content !== 'string') {
4886
- return undefined;
5246
+ return i;
5247
+ };
5248
+ const forEachTokenSegment = (json, onToken) => {
5249
+ let i = 0;
5250
+ while (i < json.length) {
5251
+ const character = json[i];
5252
+ if (character === '"') {
5253
+ const start = i;
5254
+ i++;
5255
+ while (i < json.length) {
5256
+ const currentCharacter = json[i];
5257
+ if (currentCharacter === '\\') {
5258
+ i += 2;
5259
+ continue;
5260
+ }
5261
+ if (currentCharacter === '"') {
5262
+ i++;
5263
+ break;
5264
+ }
5265
+ i++;
5266
+ }
5267
+ let lookAheadIndex = i;
5268
+ while (lookAheadIndex < json.length && isWhitespace(json[lookAheadIndex])) {
5269
+ lookAheadIndex++;
5270
+ }
5271
+ const className = json[lookAheadIndex] === ':' ? TokenKey : TokenString;
5272
+ onToken(className, json.slice(start, i));
5273
+ continue;
5274
+ }
5275
+ const numberEnd = getNumberEnd(json, i);
5276
+ if (numberEnd > i) {
5277
+ onToken(TokenNumeric, json.slice(i, numberEnd));
5278
+ i = numberEnd;
5279
+ continue;
5280
+ }
5281
+ if (json.startsWith('true', i)) {
5282
+ onToken(TokenBoolean, 'true');
5283
+ i += 4;
5284
+ continue;
5285
+ }
5286
+ if (json.startsWith('false', i)) {
5287
+ onToken(TokenBoolean, 'false');
5288
+ i += 5;
5289
+ continue;
5290
+ }
5291
+ if (json.startsWith('null', i)) {
5292
+ onToken(TokenBoolean, 'null');
5293
+ i += 4;
5294
+ continue;
5295
+ }
5296
+ onToken(TokenText, character);
5297
+ i++;
4887
5298
  }
4888
- return content;
4889
5299
  };
4890
5300
 
4891
- const getPreviewEvent = event => {
4892
- const selectedEventPreview = getSelectedEventPreview(event);
4893
- if (selectedEventPreview !== undefined) {
4894
- return selectedEventPreview;
4895
- }
4896
- const previewMessageText = getPreviewMessageText(event);
4897
- if (previewMessageText !== undefined) {
4898
- return previewMessageText;
4899
- }
4900
- const name = getPreviewName(event);
4901
- const writeFilePreviewText = getWriteFilePreviewText(event, name);
4902
- if (writeFilePreviewText !== undefined) {
4903
- return writeFilePreviewText;
4904
- }
4905
- const readFilePreviewText = getReadFilePreviewText(event, name);
4906
- if (readFilePreviewText !== undefined) {
4907
- return readFilePreviewText;
4908
- }
4909
- const listFilesPreviewEvent = getListFilesPreviewEvent(event, name);
4910
- if (listFilesPreviewEvent !== undefined) {
4911
- return listFilesPreviewEvent;
5301
+ const getJsonLines = value => {
5302
+ const json = JSON.stringify(value, null, 2);
5303
+ if (!json) {
5304
+ return [[{
5305
+ className: TokenText,
5306
+ value: String(json)
5307
+ }]];
4912
5308
  }
4913
- return getPayloadEvent(event);
5309
+ const lines = [];
5310
+ let currentLine = [];
5311
+ const pushLineSegment = (className, lineValue) => {
5312
+ if (!lineValue) {
5313
+ return;
5314
+ }
5315
+ const lastSegment = currentLine.at(-1);
5316
+ if (lastSegment && lastSegment.className === className) {
5317
+ lastSegment.value += lineValue;
5318
+ return;
5319
+ }
5320
+ currentLine.push({
5321
+ className,
5322
+ value: lineValue
5323
+ });
5324
+ };
5325
+ forEachTokenSegment(json, (className, segmentValue) => {
5326
+ let start = 0;
5327
+ for (let i = 0; i < segmentValue.length; i++) {
5328
+ if (segmentValue[i] === '\n') {
5329
+ pushLineSegment(className, segmentValue.slice(start, i));
5330
+ lines.push(currentLine);
5331
+ currentLine = [];
5332
+ start = i + 1;
5333
+ }
5334
+ }
5335
+ pushLineSegment(className, segmentValue.slice(start));
5336
+ });
5337
+ lines.push(currentLine);
5338
+ return lines;
5339
+ };
5340
+ const getLineContentNodes = line => {
5341
+ return line.flatMap(segment => {
5342
+ return [{
5343
+ childCount: 1,
5344
+ className: segment.className,
5345
+ type: Span
5346
+ }, text(segment.value)];
5347
+ });
5348
+ };
5349
+ const isChatViewEvent = value => {
5350
+ return typeof value === 'object' && value !== null && typeof value.type === 'string';
5351
+ };
5352
+ const getEventNode = value => {
5353
+ const renderedValue = isChatViewEvent(value) ? {
5354
+ ...value,
5355
+ type: getEventTypeLabel(value)
5356
+ } : value;
5357
+ const lines = getJsonLines(renderedValue);
5358
+ const lineData = lines.map(line => {
5359
+ const lineContentNodes = getLineContentNodes(line);
5360
+ return {
5361
+ childCount: lineContentNodes.length / 2,
5362
+ nodes: lineContentNodes
5363
+ };
5364
+ });
5365
+ return getEditorDom(lineData);
5366
+ };
5367
+
5368
+ const getPanelId = detailTab => {
5369
+ return `ChatDebugViewDetailsPanel-${detailTab}`;
4914
5370
  };
4915
5371
 
4916
5372
  const isAttachmentImagePreview = value => {
@@ -4955,11 +5411,11 @@ const getImagePreviewDom = preview => {
4955
5411
  }, ...getImagePreviewLabelDom(preview)];
4956
5412
  };
4957
5413
 
4958
- const getTextNode = (value, showLineNumbers = true) => {
5414
+ const getTextNode = (value, showLineNumbers = true, cursor = null) => {
4959
5415
  const lines = value.split('\n');
4960
5416
  const lineData = lines.map(line => {
4961
5417
  return {
4962
- childCount: 2,
5418
+ childCount: 1,
4963
5419
  nodes: [{
4964
5420
  childCount: 1,
4965
5421
  className: TokenText,
@@ -4967,15 +5423,15 @@ const getTextNode = (value, showLineNumbers = true) => {
4967
5423
  }, text(line)]
4968
5424
  };
4969
5425
  });
4970
- return getEditorDom(lineData, showLineNumbers);
5426
+ return getEditorDom(lineData, showLineNumbers, cursor, showLineNumbers ? HandlePreviewTextPointerDown : undefined);
4971
5427
  };
4972
5428
 
4973
- const getPreviewEventNodes = (previewEvent, selectedEvent) => {
5429
+ const getPreviewEventNodes = (previewEvent, selectedEvent, previewTextCursor) => {
4974
5430
  if (typeof previewEvent === 'string') {
4975
5431
  const isInvalidImageMessage = previewEvent === ImageCouldNotBeLoaded;
4976
5432
  const isChatMessageUpdatedPreview = !!selectedEvent && isChatMessageUpdatedEvent(selectedEvent);
4977
5433
  const showLineNumbers = !isInvalidImageMessage && !isChatMessageUpdatedPreview;
4978
- return getTextNode(previewEvent, showLineNumbers);
5434
+ return getTextNode(previewEvent, showLineNumbers, showLineNumbers ? previewTextCursor ?? null : null);
4979
5435
  }
4980
5436
  if (previewEvent === undefined) {
4981
5437
  return [];
@@ -5151,7 +5607,7 @@ const getNormalizedDetailTabs = (selectedEvent, detailTabs) => {
5151
5607
  }
5152
5608
  return createDetailTabs(getSelectedDetailTab(detailTabs), selectedEvent);
5153
5609
  };
5154
- const getDetailsDom = (previewEventNodes, payloadEventNodes = previewEventNodes, responseEventNodes = payloadEventNodes, selectedEvent = null, detailTabs = createDetailTabs()) => {
5610
+ const getDetailsDom = (previewEventNodes, payloadEventNodes = previewEventNodes, responseEventNodes = payloadEventNodes, selectedEvent = null, detailTabs = createDetailTabs(), previewTextCursorRowIndex = null, previewTextCursorColumnIndex = null) => {
5155
5611
  if (previewEventNodes.length === 0 && payloadEventNodes.length === 0 && responseEventNodes.length === 0) {
5156
5612
  return [];
5157
5613
  }
@@ -5172,7 +5628,10 @@ const getDetailsDom = (previewEventNodes, payloadEventNodes = previewEventNodes,
5172
5628
  if (selectedEvent === null) {
5173
5629
  return [];
5174
5630
  }
5175
- return getPreviewEventNodes(getPreviewEvent(selectedEvent), selectedEvent);
5631
+ return getPreviewEventNodes(getPreviewEvent(selectedEvent), selectedEvent, previewTextCursorRowIndex === null || previewTextCursorColumnIndex === null ? null : {
5632
+ columnIndex: previewTextCursorColumnIndex,
5633
+ rowIndex: previewTextCursorRowIndex
5634
+ });
5176
5635
  };
5177
5636
  const getDetailContentDomPayload = () => {
5178
5637
  if (payloadEventNodes.length > 0) {
@@ -5218,7 +5677,6 @@ const getDetailsDom = (previewEventNodes, payloadEventNodes = previewEventNodes,
5218
5677
  const getRowCellNodes = (event, isErrorStatus, visibleTableColumns) => {
5219
5678
  const orderedVisibleTableColumns = getOrderedVisibleTableColumns(visibleTableColumns);
5220
5679
  return orderedVisibleTableColumns.flatMap((column, index) => {
5221
- const isFixed = index < orderedVisibleTableColumns.length - 1;
5222
5680
  switch (column) {
5223
5681
  case Duration:
5224
5682
  return [{
@@ -5229,7 +5687,7 @@ const getRowCellNodes = (event, isErrorStatus, visibleTableColumns) => {
5229
5687
  case Status$1:
5230
5688
  return [{
5231
5689
  childCount: 1,
5232
- className: mergeClassNames(TableCell, isErrorStatus ? ChatDebugViewCellStatusError : '', isFixed ? ChatDebugViewColumnFixed : ''),
5690
+ className: mergeClassNames(TableCell, isErrorStatus ? ChatDebugViewCellStatusError : ''),
5233
5691
  type: Td
5234
5692
  }, text(getStatusText(event))];
5235
5693
  case Type:
@@ -5244,16 +5702,18 @@ const getRowCellNodes = (event, isErrorStatus, visibleTableColumns) => {
5244
5702
  });
5245
5703
  };
5246
5704
 
5247
- const getDevtoolsRows = (events, selectedEventIndex, visibleTableColumns = defaultVisibleTableColumns) => {
5705
+ const getDevtoolsRows = (events, selectedEventIndex, visibleTableColumns = defaultVisibleTableColumns, startIndex = 0) => {
5248
5706
  return events.flatMap((event, i) => {
5249
- const isEvenRow = i % 2 === 1;
5707
+ const actualIndex = startIndex + i;
5708
+ const isEvenRow = actualIndex % 2 === 1;
5250
5709
  const rowClassName = isEvenRow ? TableRowEven : TableRowOdd;
5251
- const isSelected = selectedEventIndex === i;
5710
+ const isSelected = selectedEventIndex === actualIndex;
5252
5711
  const isErrorStatus = hasErrorStatus(event);
5253
5712
  const rowCellNodes = getRowCellNodes(event, isErrorStatus, visibleTableColumns);
5254
5713
  return [{
5255
5714
  childCount: visibleTableColumns.length,
5256
5715
  className: mergeClassNames(TableRow, rowClassName, isSelected ? TableRowSelected : ''),
5716
+ 'data-index': `${actualIndex}`,
5257
5717
  type: Tr
5258
5718
  }, ...rowCellNodes];
5259
5719
  });
@@ -5273,15 +5733,25 @@ const getEventsClassName = hasSelectedEvent => {
5273
5733
  return widthClassName;
5274
5734
  };
5275
5735
 
5736
+ const getResponseEvent = event => {
5737
+ const {
5738
+ responseEvent
5739
+ } = event;
5740
+ if (responseEvent && typeof responseEvent === 'object' && typeof responseEvent.type === 'string') {
5741
+ const mergedResponseEvent = responseEvent;
5742
+ if (mergedResponseEvent.value !== undefined) {
5743
+ return mergedResponseEvent.value;
5744
+ }
5745
+ return responseEvent;
5746
+ }
5747
+ return event;
5748
+ };
5749
+
5276
5750
  const sashNodesDom = [{
5277
- childCount: 1,
5751
+ childCount: 0,
5278
5752
  className: Sash,
5279
5753
  onPointerDown: HandleSashPointerDown,
5280
5754
  type: Button$1
5281
- }, {
5282
- childCount: 0,
5283
- className: ChatDebugViewSashLine,
5284
- type: Div
5285
5755
  }];
5286
5756
  const getSashNodesDom = hasSelectedEvent => {
5287
5757
  if (!hasSelectedEvent) {
@@ -5479,26 +5949,43 @@ const getTableResizersDom = visibleTableColumns => {
5479
5949
  }, ...resizerNodes];
5480
5950
  };
5481
5951
 
5482
- const getTableWrapperDom = (rowNodes, eventCount, visibleTableColumns = defaultVisibleTableColumns, tableColumns = createTableColumns(), summary = '', focus = 0, className = '', role = '') => {
5952
+ const getTableScrollBarDom = visible => {
5953
+ if (!visible) {
5954
+ return [];
5955
+ }
5956
+ return [{
5957
+ childCount: 1,
5958
+ className: TableScrollBar,
5959
+ onPointerDown: HandleTableScrollBarPointerDown,
5960
+ type: Div
5961
+ }, {
5962
+ childCount: 0,
5963
+ className: TableScrollBarThumb,
5964
+ type: Div
5965
+ }];
5966
+ };
5967
+
5968
+ const getTableWrapperDom = (rowNodes, eventCount, visibleTableColumns = defaultVisibleTableColumns, tableColumns = createTableColumns(), summary = '', focus = 0, className = '', role = '', showScrollBar = false) => {
5483
5969
  const tableWrapperClassName = mergeClassNames(TableWrapper, focus === FocusChatDebugTable ? FocusOutline : '', className);
5484
5970
  const tableWrapperNode = {
5485
- childCount: 2,
5971
+ childCount: showScrollBar ? 3 : 2,
5486
5972
  className: tableWrapperClassName,
5973
+ onWheel: HandleTableWheel,
5487
5974
  type: Div,
5488
5975
  ...(role ? {
5489
5976
  role
5490
5977
  } : {})
5491
5978
  };
5492
- return [tableWrapperNode, ...getTableDom(rowNodes, eventCount, visibleTableColumns, tableColumns, summary, focus), ...getTableResizersDom(visibleTableColumns)];
5979
+ return [tableWrapperNode, ...getTableDom(rowNodes, eventCount, visibleTableColumns, tableColumns, summary, focus), ...getTableResizersDom(visibleTableColumns), ...getTableScrollBarDom(showScrollBar)];
5493
5980
  };
5494
5981
 
5495
- const getTableWrapperWrapperDom = (rowNodes, eventCount, visibleTableColumns = defaultVisibleTableColumns, tableColumns = createTableColumns(), summary = '', focus = 0, className = '', role = '') => {
5982
+ const getTableWrapperWrapperDom = (rowNodes, eventCount, visibleTableColumns = defaultVisibleTableColumns, tableColumns = createTableColumns(), summary = '', focus = 0, className = '', role = '', showScrollBar = false) => {
5496
5983
  const tableSummaryNodes = getTableSummaryDom(summary);
5497
5984
  return [{
5498
5985
  childCount: tableSummaryNodes.length === 0 ? 1 : 2,
5499
5986
  className: TableWrapperWrapper,
5500
5987
  type: Div
5501
- }, ...getTableWrapperDom(rowNodes, eventCount, visibleTableColumns, tableColumns, summary, focus, className, role), ...tableSummaryNodes];
5988
+ }, ...getTableWrapperDom(rowNodes, eventCount, visibleTableColumns, tableColumns, summary, focus, className, role, showScrollBar), ...tableSummaryNodes];
5502
5989
  };
5503
5990
 
5504
5991
  const getBucketUnitDom = (unitCount, presetValue) => {
@@ -5624,36 +6111,31 @@ const getTimelineBadgeNodes = timelineInfo => {
5624
6111
  };
5625
6112
 
5626
6113
  const getTimelineSummary = timelineInfo => {
6114
+ if (timelineInfo.durationSeconds === 0) {
6115
+ return '';
6116
+ }
5627
6117
  if (timelineInfo.hasSelection && timelineInfo.startSeconds !== null && timelineInfo.endSeconds !== null) {
5628
6118
  return windowSummary(formatTimelineSeconds(timelineInfo.startSeconds), formatTimelineSeconds(timelineInfo.endSeconds), formatTimelineSeconds(timelineInfo.durationSeconds));
5629
6119
  }
5630
6120
  return windowSummary('0s', formatTimelineSeconds(timelineInfo.durationSeconds), formatTimelineSeconds(timelineInfo.durationSeconds));
5631
6121
  };
5632
6122
 
5633
- const getTimelineTopDom = timelineInfo => {
5634
- return [{
5635
- childCount: 1,
5636
- className: ChatDebugViewTimelineTop,
5637
- type: Div
5638
- }, text(getTimelineSummary(timelineInfo))];
5639
- };
5640
-
5641
6123
  // cspell:ignore gettimelinedom
5642
6124
  const getTimelineDom = (timelineInfo, hoverPercent = null) => {
5643
6125
  if (timelineInfo.buckets.length === 0) {
5644
6126
  return [];
5645
6127
  }
6128
+ const summary = getTimelineSummary(timelineInfo);
5646
6129
  const badgeNodes = getTimelineBadgeNodes(timelineInfo);
5647
6130
  const bucketNodes = getBucketsDom(timelineInfo.buckets);
5648
6131
  const selectionNodes = getSelectionNodesDom(timelineInfo.hasSelection, timelineInfo.selectionStartPercent, timelineInfo.selectionEndPercent);
5649
6132
  const cursorGuideNodes = getCursorGuideNodes(hoverPercent);
5650
- const timelineTopDom = getTimelineTopDom(timelineInfo);
5651
6133
  return [{
5652
- childCount: 2,
6134
+ childCount: summary ? 2 : 1,
5653
6135
  className: ChatDebugViewTimeline,
5654
6136
  onContextMenu: HandleTimelineContextMenu,
5655
6137
  type: Section
5656
- }, ...timelineTopDom, {
6138
+ }, ...(summary ? [text(summary)] : []), {
5657
6139
  childCount: 3,
5658
6140
  className: ChatDebugViewTimelineInteractive,
5659
6141
  onDblClick: HandleTimelineDoubleClick,
@@ -5674,20 +6156,25 @@ const getTimelineDom = (timelineInfo, hoverPercent = null) => {
5674
6156
  }, ...selectionNodes];
5675
6157
  };
5676
6158
 
5677
- const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage = noEventsFound(), timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', detailTabs = createDetailTabs(), visibleTableColumns = defaultVisibleTableColumns, tableColumns = createTableColumns(), timelineInfo, timelineHoverPercent = null, focus = 0) => {
5678
- const rowNodes = getDevtoolsRows(events, selectedEventIndex, visibleTableColumns);
6159
+ const getDevtoolsDom = (events, selectedEvent, selectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage = noEventsFound(), timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', detailTabs = createDetailTabs(), visibleTableColumns = defaultVisibleTableColumns, tableColumns = createTableColumns(), timelineInfo, timelineHoverPercent = null, focus = 0, previewTextCursorRowIndex = null, previewTextCursorColumnIndex = null, minLineY = 0, maxLineY = events.length) => {
6160
+ const visibleEvents = events.slice(minLineY, maxLineY);
6161
+ const rowNodes = getDevtoolsRows(visibleEvents, selectedEventIndex, visibleTableColumns, minLineY);
5679
6162
  const effectiveRange = getEffectiveTimelineRange(timelineStartSeconds, timelineEndSeconds, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds);
5680
6163
  const resolvedTimelineInfo = timelineInfo || getTimelineInfo(timelineEvents, effectiveRange.startSeconds, effectiveRange.endSeconds);
5681
6164
  const timelineNodes = getTimelineDom(resolvedTimelineInfo, timelineHoverPercent);
5682
6165
  const previewEvent = selectedEvent ? getPreviewEvent(selectedEvent) : undefined;
5683
- const previewEventNodes = getPreviewEventNodes(previewEvent, selectedEvent);
6166
+ const previewEventNodes = getPreviewEventNodes(previewEvent, selectedEvent, previewTextCursorRowIndex === null || previewTextCursorColumnIndex === null ? null : {
6167
+ columnIndex: previewTextCursorColumnIndex,
6168
+ rowIndex: previewTextCursorRowIndex
6169
+ });
5684
6170
  const payloadEventNodes = selectedEvent ? getEventNode(getPayloadEvent(selectedEvent)) : [];
5685
- const responseEventNodes = selectedEvent ? getEventNode(selectedEvent) : [];
6171
+ const responseEventNodes = selectedEvent ? getEventNode(getResponseEvent(selectedEvent)) : [];
5686
6172
  const hasSelectedEvent = responseEventNodes.length > 0;
5687
6173
  const eventsClassName = getEventsClassName(hasSelectedEvent);
5688
6174
  const summary = getTableSummary(events);
5689
- const tableNodes = events.length === 0 ? getEmptyStateDom(emptyMessage) : getTableWrapperWrapperDom(rowNodes, events.length, visibleTableColumns, tableColumns, summary, focus);
5690
- const detailsNodes = getDetailsDom(previewEventNodes, payloadEventNodes, responseEventNodes, selectedEvent, detailTabs);
6175
+ const showScrollBar = visibleEvents.length < events.length;
6176
+ const tableNodes = events.length === 0 ? getEmptyStateDom(emptyMessage) : getTableWrapperWrapperDom(rowNodes, visibleEvents.length, visibleTableColumns, tableColumns, summary, focus, '', '', showScrollBar);
6177
+ const detailsNodes = getDetailsDom(previewEventNodes, payloadEventNodes, responseEventNodes, selectedEvent, detailTabs, previewTextCursorRowIndex, previewTextCursorColumnIndex);
5691
6178
  const sashNodes = getSashNodesDom(hasSelectedEvent);
5692
6179
  const splitChildCount = hasSelectedEvent ? 3 : 1;
5693
6180
  const rootChildCount = 3;
@@ -5741,7 +6228,7 @@ const getEventCategoryFilterDescription = eventCategoryFilters => {
5741
6228
  }
5742
6229
  return eventCategoryFilters.map(eventCategoryFilter => getEventCategoryFilterLabel(eventCategoryFilter).toLowerCase()).join(', ');
5743
6230
  };
5744
- const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilters, categoryFilters, _showEventStreamFinishedEvents, _showInputEvents, _showResponsePartEvents, useDevtoolsLayout, selectedEvent, selectedEventIndex, timelineStartSeconds, timelineEndSeconds, timelineFilterDescription, timelineEvents, events, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', visibleTableColumns = defaultVisibleTableColumns, detailTabs = createDetailTabs(), tableColumns = createTableColumns(), timelineInfo, timelineHoverPercent = null, focus = 0) => {
6231
+ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilters, categoryFilters, _showEventStreamFinishedEvents, _showInputEvents, _showResponsePartEvents, useDevtoolsLayout, selectedEvent, selectedEventIndex, timelineStartSeconds, timelineEndSeconds, timelineFilterDescription, timelineEvents, events, timelineSelectionActive = false, timelineSelectionAnchorSeconds = '', timelineSelectionFocusSeconds = '', visibleTableColumns = defaultVisibleTableColumns, detailTabs = createDetailTabs(), tableColumns = createTableColumns(), timelineInfo, timelineHoverPercent = null, focus = 0, previewTextCursorRowIndex = null, previewTextCursorColumnIndex = null, minLineY = 0, maxLineY = events.length) => {
5745
6232
  if (errorMessage) {
5746
6233
  return getDebugErrorDom(errorMessage);
5747
6234
  }
@@ -5765,7 +6252,7 @@ const getChatDebugViewDom = (errorMessage, filterValue, eventCategoryFilters, ca
5765
6252
  const emptyMessage = getEmptyMessage(events.length, hasFilterValue, useNoToolCallEventsMessage, noFilteredEventsMessage);
5766
6253
  const safeSelectedEventIndex = selectedEventIndex === null || selectedEventIndex < 0 || selectedEventIndex >= events.length ? null : selectedEventIndex;
5767
6254
  if (useDevtoolsLayout) {
5768
- const devtoolsDom = getDevtoolsDom(events, selectedEvent, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds, detailTabs, visibleTableColumns, tableColumns, timelineInfo, timelineHoverPercent, focus);
6255
+ const devtoolsDom = getDevtoolsDom(events, selectedEvent, safeSelectedEventIndex, timelineEvents, timelineStartSeconds, timelineEndSeconds, emptyMessage, timelineSelectionActive, timelineSelectionAnchorSeconds, timelineSelectionFocusSeconds, detailTabs, visibleTableColumns, tableColumns, timelineInfo, timelineHoverPercent, focus, previewTextCursorRowIndex, previewTextCursorColumnIndex, minLineY, maxLineY);
5769
6256
  const devtoolsContentNodes = devtoolsDom.slice(1);
5770
6257
  const topLevelNodes = [...getDebugViewTopDom(filterValue, useDevtoolsLayout, categoryFilters), ...devtoolsContentNodes];
5771
6258
  const rootChildCount = getTopLevelChildCount(topLevelNodes);
@@ -5797,8 +6284,8 @@ const renderItems = (oldState, newState) => {
5797
6284
  if (newState.initial) {
5798
6285
  return [SetDom2, newState.uid, []];
5799
6286
  }
5800
- const filteredEvents = filterEventsByTimelineRange(newState.timelineEvents, newState.timelineStartSeconds, newState.timelineEndSeconds);
5801
- const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, getSelectedEventCategoryFilters(newState.categoryFilters), newState.categoryFilters, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, newState.useDevtoolsLayout, newState.selectedEvent, newState.selectedEventIndex, newState.timelineStartSeconds, newState.timelineEndSeconds, newState.timelineFilterDescription, withSessionEventIds(newState.timelineEvents), withSessionEventIds(filteredEvents), newState.timelineSelectionActive, newState.timelineSelectionAnchorSeconds, newState.timelineSelectionFocusSeconds, getVisibleTableColumns(newState.tableColumns), newState.detailTabs, newState.tableColumns, newState.timelineInfo, newState.timelineHoverPercent, newState.focus);
6287
+ const filteredEvents = getCurrentEvents$2(newState);
6288
+ const dom = getChatDebugViewDom(newState.errorMessage, newState.filterValue, getSelectedEventCategoryFilters(newState.categoryFilters), newState.categoryFilters, newState.showEventStreamFinishedEvents, newState.showInputEvents, newState.showResponsePartEvents, newState.useDevtoolsLayout, newState.selectedEvent, newState.selectedEventIndex, newState.timelineStartSeconds, newState.timelineEndSeconds, newState.timelineFilterDescription, withSessionEventIds(newState.timelineEvents), withSessionEventIds(filteredEvents), newState.timelineSelectionActive, newState.timelineSelectionAnchorSeconds, newState.timelineSelectionFocusSeconds, getVisibleTableColumns(newState.tableColumns), newState.detailTabs, newState.tableColumns, newState.timelineInfo, newState.timelineHoverPercent, newState.focus, newState.previewTextCursorRowIndex, newState.previewTextCursorColumnIndex, newState.tableMinLineY, newState.tableMaxLineY);
5802
6289
  return [SetDom2, newState.uid, dom];
5803
6290
  };
5804
6291
 
@@ -5942,6 +6429,20 @@ const renderEventListeners = () => {
5942
6429
  }, {
5943
6430
  name: HandleTableResizerPointerUp,
5944
6431
  params: ['handleTableResizerPointerUp']
6432
+ }, {
6433
+ name: HandleTableScrollBarPointerDown,
6434
+ params: ['handleTableScrollBarPointerDown', ClientY],
6435
+ trackPointerEvents: [HandleTableScrollBarPointerMove, HandleTableScrollBarPointerUp]
6436
+ }, {
6437
+ name: HandleTableScrollBarPointerMove,
6438
+ params: ['handleTableScrollBarPointerMove', ClientY]
6439
+ }, {
6440
+ name: HandleTableScrollBarPointerUp,
6441
+ params: ['handleTableScrollBarPointerUp']
6442
+ }, {
6443
+ name: HandleTableWheel,
6444
+ params: ['handleTableWheel', 'event.deltaY'],
6445
+ preventDefault: true
5945
6446
  }, {
5946
6447
  name: HandleTimelinePointerDown,
5947
6448
  params: ['handleTimelinePointerDown', TargetName, ClientX],
@@ -5958,6 +6459,9 @@ const renderEventListeners = () => {
5958
6459
  }, {
5959
6460
  name: HandleTimelineDoubleClick,
5960
6461
  params: ['handleTimelineDoubleClick']
6462
+ }, {
6463
+ name: HandlePreviewTextPointerDown,
6464
+ params: ['handlePreviewTextPointerDown', 'event.clientX - event.currentTarget.getBoundingClientRect().left', 'event.clientY - event.currentTarget.getBoundingClientRect().top']
5961
6465
  }];
5962
6466
  };
5963
6467
 
@@ -5981,10 +6485,10 @@ const handleResize = (state, dimensions) => {
5981
6485
  ...state,
5982
6486
  ...dimensions
5983
6487
  };
5984
- return {
6488
+ return applyVirtualTableState({
5985
6489
  ...nextState,
5986
6490
  tableWidth: clampTableWidth(nextState.width, state.tableWidth)
5987
- };
6491
+ });
5988
6492
  };
5989
6493
 
5990
6494
  const isResizeDimensions = value => {
@@ -6033,19 +6537,22 @@ const selectCurrent = async state => {
6033
6537
  };
6034
6538
 
6035
6539
  const setEvents = (state, events) => {
6036
- return getStateWithTimelineInfo({
6540
+ return applyVirtualTableState(getStateWithTimelineInfo({
6037
6541
  ...state,
6038
6542
  errorMessage: '',
6039
6543
  events,
6040
6544
  initial: false,
6545
+ previewTextCursorColumnIndex: null,
6546
+ previewTextCursorRowIndex: null,
6041
6547
  selectedEvent: null,
6042
6548
  selectedEventId: null,
6043
6549
  selectedEventIndex: null
6044
- });
6550
+ }));
6045
6551
  };
6046
6552
 
6047
6553
  const setSessionIdDependencies = {
6048
- listChatViewEvents: listChatViewEvents
6554
+ listChatViewEvents: listChatViewEvents,
6555
+ registerUpdateListener: registerUpdateListener
6049
6556
  };
6050
6557
  const setSessionId = async (state, sessionId) => {
6051
6558
  const {
@@ -6055,12 +6562,15 @@ const setSessionId = async (state, sessionId) => {
6055
6562
  sessionIdIndexName
6056
6563
  } = state;
6057
6564
  const result = await setSessionIdDependencies.listChatViewEvents(sessionId, databaseName, dataBaseVersion, eventStoreName, sessionIdIndexName);
6565
+ await setSessionIdDependencies.registerUpdateListener(sessionId, rpcId, state.uid);
6058
6566
  if (result.type === 'error') {
6059
6567
  return {
6060
6568
  ...state,
6061
6569
  errorMessage: getFailedToLoadMessage(sessionId, result.error),
6062
6570
  events: [],
6063
6571
  initial: false,
6572
+ previewTextCursorColumnIndex: null,
6573
+ previewTextCursorRowIndex: null,
6064
6574
  selectedEvent: null,
6065
6575
  selectedEventId: null,
6066
6576
  selectedEventIndex: null,
@@ -6075,6 +6585,8 @@ const setSessionId = async (state, sessionId) => {
6075
6585
  errorMessage: '',
6076
6586
  events,
6077
6587
  initial: false,
6588
+ previewTextCursorColumnIndex: null,
6589
+ previewTextCursorRowIndex: null,
6078
6590
  selectedEvent: null,
6079
6591
  selectedEventId: null,
6080
6592
  selectedEventIndex: null,
@@ -6124,6 +6636,7 @@ const commandMap = {
6124
6636
  'ChatDebug.handleEventRowClickAt': wrapCommand(handleEventRowClickAt),
6125
6637
  'ChatDebug.handleHeaderContextMenu': wrapCommand(handleHeaderContextMenu),
6126
6638
  'ChatDebug.handleInput': wrapCommand(handleInput),
6639
+ 'ChatDebug.handlePreviewTextPointerDown': wrapCommand(handlePreviewTextPointerDown),
6127
6640
  'ChatDebug.handleSashPointerDown': wrapCommand(handleSashPointerDown),
6128
6641
  'ChatDebug.handleSashPointerMove': wrapCommand(handleSashPointerMove),
6129
6642
  'ChatDebug.handleSashPointerUp': wrapCommand(handleSashPointerUp),
@@ -6137,6 +6650,10 @@ const commandMap = {
6137
6650
  'ChatDebug.handleTableResizerPointerMove': wrapCommand(handleTableResizerPointerMove),
6138
6651
  'ChatDebug.handleTableResizerPointerUp': wrapCommand(handleTableResizerPointerUp),
6139
6652
  'ChatDebug.handleTableRowCopy': wrapCommand(handleTableRowCopy),
6653
+ 'ChatDebug.handleTableScrollBarPointerDown': wrapCommand(handleTableScrollBarPointerDown),
6654
+ 'ChatDebug.handleTableScrollBarPointerMove': wrapCommand(handleTableScrollBarPointerMove),
6655
+ 'ChatDebug.handleTableScrollBarPointerUp': wrapCommand(handleTableScrollBarPointerUp),
6656
+ 'ChatDebug.handleTableWheel': wrapCommand(handleTableWheel),
6140
6657
  'ChatDebug.handleTimelineContextMenu': wrapCommand(handleTimelineContextMenu),
6141
6658
  'ChatDebug.handleTimelineDoubleClick': wrapCommand(handleTimelineDoubleClick),
6142
6659
  'ChatDebug.handleTimelineEndSeconds': wrapCommand(handleTimelineEndSeconds),
@@ -6169,7 +6686,9 @@ const sendMessagePortToChatStorageWorker = async port => {
6169
6686
  };
6170
6687
  const initializeChatStorageWorker = async () => {
6171
6688
  const rpc = await create$4({
6172
- commandMap: {},
6689
+ commandMap: {
6690
+ [rpcId]: handleStorageWorkerUpdate
6691
+ },
6173
6692
  send: sendMessagePortToChatStorageWorker
6174
6693
  });
6175
6694
  set$2(rpc);