@opengeni/react 0.45.0 → 0.48.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 +68 -12
- package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
- package/dist/chunk-FK6VG4LL.js.map +1 -0
- package/dist/{chunk-HFO4ERGQ.js → chunk-FWXGSNXT.js} +2 -2
- package/dist/{chunk-SRFUT2ZU.js → chunk-I4MPFDRP.js} +119 -63
- package/dist/chunk-I4MPFDRP.js.map +1 -0
- package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
- package/dist/chunk-KZ73RL76.js.map +1 -0
- package/dist/{chunk-LWR4MXSS.js → chunk-LHLYWG5R.js} +10 -1
- package/dist/chunk-LHLYWG5R.js.map +1 -0
- package/dist/{chunk-L3EWO3UK.js → chunk-NJ7M2B6Z.js} +445 -84
- package/dist/chunk-NJ7M2B6Z.js.map +1 -0
- package/dist/{chunk-VCBFUSUZ.js → chunk-O4VXOBGF.js} +3 -3
- package/dist/{chunk-VCBFUSUZ.js.map → chunk-O4VXOBGF.js.map} +1 -1
- package/dist/{chunk-6EDV6YFE.js → chunk-OL6QVXGF.js} +121 -29
- package/dist/chunk-OL6QVXGF.js.map +1 -0
- package/dist/chunk-VZTQ73XT.js +86 -0
- package/dist/chunk-VZTQ73XT.js.map +1 -0
- package/dist/{chunk-EHSYZ4KP.js → chunk-WYA65Y3F.js} +16 -16
- package/dist/chunk-WYA65Y3F.js.map +1 -0
- package/dist/{chunk-FD72GJMK.js → chunk-XCNTXWBB.js} +274 -125
- package/dist/chunk-XCNTXWBB.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/components/chat-composer.d.ts +7 -2
- package/dist/components/composer-transcription-control.d.ts +2 -0
- package/dist/components/composer.d.ts +14 -0
- package/dist/components/machines/machine-detail.d.ts +3 -1
- package/dist/components/machines-dashboard.d.ts +3 -3
- package/dist/components/message-timeline.d.ts +12 -2
- package/dist/components/sandbox-files.d.ts +2 -2
- package/dist/components/sandbox-terminal.d.ts +29 -0
- package/dist/components/sandbox-workspace.d.ts +5 -1
- package/dist/components/workspace-dock.d.ts +3 -1
- package/dist/composer.d.ts +2 -2
- package/dist/composer.js +6 -6
- package/dist/hooks/internal.d.ts +6 -0
- package/dist/hooks/use-codex-accounts.d.ts +1 -1
- package/dist/hooks/use-environments.d.ts +10 -4
- package/dist/hooks/use-machines.d.ts +7 -0
- package/dist/hooks/use-sandbox-files.d.ts +19 -0
- package/dist/hooks/use-sandbox-git.d.ts +7 -0
- package/dist/hooks/use-transcription.d.ts +2 -2
- package/dist/hooks/use-voice-input.d.ts +13 -4
- package/dist/index.d.ts +6 -5
- package/dist/index.js +904 -538
- package/dist/index.js.map +1 -1
- package/dist/lib/composer-responsive-context.d.ts +9 -0
- package/dist/lib/use-portal-token-style.d.ts +14 -3
- package/dist/machines.js +2 -2
- package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-U5JFG7HT.js} +19 -18
- package/dist/queue-surface-implementation-U5JFG7HT.js.map +1 -0
- package/dist/realtime/realtime-control.d.ts +9 -0
- package/dist/realtime.js +29 -32
- package/dist/realtime.js.map +1 -1
- package/dist/session-ui.js +5 -5
- package/dist/session.js +4 -4
- package/dist/timeline/activity-rail.d.ts +3 -2
- package/dist/timeline/index.d.ts +2 -2
- package/dist/timeline/parsers.d.ts +3 -3
- package/dist/timeline/registry.d.ts +3 -0
- package/dist/timeline/screenshot-lightbox.d.ts +1 -1
- package/dist/timeline/types.d.ts +4 -0
- package/dist/voice-recording-store.d.ts +8 -2
- package/package.json +20 -4
- package/src/client.ts +3 -0
- package/src/components/chat-composer.tsx +12 -2
- package/src/components/code-editor.tsx +1 -1
- package/src/components/command-palette.tsx +1 -1
- package/src/components/composer-transcription-control.tsx +41 -16
- package/src/components/composer.tsx +52 -26
- package/src/components/copy-button.tsx +2 -2
- package/src/components/desktop-viewer.tsx +2 -2
- package/src/components/file-browser.tsx +39 -17
- package/src/components/human-input-form.tsx +2 -2
- package/src/components/machine-card.tsx +1 -1
- package/src/components/machines/machine-detail.tsx +39 -15
- package/src/components/machines-dashboard.tsx +7 -6
- package/src/components/message-timeline.tsx +44 -11
- package/src/components/model-picker.tsx +2 -2
- package/src/components/model-policy-picker.tsx +16 -15
- package/src/components/queue-surface-implementation.tsx +20 -16
- package/src/components/queue-surface-state.tsx +2 -2
- package/src/components/sandbox-files.tsx +140 -60
- package/src/components/sandbox-terminal.tsx +24 -5
- package/src/components/sandbox-workspace.tsx +180 -142
- package/src/components/session-chrome.tsx +14 -14
- package/src/components/tooltip.tsx +13 -16
- package/src/components/user-message-body.tsx +1 -1
- package/src/components/workbench-changes.tsx +4 -4
- package/src/components/workspace-dock.tsx +13 -5
- package/src/composer.ts +3 -0
- package/src/hooks/internal.ts +132 -38
- package/src/hooks/use-codex-accounts.ts +4 -4
- package/src/hooks/use-environments.ts +24 -5
- package/src/hooks/use-file-attachments.ts +70 -32
- package/src/hooks/use-goal.ts +17 -5
- package/src/hooks/use-machines.ts +47 -1
- package/src/hooks/use-sandbox-files.ts +310 -59
- package/src/hooks/use-sandbox-git.ts +148 -41
- package/src/hooks/use-session-capabilities.ts +35 -24
- package/src/hooks/use-session-events.ts +18 -4
- package/src/hooks/use-transcription.ts +4 -14
- package/src/hooks/use-turn-queue.ts +17 -5
- package/src/hooks/use-voice-input.ts +481 -36
- package/src/hooks/use-windowed-sections.ts +9 -7
- package/src/index.ts +11 -6
- package/src/lib/composer-responsive-context.ts +15 -0
- package/src/lib/use-portal-token-style.ts +60 -15
- package/src/provider.tsx +52 -7
- package/src/realtime/dropdown-menu.tsx +15 -19
- package/src/realtime/realtime-control.tsx +18 -7
- package/src/timeline/activity-rail.tsx +15 -6
- package/src/timeline/index.ts +1 -1
- package/src/timeline/parsers.ts +33 -20
- package/src/timeline/projection.ts +23 -0
- package/src/timeline/registry.ts +7 -0
- package/src/timeline/screenshot-lightbox.tsx +15 -4
- package/src/timeline/shared.tsx +8 -8
- package/src/timeline/tool-renderers.tsx +166 -22
- package/src/timeline/turn-summary.tsx +6 -6
- package/src/timeline/types.ts +4 -0
- package/src/voice-recording-store.ts +15 -0
- package/styles/compiled.css +5065 -0
- package/styles/compiled.d.ts +2 -0
- package/styles/effective-tokens.css +27 -0
- package/styles/index.css +3 -0
- package/styles/responsive.css +196 -0
- package/styles/responsive.d.ts +2 -0
- package/styles/tokens.css +50 -17
- package/dist/chunk-6EDV6YFE.js.map +0 -1
- package/dist/chunk-EB67J347.js.map +0 -1
- package/dist/chunk-EHSYZ4KP.js.map +0 -1
- package/dist/chunk-FD72GJMK.js.map +0 -1
- package/dist/chunk-JB5725BI.js +0 -48
- package/dist/chunk-JB5725BI.js.map +0 -1
- package/dist/chunk-L3EWO3UK.js.map +0 -1
- package/dist/chunk-LWR4MXSS.js.map +0 -1
- package/dist/chunk-SRFUT2ZU.js.map +0 -1
- package/dist/chunk-U3CSCMWA.js.map +0 -1
- package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
- /package/dist/{chunk-HFO4ERGQ.js.map → chunk-FWXGSNXT.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
healthPulses,
|
|
26
26
|
pointsFor,
|
|
27
27
|
useMachines
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-OL6QVXGF.js";
|
|
29
29
|
import {
|
|
30
30
|
SESSION_EVENT_BROWSER_MAX_BYTES,
|
|
31
31
|
SESSION_EVENT_BROWSER_MAX_COUNT,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
useSessionLineage,
|
|
53
53
|
useSessionMcpApprovalPolicy,
|
|
54
54
|
useTurnQueue
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-I4MPFDRP.js";
|
|
56
56
|
import {
|
|
57
57
|
ActivityDisclosure,
|
|
58
58
|
ActivityRail,
|
|
@@ -99,7 +99,6 @@ import {
|
|
|
99
99
|
parseFreeformApplyPatch,
|
|
100
100
|
parseToolArgs,
|
|
101
101
|
rawTypeOf,
|
|
102
|
-
redactSecrets,
|
|
103
102
|
sandboxCommandExitCode,
|
|
104
103
|
sessionChromeGoalPillState,
|
|
105
104
|
stripExecBanner,
|
|
@@ -111,8 +110,8 @@ import {
|
|
|
111
110
|
useThemeType,
|
|
112
111
|
userMessageLikelyNeedsDisclosure,
|
|
113
112
|
v4aToGitFileDiff
|
|
114
|
-
} from "./chunk-
|
|
115
|
-
import "./chunk-
|
|
113
|
+
} from "./chunk-XCNTXWBB.js";
|
|
114
|
+
import "./chunk-O4VXOBGF.js";
|
|
116
115
|
import {
|
|
117
116
|
buildTimeline,
|
|
118
117
|
creditExhaustedFromEvents,
|
|
@@ -120,7 +119,7 @@ import {
|
|
|
120
119
|
groupTimeline,
|
|
121
120
|
sessionStatusFromEvents,
|
|
122
121
|
toolDisplayName
|
|
123
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-LHLYWG5R.js";
|
|
124
123
|
import {
|
|
125
124
|
Actions,
|
|
126
125
|
AttachButton,
|
|
@@ -173,19 +172,20 @@ import {
|
|
|
173
172
|
useSlashCommands,
|
|
174
173
|
useTranscription,
|
|
175
174
|
useVoiceInput
|
|
176
|
-
} from "./chunk-
|
|
175
|
+
} from "./chunk-NJ7M2B6Z.js";
|
|
177
176
|
import {
|
|
178
177
|
FILE_ONLY_MESSAGE_TEXT,
|
|
179
178
|
composeSendInput,
|
|
180
179
|
shouldSteerOnKey,
|
|
181
180
|
shouldSubmitOnKey,
|
|
182
181
|
useComposer
|
|
183
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-FWXGSNXT.js";
|
|
184
183
|
import {
|
|
185
184
|
useMutationRunner,
|
|
185
|
+
usePageLiveActivity,
|
|
186
186
|
usePolledValue,
|
|
187
187
|
useSessionEventTrigger
|
|
188
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-KZ73RL76.js";
|
|
189
189
|
import {
|
|
190
190
|
BillingClassMark,
|
|
191
191
|
ModelPolicyPicker,
|
|
@@ -194,7 +194,7 @@ import {
|
|
|
194
194
|
PickerBackHeader,
|
|
195
195
|
PickerNavRow,
|
|
196
196
|
defaultModelPolicyPickerMessages
|
|
197
|
-
} from "./chunk-
|
|
197
|
+
} from "./chunk-WYA65Y3F.js";
|
|
198
198
|
import {
|
|
199
199
|
useOpenGeni,
|
|
200
200
|
useOpenGeniClient
|
|
@@ -222,7 +222,7 @@ import {
|
|
|
222
222
|
TooltipContent,
|
|
223
223
|
TooltipProvider,
|
|
224
224
|
TooltipTrigger
|
|
225
|
-
} from "./chunk-
|
|
225
|
+
} from "./chunk-FK6VG4LL.js";
|
|
226
226
|
import {
|
|
227
227
|
COMPOSER_PAYMENT_REQUIRED_MESSAGE,
|
|
228
228
|
CREDIT_EXHAUSTION_MESSAGE,
|
|
@@ -237,8 +237,9 @@ import {
|
|
|
237
237
|
tryParseJson
|
|
238
238
|
} from "./chunk-LAKLF4PA.js";
|
|
239
239
|
import {
|
|
240
|
+
usePortalTokenSource,
|
|
240
241
|
usePortalTokenStyle
|
|
241
|
-
} from "./chunk-
|
|
242
|
+
} from "./chunk-VZTQ73XT.js";
|
|
242
243
|
import {
|
|
243
244
|
cn
|
|
244
245
|
} from "./chunk-22KP6LR5.js";
|
|
@@ -423,6 +424,10 @@ function useVariableSets(options = {}) {
|
|
|
423
424
|
},
|
|
424
425
|
[client, workspaceId, run, refresh]
|
|
425
426
|
);
|
|
427
|
+
const readVariable = useCallback4(
|
|
428
|
+
async (variableSetId, name) => await run(() => client.getVariableSetVariable(workspaceId, variableSetId, name)),
|
|
429
|
+
[client, workspaceId, run]
|
|
430
|
+
);
|
|
426
431
|
const setVariable = useCallback4(
|
|
427
432
|
async (variableSetId, name, value) => {
|
|
428
433
|
const result = await run(
|
|
@@ -456,6 +461,7 @@ function useVariableSets(options = {}) {
|
|
|
456
461
|
create,
|
|
457
462
|
update,
|
|
458
463
|
remove,
|
|
464
|
+
readVariable,
|
|
459
465
|
setVariable,
|
|
460
466
|
deleteVariable,
|
|
461
467
|
mutating,
|
|
@@ -478,7 +484,10 @@ function useEnvironments(options = {}) {
|
|
|
478
484
|
deleteVariableSetVariable: options.client.deleteEnvironmentVariable ?? options.client.deleteVariableSetVariable
|
|
479
485
|
};
|
|
480
486
|
}, [options.client]);
|
|
481
|
-
const result = useVariableSets({
|
|
487
|
+
const result = useVariableSets({
|
|
488
|
+
...options,
|
|
489
|
+
...legacyClient ? { client: legacyClient } : {}
|
|
490
|
+
});
|
|
482
491
|
return { ...result, environments: result.variableSets };
|
|
483
492
|
}
|
|
484
493
|
|
|
@@ -906,6 +915,8 @@ function rotationsFrom(events) {
|
|
|
906
915
|
function useSessionCapabilities(sessionId, options = {}) {
|
|
907
916
|
const { client, workspaceId } = useOpenGeni(options);
|
|
908
917
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
918
|
+
const pageLive = usePageLiveActivity();
|
|
919
|
+
const lifecycleEnabled = enabled && pageLive;
|
|
909
920
|
const attachDesktop = options.attachDesktop ?? false;
|
|
910
921
|
const attachTerminal = options.attachTerminal ?? false;
|
|
911
922
|
const attachFiles = options.attachFiles ?? false;
|
|
@@ -940,7 +951,7 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
940
951
|
epochRef.current = 0;
|
|
941
952
|
viewerIdRef.current = null;
|
|
942
953
|
}
|
|
943
|
-
if (!
|
|
954
|
+
if (!lifecycleEnabled || !sessionId) {
|
|
944
955
|
setState("idle");
|
|
945
956
|
setCapabilities(null);
|
|
946
957
|
return;
|
|
@@ -953,7 +964,7 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
953
964
|
const startedAt = Date.now();
|
|
954
965
|
const clearTimers = () => {
|
|
955
966
|
if (pollTimer !== null) clearTimeout(pollTimer);
|
|
956
|
-
if (heartbeatTimer !== null)
|
|
967
|
+
if (heartbeatTimer !== null) clearTimeout(heartbeatTimer);
|
|
957
968
|
pollTimer = null;
|
|
958
969
|
heartbeatTimer = null;
|
|
959
970
|
};
|
|
@@ -966,19 +977,26 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
966
977
|
const startHeartbeat = (caps) => {
|
|
967
978
|
if (!localViewerId || heartbeatTimer !== null) return;
|
|
968
979
|
const intervalMs = caps.viewerHeartbeatIntervalMs > 0 ? caps.viewerHeartbeatIntervalMs : 3e4;
|
|
969
|
-
|
|
980
|
+
const schedule = () => {
|
|
970
981
|
if (cancelled || !localViewerId) return;
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
+
heartbeatTimer = setTimeout(() => {
|
|
983
|
+
heartbeatTimer = null;
|
|
984
|
+
if (cancelled || !localViewerId) return;
|
|
985
|
+
void client.heartbeatViewer(workspaceId, sessionId, localViewerId, {
|
|
986
|
+
leaseEpoch: epochRef.current
|
|
987
|
+
}).then((res) => {
|
|
988
|
+
if (!res.alive && !cancelled) {
|
|
989
|
+
renegotiate();
|
|
990
|
+
}
|
|
991
|
+
}).catch((cause) => {
|
|
992
|
+
if (cancelled) return;
|
|
993
|
+
if (cause instanceof OpenGeniApiError && (cause.status === 409 || cause.status === 410)) {
|
|
994
|
+
renegotiate();
|
|
995
|
+
}
|
|
996
|
+
}).finally(schedule);
|
|
997
|
+
}, intervalMs);
|
|
998
|
+
};
|
|
999
|
+
schedule();
|
|
982
1000
|
};
|
|
983
1001
|
const pollUntilWarm = () => {
|
|
984
1002
|
pollTimer = setTimeout(() => {
|
|
@@ -1113,7 +1131,7 @@ function useSessionCapabilities(sessionId, options = {}) {
|
|
|
1113
1131
|
client,
|
|
1114
1132
|
workspaceId,
|
|
1115
1133
|
sessionId,
|
|
1116
|
-
|
|
1134
|
+
lifecycleEnabled,
|
|
1117
1135
|
attachDesktop,
|
|
1118
1136
|
attachTerminal,
|
|
1119
1137
|
attachFiles,
|
|
@@ -1816,7 +1834,7 @@ function useSandboxTerminal(sessionId, options) {
|
|
|
1816
1834
|
}
|
|
1817
1835
|
|
|
1818
1836
|
// src/hooks/use-sandbox-files.ts
|
|
1819
|
-
import { useCallback as useCallback12, useEffect as useEffect8, useRef as useRef7, useState as useState6 } from "react";
|
|
1837
|
+
import { useCallback as useCallback12, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef7, useState as useState6 } from "react";
|
|
1820
1838
|
var CapturedFileUnavailableError = class extends Error {
|
|
1821
1839
|
constructor(path, reason) {
|
|
1822
1840
|
super(
|
|
@@ -1838,6 +1856,25 @@ var FileWriteConflictError = class extends Error {
|
|
|
1838
1856
|
}
|
|
1839
1857
|
code = "file_write_conflict";
|
|
1840
1858
|
};
|
|
1859
|
+
function normalizeRoot(root) {
|
|
1860
|
+
const normalized = root.replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
1861
|
+
return normalized === "." ? "" : normalized;
|
|
1862
|
+
}
|
|
1863
|
+
function qualifyStatusPath(root, path) {
|
|
1864
|
+
const normalized = normalizeRoot(root);
|
|
1865
|
+
return normalized ? `${normalized}/${path}` : path;
|
|
1866
|
+
}
|
|
1867
|
+
function summarizeStatuses(statuses) {
|
|
1868
|
+
const repositories = statuses.filter(({ status }) => status.isRepo);
|
|
1869
|
+
return {
|
|
1870
|
+
branch: repositories.length === 1 ? repositories[0]?.status.head ?? null : null,
|
|
1871
|
+
isRepo: repositories.length > 0,
|
|
1872
|
+
repoCount: repositories.length,
|
|
1873
|
+
ahead: repositories.reduce((sum, { status }) => sum + status.ahead, 0),
|
|
1874
|
+
behind: repositories.reduce((sum, { status }) => sum + status.behind, 0),
|
|
1875
|
+
dirtyCount: repositories.reduce((sum, { status }) => sum + status.files.length, 0)
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1841
1878
|
function parentOf(path) {
|
|
1842
1879
|
const i = path.lastIndexOf("/");
|
|
1843
1880
|
return i <= 0 ? "" : path.slice(0, i);
|
|
@@ -1881,7 +1918,10 @@ function replaceChildren(nodes, targetPath, children) {
|
|
|
1881
1918
|
return { ...node, children };
|
|
1882
1919
|
}
|
|
1883
1920
|
if (node.kind === "dir" && node.children && targetPath.startsWith(`${node.path}/`)) {
|
|
1884
|
-
return {
|
|
1921
|
+
return {
|
|
1922
|
+
...node,
|
|
1923
|
+
children: replaceChildren(node.children, targetPath, children)
|
|
1924
|
+
};
|
|
1885
1925
|
}
|
|
1886
1926
|
return node;
|
|
1887
1927
|
});
|
|
@@ -1896,6 +1936,30 @@ function findNodeByPath(nodes, path) {
|
|
|
1896
1936
|
}
|
|
1897
1937
|
return void 0;
|
|
1898
1938
|
}
|
|
1939
|
+
function loadedDirectoryPaths(nodes) {
|
|
1940
|
+
const paths = [""];
|
|
1941
|
+
const walk = (list) => {
|
|
1942
|
+
for (const node of list) {
|
|
1943
|
+
if (node.kind !== "dir" || node.children === void 0) continue;
|
|
1944
|
+
paths.push(node.path);
|
|
1945
|
+
walk(node.children);
|
|
1946
|
+
}
|
|
1947
|
+
};
|
|
1948
|
+
walk(nodes);
|
|
1949
|
+
return paths;
|
|
1950
|
+
}
|
|
1951
|
+
function initialDirectoryFrontier(rootPath, repoPaths) {
|
|
1952
|
+
const rootParts = normalizeRoot(rootPath).split("/").filter(Boolean);
|
|
1953
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1954
|
+
for (const repoPath of repoPaths) {
|
|
1955
|
+
const parts = normalizeRoot(repoPath).split("/").filter(Boolean);
|
|
1956
|
+
if (rootParts.some((part, index) => parts[index] !== part)) continue;
|
|
1957
|
+
for (let depth = rootParts.length + 1; depth <= parts.length; depth += 1) {
|
|
1958
|
+
paths.add(parts.slice(0, depth).join("/"));
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
return [...paths].sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b)).slice(0, 8);
|
|
1962
|
+
}
|
|
1899
1963
|
function parentIsLoaded(nodes, parent) {
|
|
1900
1964
|
if (parent === "") return true;
|
|
1901
1965
|
const node = findNodeByPath(nodes, parent);
|
|
@@ -1927,7 +1991,10 @@ function removeNode(nodes, path) {
|
|
|
1927
1991
|
return nodes.map((node) => {
|
|
1928
1992
|
if (node.path === parent) {
|
|
1929
1993
|
if (node.kind !== "dir" || node.children === void 0) return node;
|
|
1930
|
-
return {
|
|
1994
|
+
return {
|
|
1995
|
+
...node,
|
|
1996
|
+
children: node.children.filter((n) => n.path !== path)
|
|
1997
|
+
};
|
|
1931
1998
|
}
|
|
1932
1999
|
if (node.kind === "dir" && node.children && parent.startsWith(`${node.path}/`)) {
|
|
1933
2000
|
return { ...node, children: removeNode(node.children, path) };
|
|
@@ -1996,15 +2063,23 @@ async function assertCapturedHash(bytes, expected) {
|
|
|
1996
2063
|
function useSandboxFiles(sessionId, options = {}) {
|
|
1997
2064
|
const { client, workspaceId } = useOpenGeni(options);
|
|
1998
2065
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
2066
|
+
const active = options.active ?? true;
|
|
1999
2067
|
const rootPath = options.rootPath ?? "";
|
|
2068
|
+
const repoPathsKey = [
|
|
2069
|
+
...new Set((options.repoPaths?.length ? options.repoPaths : [rootPath]).map(normalizeRoot))
|
|
2070
|
+
].join("\0");
|
|
2071
|
+
const repoPaths = useMemo4(() => repoPathsKey.split("\0"), [repoPathsKey]);
|
|
2000
2072
|
const capture = options.capture ?? null;
|
|
2001
2073
|
const isLive2 = options.liveness === "warm" || options.liveness === "draining";
|
|
2002
|
-
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${rootPath}`;
|
|
2074
|
+
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${rootPath}\0${repoPathsKey}`;
|
|
2003
2075
|
const [tree, setTree] = useState6([]);
|
|
2004
2076
|
const treeRef = useRef7([]);
|
|
2005
2077
|
const [loading, setLoading] = useState6(false);
|
|
2006
2078
|
const [expandingPaths, setExpandingPaths] = useState6(/* @__PURE__ */ new Set());
|
|
2007
2079
|
const [error, setError] = useState6(null);
|
|
2080
|
+
const [gitSummary, setGitSummary] = useState6(null);
|
|
2081
|
+
const [gitLoading, setGitLoading] = useState6(false);
|
|
2082
|
+
const [contentRevision, setContentRevision] = useState6(0);
|
|
2008
2083
|
const [stateIdentity, setStateIdentity] = useState6(identityKey);
|
|
2009
2084
|
const [source, setSource] = useState6(null);
|
|
2010
2085
|
const sourceRef = useRef7(null);
|
|
@@ -2016,7 +2091,9 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2016
2091
|
const lastSeqRef = useRef7(0);
|
|
2017
2092
|
const pendingParentsRef = useRef7(/* @__PURE__ */ new Set());
|
|
2018
2093
|
const pendingGitRef = useRef7(false);
|
|
2094
|
+
const pendingAgentToolRef = useRef7(false);
|
|
2019
2095
|
const debounceRef = useRef7(null);
|
|
2096
|
+
const lastCommandRefreshAtRef = useRef7(0);
|
|
2020
2097
|
const ownRevisionsRef = useRef7(/* @__PURE__ */ new Set());
|
|
2021
2098
|
const onMutationError = options.onMutationError;
|
|
2022
2099
|
treeRef.current = tree;
|
|
@@ -2050,48 +2127,83 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2050
2127
|
refreshAbortRef.current = refreshAbort;
|
|
2051
2128
|
const generation = refreshGenerationRef.current += 1;
|
|
2052
2129
|
setLoading(true);
|
|
2130
|
+
setGitLoading(true);
|
|
2053
2131
|
setError(null);
|
|
2054
2132
|
try {
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
);
|
|
2062
|
-
if (refreshGenerationRef.current !== generation) return;
|
|
2063
|
-
const overlay = /* @__PURE__ */ new Map();
|
|
2064
|
-
for (const file of status.files) {
|
|
2065
|
-
const code = file.worktree ?? file.index;
|
|
2066
|
-
const mapped = code ? GIT_STATUS_TO_TREE[code] : void 0;
|
|
2067
|
-
if (mapped) overlay.set(file.path, mapped);
|
|
2068
|
-
}
|
|
2069
|
-
statusRef.current = overlay;
|
|
2070
|
-
} catch {
|
|
2071
|
-
if (refreshGenerationRef.current !== generation) return;
|
|
2072
|
-
statusRef.current = /* @__PURE__ */ new Map();
|
|
2073
|
-
}
|
|
2074
|
-
const listed = await client.fsList(
|
|
2133
|
+
const frontierPaths = initialDirectoryFrontier(rootPath, repoPaths);
|
|
2134
|
+
const listRequests = [rootPath, ...frontierPaths].map((path) => ({
|
|
2135
|
+
path,
|
|
2136
|
+
depth: 1
|
|
2137
|
+
}));
|
|
2138
|
+
const statusPromise = repoPaths.length > 0 ? client.gitReadBatch(
|
|
2075
2139
|
workspaceId,
|
|
2076
2140
|
sessionId,
|
|
2077
|
-
{
|
|
2141
|
+
{
|
|
2142
|
+
requests: repoPaths.map((root) => ({
|
|
2143
|
+
status: { path: root }
|
|
2144
|
+
}))
|
|
2145
|
+
},
|
|
2146
|
+
{ signal: refreshAbort.signal }
|
|
2147
|
+
).then(
|
|
2148
|
+
(batch) => batch.results.map((result, index) => ({
|
|
2149
|
+
root: repoPaths[index] ?? "",
|
|
2150
|
+
status: result.status
|
|
2151
|
+
}))
|
|
2152
|
+
).catch(() => null) : Promise.resolve([]);
|
|
2153
|
+
const listedBatch = await client.fsListBatch(
|
|
2154
|
+
workspaceId,
|
|
2155
|
+
sessionId,
|
|
2156
|
+
{ requests: listRequests },
|
|
2078
2157
|
{ signal: refreshAbort.signal }
|
|
2079
2158
|
);
|
|
2080
2159
|
if (refreshGenerationRef.current !== generation) return;
|
|
2160
|
+
const listed = listedBatch.results[0];
|
|
2161
|
+
if (!listed) throw new Error("Workspace list batch did not return the root result.");
|
|
2081
2162
|
const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));
|
|
2082
|
-
setTree(
|
|
2083
|
-
|
|
2084
|
-
|
|
2163
|
+
setTree((prev) => {
|
|
2164
|
+
let hydrated = prev.length === 0 ? children : mergeRootChildren(prev, children);
|
|
2165
|
+
for (const [index, path] of frontierPaths.entries()) {
|
|
2166
|
+
const prefetched = listedBatch.results[index + 1];
|
|
2167
|
+
if (!prefetched) continue;
|
|
2168
|
+
hydrated = replaceChildren(
|
|
2169
|
+
hydrated,
|
|
2170
|
+
path,
|
|
2171
|
+
(prefetched.root.children ?? []).map((node) => fsNodeToTree(node))
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
return applyStatus(hydrated);
|
|
2175
|
+
});
|
|
2085
2176
|
sourceRef.current = "live";
|
|
2086
2177
|
setSource("live");
|
|
2178
|
+
setLoading(false);
|
|
2179
|
+
const statuses = await statusPromise;
|
|
2180
|
+
if (refreshGenerationRef.current !== generation) return;
|
|
2181
|
+
if (statuses) {
|
|
2182
|
+
const overlay = /* @__PURE__ */ new Map();
|
|
2183
|
+
for (const { root, status } of statuses) {
|
|
2184
|
+
for (const file of status.files) {
|
|
2185
|
+
const code = file.worktree ?? file.index;
|
|
2186
|
+
const mapped = code ? GIT_STATUS_TO_TREE[code] : void 0;
|
|
2187
|
+
if (mapped) overlay.set(qualifyStatusPath(root, file.path), mapped);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
statusRef.current = overlay;
|
|
2191
|
+
setGitSummary(summarizeStatuses(statuses));
|
|
2192
|
+
} else {
|
|
2193
|
+
statusRef.current = /* @__PURE__ */ new Map();
|
|
2194
|
+
setGitSummary(null);
|
|
2195
|
+
}
|
|
2196
|
+
setGitLoading(false);
|
|
2197
|
+
setTree((prev) => applyStatus(prev));
|
|
2087
2198
|
} catch (cause) {
|
|
2088
2199
|
if (refreshGenerationRef.current !== generation) return;
|
|
2089
2200
|
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
2090
2201
|
} finally {
|
|
2091
2202
|
if (refreshGenerationRef.current === generation) setLoading(false);
|
|
2203
|
+
if (refreshGenerationRef.current === generation) setGitLoading(false);
|
|
2092
2204
|
if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;
|
|
2093
2205
|
}
|
|
2094
|
-
}, [client, workspaceId, sessionId, rootPath, applyStatus]);
|
|
2206
|
+
}, [client, workspaceId, sessionId, rootPath, repoPaths, applyStatus]);
|
|
2095
2207
|
const seedFromCapture = useCallback12(
|
|
2096
2208
|
(manifest) => {
|
|
2097
2209
|
const overlay = /* @__PURE__ */ new Map();
|
|
@@ -2107,6 +2219,15 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2107
2219
|
);
|
|
2108
2220
|
sourceRef.current = "capture";
|
|
2109
2221
|
setSource("capture");
|
|
2222
|
+
setGitSummary({
|
|
2223
|
+
branch: manifest.repos.length === 1 ? manifest.repos[0]?.head ?? null : null,
|
|
2224
|
+
isRepo: manifest.repos.length > 0,
|
|
2225
|
+
repoCount: manifest.repos.length,
|
|
2226
|
+
ahead: manifest.repos.reduce((sum, repo) => sum + repo.ahead, 0),
|
|
2227
|
+
behind: manifest.repos.reduce((sum, repo) => sum + repo.behind, 0),
|
|
2228
|
+
dirtyCount: manifest.files.length
|
|
2229
|
+
});
|
|
2230
|
+
setGitLoading(false);
|
|
2110
2231
|
setError(null);
|
|
2111
2232
|
},
|
|
2112
2233
|
[applyStatus]
|
|
@@ -2287,7 +2408,12 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2287
2408
|
const identitySignal = identityAbortRef.current.signal;
|
|
2288
2409
|
const parent = parentOf(path);
|
|
2289
2410
|
const exists = Boolean(findNodeByPath(tree, path));
|
|
2290
|
-
const node = {
|
|
2411
|
+
const node = {
|
|
2412
|
+
path,
|
|
2413
|
+
name: leafOf(path),
|
|
2414
|
+
kind: "file",
|
|
2415
|
+
size: content.length
|
|
2416
|
+
};
|
|
2291
2417
|
return await runOptimistic(
|
|
2292
2418
|
"write",
|
|
2293
2419
|
(nodes) => exists ? nodes : insertNode(nodes, parent, node),
|
|
@@ -2325,11 +2451,20 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2325
2451
|
async (path) => {
|
|
2326
2452
|
if (!sessionId) throw new Error("no session");
|
|
2327
2453
|
const parent = parentOf(path);
|
|
2328
|
-
const node = {
|
|
2454
|
+
const node = {
|
|
2455
|
+
path,
|
|
2456
|
+
name: leafOf(path),
|
|
2457
|
+
kind: "file",
|
|
2458
|
+
size: 0
|
|
2459
|
+
};
|
|
2329
2460
|
await runOptimistic(
|
|
2330
2461
|
"create file",
|
|
2331
2462
|
(nodes) => insertNode(nodes, parent, node),
|
|
2332
|
-
() => client.fsWrite(workspaceId, sessionId, {
|
|
2463
|
+
() => client.fsWrite(workspaceId, sessionId, {
|
|
2464
|
+
path,
|
|
2465
|
+
content: "",
|
|
2466
|
+
overwrite: false
|
|
2467
|
+
}),
|
|
2333
2468
|
[parent]
|
|
2334
2469
|
);
|
|
2335
2470
|
},
|
|
@@ -2339,7 +2474,12 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2339
2474
|
async (path) => {
|
|
2340
2475
|
if (!sessionId) throw new Error("no session");
|
|
2341
2476
|
const parent = parentOf(path);
|
|
2342
|
-
const node = {
|
|
2477
|
+
const node = {
|
|
2478
|
+
path,
|
|
2479
|
+
name: leafOf(path),
|
|
2480
|
+
kind: "dir",
|
|
2481
|
+
children: []
|
|
2482
|
+
};
|
|
2343
2483
|
await runOptimistic(
|
|
2344
2484
|
"create folder",
|
|
2345
2485
|
(nodes) => insertNode(nodes, parent, node),
|
|
@@ -2401,6 +2541,8 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2401
2541
|
lastSeqRef.current = 0;
|
|
2402
2542
|
pendingParentsRef.current = /* @__PURE__ */ new Set();
|
|
2403
2543
|
pendingGitRef.current = false;
|
|
2544
|
+
pendingAgentToolRef.current = false;
|
|
2545
|
+
lastCommandRefreshAtRef.current = 0;
|
|
2404
2546
|
if (debounceRef.current) {
|
|
2405
2547
|
clearTimeout(debounceRef.current);
|
|
2406
2548
|
debounceRef.current = null;
|
|
@@ -2415,6 +2557,9 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2415
2557
|
setSource(null);
|
|
2416
2558
|
setLoading(false);
|
|
2417
2559
|
setError(null);
|
|
2560
|
+
setGitSummary(null);
|
|
2561
|
+
setGitLoading(false);
|
|
2562
|
+
setContentRevision(0);
|
|
2418
2563
|
}
|
|
2419
2564
|
if (!enabled) {
|
|
2420
2565
|
return;
|
|
@@ -2423,6 +2568,13 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2423
2568
|
if (currentCapture && (identityChanged || !isLive2 || sourceRef.current !== "live")) {
|
|
2424
2569
|
seedFromCapture(currentCapture);
|
|
2425
2570
|
}
|
|
2571
|
+
if (!active) {
|
|
2572
|
+
if (!active) {
|
|
2573
|
+
setLoading(false);
|
|
2574
|
+
setGitLoading(false);
|
|
2575
|
+
}
|
|
2576
|
+
return;
|
|
2577
|
+
}
|
|
2426
2578
|
if (isLive2 || !currentCapture) {
|
|
2427
2579
|
void refresh();
|
|
2428
2580
|
}
|
|
@@ -2431,34 +2583,52 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2431
2583
|
refreshAbortRef.current = null;
|
|
2432
2584
|
refreshGenerationRef.current += 1;
|
|
2433
2585
|
};
|
|
2434
|
-
}, [enabled, isLive2, captureRevision, identityKey, refresh, seedFromCapture]);
|
|
2586
|
+
}, [enabled, active, isLive2, captureRevision, identityKey, refresh, seedFromCapture]);
|
|
2435
2587
|
const refreshGitOverlay = useCallback12(async () => {
|
|
2436
2588
|
if (!sessionId) return;
|
|
2437
2589
|
const identityGeneration = identityGenerationRef.current;
|
|
2438
2590
|
const identitySignal = identityAbortRef.current.signal;
|
|
2591
|
+
setGitLoading(true);
|
|
2439
2592
|
try {
|
|
2440
|
-
const
|
|
2593
|
+
const batch = await client.gitReadBatch(
|
|
2441
2594
|
workspaceId,
|
|
2442
2595
|
sessionId,
|
|
2443
|
-
{ path:
|
|
2596
|
+
{ requests: repoPaths.map((root) => ({ status: { path: root } })) },
|
|
2444
2597
|
{ signal: identitySignal }
|
|
2445
2598
|
);
|
|
2599
|
+
const statuses = batch.results.map((result, index) => ({
|
|
2600
|
+
root: repoPaths[index] ?? "",
|
|
2601
|
+
status: result.status
|
|
2602
|
+
}));
|
|
2446
2603
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
2447
2604
|
const overlay = /* @__PURE__ */ new Map();
|
|
2448
|
-
for (const
|
|
2449
|
-
const
|
|
2450
|
-
|
|
2451
|
-
|
|
2605
|
+
for (const { root, status } of statuses) {
|
|
2606
|
+
for (const file of status.files) {
|
|
2607
|
+
const code = file.worktree ?? file.index;
|
|
2608
|
+
const mapped = code ? GIT_STATUS_TO_TREE[code] : void 0;
|
|
2609
|
+
if (mapped) overlay.set(qualifyStatusPath(root, file.path), mapped);
|
|
2610
|
+
}
|
|
2452
2611
|
}
|
|
2453
2612
|
statusRef.current = overlay;
|
|
2613
|
+
setGitSummary(summarizeStatuses(statuses));
|
|
2454
2614
|
setTree((prev) => applyStatus(prev));
|
|
2455
2615
|
} catch {
|
|
2616
|
+
} finally {
|
|
2617
|
+
if (identityGenerationRef.current === identityGeneration) setGitLoading(false);
|
|
2456
2618
|
}
|
|
2457
|
-
}, [client, workspaceId, sessionId,
|
|
2619
|
+
}, [client, workspaceId, sessionId, repoPaths, applyStatus]);
|
|
2458
2620
|
const events = options.events;
|
|
2459
2621
|
useEffect8(() => {
|
|
2460
2622
|
if (!enabled || !events) return;
|
|
2623
|
+
if (!active) {
|
|
2624
|
+
for (const event of events) {
|
|
2625
|
+
if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;
|
|
2626
|
+
}
|
|
2627
|
+
return;
|
|
2628
|
+
}
|
|
2461
2629
|
let sawNew = false;
|
|
2630
|
+
let contentChanged = false;
|
|
2631
|
+
let sawCommandDelta = false;
|
|
2462
2632
|
for (const event of events) {
|
|
2463
2633
|
if (event.sequence <= lastSeqRef.current) continue;
|
|
2464
2634
|
if (event.type === "fs.changed") {
|
|
@@ -2468,6 +2638,7 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2468
2638
|
if (payload.source === "write") continue;
|
|
2469
2639
|
if (typeof payload.revision === "number" && ownRevisionsRef.current.has(payload.revision))
|
|
2470
2640
|
continue;
|
|
2641
|
+
contentChanged = true;
|
|
2471
2642
|
for (const change of payload.changes ?? []) {
|
|
2472
2643
|
pendingParentsRef.current.add(parentOf(change.path));
|
|
2473
2644
|
if (change.oldPath) pendingParentsRef.current.add(parentOf(change.oldPath));
|
|
@@ -2478,30 +2649,58 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2478
2649
|
if (payload && typeof payload === "object" && typeof payload.revision === "number" && ownRevisionsRef.current.has(payload.revision))
|
|
2479
2650
|
continue;
|
|
2480
2651
|
pendingGitRef.current = true;
|
|
2652
|
+
} else if (event.type === "agent.toolCall.output") {
|
|
2653
|
+
sawNew = true;
|
|
2654
|
+
contentChanged = true;
|
|
2655
|
+
pendingAgentToolRef.current = true;
|
|
2656
|
+
pendingGitRef.current = true;
|
|
2657
|
+
} else if (event.type === "sandbox.command.output.delta") {
|
|
2658
|
+
sawNew = true;
|
|
2659
|
+
contentChanged = true;
|
|
2660
|
+
sawCommandDelta = true;
|
|
2661
|
+
pendingAgentToolRef.current = true;
|
|
2662
|
+
pendingGitRef.current = true;
|
|
2481
2663
|
}
|
|
2482
2664
|
}
|
|
2483
2665
|
for (const event of events)
|
|
2484
2666
|
if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;
|
|
2485
2667
|
if (!sawNew) return;
|
|
2668
|
+
if (contentChanged && !sawCommandDelta) setContentRevision((revision) => revision + 1);
|
|
2486
2669
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
2487
2670
|
const identityGeneration = identityGenerationRef.current;
|
|
2671
|
+
const delay = sawCommandDelta ? Math.max(0, 1e3 - (Date.now() - lastCommandRefreshAtRef.current)) : 150;
|
|
2488
2672
|
debounceRef.current = setTimeout(() => {
|
|
2489
2673
|
debounceRef.current = null;
|
|
2490
2674
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
2675
|
+
if (sawCommandDelta) {
|
|
2676
|
+
lastCommandRefreshAtRef.current = Date.now();
|
|
2677
|
+
setContentRevision((revision) => revision + 1);
|
|
2678
|
+
}
|
|
2491
2679
|
const parents = pendingParentsRef.current;
|
|
2492
2680
|
pendingParentsRef.current = /* @__PURE__ */ new Set();
|
|
2493
2681
|
const wantGit = pendingGitRef.current;
|
|
2494
2682
|
pendingGitRef.current = false;
|
|
2683
|
+
const wantAgentTool = pendingAgentToolRef.current;
|
|
2684
|
+
pendingAgentToolRef.current = false;
|
|
2495
2685
|
void (async () => {
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
}
|
|
2686
|
+
const paths = wantAgentTool ? loadedDirectoryPaths(treeRef.current) : [...parents];
|
|
2687
|
+
await Promise.all([
|
|
2688
|
+
wantGit ? refreshGitOverlay() : Promise.resolve(),
|
|
2689
|
+
Promise.all(paths.map((path) => reconcilePath(path)))
|
|
2690
|
+
]);
|
|
2502
2691
|
})();
|
|
2503
|
-
},
|
|
2504
|
-
}, [enabled, events, reconcilePath, refreshGitOverlay]);
|
|
2692
|
+
}, delay);
|
|
2693
|
+
}, [enabled, active, events, reconcilePath, refreshGitOverlay]);
|
|
2694
|
+
useEffect8(() => {
|
|
2695
|
+
if (active) return;
|
|
2696
|
+
if (debounceRef.current) {
|
|
2697
|
+
clearTimeout(debounceRef.current);
|
|
2698
|
+
debounceRef.current = null;
|
|
2699
|
+
}
|
|
2700
|
+
pendingParentsRef.current = /* @__PURE__ */ new Set();
|
|
2701
|
+
pendingGitRef.current = false;
|
|
2702
|
+
pendingAgentToolRef.current = false;
|
|
2703
|
+
}, [active]);
|
|
2505
2704
|
useEffect8(
|
|
2506
2705
|
() => () => {
|
|
2507
2706
|
refreshAbortRef.current?.abort();
|
|
@@ -2523,25 +2722,28 @@ function useSandboxFiles(sessionId, options = {}) {
|
|
|
2523
2722
|
deleteEntry,
|
|
2524
2723
|
moveEntry,
|
|
2525
2724
|
refresh,
|
|
2725
|
+
contentRevision: identityMatches ? contentRevision : 0,
|
|
2526
2726
|
source: identityMatches ? source : null,
|
|
2527
2727
|
capturedAt: identityMatches && source === "capture" ? capture?.capturedAt ?? null : null,
|
|
2728
|
+
gitSummary: identityMatches ? gitSummary : null,
|
|
2729
|
+
gitLoading: identityMatches && gitLoading,
|
|
2528
2730
|
loading: identityMatches && loading,
|
|
2529
2731
|
error: identityMatches ? error : null
|
|
2530
2732
|
};
|
|
2531
2733
|
}
|
|
2532
2734
|
|
|
2533
2735
|
// src/hooks/use-sandbox-git.ts
|
|
2534
|
-
import { useCallback as useCallback13, useEffect as useEffect9, useMemo as
|
|
2535
|
-
function
|
|
2736
|
+
import { useCallback as useCallback13, useEffect as useEffect9, useMemo as useMemo5, useRef as useRef8, useState as useState7 } from "react";
|
|
2737
|
+
function normalizeRoot2(root) {
|
|
2536
2738
|
const normalized = root.replaceAll("\\", "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
2537
2739
|
return normalized === "." ? "" : normalized;
|
|
2538
2740
|
}
|
|
2539
2741
|
function qualifyPath(repoRoot, path) {
|
|
2540
|
-
const root =
|
|
2742
|
+
const root = normalizeRoot2(repoRoot);
|
|
2541
2743
|
return root ? `${root}/${path}` : path;
|
|
2542
2744
|
}
|
|
2543
2745
|
function qualifyDiff(repoRoot, file) {
|
|
2544
|
-
const root =
|
|
2746
|
+
const root = normalizeRoot2(repoRoot);
|
|
2545
2747
|
return {
|
|
2546
2748
|
...file,
|
|
2547
2749
|
path: qualifyPath(root, file.path),
|
|
@@ -2550,11 +2752,11 @@ function qualifyDiff(repoRoot, file) {
|
|
|
2550
2752
|
};
|
|
2551
2753
|
}
|
|
2552
2754
|
function uniqueRoots(roots) {
|
|
2553
|
-
return [...new Set(roots.map(
|
|
2755
|
+
return [...new Set(roots.map(normalizeRoot2))].sort((a, b) => a.localeCompare(b));
|
|
2554
2756
|
}
|
|
2555
2757
|
function repoForPath(manifest, repoPath) {
|
|
2556
|
-
const want =
|
|
2557
|
-
const exact = manifest.repos.find((r) =>
|
|
2758
|
+
const want = normalizeRoot2(repoPath);
|
|
2759
|
+
const exact = manifest.repos.find((r) => normalizeRoot2(r.root) === want);
|
|
2558
2760
|
if (exact) return exact;
|
|
2559
2761
|
if (want === "" && manifest.repos.length === 1) return manifest.repos[0] ?? null;
|
|
2560
2762
|
return null;
|
|
@@ -2590,16 +2792,18 @@ function mergeDiffs(current, next) {
|
|
|
2590
2792
|
function useSandboxGit(sessionId, options = {}) {
|
|
2591
2793
|
const { client, workspaceId } = useOpenGeni(options);
|
|
2592
2794
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
2795
|
+
const active = options.active ?? true;
|
|
2593
2796
|
const repoPath = options.repoPath ?? "";
|
|
2594
2797
|
const workspaceWide = options.repoPaths !== void 0;
|
|
2595
2798
|
const repoPathsKey = uniqueRoots(
|
|
2596
2799
|
options.repoPaths && options.repoPaths.length > 0 ? options.repoPaths : [repoPath]
|
|
2597
2800
|
).join("\0");
|
|
2598
|
-
const repoPaths =
|
|
2599
|
-
const
|
|
2600
|
-
const
|
|
2801
|
+
const repoPaths = useMemo5(() => repoPathsKey.split("\0"), [repoPathsKey]);
|
|
2802
|
+
const comparison = options.comparison ?? (options.staged ? "staged" : "working");
|
|
2803
|
+
const hasAdvertisedRepoPaths = (options.repoPaths?.length ?? 0) > 0;
|
|
2804
|
+
const capture = comparison === "staged" ? null : options.capture ?? null;
|
|
2601
2805
|
const isLive2 = options.liveness === "warm" || options.liveness === "draining";
|
|
2602
|
-
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${repoPathsKey}\0${workspaceWide}\0${
|
|
2806
|
+
const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${repoPathsKey}\0${workspaceWide}\0${comparison}`;
|
|
2603
2807
|
const [diff, setDiff] = useState7([]);
|
|
2604
2808
|
const [branch, setBranch] = useState7(null);
|
|
2605
2809
|
const [isRepo, setIsRepo] = useState7(false);
|
|
@@ -2614,6 +2818,7 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2614
2818
|
const refreshGenerationRef = useRef8(0);
|
|
2615
2819
|
const refreshAbortRef = useRef8(null);
|
|
2616
2820
|
const lastChangeRef = useRef8(0);
|
|
2821
|
+
const commandRefreshTimerRef = useRef8(null);
|
|
2617
2822
|
const refresh = useCallback13(async () => {
|
|
2618
2823
|
if (!sessionId) return;
|
|
2619
2824
|
refreshAbortRef.current?.abort();
|
|
@@ -2623,7 +2828,39 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2623
2828
|
setLoading(true);
|
|
2624
2829
|
setError(null);
|
|
2625
2830
|
try {
|
|
2626
|
-
const
|
|
2831
|
+
const diffRequest = (root) => client.gitDiff(
|
|
2832
|
+
workspaceId,
|
|
2833
|
+
sessionId,
|
|
2834
|
+
{
|
|
2835
|
+
path: root,
|
|
2836
|
+
...comparison === "branch" ? { fromRef: "origin/HEAD", includeUntracked: true } : comparison === "working" ? { fromRef: "HEAD", includeUntracked: true } : { staged: true, includeUntracked: false }
|
|
2837
|
+
},
|
|
2838
|
+
{ signal: refreshAbort.signal }
|
|
2839
|
+
);
|
|
2840
|
+
const prefetched = hasAdvertisedRepoPaths ? await client.gitReadBatch(
|
|
2841
|
+
workspaceId,
|
|
2842
|
+
sessionId,
|
|
2843
|
+
{
|
|
2844
|
+
requests: repoPaths.map((root) => ({
|
|
2845
|
+
status: { path: root },
|
|
2846
|
+
diff: {
|
|
2847
|
+
path: root,
|
|
2848
|
+
...comparison === "branch" ? { fromRef: "origin/HEAD", includeUntracked: true } : comparison === "working" ? { fromRef: "HEAD", includeUntracked: true } : { staged: true, includeUntracked: false }
|
|
2849
|
+
}
|
|
2850
|
+
}))
|
|
2851
|
+
},
|
|
2852
|
+
{ signal: refreshAbort.signal }
|
|
2853
|
+
).then(
|
|
2854
|
+
(batch) => batch.results.map((item, index) => ({
|
|
2855
|
+
root: repoPaths[index] ?? "",
|
|
2856
|
+
status: item.status,
|
|
2857
|
+
result: item.diff ?? {
|
|
2858
|
+
files: [],
|
|
2859
|
+
revision: item.status.revision
|
|
2860
|
+
}
|
|
2861
|
+
}))
|
|
2862
|
+
) : null;
|
|
2863
|
+
const statuses = prefetched ?? await Promise.all(
|
|
2627
2864
|
repoPaths.map(async (root) => ({
|
|
2628
2865
|
root,
|
|
2629
2866
|
status: await client.gitStatus(
|
|
@@ -2648,19 +2885,11 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2648
2885
|
setSource("live");
|
|
2649
2886
|
return;
|
|
2650
2887
|
}
|
|
2888
|
+
const prefetchedByRoot = new Map(prefetched?.map(({ root, result }) => [root, result]));
|
|
2651
2889
|
const results = await Promise.all(
|
|
2652
2890
|
repositories.map(async ({ root }) => ({
|
|
2653
2891
|
root,
|
|
2654
|
-
result: await
|
|
2655
|
-
workspaceId,
|
|
2656
|
-
sessionId,
|
|
2657
|
-
{
|
|
2658
|
-
path: root,
|
|
2659
|
-
staged,
|
|
2660
|
-
includeUntracked: !staged
|
|
2661
|
-
},
|
|
2662
|
-
{ signal: refreshAbort.signal }
|
|
2663
|
-
)
|
|
2892
|
+
result: prefetchedByRoot.get(root) ?? await diffRequest(root)
|
|
2664
2893
|
}))
|
|
2665
2894
|
);
|
|
2666
2895
|
if (refreshGenerationRef.current !== generation) return;
|
|
@@ -2681,10 +2910,21 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2681
2910
|
if (refreshGenerationRef.current === generation) setLoading(false);
|
|
2682
2911
|
if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;
|
|
2683
2912
|
}
|
|
2684
|
-
}, [
|
|
2913
|
+
}, [
|
|
2914
|
+
client,
|
|
2915
|
+
workspaceId,
|
|
2916
|
+
sessionId,
|
|
2917
|
+
repoPaths,
|
|
2918
|
+
hasAdvertisedRepoPaths,
|
|
2919
|
+
workspaceWide,
|
|
2920
|
+
comparison
|
|
2921
|
+
]);
|
|
2685
2922
|
const seedFromCapture = useCallback13(
|
|
2686
2923
|
(manifest) => {
|
|
2687
2924
|
const repositories = workspaceWide ? manifest.repos : [repoForPath(manifest, repoPath)].filter(Boolean);
|
|
2925
|
+
if (comparison === "branch" && repositories.some((repo) => repo.branchDiff === void 0)) {
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2688
2928
|
if (repositories.length === 0) {
|
|
2689
2929
|
setIsRepo(false);
|
|
2690
2930
|
setBranch(null);
|
|
@@ -2700,20 +2940,21 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2700
2940
|
setBranch(repositories.length === 1 ? repositories[0]?.head ?? null : null);
|
|
2701
2941
|
setAhead(repositories.reduce((sum, repo) => sum + repo.ahead, 0));
|
|
2702
2942
|
setBehind(repositories.reduce((sum, repo) => sum + repo.behind, 0));
|
|
2703
|
-
setRepoRoots(repositories.map((repo) =>
|
|
2943
|
+
setRepoRoots(repositories.map((repo) => normalizeRoot2(repo.root)));
|
|
2704
2944
|
setDiff(
|
|
2705
2945
|
(prev) => mergeDiffs(
|
|
2706
2946
|
prev,
|
|
2707
|
-
repositories.flatMap(
|
|
2708
|
-
|
|
2709
|
-
|
|
2947
|
+
repositories.flatMap((repo) => {
|
|
2948
|
+
const capturedDiff = comparison === "branch" ? repo.branchDiff ?? [] : repo.diff;
|
|
2949
|
+
return workspaceWide ? capturedDiff.map((file) => qualifyDiff(repo.root, file)) : capturedDiff;
|
|
2950
|
+
})
|
|
2710
2951
|
)
|
|
2711
2952
|
);
|
|
2712
2953
|
sourceRef.current = "capture";
|
|
2713
2954
|
setSource("capture");
|
|
2714
2955
|
setError(null);
|
|
2715
2956
|
},
|
|
2716
|
-
[repoPath, workspaceWide]
|
|
2957
|
+
[comparison, repoPath, workspaceWide]
|
|
2717
2958
|
);
|
|
2718
2959
|
const captureRef = useRef8(capture);
|
|
2719
2960
|
captureRef.current = capture;
|
|
@@ -2746,6 +2987,10 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2746
2987
|
if (currentCapture && (identityChanged || !isLive2 || sourceRef.current !== "live")) {
|
|
2747
2988
|
seedFromCapture(currentCapture);
|
|
2748
2989
|
}
|
|
2990
|
+
if (!active) {
|
|
2991
|
+
if (!active) setLoading(false);
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2749
2994
|
if (isLive2 || !currentCapture) {
|
|
2750
2995
|
void refresh();
|
|
2751
2996
|
}
|
|
@@ -2754,21 +2999,49 @@ function useSandboxGit(sessionId, options = {}) {
|
|
|
2754
2999
|
refreshAbortRef.current = null;
|
|
2755
3000
|
refreshGenerationRef.current += 1;
|
|
2756
3001
|
};
|
|
2757
|
-
}, [enabled, isLive2, captureRevision, identityKey, refresh, seedFromCapture]);
|
|
3002
|
+
}, [enabled, active, isLive2, captureRevision, identityKey, refresh, seedFromCapture]);
|
|
2758
3003
|
const events = options.events;
|
|
2759
3004
|
useEffect9(() => {
|
|
2760
|
-
if (!enabled || !events)
|
|
3005
|
+
if (!enabled || !active || !events) {
|
|
3006
|
+
if (commandRefreshTimerRef.current) {
|
|
3007
|
+
clearTimeout(commandRefreshTimerRef.current);
|
|
3008
|
+
commandRefreshTimerRef.current = null;
|
|
3009
|
+
}
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
2761
3012
|
let latest = lastChangeRef.current;
|
|
3013
|
+
let immediate = false;
|
|
3014
|
+
let commandDelta = false;
|
|
2762
3015
|
for (const event of events) {
|
|
2763
|
-
if (event.
|
|
3016
|
+
if (event.sequence <= latest) continue;
|
|
3017
|
+
if (event.type === "git.changed" || event.type === "agent.toolCall.output") {
|
|
3018
|
+
latest = event.sequence;
|
|
3019
|
+
immediate = true;
|
|
3020
|
+
} else if (event.type === "sandbox.command.output.delta") {
|
|
2764
3021
|
latest = event.sequence;
|
|
3022
|
+
commandDelta = true;
|
|
2765
3023
|
}
|
|
2766
3024
|
}
|
|
2767
3025
|
if (latest > lastChangeRef.current) {
|
|
2768
3026
|
lastChangeRef.current = latest;
|
|
2769
|
-
|
|
3027
|
+
if (immediate) {
|
|
3028
|
+
if (commandRefreshTimerRef.current) clearTimeout(commandRefreshTimerRef.current);
|
|
3029
|
+
commandRefreshTimerRef.current = null;
|
|
3030
|
+
void refresh();
|
|
3031
|
+
} else if (commandDelta && !commandRefreshTimerRef.current) {
|
|
3032
|
+
commandRefreshTimerRef.current = setTimeout(() => {
|
|
3033
|
+
commandRefreshTimerRef.current = null;
|
|
3034
|
+
void refresh();
|
|
3035
|
+
}, 1e3);
|
|
3036
|
+
}
|
|
2770
3037
|
}
|
|
2771
|
-
}, [enabled, events, refresh]);
|
|
3038
|
+
}, [enabled, active, events, refresh]);
|
|
3039
|
+
useEffect9(
|
|
3040
|
+
() => () => {
|
|
3041
|
+
if (commandRefreshTimerRef.current) clearTimeout(commandRefreshTimerRef.current);
|
|
3042
|
+
},
|
|
3043
|
+
[]
|
|
3044
|
+
);
|
|
2772
3045
|
const identityMatches = enabled && stateIdentity === identityKey;
|
|
2773
3046
|
const visibleRepoRoots = identityMatches ? repoRoots : [];
|
|
2774
3047
|
return {
|
|
@@ -3142,7 +3415,7 @@ function useWorkspaceEdit(sessionId, options = {}) {
|
|
|
3142
3415
|
}
|
|
3143
3416
|
|
|
3144
3417
|
// src/hooks/use-machine-chip.ts
|
|
3145
|
-
import { useMemo as
|
|
3418
|
+
import { useMemo as useMemo6 } from "react";
|
|
3146
3419
|
function formatAsOf(capturedAt, now) {
|
|
3147
3420
|
const then = Date.parse(capturedAt);
|
|
3148
3421
|
if (Number.isNaN(then)) return "recently";
|
|
@@ -3179,7 +3452,7 @@ function useMachineChip(input) {
|
|
|
3179
3452
|
capturedAt,
|
|
3180
3453
|
now
|
|
3181
3454
|
} = input;
|
|
3182
|
-
return
|
|
3455
|
+
return useMemo6(
|
|
3183
3456
|
() => deriveMachineChip({
|
|
3184
3457
|
liveness,
|
|
3185
3458
|
capabilitiesState,
|
|
@@ -3350,6 +3623,7 @@ import { LayoutGroup, motion } from "motion/react";
|
|
|
3350
3623
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
3351
3624
|
function ChatComposer({
|
|
3352
3625
|
composer,
|
|
3626
|
+
responsiveBasis,
|
|
3353
3627
|
effectiveControl,
|
|
3354
3628
|
queuedAheadCount,
|
|
3355
3629
|
canControlWorkspace,
|
|
@@ -3397,7 +3671,7 @@ function ChatComposer({
|
|
|
3397
3671
|
attachments || models || controlsLeading || controlsStart || transcription
|
|
3398
3672
|
);
|
|
3399
3673
|
const stackActions = hasControls && Boolean(actionsStart);
|
|
3400
|
-
return /* @__PURE__ */ jsxs2(Root, { controller, className, children: [
|
|
3674
|
+
return /* @__PURE__ */ jsxs2(Root, { controller, responsiveBasis, className, children: [
|
|
3401
3675
|
/* @__PURE__ */ jsxs2(Frame, { children: [
|
|
3402
3676
|
/* @__PURE__ */ jsx2(CommandPalette2, {}),
|
|
3403
3677
|
/* @__PURE__ */ jsxs2(Surface, { children: [
|
|
@@ -3406,62 +3680,69 @@ function ChatComposer({
|
|
|
3406
3680
|
/* @__PURE__ */ jsx2(Attachments, {}),
|
|
3407
3681
|
header,
|
|
3408
3682
|
/* @__PURE__ */ jsx2(Input, { placeholder, autoFocus }),
|
|
3409
|
-
controller.confirmState ? /* @__PURE__ */ jsx2(Confirmation, {}) : /* @__PURE__ */ jsx2(
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
) : null,
|
|
3425
|
-
models ? /* @__PURE__ */ jsx2(
|
|
3426
|
-
motion.span,
|
|
3427
|
-
{
|
|
3428
|
-
layout: true,
|
|
3429
|
-
transition: { duration: 0.36, ease: [0.22, 1, 0.36, 1] },
|
|
3430
|
-
className: "inline-flex min-w-0",
|
|
3431
|
-
children: /* @__PURE__ */ jsx2(
|
|
3432
|
-
ModelPicker2,
|
|
3683
|
+
controller.confirmState ? /* @__PURE__ */ jsx2(Confirmation, {}) : /* @__PURE__ */ jsx2(
|
|
3684
|
+
Footer,
|
|
3685
|
+
{
|
|
3686
|
+
"data-og-stack-actions": stackActions ? "" : void 0,
|
|
3687
|
+
className: stackActions ? "max-sm:flex-nowrap sm:flex-wrap" : void 0,
|
|
3688
|
+
children: /* @__PURE__ */ jsxs2(LayoutGroup, { id: "og-composer-footer", children: [
|
|
3689
|
+
hasControls ? /* @__PURE__ */ jsxs2(
|
|
3690
|
+
Controls,
|
|
3691
|
+
{
|
|
3692
|
+
className: stackActions ? "min-w-0 max-sm:flex-1 sm:w-auto" : void 0,
|
|
3693
|
+
children: [
|
|
3694
|
+
controlsLeading,
|
|
3695
|
+
/* @__PURE__ */ jsx2(AttachButton, { className: attachButtonClassName }),
|
|
3696
|
+
transcription ? /* @__PURE__ */ jsx2(
|
|
3697
|
+
ComposerTranscriptionControl,
|
|
3433
3698
|
{
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3699
|
+
...transcription,
|
|
3700
|
+
suppressed: transcriptionSuppressed,
|
|
3701
|
+
className: [transcription.className, transcriptionClassName].filter(Boolean).join(" ")
|
|
3437
3702
|
}
|
|
3438
|
-
)
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3703
|
+
) : null,
|
|
3704
|
+
models ? /* @__PURE__ */ jsx2(
|
|
3705
|
+
motion.span,
|
|
3706
|
+
{
|
|
3707
|
+
layout: true,
|
|
3708
|
+
transition: { duration: 0.36, ease: [0.22, 1, 0.36, 1] },
|
|
3709
|
+
className: "inline-flex min-w-0",
|
|
3710
|
+
children: /* @__PURE__ */ jsx2(
|
|
3711
|
+
ModelPicker2,
|
|
3712
|
+
{
|
|
3713
|
+
models,
|
|
3714
|
+
value: selectedModel,
|
|
3715
|
+
onChange: onSelectModel
|
|
3716
|
+
}
|
|
3717
|
+
)
|
|
3718
|
+
}
|
|
3719
|
+
) : null,
|
|
3720
|
+
controlsStart ? /* @__PURE__ */ jsx2(
|
|
3721
|
+
motion.span,
|
|
3722
|
+
{
|
|
3723
|
+
layout: true,
|
|
3724
|
+
transition: { duration: 0.36, ease: [0.22, 1, 0.36, 1] },
|
|
3725
|
+
className: "inline-flex min-w-0 items-center gap-1.5",
|
|
3726
|
+
children: controlsStart
|
|
3727
|
+
}
|
|
3728
|
+
) : null
|
|
3729
|
+
]
|
|
3730
|
+
}
|
|
3731
|
+
) : /* @__PURE__ */ jsx2(Hint, { children: hint }),
|
|
3732
|
+
/* @__PURE__ */ jsxs2(
|
|
3733
|
+
Actions,
|
|
3734
|
+
{
|
|
3735
|
+
className: stackActions ? "max-sm:shrink-0 sm:w-auto sm:justify-end" : void 0,
|
|
3736
|
+
children: [
|
|
3737
|
+
actionsStart,
|
|
3738
|
+
/* @__PURE__ */ jsx2(PauseButton, {}),
|
|
3739
|
+
/* @__PURE__ */ jsx2(SendButton, {})
|
|
3740
|
+
]
|
|
3741
|
+
}
|
|
3742
|
+
)
|
|
3743
|
+
] })
|
|
3744
|
+
}
|
|
3745
|
+
)
|
|
3465
3746
|
] })
|
|
3466
3747
|
] }),
|
|
3467
3748
|
/* @__PURE__ */ jsx2(Help, {}),
|
|
@@ -3683,6 +3964,9 @@ async function attachRenderer(prefer, loaders, onTier) {
|
|
|
3683
3964
|
|
|
3684
3965
|
// src/components/sandbox-terminal.tsx
|
|
3685
3966
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3967
|
+
function clearTerminalBootStatus(term) {
|
|
3968
|
+
term.write("\r\x1B[2K\x1B[2J\x1B[H");
|
|
3969
|
+
}
|
|
3686
3970
|
function forcedRendererFailures() {
|
|
3687
3971
|
const raw = typeof globalThis !== "undefined" ? globalThis.__OG_FORCE_RENDERER_FAIL__ : void 0;
|
|
3688
3972
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -3736,7 +4020,8 @@ function SandboxTerminal({
|
|
|
3736
4020
|
}
|
|
3737
4021
|
});
|
|
3738
4022
|
const ptyMode = ptyWs && ptyStatus !== "closed";
|
|
3739
|
-
const interactive = !readOnly && (ptyMode
|
|
4023
|
+
const interactive = !readOnly && (ptyMode ? ptyConnected : result.write !== null);
|
|
4024
|
+
const terminalModeLabel = interactive ? null : readOnly ? "read-only" : ptyMode && ptyStatus === "connecting" ? "connecting" : ptyMode && ptyStatus === "error" ? "connection error" : "output only";
|
|
3740
4025
|
const warm = liveness === "warm" || liveness === "draining";
|
|
3741
4026
|
const booting = activated && !ptyMode && !warm && liveness !== null && liveness !== void 0 && result.chunks.length === 0;
|
|
3742
4027
|
function handleActivate() {
|
|
@@ -3873,7 +4158,7 @@ function SandboxTerminal({
|
|
|
3873
4158
|
if (!booting) {
|
|
3874
4159
|
if (bootActiveRef.current) {
|
|
3875
4160
|
bootActiveRef.current = false;
|
|
3876
|
-
if (!wroteFirehoseRef.current) term
|
|
4161
|
+
if (!wroteFirehoseRef.current) clearTerminalBootStatus(term);
|
|
3877
4162
|
}
|
|
3878
4163
|
return;
|
|
3879
4164
|
}
|
|
@@ -3951,7 +4236,14 @@ function SandboxTerminal({
|
|
|
3951
4236
|
] })
|
|
3952
4237
|
] }),
|
|
3953
4238
|
/* @__PURE__ */ jsxs4("span", { className: "flex shrink-0 items-center gap-2", children: [
|
|
3954
|
-
|
|
4239
|
+
terminalModeLabel && /* @__PURE__ */ jsx4(
|
|
4240
|
+
"span",
|
|
4241
|
+
{
|
|
4242
|
+
className: "rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide",
|
|
4243
|
+
role: "status",
|
|
4244
|
+
children: terminalModeLabel
|
|
4245
|
+
}
|
|
4246
|
+
),
|
|
3955
4247
|
/* @__PURE__ */ jsx4(
|
|
3956
4248
|
"button",
|
|
3957
4249
|
{
|
|
@@ -4051,7 +4343,7 @@ import {
|
|
|
4051
4343
|
useEffect as useEffect15,
|
|
4052
4344
|
useId as useId2,
|
|
4053
4345
|
useLayoutEffect,
|
|
4054
|
-
useMemo as
|
|
4346
|
+
useMemo as useMemo8,
|
|
4055
4347
|
useRef as useRef13,
|
|
4056
4348
|
useState as useState12
|
|
4057
4349
|
} from "react";
|
|
@@ -4059,11 +4351,11 @@ import { AlertDialog } from "radix-ui";
|
|
|
4059
4351
|
import { VList } from "virtua";
|
|
4060
4352
|
|
|
4061
4353
|
// src/lib/use-unicode-fonts.ts
|
|
4062
|
-
import { useEffect as useEffect14, useMemo as
|
|
4354
|
+
import { useEffect as useEffect14, useMemo as useMemo7 } from "react";
|
|
4063
4355
|
var japaneseScript = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/u;
|
|
4064
4356
|
var arabicScript = /[\u0600-\u06ff\u0750-\u077f\u0870-\u08ff\ufb50-\ufdff\ufe70-\ufefc]/u;
|
|
4065
4357
|
function useUnicodeFallbackFonts(values) {
|
|
4066
|
-
const content =
|
|
4358
|
+
const content = useMemo7(() => collectUnicodeContent(values), [values]);
|
|
4067
4359
|
useEffect14(() => {
|
|
4068
4360
|
if (content.japanese) {
|
|
4069
4361
|
void import("./noto-sans-jp-loader.generated-HFGLYBR3.js").then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese)).catch(() => void 0);
|
|
@@ -4146,10 +4438,11 @@ function FileBrowser({
|
|
|
4146
4438
|
const [busy, setBusy] = useState12(false);
|
|
4147
4439
|
const [coarsePointer, setCoarsePointer] = useState12(false);
|
|
4148
4440
|
const treeId = useId2();
|
|
4149
|
-
const
|
|
4441
|
+
const container = usePortalTokenSource();
|
|
4442
|
+
const containerRef = container.currentRef;
|
|
4150
4443
|
const deleteReturnFocusRef = useRef13(null);
|
|
4151
4444
|
const vlistRef = useRef13(null);
|
|
4152
|
-
const portalTokenStyle = usePortalTokenStyle(
|
|
4445
|
+
const portalTokenStyle = usePortalTokenStyle(container.source);
|
|
4153
4446
|
const getTreeElement = useCallback16(
|
|
4154
4447
|
() => typeof document === "undefined" ? null : document.getElementById(treeId),
|
|
4155
4448
|
[treeId]
|
|
@@ -4209,7 +4502,7 @@ function FileBrowser({
|
|
|
4209
4502
|
[expanded, expand]
|
|
4210
4503
|
);
|
|
4211
4504
|
const cold = result.source !== "live";
|
|
4212
|
-
const renderItems =
|
|
4505
|
+
const renderItems = useMemo8(() => {
|
|
4213
4506
|
const items = [];
|
|
4214
4507
|
if (draftCreate && draftCreate.parent === "") {
|
|
4215
4508
|
items.push({ type: "create", parent: "", kind: draftCreate.kind, depth: 0 });
|
|
@@ -4240,22 +4533,22 @@ function FileBrowser({
|
|
|
4240
4533
|
walk(result.tree, 0);
|
|
4241
4534
|
return items;
|
|
4242
4535
|
}, [result.tree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);
|
|
4243
|
-
const unicodeFontPaths =
|
|
4536
|
+
const unicodeFontPaths = useMemo8(
|
|
4244
4537
|
() => renderItems.flatMap((item) => item.type === "node" ? [item.node.path] : []),
|
|
4245
4538
|
[renderItems]
|
|
4246
4539
|
);
|
|
4247
4540
|
useUnicodeFallbackFonts(unicodeFontPaths);
|
|
4248
|
-
const flatRows =
|
|
4541
|
+
const flatRows = useMemo8(
|
|
4249
4542
|
() => renderItems.flatMap(
|
|
4250
4543
|
(item) => item.type === "node" ? [{ node: item.node, depth: item.depth }] : []
|
|
4251
4544
|
),
|
|
4252
4545
|
[renderItems]
|
|
4253
4546
|
);
|
|
4254
|
-
const rowIndexByPath =
|
|
4547
|
+
const rowIndexByPath = useMemo8(
|
|
4255
4548
|
() => new Map(flatRows.map((row, index) => [row.node.path, index])),
|
|
4256
4549
|
[flatRows]
|
|
4257
4550
|
);
|
|
4258
|
-
const treePositionByPath =
|
|
4551
|
+
const treePositionByPath = useMemo8(() => {
|
|
4259
4552
|
const positions = /* @__PURE__ */ new Map();
|
|
4260
4553
|
const visit = (nodes) => {
|
|
4261
4554
|
nodes.forEach((node, index) => {
|
|
@@ -4517,6 +4810,7 @@ function FileBrowser({
|
|
|
4517
4810
|
runDelete,
|
|
4518
4811
|
supportsMutation,
|
|
4519
4812
|
coarsePointer,
|
|
4813
|
+
containerRef,
|
|
4520
4814
|
rowIndexByPath,
|
|
4521
4815
|
treeId
|
|
4522
4816
|
]
|
|
@@ -4537,7 +4831,7 @@ function FileBrowser({
|
|
|
4537
4831
|
const showDegradedTree = result.error && result.tree.length > 0;
|
|
4538
4832
|
const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;
|
|
4539
4833
|
const showToolbar = supportsMutation || result.loading;
|
|
4540
|
-
const usesVirtualTree = !showErrorEmpty && !showEmpty;
|
|
4834
|
+
const usesVirtualTree = !showErrorEmpty && !showEmpty && renderItems.length > 500;
|
|
4541
4835
|
const renderNodeRow = (node, depth) => {
|
|
4542
4836
|
const isOpen = expanded.has(node.path);
|
|
4543
4837
|
if (renderNode) {
|
|
@@ -4772,7 +5066,7 @@ function FileBrowser({
|
|
|
4772
5066
|
type: "button",
|
|
4773
5067
|
onClick: () => void result.refresh(),
|
|
4774
5068
|
disabled: result.loading,
|
|
4775
|
-
className: "inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-
|
|
5069
|
+
className: "inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11",
|
|
4776
5070
|
children: [
|
|
4777
5071
|
/* @__PURE__ */ jsx5(
|
|
4778
5072
|
RefreshCwIcon,
|
|
@@ -4791,13 +5085,7 @@ function FileBrowser({
|
|
|
4791
5085
|
/* @__PURE__ */ jsx5(
|
|
4792
5086
|
"div",
|
|
4793
5087
|
{
|
|
4794
|
-
ref:
|
|
4795
|
-
id: usesVirtualTree ? void 0 : treeId,
|
|
4796
|
-
role: usesVirtualTree ? void 0 : "tree",
|
|
4797
|
-
"aria-label": usesVirtualTree ? void 0 : "Workspace files",
|
|
4798
|
-
"aria-activedescendant": usesVirtualTree ? void 0 : activeDescendantId,
|
|
4799
|
-
tabIndex: usesVirtualTree ? void 0 : 0,
|
|
4800
|
-
"aria-multiselectable": usesVirtualTree ? void 0 : false,
|
|
5088
|
+
ref: container.ref,
|
|
4801
5089
|
onFocus: (event) => {
|
|
4802
5090
|
if (event.target.id === treeId && cursorIndex < 0) {
|
|
4803
5091
|
const first = flatRows[0];
|
|
@@ -4816,7 +5104,7 @@ function FileBrowser({
|
|
|
4816
5104
|
void onDropOnto("", src);
|
|
4817
5105
|
} : void 0,
|
|
4818
5106
|
className: cn(
|
|
4819
|
-
"flex min-h-0 min-w-0 flex-1 flex-col p-1
|
|
5107
|
+
"flex min-h-0 min-w-0 flex-1 flex-col p-1",
|
|
4820
5108
|
dragOver === "" && "ring-1 ring-inset ring-og-accent"
|
|
4821
5109
|
),
|
|
4822
5110
|
"data-opengeni-file-tree": true,
|
|
@@ -4841,7 +5129,19 @@ function FileBrowser({
|
|
|
4841
5129
|
]
|
|
4842
5130
|
}
|
|
4843
5131
|
)
|
|
4844
|
-
] }) : showEmpty ? /* @__PURE__ */ jsx5("div", { className: "p-2 text-og-sm text-og-fg-subtle", children: emptyState ?? "This directory is empty" }) : (
|
|
5132
|
+
] }) : showEmpty ? /* @__PURE__ */ jsx5("div", { className: "p-2 text-og-sm text-og-fg-subtle", children: emptyState ?? "This directory is empty" }) : !usesVirtualTree ? /* @__PURE__ */ jsx5(
|
|
5133
|
+
"div",
|
|
5134
|
+
{
|
|
5135
|
+
id: treeId,
|
|
5136
|
+
role: "tree",
|
|
5137
|
+
"aria-label": "Workspace files",
|
|
5138
|
+
"aria-activedescendant": activeDescendantId,
|
|
5139
|
+
"aria-multiselectable": false,
|
|
5140
|
+
tabIndex: 0,
|
|
5141
|
+
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",
|
|
5142
|
+
children: renderItems.map((item) => /* @__PURE__ */ jsx5("div", { className: "min-w-0", children: renderItem(item) }, itemKey(item)))
|
|
5143
|
+
}
|
|
5144
|
+
) : (
|
|
4845
5145
|
// Virtualized: only the rows in/near the viewport mount, so a 3k-node
|
|
4846
5146
|
// tree stays responsive. The flat item list already carries the
|
|
4847
5147
|
// expanded subtree + synthetic (create/skeleton/residue) rows.
|
|
@@ -4855,7 +5155,7 @@ function FileBrowser({
|
|
|
4855
5155
|
"aria-activedescendant": activeDescendantId,
|
|
4856
5156
|
"aria-multiselectable": false,
|
|
4857
5157
|
tabIndex: 0,
|
|
4858
|
-
className: "min-h-0 flex-1 outline-
|
|
5158
|
+
className: "min-h-0 flex-1 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
|
|
4859
5159
|
itemSize: coarsePointer ? 44 : 28,
|
|
4860
5160
|
ssrCount: Math.min(32, renderItems.length),
|
|
4861
5161
|
children: renderItems.map((item) => /* @__PURE__ */ jsx5("div", { className: "min-w-0", children: renderItem(item) }, itemKey(item)))
|
|
@@ -4941,11 +5241,11 @@ function DeleteDialog({
|
|
|
4941
5241
|
}
|
|
4942
5242
|
},
|
|
4943
5243
|
children: /* @__PURE__ */ jsxs5(AlertDialog.Portal, { container: typeof document === "undefined" ? null : document.body, children: [
|
|
4944
|
-
/* @__PURE__ */ jsx5(AlertDialog.Overlay, { className: "fixed inset-0 z-[100] bg-black/45 backdrop-blur-[2px]" }),
|
|
5244
|
+
/* @__PURE__ */ jsx5(AlertDialog.Overlay, { className: "og-root fixed inset-0 z-[100] bg-black/45 backdrop-blur-[2px]" }),
|
|
4945
5245
|
/* @__PURE__ */ jsxs5(
|
|
4946
5246
|
AlertDialog.Content,
|
|
4947
5247
|
{
|
|
4948
|
-
className: "og-root fixed left-1/2 top-1/2 z-[101] max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-og-lg border border-og-border-strong bg-og-surface-1 p-4 text-og-fg shadow-2xl outline-
|
|
5248
|
+
className: "og-root fixed left-1/2 top-1/2 z-[101] max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-og-lg border border-og-border-strong bg-og-surface-1 p-4 text-og-fg shadow-2xl outline-hidden",
|
|
4949
5249
|
style: portalTokenStyle,
|
|
4950
5250
|
onOpenAutoFocus: (event) => {
|
|
4951
5251
|
event.preventDefault();
|
|
@@ -5090,7 +5390,7 @@ function InlineInput({
|
|
|
5090
5390
|
className: cn(
|
|
5091
5391
|
"min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm",
|
|
5092
5392
|
"border-og-accent text-og-fg",
|
|
5093
|
-
"outline-
|
|
5393
|
+
"outline-hidden"
|
|
5094
5394
|
)
|
|
5095
5395
|
}
|
|
5096
5396
|
)
|
|
@@ -5193,14 +5493,14 @@ import {
|
|
|
5193
5493
|
useEffect as useEffect17,
|
|
5194
5494
|
useId as useId3,
|
|
5195
5495
|
useLayoutEffect as useLayoutEffect2,
|
|
5196
|
-
useMemo as
|
|
5496
|
+
useMemo as useMemo10,
|
|
5197
5497
|
useRef as useRef15,
|
|
5198
5498
|
useState as useState14
|
|
5199
5499
|
} from "react";
|
|
5200
5500
|
import { VList as VList2 } from "virtua";
|
|
5201
5501
|
|
|
5202
5502
|
// src/hooks/use-windowed-sections.ts
|
|
5203
|
-
import { useCallback as useCallback17, useEffect as useEffect16, useMemo as
|
|
5503
|
+
import { useCallback as useCallback17, useEffect as useEffect16, useMemo as useMemo9, useRef as useRef14, useState as useState13 } from "react";
|
|
5204
5504
|
function computeWindowRange(heights, scrollTop, viewport, overscan) {
|
|
5205
5505
|
const n = heights.length;
|
|
5206
5506
|
if (n === 0) return { start: 0, end: 0 };
|
|
@@ -5237,10 +5537,10 @@ function useWindowedSections(opts) {
|
|
|
5237
5537
|
);
|
|
5238
5538
|
useEffect16(() => {
|
|
5239
5539
|
setHeights((prev) => {
|
|
5240
|
-
|
|
5241
|
-
return
|
|
5540
|
+
const next = Array.from({ length: count }, (_, i) => estimateHeight(i));
|
|
5541
|
+
return prev.length === next.length && prev.every((height, index) => height === next[index]) ? prev : next;
|
|
5242
5542
|
});
|
|
5243
|
-
}, [count]);
|
|
5543
|
+
}, [count, estimateHeight]);
|
|
5244
5544
|
const heightsRef = useRef14(heights);
|
|
5245
5545
|
heightsRef.current = heights;
|
|
5246
5546
|
const [range, setRange] = useState13(() => ({
|
|
@@ -5283,7 +5583,7 @@ function useWindowedSections(opts) {
|
|
|
5283
5583
|
return next;
|
|
5284
5584
|
});
|
|
5285
5585
|
}, []);
|
|
5286
|
-
const offsets =
|
|
5586
|
+
const offsets = useMemo9(() => {
|
|
5287
5587
|
const out = new Array(count + 1);
|
|
5288
5588
|
out[0] = 0;
|
|
5289
5589
|
for (let i = 0; i < count; i++) out[i + 1] = (out[i] ?? 0) + Math.max(heights[i] ?? 0, 0);
|
|
@@ -5406,12 +5706,12 @@ function WorkbenchChanges({
|
|
|
5406
5706
|
const [layout, setLayout] = useState14("unified");
|
|
5407
5707
|
const [activePath, setActivePath] = useState14(null);
|
|
5408
5708
|
const pickerId = useId3();
|
|
5409
|
-
const unicodeFontPaths =
|
|
5709
|
+
const unicodeFontPaths = useMemo10(
|
|
5410
5710
|
() => diff.flatMap((file) => file.oldPath ? [file.path, file.oldPath] : [file.path]),
|
|
5411
5711
|
[diff]
|
|
5412
5712
|
);
|
|
5413
5713
|
useUnicodeFallbackFonts(unicodeFontPaths);
|
|
5414
|
-
const { orderedFiles, rows, grouped } =
|
|
5714
|
+
const { orderedFiles, rows, grouped } = useMemo10(() => buildRail(diff), [diff]);
|
|
5415
5715
|
const selectedIndex = orderedFiles.findIndex((file) => file.path === activePath);
|
|
5416
5716
|
const activeIndex = selectedIndex >= 0 ? selectedIndex : 0;
|
|
5417
5717
|
useChangesLayoutEffect(() => {
|
|
@@ -5441,8 +5741,8 @@ function WorkbenchChanges({
|
|
|
5441
5741
|
return () => query.removeListener(update);
|
|
5442
5742
|
}
|
|
5443
5743
|
}, []);
|
|
5444
|
-
const additions =
|
|
5445
|
-
const deletions =
|
|
5744
|
+
const additions = useMemo10(() => diff.reduce((sum, f) => sum + f.additions, 0), [diff]);
|
|
5745
|
+
const deletions = useMemo10(() => diff.reduce((sum, f) => sum + f.deletions, 0), [diff]);
|
|
5446
5746
|
const estimateHeight = useCallback18(
|
|
5447
5747
|
(index) => {
|
|
5448
5748
|
const file = orderedFiles[index];
|
|
@@ -5555,7 +5855,7 @@ function WorkbenchChanges({
|
|
|
5555
5855
|
},
|
|
5556
5856
|
title: activeFile?.path,
|
|
5557
5857
|
"data-compact-file-picker": true,
|
|
5558
|
-
className: "h-11 w-full rounded-og-md border border-og-border bg-og-bg px-3 font-og-mono text-og-sm text-og-fg outline-
|
|
5858
|
+
className: "h-11 w-full rounded-og-md border border-og-border bg-og-bg px-3 font-og-mono text-og-sm text-og-fg outline-hidden transition-colors focus:border-og-accent focus:ring-2 focus:ring-og-accent-soft",
|
|
5559
5859
|
children: orderedFiles.map((file, index) => /* @__PURE__ */ jsx6("option", { value: index, children: compactFileLabel(file) }, file.path))
|
|
5560
5860
|
}
|
|
5561
5861
|
)
|
|
@@ -5676,7 +5976,7 @@ function RailFileRow({
|
|
|
5676
5976
|
title: file.path,
|
|
5677
5977
|
"data-rail-file": true,
|
|
5678
5978
|
className: cn(
|
|
5679
|
-
"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-
|
|
5979
|
+
"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",
|
|
5680
5980
|
grouped && "pl-3",
|
|
5681
5981
|
active && "bg-og-accent-soft text-og-fg before:absolute before:inset-y-1 before:left-0 before:w-0.5 before:rounded-r-full before:bg-og-accent"
|
|
5682
5982
|
),
|
|
@@ -5774,7 +6074,7 @@ function GuardBody({
|
|
|
5774
6074
|
{
|
|
5775
6075
|
type: "button",
|
|
5776
6076
|
onClick: () => onOpenFile(file.path),
|
|
5777
|
-
className: "inline-flex min-h-8 shrink-0 items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:bg-og-surface-2 hover:text-og-fg focus-visible:outline-
|
|
6077
|
+
className: "inline-flex min-h-8 shrink-0 items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:bg-og-surface-2 hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-11",
|
|
5778
6078
|
children: [
|
|
5779
6079
|
"Open in Files",
|
|
5780
6080
|
/* @__PURE__ */ jsx6(ArrowUpRightIcon, { className: "size-3.5", "aria-hidden": true })
|
|
@@ -5793,7 +6093,7 @@ function LayoutToggle({
|
|
|
5793
6093
|
type: "button",
|
|
5794
6094
|
onClick: () => onChange(value),
|
|
5795
6095
|
className: cn(
|
|
5796
|
-
"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs capitalize focus-visible:outline-
|
|
6096
|
+
"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs capitalize focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
|
|
5797
6097
|
layout === value ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
5798
6098
|
),
|
|
5799
6099
|
children: value
|
|
@@ -5912,7 +6212,7 @@ import { Loader2Icon, SaveIcon } from "lucide-react";
|
|
|
5912
6212
|
import {
|
|
5913
6213
|
useCallback as useCallback19,
|
|
5914
6214
|
useEffect as useEffect19,
|
|
5915
|
-
useMemo as
|
|
6215
|
+
useMemo as useMemo11,
|
|
5916
6216
|
useRef as useRef16,
|
|
5917
6217
|
useState as useState16
|
|
5918
6218
|
} from "react";
|
|
@@ -6005,7 +6305,7 @@ function CodeEditor({
|
|
|
6005
6305
|
},
|
|
6006
6306
|
[baseline, onEditIntent]
|
|
6007
6307
|
);
|
|
6008
|
-
const langKey =
|
|
6308
|
+
const langKey = useMemo11(() => languageForPath(path), [path]);
|
|
6009
6309
|
useEffect19(() => {
|
|
6010
6310
|
let cancelled = false;
|
|
6011
6311
|
void (async () => {
|
|
@@ -6093,7 +6393,7 @@ function CodeEditor({
|
|
|
6093
6393
|
return () => clearTimeout(t);
|
|
6094
6394
|
}, [savedTick]);
|
|
6095
6395
|
const fileName = path.split("/").filter(Boolean).pop() ?? path;
|
|
6096
|
-
const cmExtensions =
|
|
6396
|
+
const cmExtensions = useMemo11(() => {
|
|
6097
6397
|
if (!bundle) return [];
|
|
6098
6398
|
const exts = [bundle.saveKeymapExtension(() => saveRef.current())];
|
|
6099
6399
|
if (bundle.languageExtension) exts.push(bundle.languageExtension);
|
|
@@ -6239,7 +6539,7 @@ function PlainTextarea({
|
|
|
6239
6539
|
}
|
|
6240
6540
|
},
|
|
6241
6541
|
"aria-label": "Plain text file editor",
|
|
6242
|
-
className: "h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-
|
|
6542
|
+
className: "h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-hidden"
|
|
6243
6543
|
}
|
|
6244
6544
|
);
|
|
6245
6545
|
}
|
|
@@ -6250,6 +6550,7 @@ function EditorSkeleton() {
|
|
|
6250
6550
|
// src/components/sandbox-files.tsx
|
|
6251
6551
|
import { FileCode2Icon, FileWarningIcon as FileWarningIcon2, LoaderCircleIcon } from "lucide-react";
|
|
6252
6552
|
import { useCallback as useCallback20, useEffect as useEffect20, useRef as useRef17, useState as useState17 } from "react";
|
|
6553
|
+
import { Group, Panel, Separator } from "react-resizable-panels";
|
|
6253
6554
|
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
6254
6555
|
function SandboxFiles({
|
|
6255
6556
|
files,
|
|
@@ -6297,17 +6598,30 @@ function SandboxFiles({
|
|
|
6297
6598
|
const [wide, setWide] = useState17(false);
|
|
6298
6599
|
useEffect20(() => {
|
|
6299
6600
|
const el = rootRef.current;
|
|
6300
|
-
if (!el
|
|
6301
|
-
const
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6601
|
+
if (!el) return;
|
|
6602
|
+
const update = () => setWide(el.getBoundingClientRect().width >= 720);
|
|
6603
|
+
update();
|
|
6604
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
6605
|
+
const observer = new ResizeObserver(update);
|
|
6305
6606
|
observer.observe(el);
|
|
6306
|
-
|
|
6607
|
+
const surface = el.closest("[data-workspace-surface]");
|
|
6608
|
+
const surfaceObserver = surface && typeof MutationObserver !== "undefined" ? new MutationObserver(update) : null;
|
|
6609
|
+
surfaceObserver?.observe(surface, {
|
|
6610
|
+
attributes: true,
|
|
6611
|
+
attributeFilter: ["class", "style"]
|
|
6612
|
+
});
|
|
6613
|
+
return () => {
|
|
6614
|
+
observer.disconnect();
|
|
6615
|
+
surfaceObserver?.disconnect();
|
|
6616
|
+
};
|
|
6307
6617
|
}, []);
|
|
6308
6618
|
const resolvedTheme = useThemeType(themeType);
|
|
6309
6619
|
const viewPath = selected;
|
|
6310
|
-
const fileView = useFileView(
|
|
6620
|
+
const fileView = useFileView(
|
|
6621
|
+
viewPath,
|
|
6622
|
+
files.readFile,
|
|
6623
|
+
(files.contentRevision ?? 0) + viewReloadRevision
|
|
6624
|
+
);
|
|
6311
6625
|
const selectFile = useCallback20((path) => {
|
|
6312
6626
|
if (pendingRequestRef.current !== null) {
|
|
6313
6627
|
handledRequestRef.current = pendingRequestRef.current;
|
|
@@ -6322,18 +6636,6 @@ function SandboxFiles({
|
|
|
6322
6636
|
const showEditor = canEdit && editMode;
|
|
6323
6637
|
const captureFileUnavailable = fileView.error instanceof CapturedFileUnavailableError ? fileView.error : null;
|
|
6324
6638
|
const waitingForSelectedFile = liveRequestedPath === viewPath && (!liveWorkspaceReady || files.loading) && captureFileUnavailable !== null;
|
|
6325
|
-
if (!fileSystemAvailable) {
|
|
6326
|
-
return /* @__PURE__ */ jsx10(
|
|
6327
|
-
Notice,
|
|
6328
|
-
{
|
|
6329
|
-
className,
|
|
6330
|
-
icon: /* @__PURE__ */ jsx10(FileWarningIcon2, { className: "size-5", "aria-hidden": true }),
|
|
6331
|
-
title: "Files unavailable",
|
|
6332
|
-
announce: "alert",
|
|
6333
|
-
children: "This sandbox does not expose a file system."
|
|
6334
|
-
}
|
|
6335
|
-
);
|
|
6336
|
-
}
|
|
6337
6639
|
if (workspaceResting || workspaceWaking) {
|
|
6338
6640
|
return /* @__PURE__ */ jsx10("div", { className: cn("h-full", className), "data-opengeni-workspace-resting": true, children: /* @__PURE__ */ jsxs8(
|
|
6339
6641
|
Notice,
|
|
@@ -6354,162 +6656,206 @@ function SandboxFiles({
|
|
|
6354
6656
|
}
|
|
6355
6657
|
) });
|
|
6356
6658
|
}
|
|
6659
|
+
if (!fileSystemAvailable) {
|
|
6660
|
+
return /* @__PURE__ */ jsx10(
|
|
6661
|
+
Notice,
|
|
6662
|
+
{
|
|
6663
|
+
className,
|
|
6664
|
+
icon: /* @__PURE__ */ jsx10(FileWarningIcon2, { className: "size-5", "aria-hidden": true }),
|
|
6665
|
+
title: "Files unavailable",
|
|
6666
|
+
announce: "alert",
|
|
6667
|
+
children: "This sandbox does not expose a file system."
|
|
6668
|
+
}
|
|
6669
|
+
);
|
|
6670
|
+
}
|
|
6357
6671
|
return /* @__PURE__ */ jsxs8("div", { ref: rootRef, className: cn("flex h-full min-h-0 min-w-0 flex-col", className), children: [
|
|
6358
|
-
/* @__PURE__ */ jsx10(
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
{
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
{
|
|
6370
|
-
result: files,
|
|
6371
|
-
selectedPath: selected ?? void 0,
|
|
6372
|
-
onSelectFile: selectFile,
|
|
6373
|
-
editable,
|
|
6374
|
-
emptyState: "This directory is empty",
|
|
6375
|
-
className: "min-w-0 flex-1"
|
|
6376
|
-
}
|
|
6377
|
-
)
|
|
6672
|
+
/* @__PURE__ */ jsx10(
|
|
6673
|
+
GitHeader,
|
|
6674
|
+
{
|
|
6675
|
+
loading: Boolean(files.loading || files.gitLoading || files.source === null || git?.loading) && files.gitSummary === null,
|
|
6676
|
+
git: files.gitSummary ?? {
|
|
6677
|
+
branch: git?.branch ?? null,
|
|
6678
|
+
isRepo: git?.isRepo ?? false,
|
|
6679
|
+
repoCount: git?.repoCount ?? 0,
|
|
6680
|
+
ahead: git?.ahead ?? 0,
|
|
6681
|
+
behind: git?.behind ?? 0,
|
|
6682
|
+
dirtyCount: git?.diff.length ?? 0
|
|
6378
6683
|
}
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
canEdit && /* @__PURE__ */ jsx10(
|
|
6398
|
-
Segmented,
|
|
6684
|
+
}
|
|
6685
|
+
),
|
|
6686
|
+
/* @__PURE__ */ jsxs8(
|
|
6687
|
+
Group,
|
|
6688
|
+
{
|
|
6689
|
+
orientation: wide ? "horizontal" : "vertical",
|
|
6690
|
+
className: cn("min-h-0 flex-1", wide ? "flex-row" : "flex-col"),
|
|
6691
|
+
children: [
|
|
6692
|
+
/* @__PURE__ */ jsx10(
|
|
6693
|
+
Panel,
|
|
6694
|
+
{
|
|
6695
|
+
id: "sandbox-files-tree",
|
|
6696
|
+
defaultSize: wide ? "280px" : "40%",
|
|
6697
|
+
minSize: wide ? "180px" : "120px",
|
|
6698
|
+
maxSize: wide ? "60%" : "70%",
|
|
6699
|
+
className: "flex min-h-0 min-w-0 flex-col",
|
|
6700
|
+
children: /* @__PURE__ */ jsx10(
|
|
6701
|
+
FileBrowser,
|
|
6399
6702
|
{
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6703
|
+
result: files,
|
|
6704
|
+
selectedPath: selected ?? void 0,
|
|
6705
|
+
onSelectFile: selectFile,
|
|
6706
|
+
editable,
|
|
6707
|
+
emptyState: "This directory is empty",
|
|
6708
|
+
className: "min-w-0 flex-1"
|
|
6406
6709
|
}
|
|
6407
6710
|
)
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6711
|
+
}
|
|
6712
|
+
),
|
|
6713
|
+
/* @__PURE__ */ jsx10(
|
|
6714
|
+
Separator,
|
|
6715
|
+
{
|
|
6716
|
+
"aria-label": "Resize file tree",
|
|
6717
|
+
className: cn(
|
|
6718
|
+
"group relative z-10 shrink-0 cursor-col-resize outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
|
|
6719
|
+
"w-px bg-og-border after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2",
|
|
6720
|
+
"hover:bg-og-accent focus-visible:bg-og-accent data-[separator-state=dragging]:bg-og-accent",
|
|
6721
|
+
!wide && "h-px w-full cursor-row-resize after:inset-x-0 after:inset-y-auto after:top-1/2 after:h-3 after:w-full after:-translate-x-0 after:-translate-y-1/2"
|
|
6722
|
+
)
|
|
6723
|
+
}
|
|
6724
|
+
),
|
|
6725
|
+
/* @__PURE__ */ jsxs8(
|
|
6726
|
+
Panel,
|
|
6727
|
+
{
|
|
6728
|
+
id: "sandbox-files-viewer",
|
|
6729
|
+
minSize: wide ? "240px" : "160px",
|
|
6730
|
+
className: cn("flex min-h-0 min-w-0 flex-col", !wide && "border-t border-og-border"),
|
|
6731
|
+
children: [
|
|
6732
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
|
|
6733
|
+
/* @__PURE__ */ jsx10(
|
|
6734
|
+
"span",
|
|
6735
|
+
{
|
|
6736
|
+
"data-opengeni-selected-file": true,
|
|
6737
|
+
className: "min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted",
|
|
6738
|
+
children: selected ?? "No file selected"
|
|
6739
|
+
}
|
|
6740
|
+
),
|
|
6741
|
+
canEdit && /* @__PURE__ */ jsx10(
|
|
6742
|
+
Segmented,
|
|
6743
|
+
{
|
|
6744
|
+
options: [
|
|
6745
|
+
{ value: "view", label: "View" },
|
|
6746
|
+
{ value: "edit", label: "Edit" }
|
|
6747
|
+
],
|
|
6748
|
+
value: editMode ? "edit" : "view",
|
|
6749
|
+
onChange: (v) => setEditMode(v === "edit")
|
|
6750
|
+
}
|
|
6751
|
+
)
|
|
6752
|
+
] }),
|
|
6753
|
+
/* @__PURE__ */ jsx10("div", { className: "min-h-0 flex-1 overflow-auto", children: viewPath ? showEditor && fileView.content !== null ? /* @__PURE__ */ jsx10(
|
|
6754
|
+
CodeEditor,
|
|
6427
6755
|
{
|
|
6428
|
-
|
|
6429
|
-
|
|
6756
|
+
path: viewPath,
|
|
6757
|
+
initialContents: fileView.content,
|
|
6758
|
+
themeType: resolvedTheme,
|
|
6759
|
+
onSave: (contents) => files.writeFile(viewPath, contents, { expectedContent: fileView.content }),
|
|
6760
|
+
onOverwrite: (contents) => files.writeFile(viewPath, contents, { force: true }),
|
|
6761
|
+
onReload: () => setViewReloadRevision((revision) => revision + 1),
|
|
6762
|
+
...onEditIntent ? { onEditIntent } : {},
|
|
6763
|
+
className: "h-full"
|
|
6764
|
+
},
|
|
6765
|
+
viewPath
|
|
6766
|
+
) : waitingForSelectedFile ? /* @__PURE__ */ jsxs8(
|
|
6767
|
+
Notice,
|
|
6768
|
+
{
|
|
6769
|
+
icon: /* @__PURE__ */ jsx10(
|
|
6770
|
+
LoaderCircleIcon,
|
|
6771
|
+
{
|
|
6772
|
+
className: "size-5 animate-spin motion-reduce:animate-none",
|
|
6773
|
+
"aria-hidden": true
|
|
6774
|
+
}
|
|
6775
|
+
),
|
|
6776
|
+
title: "Waking workspace",
|
|
6777
|
+
announce: "status",
|
|
6778
|
+
children: [
|
|
6779
|
+
"Opening ",
|
|
6780
|
+
viewPath,
|
|
6781
|
+
" when the live file system is ready\u2026"
|
|
6782
|
+
]
|
|
6430
6783
|
}
|
|
6431
|
-
),
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6784
|
+
) : captureFileUnavailable ? /* @__PURE__ */ jsxs8(Notice, { icon: /* @__PURE__ */ jsx10(FileCode2Icon, { className: "size-5", "aria-hidden": true }), title: "On machine", children: [
|
|
6785
|
+
/* @__PURE__ */ jsx10("p", { children: captureFileUnavailable.reason === "too-large" ? "This file is larger than the captured preview limit." : captureFileUnavailable.reason === "content-missing" ? "The captured copy is no longer available." : "This file was indexed, but it was not changed in the captured turn." }),
|
|
6786
|
+
onWakeWorkspace ? /* @__PURE__ */ jsx10(
|
|
6787
|
+
WakeButton,
|
|
6788
|
+
{
|
|
6789
|
+
onClick: () => {
|
|
6790
|
+
setLiveRequestedPath(viewPath);
|
|
6791
|
+
if (liveWorkspaceReady) void files.refresh();
|
|
6792
|
+
else onWakeWorkspace();
|
|
6793
|
+
},
|
|
6794
|
+
children: liveWorkspaceReady ? "Retry live file" : "Open live file"
|
|
6795
|
+
}
|
|
6796
|
+
) : null
|
|
6797
|
+
] }) : fileView.error ? /* @__PURE__ */ jsxs8(Notice, { announce: "alert", children: [
|
|
6798
|
+
"Could not open ",
|
|
6436
6799
|
viewPath,
|
|
6437
|
-
"
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
": ",
|
|
6457
|
-
fileView.error.message
|
|
6458
|
-
] }) : fileView.loading ? /* @__PURE__ */ jsxs8(Notice, { announce: "status", children: [
|
|
6459
|
-
"Loading ",
|
|
6460
|
-
viewPath,
|
|
6461
|
-
"\u2026"
|
|
6462
|
-
] }) : fileView.isBinary ? /* @__PURE__ */ jsxs8(Notice, { children: [
|
|
6463
|
-
viewPath,
|
|
6464
|
-
" is a binary file (",
|
|
6465
|
-
fileView.sizeBytes ?? 0,
|
|
6466
|
-
" bytes)."
|
|
6467
|
-
] }) : fileView.content !== null ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
6468
|
-
fileView.truncated && /* @__PURE__ */ jsxs8("div", { className: "border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running", children: [
|
|
6469
|
-
"Large file \u2014 showing a truncated preview (",
|
|
6470
|
-
fileView.sizeBytes ?? 0,
|
|
6471
|
-
" bytes loaded). Editing is disabled to avoid corrupting the file."
|
|
6472
|
-
] }),
|
|
6473
|
-
usePierre ? /* @__PURE__ */ jsx10(
|
|
6474
|
-
PierreFile,
|
|
6475
|
-
{
|
|
6476
|
-
path: viewPath,
|
|
6477
|
-
contents: fileView.content,
|
|
6478
|
-
themeType: resolvedTheme,
|
|
6479
|
-
fallback: /* @__PURE__ */ jsx10("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content }),
|
|
6480
|
-
className: "p-1"
|
|
6481
|
-
}
|
|
6482
|
-
) : /* @__PURE__ */ jsx10("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content })
|
|
6483
|
-
] }) : /* @__PURE__ */ jsxs8(Notice, { announce: "status", children: [
|
|
6484
|
-
"Loading ",
|
|
6485
|
-
viewPath,
|
|
6486
|
-
"\u2026"
|
|
6487
|
-
] }) : (
|
|
6488
|
-
// Nothing selected — the tree shows the whole workspace; pick a file.
|
|
6489
|
-
requestedPath && !requestedPathReady ? /* @__PURE__ */ jsxs8(
|
|
6490
|
-
Notice,
|
|
6491
|
-
{
|
|
6492
|
-
icon: /* @__PURE__ */ jsx10(
|
|
6493
|
-
LoaderCircleIcon,
|
|
6800
|
+
": ",
|
|
6801
|
+
fileView.error.message
|
|
6802
|
+
] }) : fileView.loading ? /* @__PURE__ */ jsxs8(Notice, { announce: "status", children: [
|
|
6803
|
+
"Loading ",
|
|
6804
|
+
viewPath,
|
|
6805
|
+
"\u2026"
|
|
6806
|
+
] }) : fileView.isBinary ? /* @__PURE__ */ jsxs8(Notice, { children: [
|
|
6807
|
+
viewPath,
|
|
6808
|
+
" is a binary file (",
|
|
6809
|
+
fileView.sizeBytes ?? 0,
|
|
6810
|
+
" bytes)."
|
|
6811
|
+
] }) : fileView.content !== null ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
6812
|
+
fileView.truncated && /* @__PURE__ */ jsxs8("div", { className: "border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running", children: [
|
|
6813
|
+
"Large file \u2014 showing a truncated preview (",
|
|
6814
|
+
fileView.sizeBytes ?? 0,
|
|
6815
|
+
" bytes loaded). Editing is disabled to avoid corrupting the file."
|
|
6816
|
+
] }),
|
|
6817
|
+
usePierre ? /* @__PURE__ */ jsx10(
|
|
6818
|
+
PierreFile,
|
|
6494
6819
|
{
|
|
6495
|
-
|
|
6496
|
-
|
|
6820
|
+
path: viewPath,
|
|
6821
|
+
contents: fileView.content,
|
|
6822
|
+
themeType: resolvedTheme,
|
|
6823
|
+
fallback: /* @__PURE__ */ jsx10("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content }),
|
|
6824
|
+
className: "p-1"
|
|
6497
6825
|
}
|
|
6498
|
-
),
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6826
|
+
) : /* @__PURE__ */ jsx10("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content })
|
|
6827
|
+
] }) : /* @__PURE__ */ jsxs8(Notice, { announce: "status", children: [
|
|
6828
|
+
"Loading ",
|
|
6829
|
+
viewPath,
|
|
6830
|
+
"\u2026"
|
|
6831
|
+
] }) : (
|
|
6832
|
+
// Nothing selected — the tree shows the whole workspace; pick a file.
|
|
6833
|
+
requestedPath && !requestedPathReady ? /* @__PURE__ */ jsxs8(
|
|
6834
|
+
Notice,
|
|
6835
|
+
{
|
|
6836
|
+
icon: /* @__PURE__ */ jsx10(
|
|
6837
|
+
LoaderCircleIcon,
|
|
6838
|
+
{
|
|
6839
|
+
className: "size-5 animate-spin motion-reduce:animate-none",
|
|
6840
|
+
"aria-hidden": true
|
|
6841
|
+
}
|
|
6842
|
+
),
|
|
6843
|
+
title: "Waking sandbox",
|
|
6844
|
+
announce: "status",
|
|
6845
|
+
children: [
|
|
6846
|
+
"Opening ",
|
|
6847
|
+
requestedPath,
|
|
6848
|
+
" when the live workspace is ready\u2026"
|
|
6849
|
+
]
|
|
6850
|
+
}
|
|
6851
|
+
) : /* @__PURE__ */ jsx10(Notice, { icon: /* @__PURE__ */ jsx10(FileCode2Icon, { className: "size-5", "aria-hidden": true }), title: "Choose a file", children: "Select a file in the tree to preview it." })
|
|
6852
|
+
) })
|
|
6853
|
+
]
|
|
6854
|
+
}
|
|
6855
|
+
)
|
|
6856
|
+
]
|
|
6857
|
+
}
|
|
6858
|
+
)
|
|
6513
6859
|
] });
|
|
6514
6860
|
}
|
|
6515
6861
|
function WakeButton({ children, onClick }) {
|
|
@@ -6518,13 +6864,33 @@ function WakeButton({ children, onClick }) {
|
|
|
6518
6864
|
{
|
|
6519
6865
|
type: "button",
|
|
6520
6866
|
onClick,
|
|
6521
|
-
className: "mt-1 inline-flex min-h-11 items-center justify-center rounded-og-md bg-og-accent-deep px-3 py-2 text-og-sm font-medium text-og-accent-fg shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-
|
|
6867
|
+
className: "mt-1 inline-flex min-h-11 items-center justify-center rounded-og-md bg-og-accent-deep px-3 py-2 text-og-sm font-medium text-og-accent-fg shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
|
|
6522
6868
|
children
|
|
6523
6869
|
}
|
|
6524
6870
|
);
|
|
6525
6871
|
}
|
|
6526
|
-
function GitHeader({ git,
|
|
6527
|
-
|
|
6872
|
+
function GitHeader({ git, loading }) {
|
|
6873
|
+
if (loading) {
|
|
6874
|
+
return /* @__PURE__ */ jsxs8(
|
|
6875
|
+
"div",
|
|
6876
|
+
{
|
|
6877
|
+
className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm text-og-fg-muted",
|
|
6878
|
+
role: "status",
|
|
6879
|
+
"aria-live": "polite",
|
|
6880
|
+
children: [
|
|
6881
|
+
/* @__PURE__ */ jsx10(
|
|
6882
|
+
LoaderCircleIcon,
|
|
6883
|
+
{
|
|
6884
|
+
className: "size-3.5 shrink-0 animate-spin motion-reduce:animate-none",
|
|
6885
|
+
"aria-hidden": true
|
|
6886
|
+
}
|
|
6887
|
+
),
|
|
6888
|
+
/* @__PURE__ */ jsx10("span", { children: "Loading repository\u2026" })
|
|
6889
|
+
]
|
|
6890
|
+
}
|
|
6891
|
+
);
|
|
6892
|
+
}
|
|
6893
|
+
const dirty = git.dirtyCount > 0;
|
|
6528
6894
|
return /* @__PURE__ */ jsxs8("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm", children: [
|
|
6529
6895
|
/* @__PURE__ */ jsx10(
|
|
6530
6896
|
"span",
|
|
@@ -6536,7 +6902,7 @@ function GitHeader({ git, dirtyCount }) {
|
|
|
6536
6902
|
)
|
|
6537
6903
|
}
|
|
6538
6904
|
),
|
|
6539
|
-
/* @__PURE__ */ jsx10("span", { className: "sr-only", children: dirty ? `
|
|
6905
|
+
/* @__PURE__ */ jsx10("span", { className: "sr-only", children: dirty ? `Uncommitted changes in ${git.dirtyCount} files` : "No uncommitted changes" }),
|
|
6540
6906
|
/* @__PURE__ */ jsx10("span", { className: "truncate font-og-mono text-og-fg", children: git.repoCount > 1 ? `${git.repoCount} repositories` : git.branch ?? (git.isRepo ? "(detached)" : "no repo") }),
|
|
6541
6907
|
(git.ahead > 0 || git.behind > 0) && /* @__PURE__ */ jsxs8("span", { className: "flex shrink-0 items-center gap-1.5 text-og-xs text-og-fg-subtle", children: [
|
|
6542
6908
|
git.ahead > 0 && /* @__PURE__ */ jsxs8("span", { children: [
|
|
@@ -6555,7 +6921,7 @@ function GitHeader({ git, dirtyCount }) {
|
|
|
6555
6921
|
"data-contrast-audited": true,
|
|
6556
6922
|
className: "ml-auto shrink-0 text-og-xs text-og-fg-subtle",
|
|
6557
6923
|
children: [
|
|
6558
|
-
dirtyCount,
|
|
6924
|
+
git.dirtyCount,
|
|
6559
6925
|
" changed"
|
|
6560
6926
|
]
|
|
6561
6927
|
}
|
|
@@ -6573,7 +6939,7 @@ function Segmented({
|
|
|
6573
6939
|
type: "button",
|
|
6574
6940
|
onClick: () => onChange(opt.value),
|
|
6575
6941
|
className: cn(
|
|
6576
|
-
"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs focus-visible:outline-
|
|
6942
|
+
"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
|
|
6577
6943
|
opt.value === value ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
6578
6944
|
),
|
|
6579
6945
|
children: opt.label
|
|
@@ -6582,6 +6948,7 @@ function Segmented({
|
|
|
6582
6948
|
)) });
|
|
6583
6949
|
}
|
|
6584
6950
|
function useFileView(path, readFile, reloadRevision = 0) {
|
|
6951
|
+
const previousPathRef = useRef17(null);
|
|
6585
6952
|
const [state, setState] = useState17({
|
|
6586
6953
|
content: null,
|
|
6587
6954
|
isBinary: false,
|
|
@@ -6592,6 +6959,7 @@ function useFileView(path, readFile, reloadRevision = 0) {
|
|
|
6592
6959
|
});
|
|
6593
6960
|
useEffect20(() => {
|
|
6594
6961
|
if (!path) {
|
|
6962
|
+
previousPathRef.current = null;
|
|
6595
6963
|
setState({
|
|
6596
6964
|
content: null,
|
|
6597
6965
|
isBinary: false,
|
|
@@ -6602,16 +6970,22 @@ function useFileView(path, readFile, reloadRevision = 0) {
|
|
|
6602
6970
|
});
|
|
6603
6971
|
return;
|
|
6604
6972
|
}
|
|
6973
|
+
const pathChanged = previousPathRef.current !== path;
|
|
6974
|
+
previousPathRef.current = path;
|
|
6605
6975
|
let cancelled = false;
|
|
6606
6976
|
const abort = new AbortController();
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6977
|
+
if (pathChanged) {
|
|
6978
|
+
setState({
|
|
6979
|
+
content: null,
|
|
6980
|
+
isBinary: false,
|
|
6981
|
+
truncated: false,
|
|
6982
|
+
sizeBytes: null,
|
|
6983
|
+
loading: true,
|
|
6984
|
+
error: null
|
|
6985
|
+
});
|
|
6986
|
+
} else {
|
|
6987
|
+
setState((previous) => ({ ...previous, error: null }));
|
|
6988
|
+
}
|
|
6615
6989
|
void readFile(path, { signal: abort.signal }).then((res) => {
|
|
6616
6990
|
if (cancelled) return;
|
|
6617
6991
|
const content = res.isBinary ? null : res.encoding === "base64" ? decodeBase64Utf8(res.content) : res.content;
|
|
@@ -6625,14 +6999,17 @@ function useFileView(path, readFile, reloadRevision = 0) {
|
|
|
6625
6999
|
});
|
|
6626
7000
|
}).catch((cause) => {
|
|
6627
7001
|
if (cancelled) return;
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
7002
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
7003
|
+
setState(
|
|
7004
|
+
(previous) => pathChanged ? {
|
|
7005
|
+
content: null,
|
|
7006
|
+
isBinary: false,
|
|
7007
|
+
truncated: false,
|
|
7008
|
+
sizeBytes: null,
|
|
7009
|
+
loading: false,
|
|
7010
|
+
error
|
|
7011
|
+
} : { ...previous, loading: false, error }
|
|
7012
|
+
);
|
|
6636
7013
|
});
|
|
6637
7014
|
return () => {
|
|
6638
7015
|
cancelled = true;
|
|
@@ -6924,7 +7301,7 @@ function TakeControlCallToAction({
|
|
|
6924
7301
|
"border-og-border",
|
|
6925
7302
|
"bg-og-bg/85 backdrop-blur-md",
|
|
6926
7303
|
"shadow-og-lg",
|
|
6927
|
-
"outline-
|
|
7304
|
+
"outline-hidden transition-all duration-150 ease-out",
|
|
6928
7305
|
"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
|
|
6929
7306
|
disabled ? "cursor-not-allowed opacity-60" : cn(
|
|
6930
7307
|
"cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100",
|
|
@@ -6972,7 +7349,7 @@ function InControlBar({ shared, onRelease }) {
|
|
|
6972
7349
|
className: cn(
|
|
6973
7350
|
"inline-flex items-center gap-1.5 rounded-og-sm border px-2.5 py-1 text-og-xs font-semibold shadow-og-md transition-colors",
|
|
6974
7351
|
"border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm",
|
|
6975
|
-
"outline-
|
|
7352
|
+
"outline-hidden hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
6976
7353
|
),
|
|
6977
7354
|
children: [
|
|
6978
7355
|
/* @__PURE__ */ jsx11(MonitorIcon, { className: "size-3.5", strokeWidth: 2, "aria-hidden": true }),
|
|
@@ -7075,9 +7452,9 @@ import {
|
|
|
7075
7452
|
XIcon as XIcon2
|
|
7076
7453
|
} from "lucide-react";
|
|
7077
7454
|
import {
|
|
7078
|
-
Group,
|
|
7079
|
-
Panel,
|
|
7080
|
-
Separator,
|
|
7455
|
+
Group as Group2,
|
|
7456
|
+
Panel as Panel2,
|
|
7457
|
+
Separator as Separator2,
|
|
7081
7458
|
useDefaultLayout,
|
|
7082
7459
|
usePanelRef
|
|
7083
7460
|
} from "react-resizable-panels";
|
|
@@ -7122,6 +7499,7 @@ function WorkspaceDock({
|
|
|
7122
7499
|
onActiveTabChange,
|
|
7123
7500
|
collapsed: collapsedProp,
|
|
7124
7501
|
onCollapsedChange,
|
|
7502
|
+
showCollapseControl = false,
|
|
7125
7503
|
headerAccessory,
|
|
7126
7504
|
mobileLeadingControl,
|
|
7127
7505
|
autoSaveId = "og.session.dock",
|
|
@@ -7298,6 +7676,11 @@ function WorkspaceDock({
|
|
|
7298
7676
|
className: "fixed inset-0 z-40 flex flex-col bg-og-bg",
|
|
7299
7677
|
hidden: collapsed,
|
|
7300
7678
|
style: {
|
|
7679
|
+
// Author utility classes can override the user-agent `[hidden]`
|
|
7680
|
+
// rule (for example this surface's `flex` class). Keep an inline
|
|
7681
|
+
// display guard so a collapsed mobile workspace is actually gone
|
|
7682
|
+
// visually as well as from the accessibility tree.
|
|
7683
|
+
display: collapsed ? "none" : void 0,
|
|
7301
7684
|
paddingTop: "env(safe-area-inset-top)",
|
|
7302
7685
|
paddingBottom: "env(safe-area-inset-bottom)"
|
|
7303
7686
|
},
|
|
@@ -7322,7 +7705,7 @@ function WorkspaceDock({
|
|
|
7322
7705
|
onClick: expand,
|
|
7323
7706
|
title: "Open workspace",
|
|
7324
7707
|
"aria-label": "Open workspace",
|
|
7325
|
-
className: "absolute right-3 top-3 z-30 inline-flex size-11 items-center justify-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted shadow-lg transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-
|
|
7708
|
+
className: "absolute right-3 top-3 z-30 inline-flex size-11 items-center justify-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted shadow-lg transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent",
|
|
7326
7709
|
style: { marginTop: "env(safe-area-inset-top)" },
|
|
7327
7710
|
children: /* @__PURE__ */ jsx12(ChevronsLeftRightIcon, { className: "size-4", "aria-hidden": true })
|
|
7328
7711
|
}
|
|
@@ -7346,20 +7729,20 @@ function WorkspaceDock({
|
|
|
7346
7729
|
children: maximized ? /* @__PURE__ */ jsx12(Minimize2Icon, { className: "size-3.5" }) : /* @__PURE__ */ jsx12(Maximize2Icon, { className: "size-3.5" })
|
|
7347
7730
|
}
|
|
7348
7731
|
),
|
|
7349
|
-
hostControlled ? null : /* @__PURE__ */ jsx12(ChromeButton, { onClick: collapse, title: "Collapse", label: "Collapse dock", children: /* @__PURE__ */ jsx12(PanelRightCloseIcon, { className: "size-3.5" }) })
|
|
7732
|
+
hostControlled && !showCollapseControl ? null : /* @__PURE__ */ jsx12(ChromeButton, { onClick: collapse, title: "Collapse", label: "Collapse dock", children: /* @__PURE__ */ jsx12(PanelRightCloseIcon, { className: "size-3.5" }) })
|
|
7350
7733
|
] })
|
|
7351
7734
|
}
|
|
7352
7735
|
);
|
|
7353
7736
|
return /* @__PURE__ */ jsxs10("div", { ref: rootRef, className: cn("relative flex h-full min-h-0 w-full min-w-0", className), children: [
|
|
7354
7737
|
/* @__PURE__ */ jsxs10(
|
|
7355
|
-
|
|
7738
|
+
Group2,
|
|
7356
7739
|
{
|
|
7357
7740
|
orientation: "horizontal",
|
|
7358
7741
|
className: "min-h-0 flex-1",
|
|
7359
7742
|
...defaultLayout ? { defaultLayout } : {},
|
|
7360
7743
|
onLayoutChanged,
|
|
7361
7744
|
children: [
|
|
7362
|
-
/* @__PURE__ */ jsx12(
|
|
7745
|
+
/* @__PURE__ */ jsx12(Panel2, { id: "primary", minSize: "30%", className: "min-h-0 min-w-0", children: /* @__PURE__ */ jsx12(
|
|
7363
7746
|
"div",
|
|
7364
7747
|
{
|
|
7365
7748
|
"data-workspace-primary": true,
|
|
@@ -7369,9 +7752,9 @@ function WorkspaceDock({
|
|
|
7369
7752
|
children: primary
|
|
7370
7753
|
}
|
|
7371
7754
|
) }),
|
|
7372
|
-
!collapsed && /* @__PURE__ */ jsx12(
|
|
7755
|
+
!collapsed && /* @__PURE__ */ jsx12(Separator2, { className: "group relative z-10 w-1.5 shrink-0 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent max-[1023px]:-mx-[19px] max-[1023px]:w-11 pointer-coarse:-mx-[19px] pointer-coarse:w-11", children: /* @__PURE__ */ jsx12("span", { className: "absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-og-border transition-colors group-hover:bg-og-accent group-focus-visible:bg-og-accent group-data-[separator-state=dragging]:bg-og-accent" }) }),
|
|
7373
7756
|
/* @__PURE__ */ jsx12(
|
|
7374
|
-
|
|
7757
|
+
Panel2,
|
|
7375
7758
|
{
|
|
7376
7759
|
id: "dock",
|
|
7377
7760
|
panelRef: dockPanelRef,
|
|
@@ -7435,7 +7818,7 @@ function ChromeButton({
|
|
|
7435
7818
|
onClick,
|
|
7436
7819
|
title,
|
|
7437
7820
|
"aria-label": label,
|
|
7438
|
-
className: "inline-flex size-7 items-center justify-center rounded-og-sm p-1 transition-colors hover:bg-og-surface-2 hover:text-og-fg focus-visible:outline-
|
|
7821
|
+
className: "inline-flex size-7 items-center justify-center rounded-og-sm p-1 transition-colors hover:bg-og-surface-2 hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:size-11 pointer-coarse:size-11",
|
|
7439
7822
|
children
|
|
7440
7823
|
}
|
|
7441
7824
|
);
|
|
@@ -7547,7 +7930,7 @@ function DockChrome({
|
|
|
7547
7930
|
onClick: () => onTab(tab.id),
|
|
7548
7931
|
onKeyDown: (event) => onTabKeyDown(event, index),
|
|
7549
7932
|
className: cn(
|
|
7550
|
-
"flex min-h-7 shrink-0 items-center justify-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-
|
|
7933
|
+
"flex min-h-7 shrink-0 items-center justify-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
|
|
7551
7934
|
tab.id === current ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
|
|
7552
7935
|
),
|
|
7553
7936
|
children: [
|
|
@@ -7582,14 +7965,16 @@ function DockChrome({
|
|
|
7582
7965
|
}
|
|
7583
7966
|
|
|
7584
7967
|
// src/components/sandbox-workspace.tsx
|
|
7585
|
-
import { useCallback as useCallback22, useEffect as useEffect23, useMemo as
|
|
7586
|
-
import { Popover } from "radix-ui";
|
|
7968
|
+
import { useCallback as useCallback22, useEffect as useEffect23, useMemo as useMemo12, useRef as useRef20, useState as useState20 } from "react";
|
|
7587
7969
|
import {
|
|
7588
7970
|
CircleCheckIcon,
|
|
7589
7971
|
CpuIcon,
|
|
7590
|
-
|
|
7972
|
+
FileCode2Icon as FileCode2Icon2,
|
|
7973
|
+
GitCompareArrowsIcon,
|
|
7591
7974
|
LoaderCircleIcon as LoaderCircleIcon3,
|
|
7975
|
+
MonitorIcon as MonitorIcon2,
|
|
7592
7976
|
RefreshCwIcon as RefreshCwIcon2,
|
|
7977
|
+
SquareTerminalIcon,
|
|
7593
7978
|
TriangleAlertIcon as TriangleAlertIcon2
|
|
7594
7979
|
} from "lucide-react";
|
|
7595
7980
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
@@ -7624,6 +8009,12 @@ function captureDegradedMessage(reason) {
|
|
|
7624
8009
|
return "Workspace capture is incomplete because repository discovery failed. Live files remain authoritative.";
|
|
7625
8010
|
}
|
|
7626
8011
|
}
|
|
8012
|
+
function WorkbenchTabLabel({ icon, children }) {
|
|
8013
|
+
return /* @__PURE__ */ jsxs11("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
8014
|
+
/* @__PURE__ */ jsx13("span", { className: "[&>svg]:size-3.5", "aria-hidden": true, children: icon }),
|
|
8015
|
+
/* @__PURE__ */ jsx13("span", { children })
|
|
8016
|
+
] });
|
|
8017
|
+
}
|
|
7627
8018
|
function initialWorkspaceTab(events, override) {
|
|
7628
8019
|
if (override) return override;
|
|
7629
8020
|
let bestSeq = -1;
|
|
@@ -7666,6 +8057,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7666
8057
|
const { client, workspaceId } = useOpenGeni(options);
|
|
7667
8058
|
const { sessionId, events, onNotify, requestedFilePath, requestedFileRequestId, onOpenFile } = options;
|
|
7668
8059
|
const initialTab = options.initialTab ?? null;
|
|
8060
|
+
const activeTab = options.activeTab ?? initialTab;
|
|
7669
8061
|
const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;
|
|
7670
8062
|
const surfaceSet = new Set(requestedSurfaces);
|
|
7671
8063
|
const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);
|
|
@@ -7674,6 +8066,9 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7674
8066
|
const desktopEnabled = surfaceSet.has(WORKBENCH_TAB_DESKTOP);
|
|
7675
8067
|
const workspaceDataEnabled = changesEnabled || filesEnabled;
|
|
7676
8068
|
const anySurfaceEnabled = workspaceDataEnabled || terminalEnabled || desktopEnabled;
|
|
8069
|
+
const resolvedActiveTab = activeTab ?? initialTab;
|
|
8070
|
+
const changesActive = resolvedActiveTab === WORKBENCH_TAB_CHANGES;
|
|
8071
|
+
const filesActive = resolvedActiveTab === WORKBENCH_TAB_FILES;
|
|
7677
8072
|
const surfaceIdentity = WORKBENCH_SURFACES.filter((surface) => surfaceSet.has(surface)).join(",");
|
|
7678
8073
|
const [storedWarmIntents, setStoredWarmIntents] = useState20(
|
|
7679
8074
|
() => emptyWarmIntents(sessionId)
|
|
@@ -7737,7 +8132,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7737
8132
|
const captureAvailable = captureState.available;
|
|
7738
8133
|
const liveWorkspaceExpected = liveness === "warm" || liveness === "draining";
|
|
7739
8134
|
const capturePending = !liveWorkspaceExpected && (captureState.fileCount === null || captureState.loading);
|
|
7740
|
-
const repoPaths =
|
|
8135
|
+
const repoPaths = useMemo12(() => {
|
|
7741
8136
|
const advertised = capabilities?.Git.repos ?? [];
|
|
7742
8137
|
if (advertised.length > 0) return advertised;
|
|
7743
8138
|
return captureState.capture?.repos.map((repo) => repo.root) ?? [];
|
|
@@ -7760,6 +8155,8 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7760
8155
|
// No passive Channel-A reads while cold, even after a conclusive capture
|
|
7761
8156
|
// miss. A missing capture gets an explicit "Open live workspace" gate.
|
|
7762
8157
|
enabled: filesEnabled && (captureAvailable || fileSystemOn && liveWorkspaceExpected),
|
|
8158
|
+
active: filesActive,
|
|
8159
|
+
repoPaths,
|
|
7763
8160
|
liveness,
|
|
7764
8161
|
capture: captureState.capture,
|
|
7765
8162
|
// A reverted optimistic mutation (e.g. a 409 rename collision) surfaces as a
|
|
@@ -7769,23 +8166,30 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7769
8166
|
message: `Could not ${op}: ${error.message}`
|
|
7770
8167
|
})
|
|
7771
8168
|
});
|
|
8169
|
+
const [storedChangesComparison, setStoredChangesComparison] = useState20(null);
|
|
8170
|
+
const captureSupportsBranch = captureState.capture !== null && captureState.capture.repos.length > 0 && captureState.capture.repos.every((repo) => repo.branchDiff !== void 0);
|
|
8171
|
+
const changesComparison = storedChangesComparison?.sessionId === sessionId ? storedChangesComparison.value : liveWorkspaceExpected || captureSupportsBranch ? "branch" : "working";
|
|
8172
|
+
const setChangesComparison = useCallback22(
|
|
8173
|
+
(value) => setStoredChangesComparison({ sessionId, value }),
|
|
8174
|
+
[sessionId]
|
|
8175
|
+
);
|
|
7772
8176
|
const git = useSandboxGit(sessionId, {
|
|
7773
8177
|
events,
|
|
7774
|
-
enabled: workspaceDataEnabled && (captureAvailable || gitOn && liveWorkspaceExpected),
|
|
8178
|
+
enabled: changesComparison === "working" ? workspaceDataEnabled && (captureAvailable || gitOn && liveWorkspaceExpected) : changesComparison === "branch" ? workspaceDataEnabled && (captureSupportsBranch || gitOn && liveWorkspaceExpected) : workspaceDataEnabled && gitOn && liveWorkspaceExpected,
|
|
8179
|
+
// Before the dock chooses its source-driven default, Git is the sole probe
|
|
8180
|
+
// that may need to resolve that choice on a live workspace. Files remains
|
|
8181
|
+
// dormant, avoiding the old duplicate full-tree read.
|
|
8182
|
+
active: changesActive || resolvedActiveTab === null,
|
|
7775
8183
|
repoPaths,
|
|
7776
8184
|
liveness,
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
const stagedGit = useSandboxGit(sessionId, {
|
|
7780
|
-
events,
|
|
7781
|
-
// Captures intentionally expose one combined review diff, not a staged
|
|
7782
|
-
// index. Never probe the live index while the lease is cold.
|
|
7783
|
-
enabled: filesEnabled && gitOn && liveWorkspaceExpected,
|
|
7784
|
-
staged: true,
|
|
7785
|
-
repoPaths,
|
|
7786
|
-
liveness,
|
|
7787
|
-
capture: captureState.capture
|
|
8185
|
+
comparison: changesComparison,
|
|
8186
|
+
capture: changesComparison === "staged" ? null : captureState.capture
|
|
7788
8187
|
});
|
|
8188
|
+
useEffect23(() => {
|
|
8189
|
+
if (changesComparison === "branch" && git.error && storedChangesComparison?.sessionId !== sessionId) {
|
|
8190
|
+
setStoredChangesComparison({ sessionId, value: "working" });
|
|
8191
|
+
}
|
|
8192
|
+
}, [changesComparison, git.error, sessionId, storedChangesComparison?.sessionId]);
|
|
7789
8193
|
const [xtermTheme, setXtermTheme] = useState20(void 0);
|
|
7790
8194
|
useEffect23(() => {
|
|
7791
8195
|
if (!terminalEnabled || typeof document === "undefined") return;
|
|
@@ -7838,6 +8242,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7838
8242
|
}
|
|
7839
8243
|
const captureIsAuthoritative = !liveWorkspaceExpected && (liveness !== void 0 || caps.error !== null);
|
|
7840
8244
|
const captureUnavailable = captureState.fileCount === 0 || captureState.error !== null;
|
|
8245
|
+
const implicitBranchFallbackPending = changesComparison === "branch" && git.error !== null && storedChangesComparison?.sessionId !== sessionId;
|
|
7841
8246
|
if (defaultTabRef.current.value === null) {
|
|
7842
8247
|
if (initialTab && (!isWorkbenchSurface(initialTab) || surfaceSet.has(initialTab))) {
|
|
7843
8248
|
defaultTabRef.current.value = initialTab;
|
|
@@ -7865,22 +8270,24 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7865
8270
|
changesEnabled,
|
|
7866
8271
|
filesEnabled
|
|
7867
8272
|
);
|
|
7868
|
-
} else if (captureUnavailable && git.error) {
|
|
8273
|
+
} else if (captureUnavailable && git.error && !implicitBranchFallbackPending) {
|
|
7869
8274
|
defaultTabRef.current.value = sourceDrivenDefaultTab(false, changesEnabled, filesEnabled);
|
|
7870
8275
|
}
|
|
7871
8276
|
}
|
|
7872
8277
|
const defaultTab = defaultTabRef.current.value;
|
|
7873
|
-
const tabs =
|
|
8278
|
+
const tabs = useMemo12(() => {
|
|
7874
8279
|
const list = [];
|
|
7875
8280
|
if (changesEnabled)
|
|
7876
8281
|
list.push({
|
|
7877
8282
|
id: WORKBENCH_TAB_CHANGES,
|
|
7878
|
-
label: "Changes",
|
|
8283
|
+
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(GitCompareArrowsIcon, {}), children: "Changes" }),
|
|
7879
8284
|
badge: dirtyCount > 0 ? /* @__PURE__ */ jsx13(DirtyBadge, { count: dirtyCount }) : void 0,
|
|
7880
8285
|
content: /* @__PURE__ */ jsx13(
|
|
7881
8286
|
ChangesTabBody,
|
|
7882
8287
|
{
|
|
7883
8288
|
git,
|
|
8289
|
+
comparison: changesComparison,
|
|
8290
|
+
onComparisonChange: setChangesComparison,
|
|
7884
8291
|
captureAvailable,
|
|
7885
8292
|
captureRevision: captureState.revision,
|
|
7886
8293
|
capturePending,
|
|
@@ -7902,13 +8309,12 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7902
8309
|
if (filesEnabled)
|
|
7903
8310
|
list.push({
|
|
7904
8311
|
id: WORKBENCH_TAB_FILES,
|
|
7905
|
-
label: "Files",
|
|
8312
|
+
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(FileCode2Icon2, {}), children: "Files" }),
|
|
7906
8313
|
content: /* @__PURE__ */ jsx13(
|
|
7907
8314
|
SandboxFiles,
|
|
7908
8315
|
{
|
|
7909
8316
|
files,
|
|
7910
8317
|
git,
|
|
7911
|
-
stagedGit,
|
|
7912
8318
|
fileSystemAvailable: fileSystemOn || captureAvailable,
|
|
7913
8319
|
editable: filesEditable && files.source === "live" && files.error === null && !files.loading,
|
|
7914
8320
|
workspaceResting: !liveWorkspaceExpected && liveness !== void 0 && !capturePending && !captureAvailable && !workspaceWaking,
|
|
@@ -7929,7 +8335,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7929
8335
|
if (terminalOn) {
|
|
7930
8336
|
list.push({
|
|
7931
8337
|
id: WORKBENCH_TAB_TERMINAL,
|
|
7932
|
-
label: "Terminal",
|
|
8338
|
+
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(SquareTerminalIcon, {}), children: "Terminal" }),
|
|
7933
8339
|
content: /* @__PURE__ */ jsx13("div", { className: "h-full bg-og-bg p-1", children: /* @__PURE__ */ jsx13(
|
|
7934
8340
|
SandboxTerminal,
|
|
7935
8341
|
{
|
|
@@ -7947,7 +8353,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7947
8353
|
if (desktopAdvertised) {
|
|
7948
8354
|
list.push({
|
|
7949
8355
|
id: WORKBENCH_TAB_DESKTOP,
|
|
7950
|
-
label: "Desktop",
|
|
8356
|
+
label: /* @__PURE__ */ jsx13(WorkbenchTabLabel, { icon: /* @__PURE__ */ jsx13(MonitorIcon2, {}), children: "Desktop" }),
|
|
7951
8357
|
badge: watchDesktop ? /* @__PURE__ */ jsx13("span", { className: "rounded-og-xs bg-og-status-running/20 px-1 text-og-xs text-og-status-running", children: "Live" }) : void 0,
|
|
7952
8358
|
content: /* @__PURE__ */ jsx13(
|
|
7953
8359
|
DesktopViewer,
|
|
@@ -7980,7 +8386,7 @@ function useSandboxWorkspaceTabs(options) {
|
|
|
7980
8386
|
sessionId,
|
|
7981
8387
|
files,
|
|
7982
8388
|
git,
|
|
7983
|
-
|
|
8389
|
+
changesComparison,
|
|
7984
8390
|
terminal,
|
|
7985
8391
|
xtermTheme,
|
|
7986
8392
|
capabilities,
|
|
@@ -8015,6 +8421,7 @@ function SandboxWorkspace(props) {
|
|
|
8015
8421
|
onNotify,
|
|
8016
8422
|
collapsed,
|
|
8017
8423
|
onCollapsedChange,
|
|
8424
|
+
showCollapseControl,
|
|
8018
8425
|
mobileLeadingControl,
|
|
8019
8426
|
autoSaveId,
|
|
8020
8427
|
defaultSize,
|
|
@@ -8025,6 +8432,8 @@ function SandboxWorkspace(props) {
|
|
|
8025
8432
|
const [storedSelection, setStoredSelection] = useState20(null);
|
|
8026
8433
|
const [requestedFile, setRequestedFile] = useState20(null);
|
|
8027
8434
|
const nextFileRequestId = useRef20(0);
|
|
8435
|
+
const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;
|
|
8436
|
+
const activeTabHint = selectedTab ?? initialTab ?? leadingTabs?.[0]?.id ?? null;
|
|
8028
8437
|
const openFile = useCallback22(
|
|
8029
8438
|
(path) => {
|
|
8030
8439
|
nextFileRequestId.current += 1;
|
|
@@ -8044,13 +8453,13 @@ function SandboxWorkspace(props) {
|
|
|
8044
8453
|
events,
|
|
8045
8454
|
...surfaces ? { surfaces } : {},
|
|
8046
8455
|
...initialTab ? { initialTab } : {},
|
|
8456
|
+
activeTab: activeTabHint,
|
|
8047
8457
|
...onNotify ? { onNotify } : {},
|
|
8048
8458
|
requestedFilePath: requestedFile?.sessionId === sessionId ? requestedFile.path : null,
|
|
8049
8459
|
requestedFileRequestId: requestedFile?.sessionId === sessionId ? requestedFile.requestId : null,
|
|
8050
8460
|
onOpenFile: openFile
|
|
8051
8461
|
});
|
|
8052
8462
|
const tabs = [...leadingTabs ?? [], ...workbenchTabs, ...trailingTabs ?? []];
|
|
8053
|
-
const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;
|
|
8054
8463
|
const preferredTab = selectedTab ?? defaultTab;
|
|
8055
8464
|
const activeTab = preferredTab && tabs.some((tab) => tab.id === preferredTab) ? preferredTab : tabs[0]?.id;
|
|
8056
8465
|
const selectTab = useCallback22(
|
|
@@ -8065,19 +8474,12 @@ function SandboxWorkspace(props) {
|
|
|
8065
8474
|
...activeTab !== void 0 ? { activeTab } : {},
|
|
8066
8475
|
onActiveTabChange: selectTab,
|
|
8067
8476
|
...machine.enabled ? {
|
|
8068
|
-
headerAccessory: /* @__PURE__ */ jsx13(
|
|
8069
|
-
MachineStateChip,
|
|
8070
|
-
{
|
|
8071
|
-
chip: machine.chip,
|
|
8072
|
-
activeMachine: machine.activeMachine,
|
|
8073
|
-
error: machine.error,
|
|
8074
|
-
onRetry: () => void machine.refresh()
|
|
8075
|
-
}
|
|
8076
|
-
)
|
|
8477
|
+
headerAccessory: /* @__PURE__ */ jsx13(MachineStateChip, { chip: machine.chip })
|
|
8077
8478
|
} : {},
|
|
8078
8479
|
...mobileLeadingControl !== void 0 ? { mobileLeadingControl } : {},
|
|
8079
8480
|
...collapsed !== void 0 ? { collapsed } : {},
|
|
8080
8481
|
...onCollapsedChange ? { onCollapsedChange } : {},
|
|
8482
|
+
...showCollapseControl !== void 0 ? { showCollapseControl } : {},
|
|
8081
8483
|
...autoSaveId !== void 0 ? { autoSaveId } : {},
|
|
8082
8484
|
...defaultSize !== void 0 ? { defaultSize } : {},
|
|
8083
8485
|
...minSize !== void 0 ? { minSize } : {},
|
|
@@ -8089,94 +8491,30 @@ function SandboxWorkspace(props) {
|
|
|
8089
8491
|
function DirtyBadge({ count }) {
|
|
8090
8492
|
return /* @__PURE__ */ jsx13("span", { className: "rounded-og-xs bg-og-accent-soft px-1 text-og-xs text-og-fg-muted", children: count });
|
|
8091
8493
|
}
|
|
8092
|
-
function MachineKindIcon({
|
|
8093
|
-
kind,
|
|
8094
|
-
className
|
|
8095
|
-
}) {
|
|
8096
|
-
const Icon = kind === "selfhosted" ? LaptopIcon : CpuIcon;
|
|
8097
|
-
return /* @__PURE__ */ jsx13(Icon, { className: cn("size-3.5 shrink-0 text-og-fg-subtle", className), "aria-hidden": true });
|
|
8098
|
-
}
|
|
8099
8494
|
function chipDotClass(state) {
|
|
8100
8495
|
if (state === "live") return "bg-og-status-running";
|
|
8101
8496
|
if (state === "waking") return "bg-og-status-idle animate-pulse motion-reduce:animate-none";
|
|
8102
8497
|
return "bg-og-fg-subtle";
|
|
8103
8498
|
}
|
|
8104
|
-
function MachineStateChip({
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
{
|
|
8124
|
-
className: cn("size-1.5 shrink-0 rounded-full", chipDotClass(chip.state)),
|
|
8125
|
-
"aria-hidden": true
|
|
8126
|
-
}
|
|
8127
|
-
),
|
|
8128
|
-
/* @__PURE__ */ jsx13("span", { className: "max-w-[11rem] truncate", children: chip.label })
|
|
8129
|
-
]
|
|
8130
|
-
}
|
|
8131
|
-
) }),
|
|
8132
|
-
/* @__PURE__ */ jsx13(Popover.Portal, { forceMount: true, children: /* @__PURE__ */ jsxs11(
|
|
8133
|
-
Popover.Content,
|
|
8134
|
-
{
|
|
8135
|
-
forceMount: true,
|
|
8136
|
-
"data-machine-state-popover": true,
|
|
8137
|
-
align: "end",
|
|
8138
|
-
sideOffset: 6,
|
|
8139
|
-
collisionPadding: 8,
|
|
8140
|
-
className: "og-root z-50 w-64 max-w-[calc(100vw-1rem)] rounded-og-md border border-og-border bg-og-surface-1 p-3 text-og-sm text-og-fg shadow-lg outline-none",
|
|
8141
|
-
style: portalStyle,
|
|
8142
|
-
children: [
|
|
8143
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
8144
|
-
/* @__PURE__ */ jsx13(MachineKindIcon, { kind: activeMachine?.kind }),
|
|
8145
|
-
/* @__PURE__ */ jsx13("span", { className: "min-w-0 truncate font-medium", children: activeMachine?.name ?? "Sandbox" })
|
|
8146
|
-
] }),
|
|
8147
|
-
/* @__PURE__ */ jsxs11("div", { className: "mt-2.5 flex items-center justify-between gap-2", children: [
|
|
8148
|
-
/* @__PURE__ */ jsx13("span", { className: "text-og-xs text-og-fg-subtle", children: "Connection" }),
|
|
8149
|
-
activeMachine ? /* @__PURE__ */ jsx13(
|
|
8150
|
-
ConnectionStatusPill,
|
|
8151
|
-
{
|
|
8152
|
-
status: connectionStatusForState(activeMachine.state),
|
|
8153
|
-
size: "sm"
|
|
8154
|
-
}
|
|
8155
|
-
) : /* @__PURE__ */ jsx13("span", { className: "text-og-xs text-og-fg-muted", children: chip.label })
|
|
8156
|
-
] }),
|
|
8157
|
-
chip.asOf ? /* @__PURE__ */ jsxs11("p", { className: "mt-2.5 text-og-xs leading-4 text-og-fg-subtle", children: [
|
|
8158
|
-
"Workspace shown as of ",
|
|
8159
|
-
formatAsOf(chip.asOf, Date.now()),
|
|
8160
|
-
" \u2014 the machine is not live."
|
|
8161
|
-
] }) : null,
|
|
8162
|
-
activeMachine && activeMachine.sharedSessionCount > 1 ? /* @__PURE__ */ jsx13("div", { className: "mt-2.5", children: /* @__PURE__ */ jsx13(
|
|
8163
|
-
SharedMachineDisclosure,
|
|
8164
|
-
{
|
|
8165
|
-
sharedSessionCount: activeMachine.sharedSessionCount,
|
|
8166
|
-
density: "full"
|
|
8167
|
-
}
|
|
8168
|
-
) }) : null,
|
|
8169
|
-
error ? /* @__PURE__ */ jsxs11("div", { className: "mt-2.5 space-y-1.5 border-t border-og-border pt-2.5", children: [
|
|
8170
|
-
/* @__PURE__ */ jsx13("p", { className: "text-og-xs leading-4 text-og-danger", children: "Couldn't reach the sandbox for this session." }),
|
|
8171
|
-
/* @__PURE__ */ jsxs11(DockActionButton, { onClick: onRetry, children: [
|
|
8172
|
-
/* @__PURE__ */ jsx13(RefreshCwIcon2, { className: "size-3" }),
|
|
8173
|
-
"Retry"
|
|
8174
|
-
] })
|
|
8175
|
-
] }) : null
|
|
8176
|
-
]
|
|
8177
|
-
}
|
|
8178
|
-
) })
|
|
8179
|
-
] });
|
|
8499
|
+
function MachineStateChip({ chip }) {
|
|
8500
|
+
return /* @__PURE__ */ jsxs11(
|
|
8501
|
+
"div",
|
|
8502
|
+
{
|
|
8503
|
+
role: "status",
|
|
8504
|
+
"aria-label": `Machine: ${chip.label}`,
|
|
8505
|
+
className: "inline-flex min-h-7 items-center gap-1.5 px-2 py-1 text-og-xs font-medium text-og-fg-muted max-[1023px]:min-h-11 pointer-coarse:min-h-11",
|
|
8506
|
+
children: [
|
|
8507
|
+
/* @__PURE__ */ jsx13(
|
|
8508
|
+
"span",
|
|
8509
|
+
{
|
|
8510
|
+
className: cn("size-1.5 shrink-0 rounded-full", chipDotClass(chip.state)),
|
|
8511
|
+
"aria-hidden": true
|
|
8512
|
+
}
|
|
8513
|
+
),
|
|
8514
|
+
/* @__PURE__ */ jsx13("span", { className: "max-w-[11rem] truncate", children: chip.label })
|
|
8515
|
+
]
|
|
8516
|
+
}
|
|
8517
|
+
);
|
|
8180
8518
|
}
|
|
8181
8519
|
function DockActionButton({ onClick, children }) {
|
|
8182
8520
|
return /* @__PURE__ */ jsx13(
|
|
@@ -8184,13 +8522,41 @@ function DockActionButton({ onClick, children }) {
|
|
|
8184
8522
|
{
|
|
8185
8523
|
type: "button",
|
|
8186
8524
|
onClick,
|
|
8187
|
-
className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-
|
|
8525
|
+
className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11",
|
|
8188
8526
|
children
|
|
8189
8527
|
}
|
|
8190
8528
|
);
|
|
8191
8529
|
}
|
|
8192
8530
|
function ChangesTabBody({
|
|
8531
|
+
comparison,
|
|
8532
|
+
onComparisonChange,
|
|
8533
|
+
...props
|
|
8534
|
+
}) {
|
|
8535
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
8536
|
+
/* @__PURE__ */ jsx13("div", { className: "flex shrink-0 items-center gap-1 border-b border-og-border bg-og-surface-1 px-2 py-1.5", children: [
|
|
8537
|
+
["branch", "Branch"],
|
|
8538
|
+
["working", "Uncommitted"],
|
|
8539
|
+
["staged", "Staged"]
|
|
8540
|
+
].map(([value, label]) => /* @__PURE__ */ jsx13(
|
|
8541
|
+
"button",
|
|
8542
|
+
{
|
|
8543
|
+
type: "button",
|
|
8544
|
+
"aria-pressed": comparison === value,
|
|
8545
|
+
onClick: () => onComparisonChange(value),
|
|
8546
|
+
className: cn(
|
|
8547
|
+
"rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11",
|
|
8548
|
+
comparison === value ? "bg-og-surface-2 text-og-fg shadow-sm" : "text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg"
|
|
8549
|
+
),
|
|
8550
|
+
children: label
|
|
8551
|
+
},
|
|
8552
|
+
value
|
|
8553
|
+
)) }),
|
|
8554
|
+
/* @__PURE__ */ jsx13("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx13(ChangesTabContent, { comparison, ...props }) })
|
|
8555
|
+
] });
|
|
8556
|
+
}
|
|
8557
|
+
function ChangesTabContent({
|
|
8193
8558
|
git,
|
|
8559
|
+
comparison,
|
|
8194
8560
|
captureAvailable,
|
|
8195
8561
|
captureRevision,
|
|
8196
8562
|
capturePending,
|
|
@@ -8221,7 +8587,7 @@ function ChangesTabBody({
|
|
|
8221
8587
|
type: "button",
|
|
8222
8588
|
onClick: () => void git.refresh(),
|
|
8223
8589
|
disabled: git.loading,
|
|
8224
|
-
className: "inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-
|
|
8590
|
+
className: "inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11",
|
|
8225
8591
|
children: [
|
|
8226
8592
|
/* @__PURE__ */ jsx13(
|
|
8227
8593
|
RefreshCwIcon2,
|
|
@@ -8277,7 +8643,7 @@ function ChangesTabBody({
|
|
|
8277
8643
|
}
|
|
8278
8644
|
);
|
|
8279
8645
|
}
|
|
8280
|
-
if (!liveWorkspaceExpected && !captureAvailable) {
|
|
8646
|
+
if (!liveWorkspaceExpected && (comparison !== "working" || !captureAvailable)) {
|
|
8281
8647
|
return /* @__PURE__ */ jsxs11(
|
|
8282
8648
|
CenteredState,
|
|
8283
8649
|
{
|
|
@@ -8290,7 +8656,7 @@ function ChangesTabBody({
|
|
|
8290
8656
|
) : /* @__PURE__ */ jsx13(CpuIcon, { className: "size-5", "aria-hidden": true }),
|
|
8291
8657
|
children: [
|
|
8292
8658
|
/* @__PURE__ */ jsx13("p", { className: "text-og-sm font-medium text-og-fg", children: workspaceWaking ? "Waking workspace" : "Workspace is resting" }),
|
|
8293
|
-
/* @__PURE__ */ jsx13("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: workspaceWaking ? "Connecting to the live working tree\u2026" : "No captured revision is available yet. Wake the sandbox to inspect
|
|
8659
|
+
/* @__PURE__ */ jsx13("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: workspaceWaking ? "Connecting to the live working tree\u2026" : comparison === "branch" ? "Wake the sandbox to compare this branch with the remote default branch." : comparison === "staged" ? "Wake the sandbox to inspect staged changes." : "No captured revision is available yet. Wake the sandbox to inspect uncommitted changes." }),
|
|
8294
8660
|
!workspaceWaking ? /* @__PURE__ */ jsxs11(DockActionButton, { onClick: onWake, children: [
|
|
8295
8661
|
/* @__PURE__ */ jsx13(CpuIcon, { className: "size-3" }),
|
|
8296
8662
|
"Open live workspace"
|
|
@@ -8318,8 +8684,8 @@ function ChangesTabBody({
|
|
|
8318
8684
|
);
|
|
8319
8685
|
}
|
|
8320
8686
|
return /* @__PURE__ */ jsxs11(CenteredState, { icon: /* @__PURE__ */ jsx13(CircleCheckIcon, { className: "size-5", "aria-hidden": true }), tone: "success", children: [
|
|
8321
|
-
/* @__PURE__ */ jsx13("p", { className: "text-og-sm font-medium text-og-fg", children: "
|
|
8322
|
-
/* @__PURE__ */ jsx13("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: "
|
|
8687
|
+
/* @__PURE__ */ jsx13("p", { className: "text-og-sm font-medium text-og-fg", children: comparison === "branch" ? "No branch changes" : comparison === "staged" ? "No staged changes" : "No uncommitted changes" }),
|
|
8688
|
+
/* @__PURE__ */ jsx13("p", { className: "text-og-sm leading-5 text-og-fg-subtle", children: comparison === "branch" ? "This branch matches the remote default branch." : comparison === "staged" ? "Stage files to review the next commit here." : "Local edits not yet committed will appear here." })
|
|
8323
8689
|
] });
|
|
8324
8690
|
}
|
|
8325
8691
|
function CenteredState({
|
|
@@ -8356,7 +8722,7 @@ function CenteredState({
|
|
|
8356
8722
|
// src/hooks/use-codex-accounts.ts
|
|
8357
8723
|
import { useCallback as useCallback23, useState as useState21 } from "react";
|
|
8358
8724
|
function isCodexAccountEvent(event) {
|
|
8359
|
-
return event.type === "codex.account.switched"
|
|
8725
|
+
return event.type === "codex.account.switched";
|
|
8360
8726
|
}
|
|
8361
8727
|
var EMPTY_SETTINGS = {
|
|
8362
8728
|
rotationEnabled: false,
|
|
@@ -8636,7 +9002,6 @@ export {
|
|
|
8636
9002
|
projectPendingHumanInputRequests,
|
|
8637
9003
|
projectPickerRows,
|
|
8638
9004
|
rawTypeOf,
|
|
8639
|
-
redactSecrets,
|
|
8640
9005
|
runnableLatencyModesForModel,
|
|
8641
9006
|
sandboxCommandExitCode,
|
|
8642
9007
|
sessionChromeGoalPillState,
|
|
@@ -8671,6 +9036,7 @@ export {
|
|
|
8671
9036
|
useOpenGeni,
|
|
8672
9037
|
useOpenGeniClient,
|
|
8673
9038
|
usePacks,
|
|
9039
|
+
usePageLiveActivity,
|
|
8674
9040
|
useRelayFrameStream,
|
|
8675
9041
|
useRig,
|
|
8676
9042
|
useRigChanges,
|