@robota-sdk/agent-ui-web 3.2.1 → 3.3.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/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { isObserverMessageType } from "@robota-sdk/agent-transport";
1
2
  import React, { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
2
3
  import { decodeFrame, decodeServerMessage } from "@robota-sdk/agent-transport/client";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -306,6 +307,7 @@ const SERVER_MESSAGE_HANDLING = {
306
307
  background_task_control_result: "visible-notice",
307
308
  protocol_error: "visible-notice",
308
309
  resume_gap: "transport-control",
310
+ surface_role: "reducer-state",
309
311
  settings: "reducer-state",
310
312
  settings_error: "reducer-state"
311
313
  };
@@ -400,6 +402,7 @@ function nextRequestId$6(prefix) {
400
402
  return `${prefix}_${requestCounter$6}_${Date.now()}`;
401
403
  }
402
404
  const CONNECTION_CLOSED = "The connection to the session closed.";
405
+ const READ_ONLY = "This session is read-only.";
403
406
  /**
404
407
  * The key a finished call's app view is read and called by, taken from the tool row's `appView`
405
408
  * reference; `undefined` when the row gives none. Everything outside this module treats it as an
@@ -431,7 +434,7 @@ function callAppToolMessage(requestId, viewKey, name, args) {
431
434
  * keeps its own entry. A reply that lost its connection never arrives: the owner of the connection
432
435
  * rejects every outstanding request when it drops, is replaced or goes away (`rejectPendingAppRequests`).
433
436
  */
434
- function useAppViewRequests(send, isConnected) {
437
+ function useAppViewRequests(send, isConnected, isObserving) {
435
438
  const pendingRef = useRef(/* @__PURE__ */ new Map());
436
439
  const [requestOwner] = useState(() => nextRequestId$6("app_request"));
437
440
  const rejectPendingAppRequests = useCallback((reason = CONNECTION_CLOSED) => {
@@ -447,6 +450,10 @@ function useAppViewRequests(send, isConnected) {
447
450
  reject(/* @__PURE__ */ new Error(signal?.aborted ? "The app view closed." : CONNECTION_CLOSED));
448
451
  return;
449
452
  }
453
+ if (isObserving()) {
454
+ reject(/* @__PURE__ */ new Error(READ_ONLY));
455
+ return;
456
+ }
450
457
  const requestId = nextRequestId$6(`${requestOwner}_${prefix}`);
451
458
  const dispose = () => signal?.removeEventListener("abort", abort);
452
459
  const abort = () => {
@@ -465,6 +472,7 @@ function useAppViewRequests(send, isConnected) {
465
472
  }
466
473
  }), [
467
474
  isConnected,
475
+ isObserving,
468
476
  requestOwner,
469
477
  send
470
478
  ]);
@@ -1017,7 +1025,7 @@ function initialSidebarOpen() {
1017
1025
  * on its primary one. After a reconnect to such a host this surface goes back to the session it was
1018
1026
  * on; an older host has one session for everyone, so there is nothing to go back to.
1019
1027
  */
1020
- function useSessionDirectoryState(send) {
1028
+ function useSessionDirectoryState(send, isObserving) {
1021
1029
  const { storage: { browserNamespace } } = useProductIdentity();
1022
1030
  const [sessionListing, setSessionListing] = useState(null);
1023
1031
  const [sessionsError, setSessionsError] = useState(null);
@@ -1068,6 +1076,7 @@ function useSessionDirectoryState(send) {
1068
1076
  if (target === null) return;
1069
1077
  clearStoredRestoreId(browserNamespace);
1070
1078
  if (target === listing.currentSessionId) return;
1079
+ if (isObserving()) return;
1071
1080
  if (!keepsSessionsLive(listing)) return;
1072
1081
  if (!listing.sessions.some((row) => row.id === target)) return;
1073
1082
  send({
@@ -1075,7 +1084,11 @@ function useSessionDirectoryState(send) {
1075
1084
  sessionId: target,
1076
1085
  requestId: nextRequestId$1("session_change")
1077
1086
  });
1078
- }, [send, browserNamespace]);
1087
+ }, [
1088
+ send,
1089
+ browserNamespace,
1090
+ isObserving
1091
+ ]);
1079
1092
  return {
1080
1093
  sessionListing,
1081
1094
  sessionsError,
@@ -1370,6 +1383,9 @@ function buildConversationEntriesFromDisplaySegments(displaySegments) {
1370
1383
  function useSessionClient(makeClient) {
1371
1384
  const [status, setStatus] = useState("disconnected");
1372
1385
  const statusRef = useRef("disconnected");
1386
+ const [role, setRole] = useState(null);
1387
+ const roleRef = useRef(null);
1388
+ const isObserving = useCallback(() => roleRef.current === "observe", []);
1373
1389
  const [messages, setMessages] = useState([]);
1374
1390
  const [activeTools, setActiveTools] = useState([]);
1375
1391
  const [streamingText, setStreamingText] = useState("");
@@ -1437,8 +1453,9 @@ function useSessionClient(makeClient) {
1437
1453
  const [executionDetailInput, setExecutionDetailInput] = useState();
1438
1454
  const executionDetailInputRef = useRef(null);
1439
1455
  const send = useCallback((msg) => {
1456
+ const refused = isObserving() && !isObserverMessageType(msg.type);
1440
1457
  if (msg.type === "send-background-task") {
1441
- if (executionDetailInputRef.current !== null) return;
1458
+ if (refused || executionDetailInputRef.current !== null) return;
1442
1459
  executionDetailInputRef.current = msg.taskId;
1443
1460
  setExecutionDetailInput({
1444
1461
  taskId: msg.taskId,
@@ -1461,14 +1478,16 @@ function useSessionClient(makeClient) {
1461
1478
  });
1462
1479
  return;
1463
1480
  }
1481
+ if (refused) return;
1464
1482
  commandsInFlightRef.current += 1;
1465
1483
  }
1484
+ if (refused) return;
1466
1485
  if (msg.type === "switch-session" || msg.type === "new-session") {
1467
1486
  sessionChangesInFlightRef.current += 1;
1468
1487
  if (msg.requestId !== void 0) sessionChangeRequestIdsRef.current.add(msg.requestId);
1469
1488
  }
1470
1489
  clientRef.current?.send(msg);
1471
- }, [appendEntry]);
1490
+ }, [appendEntry, isObserving]);
1472
1491
  /** One session change this surface asked for has been answered. */
1473
1492
  const settleSessionChange = useCallback((requestId) => {
1474
1493
  sessionChangesInFlightRef.current = Math.max(0, sessionChangesInFlightRef.current - 1);
@@ -1504,8 +1523,8 @@ function useSessionClient(makeClient) {
1504
1523
  const { handleExecutionDetailMessage, handleExecutionWorkspace, closeExecutionDetail, ...executionDetailState } = useExecutionDetailState(send);
1505
1524
  const { handleModelListMessage, ...modelListState } = useModelListState(send);
1506
1525
  const { handleProjectMessage, ...projectPanelState } = useProjectPanelState(send);
1507
- const { handleAppViewMessage, rejectPendingAppRequests, readAppView, callAppTool } = useAppViewRequests(send, useCallback(() => statusRef.current === "connected", []));
1508
- const { handleSessionsMessage, canListSessions, markCurrent, armRestore, ...sessionDirectoryState } = useSessionDirectoryState(send);
1526
+ const { handleAppViewMessage, rejectPendingAppRequests, readAppView, callAppTool } = useAppViewRequests(send, useCallback(() => statusRef.current === "connected", []), isObserving);
1527
+ const { handleSessionsMessage, canListSessions, markCurrent, armRestore, ...sessionDirectoryState } = useSessionDirectoryState(send, isObserving);
1509
1528
  const { requestSessions, setSessionSidebarOpen } = sessionDirectoryState;
1510
1529
  const { handleSettingsMessage, openSettings, refreshSettings, ...settingsState } = useSettingsState(send);
1511
1530
  const settingsOpenRef = useRef(false);
@@ -1527,6 +1546,10 @@ function useSessionClient(makeClient) {
1527
1546
  if (handleAgentDefinitionsMessage(msg)) return;
1528
1547
  if (handleSchedulesMessage(msg)) return;
1529
1548
  switch (msg.type) {
1549
+ case "surface_role":
1550
+ roleRef.current = msg.role;
1551
+ setRole(msg.role);
1552
+ break;
1530
1553
  case "messages": {
1531
1554
  const reconstructed = msg.display ? buildConversationEntriesFromDisplaySegments(msg.display) : msg.messages.flatMap((m) => {
1532
1555
  if (m.role !== "user" && m.role !== "assistant") return [];
@@ -1898,6 +1921,10 @@ function useSessionClient(makeClient) {
1898
1921
  const onStatusChange = (next) => {
1899
1922
  statusRef.current = next;
1900
1923
  setStatus(next);
1924
+ if (next !== "connected") {
1925
+ roleRef.current = null;
1926
+ setRole(null);
1927
+ }
1901
1928
  if (next !== "connected") {
1902
1929
  rejectPendingAppRequests();
1903
1930
  clearCompactionNotices();
@@ -1916,6 +1943,7 @@ function useSessionClient(makeClient) {
1916
1943
  sessionChangesInFlightRef.current = 0;
1917
1944
  sessionChangeRequestIdsRef.current.clear();
1918
1945
  pendingIntentRef.current = null;
1946
+ client.send({ type: "get-surface-role" });
1919
1947
  client.send({ type: "get-commands" });
1920
1948
  client.send({ type: "get-status" });
1921
1949
  client.send({ type: "get-pending" });
@@ -1924,10 +1952,18 @@ function useSessionClient(makeClient) {
1924
1952
  requestSchedules();
1925
1953
  }
1926
1954
  };
1927
- const client = makeClient({
1955
+ const inner = makeClient({
1928
1956
  onMessage: handleMessage,
1929
1957
  onStatusChange
1930
1958
  });
1959
+ const client = {
1960
+ connect: () => inner.connect(),
1961
+ disconnect: () => inner.disconnect(),
1962
+ send: (msg) => {
1963
+ if (roleRef.current === "observe" && !isObserverMessageType(msg.type)) return;
1964
+ inner.send(msg);
1965
+ }
1966
+ };
1931
1967
  clientRef.current = client;
1932
1968
  client.connect();
1933
1969
  return () => {
@@ -1956,6 +1992,7 @@ function useSessionClient(makeClient) {
1956
1992
  commandCatalog,
1957
1993
  sessionStatus,
1958
1994
  ownDriverId,
1995
+ role,
1959
1996
  send,
1960
1997
  sendCommandSilently,
1961
1998
  pendingPrompts,
@@ -3569,7 +3606,7 @@ function AgentActivityPanel({ tasks, schedules = [], goal = null, onPauseSchedul
3569
3606
  task,
3570
3607
  onPause: onPauseSchedule,
3571
3608
  onResume: onResumeSchedule,
3572
- onRequestDelete: () => setPendingDeleteId(task.id)
3609
+ onRequestDelete: onDeleteSchedule ? () => setPendingDeleteId(task.id) : void 0
3573
3610
  }, task.id))
3574
3611
  })] }),
3575
3612
  goal && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
@@ -3670,33 +3707,33 @@ function ScheduleCard({ task, onPause, onResume, onRequestDelete }) {
3670
3707
  describeScheduleStatus(task)
3671
3708
  ]
3672
3709
  }),
3673
- /* @__PURE__ */ jsxs("div", {
3710
+ onResume || onPause || onRequestDelete ? /* @__PURE__ */ jsxs("div", {
3674
3711
  className: "mt-2 flex items-center gap-3",
3675
- children: [isPaused ? /* @__PURE__ */ jsxs("button", {
3712
+ children: [isPaused ? onResume && /* @__PURE__ */ jsxs("button", {
3676
3713
  type: "button",
3677
- onClick: () => onResume?.(task.id),
3714
+ onClick: () => onResume(task.id),
3678
3715
  className: "flex items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] text-muted-foreground hover:bg-hover hover:text-foreground",
3679
3716
  children: [/* @__PURE__ */ jsx(Play, {
3680
3717
  size: 11,
3681
3718
  fill: "currentColor",
3682
3719
  "aria-hidden": "true"
3683
3720
  }), "Resume"]
3684
- }) : /* @__PURE__ */ jsxs("button", {
3721
+ }) : onPause && /* @__PURE__ */ jsxs("button", {
3685
3722
  type: "button",
3686
- onClick: () => onPause?.(task.id),
3723
+ onClick: () => onPause(task.id),
3687
3724
  className: "flex items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] text-muted-foreground hover:bg-hover hover:text-foreground",
3688
3725
  children: [/* @__PURE__ */ jsx(Pause, {
3689
3726
  size: 11,
3690
3727
  fill: "currentColor",
3691
3728
  "aria-hidden": "true"
3692
3729
  }), "Pause"]
3693
- }), /* @__PURE__ */ jsx("button", {
3730
+ }), onRequestDelete && /* @__PURE__ */ jsx("button", {
3694
3731
  type: "button",
3695
3732
  onClick: onRequestDelete,
3696
3733
  className: "flex items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] text-destructive hover:bg-destructive/10",
3697
3734
  children: "Delete…"
3698
3735
  })]
3699
- })
3736
+ }) : null
3700
3737
  ]
3701
3738
  });
3702
3739
  }
@@ -3720,7 +3757,7 @@ function GoalCard({ goal, onCancel }) {
3720
3757
  className: "mt-1.5 pl-[26px] text-[13px] text-muted-foreground",
3721
3758
  children: describeGoalStatus(goal)
3722
3759
  }),
3723
- goal.status === "active" && /* @__PURE__ */ jsx("div", {
3760
+ goal.status === "active" && onCancel && /* @__PURE__ */ jsx("div", {
3724
3761
  className: "mt-2 pl-[26px]",
3725
3762
  children: /* @__PURE__ */ jsxs("button", {
3726
3763
  type: "button",
@@ -6516,7 +6553,7 @@ function GoalBar({ status, onStop }) {
6516
6553
  goal.maxIterations
6517
6554
  ]
6518
6555
  }),
6519
- /* @__PURE__ */ jsxs("button", {
6556
+ onStop && /* @__PURE__ */ jsxs("button", {
6520
6557
  type: "button",
6521
6558
  "aria-label": "Stop goal",
6522
6559
  onClick: onStop,
@@ -8421,7 +8458,8 @@ function SetupPanel({ onSetUp, disabled }) {
8421
8458
  * The full desktop layout over an `IWsSessionState`. `surface` is an optional label shown next to the
8422
8459
  * mark (e.g. "app").
8423
8460
  */
8424
- function SessionSurface({ state, surface, personalUsageEnabled = false, draftMode = "persistent", onReconnect, pickFiles, getPathForFile, onOpenMemoryInEditor, appViewSandboxUrl }) {
8461
+ function SessionSurface({ state, surface, personalUsageEnabled: personalUsageRequested = false, draftMode = "persistent", onReconnect, pickFiles, getPathForFile, onOpenMemoryInEditor, appViewSandboxUrl }) {
8462
+ const readOnly = state.role === "observe";
8425
8463
  const [view, setView] = useState("chat");
8426
8464
  const { identity } = useProductIdentity();
8427
8465
  const appViewHost = useMemo(() => ({
@@ -8440,6 +8478,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8440
8478
  identity.displayName,
8441
8479
  surface
8442
8480
  ]);
8481
+ const personalUsageEnabled = personalUsageRequested && !readOnly;
8443
8482
  const composerRef = useRef(null);
8444
8483
  const tasks = state.executionWorkspace?.entries ?? [];
8445
8484
  const hasTasks = tasks.some((entry) => entry.kind !== "main_thread");
@@ -8459,7 +8498,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8459
8498
  const hasWorkInProgress = hasTasks || state.scheduledTasks.length > 0 || currentGoal !== null;
8460
8499
  const isEmpty = state.messages.length === 0 && !state.streamingText && !state.isThinking && state.activeTools.length === 0;
8461
8500
  const setupRequired = state.sessionStatus?.setupRequired === true;
8462
- const hasSessionList = (state.sessionListing ?? null) !== null || state.sessionsError?.code === "list_failed";
8501
+ const hasSessionList = !readOnly && ((state.sessionListing ?? null) !== null || state.sessionsError?.code === "list_failed");
8463
8502
  const sidebarOpen = hasSessionList && state.sessionSidebarOpen;
8464
8503
  const usage = personalUsageEnabled && view === "usage";
8465
8504
  const project = view === "project";
@@ -8529,7 +8568,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8529
8568
  connectionLost: state.connectionLost ?? false
8530
8569
  }), usage ? /* @__PURE__ */ jsxs("div", {
8531
8570
  className: "min-h-0 flex-1",
8532
- children: [/* @__PURE__ */ jsx(PersonalUsageDashboard, { state }), /* @__PURE__ */ jsx(PermissionPrompt, {
8571
+ children: [/* @__PURE__ */ jsx(PersonalUsageDashboard, { state }), readOnly ? null : /* @__PURE__ */ jsx(PermissionPrompt, {
8533
8572
  layout: "modal",
8534
8573
  prompts: state.pendingPrompts,
8535
8574
  onAnswerPermission: state.answerPermission,
@@ -8541,7 +8580,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8541
8580
  children: [/* @__PURE__ */ jsx(ProjectPanel, {
8542
8581
  state,
8543
8582
  onOpenMemoryInEditor
8544
- }), /* @__PURE__ */ jsx(PermissionPrompt, {
8583
+ }), readOnly ? null : /* @__PURE__ */ jsx(PermissionPrompt, {
8545
8584
  layout: "modal",
8546
8585
  prompts: state.pendingPrompts,
8547
8586
  onAnswerPermission: state.answerPermission,
@@ -8561,7 +8600,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8561
8600
  }),
8562
8601
  /* @__PURE__ */ jsx("div", {
8563
8602
  className: "min-h-0 flex-1 overflow-hidden",
8564
- children: setupRequired ? /* @__PURE__ */ jsx(SetupPanel, {
8603
+ children: setupRequired && !readOnly ? /* @__PURE__ */ jsx(SetupPanel, {
8565
8604
  onSetUp: () => state.send({
8566
8605
  type: "command",
8567
8606
  name: "provider",
@@ -8569,7 +8608,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8569
8608
  }),
8570
8609
  disabled: state.status !== "connected"
8571
8610
  }) : isEmpty ? /* @__PURE__ */ jsx(EmptyState, {}) : /* @__PURE__ */ jsx(AppViewHostContext.Provider, {
8572
- value: appViewHost,
8611
+ value: readOnly ? null : appViewHost,
8573
8612
  children: /* @__PURE__ */ jsx(ConversationView, {
8574
8613
  messages: state.messages,
8575
8614
  activeTools: state.activeTools,
@@ -8584,13 +8623,13 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8584
8623
  children: [
8585
8624
  /* @__PURE__ */ jsx(GoalBar, {
8586
8625
  status: state.sessionStatus ?? null,
8587
- onStop: () => state.send({
8626
+ onStop: readOnly ? void 0 : () => state.send({
8588
8627
  type: "command",
8589
8628
  name: "goal",
8590
8629
  args: "cancel"
8591
8630
  })
8592
8631
  }),
8593
- /* @__PURE__ */ jsx(PermissionPrompt, {
8632
+ readOnly ? null : /* @__PURE__ */ jsx(PermissionPrompt, {
8594
8633
  layout: "dock",
8595
8634
  prompts: state.pendingPrompts,
8596
8635
  onAnswerPermission: state.answerPermission,
@@ -8598,7 +8637,11 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8598
8637
  ownDriverId: state.ownDriverId,
8599
8638
  onFocusReturn: () => composerRef.current?.focus()
8600
8639
  }),
8601
- setupRequired ? null : /* @__PURE__ */ jsx(Composer, {
8640
+ readOnly ? /* @__PURE__ */ jsx("p", {
8641
+ role: "status",
8642
+ className: "rounded-2xl bg-card px-4 py-3 text-center text-[14px] text-muted-foreground",
8643
+ children: "Read-only: you are watching this session."
8644
+ }) : setupRequired ? null : /* @__PURE__ */ jsx(Composer, {
8602
8645
  ref: composerRef,
8603
8646
  draftMode,
8604
8647
  catalog: state.commandCatalog ?? null,
@@ -8653,13 +8696,13 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8653
8696
  selectedEntryId: state.openEntryId ?? void 0,
8654
8697
  onSelect: (entry) => state.openExecutionDetail(entry.id),
8655
8698
  onReturnToConversation: () => state.closeExecutionDetail(),
8656
- onStop: stopExecutionEntry,
8699
+ onStop: readOnly ? void 0 : stopExecutionEntry,
8657
8700
  schedules: state.scheduledTasks,
8658
8701
  goal: currentGoal,
8659
- onPauseSchedule: state.pauseSchedule,
8660
- onResumeSchedule: state.resumeSchedule,
8661
- onDeleteSchedule: state.deleteSchedule,
8662
- onCancelGoal: () => state.send({
8702
+ onPauseSchedule: readOnly ? void 0 : state.pauseSchedule,
8703
+ onResumeSchedule: readOnly ? void 0 : state.resumeSchedule,
8704
+ onDeleteSchedule: readOnly ? void 0 : state.deleteSchedule,
8705
+ onCancelGoal: readOnly ? void 0 : () => state.send({
8663
8706
  type: "command",
8664
8707
  name: "goal",
8665
8708
  args: "cancel"
@@ -8674,18 +8717,18 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8674
8717
  complete: state.executionDetailComplete,
8675
8718
  onClose: () => state.closeExecutionDetail(),
8676
8719
  onLoadMore: () => state.loadMoreExecutionDetail(),
8677
- onStop: openEntry ? () => stopExecutionEntry(openEntry) : void 0,
8720
+ onStop: openEntry && !readOnly ? () => stopExecutionEntry(openEntry) : void 0,
8678
8721
  inputState: state.executionDetailInput,
8679
8722
  mode: state.executionDetailMode,
8680
8723
  unreadable: state.executionDetailUnreadable,
8681
8724
  onShowEarlier: state.showEarlierExecutionDetail,
8682
8725
  onShowLive: state.showLiveExecutionDetail,
8683
- onSend: openEntry ? (prompt) => state.send({
8726
+ onSend: openEntry && !readOnly ? (prompt) => state.send({
8684
8727
  type: "send-background-task",
8685
8728
  taskId: openEntry.sourceId,
8686
8729
  input: { prompt }
8687
8730
  }) : void 0,
8688
- onContinue: openEntry?.resumeSessionId ? () => {
8731
+ onContinue: openEntry?.resumeSessionId && !readOnly ? () => {
8689
8732
  if (openEntry.resumeSessionId) state.switchSession(openEntry.resumeSessionId);
8690
8733
  } : void 0
8691
8734
  })
@@ -8693,8 +8736,8 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
8693
8736
  })]
8694
8737
  }),
8695
8738
  /* @__PURE__ */ jsx(SessionNotices, { state }),
8696
- /* @__PURE__ */ jsx(SettingsScreen, { state }),
8697
- /* @__PURE__ */ jsx(AgentSwitcherSheet, { state }),
8739
+ readOnly ? null : /* @__PURE__ */ jsx(SettingsScreen, { state }),
8740
+ readOnly ? null : /* @__PURE__ */ jsx(AgentSwitcherSheet, { state }),
8698
8741
  /* @__PURE__ */ jsx(HelpSheet, {
8699
8742
  open: state.helpOpen,
8700
8743
  onClose: () => state.closeHelp(),