@opengeni/react 0.48.0 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -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 +199 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/{chunk-NJ7M2B6Z.js → chunk-5UQPNLIO.js} +16 -8
- package/dist/{chunk-NJ7M2B6Z.js.map → chunk-5UQPNLIO.js.map} +1 -1
- package/dist/{chunk-LHLYWG5R.js → chunk-6KLX2RH5.js} +461 -38
- package/dist/chunk-6KLX2RH5.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-B6WPZSTT.js} +104 -104
- package/dist/{chunk-I4MPFDRP.js.map → chunk-B6WPZSTT.js.map} +1 -1
- package/dist/{chunk-EKZH6IDG.js → chunk-C5ZPSSS5.js} +111 -1
- package/dist/chunk-C5ZPSSS5.js.map +1 -0
- package/dist/{chunk-OL6QVXGF.js → chunk-HA46CYQK.js} +152 -8
- package/dist/chunk-HA46CYQK.js.map +1 -0
- package/dist/chunk-HUIKIDM5.js +2148 -0
- package/dist/chunk-HUIKIDM5.js.map +1 -0
- package/dist/{chunk-FWXGSNXT.js → chunk-IGC6A2ZI.js} +585 -34
- package/dist/chunk-IGC6A2ZI.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-LLOLUHVG.js +5937 -0
- package/dist/chunk-LLOLUHVG.js.map +1 -0
- package/dist/{chunk-WYA65Y3F.js → chunk-MKPIAGVL.js} +13 -3
- package/dist/chunk-MKPIAGVL.js.map +1 -0
- package/dist/chunk-PEI6RANI.js +3234 -0
- package/dist/chunk-PEI6RANI.js.map +1 -0
- package/dist/chunk-R3AZOAB5.js +933 -0
- package/dist/chunk-R3AZOAB5.js.map +1 -0
- package/dist/{chunk-O4VXOBGF.js → chunk-WSK7G5LE.js} +70 -2
- package/dist/chunk-WSK7G5LE.js.map +1 -0
- package/dist/{chunk-23EJ676W.js → chunk-XBZWOM2K.js} +9 -4
- package/dist/chunk-XBZWOM2K.js.map +1 -0
- package/dist/{chunk-XCNTXWBB.js → chunk-Y7OEDUJ5.js} +856 -338
- package/dist/chunk-Y7OEDUJ5.js.map +1 -0
- package/dist/client.d.ts +10 -2
- 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 +9 -0
- package/dist/components/artifacts/presentation-editor.d.ts +297 -0
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +14 -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-input.d.ts +7 -0
- package/dist/components/browser-viewer.d.ts +30 -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 +24 -0
- package/dist/components/copy-button.d.ts +2 -2
- package/dist/components/desktop-viewer.d.ts +50 -22
- 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/interaction-intervention-banner.d.ts +11 -0
- 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 +24 -4
- package/dist/components/sandbox-workspace.d.ts +28 -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 +7 -7
- package/dist/hooks/internal.d.ts +1 -1
- package/dist/hooks/use-attached-browsers.d.ts +21 -0
- package/dist/hooks/use-auth-runs.d.ts +32 -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-downloads.d.ts +25 -0
- package/dist/hooks/use-browser-frame-stream.d.ts +28 -0
- package/dist/hooks/use-browser-identities.d.ts +30 -0
- package/dist/hooks/use-browser-session.d.ts +29 -0
- package/dist/hooks/use-browser-sessions.d.ts +32 -0
- package/dist/hooks/use-channels.d.ts +26 -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 +29 -0
- package/dist/hooks/use-computer-sessions.d.ts +28 -0
- package/dist/hooks/use-desktop-stream.d.ts +5 -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-interaction-interventions.d.ts +27 -0
- package/dist/hooks/use-interaction-invalidation.d.ts +19 -0
- 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-network-routes.d.ts +25 -0
- 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-site-auth-connections.d.ts +25 -0
- package/dist/hooks/use-slash-commands.d.ts +1 -1
- package/dist/hooks/use-supergrok-accounts.d.ts +26 -0
- package/dist/hooks/use-terminal-stream.d.ts +11 -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 +162 -155
- package/dist/index.js +1822 -1703
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +33 -0
- package/dist/interaction.js +550 -0
- package/dist/interaction.js.map +1 -0
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +15 -0
- package/dist/interactive-workbench-viewers-TOHBXJEE.js.map +1 -0
- package/dist/lib/host-platform.d.ts +5 -0
- package/dist/lib/relay-wire.d.ts +24 -1
- 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 +2 -2
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +6 -5
- 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 +8 -8
- package/dist/realtime.d.ts +4 -4
- package/dist/realtime.js +38 -11
- package/dist/realtime.js.map +1 -1
- package/dist/session-context.d.ts +28 -2
- 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 +10 -10
- 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 +44 -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 +89 -0
- package/src/client.ts +157 -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 +104 -0
- package/src/components/artifacts/presentation-editor.tsx +3148 -0
- package/src/components/artifacts/published-html-artifact-frame.tsx +38 -0
- package/src/components/artifacts/spreadsheet-canvas.ts +799 -0
- package/src/components/artifacts/spreadsheet-grid.tsx +2129 -0
- package/src/components/browser-input.ts +65 -0
- package/src/components/browser-viewer.tsx +2702 -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 +1636 -0
- package/src/components/desktop-viewer.tsx +215 -74
- package/src/components/generated-video-player.tsx +89 -0
- package/src/components/interaction-intervention-banner.tsx +99 -0
- package/src/components/interactive-workbench-viewers.ts +2 -0
- package/src/components/machine-input-display.ts +3 -0
- package/src/components/machines/machine-detail.tsx +1 -1
- package/src/components/message-timeline.tsx +289 -32
- package/src/components/model-policy-picker.tsx +15 -0
- package/src/components/queue-surface-implementation.tsx +116 -60
- package/src/components/sandbox-files.tsx +2 -2
- package/src/components/sandbox-terminal.tsx +128 -46
- package/src/components/sandbox-workspace.tsx +256 -90
- 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/components/workspace-dock.tsx +59 -5
- package/src/hooks/use-attached-browsers.ts +154 -0
- package/src/hooks/use-auth-runs.ts +278 -0
- package/src/hooks/use-browser-downloads.ts +218 -0
- package/src/hooks/use-browser-frame-stream.ts +425 -0
- package/src/hooks/use-browser-identities.ts +266 -0
- package/src/hooks/use-browser-session.ts +543 -0
- package/src/hooks/use-browser-sessions.ts +286 -0
- package/src/hooks/use-channels.ts +99 -0
- package/src/hooks/use-composer.ts +769 -24
- package/src/hooks/use-computer-frame-stream.ts +434 -0
- package/src/hooks/use-computer-session.ts +462 -0
- package/src/hooks/use-computer-sessions.ts +251 -0
- package/src/hooks/use-desktop-stream.ts +39 -7
- package/src/hooks/use-interaction-interventions.ts +242 -0
- package/src/hooks/use-interaction-invalidation.ts +66 -0
- package/src/hooks/use-machine-chip.ts +15 -3
- package/src/hooks/use-machines.ts +33 -3
- package/src/hooks/use-network-routes.ts +214 -0
- 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-site-auth-connections.ts +226 -0
- package/src/hooks/use-supergrok-accounts.ts +81 -0
- package/src/hooks/use-terminal-stream.ts +359 -47
- package/src/hooks/use-video-artifact-playback.ts +28 -0
- package/src/hooks/use-workspace-edit.ts +2 -1
- package/src/index.ts +18 -0
- package/src/interaction.ts +101 -0
- package/src/lib/host-platform.ts +10 -0
- package/src/lib/relay-wire.ts +47 -4
- package/src/lib/sandbox-liveness.ts +11 -0
- package/src/lib/terminal-capability.ts +10 -0
- package/src/model-policy.ts +19 -4
- package/src/provider.tsx +133 -1
- package/src/realtime/realtime-control.tsx +34 -6
- package/src/session-context.ts +156 -1
- package/src/timeline/activity-rail.tsx +25 -3
- package/src/timeline/index.ts +3 -0
- package/src/timeline/parsers.ts +14 -1
- package/src/timeline/projection.ts +269 -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 +57 -3
- package/styles/compiled.css +312 -21
- package/styles/index.css +15 -0
- package/styles/responsive.css +13 -1
- package/dist/chunk-23EJ676W.js.map +0 -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-OL6QVXGF.js.map +0 -1
- package/dist/chunk-WYA65Y3F.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
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
verticalListSortingStrategy,
|
|
17
17
|
} from "@dnd-kit/sortable";
|
|
18
18
|
import { CSS } from "@dnd-kit/utilities";
|
|
19
|
-
import type { SessionPendingInputPreview, SessionTurn } from "@opengeni/sdk";
|
|
19
|
+
import type { SessionPendingInputPreview, SessionTurn, TimelineAnnotation } from "@opengeni/sdk";
|
|
20
20
|
import {
|
|
21
21
|
ArrowDownToLineIcon,
|
|
22
22
|
ArrowUpToLineIcon,
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
} from "../lib/use-portal-token-style";
|
|
47
47
|
import { requestQueueDraftEdit } from "./queue-draft-policy";
|
|
48
48
|
import { QueueErrorAlert, QueueStoppingStatus } from "./queue-surface-state";
|
|
49
|
+
import { TimelineAnnotationsChip } from "./timeline-annotations";
|
|
49
50
|
|
|
50
51
|
/** The sole pending-input surface: compact above Goal, Agents, and composer. */
|
|
51
52
|
type QueueSurfaceCommonProps = {
|
|
@@ -99,14 +100,15 @@ export function QueueSurface({
|
|
|
99
100
|
(input) => !attachedInputIds.includes(input.id),
|
|
100
101
|
);
|
|
101
102
|
const canEditInComposer = queueComposerCheckoutEnabled(composer, readOnly);
|
|
102
|
-
const collapsedPreview = useMemo(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
const collapsedPreview = useMemo(() => {
|
|
104
|
+
const firstTurn = queue.queue[0];
|
|
105
|
+
return firstTurn
|
|
106
|
+
? queueTurnPreview(firstTurn, QUEUE_COLLAPSED_PREVIEW_CHARACTERS)
|
|
107
|
+
: queuePromptPreview(
|
|
108
|
+
queue.pendingInputs[0]?.summary ?? "",
|
|
109
|
+
QUEUE_COLLAPSED_PREVIEW_CHARACTERS,
|
|
110
|
+
);
|
|
111
|
+
}, [queue.pendingInputs, queue.queue]);
|
|
110
112
|
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));
|
|
111
113
|
|
|
112
114
|
const displayedQueue = useMemo(() => {
|
|
@@ -409,8 +411,8 @@ export function QueueSurface({
|
|
|
409
411
|
dir="auto"
|
|
410
412
|
>
|
|
411
413
|
{
|
|
412
|
-
|
|
413
|
-
queue.queue.find((turn) => turn.id === draggedTurnId)
|
|
414
|
+
queueTurnPreview(
|
|
415
|
+
queue.queue.find((turn) => turn.id === draggedTurnId),
|
|
414
416
|
QUEUE_ROW_PREVIEW_CHARACTERS,
|
|
415
417
|
).summary
|
|
416
418
|
}
|
|
@@ -490,6 +492,29 @@ type QueuePromptPreview = {
|
|
|
490
492
|
isFallback: boolean;
|
|
491
493
|
};
|
|
492
494
|
|
|
495
|
+
function annotationOnlyQueuePreview(count: number): QueuePromptPreview {
|
|
496
|
+
const summary = `${count} timeline ${count === 1 ? "annotation" : "annotations"}`;
|
|
497
|
+
return {
|
|
498
|
+
summary,
|
|
499
|
+
collapsedVisual: summary,
|
|
500
|
+
visibleStart: summary,
|
|
501
|
+
visibleIdentity: null,
|
|
502
|
+
visibleIdentityLabel: null,
|
|
503
|
+
isFallback: false,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function queueTurnPreview(
|
|
508
|
+
turn: SessionTurn | undefined,
|
|
509
|
+
maxCharacters: number,
|
|
510
|
+
): QueuePromptPreview {
|
|
511
|
+
if (!turn) return queuePromptPreview("", maxCharacters);
|
|
512
|
+
const annotations = turn.annotations ?? [];
|
|
513
|
+
return turn.prompt.length === 0 && annotations.length > 0
|
|
514
|
+
? annotationOnlyQueuePreview(annotations.length)
|
|
515
|
+
: queuePromptPreview(turn.prompt, maxCharacters);
|
|
516
|
+
}
|
|
517
|
+
|
|
493
518
|
/**
|
|
494
519
|
* Build a bounded head/tail summary of an arbitrary queued prompt. Sampling
|
|
495
520
|
* both ends distinguishes prompts with equal long prefixes. Each sampled edge
|
|
@@ -752,73 +777,94 @@ function isLowSurrogate(codeUnit: number): boolean {
|
|
|
752
777
|
|
|
753
778
|
function QueuePrompt({
|
|
754
779
|
prompt,
|
|
780
|
+
annotations,
|
|
755
781
|
index,
|
|
756
782
|
onDisclosureChange,
|
|
757
783
|
}: {
|
|
758
784
|
prompt: string;
|
|
785
|
+
annotations: readonly TimelineAnnotation[];
|
|
759
786
|
index: number;
|
|
760
787
|
onDisclosureChange: (expanded: boolean) => void;
|
|
761
788
|
}) {
|
|
762
789
|
const [expanded, setExpanded] = useState(false);
|
|
763
790
|
const fullContentId = useId();
|
|
764
|
-
const preview = useMemo(
|
|
791
|
+
const preview = useMemo(
|
|
792
|
+
() =>
|
|
793
|
+
prompt.length === 0 && annotations.length > 0
|
|
794
|
+
? annotationOnlyQueuePreview(annotations.length)
|
|
795
|
+
: queuePromptPreview(prompt, QUEUE_ROW_PREVIEW_CHARACTERS),
|
|
796
|
+
[annotations.length, prompt],
|
|
797
|
+
);
|
|
765
798
|
|
|
766
799
|
return (
|
|
767
800
|
<div className="w-full min-w-0 max-w-full">
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
801
|
+
{prompt ? (
|
|
802
|
+
<div
|
|
803
|
+
aria-label={`Queued prompt ${index + 1} summary: ${preview.summary}`}
|
|
804
|
+
className="max-w-full overflow-hidden text-og-control leading-5 text-fg"
|
|
805
|
+
data-testid={`queue-prompt-preview-${index + 1}`}
|
|
806
|
+
dir="auto"
|
|
807
|
+
role="note"
|
|
808
|
+
>
|
|
776
809
|
<span
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
dir="auto"
|
|
810
|
+
aria-hidden="true"
|
|
811
|
+
className="flex min-w-0 max-w-full items-baseline gap-2 sm:block"
|
|
780
812
|
>
|
|
781
|
-
{preview.visibleStart}
|
|
782
|
-
</span>
|
|
783
|
-
{preview.visibleIdentity && preview.visibleIdentityLabel ? (
|
|
784
813
|
<span
|
|
785
|
-
className="
|
|
786
|
-
data-testid={`queue-prompt-
|
|
814
|
+
className={`${preview.isFallback ? "" : "line-clamp-1 sm:line-clamp-2"} min-w-0 flex-1 whitespace-pre-wrap break-all [unicode-bidi:plaintext]`}
|
|
815
|
+
data-testid={`queue-prompt-start-${index + 1}`}
|
|
816
|
+
dir="auto"
|
|
787
817
|
>
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
818
|
+
{preview.visibleStart}
|
|
819
|
+
</span>
|
|
820
|
+
{preview.visibleIdentity && preview.visibleIdentityLabel ? (
|
|
791
821
|
<span
|
|
792
|
-
className="min-w-0
|
|
793
|
-
data-testid={`queue-prompt-identity-${index + 1}`}
|
|
794
|
-
dir="auto"
|
|
822
|
+
className="flex min-w-0 max-w-[70%] shrink-0 items-center gap-1 text-og-xs leading-4 text-fg-muted sm:mt-0.5 sm:max-w-full"
|
|
823
|
+
data-testid={`queue-prompt-identity-row-${index + 1}`}
|
|
795
824
|
>
|
|
796
|
-
|
|
825
|
+
<span className="shrink-0 font-medium text-fg-subtle">
|
|
826
|
+
{preview.visibleIdentityLabel}
|
|
827
|
+
</span>
|
|
828
|
+
<span
|
|
829
|
+
className="min-w-0 overflow-hidden text-ellipsis whitespace-nowrap font-mono [unicode-bidi:plaintext]"
|
|
830
|
+
data-testid={`queue-prompt-identity-${index + 1}`}
|
|
831
|
+
dir="auto"
|
|
832
|
+
>
|
|
833
|
+
{preview.visibleIdentity}
|
|
834
|
+
</span>
|
|
797
835
|
</span>
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
</
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
aria-label={`${expanded ? "Hide" : "Show"} full content for queued prompt ${index + 1}`}
|
|
807
|
-
className="mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-og-xs font-medium text-fg outline-hidden focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]"
|
|
808
|
-
data-testid={`queue-prompt-disclosure-${index + 1}`}
|
|
809
|
-
onClick={() => {
|
|
810
|
-
const next = !expanded;
|
|
811
|
-
setExpanded(next);
|
|
812
|
-
onDisclosureChange(next);
|
|
813
|
-
}}
|
|
814
|
-
>
|
|
815
|
-
<ChevronDownIcon
|
|
816
|
-
aria-hidden="true"
|
|
817
|
-
className={`size-3 shrink-0 transition-transform ${expanded ? "rotate-180" : ""}`}
|
|
836
|
+
) : null}
|
|
837
|
+
</span>
|
|
838
|
+
</div>
|
|
839
|
+
) : null}
|
|
840
|
+
{annotations.length > 0 ? (
|
|
841
|
+
<TimelineAnnotationsChip
|
|
842
|
+
annotations={annotations}
|
|
843
|
+
className={prompt ? "mt-1" : undefined}
|
|
818
844
|
/>
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
845
|
+
) : null}
|
|
846
|
+
{prompt ? (
|
|
847
|
+
<button
|
|
848
|
+
type="button"
|
|
849
|
+
aria-controls={fullContentId}
|
|
850
|
+
aria-expanded={expanded}
|
|
851
|
+
aria-label={`${expanded ? "Hide" : "Show"} full content for queued prompt ${index + 1}`}
|
|
852
|
+
className="mt-1 inline-flex min-h-7 min-w-0 max-w-full items-center gap-1 whitespace-normal rounded-md text-left text-og-xs font-medium text-fg outline-hidden focus-visible:ring-2 focus-visible:ring-ring/40 pointer-coarse:min-h-[44px]"
|
|
853
|
+
data-testid={`queue-prompt-disclosure-${index + 1}`}
|
|
854
|
+
onClick={() => {
|
|
855
|
+
const next = !expanded;
|
|
856
|
+
setExpanded(next);
|
|
857
|
+
onDisclosureChange(next);
|
|
858
|
+
}}
|
|
859
|
+
>
|
|
860
|
+
<ChevronDownIcon
|
|
861
|
+
aria-hidden="true"
|
|
862
|
+
className={`size-3 shrink-0 transition-transform ${expanded ? "rotate-180" : ""}`}
|
|
863
|
+
/>
|
|
864
|
+
{expanded ? "Hide full prompt" : "View full prompt"}
|
|
865
|
+
</button>
|
|
866
|
+
) : null}
|
|
867
|
+
{expanded && prompt ? (
|
|
822
868
|
<pre
|
|
823
869
|
id={fullContentId}
|
|
824
870
|
role="region"
|
|
@@ -850,7 +896,12 @@ function ReadOnlyQueueRow({
|
|
|
850
896
|
<li className="flex min-w-0 items-start gap-2 bg-surface px-3 py-2">
|
|
851
897
|
<span className="mt-1 shrink-0 font-mono text-og-xs text-fg-subtle">{index + 1}</span>
|
|
852
898
|
<div className="min-w-0 flex-1">
|
|
853
|
-
<QueuePrompt
|
|
899
|
+
<QueuePrompt
|
|
900
|
+
prompt={turn.prompt}
|
|
901
|
+
annotations={turn.annotations ?? []}
|
|
902
|
+
index={index}
|
|
903
|
+
onDisclosureChange={onDisclosureChange}
|
|
904
|
+
/>
|
|
854
905
|
{attachedInputs.length > 0 ? (
|
|
855
906
|
<PendingMachineInputs inputs={attachedInputs} attached />
|
|
856
907
|
) : null}
|
|
@@ -941,7 +992,12 @@ function SortableQueueRow({
|
|
|
941
992
|
{index + 1}
|
|
942
993
|
</span>
|
|
943
994
|
<div className="col-span-full row-start-2 min-w-0 sm:col-span-1 sm:col-start-3 sm:row-start-1">
|
|
944
|
-
<QueuePrompt
|
|
995
|
+
<QueuePrompt
|
|
996
|
+
prompt={turn.prompt}
|
|
997
|
+
annotations={turn.annotations ?? []}
|
|
998
|
+
index={index}
|
|
999
|
+
onDisclosureChange={onDisclosureChange}
|
|
1000
|
+
/>
|
|
945
1001
|
{attachedInputs.length > 0 ? (
|
|
946
1002
|
<PendingMachineInputs inputs={attachedInputs} attached />
|
|
947
1003
|
) : null}
|
|
@@ -319,8 +319,8 @@ export function SandboxFiles({
|
|
|
319
319
|
path={viewPath}
|
|
320
320
|
initialContents={fileView.content}
|
|
321
321
|
themeType={resolvedTheme}
|
|
322
|
-
onSave={(contents) =>
|
|
323
|
-
files.writeFile(viewPath, contents, { expectedContent:
|
|
322
|
+
onSave={(contents, expectedContents) =>
|
|
323
|
+
files.writeFile(viewPath, contents, { expectedContent: expectedContents })
|
|
324
324
|
}
|
|
325
325
|
onOverwrite={(contents) => files.writeFile(viewPath, contents, { force: true })}
|
|
326
326
|
onReload={() => setViewReloadRevision((revision) => revision + 1)}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { TerminalCapability } from "@opengeni/sdk";
|
|
2
|
-
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { type ReactNode, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
|
-
import { useTerminalStream } from "../hooks/use-terminal-stream";
|
|
4
|
+
import { type TerminalStreamStatus, useTerminalStream } from "../hooks/use-terminal-stream";
|
|
5
5
|
import type { UseSandboxTerminalResult } from "../hooks/use-sandbox-terminal";
|
|
6
6
|
import { resolveTerminalFont, xtermThemeFromTokens } from "../lib/xterm-theme";
|
|
7
|
+
import { sandboxAcceptsLiveIo } from "../lib/sandbox-liveness";
|
|
8
|
+
import { terminalCanAcquirePty } from "../lib/terminal-capability";
|
|
7
9
|
import { attachRenderer, type RendererLoaders, type RendererTier } from "../lib/xterm-renderer";
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -60,7 +62,7 @@ export type SandboxTerminalProps = {
|
|
|
60
62
|
fontSize?: number | undefined;
|
|
61
63
|
/**
|
|
62
64
|
* Lease liveness (`cold` | `warming` | `warm` | `draining`). Drives the
|
|
63
|
-
* boot-in-terminal status lines: once the user has
|
|
65
|
+
* boot-in-terminal status lines: once the user has engaged the terminal and
|
|
64
66
|
* the box is not yet warm, a styled "● waking machine — Ns…" line is rendered
|
|
65
67
|
* INSIDE xterm (no overlay/spinner) until the live PTY connects.
|
|
66
68
|
*/
|
|
@@ -85,6 +87,8 @@ export type SandboxTerminalProps = {
|
|
|
85
87
|
* the firehose-only default).
|
|
86
88
|
*/
|
|
87
89
|
onActivate?: (() => void) | undefined;
|
|
90
|
+
/** Re-negotiate the terminal capability after an unexpected socket failure. */
|
|
91
|
+
onReconnectNeeded?: (() => void) | undefined;
|
|
88
92
|
className?: string | undefined;
|
|
89
93
|
};
|
|
90
94
|
|
|
@@ -92,6 +96,7 @@ export type SandboxTerminalProps = {
|
|
|
92
96
|
// drive it without a hard type dep on the lazily-imported lib.
|
|
93
97
|
type XtermLike = {
|
|
94
98
|
open: (el: HTMLElement) => void;
|
|
99
|
+
focus: () => void;
|
|
95
100
|
write: (data: string) => void;
|
|
96
101
|
clear: () => void;
|
|
97
102
|
onData: (cb: (data: string) => void) => { dispose: () => void };
|
|
@@ -110,6 +115,44 @@ type XtermLike = {
|
|
|
110
115
|
};
|
|
111
116
|
type FitAddonLike = { fit: () => void };
|
|
112
117
|
|
|
118
|
+
export type TerminalSurfaceState =
|
|
119
|
+
| "loading"
|
|
120
|
+
| "connecting"
|
|
121
|
+
| "error"
|
|
122
|
+
| "waking"
|
|
123
|
+
| "output-only"
|
|
124
|
+
| "interactive";
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Stable semantic state for hosts and browser acceptance. The xterm helper
|
|
128
|
+
* textarea exists before the live PTY socket is ready, so its presence alone
|
|
129
|
+
* must never be treated as proof that keystrokes can reach the sandbox.
|
|
130
|
+
*/
|
|
131
|
+
export function terminalSurfaceState(input: {
|
|
132
|
+
ready: boolean;
|
|
133
|
+
acceptsInput: boolean;
|
|
134
|
+
inputPending: boolean;
|
|
135
|
+
ptyStatus: TerminalStreamStatus;
|
|
136
|
+
booting: boolean;
|
|
137
|
+
}): TerminalSurfaceState {
|
|
138
|
+
if (!input.ready) return "loading";
|
|
139
|
+
if (input.acceptsInput) return "interactive";
|
|
140
|
+
if (input.inputPending) return "connecting";
|
|
141
|
+
if (input.ptyStatus === "connecting") return "connecting";
|
|
142
|
+
if (input.ptyStatus === "error") return "error";
|
|
143
|
+
if (input.booting) return "waking";
|
|
144
|
+
return "output-only";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function subscribeTerminalInput(
|
|
148
|
+
term: Pick<XtermLike, "onData"> | null,
|
|
149
|
+
sink: ((data: string) => void) | null,
|
|
150
|
+
enabled: boolean,
|
|
151
|
+
): { dispose: () => void } | null {
|
|
152
|
+
if (!enabled || !term || !sink) return null;
|
|
153
|
+
return term.onData(sink);
|
|
154
|
+
}
|
|
155
|
+
|
|
113
156
|
/** Clear the transient wake line and put the first live prompt at cell 1,1.
|
|
114
157
|
* `Terminal.clear()` removes scrollback but deliberately preserves the cursor,
|
|
115
158
|
* which lets the first PTY frame append to the old wake message. */
|
|
@@ -183,6 +226,7 @@ export function SandboxTerminal({
|
|
|
183
226
|
showHeader,
|
|
184
227
|
shell,
|
|
185
228
|
onActivate,
|
|
229
|
+
onReconnectNeeded,
|
|
186
230
|
className,
|
|
187
231
|
}: SandboxTerminalProps) {
|
|
188
232
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -193,50 +237,63 @@ export function SandboxTerminal({
|
|
|
193
237
|
const wroteFirehoseRef = useRef(false);
|
|
194
238
|
const bootActiveRef = useRef(false);
|
|
195
239
|
const [ready, setReady] = useState(false);
|
|
240
|
+
const [inputReady, setInputReady] = useState(false);
|
|
196
241
|
const [activated, setActivated] = useState(false);
|
|
197
242
|
|
|
198
243
|
// ── Interactive transport switch ─────────────────────────────────────────────
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
const
|
|
244
|
+
const ptyDescriptor =
|
|
245
|
+
terminalCapability?.transport === "pty-ws" || terminalCapability?.transport === "relay-pty";
|
|
246
|
+
const ptyAttachable = terminalCanAcquirePty(terminalCapability);
|
|
202
247
|
const {
|
|
203
248
|
status: ptyStatus,
|
|
204
249
|
write: ptyWrite,
|
|
205
250
|
resize: resizePty,
|
|
206
251
|
connected: ptyConnected,
|
|
207
252
|
} = useTerminalStream({
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
253
|
+
// Connect only after xterm exists. This makes the renderer the sole output
|
|
254
|
+
// owner from the first websocket frame and removes an otherwise unbounded
|
|
255
|
+
// pre-mount output queue during large command bursts.
|
|
256
|
+
capability:
|
|
257
|
+
ptyAttachable && ready
|
|
258
|
+
? {
|
|
259
|
+
transport: terminalCapability!.transport,
|
|
260
|
+
url: ptyDescriptor ? terminalCapability!.url : null,
|
|
261
|
+
token: ptyDescriptor ? terminalCapability!.token : null,
|
|
262
|
+
expiresAt: ptyDescriptor ? terminalCapability!.expiresAt : null,
|
|
263
|
+
}
|
|
264
|
+
: null,
|
|
215
265
|
onOutput: (data) => {
|
|
216
|
-
|
|
217
|
-
if (term) term.write(data);
|
|
218
|
-
else ptyOutputQueueRef.current.push(data);
|
|
266
|
+
termRef.current?.write(data);
|
|
219
267
|
},
|
|
268
|
+
onReconnectNeeded,
|
|
220
269
|
});
|
|
221
270
|
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
271
|
+
// A pty-ws capability exclusively owns the screen even while connecting or
|
|
272
|
+
// after a visible connection failure; never silently switch one terminal UI
|
|
273
|
+
// between two PTYs. Input is enabled during the handshake because the stream
|
|
274
|
+
// hook buffers it strictly and flushes only after ttyd auth succeeds.
|
|
275
|
+
const ptyMode = ptyDescriptor;
|
|
276
|
+
// Keep xterm stdin live for an attachable descriptor even before its URL has
|
|
277
|
+
// arrived. Focus/click triggers the grant; any immediately following input is
|
|
278
|
+
// bounded in the stream hook instead of disappearing in that HTTP interval.
|
|
279
|
+
const ptyCapturesInput = ptyAttachable && ptyStatus !== "error";
|
|
280
|
+
const interactive = !readOnly && (ptyAttachable ? ptyCapturesInput : result.write !== null);
|
|
281
|
+
// Public "interactive" means the mounted input subscription can reach a live
|
|
282
|
+
// PTY now. Before that point xterm still captures into the bounded queue, but
|
|
283
|
+
// acceptance and embedders see an explicit connecting state.
|
|
284
|
+
const acceptsInput = inputReady && (!ptyAttachable || ptyConnected);
|
|
285
|
+
const inputPending = inputReady && ptyAttachable && !ptyConnected && activated;
|
|
286
|
+
let terminalModeLabel: string | null;
|
|
287
|
+
if (readOnly) terminalModeLabel = "read-only";
|
|
288
|
+
else if (!ptyAttachable) terminalModeLabel = acceptsInput ? null : "output only";
|
|
289
|
+
else if (ptyStatus === "error") terminalModeLabel = "connection error";
|
|
290
|
+
else if (acceptsInput) terminalModeLabel = null;
|
|
291
|
+
else terminalModeLabel = activated ? "connecting" : "connect on input";
|
|
292
|
+
|
|
293
|
+
// Boot-in-terminal: after the user engages a not-yet-warm box, show styled
|
|
237
294
|
// status lines INSIDE xterm instead of an overlay — but only when there is no
|
|
238
295
|
// firehose transcript to show yet (otherwise the projected output is shown).
|
|
239
|
-
const warm = liveness
|
|
296
|
+
const warm = sandboxAcceptsLiveIo(liveness);
|
|
240
297
|
const booting =
|
|
241
298
|
activated &&
|
|
242
299
|
!ptyMode &&
|
|
@@ -244,8 +301,25 @@ export function SandboxTerminal({
|
|
|
244
301
|
liveness !== null &&
|
|
245
302
|
liveness !== undefined &&
|
|
246
303
|
result.chunks.length === 0;
|
|
304
|
+
const surfaceState = terminalSurfaceState({
|
|
305
|
+
ready,
|
|
306
|
+
acceptsInput,
|
|
307
|
+
inputPending,
|
|
308
|
+
ptyStatus,
|
|
309
|
+
booting,
|
|
310
|
+
});
|
|
247
311
|
|
|
248
312
|
function handleActivate() {
|
|
313
|
+
// Capture-phase activation may synchronously negotiate a fresh terminal
|
|
314
|
+
// capability and rerender the shell. Focus xterm before that state change so
|
|
315
|
+
// the user's first keystroke or paste reaches its already-bounded input
|
|
316
|
+
// queue instead of landing on the surrounding dock.
|
|
317
|
+
const term = termRef.current;
|
|
318
|
+
if (term && !readOnly && (ptyAttachable || result.write !== null)) {
|
|
319
|
+
term.options.disableStdin = false;
|
|
320
|
+
term.options.cursorBlink = true;
|
|
321
|
+
}
|
|
322
|
+
term?.focus();
|
|
249
323
|
if (!activated) setActivated(true);
|
|
250
324
|
onActivate?.();
|
|
251
325
|
}
|
|
@@ -361,10 +435,6 @@ export function SandboxTerminal({
|
|
|
361
435
|
requestAnimationFrame(() => {
|
|
362
436
|
if (disposed) return;
|
|
363
437
|
settle();
|
|
364
|
-
if (ptyOutputQueueRef.current.length > 0) {
|
|
365
|
-
for (const data of ptyOutputQueueRef.current) term.write(data);
|
|
366
|
-
ptyOutputQueueRef.current = [];
|
|
367
|
-
}
|
|
368
438
|
el.setAttribute("data-og-term-ready", "true");
|
|
369
439
|
if (typeof globalThis.__OG_TERMINAL_DEBUG__ === "function") {
|
|
370
440
|
globalThis.__OG_TERMINAL_DEBUG__({
|
|
@@ -397,7 +467,7 @@ export function SandboxTerminal({
|
|
|
397
467
|
|
|
398
468
|
// Sync stdin/cursor at runtime (NOT a remount) when interactivity flips, so the
|
|
399
469
|
// projection→PTY handoff keeps the single Terminal instance + its scrollback.
|
|
400
|
-
|
|
470
|
+
useLayoutEffect(() => {
|
|
401
471
|
const term = termRef.current;
|
|
402
472
|
if (!ready || !term) return;
|
|
403
473
|
term.options.disableStdin = !interactive;
|
|
@@ -455,16 +525,24 @@ export function SandboxTerminal({
|
|
|
455
525
|
}
|
|
456
526
|
}, [ready, result.chunks, ptyMode]);
|
|
457
527
|
|
|
458
|
-
// Wire interactive input when allowed.
|
|
459
|
-
//
|
|
460
|
-
|
|
528
|
+
// Wire interactive input when allowed. `ptyWrite` is stable across socket
|
|
529
|
+
// status changes, so this subscription does not tear down while a grant opens
|
|
530
|
+
// or rotates and cannot create a first-keystroke gap.
|
|
531
|
+
useLayoutEffect(() => {
|
|
461
532
|
const term = termRef.current;
|
|
462
|
-
if (!ready || !term || !interactive)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
533
|
+
if (!ready || !term || !interactive) {
|
|
534
|
+
setInputReady(false);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const sink = ptyAttachable ? ptyWrite : result.write;
|
|
538
|
+
if (!sink) {
|
|
539
|
+
setInputReady(false);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const sub = subscribeTerminalInput(term, sink, true);
|
|
543
|
+
setInputReady(sub !== null);
|
|
544
|
+
return () => sub?.dispose();
|
|
545
|
+
}, [ready, interactive, ptyAttachable, ptyWrite, result.write]);
|
|
468
546
|
|
|
469
547
|
// In PTY mode, tell ttyd the window size on the xterm resize event.
|
|
470
548
|
useEffect(() => {
|
|
@@ -551,6 +629,10 @@ export function SandboxTerminal({
|
|
|
551
629
|
className="h-full w-full"
|
|
552
630
|
style={{ visibility: ready ? "visible" : "hidden" }}
|
|
553
631
|
data-opengeni-terminal
|
|
632
|
+
data-opengeni-terminal-ready={ready ? "true" : "false"}
|
|
633
|
+
data-opengeni-terminal-interactive={surfaceState === "interactive" ? "true" : "false"}
|
|
634
|
+
data-opengeni-terminal-state={surfaceState}
|
|
635
|
+
data-opengeni-terminal-status={ptyAttachable ? ptyStatus : "firehose"}
|
|
554
636
|
/>
|
|
555
637
|
</div>
|
|
556
638
|
</div>
|