@opengeni/react 0.48.0 → 0.52.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -2
- package/dist/artifacts-document.d.ts +3 -0
- package/dist/artifacts-document.js +17 -0
- package/dist/artifacts-document.js.map +1 -0
- package/dist/artifacts-presentation.d.ts +3 -0
- package/dist/artifacts-presentation.js +17 -0
- package/dist/artifacts-presentation.js.map +1 -0
- package/dist/artifacts-spreadsheet.d.ts +3 -0
- package/dist/artifacts-spreadsheet.js +17 -0
- package/dist/artifacts-spreadsheet.js.map +1 -0
- package/dist/artifacts.d.ts +2 -0
- package/dist/artifacts.js +170 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/chunk-6BBWWOOU.js +82 -0
- package/dist/chunk-6BBWWOOU.js.map +1 -0
- package/dist/{chunk-FWXGSNXT.js → chunk-724BW4TW.js} +585 -34
- package/dist/chunk-724BW4TW.js.map +1 -0
- package/dist/chunk-7I2KB3OK.js +3895 -0
- package/dist/chunk-7I2KB3OK.js.map +1 -0
- package/dist/chunk-7WCLAEFV.js +2828 -0
- package/dist/chunk-7WCLAEFV.js.map +1 -0
- package/dist/{chunk-I4MPFDRP.js → chunk-FWS3KC3Z.js} +3 -3
- package/dist/{chunk-EKZH6IDG.js → chunk-HDBG7XGO.js} +62 -1
- package/dist/chunk-HDBG7XGO.js.map +1 -0
- package/dist/chunk-HUIKIDM5.js +2148 -0
- package/dist/chunk-HUIKIDM5.js.map +1 -0
- package/dist/{chunk-XCNTXWBB.js → chunk-JAGDUCZQ.js} +854 -340
- package/dist/chunk-JAGDUCZQ.js.map +1 -0
- package/dist/{chunk-LHLYWG5R.js → chunk-JR3QFY6B.js} +413 -37
- package/dist/chunk-JR3QFY6B.js.map +1 -0
- package/dist/chunk-JVYQRRC4.js +53 -0
- package/dist/chunk-JVYQRRC4.js.map +1 -0
- package/dist/chunk-KCGXPP5V.js +157 -0
- package/dist/chunk-KCGXPP5V.js.map +1 -0
- package/dist/chunk-PEI6RANI.js +3234 -0
- package/dist/chunk-PEI6RANI.js.map +1 -0
- package/dist/{chunk-NJ7M2B6Z.js → chunk-ROIRTM37.js} +18 -10
- package/dist/{chunk-NJ7M2B6Z.js.map → chunk-ROIRTM37.js.map} +1 -1
- package/dist/{chunk-O4VXOBGF.js → chunk-WSK7G5LE.js} +70 -2
- package/dist/chunk-WSK7G5LE.js.map +1 -0
- package/dist/{chunk-OL6QVXGF.js → chunk-X4S56Y2H.js} +27 -7
- package/dist/{chunk-OL6QVXGF.js.map → chunk-X4S56Y2H.js.map} +1 -1
- package/dist/client.d.ts +7 -1
- package/dist/clipboard.d.ts +1 -0
- package/dist/clipboard.js +7 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/commands/index.d.ts +3 -3
- package/dist/commands/registry.d.ts +1 -1
- package/dist/commands/types.d.ts +1 -1
- package/dist/components/approval-surface.d.ts +2 -2
- package/dist/components/artifacts/artifact-surface.d.ts +18 -0
- package/dist/components/artifacts/document-editor.d.ts +172 -0
- package/dist/components/artifacts/editable-artifact-ui.d.ts +13 -0
- package/dist/components/artifacts/editable-artifact-workbench.d.ts +49 -0
- package/dist/components/artifacts/editable-document.d.ts +24 -0
- package/dist/components/artifacts/editable-presentation.d.ts +24 -0
- package/dist/components/artifacts/editable-spreadsheet.d.ts +32 -0
- package/dist/components/artifacts/index.d.ts +8 -0
- package/dist/components/artifacts/presentation-editor.d.ts +297 -0
- package/dist/components/artifacts/spreadsheet-canvas.d.ts +120 -0
- package/dist/components/artifacts/spreadsheet-grid.d.ts +113 -0
- package/dist/components/browser-viewer.d.ts +29 -0
- package/dist/components/chat-composer.d.ts +8 -8
- package/dist/components/code-editor.d.ts +25 -3
- package/dist/components/command-palette.d.ts +2 -2
- package/dist/components/composer-transcription-control.d.ts +2 -2
- package/dist/components/composer.d.ts +17 -17
- package/dist/components/computer-viewer.d.ts +23 -0
- package/dist/components/copy-button.d.ts +2 -2
- package/dist/components/desktop-viewer.d.ts +25 -21
- package/dist/components/diff-view.d.ts +1 -1
- package/dist/components/enrollment-consent.d.ts +1 -1
- package/dist/components/enrollment-device-flow.d.ts +1 -1
- package/dist/components/file-browser.d.ts +2 -2
- package/dist/components/fleet-tile.d.ts +1 -1
- package/dist/components/generated-video-player.d.ts +10 -0
- package/dist/components/human-input-form.d.ts +1 -1
- package/dist/components/human-input-surface.d.ts +2 -2
- package/dist/components/interactive-workbench-viewers.d.ts +2 -0
- package/dist/components/machine-card.d.ts +2 -2
- package/dist/components/machine-dock-bar.d.ts +3 -3
- package/dist/components/machine-health-pill.d.ts +2 -2
- package/dist/components/machine-input-display.d.ts +1 -1
- package/dist/components/machine-metrics.d.ts +2 -2
- package/dist/components/machine-status-pill.d.ts +4 -4
- package/dist/components/machines/health.d.ts +1 -1
- package/dist/components/machines/machine-detail.d.ts +3 -3
- package/dist/components/machines/metric-history-chart.d.ts +1 -1
- package/dist/components/machines/metric-sparkline.d.ts +2 -2
- package/dist/components/machines/series.d.ts +2 -2
- package/dist/components/machines-dashboard.d.ts +2 -2
- package/dist/components/markdown.d.ts +1 -1
- package/dist/components/message-timeline.d.ts +12 -5
- package/dist/components/model-picker.d.ts +2 -2
- package/dist/components/model-policy-picker.d.ts +7 -7
- package/dist/components/pierre-diff.d.ts +1 -1
- package/dist/components/pierre-file.d.ts +1 -1
- package/dist/components/queue-draft-policy.d.ts +1 -1
- package/dist/components/queue-surface-implementation.d.ts +3 -3
- package/dist/components/queue-surface-state.d.ts +4 -4
- package/dist/components/queue-surface.d.ts +5 -5
- package/dist/components/sandbox-files.d.ts +3 -3
- package/dist/components/sandbox-terminal.d.ts +21 -4
- package/dist/components/sandbox-workspace.d.ts +25 -9
- package/dist/components/session-chrome.d.ts +4 -4
- package/dist/components/session-status.d.ts +2 -2
- package/dist/components/timeline-annotation-selection.d.ts +9 -0
- package/dist/components/timeline-annotations-dialog.d.ts +16 -0
- package/dist/components/timeline-annotations.d.ts +13 -0
- package/dist/components/tooltip.d.ts +4 -4
- package/dist/components/user-message-body.d.ts +2 -2
- package/dist/components/workbench-changes.d.ts +2 -2
- package/dist/components/workspace-dock.d.ts +1 -1
- package/dist/composer.d.ts +11 -11
- package/dist/composer.js +5 -5
- package/dist/hooks/internal.d.ts +1 -1
- package/dist/hooks/use-attached-browsers.d.ts +21 -0
- package/dist/hooks/use-available-models.d.ts +2 -2
- package/dist/hooks/use-billing-usage.d.ts +1 -1
- package/dist/hooks/use-browser-frame-stream.d.ts +28 -0
- package/dist/hooks/use-browser-identities.d.ts +26 -0
- package/dist/hooks/use-browser-session.d.ts +28 -0
- package/dist/hooks/use-browser-sessions.d.ts +32 -0
- package/dist/hooks/use-codex-accounts.d.ts +2 -2
- package/dist/hooks/use-composer.d.ts +36 -9
- package/dist/hooks/use-computer-frame-stream.d.ts +24 -0
- package/dist/hooks/use-computer-session.d.ts +28 -0
- package/dist/hooks/use-computer-sessions.d.ts +28 -0
- package/dist/hooks/use-desktop-stream.d.ts +1 -1
- package/dist/hooks/use-environments.d.ts +1 -1
- package/dist/hooks/use-file-attachments.d.ts +1 -1
- package/dist/hooks/use-goal.d.ts +2 -2
- package/dist/hooks/use-human-input.d.ts +2 -2
- package/dist/hooks/use-last-started-turn-policy.d.ts +2 -2
- package/dist/hooks/use-machine-chip.d.ts +2 -2
- package/dist/hooks/use-machines.d.ts +4 -4
- package/dist/hooks/use-packs.d.ts +7 -2
- package/dist/hooks/use-rigs.d.ts +1 -1
- package/dist/hooks/use-sandbox-files.d.ts +6 -4
- package/dist/hooks/use-sandbox-git.d.ts +6 -5
- package/dist/hooks/use-sandbox-terminal.d.ts +1 -1
- package/dist/hooks/use-scheduled-tasks.d.ts +1 -1
- package/dist/hooks/use-session-capabilities.d.ts +5 -4
- package/dist/hooks/use-session-control.d.ts +1 -1
- package/dist/hooks/use-session-events.d.ts +2 -2
- package/dist/hooks/use-session-lineage.d.ts +1 -1
- package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
- package/dist/hooks/use-session.d.ts +2 -2
- package/dist/hooks/use-slash-commands.d.ts +1 -1
- package/dist/hooks/use-terminal-stream.d.ts +8 -2
- package/dist/hooks/use-turn-queue.d.ts +2 -2
- package/dist/hooks/use-video-artifact-playback.d.ts +9 -0
- package/dist/hooks/use-voice-input.d.ts +1 -1
- package/dist/hooks/use-workspace-capture.d.ts +1 -1
- package/dist/hooks/use-workspace-edit.d.ts +1 -1
- package/dist/hooks/use-workspace-sessions.d.ts +1 -1
- package/dist/hooks/use-workspaces.d.ts +1 -1
- package/dist/index.d.ts +158 -155
- package/dist/index.js +906 -462
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +23 -0
- package/dist/interaction.js +36 -0
- package/dist/interaction.js.map +1 -0
- package/dist/interactive-workbench-viewers-KHNOHWQE.js +13 -0
- package/dist/interactive-workbench-viewers-KHNOHWQE.js.map +1 -0
- package/dist/lib/relay-wire.d.ts +4 -0
- package/dist/lib/sandbox-liveness.d.ts +9 -0
- package/dist/lib/terminal-capability.d.ts +5 -0
- package/dist/lib/xterm-theme.d.ts +1 -1
- package/dist/machines.d.ts +30 -30
- package/dist/machines.js +3 -3
- package/dist/provider.d.ts +4 -4
- package/dist/{queue-surface-implementation-U5JFG7HT.js → queue-surface-implementation-2KVJTYXH.js} +100 -48
- package/dist/queue-surface-implementation-2KVJTYXH.js.map +1 -0
- package/dist/realtime/dropdown-menu.d.ts +8 -8
- package/dist/realtime/realtime-control.d.ts +6 -6
- package/dist/realtime.d.ts +4 -4
- package/dist/realtime.js +3 -3
- package/dist/session-context.d.ts +19 -1
- package/dist/session-ui.d.ts +14 -14
- package/dist/session-ui.js +5 -4
- package/dist/session.d.ts +28 -28
- package/dist/session.js +5 -5
- package/dist/timeline/activity-rail.d.ts +5 -3
- package/dist/timeline/disclosure-context.d.ts +1 -1
- package/dist/timeline/fleet-decision-projection.d.ts +1 -1
- package/dist/timeline/fleet-decision-row.d.ts +3 -3
- package/dist/timeline/index.d.ts +19 -19
- package/dist/timeline/parsers.d.ts +4 -1
- package/dist/timeline/projection.d.ts +3 -3
- package/dist/timeline/registry.d.ts +8 -2
- package/dist/timeline/screenshot-lightbox.d.ts +2 -2
- package/dist/timeline/shared.d.ts +21 -10
- package/dist/timeline/tool-diff.d.ts +2 -2
- package/dist/timeline/tool-renderers.d.ts +1 -1
- package/dist/timeline/turn-summary.d.ts +3 -3
- package/dist/timeline/types.d.ts +39 -3
- package/dist/timeline-annotation-selection-3L7LHGG2.js +187 -0
- package/dist/timeline-annotation-selection-3L7LHGG2.js.map +1 -0
- package/dist/timeline-annotations-dialog-U7EVLR75.js +196 -0
- package/dist/timeline-annotations-dialog-U7EVLR75.js.map +1 -0
- package/package.json +36 -7
- package/src/artifacts-document.ts +31 -0
- package/src/artifacts-presentation.ts +36 -0
- package/src/artifacts-spreadsheet.ts +21 -0
- package/src/artifacts.ts +86 -0
- package/src/client.ts +87 -1
- package/src/clipboard.ts +2 -0
- package/src/components/artifacts/artifact-surface.tsx +93 -0
- package/src/components/artifacts/document-editor.tsx +2255 -0
- package/src/components/artifacts/editable-artifact-ui.tsx +89 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +203 -0
- package/src/components/artifacts/editable-document.tsx +657 -0
- package/src/components/artifacts/editable-presentation.tsx +1020 -0
- package/src/components/artifacts/editable-spreadsheet.tsx +733 -0
- package/src/components/artifacts/index.ts +99 -0
- package/src/components/artifacts/presentation-editor.tsx +3148 -0
- package/src/components/artifacts/spreadsheet-canvas.ts +799 -0
- package/src/components/artifacts/spreadsheet-grid.tsx +2129 -0
- package/src/components/browser-viewer.tsx +1592 -0
- package/src/components/chat-composer.tsx +13 -0
- package/src/components/code-editor.tsx +89 -30
- package/src/components/composer-transcription-control.tsx +10 -6
- package/src/components/computer-viewer.tsx +1139 -0
- package/src/components/desktop-viewer.tsx +101 -73
- package/src/components/generated-video-player.tsx +89 -0
- package/src/components/interactive-workbench-viewers.ts +2 -0
- package/src/components/machine-input-display.ts +3 -0
- package/src/components/message-timeline.tsx +289 -32
- package/src/components/queue-surface-implementation.tsx +116 -60
- package/src/components/sandbox-files.tsx +2 -2
- package/src/components/sandbox-terminal.tsx +106 -41
- package/src/components/sandbox-workspace.tsx +215 -87
- package/src/components/session-chrome.tsx +53 -13
- package/src/components/timeline-annotation-selection.tsx +221 -0
- package/src/components/timeline-annotations-dialog.tsx +213 -0
- package/src/components/timeline-annotations.tsx +84 -0
- package/src/components/workbench-changes.tsx +188 -31
- package/src/hooks/use-attached-browsers.ts +152 -0
- package/src/hooks/use-browser-frame-stream.ts +316 -0
- package/src/hooks/use-browser-identities.ts +225 -0
- package/src/hooks/use-browser-session.ts +476 -0
- package/src/hooks/use-browser-sessions.ts +281 -0
- package/src/hooks/use-composer.ts +769 -24
- package/src/hooks/use-computer-frame-stream.ts +311 -0
- package/src/hooks/use-computer-session.ts +442 -0
- package/src/hooks/use-computer-sessions.ts +245 -0
- package/src/hooks/use-machine-chip.ts +5 -3
- package/src/hooks/use-machines.ts +33 -3
- package/src/hooks/use-packs.ts +51 -0
- package/src/hooks/use-sandbox-files.ts +98 -55
- package/src/hooks/use-sandbox-git.ts +93 -38
- package/src/hooks/use-sandbox-terminal.ts +3 -2
- package/src/hooks/use-session-capabilities.ts +59 -46
- package/src/hooks/use-terminal-stream.ts +102 -23
- package/src/hooks/use-video-artifact-playback.ts +28 -0
- package/src/hooks/use-workspace-edit.ts +2 -1
- package/src/index.ts +10 -0
- package/src/interaction.ts +71 -0
- package/src/lib/relay-wire.ts +4 -0
- package/src/lib/sandbox-liveness.ts +11 -0
- package/src/lib/terminal-capability.ts +10 -0
- package/src/session-context.ts +90 -0
- package/src/timeline/activity-rail.tsx +19 -3
- package/src/timeline/index.ts +3 -0
- package/src/timeline/parsers.ts +14 -1
- package/src/timeline/projection.ts +211 -14
- package/src/timeline/registry.ts +13 -1
- package/src/timeline/screenshot-lightbox.tsx +19 -9
- package/src/timeline/shared.tsx +56 -8
- package/src/timeline/tool-renderers.tsx +303 -50
- package/src/timeline/types.ts +55 -3
- package/styles/compiled.css +248 -15
- package/styles/index.css +15 -0
- package/styles/responsive.css +13 -1
- package/dist/chunk-EKZH6IDG.js.map +0 -1
- package/dist/chunk-FWXGSNXT.js.map +0 -1
- package/dist/chunk-LHLYWG5R.js.map +0 -1
- package/dist/chunk-O4VXOBGF.js.map +0 -1
- package/dist/chunk-XCNTXWBB.js.map +0 -1
- package/dist/fleet-decision-projection-SLNZMS42.js +0 -241
- package/dist/fleet-decision-projection-SLNZMS42.js.map +0 -1
- package/dist/queue-surface-implementation-U5JFG7HT.js.map +0 -1
- /package/dist/{chunk-I4MPFDRP.js.map → chunk-FWS3KC3Z.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,58 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CONNECTION_STATUS_META,
|
|
3
|
-
ConnectionDot,
|
|
4
|
-
ConnectionStatusPill,
|
|
5
|
-
EnrollmentConsent,
|
|
6
|
-
EnrollmentDeviceFlow,
|
|
7
|
-
HEALTH_TOKEN,
|
|
8
|
-
MACHINE_STATE_BADGE_META,
|
|
9
|
-
METRICS,
|
|
10
|
-
METRIC_WINDOWS,
|
|
11
|
-
MachineCard,
|
|
12
|
-
MachineDetail,
|
|
13
|
-
MachineDockBar,
|
|
14
|
-
MachineHealthPill,
|
|
15
|
-
MachineMetrics,
|
|
16
|
-
MachineStatusPill,
|
|
17
|
-
MachinesDashboard,
|
|
18
|
-
MetricHistoryChart,
|
|
19
|
-
MetricSparkline,
|
|
20
|
-
OpenGeniProvider,
|
|
21
|
-
SharedMachineDisclosure,
|
|
22
|
-
WINDOW_LABEL,
|
|
23
|
-
connectionStatusForState,
|
|
24
|
-
deriveHealth,
|
|
25
|
-
healthPulses,
|
|
26
|
-
pointsFor,
|
|
27
|
-
useMachines
|
|
28
|
-
} from "./chunk-OL6QVXGF.js";
|
|
29
|
-
import {
|
|
30
|
-
SESSION_EVENT_BROWSER_MAX_BYTES,
|
|
31
|
-
SESSION_EVENT_BROWSER_MAX_COUNT,
|
|
32
|
-
SESSION_EVENT_BROWSER_PENDING_MAX_BYTES,
|
|
33
|
-
SESSION_EVENT_BROWSER_PENDING_MAX_COUNT,
|
|
34
|
-
SESSION_EVENT_BROWSER_SINGLE_EVENT_MAX_BYTES,
|
|
35
|
-
approvalsFromRequiresAction,
|
|
36
|
-
boundBrowserSessionEventWindow,
|
|
37
|
-
humanInputRequestFromEvent,
|
|
38
|
-
isGoalEvent,
|
|
39
|
-
isHumanInputEvent,
|
|
40
|
-
isLineageRefreshEvent,
|
|
41
|
-
isSessionMcpApprovalPolicyEvent,
|
|
42
|
-
isTitleEvent,
|
|
43
|
-
isTurnQueueEvent,
|
|
44
|
-
projectPendingApprovals,
|
|
45
|
-
projectPendingHumanInputRequests,
|
|
46
|
-
useFileAttachments,
|
|
47
|
-
useGoal,
|
|
48
|
-
useHumanInputRequests,
|
|
49
|
-
useSession,
|
|
50
|
-
useSessionControl,
|
|
51
|
-
useSessionEvents,
|
|
52
|
-
useSessionLineage,
|
|
53
|
-
useSessionMcpApprovalPolicy,
|
|
54
|
-
useTurnQueue
|
|
55
|
-
} from "./chunk-I4MPFDRP.js";
|
|
56
1
|
import {
|
|
57
2
|
ActivityDisclosure,
|
|
58
3
|
ActivityRail,
|
|
@@ -61,6 +6,7 @@ import {
|
|
|
61
6
|
CopyButton,
|
|
62
7
|
CopyHoverFrame,
|
|
63
8
|
DisclosureDefaultsProvider,
|
|
9
|
+
GeneratedVideoPlayer,
|
|
64
10
|
HumanInputForm,
|
|
65
11
|
HumanInputSurface,
|
|
66
12
|
LightboxProvider,
|
|
@@ -85,7 +31,6 @@ import {
|
|
|
85
31
|
applyPatchOps,
|
|
86
32
|
applyPatchOpsFromToolItem,
|
|
87
33
|
controlCaret,
|
|
88
|
-
copyTextToClipboard,
|
|
89
34
|
createDefaultToolRegistry,
|
|
90
35
|
createToolRegistry,
|
|
91
36
|
defaultHumanInputFormMessages,
|
|
@@ -102,7 +47,6 @@ import {
|
|
|
102
47
|
sandboxCommandExitCode,
|
|
103
48
|
sessionChromeGoalPillState,
|
|
104
49
|
stripExecBanner,
|
|
105
|
-
tableElementToTsv,
|
|
106
50
|
tailPeek,
|
|
107
51
|
unwrapMcpOutput,
|
|
108
52
|
useLightbox,
|
|
@@ -110,16 +54,7 @@ import {
|
|
|
110
54
|
useThemeType,
|
|
111
55
|
userMessageLikelyNeedsDisclosure,
|
|
112
56
|
v4aToGitFileDiff
|
|
113
|
-
} from "./chunk-
|
|
114
|
-
import "./chunk-O4VXOBGF.js";
|
|
115
|
-
import {
|
|
116
|
-
buildTimeline,
|
|
117
|
-
creditExhaustedFromEvents,
|
|
118
|
-
extractSessionRef,
|
|
119
|
-
groupTimeline,
|
|
120
|
-
sessionStatusFromEvents,
|
|
121
|
-
toolDisplayName
|
|
122
|
-
} from "./chunk-LHLYWG5R.js";
|
|
57
|
+
} from "./chunk-JAGDUCZQ.js";
|
|
123
58
|
import {
|
|
124
59
|
Actions,
|
|
125
60
|
AttachButton,
|
|
@@ -172,20 +107,7 @@ import {
|
|
|
172
107
|
useSlashCommands,
|
|
173
108
|
useTranscription,
|
|
174
109
|
useVoiceInput
|
|
175
|
-
} from "./chunk-
|
|
176
|
-
import {
|
|
177
|
-
FILE_ONLY_MESSAGE_TEXT,
|
|
178
|
-
composeSendInput,
|
|
179
|
-
shouldSteerOnKey,
|
|
180
|
-
shouldSubmitOnKey,
|
|
181
|
-
useComposer
|
|
182
|
-
} from "./chunk-FWXGSNXT.js";
|
|
183
|
-
import {
|
|
184
|
-
useMutationRunner,
|
|
185
|
-
usePageLiveActivity,
|
|
186
|
-
usePolledValue,
|
|
187
|
-
useSessionEventTrigger
|
|
188
|
-
} from "./chunk-KZ73RL76.js";
|
|
110
|
+
} from "./chunk-ROIRTM37.js";
|
|
189
111
|
import {
|
|
190
112
|
BillingClassMark,
|
|
191
113
|
ModelPolicyPicker,
|
|
@@ -195,10 +117,6 @@ import {
|
|
|
195
117
|
PickerNavRow,
|
|
196
118
|
defaultModelPolicyPickerMessages
|
|
197
119
|
} from "./chunk-WYA65Y3F.js";
|
|
198
|
-
import {
|
|
199
|
-
useOpenGeni,
|
|
200
|
-
useOpenGeniClient
|
|
201
|
-
} from "./chunk-EKZH6IDG.js";
|
|
202
120
|
import {
|
|
203
121
|
advancedSourceSummary,
|
|
204
122
|
availabilityReasonLabel,
|
|
@@ -223,6 +141,83 @@ import {
|
|
|
223
141
|
TooltipProvider,
|
|
224
142
|
TooltipTrigger
|
|
225
143
|
} from "./chunk-FK6VG4LL.js";
|
|
144
|
+
import {
|
|
145
|
+
TimelineAnnotationsChip
|
|
146
|
+
} from "./chunk-WSK7G5LE.js";
|
|
147
|
+
import {
|
|
148
|
+
usePortalTokenSource,
|
|
149
|
+
usePortalTokenStyle
|
|
150
|
+
} from "./chunk-VZTQ73XT.js";
|
|
151
|
+
import {
|
|
152
|
+
CONNECTION_STATUS_META,
|
|
153
|
+
ConnectionDot,
|
|
154
|
+
ConnectionStatusPill,
|
|
155
|
+
EnrollmentConsent,
|
|
156
|
+
EnrollmentDeviceFlow,
|
|
157
|
+
HEALTH_TOKEN,
|
|
158
|
+
MACHINE_STATE_BADGE_META,
|
|
159
|
+
METRICS,
|
|
160
|
+
METRIC_WINDOWS,
|
|
161
|
+
MachineCard,
|
|
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";
|
|
206
|
+
import {
|
|
207
|
+
buildTimeline,
|
|
208
|
+
creditExhaustedFromEvents,
|
|
209
|
+
extractSessionRef,
|
|
210
|
+
groupTimeline,
|
|
211
|
+
sessionStatusFromEvents,
|
|
212
|
+
toolDisplayName
|
|
213
|
+
} from "./chunk-JR3QFY6B.js";
|
|
214
|
+
import {
|
|
215
|
+
FILE_ONLY_MESSAGE_TEXT,
|
|
216
|
+
composeSendInput,
|
|
217
|
+
shouldSteerOnKey,
|
|
218
|
+
shouldSubmitOnKey,
|
|
219
|
+
useComposer
|
|
220
|
+
} from "./chunk-724BW4TW.js";
|
|
226
221
|
import {
|
|
227
222
|
COMPOSER_PAYMENT_REQUIRED_MESSAGE,
|
|
228
223
|
CREDIT_EXHAUSTION_MESSAGE,
|
|
@@ -237,12 +232,48 @@ import {
|
|
|
237
232
|
tryParseJson
|
|
238
233
|
} from "./chunk-LAKLF4PA.js";
|
|
239
234
|
import {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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";
|
|
243
251
|
import {
|
|
244
252
|
cn
|
|
245
253
|
} from "./chunk-22KP6LR5.js";
|
|
254
|
+
import {
|
|
255
|
+
copyTextToClipboard,
|
|
256
|
+
tableElementToTsv
|
|
257
|
+
} from "./chunk-JVYQRRC4.js";
|
|
258
|
+
|
|
259
|
+
// src/hooks/use-video-artifact-playback.ts
|
|
260
|
+
import { useMemo } from "react";
|
|
261
|
+
function useVideoArtifactPlaybackLoader(options = {}) {
|
|
262
|
+
const { client, workspaceId } = useOpenGeni(options);
|
|
263
|
+
return useMemo(
|
|
264
|
+
() => async (artifactId, signal) => {
|
|
265
|
+
if (typeof client.createVideoArtifactPlaybackSource !== "function") {
|
|
266
|
+
throw new Error("This OpenGeni host does not expose retained-video playback.");
|
|
267
|
+
}
|
|
268
|
+
return await client.createVideoArtifactPlaybackSource(
|
|
269
|
+
workspaceId,
|
|
270
|
+
artifactId,
|
|
271
|
+
signal ? { signal } : {}
|
|
272
|
+
);
|
|
273
|
+
},
|
|
274
|
+
[client, workspaceId]
|
|
275
|
+
);
|
|
276
|
+
}
|
|
246
277
|
|
|
247
278
|
// src/hooks/use-last-started-turn-policy.ts
|
|
248
279
|
import { useCallback, useEffect } from "react";
|
|
@@ -379,7 +410,7 @@ function useWorkspaceSessions(options = {}) {
|
|
|
379
410
|
}
|
|
380
411
|
|
|
381
412
|
// src/hooks/use-environments.ts
|
|
382
|
-
import { useCallback as useCallback4, useMemo } from "react";
|
|
413
|
+
import { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
383
414
|
function useVariableSets(options = {}) {
|
|
384
415
|
const { client, workspaceId } = useOpenGeni(options);
|
|
385
416
|
const load = useCallback4(
|
|
@@ -470,7 +501,7 @@ function useVariableSets(options = {}) {
|
|
|
470
501
|
};
|
|
471
502
|
}
|
|
472
503
|
function useEnvironments(options = {}) {
|
|
473
|
-
const legacyClient =
|
|
504
|
+
const legacyClient = useMemo2(() => {
|
|
474
505
|
if (!options.client) {
|
|
475
506
|
return void 0;
|
|
476
507
|
}
|
|
@@ -737,6 +768,30 @@ function usePacks(options = {}) {
|
|
|
737
768
|
},
|
|
738
769
|
[client, workspaceId, run, refresh]
|
|
739
770
|
);
|
|
771
|
+
const previewInstallation = useCallback6(
|
|
772
|
+
async (packId, request = {}) => await run(() => client.previewPackInstallation(workspaceId, packId, request)),
|
|
773
|
+
[client, workspaceId, run]
|
|
774
|
+
);
|
|
775
|
+
const install = useCallback6(
|
|
776
|
+
async (packId, request) => {
|
|
777
|
+
const result = await run(() => client.installPack(workspaceId, packId, request));
|
|
778
|
+
if (result) await refresh();
|
|
779
|
+
return result;
|
|
780
|
+
},
|
|
781
|
+
[client, workspaceId, run, refresh]
|
|
782
|
+
);
|
|
783
|
+
const previewUninstall = useCallback6(
|
|
784
|
+
async (packId) => await run(() => client.previewPackUninstall(workspaceId, packId)),
|
|
785
|
+
[client, workspaceId, run]
|
|
786
|
+
);
|
|
787
|
+
const uninstall = useCallback6(
|
|
788
|
+
async (packId, request) => {
|
|
789
|
+
const result = await run(() => client.uninstallPack(workspaceId, packId, request));
|
|
790
|
+
if (result) await refresh();
|
|
791
|
+
return result;
|
|
792
|
+
},
|
|
793
|
+
[client, workspaceId, run, refresh]
|
|
794
|
+
);
|
|
740
795
|
const remove = useCallback6(
|
|
741
796
|
async (packId) => {
|
|
742
797
|
const result = await run(async () => {
|
|
@@ -764,6 +819,10 @@ function usePacks(options = {}) {
|
|
|
764
819
|
refresh,
|
|
765
820
|
register,
|
|
766
821
|
enable,
|
|
822
|
+
previewInstallation,
|
|
823
|
+
install,
|
|
824
|
+
previewUninstall,
|
|
825
|
+
uninstall,
|
|
767
826
|
remove,
|
|
768
827
|
mutating,
|
|
769
828
|
mutationError,
|
|
@@ -893,16 +952,24 @@ import {
|
|
|
893
952
|
applyUrlRotation
|
|
894
953
|
} from "@opengeni/sdk";
|
|
895
954
|
import { useCallback as useCallback10, useEffect as useEffect3, useRef as useRef2, useState } from "react";
|
|
955
|
+
|
|
956
|
+
// src/lib/sandbox-liveness.ts
|
|
957
|
+
function sandboxAcceptsLiveIo(liveness) {
|
|
958
|
+
return liveness === "warm";
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// src/lib/terminal-capability.ts
|
|
962
|
+
function terminalCanAcquirePty(cell) {
|
|
963
|
+
if (!cell?.ptyCapable) return false;
|
|
964
|
+
if (cell.transport === "pty-ws") return true;
|
|
965
|
+
return cell.reason === "lease_cold" || cell.reason === "not_provisioned";
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/hooks/use-session-capabilities.ts
|
|
896
969
|
function desktopAttachable(cell) {
|
|
897
970
|
if (cell.transport !== null) return true;
|
|
898
971
|
return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
|
|
899
972
|
}
|
|
900
|
-
function terminalAttachable(cell) {
|
|
901
|
-
if (cell.transport === null) {
|
|
902
|
-
return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
|
|
903
|
-
}
|
|
904
|
-
return true;
|
|
905
|
-
}
|
|
906
973
|
function rotationsFrom(events) {
|
|
907
974
|
const out = [];
|
|
908
975
|
for (const event of events) {
|
|
@@ -954,8 +1021,12 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
954
1021
|
if (!lifecycleEnabled || !sessionId) {
|
|
955
1022
|
setState("idle");
|
|
956
1023
|
setCapabilities(null);
|
|
1024
|
+
viewerIdRef.current = null;
|
|
1025
|
+
setViewerId(null);
|
|
957
1026
|
return;
|
|
958
1027
|
}
|
|
1028
|
+
viewerIdRef.current = null;
|
|
1029
|
+
setViewerId(null);
|
|
959
1030
|
let cancelled = false;
|
|
960
1031
|
let pollTimer = null;
|
|
961
1032
|
let heartbeatTimer = null;
|
|
@@ -1004,7 +1075,7 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1004
1075
|
void client.getStreamCapabilities(workspaceId, sessionId, { signal: requestAbort.signal }).then((caps) => {
|
|
1005
1076
|
if (cancelled) return;
|
|
1006
1077
|
settle(caps);
|
|
1007
|
-
if (caps.liveness
|
|
1078
|
+
if (sandboxAcceptsLiveIo(caps.liveness)) {
|
|
1008
1079
|
setState("ready");
|
|
1009
1080
|
return;
|
|
1010
1081
|
}
|
|
@@ -1033,18 +1104,25 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1033
1104
|
if (cancelled) return;
|
|
1034
1105
|
settle(caps);
|
|
1035
1106
|
const wantDesktopAttach = attachDesktop && desktopAttachable(caps.DesktopStream);
|
|
1036
|
-
const wantTerminalAttach = attachTerminal &&
|
|
1107
|
+
const wantTerminalAttach = attachTerminal && terminalCanAcquirePty(caps.Terminal);
|
|
1037
1108
|
const wantFilesAttach = attachFiles && caps.FileSystem.available;
|
|
1038
1109
|
if (wantDesktopAttach || wantTerminalAttach || wantFilesAttach) {
|
|
1039
1110
|
try {
|
|
1040
1111
|
const holder = await client.attachViewer(workspaceId, sessionId, {
|
|
1041
|
-
desktop: wantDesktopAttach
|
|
1112
|
+
desktop: wantDesktopAttach,
|
|
1113
|
+
terminal: wantTerminalAttach,
|
|
1114
|
+
files: wantFilesAttach
|
|
1042
1115
|
});
|
|
1043
1116
|
if (cancelled) {
|
|
1044
1117
|
void client.detachViewer(workspaceId, sessionId, holder.viewerId).catch(() => {
|
|
1045
1118
|
});
|
|
1046
1119
|
return;
|
|
1047
1120
|
}
|
|
1121
|
+
if (wantDesktopAttach && (!holder.dataPlaneUrl || !holder.transport || !holder.client) || wantTerminalAttach && (!holder.terminalUrl || !holder.terminalTransport)) {
|
|
1122
|
+
await client.detachViewer(workspaceId, sessionId, holder.viewerId).catch(() => {
|
|
1123
|
+
});
|
|
1124
|
+
throw new Error("live plane unavailable");
|
|
1125
|
+
}
|
|
1048
1126
|
localViewerId = holder.viewerId;
|
|
1049
1127
|
viewerIdRef.current = holder.viewerId;
|
|
1050
1128
|
setViewerId(holder.viewerId);
|
|
@@ -1059,19 +1137,20 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1059
1137
|
...prev.DesktopStream,
|
|
1060
1138
|
transport: holder.transport ?? prev.DesktopStream.transport,
|
|
1061
1139
|
client: holder.client ?? prev.DesktopStream.client,
|
|
1062
|
-
url: holder.dataPlaneUrl
|
|
1063
|
-
token: holder.streamToken
|
|
1064
|
-
expiresAt: holder.streamExpiresAt
|
|
1140
|
+
url: holder.dataPlaneUrl,
|
|
1141
|
+
token: holder.streamToken,
|
|
1142
|
+
expiresAt: holder.streamExpiresAt,
|
|
1065
1143
|
resolution: holder.resolution ?? prev.DesktopStream.resolution
|
|
1066
1144
|
} : prev.DesktopStream,
|
|
1067
|
-
Terminal:
|
|
1145
|
+
Terminal: wantTerminalAttach ? {
|
|
1068
1146
|
...prev.Terminal,
|
|
1069
|
-
transport: holder.terminalTransport,
|
|
1147
|
+
transport: holder.terminalTransport ?? prev.Terminal.transport,
|
|
1070
1148
|
url: holder.terminalUrl,
|
|
1071
|
-
token: holder.terminalToken
|
|
1149
|
+
token: holder.terminalToken,
|
|
1150
|
+
expiresAt: holder.terminalExpiresAt,
|
|
1072
1151
|
// A live pty-ws means the box is pty-capable for real.
|
|
1073
|
-
ptyCapable: true,
|
|
1074
|
-
reason: null
|
|
1152
|
+
ptyCapable: holder.terminalTransport ? true : prev.Terminal.ptyCapable,
|
|
1153
|
+
reason: holder.terminalTransport ? null : prev.Terminal.reason
|
|
1075
1154
|
} : prev.Terminal
|
|
1076
1155
|
} : prev
|
|
1077
1156
|
);
|
|
@@ -1090,6 +1169,8 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1090
1169
|
setState("error");
|
|
1091
1170
|
setError(cause);
|
|
1092
1171
|
return;
|
|
1172
|
+
} else {
|
|
1173
|
+
throw cause;
|
|
1093
1174
|
}
|
|
1094
1175
|
} else {
|
|
1095
1176
|
throw cause;
|
|
@@ -1097,7 +1178,7 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1097
1178
|
}
|
|
1098
1179
|
}
|
|
1099
1180
|
const warmUpRequested = wantDesktopAttach || wantTerminalAttach || wantFilesAttach;
|
|
1100
|
-
if (caps.liveness
|
|
1181
|
+
if (sandboxAcceptsLiveIo(caps.liveness) || localViewerId) {
|
|
1101
1182
|
setState("ready");
|
|
1102
1183
|
startHeartbeat(caps);
|
|
1103
1184
|
} else if (warmUpRequested) {
|
|
@@ -1180,76 +1261,6 @@ import {
|
|
|
1180
1261
|
} from "@opengeni/sdk";
|
|
1181
1262
|
import { useEffect as useEffect5, useRef as useRef4, useState as useState3 } from "react";
|
|
1182
1263
|
|
|
1183
|
-
// src/lib/relay-wire.ts
|
|
1184
|
-
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
|
1185
|
-
var STREAM_KIND_DESKTOP = 2;
|
|
1186
|
-
var STREAM_ROLE_CLIENT = 2;
|
|
1187
|
-
function encodeChannel(message, writer) {
|
|
1188
|
-
if (message.channelId !== "") writer.uint32(10).string(message.channelId);
|
|
1189
|
-
if (message.workspaceId !== "") writer.uint32(18).string(message.workspaceId);
|
|
1190
|
-
if (message.agentId !== "") writer.uint32(26).string(message.agentId);
|
|
1191
|
-
if (message.kind !== 0) writer.uint32(32).int32(message.kind);
|
|
1192
|
-
if (message.port !== 0) writer.uint32(40).uint32(message.port);
|
|
1193
|
-
return writer;
|
|
1194
|
-
}
|
|
1195
|
-
function encodeStreamOpen(message) {
|
|
1196
|
-
const writer = new BinaryWriter();
|
|
1197
|
-
encodeChannel(message.channel, writer.uint32(10).fork()).join();
|
|
1198
|
-
if (message.token !== "") writer.uint32(18).string(message.token);
|
|
1199
|
-
if (message.role !== 0) writer.uint32(24).int32(message.role);
|
|
1200
|
-
if (message.resumeFromSeq !== "0") writer.uint32(32).uint64(message.resumeFromSeq);
|
|
1201
|
-
return writer.finish();
|
|
1202
|
-
}
|
|
1203
|
-
function decodeAgentErrorMessage(reader, length) {
|
|
1204
|
-
const end = reader.pos + length;
|
|
1205
|
-
let message;
|
|
1206
|
-
while (reader.pos < end) {
|
|
1207
|
-
const tag = reader.uint32();
|
|
1208
|
-
if (tag >>> 3 === 2 && tag === 18) {
|
|
1209
|
-
message = reader.string();
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
if ((tag & 7) === 4 || tag === 0) break;
|
|
1213
|
-
reader.skip(tag & 7);
|
|
1214
|
-
}
|
|
1215
|
-
return message !== void 0 ? { message } : {};
|
|
1216
|
-
}
|
|
1217
|
-
function decodeStreamOpenAck(bytes) {
|
|
1218
|
-
const reader = new BinaryReader(bytes);
|
|
1219
|
-
const end = reader.len;
|
|
1220
|
-
let accepted = false;
|
|
1221
|
-
let error;
|
|
1222
|
-
while (reader.pos < end) {
|
|
1223
|
-
const tag = reader.uint32();
|
|
1224
|
-
if (tag >>> 3 === 1 && tag === 8) {
|
|
1225
|
-
accepted = reader.bool();
|
|
1226
|
-
continue;
|
|
1227
|
-
}
|
|
1228
|
-
if (tag >>> 3 === 2 && tag === 18) {
|
|
1229
|
-
error = decodeAgentErrorMessage(reader, reader.uint32());
|
|
1230
|
-
continue;
|
|
1231
|
-
}
|
|
1232
|
-
if ((tag & 7) === 4 || tag === 0) break;
|
|
1233
|
-
reader.skip(tag & 7);
|
|
1234
|
-
}
|
|
1235
|
-
return error !== void 0 ? { accepted, error } : { accepted };
|
|
1236
|
-
}
|
|
1237
|
-
function decodeStreamFrame(bytes) {
|
|
1238
|
-
const reader = new BinaryReader(bytes);
|
|
1239
|
-
const end = reader.len;
|
|
1240
|
-
let data = new Uint8Array(0);
|
|
1241
|
-
while (reader.pos < end) {
|
|
1242
|
-
const tag = reader.uint32();
|
|
1243
|
-
if (tag >>> 3 === 3 && tag === 26) {
|
|
1244
|
-
data = new Uint8Array(reader.bytes());
|
|
1245
|
-
continue;
|
|
1246
|
-
}
|
|
1247
|
-
if ((tag & 7) === 4 || tag === 0) break;
|
|
1248
|
-
reader.skip(tag & 7);
|
|
1249
|
-
}
|
|
1250
|
-
return { data };
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
1264
|
// src/hooks/use-relay-frame-stream.ts
|
|
1254
1265
|
import { useEffect as useEffect4, useRef as useRef3, useState as useState2 } from "react";
|
|
1255
1266
|
var TAG_OPEN = 1;
|
|
@@ -1580,7 +1591,15 @@ import {
|
|
|
1580
1591
|
ttydResizeFrame,
|
|
1581
1592
|
TtydServerCommand
|
|
1582
1593
|
} from "@opengeni/sdk";
|
|
1583
|
-
import { useEffect as useEffect6, useMemo as
|
|
1594
|
+
import { useEffect as useEffect6, useMemo as useMemo3, useRef as useRef5, useState as useState4 } from "react";
|
|
1595
|
+
var MAX_PENDING_TERMINAL_INPUT_CODE_UNITS = 64 * 1024;
|
|
1596
|
+
var TERMINAL_CONNECT_EXPIRY_SKEW_MS = 5e3;
|
|
1597
|
+
function terminalStreamCredentialUsable(capability, nowMs = Date.now()) {
|
|
1598
|
+
if (capability?.transport !== "pty-ws" || !capability.url) return false;
|
|
1599
|
+
if (!capability.expiresAt) return true;
|
|
1600
|
+
const expiresAt = Date.parse(capability.expiresAt);
|
|
1601
|
+
return Number.isFinite(expiresAt) && expiresAt > nowMs + TERMINAL_CONNECT_EXPIRY_SKEW_MS;
|
|
1602
|
+
}
|
|
1584
1603
|
function decodeFrame(data) {
|
|
1585
1604
|
if (typeof data === "string") {
|
|
1586
1605
|
return { command: data.charAt(0), payload: data.slice(1) };
|
|
@@ -1590,10 +1609,19 @@ function decodeFrame(data) {
|
|
|
1590
1609
|
const payload = bytes.length > 1 ? new TextDecoder().decode(bytes.subarray(1)) : "";
|
|
1591
1610
|
return { command, payload };
|
|
1592
1611
|
}
|
|
1612
|
+
function closeSocket(socket) {
|
|
1613
|
+
try {
|
|
1614
|
+
socket?.close();
|
|
1615
|
+
} catch {
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1593
1618
|
function useTerminalStream(options) {
|
|
1594
1619
|
const { capability, onOutput, onTitle, initialCols, initialRows } = options;
|
|
1595
1620
|
const [status, setStatus] = useState4("closed");
|
|
1596
1621
|
const wsRef = useRef5(null);
|
|
1622
|
+
const pendingInputRef = useRef5("");
|
|
1623
|
+
const socketFailedRef = useRef5(false);
|
|
1624
|
+
const socketAuthenticatedRef = useRef5(false);
|
|
1597
1625
|
const sizeRef = useRef5({
|
|
1598
1626
|
cols: initialCols ?? 80,
|
|
1599
1627
|
rows: initialRows ?? 24
|
|
@@ -1605,9 +1633,22 @@ function useTerminalStream(options) {
|
|
|
1605
1633
|
const transport = capability?.transport ?? null;
|
|
1606
1634
|
const url = capability?.url ?? null;
|
|
1607
1635
|
const token = capability?.token ?? null;
|
|
1636
|
+
const expiresAt = capability?.expiresAt ?? null;
|
|
1608
1637
|
useEffect6(() => {
|
|
1609
1638
|
if (typeof window === "undefined" || typeof WebSocket === "undefined") return;
|
|
1610
|
-
if (transport !== "pty-ws"
|
|
1639
|
+
if (transport !== "pty-ws") {
|
|
1640
|
+
pendingInputRef.current = "";
|
|
1641
|
+
socketAuthenticatedRef.current = false;
|
|
1642
|
+
setStatus("closed");
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
socketFailedRef.current = false;
|
|
1646
|
+
socketAuthenticatedRef.current = false;
|
|
1647
|
+
if (!url) {
|
|
1648
|
+
setStatus("closed");
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {
|
|
1611
1652
|
setStatus("closed");
|
|
1612
1653
|
return;
|
|
1613
1654
|
}
|
|
@@ -1617,6 +1658,7 @@ function useTerminalStream(options) {
|
|
|
1617
1658
|
try {
|
|
1618
1659
|
socket = new WebSocket(terminalSocketUrl({ url }), TTYD_SUBPROTOCOL);
|
|
1619
1660
|
} catch {
|
|
1661
|
+
socketFailedRef.current = true;
|
|
1620
1662
|
setStatus("error");
|
|
1621
1663
|
return;
|
|
1622
1664
|
}
|
|
@@ -1627,7 +1669,16 @@ function useTerminalStream(options) {
|
|
|
1627
1669
|
try {
|
|
1628
1670
|
socket.send(ttydAuthFrame({ columns: sizeRef.current.cols, rows: sizeRef.current.rows }));
|
|
1629
1671
|
socket.send(ttydResizeFrame(sizeRef.current.cols, sizeRef.current.rows));
|
|
1672
|
+
if (pendingInputRef.current.length > 0) {
|
|
1673
|
+
socket.send(ttydInputFrame(pendingInputRef.current));
|
|
1674
|
+
pendingInputRef.current = "";
|
|
1675
|
+
}
|
|
1676
|
+
socketAuthenticatedRef.current = true;
|
|
1630
1677
|
} catch {
|
|
1678
|
+
socketFailedRef.current = true;
|
|
1679
|
+
setStatus("error");
|
|
1680
|
+
closeSocket(socket);
|
|
1681
|
+
return;
|
|
1631
1682
|
}
|
|
1632
1683
|
setStatus("open");
|
|
1633
1684
|
};
|
|
@@ -1647,39 +1698,55 @@ function useTerminalStream(options) {
|
|
|
1647
1698
|
}
|
|
1648
1699
|
};
|
|
1649
1700
|
socket.onerror = () => {
|
|
1650
|
-
if (!disposed)
|
|
1701
|
+
if (!disposed) {
|
|
1702
|
+
socketFailedRef.current = true;
|
|
1703
|
+
setStatus("error");
|
|
1704
|
+
}
|
|
1651
1705
|
};
|
|
1652
1706
|
socket.onclose = () => {
|
|
1653
|
-
if (
|
|
1707
|
+
if (wsRef.current === socket) wsRef.current = null;
|
|
1708
|
+
socketAuthenticatedRef.current = false;
|
|
1709
|
+
if (!disposed) setStatus(socketFailedRef.current ? "error" : "closed");
|
|
1654
1710
|
};
|
|
1655
1711
|
return () => {
|
|
1656
1712
|
disposed = true;
|
|
1657
1713
|
wsRef.current = null;
|
|
1714
|
+
socketAuthenticatedRef.current = false;
|
|
1658
1715
|
socket.onopen = null;
|
|
1659
1716
|
socket.onmessage = null;
|
|
1660
1717
|
socket.onerror = null;
|
|
1661
1718
|
socket.onclose = null;
|
|
1662
|
-
|
|
1663
|
-
socket.close();
|
|
1664
|
-
} catch {
|
|
1665
|
-
}
|
|
1719
|
+
closeSocket(socket);
|
|
1666
1720
|
};
|
|
1667
|
-
}, [transport, url, token]);
|
|
1668
|
-
return
|
|
1721
|
+
}, [transport, url, token, expiresAt]);
|
|
1722
|
+
return useMemo3(() => {
|
|
1669
1723
|
const write = (data) => {
|
|
1670
1724
|
const ws = wsRef.current;
|
|
1671
|
-
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
1725
|
+
if (ws && ws.readyState === WebSocket.OPEN && socketAuthenticatedRef.current) {
|
|
1672
1726
|
try {
|
|
1673
1727
|
ws.send(ttydInputFrame(data));
|
|
1674
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;
|
|
1675
1741
|
}
|
|
1742
|
+
pendingInputRef.current += data;
|
|
1676
1743
|
}
|
|
1677
1744
|
};
|
|
1678
1745
|
const resize = (cols, rows) => {
|
|
1679
1746
|
if (cols <= 0 || rows <= 0) return;
|
|
1680
1747
|
sizeRef.current = { cols, rows };
|
|
1681
1748
|
const ws = wsRef.current;
|
|
1682
|
-
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
1749
|
+
if (ws && ws.readyState === WebSocket.OPEN && socketAuthenticatedRef.current) {
|
|
1683
1750
|
try {
|
|
1684
1751
|
ws.send(ttydResizeFrame(cols, rows));
|
|
1685
1752
|
} catch {
|
|
@@ -1689,20 +1756,19 @@ function useTerminalStream(options) {
|
|
|
1689
1756
|
const disconnect = () => {
|
|
1690
1757
|
const ws = wsRef.current;
|
|
1691
1758
|
wsRef.current = null;
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
}
|
|
1759
|
+
pendingInputRef.current = "";
|
|
1760
|
+
socketFailedRef.current = false;
|
|
1761
|
+
socketAuthenticatedRef.current = false;
|
|
1762
|
+
setStatus("closed");
|
|
1763
|
+
closeSocket(ws);
|
|
1698
1764
|
};
|
|
1699
1765
|
return { connected: status === "open", status, write, resize, disconnect };
|
|
1700
|
-
}, [status]);
|
|
1766
|
+
}, [status, transport]);
|
|
1701
1767
|
}
|
|
1702
1768
|
|
|
1703
1769
|
// src/hooks/use-sandbox-terminal.ts
|
|
1704
1770
|
import { OpenGeniApiError as OpenGeniApiError2 } from "@opengeni/sdk";
|
|
1705
|
-
import { useCallback as useCallback11, useEffect as useEffect7, useMemo as
|
|
1771
|
+
import { useCallback as useCallback11, useEffect as useEffect7, useMemo as useMemo4, useRef as useRef6, useState as useState5 } from "react";
|
|
1706
1772
|
function useSandboxTerminal(sessionId, options) {
|
|
1707
1773
|
const { client, workspaceId } = useOpenGeni(options);
|
|
1708
1774
|
const includeAgentFirehose = options.includeAgentFirehose ?? true;
|
|
@@ -1722,7 +1788,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1722
1788
|
setOpenError(null);
|
|
1723
1789
|
}, [identityKey]);
|
|
1724
1790
|
const openInFlight = useRef6(false);
|
|
1725
|
-
const boxWarm = liveness === void 0 || liveness
|
|
1791
|
+
const boxWarm = liveness === void 0 || sandboxAcceptsLiveIo(liveness);
|
|
1726
1792
|
useEffect7(() => {
|
|
1727
1793
|
if (!interactive || !sessionId || ptyFilter || !boxWarm) {
|
|
1728
1794
|
setOpenError(null);
|
|
@@ -1753,7 +1819,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1753
1819
|
});
|
|
1754
1820
|
};
|
|
1755
1821
|
}, [interactive, client, workspaceId, sessionId, ptyFilter, boxWarm, reopenNonce]);
|
|
1756
|
-
const { chunks, openPty, supportsInput } =
|
|
1822
|
+
const { chunks, openPty, supportsInput } = useMemo4(() => {
|
|
1757
1823
|
const out = [];
|
|
1758
1824
|
const open = /* @__PURE__ */ new Map();
|
|
1759
1825
|
let lastOpened = null;
|
|
@@ -1806,7 +1872,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1806
1872
|
const identityMatches = stateIdentity === identityKey;
|
|
1807
1873
|
const activePtyId = identityMatches ? openedPtyId ?? openPty : null;
|
|
1808
1874
|
const canWrite = openedPtyId !== null || supportsInput;
|
|
1809
|
-
const write =
|
|
1875
|
+
const write = useMemo4(() => {
|
|
1810
1876
|
if (!activePtyId || !canWrite || !sessionId) return null;
|
|
1811
1877
|
const writeIdentity = identityKey;
|
|
1812
1878
|
return (data) => {
|
|
@@ -1834,7 +1900,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1834
1900
|
}
|
|
1835
1901
|
|
|
1836
1902
|
// src/hooks/use-sandbox-files.ts
|
|
1837
|
-
import { useCallback as useCallback12, useEffect as useEffect8, useMemo as
|
|
1903
|
+
import { useCallback as useCallback12, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef7, useState as useState6 } from "react";
|
|
1838
1904
|
var CapturedFileUnavailableError = class extends Error {
|
|
1839
1905
|
constructor(path, reason) {
|
|
1840
1906
|
super(
|
|
@@ -2068,9 +2134,13 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2068
2134
|
const repoPathsKey = [
|
|
2069
2135
|
...new Set((options.repoPaths?.length ? options.repoPaths : [rootPath]).map(normalizeRoot))
|
|
2070
2136
|
].join("\0");
|
|
2071
|
-
const repoPaths =
|
|
2137
|
+
const repoPaths = useMemo5(() => repoPathsKey.split("\0"), [repoPathsKey]);
|
|
2072
2138
|
const capture = options.capture ?? null;
|
|
2073
|
-
const isLive2 = options.liveness
|
|
2139
|
+
const isLive2 = sandboxAcceptsLiveIo(options.liveness);
|
|
2140
|
+
const acceptsEventReads = options.liveness === void 0 || isLive2;
|
|
2141
|
+
const acceptsEventReadsRef = useRef7(acceptsEventReads);
|
|
2142
|
+
acceptsEventReadsRef.current = acceptsEventReads;
|
|
2143
|
+
const hasLiveIoFence = options.liveness !== void 0;
|
|
2074
2144
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${rootPath}\0${repoPathsKey}`;
|
|
2075
2145
|
const [tree, setTree] = useState6([]);
|
|
2076
2146
|
const treeRef = useRef7([]);
|
|
@@ -2087,6 +2157,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2087
2157
|
const refreshGenerationRef = useRef7(0);
|
|
2088
2158
|
const refreshAbortRef = useRef7(null);
|
|
2089
2159
|
const identityAbortRef = useRef7(new AbortController());
|
|
2160
|
+
const eventReadAbortRef = useRef7(new AbortController());
|
|
2090
2161
|
const identityGenerationRef = useRef7(0);
|
|
2091
2162
|
const lastSeqRef = useRef7(0);
|
|
2092
2163
|
const pendingParentsRef = useRef7(/* @__PURE__ */ new Set());
|
|
@@ -2345,18 +2416,14 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2345
2416
|
[client, workspaceId, sessionId, capture, source]
|
|
2346
2417
|
);
|
|
2347
2418
|
const reconcilePath = useCallback12(
|
|
2348
|
-
async (path) => {
|
|
2419
|
+
async (path, requestSignal) => {
|
|
2349
2420
|
if (!sessionId) return;
|
|
2350
2421
|
const identityGeneration = identityGenerationRef.current;
|
|
2351
2422
|
const identitySignal = identityAbortRef.current.signal;
|
|
2423
|
+
const signal = requestSignal ? AbortSignal.any([identitySignal, requestSignal]) : identitySignal;
|
|
2352
2424
|
if (!parentIsLoaded(treeRef.current, path)) return;
|
|
2353
2425
|
try {
|
|
2354
|
-
const listed = await client.fsList(
|
|
2355
|
-
workspaceId,
|
|
2356
|
-
sessionId,
|
|
2357
|
-
{ path, depth: 1 },
|
|
2358
|
-
{ signal: identitySignal }
|
|
2359
|
-
);
|
|
2426
|
+
const listed = await client.fsList(workspaceId, sessionId, { path, depth: 1 }, { signal });
|
|
2360
2427
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
2361
2428
|
const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));
|
|
2362
2429
|
if (path === "") setTree((prev) => applyStatus(mergeRootChildren(prev, children)));
|
|
@@ -2532,6 +2599,8 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2532
2599
|
refreshAbortRef.current?.abort();
|
|
2533
2600
|
refreshAbortRef.current = null;
|
|
2534
2601
|
refreshGenerationRef.current += 1;
|
|
2602
|
+
eventReadAbortRef.current.abort();
|
|
2603
|
+
eventReadAbortRef.current = new AbortController();
|
|
2535
2604
|
const identityChanged = previousIdentityRef.current !== identityKey;
|
|
2536
2605
|
previousIdentityRef.current = identityKey;
|
|
2537
2606
|
if (identityChanged || !enabled) {
|
|
@@ -2575,55 +2644,76 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2575
2644
|
}
|
|
2576
2645
|
return;
|
|
2577
2646
|
}
|
|
2578
|
-
if (isLive2 || !currentCapture) {
|
|
2647
|
+
if (isLive2 || !hasLiveIoFence && !currentCapture) {
|
|
2579
2648
|
void refresh();
|
|
2580
2649
|
}
|
|
2581
2650
|
return () => {
|
|
2582
2651
|
refreshAbortRef.current?.abort();
|
|
2583
2652
|
refreshAbortRef.current = null;
|
|
2584
2653
|
refreshGenerationRef.current += 1;
|
|
2654
|
+
eventReadAbortRef.current.abort();
|
|
2585
2655
|
};
|
|
2586
|
-
}, [
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
);
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2656
|
+
}, [
|
|
2657
|
+
enabled,
|
|
2658
|
+
active,
|
|
2659
|
+
isLive2,
|
|
2660
|
+
hasLiveIoFence,
|
|
2661
|
+
captureRevision,
|
|
2662
|
+
identityKey,
|
|
2663
|
+
refresh,
|
|
2664
|
+
seedFromCapture
|
|
2665
|
+
]);
|
|
2666
|
+
const refreshGitOverlay = useCallback12(
|
|
2667
|
+
async (requestSignal) => {
|
|
2668
|
+
if (!sessionId) return;
|
|
2669
|
+
const identityGeneration = identityGenerationRef.current;
|
|
2670
|
+
const identitySignal = identityAbortRef.current.signal;
|
|
2671
|
+
const signal = requestSignal ? AbortSignal.any([identitySignal, requestSignal]) : identitySignal;
|
|
2672
|
+
setGitLoading(true);
|
|
2673
|
+
try {
|
|
2674
|
+
const batch = await client.gitReadBatch(
|
|
2675
|
+
workspaceId,
|
|
2676
|
+
sessionId,
|
|
2677
|
+
{ requests: repoPaths.map((root) => ({ status: { path: root } })) },
|
|
2678
|
+
{ signal }
|
|
2679
|
+
);
|
|
2680
|
+
const statuses = batch.results.map((result, index) => ({
|
|
2681
|
+
root: repoPaths[index] ?? "",
|
|
2682
|
+
status: result.status
|
|
2683
|
+
}));
|
|
2684
|
+
if (identityGenerationRef.current !== identityGeneration) return;
|
|
2685
|
+
const overlay = /* @__PURE__ */ new Map();
|
|
2686
|
+
for (const { root, status } of statuses) {
|
|
2687
|
+
for (const file of status.files) {
|
|
2688
|
+
const code = file.worktree ?? file.index;
|
|
2689
|
+
const mapped = code ? GIT_STATUS_TO_TREE[code] : void 0;
|
|
2690
|
+
if (mapped) overlay.set(qualifyStatusPath(root, file.path), mapped);
|
|
2691
|
+
}
|
|
2610
2692
|
}
|
|
2693
|
+
statusRef.current = overlay;
|
|
2694
|
+
setGitSummary(summarizeStatuses(statuses));
|
|
2695
|
+
setTree((prev) => applyStatus(prev));
|
|
2696
|
+
} catch {
|
|
2697
|
+
} finally {
|
|
2698
|
+
if (identityGenerationRef.current === identityGeneration) setGitLoading(false);
|
|
2611
2699
|
}
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
} catch {
|
|
2616
|
-
} finally {
|
|
2617
|
-
if (identityGenerationRef.current === identityGeneration) setGitLoading(false);
|
|
2618
|
-
}
|
|
2619
|
-
}, [client, workspaceId, sessionId, repoPaths, applyStatus]);
|
|
2700
|
+
},
|
|
2701
|
+
[client, workspaceId, sessionId, repoPaths, applyStatus]
|
|
2702
|
+
);
|
|
2620
2703
|
const events = options.events;
|
|
2621
2704
|
useEffect8(() => {
|
|
2622
2705
|
if (!enabled || !events) return;
|
|
2623
|
-
if (!active) {
|
|
2706
|
+
if (!active || !acceptsEventReads) {
|
|
2624
2707
|
for (const event of events) {
|
|
2625
2708
|
if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;
|
|
2626
2709
|
}
|
|
2710
|
+
if (debounceRef.current) {
|
|
2711
|
+
clearTimeout(debounceRef.current);
|
|
2712
|
+
debounceRef.current = null;
|
|
2713
|
+
}
|
|
2714
|
+
pendingParentsRef.current = /* @__PURE__ */ new Set();
|
|
2715
|
+
pendingGitRef.current = false;
|
|
2716
|
+
pendingAgentToolRef.current = false;
|
|
2627
2717
|
return;
|
|
2628
2718
|
}
|
|
2629
2719
|
let sawNew = false;
|
|
@@ -2672,6 +2762,12 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2672
2762
|
debounceRef.current = setTimeout(() => {
|
|
2673
2763
|
debounceRef.current = null;
|
|
2674
2764
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
2765
|
+
if (!acceptsEventReadsRef.current) {
|
|
2766
|
+
pendingParentsRef.current = /* @__PURE__ */ new Set();
|
|
2767
|
+
pendingGitRef.current = false;
|
|
2768
|
+
pendingAgentToolRef.current = false;
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2675
2771
|
if (sawCommandDelta) {
|
|
2676
2772
|
lastCommandRefreshAtRef.current = Date.now();
|
|
2677
2773
|
setContentRevision((revision) => revision + 1);
|
|
@@ -2682,17 +2778,18 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2682
2778
|
pendingGitRef.current = false;
|
|
2683
2779
|
const wantAgentTool = pendingAgentToolRef.current;
|
|
2684
2780
|
pendingAgentToolRef.current = false;
|
|
2781
|
+
const eventReadSignal = eventReadAbortRef.current.signal;
|
|
2685
2782
|
void (async () => {
|
|
2686
2783
|
const paths = wantAgentTool ? loadedDirectoryPaths(treeRef.current) : [...parents];
|
|
2687
2784
|
await Promise.all([
|
|
2688
|
-
wantGit ? refreshGitOverlay() : Promise.resolve(),
|
|
2689
|
-
Promise.all(paths.map((path) => reconcilePath(path)))
|
|
2785
|
+
wantGit ? refreshGitOverlay(eventReadSignal) : Promise.resolve(),
|
|
2786
|
+
Promise.all(paths.map((path) => reconcilePath(path, eventReadSignal)))
|
|
2690
2787
|
]);
|
|
2691
2788
|
})();
|
|
2692
2789
|
}, delay);
|
|
2693
|
-
}, [enabled, active, events, reconcilePath, refreshGitOverlay]);
|
|
2790
|
+
}, [enabled, active, acceptsEventReads, events, reconcilePath, refreshGitOverlay]);
|
|
2694
2791
|
useEffect8(() => {
|
|
2695
|
-
if (active) return;
|
|
2792
|
+
if (active && acceptsEventReads) return;
|
|
2696
2793
|
if (debounceRef.current) {
|
|
2697
2794
|
clearTimeout(debounceRef.current);
|
|
2698
2795
|
debounceRef.current = null;
|
|
@@ -2700,11 +2797,12 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2700
2797
|
pendingParentsRef.current = /* @__PURE__ */ new Set();
|
|
2701
2798
|
pendingGitRef.current = false;
|
|
2702
2799
|
pendingAgentToolRef.current = false;
|
|
2703
|
-
}, [active]);
|
|
2800
|
+
}, [active, acceptsEventReads]);
|
|
2704
2801
|
useEffect8(
|
|
2705
2802
|
() => () => {
|
|
2706
2803
|
refreshAbortRef.current?.abort();
|
|
2707
2804
|
identityAbortRef.current.abort();
|
|
2805
|
+
eventReadAbortRef.current.abort();
|
|
2708
2806
|
identityGenerationRef.current += 1;
|
|
2709
2807
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
2710
2808
|
},
|
|
@@ -2733,7 +2831,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2733
2831
|
}
|
|
2734
2832
|
|
|
2735
2833
|
// src/hooks/use-sandbox-git.ts
|
|
2736
|
-
import { useCallback as useCallback13, useEffect as useEffect9, useMemo as
|
|
2834
|
+
import { useCallback as useCallback13, useEffect as useEffect9, useMemo as useMemo6, useRef as useRef8, useState as useState7 } from "react";
|
|
2737
2835
|
function normalizeRoot2(root) {
|
|
2738
2836
|
const normalized = root.replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
2739
2837
|
return normalized === "." ? "" : normalized;
|
|
@@ -2754,6 +2852,7 @@ function qualifyDiff(repoRoot, file) {
|
|
|
2754
2852
|
function uniqueRoots(roots) {
|
|
2755
2853
|
return [...new Set(roots.map(normalizeRoot2))].sort((a, b) => a.localeCompare(b));
|
|
2756
2854
|
}
|
|
2855
|
+
var GIT_READ_BATCH_REQUEST_LIMIT = 32;
|
|
2757
2856
|
function repoForPath(manifest, repoPath) {
|
|
2758
2857
|
const want = normalizeRoot2(repoPath);
|
|
2759
2858
|
const exact = manifest.repos.find((r) => normalizeRoot2(r.root) === want);
|
|
@@ -2798,11 +2897,15 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2798
2897
|
const repoPathsKey = uniqueRoots(
|
|
2799
2898
|
options.repoPaths && options.repoPaths.length > 0 ? options.repoPaths : [repoPath]
|
|
2800
2899
|
).join("\0");
|
|
2801
|
-
const repoPaths =
|
|
2900
|
+
const repoPaths = useMemo6(() => repoPathsKey.split("\0"), [repoPathsKey]);
|
|
2802
2901
|
const comparison = options.comparison ?? (options.staged ? "staged" : "working");
|
|
2803
2902
|
const hasAdvertisedRepoPaths = (options.repoPaths?.length ?? 0) > 0;
|
|
2804
2903
|
const capture = comparison === "staged" ? null : options.capture ?? null;
|
|
2805
|
-
const isLive2 = options.liveness
|
|
2904
|
+
const isLive2 = sandboxAcceptsLiveIo(options.liveness);
|
|
2905
|
+
const acceptsEventReads = options.liveness === void 0 || isLive2;
|
|
2906
|
+
const acceptsEventReadsRef = useRef8(acceptsEventReads);
|
|
2907
|
+
acceptsEventReadsRef.current = acceptsEventReads;
|
|
2908
|
+
const hasLiveIoFence = options.liveness !== void 0;
|
|
2806
2909
|
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${repoPathsKey}\0${workspaceWide}\0${comparison}`;
|
|
2807
2910
|
const [diff, setDiff] = useState7([]);
|
|
2808
2911
|
const [branch, setBranch] = useState7(null);
|
|
@@ -2837,29 +2940,42 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2837
2940
|
},
|
|
2838
2941
|
{ signal: refreshAbort.signal }
|
|
2839
2942
|
);
|
|
2840
|
-
const prefetched = hasAdvertisedRepoPaths ? await
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2943
|
+
const prefetched = hasAdvertisedRepoPaths ? await (async () => {
|
|
2944
|
+
const prefetchedRepos = [];
|
|
2945
|
+
for (let offset = 0; offset < repoPaths.length; offset += GIT_READ_BATCH_REQUEST_LIMIT) {
|
|
2946
|
+
const roots2 = repoPaths.slice(offset, offset + GIT_READ_BATCH_REQUEST_LIMIT);
|
|
2947
|
+
const batch = await client.gitReadBatch(
|
|
2948
|
+
workspaceId,
|
|
2949
|
+
sessionId,
|
|
2950
|
+
{
|
|
2951
|
+
requests: roots2.map((root) => ({
|
|
2952
|
+
status: { path: root },
|
|
2953
|
+
diff: {
|
|
2954
|
+
path: root,
|
|
2955
|
+
...comparison === "branch" ? { fromRef: "origin/HEAD", includeUntracked: true } : comparison === "working" ? { fromRef: "HEAD", includeUntracked: true } : { staged: true, includeUntracked: false }
|
|
2956
|
+
}
|
|
2957
|
+
}))
|
|
2958
|
+
},
|
|
2959
|
+
{ signal: refreshAbort.signal }
|
|
2960
|
+
);
|
|
2961
|
+
if (batch.results.length !== roots2.length) {
|
|
2962
|
+
throw new Error(
|
|
2963
|
+
`Workspace Git batch returned ${batch.results.length} results for ${roots2.length} repositories.`
|
|
2964
|
+
);
|
|
2860
2965
|
}
|
|
2861
|
-
|
|
2862
|
-
|
|
2966
|
+
batch.results.forEach((item, index) => {
|
|
2967
|
+
prefetchedRepos.push({
|
|
2968
|
+
root: roots2[index],
|
|
2969
|
+
status: item.status,
|
|
2970
|
+
result: item.diff ?? {
|
|
2971
|
+
files: [],
|
|
2972
|
+
revision: item.status.revision
|
|
2973
|
+
}
|
|
2974
|
+
});
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
return prefetchedRepos;
|
|
2978
|
+
})() : null;
|
|
2863
2979
|
const statuses = prefetched ?? await Promise.all(
|
|
2864
2980
|
repoPaths.map(async (root) => ({
|
|
2865
2981
|
root,
|
|
@@ -2991,7 +3107,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2991
3107
|
if (!active) setLoading(false);
|
|
2992
3108
|
return;
|
|
2993
3109
|
}
|
|
2994
|
-
if (isLive2 || !currentCapture) {
|
|
3110
|
+
if (isLive2 || !hasLiveIoFence && !currentCapture) {
|
|
2995
3111
|
void refresh();
|
|
2996
3112
|
}
|
|
2997
3113
|
return () => {
|
|
@@ -2999,10 +3115,29 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2999
3115
|
refreshAbortRef.current = null;
|
|
3000
3116
|
refreshGenerationRef.current += 1;
|
|
3001
3117
|
};
|
|
3002
|
-
}, [
|
|
3118
|
+
}, [
|
|
3119
|
+
enabled,
|
|
3120
|
+
active,
|
|
3121
|
+
isLive2,
|
|
3122
|
+
hasLiveIoFence,
|
|
3123
|
+
captureRevision,
|
|
3124
|
+
identityKey,
|
|
3125
|
+
refresh,
|
|
3126
|
+
seedFromCapture
|
|
3127
|
+
]);
|
|
3003
3128
|
const events = options.events;
|
|
3004
3129
|
useEffect9(() => {
|
|
3005
|
-
if (!enabled || !
|
|
3130
|
+
if (!enabled || !events) {
|
|
3131
|
+
if (commandRefreshTimerRef.current) {
|
|
3132
|
+
clearTimeout(commandRefreshTimerRef.current);
|
|
3133
|
+
commandRefreshTimerRef.current = null;
|
|
3134
|
+
}
|
|
3135
|
+
return;
|
|
3136
|
+
}
|
|
3137
|
+
if (!active || !acceptsEventReads) {
|
|
3138
|
+
for (const event of events) {
|
|
3139
|
+
if (event.sequence > lastChangeRef.current) lastChangeRef.current = event.sequence;
|
|
3140
|
+
}
|
|
3006
3141
|
if (commandRefreshTimerRef.current) {
|
|
3007
3142
|
clearTimeout(commandRefreshTimerRef.current);
|
|
3008
3143
|
commandRefreshTimerRef.current = null;
|
|
@@ -3027,15 +3162,15 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
3027
3162
|
if (immediate) {
|
|
3028
3163
|
if (commandRefreshTimerRef.current) clearTimeout(commandRefreshTimerRef.current);
|
|
3029
3164
|
commandRefreshTimerRef.current = null;
|
|
3030
|
-
void refresh();
|
|
3165
|
+
if (acceptsEventReadsRef.current) void refresh();
|
|
3031
3166
|
} else if (commandDelta && !commandRefreshTimerRef.current) {
|
|
3032
3167
|
commandRefreshTimerRef.current = setTimeout(() => {
|
|
3033
3168
|
commandRefreshTimerRef.current = null;
|
|
3034
|
-
void refresh();
|
|
3169
|
+
if (acceptsEventReadsRef.current) void refresh();
|
|
3035
3170
|
}, 1e3);
|
|
3036
3171
|
}
|
|
3037
3172
|
}
|
|
3038
|
-
}, [enabled, active, events, refresh]);
|
|
3173
|
+
}, [enabled, active, acceptsEventReads, events, refresh]);
|
|
3039
3174
|
useEffect9(
|
|
3040
3175
|
() => () => {
|
|
3041
3176
|
if (commandRefreshTimerRef.current) clearTimeout(commandRefreshTimerRef.current);
|
|
@@ -3258,7 +3393,7 @@ function useWorkspaceCapture(sessionId, options = {}) {
|
|
|
3258
3393
|
// src/hooks/use-workspace-edit.ts
|
|
3259
3394
|
import { useCallback as useCallback15, useEffect as useEffect11, useRef as useRef10, useState as useState9 } from "react";
|
|
3260
3395
|
function isLive(liveness) {
|
|
3261
|
-
return liveness
|
|
3396
|
+
return sandboxAcceptsLiveIo(liveness);
|
|
3262
3397
|
}
|
|
3263
3398
|
function useWorkspaceEdit(sessionId, options = {}) {
|
|
3264
3399
|
const { client, workspaceId } = useOpenGeni(options);
|
|
@@ -3415,7 +3550,7 @@ function useWorkspaceEdit(sessionId, options = {}) {
|
|
|
3415
3550
|
}
|
|
3416
3551
|
|
|
3417
3552
|
// src/hooks/use-machine-chip.ts
|
|
3418
|
-
import { useMemo as
|
|
3553
|
+
import { useMemo as useMemo7 } from "react";
|
|
3419
3554
|
function formatAsOf(capturedAt, now) {
|
|
3420
3555
|
const then = Date.parse(capturedAt);
|
|
3421
3556
|
if (Number.isNaN(then)) return "recently";
|
|
@@ -3432,7 +3567,7 @@ function deriveMachineChip(input) {
|
|
|
3432
3567
|
const now = input.now ?? Date.now();
|
|
3433
3568
|
const asOf = input.capturedAt ?? null;
|
|
3434
3569
|
const offlineLabel = asOf ? `Offline \u2014 as of ${formatAsOf(asOf, now)}` : "Offline";
|
|
3435
|
-
if (input.liveness
|
|
3570
|
+
if (sandboxAcceptsLiveIo(input.liveness)) {
|
|
3436
3571
|
return { state: "live", label: "Live", asOf: null };
|
|
3437
3572
|
}
|
|
3438
3573
|
const selfhostedOffline = input.activeIsSelfhosted === true && input.activeMachineState === "offline";
|
|
@@ -3452,7 +3587,7 @@ function useMachineChip(input) {
|
|
|
3452
3587
|
capturedAt,
|
|
3453
3588
|
now
|
|
3454
3589
|
} = input;
|
|
3455
|
-
return
|
|
3590
|
+
return useMemo7(
|
|
3456
3591
|
() => deriveMachineChip({
|
|
3457
3592
|
liveness,
|
|
3458
3593
|
capabilitiesState,
|
|
@@ -3679,6 +3814,17 @@ function ChatComposer({
|
|
|
3679
3814
|
/* @__PURE__ */ jsx2(RestoredResources, {}),
|
|
3680
3815
|
/* @__PURE__ */ jsx2(Attachments, {}),
|
|
3681
3816
|
header,
|
|
3817
|
+
composer.annotations && composer.annotations.length > 0 ? /* @__PURE__ */ jsx2("div", { className: "px-3 pt-2 sm:px-4", children: /* @__PURE__ */ jsx2(
|
|
3818
|
+
TimelineAnnotationsChip,
|
|
3819
|
+
{
|
|
3820
|
+
annotations: composer.annotations,
|
|
3821
|
+
editable: true,
|
|
3822
|
+
focusAnnotationId: composer.annotationReviewTargetId,
|
|
3823
|
+
onFocusConsumed: composer.clearAnnotationReviewTarget,
|
|
3824
|
+
onUpdate: composer.updateAnnotation,
|
|
3825
|
+
onRemove: composer.removeAnnotation
|
|
3826
|
+
}
|
|
3827
|
+
) }) : null,
|
|
3682
3828
|
/* @__PURE__ */ jsx2(Input, { placeholder, autoFocus }),
|
|
3683
3829
|
controller.confirmState ? /* @__PURE__ */ jsx2(Confirmation, {}) : /* @__PURE__ */ jsx2(
|
|
3684
3830
|
Footer,
|
|
@@ -3964,6 +4110,19 @@ async function attachRenderer(prefer, loaders, onTier) {
|
|
|
3964
4110
|
|
|
3965
4111
|
// src/components/sandbox-terminal.tsx
|
|
3966
4112
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4113
|
+
function terminalSurfaceState(input) {
|
|
4114
|
+
if (!input.ready) return "loading";
|
|
4115
|
+
if (input.acceptsInput) return "interactive";
|
|
4116
|
+
if (input.inputPending) return "connecting";
|
|
4117
|
+
if (input.ptyStatus === "connecting") return "connecting";
|
|
4118
|
+
if (input.ptyStatus === "error") return "error";
|
|
4119
|
+
if (input.booting) return "waking";
|
|
4120
|
+
return "output-only";
|
|
4121
|
+
}
|
|
4122
|
+
function subscribeTerminalInput(term, sink, enabled) {
|
|
4123
|
+
if (!enabled || !term || !sink) return null;
|
|
4124
|
+
return term.onData(sink);
|
|
4125
|
+
}
|
|
3967
4126
|
function clearTerminalBootStatus(term) {
|
|
3968
4127
|
term.write("\r\x1B[2K\x1B[2J\x1B[H");
|
|
3969
4128
|
}
|
|
@@ -3999,31 +4158,49 @@ function SandboxTerminal({
|
|
|
3999
4158
|
const wroteFirehoseRef = useRef12(false);
|
|
4000
4159
|
const bootActiveRef = useRef12(false);
|
|
4001
4160
|
const [ready, setReady] = useState11(false);
|
|
4161
|
+
const [inputReady, setInputReady] = useState11(false);
|
|
4002
4162
|
const [activated, setActivated] = useState11(false);
|
|
4003
|
-
const
|
|
4004
|
-
const
|
|
4163
|
+
const ptyDescriptor = terminalCapability?.transport === "pty-ws";
|
|
4164
|
+
const ptyAttachable = terminalCanAcquirePty(terminalCapability);
|
|
4005
4165
|
const {
|
|
4006
4166
|
status: ptyStatus,
|
|
4007
4167
|
write: ptyWrite,
|
|
4008
4168
|
resize: resizePty,
|
|
4009
4169
|
connected: ptyConnected
|
|
4010
4170
|
} = useTerminalStream({
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4171
|
+
// Connect only after xterm exists. This makes the renderer the sole output
|
|
4172
|
+
// owner from the first websocket frame and removes an otherwise unbounded
|
|
4173
|
+
// pre-mount output queue during large command bursts.
|
|
4174
|
+
capability: ptyAttachable && ready ? {
|
|
4175
|
+
transport: "pty-ws",
|
|
4176
|
+
url: ptyDescriptor ? terminalCapability.url : null,
|
|
4177
|
+
token: ptyDescriptor ? terminalCapability.token : null,
|
|
4178
|
+
expiresAt: ptyDescriptor ? terminalCapability.expiresAt : null
|
|
4015
4179
|
} : null,
|
|
4016
4180
|
onOutput: (data) => {
|
|
4017
|
-
|
|
4018
|
-
if (term) term.write(data);
|
|
4019
|
-
else ptyOutputQueueRef.current.push(data);
|
|
4181
|
+
termRef.current?.write(data);
|
|
4020
4182
|
}
|
|
4021
4183
|
});
|
|
4022
|
-
const ptyMode =
|
|
4023
|
-
const
|
|
4024
|
-
const
|
|
4025
|
-
const
|
|
4184
|
+
const ptyMode = ptyDescriptor;
|
|
4185
|
+
const ptyCapturesInput = ptyAttachable && ptyStatus !== "error";
|
|
4186
|
+
const interactive = !readOnly && (ptyAttachable ? ptyCapturesInput : result.write !== null);
|
|
4187
|
+
const acceptsInput = inputReady && (!ptyAttachable || ptyConnected);
|
|
4188
|
+
const inputPending = inputReady && ptyAttachable && !ptyConnected && activated;
|
|
4189
|
+
let terminalModeLabel;
|
|
4190
|
+
if (readOnly) terminalModeLabel = "read-only";
|
|
4191
|
+
else if (!ptyAttachable) terminalModeLabel = acceptsInput ? null : "output only";
|
|
4192
|
+
else if (ptyStatus === "error") terminalModeLabel = "connection error";
|
|
4193
|
+
else if (acceptsInput) terminalModeLabel = null;
|
|
4194
|
+
else terminalModeLabel = activated ? "connecting" : "connect on input";
|
|
4195
|
+
const warm = sandboxAcceptsLiveIo(liveness);
|
|
4026
4196
|
const booting = activated && !ptyMode && !warm && liveness !== null && liveness !== void 0 && result.chunks.length === 0;
|
|
4197
|
+
const surfaceState = terminalSurfaceState({
|
|
4198
|
+
ready,
|
|
4199
|
+
acceptsInput,
|
|
4200
|
+
inputPending,
|
|
4201
|
+
ptyStatus,
|
|
4202
|
+
booting
|
|
4203
|
+
});
|
|
4027
4204
|
function handleActivate() {
|
|
4028
4205
|
if (!activated) setActivated(true);
|
|
4029
4206
|
onActivate?.();
|
|
@@ -4110,10 +4287,6 @@ function SandboxTerminal({
|
|
|
4110
4287
|
requestAnimationFrame(() => {
|
|
4111
4288
|
if (disposed) return;
|
|
4112
4289
|
settle();
|
|
4113
|
-
if (ptyOutputQueueRef.current.length > 0) {
|
|
4114
|
-
for (const data of ptyOutputQueueRef.current) term.write(data);
|
|
4115
|
-
ptyOutputQueueRef.current = [];
|
|
4116
|
-
}
|
|
4117
4290
|
el.setAttribute("data-og-term-ready", "true");
|
|
4118
4291
|
if (typeof globalThis.__OG_TERMINAL_DEBUG__ === "function") {
|
|
4119
4292
|
globalThis.__OG_TERMINAL_DEBUG__({
|
|
@@ -4185,12 +4358,19 @@ function SandboxTerminal({
|
|
|
4185
4358
|
}, [ready, result.chunks, ptyMode]);
|
|
4186
4359
|
useEffect13(() => {
|
|
4187
4360
|
const term = termRef.current;
|
|
4188
|
-
if (!ready || !term || !interactive)
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4361
|
+
if (!ready || !term || !interactive) {
|
|
4362
|
+
setInputReady(false);
|
|
4363
|
+
return;
|
|
4364
|
+
}
|
|
4365
|
+
const sink = ptyAttachable ? ptyWrite : result.write;
|
|
4366
|
+
if (!sink) {
|
|
4367
|
+
setInputReady(false);
|
|
4368
|
+
return;
|
|
4369
|
+
}
|
|
4370
|
+
const sub = subscribeTerminalInput(term, sink, true);
|
|
4371
|
+
setInputReady(sub !== null);
|
|
4372
|
+
return () => sub?.dispose();
|
|
4373
|
+
}, [ready, interactive, ptyAttachable, ptyWrite, result.write]);
|
|
4194
4374
|
useEffect13(() => {
|
|
4195
4375
|
const term = termRef.current;
|
|
4196
4376
|
if (!ready || !term || !ptyMode) return;
|
|
@@ -4273,7 +4453,11 @@ function SandboxTerminal({
|
|
|
4273
4453
|
ref: containerRef,
|
|
4274
4454
|
className: "h-full w-full",
|
|
4275
4455
|
style: { visibility: ready ? "visible" : "hidden" },
|
|
4276
|
-
"data-opengeni-terminal": true
|
|
4456
|
+
"data-opengeni-terminal": true,
|
|
4457
|
+
"data-opengeni-terminal-ready": ready ? "true" : "false",
|
|
4458
|
+
"data-opengeni-terminal-interactive": surfaceState === "interactive" ? "true" : "false",
|
|
4459
|
+
"data-opengeni-terminal-state": surfaceState,
|
|
4460
|
+
"data-opengeni-terminal-status": ptyAttachable ? ptyStatus : "firehose"
|
|
4277
4461
|
}
|
|
4278
4462
|
)
|
|
4279
4463
|
]
|
|
@@ -4343,7 +4527,7 @@ import {
|
|
|
4343
4527
|
useEffect as useEffect15,
|
|
4344
4528
|
useId as useId2,
|
|
4345
4529
|
useLayoutEffect,
|
|
4346
|
-
useMemo as
|
|
4530
|
+
useMemo as useMemo9,
|
|
4347
4531
|
useRef as useRef13,
|
|
4348
4532
|
useState as useState12
|
|
4349
4533
|
} from "react";
|
|
@@ -4351,11 +4535,11 @@ import { AlertDialog } from "radix-ui";
|
|
|
4351
4535
|
import { VList } from "virtua";
|
|
4352
4536
|
|
|
4353
4537
|
// src/lib/use-unicode-fonts.ts
|
|
4354
|
-
import { useEffect as useEffect14, useMemo as
|
|
4538
|
+
import { useEffect as useEffect14, useMemo as useMemo8 } from "react";
|
|
4355
4539
|
var japaneseScript = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/u;
|
|
4356
4540
|
var arabicScript = /[\u0600-\u06ff\u0750-\u077f\u0870-\u08ff\ufb50-\ufdff\ufe70-\ufefc]/u;
|
|
4357
4541
|
function useUnicodeFallbackFonts(values) {
|
|
4358
|
-
const content =
|
|
4542
|
+
const content = useMemo8(() => collectUnicodeContent(values), [values]);
|
|
4359
4543
|
useEffect14(() => {
|
|
4360
4544
|
if (content.japanese) {
|
|
4361
4545
|
void import("./noto-sans-jp-loader.generated-HFGLYBR3.js").then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese)).catch(() => void 0);
|
|
@@ -4502,7 +4686,7 @@ function FileBrowser({
|
|
|
4502
4686
|
[expanded, expand]
|
|
4503
4687
|
);
|
|
4504
4688
|
const cold = result.source !== "live";
|
|
4505
|
-
const renderItems =
|
|
4689
|
+
const renderItems = useMemo9(() => {
|
|
4506
4690
|
const items = [];
|
|
4507
4691
|
if (draftCreate && draftCreate.parent === "") {
|
|
4508
4692
|
items.push({ type: "create", parent: "", kind: draftCreate.kind, depth: 0 });
|
|
@@ -4533,22 +4717,22 @@ function FileBrowser({
|
|
|
4533
4717
|
walk(result.tree, 0);
|
|
4534
4718
|
return items;
|
|
4535
4719
|
}, [result.tree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);
|
|
4536
|
-
const unicodeFontPaths =
|
|
4720
|
+
const unicodeFontPaths = useMemo9(
|
|
4537
4721
|
() => renderItems.flatMap((item) => item.type === "node" ? [item.node.path] : []),
|
|
4538
4722
|
[renderItems]
|
|
4539
4723
|
);
|
|
4540
4724
|
useUnicodeFallbackFonts(unicodeFontPaths);
|
|
4541
|
-
const flatRows =
|
|
4725
|
+
const flatRows = useMemo9(
|
|
4542
4726
|
() => renderItems.flatMap(
|
|
4543
4727
|
(item) => item.type === "node" ? [{ node: item.node, depth: item.depth }] : []
|
|
4544
4728
|
),
|
|
4545
4729
|
[renderItems]
|
|
4546
4730
|
);
|
|
4547
|
-
const rowIndexByPath =
|
|
4731
|
+
const rowIndexByPath = useMemo9(
|
|
4548
4732
|
() => new Map(flatRows.map((row, index) => [row.node.path, index])),
|
|
4549
4733
|
[flatRows]
|
|
4550
4734
|
);
|
|
4551
|
-
const treePositionByPath =
|
|
4735
|
+
const treePositionByPath = useMemo9(() => {
|
|
4552
4736
|
const positions = /* @__PURE__ */ new Map();
|
|
4553
4737
|
const visit = (nodes) => {
|
|
4554
4738
|
nodes.forEach((node, index) => {
|
|
@@ -5489,18 +5673,19 @@ function ContextMenu({
|
|
|
5489
5673
|
// src/components/workbench-changes.tsx
|
|
5490
5674
|
import { ArrowUpRightIcon, FileWarningIcon, HistoryIcon } from "lucide-react";
|
|
5491
5675
|
import {
|
|
5676
|
+
Component,
|
|
5492
5677
|
useCallback as useCallback18,
|
|
5493
5678
|
useEffect as useEffect17,
|
|
5494
5679
|
useId as useId3,
|
|
5495
5680
|
useLayoutEffect as useLayoutEffect2,
|
|
5496
|
-
useMemo as
|
|
5681
|
+
useMemo as useMemo11,
|
|
5497
5682
|
useRef as useRef15,
|
|
5498
5683
|
useState as useState14
|
|
5499
5684
|
} from "react";
|
|
5500
5685
|
import { VList as VList2 } from "virtua";
|
|
5501
5686
|
|
|
5502
5687
|
// src/hooks/use-windowed-sections.ts
|
|
5503
|
-
import { useCallback as useCallback17, useEffect as useEffect16, useMemo as
|
|
5688
|
+
import { useCallback as useCallback17, useEffect as useEffect16, useMemo as useMemo10, useRef as useRef14, useState as useState13 } from "react";
|
|
5504
5689
|
function computeWindowRange(heights, scrollTop, viewport, overscan) {
|
|
5505
5690
|
const n = heights.length;
|
|
5506
5691
|
if (n === 0) return { start: 0, end: 0 };
|
|
@@ -5583,7 +5768,7 @@ function useWindowedSections(opts) {
|
|
|
5583
5768
|
return next;
|
|
5584
5769
|
});
|
|
5585
5770
|
}, []);
|
|
5586
|
-
const offsets =
|
|
5771
|
+
const offsets = useMemo10(() => {
|
|
5587
5772
|
const out = new Array(count + 1);
|
|
5588
5773
|
out[0] = 0;
|
|
5589
5774
|
for (let i = 0; i < count; i++) out[i + 1] = (out[i] ?? 0) + Math.max(heights[i] ?? 0, 0);
|
|
@@ -5648,6 +5833,101 @@ function compactFileLabel(file) {
|
|
|
5648
5833
|
const parent = slash >= 0 ? file.path.slice(0, slash + 1) : "";
|
|
5649
5834
|
return `${STATUS_LETTER[file.status]} \xB7 ${basename}${parent ? ` \u2014 ${parent}` : ""}`;
|
|
5650
5835
|
}
|
|
5836
|
+
var ChangesRailVList = class extends Component {
|
|
5837
|
+
state = {
|
|
5838
|
+
renderedRowCount: this.props.rowCount,
|
|
5839
|
+
resetVersion: 0
|
|
5840
|
+
};
|
|
5841
|
+
host = null;
|
|
5842
|
+
listHandle = null;
|
|
5843
|
+
pendingFocusedPath = null;
|
|
5844
|
+
restoreFrame = null;
|
|
5845
|
+
static getDerivedStateFromProps(props, state) {
|
|
5846
|
+
if (props.rowCount === state.renderedRowCount) return null;
|
|
5847
|
+
return {
|
|
5848
|
+
renderedRowCount: props.rowCount,
|
|
5849
|
+
resetVersion: props.rowCount < state.renderedRowCount ? state.resetVersion + 1 : state.resetVersion
|
|
5850
|
+
};
|
|
5851
|
+
}
|
|
5852
|
+
getSnapshotBeforeUpdate(_previousProps, previousState) {
|
|
5853
|
+
if (previousState.resetVersion === this.state.resetVersion) return null;
|
|
5854
|
+
const scroller = this.host?.firstElementChild;
|
|
5855
|
+
if (!(scroller instanceof HTMLElement)) return null;
|
|
5856
|
+
const active = document.activeElement;
|
|
5857
|
+
const focusedRow = active instanceof HTMLElement && scroller.contains(active) ? active.closest("[data-rail-file-path]") : null;
|
|
5858
|
+
return {
|
|
5859
|
+
focusedPath: focusedRow?.dataset.railFilePath ?? this.pendingFocusedPath,
|
|
5860
|
+
scrollOffset: scroller.scrollTop
|
|
5861
|
+
};
|
|
5862
|
+
}
|
|
5863
|
+
componentDidUpdate(_previousProps, _previousState, snapshot) {
|
|
5864
|
+
if (!snapshot || !this.listHandle) return;
|
|
5865
|
+
this.cancelRestoreFrame();
|
|
5866
|
+
const maxOffset = Math.max(0, this.listHandle.scrollSize - this.listHandle.viewportSize);
|
|
5867
|
+
this.listHandle.scrollTo(Math.min(Math.max(snapshot.scrollOffset, 0), maxOffset));
|
|
5868
|
+
const focusedPath = snapshot.focusedPath;
|
|
5869
|
+
if (!focusedPath) return;
|
|
5870
|
+
this.pendingFocusedPath = focusedPath;
|
|
5871
|
+
this.continueFocusRestore();
|
|
5872
|
+
}
|
|
5873
|
+
componentWillUnmount() {
|
|
5874
|
+
this.cancelRestoreFrame();
|
|
5875
|
+
this.pendingFocusedPath = null;
|
|
5876
|
+
}
|
|
5877
|
+
cancelRestoreFrame() {
|
|
5878
|
+
if (this.restoreFrame === null) return;
|
|
5879
|
+
if (typeof cancelAnimationFrame === "function") cancelAnimationFrame(this.restoreFrame);
|
|
5880
|
+
this.restoreFrame = null;
|
|
5881
|
+
}
|
|
5882
|
+
continueFocusRestore = () => {
|
|
5883
|
+
const path = this.pendingFocusedPath;
|
|
5884
|
+
if (!path) return;
|
|
5885
|
+
if (this.restoreFocusedPath(path)) {
|
|
5886
|
+
this.pendingFocusedPath = null;
|
|
5887
|
+
return;
|
|
5888
|
+
}
|
|
5889
|
+
if (this.restoreFrame === null && typeof requestAnimationFrame === "function") {
|
|
5890
|
+
this.restoreFrame = requestAnimationFrame(() => {
|
|
5891
|
+
this.restoreFrame = null;
|
|
5892
|
+
this.continueFocusRestore();
|
|
5893
|
+
});
|
|
5894
|
+
}
|
|
5895
|
+
};
|
|
5896
|
+
restoreFocusedPath(path) {
|
|
5897
|
+
const host = this.host;
|
|
5898
|
+
if (!host) return true;
|
|
5899
|
+
const active = document.activeElement;
|
|
5900
|
+
if (active instanceof HTMLElement && active.isConnected && active !== document.body) {
|
|
5901
|
+
return true;
|
|
5902
|
+
}
|
|
5903
|
+
if (!this.props.files.some((file) => file.path === path)) return true;
|
|
5904
|
+
const row = Array.from(host.querySelectorAll("[data-rail-file-path]")).find(
|
|
5905
|
+
(candidate) => candidate.dataset.railFilePath === path
|
|
5906
|
+
);
|
|
5907
|
+
if (!row) return false;
|
|
5908
|
+
row.focus({ preventScroll: true });
|
|
5909
|
+
return true;
|
|
5910
|
+
}
|
|
5911
|
+
setHost = (host) => {
|
|
5912
|
+
this.host = host;
|
|
5913
|
+
};
|
|
5914
|
+
setListHandle = (handle) => {
|
|
5915
|
+
this.listHandle = handle;
|
|
5916
|
+
};
|
|
5917
|
+
render() {
|
|
5918
|
+
return /* @__PURE__ */ jsx6("div", { ref: this.setHost, "data-opengeni-changes-rail": true, className: this.props.className, children: /* @__PURE__ */ jsx6(
|
|
5919
|
+
VList2,
|
|
5920
|
+
{
|
|
5921
|
+
ref: this.setListHandle,
|
|
5922
|
+
className: "h-full",
|
|
5923
|
+
itemSize: this.props.coarsePointer ? 44 : 28,
|
|
5924
|
+
ssrCount: Math.min(30, this.props.rowCount),
|
|
5925
|
+
children: this.props.children
|
|
5926
|
+
},
|
|
5927
|
+
this.state.resetVersion
|
|
5928
|
+
) });
|
|
5929
|
+
}
|
|
5930
|
+
};
|
|
5651
5931
|
function buildRail(files) {
|
|
5652
5932
|
const roots = new Set(
|
|
5653
5933
|
files.flatMap((file) => file.repoRoot === void 0 ? [] : [file.repoRoot])
|
|
@@ -5706,12 +5986,12 @@ function WorkbenchChanges({
|
|
|
5706
5986
|
const [layout, setLayout] = useState14("unified");
|
|
5707
5987
|
const [activePath, setActivePath] = useState14(null);
|
|
5708
5988
|
const pickerId = useId3();
|
|
5709
|
-
const unicodeFontPaths =
|
|
5989
|
+
const unicodeFontPaths = useMemo11(
|
|
5710
5990
|
() => diff.flatMap((file) => file.oldPath ? [file.path, file.oldPath] : [file.path]),
|
|
5711
5991
|
[diff]
|
|
5712
5992
|
);
|
|
5713
5993
|
useUnicodeFallbackFonts(unicodeFontPaths);
|
|
5714
|
-
const { orderedFiles, rows, grouped } =
|
|
5994
|
+
const { orderedFiles, rows, grouped } = useMemo11(() => buildRail(diff), [diff]);
|
|
5715
5995
|
const selectedIndex = orderedFiles.findIndex((file) => file.path === activePath);
|
|
5716
5996
|
const activeIndex = selectedIndex >= 0 ? selectedIndex : 0;
|
|
5717
5997
|
useChangesLayoutEffect(() => {
|
|
@@ -5741,8 +6021,8 @@ function WorkbenchChanges({
|
|
|
5741
6021
|
return () => query.removeListener(update);
|
|
5742
6022
|
}
|
|
5743
6023
|
}, []);
|
|
5744
|
-
const additions =
|
|
5745
|
-
const deletions =
|
|
6024
|
+
const additions = useMemo11(() => diff.reduce((sum, f) => sum + f.additions, 0), [diff]);
|
|
6025
|
+
const deletions = useMemo11(() => diff.reduce((sum, f) => sum + f.deletions, 0), [diff]);
|
|
5746
6026
|
const estimateHeight = useCallback18(
|
|
5747
6027
|
(index) => {
|
|
5748
6028
|
const file = orderedFiles[index];
|
|
@@ -5860,22 +6140,33 @@ function WorkbenchChanges({
|
|
|
5860
6140
|
}
|
|
5861
6141
|
)
|
|
5862
6142
|
] }),
|
|
5863
|
-
/* @__PURE__ */ jsx6(
|
|
5864
|
-
|
|
6143
|
+
/* @__PURE__ */ jsx6(
|
|
6144
|
+
"div",
|
|
5865
6145
|
{
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
6146
|
+
"aria-label": "Changed file diff",
|
|
6147
|
+
className: "min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
|
|
6148
|
+
"data-opengeni-changes-pane": true,
|
|
6149
|
+
role: "region",
|
|
6150
|
+
tabIndex: 0,
|
|
6151
|
+
children: activeFile ? /* @__PURE__ */ jsx6(
|
|
6152
|
+
DiffSection,
|
|
6153
|
+
{
|
|
6154
|
+
file: activeFile,
|
|
6155
|
+
layout: "unified",
|
|
6156
|
+
themeType: resolvedTheme,
|
|
6157
|
+
...onOpenFile ? { onOpenFile } : {}
|
|
6158
|
+
}
|
|
6159
|
+
) : null
|
|
5870
6160
|
}
|
|
5871
|
-
)
|
|
6161
|
+
)
|
|
5872
6162
|
] }) : /* @__PURE__ */ jsxs6("div", { className: "flex min-h-0 flex-1", children: [
|
|
5873
|
-
/* @__PURE__ */ jsx6(
|
|
5874
|
-
|
|
6163
|
+
/* @__PURE__ */ jsx6(
|
|
6164
|
+
ChangesRailVList,
|
|
5875
6165
|
{
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
6166
|
+
rowCount: rows.length,
|
|
6167
|
+
coarsePointer,
|
|
6168
|
+
files: orderedFiles,
|
|
6169
|
+
className: "w-[clamp(12rem,28%,15rem)] shrink-0 border-r border-og-border bg-og-surface-1/35",
|
|
5879
6170
|
children: rows.map(
|
|
5880
6171
|
(row) => row.kind === "group" ? /* @__PURE__ */ jsxs6(
|
|
5881
6172
|
"div",
|
|
@@ -5900,13 +6191,16 @@ function WorkbenchChanges({
|
|
|
5900
6191
|
)
|
|
5901
6192
|
)
|
|
5902
6193
|
}
|
|
5903
|
-
)
|
|
6194
|
+
),
|
|
5904
6195
|
/* @__PURE__ */ jsx6(
|
|
5905
6196
|
"div",
|
|
5906
6197
|
{
|
|
5907
6198
|
ref: windowed.scrollRef,
|
|
5908
|
-
|
|
6199
|
+
"aria-label": "Changed files diff",
|
|
6200
|
+
className: "min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
|
|
5909
6201
|
"data-opengeni-changes-pane": true,
|
|
6202
|
+
role: "region",
|
|
6203
|
+
tabIndex: 0,
|
|
5910
6204
|
children: /* @__PURE__ */ jsx6("div", { style: { position: "relative", height: windowed.totalHeight }, children: orderedFiles.map((file, index) => {
|
|
5911
6205
|
if (index < windowed.range.start || index >= windowed.range.end) return null;
|
|
5912
6206
|
return /* @__PURE__ */ jsx6(
|
|
@@ -5975,6 +6269,7 @@ function RailFileRow({
|
|
|
5975
6269
|
onClick,
|
|
5976
6270
|
title: file.path,
|
|
5977
6271
|
"data-rail-file": true,
|
|
6272
|
+
"data-rail-file-path": file.path,
|
|
5978
6273
|
className: cn(
|
|
5979
6274
|
"relative flex min-h-7 w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm transition-colors hover:bg-og-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent pointer-coarse:min-h-11",
|
|
5980
6275
|
grouped && "pl-3",
|
|
@@ -6212,7 +6507,7 @@ import { Loader2Icon, SaveIcon } from "lucide-react";
|
|
|
6212
6507
|
import {
|
|
6213
6508
|
useCallback as useCallback19,
|
|
6214
6509
|
useEffect as useEffect19,
|
|
6215
|
-
useMemo as
|
|
6510
|
+
useMemo as useMemo12,
|
|
6216
6511
|
useRef as useRef16,
|
|
6217
6512
|
useState as useState16
|
|
6218
6513
|
} from "react";
|
|
@@ -6260,6 +6555,19 @@ function languageForPath(path) {
|
|
|
6260
6555
|
return null;
|
|
6261
6556
|
}
|
|
6262
6557
|
}
|
|
6558
|
+
function reconcileEditorBuffer(current, incoming) {
|
|
6559
|
+
if (current.path === incoming.path && current.value !== current.baseline) {
|
|
6560
|
+
return current;
|
|
6561
|
+
}
|
|
6562
|
+
if (current.path === incoming.path && current.value === incoming.contents && current.baseline === incoming.contents) {
|
|
6563
|
+
return current;
|
|
6564
|
+
}
|
|
6565
|
+
return {
|
|
6566
|
+
path: incoming.path,
|
|
6567
|
+
value: incoming.contents,
|
|
6568
|
+
baseline: incoming.contents
|
|
6569
|
+
};
|
|
6570
|
+
}
|
|
6263
6571
|
function CodeEditor({
|
|
6264
6572
|
path,
|
|
6265
6573
|
initialContents,
|
|
@@ -6275,28 +6583,30 @@ function CodeEditor({
|
|
|
6275
6583
|
}) {
|
|
6276
6584
|
const [failed, setFailed] = useState16(false);
|
|
6277
6585
|
const [bundle, setBundle] = useState16(null);
|
|
6278
|
-
const [
|
|
6279
|
-
|
|
6586
|
+
const [buffer, setBuffer] = useState16(() => ({
|
|
6587
|
+
path,
|
|
6588
|
+
value: initialContents,
|
|
6589
|
+
baseline: initialContents
|
|
6590
|
+
}));
|
|
6591
|
+
const { value, baseline } = buffer;
|
|
6280
6592
|
const [saving, setSaving] = useState16(false);
|
|
6281
6593
|
const [saveError, setSaveError] = useState16(null);
|
|
6282
6594
|
const [savedTick, setSavedTick] = useState16(false);
|
|
6595
|
+
const saveInFlightRef = useRef16(false);
|
|
6283
6596
|
const dirty = value !== baseline;
|
|
6284
6597
|
const saveConflict = saveError !== null && saveError.code === "file_write_conflict";
|
|
6285
6598
|
const editIntentFiredRef = useRef16(false);
|
|
6286
|
-
const lastSeed = useRef16({ path, contents: initialContents });
|
|
6287
6599
|
useEffect19(() => {
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6600
|
+
setBuffer((current) => reconcileEditorBuffer(current, { path, contents: initialContents }));
|
|
6601
|
+
}, [path, initialContents]);
|
|
6602
|
+
useEffect19(() => {
|
|
6291
6603
|
editIntentFiredRef.current = false;
|
|
6292
|
-
setValue(initialContents);
|
|
6293
|
-
setBaseline(initialContents);
|
|
6294
6604
|
setSaveError(null);
|
|
6295
6605
|
setSavedTick(false);
|
|
6296
|
-
}, [path
|
|
6606
|
+
}, [path]);
|
|
6297
6607
|
const noteEdit = useCallback19(
|
|
6298
6608
|
(next) => {
|
|
6299
|
-
|
|
6609
|
+
setBuffer((current) => ({ ...current, value: next }));
|
|
6300
6610
|
setSavedTick(false);
|
|
6301
6611
|
if (!editIntentFiredRef.current && next !== baseline) {
|
|
6302
6612
|
editIntentFiredRef.current = true;
|
|
@@ -6305,7 +6615,7 @@ function CodeEditor({
|
|
|
6305
6615
|
},
|
|
6306
6616
|
[baseline, onEditIntent]
|
|
6307
6617
|
);
|
|
6308
|
-
const langKey =
|
|
6618
|
+
const langKey = useMemo12(() => languageForPath(path), [path]);
|
|
6309
6619
|
useEffect19(() => {
|
|
6310
6620
|
let cancelled = false;
|
|
6311
6621
|
void (async () => {
|
|
@@ -6349,38 +6659,44 @@ function CodeEditor({
|
|
|
6349
6659
|
const saveRef = useRef16(() => {
|
|
6350
6660
|
});
|
|
6351
6661
|
const save = useCallback19(async () => {
|
|
6352
|
-
if (readOnly) return;
|
|
6662
|
+
if (readOnly || saveInFlightRef.current) return;
|
|
6353
6663
|
const snapshot = value;
|
|
6354
6664
|
if (snapshot === baseline) return;
|
|
6665
|
+
saveInFlightRef.current = true;
|
|
6355
6666
|
setSaving(true);
|
|
6356
6667
|
setSaveError(null);
|
|
6357
6668
|
setSavedTick(false);
|
|
6358
6669
|
try {
|
|
6359
|
-
await onSave(snapshot);
|
|
6360
|
-
|
|
6361
|
-
|
|
6670
|
+
await onSave(snapshot, baseline);
|
|
6671
|
+
setBuffer(
|
|
6672
|
+
(current) => current.path === path ? { ...current, baseline: snapshot } : current
|
|
6673
|
+
);
|
|
6362
6674
|
setSavedTick(true);
|
|
6363
6675
|
} catch (cause) {
|
|
6364
6676
|
setSaveError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
6365
6677
|
} finally {
|
|
6678
|
+
saveInFlightRef.current = false;
|
|
6366
6679
|
setSaving(false);
|
|
6367
6680
|
}
|
|
6368
6681
|
}, [readOnly, value, baseline, onSave, path]);
|
|
6369
6682
|
const overwrite = useCallback19(async () => {
|
|
6370
|
-
if (readOnly || !onOverwrite) return;
|
|
6683
|
+
if (readOnly || !onOverwrite || saveInFlightRef.current) return;
|
|
6371
6684
|
const snapshot = value;
|
|
6372
6685
|
if (snapshot === baseline) return;
|
|
6686
|
+
saveInFlightRef.current = true;
|
|
6373
6687
|
setSaving(true);
|
|
6374
6688
|
setSaveError(null);
|
|
6375
6689
|
setSavedTick(false);
|
|
6376
6690
|
try {
|
|
6377
6691
|
await onOverwrite(snapshot);
|
|
6378
|
-
|
|
6379
|
-
|
|
6692
|
+
setBuffer(
|
|
6693
|
+
(current) => current.path === path ? { ...current, baseline: snapshot } : current
|
|
6694
|
+
);
|
|
6380
6695
|
setSavedTick(true);
|
|
6381
6696
|
} catch (cause) {
|
|
6382
6697
|
setSaveError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
6383
6698
|
} finally {
|
|
6699
|
+
saveInFlightRef.current = false;
|
|
6384
6700
|
setSaving(false);
|
|
6385
6701
|
}
|
|
6386
6702
|
}, [readOnly, onOverwrite, value, baseline, path]);
|
|
@@ -6393,18 +6709,26 @@ function CodeEditor({
|
|
|
6393
6709
|
return () => clearTimeout(t);
|
|
6394
6710
|
}, [savedTick]);
|
|
6395
6711
|
const fileName = path.split("/").filter(Boolean).pop() ?? path;
|
|
6396
|
-
const cmExtensions =
|
|
6712
|
+
const cmExtensions = useMemo12(() => {
|
|
6397
6713
|
if (!bundle) return [];
|
|
6398
6714
|
const exts = [bundle.saveKeymapExtension(() => saveRef.current())];
|
|
6399
6715
|
if (bundle.languageExtension) exts.push(bundle.languageExtension);
|
|
6400
6716
|
return exts;
|
|
6401
6717
|
}, [bundle]);
|
|
6402
6718
|
const Editor = bundle?.Editor;
|
|
6719
|
+
const reload = useCallback19(() => {
|
|
6720
|
+
setBuffer({ path, value: initialContents, baseline: initialContents });
|
|
6721
|
+
editIntentFiredRef.current = false;
|
|
6722
|
+
setSaveError(null);
|
|
6723
|
+
setSavedTick(false);
|
|
6724
|
+
onReload?.();
|
|
6725
|
+
}, [initialContents, onReload, path]);
|
|
6403
6726
|
return /* @__PURE__ */ jsxs7(
|
|
6404
6727
|
"div",
|
|
6405
6728
|
{
|
|
6406
6729
|
className: cn("flex h-full min-h-0 flex-col", className),
|
|
6407
6730
|
"data-opengeni-code-editor": true,
|
|
6731
|
+
"data-opengeni-editor-dirty": dirty ? "true" : "false",
|
|
6408
6732
|
style: editorVars,
|
|
6409
6733
|
children: [
|
|
6410
6734
|
/* @__PURE__ */ jsxs7("div", { className: "flex min-h-9 shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
|
|
@@ -6431,7 +6755,7 @@ function CodeEditor({
|
|
|
6431
6755
|
children: saveError.message
|
|
6432
6756
|
}
|
|
6433
6757
|
),
|
|
6434
|
-
!saveError && savedTick && /* @__PURE__ */ jsx9("span", { className: "text-og-xs text-og-status-idle", children: "Saved" }),
|
|
6758
|
+
!saveError && savedTick && !dirty && /* @__PURE__ */ jsx9("span", { className: "text-og-xs text-og-status-idle", children: "Saved" }),
|
|
6435
6759
|
readOnly ? /* @__PURE__ */ jsx9("span", { className: "text-og-xs uppercase tracking-wide text-og-fg-subtle", children: "Read-only" }) : !saveConflict ? /* @__PURE__ */ jsxs7(
|
|
6436
6760
|
"button",
|
|
6437
6761
|
{
|
|
@@ -6468,8 +6792,7 @@ function CodeEditor({
|
|
|
6468
6792
|
{
|
|
6469
6793
|
type: "button",
|
|
6470
6794
|
onClick: () => {
|
|
6471
|
-
|
|
6472
|
-
onReload();
|
|
6795
|
+
reload();
|
|
6473
6796
|
},
|
|
6474
6797
|
className: "min-h-8 rounded-og-sm border border-og-border bg-og-surface-1 px-2 text-og-xs font-medium text-og-fg hover:bg-og-surface-2 pointer-coarse:min-h-11",
|
|
6475
6798
|
children: "Reload live"
|
|
@@ -6756,7 +7079,7 @@ function SandboxFiles({
|
|
|
6756
7079
|
path: viewPath,
|
|
6757
7080
|
initialContents: fileView.content,
|
|
6758
7081
|
themeType: resolvedTheme,
|
|
6759
|
-
onSave: (contents) => files.writeFile(viewPath, contents, { expectedContent:
|
|
7082
|
+
onSave: (contents, expectedContents) => files.writeFile(viewPath, contents, { expectedContent: expectedContents }),
|
|
6760
7083
|
onOverwrite: (contents) => files.writeFile(viewPath, contents, { force: true }),
|
|
6761
7084
|
onReload: () => setViewReloadRevision((revision) => revision + 1),
|
|
6762
7085
|
...onEditIntent ? { onEditIntent } : {},
|
|
@@ -7080,7 +7403,7 @@ function DesktopViewer({
|
|
|
7080
7403
|
scaleViewport,
|
|
7081
7404
|
rfbFactory,
|
|
7082
7405
|
webSocketFactory,
|
|
7083
|
-
|
|
7406
|
+
onActivate,
|
|
7084
7407
|
onAcknowledge,
|
|
7085
7408
|
watching,
|
|
7086
7409
|
onWarm,
|
|
@@ -7092,22 +7415,55 @@ function DesktopViewer({
|
|
|
7092
7415
|
className
|
|
7093
7416
|
}) {
|
|
7094
7417
|
const containerRef = useRef18(null);
|
|
7095
|
-
const
|
|
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);
|
|
7096
7425
|
const [takeControl, setTakeControl] = useState18(interactive ?? false);
|
|
7097
7426
|
const externallyControlled = interactive !== void 0;
|
|
7098
7427
|
const serverAllowsControl = capability?.mode !== "read-only";
|
|
7099
7428
|
const wantControl = externallyControlled ? interactive : takeControl;
|
|
7100
7429
|
const inControl = Boolean(wantControl) && serverAllowsControl;
|
|
7101
|
-
const isWatching = watching ??
|
|
7430
|
+
const isWatching = watching ?? true;
|
|
7102
7431
|
const transportNull = !capability || capability.transport === null;
|
|
7103
7432
|
const reason = capability?.reason ?? null;
|
|
7104
|
-
const
|
|
7433
|
+
const needsAcknowledgment = capability?.requiresAcknowledgment === true && capability.acknowledged !== true;
|
|
7105
7434
|
const noLiveAddress = Boolean(capability) && !transportNull && !capability.url;
|
|
7106
7435
|
const coldWarmable = transportNull && reason === "lease_cold" || !transportNull && noLiveAddress;
|
|
7107
7436
|
const hardUnavailable = transportNull && isHardUnavailable(reason);
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
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);
|
|
7111
7467
|
};
|
|
7112
7468
|
useEffect21(() => {
|
|
7113
7469
|
if (!inControl || externallyControlled) return;
|
|
@@ -7122,7 +7478,7 @@ function DesktopViewer({
|
|
|
7122
7478
|
window.removeEventListener("keydown", onKey);
|
|
7123
7479
|
};
|
|
7124
7480
|
}, [inControl, externallyControlled]);
|
|
7125
|
-
const connectCapability = !transportNull && !
|
|
7481
|
+
const connectCapability = !transportNull && !needsAcknowledgment && !viewerCapReached ? capability : null;
|
|
7126
7482
|
const stream = useDesktopStream({
|
|
7127
7483
|
capability: connectCapability,
|
|
7128
7484
|
containerRef,
|
|
@@ -7137,17 +7493,16 @@ function DesktopViewer({
|
|
|
7137
7493
|
streamStateRef.current = stream.state;
|
|
7138
7494
|
const warmKeyRef = useRef18(null);
|
|
7139
7495
|
useEffect21(() => {
|
|
7140
|
-
if (!isWatching || !coldWarmable ||
|
|
7496
|
+
if (!isWatching || !coldWarmable || needsAcknowledgment || viewerCapReached) {
|
|
7141
7497
|
if (!coldWarmable) warmKeyRef.current = null;
|
|
7142
7498
|
return;
|
|
7143
7499
|
}
|
|
7144
|
-
|
|
7145
|
-
if (!warm) return;
|
|
7500
|
+
if (!onWarm) return;
|
|
7146
7501
|
const key = `${capability?.reason ?? ""}:${capability?.url ?? ""}:${capability?.expiresAt ?? ""}`;
|
|
7147
7502
|
if (warmKeyRef.current === key) return;
|
|
7148
7503
|
warmKeyRef.current = key;
|
|
7149
|
-
|
|
7150
|
-
}, [isWatching, coldWarmable,
|
|
7504
|
+
onWarm();
|
|
7505
|
+
}, [isWatching, coldWarmable, needsAcknowledgment, viewerCapReached, capability, onWarm]);
|
|
7151
7506
|
useEffect21(() => {
|
|
7152
7507
|
if (!hasLiveUrl || typeof document === "undefined") return;
|
|
7153
7508
|
const maybeReattach = () => {
|
|
@@ -7180,13 +7535,14 @@ function DesktopViewer({
|
|
|
7180
7535
|
let uiState;
|
|
7181
7536
|
if (viewerCapReached) uiState = "viewer_cap";
|
|
7182
7537
|
else if (hardUnavailable) uiState = "unavailable";
|
|
7183
|
-
else if (
|
|
7538
|
+
else if (acknowledgmentError) uiState = "acknowledgment_error";
|
|
7539
|
+
else if (needsAcknowledgment) uiState = "opening";
|
|
7184
7540
|
else if (coldWarmable) uiState = "warming";
|
|
7185
7541
|
else if (connected) uiState = "connected";
|
|
7186
7542
|
else if (stream.error) uiState = "error";
|
|
7187
7543
|
else if (connectTimedOut) uiState = "connect_failed";
|
|
7188
7544
|
else uiState = "connecting";
|
|
7189
|
-
const overlayShown = uiState !== "connected" && uiState !== "connecting";
|
|
7545
|
+
const overlayShown = uiState !== "connected" && uiState !== "connecting" && uiState !== "opening";
|
|
7190
7546
|
const showToggle = showControlToggle && !overlayShown;
|
|
7191
7547
|
let overlay = null;
|
|
7192
7548
|
switch (uiState) {
|
|
@@ -7199,8 +7555,12 @@ function DesktopViewer({
|
|
|
7199
7555
|
case "unavailable":
|
|
7200
7556
|
overlay = renderUnavailable?.(reason) ?? defaultNotice("Desktop unavailable", unavailableCopy(reason));
|
|
7201
7557
|
break;
|
|
7202
|
-
case "
|
|
7203
|
-
overlay =
|
|
7558
|
+
case "acknowledgment_error":
|
|
7559
|
+
overlay = defaultNotice(
|
|
7560
|
+
"Couldn\u2019t open desktop",
|
|
7561
|
+
acknowledgmentError?.message ?? "The desktop acknowledgment failed.",
|
|
7562
|
+
retryAcknowledgment
|
|
7563
|
+
);
|
|
7204
7564
|
break;
|
|
7205
7565
|
case "warming":
|
|
7206
7566
|
overlay = renderWarming?.() ?? /* @__PURE__ */ jsx11(WarmingNotice, {});
|
|
@@ -7219,6 +7579,7 @@ function DesktopViewer({
|
|
|
7219
7579
|
reconnect
|
|
7220
7580
|
);
|
|
7221
7581
|
break;
|
|
7582
|
+
case "opening":
|
|
7222
7583
|
case "connecting":
|
|
7223
7584
|
case "connected":
|
|
7224
7585
|
overlay = null;
|
|
@@ -7247,7 +7608,7 @@ function DesktopViewer({
|
|
|
7247
7608
|
"data-state": stream.state
|
|
7248
7609
|
}
|
|
7249
7610
|
),
|
|
7250
|
-
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: [
|
|
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: [
|
|
7251
7612
|
/* @__PURE__ */ jsxs9("span", { className: "relative flex items-center justify-center", children: [
|
|
7252
7613
|
/* @__PURE__ */ jsx11(MonitorIcon, { className: "size-8 opacity-30", strokeWidth: 1.5 }),
|
|
7253
7614
|
/* @__PURE__ */ jsx11(
|
|
@@ -7258,7 +7619,7 @@ function DesktopViewer({
|
|
|
7258
7619
|
}
|
|
7259
7620
|
)
|
|
7260
7621
|
] }),
|
|
7261
|
-
/* @__PURE__ */ jsx11("span", { className: "text-og-sm", children: "Connecting to the desktop\u2026" })
|
|
7622
|
+
/* @__PURE__ */ jsx11("span", { className: "text-og-sm", children: uiState === "opening" ? "Opening the desktop\u2026" : "Connecting to the desktop\u2026" })
|
|
7262
7623
|
] }),
|
|
7263
7624
|
showToggle && !externallyControlled && inControl && /* @__PURE__ */ jsx11(
|
|
7264
7625
|
InControlBar,
|
|
@@ -7396,26 +7757,6 @@ function WarmingNotice({ onRetry }) {
|
|
|
7396
7757
|
)
|
|
7397
7758
|
] });
|
|
7398
7759
|
}
|
|
7399
|
-
function DefaultConsentGate({ shared, onAccept }) {
|
|
7400
|
-
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: [
|
|
7401
|
-
/* @__PURE__ */ jsx11("div", { className: "mb-1 font-medium", children: "Watch the live desktop?" }),
|
|
7402
|
-
/* @__PURE__ */ jsxs9("p", { className: "mb-3 text-og-sm text-og-fg-subtle", children: [
|
|
7403
|
-
"The desktop pixel stream is ",
|
|
7404
|
-
/* @__PURE__ */ jsx11("strong", { children: "un-redacted" }),
|
|
7405
|
-
" \u2014 it can show secrets the agent prints on screen.",
|
|
7406
|
-
shared ? " This sandbox is shared: you'll also see other sessions' agents on the same screen." : ""
|
|
7407
|
-
] }),
|
|
7408
|
-
/* @__PURE__ */ jsx11(
|
|
7409
|
-
"button",
|
|
7410
|
-
{
|
|
7411
|
-
type: "button",
|
|
7412
|
-
onClick: onAccept,
|
|
7413
|
-
className: "rounded-og-sm bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg pointer-coarse:min-h-11",
|
|
7414
|
-
children: "I understand \u2014 show the desktop"
|
|
7415
|
-
}
|
|
7416
|
-
)
|
|
7417
|
-
] });
|
|
7418
|
-
}
|
|
7419
7760
|
function defaultNotice(title, body, onRetry) {
|
|
7420
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: [
|
|
7421
7762
|
/* @__PURE__ */ jsxs9("div", { className: "mb-1 flex items-center justify-center gap-1.5 font-medium", children: [
|
|
@@ -7965,12 +8306,21 @@ function DockChrome({
|
|
|
7965
8306
|
}
|
|
7966
8307
|
|
|
7967
8308
|
// src/components/sandbox-workspace.tsx
|
|
7968
|
-
import {
|
|
8309
|
+
import {
|
|
8310
|
+
lazy as lazy2,
|
|
8311
|
+
Suspense as Suspense2,
|
|
8312
|
+
useCallback as useCallback22,
|
|
8313
|
+
useEffect as useEffect23,
|
|
8314
|
+
useMemo as useMemo13,
|
|
8315
|
+
useRef as useRef20,
|
|
8316
|
+
useState as useState20
|
|
8317
|
+
} from "react";
|
|
7969
8318
|
import {
|
|
7970
8319
|
CircleCheckIcon,
|
|
7971
8320
|
CpuIcon,
|
|
7972
8321
|
FileCode2Icon as FileCode2Icon2,
|
|
7973
8322
|
GitCompareArrowsIcon,
|
|
8323
|
+
Globe2Icon,
|
|
7974
8324
|
LoaderCircleIcon as LoaderCircleIcon3,
|
|
7975
8325
|
MonitorIcon as MonitorIcon2,
|
|
7976
8326
|
RefreshCwIcon as RefreshCwIcon2,
|
|
@@ -7978,14 +8328,24 @@ import {
|
|
|
7978
8328
|
TriangleAlertIcon as TriangleAlertIcon2
|
|
7979
8329
|
} from "lucide-react";
|
|
7980
8330
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
8331
|
+
var LazyBrowserViewer = lazy2(async () => {
|
|
8332
|
+
const viewers = await import("./interactive-workbench-viewers-KHNOHWQE.js");
|
|
8333
|
+
return { default: viewers.BrowserViewer };
|
|
8334
|
+
});
|
|
8335
|
+
var LazyComputerViewer = lazy2(async () => {
|
|
8336
|
+
const viewers = await import("./interactive-workbench-viewers-KHNOHWQE.js");
|
|
8337
|
+
return { default: viewers.ComputerViewer };
|
|
8338
|
+
});
|
|
7981
8339
|
var WORKBENCH_TAB_CHANGES = "changes";
|
|
7982
8340
|
var WORKBENCH_TAB_FILES = "files";
|
|
7983
8341
|
var WORKBENCH_TAB_TERMINAL = "terminal";
|
|
8342
|
+
var WORKBENCH_TAB_BROWSER = "browser";
|
|
7984
8343
|
var WORKBENCH_TAB_DESKTOP = "desktop";
|
|
7985
8344
|
var WORKBENCH_SURFACES = [
|
|
7986
8345
|
WORKBENCH_TAB_CHANGES,
|
|
7987
8346
|
WORKBENCH_TAB_FILES,
|
|
7988
8347
|
WORKBENCH_TAB_TERMINAL,
|
|
8348
|
+
WORKBENCH_TAB_BROWSER,
|
|
7989
8349
|
WORKBENCH_TAB_DESKTOP
|
|
7990
8350
|
];
|
|
7991
8351
|
function isWorkbenchSurface(value) {
|
|
@@ -8015,6 +8375,18 @@ function WorkbenchTabLabel({ icon, children }) {
|
|
|
8015
8375
|
/* @__PURE__ */ jsx13("span", { children })
|
|
8016
8376
|
] });
|
|
8017
8377
|
}
|
|
8378
|
+
function WorkbenchSurfaceLoading({ name }) {
|
|
8379
|
+
return /* @__PURE__ */ jsx13(
|
|
8380
|
+
CenteredState,
|
|
8381
|
+
{
|
|
8382
|
+
icon: /* @__PURE__ */ jsx13(LoaderCircleIcon3, { className: "size-5 animate-spin motion-reduce:animate-none", "aria-hidden": true }),
|
|
8383
|
+
children: /* @__PURE__ */ jsxs11("p", { className: "text-og-sm font-medium text-og-fg", children: [
|
|
8384
|
+
"Opening ",
|
|
8385
|
+
name
|
|
8386
|
+
] })
|
|
8387
|
+
}
|
|
8388
|
+
);
|
|
8389
|
+
}
|
|
8018
8390
|
function initialWorkspaceTab(events, override) {
|
|
8019
8391
|
if (override) return override;
|
|
8020
8392
|
let bestSeq = -1;
|
|
@@ -8026,7 +8398,17 @@ function initialWorkspaceTab(events, override) {
|
|
|
8026
8398
|
bestSeq = event.sequence;
|
|
8027
8399
|
bestFileCount = typeof stats?.fileCount === "number" ? stats.fileCount : 0;
|
|
8028
8400
|
}
|
|
8029
|
-
|
|
8401
|
+
if (bestFileCount > 0) return WORKBENCH_TAB_CHANGES;
|
|
8402
|
+
let latestGitSeq = -1;
|
|
8403
|
+
let committedOnly = false;
|
|
8404
|
+
for (const event of events ?? []) {
|
|
8405
|
+
if (event.type !== "git.changed" || event.sequence > bestSeq) continue;
|
|
8406
|
+
if (event.sequence <= latestGitSeq) continue;
|
|
8407
|
+
const payload = event.payload;
|
|
8408
|
+
latestGitSeq = event.sequence;
|
|
8409
|
+
committedOnly = typeof payload?.ahead === "number" && payload.ahead > 0 || payload?.reason === "commit";
|
|
8410
|
+
}
|
|
8411
|
+
return committedOnly ? WORKBENCH_TAB_CHANGES : WORKBENCH_TAB_FILES;
|
|
8030
8412
|
}
|
|
8031
8413
|
function sandboxProvisionInFlight(events) {
|
|
8032
8414
|
let inFlight = false;
|
|
@@ -8048,14 +8430,25 @@ function sandboxProvisionInFlight(events) {
|
|
|
8048
8430
|
function emptyWarmIntents(sessionId) {
|
|
8049
8431
|
return {
|
|
8050
8432
|
sessionId,
|
|
8051
|
-
watchDesktop: false,
|
|
8052
8433
|
warmTerminal: false,
|
|
8053
8434
|
warmFiles: false
|
|
8054
8435
|
};
|
|
8055
8436
|
}
|
|
8056
8437
|
function useSandboxWorkspaceTabs(options) {
|
|
8057
8438
|
const { client, workspaceId } = useOpenGeni(options);
|
|
8058
|
-
const {
|
|
8439
|
+
const {
|
|
8440
|
+
sessionId,
|
|
8441
|
+
events,
|
|
8442
|
+
onNotify,
|
|
8443
|
+
browserWebSocketFactory,
|
|
8444
|
+
computerWebSocketFactory,
|
|
8445
|
+
requestedFilePath,
|
|
8446
|
+
requestedFileRequestId,
|
|
8447
|
+
onOpenFile,
|
|
8448
|
+
onOpenComputerSession,
|
|
8449
|
+
requestedComputerSessionId,
|
|
8450
|
+
requestedComputerRequestId
|
|
8451
|
+
} = options;
|
|
8059
8452
|
const initialTab = options.initialTab ?? null;
|
|
8060
8453
|
const activeTab = options.activeTab ?? initialTab;
|
|
8061
8454
|
const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;
|
|
@@ -8063,9 +8456,24 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8063
8456
|
const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);
|
|
8064
8457
|
const filesEnabled = surfaceSet.has(WORKBENCH_TAB_FILES);
|
|
8065
8458
|
const terminalEnabled = surfaceSet.has(WORKBENCH_TAB_TERMINAL);
|
|
8459
|
+
const browserEnabled = surfaceSet.has(WORKBENCH_TAB_BROWSER);
|
|
8066
8460
|
const desktopEnabled = surfaceSet.has(WORKBENCH_TAB_DESKTOP);
|
|
8461
|
+
const createLinkedComputer = useCallback22(
|
|
8462
|
+
async (name) => {
|
|
8463
|
+
const response = await client.createComputerSession(workspaceId, {
|
|
8464
|
+
operationId: crypto.randomUUID(),
|
|
8465
|
+
sessionId,
|
|
8466
|
+
name
|
|
8467
|
+
});
|
|
8468
|
+
return {
|
|
8469
|
+
id: response.session.id,
|
|
8470
|
+
placement: response.session.placement
|
|
8471
|
+
};
|
|
8472
|
+
},
|
|
8473
|
+
[client, sessionId, workspaceId]
|
|
8474
|
+
);
|
|
8067
8475
|
const workspaceDataEnabled = changesEnabled || filesEnabled;
|
|
8068
|
-
const
|
|
8476
|
+
const machineSurfaceEnabled = workspaceDataEnabled || terminalEnabled || desktopEnabled;
|
|
8069
8477
|
const resolvedActiveTab = activeTab ?? initialTab;
|
|
8070
8478
|
const changesActive = resolvedActiveTab === WORKBENCH_TAB_CHANGES;
|
|
8071
8479
|
const filesActive = resolvedActiveTab === WORKBENCH_TAB_FILES;
|
|
@@ -8074,7 +8482,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8074
8482
|
() => emptyWarmIntents(sessionId)
|
|
8075
8483
|
);
|
|
8076
8484
|
const warmIntents = storedWarmIntents.sessionId === sessionId ? storedWarmIntents : emptyWarmIntents(sessionId);
|
|
8077
|
-
const {
|
|
8485
|
+
const { warmTerminal, warmFiles } = warmIntents;
|
|
8078
8486
|
const requestWarmIntent = useCallback22(
|
|
8079
8487
|
(intent) => {
|
|
8080
8488
|
setStoredWarmIntents((previous) => {
|
|
@@ -8088,13 +8496,13 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8088
8496
|
workspaceId,
|
|
8089
8497
|
sessionId,
|
|
8090
8498
|
pollIntervalMs: 8e3,
|
|
8091
|
-
enabled:
|
|
8499
|
+
enabled: machineSurfaceEnabled
|
|
8092
8500
|
});
|
|
8093
8501
|
const activeMachine = machines.machines.find((m) => m.sandboxId === machines.activeSandboxId) ?? machines.machines.find((m) => m.active) ?? null;
|
|
8094
8502
|
const caps = useSessionCapabilities(sessionId, {
|
|
8095
8503
|
events,
|
|
8096
|
-
enabled:
|
|
8097
|
-
attachDesktop:
|
|
8504
|
+
enabled: machineSurfaceEnabled,
|
|
8505
|
+
attachDesktop: false,
|
|
8098
8506
|
attachTerminal: terminalEnabled && warmTerminal,
|
|
8099
8507
|
// Explicit live-file intent only — NOT "the Files tab is open". A cold edit
|
|
8100
8508
|
// or guarded-file open wakes the box; a glance at the tree/diff does not.
|
|
@@ -8102,19 +8510,18 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8102
8510
|
});
|
|
8103
8511
|
const capabilities = caps.capabilities;
|
|
8104
8512
|
const liveness = capabilities?.liveness;
|
|
8513
|
+
const liveIoLiveness = liveness ?? null;
|
|
8105
8514
|
const fileSystemOn = capabilities?.FileSystem.available ?? false;
|
|
8106
8515
|
const fsReadOnly = capabilities?.FileSystem.readOnly ?? false;
|
|
8107
|
-
const filesEditable = fileSystemOn && !fsReadOnly && (liveness
|
|
8516
|
+
const filesEditable = fileSystemOn && !fsReadOnly && sandboxAcceptsLiveIo(liveness);
|
|
8108
8517
|
const gitOn = capabilities?.Git.available ?? false;
|
|
8109
8518
|
const terminalOn = terminalEnabled && (capabilities?.Terminal.transport ?? null) !== null;
|
|
8110
|
-
const
|
|
8111
|
-
const ptyCapable = (capabilities?.Terminal.ptyCapable ?? false) && !ptyWsLive;
|
|
8519
|
+
const ptyCapable = warmTerminal && (capabilities?.Terminal.ptyCapable ?? false) && capabilities?.Terminal.transport === "sse-events" && capabilities?.Terminal.reason === null;
|
|
8112
8520
|
const terminal = useSandboxTerminal(sessionId, {
|
|
8113
8521
|
events: terminalEnabled ? events : [],
|
|
8114
8522
|
interactive: terminalEnabled && ptyCapable,
|
|
8115
8523
|
liveness
|
|
8116
8524
|
});
|
|
8117
|
-
const desktopAdvertised = desktopEnabled && ((capabilities?.DesktopStream.transport ?? null) !== null || capabilities?.DesktopStream.reason === "lease_cold");
|
|
8118
8525
|
const provisioning = sandboxProvisionInFlight(events);
|
|
8119
8526
|
const renegotiate = caps.renegotiate;
|
|
8120
8527
|
const provisioningRef = useRef20({ sessionId, provisioning });
|
|
@@ -8130,9 +8537,9 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8130
8537
|
enabled: workspaceDataEnabled
|
|
8131
8538
|
});
|
|
8132
8539
|
const captureAvailable = captureState.available;
|
|
8133
|
-
const liveWorkspaceExpected = liveness
|
|
8540
|
+
const liveWorkspaceExpected = sandboxAcceptsLiveIo(liveness);
|
|
8134
8541
|
const capturePending = !liveWorkspaceExpected && (captureState.fileCount === null || captureState.loading);
|
|
8135
|
-
const repoPaths =
|
|
8542
|
+
const repoPaths = useMemo13(() => {
|
|
8136
8543
|
const advertised = capabilities?.Git.repos ?? [];
|
|
8137
8544
|
if (advertised.length > 0) return advertised;
|
|
8138
8545
|
return captureState.capture?.repos.map((repo) => repo.root) ?? [];
|
|
@@ -8157,7 +8564,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8157
8564
|
enabled: filesEnabled && (captureAvailable || fileSystemOn && liveWorkspaceExpected),
|
|
8158
8565
|
active: filesActive,
|
|
8159
8566
|
repoPaths,
|
|
8160
|
-
liveness,
|
|
8567
|
+
liveness: liveIoLiveness,
|
|
8161
8568
|
capture: captureState.capture,
|
|
8162
8569
|
// A reverted optimistic mutation (e.g. a 409 rename collision) surfaces as a
|
|
8163
8570
|
// host notification — the tree silently rolls back, the user sees why.
|
|
@@ -8181,7 +8588,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8181
8588
|
// dormant, avoiding the old duplicate full-tree read.
|
|
8182
8589
|
active: changesActive || resolvedActiveTab === null,
|
|
8183
8590
|
repoPaths,
|
|
8184
|
-
liveness,
|
|
8591
|
+
liveness: liveIoLiveness,
|
|
8185
8592
|
comparison: changesComparison,
|
|
8186
8593
|
capture: changesComparison === "staged" ? null : captureState.capture
|
|
8187
8594
|
});
|
|
@@ -8202,33 +8609,13 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8202
8609
|
});
|
|
8203
8610
|
return () => observer.disconnect();
|
|
8204
8611
|
}, [terminalEnabled]);
|
|
8205
|
-
async function acknowledgeAndWatch() {
|
|
8206
|
-
try {
|
|
8207
|
-
const shared = capabilities?.DesktopStream.shared ?? false;
|
|
8208
|
-
await client.acknowledgeStream(workspaceId, sessionId, {
|
|
8209
|
-
acknowledgeUnredacted: true,
|
|
8210
|
-
acknowledgeShared: shared
|
|
8211
|
-
});
|
|
8212
|
-
requestWarmIntent("watchDesktop");
|
|
8213
|
-
caps.renegotiate();
|
|
8214
|
-
} catch (error) {
|
|
8215
|
-
onNotify?.({
|
|
8216
|
-
kind: "error",
|
|
8217
|
-
message: `Could not start the desktop stream: ${error instanceof Error ? error.message : String(error)}`
|
|
8218
|
-
});
|
|
8219
|
-
}
|
|
8220
|
-
}
|
|
8221
|
-
function rewarmDesktop() {
|
|
8222
|
-
if (!watchDesktop) requestWarmIntent("watchDesktop");
|
|
8223
|
-
caps.renegotiate();
|
|
8224
|
-
}
|
|
8225
8612
|
const dirtyCount = git.diff.length;
|
|
8226
8613
|
const chip = useMachineChip({
|
|
8227
8614
|
liveness,
|
|
8228
8615
|
capabilitiesState: caps.state,
|
|
8229
8616
|
activeMachineState: activeMachine?.state ?? null,
|
|
8230
8617
|
activeIsSelfhosted: activeMachine?.kind === "selfhosted",
|
|
8231
|
-
wantsWarm: terminalEnabled && warmTerminal ||
|
|
8618
|
+
wantsWarm: terminalEnabled && warmTerminal || workspaceDataEnabled && warmFiles,
|
|
8232
8619
|
capturedAt: captureState.capturedAt
|
|
8233
8620
|
});
|
|
8234
8621
|
const workspaceWaking = chip.state === "waking";
|
|
@@ -8241,7 +8628,8 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8241
8628
|
defaultTabRef.current = { identity: defaultIdentity, value: null };
|
|
8242
8629
|
}
|
|
8243
8630
|
const captureIsAuthoritative = !liveWorkspaceExpected && (liveness !== void 0 || caps.error !== null);
|
|
8244
|
-
const
|
|
8631
|
+
const captureHasChanges = (captureState.fileCount ?? 0) > 0 || (captureState.capture?.repos.some((repo) => (repo.branchDiff?.length ?? 0) > 0) ?? false);
|
|
8632
|
+
const captureUnavailable = captureState.fileCount === 0 && !captureHasChanges || captureState.error !== null;
|
|
8245
8633
|
const implicitBranchFallbackPending = changesComparison === "branch" && git.error !== null && storedChangesComparison?.sessionId !== sessionId;
|
|
8246
8634
|
if (defaultTabRef.current.value === null) {
|
|
8247
8635
|
if (initialTab && (!isWorkbenchSurface(initialTab) || surfaceSet.has(initialTab))) {
|
|
@@ -8254,7 +8642,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8254
8642
|
);
|
|
8255
8643
|
} else if (captureIsAuthoritative && captureState.fileCount !== null && captureState.available) {
|
|
8256
8644
|
defaultTabRef.current.value = sourceDrivenDefaultTab(
|
|
8257
|
-
|
|
8645
|
+
captureHasChanges,
|
|
8258
8646
|
changesEnabled,
|
|
8259
8647
|
filesEnabled
|
|
8260
8648
|
);
|
|
@@ -8266,7 +8654,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8266
8654
|
defaultTabRef.current.value = sourceDrivenDefaultTab(false, changesEnabled, filesEnabled);
|
|
8267
8655
|
} else if (captureState.available && git.error && captureState.fileCount !== null) {
|
|
8268
8656
|
defaultTabRef.current.value = sourceDrivenDefaultTab(
|
|
8269
|
-
|
|
8657
|
+
captureHasChanges,
|
|
8270
8658
|
changesEnabled,
|
|
8271
8659
|
filesEnabled
|
|
8272
8660
|
);
|
|
@@ -8275,7 +8663,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8275
8663
|
}
|
|
8276
8664
|
}
|
|
8277
8665
|
const defaultTab = defaultTabRef.current.value;
|
|
8278
|
-
const tabs =
|
|
8666
|
+
const tabs = useMemo13(() => {
|
|
8279
8667
|
const list = [];
|
|
8280
8668
|
if (changesEnabled)
|
|
8281
8669
|
list.push({
|
|
@@ -8324,7 +8712,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8324
8712
|
...requestedFilePath ? {
|
|
8325
8713
|
requestedPath: requestedFilePath,
|
|
8326
8714
|
...requestedFileRequestId !== null && requestedFileRequestId !== void 0 ? { requestedPathRequestId: requestedFileRequestId } : {},
|
|
8327
|
-
requestedPathReady: liveness
|
|
8715
|
+
requestedPathReady: sandboxAcceptsLiveIo(liveness)
|
|
8328
8716
|
} : {},
|
|
8329
8717
|
onEditIntent: () => requestWarmIntent("warmFiles"),
|
|
8330
8718
|
className: "h-full"
|
|
@@ -8346,26 +8734,49 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8346
8734
|
shell: capabilities?.Terminal.shell ?? void 0,
|
|
8347
8735
|
liveness,
|
|
8348
8736
|
...xtermTheme ? { theme: xtermTheme } : {}
|
|
8349
|
-
}
|
|
8737
|
+
},
|
|
8738
|
+
sessionId
|
|
8350
8739
|
) })
|
|
8351
8740
|
});
|
|
8352
8741
|
}
|
|
8353
|
-
if (
|
|
8742
|
+
if (browserEnabled) {
|
|
8743
|
+
list.push({
|
|
8744
|
+
id: WORKBENCH_TAB_BROWSER,
|
|
8745
|
+
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(Globe2Icon, {}), children: "Browser" }),
|
|
8746
|
+
content: /* @__PURE__ */ jsx13(Suspense2, { fallback: /* @__PURE__ */ jsx13(WorkbenchSurfaceLoading, { name: "Browser" }), children: /* @__PURE__ */ jsx13(
|
|
8747
|
+
LazyBrowserViewer,
|
|
8748
|
+
{
|
|
8749
|
+
client,
|
|
8750
|
+
workspaceId,
|
|
8751
|
+
sessionId,
|
|
8752
|
+
onNotify,
|
|
8753
|
+
...desktopEnabled ? { createLinkedComputer } : {},
|
|
8754
|
+
...onOpenComputerSession ? { onOpenComputer: onOpenComputerSession } : {},
|
|
8755
|
+
...browserWebSocketFactory ? { webSocketFactory: browserWebSocketFactory } : {},
|
|
8756
|
+
className: "h-full"
|
|
8757
|
+
},
|
|
8758
|
+
sessionId
|
|
8759
|
+
) })
|
|
8760
|
+
});
|
|
8761
|
+
}
|
|
8762
|
+
if (desktopEnabled) {
|
|
8354
8763
|
list.push({
|
|
8355
8764
|
id: WORKBENCH_TAB_DESKTOP,
|
|
8356
|
-
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(MonitorIcon2, {}), children: "
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
DesktopViewer,
|
|
8765
|
+
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(MonitorIcon2, {}), children: "Computer" }),
|
|
8766
|
+
content: /* @__PURE__ */ jsx13(Suspense2, { fallback: /* @__PURE__ */ jsx13(WorkbenchSurfaceLoading, { name: "Computer" }), children: /* @__PURE__ */ jsx13(
|
|
8767
|
+
LazyComputerViewer,
|
|
8360
8768
|
{
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8769
|
+
client,
|
|
8770
|
+
workspaceId,
|
|
8771
|
+
sessionId,
|
|
8772
|
+
onNotify,
|
|
8773
|
+
requestedComputerSessionId,
|
|
8774
|
+
requestedComputerRequestId,
|
|
8775
|
+
...computerWebSocketFactory ? { webSocketFactory: computerWebSocketFactory } : {},
|
|
8366
8776
|
className: "h-full"
|
|
8367
|
-
}
|
|
8368
|
-
|
|
8777
|
+
},
|
|
8778
|
+
sessionId
|
|
8779
|
+
) })
|
|
8369
8780
|
});
|
|
8370
8781
|
}
|
|
8371
8782
|
return list;
|
|
@@ -8374,14 +8785,22 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8374
8785
|
changesEnabled,
|
|
8375
8786
|
filesEnabled,
|
|
8376
8787
|
terminalOn,
|
|
8377
|
-
|
|
8788
|
+
browserEnabled,
|
|
8789
|
+
desktopEnabled,
|
|
8378
8790
|
captureAvailable,
|
|
8379
8791
|
dirtyCount,
|
|
8380
|
-
watchDesktop,
|
|
8381
8792
|
warmTerminal,
|
|
8382
8793
|
requestedFilePath,
|
|
8383
8794
|
requestedFileRequestId,
|
|
8384
8795
|
onOpenFile,
|
|
8796
|
+
onOpenComputerSession,
|
|
8797
|
+
requestedComputerSessionId,
|
|
8798
|
+
requestedComputerRequestId,
|
|
8799
|
+
onNotify,
|
|
8800
|
+
browserWebSocketFactory,
|
|
8801
|
+
computerWebSocketFactory,
|
|
8802
|
+
client,
|
|
8803
|
+
workspaceId,
|
|
8385
8804
|
liveness,
|
|
8386
8805
|
sessionId,
|
|
8387
8806
|
files,
|
|
@@ -8394,13 +8813,14 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
8394
8813
|
caps.state,
|
|
8395
8814
|
caps.error,
|
|
8396
8815
|
caps.viewerCapReached,
|
|
8397
|
-
requestWarmIntent
|
|
8816
|
+
requestWarmIntent,
|
|
8817
|
+
createLinkedComputer
|
|
8398
8818
|
]);
|
|
8399
8819
|
return {
|
|
8400
8820
|
tabs,
|
|
8401
8821
|
defaultTab,
|
|
8402
8822
|
machine: {
|
|
8403
|
-
enabled:
|
|
8823
|
+
enabled: machineSurfaceEnabled,
|
|
8404
8824
|
chip,
|
|
8405
8825
|
activeMachine,
|
|
8406
8826
|
loading: machines.loading,
|
|
@@ -8419,6 +8839,8 @@ function SandboxWorkspace(props) {
|
|
|
8419
8839
|
trailingTabs,
|
|
8420
8840
|
initialTab,
|
|
8421
8841
|
onNotify,
|
|
8842
|
+
browserWebSocketFactory,
|
|
8843
|
+
computerWebSocketFactory,
|
|
8422
8844
|
collapsed,
|
|
8423
8845
|
onCollapsedChange,
|
|
8424
8846
|
showCollapseControl,
|
|
@@ -8431,7 +8853,9 @@ function SandboxWorkspace(props) {
|
|
|
8431
8853
|
} = props;
|
|
8432
8854
|
const [storedSelection, setStoredSelection] = useState20(null);
|
|
8433
8855
|
const [requestedFile, setRequestedFile] = useState20(null);
|
|
8856
|
+
const [requestedComputer, setRequestedComputer] = useState20(null);
|
|
8434
8857
|
const nextFileRequestId = useRef20(0);
|
|
8858
|
+
const nextComputerRequestId = useRef20(0);
|
|
8435
8859
|
const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;
|
|
8436
8860
|
const activeTabHint = selectedTab ?? initialTab ?? leadingTabs?.[0]?.id ?? null;
|
|
8437
8861
|
const openFile = useCallback22(
|
|
@@ -8442,6 +8866,18 @@ function SandboxWorkspace(props) {
|
|
|
8442
8866
|
},
|
|
8443
8867
|
[sessionId]
|
|
8444
8868
|
);
|
|
8869
|
+
const openComputer = useCallback22(
|
|
8870
|
+
(computerSessionId) => {
|
|
8871
|
+
nextComputerRequestId.current += 1;
|
|
8872
|
+
setRequestedComputer({
|
|
8873
|
+
sessionId,
|
|
8874
|
+
computerSessionId,
|
|
8875
|
+
requestId: nextComputerRequestId.current
|
|
8876
|
+
});
|
|
8877
|
+
setStoredSelection({ sessionId, tab: WORKBENCH_TAB_DESKTOP });
|
|
8878
|
+
},
|
|
8879
|
+
[sessionId]
|
|
8880
|
+
);
|
|
8445
8881
|
const {
|
|
8446
8882
|
tabs: workbenchTabs,
|
|
8447
8883
|
machine,
|
|
@@ -8455,9 +8891,14 @@ function SandboxWorkspace(props) {
|
|
|
8455
8891
|
...initialTab ? { initialTab } : {},
|
|
8456
8892
|
activeTab: activeTabHint,
|
|
8457
8893
|
...onNotify ? { onNotify } : {},
|
|
8894
|
+
...browserWebSocketFactory ? { browserWebSocketFactory } : {},
|
|
8895
|
+
...computerWebSocketFactory ? { computerWebSocketFactory } : {},
|
|
8458
8896
|
requestedFilePath: requestedFile?.sessionId === sessionId ? requestedFile.path : null,
|
|
8459
8897
|
requestedFileRequestId: requestedFile?.sessionId === sessionId ? requestedFile.requestId : null,
|
|
8460
|
-
onOpenFile: openFile
|
|
8898
|
+
onOpenFile: openFile,
|
|
8899
|
+
onOpenComputerSession: openComputer,
|
|
8900
|
+
requestedComputerSessionId: requestedComputer?.sessionId === sessionId ? requestedComputer.computerSessionId : null,
|
|
8901
|
+
requestedComputerRequestId: requestedComputer?.sessionId === sessionId ? requestedComputer.requestId : null
|
|
8461
8902
|
});
|
|
8462
8903
|
const tabs = [...leadingTabs ?? [], ...workbenchTabs, ...trailingTabs ?? []];
|
|
8463
8904
|
const preferredTab = selectedTab ?? defaultTab;
|
|
@@ -8849,6 +9290,7 @@ export {
|
|
|
8849
9290
|
FileBrowser,
|
|
8850
9291
|
FileWriteConflictError,
|
|
8851
9292
|
FleetTile,
|
|
9293
|
+
GeneratedVideoPlayer,
|
|
8852
9294
|
HEALTH_TOKEN,
|
|
8853
9295
|
HumanInputForm,
|
|
8854
9296
|
HumanInputSurface,
|
|
@@ -8917,6 +9359,7 @@ export {
|
|
|
8917
9359
|
VoiceRecordingStorageUnavailableError,
|
|
8918
9360
|
WINDOW_LABEL,
|
|
8919
9361
|
WORKBENCH_SURFACES,
|
|
9362
|
+
WORKBENCH_TAB_BROWSER,
|
|
8920
9363
|
WORKBENCH_TAB_CHANGES,
|
|
8921
9364
|
WORKBENCH_TAB_DESKTOP,
|
|
8922
9365
|
WORKBENCH_TAB_FILES,
|
|
@@ -9058,6 +9501,7 @@ export {
|
|
|
9058
9501
|
useTranscription,
|
|
9059
9502
|
useTurnQueue,
|
|
9060
9503
|
useVariableSets,
|
|
9504
|
+
useVideoArtifactPlaybackLoader,
|
|
9061
9505
|
useVoiceInput,
|
|
9062
9506
|
useWorkspaceCapture,
|
|
9063
9507
|
useWorkspaceEdit,
|