@opengeni/react 0.3.1 → 0.5.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 (42) hide show
  1. package/dist/index.d.ts +1055 -27
  2. package/dist/index.js +6993 -1954
  3. package/dist/index.js.map +1 -1
  4. package/package.json +65 -2
  5. package/src/client.ts +22 -0
  6. package/src/components/code-editor.tsx +398 -0
  7. package/src/components/desktop-viewer.tsx +647 -0
  8. package/src/components/diff-view.tsx +230 -0
  9. package/src/components/file-browser.tsx +838 -0
  10. package/src/components/fleet-tile.tsx +5 -0
  11. package/src/components/message-timeline.tsx +70 -196
  12. package/src/components/pierre-diff.tsx +140 -0
  13. package/src/components/pierre-file.tsx +142 -0
  14. package/src/components/sandbox-files.tsx +509 -0
  15. package/src/components/sandbox-terminal.tsx +425 -0
  16. package/src/components/workspace-dock.tsx +247 -0
  17. package/src/hooks/use-desktop-stream.ts +214 -0
  18. package/src/hooks/use-sandbox-files.ts +670 -0
  19. package/src/hooks/use-sandbox-git.ts +105 -0
  20. package/src/hooks/use-sandbox-terminal.ts +226 -0
  21. package/src/hooks/use-session-capabilities.ts +415 -0
  22. package/src/hooks/use-session.ts +80 -12
  23. package/src/hooks/use-terminal-stream.ts +207 -0
  24. package/src/index.ts +112 -3
  25. package/src/lib/cn.ts +20 -1
  26. package/src/lib/git-patch.ts +43 -0
  27. package/src/lib/use-theme-type.ts +40 -0
  28. package/src/lib/xterm-theme.ts +34 -0
  29. package/src/timeline/activity-rail.tsx +207 -0
  30. package/src/timeline/disclosure-context.tsx +34 -0
  31. package/src/timeline/index.ts +85 -0
  32. package/src/timeline/parsers.ts +253 -0
  33. package/src/{timeline.ts → timeline/projection.ts} +59 -134
  34. package/src/timeline/registry.ts +96 -0
  35. package/src/timeline/screenshot-lightbox.tsx +152 -0
  36. package/src/timeline/shared.tsx +481 -0
  37. package/src/timeline/tool-diff.tsx +91 -0
  38. package/src/timeline/tool-renderers.tsx +882 -0
  39. package/src/timeline/turn-summary.tsx +125 -0
  40. package/src/timeline/types.ts +131 -0
  41. package/src/types/external.d.ts +7 -0
  42. package/styles/index.css +72 -0
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { OpenGeniClient, Session, ResourceRef, ToolRef, SessionStatus as SessionStatus$1, SessionEvent, StreamConnectionState, SendMessageInput, FileAsset, FileResourceRef, SessionTurn, UpdateSessionTurnRequest, SessionGoal, ScheduledTask, WorkspaceEnvironment, CreateWorkspaceEnvironmentRequest, UpdateWorkspaceEnvironmentRequest, WorkspaceEnvironmentVariableMetadata, CapabilityPack, PackInstallation, RegisterCapabilityPackRequest, WorkspaceRegisteredPack, EnablePackRequest, Workspace, CreateWorkspaceRequest, UpdateWorkspaceRequest, BillingBalance, UsageEvent, ClientModel, Permission } from '@opengeni/sdk';
1
+ import { OpenGeniClient, SessionEvent, Session, ResourceRef, ToolRef, SessionStatus as SessionStatus$1, GitFileDiff, StreamConnectionState, SendMessageInput, FileAsset, FileResourceRef, SessionTurn, UpdateSessionTurnRequest, SessionGoal, ScheduledTask, WorkspaceEnvironment, CreateWorkspaceEnvironmentRequest, UpdateWorkspaceEnvironmentRequest, WorkspaceEnvironmentVariableMetadata, CapabilityPack, PackInstallation, RegisterCapabilityPackRequest, WorkspaceRegisteredPack, EnablePackRequest, Workspace, CreateWorkspaceRequest, UpdateWorkspaceRequest, BillingBalance, UsageEvent, ClientModel, SessionCapabilities, DesktopStreamCapability, DesktopRfbFactory, DesktopConnectionState, TerminalCapability, FsReadResponse, FsWriteResponse, Permission, CapabilityUnavailableReason } from '@opengeni/sdk';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import * as react from 'react';
4
- import { ReactNode, KeyboardEvent, ClipboardEvent } from 'react';
4
+ import { ReactNode, ComponentType, RefObject, KeyboardEvent, ClipboardEvent } from 'react';
5
5
  import { ClassValue } from 'clsx';
6
6
 
7
7
  /**
@@ -9,7 +9,7 @@ import { ClassValue } from 'clsx';
9
9
  * pass the real SDK client, a proxy-backed client that routes through their
10
10
  * own API, or a scripted client in tests/demos.
11
11
  */
12
- type SessionClientLike = Pick<OpenGeniClient, "getClientConfig" | "getSession" | "listSessions" | "sendMessage" | "steerMessage" | "interrupt" | "sendApprovalDecision" | "streamEvents" | "listTurns" | "updateQueuedTurn" | "reorderQueuedTurns" | "deleteQueuedTurn" | "getGoal" | "updateGoal" | "clearSessionContext" | "compactSessionContext" | "listScheduledTasks" | "uploadFile" | "getFile" | "createFileDownloadUrl" | "listEnvironments" | "createEnvironment" | "updateEnvironment" | "deleteEnvironment" | "setEnvironmentVariable" | "deleteEnvironmentVariable" | "listPacks" | "registerPack" | "enablePack" | "deletePack" | "listWorkspaces" | "createWorkspace" | "updateWorkspace" | "getBillingUsage">;
12
+ type SessionClientLike = Pick<OpenGeniClient, "getClientConfig" | "getSession" | "updateSession" | "listSessions" | "sendMessage" | "steerMessage" | "interrupt" | "sendApprovalDecision" | "streamEvents" | "listTurns" | "updateQueuedTurn" | "reorderQueuedTurns" | "deleteQueuedTurn" | "getGoal" | "updateGoal" | "clearSessionContext" | "compactSessionContext" | "listScheduledTasks" | "uploadFile" | "getFile" | "createFileDownloadUrl" | "listEnvironments" | "createEnvironment" | "updateEnvironment" | "deleteEnvironment" | "setEnvironmentVariable" | "deleteEnvironmentVariable" | "listPacks" | "registerPack" | "enablePack" | "deletePack" | "listWorkspaces" | "createWorkspace" | "updateWorkspace" | "getBillingUsage" | "getClientConfig" | "getStreamCapabilities" | "acknowledgeStream" | "attachViewer" | "heartbeatViewer" | "detachViewer" | "fsList" | "fsRead" | "fsWrite" | "fsDelete" | "fsMove" | "fsMkdir" | "gitStatus" | "gitDiff" | "terminalExec" | "terminalPtyOpen" | "terminalPtyWrite" | "terminalPtyResize" | "terminalPtyClose">;
13
13
 
14
14
  type OpenGeniContextValue = {
15
15
  client: SessionClientLike;
@@ -37,18 +37,35 @@ declare function useOpenGeni(override?: ClientOverride): OpenGeniContextValue;
37
37
  */
38
38
  declare function useOpenGeniClient(override?: Pick<ClientOverride, "client">): SessionClientLike;
39
39
 
40
- type UseSessionOptions = ClientOverride & {
40
+ type SessionEventFeedOptions = {
41
+ /**
42
+ * Share an existing event log (from `useSessionEvents`) instead of opening
43
+ * a second stream. When omitted the hook tails the session's event stream
44
+ * itself, starting at the current `lastSequence`.
45
+ */
46
+ events?: SessionEvent[] | undefined;
47
+ enabled?: boolean | undefined;
48
+ };
49
+
50
+ type UseSessionOptions = ClientOverride & SessionEventFeedOptions & {
41
51
  /** Re-fetch on an interval (ms). Off by default — pair with `useSessionEvents` for live status. */
42
52
  pollIntervalMs?: number | undefined;
43
- enabled?: boolean | undefined;
44
53
  };
45
54
  type UseSessionResult = {
46
55
  session: Session | null;
47
56
  loading: boolean;
48
57
  error: Error | null;
49
58
  refresh: () => Promise<void>;
59
+ /** Manually rename the session (PATCH, source='user'). Returns the updated session, or null on failure. */
60
+ updateTitle: (title: string) => Promise<Session | null>;
61
+ /** True while a rename is in flight. */
62
+ updating: boolean;
63
+ mutationError: Error | null;
64
+ clearMutationError: () => void;
50
65
  };
51
- /** Fetch one session (with optional polling). */
66
+ /** Event types that change the session title (auto + cross-client renames). */
67
+ declare function isTitleEvent(event: Pick<SessionEvent, "type">): boolean;
68
+ /** Fetch one session (with optional polling), live-patching its title on `session.title_set`. */
52
69
  declare function useSession(sessionId: string | null | undefined, options?: UseSessionOptions): UseSessionResult;
53
70
 
54
71
  type UserMessageItem = {
@@ -86,7 +103,15 @@ type ToolCallItem = {
86
103
  name: string;
87
104
  arguments: unknown;
88
105
  output: unknown;
89
- status: "running" | "complete";
106
+ /**
107
+ * The provider-native tool item (`agent.toolCall.created.payload.raw`). Carries
108
+ * `type` (e.g. `apply_patch_call`, `computer_call`, `hosted_tool_call`) and the
109
+ * tool-specific fields the per-tool renderers read (`operation`, `action`,
110
+ * `providerData`, …). `undefined` for first-party MCP tools, which carry their
111
+ * payload in `arguments`/`output` instead.
112
+ */
113
+ raw: unknown;
114
+ status: "running" | "complete" | "failed" | "cancelled";
90
115
  occurredAt: string;
91
116
  };
92
117
  /**
@@ -104,7 +129,7 @@ type WorkerItem = {
104
129
  prompt: string | null;
105
130
  /** The target/spawned worker session id, when parseable from args/output. */
106
131
  workerSessionId: string | null;
107
- status: "running" | "complete";
132
+ status: "running" | "complete" | "failed" | "cancelled";
108
133
  occurredAt: string;
109
134
  };
110
135
  type SandboxItem = {
@@ -114,7 +139,7 @@ type SandboxItem = {
114
139
  name: string;
115
140
  command: string | null;
116
141
  output: string;
117
- status: "running" | "complete" | "failed";
142
+ status: "running" | "complete" | "failed" | "cancelled";
118
143
  occurredAt: string;
119
144
  };
120
145
  type SessionStatusItem = {
@@ -138,17 +163,20 @@ type NoticeItem = {
138
163
  occurredAt: string;
139
164
  };
140
165
  type TimelineItem = UserMessageItem | AgentMessageItem | ReasoningItem | ToolCallItem | WorkerItem | SandboxItem | SessionStatusItem | GoalItem | NoticeItem;
141
- declare function buildTimeline(events: SessionEvent[]): TimelineItem[];
142
- /** The latest session status carried in the event log, if any. */
143
- declare function sessionStatusFromEvents(events: SessionEvent[]): SessionStatus$1 | null;
166
+ /** Activity items cluster between chat messages (reasoning, tools, workers, sandbox). */
167
+ type ActivityItem = ReasoningItem | ToolCallItem | WorkerItem | SandboxItem;
144
168
  type TimelineGroup = {
145
169
  kind: "item";
146
170
  item: TimelineItem;
147
171
  } | {
148
172
  kind: "activity";
149
173
  id: string;
150
- items: (ReasoningItem | ToolCallItem | WorkerItem | SandboxItem)[];
174
+ items: ActivityItem[];
151
175
  };
176
+
177
+ declare function buildTimeline(events: SessionEvent[]): TimelineItem[];
178
+ /** The latest session status carried in the event log, if any. */
179
+ declare function sessionStatusFromEvents(events: SessionEvent[]): SessionStatus$1 | null;
152
180
  declare function groupTimeline(items: TimelineItem[]): TimelineGroup[];
153
181
  /**
154
182
  * Find a session id in orchestration tool arguments or output. Handles raw
@@ -158,8 +186,308 @@ declare function groupTimeline(items: TimelineItem[]): TimelineGroup[];
158
186
  declare function extractSessionRef(value: unknown, depth?: number): string | null;
159
187
  /** Readable label for a tool call ("session_create" -> "session create"). */
160
188
  declare function toolDisplayName(name: string): string;
161
- /** Compact, single-line preview of tool arguments/outputs for collapsed rows. */
162
- declare function compactPayloadPreview(value: unknown, maxLength?: number): string;
189
+
190
+ type ToolRendererProps = {
191
+ item: ToolCallItem;
192
+ };
193
+ type ToolRenderer = ComponentType<ToolRendererProps>;
194
+ /** A registry entry: which key it matches and the component that renders it. */
195
+ type ToolRegistryEntry = {
196
+ match: "rawType";
197
+ type: string;
198
+ render: ToolRenderer;
199
+ } | {
200
+ match: "name";
201
+ name: string;
202
+ render: ToolRenderer;
203
+ };
204
+ type ToolRegistry = {
205
+ /** Resolve the renderer for a call (never null — falls back to generic). */
206
+ resolve: (item: ToolCallItem) => ToolRenderer;
207
+ /** The generic fallback renderer. */
208
+ fallback: ToolRenderer;
209
+ };
210
+ type CreateToolRegistryOptions = {
211
+ /**
212
+ * Entries that take precedence over the built-ins. Earlier entries win, so a
213
+ * consumer can shadow a default renderer for the same key.
214
+ */
215
+ entries?: ToolRegistryEntry[] | undefined;
216
+ /** Replace the generic fallback used for unmatched tools. */
217
+ fallback?: ToolRenderer | undefined;
218
+ };
219
+ /** The `raw.type` of a projected tool call, when the provider item carries one. */
220
+ declare function rawTypeOf(item: ToolCallItem): string | null;
221
+ /**
222
+ * Build a tool registry from a set of entries and a fallback. The returned
223
+ * registry resolves in priority order: `raw.type` entries first, then `name`
224
+ * entries, then the fallback. Consumer `entries` are consulted before the
225
+ * built-in `baseEntries`, so they shadow defaults cleanly.
226
+ */
227
+ declare function createToolRegistry(baseEntries: ToolRegistryEntry[], baseFallback: ToolRenderer, options?: CreateToolRegistryOptions): ToolRegistry;
228
+
229
+ /** The built-in tool renderer registry: every first-party tool plus a fallback. */
230
+ declare const defaultToolRegistry: ToolRegistry;
231
+ /** Build a registry that extends the built-ins with consumer entries/fallback. */
232
+ declare function createDefaultToolRegistry(options?: Parameters<typeof createToolRegistry>[2]): ToolRegistry;
233
+
234
+ type ActivityRailProps = {
235
+ items: ActivityItem[];
236
+ /** Renderer registry for tool calls. Defaults to {@link defaultToolRegistry}. */
237
+ toolRegistry?: ToolRegistry | undefined;
238
+ /** Drill into a spawned worker session. */
239
+ onOpenSession?: ((sessionId: string) => void) | undefined;
240
+ /** Drop the left rule + indent (used inside a folded turn summary). */
241
+ bare?: boolean | undefined;
242
+ className?: string | undefined;
243
+ };
244
+ declare function ActivityRail({ items, toolRegistry, onOpenSession, bare, className }: ActivityRailProps): react_jsx_runtime.JSX.Element;
245
+
246
+ /**
247
+ * A subtle settle signal — see the CHIP DOCTRINE above. The closed tone set.
248
+ * `"interrupted"` is a calm neutral tone for cancelled items — no dot, same
249
+ * quiet weight as `"muted"`, but semantically distinct from metadata.
250
+ */
251
+ type DisclosureChip = {
252
+ tone: "ok" | "bad" | "muted" | "interrupted";
253
+ text: string;
254
+ };
255
+ type ActivityDisclosureProps = {
256
+ icon: ReactNode;
257
+ /** Icon tint. Defaults to the muted foreground; renderers pass accent/failed. */
258
+ iconTone?: "accent" | "failed" | "running" | "muted" | undefined;
259
+ title: ReactNode;
260
+ /** Render the title in the mono face (commands, paths). */
261
+ titleMono?: boolean | undefined;
262
+ /** Shimmer the title while the tool is in-flight. */
263
+ running?: boolean | undefined;
264
+ /**
265
+ * Quiet single-line secondary text (truncated). It is detail-on-demand: hidden
266
+ * when a media preview is set, AND hidden once the row is expanded (the body
267
+ * then owns the detail), so a stat/path never appears twice at once.
268
+ */
269
+ preview?: ReactNode | undefined;
270
+ /** A small inline media preview (a screenshot thumbnail) shown in place of `preview`. */
271
+ media?: ReactNode | undefined;
272
+ /** At most one quiet settle chip, right-aligned to the gutter. */
273
+ chip?: DisclosureChip | undefined;
274
+ /**
275
+ * When true the row carries the standard failure affordance: the icon is tinted
276
+ * red and a "failed" bad-chip appears in the right gutter (unless an explicit
277
+ * `chip` is already supplied — the caller's chip wins). Output is still visible
278
+ * on expand; this is a quiet status signal, not a blocking banner.
279
+ *
280
+ * Renderers should pass `failed={item.status === "failed"}` on their settled
281
+ * (non-running) paths so any tool with a failed status shows a consistent
282
+ * affordance without each renderer having to duplicate the logic.
283
+ */
284
+ failed?: boolean | undefined;
285
+ /**
286
+ * When true the row carries a calm "interrupted" affordance: the icon stays
287
+ * muted (no red) and a quiet "interrupted" chip appears in the right gutter
288
+ * (unless an explicit `chip` is already supplied — the caller's chip wins).
289
+ * This is the cancelled-status analogue of `failed`, but deliberately calm
290
+ * and neutral — it is NOT an error; the user chose to stop.
291
+ *
292
+ * Renderers should pass `cancelled={item.status === "cancelled"}` so any
293
+ * in-flight item that was interrupted on turn.cancelled reads consistently.
294
+ * `cancelled` is ignored when `failed` is also true (failure takes precedence).
295
+ */
296
+ cancelled?: boolean | undefined;
297
+ /** When false the row is a static line (no expand affordance). */
298
+ expandable?: boolean | undefined;
299
+ children?: ReactNode | undefined;
300
+ };
301
+ /**
302
+ * The one disclosure row shape every activity row reuses (tool calls, reasoning,
303
+ * sandbox ops): a chevron, a tinted icon, a title, an optional muted preview or
304
+ * inline media, and at most one right-gutter settle chip. Compact by default;
305
+ * the body mounts only when expanded.
306
+ */
307
+ declare function ActivityDisclosure({ icon, iconTone: iconToneProp, title, titleMono, running, preview, media, chip: chipProp, failed, cancelled, expandable, children, }: ActivityDisclosureProps): react_jsx_runtime.JSX.Element;
308
+ declare function TermBlock({ command, workdir, output, live, tailLines, }: {
309
+ /**
310
+ * The command shown in the prompt header. Pass `null` when the row title
311
+ * already carries it (e.g. an exec row titled `$ cmd`): the header then drops
312
+ * the command — and the whole prompt line if there is no workdir either — so
313
+ * the command never reads twice, stacked, above the output.
314
+ */
315
+ command: string | null;
316
+ workdir?: string | null | undefined;
317
+ /** The FULL output. TermBlock owns the tail/full slicing internally. */
318
+ output: string;
319
+ live?: boolean | undefined;
320
+ /**
321
+ * When the output exceeds the tail window, only the last `tailLines` are shown
322
+ * with a "show full output" toggle. The component holds the full text, so the
323
+ * toggle reveals the rest (never a dead affordance). Defaults to 12.
324
+ */
325
+ tailLines?: number | undefined;
326
+ }): react_jsx_runtime.JSX.Element;
327
+ declare function PayloadBlock({ label, value, failed }: {
328
+ label: string;
329
+ value: unknown;
330
+ failed?: boolean | undefined;
331
+ }): react_jsx_runtime.JSX.Element | null;
332
+ /** A quiet inline note inside an expanded body (lost output, empty frame, …). */
333
+ declare function BodyNote({ children, tone }: {
334
+ children: ReactNode;
335
+ tone?: "error" | "muted" | undefined;
336
+ }): react_jsx_runtime.JSX.Element;
337
+ /**
338
+ * A loading screenshot placeholder. A faint camera glyph over a shimmering box,
339
+ * so a still frame of the running state reads unambiguously as "capturing" — not
340
+ * a broken thumbnail.
341
+ */
342
+ declare function MediaSkeleton(): react_jsx_runtime.JSX.Element;
343
+ /** A standardized "tool ran, produced no image" placeholder in the media slot. */
344
+ declare function MediaEmpty(): react_jsx_runtime.JSX.Element;
345
+ /**
346
+ * A small inline screenshot thumbnail that opens the app lightbox on click.
347
+ *
348
+ * Requires a `LightboxProvider` ancestor for the click-to-expand affordance.
349
+ * Outside one it degrades to a plain, non-interactive image — never a dead
350
+ * "Expand" button that announces an action it cannot perform.
351
+ */
352
+ declare function Thumbnail({ src, caption, alt }: {
353
+ src: string;
354
+ caption?: string | undefined;
355
+ alt?: string;
356
+ }): react_jsx_runtime.JSX.Element;
357
+ /**
358
+ * The expanded screenshot inside a tool body: a contained, clickable preview
359
+ * (opens the lightbox) with a quiet caption. Constrained height + object-contain
360
+ * so it never breaks the row layout. Like {@link Thumbnail}, it degrades to a
361
+ * plain image outside a `LightboxProvider`.
362
+ */
363
+ declare function ScreenshotFigure({ src, caption, alt }: {
364
+ src: string;
365
+ caption?: string | undefined;
366
+ alt?: string;
367
+ }): react_jsx_runtime.JSX.Element;
368
+
369
+ type LightboxController = {
370
+ open: (src: string, caption?: string) => void;
371
+ };
372
+ /** Open the app-level screenshot lightbox. No-op outside a `LightboxProvider`. */
373
+ declare function useLightbox(): LightboxController;
374
+ /**
375
+ * The lightbox controller when one is mounted, or `null` outside a
376
+ * `LightboxProvider`. Lets a media primitive degrade to a non-interactive image
377
+ * (rather than a dead "Expand" button that announces an action it cannot do).
378
+ */
379
+ declare function useLightboxOptional(): LightboxController | null;
380
+ /**
381
+ * The app-level screenshot lightbox. Render once near the timeline; renderers
382
+ * call `useLightbox().open(src)`.
383
+ *
384
+ * Idempotent by design: when an ancestor `LightboxProvider` already exists (e.g.
385
+ * a `MessageTimeline` mounted inside an app that already wraps its shell), this
386
+ * one becomes a pass-through and does NOT mount a second focus-trapping Dialog.
387
+ * That keeps `MessageTimeline` self-sufficient (it owns its own provider) while
388
+ * composing cleanly when nested.
389
+ */
390
+ declare function LightboxProvider({ children }: {
391
+ children: ReactNode;
392
+ }): react_jsx_runtime.JSX.Element;
393
+
394
+ /**
395
+ * Seed the initial open state of every timeline collapsible below this node.
396
+ * Intended for screenshot/test instrumentation only; absent by default.
397
+ */
398
+ declare function DisclosureDefaultsProvider({ defaultOpen, children }: {
399
+ defaultOpen: boolean;
400
+ children: ReactNode;
401
+ }): react_jsx_runtime.JSX.Element;
402
+
403
+ type TurnOutcome = "complete" | "failed" | "cancelled";
404
+ type TurnSummaryProps = {
405
+ /** The activity items in the turn (used only to compute the facet counts). */
406
+ items: ActivityItem[];
407
+ outcome: TurnOutcome;
408
+ /** A short failure reason shown inline on a failed chip (never hidden). */
409
+ failureText?: string | undefined;
410
+ /** Start expanded. */
411
+ defaultOpen?: boolean | undefined;
412
+ /** The rendered activity rail revealed on expand. */
413
+ children: React.ReactNode;
414
+ };
415
+ declare function TurnSummary({ items, outcome, failureText, defaultOpen, children }: TurnSummaryProps): react_jsx_runtime.JSX.Element;
416
+
417
+ /** Recover the exit code from a sandbox exec banner (`Process exited with code N`). */
418
+ declare function sandboxCommandExitCode(out: unknown): number | null;
419
+ /**
420
+ * Recover the numeric exec-session id the sandbox embeds for a STILL-RUNNING
421
+ * (backgrounded) process (`Process running with session ID N`). A finished
422
+ * command emits `Process exited with code N` instead, which yields `null`.
423
+ */
424
+ declare function parseExecBannerSessionId(out: unknown): number | null;
425
+ /** Strip the exec banner (`Chunk ID ...\n...\nOutput:\n`) down to the command's stdout. */
426
+ declare function stripExecBanner(out: unknown): string;
427
+ /** The sandbox clamped the output (token/line truncation markers in the banner). */
428
+ declare function execTruncated(out: unknown): boolean;
429
+ /** A `write_stdin` whose target PTY vanished (`write_stdin failed: session not found: N`). */
430
+ declare function isExecSessionLostBanner(out: unknown): boolean;
431
+ /** True when the exec stdout looks binary/garbled (a NUL byte or ELF magic). */
432
+ declare function looksBinary(text: string): boolean;
433
+ /**
434
+ * Render unprintable control characters as caret notation (0x03 -> `^C`) so a
435
+ * `write_stdin` keystroke payload reads cleanly in the row title.
436
+ */
437
+ declare function controlCaret(printable: string): string;
438
+ /** One operation inside an `apply_patch_call` (a V4A file edit). */
439
+ type ApplyPatchOperation = {
440
+ /**
441
+ * The V4A op kind. The three canonical values are `create_file`,
442
+ * `update_file`, and `delete_file`; the open `string` tail tolerates a
443
+ * forward-compatible/unknown op kind from the provider without a type error
444
+ * (it falls through to the "Edited" treatment).
445
+ */
446
+ type: "create_file" | "update_file" | "delete_file" | (string & {});
447
+ path: string;
448
+ /** Rename target -- when present the op is a move/rename. */
449
+ moveTo?: string | null | undefined;
450
+ /** The V4A hunk string (`@@ ...` lines with `+`/`-`/context prefixes). */
451
+ diff?: string | undefined;
452
+ };
453
+ /**
454
+ * Parse a single V4A `apply_patch` operation into the SDK's `GitFileDiff` shape
455
+ * so it can flow into the SAME `DiffView` / `PierreDiff` the Files tab uses.
456
+ * Throws on a hunk string it cannot structure (no `@@` anchor on an update); the
457
+ * renderer catches and falls back to a raw-patch view.
458
+ */
459
+ declare function v4aToGitFileDiff(op: ApplyPatchOperation): GitFileDiff;
460
+ /**
461
+ * Extract the `apply_patch` operations from a provider-native tool item's `raw`
462
+ * payload, normalizing the two wire shapes (`raw.operations[]` for a multi-file
463
+ * patch, `raw.operation` for a single op). The single owner of this shape so the
464
+ * renderer and the turn-summary facet counter never drift.
465
+ */
466
+ declare function applyPatchOps(raw: unknown): ApplyPatchOperation[];
467
+ /**
468
+ * True when a tool item is an `apply_patch_call` — by its provider-native
469
+ * `raw.type` (the live-wire source of truth) or by tool `name` (first-party
470
+ * replays that omit `raw`). Centralizes the rawType-or-name check.
471
+ */
472
+ declare function isApplyPatch(item: {
473
+ name: string;
474
+ raw: unknown;
475
+ }): boolean;
476
+ /** Deep-redact secret-looking values so arguments never leak a key into the UI. */
477
+ declare function redactSecrets(value: unknown): unknown;
478
+ /** Parse tool arguments that may arrive as a JSON string or an object. */
479
+ declare function parseToolArgs(args: unknown): Record<string, unknown>;
480
+ /** The last non-empty line of a string -- the compact "what happened" peek. */
481
+ declare function tailPeek(text: string): string;
482
+ /**
483
+ * Unwrap an MCP tool result (`{ content: [{ type: "text", text }], isError? }`)
484
+ * into a flat `{ text, isError }`. Non-MCP outputs pass through as their string
485
+ * form.
486
+ */
487
+ declare function unwrapMcpOutput(output: unknown): {
488
+ text: string;
489
+ isError: boolean;
490
+ };
163
491
 
164
492
  type SessionEventsConnectionState = StreamConnectionState | "idle" | "ended" | "error";
165
493
  type UseSessionEventsOptions = ClientOverride & {
@@ -296,16 +624,6 @@ type UseFileAttachmentsResult = {
296
624
  */
297
625
  declare function useFileAttachments(options?: UseFileAttachmentsOptions): UseFileAttachmentsResult;
298
626
 
299
- type SessionEventFeedOptions = {
300
- /**
301
- * Share an existing event log (from `useSessionEvents`) instead of opening
302
- * a second stream. When omitted the hook tails the session's event stream
303
- * itself, starting at the current `lastSequence`.
304
- */
305
- events?: SessionEvent[] | undefined;
306
- enabled?: boolean | undefined;
307
- };
308
-
309
627
  /** Event types that change the turn queue (queue/edit/reorder/claim/finish). */
310
628
  declare function isTurnQueueEvent(event: Pick<SessionEvent, "type">): boolean;
311
629
  /** Queued turns in execution order (position, then creation time). */
@@ -561,6 +879,323 @@ type UseAvailableModelsResult = {
561
879
  */
562
880
  declare function useAvailableModels(options?: UseAvailableModelsOptions): UseAvailableModelsResult;
563
881
 
882
+ type SessionCapabilitiesState = "idle" | "negotiating" | "ready" | "cold" | "error";
883
+ type UseSessionCapabilitiesOptions = ClientOverride & {
884
+ /**
885
+ * Live event log to fold `stream.url.rotated` from (usually
886
+ * `useSessionEvents().events`). When present the desktop socket stays fresh on
887
+ * a box rollover without a round-trip; stale-epoch rotations are dropped.
888
+ */
889
+ events?: SessionEvent[] | undefined;
890
+ /**
891
+ * Whether to acquire a viewer holder for the desktop pixel plane. Requires the
892
+ * un-redacted acknowledgment to have been recorded (else the attach 409s and
893
+ * the hook surfaces the consent requirement). Default false: read-only
894
+ * negotiation (no holder, no warm) — terminal/files/git work without it.
895
+ */
896
+ attachDesktop?: boolean | undefined;
897
+ /**
898
+ * Whether to acquire a viewer holder to warm the box for the REAL interactive
899
+ * terminal (the ttyd pty-ws plane). Symmetric with `attachDesktop` and shares
900
+ * the SAME viewer attach (one warm box serves both planes), but needs NO
901
+ * un-redacted acknowledgment — a shell is interactive by nature, and the gate
902
+ * is the scoped tunnel URL + stream token. Default false: the terminal stays on
903
+ * the read-only Channel-A firehose until the user opens/focuses it. The attach
904
+ * folds the minted `pty-ws` url+token into the `Terminal` cell.
905
+ */
906
+ attachTerminal?: boolean | undefined;
907
+ /**
908
+ * Whether to acquire a viewer holder purely to KEEP THE BOX WARM while the
909
+ * structured Files surface is open. Shares the SAME viewer attach as the
910
+ * desktop/terminal (one warm box, one holder) and — like the terminal — needs
911
+ * NO un-redacted acknowledgment: listing/reading/writing files is the ordinary
912
+ * Channel-A control plane, not the pixel plane. Default false: the Files tab
913
+ * negotiates read-only and each op pays the cold-box resume (~5s). When true,
914
+ * the holder warms the box once and heartbeats it, so subsequent fs ops are
915
+ * ~100ms instead of re-resuming the box on every list/write. It folds NO live
916
+ * URL (files ride the stateless HTTP plane) — it only refcounts liveness.
917
+ */
918
+ attachFiles?: boolean | undefined;
919
+ /** Hold off negotiating (e.g. the workbench panel is collapsed). Default true. */
920
+ enabled?: boolean | undefined;
921
+ /** Poll cadence (ms) while the lease is cold/warming. Default 1500. */
922
+ warmingPollMs?: number | undefined;
923
+ /**
924
+ * Give up waiting for `warm` after this long while polling (ms) and surface a
925
+ * stalled error with a manual `renegotiate`. Default 30000 (must agree with
926
+ * the lease warming TTL — I15). 0 disables the deadline.
927
+ */
928
+ warmingDeadlineMs?: number | undefined;
929
+ };
930
+ type UseSessionCapabilitiesResult = {
931
+ /** The negotiated capability doc — the single source of UI truth. */
932
+ capabilities: SessionCapabilities | null;
933
+ state: SessionCapabilitiesState;
934
+ error: Error | null;
935
+ /**
936
+ * 409 from the desktop attach: the un-redacted (or shared) plane needs explicit
937
+ * acknowledgment before a viewer holder is granted. Drives the consent prompt.
938
+ */
939
+ acknowledgmentRequired: "unredacted" | "shared" | null;
940
+ /** 429 from the desktop attach: the per-session viewer cap is reached. */
941
+ viewerCapReached: boolean;
942
+ /** The viewer holder id minted on a desktop attach (for detach/heartbeat). */
943
+ viewerId: string | null;
944
+ /** Force a re-negotiation (after acknowledging, a resolution change, etc.). */
945
+ renegotiate: () => void;
946
+ };
947
+ /**
948
+ * The capability-negotiation hook. Discovers what THIS session+backend+OS
949
+ * supports (FileSystem/Terminal/Git always-ish; DesktopStream/Recording
950
+ * sometimes), drives capability-gated rendering, and — when `attachDesktop` —
951
+ * holds a viewer lease + heartbeats it so the box stays warm while watched.
952
+ *
953
+ * Degradation is a value, never a crash: an unsupported surface comes back
954
+ * `available:false`/`transport:null` + a `reason`; the components render the
955
+ * reason-aware empty state. 409 (consent) and 429 (viewer cap) are surfaced as
956
+ * typed signals, not thrown.
957
+ */
958
+ declare function useSessionCapabilities(sessionId: string | null | undefined, options?: UseSessionCapabilitiesOptions): UseSessionCapabilitiesResult;
959
+
960
+ type UseDesktopStreamOptions = {
961
+ /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */
962
+ capability: DesktopStreamCapability | null;
963
+ /** The mount target. RFB attaches here on connect. */
964
+ containerRef: RefObject<HTMLDivElement | null>;
965
+ /** Read-only by default (v1 ruling H). interactive only when cap.mode allows. */
966
+ interactive?: boolean | undefined;
967
+ scaleViewport?: boolean | undefined;
968
+ /** Custom RFB factory (tests / a WebRTC swap). Defaults to a lazy @novnc/novnc. */
969
+ rfbFactory?: DesktopRfbFactory | undefined;
970
+ };
971
+ type UseDesktopStreamResult = {
972
+ state: DesktopConnectionState;
973
+ error: Error | null;
974
+ /** Manual reconnect (e.g. after a securityfailure once a fresh URL arrives). */
975
+ reconnect: () => void;
976
+ };
977
+ /**
978
+ * Drive the noVNC RFB lifecycle from a `DesktopStreamCapability`, using the
979
+ * SDK's `desktop.ts` reducer + `desktopSocketUrl`. SSR-safe: the RFB import and
980
+ * the DOM attach happen inside `useEffect`, so a server render is a no-op and
981
+ * the component shows its placeholder until hydration.
982
+ *
983
+ * Read-only is enforced at three layers: `capability.mode` (server) →
984
+ * `interactive` prop → `RFB.viewOnly`. v1 always resolves to read-only. On a
985
+ * capability `url` change (a rotation), the old RFB disconnects and a fresh one
986
+ * connects to the new URL — a brief "desktop blink", acceptable on rollover.
987
+ */
988
+ declare function useDesktopStream(options: UseDesktopStreamOptions): UseDesktopStreamResult;
989
+
990
+ /** The ttyd connection lifecycle as surfaced to the component. */
991
+ type TerminalStreamStatus = "connecting" | "open" | "closed" | "error";
992
+ type UseTerminalStreamOptions = {
993
+ /** The Terminal cell of the negotiated capabilities (`capabilities.Terminal`).
994
+ * The stream connects ONLY when `transport === "pty-ws"` and `url` is set; on a
995
+ * cold box (`transport === "sse-events"` / no url) it stays idle and the caller
996
+ * falls back to the Channel-A read-only firehose. */
997
+ capability: Pick<TerminalCapability, "transport" | "url" | "token"> | null;
998
+ /** Called for each OUTPUT payload from ttyd (write verbatim into xterm). */
999
+ onOutput?: ((data: string) => void) | undefined;
1000
+ /** Called when ttyd sends a SET_WINDOW_TITLE frame. */
1001
+ onTitle?: ((title: string) => void) | undefined;
1002
+ /** Initial PTY size to seed the ttyd auth frame + first resize. */
1003
+ initialCols?: number | undefined;
1004
+ initialRows?: number | undefined;
1005
+ };
1006
+ type UseTerminalStreamResult = {
1007
+ /** True once the ttyd socket is open (and the auth frame has been sent). */
1008
+ connected: boolean;
1009
+ status: TerminalStreamStatus;
1010
+ /** Pipe a keystroke/paste to the PTY stdin. No-op until the socket is open. */
1011
+ write: (data: string) => void;
1012
+ /** Tell ttyd the PTY window changed size (on xterm fit/resize). */
1013
+ resize: (cols: number, rows: number) => void;
1014
+ /** Tear the socket down (the effect also tears down on unmount / url change). */
1015
+ disconnect: () => void;
1016
+ };
1017
+ /**
1018
+ * Drive a ttyd PTY-over-websocket connection from a `pty-ws` Terminal capability,
1019
+ * symmetric with `use-desktop-stream` (the noVNC-over-tunnel hook). The scoped
1020
+ * stream token is already embedded in the minted tunnel `url`; the WebSocket is
1021
+ * opened with the REQUIRED ttyd subprotocol "tty".
1022
+ *
1023
+ * ttyd wire protocol (see `@opengeni/sdk/terminal`):
1024
+ * - first frame: `JSON.stringify({ AuthToken: "" })` (+ optional columns/rows).
1025
+ * - client→server: INPUT = "0"+data ; RESIZE = "1"+JSON({columns,rows}).
1026
+ * - server→client: "0" = OUTPUT (→ xterm) ; "1" = SET_WINDOW_TITLE ;
1027
+ * "2" = SET_PREFERENCES (ignored). Binary frames are decoded the same way.
1028
+ *
1029
+ * On a `url`/`token` rotation (a box rollover folds a fresh address into the cell)
1030
+ * the effect re-runs: the old socket closes and a fresh one connects — a brief
1031
+ * terminal blink, acceptable on rollover (mirrors the desktop's RFB hot-swap).
1032
+ * SSR-safe: the socket open lives in `useEffect`, so a server render is a no-op.
1033
+ */
1034
+ declare function useTerminalStream(options: UseTerminalStreamOptions): UseTerminalStreamResult;
1035
+
1036
+ type TerminalChunk = {
1037
+ /** Stable key (the source event id) so the xterm writer tracks a written-cursor. */
1038
+ id: string;
1039
+ /** Raw output bytes (utf-8 lossy) — written verbatim into xterm. */
1040
+ text: string;
1041
+ /** stdout vs stderr (drives optional tinting). */
1042
+ stream: "stdout" | "stderr";
1043
+ /** Global ordering: the source event sequence. */
1044
+ seq: number;
1045
+ };
1046
+ type UseSandboxTerminalOptions = ClientOverride & {
1047
+ /** The live session event log (usually `useSessionEvents().events`). */
1048
+ events: SessionEvent[];
1049
+ /** Restrict to one PTY (by ptyId). Omit to interleave the agent firehose +
1050
+ * every PTY. */
1051
+ ptyId?: string | undefined;
1052
+ /** Include the agent's command-output firehose (sandbox.command.output.delta).
1053
+ * Default true — the read-only "terminal-as-events" the data path settled on. */
1054
+ includeAgentFirehose?: boolean | undefined;
1055
+ /**
1056
+ * OPEN an interactive PTY against the box so the user can type, not just watch.
1057
+ * When true (and the session is live) the hook calls `terminalPtyOpen` once,
1058
+ * tracks the returned ptyId, exposes `write` immediately (bound to that ptyId),
1059
+ * and closes the PTY on unmount. The PTY's banner + every output delta ride the
1060
+ * SSE spine (`terminal.pty.*`) back into `events`, so xterm fills in. Default
1061
+ * false — a caller that only wants the read-only firehose stays projection-only.
1062
+ */
1063
+ interactive?: boolean | undefined;
1064
+ /** Lease liveness ("cold" | "warm" | "draining"). The interactive PTY is only
1065
+ * opened once the box is warm — opening on a cold box (ptyCapable is advertised
1066
+ * cold too) races the box and leaves a dead read-only terminal. */
1067
+ liveness?: string | undefined;
1068
+ };
1069
+ type UseSandboxTerminalResult = {
1070
+ /** Ordered, deduped output chunks to write() into xterm.js. */
1071
+ chunks: TerminalChunk[];
1072
+ /** Whether a PTY is currently open (drives the prompt/cursor affordance). */
1073
+ running: boolean;
1074
+ /**
1075
+ * Interactive write fn when a PTY is open and the backend supports stdin
1076
+ * (`terminal.transport === "pty-ws"` / `PtyOpenResponse.supportsInput`). Null
1077
+ * in the read-only event-projection case (v1 default).
1078
+ */
1079
+ write: ((data: string) => void) | null;
1080
+ /** The active PTY id, if one is open. */
1081
+ activePtyId: string | null;
1082
+ /** Close the active PTY (no-op when none is open). */
1083
+ close: () => void;
1084
+ /** A PTY-open failure (interactive mode), if any. */
1085
+ error: Error | null;
1086
+ };
1087
+ /**
1088
+ * Project the Channel-A event log into an xterm-writable byte stream. The
1089
+ * terminal is "terminal-as-events": there is NO new socket in v1 — the agent's
1090
+ * command output (`sandbox.command.output.delta`) and any interactive PTY
1091
+ * (`terminal.pty.output.delta`) ride the existing SSE spine. When a PTY is open
1092
+ * and the backend accepts stdin, `write` pipes keystrokes via the SDK
1093
+ * `terminalPtyWrite` (the synchronous Channel-A control path).
1094
+ */
1095
+ declare function useSandboxTerminal(sessionId: string | null | undefined, options: UseSandboxTerminalOptions): UseSandboxTerminalResult;
1096
+
1097
+ /** The git-status overlay a file row may carry (tints modified files in the tree). */
1098
+ type FileTreeStatus = "added" | "modified" | "deleted" | "renamed" | "untracked";
1099
+ /** A node in the Pierre file tree. `children === undefined` ⇒ an unexpanded dir
1100
+ * (lazy treeMode); `children: []` ⇒ an expanded-but-empty dir. */
1101
+ type FileTreeNode = {
1102
+ path: string;
1103
+ name: string;
1104
+ kind: "file" | "dir";
1105
+ children?: FileTreeNode[] | undefined;
1106
+ size?: number | null | undefined;
1107
+ status?: FileTreeStatus | undefined;
1108
+ };
1109
+ type UseSandboxFilesOptions = ClientOverride & {
1110
+ /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh
1111
+ * on `fs.changed` / `git.changed`. */
1112
+ events?: SessionEvent[] | undefined;
1113
+ /** Initial path to list (workspace root by default). */
1114
+ rootPath?: string | undefined;
1115
+ /** Hold off the initial list (e.g. panel collapsed). Default true. */
1116
+ enabled?: boolean | undefined;
1117
+ /** The lease liveness ("cold" | "warm" | "draining"). The structured FileSystem
1118
+ * capability is advertised even on a COLD box, so the mount-time list can race
1119
+ * the box: it lists before the box is warm, gets an empty/errored result, and
1120
+ * (with no `fs.changed` event) never re-lists. Passing liveness re-lists when
1121
+ * the box first becomes warm, so the tree populates as soon as the box is up. */
1122
+ liveness?: string | undefined;
1123
+ /** Called when an OPTIMISTIC mutation is reverted because its background
1124
+ * Channel-A op failed (e.g. a 409 rename collision). The host wires this to a
1125
+ * toast — the tree silently rolls the node back, the user sees why. */
1126
+ onMutationError?: ((error: Error, op: string) => void) | undefined;
1127
+ };
1128
+ type UseSandboxFilesResult = {
1129
+ /** The tree roots (the listed root's children). */
1130
+ tree: FileTreeNode[];
1131
+ /** Lazy-expand a directory node in place (lists its immediate children). */
1132
+ expand: (path: string) => Promise<void>;
1133
+ /** Paths whose lazy `fs.list` is currently in flight — the FileBrowser shows a
1134
+ * spinner on these nodes so a 2-3s Channel-A list never looks frozen. */
1135
+ expandingPaths: Set<string>;
1136
+ /** Read a file for the preview pane (text or base64-for-binary, size-capped). */
1137
+ readFile: (path: string) => Promise<FsReadResponse>;
1138
+ /** Write a file (overwrite, last-writer-wins) — the editor save path.
1139
+ * Optimistic: a brand-new file is spliced into the tree immediately and the
1140
+ * Channel-A write runs in the background; on failure the splice is reverted. */
1141
+ writeFile: (path: string, content: string) => Promise<FsWriteResponse>;
1142
+ /** Create a new empty file (refuses to clobber an existing path: overwrite=false). */
1143
+ createFile: (path: string) => Promise<void>;
1144
+ /** Create a directory (recursive by default). */
1145
+ createDir: (path: string) => Promise<void>;
1146
+ /** Delete a path (pass recursive=true for a non-empty directory). */
1147
+ deleteEntry: (path: string, recursive?: boolean) => Promise<void>;
1148
+ /** Move / rename a path (rename == move). Refuses to clobber unless overwrite=true. */
1149
+ moveEntry: (path: string, newPath: string, opts?: {
1150
+ overwrite?: boolean;
1151
+ }) => Promise<void>;
1152
+ /** Re-list the whole tree from the root. */
1153
+ refresh: () => Promise<void>;
1154
+ loading: boolean;
1155
+ error: Error | null;
1156
+ };
1157
+ /**
1158
+ * Project the FileSystem service into a lazy-loaded Pierre tree. The initial
1159
+ * list pulls one level (depth 1); `expand(path)` lists a directory's immediate
1160
+ * children on demand (the fast lazy-tree UX). A git-status overlay tints
1161
+ * modified files. Auto-refreshes when an `fs.changed` / `git.changed` event
1162
+ * arrives on the live log.
1163
+ */
1164
+ declare function useSandboxFiles(sessionId: string | null | undefined, options?: UseSandboxFilesOptions): UseSandboxFilesResult;
1165
+
1166
+ type UseSandboxGitOptions = ClientOverride & {
1167
+ /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh
1168
+ * on `git.changed`. */
1169
+ events?: SessionEvent[] | undefined;
1170
+ /** Repo root within the workspace (multi-repo). Default: workspace root. */
1171
+ repoPath?: string | undefined;
1172
+ /** Diff the staged index vs HEAD (`--cached`) instead of the working tree. */
1173
+ staged?: boolean | undefined;
1174
+ /** Hold off the initial fetch. Default true. */
1175
+ enabled?: boolean | undefined;
1176
+ };
1177
+ type UseSandboxGitResult = {
1178
+ /** Working-tree (or staged) diff vs HEAD — the structured hunks the Pierre
1179
+ * diff view renders. */
1180
+ diff: GitFileDiff[];
1181
+ branch: string | null;
1182
+ /** Whether a repo is actually mounted (drives "no repository" vs "no changes"). */
1183
+ isRepo: boolean;
1184
+ ahead: number;
1185
+ behind: number;
1186
+ refresh: () => Promise<void>;
1187
+ loading: boolean;
1188
+ error: Error | null;
1189
+ };
1190
+ /**
1191
+ * Project the Git service into the Pierre diff data contract: structured
1192
+ * `GitFileDiff[]` (per-file hunks with per-line old/new numbers, rename
1193
+ * detection, binary flag, add/del counts) plus branch + ahead/behind. The
1194
+ * `git diff` runs in-box (API-direct) and the hunks come back inline. Refreshes
1195
+ * on `git.changed`.
1196
+ */
1197
+ declare function useSandboxGit(sessionId: string | null | undefined, options?: UseSandboxGitOptions): UseSandboxGitResult;
1198
+
564
1199
  type PendingApproval = {
565
1200
  /** The id to send back via `user.approvalDecision` (`approvalId`). */
566
1201
  id: string;
@@ -884,6 +1519,12 @@ type MessageTimelineProps = {
884
1519
  renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;
885
1520
  /** Drill into a spawned worker session. */
886
1521
  onOpenSession?: ((sessionId: string) => void) | undefined;
1522
+ /**
1523
+ * The tool-renderer registry that resolves how each tool call is drawn.
1524
+ * Defaults to {@link defaultToolRegistry}; pass a registry from
1525
+ * `createDefaultToolRegistry({ entries })` to add custom tool renderers.
1526
+ */
1527
+ toolRegistry?: ToolRegistry | undefined;
887
1528
  /** Follow new events when pinned to the bottom. Defaults to true. */
888
1529
  autoFollow?: boolean | undefined;
889
1530
  emptyState?: ReactNode | undefined;
@@ -895,7 +1536,16 @@ type MessageTimelineProps = {
895
1536
  * cards, goal markers, and status transitions. Owns stick-to-bottom scrolling
896
1537
  * with a "jump to latest" affordance when the reader scrolls back.
897
1538
  */
898
- declare function MessageTimeline({ events, items, status, renderMessageText, onOpenSession, autoFollow, emptyState, className, }: MessageTimelineProps): react_jsx_runtime.JSX.Element;
1539
+ declare function MessageTimeline({ events, items, status, renderMessageText, onOpenSession, toolRegistry, autoFollow, emptyState, className, }: MessageTimelineProps): react_jsx_runtime.JSX.Element;
1540
+ /**
1541
+ * Render one non-activity timeline item (chat message, status divider, goal
1542
+ * landmark, notice). Exported so the component demo draws the EXACT same rows as
1543
+ * the live app — no forked bubble/goal markup.
1544
+ */
1545
+ declare function TimelineRow({ item, renderMessageText, }: {
1546
+ item: TimelineItem;
1547
+ renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;
1548
+ }): react_jsx_runtime.JSX.Element | null;
899
1549
 
900
1550
  /**
901
1551
  * The default renderer for chat message bodies in {@link MessageTimeline}.
@@ -962,6 +1612,384 @@ declare function sessionDisplayTitle(session: Session): string;
962
1612
  */
963
1613
  declare function FleetTile({ session, title, subtitle, onOpen, className }: FleetTileProps): react_jsx_runtime.JSX.Element;
964
1614
 
1615
+ /** A subset of xterm.js's ITheme — the tokens worth themeing from a host app. */
1616
+ type XtermTheme = {
1617
+ background?: string;
1618
+ foreground?: string;
1619
+ cursor?: string;
1620
+ cursorAccent?: string;
1621
+ selectionBackground?: string;
1622
+ };
1623
+ type SandboxTerminalProps = {
1624
+ /** From `useSandboxTerminal(...)`. */
1625
+ result: UseSandboxTerminalResult;
1626
+ /**
1627
+ * The negotiated Terminal capability cell. When it advertises `transport:
1628
+ * "pty-ws"` + a live `url` (a warm box with a viewer attached), the terminal is
1629
+ * driven by a REAL bidirectional PTY over the Modal tunnel (ttyd-over-websocket)
1630
+ * INSTEAD of the broken ptyWrite-over-HTTP path: xterm input → the socket, the
1631
+ * socket's output → xterm, xterm resize → the socket. On a cold box / no url
1632
+ * (`transport: "sse-events"`) it stays on the read-only Channel-A firehose
1633
+ * (`result.chunks`). Omit to force the legacy firehose-only behavior.
1634
+ */
1635
+ terminalCapability?: TerminalCapability | null | undefined;
1636
+ theme?: XtermTheme | undefined;
1637
+ fontFamily?: string | undefined;
1638
+ fontSize?: number | undefined;
1639
+ /**
1640
+ * Force read-only even when the PTY accepts stdin. Default: interactive
1641
+ * whenever a live pty-ws stream is connected OR `result.write !== null` (the box
1642
+ * advertises an interactive PTY); otherwise the read-only agent firehose.
1643
+ */
1644
+ readOnly?: boolean | undefined;
1645
+ /** Shown on the server / before xterm hydrates (SSR-safe placeholder). */
1646
+ placeholder?: ReactNode | undefined;
1647
+ /** Render the small status header (pty/shell + running dot + read-only pill). */
1648
+ showHeader?: boolean | undefined;
1649
+ /** Shell label for the header (e.g. `/bin/bash`). */
1650
+ shell?: string | undefined;
1651
+ /**
1652
+ * Fired the first time the user engages the terminal surface (focus or click).
1653
+ * The host wires this to warm the box for the REAL pty-ws terminal (the viewer
1654
+ * attach), so a cold box upgrades from the read-only firehose to a live PTY ON
1655
+ * INTERACT — never on mere mount (which would force a box spin-up and regress
1656
+ * the firehose-only default).
1657
+ */
1658
+ onActivate?: (() => void) | undefined;
1659
+ className?: string | undefined;
1660
+ };
1661
+ /**
1662
+ * An xterm.js terminal fed by the Channel-A event projection
1663
+ * (`useSandboxTerminal`). xterm + the fit + web-links addons are lazy-imported
1664
+ * inside an effect, so SSR renders the placeholder and the terminal mounts on
1665
+ * hydration. Output chunks are written incrementally (tracking a written-cursor
1666
+ * by chunk id so a re-render never re-writes). When `result.write` is non-null
1667
+ * and not forced read-only, keystrokes pipe back through the PTY.
1668
+ *
1669
+ * Resizes are tracked with a `ResizeObserver` on the container (not just
1670
+ * `window.resize`) so dragging the dock handle refits the grid instead of
1671
+ * leaving the terminal mis-sized.
1672
+ */
1673
+ declare function SandboxTerminal({ result, terminalCapability, theme, fontFamily, fontSize, readOnly, placeholder, showHeader, shell, onActivate, className, }: SandboxTerminalProps): react_jsx_runtime.JSX.Element;
1674
+
1675
+ type FileBrowserProps = {
1676
+ /** From `useSandboxFiles(...)`. */
1677
+ result: UseSandboxFilesResult;
1678
+ /**
1679
+ * Rendered instead of the built-in tree when the file surface is unavailable
1680
+ * (e.g. a `FileSystem.available === false` capability). Default: a quiet notice.
1681
+ */
1682
+ fallback?: ReactNode | undefined;
1683
+ /** Selection callback for the preview pane. */
1684
+ onSelectFile?: ((path: string) => void) | undefined;
1685
+ selectedPath?: string | undefined;
1686
+ /** Render-prop to theme/replace a row entirely (the Pierre-swap escape hatch). */
1687
+ renderNode?: ((node: FileTreeNode, depth: number, expanded: boolean) => ReactNode) | undefined;
1688
+ /** Shown when the tree is empty (no files / not loaded yet). */
1689
+ emptyState?: ReactNode | undefined;
1690
+ /**
1691
+ * Enable the file-manager affordances (toolbar, context menu, drag-drop move,
1692
+ * inline rename, delete, new file/folder). Defaults to `true` when the hook
1693
+ * exposes the mutation methods; pass `false` for a strictly read-only tree.
1694
+ */
1695
+ editable?: boolean | undefined;
1696
+ /**
1697
+ * Confirm a (recursive) delete before it runs. Return `false` to cancel.
1698
+ * Defaults to `window.confirm`. Pass a no-op returning `true` to skip.
1699
+ */
1700
+ confirmDelete?: ((node: FileTreeNode) => boolean | Promise<boolean>) | undefined;
1701
+ className?: string | undefined;
1702
+ };
1703
+ /**
1704
+ * The file MANAGER, fed by the FileSystem service via `useSandboxFiles`. This is
1705
+ * a first-class editable tree (not a render-only view): lazy-expand with a
1706
+ * spinner on the in-flight node, git-status tinting, full keyboard navigation,
1707
+ * selection, and the mutating affordances wired straight to the hook —
1708
+ *
1709
+ * • drag-and-drop MOVE → `moveEntry(from, to)`
1710
+ * • inline RENAME → `moveEntry(path, newPath)` (F2 / double-click / menu)
1711
+ * • DELETE → `deleteEntry(path, recursive)` (Del / menu, confirmed)
1712
+ * • NEW FILE / FOLDER → `createFile` / `createDir` (toolbar + menu), then open
1713
+ * • right-click CONTEXT MENU
1714
+ *
1715
+ * `renderNode` is still honoured as the Pierre-swap escape hatch for the row
1716
+ * chrome; the manager scaffolding (toolbar, dnd, menu, inline inputs) wraps it.
1717
+ */
1718
+ declare function FileBrowser({ result, fallback, onSelectFile, selectedPath, renderNode, emptyState, editable, confirmDelete, className, }: FileBrowserProps): react_jsx_runtime.JSX.Element;
1719
+
1720
+ /** Theme tokens for the diff line backgrounds. */
1721
+ type DiffTheme = {
1722
+ addBackground?: string;
1723
+ delBackground?: string;
1724
+ contextBackground?: string;
1725
+ metaForeground?: string;
1726
+ };
1727
+ type DiffViewProps = {
1728
+ /** From `useSandboxGit().diff` — the structured per-file hunks. */
1729
+ diff: GitFileDiff[];
1730
+ /** Rendered instead of the built-in diff (the Pierre-swap escape hatch). */
1731
+ fallback?: ReactNode | undefined;
1732
+ /** unified | split. Default "unified". */
1733
+ layout?: "unified" | "split" | undefined;
1734
+ theme?: DiffTheme | undefined;
1735
+ onSelectFile?: ((path: string) => void) | undefined;
1736
+ /** Distinguishes "no changes" from "no repository mounted". */
1737
+ isRepo?: boolean | undefined;
1738
+ emptyState?: ReactNode | undefined;
1739
+ className?: string | undefined;
1740
+ };
1741
+ /**
1742
+ * The diff view, fed by the Git service via `useSandboxGit().diff`. This is our
1743
+ * `PierreDiff` boundary: the built-in renderer delivers the same UX (per-file
1744
+ * hunks, unified or side-by-side, old/new line numbers, add/del counts), and a
1745
+ * consumer with Pierre's `@pierre/diffs` installed can swap it via `fallback`
1746
+ * while keeping the same `GitFileDiff[]` data contract from the hook.
1747
+ */
1748
+ declare function DiffView({ diff, fallback, layout, theme, onSelectFile, isRepo, emptyState, className, }: DiffViewProps): react_jsx_runtime.JSX.Element;
1749
+
1750
+ type PierreDiffProps = {
1751
+ diff: GitFileDiff[];
1752
+ layout?: "unified" | "split" | undefined;
1753
+ themeType?: "dark" | "light" | undefined;
1754
+ /** Shiki bundled theme names (dark/light) — derived from the host palette. */
1755
+ theme?: {
1756
+ dark: string;
1757
+ light: string;
1758
+ } | undefined;
1759
+ /** Disable Pierre's worker pool if its worker bundling fights the host bundler. */
1760
+ disableWorkerPool?: boolean | undefined;
1761
+ /** Rendered while the (lazy) Pierre bundle loads. */
1762
+ loading?: ReactNode | undefined;
1763
+ /** Rendered if `@pierre/diffs/react` is not installed / fails to import. */
1764
+ fallback?: ReactNode | undefined;
1765
+ className?: string | undefined;
1766
+ };
1767
+ /**
1768
+ * The Pierre-backed diff: Shiki-highlighted, virtualized, unified/split. Renders
1769
+ * one `PatchDiff` per changed file (a reconstructed unified patch from the
1770
+ * `GitFileDiff` hunks). This sits behind `DiffView`'s `fallback` seam so a host
1771
+ * that lacks `@pierre/diffs` keeps the hand-rolled renderer.
1772
+ */
1773
+ declare function PierreDiff({ diff, layout, themeType, theme, disableWorkerPool, loading, fallback, className, }: PierreDiffProps): react_jsx_runtime.JSX.Element;
1774
+
1775
+ type PierreFileProps = {
1776
+ /** Workspace-relative path (used for the header + language inference). */
1777
+ path: string;
1778
+ /** The decoded text contents. */
1779
+ contents: string;
1780
+ themeType?: "dark" | "light" | undefined;
1781
+ /** Shiki bundled theme names (dark/light) — derived from the host palette. */
1782
+ theme?: {
1783
+ dark: string;
1784
+ light: string;
1785
+ } | undefined;
1786
+ /** Disable Pierre's worker pool if its worker bundling fights the host bundler. */
1787
+ disableWorkerPool?: boolean | undefined;
1788
+ /** Rendered while the (lazy) Pierre bundle loads. */
1789
+ loading?: ReactNode | undefined;
1790
+ /** Rendered if `@pierre/diffs/react` is not installed / fails to import. */
1791
+ fallback?: ReactNode | undefined;
1792
+ className?: string | undefined;
1793
+ };
1794
+ /**
1795
+ * The Pierre-backed single-file VIEWER: Shiki-highlighted, language inferred from
1796
+ * the filename — the read complement of `PierreDiff`. Wired to `fs.read` so
1797
+ * clicking any file in the tree shows its contents (NOT a diff; no repo needed).
1798
+ * Falls back to a plain `<pre>` when `@pierre/diffs` is absent / fails to import.
1799
+ */
1800
+ declare function PierreFile({ path, contents, themeType, theme, disableWorkerPool, loading, fallback, className, }: PierreFileProps): react_jsx_runtime.JSX.Element;
1801
+
1802
+ /** Language grammar loaders, keyed by the extension class we infer from the path. */
1803
+ declare const LANGUAGE_LOADERS: Record<string, () => Promise<unknown>>;
1804
+ /** Map a filename to a grammar key (or null for plain text — still fully editable). */
1805
+ declare function languageForPath(path: string): keyof typeof LANGUAGE_LOADERS | null;
1806
+ type CodeEditorProps = {
1807
+ /** Workspace-relative path — drives language inference (and the save target upstream). */
1808
+ path: string;
1809
+ /** The decoded text contents to seed the editor with. */
1810
+ initialContents: string;
1811
+ /** Persist the current buffer. Resolves when the write lands; rejects to surface an error. */
1812
+ onSave: (contents: string) => Promise<unknown>;
1813
+ /** Read-only mode (e.g. a truncated/too-large file shown for reference only). */
1814
+ readOnly?: boolean | undefined;
1815
+ themeType?: "dark" | "light" | undefined;
1816
+ /** Rendered while the (lazy) CodeMirror bundle loads. */
1817
+ loading?: ReactNode | undefined;
1818
+ /** Rendered if `@uiw/react-codemirror` is not installed / fails to import. */
1819
+ fallback?: ReactNode | undefined;
1820
+ className?: string | undefined;
1821
+ };
1822
+ /**
1823
+ * The EDITABLE single-file pane: CodeMirror 6 with a per-language grammar chosen
1824
+ * from the filename, og-* themed, with dirty tracking and a save path wired to
1825
+ * `Cmd/Ctrl+S` *and* an explicit Save button. The viewer (Pierre `File`) stays
1826
+ * the read-only complement — this is only mounted when the user opts to edit.
1827
+ *
1828
+ * Save semantics: the buffer is "dirty" the moment it diverges from the last
1829
+ * saved baseline; a successful `onSave` clears dirty and re-baselines. A failed
1830
+ * save keeps the buffer dirty (nothing is lost) and surfaces the error inline.
1831
+ * `readOnly` suppresses every mutation path so a truncated/binary file can never
1832
+ * be saved back (which would corrupt it by writing the truncated prefix).
1833
+ */
1834
+ declare function CodeEditor({ path, initialContents, onSave, readOnly, themeType, loading, fallback, className, }: CodeEditorProps): react_jsx_runtime.JSX.Element;
1835
+
1836
+ type SandboxFilesProps = {
1837
+ /** From `useSandboxFiles(...)`. */
1838
+ files: UseSandboxFilesResult;
1839
+ /** From `useSandboxGit(...)` — the working-tree diff. */
1840
+ git: UseSandboxGitResult;
1841
+ /** From a second `useSandboxGit(..., { staged: true })` — the staged diff. */
1842
+ stagedGit?: UseSandboxGitResult | undefined;
1843
+ /** Whether a FileSystem surface is advertised (drives the unavailable notice). */
1844
+ fileSystemAvailable?: boolean | undefined;
1845
+ /** Use Pierre's Shiki-highlighted diff (default true; falls back to built-in). */
1846
+ usePierre?: boolean | undefined;
1847
+ /** Allow in-place editing of tree files (CodeMirror). Default true. When false
1848
+ * the surface is review-only: every text file opens in the read-only viewer. */
1849
+ editable?: boolean | undefined;
1850
+ themeType?: "dark" | "light" | undefined;
1851
+ className?: string | undefined;
1852
+ };
1853
+ /**
1854
+ * The review-first Files surface: a sticky branch/dirty header, a "Changes"
1855
+ * group (changed files vs HEAD, badged), the full lazy file tree for context,
1856
+ * and an inline diff pane below for the selected changed file. The agent
1857
+ * commits; the human reviews — there is no stage/commit/push UI here (power-git
1858
+ * lives in the terminal).
1859
+ */
1860
+ declare function SandboxFiles({ files, git, stagedGit, fileSystemAvailable, usePierre, editable, themeType, className, }: SandboxFilesProps): react_jsx_runtime.JSX.Element;
1861
+
1862
+ type DesktopViewerProps = {
1863
+ /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */
1864
+ capability: DesktopStreamCapability | null;
1865
+ /**
1866
+ * Initial control mode. Default false (watch). When the user flips
1867
+ * "Take control" the viewer drives input — but only if `capability.mode`
1868
+ * permits it (server-gated; a read-only deployment disables the toggle).
1869
+ * Pass a value to control it externally; omit to let the viewer own the state.
1870
+ */
1871
+ interactive?: boolean | undefined;
1872
+ /** Render the built-in Watching ⇄ Take control toggle (default true). */
1873
+ showControlToggle?: boolean | undefined;
1874
+ scaleViewport?: boolean | undefined;
1875
+ /** Custom RFB factory (tests / a WebRTC swap). Defaults to lazy @novnc/novnc. */
1876
+ rfbFactory?: DesktopRfbFactory | undefined;
1877
+ /**
1878
+ * Consent gate for the un-redacted (and possibly shared) pixel plane. Rendered
1879
+ * BEFORE connecting whenever the desktop requires acknowledgment that hasn't
1880
+ * been given. Call `onAccept` to record consent (the host wires it to
1881
+ * `client.acknowledgeStream` + a re-negotiate). When omitted, a default
1882
+ * banner is shown.
1883
+ */
1884
+ renderConsentGate?: ((onAccept: () => void, shared: boolean) => ReactNode) | undefined;
1885
+ /** Called when the default consent gate's accept button is pressed. */
1886
+ onAcknowledge?: (() => void) | undefined;
1887
+ /**
1888
+ * Whether the host has the viewer attach engaged (i.e. the user has opted into
1889
+ * watching — the parent's `watchDesktop`/`attachDesktop`). Drives the
1890
+ * cold-state behaviour: when watching, a cold-but-warmable lease AUTO-WARMS
1891
+ * (and re-warms when the box drains) instead of dead-ending. When omitted we
1892
+ * infer it from a recorded consent (the default gate's accept), so the
1893
+ * component still self-heals after the first acknowledgment.
1894
+ */
1895
+ watching?: boolean | undefined;
1896
+ /**
1897
+ * Request a (re)warm of the sandbox WITHOUT re-acknowledging (the consent has
1898
+ * already been recorded — only the box drained). The host wires this to
1899
+ * "engage the viewer attach + re-negotiate". Called automatically when a
1900
+ * watched desktop is found cold-but-warmable, and behind the manual retry on
1901
+ * the warming notice. Distinct from `onAcknowledge`, which is the FIRST,
1902
+ * consent-bearing warm.
1903
+ */
1904
+ onWarm?: (() => void) | undefined;
1905
+ /** Shown when transport is null (headless backend / degraded / disabled). */
1906
+ renderUnavailable?: ((reason: CapabilityUnavailableReason | null) => ReactNode) | undefined;
1907
+ /** Shown while the box is cold/warming (no live address yet). */
1908
+ renderWarming?: (() => ReactNode) | undefined;
1909
+ /** Shown when the per-session viewer cap (429) was hit. */
1910
+ renderViewerCap?: (() => ReactNode) | undefined;
1911
+ /** Surface the 429 cap state from `useSessionCapabilities().viewerCapReached`. */
1912
+ viewerCapReached?: boolean | undefined;
1913
+ /**
1914
+ * Connect watchdog (ms): if a live url is present but the RFB hasn't connected
1915
+ * within this window, surface a "Couldn't connect" + Reconnect instead of an
1916
+ * eternal idle scrim. Default 13000. 0 disables the watchdog.
1917
+ */
1918
+ connectTimeoutMs?: number | undefined;
1919
+ className?: string | undefined;
1920
+ };
1921
+ /**
1922
+ * The desktop surface: a noVNC client connecting to the Channel-B scoped tunnel
1923
+ * URL from the capability doc. Owns the mount `<div ref>`, drives
1924
+ * `useDesktopStream` (SSR-safe lazy RFB), and renders a real
1925
+ * cold → warming → connecting → connected → error state machine with live
1926
+ * feedback (spinners, transitions) — never a dead black box with stale text.
1927
+ *
1928
+ * The read-only vs interactive decision is enforced server-first
1929
+ * (`capability.mode`): when the deployment advertises mode "interactive" the
1930
+ * viewer can TAKE CONTROL and drive the mouse & keyboard into the box's :0; a
1931
+ * "read-only" deployment disables the take-control affordance (graceful, with a
1932
+ * reason).
1933
+ *
1934
+ * Warming: a cold-but-warmable lease (`reason: "lease_cold"`) is NOT a dead end.
1935
+ * When the user is watching (consented), the viewer asks the host to (re)warm
1936
+ * the box (`onWarm`) and shows a "Warming…" spinner; if the box later drains to
1937
+ * cold it re-warms. Genuinely-unavailable surfaces (headless/policy/os/backend)
1938
+ * keep a clear, static unavailable notice.
1939
+ */
1940
+ declare function DesktopViewer({ capability, interactive, showControlToggle, scaleViewport, rfbFactory, renderConsentGate, onAcknowledge, watching, onWarm, renderUnavailable, renderWarming, renderViewerCap, viewerCapReached, connectTimeoutMs, className, }: DesktopViewerProps): react_jsx_runtime.JSX.Element;
1941
+
1942
+ type WorkspaceTab = {
1943
+ id: string;
1944
+ label: ReactNode;
1945
+ /** Rendered as the active surface. */
1946
+ content: ReactNode;
1947
+ /** A small badge after the label (e.g. dirty count, live pill). */
1948
+ badge?: ReactNode | undefined;
1949
+ };
1950
+ type WorkspaceDockProps = {
1951
+ /** The chat / primary pane shown beside the dock. */
1952
+ primary: ReactNode;
1953
+ tabs: WorkspaceTab[];
1954
+ /** Controlled active tab. Falls back to the first tab. */
1955
+ activeTab?: string | undefined;
1956
+ onActiveTabChange?: ((id: string) => void) | undefined;
1957
+ /** Persisted layout id (localStorage key) for react-resizable-panels. */
1958
+ autoSaveId?: string | undefined;
1959
+ /** Default dock width as a percent of the session area. */
1960
+ defaultSize?: number | undefined;
1961
+ minSize?: number | undefined;
1962
+ maxSize?: number | undefined;
1963
+ className?: string | undefined;
1964
+ };
1965
+ /**
1966
+ * The resizable / collapsible / maximizable right-hand Workspace dock. Replaces
1967
+ * a fixed grid column: drag the separator to set width, collapse to a thin rail
1968
+ * that re-opens on click, and maximize to a full-workspace overlay (Esc /
1969
+ * restore button returns). Layout persists via `useDefaultLayout` keyed on
1970
+ * `autoSaveId`. Maximize is a mode ABOVE the Group (a `fixed inset-0` overlay) —
1971
+ * pushing a Panel to ~100% still fights min sizes and leaves a chat sliver.
1972
+ */
1973
+ declare function WorkspaceDock({ primary, tabs, activeTab, onActiveTabChange, autoSaveId, defaultSize, minSize, maxSize, className, }: WorkspaceDockProps): react_jsx_runtime.JSX.Element;
1974
+
1975
+ /**
1976
+ * Reconstruct a unified-diff patch string for a single `GitFileDiff` so it can
1977
+ * be fed to a generic patch renderer (e.g. Pierre's `PatchDiff`). The hook
1978
+ * already carries per-line old/new numbers and a hunk header, so we emit a
1979
+ * conventional `--- / +++ / @@` patch the parser understands.
1980
+ */
1981
+ declare function gitFileDiffToPatch(file: GitFileDiff): string;
1982
+
1983
+ /**
1984
+ * Derive an xterm `ITheme` subset from the live OKLCH `--og-*` token system (or
1985
+ * the app's `--color-*` aliases). Reads the COMPUTED values so xterm — which
1986
+ * paints into a canvas and can't consume CSS vars — gets concrete colors. Call
1987
+ * on mount and re-derive on a `data-og-theme` flip.
1988
+ *
1989
+ * SSR-safe: returns undefined off the DOM (the caller keeps xterm's defaults).
1990
+ */
1991
+ declare function xtermThemeFromTokens(root?: HTMLElement | null): XtermTheme | undefined;
1992
+
965
1993
  /** Merge class names with Tailwind-aware conflict resolution. */
966
1994
  declare function cn(...inputs: ClassValue[]): string;
967
1995
 
@@ -976,4 +2004,4 @@ declare function stringifyPayload(value: unknown): string;
976
2004
  /** JSON.parse that returns `undefined` instead of throwing. */
977
2005
  declare function tryParseJson(text: string): unknown;
978
2006
 
979
- export { type AgentMessageItem, ChatComposer, type ChatComposerProps, type ClientOverride, type CommandContext, CommandPalette, type CommandPaletteProps, type CommandResult, type ComposerMode, type ComposerSendExtras, type ComposerState, type ConfirmState, type FileAttachment, FleetTile, type FleetTileProps, type GoalItem, Markdown, type MarkdownProps, MessageTimeline, type MessageTimelineProps, ModelPicker, type ModelPickerProps, type Notice, type NoticeItem, type OpenGeniContextValue, OpenGeniProvider, type OpenGeniProviderProps, type ParsedCommandLine, type PendingApproval, type ReasoningItem, SESSION_STATUS_META, type SandboxItem, type SessionClientLike, type SessionEventsConnectionState, SessionStatus, type SessionStatusItem, type SessionStatusMeta, type SessionStatusProps, type SlashArg, type SlashCommand, type SlashCommandContext, type SlashCommandHandlers, StatusDot, type StatusDotProps, type TimelineGroup, type TimelineItem, type ToolCallItem, type UseAvailableModelsOptions, type UseAvailableModelsResult, type UseBillingUsageOptions, type UseBillingUsageResult, type UseComposerOptions, type UseEnvironmentsOptions, type UseEnvironmentsResult, type UseFileAttachmentsOptions, type UseFileAttachmentsResult, type UseGoalOptions, type UseGoalResult, type UsePacksOptions, type UsePacksResult, type UseScheduledTasksOptions, type UseScheduledTasksResult, type UseSessionControlOptions, type UseSessionControlResult, type UseSessionEventsOptions, type UseSessionEventsResult, type UseSessionOptions, type UseSessionResult, type UseSlashCommandsOptions, type UseSlashCommandsResult, type UseTurnQueueOptions, type UseTurnQueueResult, type UseWorkspaceSessionsOptions, type UseWorkspaceSessionsResult, type UseWorkspacesOptions, type UseWorkspacesResult, type UserMessageItem, type WorkerItem, activeTurnFromTurns, applyTurnEdit, applyTurnRemoval, applyTurnReorder, approvalsFromRequiresAction, argHint, buildTimeline, cn, compactPayloadPreview, composeSendInput, defaultCommands, extractSessionRef, filterCommands, firstMissingRequiredArg, formatBytes, formatRelativeTime, groupTimeline, hasPermission, isGoalEvent, isTurnQueueEvent, matchCommand, parseCommandLine, projectPendingApprovals, queueFromTurns, sessionDisplayTitle, sessionStatusFromEvents, shouldSubmitOnKey, stringifyPayload, toolDisplayName, truncate, tryParseJson, useAvailableModels, useBillingUsage, useComposer, useEnvironments, useFileAttachments, useGoal, useOpenGeni, useOpenGeniClient, usePacks, useScheduledTasks, useSession, useSessionControl, useSessionEvents, useSlashCommands, useTurnQueue, useWorkspaceSessions, useWorkspaces };
2007
+ export { ActivityDisclosure, type ActivityDisclosureProps, type ActivityItem, ActivityRail, type ActivityRailProps, type AgentMessageItem, type ApplyPatchOperation, BodyNote, ChatComposer, type ChatComposerProps, type ClientOverride, CodeEditor, type CodeEditorProps, type CommandContext, CommandPalette, type CommandPaletteProps, type CommandResult, type ComposerMode, type ComposerSendExtras, type ComposerState, type ConfirmState, type CreateToolRegistryOptions, DesktopViewer, type DesktopViewerProps, type DiffTheme, DiffView, type DiffViewProps, type DisclosureChip, DisclosureDefaultsProvider, type FileAttachment, FileBrowser, type FileBrowserProps, type FileTreeNode, type FileTreeStatus, FleetTile, type FleetTileProps, type GoalItem, LightboxProvider, Markdown, type MarkdownProps, MediaEmpty, MediaSkeleton, MessageTimeline, type MessageTimelineProps, ModelPicker, type ModelPickerProps, type Notice, type NoticeItem, type OpenGeniContextValue, OpenGeniProvider, type OpenGeniProviderProps, type ParsedCommandLine, PayloadBlock, type PendingApproval, PierreDiff, type PierreDiffProps, PierreFile, type PierreFileProps, type ReasoningItem, SESSION_STATUS_META, SandboxFiles, type SandboxFilesProps, type SandboxItem, SandboxTerminal, type SandboxTerminalProps, ScreenshotFigure, type SessionCapabilitiesState, type SessionClientLike, type SessionEventsConnectionState, SessionStatus, type SessionStatusItem, type SessionStatusMeta, type SessionStatusProps, type SlashArg, type SlashCommand, type SlashCommandContext, type SlashCommandHandlers, StatusDot, type StatusDotProps, TermBlock, type TerminalChunk, type TerminalStreamStatus, Thumbnail, type TimelineGroup, type TimelineItem, TimelineRow, type ToolCallItem, type ToolRegistry, type ToolRegistryEntry, type ToolRenderer, type ToolRendererProps, type TurnOutcome, TurnSummary, type TurnSummaryProps, type UseAvailableModelsOptions, type UseAvailableModelsResult, type UseBillingUsageOptions, type UseBillingUsageResult, type UseComposerOptions, type UseDesktopStreamOptions, type UseDesktopStreamResult, type UseEnvironmentsOptions, type UseEnvironmentsResult, type UseFileAttachmentsOptions, type UseFileAttachmentsResult, type UseGoalOptions, type UseGoalResult, type UsePacksOptions, type UsePacksResult, type UseSandboxFilesOptions, type UseSandboxFilesResult, type UseSandboxGitOptions, type UseSandboxGitResult, type UseSandboxTerminalOptions, type UseSandboxTerminalResult, type UseScheduledTasksOptions, type UseScheduledTasksResult, type UseSessionCapabilitiesOptions, type UseSessionCapabilitiesResult, type UseSessionControlOptions, type UseSessionControlResult, type UseSessionEventsOptions, type UseSessionEventsResult, type UseSessionOptions, type UseSessionResult, type UseSlashCommandsOptions, type UseSlashCommandsResult, type UseTerminalStreamOptions, type UseTerminalStreamResult, type UseTurnQueueOptions, type UseTurnQueueResult, type UseWorkspaceSessionsOptions, type UseWorkspaceSessionsResult, type UseWorkspacesOptions, type UseWorkspacesResult, type UserMessageItem, type WorkerItem, WorkspaceDock, type WorkspaceDockProps, type WorkspaceTab, type XtermTheme, activeTurnFromTurns, applyPatchOps, applyTurnEdit, applyTurnRemoval, applyTurnReorder, approvalsFromRequiresAction, argHint, buildTimeline, cn, composeSendInput, controlCaret, createDefaultToolRegistry, createToolRegistry, defaultCommands, defaultToolRegistry, execTruncated, extractSessionRef, filterCommands, firstMissingRequiredArg, formatBytes, formatRelativeTime, gitFileDiffToPatch, groupTimeline, hasPermission, isApplyPatch, isExecSessionLostBanner, isGoalEvent, isTitleEvent, isTurnQueueEvent, languageForPath, looksBinary, matchCommand, parseCommandLine, parseExecBannerSessionId, parseToolArgs, projectPendingApprovals, queueFromTurns, rawTypeOf, redactSecrets, sandboxCommandExitCode, sessionDisplayTitle, sessionStatusFromEvents, shouldSubmitOnKey, stringifyPayload, stripExecBanner, tailPeek, toolDisplayName, truncate, tryParseJson, unwrapMcpOutput, useAvailableModels, useBillingUsage, useComposer, useDesktopStream, useEnvironments, useFileAttachments, useGoal, useLightbox, useLightboxOptional, useOpenGeni, useOpenGeniClient, usePacks, useSandboxFiles, useSandboxGit, useSandboxTerminal, useScheduledTasks, useSession, useSessionCapabilities, useSessionControl, useSessionEvents, useSlashCommands, useTerminalStream, useTurnQueue, useWorkspaceSessions, useWorkspaces, v4aToGitFileDiff, xtermThemeFromTokens };