@opengeni/react 0.13.0 → 0.20.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.
Files changed (113) hide show
  1. package/README.md +129 -23
  2. package/dist/chunk-6BXBGJ3B.js +1956 -0
  3. package/dist/chunk-6BXBGJ3B.js.map +1 -0
  4. package/dist/chunk-6UT5OC3P.js +2133 -0
  5. package/dist/chunk-6UT5OC3P.js.map +1 -0
  6. package/dist/chunk-EBTT3MYN.js +92 -0
  7. package/dist/chunk-EBTT3MYN.js.map +1 -0
  8. package/dist/chunk-HHFA4AFX.js +425 -0
  9. package/dist/chunk-HHFA4AFX.js.map +1 -0
  10. package/dist/chunk-LAZ2A743.js +2393 -0
  11. package/dist/chunk-LAZ2A743.js.map +1 -0
  12. package/dist/chunk-MRSECXRP.js +563 -0
  13. package/dist/chunk-MRSECXRP.js.map +1 -0
  14. package/dist/chunk-TK7G6XLT.js +18 -0
  15. package/dist/chunk-TK7G6XLT.js.map +1 -0
  16. package/dist/composer-DvUaa5ki.d.ts +585 -0
  17. package/dist/composer.d.ts +6 -0
  18. package/dist/composer.js +56 -0
  19. package/dist/composer.js.map +1 -0
  20. package/dist/index.d.ts +642 -1080
  21. package/dist/index.js +7672 -8005
  22. package/dist/index.js.map +1 -1
  23. package/dist/machines.d.ts +412 -3
  24. package/dist/machines.js +25 -1
  25. package/dist/noto-sans-arabic-loader-IA2T4X2A.js +21 -0
  26. package/dist/noto-sans-arabic-loader-IA2T4X2A.js.map +1 -0
  27. package/dist/noto-sans-jp-loader.generated-HFGLYBR3.js +292 -0
  28. package/dist/noto-sans-jp-loader.generated-HFGLYBR3.js.map +1 -0
  29. package/dist/queue-surface-implementation-NQMV2ML3.js +890 -0
  30. package/dist/queue-surface-implementation-NQMV2ML3.js.map +1 -0
  31. package/dist/session-Gd4iVPYw.d.ts +425 -0
  32. package/dist/session-context-DIFFlXKc.d.ts +52 -0
  33. package/dist/session.d.ts +4 -0
  34. package/dist/session.js +50 -0
  35. package/dist/session.js.map +1 -0
  36. package/dist/use-composer-BCfm4mzX.d.ts +112 -0
  37. package/package.json +23 -4
  38. package/src/approvals.ts +5 -3
  39. package/src/client.ts +50 -1
  40. package/src/components/approval-surface.tsx +198 -0
  41. package/src/components/chat-composer.tsx +104 -751
  42. package/src/components/code-editor.tsx +104 -26
  43. package/src/components/command-palette.tsx +8 -2
  44. package/src/components/composer-transcription-control.tsx +211 -0
  45. package/src/components/composer.tsx +1536 -0
  46. package/src/components/desktop-viewer.tsx +3 -3
  47. package/src/components/enrollment-consent.tsx +2 -2
  48. package/src/components/file-browser.tsx +367 -29
  49. package/src/components/human-input-form.tsx +417 -0
  50. package/src/components/machine-card.tsx +82 -16
  51. package/src/components/machine-health-pill.tsx +68 -0
  52. package/src/components/machine-metrics.tsx +10 -24
  53. package/src/components/machines/health.ts +146 -0
  54. package/src/components/machines/machine-detail.tsx +220 -0
  55. package/src/components/machines/metric-history-chart.tsx +298 -0
  56. package/src/components/machines/metric-sparkline.tsx +76 -0
  57. package/src/components/machines/series.ts +113 -0
  58. package/src/components/machines-dashboard.tsx +16 -4
  59. package/src/components/message-timeline.tsx +15 -7
  60. package/src/components/model-picker.tsx +12 -3
  61. package/src/components/pierre-diff.tsx +32 -6
  62. package/src/components/queue-surface-implementation.tsx +1041 -0
  63. package/src/components/queue-surface-state.tsx +94 -0
  64. package/src/components/queue-surface.tsx +60 -0
  65. package/src/components/sandbox-files.tsx +230 -21
  66. package/src/components/sandbox-terminal.tsx +8 -2
  67. package/src/components/sandbox-workspace.tsx +489 -135
  68. package/src/components/session-status.tsx +0 -6
  69. package/src/components/workbench-changes.tsx +145 -50
  70. package/src/components/workspace-dock.tsx +329 -68
  71. package/src/composer.ts +60 -0
  72. package/src/hooks/internal.ts +115 -34
  73. package/src/hooks/use-composer.ts +635 -74
  74. package/src/hooks/use-human-input.ts +131 -0
  75. package/src/hooks/use-machine-chip.ts +2 -2
  76. package/src/hooks/use-machines.ts +27 -11
  77. package/src/hooks/use-sandbox-files.ts +310 -62
  78. package/src/hooks/use-sandbox-git.ts +154 -40
  79. package/src/hooks/use-sandbox-terminal.ts +28 -6
  80. package/src/hooks/use-session-capabilities.ts +38 -9
  81. package/src/hooks/use-session-control.ts +43 -15
  82. package/src/hooks/use-session-events.ts +523 -48
  83. package/src/hooks/use-session-lineage.ts +15 -6
  84. package/src/hooks/use-session.ts +10 -2
  85. package/src/hooks/use-slash-commands.ts +38 -38
  86. package/src/hooks/use-transcription.ts +757 -0
  87. package/src/hooks/use-turn-queue.ts +273 -77
  88. package/src/hooks/use-windowed-sections.ts +2 -2
  89. package/src/hooks/use-workspace-capture.ts +146 -40
  90. package/src/hooks/use-workspace-edit.ts +50 -14
  91. package/src/hooks/use-workspace-sessions.ts +3 -0
  92. package/src/human-input.ts +72 -0
  93. package/src/index.ts +88 -12
  94. package/src/lib/noto-sans-arabic-loader.ts +21 -0
  95. package/src/lib/noto-sans-jp-loader.generated.ts +295 -0
  96. package/src/lib/use-portal-token-style.ts +51 -0
  97. package/src/lib/use-unicode-fonts.ts +57 -0
  98. package/src/machines.ts +16 -0
  99. package/src/provider.tsx +163 -41
  100. package/src/session-context.ts +135 -0
  101. package/src/session.ts +79 -0
  102. package/src/timeline/parsers.ts +78 -6
  103. package/src/timeline/projection.ts +36 -6
  104. package/src/timeline/tool-renderers.tsx +41 -0
  105. package/src/timeline/turn-summary.tsx +2 -2
  106. package/src/timeline/types.ts +16 -8
  107. package/styles/index.css +78 -0
  108. package/styles/index.d.ts +2 -0
  109. package/styles/tokens.css +11 -6
  110. package/styles/tokens.d.ts +2 -0
  111. package/dist/chunk-NFYVQWIB.js +0 -1377
  112. package/dist/chunk-NFYVQWIB.js.map +0 -1
  113. package/dist/machines-CnlMb7E-.d.ts +0 -329
@@ -57,7 +57,8 @@ export function useSessionLineage(
57
57
  sessionId: string | null | undefined,
58
58
  options: UseSessionLineageOptions = {},
59
59
  ): UseSessionLineageResult {
60
- const { client, workspaceId } = useOpenGeni(options);
60
+ const { client, workspaceId, workspaceControlEvent, registerSessionReconciler } =
61
+ useOpenGeni(options);
61
62
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
62
63
  const load = useCallback(
63
64
  async () =>
@@ -67,7 +68,15 @@ export function useSessionLineage(
67
68
  [client, workspaceId, sessionId],
68
69
  );
69
70
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled });
70
- const refreshSoon = useDebouncedCallback(() => void state.refresh(), 150);
71
+ const refresh = state.refresh;
72
+ useEffect(() => {
73
+ if (enabled && workspaceControlEvent) void refresh();
74
+ }, [enabled, refresh, workspaceControlEvent]);
75
+ useEffect(() => {
76
+ if (!sessionId || !enabled) return;
77
+ return registerSessionReconciler(sessionId, "lineage", refresh);
78
+ }, [enabled, refresh, registerSessionReconciler, sessionId]);
79
+ const refreshSoon = useDebouncedCallback(() => void refresh(), 150);
71
80
  const delayedChildRefreshRef = useRef<ReturnType<typeof setTimeout> | null>(null);
72
81
  // Clear a pending delayed refresh on session/workspace SWITCH (not just
73
82
  // unmount): otherwise a timer scheduled for the previous session can fire
@@ -81,15 +90,15 @@ export function useSessionLineage(
81
90
  };
82
91
  }, [sessionId, workspaceId]);
83
92
  const refreshAfterChildCreate = useCallback(() => {
84
- void state.refresh();
93
+ void refresh();
85
94
  if (delayedChildRefreshRef.current !== null) {
86
95
  clearTimeout(delayedChildRefreshRef.current);
87
96
  }
88
97
  delayedChildRefreshRef.current = setTimeout(() => {
89
98
  delayedChildRefreshRef.current = null;
90
- void state.refresh();
99
+ void refresh();
91
100
  }, 2500);
92
- }, [state]);
101
+ }, [refresh]);
93
102
  useSessionEventTrigger(
94
103
  client,
95
104
  workspaceId,
@@ -114,6 +123,6 @@ export function useSessionLineage(
114
123
  lineage: state.data,
115
124
  loading: state.loading,
116
125
  error: state.error,
117
- refresh: state.refresh,
126
+ refresh,
118
127
  };
119
128
  }
@@ -1,5 +1,5 @@
1
1
  import type { Session, SessionEvent } from "@opengeni/sdk";
2
- import { useCallback, useState } from "react";
2
+ import { useCallback, useEffect, useState } from "react";
3
3
  import { useOpenGeni, type ClientOverride } from "../provider";
4
4
  import {
5
5
  useMutationRunner,
@@ -37,7 +37,8 @@ export function useSession(
37
37
  sessionId: string | null | undefined,
38
38
  options: UseSessionOptions = {},
39
39
  ): UseSessionResult {
40
- const { client, workspaceId } = useOpenGeni(options);
40
+ const { client, workspaceId, workspaceControlEvent, registerSessionReconciler } =
41
+ useOpenGeni(options);
41
42
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
42
43
  const [override, setOverride] = useState<Session | null>(null);
43
44
  const { run, mutating, mutationError, clearMutationError } = useMutationRunner();
@@ -54,6 +55,13 @@ export function useSession(
54
55
  pollIntervalMs: options.pollIntervalMs,
55
56
  enabled,
56
57
  });
58
+ useEffect(() => {
59
+ if (enabled && workspaceControlEvent) void refresh();
60
+ }, [enabled, refresh, workspaceControlEvent]);
61
+ useEffect(() => {
62
+ if (!sessionId || !enabled) return;
63
+ return registerSessionReconciler(sessionId, "session", refresh);
64
+ }, [enabled, refresh, registerSessionReconciler, sessionId]);
57
65
 
58
66
  const base = data ?? null;
59
67
  // The override only ever carries title/titleSource patches; it is reset on
@@ -194,6 +194,10 @@ export function useSlashCommands(options: UseSlashCommandsOptions): UseSlashComm
194
194
  }
195
195
  }, [items, clampedHighlight, autocomplete]);
196
196
 
197
+ // Pointer and keyboard activation share this synchronous fence. React state
198
+ // cannot disable a command row before a second same-tick activation arrives.
199
+ const runningRef = useRef(false);
200
+
197
201
  // Resolve a SPECIFIC, already-chosen command against the current draft, then
198
202
  // either autocomplete (name-only / required arg missing) or execute. This is
199
203
  // the shared core for both Enter (which first resolves WHICH command via the
@@ -201,39 +205,44 @@ export function useSlashCommands(options: UseSlashCommandsOptions): UseSlashComm
201
205
  // command — the clicked row — and must not re-resolve to a near-match).
202
206
  const runResolved = useCallback(
203
207
  async (command: SlashCommand, executionOptions?: { explicit?: boolean }): Promise<void> => {
204
- if (!parsed) {
205
- return;
206
- }
207
- const explicit = executionOptions?.explicit ?? false;
208
- // Token-vs-command equality is case-insensitive (matching the registry's
209
- // matchCommand/filterCommands), so a fully-typed "/Clear" counts as having
210
- // named `clear` and runs rather than autocompleting.
211
- const nameMatchesToken =
212
- command.name === parsed.name.toLowerCase() ||
213
- (command.aliases?.includes(parsed.name.toLowerCase()) ?? false);
214
- // A name-only token whose name doesn't yet equal the resolved command (e.g.
215
- // "/cl" -> clear) first autocompletes so the operator sees the full name.
216
- // An EXPLICIT pointer click skips this: the operator already chose the row,
217
- // so clicking "/clear-view" (while the token is "clear") runs it outright
218
- // rather than merely filling the name and waiting for a second Enter.
219
- if (!explicit && !activeCommand && !nameMatchesToken && !parsed.hasTrailingSpace) {
220
- autocomplete(command);
208
+ if (!parsed || runningRef.current) {
221
209
  return;
222
210
  }
223
- // When the click resolves a different command than the typed token, the
224
- // typed token's tail isn't this command's args — run with no positional
225
- // args and let the required-arg guard below prompt for them via autocomplete.
226
- const args = nameMatchesToken || parsed.hasTrailingSpace ? parsed.args : [];
227
- const missing = firstMissingRequiredArg(command, args);
228
- if (missing) {
229
- // A required arg is absent: keep the palette open at the arg hint rather
230
- // than firing a half-formed command.
231
- if (!parsed.hasTrailingSpace) {
211
+ runningRef.current = true;
212
+ try {
213
+ const explicit = executionOptions?.explicit ?? false;
214
+ // Token-vs-command equality is case-insensitive (matching the registry's
215
+ // matchCommand/filterCommands), so a fully-typed "/Clear" counts as having
216
+ // named `clear` and runs rather than autocompleting.
217
+ const nameMatchesToken =
218
+ command.name === parsed.name.toLowerCase() ||
219
+ (command.aliases?.includes(parsed.name.toLowerCase()) ?? false);
220
+ // A name-only token whose name doesn't yet equal the resolved command (e.g.
221
+ // "/cl" -> clear) first autocompletes so the operator sees the full name.
222
+ // An EXPLICIT pointer click skips this: the operator already chose the row,
223
+ // so clicking "/clear-view" (while the token is "clear") runs it outright
224
+ // rather than merely filling the name and waiting for a second Enter.
225
+ if (!explicit && !activeCommand && !nameMatchesToken && !parsed.hasTrailingSpace) {
232
226
  autocomplete(command);
227
+ return;
233
228
  }
234
- return;
229
+ // When the click resolves a different command than the typed token, the
230
+ // typed token's tail isn't this command's args — run with no positional
231
+ // args and let the required-arg guard below prompt for them via autocomplete.
232
+ const args = nameMatchesToken || parsed.hasTrailingSpace ? parsed.args : [];
233
+ const missing = firstMissingRequiredArg(command, args);
234
+ if (missing) {
235
+ // A required arg is absent: keep the palette open at the arg hint rather
236
+ // than firing a half-formed command.
237
+ if (!parsed.hasTrailingSpace) {
238
+ autocomplete(command);
239
+ }
240
+ return;
241
+ }
242
+ await execute(command, args);
243
+ } finally {
244
+ runningRef.current = false;
235
245
  }
236
- await execute(command, args);
237
246
  },
238
247
  [parsed, activeCommand, autocomplete, execute],
239
248
  );
@@ -286,9 +295,6 @@ export function useSlashCommands(options: UseSlashCommandsOptions): UseSlashComm
286
295
  [items, runResolved],
287
296
  );
288
297
 
289
- // Track an in-flight run so Enter can't double-fire.
290
- const runningRef = useRef(false);
291
-
292
298
  const onKeyDown = useCallback(
293
299
  (event: KeyboardEvent<HTMLTextAreaElement>): boolean => {
294
300
  if (!open) {
@@ -322,13 +328,7 @@ export function useSlashCommands(options: UseSlashCommandsOptions): UseSlashComm
322
328
  return false;
323
329
  }
324
330
  event.preventDefault();
325
- if (runningRef.current) {
326
- return true;
327
- }
328
- runningRef.current = true;
329
- void runHighlighted().finally(() => {
330
- runningRef.current = false;
331
- });
331
+ void runHighlighted();
332
332
  return true;
333
333
  }
334
334
  case "Escape": {