@opengeni/react 0.52.1 → 0.57.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.
- package/README.md +48 -0
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +43 -14
- package/dist/artifacts.js.map +1 -1
- package/dist/{chunk-ROIRTM37.js → chunk-5UQPNLIO.js} +6 -6
- package/dist/{chunk-JR3QFY6B.js → chunk-6KLX2RH5.js} +49 -2
- package/dist/chunk-6KLX2RH5.js.map +1 -0
- package/dist/{chunk-FWS3KC3Z.js → chunk-B6WPZSTT.js} +104 -104
- package/dist/{chunk-FWS3KC3Z.js.map → chunk-B6WPZSTT.js.map} +1 -1
- package/dist/{chunk-HDBG7XGO.js → chunk-C5ZPSSS5.js} +50 -1
- package/dist/chunk-C5ZPSSS5.js.map +1 -0
- package/dist/{chunk-X4S56Y2H.js → chunk-HA46CYQK.js} +135 -11
- package/dist/chunk-HA46CYQK.js.map +1 -0
- package/dist/{chunk-724BW4TW.js → chunk-IGC6A2ZI.js} +2 -2
- package/dist/chunk-LLOLUHVG.js +5937 -0
- package/dist/chunk-LLOLUHVG.js.map +1 -0
- package/dist/{chunk-WYA65Y3F.js → chunk-MKPIAGVL.js} +13 -3
- package/dist/chunk-MKPIAGVL.js.map +1 -0
- package/dist/chunk-R3AZOAB5.js +933 -0
- package/dist/chunk-R3AZOAB5.js.map +1 -0
- package/dist/{chunk-23EJ676W.js → chunk-XBZWOM2K.js} +9 -4
- package/dist/chunk-XBZWOM2K.js.map +1 -0
- package/dist/{chunk-JAGDUCZQ.js → chunk-Y7OEDUJ5.js} +17 -13
- package/dist/chunk-Y7OEDUJ5.js.map +1 -0
- package/dist/client.d.ts +6 -4
- package/dist/components/artifacts/index.d.ts +1 -0
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +14 -0
- package/dist/components/browser-input.d.ts +7 -0
- package/dist/components/browser-viewer.d.ts +5 -4
- package/dist/components/computer-viewer.d.ts +2 -1
- package/dist/components/desktop-viewer.d.ts +26 -2
- package/dist/components/interaction-intervention-banner.d.ts +11 -0
- package/dist/components/sandbox-terminal.d.ts +4 -1
- package/dist/components/sandbox-workspace.d.ts +3 -0
- package/dist/composer.js +6 -6
- package/dist/hooks/use-auth-runs.d.ts +32 -0
- package/dist/hooks/use-browser-downloads.d.ts +25 -0
- package/dist/hooks/use-browser-identities.d.ts +5 -1
- package/dist/hooks/use-browser-session.d.ts +2 -1
- package/dist/hooks/use-browser-sessions.d.ts +1 -1
- package/dist/hooks/use-channels.d.ts +26 -0
- package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
- package/dist/hooks/use-computer-session.d.ts +2 -1
- package/dist/hooks/use-computer-sessions.d.ts +1 -1
- package/dist/hooks/use-desktop-stream.d.ts +4 -0
- package/dist/hooks/use-interaction-interventions.d.ts +27 -0
- package/dist/hooks/use-interaction-invalidation.d.ts +19 -0
- package/dist/hooks/use-network-routes.d.ts +25 -0
- package/dist/hooks/use-site-auth-connections.d.ts +25 -0
- package/dist/hooks/use-supergrok-accounts.d.ts +26 -0
- package/dist/hooks/use-terminal-stream.d.ts +3 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1220 -1545
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +13 -3
- package/dist/interaction.js +520 -6
- package/dist/interaction.js.map +1 -1
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +15 -0
- package/dist/lib/host-platform.d.ts +5 -0
- package/dist/lib/relay-wire.d.ts +20 -1
- package/dist/machines.js +3 -3
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +3 -2
- package/dist/realtime/realtime-control.d.ts +2 -2
- package/dist/realtime.js +36 -9
- package/dist/realtime.js.map +1 -1
- package/dist/session-context.d.ts +10 -2
- package/dist/session-ui.js +3 -3
- package/dist/session.js +11 -11
- package/dist/timeline/types.d.ts +5 -0
- package/package.json +2 -2
- package/src/artifacts.ts +3 -0
- package/src/client.ts +73 -3
- package/src/components/artifacts/index.ts +5 -0
- package/src/components/artifacts/published-html-artifact-frame.tsx +38 -0
- package/src/components/browser-input.ts +65 -0
- package/src/components/browser-viewer.tsx +1287 -177
- package/src/components/computer-viewer.tsx +611 -114
- package/src/components/desktop-viewer.tsx +114 -1
- package/src/components/interaction-intervention-banner.tsx +99 -0
- package/src/components/machines/machine-detail.tsx +1 -1
- package/src/components/model-policy-picker.tsx +15 -0
- package/src/components/sandbox-terminal.tsx +24 -7
- package/src/components/sandbox-workspace.tsx +42 -4
- package/src/components/workspace-dock.tsx +59 -5
- package/src/hooks/use-attached-browsers.ts +13 -11
- package/src/hooks/use-auth-runs.ts +278 -0
- package/src/hooks/use-browser-downloads.ts +218 -0
- package/src/hooks/use-browser-frame-stream.ts +168 -59
- package/src/hooks/use-browser-identities.ts +47 -6
- package/src/hooks/use-browser-session.ts +94 -27
- package/src/hooks/use-browser-sessions.ts +19 -14
- package/src/hooks/use-channels.ts +99 -0
- package/src/hooks/use-computer-frame-stream.ts +184 -61
- package/src/hooks/use-computer-session.ts +22 -2
- package/src/hooks/use-computer-sessions.ts +19 -13
- package/src/hooks/use-desktop-stream.ts +39 -7
- package/src/hooks/use-interaction-interventions.ts +242 -0
- package/src/hooks/use-interaction-invalidation.ts +66 -0
- package/src/hooks/use-machine-chip.ts +13 -3
- package/src/hooks/use-network-routes.ts +214 -0
- package/src/hooks/use-site-auth-connections.ts +226 -0
- package/src/hooks/use-supergrok-accounts.ts +81 -0
- package/src/hooks/use-terminal-stream.ts +288 -55
- package/src/index.ts +8 -0
- package/src/interaction.ts +30 -0
- package/src/lib/host-platform.ts +10 -0
- package/src/lib/relay-wire.ts +43 -4
- package/src/lib/terminal-capability.ts +1 -1
- package/src/model-policy.ts +19 -4
- package/src/provider.tsx +133 -1
- package/src/realtime/realtime-control.tsx +34 -6
- package/src/session-context.ts +66 -1
- package/src/timeline/activity-rail.tsx +6 -0
- package/src/timeline/projection.ts +58 -0
- package/src/timeline/types.ts +2 -0
- package/styles/compiled.css +64 -6
- package/dist/chunk-23EJ676W.js.map +0 -1
- package/dist/chunk-6BBWWOOU.js +0 -82
- package/dist/chunk-6BBWWOOU.js.map +0 -1
- package/dist/chunk-7I2KB3OK.js +0 -3895
- package/dist/chunk-7I2KB3OK.js.map +0 -1
- package/dist/chunk-HDBG7XGO.js.map +0 -1
- package/dist/chunk-JAGDUCZQ.js.map +0 -1
- package/dist/chunk-JR3QFY6B.js.map +0 -1
- package/dist/chunk-WYA65Y3F.js.map +0 -1
- package/dist/chunk-X4S56Y2H.js.map +0 -1
- package/dist/interactive-workbench-viewers-KHNOHWQE.js +0 -13
- /package/dist/{chunk-ROIRTM37.js.map → chunk-5UQPNLIO.js.map} +0 -0
- /package/dist/{chunk-724BW4TW.js.map → chunk-IGC6A2ZI.js.map} +0 -0
- /package/dist/{interactive-workbench-viewers-KHNOHWQE.js.map → interactive-workbench-viewers-TOHBXJEE.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,60 +1,58 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
v4aToGitFileDiff
|
|
57
|
-
} from "./chunk-JAGDUCZQ.js";
|
|
2
|
+
SESSION_EVENT_BROWSER_MAX_BYTES,
|
|
3
|
+
SESSION_EVENT_BROWSER_MAX_COUNT,
|
|
4
|
+
SESSION_EVENT_BROWSER_PENDING_MAX_BYTES,
|
|
5
|
+
SESSION_EVENT_BROWSER_PENDING_MAX_COUNT,
|
|
6
|
+
SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES,
|
|
7
|
+
approvalsFromRequiresAction,
|
|
8
|
+
boundBrowserSessionEventWindow,
|
|
9
|
+
humanInputRequestFromEvent,
|
|
10
|
+
isGoalEvent,
|
|
11
|
+
isHumanInputEvent,
|
|
12
|
+
isLineageRefreshEvent,
|
|
13
|
+
isSessionMcpApprovalPolicyEvent,
|
|
14
|
+
isTitleEvent,
|
|
15
|
+
isTurnQueueEvent,
|
|
16
|
+
projectPendingApprovals,
|
|
17
|
+
projectPendingHumanInputRequests,
|
|
18
|
+
useFileAttachments,
|
|
19
|
+
useGoal,
|
|
20
|
+
useHumanInputRequests,
|
|
21
|
+
useSession,
|
|
22
|
+
useSessionControl,
|
|
23
|
+
useSessionEvents,
|
|
24
|
+
useSessionLineage,
|
|
25
|
+
useSessionMcpApprovalPolicy,
|
|
26
|
+
useTurnQueue
|
|
27
|
+
} from "./chunk-B6WPZSTT.js";
|
|
28
|
+
import {
|
|
29
|
+
CONNECTION_STATUS_META,
|
|
30
|
+
ConnectionDot,
|
|
31
|
+
ConnectionStatusPill,
|
|
32
|
+
EnrollmentConsent,
|
|
33
|
+
EnrollmentDeviceFlow,
|
|
34
|
+
HEALTH_TOKEN,
|
|
35
|
+
MACHINE_STATE_BADGE_META,
|
|
36
|
+
METRICS,
|
|
37
|
+
METRIC_WINDOWS,
|
|
38
|
+
MachineCard,
|
|
39
|
+
MachineDetail,
|
|
40
|
+
MachineDockBar,
|
|
41
|
+
MachineHealthPill,
|
|
42
|
+
MachineMetrics,
|
|
43
|
+
MachineStatusPill,
|
|
44
|
+
MachinesDashboard,
|
|
45
|
+
MetricHistoryChart,
|
|
46
|
+
MetricSparkline,
|
|
47
|
+
OpenGeniProvider,
|
|
48
|
+
SharedMachineDisclosure,
|
|
49
|
+
WINDOW_LABEL,
|
|
50
|
+
connectionStatusForState,
|
|
51
|
+
deriveHealth,
|
|
52
|
+
healthPulses,
|
|
53
|
+
pointsFor,
|
|
54
|
+
useMachines
|
|
55
|
+
} from "./chunk-HA46CYQK.js";
|
|
58
56
|
import {
|
|
59
57
|
Actions,
|
|
60
58
|
AttachButton,
|
|
@@ -107,7 +105,14 @@ import {
|
|
|
107
105
|
useSlashCommands,
|
|
108
106
|
useTranscription,
|
|
109
107
|
useVoiceInput
|
|
110
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-5UQPNLIO.js";
|
|
109
|
+
import {
|
|
110
|
+
FILE_ONLY_MESSAGE_TEXT,
|
|
111
|
+
composeSendInput,
|
|
112
|
+
shouldSteerOnKey,
|
|
113
|
+
shouldSubmitOnKey,
|
|
114
|
+
useComposer
|
|
115
|
+
} from "./chunk-IGC6A2ZI.js";
|
|
111
116
|
import {
|
|
112
117
|
BillingClassMark,
|
|
113
118
|
ModelPolicyPicker,
|
|
@@ -116,7 +121,7 @@ import {
|
|
|
116
121
|
PickerBackHeader,
|
|
117
122
|
PickerNavRow,
|
|
118
123
|
defaultModelPolicyPickerMessages
|
|
119
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-MKPIAGVL.js";
|
|
120
125
|
import {
|
|
121
126
|
advancedSourceSummary,
|
|
122
127
|
availabilityReasonLabel,
|
|
@@ -134,90 +139,106 @@ import {
|
|
|
134
139
|
projectPickerRows,
|
|
135
140
|
runnableLatencyModesForModel,
|
|
136
141
|
sortPickerRows
|
|
137
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-XBZWOM2K.js";
|
|
143
|
+
import {
|
|
144
|
+
ActivityDisclosure,
|
|
145
|
+
ActivityRail,
|
|
146
|
+
BUILT_IN_TURN_SUMMARY_FACET_IDS,
|
|
147
|
+
BodyNote,
|
|
148
|
+
CopyButton,
|
|
149
|
+
CopyHoverFrame,
|
|
150
|
+
DisclosureDefaultsProvider,
|
|
151
|
+
GeneratedVideoPlayer,
|
|
152
|
+
HumanInputForm,
|
|
153
|
+
HumanInputSurface,
|
|
154
|
+
LightboxProvider,
|
|
155
|
+
Markdown,
|
|
156
|
+
MediaEmpty,
|
|
157
|
+
MediaSkeleton,
|
|
158
|
+
MessageTimeline,
|
|
159
|
+
PayloadBlock,
|
|
160
|
+
PierreDiff,
|
|
161
|
+
QueueSurface,
|
|
162
|
+
SESSION_STATUS_META,
|
|
163
|
+
ScreenshotFigure,
|
|
164
|
+
SessionChrome,
|
|
165
|
+
SessionStatus,
|
|
166
|
+
StatusDot,
|
|
167
|
+
TermBlock,
|
|
168
|
+
Thumbnail,
|
|
169
|
+
TimelineRow,
|
|
170
|
+
TurnSummary,
|
|
171
|
+
UserMessageBody,
|
|
172
|
+
answersFromDrafts,
|
|
173
|
+
applyPatchOps,
|
|
174
|
+
applyPatchOpsFromToolItem,
|
|
175
|
+
controlCaret,
|
|
176
|
+
createDefaultToolRegistry,
|
|
177
|
+
createToolRegistry,
|
|
178
|
+
defaultHumanInputFormMessages,
|
|
179
|
+
defaultToolRegistry,
|
|
180
|
+
execTruncated,
|
|
181
|
+
gitFileDiffToPatch,
|
|
182
|
+
isApplyPatch,
|
|
183
|
+
isExecSessionLostBanner,
|
|
184
|
+
looksBinary,
|
|
185
|
+
parseExecBannerSessionId,
|
|
186
|
+
parseFreeformApplyPatch,
|
|
187
|
+
parseToolArgs,
|
|
188
|
+
rawTypeOf,
|
|
189
|
+
sandboxCommandExitCode,
|
|
190
|
+
sessionChromeGoalPillState,
|
|
191
|
+
stripExecBanner,
|
|
192
|
+
tailPeek,
|
|
193
|
+
unwrapMcpOutput,
|
|
194
|
+
useLightbox,
|
|
195
|
+
useLightboxOptional,
|
|
196
|
+
useThemeType,
|
|
197
|
+
userMessageLikelyNeedsDisclosure,
|
|
198
|
+
v4aToGitFileDiff
|
|
199
|
+
} from "./chunk-Y7OEDUJ5.js";
|
|
200
|
+
import {
|
|
201
|
+
buildTimeline,
|
|
202
|
+
creditExhaustedFromEvents,
|
|
203
|
+
extractSessionRef,
|
|
204
|
+
groupTimeline,
|
|
205
|
+
sessionStatusFromEvents,
|
|
206
|
+
toolDisplayName
|
|
207
|
+
} from "./chunk-6KLX2RH5.js";
|
|
208
|
+
import {
|
|
209
|
+
TimelineAnnotationsChip
|
|
210
|
+
} from "./chunk-WSK7G5LE.js";
|
|
138
211
|
import {
|
|
139
212
|
Tooltip,
|
|
140
213
|
TooltipContent,
|
|
141
214
|
TooltipProvider,
|
|
142
215
|
TooltipTrigger
|
|
143
216
|
} from "./chunk-FK6VG4LL.js";
|
|
144
|
-
import {
|
|
145
|
-
TimelineAnnotationsChip
|
|
146
|
-
} from "./chunk-WSK7G5LE.js";
|
|
147
217
|
import {
|
|
148
218
|
usePortalTokenSource,
|
|
149
219
|
usePortalTokenStyle
|
|
150
220
|
} from "./chunk-VZTQ73XT.js";
|
|
151
221
|
import {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
MachineDetail,
|
|
163
|
-
MachineDockBar,
|
|
164
|
-
MachineHealthPill,
|
|
165
|
-
MachineMetrics,
|
|
166
|
-
MachineStatusPill,
|
|
167
|
-
MachinesDashboard,
|
|
168
|
-
MetricHistoryChart,
|
|
169
|
-
MetricSparkline,
|
|
170
|
-
OpenGeniProvider,
|
|
171
|
-
SharedMachineDisclosure,
|
|
172
|
-
WINDOW_LABEL,
|
|
173
|
-
connectionStatusForState,
|
|
174
|
-
deriveHealth,
|
|
175
|
-
healthPulses,
|
|
176
|
-
pointsFor,
|
|
177
|
-
useMachines
|
|
178
|
-
} from "./chunk-X4S56Y2H.js";
|
|
179
|
-
import {
|
|
180
|
-
SESSION_EVENT_BROWSER_MAX_BYTES,
|
|
181
|
-
SESSION_EVENT_BROWSER_MAX_COUNT,
|
|
182
|
-
SESSION_EVENT_BROWSER_PENDING_MAX_BYTES,
|
|
183
|
-
SESSION_EVENT_BROWSER_PENDING_MAX_COUNT,
|
|
184
|
-
SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES,
|
|
185
|
-
approvalsFromRequiresAction,
|
|
186
|
-
boundBrowserSessionEventWindow,
|
|
187
|
-
humanInputRequestFromEvent,
|
|
188
|
-
isGoalEvent,
|
|
189
|
-
isHumanInputEvent,
|
|
190
|
-
isLineageRefreshEvent,
|
|
191
|
-
isSessionMcpApprovalPolicyEvent,
|
|
192
|
-
isTitleEvent,
|
|
193
|
-
isTurnQueueEvent,
|
|
194
|
-
projectPendingApprovals,
|
|
195
|
-
projectPendingHumanInputRequests,
|
|
196
|
-
useFileAttachments,
|
|
197
|
-
useGoal,
|
|
198
|
-
useHumanInputRequests,
|
|
199
|
-
useSession,
|
|
200
|
-
useSessionControl,
|
|
201
|
-
useSessionEvents,
|
|
202
|
-
useSessionLineage,
|
|
203
|
-
useSessionMcpApprovalPolicy,
|
|
204
|
-
useTurnQueue
|
|
205
|
-
} from "./chunk-FWS3KC3Z.js";
|
|
222
|
+
DesktopViewer,
|
|
223
|
+
STREAM_KIND_PTY,
|
|
224
|
+
STREAM_ROLE_CLIENT,
|
|
225
|
+
decodeStreamFrame,
|
|
226
|
+
decodeStreamOpenAck,
|
|
227
|
+
encodeStreamFrame,
|
|
228
|
+
encodeStreamOpen,
|
|
229
|
+
useDesktopStream,
|
|
230
|
+
useRelayFrameStream
|
|
231
|
+
} from "./chunk-R3AZOAB5.js";
|
|
206
232
|
import {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
toolDisplayName
|
|
213
|
-
} from "./chunk-JR3QFY6B.js";
|
|
233
|
+
useMutationRunner,
|
|
234
|
+
usePageLiveActivity,
|
|
235
|
+
usePolledValue,
|
|
236
|
+
useSessionEventTrigger
|
|
237
|
+
} from "./chunk-KZ73RL76.js";
|
|
214
238
|
import {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
shouldSubmitOnKey,
|
|
219
|
-
useComposer
|
|
220
|
-
} from "./chunk-724BW4TW.js";
|
|
239
|
+
useOpenGeni,
|
|
240
|
+
useOpenGeniClient
|
|
241
|
+
} from "./chunk-C5ZPSSS5.js";
|
|
221
242
|
import {
|
|
222
243
|
COMPOSER_PAYMENT_REQUIRED_MESSAGE,
|
|
223
244
|
CREDIT_EXHAUSTION_MESSAGE,
|
|
@@ -231,23 +252,6 @@ import {
|
|
|
231
252
|
truncate,
|
|
232
253
|
tryParseJson
|
|
233
254
|
} from "./chunk-LAKLF4PA.js";
|
|
234
|
-
import {
|
|
235
|
-
STREAM_KIND_DESKTOP,
|
|
236
|
-
STREAM_ROLE_CLIENT,
|
|
237
|
-
decodeStreamFrame,
|
|
238
|
-
decodeStreamOpenAck,
|
|
239
|
-
encodeStreamOpen
|
|
240
|
-
} from "./chunk-6BBWWOOU.js";
|
|
241
|
-
import {
|
|
242
|
-
useMutationRunner,
|
|
243
|
-
usePageLiveActivity,
|
|
244
|
-
usePolledValue,
|
|
245
|
-
useSessionEventTrigger
|
|
246
|
-
} from "./chunk-KZ73RL76.js";
|
|
247
|
-
import {
|
|
248
|
-
useOpenGeni,
|
|
249
|
-
useOpenGeniClient
|
|
250
|
-
} from "./chunk-HDBG7XGO.js";
|
|
251
255
|
import {
|
|
252
256
|
cn
|
|
253
257
|
} from "./chunk-22KP6LR5.js";
|
|
@@ -451,19 +455,103 @@ function useVariableSets(options = {}) {
|
|
|
451
455
|
if (result) {
|
|
452
456
|
await refresh();
|
|
453
457
|
}
|
|
454
|
-
return result === true;
|
|
458
|
+
return result === true;
|
|
459
|
+
},
|
|
460
|
+
[client, workspaceId, run, refresh]
|
|
461
|
+
);
|
|
462
|
+
const readVariable = useCallback4(
|
|
463
|
+
async (variableSetId, name) => await run(() => client.getVariableSetVariable(workspaceId, variableSetId, name)),
|
|
464
|
+
[client, workspaceId, run]
|
|
465
|
+
);
|
|
466
|
+
const setVariable = useCallback4(
|
|
467
|
+
async (variableSetId, name, value) => {
|
|
468
|
+
const result = await run(
|
|
469
|
+
() => client.setVariableSetVariable(workspaceId, variableSetId, name, value)
|
|
470
|
+
);
|
|
471
|
+
if (result) {
|
|
472
|
+
await refresh();
|
|
473
|
+
}
|
|
474
|
+
return result;
|
|
475
|
+
},
|
|
476
|
+
[client, workspaceId, run, refresh]
|
|
477
|
+
);
|
|
478
|
+
const deleteVariable = useCallback4(
|
|
479
|
+
async (variableSetId, name) => {
|
|
480
|
+
const result = await run(async () => {
|
|
481
|
+
await client.deleteVariableSetVariable(workspaceId, variableSetId, name);
|
|
482
|
+
return true;
|
|
483
|
+
});
|
|
484
|
+
if (result) {
|
|
485
|
+
await refresh();
|
|
486
|
+
}
|
|
487
|
+
return result === true;
|
|
488
|
+
},
|
|
489
|
+
[client, workspaceId, run, refresh]
|
|
490
|
+
);
|
|
491
|
+
return {
|
|
492
|
+
variableSets: data ?? [],
|
|
493
|
+
loading,
|
|
494
|
+
error,
|
|
495
|
+
refresh,
|
|
496
|
+
create,
|
|
497
|
+
update,
|
|
498
|
+
remove,
|
|
499
|
+
readVariable,
|
|
500
|
+
setVariable,
|
|
501
|
+
deleteVariable,
|
|
502
|
+
mutating,
|
|
503
|
+
mutationError,
|
|
504
|
+
clearMutationError
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function useEnvironments(options = {}) {
|
|
508
|
+
const legacyClient = useMemo2(() => {
|
|
509
|
+
if (!options.client) {
|
|
510
|
+
return void 0;
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
...options.client,
|
|
514
|
+
listVariableSets: options.client.listEnvironments ?? options.client.listVariableSets,
|
|
515
|
+
createVariableSet: options.client.createEnvironment ?? options.client.createVariableSet,
|
|
516
|
+
updateVariableSet: options.client.updateEnvironment ?? options.client.updateVariableSet,
|
|
517
|
+
deleteVariableSet: options.client.deleteEnvironment ?? options.client.deleteVariableSet,
|
|
518
|
+
setVariableSetVariable: options.client.setEnvironmentVariable ?? options.client.setVariableSetVariable,
|
|
519
|
+
deleteVariableSetVariable: options.client.deleteEnvironmentVariable ?? options.client.deleteVariableSetVariable
|
|
520
|
+
};
|
|
521
|
+
}, [options.client]);
|
|
522
|
+
const result = useVariableSets({
|
|
523
|
+
...options,
|
|
524
|
+
...legacyClient ? { client: legacyClient } : {}
|
|
525
|
+
});
|
|
526
|
+
return { ...result, environments: result.variableSets };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/hooks/use-channels.ts
|
|
530
|
+
import { useCallback as useCallback5 } from "react";
|
|
531
|
+
function useChannels(options = {}) {
|
|
532
|
+
const { client, workspaceId } = useOpenGeni(options);
|
|
533
|
+
const load = useCallback5(
|
|
534
|
+
async () => await client.listChannels(workspaceId),
|
|
535
|
+
[client, workspaceId]
|
|
536
|
+
);
|
|
537
|
+
const { data, loading, error, refresh } = usePolledValue(load, {
|
|
538
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
539
|
+
enabled: options.enabled
|
|
540
|
+
});
|
|
541
|
+
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
542
|
+
const create = useCallback5(
|
|
543
|
+
async (request) => {
|
|
544
|
+
const result = await run(() => client.createChannel(workspaceId, request));
|
|
545
|
+
if (result) {
|
|
546
|
+
await refresh();
|
|
547
|
+
}
|
|
548
|
+
return result;
|
|
455
549
|
},
|
|
456
550
|
[client, workspaceId, run, refresh]
|
|
457
551
|
);
|
|
458
|
-
const
|
|
459
|
-
async (
|
|
460
|
-
|
|
461
|
-
);
|
|
462
|
-
const setVariable = useCallback4(
|
|
463
|
-
async (variableSetId, name, value) => {
|
|
464
|
-
const result = await run(
|
|
465
|
-
() => client.setVariableSetVariable(workspaceId, variableSetId, name, value)
|
|
466
|
-
);
|
|
552
|
+
const update = useCallback5(
|
|
553
|
+
async (channelId, request) => {
|
|
554
|
+
const result = await run(() => client.updateChannel(workspaceId, channelId, request));
|
|
467
555
|
if (result) {
|
|
468
556
|
await refresh();
|
|
469
557
|
}
|
|
@@ -471,10 +559,10 @@ function useVariableSets(options = {}) {
|
|
|
471
559
|
},
|
|
472
560
|
[client, workspaceId, run, refresh]
|
|
473
561
|
);
|
|
474
|
-
const
|
|
475
|
-
async (
|
|
562
|
+
const remove = useCallback5(
|
|
563
|
+
async (channelId) => {
|
|
476
564
|
const result = await run(async () => {
|
|
477
|
-
await client.
|
|
565
|
+
await client.deleteChannel(workspaceId, channelId);
|
|
478
566
|
return true;
|
|
479
567
|
});
|
|
480
568
|
if (result) {
|
|
@@ -484,55 +572,38 @@ function useVariableSets(options = {}) {
|
|
|
484
572
|
},
|
|
485
573
|
[client, workspaceId, run, refresh]
|
|
486
574
|
);
|
|
575
|
+
const moveSession = useCallback5(
|
|
576
|
+
async (sessionId, channelId) => {
|
|
577
|
+
return await run(() => client.updateSessionChannel(workspaceId, sessionId, { channelId }));
|
|
578
|
+
},
|
|
579
|
+
[client, workspaceId, run]
|
|
580
|
+
);
|
|
487
581
|
return {
|
|
488
|
-
|
|
582
|
+
channels: data ?? [],
|
|
489
583
|
loading,
|
|
490
584
|
error,
|
|
491
585
|
refresh,
|
|
492
586
|
create,
|
|
493
587
|
update,
|
|
494
588
|
remove,
|
|
495
|
-
|
|
496
|
-
setVariable,
|
|
497
|
-
deleteVariable,
|
|
589
|
+
moveSession,
|
|
498
590
|
mutating,
|
|
499
591
|
mutationError,
|
|
500
592
|
clearMutationError
|
|
501
593
|
};
|
|
502
594
|
}
|
|
503
|
-
function useEnvironments(options = {}) {
|
|
504
|
-
const legacyClient = useMemo2(() => {
|
|
505
|
-
if (!options.client) {
|
|
506
|
-
return void 0;
|
|
507
|
-
}
|
|
508
|
-
return {
|
|
509
|
-
...options.client,
|
|
510
|
-
listVariableSets: options.client.listEnvironments ?? options.client.listVariableSets,
|
|
511
|
-
createVariableSet: options.client.createEnvironment ?? options.client.createVariableSet,
|
|
512
|
-
updateVariableSet: options.client.updateEnvironment ?? options.client.updateVariableSet,
|
|
513
|
-
deleteVariableSet: options.client.deleteEnvironment ?? options.client.deleteVariableSet,
|
|
514
|
-
setVariableSetVariable: options.client.setEnvironmentVariable ?? options.client.setVariableSetVariable,
|
|
515
|
-
deleteVariableSetVariable: options.client.deleteEnvironmentVariable ?? options.client.deleteVariableSetVariable
|
|
516
|
-
};
|
|
517
|
-
}, [options.client]);
|
|
518
|
-
const result = useVariableSets({
|
|
519
|
-
...options,
|
|
520
|
-
...legacyClient ? { client: legacyClient } : {}
|
|
521
|
-
});
|
|
522
|
-
return { ...result, environments: result.variableSets };
|
|
523
|
-
}
|
|
524
595
|
|
|
525
596
|
// src/hooks/use-rigs.ts
|
|
526
|
-
import { useCallback as
|
|
597
|
+
import { useCallback as useCallback6 } from "react";
|
|
527
598
|
function useRigs(options = {}) {
|
|
528
599
|
const { client, workspaceId } = useOpenGeni(options);
|
|
529
|
-
const load =
|
|
600
|
+
const load = useCallback6(async () => await client.listRigs(workspaceId), [client, workspaceId]);
|
|
530
601
|
const { data, loading, error, refresh } = usePolledValue(load, {
|
|
531
602
|
pollIntervalMs: options.pollIntervalMs,
|
|
532
603
|
enabled: options.enabled
|
|
533
604
|
});
|
|
534
605
|
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
535
|
-
const create =
|
|
606
|
+
const create = useCallback6(
|
|
536
607
|
async (request) => {
|
|
537
608
|
const result = await run(() => client.createRig(workspaceId, request));
|
|
538
609
|
if (result) {
|
|
@@ -542,7 +613,7 @@ function useRigs(options = {}) {
|
|
|
542
613
|
},
|
|
543
614
|
[client, workspaceId, run, refresh]
|
|
544
615
|
);
|
|
545
|
-
const update =
|
|
616
|
+
const update = useCallback6(
|
|
546
617
|
async (rigId, request) => {
|
|
547
618
|
const result = await run(() => client.updateRig(workspaceId, rigId, request));
|
|
548
619
|
if (result) {
|
|
@@ -552,7 +623,7 @@ function useRigs(options = {}) {
|
|
|
552
623
|
},
|
|
553
624
|
[client, workspaceId, run, refresh]
|
|
554
625
|
);
|
|
555
|
-
const remove =
|
|
626
|
+
const remove = useCallback6(
|
|
556
627
|
async (rigId) => {
|
|
557
628
|
const result = await run(async () => {
|
|
558
629
|
await client.deleteRig(workspaceId, rigId);
|
|
@@ -565,13 +636,13 @@ function useRigs(options = {}) {
|
|
|
565
636
|
},
|
|
566
637
|
[client, workspaceId, run, refresh]
|
|
567
638
|
);
|
|
568
|
-
const listVersions =
|
|
639
|
+
const listVersions = useCallback6(
|
|
569
640
|
async (rigId) => {
|
|
570
641
|
return await run(() => client.listRigVersions(workspaceId, rigId));
|
|
571
642
|
},
|
|
572
643
|
[client, workspaceId, run]
|
|
573
644
|
);
|
|
574
|
-
const activateVersion =
|
|
645
|
+
const activateVersion = useCallback6(
|
|
575
646
|
async (rigId, versionId) => {
|
|
576
647
|
const result = await run(() => client.activateRigVersion(workspaceId, rigId, versionId));
|
|
577
648
|
if (result) {
|
|
@@ -581,13 +652,13 @@ function useRigs(options = {}) {
|
|
|
581
652
|
},
|
|
582
653
|
[client, workspaceId, run, refresh]
|
|
583
654
|
);
|
|
584
|
-
const listChanges =
|
|
655
|
+
const listChanges = useCallback6(
|
|
585
656
|
async (rigId) => {
|
|
586
657
|
return await run(() => client.listRigChanges(workspaceId, rigId));
|
|
587
658
|
},
|
|
588
659
|
[client, workspaceId, run]
|
|
589
660
|
);
|
|
590
|
-
const proposeChange =
|
|
661
|
+
const proposeChange = useCallback6(
|
|
591
662
|
async (rigId, request) => {
|
|
592
663
|
const result = await run(() => client.proposeRigChange(workspaceId, rigId, request));
|
|
593
664
|
if (result) {
|
|
@@ -616,7 +687,7 @@ function useRigs(options = {}) {
|
|
|
616
687
|
}
|
|
617
688
|
function useRig(rigId, options = {}) {
|
|
618
689
|
const { client, workspaceId } = useOpenGeni(options);
|
|
619
|
-
const load =
|
|
690
|
+
const load = useCallback6(
|
|
620
691
|
async () => await client.getRig(workspaceId, rigId),
|
|
621
692
|
[client, workspaceId, rigId]
|
|
622
693
|
);
|
|
@@ -625,7 +696,7 @@ function useRig(rigId, options = {}) {
|
|
|
625
696
|
enabled: options.enabled
|
|
626
697
|
});
|
|
627
698
|
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
628
|
-
const update =
|
|
699
|
+
const update = useCallback6(
|
|
629
700
|
async (request) => {
|
|
630
701
|
const result = await run(() => client.updateRig(workspaceId, rigId, request));
|
|
631
702
|
if (result) {
|
|
@@ -635,14 +706,14 @@ function useRig(rigId, options = {}) {
|
|
|
635
706
|
},
|
|
636
707
|
[client, workspaceId, rigId, run, refresh]
|
|
637
708
|
);
|
|
638
|
-
const remove =
|
|
709
|
+
const remove = useCallback6(async () => {
|
|
639
710
|
const result = await run(async () => {
|
|
640
711
|
await client.deleteRig(workspaceId, rigId);
|
|
641
712
|
return true;
|
|
642
713
|
});
|
|
643
714
|
return result === true;
|
|
644
715
|
}, [client, workspaceId, rigId, run]);
|
|
645
|
-
const activateVersion =
|
|
716
|
+
const activateVersion = useCallback6(
|
|
646
717
|
async (versionId) => {
|
|
647
718
|
const result = await run(() => client.activateRigVersion(workspaceId, rigId, versionId));
|
|
648
719
|
if (result) {
|
|
@@ -652,7 +723,7 @@ function useRig(rigId, options = {}) {
|
|
|
652
723
|
},
|
|
653
724
|
[client, workspaceId, rigId, run, refresh]
|
|
654
725
|
);
|
|
655
|
-
const proposeChange =
|
|
726
|
+
const proposeChange = useCallback6(
|
|
656
727
|
async (request) => {
|
|
657
728
|
const result = await run(() => client.proposeRigChange(workspaceId, rigId, request));
|
|
658
729
|
if (result) {
|
|
@@ -662,7 +733,7 @@ function useRig(rigId, options = {}) {
|
|
|
662
733
|
},
|
|
663
734
|
[client, workspaceId, rigId, run, refresh]
|
|
664
735
|
);
|
|
665
|
-
const verifyChange =
|
|
736
|
+
const verifyChange = useCallback6(
|
|
666
737
|
async (changeId) => {
|
|
667
738
|
const result = await run(() => client.verifyRigChange(workspaceId, rigId, changeId));
|
|
668
739
|
if (result) {
|
|
@@ -672,7 +743,7 @@ function useRig(rigId, options = {}) {
|
|
|
672
743
|
},
|
|
673
744
|
[client, workspaceId, rigId, run, refresh]
|
|
674
745
|
);
|
|
675
|
-
const promoteChange =
|
|
746
|
+
const promoteChange = useCallback6(
|
|
676
747
|
async (changeId) => {
|
|
677
748
|
const result = await run(() => client.promoteRigChange(workspaceId, rigId, changeId));
|
|
678
749
|
if (result) {
|
|
@@ -682,7 +753,7 @@ function useRig(rigId, options = {}) {
|
|
|
682
753
|
},
|
|
683
754
|
[client, workspaceId, rigId, run, refresh]
|
|
684
755
|
);
|
|
685
|
-
const verify =
|
|
756
|
+
const verify = useCallback6(async () => {
|
|
686
757
|
return await run(() => client.verifyRig(workspaceId, rigId));
|
|
687
758
|
}, [client, workspaceId, rigId, run]);
|
|
688
759
|
return {
|
|
@@ -704,7 +775,7 @@ function useRig(rigId, options = {}) {
|
|
|
704
775
|
}
|
|
705
776
|
function useRigVersions(rigId, options = {}) {
|
|
706
777
|
const { client, workspaceId } = useOpenGeni(options);
|
|
707
|
-
const load =
|
|
778
|
+
const load = useCallback6(
|
|
708
779
|
async () => await client.listRigVersions(workspaceId, rigId),
|
|
709
780
|
[client, workspaceId, rigId]
|
|
710
781
|
);
|
|
@@ -721,7 +792,7 @@ function useRigVersions(rigId, options = {}) {
|
|
|
721
792
|
}
|
|
722
793
|
function useRigChanges(rigId, options = {}) {
|
|
723
794
|
const { client, workspaceId } = useOpenGeni(options);
|
|
724
|
-
const load =
|
|
795
|
+
const load = useCallback6(
|
|
725
796
|
async () => await client.listRigChanges(workspaceId, rigId),
|
|
726
797
|
[client, workspaceId, rigId]
|
|
727
798
|
);
|
|
@@ -738,17 +809,17 @@ function useRigChanges(rigId, options = {}) {
|
|
|
738
809
|
}
|
|
739
810
|
|
|
740
811
|
// src/hooks/use-packs.ts
|
|
741
|
-
import { useCallback as
|
|
812
|
+
import { useCallback as useCallback7 } from "react";
|
|
742
813
|
var EMPTY_INSTALLATIONS = [];
|
|
743
814
|
function usePacks(options = {}) {
|
|
744
815
|
const { client, workspaceId } = useOpenGeni(options);
|
|
745
|
-
const load =
|
|
816
|
+
const load = useCallback7(async () => await client.listPacks(workspaceId), [client, workspaceId]);
|
|
746
817
|
const { data, loading, error, refresh } = usePolledValue(load, {
|
|
747
818
|
pollIntervalMs: options.pollIntervalMs,
|
|
748
819
|
enabled: options.enabled
|
|
749
820
|
});
|
|
750
821
|
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
751
|
-
const register =
|
|
822
|
+
const register = useCallback7(
|
|
752
823
|
async (manifest) => {
|
|
753
824
|
const result = await run(() => client.registerPack(workspaceId, manifest));
|
|
754
825
|
if (result) {
|
|
@@ -758,7 +829,7 @@ function usePacks(options = {}) {
|
|
|
758
829
|
},
|
|
759
830
|
[client, workspaceId, run, refresh]
|
|
760
831
|
);
|
|
761
|
-
const enable =
|
|
832
|
+
const enable = useCallback7(
|
|
762
833
|
async (packId, request = {}) => {
|
|
763
834
|
const result = await run(() => client.enablePack(workspaceId, packId, request));
|
|
764
835
|
if (result) {
|
|
@@ -768,11 +839,11 @@ function usePacks(options = {}) {
|
|
|
768
839
|
},
|
|
769
840
|
[client, workspaceId, run, refresh]
|
|
770
841
|
);
|
|
771
|
-
const previewInstallation =
|
|
842
|
+
const previewInstallation = useCallback7(
|
|
772
843
|
async (packId, request = {}) => await run(() => client.previewPackInstallation(workspaceId, packId, request)),
|
|
773
844
|
[client, workspaceId, run]
|
|
774
845
|
);
|
|
775
|
-
const install =
|
|
846
|
+
const install = useCallback7(
|
|
776
847
|
async (packId, request) => {
|
|
777
848
|
const result = await run(() => client.installPack(workspaceId, packId, request));
|
|
778
849
|
if (result) await refresh();
|
|
@@ -780,11 +851,11 @@ function usePacks(options = {}) {
|
|
|
780
851
|
},
|
|
781
852
|
[client, workspaceId, run, refresh]
|
|
782
853
|
);
|
|
783
|
-
const previewUninstall =
|
|
854
|
+
const previewUninstall = useCallback7(
|
|
784
855
|
async (packId) => await run(() => client.previewPackUninstall(workspaceId, packId)),
|
|
785
856
|
[client, workspaceId, run]
|
|
786
857
|
);
|
|
787
|
-
const uninstall =
|
|
858
|
+
const uninstall = useCallback7(
|
|
788
859
|
async (packId, request) => {
|
|
789
860
|
const result = await run(() => client.uninstallPack(workspaceId, packId, request));
|
|
790
861
|
if (result) await refresh();
|
|
@@ -792,7 +863,7 @@ function usePacks(options = {}) {
|
|
|
792
863
|
},
|
|
793
864
|
[client, workspaceId, run, refresh]
|
|
794
865
|
);
|
|
795
|
-
const remove =
|
|
866
|
+
const remove = useCallback7(
|
|
796
867
|
async (packId) => {
|
|
797
868
|
const result = await run(async () => {
|
|
798
869
|
await client.deletePack(workspaceId, packId);
|
|
@@ -806,7 +877,7 @@ function usePacks(options = {}) {
|
|
|
806
877
|
[client, workspaceId, run, refresh]
|
|
807
878
|
);
|
|
808
879
|
const installations = data?.installations ?? EMPTY_INSTALLATIONS;
|
|
809
|
-
const installationFor =
|
|
880
|
+
const installationFor = useCallback7(
|
|
810
881
|
(packId) => installations.find((installation) => installation.packId === packId) ?? null,
|
|
811
882
|
[installations]
|
|
812
883
|
);
|
|
@@ -831,16 +902,16 @@ function usePacks(options = {}) {
|
|
|
831
902
|
}
|
|
832
903
|
|
|
833
904
|
// src/hooks/use-workspaces.ts
|
|
834
|
-
import { useCallback as
|
|
905
|
+
import { useCallback as useCallback8 } from "react";
|
|
835
906
|
function useWorkspaces(options = {}) {
|
|
836
907
|
const client = useOpenGeniClient(options);
|
|
837
|
-
const load =
|
|
908
|
+
const load = useCallback8(async () => await client.listWorkspaces(), [client]);
|
|
838
909
|
const { data, loading, error, refresh } = usePolledValue(load, {
|
|
839
910
|
pollIntervalMs: options.pollIntervalMs,
|
|
840
911
|
enabled: options.enabled
|
|
841
912
|
});
|
|
842
913
|
const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
|
|
843
|
-
const create =
|
|
914
|
+
const create = useCallback8(
|
|
844
915
|
async (request) => {
|
|
845
916
|
const result = await run(() => client.createWorkspace(request));
|
|
846
917
|
if (result) {
|
|
@@ -850,7 +921,7 @@ function useWorkspaces(options = {}) {
|
|
|
850
921
|
},
|
|
851
922
|
[client, run, refresh]
|
|
852
923
|
);
|
|
853
|
-
const update =
|
|
924
|
+
const update = useCallback8(
|
|
854
925
|
async (workspaceId, request) => {
|
|
855
926
|
const result = await run(() => client.updateWorkspace(workspaceId, request));
|
|
856
927
|
if (result) {
|
|
@@ -874,12 +945,12 @@ function useWorkspaces(options = {}) {
|
|
|
874
945
|
}
|
|
875
946
|
|
|
876
947
|
// src/hooks/use-billing-usage.ts
|
|
877
|
-
import { useCallback as
|
|
948
|
+
import { useCallback as useCallback9 } from "react";
|
|
878
949
|
function useBillingUsage(options = {}) {
|
|
879
950
|
const client = useOpenGeniClient(options);
|
|
880
951
|
const accountId = options.accountId;
|
|
881
952
|
const workspaceId = options.workspaceId;
|
|
882
|
-
const load =
|
|
953
|
+
const load = useCallback9(
|
|
883
954
|
async () => await client.getBillingUsage({
|
|
884
955
|
...accountId !== void 0 ? { accountId } : {},
|
|
885
956
|
...workspaceId !== void 0 ? { workspaceId } : {}
|
|
@@ -900,10 +971,10 @@ function useBillingUsage(options = {}) {
|
|
|
900
971
|
}
|
|
901
972
|
|
|
902
973
|
// src/hooks/use-available-models.ts
|
|
903
|
-
import { useCallback as
|
|
974
|
+
import { useCallback as useCallback10 } from "react";
|
|
904
975
|
function useAvailableModels(options = {}) {
|
|
905
976
|
const client = useOpenGeniClient(options);
|
|
906
|
-
const load =
|
|
977
|
+
const load = useCallback10(async () => await client.getClientConfig(), [client]);
|
|
907
978
|
const state = usePolledValue(load, {
|
|
908
979
|
pollIntervalMs: options.pollIntervalMs,
|
|
909
980
|
enabled: options.enabled
|
|
@@ -918,7 +989,7 @@ function useAvailableModels(options = {}) {
|
|
|
918
989
|
}
|
|
919
990
|
function useWorkspaceModelCatalog(options) {
|
|
920
991
|
const client = useOpenGeniClient(options);
|
|
921
|
-
const load =
|
|
992
|
+
const load = useCallback10(async () => {
|
|
922
993
|
if (!options.workspaceId) {
|
|
923
994
|
return { models: [], defaultModel: null };
|
|
924
995
|
}
|
|
@@ -951,7 +1022,7 @@ import {
|
|
|
951
1022
|
OpenGeniApiError,
|
|
952
1023
|
applyUrlRotation
|
|
953
1024
|
} from "@opengeni/sdk";
|
|
954
|
-
import { useCallback as
|
|
1025
|
+
import { useCallback as useCallback11, useEffect as useEffect3, useRef as useRef2, useState } from "react";
|
|
955
1026
|
|
|
956
1027
|
// src/lib/sandbox-liveness.ts
|
|
957
1028
|
function sandboxAcceptsLiveIo(liveness) {
|
|
@@ -961,7 +1032,7 @@ function sandboxAcceptsLiveIo(liveness) {
|
|
|
961
1032
|
// src/lib/terminal-capability.ts
|
|
962
1033
|
function terminalCanAcquirePty(cell) {
|
|
963
1034
|
if (!cell?.ptyCapable) return false;
|
|
964
|
-
if (cell.transport === "pty-ws") return true;
|
|
1035
|
+
if (cell.transport === "pty-ws" || cell.transport === "relay-pty") return true;
|
|
965
1036
|
return cell.reason === "lease_cold" || cell.reason === "not_provisioned";
|
|
966
1037
|
}
|
|
967
1038
|
|
|
@@ -1001,7 +1072,7 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1001
1072
|
const epochRef = useRef2(0);
|
|
1002
1073
|
const viewerIdRef = useRef2(null);
|
|
1003
1074
|
const previousIdentityRef = useRef2(identityKey);
|
|
1004
|
-
const renegotiate =
|
|
1075
|
+
const renegotiate = useCallback11(() => {
|
|
1005
1076
|
setNonce((n) => n + 1);
|
|
1006
1077
|
}, []);
|
|
1007
1078
|
useEffect3(() => {
|
|
@@ -1164,422 +1235,94 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1164
1235
|
);
|
|
1165
1236
|
}
|
|
1166
1237
|
} else if (cause.status === 429) {
|
|
1167
|
-
setViewerCapReached(true);
|
|
1168
|
-
} else if (cause.status === 403) {
|
|
1169
|
-
setState("error");
|
|
1170
|
-
setError(cause);
|
|
1171
|
-
return;
|
|
1172
|
-
} else {
|
|
1173
|
-
throw cause;
|
|
1174
|
-
}
|
|
1175
|
-
} else {
|
|
1176
|
-
throw cause;
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
const warmUpRequested = wantDesktopAttach || wantTerminalAttach || wantFilesAttach;
|
|
1181
|
-
if (sandboxAcceptsLiveIo(caps.liveness) || localViewerId) {
|
|
1182
|
-
setState("ready");
|
|
1183
|
-
startHeartbeat(caps);
|
|
1184
|
-
} else if (warmUpRequested) {
|
|
1185
|
-
setState("cold");
|
|
1186
|
-
pollUntilWarm();
|
|
1187
|
-
} else {
|
|
1188
|
-
setState("on-demand");
|
|
1189
|
-
}
|
|
1190
|
-
} catch (cause) {
|
|
1191
|
-
if (cancelled) return;
|
|
1192
|
-
if (cause instanceof OpenGeniApiError && cause.status === 403) {
|
|
1193
|
-
setState("error");
|
|
1194
|
-
setError(new Error("not permitted to view this session's sandbox"));
|
|
1195
|
-
return;
|
|
1196
|
-
}
|
|
1197
|
-
setState("error");
|
|
1198
|
-
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
1199
|
-
}
|
|
1200
|
-
})();
|
|
1201
|
-
return () => {
|
|
1202
|
-
cancelled = true;
|
|
1203
|
-
requestAbort.abort();
|
|
1204
|
-
clearTimers();
|
|
1205
|
-
const releaseId = localViewerId ?? viewerIdRef.current;
|
|
1206
|
-
if (releaseId) {
|
|
1207
|
-
void client.detachViewer(workspaceId, sessionId, releaseId).catch(() => {
|
|
1208
|
-
});
|
|
1209
|
-
}
|
|
1210
|
-
};
|
|
1211
|
-
}, [
|
|
1212
|
-
client,
|
|
1213
|
-
workspaceId,
|
|
1214
|
-
sessionId,
|
|
1215
|
-
lifecycleEnabled,
|
|
1216
|
-
attachDesktop,
|
|
1217
|
-
attachTerminal,
|
|
1218
|
-
attachFiles,
|
|
1219
|
-
warmingPollMs,
|
|
1220
|
-
warmingDeadlineMs,
|
|
1221
|
-
nonce,
|
|
1222
|
-
identityKey
|
|
1223
|
-
]);
|
|
1224
|
-
const events = options.events;
|
|
1225
|
-
useEffect3(() => {
|
|
1226
|
-
if (!events || events.length === 0) return;
|
|
1227
|
-
setCapabilities((prev) => {
|
|
1228
|
-
if (!prev || !prev.DesktopStream.url) return prev;
|
|
1229
|
-
let next = prev.DesktopStream;
|
|
1230
|
-
let changed = false;
|
|
1231
|
-
for (const rotation of rotationsFrom(events)) {
|
|
1232
|
-
if (rotation.viewerId && viewerIdRef.current && rotation.viewerId !== viewerIdRef.current) {
|
|
1233
|
-
continue;
|
|
1234
|
-
}
|
|
1235
|
-
const applied = applyUrlRotation(next, rotation, epochRef.current);
|
|
1236
|
-
if (applied) {
|
|
1237
|
-
next = { ...next, url: applied.url, token: applied.token, expiresAt: applied.expiresAt };
|
|
1238
|
-
epochRef.current = Math.max(epochRef.current, rotation.leaseEpoch);
|
|
1239
|
-
changed = true;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
return changed ? { ...prev, DesktopStream: next, leaseEpoch: epochRef.current } : prev;
|
|
1243
|
-
});
|
|
1244
|
-
}, [events]);
|
|
1245
|
-
const identityMatches = enabled && stateIdentity === identityKey;
|
|
1246
|
-
return {
|
|
1247
|
-
capabilities: identityMatches ? capabilities : null,
|
|
1248
|
-
state: identityMatches ? state : "idle",
|
|
1249
|
-
error: identityMatches ? error : null,
|
|
1250
|
-
acknowledgmentRequired: identityMatches ? acknowledgmentRequired : null,
|
|
1251
|
-
viewerCapReached: identityMatches && viewerCapReached,
|
|
1252
|
-
viewerId: identityMatches ? viewerId : null,
|
|
1253
|
-
renegotiate
|
|
1254
|
-
};
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
// src/hooks/use-desktop-stream.ts
|
|
1258
|
-
import {
|
|
1259
|
-
desktopSocketUrl,
|
|
1260
|
-
nextDesktopState
|
|
1261
|
-
} from "@opengeni/sdk";
|
|
1262
|
-
import { useEffect as useEffect5, useRef as useRef4, useState as useState3 } from "react";
|
|
1263
|
-
|
|
1264
|
-
// src/hooks/use-relay-frame-stream.ts
|
|
1265
|
-
import { useEffect as useEffect4, useRef as useRef3, useState as useState2 } from "react";
|
|
1266
|
-
var TAG_OPEN = 1;
|
|
1267
|
-
var TAG_OPENACK = 2;
|
|
1268
|
-
var TAG_FRAME = 3;
|
|
1269
|
-
function datagram(tag, body) {
|
|
1270
|
-
const out = new Uint8Array(body.length + 1);
|
|
1271
|
-
out[0] = tag;
|
|
1272
|
-
out.set(body, 1);
|
|
1273
|
-
return out;
|
|
1274
|
-
}
|
|
1275
|
-
function defaultWebSocketFactory(url) {
|
|
1276
|
-
return new WebSocket(url);
|
|
1277
|
-
}
|
|
1278
|
-
function useRelayFrameStream(options) {
|
|
1279
|
-
const { capability, containerRef, webSocketFactory } = options;
|
|
1280
|
-
const [state, setState] = useState2("idle");
|
|
1281
|
-
const [error, setError] = useState2(null);
|
|
1282
|
-
const [nonce, setNonce] = useState2(0);
|
|
1283
|
-
const stateRef = useRef3("idle");
|
|
1284
|
-
const setBoth = (next) => {
|
|
1285
|
-
stateRef.current = next;
|
|
1286
|
-
setState(next);
|
|
1287
|
-
};
|
|
1288
|
-
const reconnect = () => setNonce((n) => n + 1);
|
|
1289
|
-
const transport = capability?.transport ?? null;
|
|
1290
|
-
const url = capability?.url ?? null;
|
|
1291
|
-
const token = capability?.token ?? null;
|
|
1292
|
-
const factoryRef = useRef3(webSocketFactory);
|
|
1293
|
-
factoryRef.current = webSocketFactory;
|
|
1294
|
-
useEffect4(() => {
|
|
1295
|
-
if (typeof window === "undefined") return;
|
|
1296
|
-
if (transport !== "relay-frames" || !url) {
|
|
1297
|
-
setBoth("idle");
|
|
1298
|
-
return;
|
|
1299
|
-
}
|
|
1300
|
-
const container = containerRef.current;
|
|
1301
|
-
if (!container) {
|
|
1302
|
-
setBoth("idle");
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
let channel;
|
|
1306
|
-
try {
|
|
1307
|
-
const u = new URL(url);
|
|
1308
|
-
channel = {
|
|
1309
|
-
channelId: u.searchParams.get("channel") ?? "",
|
|
1310
|
-
workspaceId: u.searchParams.get("ws") ?? "",
|
|
1311
|
-
agentId: u.searchParams.get("agent") ?? "",
|
|
1312
|
-
kind: STREAM_KIND_DESKTOP,
|
|
1313
|
-
port: Number(u.searchParams.get("port") ?? "0")
|
|
1314
|
-
};
|
|
1315
|
-
} catch (cause) {
|
|
1316
|
-
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
1317
|
-
setBoth("error");
|
|
1318
|
-
return;
|
|
1319
|
-
}
|
|
1320
|
-
setError(null);
|
|
1321
|
-
setBoth("connecting");
|
|
1322
|
-
const canvas = document.createElement("canvas");
|
|
1323
|
-
canvas.setAttribute("data-opengeni-desktop-frames", "");
|
|
1324
|
-
const style = canvas.style;
|
|
1325
|
-
style.position = "absolute";
|
|
1326
|
-
style.top = "0";
|
|
1327
|
-
style.left = "0";
|
|
1328
|
-
style.right = "0";
|
|
1329
|
-
style.bottom = "0";
|
|
1330
|
-
style.margin = "auto";
|
|
1331
|
-
style.maxWidth = "100%";
|
|
1332
|
-
style.maxHeight = "100%";
|
|
1333
|
-
style.width = "auto";
|
|
1334
|
-
style.height = "auto";
|
|
1335
|
-
style.display = "block";
|
|
1336
|
-
style.imageRendering = "auto";
|
|
1337
|
-
container.appendChild(canvas);
|
|
1338
|
-
const ctx = canvas.getContext("2d");
|
|
1339
|
-
let disposed = false;
|
|
1340
|
-
let acked = false;
|
|
1341
|
-
let decoding = false;
|
|
1342
|
-
let pending = null;
|
|
1343
|
-
const drainLatest = async () => {
|
|
1344
|
-
if (decoding) return;
|
|
1345
|
-
decoding = true;
|
|
1346
|
-
try {
|
|
1347
|
-
while (pending) {
|
|
1348
|
-
if (disposed) break;
|
|
1349
|
-
const data = pending;
|
|
1350
|
-
pending = null;
|
|
1351
|
-
let bmp;
|
|
1352
|
-
try {
|
|
1353
|
-
bmp = await createImageBitmap(new Blob([new Uint8Array(data)], { type: "image/png" }));
|
|
1354
|
-
} catch {
|
|
1355
|
-
continue;
|
|
1356
|
-
}
|
|
1357
|
-
if (disposed) {
|
|
1358
|
-
bmp.close();
|
|
1359
|
-
break;
|
|
1360
|
-
}
|
|
1361
|
-
if (canvas.width !== bmp.width || canvas.height !== bmp.height) {
|
|
1362
|
-
canvas.width = bmp.width;
|
|
1363
|
-
canvas.height = bmp.height;
|
|
1364
|
-
}
|
|
1365
|
-
ctx?.drawImage(bmp, 0, 0, canvas.width, canvas.height);
|
|
1366
|
-
bmp.close();
|
|
1367
|
-
if (!disposed && stateRef.current !== "connected") setBoth("connected");
|
|
1368
|
-
}
|
|
1369
|
-
} finally {
|
|
1370
|
-
decoding = false;
|
|
1371
|
-
}
|
|
1372
|
-
};
|
|
1373
|
-
let ws;
|
|
1374
|
-
try {
|
|
1375
|
-
ws = (factoryRef.current ?? defaultWebSocketFactory)(url);
|
|
1376
|
-
} catch (cause) {
|
|
1377
|
-
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
1378
|
-
setBoth("error");
|
|
1379
|
-
canvas.remove();
|
|
1380
|
-
return;
|
|
1381
|
-
}
|
|
1382
|
-
ws.binaryType = "arraybuffer";
|
|
1383
|
-
const onOpen = () => {
|
|
1384
|
-
if (disposed) return;
|
|
1385
|
-
const body = encodeStreamOpen({
|
|
1386
|
-
channel,
|
|
1387
|
-
token: token ?? "",
|
|
1388
|
-
role: STREAM_ROLE_CLIENT,
|
|
1389
|
-
resumeFromSeq: "0"
|
|
1390
|
-
});
|
|
1391
|
-
try {
|
|
1392
|
-
ws.send(datagram(TAG_OPEN, body).buffer);
|
|
1393
|
-
} catch {
|
|
1394
|
-
}
|
|
1395
|
-
};
|
|
1396
|
-
const onMessage = (ev) => {
|
|
1397
|
-
if (disposed) return;
|
|
1398
|
-
const data = ev.data;
|
|
1399
|
-
if (!(data instanceof ArrayBuffer)) return;
|
|
1400
|
-
const buf = new Uint8Array(data);
|
|
1401
|
-
if (buf.length === 0) return;
|
|
1402
|
-
const tag = buf[0];
|
|
1403
|
-
const rest = buf.subarray(1);
|
|
1404
|
-
if (tag === TAG_OPENACK) {
|
|
1405
|
-
let ack;
|
|
1406
|
-
try {
|
|
1407
|
-
ack = decodeStreamOpenAck(rest);
|
|
1408
|
-
} catch {
|
|
1409
|
-
return;
|
|
1410
|
-
}
|
|
1411
|
-
if (!ack.accepted) {
|
|
1412
|
-
setError(
|
|
1413
|
-
new Error(
|
|
1414
|
-
ack.error?.message ? `desktop stream rejected: ${ack.error.message}` : "desktop stream rejected by the relay"
|
|
1415
|
-
)
|
|
1416
|
-
);
|
|
1417
|
-
setBoth("error");
|
|
1418
|
-
try {
|
|
1419
|
-
ws.close();
|
|
1420
|
-
} catch {
|
|
1421
|
-
}
|
|
1422
|
-
return;
|
|
1423
|
-
}
|
|
1424
|
-
acked = true;
|
|
1425
|
-
} else if (tag === TAG_FRAME) {
|
|
1426
|
-
let fr;
|
|
1427
|
-
try {
|
|
1428
|
-
fr = decodeStreamFrame(rest);
|
|
1429
|
-
} catch {
|
|
1430
|
-
return;
|
|
1431
|
-
}
|
|
1432
|
-
if (fr.data && fr.data.length > 0) {
|
|
1433
|
-
pending = fr.data;
|
|
1434
|
-
void drainLatest();
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
};
|
|
1438
|
-
const onError = () => {
|
|
1439
|
-
if (disposed) return;
|
|
1440
|
-
setError((prev) => prev ?? new Error("desktop stream connection error"));
|
|
1441
|
-
setBoth("error");
|
|
1442
|
-
};
|
|
1443
|
-
const onClose = () => {
|
|
1444
|
-
if (disposed) return;
|
|
1445
|
-
setError(
|
|
1446
|
-
(prev) => prev ?? new Error(acked ? "desktop stream closed" : "desktop stream closed before it opened")
|
|
1447
|
-
);
|
|
1448
|
-
setBoth("error");
|
|
1449
|
-
};
|
|
1450
|
-
ws.addEventListener("open", onOpen);
|
|
1451
|
-
ws.addEventListener("message", onMessage);
|
|
1452
|
-
ws.addEventListener("error", onError);
|
|
1453
|
-
ws.addEventListener("close", onClose);
|
|
1454
|
-
return () => {
|
|
1455
|
-
disposed = true;
|
|
1456
|
-
pending = null;
|
|
1457
|
-
ws.removeEventListener("open", onOpen);
|
|
1458
|
-
ws.removeEventListener("message", onMessage);
|
|
1459
|
-
ws.removeEventListener("error", onError);
|
|
1460
|
-
ws.removeEventListener("close", onClose);
|
|
1461
|
-
try {
|
|
1462
|
-
ws.close();
|
|
1463
|
-
} catch {
|
|
1464
|
-
}
|
|
1465
|
-
canvas.remove();
|
|
1466
|
-
};
|
|
1467
|
-
}, [url, token, transport, nonce]);
|
|
1468
|
-
return { state, error, reconnect };
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
// src/hooks/use-desktop-stream.ts
|
|
1472
|
-
async function defaultRfbFactory() {
|
|
1473
|
-
const mod = await import("@novnc/novnc");
|
|
1474
|
-
const RFB = mod.default;
|
|
1475
|
-
return (target, url, opts) => new RFB(target, url, opts);
|
|
1476
|
-
}
|
|
1477
|
-
function useDesktopStream(options) {
|
|
1478
|
-
const { capability, containerRef, interactive, scaleViewport, rfbFactory, webSocketFactory } = options;
|
|
1479
|
-
const frameStream = useRelayFrameStream({
|
|
1480
|
-
capability,
|
|
1481
|
-
containerRef,
|
|
1482
|
-
...webSocketFactory ? { webSocketFactory } : {}
|
|
1483
|
-
});
|
|
1484
|
-
const [state, setState] = useState3("idle");
|
|
1485
|
-
const [error, setError] = useState3(null);
|
|
1486
|
-
const [nonce, setNonce] = useState3(0);
|
|
1487
|
-
const stateRef = useRef4("idle");
|
|
1488
|
-
const setBoth = (next) => {
|
|
1489
|
-
stateRef.current = next;
|
|
1490
|
-
setState(next);
|
|
1491
|
-
};
|
|
1492
|
-
const reconnect = () => setNonce((n) => n + 1);
|
|
1493
|
-
const url = capability?.url ?? null;
|
|
1494
|
-
const token = capability?.token ?? null;
|
|
1495
|
-
const transport = capability?.transport ?? null;
|
|
1496
|
-
const mode = capability?.mode ?? "read-only";
|
|
1497
|
-
const rfbRef = useRef4(null);
|
|
1498
|
-
const interactiveRef = useRef4(interactive);
|
|
1499
|
-
const scaleViewportRef = useRef4(scaleViewport);
|
|
1500
|
-
const modeRef = useRef4(mode);
|
|
1501
|
-
const rfbFactoryRef = useRef4(rfbFactory);
|
|
1502
|
-
interactiveRef.current = interactive;
|
|
1503
|
-
scaleViewportRef.current = scaleViewport;
|
|
1504
|
-
modeRef.current = mode;
|
|
1505
|
-
rfbFactoryRef.current = rfbFactory;
|
|
1506
|
-
const viewOnlyFor = (m, want) => m === "read-only" || !want;
|
|
1507
|
-
useEffect5(() => {
|
|
1508
|
-
if (typeof window === "undefined") return;
|
|
1509
|
-
if (transport !== "vnc-ws" || !url) {
|
|
1510
|
-
setBoth("idle");
|
|
1511
|
-
return;
|
|
1512
|
-
}
|
|
1513
|
-
const container = containerRef.current;
|
|
1514
|
-
if (!container) {
|
|
1515
|
-
setBoth("idle");
|
|
1516
|
-
return;
|
|
1517
|
-
}
|
|
1518
|
-
let rfb = null;
|
|
1519
|
-
let disposed = false;
|
|
1520
|
-
setError(null);
|
|
1521
|
-
setBoth("negotiating");
|
|
1522
|
-
const onConnect = () => {
|
|
1523
|
-
if (!disposed) setBoth(nextDesktopState(stateRef.current, { type: "connected" }));
|
|
1524
|
-
};
|
|
1525
|
-
const onDisconnect = () => {
|
|
1526
|
-
if (!disposed) setBoth(nextDesktopState(stateRef.current, { type: "disconnected" }));
|
|
1527
|
-
};
|
|
1528
|
-
const onSecurityFailure = () => {
|
|
1529
|
-
if (disposed) return;
|
|
1530
|
-
setError(new Error("desktop authentication failed (token expired or revoked)"));
|
|
1531
|
-
setBoth(nextDesktopState(stateRef.current, { type: "fail" }));
|
|
1532
|
-
};
|
|
1533
|
-
void (async () => {
|
|
1534
|
-
try {
|
|
1535
|
-
const factory = rfbFactoryRef.current ?? await defaultRfbFactory();
|
|
1536
|
-
if (disposed) return;
|
|
1537
|
-
const socketUrl = desktopSocketUrl({ url });
|
|
1538
|
-
setBoth(nextDesktopState(stateRef.current, { type: "negotiated" }));
|
|
1539
|
-
rfb = factory(container, socketUrl, {
|
|
1540
|
-
credentials: token ? { password: token } : void 0
|
|
1541
|
-
});
|
|
1542
|
-
rfb.viewOnly = viewOnlyFor(modeRef.current, interactiveRef.current);
|
|
1543
|
-
rfb.clipViewport = false;
|
|
1544
|
-
rfb.scaleViewport = scaleViewportRef.current ?? true;
|
|
1545
|
-
rfb.addEventListener("connect", onConnect);
|
|
1546
|
-
rfb.addEventListener("disconnect", onDisconnect);
|
|
1547
|
-
rfb.addEventListener("securityfailure", onSecurityFailure);
|
|
1548
|
-
rfbRef.current = rfb;
|
|
1238
|
+
setViewerCapReached(true);
|
|
1239
|
+
} else if (cause.status === 403) {
|
|
1240
|
+
setState("error");
|
|
1241
|
+
setError(cause);
|
|
1242
|
+
return;
|
|
1243
|
+
} else {
|
|
1244
|
+
throw cause;
|
|
1245
|
+
}
|
|
1246
|
+
} else {
|
|
1247
|
+
throw cause;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
const warmUpRequested = wantDesktopAttach || wantTerminalAttach || wantFilesAttach;
|
|
1252
|
+
if (sandboxAcceptsLiveIo(caps.liveness) || localViewerId) {
|
|
1253
|
+
setState("ready");
|
|
1254
|
+
startHeartbeat(caps);
|
|
1255
|
+
} else if (warmUpRequested) {
|
|
1256
|
+
setState("cold");
|
|
1257
|
+
pollUntilWarm();
|
|
1258
|
+
} else {
|
|
1259
|
+
setState("on-demand");
|
|
1260
|
+
}
|
|
1549
1261
|
} catch (cause) {
|
|
1550
|
-
if (
|
|
1551
|
-
|
|
1552
|
-
|
|
1262
|
+
if (cancelled) return;
|
|
1263
|
+
if (cause instanceof OpenGeniApiError && cause.status === 403) {
|
|
1264
|
+
setState("error");
|
|
1265
|
+
setError(new Error("not permitted to view this session's sandbox"));
|
|
1266
|
+
return;
|
|
1553
1267
|
}
|
|
1268
|
+
setState("error");
|
|
1269
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
1554
1270
|
}
|
|
1555
1271
|
})();
|
|
1556
1272
|
return () => {
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
rfb.disconnect();
|
|
1565
|
-
} catch {
|
|
1566
|
-
}
|
|
1273
|
+
cancelled = true;
|
|
1274
|
+
requestAbort.abort();
|
|
1275
|
+
clearTimers();
|
|
1276
|
+
const releaseId = localViewerId ?? viewerIdRef.current;
|
|
1277
|
+
if (releaseId) {
|
|
1278
|
+
void client.detachViewer(workspaceId, sessionId, releaseId).catch(() => {
|
|
1279
|
+
});
|
|
1567
1280
|
}
|
|
1568
1281
|
};
|
|
1569
|
-
}, [
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1282
|
+
}, [
|
|
1283
|
+
client,
|
|
1284
|
+
workspaceId,
|
|
1285
|
+
sessionId,
|
|
1286
|
+
lifecycleEnabled,
|
|
1287
|
+
attachDesktop,
|
|
1288
|
+
attachTerminal,
|
|
1289
|
+
attachFiles,
|
|
1290
|
+
warmingPollMs,
|
|
1291
|
+
warmingDeadlineMs,
|
|
1292
|
+
nonce,
|
|
1293
|
+
identityKey
|
|
1294
|
+
]);
|
|
1295
|
+
const events = options.events;
|
|
1296
|
+
useEffect3(() => {
|
|
1297
|
+
if (!events || events.length === 0) return;
|
|
1298
|
+
setCapabilities((prev) => {
|
|
1299
|
+
if (!prev || !prev.DesktopStream.url) return prev;
|
|
1300
|
+
let next = prev.DesktopStream;
|
|
1301
|
+
let changed = false;
|
|
1302
|
+
for (const rotation of rotationsFrom(events)) {
|
|
1303
|
+
if (rotation.viewerId && viewerIdRef.current && rotation.viewerId !== viewerIdRef.current) {
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
1306
|
+
const applied = applyUrlRotation(next, rotation, epochRef.current);
|
|
1307
|
+
if (applied) {
|
|
1308
|
+
next = { ...next, url: applied.url, token: applied.token, expiresAt: applied.expiresAt };
|
|
1309
|
+
epochRef.current = Math.max(epochRef.current, rotation.leaseEpoch);
|
|
1310
|
+
changed = true;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
return changed ? { ...prev, DesktopStream: next, leaseEpoch: epochRef.current } : prev;
|
|
1314
|
+
});
|
|
1315
|
+
}, [events]);
|
|
1316
|
+
const identityMatches = enabled && stateIdentity === identityKey;
|
|
1317
|
+
return {
|
|
1318
|
+
capabilities: identityMatches ? capabilities : null,
|
|
1319
|
+
state: identityMatches ? state : "idle",
|
|
1320
|
+
error: identityMatches ? error : null,
|
|
1321
|
+
acknowledgmentRequired: identityMatches ? acknowledgmentRequired : null,
|
|
1322
|
+
viewerCapReached: identityMatches && viewerCapReached,
|
|
1323
|
+
viewerId: identityMatches ? viewerId : null,
|
|
1324
|
+
renegotiate
|
|
1325
|
+
};
|
|
1583
1326
|
}
|
|
1584
1327
|
|
|
1585
1328
|
// src/hooks/use-terminal-stream.ts
|
|
@@ -1591,11 +1334,51 @@ import {
|
|
|
1591
1334
|
ttydResizeFrame,
|
|
1592
1335
|
TtydServerCommand
|
|
1593
1336
|
} from "@opengeni/sdk";
|
|
1594
|
-
import { useEffect as
|
|
1337
|
+
import { useCallback as useCallback12, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState2 } from "react";
|
|
1595
1338
|
var MAX_PENDING_TERMINAL_INPUT_CODE_UNITS = 64 * 1024;
|
|
1596
1339
|
var TERMINAL_CONNECT_EXPIRY_SKEW_MS = 5e3;
|
|
1340
|
+
var TERMINAL_RECONNECT_INITIAL_MS = 100;
|
|
1341
|
+
var TERMINAL_RECONNECT_MAX_MS = 3e3;
|
|
1342
|
+
var RELAY_TAG_OPEN = 1;
|
|
1343
|
+
var RELAY_TAG_OPEN_ACK = 2;
|
|
1344
|
+
var RELAY_TAG_FRAME = 3;
|
|
1345
|
+
function relayDatagram(tag, body) {
|
|
1346
|
+
const bytes = new Uint8Array(body.length + 1);
|
|
1347
|
+
bytes[0] = tag;
|
|
1348
|
+
bytes.set(body, 1);
|
|
1349
|
+
return bytes.buffer;
|
|
1350
|
+
}
|
|
1351
|
+
function relayChannelFromUrl(url) {
|
|
1352
|
+
const endpoint = new URL(url);
|
|
1353
|
+
const channel = {
|
|
1354
|
+
channelId: endpoint.searchParams.get("channel") ?? "",
|
|
1355
|
+
workspaceId: endpoint.searchParams.get("ws") ?? "",
|
|
1356
|
+
agentId: endpoint.searchParams.get("agent") ?? "",
|
|
1357
|
+
kind: STREAM_KIND_PTY,
|
|
1358
|
+
port: Number(endpoint.searchParams.get("port") ?? "0")
|
|
1359
|
+
};
|
|
1360
|
+
if (!channel.channelId || !channel.workspaceId || !channel.agentId || !Number.isSafeInteger(channel.port) || channel.port <= 0) {
|
|
1361
|
+
throw new Error("terminal relay endpoint is incomplete");
|
|
1362
|
+
}
|
|
1363
|
+
return channel;
|
|
1364
|
+
}
|
|
1365
|
+
function sendRelayInput(socket, channel, sequence, data) {
|
|
1366
|
+
socket.send(
|
|
1367
|
+
relayDatagram(
|
|
1368
|
+
RELAY_TAG_FRAME,
|
|
1369
|
+
encodeStreamFrame({
|
|
1370
|
+
channelId: channel.channelId,
|
|
1371
|
+
seq: sequence.toString(),
|
|
1372
|
+
data: new TextEncoder().encode(data),
|
|
1373
|
+
producedAtMs: String(Date.now())
|
|
1374
|
+
})
|
|
1375
|
+
)
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1597
1378
|
function terminalStreamCredentialUsable(capability, nowMs = Date.now()) {
|
|
1598
|
-
if (capability?.transport !== "pty-ws" || !capability.url)
|
|
1379
|
+
if (capability?.transport !== "pty-ws" && capability?.transport !== "relay-pty" || !capability.url) {
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1599
1382
|
if (!capability.expiresAt) return true;
|
|
1600
1383
|
const expiresAt = Date.parse(capability.expiresAt);
|
|
1601
1384
|
return Number.isFinite(expiresAt) && expiresAt > nowMs + TERMINAL_CONNECT_EXPIRY_SKEW_MS;
|
|
@@ -1616,32 +1399,58 @@ function closeSocket(socket) {
|
|
|
1616
1399
|
}
|
|
1617
1400
|
}
|
|
1618
1401
|
function useTerminalStream(options) {
|
|
1619
|
-
const { capability, onOutput, onTitle, initialCols, initialRows } = options;
|
|
1620
|
-
const [status, setStatus] =
|
|
1621
|
-
const
|
|
1622
|
-
const
|
|
1623
|
-
const
|
|
1624
|
-
const
|
|
1625
|
-
const
|
|
1402
|
+
const { capability, onOutput, onTitle, onReconnectNeeded, initialCols, initialRows } = options;
|
|
1403
|
+
const [status, setStatus] = useState2("closed");
|
|
1404
|
+
const [reconnectGeneration, setReconnectGeneration] = useState2(0);
|
|
1405
|
+
const wsRef = useRef3(null);
|
|
1406
|
+
const pendingInputRef = useRef3("");
|
|
1407
|
+
const socketFailedRef = useRef3(false);
|
|
1408
|
+
const socketAuthenticatedRef = useRef3(false);
|
|
1409
|
+
const relayChannelRef = useRef3(null);
|
|
1410
|
+
const relayIdentityRef = useRef3(null);
|
|
1411
|
+
const relayInputSequenceRef = useRef3(0n);
|
|
1412
|
+
const relayOutputSequenceRef = useRef3(0n);
|
|
1413
|
+
const reconnectAttemptRef = useRef3(0);
|
|
1414
|
+
const credentialIdentityRef = useRef3(null);
|
|
1415
|
+
const refreshRequestedRef = useRef3(false);
|
|
1416
|
+
const intentionalCloseRef = useRef3(/* @__PURE__ */ new WeakSet());
|
|
1417
|
+
const sizeRef = useRef3({
|
|
1626
1418
|
cols: initialCols ?? 80,
|
|
1627
1419
|
rows: initialRows ?? 24
|
|
1628
1420
|
});
|
|
1629
|
-
const onOutputRef =
|
|
1630
|
-
const onTitleRef =
|
|
1421
|
+
const onOutputRef = useRef3(onOutput);
|
|
1422
|
+
const onTitleRef = useRef3(onTitle);
|
|
1423
|
+
const onReconnectNeededRef = useRef3(onReconnectNeeded);
|
|
1631
1424
|
onOutputRef.current = onOutput;
|
|
1632
1425
|
onTitleRef.current = onTitle;
|
|
1426
|
+
onReconnectNeededRef.current = onReconnectNeeded;
|
|
1633
1427
|
const transport = capability?.transport ?? null;
|
|
1634
1428
|
const url = capability?.url ?? null;
|
|
1635
1429
|
const token = capability?.token ?? null;
|
|
1636
1430
|
const expiresAt = capability?.expiresAt ?? null;
|
|
1637
|
-
|
|
1431
|
+
const transportRef = useRef3(transport);
|
|
1432
|
+
transportRef.current = transport;
|
|
1433
|
+
useEffect4(() => {
|
|
1638
1434
|
if (typeof window === "undefined" || typeof WebSocket === "undefined") return;
|
|
1639
|
-
|
|
1435
|
+
const relay = transport === "relay-pty";
|
|
1436
|
+
if (transport !== "pty-ws" && !relay) {
|
|
1640
1437
|
pendingInputRef.current = "";
|
|
1641
1438
|
socketAuthenticatedRef.current = false;
|
|
1439
|
+
relayIdentityRef.current = null;
|
|
1440
|
+
relayInputSequenceRef.current = 0n;
|
|
1441
|
+
relayOutputSequenceRef.current = 0n;
|
|
1442
|
+
reconnectAttemptRef.current = 0;
|
|
1443
|
+
credentialIdentityRef.current = null;
|
|
1444
|
+
refreshRequestedRef.current = false;
|
|
1642
1445
|
setStatus("closed");
|
|
1643
1446
|
return;
|
|
1644
1447
|
}
|
|
1448
|
+
const credentialIdentity = `${transport}\0${url ?? ""}\0${token ?? ""}\0${expiresAt ?? ""}`;
|
|
1449
|
+
if (credentialIdentityRef.current !== credentialIdentity) {
|
|
1450
|
+
credentialIdentityRef.current = credentialIdentity;
|
|
1451
|
+
reconnectAttemptRef.current = 0;
|
|
1452
|
+
refreshRequestedRef.current = false;
|
|
1453
|
+
}
|
|
1645
1454
|
socketFailedRef.current = false;
|
|
1646
1455
|
socketAuthenticatedRef.current = false;
|
|
1647
1456
|
if (!url) {
|
|
@@ -1650,13 +1459,37 @@ function useTerminalStream(options) {
|
|
|
1650
1459
|
}
|
|
1651
1460
|
if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {
|
|
1652
1461
|
setStatus("closed");
|
|
1462
|
+
if (!refreshRequestedRef.current) {
|
|
1463
|
+
refreshRequestedRef.current = true;
|
|
1464
|
+
onReconnectNeededRef.current?.();
|
|
1465
|
+
}
|
|
1653
1466
|
return;
|
|
1654
1467
|
}
|
|
1655
1468
|
let disposed = false;
|
|
1469
|
+
let reconnectTimer = null;
|
|
1656
1470
|
let socket;
|
|
1471
|
+
let relayChannel = null;
|
|
1472
|
+
const relayOutputDecoder = new TextDecoder();
|
|
1657
1473
|
setStatus("connecting");
|
|
1658
1474
|
try {
|
|
1659
|
-
|
|
1475
|
+
if (relay) {
|
|
1476
|
+
relayChannel = relayChannelFromUrl(url);
|
|
1477
|
+
const relayIdentity = [
|
|
1478
|
+
relayChannel.workspaceId,
|
|
1479
|
+
relayChannel.agentId,
|
|
1480
|
+
relayChannel.port,
|
|
1481
|
+
relayChannel.channelId
|
|
1482
|
+
].join("\0");
|
|
1483
|
+
if (relayIdentityRef.current !== relayIdentity) {
|
|
1484
|
+
relayIdentityRef.current = relayIdentity;
|
|
1485
|
+
relayInputSequenceRef.current = 0n;
|
|
1486
|
+
relayOutputSequenceRef.current = 0n;
|
|
1487
|
+
}
|
|
1488
|
+
relayChannelRef.current = relayChannel;
|
|
1489
|
+
socket = new WebSocket(url);
|
|
1490
|
+
} else {
|
|
1491
|
+
socket = new WebSocket(terminalSocketUrl({ url }), TTYD_SUBPROTOCOL);
|
|
1492
|
+
}
|
|
1660
1493
|
} catch {
|
|
1661
1494
|
socketFailedRef.current = true;
|
|
1662
1495
|
setStatus("error");
|
|
@@ -1664,8 +1497,52 @@ function useTerminalStream(options) {
|
|
|
1664
1497
|
}
|
|
1665
1498
|
socket.binaryType = "arraybuffer";
|
|
1666
1499
|
wsRef.current = socket;
|
|
1500
|
+
const requestFreshGrant = () => {
|
|
1501
|
+
if (disposed || refreshRequestedRef.current || intentionalCloseRef.current.has(socket))
|
|
1502
|
+
return;
|
|
1503
|
+
refreshRequestedRef.current = true;
|
|
1504
|
+
onReconnectNeededRef.current?.();
|
|
1505
|
+
};
|
|
1506
|
+
const scheduleTransportReconnect = () => {
|
|
1507
|
+
if (disposed || reconnectTimer !== null || intentionalCloseRef.current.has(socket)) return;
|
|
1508
|
+
if (refreshRequestedRef.current) return;
|
|
1509
|
+
if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {
|
|
1510
|
+
requestFreshGrant();
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
const attempt = reconnectAttemptRef.current++;
|
|
1514
|
+
const delay = Math.min(
|
|
1515
|
+
TERMINAL_RECONNECT_INITIAL_MS * 2 ** Math.min(attempt, 8),
|
|
1516
|
+
TERMINAL_RECONNECT_MAX_MS
|
|
1517
|
+
);
|
|
1518
|
+
setStatus("connecting");
|
|
1519
|
+
reconnectTimer = setTimeout(() => {
|
|
1520
|
+
reconnectTimer = null;
|
|
1521
|
+
if (!disposed) setReconnectGeneration((generation) => generation + 1);
|
|
1522
|
+
}, delay);
|
|
1523
|
+
};
|
|
1667
1524
|
socket.onopen = () => {
|
|
1668
1525
|
if (disposed) return;
|
|
1526
|
+
if (relay && relayChannel) {
|
|
1527
|
+
try {
|
|
1528
|
+
socket.send(
|
|
1529
|
+
relayDatagram(
|
|
1530
|
+
RELAY_TAG_OPEN,
|
|
1531
|
+
encodeStreamOpen({
|
|
1532
|
+
channel: relayChannel,
|
|
1533
|
+
token: token ?? "",
|
|
1534
|
+
role: STREAM_ROLE_CLIENT,
|
|
1535
|
+
resumeFromSeq: relayOutputSequenceRef.current.toString()
|
|
1536
|
+
})
|
|
1537
|
+
)
|
|
1538
|
+
);
|
|
1539
|
+
} catch {
|
|
1540
|
+
socketFailedRef.current = false;
|
|
1541
|
+
setStatus("connecting");
|
|
1542
|
+
closeSocket(socket);
|
|
1543
|
+
}
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1669
1546
|
try {
|
|
1670
1547
|
socket.send(ttydAuthFrame({ columns: sizeRef.current.cols, rows: sizeRef.current.rows }));
|
|
1671
1548
|
socket.send(ttydResizeFrame(sizeRef.current.cols, sizeRef.current.rows));
|
|
@@ -1675,15 +1552,60 @@ function useTerminalStream(options) {
|
|
|
1675
1552
|
}
|
|
1676
1553
|
socketAuthenticatedRef.current = true;
|
|
1677
1554
|
} catch {
|
|
1678
|
-
socketFailedRef.current =
|
|
1679
|
-
setStatus("
|
|
1555
|
+
socketFailedRef.current = false;
|
|
1556
|
+
setStatus("connecting");
|
|
1680
1557
|
closeSocket(socket);
|
|
1681
1558
|
return;
|
|
1682
1559
|
}
|
|
1683
1560
|
setStatus("open");
|
|
1561
|
+
reconnectAttemptRef.current = 0;
|
|
1562
|
+
refreshRequestedRef.current = false;
|
|
1684
1563
|
};
|
|
1685
1564
|
socket.onmessage = (ev) => {
|
|
1686
1565
|
if (disposed) return;
|
|
1566
|
+
if (relay) {
|
|
1567
|
+
if (!(ev.data instanceof ArrayBuffer) || !relayChannel) return;
|
|
1568
|
+
const bytes = new Uint8Array(ev.data);
|
|
1569
|
+
if (bytes.length < 1) return;
|
|
1570
|
+
const tag = bytes[0];
|
|
1571
|
+
const body = bytes.subarray(1);
|
|
1572
|
+
if (tag === RELAY_TAG_OPEN_ACK) {
|
|
1573
|
+
try {
|
|
1574
|
+
const ack = decodeStreamOpenAck(body);
|
|
1575
|
+
if (!ack.accepted) throw new Error(ack.error?.message ?? "terminal relay rejected");
|
|
1576
|
+
reconnectAttemptRef.current = 0;
|
|
1577
|
+
refreshRequestedRef.current = false;
|
|
1578
|
+
socketAuthenticatedRef.current = true;
|
|
1579
|
+
if (pendingInputRef.current.length > 0) {
|
|
1580
|
+
sendRelayInput(
|
|
1581
|
+
socket,
|
|
1582
|
+
relayChannel,
|
|
1583
|
+
relayInputSequenceRef.current++,
|
|
1584
|
+
pendingInputRef.current
|
|
1585
|
+
);
|
|
1586
|
+
pendingInputRef.current = "";
|
|
1587
|
+
}
|
|
1588
|
+
setStatus("open");
|
|
1589
|
+
} catch {
|
|
1590
|
+
socketFailedRef.current = true;
|
|
1591
|
+
setStatus("error");
|
|
1592
|
+
requestFreshGrant();
|
|
1593
|
+
closeSocket(socket);
|
|
1594
|
+
}
|
|
1595
|
+
} else if (tag === RELAY_TAG_FRAME && socketAuthenticatedRef.current) {
|
|
1596
|
+
try {
|
|
1597
|
+
const frame = decodeStreamFrame(body);
|
|
1598
|
+
const sequence = BigInt(frame.seq);
|
|
1599
|
+
if (sequence < relayOutputSequenceRef.current) return;
|
|
1600
|
+
relayOutputSequenceRef.current = sequence + 1n;
|
|
1601
|
+
if (frame.data.length > 0) {
|
|
1602
|
+
onOutputRef.current?.(relayOutputDecoder.decode(frame.data, { stream: true }));
|
|
1603
|
+
}
|
|
1604
|
+
} catch {
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1687
1609
|
const { command, payload } = decodeFrame(ev.data);
|
|
1688
1610
|
switch (command) {
|
|
1689
1611
|
case TtydServerCommand.OUTPUT:
|
|
@@ -1699,76 +1621,90 @@ function useTerminalStream(options) {
|
|
|
1699
1621
|
};
|
|
1700
1622
|
socket.onerror = () => {
|
|
1701
1623
|
if (!disposed) {
|
|
1702
|
-
socketFailedRef.current =
|
|
1703
|
-
setStatus("
|
|
1624
|
+
socketFailedRef.current = false;
|
|
1625
|
+
setStatus("connecting");
|
|
1626
|
+
closeSocket(socket);
|
|
1704
1627
|
}
|
|
1705
1628
|
};
|
|
1706
1629
|
socket.onclose = () => {
|
|
1707
1630
|
if (wsRef.current === socket) wsRef.current = null;
|
|
1708
1631
|
socketAuthenticatedRef.current = false;
|
|
1709
|
-
if (!disposed)
|
|
1632
|
+
if (!disposed) {
|
|
1633
|
+
if (socketFailedRef.current) setStatus("error");
|
|
1634
|
+
else scheduleTransportReconnect();
|
|
1635
|
+
}
|
|
1710
1636
|
};
|
|
1711
1637
|
return () => {
|
|
1712
1638
|
disposed = true;
|
|
1713
1639
|
wsRef.current = null;
|
|
1714
1640
|
socketAuthenticatedRef.current = false;
|
|
1641
|
+
relayChannelRef.current = null;
|
|
1642
|
+
if (reconnectTimer !== null) clearTimeout(reconnectTimer);
|
|
1715
1643
|
socket.onopen = null;
|
|
1716
1644
|
socket.onmessage = null;
|
|
1717
1645
|
socket.onerror = null;
|
|
1718
1646
|
socket.onclose = null;
|
|
1719
1647
|
closeSocket(socket);
|
|
1720
1648
|
};
|
|
1721
|
-
}, [transport, url, token, expiresAt]);
|
|
1722
|
-
|
|
1723
|
-
const
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1649
|
+
}, [transport, url, token, expiresAt, reconnectGeneration]);
|
|
1650
|
+
const write = useCallback12((data) => {
|
|
1651
|
+
const currentTransport = transportRef.current;
|
|
1652
|
+
const ws = wsRef.current;
|
|
1653
|
+
if (ws && ws.readyState === WebSocket.OPEN && socketAuthenticatedRef.current) {
|
|
1654
|
+
try {
|
|
1655
|
+
const relayChannel = relayChannelRef.current;
|
|
1656
|
+
if (currentTransport === "relay-pty" && relayChannel) {
|
|
1657
|
+
sendRelayInput(ws, relayChannel, relayInputSequenceRef.current++, data);
|
|
1658
|
+
} else {
|
|
1727
1659
|
ws.send(ttydInputFrame(data));
|
|
1728
|
-
} catch {
|
|
1729
|
-
socketFailedRef.current = true;
|
|
1730
|
-
setStatus("error");
|
|
1731
|
-
closeSocket(ws);
|
|
1732
|
-
}
|
|
1733
|
-
} else if (transport === "pty-ws" && !socketFailedRef.current) {
|
|
1734
|
-
const nextSize = pendingInputRef.current.length + data.length;
|
|
1735
|
-
if (nextSize > MAX_PENDING_TERMINAL_INPUT_CODE_UNITS) {
|
|
1736
|
-
pendingInputRef.current = "";
|
|
1737
|
-
socketFailedRef.current = true;
|
|
1738
|
-
setStatus("error");
|
|
1739
|
-
closeSocket(ws);
|
|
1740
|
-
return;
|
|
1741
1660
|
}
|
|
1742
|
-
|
|
1661
|
+
} catch {
|
|
1662
|
+
socketFailedRef.current = false;
|
|
1663
|
+
setStatus("connecting");
|
|
1664
|
+
closeSocket(ws);
|
|
1743
1665
|
}
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
if (
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
} catch {
|
|
1753
|
-
}
|
|
1666
|
+
} else if ((currentTransport === "pty-ws" || currentTransport === "relay-pty") && !socketFailedRef.current) {
|
|
1667
|
+
const nextSize = pendingInputRef.current.length + data.length;
|
|
1668
|
+
if (nextSize > MAX_PENDING_TERMINAL_INPUT_CODE_UNITS) {
|
|
1669
|
+
pendingInputRef.current = "";
|
|
1670
|
+
socketFailedRef.current = true;
|
|
1671
|
+
setStatus("error");
|
|
1672
|
+
closeSocket(ws);
|
|
1673
|
+
return;
|
|
1754
1674
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1675
|
+
pendingInputRef.current += data;
|
|
1676
|
+
}
|
|
1677
|
+
}, []);
|
|
1678
|
+
const resize = useCallback12((cols, rows) => {
|
|
1679
|
+
if (cols <= 0 || rows <= 0) return;
|
|
1680
|
+
sizeRef.current = { cols, rows };
|
|
1681
|
+
const ws = wsRef.current;
|
|
1682
|
+
if (ws && ws.readyState === WebSocket.OPEN && socketAuthenticatedRef.current) {
|
|
1683
|
+
try {
|
|
1684
|
+
if (transportRef.current === "pty-ws") ws.send(ttydResizeFrame(cols, rows));
|
|
1685
|
+
} catch {
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}, []);
|
|
1689
|
+
const disconnect = useCallback12(() => {
|
|
1690
|
+
const ws = wsRef.current;
|
|
1691
|
+
wsRef.current = null;
|
|
1692
|
+
pendingInputRef.current = "";
|
|
1693
|
+
socketFailedRef.current = false;
|
|
1694
|
+
socketAuthenticatedRef.current = false;
|
|
1695
|
+
relayChannelRef.current = null;
|
|
1696
|
+
setStatus("closed");
|
|
1697
|
+
if (ws) intentionalCloseRef.current.add(ws);
|
|
1698
|
+
closeSocket(ws);
|
|
1699
|
+
}, []);
|
|
1700
|
+
return useMemo3(() => {
|
|
1765
1701
|
return { connected: status === "open", status, write, resize, disconnect };
|
|
1766
|
-
}, [status,
|
|
1702
|
+
}, [status, write, resize, disconnect]);
|
|
1767
1703
|
}
|
|
1768
1704
|
|
|
1769
1705
|
// src/hooks/use-sandbox-terminal.ts
|
|
1770
1706
|
import { OpenGeniApiError as OpenGeniApiError2 } from "@opengeni/sdk";
|
|
1771
|
-
import { useCallback as
|
|
1707
|
+
import { useCallback as useCallback13, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef4, useState as useState3 } from "react";
|
|
1772
1708
|
function useSandboxTerminal(sessionId, options) {
|
|
1773
1709
|
const { client, workspaceId } = useOpenGeni(options);
|
|
1774
1710
|
const includeAgentFirehose = options.includeAgentFirehose ?? true;
|
|
@@ -1776,20 +1712,20 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1776
1712
|
const ptyFilter = options.ptyId;
|
|
1777
1713
|
const liveness = options.liveness;
|
|
1778
1714
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${interactive}\0${ptyFilter ?? ""}`;
|
|
1779
|
-
const [openedPtyId, setOpenedPtyId] =
|
|
1780
|
-
const [openError, setOpenError] =
|
|
1781
|
-
const [stateIdentity, setStateIdentity] =
|
|
1782
|
-
const [reopenNonce, setReopenNonce] =
|
|
1783
|
-
const currentIdentityRef =
|
|
1715
|
+
const [openedPtyId, setOpenedPtyId] = useState3(null);
|
|
1716
|
+
const [openError, setOpenError] = useState3(null);
|
|
1717
|
+
const [stateIdentity, setStateIdentity] = useState3(identityKey);
|
|
1718
|
+
const [reopenNonce, setReopenNonce] = useState3(0);
|
|
1719
|
+
const currentIdentityRef = useRef4(identityKey);
|
|
1784
1720
|
currentIdentityRef.current = identityKey;
|
|
1785
|
-
|
|
1721
|
+
useEffect5(() => {
|
|
1786
1722
|
setStateIdentity(identityKey);
|
|
1787
1723
|
setOpenedPtyId(null);
|
|
1788
1724
|
setOpenError(null);
|
|
1789
1725
|
}, [identityKey]);
|
|
1790
|
-
const openInFlight =
|
|
1726
|
+
const openInFlight = useRef4(false);
|
|
1791
1727
|
const boxWarm = liveness === void 0 || sandboxAcceptsLiveIo(liveness);
|
|
1792
|
-
|
|
1728
|
+
useEffect5(() => {
|
|
1793
1729
|
if (!interactive || !sessionId || ptyFilter || !boxWarm) {
|
|
1794
1730
|
setOpenError(null);
|
|
1795
1731
|
return;
|
|
@@ -1884,7 +1820,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1884
1820
|
});
|
|
1885
1821
|
};
|
|
1886
1822
|
}, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId, identityKey]);
|
|
1887
|
-
const close =
|
|
1823
|
+
const close = useCallback13(() => {
|
|
1888
1824
|
if (!activePtyId || !sessionId) return;
|
|
1889
1825
|
void client.terminalPtyClose(workspaceId, sessionId, { ptyId: activePtyId }).catch(() => {
|
|
1890
1826
|
});
|
|
@@ -1900,7 +1836,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1900
1836
|
}
|
|
1901
1837
|
|
|
1902
1838
|
// src/hooks/use-sandbox-files.ts
|
|
1903
|
-
import { useCallback as
|
|
1839
|
+
import { useCallback as useCallback14, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef5, useState as useState4 } from "react";
|
|
1904
1840
|
var CapturedFileUnavailableError = class extends Error {
|
|
1905
1841
|
constructor(path, reason) {
|
|
1906
1842
|
super(
|
|
@@ -2138,37 +2074,37 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2138
2074
|
const capture = options.capture ?? null;
|
|
2139
2075
|
const isLive2 = sandboxAcceptsLiveIo(options.liveness);
|
|
2140
2076
|
const acceptsEventReads = options.liveness === void 0 || isLive2;
|
|
2141
|
-
const acceptsEventReadsRef =
|
|
2077
|
+
const acceptsEventReadsRef = useRef5(acceptsEventReads);
|
|
2142
2078
|
acceptsEventReadsRef.current = acceptsEventReads;
|
|
2143
2079
|
const hasLiveIoFence = options.liveness !== void 0;
|
|
2144
2080
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${rootPath}\0${repoPathsKey}`;
|
|
2145
|
-
const [tree, setTree] =
|
|
2146
|
-
const treeRef =
|
|
2147
|
-
const [loading, setLoading] =
|
|
2148
|
-
const [expandingPaths, setExpandingPaths] =
|
|
2149
|
-
const [error, setError] =
|
|
2150
|
-
const [gitSummary, setGitSummary] =
|
|
2151
|
-
const [gitLoading, setGitLoading] =
|
|
2152
|
-
const [contentRevision, setContentRevision] =
|
|
2153
|
-
const [stateIdentity, setStateIdentity] =
|
|
2154
|
-
const [source, setSource] =
|
|
2155
|
-
const sourceRef =
|
|
2156
|
-
const statusRef =
|
|
2157
|
-
const refreshGenerationRef =
|
|
2158
|
-
const refreshAbortRef =
|
|
2159
|
-
const identityAbortRef =
|
|
2160
|
-
const eventReadAbortRef =
|
|
2161
|
-
const identityGenerationRef =
|
|
2162
|
-
const lastSeqRef =
|
|
2163
|
-
const pendingParentsRef =
|
|
2164
|
-
const pendingGitRef =
|
|
2165
|
-
const pendingAgentToolRef =
|
|
2166
|
-
const debounceRef =
|
|
2167
|
-
const lastCommandRefreshAtRef =
|
|
2168
|
-
const ownRevisionsRef =
|
|
2081
|
+
const [tree, setTree] = useState4([]);
|
|
2082
|
+
const treeRef = useRef5([]);
|
|
2083
|
+
const [loading, setLoading] = useState4(false);
|
|
2084
|
+
const [expandingPaths, setExpandingPaths] = useState4(/* @__PURE__ */ new Set());
|
|
2085
|
+
const [error, setError] = useState4(null);
|
|
2086
|
+
const [gitSummary, setGitSummary] = useState4(null);
|
|
2087
|
+
const [gitLoading, setGitLoading] = useState4(false);
|
|
2088
|
+
const [contentRevision, setContentRevision] = useState4(0);
|
|
2089
|
+
const [stateIdentity, setStateIdentity] = useState4(identityKey);
|
|
2090
|
+
const [source, setSource] = useState4(null);
|
|
2091
|
+
const sourceRef = useRef5(null);
|
|
2092
|
+
const statusRef = useRef5(/* @__PURE__ */ new Map());
|
|
2093
|
+
const refreshGenerationRef = useRef5(0);
|
|
2094
|
+
const refreshAbortRef = useRef5(null);
|
|
2095
|
+
const identityAbortRef = useRef5(new AbortController());
|
|
2096
|
+
const eventReadAbortRef = useRef5(new AbortController());
|
|
2097
|
+
const identityGenerationRef = useRef5(0);
|
|
2098
|
+
const lastSeqRef = useRef5(0);
|
|
2099
|
+
const pendingParentsRef = useRef5(/* @__PURE__ */ new Set());
|
|
2100
|
+
const pendingGitRef = useRef5(false);
|
|
2101
|
+
const pendingAgentToolRef = useRef5(false);
|
|
2102
|
+
const debounceRef = useRef5(null);
|
|
2103
|
+
const lastCommandRefreshAtRef = useRef5(0);
|
|
2104
|
+
const ownRevisionsRef = useRef5(/* @__PURE__ */ new Set());
|
|
2169
2105
|
const onMutationError = options.onMutationError;
|
|
2170
2106
|
treeRef.current = tree;
|
|
2171
|
-
const applyStatus =
|
|
2107
|
+
const applyStatus = useCallback14((nodes) => {
|
|
2172
2108
|
const overlay = statusRef.current;
|
|
2173
2109
|
const walk = (list) => {
|
|
2174
2110
|
let changed = false;
|
|
@@ -2191,7 +2127,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2191
2127
|
};
|
|
2192
2128
|
return walk(nodes);
|
|
2193
2129
|
}, []);
|
|
2194
|
-
const refresh =
|
|
2130
|
+
const refresh = useCallback14(async () => {
|
|
2195
2131
|
if (!sessionId) return;
|
|
2196
2132
|
refreshAbortRef.current?.abort();
|
|
2197
2133
|
const refreshAbort = new AbortController();
|
|
@@ -2275,7 +2211,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2275
2211
|
if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;
|
|
2276
2212
|
}
|
|
2277
2213
|
}, [client, workspaceId, sessionId, rootPath, repoPaths, applyStatus]);
|
|
2278
|
-
const seedFromCapture =
|
|
2214
|
+
const seedFromCapture = useCallback14(
|
|
2279
2215
|
(manifest) => {
|
|
2280
2216
|
const overlay = /* @__PURE__ */ new Map();
|
|
2281
2217
|
for (const file of manifest.files) {
|
|
@@ -2303,7 +2239,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2303
2239
|
},
|
|
2304
2240
|
[applyStatus]
|
|
2305
2241
|
);
|
|
2306
|
-
const expand =
|
|
2242
|
+
const expand = useCallback14(
|
|
2307
2243
|
async (path) => {
|
|
2308
2244
|
if (!sessionId) return;
|
|
2309
2245
|
if (source === "capture" && capture) return;
|
|
@@ -2340,7 +2276,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2340
2276
|
},
|
|
2341
2277
|
[client, workspaceId, sessionId, capture, source, applyStatus]
|
|
2342
2278
|
);
|
|
2343
|
-
const readFile =
|
|
2279
|
+
const readFile = useCallback14(
|
|
2344
2280
|
async (path, requestOptions = {}) => {
|
|
2345
2281
|
if (!sessionId) throw new Error("no session");
|
|
2346
2282
|
const identitySignal = identityAbortRef.current.signal;
|
|
@@ -2415,7 +2351,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2415
2351
|
},
|
|
2416
2352
|
[client, workspaceId, sessionId, capture, source]
|
|
2417
2353
|
);
|
|
2418
|
-
const reconcilePath =
|
|
2354
|
+
const reconcilePath = useCallback14(
|
|
2419
2355
|
async (path, requestSignal) => {
|
|
2420
2356
|
if (!sessionId) return;
|
|
2421
2357
|
const identityGeneration = identityGenerationRef.current;
|
|
@@ -2438,7 +2374,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2438
2374
|
},
|
|
2439
2375
|
[client, workspaceId, sessionId, applyStatus]
|
|
2440
2376
|
);
|
|
2441
|
-
const runOptimistic =
|
|
2377
|
+
const runOptimistic = useCallback14(
|
|
2442
2378
|
async (opName, apply, op, reconcileParents) => {
|
|
2443
2379
|
const identityGeneration = identityGenerationRef.current;
|
|
2444
2380
|
const snapshot = treeRef.current;
|
|
@@ -2468,7 +2404,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2468
2404
|
},
|
|
2469
2405
|
[applyStatus, reconcilePath, onMutationError]
|
|
2470
2406
|
);
|
|
2471
|
-
const writeFile =
|
|
2407
|
+
const writeFile = useCallback14(
|
|
2472
2408
|
async (path, content, writeOptions = {}) => {
|
|
2473
2409
|
if (!sessionId) throw new Error("no session");
|
|
2474
2410
|
const identityGeneration = identityGenerationRef.current;
|
|
@@ -2514,7 +2450,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2514
2450
|
},
|
|
2515
2451
|
[client, workspaceId, sessionId, tree, runOptimistic]
|
|
2516
2452
|
);
|
|
2517
|
-
const createFile =
|
|
2453
|
+
const createFile = useCallback14(
|
|
2518
2454
|
async (path) => {
|
|
2519
2455
|
if (!sessionId) throw new Error("no session");
|
|
2520
2456
|
const parent = parentOf(path);
|
|
@@ -2537,7 +2473,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2537
2473
|
},
|
|
2538
2474
|
[client, workspaceId, sessionId, runOptimistic]
|
|
2539
2475
|
);
|
|
2540
|
-
const createDir =
|
|
2476
|
+
const createDir = useCallback14(
|
|
2541
2477
|
async (path) => {
|
|
2542
2478
|
if (!sessionId) throw new Error("no session");
|
|
2543
2479
|
const parent = parentOf(path);
|
|
@@ -2556,7 +2492,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2556
2492
|
},
|
|
2557
2493
|
[client, workspaceId, sessionId, runOptimistic]
|
|
2558
2494
|
);
|
|
2559
|
-
const deleteEntry =
|
|
2495
|
+
const deleteEntry = useCallback14(
|
|
2560
2496
|
async (path, recursive = false) => {
|
|
2561
2497
|
if (!sessionId) throw new Error("no session");
|
|
2562
2498
|
await runOptimistic(
|
|
@@ -2568,7 +2504,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2568
2504
|
},
|
|
2569
2505
|
[client, workspaceId, sessionId, runOptimistic]
|
|
2570
2506
|
);
|
|
2571
|
-
const moveEntry =
|
|
2507
|
+
const moveEntry = useCallback14(
|
|
2572
2508
|
async (path, newPath, opts) => {
|
|
2573
2509
|
if (!sessionId) throw new Error("no session");
|
|
2574
2510
|
const from = parentOf(path);
|
|
@@ -2591,11 +2527,11 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2591
2527
|
},
|
|
2592
2528
|
[client, workspaceId, sessionId, runOptimistic]
|
|
2593
2529
|
);
|
|
2594
|
-
const captureRef =
|
|
2530
|
+
const captureRef = useRef5(capture);
|
|
2595
2531
|
captureRef.current = capture;
|
|
2596
2532
|
const captureRevision = capture?.revision ?? null;
|
|
2597
|
-
const previousIdentityRef =
|
|
2598
|
-
|
|
2533
|
+
const previousIdentityRef = useRef5(identityKey);
|
|
2534
|
+
useEffect6(() => {
|
|
2599
2535
|
refreshAbortRef.current?.abort();
|
|
2600
2536
|
refreshAbortRef.current = null;
|
|
2601
2537
|
refreshGenerationRef.current += 1;
|
|
@@ -2663,7 +2599,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2663
2599
|
refresh,
|
|
2664
2600
|
seedFromCapture
|
|
2665
2601
|
]);
|
|
2666
|
-
const refreshGitOverlay =
|
|
2602
|
+
const refreshGitOverlay = useCallback14(
|
|
2667
2603
|
async (requestSignal) => {
|
|
2668
2604
|
if (!sessionId) return;
|
|
2669
2605
|
const identityGeneration = identityGenerationRef.current;
|
|
@@ -2701,7 +2637,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2701
2637
|
[client, workspaceId, sessionId, repoPaths, applyStatus]
|
|
2702
2638
|
);
|
|
2703
2639
|
const events = options.events;
|
|
2704
|
-
|
|
2640
|
+
useEffect6(() => {
|
|
2705
2641
|
if (!enabled || !events) return;
|
|
2706
2642
|
if (!active || !acceptsEventReads) {
|
|
2707
2643
|
for (const event of events) {
|
|
@@ -2788,7 +2724,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2788
2724
|
})();
|
|
2789
2725
|
}, delay);
|
|
2790
2726
|
}, [enabled, active, acceptsEventReads, events, reconcilePath, refreshGitOverlay]);
|
|
2791
|
-
|
|
2727
|
+
useEffect6(() => {
|
|
2792
2728
|
if (active && acceptsEventReads) return;
|
|
2793
2729
|
if (debounceRef.current) {
|
|
2794
2730
|
clearTimeout(debounceRef.current);
|
|
@@ -2798,7 +2734,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2798
2734
|
pendingGitRef.current = false;
|
|
2799
2735
|
pendingAgentToolRef.current = false;
|
|
2800
2736
|
}, [active, acceptsEventReads]);
|
|
2801
|
-
|
|
2737
|
+
useEffect6(
|
|
2802
2738
|
() => () => {
|
|
2803
2739
|
refreshAbortRef.current?.abort();
|
|
2804
2740
|
identityAbortRef.current.abort();
|
|
@@ -2831,7 +2767,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2831
2767
|
}
|
|
2832
2768
|
|
|
2833
2769
|
// src/hooks/use-sandbox-git.ts
|
|
2834
|
-
import { useCallback as
|
|
2770
|
+
import { useCallback as useCallback15, useEffect as useEffect7, useMemo as useMemo6, useRef as useRef6, useState as useState5 } from "react";
|
|
2835
2771
|
function normalizeRoot2(root) {
|
|
2836
2772
|
const normalized = root.replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
2837
2773
|
return normalized === "." ? "" : normalized;
|
|
@@ -2903,26 +2839,26 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2903
2839
|
const capture = comparison === "staged" ? null : options.capture ?? null;
|
|
2904
2840
|
const isLive2 = sandboxAcceptsLiveIo(options.liveness);
|
|
2905
2841
|
const acceptsEventReads = options.liveness === void 0 || isLive2;
|
|
2906
|
-
const acceptsEventReadsRef =
|
|
2842
|
+
const acceptsEventReadsRef = useRef6(acceptsEventReads);
|
|
2907
2843
|
acceptsEventReadsRef.current = acceptsEventReads;
|
|
2908
2844
|
const hasLiveIoFence = options.liveness !== void 0;
|
|
2909
2845
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${repoPathsKey}\0${workspaceWide}\0${comparison}`;
|
|
2910
|
-
const [diff, setDiff] =
|
|
2911
|
-
const [branch, setBranch] =
|
|
2912
|
-
const [isRepo, setIsRepo] =
|
|
2913
|
-
const [ahead, setAhead] =
|
|
2914
|
-
const [behind, setBehind] =
|
|
2915
|
-
const [repoRoots, setRepoRoots] =
|
|
2916
|
-
const [source, setSource] =
|
|
2917
|
-
const sourceRef =
|
|
2918
|
-
const [loading, setLoading] =
|
|
2919
|
-
const [error, setError] =
|
|
2920
|
-
const [stateIdentity, setStateIdentity] =
|
|
2921
|
-
const refreshGenerationRef =
|
|
2922
|
-
const refreshAbortRef =
|
|
2923
|
-
const lastChangeRef =
|
|
2924
|
-
const commandRefreshTimerRef =
|
|
2925
|
-
const refresh =
|
|
2846
|
+
const [diff, setDiff] = useState5([]);
|
|
2847
|
+
const [branch, setBranch] = useState5(null);
|
|
2848
|
+
const [isRepo, setIsRepo] = useState5(false);
|
|
2849
|
+
const [ahead, setAhead] = useState5(0);
|
|
2850
|
+
const [behind, setBehind] = useState5(0);
|
|
2851
|
+
const [repoRoots, setRepoRoots] = useState5([]);
|
|
2852
|
+
const [source, setSource] = useState5(null);
|
|
2853
|
+
const sourceRef = useRef6(null);
|
|
2854
|
+
const [loading, setLoading] = useState5(false);
|
|
2855
|
+
const [error, setError] = useState5(null);
|
|
2856
|
+
const [stateIdentity, setStateIdentity] = useState5(identityKey);
|
|
2857
|
+
const refreshGenerationRef = useRef6(0);
|
|
2858
|
+
const refreshAbortRef = useRef6(null);
|
|
2859
|
+
const lastChangeRef = useRef6(0);
|
|
2860
|
+
const commandRefreshTimerRef = useRef6(null);
|
|
2861
|
+
const refresh = useCallback15(async () => {
|
|
2926
2862
|
if (!sessionId) return;
|
|
2927
2863
|
refreshAbortRef.current?.abort();
|
|
2928
2864
|
const refreshAbort = new AbortController();
|
|
@@ -3035,7 +2971,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
3035
2971
|
workspaceWide,
|
|
3036
2972
|
comparison
|
|
3037
2973
|
]);
|
|
3038
|
-
const seedFromCapture =
|
|
2974
|
+
const seedFromCapture = useCallback15(
|
|
3039
2975
|
(manifest) => {
|
|
3040
2976
|
const repositories = workspaceWide ? manifest.repos : [repoForPath(manifest, repoPath)].filter(Boolean);
|
|
3041
2977
|
if (comparison === "branch" && repositories.some((repo) => repo.branchDiff === void 0)) {
|
|
@@ -3072,11 +3008,11 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
3072
3008
|
},
|
|
3073
3009
|
[comparison, repoPath, workspaceWide]
|
|
3074
3010
|
);
|
|
3075
|
-
const captureRef =
|
|
3011
|
+
const captureRef = useRef6(capture);
|
|
3076
3012
|
captureRef.current = capture;
|
|
3077
3013
|
const captureRevision = capture?.revision ?? null;
|
|
3078
|
-
const previousIdentityRef =
|
|
3079
|
-
|
|
3014
|
+
const previousIdentityRef = useRef6(identityKey);
|
|
3015
|
+
useEffect7(() => {
|
|
3080
3016
|
refreshAbortRef.current?.abort();
|
|
3081
3017
|
refreshAbortRef.current = null;
|
|
3082
3018
|
refreshGenerationRef.current += 1;
|
|
@@ -3126,7 +3062,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
3126
3062
|
seedFromCapture
|
|
3127
3063
|
]);
|
|
3128
3064
|
const events = options.events;
|
|
3129
|
-
|
|
3065
|
+
useEffect7(() => {
|
|
3130
3066
|
if (!enabled || !events) {
|
|
3131
3067
|
if (commandRefreshTimerRef.current) {
|
|
3132
3068
|
clearTimeout(commandRefreshTimerRef.current);
|
|
@@ -3171,7 +3107,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
3171
3107
|
}
|
|
3172
3108
|
}
|
|
3173
3109
|
}, [enabled, active, acceptsEventReads, events, refresh]);
|
|
3174
|
-
|
|
3110
|
+
useEffect7(
|
|
3175
3111
|
() => () => {
|
|
3176
3112
|
if (commandRefreshTimerRef.current) clearTimeout(commandRefreshTimerRef.current);
|
|
3177
3113
|
},
|
|
@@ -3196,7 +3132,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
3196
3132
|
}
|
|
3197
3133
|
|
|
3198
3134
|
// src/hooks/use-workspace-capture.ts
|
|
3199
|
-
import { useCallback as
|
|
3135
|
+
import { useCallback as useCallback16, useEffect as useEffect8, useRef as useRef7, useState as useState6 } from "react";
|
|
3200
3136
|
var REVISION_CAPTURED = "workspace.revision.captured";
|
|
3201
3137
|
var REVISION_DEGRADED = "workspace.revision.degraded";
|
|
3202
3138
|
var MANIFEST_FETCH_TIMEOUT_MS = 15e3;
|
|
@@ -3235,18 +3171,18 @@ function useWorkspaceCapture(sessionId, options = {}) {
|
|
|
3235
3171
|
const { client, workspaceId } = useOpenGeni(options);
|
|
3236
3172
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
3237
3173
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}`;
|
|
3238
|
-
const [capture, setCapture] =
|
|
3239
|
-
const [available, setAvailable] =
|
|
3240
|
-
const [degradedReason, setDegradedReason] =
|
|
3241
|
-
const [fileCount, setFileCount] =
|
|
3242
|
-
const [loading, setLoading] =
|
|
3243
|
-
const [error, setError] =
|
|
3244
|
-
const [announcedRevision, setAnnouncedRevision] =
|
|
3245
|
-
const [stateIdentity, setStateIdentity] =
|
|
3246
|
-
const generationRef =
|
|
3247
|
-
const requestAbortRef =
|
|
3248
|
-
const lastSeqRef =
|
|
3249
|
-
const refresh =
|
|
3174
|
+
const [capture, setCapture] = useState6(null);
|
|
3175
|
+
const [available, setAvailable] = useState6(false);
|
|
3176
|
+
const [degradedReason, setDegradedReason] = useState6(null);
|
|
3177
|
+
const [fileCount, setFileCount] = useState6(null);
|
|
3178
|
+
const [loading, setLoading] = useState6(false);
|
|
3179
|
+
const [error, setError] = useState6(null);
|
|
3180
|
+
const [announcedRevision, setAnnouncedRevision] = useState6(null);
|
|
3181
|
+
const [stateIdentity, setStateIdentity] = useState6(identityKey);
|
|
3182
|
+
const generationRef = useRef7(0);
|
|
3183
|
+
const requestAbortRef = useRef7(null);
|
|
3184
|
+
const lastSeqRef = useRef7(0);
|
|
3185
|
+
const refresh = useCallback16(async () => {
|
|
3250
3186
|
if (!sessionId) return;
|
|
3251
3187
|
requestAbortRef.current?.abort();
|
|
3252
3188
|
const requestAbort = new AbortController();
|
|
@@ -3319,7 +3255,7 @@ function useWorkspaceCapture(sessionId, options = {}) {
|
|
|
3319
3255
|
if (requestAbortRef.current === requestAbort) requestAbortRef.current = null;
|
|
3320
3256
|
}
|
|
3321
3257
|
}, [client, workspaceId, sessionId, identityKey]);
|
|
3322
|
-
|
|
3258
|
+
useEffect8(() => {
|
|
3323
3259
|
requestAbortRef.current?.abort();
|
|
3324
3260
|
requestAbortRef.current = null;
|
|
3325
3261
|
generationRef.current += 1;
|
|
@@ -3342,7 +3278,7 @@ function useWorkspaceCapture(sessionId, options = {}) {
|
|
|
3342
3278
|
};
|
|
3343
3279
|
}, [enabled, refresh]);
|
|
3344
3280
|
const events = options.events;
|
|
3345
|
-
|
|
3281
|
+
useEffect8(() => {
|
|
3346
3282
|
if (!enabled || !events) return;
|
|
3347
3283
|
let newest = null;
|
|
3348
3284
|
for (const event of events) {
|
|
@@ -3368,7 +3304,7 @@ function useWorkspaceCapture(sessionId, options = {}) {
|
|
|
3368
3304
|
const visibleCapture = identityMatches ? capture : null;
|
|
3369
3305
|
const visibleAnnouncedRevision = identityMatches ? announcedRevision : null;
|
|
3370
3306
|
const loadedRevision = visibleCapture?.revision ?? null;
|
|
3371
|
-
|
|
3307
|
+
useEffect8(() => {
|
|
3372
3308
|
if (!enabled) return;
|
|
3373
3309
|
if (visibleAnnouncedRevision === null) return;
|
|
3374
3310
|
if (loadedRevision !== null && visibleAnnouncedRevision <= loadedRevision) return;
|
|
@@ -3391,7 +3327,7 @@ function useWorkspaceCapture(sessionId, options = {}) {
|
|
|
3391
3327
|
}
|
|
3392
3328
|
|
|
3393
3329
|
// src/hooks/use-workspace-edit.ts
|
|
3394
|
-
import { useCallback as
|
|
3330
|
+
import { useCallback as useCallback17, useEffect as useEffect9, useRef as useRef8, useState as useState7 } from "react";
|
|
3395
3331
|
function isLive(liveness) {
|
|
3396
3332
|
return sandboxAcceptsLiveIo(liveness);
|
|
3397
3333
|
}
|
|
@@ -3402,20 +3338,20 @@ function useWorkspaceEdit(sessionId, options = {}) {
|
|
|
3402
3338
|
const live = isLive(options.liveness);
|
|
3403
3339
|
const offline = options.offline === true;
|
|
3404
3340
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${path ?? ""}`;
|
|
3405
|
-
const [buffer, setBuffer] =
|
|
3406
|
-
const [wantsWarm, setWantsWarm] =
|
|
3407
|
-
const [flush, setFlush] =
|
|
3408
|
-
const [conflict, setConflict] =
|
|
3409
|
-
const [error, setError] =
|
|
3410
|
-
const [stateIdentity, setStateIdentity] =
|
|
3341
|
+
const [buffer, setBuffer] = useState7(null);
|
|
3342
|
+
const [wantsWarm, setWantsWarm] = useState7(false);
|
|
3343
|
+
const [flush, setFlush] = useState7("idle");
|
|
3344
|
+
const [conflict, setConflict] = useState7(null);
|
|
3345
|
+
const [error, setError] = useState7(null);
|
|
3346
|
+
const [stateIdentity, setStateIdentity] = useState7(identityKey);
|
|
3411
3347
|
const onWarmRequested = options.onWarmRequested;
|
|
3412
|
-
const bufferRef =
|
|
3348
|
+
const bufferRef = useRef8(null);
|
|
3413
3349
|
bufferRef.current = buffer;
|
|
3414
|
-
const flushingRef =
|
|
3415
|
-
const identityGenerationRef =
|
|
3416
|
-
const flushAttemptRef =
|
|
3417
|
-
const readAbortRef =
|
|
3418
|
-
|
|
3350
|
+
const flushingRef = useRef8(false);
|
|
3351
|
+
const identityGenerationRef = useRef8(0);
|
|
3352
|
+
const flushAttemptRef = useRef8(0);
|
|
3353
|
+
const readAbortRef = useRef8(null);
|
|
3354
|
+
useEffect9(() => {
|
|
3419
3355
|
identityGenerationRef.current += 1;
|
|
3420
3356
|
flushAttemptRef.current += 1;
|
|
3421
3357
|
readAbortRef.current?.abort();
|
|
@@ -3434,7 +3370,7 @@ function useWorkspaceEdit(sessionId, options = {}) {
|
|
|
3434
3370
|
readAbortRef.current = null;
|
|
3435
3371
|
};
|
|
3436
3372
|
}, [identityKey]);
|
|
3437
|
-
const edit =
|
|
3373
|
+
const edit = useCallback17(
|
|
3438
3374
|
(content) => {
|
|
3439
3375
|
if (stateIdentity !== identityKey) return;
|
|
3440
3376
|
if (offline) return;
|
|
@@ -3450,7 +3386,7 @@ function useWorkspaceEdit(sessionId, options = {}) {
|
|
|
3450
3386
|
},
|
|
3451
3387
|
[offline, live, onWarmRequested, stateIdentity, identityKey]
|
|
3452
3388
|
);
|
|
3453
|
-
const doFlush =
|
|
3389
|
+
const doFlush = useCallback17(
|
|
3454
3390
|
async (force) => {
|
|
3455
3391
|
if (stateIdentity !== identityKey) return;
|
|
3456
3392
|
if (!sessionId || !path) return;
|
|
@@ -3500,17 +3436,17 @@ function useWorkspaceEdit(sessionId, options = {}) {
|
|
|
3500
3436
|
},
|
|
3501
3437
|
[client, workspaceId, sessionId, path, baseContent, stateIdentity, identityKey]
|
|
3502
3438
|
);
|
|
3503
|
-
|
|
3439
|
+
useEffect9(() => {
|
|
3504
3440
|
if (offline) return;
|
|
3505
3441
|
if (!live) return;
|
|
3506
3442
|
if (buffer === null) return;
|
|
3507
3443
|
if (flush === "flushed" || flush === "conflict" || flush === "flushing") return;
|
|
3508
3444
|
void doFlush(false);
|
|
3509
3445
|
}, [offline, live, buffer, flush, doFlush]);
|
|
3510
|
-
const overwrite =
|
|
3446
|
+
const overwrite = useCallback17(async () => {
|
|
3511
3447
|
await doFlush(true);
|
|
3512
3448
|
}, [doFlush]);
|
|
3513
|
-
const discard =
|
|
3449
|
+
const discard = useCallback17(() => {
|
|
3514
3450
|
setBuffer(null);
|
|
3515
3451
|
setWantsWarm(false);
|
|
3516
3452
|
setFlush("idle");
|
|
@@ -3567,7 +3503,8 @@ function deriveMachineChip(input) {
|
|
|
3567
3503
|
const now = input.now ?? Date.now();
|
|
3568
3504
|
const asOf = input.capturedAt ?? null;
|
|
3569
3505
|
const offlineLabel = asOf ? `Offline \u2014 as of ${formatAsOf(asOf, now)}` : "Offline";
|
|
3570
|
-
|
|
3506
|
+
const selfhostedOnline = input.activeIsSelfhosted === true && input.activeMachineState != null && connectionStatusForState(input.activeMachineState) === "online";
|
|
3507
|
+
if (sandboxAcceptsLiveIo(input.liveness) || selfhostedOnline) {
|
|
3571
3508
|
return { state: "live", label: "Live", asOf: null };
|
|
3572
3509
|
}
|
|
3573
3510
|
const selfhostedOffline = input.activeIsSelfhosted === true && input.activeMachineState === "offline";
|
|
@@ -3613,7 +3550,7 @@ function useMachineChip(input) {
|
|
|
3613
3550
|
|
|
3614
3551
|
// src/components/approval-surface.tsx
|
|
3615
3552
|
import { CheckIcon, ShieldCheckIcon, XIcon } from "lucide-react";
|
|
3616
|
-
import { useEffect as
|
|
3553
|
+
import { useEffect as useEffect10, useId, useRef as useRef9, useState as useState8 } from "react";
|
|
3617
3554
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3618
3555
|
var defaultApprovalSurfaceMessages = {
|
|
3619
3556
|
title: "Approval required",
|
|
@@ -3653,10 +3590,10 @@ function ApprovalSurface({
|
|
|
3653
3590
|
}) {
|
|
3654
3591
|
const titleId = useId();
|
|
3655
3592
|
const messages = { ...defaultApprovalSurfaceMessages, ...overrides };
|
|
3656
|
-
const [pending, setPending] =
|
|
3657
|
-
const pendingRef =
|
|
3658
|
-
const [decisionError, setDecisionError] =
|
|
3659
|
-
|
|
3593
|
+
const [pending, setPending] = useState8(null);
|
|
3594
|
+
const pendingRef = useRef9(null);
|
|
3595
|
+
const [decisionError, setDecisionError] = useState8(null);
|
|
3596
|
+
useEffect10(() => {
|
|
3660
3597
|
if (pending && !approvals.some((approval) => approvalOwnershipKey(approval) === pending.approvalKey)) {
|
|
3661
3598
|
if (pendingRef.current?.token === pending.token) {
|
|
3662
3599
|
pendingRef.current = null;
|
|
@@ -3956,7 +3893,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
|
|
|
3956
3893
|
}
|
|
3957
3894
|
|
|
3958
3895
|
// src/components/sandbox-terminal.tsx
|
|
3959
|
-
import { useEffect as
|
|
3896
|
+
import { useEffect as useEffect11, useLayoutEffect, useRef as useRef10, useState as useState9 } from "react";
|
|
3960
3897
|
|
|
3961
3898
|
// src/lib/xterm-theme.ts
|
|
3962
3899
|
var DARK_ANSI = {
|
|
@@ -4148,19 +4085,20 @@ function SandboxTerminal({
|
|
|
4148
4085
|
showHeader,
|
|
4149
4086
|
shell,
|
|
4150
4087
|
onActivate,
|
|
4088
|
+
onReconnectNeeded,
|
|
4151
4089
|
className
|
|
4152
4090
|
}) {
|
|
4153
|
-
const containerRef =
|
|
4154
|
-
const termRef =
|
|
4155
|
-
const fitRef =
|
|
4156
|
-
const rendererRef =
|
|
4157
|
-
const writtenRef =
|
|
4158
|
-
const wroteFirehoseRef =
|
|
4159
|
-
const bootActiveRef =
|
|
4160
|
-
const [ready, setReady] =
|
|
4161
|
-
const [inputReady, setInputReady] =
|
|
4162
|
-
const [activated, setActivated] =
|
|
4163
|
-
const ptyDescriptor = terminalCapability?.transport === "pty-ws";
|
|
4091
|
+
const containerRef = useRef10(null);
|
|
4092
|
+
const termRef = useRef10(null);
|
|
4093
|
+
const fitRef = useRef10(null);
|
|
4094
|
+
const rendererRef = useRef10(null);
|
|
4095
|
+
const writtenRef = useRef10(/* @__PURE__ */ new Set());
|
|
4096
|
+
const wroteFirehoseRef = useRef10(false);
|
|
4097
|
+
const bootActiveRef = useRef10(false);
|
|
4098
|
+
const [ready, setReady] = useState9(false);
|
|
4099
|
+
const [inputReady, setInputReady] = useState9(false);
|
|
4100
|
+
const [activated, setActivated] = useState9(false);
|
|
4101
|
+
const ptyDescriptor = terminalCapability?.transport === "pty-ws" || terminalCapability?.transport === "relay-pty";
|
|
4164
4102
|
const ptyAttachable = terminalCanAcquirePty(terminalCapability);
|
|
4165
4103
|
const {
|
|
4166
4104
|
status: ptyStatus,
|
|
@@ -4172,14 +4110,15 @@ function SandboxTerminal({
|
|
|
4172
4110
|
// owner from the first websocket frame and removes an otherwise unbounded
|
|
4173
4111
|
// pre-mount output queue during large command bursts.
|
|
4174
4112
|
capability: ptyAttachable && ready ? {
|
|
4175
|
-
transport:
|
|
4113
|
+
transport: terminalCapability.transport,
|
|
4176
4114
|
url: ptyDescriptor ? terminalCapability.url : null,
|
|
4177
4115
|
token: ptyDescriptor ? terminalCapability.token : null,
|
|
4178
4116
|
expiresAt: ptyDescriptor ? terminalCapability.expiresAt : null
|
|
4179
4117
|
} : null,
|
|
4180
4118
|
onOutput: (data) => {
|
|
4181
4119
|
termRef.current?.write(data);
|
|
4182
|
-
}
|
|
4120
|
+
},
|
|
4121
|
+
onReconnectNeeded
|
|
4183
4122
|
});
|
|
4184
4123
|
const ptyMode = ptyDescriptor;
|
|
4185
4124
|
const ptyCapturesInput = ptyAttachable && ptyStatus !== "error";
|
|
@@ -4202,10 +4141,16 @@ function SandboxTerminal({
|
|
|
4202
4141
|
booting
|
|
4203
4142
|
});
|
|
4204
4143
|
function handleActivate() {
|
|
4144
|
+
const term = termRef.current;
|
|
4145
|
+
if (term && !readOnly && (ptyAttachable || result.write !== null)) {
|
|
4146
|
+
term.options.disableStdin = false;
|
|
4147
|
+
term.options.cursorBlink = true;
|
|
4148
|
+
}
|
|
4149
|
+
term?.focus();
|
|
4205
4150
|
if (!activated) setActivated(true);
|
|
4206
4151
|
onActivate?.();
|
|
4207
4152
|
}
|
|
4208
|
-
|
|
4153
|
+
useEffect11(() => {
|
|
4209
4154
|
if (typeof window === "undefined") return;
|
|
4210
4155
|
const el = containerRef.current;
|
|
4211
4156
|
if (!el) return;
|
|
@@ -4313,19 +4258,19 @@ function SandboxTerminal({
|
|
|
4313
4258
|
setReady(false);
|
|
4314
4259
|
};
|
|
4315
4260
|
}, []);
|
|
4316
|
-
|
|
4261
|
+
useLayoutEffect(() => {
|
|
4317
4262
|
const term = termRef.current;
|
|
4318
4263
|
if (!ready || !term) return;
|
|
4319
4264
|
term.options.disableStdin = !interactive;
|
|
4320
4265
|
term.options.cursorBlink = interactive;
|
|
4321
4266
|
}, [ready, interactive]);
|
|
4322
|
-
|
|
4267
|
+
useEffect11(() => {
|
|
4323
4268
|
const term = termRef.current;
|
|
4324
4269
|
if (!ready || !term) return;
|
|
4325
4270
|
const next = theme ?? xtermThemeFromTokens(containerRef.current);
|
|
4326
4271
|
if (next) term.options.theme = next;
|
|
4327
4272
|
}, [ready, theme]);
|
|
4328
|
-
|
|
4273
|
+
useEffect11(() => {
|
|
4329
4274
|
const term = termRef.current;
|
|
4330
4275
|
if (!ready || !term) return;
|
|
4331
4276
|
if (!booting) {
|
|
@@ -4346,7 +4291,7 @@ function SandboxTerminal({
|
|
|
4346
4291
|
const id = setInterval(paint, 1e3);
|
|
4347
4292
|
return () => clearInterval(id);
|
|
4348
4293
|
}, [ready, booting]);
|
|
4349
|
-
|
|
4294
|
+
useEffect11(() => {
|
|
4350
4295
|
const term = termRef.current;
|
|
4351
4296
|
if (!ready || !term || ptyMode) return;
|
|
4352
4297
|
for (const chunk of result.chunks) {
|
|
@@ -4356,7 +4301,7 @@ function SandboxTerminal({
|
|
|
4356
4301
|
term.write(chunk.text);
|
|
4357
4302
|
}
|
|
4358
4303
|
}, [ready, result.chunks, ptyMode]);
|
|
4359
|
-
|
|
4304
|
+
useLayoutEffect(() => {
|
|
4360
4305
|
const term = termRef.current;
|
|
4361
4306
|
if (!ready || !term || !interactive) {
|
|
4362
4307
|
setInputReady(false);
|
|
@@ -4371,14 +4316,14 @@ function SandboxTerminal({
|
|
|
4371
4316
|
setInputReady(sub !== null);
|
|
4372
4317
|
return () => sub?.dispose();
|
|
4373
4318
|
}, [ready, interactive, ptyAttachable, ptyWrite, result.write]);
|
|
4374
|
-
|
|
4319
|
+
useEffect11(() => {
|
|
4375
4320
|
const term = termRef.current;
|
|
4376
4321
|
if (!ready || !term || !ptyMode) return;
|
|
4377
4322
|
resizePty(term.cols, term.rows);
|
|
4378
4323
|
const sub = term.onResize(({ cols, rows }) => resizePty(cols, rows));
|
|
4379
4324
|
return () => sub.dispose();
|
|
4380
4325
|
}, [ready, ptyMode, ptyConnected, resizePty]);
|
|
4381
|
-
|
|
4326
|
+
useEffect11(() => {
|
|
4382
4327
|
if (typeof window === "undefined") return;
|
|
4383
4328
|
const refit = () => {
|
|
4384
4329
|
try {
|
|
@@ -4523,24 +4468,24 @@ import {
|
|
|
4523
4468
|
Trash2Icon
|
|
4524
4469
|
} from "lucide-react";
|
|
4525
4470
|
import {
|
|
4526
|
-
useCallback as
|
|
4527
|
-
useEffect as
|
|
4471
|
+
useCallback as useCallback18,
|
|
4472
|
+
useEffect as useEffect13,
|
|
4528
4473
|
useId as useId2,
|
|
4529
|
-
useLayoutEffect,
|
|
4474
|
+
useLayoutEffect as useLayoutEffect2,
|
|
4530
4475
|
useMemo as useMemo9,
|
|
4531
|
-
useRef as
|
|
4532
|
-
useState as
|
|
4476
|
+
useRef as useRef11,
|
|
4477
|
+
useState as useState10
|
|
4533
4478
|
} from "react";
|
|
4534
4479
|
import { AlertDialog } from "radix-ui";
|
|
4535
4480
|
import { VList } from "virtua";
|
|
4536
4481
|
|
|
4537
4482
|
// src/lib/use-unicode-fonts.ts
|
|
4538
|
-
import { useEffect as
|
|
4483
|
+
import { useEffect as useEffect12, useMemo as useMemo8 } from "react";
|
|
4539
4484
|
var japaneseScript = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/u;
|
|
4540
4485
|
var arabicScript = /[\u0600-\u06ff\u0750-\u077f\u0870-\u08ff\ufb50-\ufdff\ufe70-\ufefc]/u;
|
|
4541
4486
|
function useUnicodeFallbackFonts(values) {
|
|
4542
4487
|
const content = useMemo8(() => collectUnicodeContent(values), [values]);
|
|
4543
|
-
|
|
4488
|
+
useEffect12(() => {
|
|
4544
4489
|
if (content.japanese) {
|
|
4545
4490
|
void import("./noto-sans-jp-loader.generated-HFGLYBR3.js").then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese)).catch(() => void 0);
|
|
4546
4491
|
}
|
|
@@ -4570,7 +4515,7 @@ var STATUS_TINT = {
|
|
|
4570
4515
|
renamed: "text-og-accent",
|
|
4571
4516
|
untracked: "text-og-fg-subtle"
|
|
4572
4517
|
};
|
|
4573
|
-
var useBrowserLayoutEffect = typeof window === "undefined" ?
|
|
4518
|
+
var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect13 : useLayoutEffect2;
|
|
4574
4519
|
function parentOf2(path) {
|
|
4575
4520
|
const i = path.lastIndexOf("/");
|
|
4576
4521
|
return i <= 0 ? "" : path.slice(0, i);
|
|
@@ -4611,23 +4556,23 @@ function FileBrowser({
|
|
|
4611
4556
|
confirmDelete,
|
|
4612
4557
|
className
|
|
4613
4558
|
}) {
|
|
4614
|
-
const [expanded, setExpanded] =
|
|
4615
|
-
const [loadingPaths, setLoadingPaths] =
|
|
4616
|
-
const [active, setActive] =
|
|
4617
|
-
const [draftCreate, setDraftCreate] =
|
|
4618
|
-
const [draftRename, setDraftRename] =
|
|
4619
|
-
const [dragOver, setDragOver] =
|
|
4620
|
-
const [menu, setMenu] =
|
|
4621
|
-
const [pendingDelete, setPendingDelete] =
|
|
4622
|
-
const [busy, setBusy] =
|
|
4623
|
-
const [coarsePointer, setCoarsePointer] =
|
|
4559
|
+
const [expanded, setExpanded] = useState10(/* @__PURE__ */ new Set());
|
|
4560
|
+
const [loadingPaths, setLoadingPaths] = useState10(/* @__PURE__ */ new Set());
|
|
4561
|
+
const [active, setActive] = useState10(null);
|
|
4562
|
+
const [draftCreate, setDraftCreate] = useState10(null);
|
|
4563
|
+
const [draftRename, setDraftRename] = useState10(null);
|
|
4564
|
+
const [dragOver, setDragOver] = useState10(null);
|
|
4565
|
+
const [menu, setMenu] = useState10(null);
|
|
4566
|
+
const [pendingDelete, setPendingDelete] = useState10(null);
|
|
4567
|
+
const [busy, setBusy] = useState10(false);
|
|
4568
|
+
const [coarsePointer, setCoarsePointer] = useState10(false);
|
|
4624
4569
|
const treeId = useId2();
|
|
4625
4570
|
const container = usePortalTokenSource();
|
|
4626
4571
|
const containerRef = container.currentRef;
|
|
4627
|
-
const deleteReturnFocusRef =
|
|
4628
|
-
const vlistRef =
|
|
4572
|
+
const deleteReturnFocusRef = useRef11(null);
|
|
4573
|
+
const vlistRef = useRef11(null);
|
|
4629
4574
|
const portalTokenStyle = usePortalTokenStyle(container.source);
|
|
4630
|
-
const getTreeElement =
|
|
4575
|
+
const getTreeElement = useCallback18(
|
|
4631
4576
|
() => typeof document === "undefined" ? null : document.getElementById(treeId),
|
|
4632
4577
|
[treeId]
|
|
4633
4578
|
);
|
|
@@ -4646,7 +4591,7 @@ function FileBrowser({
|
|
|
4646
4591
|
}
|
|
4647
4592
|
}, []);
|
|
4648
4593
|
const cursor = active ?? selectedPath ?? null;
|
|
4649
|
-
const expand =
|
|
4594
|
+
const expand = useCallback18(
|
|
4650
4595
|
async (path) => {
|
|
4651
4596
|
const node = findNode(result.tree, path);
|
|
4652
4597
|
if (node && node.kind === "dir" && node.children === void 0) {
|
|
@@ -4664,14 +4609,14 @@ function FileBrowser({
|
|
|
4664
4609
|
},
|
|
4665
4610
|
[result]
|
|
4666
4611
|
);
|
|
4667
|
-
const open =
|
|
4612
|
+
const open = useCallback18(
|
|
4668
4613
|
(path) => {
|
|
4669
4614
|
setExpanded((prev) => new Set(prev).add(path));
|
|
4670
4615
|
void expand(path);
|
|
4671
4616
|
},
|
|
4672
4617
|
[expand]
|
|
4673
4618
|
);
|
|
4674
|
-
const toggle =
|
|
4619
|
+
const toggle = useCallback18(
|
|
4675
4620
|
async (node) => {
|
|
4676
4621
|
if (node.kind !== "dir") return;
|
|
4677
4622
|
const isOpen = expanded.has(node.path);
|
|
@@ -4746,7 +4691,7 @@ function FileBrowser({
|
|
|
4746
4691
|
const cursorIndex = cursor ? rowIndexByPath.get(cursor) ?? -1 : -1;
|
|
4747
4692
|
const activeDescendantId = cursorIndex >= 0 ? `${treeId}-item-${cursorIndex}` : void 0;
|
|
4748
4693
|
const supportsMutation = editable && result.source === "live" && result.error === null && !result.loading;
|
|
4749
|
-
const performDelete =
|
|
4694
|
+
const performDelete = useCallback18(
|
|
4750
4695
|
async (node) => {
|
|
4751
4696
|
if (!supportsMutation) return;
|
|
4752
4697
|
const recursive = node.kind === "dir";
|
|
@@ -4760,7 +4705,7 @@ function FileBrowser({
|
|
|
4760
4705
|
},
|
|
4761
4706
|
[supportsMutation, result]
|
|
4762
4707
|
);
|
|
4763
|
-
const runDelete =
|
|
4708
|
+
const runDelete = useCallback18(
|
|
4764
4709
|
async (node, returnFocus) => {
|
|
4765
4710
|
if (!supportsMutation) return;
|
|
4766
4711
|
setMenu(null);
|
|
@@ -4773,7 +4718,7 @@ function FileBrowser({
|
|
|
4773
4718
|
},
|
|
4774
4719
|
[supportsMutation, confirmDelete, performDelete]
|
|
4775
4720
|
);
|
|
4776
|
-
const closePendingDelete =
|
|
4721
|
+
const closePendingDelete = useCallback18(
|
|
4777
4722
|
(restoreTrigger) => {
|
|
4778
4723
|
const returnTarget = restoreTrigger ? deleteReturnFocusRef.current : getTreeElement();
|
|
4779
4724
|
deleteReturnFocusRef.current = null;
|
|
@@ -4787,7 +4732,7 @@ function FileBrowser({
|
|
|
4787
4732
|
},
|
|
4788
4733
|
[getTreeElement]
|
|
4789
4734
|
);
|
|
4790
|
-
const commitCreate =
|
|
4735
|
+
const commitCreate = useCallback18(
|
|
4791
4736
|
async (name) => {
|
|
4792
4737
|
const draft = draftCreate;
|
|
4793
4738
|
setDraftCreate(null);
|
|
@@ -4812,7 +4757,7 @@ function FileBrowser({
|
|
|
4812
4757
|
},
|
|
4813
4758
|
[draftCreate, supportsMutation, result, open, onSelectFile]
|
|
4814
4759
|
);
|
|
4815
|
-
const commitRename =
|
|
4760
|
+
const commitRename = useCallback18(
|
|
4816
4761
|
async (name) => {
|
|
4817
4762
|
const draft = draftRename;
|
|
4818
4763
|
setDraftRename(null);
|
|
@@ -4835,7 +4780,7 @@ function FileBrowser({
|
|
|
4835
4780
|
},
|
|
4836
4781
|
[draftRename, supportsMutation, result, selectedPath, active, onSelectFile]
|
|
4837
4782
|
);
|
|
4838
|
-
const startCreate =
|
|
4783
|
+
const startCreate = useCallback18(
|
|
4839
4784
|
(kind) => {
|
|
4840
4785
|
if (!supportsMutation) return;
|
|
4841
4786
|
const anchor = cursor ? findNode(result.tree, cursor) : void 0;
|
|
@@ -4847,7 +4792,7 @@ function FileBrowser({
|
|
|
4847
4792
|
},
|
|
4848
4793
|
[supportsMutation, cursor, result.tree, open]
|
|
4849
4794
|
);
|
|
4850
|
-
const startRename =
|
|
4795
|
+
const startRename = useCallback18(
|
|
4851
4796
|
(node) => {
|
|
4852
4797
|
if (!supportsMutation) return;
|
|
4853
4798
|
setDraftCreate(null);
|
|
@@ -4856,7 +4801,7 @@ function FileBrowser({
|
|
|
4856
4801
|
},
|
|
4857
4802
|
[supportsMutation]
|
|
4858
4803
|
);
|
|
4859
|
-
const onDropOnto =
|
|
4804
|
+
const onDropOnto = useCallback18(
|
|
4860
4805
|
async (targetDir, sourcePath) => {
|
|
4861
4806
|
setDragOver(null);
|
|
4862
4807
|
if (!supportsMutation || !sourcePath) return;
|
|
@@ -4880,7 +4825,7 @@ function FileBrowser({
|
|
|
4880
4825
|
},
|
|
4881
4826
|
[supportsMutation, result, selectedPath, active, onSelectFile]
|
|
4882
4827
|
);
|
|
4883
|
-
const onKeyDown =
|
|
4828
|
+
const onKeyDown = useCallback18(
|
|
4884
4829
|
(e) => {
|
|
4885
4830
|
if (draftCreate || draftRename) return;
|
|
4886
4831
|
if (flatRows.length === 0) return;
|
|
@@ -4999,7 +4944,7 @@ function FileBrowser({
|
|
|
4999
4944
|
treeId
|
|
5000
4945
|
]
|
|
5001
4946
|
);
|
|
5002
|
-
|
|
4947
|
+
useEffect13(() => {
|
|
5003
4948
|
if (!menu) return;
|
|
5004
4949
|
const close = () => setMenu(null);
|
|
5005
4950
|
window.addEventListener("click", close);
|
|
@@ -5180,7 +5125,7 @@ function FileBrowser({
|
|
|
5180
5125
|
);
|
|
5181
5126
|
}
|
|
5182
5127
|
};
|
|
5183
|
-
|
|
5128
|
+
useEffect13(() => {
|
|
5184
5129
|
if (!cursor) return;
|
|
5185
5130
|
const index = renderItems.findIndex((it) => it.type === "node" && it.node.path === cursor);
|
|
5186
5131
|
if (index >= 0) vlistRef.current?.scrollToIndex(index);
|
|
@@ -5387,11 +5332,11 @@ function DeleteDialog({
|
|
|
5387
5332
|
onCancel,
|
|
5388
5333
|
onConfirm
|
|
5389
5334
|
}) {
|
|
5390
|
-
const cancelRef =
|
|
5391
|
-
const [open, setOpen] =
|
|
5392
|
-
const closeIntentRef =
|
|
5393
|
-
const settledRef =
|
|
5394
|
-
const settleTimerRef =
|
|
5335
|
+
const cancelRef = useRef11(null);
|
|
5336
|
+
const [open, setOpen] = useState10(true);
|
|
5337
|
+
const closeIntentRef = useRef11("cancel");
|
|
5338
|
+
const settledRef = useRef11(false);
|
|
5339
|
+
const settleTimerRef = useRef11(null);
|
|
5395
5340
|
const settle = () => {
|
|
5396
5341
|
if (settledRef.current) return;
|
|
5397
5342
|
settledRef.current = true;
|
|
@@ -5408,7 +5353,7 @@ function DeleteDialog({
|
|
|
5408
5353
|
settle();
|
|
5409
5354
|
}, 0);
|
|
5410
5355
|
};
|
|
5411
|
-
|
|
5356
|
+
useEffect13(
|
|
5412
5357
|
() => () => {
|
|
5413
5358
|
if (settleTimerRef.current !== null) clearTimeout(settleTimerRef.current);
|
|
5414
5359
|
},
|
|
@@ -5526,10 +5471,10 @@ function InlineInput({
|
|
|
5526
5471
|
onCommit,
|
|
5527
5472
|
onCancel
|
|
5528
5473
|
}) {
|
|
5529
|
-
const [value, setValue] =
|
|
5530
|
-
const ref =
|
|
5531
|
-
const doneRef =
|
|
5532
|
-
|
|
5474
|
+
const [value, setValue] = useState10(initialValue);
|
|
5475
|
+
const ref = useRef11(null);
|
|
5476
|
+
const doneRef = useRef11(false);
|
|
5477
|
+
useEffect13(() => {
|
|
5533
5478
|
const el = ref.current;
|
|
5534
5479
|
if (!el) return;
|
|
5535
5480
|
el.focus();
|
|
@@ -5593,12 +5538,12 @@ function ContextMenu({
|
|
|
5593
5538
|
onClose
|
|
5594
5539
|
}) {
|
|
5595
5540
|
const isDir = node.kind === "dir";
|
|
5596
|
-
const menuRef =
|
|
5541
|
+
const menuRef = useRef11(null);
|
|
5597
5542
|
const vw = typeof window !== "undefined" ? window.innerWidth : 9999;
|
|
5598
5543
|
const vh = typeof window !== "undefined" ? window.innerHeight : 9999;
|
|
5599
5544
|
const left = Math.max(4, Math.min(x, vw - 180));
|
|
5600
5545
|
const top = Math.max(4, Math.min(y, vh - 160));
|
|
5601
|
-
|
|
5546
|
+
useEffect13(() => {
|
|
5602
5547
|
menuRef.current?.querySelector('[role="menuitem"]')?.focus();
|
|
5603
5548
|
}, []);
|
|
5604
5549
|
const onKeyDown = (event) => {
|
|
@@ -5674,18 +5619,18 @@ function ContextMenu({
|
|
|
5674
5619
|
import { ArrowUpRightIcon, FileWarningIcon, HistoryIcon } from "lucide-react";
|
|
5675
5620
|
import {
|
|
5676
5621
|
Component,
|
|
5677
|
-
useCallback as
|
|
5678
|
-
useEffect as
|
|
5622
|
+
useCallback as useCallback20,
|
|
5623
|
+
useEffect as useEffect15,
|
|
5679
5624
|
useId as useId3,
|
|
5680
|
-
useLayoutEffect as
|
|
5625
|
+
useLayoutEffect as useLayoutEffect3,
|
|
5681
5626
|
useMemo as useMemo11,
|
|
5682
|
-
useRef as
|
|
5683
|
-
useState as
|
|
5627
|
+
useRef as useRef13,
|
|
5628
|
+
useState as useState12
|
|
5684
5629
|
} from "react";
|
|
5685
5630
|
import { VList as VList2 } from "virtua";
|
|
5686
5631
|
|
|
5687
5632
|
// src/hooks/use-windowed-sections.ts
|
|
5688
|
-
import { useCallback as
|
|
5633
|
+
import { useCallback as useCallback19, useEffect as useEffect14, useMemo as useMemo10, useRef as useRef12, useState as useState11 } from "react";
|
|
5689
5634
|
function computeWindowRange(heights, scrollTop, viewport, overscan) {
|
|
5690
5635
|
const n = heights.length;
|
|
5691
5636
|
if (n === 0) return { start: 0, end: 0 };
|
|
@@ -5716,29 +5661,29 @@ function computeWindowRange(heights, scrollTop, viewport, overscan) {
|
|
|
5716
5661
|
}
|
|
5717
5662
|
function useWindowedSections(opts) {
|
|
5718
5663
|
const { count, estimateHeight, overscan = 3 } = opts;
|
|
5719
|
-
const scrollRef =
|
|
5720
|
-
const [heights, setHeights] =
|
|
5664
|
+
const scrollRef = useRef12(null);
|
|
5665
|
+
const [heights, setHeights] = useState11(
|
|
5721
5666
|
() => Array.from({ length: count }, (_, i) => estimateHeight(i))
|
|
5722
5667
|
);
|
|
5723
|
-
|
|
5668
|
+
useEffect14(() => {
|
|
5724
5669
|
setHeights((prev) => {
|
|
5725
5670
|
const next = Array.from({ length: count }, (_, i) => estimateHeight(i));
|
|
5726
5671
|
return prev.length === next.length && prev.every((height, index) => height === next[index]) ? prev : next;
|
|
5727
5672
|
});
|
|
5728
5673
|
}, [count, estimateHeight]);
|
|
5729
|
-
const heightsRef =
|
|
5674
|
+
const heightsRef = useRef12(heights);
|
|
5730
5675
|
heightsRef.current = heights;
|
|
5731
|
-
const [range, setRange] =
|
|
5676
|
+
const [range, setRange] = useState11(() => ({
|
|
5732
5677
|
start: 0,
|
|
5733
5678
|
end: Math.min(count, overscan + 1)
|
|
5734
5679
|
}));
|
|
5735
|
-
const recompute =
|
|
5680
|
+
const recompute = useCallback19(() => {
|
|
5736
5681
|
const el = scrollRef.current;
|
|
5737
5682
|
if (!el) return;
|
|
5738
5683
|
const next = computeWindowRange(heightsRef.current, el.scrollTop, el.clientHeight, overscan);
|
|
5739
5684
|
setRange((prev) => prev.start === next.start && prev.end === next.end ? prev : next);
|
|
5740
5685
|
}, [overscan]);
|
|
5741
|
-
|
|
5686
|
+
useEffect14(() => {
|
|
5742
5687
|
const el = scrollRef.current;
|
|
5743
5688
|
if (!el) return;
|
|
5744
5689
|
let raf = 0;
|
|
@@ -5759,7 +5704,7 @@ function useWindowedSections(opts) {
|
|
|
5759
5704
|
if (raf && typeof cancelAnimationFrame === "function") cancelAnimationFrame(raf);
|
|
5760
5705
|
};
|
|
5761
5706
|
}, [recompute, count]);
|
|
5762
|
-
const measure =
|
|
5707
|
+
const measure = useCallback19((index, height) => {
|
|
5763
5708
|
if (height <= 0) return;
|
|
5764
5709
|
setHeights((prev) => {
|
|
5765
5710
|
if (Math.abs((prev[index] ?? 0) - height) < 1) return prev;
|
|
@@ -5774,10 +5719,10 @@ function useWindowedSections(opts) {
|
|
|
5774
5719
|
for (let i = 0; i < count; i++) out[i + 1] = (out[i] ?? 0) + Math.max(heights[i] ?? 0, 0);
|
|
5775
5720
|
return out;
|
|
5776
5721
|
}, [heights, count]);
|
|
5777
|
-
|
|
5722
|
+
useEffect14(() => {
|
|
5778
5723
|
recompute();
|
|
5779
5724
|
}, [offsets, recompute]);
|
|
5780
|
-
const scrollToIndex =
|
|
5725
|
+
const scrollToIndex = useCallback19(
|
|
5781
5726
|
(index) => {
|
|
5782
5727
|
const el = scrollRef.current;
|
|
5783
5728
|
if (!el) return;
|
|
@@ -5804,7 +5749,7 @@ var HEADER_PX = 30;
|
|
|
5804
5749
|
var LINE_PX = 18;
|
|
5805
5750
|
var GUARD_BODY_PX = 52;
|
|
5806
5751
|
var COMPACT_SURFACE_PX = 560;
|
|
5807
|
-
var useChangesLayoutEffect = typeof window === "undefined" ?
|
|
5752
|
+
var useChangesLayoutEffect = typeof window === "undefined" ? useEffect15 : useLayoutEffect3;
|
|
5808
5753
|
var STATUS_TINT2 = {
|
|
5809
5754
|
added: "text-og-status-idle",
|
|
5810
5755
|
modified: "text-og-status-running",
|
|
@@ -5979,12 +5924,12 @@ function WorkbenchChanges({
|
|
|
5979
5924
|
onOpenFile,
|
|
5980
5925
|
className
|
|
5981
5926
|
}) {
|
|
5982
|
-
const rootRef =
|
|
5983
|
-
const [compact, setCompact] =
|
|
5984
|
-
const [coarsePointer, setCoarsePointer] =
|
|
5927
|
+
const rootRef = useRef13(null);
|
|
5928
|
+
const [compact, setCompact] = useState12(false);
|
|
5929
|
+
const [coarsePointer, setCoarsePointer] = useState12(false);
|
|
5985
5930
|
const resolvedTheme = useThemeType(themeType);
|
|
5986
|
-
const [layout, setLayout] =
|
|
5987
|
-
const [activePath, setActivePath] =
|
|
5931
|
+
const [layout, setLayout] = useState12("unified");
|
|
5932
|
+
const [activePath, setActivePath] = useState12(null);
|
|
5988
5933
|
const pickerId = useId3();
|
|
5989
5934
|
const unicodeFontPaths = useMemo11(
|
|
5990
5935
|
() => diff.flatMap((file) => file.oldPath ? [file.path, file.oldPath] : [file.path]),
|
|
@@ -6023,7 +5968,7 @@ function WorkbenchChanges({
|
|
|
6023
5968
|
}, []);
|
|
6024
5969
|
const additions = useMemo11(() => diff.reduce((sum, f) => sum + f.additions, 0), [diff]);
|
|
6025
5970
|
const deletions = useMemo11(() => diff.reduce((sum, f) => sum + f.deletions, 0), [diff]);
|
|
6026
|
-
const estimateHeight =
|
|
5971
|
+
const estimateHeight = useCallback20(
|
|
6027
5972
|
(index) => {
|
|
6028
5973
|
const file = orderedFiles[index];
|
|
6029
5974
|
return file ? estimateSectionHeight(file) : HEADER_PX + LINE_PX;
|
|
@@ -6035,14 +5980,14 @@ function WorkbenchChanges({
|
|
|
6035
5980
|
estimateHeight,
|
|
6036
5981
|
overscan: OVERSCAN
|
|
6037
5982
|
});
|
|
6038
|
-
const jumpTo =
|
|
5983
|
+
const jumpTo = useCallback20(
|
|
6039
5984
|
(index) => {
|
|
6040
5985
|
setActivePath(orderedFiles[index]?.path ?? null);
|
|
6041
5986
|
windowed.scrollToIndex(index);
|
|
6042
5987
|
},
|
|
6043
5988
|
[orderedFiles, windowed]
|
|
6044
5989
|
);
|
|
6045
|
-
const onPaneScroll =
|
|
5990
|
+
const onPaneScroll = useCallback20(() => {
|
|
6046
5991
|
const el = windowed.scrollRef.current;
|
|
6047
5992
|
if (!el) {
|
|
6048
5993
|
return;
|
|
@@ -6057,7 +6002,7 @@ function WorkbenchChanges({
|
|
|
6057
6002
|
const nextPath = orderedFiles[idx]?.path ?? null;
|
|
6058
6003
|
setActivePath((previous) => previous === nextPath ? previous : nextPath);
|
|
6059
6004
|
}, [windowed, orderedFiles]);
|
|
6060
|
-
|
|
6005
|
+
useEffect15(() => {
|
|
6061
6006
|
const el = windowed.scrollRef.current;
|
|
6062
6007
|
if (!el) return;
|
|
6063
6008
|
el.addEventListener("scroll", onPaneScroll, { passive: true });
|
|
@@ -6305,8 +6250,8 @@ function MeasuredSection({
|
|
|
6305
6250
|
onMeasure,
|
|
6306
6251
|
children
|
|
6307
6252
|
}) {
|
|
6308
|
-
const ref =
|
|
6309
|
-
|
|
6253
|
+
const ref = useRef13(null);
|
|
6254
|
+
useEffect15(() => {
|
|
6310
6255
|
const el = ref.current;
|
|
6311
6256
|
if (!el) return;
|
|
6312
6257
|
const report = () => onMeasure(index, el.offsetHeight);
|
|
@@ -6427,8 +6372,8 @@ function DiffView({
|
|
|
6427
6372
|
import {
|
|
6428
6373
|
lazy,
|
|
6429
6374
|
Suspense,
|
|
6430
|
-
useEffect as
|
|
6431
|
-
useState as
|
|
6375
|
+
useEffect as useEffect16,
|
|
6376
|
+
useState as useState13
|
|
6432
6377
|
} from "react";
|
|
6433
6378
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
6434
6379
|
var LazyFile = lazy(async () => {
|
|
@@ -6445,8 +6390,8 @@ function PierreFile({
|
|
|
6445
6390
|
fallback,
|
|
6446
6391
|
className
|
|
6447
6392
|
}) {
|
|
6448
|
-
const [failed, setFailed] =
|
|
6449
|
-
|
|
6393
|
+
const [failed, setFailed] = useState13(false);
|
|
6394
|
+
useEffect16(() => {
|
|
6450
6395
|
let cancelled = false;
|
|
6451
6396
|
void import("@pierre/diffs/react").catch(() => {
|
|
6452
6397
|
if (!cancelled) setFailed(true);
|
|
@@ -6505,11 +6450,11 @@ function FileSkeleton() {
|
|
|
6505
6450
|
// src/components/code-editor.tsx
|
|
6506
6451
|
import { Loader2Icon, SaveIcon } from "lucide-react";
|
|
6507
6452
|
import {
|
|
6508
|
-
useCallback as
|
|
6509
|
-
useEffect as
|
|
6453
|
+
useCallback as useCallback21,
|
|
6454
|
+
useEffect as useEffect17,
|
|
6510
6455
|
useMemo as useMemo12,
|
|
6511
|
-
useRef as
|
|
6512
|
-
useState as
|
|
6456
|
+
useRef as useRef14,
|
|
6457
|
+
useState as useState14
|
|
6513
6458
|
} from "react";
|
|
6514
6459
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
6515
6460
|
var LANGUAGE_LOADERS = {
|
|
@@ -6581,30 +6526,30 @@ function CodeEditor({
|
|
|
6581
6526
|
fallback,
|
|
6582
6527
|
className
|
|
6583
6528
|
}) {
|
|
6584
|
-
const [failed, setFailed] =
|
|
6585
|
-
const [bundle, setBundle] =
|
|
6586
|
-
const [buffer, setBuffer] =
|
|
6529
|
+
const [failed, setFailed] = useState14(false);
|
|
6530
|
+
const [bundle, setBundle] = useState14(null);
|
|
6531
|
+
const [buffer, setBuffer] = useState14(() => ({
|
|
6587
6532
|
path,
|
|
6588
6533
|
value: initialContents,
|
|
6589
6534
|
baseline: initialContents
|
|
6590
6535
|
}));
|
|
6591
6536
|
const { value, baseline } = buffer;
|
|
6592
|
-
const [saving, setSaving] =
|
|
6593
|
-
const [saveError, setSaveError] =
|
|
6594
|
-
const [savedTick, setSavedTick] =
|
|
6595
|
-
const saveInFlightRef =
|
|
6537
|
+
const [saving, setSaving] = useState14(false);
|
|
6538
|
+
const [saveError, setSaveError] = useState14(null);
|
|
6539
|
+
const [savedTick, setSavedTick] = useState14(false);
|
|
6540
|
+
const saveInFlightRef = useRef14(false);
|
|
6596
6541
|
const dirty = value !== baseline;
|
|
6597
6542
|
const saveConflict = saveError !== null && saveError.code === "file_write_conflict";
|
|
6598
|
-
const editIntentFiredRef =
|
|
6599
|
-
|
|
6543
|
+
const editIntentFiredRef = useRef14(false);
|
|
6544
|
+
useEffect17(() => {
|
|
6600
6545
|
setBuffer((current) => reconcileEditorBuffer(current, { path, contents: initialContents }));
|
|
6601
6546
|
}, [path, initialContents]);
|
|
6602
|
-
|
|
6547
|
+
useEffect17(() => {
|
|
6603
6548
|
editIntentFiredRef.current = false;
|
|
6604
6549
|
setSaveError(null);
|
|
6605
6550
|
setSavedTick(false);
|
|
6606
6551
|
}, [path]);
|
|
6607
|
-
const noteEdit =
|
|
6552
|
+
const noteEdit = useCallback21(
|
|
6608
6553
|
(next) => {
|
|
6609
6554
|
setBuffer((current) => ({ ...current, value: next }));
|
|
6610
6555
|
setSavedTick(false);
|
|
@@ -6616,7 +6561,7 @@ function CodeEditor({
|
|
|
6616
6561
|
[baseline, onEditIntent]
|
|
6617
6562
|
);
|
|
6618
6563
|
const langKey = useMemo12(() => languageForPath(path), [path]);
|
|
6619
|
-
|
|
6564
|
+
useEffect17(() => {
|
|
6620
6565
|
let cancelled = false;
|
|
6621
6566
|
void (async () => {
|
|
6622
6567
|
try {
|
|
@@ -6656,9 +6601,9 @@ function CodeEditor({
|
|
|
6656
6601
|
cancelled = true;
|
|
6657
6602
|
};
|
|
6658
6603
|
}, [langKey]);
|
|
6659
|
-
const saveRef =
|
|
6604
|
+
const saveRef = useRef14(() => {
|
|
6660
6605
|
});
|
|
6661
|
-
const save =
|
|
6606
|
+
const save = useCallback21(async () => {
|
|
6662
6607
|
if (readOnly || saveInFlightRef.current) return;
|
|
6663
6608
|
const snapshot = value;
|
|
6664
6609
|
if (snapshot === baseline) return;
|
|
@@ -6679,7 +6624,7 @@ function CodeEditor({
|
|
|
6679
6624
|
setSaving(false);
|
|
6680
6625
|
}
|
|
6681
6626
|
}, [readOnly, value, baseline, onSave, path]);
|
|
6682
|
-
const overwrite =
|
|
6627
|
+
const overwrite = useCallback21(async () => {
|
|
6683
6628
|
if (readOnly || !onOverwrite || saveInFlightRef.current) return;
|
|
6684
6629
|
const snapshot = value;
|
|
6685
6630
|
if (snapshot === baseline) return;
|
|
@@ -6703,7 +6648,7 @@ function CodeEditor({
|
|
|
6703
6648
|
saveRef.current = () => {
|
|
6704
6649
|
void save();
|
|
6705
6650
|
};
|
|
6706
|
-
|
|
6651
|
+
useEffect17(() => {
|
|
6707
6652
|
if (!savedTick) return;
|
|
6708
6653
|
const t = setTimeout(() => setSavedTick(false), 1800);
|
|
6709
6654
|
return () => clearTimeout(t);
|
|
@@ -6716,7 +6661,7 @@ function CodeEditor({
|
|
|
6716
6661
|
return exts;
|
|
6717
6662
|
}, [bundle]);
|
|
6718
6663
|
const Editor = bundle?.Editor;
|
|
6719
|
-
const reload =
|
|
6664
|
+
const reload = useCallback21(() => {
|
|
6720
6665
|
setBuffer({ path, value: initialContents, baseline: initialContents });
|
|
6721
6666
|
editIntentFiredRef.current = false;
|
|
6722
6667
|
setSaveError(null);
|
|
@@ -6872,7 +6817,7 @@ function EditorSkeleton() {
|
|
|
6872
6817
|
|
|
6873
6818
|
// src/components/sandbox-files.tsx
|
|
6874
6819
|
import { FileCode2Icon, FileWarningIcon as FileWarningIcon2, LoaderCircleIcon } from "lucide-react";
|
|
6875
|
-
import { useCallback as
|
|
6820
|
+
import { useCallback as useCallback22, useEffect as useEffect18, useRef as useRef15, useState as useState15 } from "react";
|
|
6876
6821
|
import { Group, Panel, Separator } from "react-resizable-panels";
|
|
6877
6822
|
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
6878
6823
|
function SandboxFiles({
|
|
@@ -6892,14 +6837,14 @@ function SandboxFiles({
|
|
|
6892
6837
|
themeType,
|
|
6893
6838
|
className
|
|
6894
6839
|
}) {
|
|
6895
|
-
const [selected, setSelected] =
|
|
6896
|
-
const [editMode, setEditMode] =
|
|
6897
|
-
const [liveRequestedPath, setLiveRequestedPath] =
|
|
6898
|
-
const [viewReloadRevision, setViewReloadRevision] =
|
|
6899
|
-
const pendingRequestRef =
|
|
6900
|
-
const handledRequestRef =
|
|
6840
|
+
const [selected, setSelected] = useState15(null);
|
|
6841
|
+
const [editMode, setEditMode] = useState15(false);
|
|
6842
|
+
const [liveRequestedPath, setLiveRequestedPath] = useState15(null);
|
|
6843
|
+
const [viewReloadRevision, setViewReloadRevision] = useState15(0);
|
|
6844
|
+
const pendingRequestRef = useRef15(null);
|
|
6845
|
+
const handledRequestRef = useRef15(null);
|
|
6901
6846
|
const requestKey = requestedPath ? requestedPathRequestId ?? requestedPath : null;
|
|
6902
|
-
|
|
6847
|
+
useEffect18(() => {
|
|
6903
6848
|
if (!requestedPath || requestKey === null) {
|
|
6904
6849
|
pendingRequestRef.current = null;
|
|
6905
6850
|
handledRequestRef.current = null;
|
|
@@ -6917,9 +6862,9 @@ function SandboxFiles({
|
|
|
6917
6862
|
setSelected(requestedPath);
|
|
6918
6863
|
setEditMode(false);
|
|
6919
6864
|
}, [requestKey, requestedPath, requestedPathReady]);
|
|
6920
|
-
const rootRef =
|
|
6921
|
-
const [wide, setWide] =
|
|
6922
|
-
|
|
6865
|
+
const rootRef = useRef15(null);
|
|
6866
|
+
const [wide, setWide] = useState15(false);
|
|
6867
|
+
useEffect18(() => {
|
|
6923
6868
|
const el = rootRef.current;
|
|
6924
6869
|
if (!el) return;
|
|
6925
6870
|
const update = () => setWide(el.getBoundingClientRect().width >= 720);
|
|
@@ -6945,7 +6890,7 @@ function SandboxFiles({
|
|
|
6945
6890
|
files.readFile,
|
|
6946
6891
|
(files.contentRevision ?? 0) + viewReloadRevision
|
|
6947
6892
|
);
|
|
6948
|
-
const selectFile =
|
|
6893
|
+
const selectFile = useCallback22((path) => {
|
|
6949
6894
|
if (pendingRequestRef.current !== null) {
|
|
6950
6895
|
handledRequestRef.current = pendingRequestRef.current;
|
|
6951
6896
|
pendingRequestRef.current = null;
|
|
@@ -7271,8 +7216,8 @@ function Segmented({
|
|
|
7271
7216
|
)) });
|
|
7272
7217
|
}
|
|
7273
7218
|
function useFileView(path, readFile, reloadRevision = 0) {
|
|
7274
|
-
const previousPathRef =
|
|
7275
|
-
const [state, setState] =
|
|
7219
|
+
const previousPathRef = useRef15(null);
|
|
7220
|
+
const [state, setState] = useState15({
|
|
7276
7221
|
content: null,
|
|
7277
7222
|
isBinary: false,
|
|
7278
7223
|
truncated: false,
|
|
@@ -7280,7 +7225,7 @@ function useFileView(path, readFile, reloadRevision = 0) {
|
|
|
7280
7225
|
loading: false,
|
|
7281
7226
|
error: null
|
|
7282
7227
|
});
|
|
7283
|
-
|
|
7228
|
+
useEffect18(() => {
|
|
7284
7229
|
if (!path) {
|
|
7285
7230
|
previousPathRef.current = null;
|
|
7286
7231
|
setState({
|
|
@@ -7379,411 +7324,14 @@ function Notice({
|
|
|
7379
7324
|
);
|
|
7380
7325
|
}
|
|
7381
7326
|
|
|
7382
|
-
// src/components/desktop-viewer.tsx
|
|
7383
|
-
import { LoaderCircleIcon as LoaderCircleIcon2, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from "lucide-react";
|
|
7384
|
-
import { useEffect as useEffect21, useRef as useRef18, useState as useState18 } from "react";
|
|
7385
|
-
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
7386
|
-
var DESKTOP_MEDIA_BACKGROUND = "#000";
|
|
7387
|
-
function isHardUnavailable(reason) {
|
|
7388
|
-
switch (reason) {
|
|
7389
|
-
case "backend_unsupported":
|
|
7390
|
-
case "os_unsupported":
|
|
7391
|
-
case "not_provisioned":
|
|
7392
|
-
case "disabled_by_policy":
|
|
7393
|
-
case "tier_headless":
|
|
7394
|
-
return true;
|
|
7395
|
-
default:
|
|
7396
|
-
return false;
|
|
7397
|
-
}
|
|
7398
|
-
}
|
|
7399
|
-
function DesktopViewer({
|
|
7400
|
-
capability,
|
|
7401
|
-
interactive,
|
|
7402
|
-
showControlToggle = true,
|
|
7403
|
-
scaleViewport,
|
|
7404
|
-
rfbFactory,
|
|
7405
|
-
webSocketFactory,
|
|
7406
|
-
onActivate,
|
|
7407
|
-
onAcknowledge,
|
|
7408
|
-
watching,
|
|
7409
|
-
onWarm,
|
|
7410
|
-
renderUnavailable,
|
|
7411
|
-
renderWarming,
|
|
7412
|
-
renderViewerCap,
|
|
7413
|
-
viewerCapReached,
|
|
7414
|
-
connectTimeoutMs = 13e3,
|
|
7415
|
-
className
|
|
7416
|
-
}) {
|
|
7417
|
-
const containerRef = useRef18(null);
|
|
7418
|
-
const onActivateRef = useRef18(onActivate);
|
|
7419
|
-
const onAcknowledgeRef = useRef18(onAcknowledge);
|
|
7420
|
-
onActivateRef.current = onActivate;
|
|
7421
|
-
onAcknowledgeRef.current = onAcknowledge;
|
|
7422
|
-
const acknowledgmentAttemptedRef = useRef18(false);
|
|
7423
|
-
const [acknowledgmentError, setAcknowledgmentError] = useState18(null);
|
|
7424
|
-
const [acknowledgmentRetryNonce, setAcknowledgmentRetryNonce] = useState18(0);
|
|
7425
|
-
const [takeControl, setTakeControl] = useState18(interactive ?? false);
|
|
7426
|
-
const externallyControlled = interactive !== void 0;
|
|
7427
|
-
const serverAllowsControl = capability?.mode !== "read-only";
|
|
7428
|
-
const wantControl = externallyControlled ? interactive : takeControl;
|
|
7429
|
-
const inControl = Boolean(wantControl) && serverAllowsControl;
|
|
7430
|
-
const isWatching = watching ?? true;
|
|
7431
|
-
const transportNull = !capability || capability.transport === null;
|
|
7432
|
-
const reason = capability?.reason ?? null;
|
|
7433
|
-
const needsAcknowledgment = capability?.requiresAcknowledgment === true && capability.acknowledged !== true;
|
|
7434
|
-
const noLiveAddress = Boolean(capability) && !transportNull && !capability.url;
|
|
7435
|
-
const coldWarmable = transportNull && reason === "lease_cold" || !transportNull && noLiveAddress;
|
|
7436
|
-
const hardUnavailable = transportNull && isHardUnavailable(reason);
|
|
7437
|
-
useEffect21(() => {
|
|
7438
|
-
onActivateRef.current?.();
|
|
7439
|
-
}, []);
|
|
7440
|
-
useEffect21(() => {
|
|
7441
|
-
if (!needsAcknowledgment) {
|
|
7442
|
-
acknowledgmentAttemptedRef.current = false;
|
|
7443
|
-
setAcknowledgmentError(null);
|
|
7444
|
-
return;
|
|
7445
|
-
}
|
|
7446
|
-
if (acknowledgmentAttemptedRef.current) return;
|
|
7447
|
-
acknowledgmentAttemptedRef.current = true;
|
|
7448
|
-
setAcknowledgmentError(null);
|
|
7449
|
-
const acknowledge = onAcknowledgeRef.current;
|
|
7450
|
-
if (!acknowledge) {
|
|
7451
|
-
setAcknowledgmentError(new Error("Desktop acknowledgment is not configured."));
|
|
7452
|
-
return;
|
|
7453
|
-
}
|
|
7454
|
-
let active = true;
|
|
7455
|
-
void Promise.resolve().then(() => acknowledge()).catch((cause) => {
|
|
7456
|
-
if (!active) return;
|
|
7457
|
-
setAcknowledgmentError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
7458
|
-
});
|
|
7459
|
-
return () => {
|
|
7460
|
-
active = false;
|
|
7461
|
-
};
|
|
7462
|
-
}, [needsAcknowledgment, acknowledgmentRetryNonce]);
|
|
7463
|
-
const retryAcknowledgment = () => {
|
|
7464
|
-
acknowledgmentAttemptedRef.current = false;
|
|
7465
|
-
setAcknowledgmentError(null);
|
|
7466
|
-
setAcknowledgmentRetryNonce((nonce) => nonce + 1);
|
|
7467
|
-
};
|
|
7468
|
-
useEffect21(() => {
|
|
7469
|
-
if (!inControl || externallyControlled) return;
|
|
7470
|
-
const onKey = (event) => {
|
|
7471
|
-
if (event.ctrlKey && event.altKey && event.shiftKey && (event.key === "Control" || event.key === "Alt" || event.key === "Shift")) {
|
|
7472
|
-
event.preventDefault();
|
|
7473
|
-
setTakeControl(false);
|
|
7474
|
-
}
|
|
7475
|
-
};
|
|
7476
|
-
window.addEventListener("keydown", onKey);
|
|
7477
|
-
return () => {
|
|
7478
|
-
window.removeEventListener("keydown", onKey);
|
|
7479
|
-
};
|
|
7480
|
-
}, [inControl, externallyControlled]);
|
|
7481
|
-
const connectCapability = !transportNull && !needsAcknowledgment && !viewerCapReached ? capability : null;
|
|
7482
|
-
const stream = useDesktopStream({
|
|
7483
|
-
capability: connectCapability,
|
|
7484
|
-
containerRef,
|
|
7485
|
-
interactive: inControl,
|
|
7486
|
-
...scaleViewport !== void 0 ? { scaleViewport } : {},
|
|
7487
|
-
...rfbFactory ? { rfbFactory } : {},
|
|
7488
|
-
...webSocketFactory ? { webSocketFactory } : {}
|
|
7489
|
-
});
|
|
7490
|
-
const connected = stream.state === "connected";
|
|
7491
|
-
const hasLiveUrl = Boolean(connectCapability?.url);
|
|
7492
|
-
const streamStateRef = useRef18(stream.state);
|
|
7493
|
-
streamStateRef.current = stream.state;
|
|
7494
|
-
const warmKeyRef = useRef18(null);
|
|
7495
|
-
useEffect21(() => {
|
|
7496
|
-
if (!isWatching || !coldWarmable || needsAcknowledgment || viewerCapReached) {
|
|
7497
|
-
if (!coldWarmable) warmKeyRef.current = null;
|
|
7498
|
-
return;
|
|
7499
|
-
}
|
|
7500
|
-
if (!onWarm) return;
|
|
7501
|
-
const key = `${capability?.reason ?? ""}:${capability?.url ?? ""}:${capability?.expiresAt ?? ""}`;
|
|
7502
|
-
if (warmKeyRef.current === key) return;
|
|
7503
|
-
warmKeyRef.current = key;
|
|
7504
|
-
onWarm();
|
|
7505
|
-
}, [isWatching, coldWarmable, needsAcknowledgment, viewerCapReached, capability, onWarm]);
|
|
7506
|
-
useEffect21(() => {
|
|
7507
|
-
if (!hasLiveUrl || typeof document === "undefined") return;
|
|
7508
|
-
const maybeReattach = () => {
|
|
7509
|
-
if (document.visibilityState !== "visible") return;
|
|
7510
|
-
if (streamStateRef.current === "idle") stream.reconnect();
|
|
7511
|
-
};
|
|
7512
|
-
document.addEventListener("visibilitychange", maybeReattach);
|
|
7513
|
-
return () => document.removeEventListener("visibilitychange", maybeReattach);
|
|
7514
|
-
}, [hasLiveUrl, connectCapability?.url]);
|
|
7515
|
-
const [connectTimedOut, setConnectTimedOut] = useState18(false);
|
|
7516
|
-
const [reconnectNonce, setReconnectNonce] = useState18(0);
|
|
7517
|
-
useEffect21(() => {
|
|
7518
|
-
setConnectTimedOut(false);
|
|
7519
|
-
if (!hasLiveUrl || connected || stream.error || connectTimeoutMs <= 0) return;
|
|
7520
|
-
const timer = setTimeout(() => setConnectTimedOut(true), connectTimeoutMs);
|
|
7521
|
-
return () => clearTimeout(timer);
|
|
7522
|
-
}, [
|
|
7523
|
-
hasLiveUrl,
|
|
7524
|
-
connected,
|
|
7525
|
-
connectTimeoutMs,
|
|
7526
|
-
connectCapability?.url,
|
|
7527
|
-
stream.error,
|
|
7528
|
-
reconnectNonce
|
|
7529
|
-
]);
|
|
7530
|
-
const reconnect = () => {
|
|
7531
|
-
setConnectTimedOut(false);
|
|
7532
|
-
setReconnectNonce((n) => n + 1);
|
|
7533
|
-
stream.reconnect();
|
|
7534
|
-
};
|
|
7535
|
-
let uiState;
|
|
7536
|
-
if (viewerCapReached) uiState = "viewer_cap";
|
|
7537
|
-
else if (hardUnavailable) uiState = "unavailable";
|
|
7538
|
-
else if (acknowledgmentError) uiState = "acknowledgment_error";
|
|
7539
|
-
else if (needsAcknowledgment) uiState = "opening";
|
|
7540
|
-
else if (coldWarmable) uiState = "warming";
|
|
7541
|
-
else if (connected) uiState = "connected";
|
|
7542
|
-
else if (stream.error) uiState = "error";
|
|
7543
|
-
else if (connectTimedOut) uiState = "connect_failed";
|
|
7544
|
-
else uiState = "connecting";
|
|
7545
|
-
const overlayShown = uiState !== "connected" && uiState !== "connecting" && uiState !== "opening";
|
|
7546
|
-
const showToggle = showControlToggle && !overlayShown;
|
|
7547
|
-
let overlay = null;
|
|
7548
|
-
switch (uiState) {
|
|
7549
|
-
case "viewer_cap":
|
|
7550
|
-
overlay = renderViewerCap?.() ?? defaultNotice(
|
|
7551
|
-
"Too many viewers",
|
|
7552
|
-
"This session has reached its live-viewer limit. Try again shortly."
|
|
7553
|
-
);
|
|
7554
|
-
break;
|
|
7555
|
-
case "unavailable":
|
|
7556
|
-
overlay = renderUnavailable?.(reason) ?? defaultNotice("Desktop unavailable", unavailableCopy(reason));
|
|
7557
|
-
break;
|
|
7558
|
-
case "acknowledgment_error":
|
|
7559
|
-
overlay = defaultNotice(
|
|
7560
|
-
"Couldn\u2019t open desktop",
|
|
7561
|
-
acknowledgmentError?.message ?? "The desktop acknowledgment failed.",
|
|
7562
|
-
retryAcknowledgment
|
|
7563
|
-
);
|
|
7564
|
-
break;
|
|
7565
|
-
case "warming":
|
|
7566
|
-
overlay = renderWarming?.() ?? /* @__PURE__ */ jsx11(WarmingNotice, {});
|
|
7567
|
-
break;
|
|
7568
|
-
case "connect_failed":
|
|
7569
|
-
overlay = defaultNotice(
|
|
7570
|
-
"Couldn\u2019t connect",
|
|
7571
|
-
"The desktop is warm but the live stream didn\u2019t come up. This usually clears on a retry.",
|
|
7572
|
-
reconnect
|
|
7573
|
-
);
|
|
7574
|
-
break;
|
|
7575
|
-
case "error":
|
|
7576
|
-
overlay = defaultNotice(
|
|
7577
|
-
"Desktop disconnected",
|
|
7578
|
-
stream.error?.message ?? "The stream dropped.",
|
|
7579
|
-
reconnect
|
|
7580
|
-
);
|
|
7581
|
-
break;
|
|
7582
|
-
case "opening":
|
|
7583
|
-
case "connecting":
|
|
7584
|
-
case "connected":
|
|
7585
|
-
overlay = null;
|
|
7586
|
-
break;
|
|
7587
|
-
}
|
|
7588
|
-
return /* @__PURE__ */ jsxs9(
|
|
7589
|
-
"div",
|
|
7590
|
-
{
|
|
7591
|
-
className: cn(
|
|
7592
|
-
"relative h-full w-full overflow-hidden",
|
|
7593
|
-
inControl && "ring-2 ring-inset ring-og-accent",
|
|
7594
|
-
className
|
|
7595
|
-
),
|
|
7596
|
-
style: { backgroundColor: DESKTOP_MEDIA_BACKGROUND },
|
|
7597
|
-
"data-opengeni-desktop": true,
|
|
7598
|
-
"data-state": stream.state,
|
|
7599
|
-
"data-ui-state": uiState,
|
|
7600
|
-
"data-in-control": inControl ? "true" : void 0,
|
|
7601
|
-
children: [
|
|
7602
|
-
/* @__PURE__ */ jsx11(
|
|
7603
|
-
"div",
|
|
7604
|
-
{
|
|
7605
|
-
ref: containerRef,
|
|
7606
|
-
className: "absolute inset-0 overflow-hidden",
|
|
7607
|
-
"data-opengeni-desktop-canvas": true,
|
|
7608
|
-
"data-state": stream.state
|
|
7609
|
-
}
|
|
7610
|
-
),
|
|
7611
|
-
(uiState === "opening" || uiState === "connecting") && /* @__PURE__ */ jsxs9("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-og-fg-subtle", children: [
|
|
7612
|
-
/* @__PURE__ */ jsxs9("span", { className: "relative flex items-center justify-center", children: [
|
|
7613
|
-
/* @__PURE__ */ jsx11(MonitorIcon, { className: "size-8 opacity-30", strokeWidth: 1.5 }),
|
|
7614
|
-
/* @__PURE__ */ jsx11(
|
|
7615
|
-
LoaderCircleIcon2,
|
|
7616
|
-
{
|
|
7617
|
-
className: "absolute size-12 animate-og-spin text-og-accent opacity-70",
|
|
7618
|
-
strokeWidth: 1.25
|
|
7619
|
-
}
|
|
7620
|
-
)
|
|
7621
|
-
] }),
|
|
7622
|
-
/* @__PURE__ */ jsx11("span", { className: "text-og-sm", children: uiState === "opening" ? "Opening the desktop\u2026" : "Connecting to the desktop\u2026" })
|
|
7623
|
-
] }),
|
|
7624
|
-
showToggle && !externallyControlled && inControl && /* @__PURE__ */ jsx11(
|
|
7625
|
-
InControlBar,
|
|
7626
|
-
{
|
|
7627
|
-
shared: capability?.shared ?? false,
|
|
7628
|
-
onRelease: () => setTakeControl(false)
|
|
7629
|
-
}
|
|
7630
|
-
),
|
|
7631
|
-
showToggle && !externallyControlled && !inControl && connected && /* @__PURE__ */ jsx11(
|
|
7632
|
-
TakeControlCallToAction,
|
|
7633
|
-
{
|
|
7634
|
-
disabled: !serverAllowsControl,
|
|
7635
|
-
disabledReason: !serverAllowsControl ? capability?.client === "frames" ? "View-only \u2014 live control isn't available for this machine yet." : "This deployment streams the desktop read-only." : void 0,
|
|
7636
|
-
onTakeControl: () => setTakeControl(true)
|
|
7637
|
-
}
|
|
7638
|
-
),
|
|
7639
|
-
overlay && /* @__PURE__ */ jsx11("div", { className: "absolute inset-0 flex items-center justify-center p-4", children: overlay })
|
|
7640
|
-
]
|
|
7641
|
-
}
|
|
7642
|
-
);
|
|
7643
|
-
}
|
|
7644
|
-
function TakeControlCallToAction({
|
|
7645
|
-
disabled,
|
|
7646
|
-
disabledReason,
|
|
7647
|
-
onTakeControl
|
|
7648
|
-
}) {
|
|
7649
|
-
return (
|
|
7650
|
-
// The wrapper spans the surface but is click-through (pointer-events-none); only
|
|
7651
|
-
// the button itself is interactive, so watchers can still see the desktop.
|
|
7652
|
-
/* @__PURE__ */ jsx11("div", { className: "pointer-events-none absolute inset-0 flex items-end justify-center pb-[8%]", children: /* @__PURE__ */ jsxs9(
|
|
7653
|
-
"button",
|
|
7654
|
-
{
|
|
7655
|
-
type: "button",
|
|
7656
|
-
disabled,
|
|
7657
|
-
"aria-label": "Take control of the desktop",
|
|
7658
|
-
title: disabled ? disabledReason : "Take control of the desktop",
|
|
7659
|
-
onClick: onTakeControl,
|
|
7660
|
-
className: cn(
|
|
7661
|
-
"group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3",
|
|
7662
|
-
"border-og-border",
|
|
7663
|
-
"bg-og-bg/85 backdrop-blur-md",
|
|
7664
|
-
"shadow-og-lg",
|
|
7665
|
-
"outline-hidden transition-all duration-150 ease-out",
|
|
7666
|
-
"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
|
|
7667
|
-
disabled ? "cursor-not-allowed opacity-60" : cn(
|
|
7668
|
-
"cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100",
|
|
7669
|
-
"hover:border-og-accent",
|
|
7670
|
-
"hover:bg-og-accent/10"
|
|
7671
|
-
)
|
|
7672
|
-
),
|
|
7673
|
-
children: [
|
|
7674
|
-
/* @__PURE__ */ jsx11(
|
|
7675
|
-
"span",
|
|
7676
|
-
{
|
|
7677
|
-
className: cn(
|
|
7678
|
-
"flex size-9 shrink-0 items-center justify-center rounded-full transition-colors",
|
|
7679
|
-
"bg-og-accent",
|
|
7680
|
-
"text-og-accent-fg",
|
|
7681
|
-
disabled ? "" : "group-hover:scale-105"
|
|
7682
|
-
),
|
|
7683
|
-
children: /* @__PURE__ */ jsx11(MousePointerClickIcon, { className: "size-5", strokeWidth: 2 })
|
|
7684
|
-
}
|
|
7685
|
-
),
|
|
7686
|
-
/* @__PURE__ */ jsxs9("span", { className: "flex flex-col items-start leading-tight", children: [
|
|
7687
|
-
/* @__PURE__ */ jsx11("span", { className: "text-og-base font-semibold text-og-fg", children: "Take control" }),
|
|
7688
|
-
/* @__PURE__ */ jsx11("span", { className: "text-og-xs text-og-fg-subtle", children: disabled && disabledReason ? disabledReason : "Drive the mouse & keyboard" })
|
|
7689
|
-
] })
|
|
7690
|
-
]
|
|
7691
|
-
}
|
|
7692
|
-
) })
|
|
7693
|
-
);
|
|
7694
|
-
}
|
|
7695
|
-
function InControlBar({ shared, onRelease }) {
|
|
7696
|
-
return /* @__PURE__ */ jsxs9("div", { className: "pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2", children: [
|
|
7697
|
-
/* @__PURE__ */ jsxs9("span", { className: "pointer-events-auto inline-flex items-center gap-2 rounded-og-sm bg-og-accent px-2.5 py-1 text-og-xs font-medium text-og-accent-fg shadow-og-md", children: [
|
|
7698
|
-
/* @__PURE__ */ jsx11("span", { className: "size-1.5 animate-pulse rounded-full bg-current", "aria-hidden": true }),
|
|
7699
|
-
"You're in control",
|
|
7700
|
-
/* @__PURE__ */ jsx11("span", { className: "opacity-75", children: "\xB7 click Return control (or Ctrl+Alt+Shift)" })
|
|
7701
|
-
] }),
|
|
7702
|
-
/* @__PURE__ */ jsxs9("div", { className: "pointer-events-auto flex items-center gap-1.5", children: [
|
|
7703
|
-
shared && /* @__PURE__ */ jsx11("span", { className: "rounded-og-sm bg-og-status-failed/85 px-2 py-0.5 text-og-xs text-og-accent-fg", children: "Shared sandbox \u2014 others are watching" }),
|
|
7704
|
-
/* @__PURE__ */ jsxs9(
|
|
7705
|
-
"button",
|
|
7706
|
-
{
|
|
7707
|
-
type: "button",
|
|
7708
|
-
onClick: onRelease,
|
|
7709
|
-
title: "Return control (or press Ctrl+Alt+Shift)",
|
|
7710
|
-
className: cn(
|
|
7711
|
-
"inline-flex items-center gap-1.5 rounded-og-sm border px-2.5 py-1 text-og-xs font-semibold shadow-og-md transition-colors",
|
|
7712
|
-
"border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm",
|
|
7713
|
-
"outline-hidden hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
7714
|
-
),
|
|
7715
|
-
children: [
|
|
7716
|
-
/* @__PURE__ */ jsx11(MonitorIcon, { className: "size-3.5", strokeWidth: 2, "aria-hidden": true }),
|
|
7717
|
-
"Return control"
|
|
7718
|
-
]
|
|
7719
|
-
}
|
|
7720
|
-
)
|
|
7721
|
-
] })
|
|
7722
|
-
] });
|
|
7723
|
-
}
|
|
7724
|
-
function unavailableCopy(reason) {
|
|
7725
|
-
switch (reason) {
|
|
7726
|
-
case "backend_unsupported":
|
|
7727
|
-
return "This sandbox backend cannot stream a desktop.";
|
|
7728
|
-
case "tier_headless":
|
|
7729
|
-
return "This deployment is headless \u2014 terminal, files, and diff only.";
|
|
7730
|
-
case "os_unsupported":
|
|
7731
|
-
return "The sandbox OS does not support a desktop stream.";
|
|
7732
|
-
case "not_provisioned":
|
|
7733
|
-
return "This sandbox doesn't have a desktop yet.";
|
|
7734
|
-
case "disabled_by_policy":
|
|
7735
|
-
return "Desktop streaming is disabled on this deployment.";
|
|
7736
|
-
case "lease_cold":
|
|
7737
|
-
return "Waiting for the sandbox to start\u2026";
|
|
7738
|
-
default:
|
|
7739
|
-
return "The desktop isn\u2019t available for this sandbox.";
|
|
7740
|
-
}
|
|
7741
|
-
}
|
|
7742
|
-
function WarmingNotice({ onRetry }) {
|
|
7743
|
-
return /* @__PURE__ */ jsxs9("div", { className: "flex max-w-sm flex-col items-center gap-3 rounded-og-lg border border-og-border bg-og-bg/90 p-5 text-center text-og-base text-og-fg backdrop-blur-sm", children: [
|
|
7744
|
-
/* @__PURE__ */ jsx11(LoaderCircleIcon2, { className: "size-7 animate-og-spin text-og-accent", strokeWidth: 1.5 }),
|
|
7745
|
-
/* @__PURE__ */ jsxs9("div", { className: "space-y-1", children: [
|
|
7746
|
-
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Warming the sandbox\u2026" }),
|
|
7747
|
-
/* @__PURE__ */ jsx11("p", { className: "text-og-sm text-og-fg-subtle", children: "Spinning up the desktop \u2014 this takes a few seconds." })
|
|
7748
|
-
] }),
|
|
7749
|
-
onRetry && /* @__PURE__ */ jsx11(
|
|
7750
|
-
"button",
|
|
7751
|
-
{
|
|
7752
|
-
type: "button",
|
|
7753
|
-
onClick: onRetry,
|
|
7754
|
-
className: "rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm text-og-fg-muted transition-colors hover:text-og-fg pointer-coarse:min-h-11",
|
|
7755
|
-
children: "Taking too long? Retry"
|
|
7756
|
-
}
|
|
7757
|
-
)
|
|
7758
|
-
] });
|
|
7759
|
-
}
|
|
7760
|
-
function defaultNotice(title, body, onRetry) {
|
|
7761
|
-
return /* @__PURE__ */ jsxs9("div", { className: "max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg", children: [
|
|
7762
|
-
/* @__PURE__ */ jsxs9("div", { className: "mb-1 flex items-center justify-center gap-1.5 font-medium", children: [
|
|
7763
|
-
onRetry && /* @__PURE__ */ jsx11(WifiOffIcon, { className: "size-4 opacity-70", strokeWidth: 1.75 }),
|
|
7764
|
-
title
|
|
7765
|
-
] }),
|
|
7766
|
-
/* @__PURE__ */ jsx11("p", { className: "text-og-sm text-og-fg-subtle", children: body }),
|
|
7767
|
-
onRetry && /* @__PURE__ */ jsx11(
|
|
7768
|
-
"button",
|
|
7769
|
-
{
|
|
7770
|
-
type: "button",
|
|
7771
|
-
onClick: onRetry,
|
|
7772
|
-
className: "mt-3 rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm transition-colors hover:border-og-accent pointer-coarse:min-h-11",
|
|
7773
|
-
children: "Reconnect"
|
|
7774
|
-
}
|
|
7775
|
-
)
|
|
7776
|
-
] });
|
|
7777
|
-
}
|
|
7778
|
-
|
|
7779
7327
|
// src/components/workspace-dock.tsx
|
|
7780
7328
|
import {
|
|
7781
|
-
useCallback as
|
|
7782
|
-
useEffect as
|
|
7329
|
+
useCallback as useCallback23,
|
|
7330
|
+
useEffect as useEffect19,
|
|
7783
7331
|
useId as useId4,
|
|
7784
|
-
useLayoutEffect as
|
|
7785
|
-
useRef as
|
|
7786
|
-
useState as
|
|
7332
|
+
useLayoutEffect as useLayoutEffect4,
|
|
7333
|
+
useRef as useRef16,
|
|
7334
|
+
useState as useState16
|
|
7787
7335
|
} from "react";
|
|
7788
7336
|
import {
|
|
7789
7337
|
ChevronsLeftRightIcon,
|
|
@@ -7799,7 +7347,7 @@ import {
|
|
|
7799
7347
|
useDefaultLayout,
|
|
7800
7348
|
usePanelRef
|
|
7801
7349
|
} from "react-resizable-panels";
|
|
7802
|
-
import { Fragment as Fragment4, jsx as
|
|
7350
|
+
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
7803
7351
|
var SERVER_LAYOUT_STORAGE = {
|
|
7804
7352
|
getItem: () => null,
|
|
7805
7353
|
setItem: () => {
|
|
@@ -7813,10 +7361,10 @@ function getLayoutStorage() {
|
|
|
7813
7361
|
return SERVER_LAYOUT_STORAGE;
|
|
7814
7362
|
}
|
|
7815
7363
|
}
|
|
7816
|
-
var useDockLayoutEffect = typeof window === "undefined" ?
|
|
7364
|
+
var useDockLayoutEffect = typeof window === "undefined" ? useEffect19 : useLayoutEffect4;
|
|
7817
7365
|
var DOCK_OVERLAY_BREAKPOINT = 1024;
|
|
7818
7366
|
function useIsNarrow(maxWidth) {
|
|
7819
|
-
const [narrow, setNarrow] =
|
|
7367
|
+
const [narrow, setNarrow] = useState16(false);
|
|
7820
7368
|
useDockLayoutEffect(() => {
|
|
7821
7369
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
7822
7370
|
return;
|
|
@@ -7850,17 +7398,17 @@ function WorkspaceDock({
|
|
|
7850
7398
|
className
|
|
7851
7399
|
}) {
|
|
7852
7400
|
const narrow = useIsNarrow(DOCK_OVERLAY_BREAKPOINT);
|
|
7853
|
-
const rootRef =
|
|
7854
|
-
const reopenRef =
|
|
7855
|
-
const returnFocusRef =
|
|
7856
|
-
const initialNarrowFocusRef =
|
|
7401
|
+
const rootRef = useRef16(null);
|
|
7402
|
+
const reopenRef = useRef16(null);
|
|
7403
|
+
const returnFocusRef = useRef16(null);
|
|
7404
|
+
const initialNarrowFocusRef = useRef16(false);
|
|
7857
7405
|
const dockPanelRef = usePanelRef();
|
|
7858
|
-
const [internalCollapsed, setInternalCollapsed] =
|
|
7859
|
-
const [maximized, setMaximized] =
|
|
7860
|
-
const [internalTab, setInternalTab] =
|
|
7406
|
+
const [internalCollapsed, setInternalCollapsed] = useState16(false);
|
|
7407
|
+
const [maximized, setMaximized] = useState16(false);
|
|
7408
|
+
const [internalTab, setInternalTab] = useState16(tabs[0]?.id ?? "");
|
|
7861
7409
|
const collapsed = collapsedProp ?? internalCollapsed;
|
|
7862
7410
|
const hostControlled = collapsedProp !== void 0;
|
|
7863
|
-
const previousCollapsedRef =
|
|
7411
|
+
const previousCollapsedRef = useRef16(collapsed);
|
|
7864
7412
|
const { defaultLayout, onLayoutChanged } = useDefaultLayout({
|
|
7865
7413
|
panelIds: ["primary", "dock"],
|
|
7866
7414
|
storage: getLayoutStorage(),
|
|
@@ -7871,14 +7419,14 @@ function WorkspaceDock({
|
|
|
7871
7419
|
const firstTabId = tabs[0]?.id ?? "";
|
|
7872
7420
|
const requestedTabIsValid = tabIds.includes(requestedTab);
|
|
7873
7421
|
const current = requestedTabIsValid ? requestedTab : firstTabId;
|
|
7874
|
-
const setTab =
|
|
7422
|
+
const setTab = useCallback23(
|
|
7875
7423
|
(id) => {
|
|
7876
7424
|
setInternalTab(id);
|
|
7877
7425
|
onActiveTabChange?.(id);
|
|
7878
7426
|
},
|
|
7879
7427
|
[onActiveTabChange]
|
|
7880
7428
|
);
|
|
7881
|
-
const setCollapsed =
|
|
7429
|
+
const setCollapsed = useCallback23(
|
|
7882
7430
|
(next) => {
|
|
7883
7431
|
setInternalCollapsed((previous) => previous === next ? previous : next);
|
|
7884
7432
|
onCollapsedChange?.(next);
|
|
@@ -7896,7 +7444,7 @@ function WorkspaceDock({
|
|
|
7896
7444
|
dockPanelRef.current?.expand();
|
|
7897
7445
|
}
|
|
7898
7446
|
}, [collapsedProp, dockPanelRef]);
|
|
7899
|
-
|
|
7447
|
+
useEffect19(() => {
|
|
7900
7448
|
const previous = previousCollapsedRef.current;
|
|
7901
7449
|
previousCollapsedRef.current = collapsed;
|
|
7902
7450
|
if (previous === collapsed) return;
|
|
@@ -7926,7 +7474,7 @@ function WorkspaceDock({
|
|
|
7926
7474
|
});
|
|
7927
7475
|
return () => cancelAnimationFrame(frame);
|
|
7928
7476
|
}, [collapsed, hostControlled, narrow]);
|
|
7929
|
-
|
|
7477
|
+
useEffect19(() => {
|
|
7930
7478
|
if (!narrow || collapsed || initialNarrowFocusRef.current) return;
|
|
7931
7479
|
initialNarrowFocusRef.current = true;
|
|
7932
7480
|
const active = document.activeElement;
|
|
@@ -7939,20 +7487,20 @@ function WorkspaceDock({
|
|
|
7939
7487
|
});
|
|
7940
7488
|
return () => cancelAnimationFrame(frame);
|
|
7941
7489
|
}, [collapsed, narrow]);
|
|
7942
|
-
|
|
7490
|
+
useEffect19(() => {
|
|
7943
7491
|
if (firstTabId && !requestedTabIsValid) {
|
|
7944
7492
|
setTab(firstTabId);
|
|
7945
7493
|
}
|
|
7946
7494
|
}, [firstTabId, requestedTabIsValid, setTab]);
|
|
7947
|
-
const collapse =
|
|
7495
|
+
const collapse = useCallback23(() => {
|
|
7948
7496
|
dockPanelRef.current?.collapse();
|
|
7949
7497
|
setCollapsed(true);
|
|
7950
7498
|
}, [dockPanelRef, setCollapsed]);
|
|
7951
|
-
const expand =
|
|
7499
|
+
const expand = useCallback23(() => {
|
|
7952
7500
|
dockPanelRef.current?.expand();
|
|
7953
7501
|
setCollapsed(false);
|
|
7954
7502
|
}, [dockPanelRef, setCollapsed]);
|
|
7955
|
-
|
|
7503
|
+
useEffect19(() => {
|
|
7956
7504
|
const overlayOpen = maximized || narrow && !collapsed;
|
|
7957
7505
|
if (!overlayOpen) return;
|
|
7958
7506
|
const onKey = (event) => {
|
|
@@ -7996,8 +7544,8 @@ function WorkspaceDock({
|
|
|
7996
7544
|
return () => window.removeEventListener("keydown", onKey);
|
|
7997
7545
|
}, [maximized, narrow, collapsed, collapse]);
|
|
7998
7546
|
if (narrow) {
|
|
7999
|
-
return /* @__PURE__ */
|
|
8000
|
-
/* @__PURE__ */
|
|
7547
|
+
return /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
7548
|
+
/* @__PURE__ */ jsx11(
|
|
8001
7549
|
"div",
|
|
8002
7550
|
{
|
|
8003
7551
|
"data-workspace-primary": true,
|
|
@@ -8007,7 +7555,7 @@ function WorkspaceDock({
|
|
|
8007
7555
|
children: primary
|
|
8008
7556
|
}
|
|
8009
7557
|
),
|
|
8010
|
-
/* @__PURE__ */
|
|
7558
|
+
/* @__PURE__ */ jsx11(
|
|
8011
7559
|
"div",
|
|
8012
7560
|
{
|
|
8013
7561
|
"data-workspace-surface": true,
|
|
@@ -8025,7 +7573,7 @@ function WorkspaceDock({
|
|
|
8025
7573
|
paddingTop: "env(safe-area-inset-top)",
|
|
8026
7574
|
paddingBottom: "env(safe-area-inset-bottom)"
|
|
8027
7575
|
},
|
|
8028
|
-
children: /* @__PURE__ */
|
|
7576
|
+
children: /* @__PURE__ */ jsx11(
|
|
8029
7577
|
DockChrome,
|
|
8030
7578
|
{
|
|
8031
7579
|
tabs,
|
|
@@ -8033,12 +7581,12 @@ function WorkspaceDock({
|
|
|
8033
7581
|
onTab: setTab,
|
|
8034
7582
|
leading: mobileLeadingControl,
|
|
8035
7583
|
accessory: headerAccessory,
|
|
8036
|
-
controls: /* @__PURE__ */
|
|
7584
|
+
controls: /* @__PURE__ */ jsx11(ChromeButton, { onClick: collapse, title: "Close workspace", label: "Close workspace", children: /* @__PURE__ */ jsx11(XIcon2, { className: "size-4" }) })
|
|
8037
7585
|
}
|
|
8038
7586
|
)
|
|
8039
7587
|
}
|
|
8040
7588
|
),
|
|
8041
|
-
collapsed && !hostControlled ? /* @__PURE__ */
|
|
7589
|
+
collapsed && !hostControlled ? /* @__PURE__ */ jsx11(
|
|
8042
7590
|
"button",
|
|
8043
7591
|
{
|
|
8044
7592
|
ref: reopenRef,
|
|
@@ -8048,34 +7596,34 @@ function WorkspaceDock({
|
|
|
8048
7596
|
"aria-label": "Open workspace",
|
|
8049
7597
|
className: "absolute right-3 top-3 z-30 inline-flex size-11 items-center justify-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted shadow-lg transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent",
|
|
8050
7598
|
style: { marginTop: "env(safe-area-inset-top)" },
|
|
8051
|
-
children: /* @__PURE__ */
|
|
7599
|
+
children: /* @__PURE__ */ jsx11(ChevronsLeftRightIcon, { className: "size-4", "aria-hidden": true })
|
|
8052
7600
|
}
|
|
8053
7601
|
) : null
|
|
8054
7602
|
] });
|
|
8055
7603
|
}
|
|
8056
|
-
const dockChrome = /* @__PURE__ */
|
|
7604
|
+
const dockChrome = /* @__PURE__ */ jsx11(
|
|
8057
7605
|
DockChrome,
|
|
8058
7606
|
{
|
|
8059
7607
|
tabs,
|
|
8060
7608
|
current,
|
|
8061
7609
|
onTab: setTab,
|
|
8062
7610
|
accessory: headerAccessory,
|
|
8063
|
-
controls: /* @__PURE__ */
|
|
8064
|
-
/* @__PURE__ */
|
|
7611
|
+
controls: /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
7612
|
+
/* @__PURE__ */ jsx11(
|
|
8065
7613
|
ChromeButton,
|
|
8066
7614
|
{
|
|
8067
7615
|
onClick: () => setMaximized((m) => !m),
|
|
8068
7616
|
title: maximized ? "Restore (Esc)" : "Maximize",
|
|
8069
7617
|
label: maximized ? "Restore dock" : "Maximize dock",
|
|
8070
|
-
children: maximized ? /* @__PURE__ */
|
|
7618
|
+
children: maximized ? /* @__PURE__ */ jsx11(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx11(Maximize2Icon, { className: "size-3.5" })
|
|
8071
7619
|
}
|
|
8072
7620
|
),
|
|
8073
|
-
hostControlled && !showCollapseControl ? null : /* @__PURE__ */
|
|
7621
|
+
hostControlled && !showCollapseControl ? null : /* @__PURE__ */ jsx11(ChromeButton, { onClick: collapse, title: "Collapse", label: "Collapse dock", children: /* @__PURE__ */ jsx11(PanelRightCloseIcon, { className: "size-3.5" }) })
|
|
8074
7622
|
] })
|
|
8075
7623
|
}
|
|
8076
7624
|
);
|
|
8077
|
-
return /* @__PURE__ */
|
|
8078
|
-
/* @__PURE__ */
|
|
7625
|
+
return /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
7626
|
+
/* @__PURE__ */ jsxs9(
|
|
8079
7627
|
Group2,
|
|
8080
7628
|
{
|
|
8081
7629
|
orientation: "horizontal",
|
|
@@ -8083,7 +7631,7 @@ function WorkspaceDock({
|
|
|
8083
7631
|
...defaultLayout ? { defaultLayout } : {},
|
|
8084
7632
|
onLayoutChanged,
|
|
8085
7633
|
children: [
|
|
8086
|
-
/* @__PURE__ */
|
|
7634
|
+
/* @__PURE__ */ jsx11(Panel2, { id: "primary", minSize: "30%", className: "min-h-0 min-w-0", children: /* @__PURE__ */ jsx11(
|
|
8087
7635
|
"div",
|
|
8088
7636
|
{
|
|
8089
7637
|
"data-workspace-primary": true,
|
|
@@ -8093,8 +7641,8 @@ function WorkspaceDock({
|
|
|
8093
7641
|
children: primary
|
|
8094
7642
|
}
|
|
8095
7643
|
) }),
|
|
8096
|
-
!collapsed && /* @__PURE__ */
|
|
8097
|
-
/* @__PURE__ */
|
|
7644
|
+
!collapsed && /* @__PURE__ */ jsx11(Separator2, { className: "group relative z-10 w-1.5 shrink-0 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent max-[1023px]:-mx-[19px] max-[1023px]:w-11 pointer-coarse:-mx-[19px] pointer-coarse:w-11", children: /* @__PURE__ */ jsx11("span", { className: "absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-og-border transition-colors group-hover:bg-og-accent group-focus-visible:bg-og-accent group-data-[separator-state=dragging]:bg-og-accent" }) }),
|
|
7645
|
+
/* @__PURE__ */ jsx11(
|
|
8098
7646
|
Panel2,
|
|
8099
7647
|
{
|
|
8100
7648
|
id: "dock",
|
|
@@ -8112,7 +7660,7 @@ function WorkspaceDock({
|
|
|
8112
7660
|
}
|
|
8113
7661
|
},
|
|
8114
7662
|
className: "min-h-0 min-w-0",
|
|
8115
|
-
children: /* @__PURE__ */
|
|
7663
|
+
children: /* @__PURE__ */ jsx11(
|
|
8116
7664
|
"div",
|
|
8117
7665
|
{
|
|
8118
7666
|
"data-workspace-surface": true,
|
|
@@ -8133,7 +7681,7 @@ function WorkspaceDock({
|
|
|
8133
7681
|
]
|
|
8134
7682
|
}
|
|
8135
7683
|
),
|
|
8136
|
-
collapsed && !maximized && !hostControlled && /* @__PURE__ */
|
|
7684
|
+
collapsed && !maximized && !hostControlled && /* @__PURE__ */ jsx11(
|
|
8137
7685
|
"button",
|
|
8138
7686
|
{
|
|
8139
7687
|
ref: reopenRef,
|
|
@@ -8141,7 +7689,7 @@ function WorkspaceDock({
|
|
|
8141
7689
|
onClick: expand,
|
|
8142
7690
|
title: "Open workspace",
|
|
8143
7691
|
className: "absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-og-border bg-og-surface-1 text-og-fg-subtle hover:text-og-fg",
|
|
8144
|
-
children: /* @__PURE__ */
|
|
7692
|
+
children: /* @__PURE__ */ jsx11(ChevronsLeftRightIcon, { className: "size-3.5" })
|
|
8145
7693
|
}
|
|
8146
7694
|
)
|
|
8147
7695
|
] });
|
|
@@ -8152,7 +7700,7 @@ function ChromeButton({
|
|
|
8152
7700
|
label,
|
|
8153
7701
|
children
|
|
8154
7702
|
}) {
|
|
8155
|
-
return /* @__PURE__ */
|
|
7703
|
+
return /* @__PURE__ */ jsx11(
|
|
8156
7704
|
"button",
|
|
8157
7705
|
{
|
|
8158
7706
|
type: "button",
|
|
@@ -8172,19 +7720,38 @@ function DockChrome({
|
|
|
8172
7720
|
accessory,
|
|
8173
7721
|
controls
|
|
8174
7722
|
}) {
|
|
7723
|
+
const chromeRef = useRef16(null);
|
|
7724
|
+
const [compact, setCompact] = useState16(false);
|
|
8175
7725
|
const active = tabs.find((t) => t.id === current) ?? tabs[0];
|
|
8176
7726
|
const tabsetId = useId4();
|
|
8177
|
-
const tabRefs =
|
|
8178
|
-
const tabListRef =
|
|
8179
|
-
const [visitedTabs, setVisitedTabs] =
|
|
8180
|
-
const [tabOverflow, setTabOverflow] =
|
|
7727
|
+
const tabRefs = useRef16([]);
|
|
7728
|
+
const tabListRef = useRef16(null);
|
|
7729
|
+
const [visitedTabs, setVisitedTabs] = useState16(() => /* @__PURE__ */ new Set());
|
|
7730
|
+
const [tabOverflow, setTabOverflow] = useState16({ start: false, end: false });
|
|
8181
7731
|
const activeId = active?.id ?? "";
|
|
8182
7732
|
const activeTabIndex = tabs.findIndex((tab) => tab.id === activeId);
|
|
8183
|
-
|
|
7733
|
+
useDockLayoutEffect(() => {
|
|
7734
|
+
const node = chromeRef.current;
|
|
7735
|
+
if (!node) return;
|
|
7736
|
+
const update = () => {
|
|
7737
|
+
const desktop = typeof window.matchMedia !== "function" || window.matchMedia("(min-width: 1024px)").matches;
|
|
7738
|
+
const next = desktop && node.getBoundingClientRect().width < 420;
|
|
7739
|
+
setCompact((previous) => previous === next ? previous : next);
|
|
7740
|
+
};
|
|
7741
|
+
update();
|
|
7742
|
+
if (typeof ResizeObserver === "undefined") {
|
|
7743
|
+
window.addEventListener("resize", update);
|
|
7744
|
+
return () => window.removeEventListener("resize", update);
|
|
7745
|
+
}
|
|
7746
|
+
const observer = new ResizeObserver(update);
|
|
7747
|
+
observer.observe(node);
|
|
7748
|
+
return () => observer.disconnect();
|
|
7749
|
+
}, []);
|
|
7750
|
+
const keepActiveTabVisible = useCallback23(() => {
|
|
8184
7751
|
const selected = activeTabIndex >= 0 ? tabRefs.current[activeTabIndex] : null;
|
|
8185
7752
|
selected?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
8186
7753
|
}, [activeTabIndex]);
|
|
8187
|
-
|
|
7754
|
+
useEffect19(() => {
|
|
8188
7755
|
if (!activeId) return;
|
|
8189
7756
|
setVisitedTabs((previous) => {
|
|
8190
7757
|
if (previous.has(activeId)) return previous;
|
|
@@ -8241,55 +7808,98 @@ function DockChrome({
|
|
|
8241
7808
|
event.preventDefault();
|
|
8242
7809
|
activateTab(nextIndex);
|
|
8243
7810
|
};
|
|
8244
|
-
return /* @__PURE__ */
|
|
8245
|
-
/* @__PURE__ */
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
"
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
7811
|
+
return /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
7812
|
+
/* @__PURE__ */ jsxs9(
|
|
7813
|
+
"div",
|
|
7814
|
+
{
|
|
7815
|
+
ref: chromeRef,
|
|
7816
|
+
"data-dock-chrome": true,
|
|
7817
|
+
"data-compact": compact ? "true" : void 0,
|
|
7818
|
+
className: cn(
|
|
7819
|
+
"grid shrink-0 grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-2 border-b border-og-border px-1.5 py-1 max-[1023px]:grid-cols-[auto_minmax(0,1fr)_auto] max-[1023px]:gap-y-0 max-[1023px]:px-2 max-[1023px]:pb-1 max-[1023px]:pt-0 min-[640px]:max-[1023px]:grid-cols-[auto_minmax(0,1fr)_auto_auto]",
|
|
7820
|
+
compact && "gap-y-1"
|
|
7821
|
+
),
|
|
7822
|
+
style: compact ? { gridTemplateColumns: "minmax(0, 1fr) auto" } : void 0,
|
|
7823
|
+
children: [
|
|
7824
|
+
/* @__PURE__ */ jsx11(
|
|
7825
|
+
"div",
|
|
7826
|
+
{
|
|
7827
|
+
className: cn(
|
|
7828
|
+
"flex min-w-0 shrink-0 items-center max-[1023px]:min-h-11 min-[640px]:max-[1023px]:col-start-1 min-[640px]:max-[1023px]:row-start-1",
|
|
7829
|
+
compact && "hidden"
|
|
7830
|
+
),
|
|
7831
|
+
children: leading ?? /* @__PURE__ */ jsx11("span", { className: "hidden truncate px-1 text-og-sm font-semibold text-og-fg max-[1023px]:inline", children: "Workspace" })
|
|
7832
|
+
}
|
|
7833
|
+
),
|
|
7834
|
+
/* @__PURE__ */ jsx11(
|
|
7835
|
+
"div",
|
|
8261
7836
|
{
|
|
8262
|
-
ref:
|
|
8263
|
-
|
|
7837
|
+
ref: tabListRef,
|
|
7838
|
+
className: cn(
|
|
7839
|
+
"flex min-w-0 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden max-[1023px]:col-span-3 max-[1023px]:row-start-2 max-[1023px]:w-full min-[640px]:max-[1023px]:col-span-1 min-[640px]:max-[1023px]:col-start-2 min-[640px]:max-[1023px]:row-start-1",
|
|
7840
|
+
compact && "col-span-2 col-start-1 row-start-2 w-full"
|
|
7841
|
+
),
|
|
7842
|
+
role: "tablist",
|
|
7843
|
+
"aria-orientation": "horizontal",
|
|
7844
|
+
style: {
|
|
7845
|
+
maskImage: tabMask,
|
|
7846
|
+
WebkitMaskImage: tabMask,
|
|
7847
|
+
scrollPaddingInline: "16px"
|
|
8264
7848
|
},
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
7849
|
+
children: tabs.map((tab, index) => /* @__PURE__ */ jsxs9(
|
|
7850
|
+
"button",
|
|
7851
|
+
{
|
|
7852
|
+
ref: (node) => {
|
|
7853
|
+
tabRefs.current[index] = node;
|
|
7854
|
+
},
|
|
7855
|
+
id: `${tabsetId}-tab-${index}`,
|
|
7856
|
+
type: "button",
|
|
7857
|
+
role: "tab",
|
|
7858
|
+
"aria-selected": tab.id === current,
|
|
7859
|
+
"aria-controls": `${tabsetId}-panel-${index}`,
|
|
7860
|
+
tabIndex: tab.id === current ? 0 : -1,
|
|
7861
|
+
onClick: () => onTab(tab.id),
|
|
7862
|
+
onKeyDown: (event) => onTabKeyDown(event, index),
|
|
7863
|
+
className: cn(
|
|
7864
|
+
"flex min-h-7 shrink-0 items-center justify-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
|
|
7865
|
+
tab.id === current ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
7866
|
+
),
|
|
7867
|
+
children: [
|
|
7868
|
+
/* @__PURE__ */ jsx11("span", { "data-contrast-audited": true, children: tab.label }),
|
|
7869
|
+
tab.badge
|
|
7870
|
+
]
|
|
7871
|
+
},
|
|
7872
|
+
tab.id
|
|
7873
|
+
))
|
|
7874
|
+
}
|
|
7875
|
+
),
|
|
7876
|
+
/* @__PURE__ */ jsx11(
|
|
7877
|
+
"div",
|
|
7878
|
+
{
|
|
8273
7879
|
className: cn(
|
|
8274
|
-
"flex min-
|
|
8275
|
-
|
|
7880
|
+
"flex min-w-0 shrink-0 items-center justify-self-end min-[640px]:max-[1023px]:col-start-3 min-[640px]:max-[1023px]:row-start-1",
|
|
7881
|
+
compact && "col-start-1 row-start-1 justify-self-start"
|
|
8276
7882
|
),
|
|
8277
|
-
children:
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
7883
|
+
children: accessory
|
|
7884
|
+
}
|
|
7885
|
+
),
|
|
7886
|
+
/* @__PURE__ */ jsx11(
|
|
7887
|
+
"div",
|
|
7888
|
+
{
|
|
7889
|
+
className: cn(
|
|
7890
|
+
"flex shrink-0 items-center gap-0.5 text-og-fg-subtle min-[640px]:max-[1023px]:col-start-4 min-[640px]:max-[1023px]:row-start-1",
|
|
7891
|
+
compact && "col-start-2 row-start-1"
|
|
7892
|
+
),
|
|
7893
|
+
children: controls
|
|
7894
|
+
}
|
|
7895
|
+
)
|
|
7896
|
+
]
|
|
7897
|
+
}
|
|
7898
|
+
),
|
|
7899
|
+
/* @__PURE__ */ jsx11("div", { className: "min-h-0 min-w-0 flex-1 overflow-hidden", children: tabs.length > 0 ? tabs.map((tab, index) => {
|
|
8290
7900
|
const selected = tab.id === activeId;
|
|
8291
7901
|
const shouldMount = selected || visitedTabs.has(tab.id);
|
|
8292
|
-
return /* @__PURE__ */
|
|
7902
|
+
return /* @__PURE__ */ jsx11(
|
|
8293
7903
|
"div",
|
|
8294
7904
|
{
|
|
8295
7905
|
id: `${tabsetId}-panel-${index}`,
|
|
@@ -8301,7 +7911,7 @@ function DockChrome({
|
|
|
8301
7911
|
},
|
|
8302
7912
|
tab.id
|
|
8303
7913
|
);
|
|
8304
|
-
}) : /* @__PURE__ */
|
|
7914
|
+
}) : /* @__PURE__ */ jsx11("div", { className: "h-full min-h-0 min-w-0", "aria-label": "Workspace", role: "tabpanel" }) })
|
|
8305
7915
|
] });
|
|
8306
7916
|
}
|
|
8307
7917
|
|
|
@@ -8309,11 +7919,11 @@ function DockChrome({
|
|
|
8309
7919
|
import {
|
|
8310
7920
|
lazy as lazy2,
|
|
8311
7921
|
Suspense as Suspense2,
|
|
8312
|
-
useCallback as
|
|
8313
|
-
useEffect as
|
|
7922
|
+
useCallback as useCallback24,
|
|
7923
|
+
useEffect as useEffect20,
|
|
8314
7924
|
useMemo as useMemo13,
|
|
8315
|
-
useRef as
|
|
8316
|
-
useState as
|
|
7925
|
+
useRef as useRef17,
|
|
7926
|
+
useState as useState17
|
|
8317
7927
|
} from "react";
|
|
8318
7928
|
import {
|
|
8319
7929
|
CircleCheckIcon,
|
|
@@ -8321,19 +7931,19 @@ import {
|
|
|
8321
7931
|
FileCode2Icon as FileCode2Icon2,
|
|
8322
7932
|
GitCompareArrowsIcon,
|
|
8323
7933
|
Globe2Icon,
|
|
8324
|
-
LoaderCircleIcon as
|
|
8325
|
-
MonitorIcon
|
|
7934
|
+
LoaderCircleIcon as LoaderCircleIcon2,
|
|
7935
|
+
MonitorIcon,
|
|
8326
7936
|
RefreshCwIcon as RefreshCwIcon2,
|
|
8327
7937
|
SquareTerminalIcon,
|
|
8328
7938
|
TriangleAlertIcon as TriangleAlertIcon2
|
|
8329
7939
|
} from "lucide-react";
|
|
8330
|
-
import { jsx as
|
|
7940
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
8331
7941
|
var LazyBrowserViewer = lazy2(async () => {
|
|
8332
|
-
const viewers = await import("./interactive-workbench-viewers-
|
|
7942
|
+
const viewers = await import("./interactive-workbench-viewers-TOHBXJEE.js");
|
|
8333
7943
|
return { default: viewers.BrowserViewer };
|
|
8334
7944
|
});
|
|
8335
7945
|
var LazyComputerViewer = lazy2(async () => {
|
|
8336
|
-
const viewers = await import("./interactive-workbench-viewers-
|
|
7946
|
+
const viewers = await import("./interactive-workbench-viewers-TOHBXJEE.js");
|
|
8337
7947
|
return { default: viewers.ComputerViewer };
|
|
8338
7948
|
});
|
|
8339
7949
|
var WORKBENCH_TAB_CHANGES = "changes";
|
|
@@ -8370,17 +7980,17 @@ function captureDegradedMessage(reason) {
|
|
|
8370
7980
|
}
|
|
8371
7981
|
}
|
|
8372
7982
|
function WorkbenchTabLabel({ icon, children }) {
|
|
8373
|
-
return /* @__PURE__ */
|
|
8374
|
-
/* @__PURE__ */
|
|
8375
|
-
/* @__PURE__ */
|
|
7983
|
+
return /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
7984
|
+
/* @__PURE__ */ jsx12("span", { className: "[&>svg]:size-3.5", "aria-hidden": true, children: icon }),
|
|
7985
|
+
/* @__PURE__ */ jsx12("span", { children })
|
|
8376
7986
|
] });
|
|
8377
7987
|
}
|
|
8378
7988
|
function WorkbenchSurfaceLoading({ name }) {
|
|
8379
|
-
return /* @__PURE__ */
|
|
7989
|
+
return /* @__PURE__ */ jsx12(
|
|
8380
7990
|
CenteredState,
|
|
8381
7991
|
{
|
|
8382
|
-
icon: /* @__PURE__ */
|
|
8383
|
-
children: /* @__PURE__ */
|
|
7992
|
+
icon: /* @__PURE__ */ jsx12(LoaderCircleIcon2, { className: "size-5 animate-spin motion-reduce:animate-none", "aria-hidden": true }),
|
|
7993
|
+
children: /* @__PURE__ */ jsxs10("p", { className: "text-og-sm font-medium text-og-fg", children: [
|
|
8384
7994
|
"Opening ",
|
|
8385
7995
|
name
|
|
8386
7996
|
] })
|
|
@@ -8435,7 +8045,7 @@ function emptyWarmIntents(sessionId) {
|
|
|
8435
8045
|
};
|
|
8436
8046
|
}
|
|
8437
8047
|
function useSandboxWorkspaceTabs(options) {
|
|
8438
|
-
const { client, workspaceId } = useOpenGeni(options);
|
|
8048
|
+
const { client, workspaceId, workspaceInteractionEvent } = useOpenGeni(options);
|
|
8439
8049
|
const {
|
|
8440
8050
|
sessionId,
|
|
8441
8051
|
events,
|
|
@@ -8451,6 +8061,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8451
8061
|
} = options;
|
|
8452
8062
|
const initialTab = options.initialTab ?? null;
|
|
8453
8063
|
const activeTab = options.activeTab ?? initialTab;
|
|
8064
|
+
const workspaceVisible = options.workspaceVisible ?? true;
|
|
8454
8065
|
const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;
|
|
8455
8066
|
const surfaceSet = new Set(requestedSurfaces);
|
|
8456
8067
|
const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);
|
|
@@ -8458,13 +8069,17 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8458
8069
|
const terminalEnabled = surfaceSet.has(WORKBENCH_TAB_TERMINAL);
|
|
8459
8070
|
const browserEnabled = surfaceSet.has(WORKBENCH_TAB_BROWSER);
|
|
8460
8071
|
const desktopEnabled = surfaceSet.has(WORKBENCH_TAB_DESKTOP);
|
|
8461
|
-
const createLinkedComputer =
|
|
8462
|
-
async (name) => {
|
|
8072
|
+
const createLinkedComputer = useCallback24(
|
|
8073
|
+
async (name, placement) => {
|
|
8463
8074
|
const response = await client.createComputerSession(workspaceId, {
|
|
8464
8075
|
operationId: crypto.randomUUID(),
|
|
8465
8076
|
sessionId,
|
|
8466
|
-
name
|
|
8077
|
+
name,
|
|
8078
|
+
...placement ? { placement } : {}
|
|
8467
8079
|
});
|
|
8080
|
+
if (response.operation.state !== "completed" || response.session.lifecycle !== "active") {
|
|
8081
|
+
throw new Error(response.operation.error?.message ?? "The computer could not be opened.");
|
|
8082
|
+
}
|
|
8468
8083
|
return {
|
|
8469
8084
|
id: response.session.id,
|
|
8470
8085
|
placement: response.session.placement
|
|
@@ -8478,12 +8093,12 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8478
8093
|
const changesActive = resolvedActiveTab === WORKBENCH_TAB_CHANGES;
|
|
8479
8094
|
const filesActive = resolvedActiveTab === WORKBENCH_TAB_FILES;
|
|
8480
8095
|
const surfaceIdentity = WORKBENCH_SURFACES.filter((surface) => surfaceSet.has(surface)).join(",");
|
|
8481
|
-
const [storedWarmIntents, setStoredWarmIntents] =
|
|
8096
|
+
const [storedWarmIntents, setStoredWarmIntents] = useState17(
|
|
8482
8097
|
() => emptyWarmIntents(sessionId)
|
|
8483
8098
|
);
|
|
8484
8099
|
const warmIntents = storedWarmIntents.sessionId === sessionId ? storedWarmIntents : emptyWarmIntents(sessionId);
|
|
8485
8100
|
const { warmTerminal, warmFiles } = warmIntents;
|
|
8486
|
-
const requestWarmIntent =
|
|
8101
|
+
const requestWarmIntent = useCallback24(
|
|
8487
8102
|
(intent) => {
|
|
8488
8103
|
setStoredWarmIntents((previous) => {
|
|
8489
8104
|
const current = previous.sessionId === sessionId ? previous : emptyWarmIntents(sessionId);
|
|
@@ -8524,14 +8139,18 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8524
8139
|
});
|
|
8525
8140
|
const provisioning = sandboxProvisionInFlight(events);
|
|
8526
8141
|
const renegotiate = caps.renegotiate;
|
|
8527
|
-
const provisioningRef =
|
|
8528
|
-
|
|
8142
|
+
const provisioningRef = useRef17({ sessionId, provisioning });
|
|
8143
|
+
useEffect20(() => {
|
|
8529
8144
|
const previous = provisioningRef.current;
|
|
8530
8145
|
if (previous.sessionId === sessionId && previous.provisioning && !provisioning) {
|
|
8531
8146
|
renegotiate();
|
|
8532
8147
|
}
|
|
8533
8148
|
provisioningRef.current = { sessionId, provisioning };
|
|
8534
8149
|
}, [sessionId, provisioning, renegotiate]);
|
|
8150
|
+
useEffect20(() => {
|
|
8151
|
+
if (workspaceInteractionEvent?.workspaceId !== workspaceId) return;
|
|
8152
|
+
renegotiate();
|
|
8153
|
+
}, [workspaceId, workspaceInteractionEvent, renegotiate]);
|
|
8535
8154
|
const captureState = useWorkspaceCapture(sessionId, {
|
|
8536
8155
|
events,
|
|
8537
8156
|
enabled: workspaceDataEnabled
|
|
@@ -8544,14 +8163,14 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8544
8163
|
if (advertised.length > 0) return advertised;
|
|
8545
8164
|
return captureState.capture?.repos.map((repo) => repo.root) ?? [];
|
|
8546
8165
|
}, [capabilities?.Git.repos, captureState.capture]);
|
|
8547
|
-
const notifiedCaptureDegradedReason =
|
|
8166
|
+
const notifiedCaptureDegradedReason = useRef17({
|
|
8548
8167
|
sessionId,
|
|
8549
8168
|
reason: null
|
|
8550
8169
|
});
|
|
8551
8170
|
if (notifiedCaptureDegradedReason.current.sessionId !== sessionId) {
|
|
8552
8171
|
notifiedCaptureDegradedReason.current = { sessionId, reason: null };
|
|
8553
8172
|
}
|
|
8554
|
-
|
|
8173
|
+
useEffect20(() => {
|
|
8555
8174
|
const reason = captureState.degradedReason;
|
|
8556
8175
|
if (!reason || notifiedCaptureDegradedReason.current.reason === reason) return;
|
|
8557
8176
|
notifiedCaptureDegradedReason.current = { sessionId, reason };
|
|
@@ -8573,10 +8192,10 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8573
8192
|
message: `Could not ${op}: ${error.message}`
|
|
8574
8193
|
})
|
|
8575
8194
|
});
|
|
8576
|
-
const [storedChangesComparison, setStoredChangesComparison] =
|
|
8195
|
+
const [storedChangesComparison, setStoredChangesComparison] = useState17(null);
|
|
8577
8196
|
const captureSupportsBranch = captureState.capture !== null && captureState.capture.repos.length > 0 && captureState.capture.repos.every((repo) => repo.branchDiff !== void 0);
|
|
8578
8197
|
const changesComparison = storedChangesComparison?.sessionId === sessionId ? storedChangesComparison.value : liveWorkspaceExpected || captureSupportsBranch ? "branch" : "working";
|
|
8579
|
-
const setChangesComparison =
|
|
8198
|
+
const setChangesComparison = useCallback24(
|
|
8580
8199
|
(value) => setStoredChangesComparison({ sessionId, value }),
|
|
8581
8200
|
[sessionId]
|
|
8582
8201
|
);
|
|
@@ -8592,13 +8211,13 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8592
8211
|
comparison: changesComparison,
|
|
8593
8212
|
capture: changesComparison === "staged" ? null : captureState.capture
|
|
8594
8213
|
});
|
|
8595
|
-
|
|
8214
|
+
useEffect20(() => {
|
|
8596
8215
|
if (changesComparison === "branch" && git.error && storedChangesComparison?.sessionId !== sessionId) {
|
|
8597
8216
|
setStoredChangesComparison({ sessionId, value: "working" });
|
|
8598
8217
|
}
|
|
8599
8218
|
}, [changesComparison, git.error, sessionId, storedChangesComparison?.sessionId]);
|
|
8600
|
-
const [xtermTheme, setXtermTheme] =
|
|
8601
|
-
|
|
8219
|
+
const [xtermTheme, setXtermTheme] = useState17(void 0);
|
|
8220
|
+
useEffect20(() => {
|
|
8602
8221
|
if (!terminalEnabled || typeof document === "undefined") return;
|
|
8603
8222
|
const derive = () => setXtermTheme(xtermThemeFromTokens());
|
|
8604
8223
|
derive();
|
|
@@ -8620,7 +8239,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8620
8239
|
});
|
|
8621
8240
|
const workspaceWaking = chip.state === "waking";
|
|
8622
8241
|
const defaultIdentity = `${sessionId}\0${surfaceIdentity}`;
|
|
8623
|
-
const defaultTabRef =
|
|
8242
|
+
const defaultTabRef = useRef17({
|
|
8624
8243
|
identity: defaultIdentity,
|
|
8625
8244
|
value: null
|
|
8626
8245
|
});
|
|
@@ -8668,9 +8287,9 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8668
8287
|
if (changesEnabled)
|
|
8669
8288
|
list.push({
|
|
8670
8289
|
id: WORKBENCH_TAB_CHANGES,
|
|
8671
|
-
label: /* @__PURE__ */
|
|
8672
|
-
badge: dirtyCount > 0 ? /* @__PURE__ */
|
|
8673
|
-
content: /* @__PURE__ */
|
|
8290
|
+
label: /* @__PURE__ */ jsx12(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx12(GitCompareArrowsIcon, {}), children: "Changes" }),
|
|
8291
|
+
badge: dirtyCount > 0 ? /* @__PURE__ */ jsx12(DirtyBadge, { count: dirtyCount }) : void 0,
|
|
8292
|
+
content: /* @__PURE__ */ jsx12(
|
|
8674
8293
|
ChangesTabBody,
|
|
8675
8294
|
{
|
|
8676
8295
|
git,
|
|
@@ -8697,8 +8316,8 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8697
8316
|
if (filesEnabled)
|
|
8698
8317
|
list.push({
|
|
8699
8318
|
id: WORKBENCH_TAB_FILES,
|
|
8700
|
-
label: /* @__PURE__ */
|
|
8701
|
-
content: /* @__PURE__ */
|
|
8319
|
+
label: /* @__PURE__ */ jsx12(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx12(FileCode2Icon2, {}), children: "Files" }),
|
|
8320
|
+
content: /* @__PURE__ */ jsx12(
|
|
8702
8321
|
SandboxFiles,
|
|
8703
8322
|
{
|
|
8704
8323
|
files,
|
|
@@ -8723,13 +8342,14 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8723
8342
|
if (terminalOn) {
|
|
8724
8343
|
list.push({
|
|
8725
8344
|
id: WORKBENCH_TAB_TERMINAL,
|
|
8726
|
-
label: /* @__PURE__ */
|
|
8727
|
-
content: /* @__PURE__ */
|
|
8345
|
+
label: /* @__PURE__ */ jsx12(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx12(SquareTerminalIcon, {}), children: "Terminal" }),
|
|
8346
|
+
content: /* @__PURE__ */ jsx12("div", { className: "h-full bg-og-bg p-1", children: /* @__PURE__ */ jsx12(
|
|
8728
8347
|
SandboxTerminal,
|
|
8729
8348
|
{
|
|
8730
8349
|
result: terminal,
|
|
8731
8350
|
terminalCapability: capabilities?.Terminal ?? null,
|
|
8732
8351
|
onActivate: () => requestWarmIntent("warmTerminal"),
|
|
8352
|
+
onReconnectNeeded: caps.renegotiate,
|
|
8733
8353
|
showHeader: true,
|
|
8734
8354
|
shell: capabilities?.Terminal.shell ?? void 0,
|
|
8735
8355
|
liveness,
|
|
@@ -8742,13 +8362,14 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8742
8362
|
if (browserEnabled) {
|
|
8743
8363
|
list.push({
|
|
8744
8364
|
id: WORKBENCH_TAB_BROWSER,
|
|
8745
|
-
label: /* @__PURE__ */
|
|
8746
|
-
content: /* @__PURE__ */
|
|
8365
|
+
label: /* @__PURE__ */ jsx12(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx12(Globe2Icon, {}), children: "Browser" }),
|
|
8366
|
+
content: /* @__PURE__ */ jsx12(Suspense2, { fallback: /* @__PURE__ */ jsx12(WorkbenchSurfaceLoading, { name: "Browser" }), children: /* @__PURE__ */ jsx12(
|
|
8747
8367
|
LazyBrowserViewer,
|
|
8748
8368
|
{
|
|
8749
8369
|
client,
|
|
8750
8370
|
workspaceId,
|
|
8751
8371
|
sessionId,
|
|
8372
|
+
enabled: workspaceVisible,
|
|
8752
8373
|
onNotify,
|
|
8753
8374
|
...desktopEnabled ? { createLinkedComputer } : {},
|
|
8754
8375
|
...onOpenComputerSession ? { onOpenComputer: onOpenComputerSession } : {},
|
|
@@ -8762,13 +8383,14 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8762
8383
|
if (desktopEnabled) {
|
|
8763
8384
|
list.push({
|
|
8764
8385
|
id: WORKBENCH_TAB_DESKTOP,
|
|
8765
|
-
label: /* @__PURE__ */
|
|
8766
|
-
content: /* @__PURE__ */
|
|
8386
|
+
label: /* @__PURE__ */ jsx12(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx12(MonitorIcon, {}), children: "Computer" }),
|
|
8387
|
+
content: /* @__PURE__ */ jsx12(Suspense2, { fallback: /* @__PURE__ */ jsx12(WorkbenchSurfaceLoading, { name: "Computer" }), children: /* @__PURE__ */ jsx12(
|
|
8767
8388
|
LazyComputerViewer,
|
|
8768
8389
|
{
|
|
8769
8390
|
client,
|
|
8770
8391
|
workspaceId,
|
|
8771
8392
|
sessionId,
|
|
8393
|
+
enabled: workspaceVisible,
|
|
8772
8394
|
onNotify,
|
|
8773
8395
|
requestedComputerSessionId,
|
|
8774
8396
|
requestedComputerRequestId,
|
|
@@ -8799,6 +8421,8 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8799
8421
|
onNotify,
|
|
8800
8422
|
browserWebSocketFactory,
|
|
8801
8423
|
computerWebSocketFactory,
|
|
8424
|
+
workspaceVisible,
|
|
8425
|
+
resolvedActiveTab,
|
|
8802
8426
|
client,
|
|
8803
8427
|
workspaceId,
|
|
8804
8428
|
liveness,
|
|
@@ -8851,14 +8475,14 @@ function SandboxWorkspace(props) {
|
|
|
8851
8475
|
maxSize,
|
|
8852
8476
|
className
|
|
8853
8477
|
} = props;
|
|
8854
|
-
const [storedSelection, setStoredSelection] =
|
|
8855
|
-
const [requestedFile, setRequestedFile] =
|
|
8856
|
-
const [requestedComputer, setRequestedComputer] =
|
|
8857
|
-
const nextFileRequestId =
|
|
8858
|
-
const nextComputerRequestId =
|
|
8478
|
+
const [storedSelection, setStoredSelection] = useState17(null);
|
|
8479
|
+
const [requestedFile, setRequestedFile] = useState17(null);
|
|
8480
|
+
const [requestedComputer, setRequestedComputer] = useState17(null);
|
|
8481
|
+
const nextFileRequestId = useRef17(0);
|
|
8482
|
+
const nextComputerRequestId = useRef17(0);
|
|
8859
8483
|
const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;
|
|
8860
8484
|
const activeTabHint = selectedTab ?? initialTab ?? leadingTabs?.[0]?.id ?? null;
|
|
8861
|
-
const openFile =
|
|
8485
|
+
const openFile = useCallback24(
|
|
8862
8486
|
(path) => {
|
|
8863
8487
|
nextFileRequestId.current += 1;
|
|
8864
8488
|
setRequestedFile({ sessionId, path, requestId: nextFileRequestId.current });
|
|
@@ -8866,7 +8490,7 @@ function SandboxWorkspace(props) {
|
|
|
8866
8490
|
},
|
|
8867
8491
|
[sessionId]
|
|
8868
8492
|
);
|
|
8869
|
-
const openComputer =
|
|
8493
|
+
const openComputer = useCallback24(
|
|
8870
8494
|
(computerSessionId) => {
|
|
8871
8495
|
nextComputerRequestId.current += 1;
|
|
8872
8496
|
setRequestedComputer({
|
|
@@ -8890,6 +8514,7 @@ function SandboxWorkspace(props) {
|
|
|
8890
8514
|
...surfaces ? { surfaces } : {},
|
|
8891
8515
|
...initialTab ? { initialTab } : {},
|
|
8892
8516
|
activeTab: activeTabHint,
|
|
8517
|
+
workspaceVisible: collapsed !== true,
|
|
8893
8518
|
...onNotify ? { onNotify } : {},
|
|
8894
8519
|
...browserWebSocketFactory ? { browserWebSocketFactory } : {},
|
|
8895
8520
|
...computerWebSocketFactory ? { computerWebSocketFactory } : {},
|
|
@@ -8903,11 +8528,11 @@ function SandboxWorkspace(props) {
|
|
|
8903
8528
|
const tabs = [...leadingTabs ?? [], ...workbenchTabs, ...trailingTabs ?? []];
|
|
8904
8529
|
const preferredTab = selectedTab ?? defaultTab;
|
|
8905
8530
|
const activeTab = preferredTab && tabs.some((tab) => tab.id === preferredTab) ? preferredTab : tabs[0]?.id;
|
|
8906
|
-
const selectTab =
|
|
8531
|
+
const selectTab = useCallback24(
|
|
8907
8532
|
(tab) => setStoredSelection({ sessionId, tab }),
|
|
8908
8533
|
[sessionId]
|
|
8909
8534
|
);
|
|
8910
|
-
return /* @__PURE__ */
|
|
8535
|
+
return /* @__PURE__ */ jsx12(
|
|
8911
8536
|
WorkspaceDock,
|
|
8912
8537
|
{
|
|
8913
8538
|
primary,
|
|
@@ -8915,7 +8540,7 @@ function SandboxWorkspace(props) {
|
|
|
8915
8540
|
...activeTab !== void 0 ? { activeTab } : {},
|
|
8916
8541
|
onActiveTabChange: selectTab,
|
|
8917
8542
|
...machine.enabled ? {
|
|
8918
|
-
headerAccessory: /* @__PURE__ */
|
|
8543
|
+
headerAccessory: /* @__PURE__ */ jsx12(MachineStateChip, { chip: machine.chip })
|
|
8919
8544
|
} : {},
|
|
8920
8545
|
...mobileLeadingControl !== void 0 ? { mobileLeadingControl } : {},
|
|
8921
8546
|
...collapsed !== void 0 ? { collapsed } : {},
|
|
@@ -8930,7 +8555,7 @@ function SandboxWorkspace(props) {
|
|
|
8930
8555
|
);
|
|
8931
8556
|
}
|
|
8932
8557
|
function DirtyBadge({ count }) {
|
|
8933
|
-
return /* @__PURE__ */
|
|
8558
|
+
return /* @__PURE__ */ jsx12("span", { className: "rounded-og-xs bg-og-accent-soft px-1 text-og-xs text-og-fg-muted", children: count });
|
|
8934
8559
|
}
|
|
8935
8560
|
function chipDotClass(state) {
|
|
8936
8561
|
if (state === "live") return "bg-og-status-running";
|
|
@@ -8938,27 +8563,27 @@ function chipDotClass(state) {
|
|
|
8938
8563
|
return "bg-og-fg-subtle";
|
|
8939
8564
|
}
|
|
8940
8565
|
function MachineStateChip({ chip }) {
|
|
8941
|
-
return /* @__PURE__ */
|
|
8566
|
+
return /* @__PURE__ */ jsxs10(
|
|
8942
8567
|
"div",
|
|
8943
8568
|
{
|
|
8944
8569
|
role: "status",
|
|
8945
8570
|
"aria-label": `Machine: ${chip.label}`,
|
|
8946
|
-
className: "inline-flex min-h-7 items-center gap-1.5 px-2 py-1 text-og-xs font-medium text-og-fg-muted max-[1023px]:min-h-11 pointer-coarse:min-h-11",
|
|
8571
|
+
className: "inline-flex min-h-7 min-w-0 items-center gap-1.5 px-2 py-1 text-og-xs font-medium text-og-fg-muted max-[1023px]:min-h-11 pointer-coarse:min-h-11",
|
|
8947
8572
|
children: [
|
|
8948
|
-
/* @__PURE__ */
|
|
8573
|
+
/* @__PURE__ */ jsx12(
|
|
8949
8574
|
"span",
|
|
8950
8575
|
{
|
|
8951
8576
|
className: cn("size-1.5 shrink-0 rounded-full", chipDotClass(chip.state)),
|
|
8952
8577
|
"aria-hidden": true
|
|
8953
8578
|
}
|
|
8954
8579
|
),
|
|
8955
|
-
/* @__PURE__ */
|
|
8580
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 max-w-[11rem] truncate", children: chip.label })
|
|
8956
8581
|
]
|
|
8957
8582
|
}
|
|
8958
8583
|
);
|
|
8959
8584
|
}
|
|
8960
8585
|
function DockActionButton({ onClick, children }) {
|
|
8961
|
-
return /* @__PURE__ */
|
|
8586
|
+
return /* @__PURE__ */ jsx12(
|
|
8962
8587
|
"button",
|
|
8963
8588
|
{
|
|
8964
8589
|
type: "button",
|
|
@@ -8973,12 +8598,12 @@ function ChangesTabBody({
|
|
|
8973
8598
|
onComparisonChange,
|
|
8974
8599
|
...props
|
|
8975
8600
|
}) {
|
|
8976
|
-
return /* @__PURE__ */
|
|
8977
|
-
/* @__PURE__ */
|
|
8601
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
8602
|
+
/* @__PURE__ */ jsx12("div", { className: "flex shrink-0 items-center gap-1 border-b border-og-border bg-og-surface-1 px-2 py-1.5", children: [
|
|
8978
8603
|
["branch", "Branch"],
|
|
8979
8604
|
["working", "Uncommitted"],
|
|
8980
8605
|
["staged", "Staged"]
|
|
8981
|
-
].map(([value, label]) => /* @__PURE__ */
|
|
8606
|
+
].map(([value, label]) => /* @__PURE__ */ jsx12(
|
|
8982
8607
|
"button",
|
|
8983
8608
|
{
|
|
8984
8609
|
type: "button",
|
|
@@ -8992,7 +8617,7 @@ function ChangesTabBody({
|
|
|
8992
8617
|
},
|
|
8993
8618
|
value
|
|
8994
8619
|
)) }),
|
|
8995
|
-
/* @__PURE__ */
|
|
8620
|
+
/* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx12(ChangesTabContent, { comparison, ...props }) })
|
|
8996
8621
|
] });
|
|
8997
8622
|
}
|
|
8998
8623
|
function ChangesTabContent({
|
|
@@ -9011,8 +8636,8 @@ function ChangesTabContent({
|
|
|
9011
8636
|
}) {
|
|
9012
8637
|
const diff = git.diff;
|
|
9013
8638
|
if (diff.length > 0) {
|
|
9014
|
-
return /* @__PURE__ */
|
|
9015
|
-
git.error ? /* @__PURE__ */
|
|
8639
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
8640
|
+
git.error ? /* @__PURE__ */ jsxs10(
|
|
9016
8641
|
"div",
|
|
9017
8642
|
{
|
|
9018
8643
|
role: "status",
|
|
@@ -9020,9 +8645,9 @@ function ChangesTabContent({
|
|
|
9020
8645
|
"data-opengeni-changes-degraded": true,
|
|
9021
8646
|
className: "flex shrink-0 items-center gap-2 border-b border-og-status-running/30 bg-og-status-running/10 px-2 py-1.5 text-og-xs text-og-fg-muted",
|
|
9022
8647
|
children: [
|
|
9023
|
-
/* @__PURE__ */
|
|
9024
|
-
/* @__PURE__ */
|
|
9025
|
-
/* @__PURE__ */
|
|
8648
|
+
/* @__PURE__ */ jsx12(TriangleAlertIcon2, { className: "size-3.5 shrink-0 text-og-status-running", "aria-hidden": true }),
|
|
8649
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1", children: git.source === "capture" ? "Live changes are temporarily unavailable. Showing the latest captured revision." : "Live refresh failed. Showing the last loaded changes." }),
|
|
8650
|
+
/* @__PURE__ */ jsxs10(
|
|
9026
8651
|
"button",
|
|
9027
8652
|
{
|
|
9028
8653
|
type: "button",
|
|
@@ -9030,7 +8655,7 @@ function ChangesTabContent({
|
|
|
9030
8655
|
disabled: git.loading,
|
|
9031
8656
|
className: "inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11",
|
|
9032
8657
|
children: [
|
|
9033
|
-
/* @__PURE__ */
|
|
8658
|
+
/* @__PURE__ */ jsx12(
|
|
9034
8659
|
RefreshCwIcon2,
|
|
9035
8660
|
{
|
|
9036
8661
|
className: cn("size-3", git.loading && "animate-spin motion-reduce:animate-none"),
|
|
@@ -9044,7 +8669,7 @@ function ChangesTabContent({
|
|
|
9044
8669
|
]
|
|
9045
8670
|
}
|
|
9046
8671
|
) : null,
|
|
9047
|
-
/* @__PURE__ */
|
|
8672
|
+
/* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx12(
|
|
9048
8673
|
WorkbenchChanges,
|
|
9049
8674
|
{
|
|
9050
8675
|
diff,
|
|
@@ -9057,49 +8682,49 @@ function ChangesTabContent({
|
|
|
9057
8682
|
] });
|
|
9058
8683
|
}
|
|
9059
8684
|
if (capabilitiesError && !captureAvailable) {
|
|
9060
|
-
return /* @__PURE__ */
|
|
9061
|
-
/* @__PURE__ */
|
|
9062
|
-
/* @__PURE__ */
|
|
9063
|
-
/* @__PURE__ */
|
|
9064
|
-
/* @__PURE__ */
|
|
8685
|
+
return /* @__PURE__ */ jsxs10(CenteredState, { icon: /* @__PURE__ */ jsx12(TriangleAlertIcon2, { className: "size-5", "aria-hidden": true }), tone: "danger", children: [
|
|
8686
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm font-medium text-og-fg", children: "Sandbox unavailable" }),
|
|
8687
|
+
/* @__PURE__ */ jsx12("p", { "data-contrast-audited": true, className: "text-og-sm leading-5 text-og-fg-muted", children: capabilitiesError.message || "Couldn't reach the sandbox for this session." }),
|
|
8688
|
+
/* @__PURE__ */ jsxs10(DockActionButton, { onClick: onRetry, children: [
|
|
8689
|
+
/* @__PURE__ */ jsx12(RefreshCwIcon2, { className: "size-3" }),
|
|
9065
8690
|
"Retry"
|
|
9066
8691
|
] })
|
|
9067
8692
|
] });
|
|
9068
8693
|
}
|
|
9069
8694
|
if ((capturePending || capabilitiesState === "negotiating") && !captureAvailable && !workspaceWaking) {
|
|
9070
|
-
return /* @__PURE__ */
|
|
8695
|
+
return /* @__PURE__ */ jsxs10(
|
|
9071
8696
|
CenteredState,
|
|
9072
8697
|
{
|
|
9073
|
-
icon: /* @__PURE__ */
|
|
9074
|
-
|
|
8698
|
+
icon: /* @__PURE__ */ jsx12(
|
|
8699
|
+
LoaderCircleIcon2,
|
|
9075
8700
|
{
|
|
9076
8701
|
className: "size-5 animate-spin motion-reduce:animate-none",
|
|
9077
8702
|
"aria-hidden": true
|
|
9078
8703
|
}
|
|
9079
8704
|
),
|
|
9080
8705
|
children: [
|
|
9081
|
-
/* @__PURE__ */
|
|
9082
|
-
/* @__PURE__ */
|
|
8706
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm font-medium text-og-fg", children: "Connecting workspace" }),
|
|
8707
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: "Looking for the latest files and changes\u2026" })
|
|
9083
8708
|
]
|
|
9084
8709
|
}
|
|
9085
8710
|
);
|
|
9086
8711
|
}
|
|
9087
8712
|
if (!liveWorkspaceExpected && (comparison !== "working" || !captureAvailable)) {
|
|
9088
|
-
return /* @__PURE__ */
|
|
8713
|
+
return /* @__PURE__ */ jsxs10(
|
|
9089
8714
|
CenteredState,
|
|
9090
8715
|
{
|
|
9091
|
-
icon: workspaceWaking ? /* @__PURE__ */
|
|
9092
|
-
|
|
8716
|
+
icon: workspaceWaking ? /* @__PURE__ */ jsx12(
|
|
8717
|
+
LoaderCircleIcon2,
|
|
9093
8718
|
{
|
|
9094
8719
|
className: "size-5 animate-spin motion-reduce:animate-none",
|
|
9095
8720
|
"aria-hidden": true
|
|
9096
8721
|
}
|
|
9097
|
-
) : /* @__PURE__ */
|
|
8722
|
+
) : /* @__PURE__ */ jsx12(CpuIcon, { className: "size-5", "aria-hidden": true }),
|
|
9098
8723
|
children: [
|
|
9099
|
-
/* @__PURE__ */
|
|
9100
|
-
/* @__PURE__ */
|
|
9101
|
-
!workspaceWaking ? /* @__PURE__ */
|
|
9102
|
-
/* @__PURE__ */
|
|
8724
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm font-medium text-og-fg", children: workspaceWaking ? "Waking workspace" : "Workspace is resting" }),
|
|
8725
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: workspaceWaking ? "Connecting to the live working tree\u2026" : comparison === "branch" ? "Wake the sandbox to compare this branch with the remote default branch." : comparison === "staged" ? "Wake the sandbox to inspect staged changes." : "No captured revision is available yet. Wake the sandbox to inspect uncommitted changes." }),
|
|
8726
|
+
!workspaceWaking ? /* @__PURE__ */ jsxs10(DockActionButton, { onClick: onWake, children: [
|
|
8727
|
+
/* @__PURE__ */ jsx12(CpuIcon, { className: "size-3" }),
|
|
9103
8728
|
"Open live workspace"
|
|
9104
8729
|
] }) : null
|
|
9105
8730
|
]
|
|
@@ -9107,26 +8732,26 @@ function ChangesTabContent({
|
|
|
9107
8732
|
);
|
|
9108
8733
|
}
|
|
9109
8734
|
if (git.loading && git.source === null) {
|
|
9110
|
-
return /* @__PURE__ */
|
|
8735
|
+
return /* @__PURE__ */ jsxs10(
|
|
9111
8736
|
CenteredState,
|
|
9112
8737
|
{
|
|
9113
|
-
icon: /* @__PURE__ */
|
|
9114
|
-
|
|
8738
|
+
icon: /* @__PURE__ */ jsx12(
|
|
8739
|
+
LoaderCircleIcon2,
|
|
9115
8740
|
{
|
|
9116
8741
|
className: "size-5 animate-spin motion-reduce:animate-none",
|
|
9117
8742
|
"aria-hidden": true
|
|
9118
8743
|
}
|
|
9119
8744
|
),
|
|
9120
8745
|
children: [
|
|
9121
|
-
/* @__PURE__ */
|
|
9122
|
-
/* @__PURE__ */
|
|
8746
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm font-medium text-og-fg", children: "Loading workspace" }),
|
|
8747
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: "Reading the current working tree\u2026" })
|
|
9123
8748
|
]
|
|
9124
8749
|
}
|
|
9125
8750
|
);
|
|
9126
8751
|
}
|
|
9127
|
-
return /* @__PURE__ */
|
|
9128
|
-
/* @__PURE__ */
|
|
9129
|
-
/* @__PURE__ */
|
|
8752
|
+
return /* @__PURE__ */ jsxs10(CenteredState, { icon: /* @__PURE__ */ jsx12(CircleCheckIcon, { className: "size-5", "aria-hidden": true }), tone: "success", children: [
|
|
8753
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm font-medium text-og-fg", children: comparison === "branch" ? "No branch changes" : comparison === "staged" ? "No staged changes" : "No uncommitted changes" }),
|
|
8754
|
+
/* @__PURE__ */ jsx12("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: comparison === "branch" ? "This branch matches the remote default branch." : comparison === "staged" ? "Stage files to review the next commit here." : "Local edits not yet committed will appear here." })
|
|
9130
8755
|
] });
|
|
9131
8756
|
}
|
|
9132
8757
|
function CenteredState({
|
|
@@ -9134,15 +8759,15 @@ function CenteredState({
|
|
|
9134
8759
|
icon,
|
|
9135
8760
|
tone = "neutral"
|
|
9136
8761
|
}) {
|
|
9137
|
-
return /* @__PURE__ */
|
|
8762
|
+
return /* @__PURE__ */ jsx12(
|
|
9138
8763
|
"div",
|
|
9139
8764
|
{
|
|
9140
8765
|
role: tone === "danger" ? "alert" : "status",
|
|
9141
8766
|
"aria-atomic": "true",
|
|
9142
8767
|
"aria-live": tone === "danger" ? "assertive" : "polite",
|
|
9143
8768
|
className: "grid h-full place-items-center p-6 text-center",
|
|
9144
|
-
children: /* @__PURE__ */
|
|
9145
|
-
icon ? /* @__PURE__ */
|
|
8769
|
+
children: /* @__PURE__ */ jsxs10("div", { className: "flex max-w-sm flex-col items-center gap-2.5", children: [
|
|
8770
|
+
icon ? /* @__PURE__ */ jsx12(
|
|
9146
8771
|
"span",
|
|
9147
8772
|
{
|
|
9148
8773
|
className: cn(
|
|
@@ -9161,7 +8786,7 @@ function CenteredState({
|
|
|
9161
8786
|
}
|
|
9162
8787
|
|
|
9163
8788
|
// src/hooks/use-codex-accounts.ts
|
|
9164
|
-
import { useCallback as
|
|
8789
|
+
import { useCallback as useCallback25, useState as useState18 } from "react";
|
|
9165
8790
|
function isCodexAccountEvent(event) {
|
|
9166
8791
|
return event.type === "codex.account.switched";
|
|
9167
8792
|
}
|
|
@@ -9182,7 +8807,7 @@ function useCodexAccounts(options = {}) {
|
|
|
9182
8807
|
const codexClient = options.codexClient ?? client;
|
|
9183
8808
|
const sessionId = options.sessionId;
|
|
9184
8809
|
const sharedEvents = options.events;
|
|
9185
|
-
const load =
|
|
8810
|
+
const load = useCallback25(async () => {
|
|
9186
8811
|
const accountsP = codexClient.listCodexAccounts(workspaceId);
|
|
9187
8812
|
const sessionP = sessionId && codexClient.getSession ? codexClient.getSession(workspaceId, sessionId).catch(() => null) : Promise.resolve(null);
|
|
9188
8813
|
const [acc, session] = await Promise.all([accountsP, sessionP]);
|
|
@@ -9204,7 +8829,7 @@ function useCodexAccounts(options = {}) {
|
|
|
9204
8829
|
});
|
|
9205
8830
|
const { run: runMutation, mutating: pinning, mutationError } = useMutationRunner();
|
|
9206
8831
|
const { run: runUsageMutation, mutating: refreshingUsage } = useMutationRunner();
|
|
9207
|
-
const [pinningTarget, setPinningTarget] =
|
|
8832
|
+
const [pinningTarget, setPinningTarget] = useState18(null);
|
|
9208
8833
|
useSessionEventTrigger(
|
|
9209
8834
|
client,
|
|
9210
8835
|
workspaceId,
|
|
@@ -9216,7 +8841,7 @@ function useCodexAccounts(options = {}) {
|
|
|
9216
8841
|
...sharedEvents !== void 0 ? { events: sharedEvents } : {}
|
|
9217
8842
|
}
|
|
9218
8843
|
);
|
|
9219
|
-
const pin =
|
|
8844
|
+
const pin = useCallback25(
|
|
9220
8845
|
async (target) => {
|
|
9221
8846
|
if (!sessionId || !codexClient.pinSessionCodexAccount) {
|
|
9222
8847
|
return false;
|
|
@@ -9232,7 +8857,7 @@ function useCodexAccounts(options = {}) {
|
|
|
9232
8857
|
},
|
|
9233
8858
|
[codexClient, workspaceId, sessionId, runMutation, refresh]
|
|
9234
8859
|
);
|
|
9235
|
-
const refreshUsage =
|
|
8860
|
+
const refreshUsage = useCallback25(async () => {
|
|
9236
8861
|
if (!codexClient.refreshCodexUsage) {
|
|
9237
8862
|
return false;
|
|
9238
8863
|
}
|
|
@@ -9262,6 +8887,54 @@ function useCodexAccounts(options = {}) {
|
|
|
9262
8887
|
mutationError
|
|
9263
8888
|
};
|
|
9264
8889
|
}
|
|
8890
|
+
|
|
8891
|
+
// src/hooks/use-supergrok-accounts.ts
|
|
8892
|
+
import { useCallback as useCallback26 } from "react";
|
|
8893
|
+
var EMPTY = {
|
|
8894
|
+
accounts: [],
|
|
8895
|
+
activeAccountId: null,
|
|
8896
|
+
settings: {
|
|
8897
|
+
rotationEnabled: false,
|
|
8898
|
+
rotationStrategy: "sharded",
|
|
8899
|
+
activeCredentialId: null
|
|
8900
|
+
}
|
|
8901
|
+
};
|
|
8902
|
+
function useSuperGrokAccounts(options = {}) {
|
|
8903
|
+
const { client, workspaceId } = useOpenGeni(options);
|
|
8904
|
+
const supergrokClient = options.supergrokClient ?? client;
|
|
8905
|
+
const load = useCallback26(
|
|
8906
|
+
async () => await supergrokClient.listSuperGrokAccounts(workspaceId),
|
|
8907
|
+
[supergrokClient, workspaceId]
|
|
8908
|
+
);
|
|
8909
|
+
const { data, loading, refresh } = usePolledValue(load, {
|
|
8910
|
+
enabled: options.enabled,
|
|
8911
|
+
pollIntervalMs: options.pollIntervalMs
|
|
8912
|
+
});
|
|
8913
|
+
const { run, mutating: activating, mutationError } = useMutationRunner();
|
|
8914
|
+
const activate = useCallback26(
|
|
8915
|
+
async (accountId) => {
|
|
8916
|
+
if (!supergrokClient.activateSuperGrokAccount) return false;
|
|
8917
|
+
const result = await run(async () => {
|
|
8918
|
+
await supergrokClient.activateSuperGrokAccount(workspaceId, accountId);
|
|
8919
|
+
return true;
|
|
8920
|
+
});
|
|
8921
|
+
if (result) await refresh();
|
|
8922
|
+
return result === true;
|
|
8923
|
+
},
|
|
8924
|
+
[refresh, run, supergrokClient, workspaceId]
|
|
8925
|
+
);
|
|
8926
|
+
const state = data ?? EMPTY;
|
|
8927
|
+
return {
|
|
8928
|
+
accounts: state.accounts,
|
|
8929
|
+
activeAccountId: state.activeAccountId,
|
|
8930
|
+
settings: state.settings,
|
|
8931
|
+
loading,
|
|
8932
|
+
refresh,
|
|
8933
|
+
activate,
|
|
8934
|
+
activating,
|
|
8935
|
+
mutationError
|
|
8936
|
+
};
|
|
8937
|
+
}
|
|
9265
8938
|
export {
|
|
9266
8939
|
ActivityDisclosure,
|
|
9267
8940
|
ActivityRail,
|
|
@@ -9464,6 +9137,7 @@ export {
|
|
|
9464
9137
|
unwrapMcpOutput,
|
|
9465
9138
|
useAvailableModels,
|
|
9466
9139
|
useBillingUsage,
|
|
9140
|
+
useChannels,
|
|
9467
9141
|
useCodexAccounts,
|
|
9468
9142
|
useComposer,
|
|
9469
9143
|
useDesktopStream,
|
|
@@ -9497,6 +9171,7 @@ export {
|
|
|
9497
9171
|
useSessionLineage,
|
|
9498
9172
|
useSessionMcpApprovalPolicy,
|
|
9499
9173
|
useSlashCommands,
|
|
9174
|
+
useSuperGrokAccounts,
|
|
9500
9175
|
useTerminalStream,
|
|
9501
9176
|
useTranscription,
|
|
9502
9177
|
useTurnQueue,
|