@opengeni/react 0.15.0 → 0.23.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 +110 -10
- package/dist/{chunk-TOJR776I.js → chunk-6XUS5VFM.js} +45 -369
- package/dist/chunk-6XUS5VFM.js.map +1 -0
- package/dist/chunk-CATATY77.js +2393 -0
- package/dist/chunk-CATATY77.js.map +1 -0
- package/dist/chunk-I3BJZIG5.js +439 -0
- package/dist/chunk-I3BJZIG5.js.map +1 -0
- package/dist/chunk-TK7G6XLT.js +18 -0
- package/dist/chunk-TK7G6XLT.js.map +1 -0
- package/dist/chunk-UAHPKLB6.js +2237 -0
- package/dist/chunk-UAHPKLB6.js.map +1 -0
- package/dist/chunk-UQS7OQDE.js +591 -0
- package/dist/chunk-UQS7OQDE.js.map +1 -0
- package/dist/chunk-YDNWMKXO.js +102 -0
- package/dist/chunk-YDNWMKXO.js.map +1 -0
- package/dist/composer-CVm5uoUI.d.ts +585 -0
- package/dist/composer.d.ts +6 -0
- package/dist/composer.js +56 -0
- package/dist/composer.js.map +1 -0
- package/dist/index.d.ts +1288 -1785
- package/dist/index.js +7140 -8817
- package/dist/index.js.map +1 -1
- package/dist/machines.d.ts +412 -3
- package/dist/machines.js +3 -1
- package/dist/noto-sans-arabic-loader-IA2T4X2A.js +21 -0
- package/dist/noto-sans-arabic-loader-IA2T4X2A.js.map +1 -0
- package/dist/noto-sans-jp-loader.generated-HFGLYBR3.js +292 -0
- package/dist/noto-sans-jp-loader.generated-HFGLYBR3.js.map +1 -0
- package/dist/queue-surface-implementation-3UW3MIIR.js +890 -0
- package/dist/queue-surface-implementation-3UW3MIIR.js.map +1 -0
- package/dist/session-Db00TRwl.d.ts +446 -0
- package/dist/session-context-rgrfElMl.d.ts +58 -0
- package/dist/session.d.ts +4 -0
- package/dist/session.js +54 -0
- package/dist/session.js.map +1 -0
- package/dist/use-composer-By1wn3MM.d.ts +99 -0
- package/package.json +20 -4
- package/src/approvals.ts +5 -3
- package/src/client.ts +44 -0
- package/src/components/approval-surface.tsx +198 -0
- package/src/components/chat-composer.tsx +94 -993
- package/src/components/code-editor.tsx +104 -26
- package/src/components/command-palette.tsx +8 -2
- package/src/components/composer-transcription-control.tsx +211 -0
- package/src/components/composer.tsx +1536 -0
- package/src/components/desktop-viewer.tsx +3 -3
- package/src/components/enrollment-consent.tsx +2 -2
- package/src/components/file-browser.tsx +367 -29
- package/src/components/human-input-form.tsx +417 -0
- package/src/components/machine-card.tsx +1 -1
- package/src/components/machines-dashboard.tsx +3 -3
- package/src/components/message-timeline.tsx +205 -25
- package/src/components/model-picker.tsx +12 -3
- package/src/components/pierre-diff.tsx +32 -6
- package/src/components/queue-draft-policy.ts +18 -0
- package/src/components/queue-surface-implementation.tsx +1037 -0
- package/src/components/queue-surface-state.tsx +94 -0
- package/src/components/queue-surface.tsx +42 -559
- package/src/components/sandbox-files.tsx +138 -14
- package/src/components/sandbox-terminal.tsx +8 -2
- package/src/components/sandbox-workspace.tsx +339 -119
- package/src/components/workbench-changes.tsx +84 -33
- package/src/components/workspace-dock.tsx +188 -18
- package/src/composer.ts +60 -0
- package/src/hooks/internal.ts +115 -34
- package/src/hooks/use-composer.ts +385 -104
- package/src/hooks/use-human-input.ts +131 -0
- package/src/hooks/use-machine-chip.ts +2 -2
- package/src/hooks/use-machines.ts +27 -11
- package/src/hooks/use-sandbox-files.ts +310 -62
- package/src/hooks/use-sandbox-git.ts +154 -40
- package/src/hooks/use-sandbox-terminal.ts +28 -6
- package/src/hooks/use-session-capabilities.ts +38 -9
- package/src/hooks/use-session-control.ts +37 -8
- package/src/hooks/use-session-events.ts +522 -48
- package/src/hooks/use-session-mcp-approval-policy.ts +161 -0
- package/src/hooks/use-slash-commands.ts +38 -38
- package/src/hooks/use-transcription.ts +757 -0
- package/src/hooks/use-turn-queue.ts +134 -66
- package/src/hooks/use-windowed-sections.ts +2 -2
- package/src/hooks/use-workspace-capture.ts +146 -40
- package/src/hooks/use-workspace-edit.ts +50 -14
- package/src/hooks/use-workspace-sessions.ts +3 -0
- package/src/human-input.ts +72 -0
- package/src/index.ts +85 -6
- package/src/lib/noto-sans-arabic-loader.ts +21 -0
- package/src/lib/noto-sans-jp-loader.generated.ts +295 -0
- package/src/lib/use-portal-token-style.ts +51 -0
- package/src/lib/use-unicode-fonts.ts +57 -0
- package/src/provider.tsx +4 -69
- package/src/session-context.ts +160 -0
- package/src/session.ts +89 -0
- package/src/timeline/parsers.ts +35 -0
- package/src/timeline/projection.ts +12 -4
- package/src/timeline/tool-renderers.tsx +41 -0
- package/src/timeline/turn-summary.tsx +2 -2
- package/src/timeline/types.ts +10 -9
- package/styles/index.css +56 -0
- package/styles/index.d.ts +2 -0
- package/styles/tokens.css +11 -6
- package/styles/tokens.d.ts +2 -0
- package/dist/chunk-TOJR776I.js.map +0 -1
- package/dist/machines-BpdwuQcD.d.ts +0 -449
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SessionEvent,
|
|
3
|
+
SessionMcpApprovalPolicy,
|
|
4
|
+
SessionMcpServerMetadata,
|
|
5
|
+
UpdateSessionMcpApprovalPolicyResponse,
|
|
6
|
+
} from "@opengeni/sdk";
|
|
7
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import {
|
|
9
|
+
useEmbeddedSessionMcpApprovalPolicy,
|
|
10
|
+
type EmbeddedSessionMcpApprovalPolicyClientOverride,
|
|
11
|
+
} from "../session-context";
|
|
12
|
+
import {
|
|
13
|
+
useDebouncedCallback,
|
|
14
|
+
useMutationRunner,
|
|
15
|
+
usePolledValue,
|
|
16
|
+
useSessionEventTrigger,
|
|
17
|
+
type SessionEventFeedOptions,
|
|
18
|
+
} from "./internal";
|
|
19
|
+
|
|
20
|
+
export function isSessionMcpApprovalPolicyEvent(
|
|
21
|
+
event: Pick<SessionEvent, "type" | "payload">,
|
|
22
|
+
serverId?: string,
|
|
23
|
+
): boolean {
|
|
24
|
+
if (event.type !== "session.mcp.approval_policy.updated") {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (serverId === undefined) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
const payload = event.payload as { serverId?: unknown } | null;
|
|
31
|
+
return payload?.serverId === serverId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type UseSessionMcpApprovalPolicyOptions = EmbeddedSessionMcpApprovalPolicyClientOverride &
|
|
35
|
+
SessionEventFeedOptions & {
|
|
36
|
+
/** Optional safety-net polling (ms). Off by default; policy events drive refreshes. */
|
|
37
|
+
pollIntervalMs?: number | undefined;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type UseSessionMcpApprovalPolicyResult = {
|
|
41
|
+
server: SessionMcpServerMetadata | null;
|
|
42
|
+
policy: SessionMcpApprovalPolicy | null;
|
|
43
|
+
loading: boolean;
|
|
44
|
+
error: Error | null;
|
|
45
|
+
refresh: () => Promise<void>;
|
|
46
|
+
update: (
|
|
47
|
+
policy: SessionMcpApprovalPolicy,
|
|
48
|
+
) => Promise<UpdateSessionMcpApprovalPolicyResponse | null>;
|
|
49
|
+
updating: boolean;
|
|
50
|
+
clearError: () => void;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Read and update one existing session MCP server's approval policy. Updates
|
|
55
|
+
* become effective for the next claimed attempt; current work is unchanged.
|
|
56
|
+
*/
|
|
57
|
+
export function useSessionMcpApprovalPolicy(
|
|
58
|
+
sessionId: string | null | undefined,
|
|
59
|
+
serverId: string | null | undefined,
|
|
60
|
+
options: UseSessionMcpApprovalPolicyOptions = {},
|
|
61
|
+
): UseSessionMcpApprovalPolicyResult {
|
|
62
|
+
const { client, workspaceId } = useEmbeddedSessionMcpApprovalPolicy(options);
|
|
63
|
+
const enabled = (options.enabled ?? true) && Boolean(sessionId && serverId);
|
|
64
|
+
const [override, setOverride] = useState<SessionMcpServerMetadata | null>(null);
|
|
65
|
+
const targetKey = `${workspaceId}\u0000${sessionId ?? ""}\u0000${serverId ?? ""}`;
|
|
66
|
+
const authoritativeGeneration = useRef(0);
|
|
67
|
+
const mutationIdentity = useMemo(() => ({ client, targetKey }), [client, targetKey]);
|
|
68
|
+
const { run, mutating, mutationError, clearMutationError } = useMutationRunner(mutationIdentity);
|
|
69
|
+
|
|
70
|
+
useLayoutEffect(() => {
|
|
71
|
+
authoritativeGeneration.current += 1;
|
|
72
|
+
setOverride(null);
|
|
73
|
+
}, [client, targetKey]);
|
|
74
|
+
|
|
75
|
+
type PolicyRead = {
|
|
76
|
+
targetKey: string;
|
|
77
|
+
generation: number;
|
|
78
|
+
server: SessionMcpServerMetadata | null;
|
|
79
|
+
};
|
|
80
|
+
const load = useCallback(async (): Promise<PolicyRead> => {
|
|
81
|
+
const generation = authoritativeGeneration.current;
|
|
82
|
+
if (!sessionId || !serverId) {
|
|
83
|
+
return { targetKey, generation, server: null };
|
|
84
|
+
}
|
|
85
|
+
const session = await client.getSession(workspaceId, sessionId);
|
|
86
|
+
return {
|
|
87
|
+
targetKey,
|
|
88
|
+
generation,
|
|
89
|
+
server: session.mcpServers.find((server) => server.id === serverId) ?? null,
|
|
90
|
+
};
|
|
91
|
+
}, [client, serverId, sessionId, targetKey, workspaceId]);
|
|
92
|
+
const {
|
|
93
|
+
data,
|
|
94
|
+
loading,
|
|
95
|
+
error: loadError,
|
|
96
|
+
refresh,
|
|
97
|
+
} = usePolledValue(load, {
|
|
98
|
+
enabled,
|
|
99
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
100
|
+
});
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (data?.targetKey === targetKey && data.generation === authoritativeGeneration.current) {
|
|
103
|
+
setOverride(null);
|
|
104
|
+
}
|
|
105
|
+
}, [data, targetKey]);
|
|
106
|
+
|
|
107
|
+
const scheduleRefresh = useDebouncedCallback(() => void refresh());
|
|
108
|
+
const matchesPolicyEvent = useCallback(
|
|
109
|
+
(event: Pick<SessionEvent, "type" | "payload">) =>
|
|
110
|
+
isSessionMcpApprovalPolicyEvent(event, serverId ?? undefined),
|
|
111
|
+
[serverId],
|
|
112
|
+
);
|
|
113
|
+
useSessionEventTrigger(
|
|
114
|
+
client,
|
|
115
|
+
workspaceId,
|
|
116
|
+
sessionId,
|
|
117
|
+
matchesPolicyEvent,
|
|
118
|
+
scheduleRefresh,
|
|
119
|
+
{
|
|
120
|
+
enabled,
|
|
121
|
+
...(options.events !== undefined ? { events: options.events } : {}),
|
|
122
|
+
},
|
|
123
|
+
async () => await refresh(),
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const update = useCallback(
|
|
127
|
+
async (
|
|
128
|
+
policy: SessionMcpApprovalPolicy,
|
|
129
|
+
): Promise<UpdateSessionMcpApprovalPolicyResponse | null> => {
|
|
130
|
+
if (!sessionId || !serverId) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const response = await run(() =>
|
|
134
|
+
client.updateSessionMcpApprovalPolicy(workspaceId, sessionId, serverId, {
|
|
135
|
+
requireApproval: policy,
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
138
|
+
if (response) {
|
|
139
|
+
authoritativeGeneration.current += 1;
|
|
140
|
+
setOverride(response.server);
|
|
141
|
+
void refresh();
|
|
142
|
+
}
|
|
143
|
+
return response;
|
|
144
|
+
},
|
|
145
|
+
[client, refresh, run, serverId, sessionId, workspaceId],
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const server = override ?? data?.server ?? null;
|
|
149
|
+
return {
|
|
150
|
+
server,
|
|
151
|
+
policy: server?.requireApproval ?? null,
|
|
152
|
+
loading,
|
|
153
|
+
error: mutationError ?? loadError,
|
|
154
|
+
refresh: async () => {
|
|
155
|
+
await refresh();
|
|
156
|
+
},
|
|
157
|
+
update,
|
|
158
|
+
updating: mutating,
|
|
159
|
+
clearError: clearMutationError,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
@@ -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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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": {
|