@buoy-gg/js-top 7.0.40 → 7.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +12 -67
  2. package/lib/commonjs/index.js +1 -97
  3. package/lib/commonjs/js-top/components/BusySparkline.js +1 -56
  4. package/lib/commonjs/js-top/components/JsTopHudOverlay.js +1 -79
  5. package/lib/commonjs/js-top/components/JsTopModal.js +1 -349
  6. package/lib/commonjs/js-top/components/TaskDetailView.js +1 -330
  7. package/lib/commonjs/js-top/components/TaskTable.js +1 -360
  8. package/lib/commonjs/js-top/engine/JsTopController.js +1 -350
  9. package/lib/commonjs/js-top/engine/aggregator.js +1 -148
  10. package/lib/commonjs/js-top/engine/busyProbe.js +1 -101
  11. package/lib/commonjs/js-top/engine/frameStack.js +1 -133
  12. package/lib/commonjs/js-top/engine/longtasks.js +1 -141
  13. package/lib/commonjs/js-top/engine/now.js +1 -38
  14. package/lib/commonjs/js-top/engine/originRegistry.js +1 -402
  15. package/lib/commonjs/js-top/engine/patches/bridge.js +1 -60
  16. package/lib/commonjs/js-top/engine/patches/microtasks.js +1 -27
  17. package/lib/commonjs/js-top/engine/patches/promises.js +1 -65
  18. package/lib/commonjs/js-top/engine/patches/timers.js +1 -66
  19. package/lib/commonjs/js-top/engine/state.js +1 -63
  20. package/lib/commonjs/js-top/engine/symbolicate.js +1 -95
  21. package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js +1 -74
  22. package/lib/commonjs/js-top/types/index.js +1 -46
  23. package/lib/commonjs/js-top/utils/preferences.js +1 -31
  24. package/lib/commonjs/preset.js +1 -75
  25. package/lib/module/index.js +1 -47
  26. package/lib/module/js-top/components/BusySparkline.js +1 -52
  27. package/lib/module/js-top/components/JsTopHudOverlay.js +1 -75
  28. package/lib/module/js-top/components/JsTopModal.js +1 -345
  29. package/lib/module/js-top/components/TaskDetailView.js +1 -326
  30. package/lib/module/js-top/components/TaskTable.js +1 -353
  31. package/lib/module/js-top/engine/JsTopController.js +1 -347
  32. package/lib/module/js-top/engine/aggregator.js +1 -136
  33. package/lib/module/js-top/engine/busyProbe.js +1 -94
  34. package/lib/module/js-top/engine/frameStack.js +1 -126
  35. package/lib/module/js-top/engine/longtasks.js +1 -133
  36. package/lib/module/js-top/engine/now.js +1 -33
  37. package/lib/module/js-top/engine/originRegistry.js +1 -388
  38. package/lib/module/js-top/engine/patches/bridge.js +1 -56
  39. package/lib/module/js-top/engine/patches/microtasks.js +1 -23
  40. package/lib/module/js-top/engine/patches/promises.js +1 -62
  41. package/lib/module/js-top/engine/patches/timers.js +1 -62
  42. package/lib/module/js-top/engine/state.js +1 -54
  43. package/lib/module/js-top/engine/symbolicate.js +1 -91
  44. package/lib/module/js-top/sync/jsTopSyncAdapter.js +1 -70
  45. package/lib/module/js-top/types/index.js +1 -42
  46. package/lib/module/js-top/utils/preferences.js +1 -26
  47. package/lib/module/preset.js +1 -71
  48. package/lib/web/index.mjs +2 -0
  49. package/package.json +39 -5
  50. package/lib/commonjs/index.js.map +0 -1
  51. package/lib/commonjs/js-top/components/BusySparkline.js.map +0 -1
  52. package/lib/commonjs/js-top/components/JsTopHudOverlay.js.map +0 -1
  53. package/lib/commonjs/js-top/components/JsTopModal.js.map +0 -1
  54. package/lib/commonjs/js-top/components/TaskDetailView.js.map +0 -1
  55. package/lib/commonjs/js-top/components/TaskTable.js.map +0 -1
  56. package/lib/commonjs/js-top/engine/JsTopController.js.map +0 -1
  57. package/lib/commonjs/js-top/engine/aggregator.js.map +0 -1
  58. package/lib/commonjs/js-top/engine/busyProbe.js.map +0 -1
  59. package/lib/commonjs/js-top/engine/frameStack.js.map +0 -1
  60. package/lib/commonjs/js-top/engine/longtasks.js.map +0 -1
  61. package/lib/commonjs/js-top/engine/now.js.map +0 -1
  62. package/lib/commonjs/js-top/engine/originRegistry.js.map +0 -1
  63. package/lib/commonjs/js-top/engine/patches/bridge.js.map +0 -1
  64. package/lib/commonjs/js-top/engine/patches/microtasks.js.map +0 -1
  65. package/lib/commonjs/js-top/engine/patches/promises.js.map +0 -1
  66. package/lib/commonjs/js-top/engine/patches/timers.js.map +0 -1
  67. package/lib/commonjs/js-top/engine/state.js.map +0 -1
  68. package/lib/commonjs/js-top/engine/symbolicate.js.map +0 -1
  69. package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js.map +0 -1
  70. package/lib/commonjs/js-top/types/index.js.map +0 -1
  71. package/lib/commonjs/js-top/utils/preferences.js.map +0 -1
  72. package/lib/commonjs/preset.js.map +0 -1
  73. package/lib/module/index.js.map +0 -1
  74. package/lib/module/js-top/components/BusySparkline.js.map +0 -1
  75. package/lib/module/js-top/components/JsTopHudOverlay.js.map +0 -1
  76. package/lib/module/js-top/components/JsTopModal.js.map +0 -1
  77. package/lib/module/js-top/components/TaskDetailView.js.map +0 -1
  78. package/lib/module/js-top/components/TaskTable.js.map +0 -1
  79. package/lib/module/js-top/engine/JsTopController.js.map +0 -1
  80. package/lib/module/js-top/engine/aggregator.js.map +0 -1
  81. package/lib/module/js-top/engine/busyProbe.js.map +0 -1
  82. package/lib/module/js-top/engine/frameStack.js.map +0 -1
  83. package/lib/module/js-top/engine/longtasks.js.map +0 -1
  84. package/lib/module/js-top/engine/now.js.map +0 -1
  85. package/lib/module/js-top/engine/originRegistry.js.map +0 -1
  86. package/lib/module/js-top/engine/patches/bridge.js.map +0 -1
  87. package/lib/module/js-top/engine/patches/microtasks.js.map +0 -1
  88. package/lib/module/js-top/engine/patches/promises.js.map +0 -1
  89. package/lib/module/js-top/engine/patches/timers.js.map +0 -1
  90. package/lib/module/js-top/engine/state.js.map +0 -1
  91. package/lib/module/js-top/engine/symbolicate.js.map +0 -1
  92. package/lib/module/js-top/sync/jsTopSyncAdapter.js.map +0 -1
  93. package/lib/module/js-top/types/index.js.map +0 -1
  94. package/lib/module/js-top/utils/preferences.js.map +0 -1
  95. package/lib/module/preset.js.map +0 -1
  96. package/lib/typescript/index.d.ts.map +0 -1
  97. package/lib/typescript/js-top/components/BusySparkline.d.ts.map +0 -1
  98. package/lib/typescript/js-top/components/JsTopHudOverlay.d.ts.map +0 -1
  99. package/lib/typescript/js-top/components/JsTopModal.d.ts.map +0 -1
  100. package/lib/typescript/js-top/components/TaskDetailView.d.ts.map +0 -1
  101. package/lib/typescript/js-top/components/TaskTable.d.ts.map +0 -1
  102. package/lib/typescript/js-top/engine/JsTopController.d.ts.map +0 -1
  103. package/lib/typescript/js-top/engine/aggregator.d.ts.map +0 -1
  104. package/lib/typescript/js-top/engine/busyProbe.d.ts.map +0 -1
  105. package/lib/typescript/js-top/engine/frameStack.d.ts.map +0 -1
  106. package/lib/typescript/js-top/engine/longtasks.d.ts.map +0 -1
  107. package/lib/typescript/js-top/engine/now.d.ts.map +0 -1
  108. package/lib/typescript/js-top/engine/originRegistry.d.ts.map +0 -1
  109. package/lib/typescript/js-top/engine/patches/bridge.d.ts.map +0 -1
  110. package/lib/typescript/js-top/engine/patches/microtasks.d.ts.map +0 -1
  111. package/lib/typescript/js-top/engine/patches/promises.d.ts.map +0 -1
  112. package/lib/typescript/js-top/engine/patches/timers.d.ts.map +0 -1
  113. package/lib/typescript/js-top/engine/state.d.ts.map +0 -1
  114. package/lib/typescript/js-top/engine/symbolicate.d.ts.map +0 -1
  115. package/lib/typescript/js-top/sync/jsTopSyncAdapter.d.ts.map +0 -1
  116. package/lib/typescript/js-top/types/index.d.ts.map +0 -1
  117. package/lib/typescript/js-top/utils/preferences.d.ts.map +0 -1
  118. package/lib/typescript/preset.d.ts.map +0 -1
@@ -1,345 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * JS TOP modal — the Task Manager window.
5
- *
6
- * Layout: header (busy% pill + pause/clear controls) → busy sparkline →
7
- * coverage banner (when bridge tier is unavailable) → ranked task table →
8
- * blocking-task list.
9
- *
10
- * Data source is the local JsTopController by default. The desktop
11
- * dashboard mounts this same component via react-native-web and injects the
12
- * synced device snapshot + remote actions through `remoteSnapshot` /
13
- * `remoteActions` — the modal never samples the Electron renderer.
14
- */
15
-
16
- import { useCallback, useEffect, useMemo, useState } from "react";
17
- import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
18
- import { Activity, JsModal, macOSColors, night, ModalHeader, Pause, Play, Trash2 } from "@buoy-gg/shared-ui";
19
- import { JsTopController } from "../engine/JsTopController";
20
- import { BusySparkline } from "./BusySparkline";
21
- import { TaskTable } from "./TaskTable";
22
- import { TaskDetailView } from "./TaskDetailView";
23
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
24
- function busyColor(pct) {
25
- if (pct >= 80) return macOSColors.semantic.error;
26
- if (pct >= 40) return macOSColors.semantic.warning;
27
- return macOSColors.semantic.success;
28
- }
29
-
30
- /** ≥100ms is a dropped-tap-level freeze — escalate to red. */
31
- function freezeColor(worstMs) {
32
- return worstMs >= 100 ? macOSColors.semantic.error : macOSColors.semantic.warning;
33
- }
34
-
35
- /**
36
- * The one-line answer to "what should I look at?" — rendered above the
37
- * table so triage never requires reading it. Priority: a named culprit >
38
- * freezes > saturated-by-UI-work > healthy.
39
- */
40
- function diagnose(s) {
41
- const culprit = s.rows.find(r => r.api !== "unattributed" && r.api !== "other");
42
- if (culprit && culprit.pctOfBusy >= 25 && s.busyPct >= 15) {
43
- return {
44
- color: culprit.pctOfBusy >= 50 ? macOSColors.semantic.error : macOSColors.semantic.warning,
45
- icon: "▲",
46
- text: `${culprit.label} is eating ${Math.round(culprit.pctOfBusy)}% of thread time — start there.`
47
- };
48
- }
49
- if (s.freezeSummary.count > 0) {
50
- return {
51
- color: freezeColor(s.freezeSummary.worstMs),
52
- icon: "▲",
53
- text: `${s.freezeSummary.count} freeze${s.freezeSummary.count === 1 ? "" : "s"} in the last 60s (worst ${s.freezeSummary.worstMs}ms) — check rows marked ⚠.`
54
- };
55
- }
56
- if (s.busyPct >= 80) {
57
- return {
58
- color: macOSColors.semantic.warning,
59
- icon: "▲",
60
- text: "Thread saturated by UI/React work — open Highlight Updates to find re-renders."
61
- };
62
- }
63
- return {
64
- color: macOSColors.semantic.success,
65
- icon: "●",
66
- text: `Thread healthy at ${Math.round(s.busyPct)}% load — nothing worth chasing.`
67
- };
68
- }
69
- export function JsTopModal({
70
- visible,
71
- onClose,
72
- onBack,
73
- onMinimize,
74
- initialModalState,
75
- minimizeTargetPosition,
76
- remoteSnapshot,
77
- remoteActions,
78
- embedded = false
79
- }) {
80
- const isRemote = remoteSnapshot !== undefined;
81
- const [localSnapshot, setLocalSnapshot] = useState(null);
82
-
83
- // Local mode: subscribing is what starts the engine (and unsubscribing on
84
- // close is what stops it — zero overhead when the window isn't open).
85
- useEffect(() => {
86
- if (isRemote || !visible) return;
87
- return JsTopController.subscribe(setLocalSnapshot);
88
- }, [isRemote, visible]);
89
- const snapshot = isRemote ? remoteSnapshot : localSnapshot;
90
- const actions = useMemo(() => remoteActions ?? {
91
- pause: () => JsTopController.pause(),
92
- resume: () => JsTopController.resume(),
93
- clear: () => JsTopController.clear()
94
- }, [remoteActions]);
95
- const paused = snapshot?.paused ?? false;
96
- const hasData = (snapshot?.rows.length ?? 0) > 0;
97
-
98
- // Tap-through detail. Local mode re-pulls the detail on every snapshot
99
- // tick (this component re-renders), so the detail view stays live.
100
- // Remote mode (desktop) has no local engine — rows aren't tappable there.
101
- const [detailKey, setDetailKey] = useState(null);
102
- const onSelectRow = useCallback(row => setDetailKey(row.key), []);
103
- const detail = !isRemote && detailKey ? JsTopController.getOriginDetail(detailKey) : null;
104
- const inDetail = detailKey !== null;
105
-
106
- // Shared ModalHeader compound — same structure as Network/Events/Console:
107
- // Content (brand icon + title + live busy pill) and 32px icon Actions.
108
- // In the detail view the chevron pops back to the table.
109
- const headerContent = /*#__PURE__*/_jsxs(ModalHeader, {
110
- children: [inDetail ? /*#__PURE__*/_jsx(ModalHeader.Navigation, {
111
- onBack: () => setDetailKey(null)
112
- }) : onBack ? /*#__PURE__*/_jsx(ModalHeader.Navigation, {
113
- onBack: onBack
114
- }) : null, /*#__PURE__*/_jsx(ModalHeader.Content, {
115
- title: "",
116
- noMargin: true,
117
- children: /*#__PURE__*/_jsxs(View, {
118
- style: styles.titleRow,
119
- children: [/*#__PURE__*/_jsx(Activity, {
120
- size: 14,
121
- color: "#34D399"
122
- }), /*#__PURE__*/_jsx(Text, {
123
- style: styles.title,
124
- children: "JS Top"
125
- }), snapshot && /*#__PURE__*/_jsx(View, {
126
- style: [styles.busyPill, {
127
- borderColor: busyColor(snapshot.busyPct)
128
- }],
129
- children: /*#__PURE__*/_jsxs(Text, {
130
- style: [styles.busyText, {
131
- color: busyColor(snapshot.busyPct)
132
- }],
133
- children: [snapshot.busyPct.toFixed(0), "% BUSY"]
134
- })
135
- }), snapshot && snapshot.freezeSummary.count > 0 && /*#__PURE__*/_jsx(View, {
136
- style: [styles.busyPill, {
137
- borderColor: freezeColor(snapshot.freezeSummary.worstMs)
138
- }],
139
- children: /*#__PURE__*/_jsxs(Text, {
140
- style: [styles.busyText, {
141
- color: freezeColor(snapshot.freezeSummary.worstMs)
142
- }],
143
- children: ["\u26A0 ", snapshot.freezeSummary.count, " \xB7", " ", snapshot.freezeSummary.worstMs, "ms"]
144
- })
145
- })]
146
- })
147
- }), /*#__PURE__*/_jsxs(ModalHeader.Actions, {
148
- children: [/*#__PURE__*/_jsx(TouchableOpacity, {
149
- onPress: paused ? actions.resume : actions.pause,
150
- style: [styles.actionBtn, paused && styles.actionBtnActive],
151
- accessibilityLabel: paused ? "Resume sampling" : "Pause sampling",
152
- children: paused ? /*#__PURE__*/_jsx(Play, {
153
- size: 14,
154
- color: night.color.accent
155
- }) : /*#__PURE__*/_jsx(Pause, {
156
- size: 14,
157
- color: night.color.textSecondary
158
- })
159
- }), /*#__PURE__*/_jsx(TouchableOpacity, {
160
- onPress: actions.clear,
161
- disabled: !hasData,
162
- style: [styles.actionBtn, !hasData && styles.actionBtnDisabled],
163
- accessibilityLabel: "Clear stats",
164
- children: /*#__PURE__*/_jsx(Trash2, {
165
- size: 14,
166
- color: hasData ? night.color.textTertiary : night.color.textTertiary
167
- })
168
- })]
169
- })]
170
- });
171
- const body = /*#__PURE__*/_jsx(View, {
172
- style: styles.body,
173
- children: inDetail ? detail ? /*#__PURE__*/_jsx(TaskDetailView, {
174
- detail: detail
175
- }) : /*#__PURE__*/_jsx(Text, {
176
- style: styles.waiting,
177
- children: "This origin is no longer tracked (cleared or evicted)."
178
- }) : snapshot ? /*#__PURE__*/_jsxs(_Fragment, {
179
- children: [(() => {
180
- const d = diagnose(snapshot);
181
- return /*#__PURE__*/_jsxs(View, {
182
- style: [styles.diagnosis, {
183
- borderLeftColor: d.color
184
- }],
185
- children: [/*#__PURE__*/_jsx(Text, {
186
- style: [styles.diagnosisIcon, {
187
- color: d.color
188
- }],
189
- children: d.icon
190
- }), /*#__PURE__*/_jsx(Text, {
191
- style: styles.diagnosisText,
192
- children: d.text
193
- })]
194
- });
195
- })(), /*#__PURE__*/_jsxs(View, {
196
- style: styles.sparklineRow,
197
- children: [/*#__PURE__*/_jsx(Text, {
198
- style: styles.sparklineCaption,
199
- children: "JS THREAD LOAD \xB7 LAST 30s"
200
- }), /*#__PURE__*/_jsx(BusySparkline, {
201
- history: snapshot.busyHistory
202
- })]
203
- }), !snapshot.tiers.bridge && /*#__PURE__*/_jsx(Text, {
204
- style: styles.tierBanner,
205
- children: "\u201CSystem\u201D rows are UI/React/native work pure JS can\u2019t name \u2014 timers, rAF and Promise chains are fully attributed."
206
- }), /*#__PURE__*/_jsx(TaskTable, {
207
- rows: snapshot.rows,
208
- onSelectRow: isRemote ? undefined : onSelectRow
209
- })]
210
- }) : /*#__PURE__*/_jsx(Text, {
211
- style: styles.waiting,
212
- children: isRemote ? "Waiting for device…" : "Starting engine…"
213
- })
214
- });
215
- if (embedded) {
216
- return /*#__PURE__*/_jsxs(View, {
217
- style: styles.embeddedRoot,
218
- children: [/*#__PURE__*/_jsx(View, {
219
- style: styles.embeddedHeader,
220
- children: headerContent
221
- }), body]
222
- });
223
- }
224
- return /*#__PURE__*/_jsx(JsModal, {
225
- visible: visible,
226
- onClose: onClose,
227
- onMinimize: onMinimize,
228
- minimizeTargetPosition: minimizeTargetPosition,
229
- initialModalState: initialModalState,
230
- header: {
231
- showToggleButton: true,
232
- customContent: headerContent
233
- },
234
- persistenceKey: "buoy-js-top-modal",
235
- enablePersistence: true,
236
- initialMode: "bottomSheet",
237
- disableScrollWrapper: true,
238
- children: body
239
- });
240
- }
241
- const styles = StyleSheet.create({
242
- titleRow: {
243
- flexDirection: "row",
244
- alignItems: "center",
245
- gap: 8
246
- },
247
- title: {
248
- color: night.color.text,
249
- fontSize: 14,
250
- fontWeight: "500"
251
- },
252
- busyPill: {
253
- borderWidth: 1,
254
- borderRadius: 4,
255
- paddingHorizontal: 6,
256
- paddingVertical: 2
257
- },
258
- busyText: {
259
- fontSize: 10,
260
- fontWeight: "700",
261
- fontVariant: ["tabular-nums"]
262
- },
263
- actionBtn: {
264
- width: 32,
265
- height: 32,
266
- borderRadius: 8,
267
- backgroundColor: night.color.buttonSurface,
268
- borderWidth: 1,
269
- borderColor: night.color.border,
270
- alignItems: "center",
271
- justifyContent: "center"
272
- },
273
- actionBtnActive: {
274
- backgroundColor: night.color.accentSoft,
275
- borderColor: night.color.accentBorderStrong
276
- },
277
- actionBtnDisabled: {
278
- opacity: 0.55
279
- },
280
- body: {
281
- flex: 1,
282
- minHeight: 0,
283
- // Transparent so JsModal's ToolBackground shows through (the modal paints
284
- // opaque base beneath it). The embedded path keeps `embeddedRoot`'s base fill.
285
- backgroundColor: "transparent"
286
- },
287
- diagnosis: {
288
- flexDirection: "row",
289
- alignItems: "center",
290
- gap: 8,
291
- marginHorizontal: 10,
292
- marginTop: 8,
293
- paddingHorizontal: 10,
294
- paddingVertical: 8,
295
- backgroundColor: night.color.surface,
296
- borderRadius: 6,
297
- borderLeftWidth: 3
298
- },
299
- diagnosisIcon: {
300
- fontSize: 11,
301
- fontWeight: "700"
302
- },
303
- diagnosisText: {
304
- flex: 1,
305
- color: night.color.text,
306
- fontSize: 12,
307
- lineHeight: 16
308
- },
309
- sparklineRow: {
310
- paddingHorizontal: 10,
311
- paddingVertical: 8,
312
- gap: 4
313
- },
314
- sparklineCaption: {
315
- color: night.color.textTertiary,
316
- fontSize: 8,
317
- fontWeight: "700",
318
- letterSpacing: 0.5
319
- },
320
- tierBanner: {
321
- color: night.color.textTertiary,
322
- fontSize: 10,
323
- paddingHorizontal: 10,
324
- paddingBottom: 6
325
- },
326
- waiting: {
327
- color: night.color.textTertiary,
328
- fontSize: 12,
329
- textAlign: "center",
330
- paddingVertical: 32
331
- },
332
- embeddedRoot: {
333
- position: "absolute",
334
- top: 0,
335
- left: 0,
336
- right: 0,
337
- bottom: 0,
338
- backgroundColor: macOSColors.background.base
339
- },
340
- embeddedHeader: {
341
- borderBottomWidth: 1,
342
- borderBottomColor: macOSColors.border.default
343
- }
344
- });
345
- //# sourceMappingURL=JsTopModal.js.map
1
+ "use strict";import{useCallback as O,useEffect as V,useMemo as j,useState as P}from"react";import{StyleSheet as J,Text as a,TouchableOpacity as R,View as l}from"react-native";import{Activity as $,JsModal as F,macOSColors as n,night as i,ModalHeader as y,Pause as U,Play as K,Trash2 as _}from"@buoy-gg/shared-ui";import{JsTopController as g}from"../engine/JsTopController";import{BusySparkline as E}from"./BusySparkline";import{TaskTable as N}from"./TaskTable";import{TaskDetailView as Y}from"./TaskDetailView";import{jsx as e,jsxs as s,Fragment as q}from"react/jsx-runtime";function M(r){if(r>=80)return n.semantic.error;if(r>=40)return n.semantic.warning;return n.semantic.success}function S(r){return r>=100?n.semantic.error:n.semantic.warning}function G(r){const c=r.rows.find(m=>m.api!=="unattributed"&&m.api!=="other");if(c&&c.pctOfBusy>=25&&r.busyPct>=15){return{color:c.pctOfBusy>=50?n.semantic.error:n.semantic.warning,icon:"\u25B2",text:`${c.label} is eating ${Math.round(c.pctOfBusy)}% of thread time \u2014 start there.`}}if(r.freezeSummary.count>0){return{color:S(r.freezeSummary.worstMs),icon:"\u25B2",text:`${r.freezeSummary.count} freeze${r.freezeSummary.count===1?"":"s"} in the last 60s (worst ${r.freezeSummary.worstMs}ms) \u2014 check rows marked \u26A0.`}}if(r.busyPct>=80){return{color:n.semantic.warning,icon:"\u25B2",text:"Thread saturated by UI/React work \u2014 open Highlight Updates to find re-renders."}}return{color:n.semantic.success,icon:"\u25CF",text:`Thread healthy at ${Math.round(r.busyPct)}% load \u2014 nothing worth chasing.`}}export function JsTopModal({visible:r,onClose:c,onBack:m,onMinimize:D,initialModalState:H,minimizeTargetPosition:W,remoteSnapshot:w,remoteActions:x,embedded:A=false}){const d=w!==void 0;const[v,I]=P(null);V(()=>{if(d||!r)return;return g.subscribe(I)},[d,r]);const o=d?w:v;const h=j(()=>x??{pause:()=>g.pause(),resume:()=>g.resume(),clear:()=>g.clear()},[x]);const f=o?.paused??false;const b=(o?.rows.length??0)>0;const[p,z]=P(null);const L=O(u=>z(u.key),[]);const T=!d&&p?g.getOriginDetail(p):null;const C=p!==null;const B=s(y,{children:[C?e(y.Navigation,{onBack:()=>z(null)}):m?e(y.Navigation,{onBack:m}):null,e(y.Content,{title:"",noMargin:true,children:s(l,{style:t.titleRow,children:[e($,{size:14,color:"#34D399"}),e(a,{style:t.title,children:"JS Top"}),o&&e(l,{style:[t.busyPill,{borderColor:M(o.busyPct)}],children:s(a,{style:[t.busyText,{color:M(o.busyPct)}],children:[o.busyPct.toFixed(0),"% BUSY"]})}),o&&o.freezeSummary.count>0&&e(l,{style:[t.busyPill,{borderColor:S(o.freezeSummary.worstMs)}],children:s(a,{style:[t.busyText,{color:S(o.freezeSummary.worstMs)}],children:["\u26A0 ",o.freezeSummary.count," \xB7"," ",o.freezeSummary.worstMs,"ms"]})})]})}),s(y.Actions,{children:[e(R,{onPress:f?h.resume:h.pause,style:[t.actionBtn,f&&t.actionBtnActive],accessibilityLabel:f?"Resume sampling":"Pause sampling",children:f?e(K,{size:14,color:i.color.accent}):e(U,{size:14,color:i.color.textSecondary})}),e(R,{onPress:h.clear,disabled:!b,style:[t.actionBtn,!b&&t.actionBtnDisabled],accessibilityLabel:"Clear stats",children:e(_,{size:14,color:b?i.color.textTertiary:i.color.textTertiary})})]})]});const k=e(l,{style:t.body,children:C?T?e(Y,{detail:T}):e(a,{style:t.waiting,children:"This origin is no longer tracked (cleared or evicted)."}):o?s(q,{children:[(()=>{const u=G(o);return s(l,{style:[t.diagnosis,{borderLeftColor:u.color}],children:[e(a,{style:[t.diagnosisIcon,{color:u.color}],children:u.icon}),e(a,{style:t.diagnosisText,children:u.text})]})})(),s(l,{style:t.sparklineRow,children:[e(a,{style:t.sparklineCaption,children:"JS THREAD LOAD \xB7 LAST 30s"}),e(E,{history:o.busyHistory})]}),!o.tiers.bridge&&e(a,{style:t.tierBanner,children:"\u201CSystem\u201D rows are UI/React/native work pure JS can\u2019t name \u2014 timers, rAF and Promise chains are fully attributed."}),e(N,{rows:o.rows,onSelectRow:d?void 0:L})]}):e(a,{style:t.waiting,children:d?"Waiting for device\u2026":"Starting engine\u2026"})});if(A){return s(l,{style:t.embeddedRoot,children:[e(l,{style:t.embeddedHeader,children:B}),k]})}return e(F,{visible:r,onClose:c,onMinimize:D,minimizeTargetPosition:W,initialModalState:H,header:{showToggleButton:true,customContent:B},persistenceKey:"buoy-js-top-modal",enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:k})}const t=J.create({titleRow:{flexDirection:"row",alignItems:"center",gap:8},title:{color:i.color.text,fontSize:14,fontWeight:"500"},busyPill:{borderWidth:1,borderRadius:4,paddingHorizontal:6,paddingVertical:2},busyText:{fontSize:10,fontWeight:"700",fontVariant:["tabular-nums"]},actionBtn:{width:32,height:32,borderRadius:8,backgroundColor:i.color.buttonSurface,borderWidth:1,borderColor:i.color.border,alignItems:"center",justifyContent:"center"},actionBtnActive:{backgroundColor:i.color.accentSoft,borderColor:i.color.accentBorderStrong},actionBtnDisabled:{opacity:.55},body:{flex:1,minHeight:0,backgroundColor:"transparent"},diagnosis:{flexDirection:"row",alignItems:"center",gap:8,marginHorizontal:10,marginTop:8,paddingHorizontal:10,paddingVertical:8,backgroundColor:i.color.surface,borderRadius:6,borderLeftWidth:3},diagnosisIcon:{fontSize:11,fontWeight:"700"},diagnosisText:{flex:1,color:i.color.text,fontSize:12,lineHeight:16},sparklineRow:{paddingHorizontal:10,paddingVertical:8,gap:4},sparklineCaption:{color:i.color.textTertiary,fontSize:8,fontWeight:"700",letterSpacing:.5},tierBanner:{color:i.color.textTertiary,fontSize:10,paddingHorizontal:10,paddingBottom:6},waiting:{color:i.color.textTertiary,fontSize:12,textAlign:"center",paddingVertical:32},embeddedRoot:{position:"absolute",top:0,left:0,right:0,bottom:0,backgroundColor:n.background.base},embeddedHeader:{borderBottomWidth:1,borderBottomColor:n.border.default}});
@@ -1,326 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * TaskDetailView — the "inspect process" screen behind a row tap.
5
- *
6
- * Shows everything the engine knows about one origin: a 5s activity bar
7
- * chart (the per-origin bucket ring, rendered nowhere else), the full stat
8
- * grid (schedules vs runs, avg/max/total, freezes), the captured scheduling
9
- * site (caller + raw frames), and a plain-language explanation of what this
10
- * origin type means. Data refreshes with the modal's snapshot tick — the
11
- * parent re-renders us and we re-pull the detail.
12
- */
13
-
14
- import { memo } from "react";
15
- import { ScrollView, StyleSheet, Text, View } from "react-native";
16
- import { macOSColors, night, useSafeAreaInsets } from "@buoy-gg/shared-ui";
17
- import { badgeFor, displayName } from "./TaskTable";
18
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
19
- const API_EXPLAINER = {
20
- timeout: "Work scheduled with setTimeout. Time shown is the callback's exclusive run time on the JS thread.",
21
- interval: "A repeating setInterval. One scheduling site, many runs — a hot interval is the classic silent JS-FPS killer.",
22
- immediate: "Work scheduled with setImmediate — runs at the end of the current event-loop turn.",
23
- raf: "requestAnimationFrame work — runs once per frame while scheduled. Cost here directly trades against 60fps.",
24
- microtask: "queueMicrotask work — runs after the current task, before the thread yields.",
25
- then: "Promise reaction (.then/.catch/.finally). Named by the function that attached the reaction. Note: async/await bodies bypass .then and land in the System row instead.",
26
- bridge: "A native→JS call-in over the legacy bridge (events, module callbacks), measured as its un-nested remainder.",
27
- unattributed: "Thread time the probe measured but no JS wrapper could claim: touch handlers, React commits, native call-ins, and async/await bodies. High here on New Architecture is normal — it's where UI work lives.",
28
- other: "Origins evicted from the table when the registry hit its cap — their totals are preserved here."
29
- };
30
- function explainerFor(api) {
31
- return API_EXPLAINER[api] ?? API_EXPLAINER.other;
32
- }
33
- function fmt(n) {
34
- if (n >= 10_000) return `${Math.round(n / 1000)}k`;
35
- if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
36
- if (n >= 100) return `${Math.round(n)}`;
37
- return `${Math.round(n * 100) / 100}`;
38
- }
39
- function agoFmt(ms) {
40
- if (ms <= 0) return "—";
41
- const sec = ms / 1000;
42
- if (sec < 1) return "just now";
43
- if (sec < 60) return `${Math.round(sec)}s ago`;
44
- return `${Math.floor(sec / 60)}m ago`;
45
- }
46
- function Stat({
47
- label,
48
- value,
49
- accent
50
- }) {
51
- return /*#__PURE__*/_jsxs(View, {
52
- style: styles.stat,
53
- children: [/*#__PURE__*/_jsx(Text, {
54
- style: styles.statLabel,
55
- children: label
56
- }), /*#__PURE__*/_jsx(Text, {
57
- style: [styles.statValue, accent ? {
58
- color: accent
59
- } : null],
60
- children: value
61
- })]
62
- });
63
- }
64
- export const TaskDetailView = /*#__PURE__*/memo(function TaskDetailView({
65
- detail
66
- }) {
67
- const badge = badgeFor(detail.api);
68
- const insets = useSafeAreaInsets({
69
- minBottom: 12
70
- });
71
- const maxBucket = Math.max(1, ...detail.buckets);
72
- return /*#__PURE__*/_jsxs(ScrollView, {
73
- style: styles.root,
74
- contentContainerStyle: {
75
- paddingBottom: insets.bottom
76
- },
77
- children: [/*#__PURE__*/_jsxs(View, {
78
- style: styles.identityRow,
79
- children: [/*#__PURE__*/_jsx(View, {
80
- style: [styles.badge, {
81
- borderColor: badge.color,
82
- backgroundColor: `${badge.color}1A`
83
- }],
84
- children: /*#__PURE__*/_jsx(Text, {
85
- style: [styles.badgeText, {
86
- color: badge.color
87
- }],
88
- children: badge.text
89
- })
90
- }), /*#__PURE__*/_jsx(Text, {
91
- style: styles.name,
92
- numberOfLines: 2,
93
- children: displayName(detail)
94
- })]
95
- }), /*#__PURE__*/_jsx(Text, {
96
- style: styles.explainer,
97
- children: explainerFor(detail.api)
98
- }), /*#__PURE__*/_jsx(Text, {
99
- style: styles.sectionTitle,
100
- children: "ACTIVITY \xB7 LAST 5S"
101
- }), /*#__PURE__*/_jsx(View, {
102
- style: styles.chartRow,
103
- children: detail.buckets.map((ms, i) => /*#__PURE__*/_jsx(View, {
104
- style: styles.chartBarSlot,
105
- children: /*#__PURE__*/_jsx(View, {
106
- style: [styles.chartBar, {
107
- height: Math.max(2, ms / maxBucket * 44),
108
- backgroundColor: badge.color
109
- }]
110
- })
111
- }, `bk${i}`))
112
- }), /*#__PURE__*/_jsxs(View, {
113
- style: styles.chartLegend,
114
- children: [/*#__PURE__*/_jsxs(Text, {
115
- style: styles.chartLegendText,
116
- children: [fmt(detail.windowMs), " ms in window \xB7 ", detail.pctOfBusy.toFixed(1), "% of busy time"]
117
- }), /*#__PURE__*/_jsxs(Text, {
118
- style: styles.chartLegendText,
119
- children: ["peak ", fmt(maxBucket), " ms/250ms"]
120
- })]
121
- }), /*#__PURE__*/_jsx(Text, {
122
- style: styles.sectionTitle,
123
- children: "STATS \xB7 SINCE START"
124
- }), /*#__PURE__*/_jsxs(View, {
125
- style: styles.statGrid,
126
- children: [/*#__PURE__*/_jsx(Stat, {
127
- label: "RUNS",
128
- value: detail.calls > 0 ? fmt(detail.calls) : "—"
129
- }), /*#__PURE__*/_jsx(Stat, {
130
- label: "SCHEDULED",
131
- value: detail.scheduleCount > 0 ? fmt(detail.scheduleCount) : "—"
132
- }), /*#__PURE__*/_jsx(Stat, {
133
- label: "AVG / RUN",
134
- value: detail.calls > 0 ? `${fmt(detail.avgMs)} ms` : "—"
135
- }), /*#__PURE__*/_jsx(Stat, {
136
- label: "MAX / RUN",
137
- value: detail.maxMs > 0 ? `${fmt(detail.maxMs)} ms` : "—",
138
- accent: detail.maxMs >= 50 ? macOSColors.semantic.warning : undefined
139
- }), /*#__PURE__*/_jsx(Stat, {
140
- label: "TOTAL",
141
- value: detail.totalMs > 0 ? `${fmt(detail.totalMs)} ms` : "—"
142
- }), /*#__PURE__*/_jsx(Stat, {
143
- label: "LAST RUN",
144
- value: agoFmt(detail.lastSeenAgoMs)
145
- }), /*#__PURE__*/_jsx(Stat, {
146
- label: "FREEZES \xB7 60S",
147
- value: detail.freezes > 0 ? `${detail.freezes}` : "0",
148
- accent: detail.freezes > 0 ? macOSColors.semantic.error : undefined
149
- }), /*#__PURE__*/_jsx(Stat, {
150
- label: "WORST FREEZE",
151
- value: detail.worstFreezeMs > 0 ? `${detail.worstFreezeMs} ms` : "—",
152
- accent: detail.worstFreezeMs >= 100 ? macOSColors.semantic.error : detail.worstFreezeMs > 0 ? macOSColors.semantic.warning : undefined
153
- })]
154
- }), (detail.caller || (detail.frames?.length ?? 0) > 0) && /*#__PURE__*/_jsxs(_Fragment, {
155
- children: [/*#__PURE__*/_jsx(Text, {
156
- style: styles.sectionTitle,
157
- children: "SCHEDULED FROM"
158
- }), /*#__PURE__*/_jsxs(View, {
159
- style: styles.siteCard,
160
- children: [detail.caller && /*#__PURE__*/_jsxs(Text, {
161
- style: styles.siteCaller,
162
- children: [detail.caller, "()"]
163
- }), detail.file && /*#__PURE__*/_jsxs(Text, {
164
- style: styles.siteFile,
165
- children: [detail.file, detail.line != null ? `:${detail.line}` : ""]
166
- }), detail.frames?.map((f, i) => /*#__PURE__*/_jsxs(Text, {
167
- style: styles.siteFrame,
168
- numberOfLines: 1,
169
- children: [f.file, ":", f.line, ":", f.col]
170
- }, `fr${i}`)), /*#__PURE__*/_jsx(Text, {
171
- style: styles.siteNote,
172
- children: "Frames are bundle offsets (Hermes) \u2014 the caller name above is the readable part. Captured once when this origin got hot."
173
- })]
174
- })]
175
- }), !detail.caller && (detail.frames?.length ?? 0) === 0 && detail.api !== "unattributed" && detail.api !== "other" && /*#__PURE__*/_jsxs(_Fragment, {
176
- children: [/*#__PURE__*/_jsx(Text, {
177
- style: styles.sectionTitle,
178
- children: "SCHEDULED FROM"
179
- }), /*#__PURE__*/_jsx(Text, {
180
- style: styles.sitePending,
181
- children: detail.promoted ? "Stack capture pending — next schedule from this site will record it." : "Not hot enough yet — the scheduling stack is captured once an origin passes 25 schedules or 50ms total."
182
- })]
183
- })]
184
- });
185
- });
186
- const styles = StyleSheet.create({
187
- root: {
188
- flex: 1,
189
- // Transparent so JsModal's ToolBackground shows through (the modal paints opaque base beneath it).
190
- backgroundColor: "transparent",
191
- paddingHorizontal: 12
192
- },
193
- identityRow: {
194
- flexDirection: "row",
195
- alignItems: "center",
196
- gap: 8,
197
- paddingTop: 12
198
- },
199
- badge: {
200
- borderWidth: 1,
201
- borderRadius: 3,
202
- paddingHorizontal: 5,
203
- paddingVertical: 2
204
- },
205
- badgeText: {
206
- fontSize: 9,
207
- fontWeight: "700",
208
- letterSpacing: 0.4
209
- },
210
- name: {
211
- flex: 1,
212
- color: night.color.text,
213
- fontSize: 15,
214
- fontWeight: "600"
215
- },
216
- explainer: {
217
- color: night.color.textTertiary,
218
- fontSize: 11,
219
- lineHeight: 15,
220
- marginTop: 6,
221
- marginBottom: 4
222
- },
223
- sectionTitle: {
224
- color: night.color.textTertiary,
225
- fontSize: 9,
226
- fontWeight: "700",
227
- letterSpacing: 0.5,
228
- marginTop: 14,
229
- marginBottom: 6
230
- },
231
- chartRow: {
232
- flexDirection: "row",
233
- alignItems: "flex-end",
234
- height: 48,
235
- gap: 2,
236
- backgroundColor: night.color.surface,
237
- borderRadius: 6,
238
- borderWidth: 1,
239
- borderColor: night.color.border,
240
- paddingHorizontal: 6,
241
- paddingTop: 2
242
- },
243
- chartBarSlot: {
244
- flex: 1,
245
- alignItems: "center",
246
- justifyContent: "flex-end"
247
- },
248
- chartBar: {
249
- width: "70%",
250
- borderTopLeftRadius: 2,
251
- borderTopRightRadius: 2,
252
- opacity: 0.9
253
- },
254
- chartLegend: {
255
- flexDirection: "row",
256
- justifyContent: "space-between",
257
- marginTop: 4
258
- },
259
- chartLegendText: {
260
- color: night.color.textTertiary,
261
- fontSize: 10,
262
- fontVariant: ["tabular-nums"]
263
- },
264
- statGrid: {
265
- flexDirection: "row",
266
- flexWrap: "wrap",
267
- gap: 8
268
- },
269
- stat: {
270
- width: "23%",
271
- minWidth: 76,
272
- flexGrow: 1,
273
- backgroundColor: night.color.surface,
274
- borderWidth: 1,
275
- borderColor: night.color.border,
276
- borderRadius: 6,
277
- paddingHorizontal: 8,
278
- paddingVertical: 6
279
- },
280
- statLabel: {
281
- color: night.color.textTertiary,
282
- fontSize: 8,
283
- fontWeight: "700",
284
- letterSpacing: 0.4,
285
- marginBottom: 3
286
- },
287
- statValue: {
288
- color: night.color.text,
289
- fontSize: 13,
290
- fontWeight: "600",
291
- fontVariant: ["tabular-nums"]
292
- },
293
- siteCard: {
294
- backgroundColor: night.color.surface,
295
- borderWidth: 1,
296
- borderColor: night.color.border,
297
- borderRadius: 6,
298
- padding: 10,
299
- gap: 3
300
- },
301
- siteCaller: {
302
- color: night.color.text,
303
- fontSize: 13,
304
- fontWeight: "600"
305
- },
306
- siteFile: {
307
- color: night.color.info,
308
- fontSize: 11
309
- },
310
- siteFrame: {
311
- color: night.color.textTertiary,
312
- fontSize: 10,
313
- fontVariant: ["tabular-nums"]
314
- },
315
- siteNote: {
316
- color: night.color.textTertiary,
317
- fontSize: 9,
318
- opacity: 0.8,
319
- marginTop: 4
320
- },
321
- sitePending: {
322
- color: night.color.textTertiary,
323
- fontSize: 11
324
- }
325
- });
326
- //# sourceMappingURL=TaskDetailView.js.map
1
+ "use strict";import{memo as y}from"react";import{ScrollView as x,StyleSheet as S,Text as n,View as s}from"react-native";import{macOSColors as u,night as o,useSafeAreaInsets as w}from"@buoy-gg/shared-ui";import{badgeFor as T,displayName as k}from"./TaskTable";import{jsx as r,jsxs as a,Fragment as g}from"react/jsx-runtime";const b={timeout:"Work scheduled with setTimeout. Time shown is the callback's exclusive run time on the JS thread.",interval:"A repeating setInterval. One scheduling site, many runs \u2014 a hot interval is the classic silent JS-FPS killer.",immediate:"Work scheduled with setImmediate \u2014 runs at the end of the current event-loop turn.",raf:"requestAnimationFrame work \u2014 runs once per frame while scheduled. Cost here directly trades against 60fps.",microtask:"queueMicrotask work \u2014 runs after the current task, before the thread yields.",then:"Promise reaction (.then/.catch/.finally). Named by the function that attached the reaction. Note: async/await bodies bypass .then and land in the System row instead.",bridge:"A native\u2192JS call-in over the legacy bridge (events, module callbacks), measured as its un-nested remainder.",unattributed:"Thread time the probe measured but no JS wrapper could claim: touch handlers, React commits, native call-ins, and async/await bodies. High here on New Architecture is normal \u2014 it's where UI work lives.",other:"Origins evicted from the table when the registry hit its cap \u2014 their totals are preserved here."};function C(i){return b[i]??b.other}function d(i){if(i>=1e4)return`${Math.round(i/1e3)}k`;if(i>=1e3)return`${(i/1e3).toFixed(1)}k`;if(i>=100)return`${Math.round(i)}`;return`${Math.round(i*100)/100}`}function z(i){if(i<=0)return"\u2014";const e=i/1e3;if(e<1)return"just now";if(e<60)return`${Math.round(e)}s ago`;return`${Math.floor(e/60)}m ago`}function c({label:i,value:e,accent:l}){return a(s,{style:t.stat,children:[r(n,{style:t.statLabel,children:i}),r(n,{style:[t.statValue,l?{color:l}:null],children:e})]})}export const TaskDetailView=y(function i({detail:e}){const l=T(e.api);const p=w({minBottom:12});const f=Math.max(1,...e.buckets);return a(x,{style:t.root,contentContainerStyle:{paddingBottom:p.bottom},children:[a(s,{style:t.identityRow,children:[r(s,{style:[t.badge,{borderColor:l.color,backgroundColor:`${l.color}1A`}],children:r(n,{style:[t.badgeText,{color:l.color}],children:l.text})}),r(n,{style:t.name,numberOfLines:2,children:k(e)})]}),r(n,{style:t.explainer,children:C(e.api)}),r(n,{style:t.sectionTitle,children:"ACTIVITY \xB7 LAST 5S"}),r(s,{style:t.chartRow,children:e.buckets.map((h,m)=>r(s,{style:t.chartBarSlot,children:r(s,{style:[t.chartBar,{height:Math.max(2,h/f*44),backgroundColor:l.color}]})},`bk${m}`))}),a(s,{style:t.chartLegend,children:[a(n,{style:t.chartLegendText,children:[d(e.windowMs)," ms in window \xB7 ",e.pctOfBusy.toFixed(1),"% of busy time"]}),a(n,{style:t.chartLegendText,children:["peak ",d(f)," ms/250ms"]})]}),r(n,{style:t.sectionTitle,children:"STATS \xB7 SINCE START"}),a(s,{style:t.statGrid,children:[r(c,{label:"RUNS",value:e.calls>0?d(e.calls):"\u2014"}),r(c,{label:"SCHEDULED",value:e.scheduleCount>0?d(e.scheduleCount):"\u2014"}),r(c,{label:"AVG / RUN",value:e.calls>0?`${d(e.avgMs)} ms`:"\u2014"}),r(c,{label:"MAX / RUN",value:e.maxMs>0?`${d(e.maxMs)} ms`:"\u2014",accent:e.maxMs>=50?u.semantic.warning:void 0}),r(c,{label:"TOTAL",value:e.totalMs>0?`${d(e.totalMs)} ms`:"\u2014"}),r(c,{label:"LAST RUN",value:z(e.lastSeenAgoMs)}),r(c,{label:"FREEZES \xB7 60S",value:e.freezes>0?`${e.freezes}`:"0",accent:e.freezes>0?u.semantic.error:void 0}),r(c,{label:"WORST FREEZE",value:e.worstFreezeMs>0?`${e.worstFreezeMs} ms`:"\u2014",accent:e.worstFreezeMs>=100?u.semantic.error:e.worstFreezeMs>0?u.semantic.warning:void 0})]}),(e.caller||(e.frames?.length??0)>0)&&a(g,{children:[r(n,{style:t.sectionTitle,children:"SCHEDULED FROM"}),a(s,{style:t.siteCard,children:[e.caller&&a(n,{style:t.siteCaller,children:[e.caller,"()"]}),e.file&&a(n,{style:t.siteFile,children:[e.file,e.line!=null?`:${e.line}`:""]}),e.frames?.map((h,m)=>a(n,{style:t.siteFrame,numberOfLines:1,children:[h.file,":",h.line,":",h.col]},`fr${m}`)),r(n,{style:t.siteNote,children:"Frames are bundle offsets (Hermes) \u2014 the caller name above is the readable part. Captured once when this origin got hot."})]})]}),!e.caller&&(e.frames?.length??0)===0&&e.api!=="unattributed"&&e.api!=="other"&&a(g,{children:[r(n,{style:t.sectionTitle,children:"SCHEDULED FROM"}),r(n,{style:t.sitePending,children:e.promoted?"Stack capture pending \u2014 next schedule from this site will record it.":"Not hot enough yet \u2014 the scheduling stack is captured once an origin passes 25 schedules or 50ms total."})]})]})});const t=S.create({root:{flex:1,backgroundColor:"transparent",paddingHorizontal:12},identityRow:{flexDirection:"row",alignItems:"center",gap:8,paddingTop:12},badge:{borderWidth:1,borderRadius:3,paddingHorizontal:5,paddingVertical:2},badgeText:{fontSize:9,fontWeight:"700",letterSpacing:.4},name:{flex:1,color:o.color.text,fontSize:15,fontWeight:"600"},explainer:{color:o.color.textTertiary,fontSize:11,lineHeight:15,marginTop:6,marginBottom:4},sectionTitle:{color:o.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.5,marginTop:14,marginBottom:6},chartRow:{flexDirection:"row",alignItems:"flex-end",height:48,gap:2,backgroundColor:o.color.surface,borderRadius:6,borderWidth:1,borderColor:o.color.border,paddingHorizontal:6,paddingTop:2},chartBarSlot:{flex:1,alignItems:"center",justifyContent:"flex-end"},chartBar:{width:"70%",borderTopLeftRadius:2,borderTopRightRadius:2,opacity:.9},chartLegend:{flexDirection:"row",justifyContent:"space-between",marginTop:4},chartLegendText:{color:o.color.textTertiary,fontSize:10,fontVariant:["tabular-nums"]},statGrid:{flexDirection:"row",flexWrap:"wrap",gap:8},stat:{width:"23%",minWidth:76,flexGrow:1,backgroundColor:o.color.surface,borderWidth:1,borderColor:o.color.border,borderRadius:6,paddingHorizontal:8,paddingVertical:6},statLabel:{color:o.color.textTertiary,fontSize:8,fontWeight:"700",letterSpacing:.4,marginBottom:3},statValue:{color:o.color.text,fontSize:13,fontWeight:"600",fontVariant:["tabular-nums"]},siteCard:{backgroundColor:o.color.surface,borderWidth:1,borderColor:o.color.border,borderRadius:6,padding:10,gap:3},siteCaller:{color:o.color.text,fontSize:13,fontWeight:"600"},siteFile:{color:o.color.info,fontSize:11},siteFrame:{color:o.color.textTertiary,fontSize:10,fontVariant:["tabular-nums"]},siteNote:{color:o.color.textTertiary,fontSize:9,opacity:.8,marginTop:4},sitePending:{color:o.color.textTertiary,fontSize:11}});