Skip to content

zidane-ui/app

import { … } from 'zidane-ui/app'ui/src/app/index.ts

Components#

AppHostProviderComponent#

Provides an AppHost to the components below it, host.chat through a ChatProvider and host.palette through a PaletteProvider when present.

TypeScript
function AppHostProvider(props: AppHostProviderProps): Element
Parameters
NameTypeDescription
propsAppHostProviderProps

Provider props: the host, optional chatLabels, and the children to render.

Element
AppHostProvider props
NameTypeDescription
chatLabels?Partial<{ addDiagnosticToChat: (message: string) => string; addFavorite: string; additionalInstructions: string; additionalInstructionsHint: string; additionalInstructionsPlaceholder: string; address: string; addressPlaceholder: string; addToChat: string; agent: string; agentDraftNote: string; agentProfiles: string; archive: string; archived: string; attachFile: string; attachmentEmpty: (name: string) => string; attachmentExportPdf: (name: string) => string; attachmentNotices: string; attachmentReadFailed: (name: string) => string; attachments: string; attachmentTitle: (name: string, detail: string) => string; attachmentTooLarge: (name: string, size: string, limit: string) => string; attachmentUnreadableImage: (name: string) => string; attachmentUnsupported: (name: string) => string; authCancel: string; authCard: string; authCopied: string; authCopyDetails: string; authEnterCode: (code: string) => string; authFailed: (message: string) => string; authFixed: string; authHeadline: (auth: AuthFailure, label: string) => string; authOpeningBrowser: string; authOpenPage: string; authPaste: string; authPasteSend: string; authSettings: string; authSettingsHint: string; authSignedIn: string; authSignedInRetrying: string; authSignInAgain: string; authSwitching: (account: string) => string; authTryAgain: string; authUseAccount: (account: string) => string; authWaiting: string; autoDenied: string; back: string; badgeCopied: string; badgeNoComposer: string; badgeOpenIn: (app: string) => string; badgeOpenInBrowserPane: string; badgePathUnavailable: string; blockRunAgain: string; blockRunAttach: string; blockRunAttachmentName: string; blockRunCopy: string; blockRunFailed: (reason: string) => string; blockRunHere: string; blockRunInTerminal: string; blockRunMenu: string; blockRunNeedsTerminal: string; blockRunning: string; blockRunOutput: string; blockRunRemove: string; blockRunStop: string; blockRunStopped: string; blockRunTimedOut: string; blockRunTruncated: string; cancel: string; chats: string; chipBranch: (name: string) => string; chipChat: (name: string) => string; chipCommand: (name: string) => string; chipCommit: (sha: string) => string; chipFactAliases: string; chipFactBranch: string; chipFactChanges: string; chipFactContext: string; chipFactDate: string; chipFactModel: string; chipFactPrompts: string; chipFactSize: string; chipFactTurns: string; chipFactUpdated: string; chipLoading: string; chipNotAmongChats: string; chipNotFound: (title: string) => string; chipRemoteFile: (path: string, host: string) => string; chipSessionError: string; chipSessionRunning: string; chipSkill: (name: string) => string; chipTokens: (count: string) => string; chipUntitledChat: string; chooseModel: string; clickToAnswer: string; close: string; closeTab: (name: string) => string; code: string; collapseGroup: (label: string) => string; commandDetail: string; commandSuggestions: string; completionSuggestions: string; composerBadges: string; composerLabel: string; composerPlaceholder: string; composerPlaceholderQueue: string; composerPlaceholderSteer: string; confirm: string; confirmNo: string; confirmYes: string; contextActiveSkills: string; contextAutoCompact: (pct: number) => string; contextCacheRead: string; contextCacheWrite: string; contextClickToCopy: (hasDescription: boolean) => string; contextCopied: string; contextDeferred: string; contextDetail: string; contextEstimated: string; contextFreshInput: string; contextLastTurn: string; contextNoBreakdown: string; contextOutput: string; contextRunCount: (runs: number) => string; contextSessionCost: string; contextSummary: (used: string, window: string, pct: number) => string; contextSummaryCost: (summary: string, cost: string) => string; contextWindow: string; continue: string; continueHint: string; continueRun: string; copied: string; copy: string; copyCode: string; copyDiagramSource: string; copyImage: string; copyImageBase64: string; copyImageDataUrl: string; current: string; declineSecret: string; declineSecretHint: string; defaultAgent: string; delete: string; diagnosticsCheckedBy: (source: string) => string; diagnosticsChecking: string; diagnosticsNone: string; diagram: (type: string | null) => string; diagramError: (message: string, at: string) => string; diagramErrorAt: (line: number, column: number) => string; dismiss: string; dismissHint: string; dotAttached: string; dotAttention: string; dotCompleted: string; dotError: string; dotIdle: string; dotPending: string; dotRunning: string; earlierHistory: string; earlierLines: (count: number) => string; earlierMessages: (count: number) => string; editorConflict: string; editorConflictDetail: string; editorEmpty: string; editorOverwrite: string; editorReadFailed: (message: string) => string; editorReload: string; effortLevel: (level: string) => string; errorFailed: (region: string) => string; errorStack: string; errorTryAgain: string; estimateDue: string; estimateDueTitle: string; estimateOver: string; estimateOverTitle: string; estimatePausedTitle: (left: string) => string; estimateProblemTitle: (reason: string, message?: string) => string; estimateTitle: (left: string) => string; expandGroup: (label: string) => string; favorites: string; filePath: (path: string) => string; fileReadOnly: (path: string) => string; fileTree: string; fileUnsaved: string; fileUnsavedTitle: (path: string) => string; filterActivities: { '1d': string; '30d': string; '3d': string; '7d': string; all: string }; filterActivity: string; filterAgent: string; filterAllAgents: string; filterAllAgentsOption: string; filterAllProjects: string; filterAllProjectsOption: string; filterAny: string; filterNoAgents: string; filterNoProjects: string; filterOrigin: string; filterOrigins: { all: string; scheduled: string; unscheduled: string }; filterPicked: (count: number) => string; filterProject: string; filterSaveView: string; filterSessions: string; filterSort: string; filterSorts: { alphabetical: string; createdTime: string; recency: string }; filterSpaceDefault: string; filterStatus: string; filterStatuses: { active: string; all: string; archived: string }; filterView: string; filterViews: { agent: string; date: string; host: string; none: string; project: string; state: string }; findClose: string; findCloseHint: string; findInConversation: string; findInConversationClose: string; findInFile: string; findMatchCase: string; findNext: string; findNextHint: string; findNoResults: string; findPrevious: string; findPreviousHint: string; findReferences: string; fitDiagram: string; foldOutcomes: (ok: number, failed: number) => string; foldSteps: (count: number) => string; generatedImage: string; generatingImage: (model: string | null) => string; generatingImages: (count: number, model: string | null) => string; goToDefinition: string; goToStep: (step: string) => string; hostBadgeTitle: (host: string, status: string) => string; hostCollapse: (name: string) => string; hostExpand: (name: string) => string; hostOpenSettings: (host: string) => string; hostPicker: string; hostRunsOn: (name: string) => string; hostRunsOnSection: string; hostStatusError: (status: string, error: string) => string; hostStatuses: { 'auth-refused': string; connected: string; connecting: string; identity: string; local: string; offline: string; reconnecting: string; 'version-mismatch': string }; hostThisMachine: string; imageModelReferences: string; imageModelReferencesHint: string; imageModelsNone: string; imageModelsPill: string; imageModelTransparency: string; imageModelTransparencyHint: string; inboxEmpty: string; inboxInProgress: string; inboxNeedsYou: string; inboxPreviousSession: string; inboxRecent: string; inputCaption: string; interactionAnsweredBy: (who: string) => string; interactionApproved: string; interactionDismissed: string; interactionPlan: string; interactionQuestion: string; interactionRejected: string; interactionRevise: string; interactionsLabel: string; interactionWaitingAnswers: string; interactionWaitingDecision: string; justNow: string; loadEarlierHistory: string; loadFullOutput: string; loading: string; loadingEarlierHistory: string; loadingEarlierMessages: string; loadingFullOutput: string; mentionSuggestions: string; modalBack: string; modalFailed: string; modelAccountBlocked: (provider: string) => string; modelChain: string; modelChainNoModel: string; modelChainOrderHint: string; modelFallback: string; modelFallbackHint: string; modelFallbackPosition: (n: number) => string; modelFeatures: string; modelForNextChat: string; modelInUse: string; modelKinds: string; modelLegacy: string; modelLegacyHint: string; modelNotInCatalog: string; modelNotInCatalogHint: string; modelOptions: string; modelOptionsEmpty: string; modelOptionsHint: string; modelPrimary: string; modelPrimaryHint: string; modelReasoning: string; modelReasoningHint: string; modelRemoveFallback: (n: number) => string; modelRemoveFromChain: string; modelRemovePrimary: string; modelsChatTab: string; modelsCustomId: string; modelServing: (picked: string, serving: string) => string; modelServingFallback: string; modelsImageTab: string; modelsInUse: string; modelsJumpHint: (provider: string, digit: number | null) => string; modelsJumpToProvider: string; modelsLegacy: string; modelsLegacyHidden: (count: number) => string; modelsLoadFailed: (error: string) => string; modelsLoading: string; modelsNoMatch: (query: string) => string; modelsNoProviders: string; modelsSelected: (count: number) => string; modelsShowLegacy: string; modelsShowLegacyHint: string; modelsShownOf: (shown: number, total: number) => string; modelsTypeAnId: string; modelUnavailable: string; modelVerdictTitle: (approved: boolean, model: string, confidence: string | null) => string; modelVia: string; modelViaHint: (modelId: string, provider: string) => string; months: readonly string[]; moreActions: string; moreAttachments: (count: number) => string; newSession: string; newSessionIn: (label: string) => string; next: string; noAnswer: string; noMatches: (query: string) => string; noReferences: string; noSessions: string; noSuggestions: string; of: (index: number, count: number) => string; openFiles: string; openGroup: (label: string) => string; openImageFile: (path: string) => string; openInNewTab: string; openNamedSession: (title: string) => string; openSecrets: string; openSession: string; outputCaption: string; paletteBack: string; paletteBackHint: string; paletteChoose: string; paletteEmpty: string; paletteFilter: string; paletteLabel: string; paletteLoading: string; paletteNoMatch: (query: string) => string; paletteOpen: string; paletteRun: string; paletteScopeHint: string; paletteTurnOff: string; paletteTurnOn: string; pickModel: string; pickOneOrMore: string; planApprove: string; planReject: string; planRejectAndStop: string; planRejectNote: string; planRejectPlaceholder: string; planRevise: string; planReviseNote: string; planRevisePlaceholder: string; planSendRevision: string; previewFailed: (name: string) => string; previewTooLarge: (name: string, size: string) => string; previous: string; questionCount: (count: number) => string; queueHint: string; queueMessage: string; reasoningEffort: string; receiptAgent: string; receiptAgentSwitched: string; receiptCost: string; receiptDuration: string; receiptModel: string; receiptModelOthers: (others: number) => string; receiptSpeed: string; receiptTokens: (sent: string, received: string) => string; receiptTurns: (turns: number) => string; reload: string; removeAttachment: (name: string) => string; removeFavorite: string; rename: string; requiredHint: string; requiredMark: string; resetsAt: (time: string) => string; retry: string; retryHint: string; runningFor: (elapsed: string) => string; runReceipt: string; runRetrying: (attempt: number, max: number, source?: string) => string; runWaiting: string; saveSecurely: string; screenBack: (screen: string) => string; screenBackKey: string; scriptCallsDone: (done: number) => string; scriptCallsFailed: (failed: number) => string; scriptCallsOf: (done: number, total: number) => string; scriptCallsRunning: (running: number) => string; scriptLineCalls: (calls: number) => string; scriptLiveOutput: string; scriptLoop: string; scriptLoopRound: (round: number) => string; scriptLoopRounds: (rounds: number) => string; scriptLoopRuns: (runs: number) => string; scriptOptionOutput: string; scriptOptions: string; scriptOptionTimeout: string; scriptOptionTokens: (tokens: number) => string; scriptPercent: (percent: number) => string; scriptProgress: string; scriptWaitLeft: (seconds: number) => string; searchModels: string; searchModelsPlaceholder: string; searchSessions: string; secretDeclined: (name: string) => string; secretNote: (ttl: SecretTtl) => string; secretReused: (name: string) => string; secretSaved: (name: string, left: SecretTimeLeft) => string; secretSent: (name: string) => string; secretTtlLabel: string; secretTtlName: (ttl: SecretTtl) => string; secretValueLabel: string; secretValuePlaceholder: string; selectTurnCopied: string; selectTurnCopy: string; selectTurnDetails: string; selectTurnExit: string; selectTurnFork: string; selectTurnForkFailed: string; selectTurnMove: string; selectTurnNothingToCopy: string; selectTurnSelecting: string; sendAnswers: (count: number) => string; sendHint: string; sendMessage: string; sessionActions: string; sessionEventLabel: (title: string, verb: string, needsAttention: boolean) => string; sessions: string; setModelOptions: string; shellCancelled: string; shellExit: (code: number) => string; shellKilled: string; showDiagram: string; showDiagramSource: string; showMore: string; showMoreAttachments: (count: number) => string; showOutput: string; showSystemPrompt: string; signInCopyCode: string; signInDone: (account?: string) => string; signInEnterCode: (host: string) => string; signInFailed: string; signInInBrowser: (service: string) => string; signInNotOpened: string; signInOpenPage: string; signInPaste: string; signInStarting: string; signInSubmit: string; skip: string; spawnResumes: (childId: string) => string; spawnTask: string; stateCompleted: string; stateError: string; stateIdle: string; stateRunning: string; steerHint: string; steerMessage: string; stepDone: string; stepFailed: string; stepOf: (index: number, count: number) => string; stepResuming: string; stepRunning: string; steps: string; stepWaiting: string; stopCommand: string; stopHint: string; stopped: string; stoppedByYou: string; stopRun: string; switchAgent: string; switchingAgent: string; switchModel: string; terminal: string; terminalExited: (code: number) => string; terminalLoadFailed: (message: string) => string; thinkingLive: string; thoughtFor: (seconds: number) => string; thoughts: string; thoughtTimes: (count: number) => string; today: string; toolAttachments: string; transcriptLoading: string; turnMenuCopy: string; turnMenuCopySelection: string; turnMenuCopySelectionFailed: string; turnMenuDelete: string; turnMenuEdit: string; turnMenuEditNeedsComposer: string; turnMenuFork: string; turnMenuRewind: string; turnMenuSent: (age: string) => string; turnMenuStopFirst: (label: string) => string; turnsCompacted: string; unarchive: string; unsupportedInteraction: (tool: string) => string; viewAttachment: (name: string) => string; waitingForSlot: (max: number) => string; workerContinues: string; workerModel: string; workerSystemPrompt: string; workerSystemReplaced: string; workerType: string; working: string; wrapLines: string; yesterday: string; zoomFit: string; zoomInDiagram: string; zoomOutDiagram: string; zoomPercent: (percent: number) => string }>

Overrides for the chat components' strings, passed to ChatProvider. Keys you leave out keep the default English label.

childrenReactNode

The app's components.

hostAppHost

Every area's host the app offers.

loadExtensionModule?ExtensionModuleLoader

Loads an extension's ui.tsx module for the extension components (ExtensionsProvider's loadModule). Absent: extension items draw their data.

ui/src/app/AppHostProvider.tsx:62

ModalProviderComponent#

Holds the modal slot and its stacked layer, and renders them above children (see the top of this file).

TypeScript
function ModalProvider(props: ModalProviderProps): Element
Parameters
NameTypeDescription
propsModalProviderProps

The children and an optional chromeInset.

Element
ModalProvider props
NameTypeDescription
childrenReactNode

The app: inert while a modal is open.

chromeInset?ModalChromeInset

Native window chrome over the page; absent: a 44px band with nothing to keep clear.

ui/src/app/ModalProvider.tsx:149

ModalShellComponent#

Standard modal shell — title row + body + optional footer. Every modal in the app uses this so spacing, borders, and the close-X stay consistent.

TypeScript
function ModalShell(props: ModalShellProps): Element
Parameters
NameTypeDescription
propsModalShellProps

The title, body, footer, size and close handlers.

Element
ModalShell props
NameTypeDescription
childrenReactNode

The body.

className?string

Extra classes on the panel.

description?ReactNode

A line under the title.

footer?ReactNode

Optional element rendered in the bottom-right corner (e.g. primary action).

onBack?() => void

Optional back-navigation handler. When set, the header renders a chevron-left button to the left of the title. Used by the surfaces Settings opens (Safelist, the Claude Code import) so the sub-modal can return to Settings instead of dead-ending on close. onClose is still called for the X button and Esc.

onClose() => void

The close button and Esc.

scrollBody?boolean

When false, the shell body clips instead of scrolling and the child owns its scroll containers. For modals with an internal fixed rail + scrolling panel (Settings): a scrolling shell body would drag the rail along whenever the content outgrows the viewport. Default true.

size?'medium' | 'large' | 'xlarge' | 'xxlarge'

Size preset, by panel width: medium 560px for forms / pickers; large 760px for content-rich surfaces (the model picker, the safelist); xlarge 920px for diff-heavy modals (the file-edit review, chat/composer/ApprovalDock.tsx); xxlarge 1040px for workspace-style surfaces with their own internal navigation. It also raises the height cap from 85vh to 88vh. Every preset is clamped by max-w-[92vw] on narrower windows.

style?CSSProperties

Inline styles on the panel.

titleReactNode

Plain string for most modals; a ReactNode lets a modal animate its own heading content (Settings crossfades the active tab's label in place).

ui/src/app/ModalProvider.tsx:568

ScreenShellComponent#

Two-column full-window shell mirroring the chat layout: a sidebar-width left column on the tray tone (traffic-light spacer, back button, then whatever navigation the surface provides) and a main column with a heading row over the content. Escape and the back button both call onClose.

TypeScript
function ScreenShell(props: ScreenShellProps): Element
Parameters
NameTypeDescription
propsScreenShellProps

The heading, the left column, the body and onClose.

Element
ScreenShell props
NameTypeDescription
aside{ nav: ReactNode; search?: ReactNode }

Left column: search shares the title row; nav fills the rest.

asideFooter?ReactNode

Pinned to the bottom of the left column.

childrenReactNode

The main column's body.

className?string

Extra classes on the root.

description?ReactNode

A line under the heading.

headerActions?ReactNode

Right-aligned controls on the main header row.

lead?ReactNode

Before the heading and its line (a mark).

onClose() => void

The back button and Esc.

screenLabelstring

Label for the back affordance in the left column, e.g. "Settings".

style?CSSProperties

Inline styles on the root.

titleReactNode

Heading for the main column (stamped with MODAL_TITLE_ID).

ui/src/app/ModalProvider.tsx:654

Functions#

useAppHostFunction#

Returns the AppHost from the nearest AppHostProvider. Throws when called outside one.

TypeScript
function useAppHost(): AppHost

ui/src/app/AppHostProvider.tsx:131

useConfirmFunction#

A function that opens a ConfirmDialog above whatever is open and resolves with the choice. Needs a ModalProvider.

TypeScript
function useConfirm(): (options: ConfirmOptions) => Promise<boolean>
(options: ConfirmOptions) => Promise<boolean>

ui/src/app/useConfirm.tsx:46

useModalFunction#

The modal layer of the nearest ModalProvider; throws outside one.

TypeScript
function useModal(): ModalContextValue

ui/src/app/ModalProvider.tsx:392

useOptionalConfirmFunction#

useConfirm where a ModalProvider may be missing (a component mounted on its own, a gallery): null there, so the caller leaves out what must ask first.

TypeScript
function useOptionalConfirm(): ((options: ConfirmOptions) => Promise<boolean>) | null
((options: ConfirmOptions) => Promise<boolean>) | null

ui/src/app/useConfirm.tsx:55

useOptionalModalFunction#

The modal layer, or null outside a ModalProvider (a component that can do without it).

TypeScript
function useOptionalModal(): ModalContextValue | null

ui/src/app/ModalProvider.tsx:387

useResourceFunction#

The resource spec describes, kept current (null: nothing). Re-renders only when its snapshot changes.

TypeScript
function useResource<T, Topic extends string = string>(
  store: ResourceStore<Topic>,
  spec: ResourceSpec<T, Topic> | null,
): ResourceSnapshot<T>
Type parameters
NameTypeDefaultDescription
T
Topicextends stringstring
Parameters
NameTypeDescription
storeResourceStore<Topic>

The store holding it.

specResourceSpec<T, Topic> | null

The resource; its key names it, so a new spec object with the same key reads the same entry.

ui/src/app/useResource.ts:17

Constants#

Stable id contract — every <ModalShell> stamps this id onto its title <h2> so the scrim can reference it via aria-labelledby. Only one modal is open at a time, so a static id is collision-free.

TypeScript
const MODAL_TITLE_ID = 'zg-modal-title'

ui/src/app/ModalProvider.tsx:57

Interfaces#

AppHostProviderPropsInterface#

Props for AppHostProvider.

TypeScript
interface AppHostProviderProps
AppHostProviderProps properties
NameTypeDescription
chatLabels?Partial<{ addDiagnosticToChat: (message: string) => string; addFavorite: string; additionalInstructions: string; additionalInstructionsHint: string; additionalInstructionsPlaceholder: string; address: string; addressPlaceholder: string; addToChat: string; agent: string; agentDraftNote: string; agentProfiles: string; archive: string; archived: string; attachFile: string; attachmentEmpty: (name: string) => string; attachmentExportPdf: (name: string) => string; attachmentNotices: string; attachmentReadFailed: (name: string) => string; attachments: string; attachmentTitle: (name: string, detail: string) => string; attachmentTooLarge: (name: string, size: string, limit: string) => string; attachmentUnreadableImage: (name: string) => string; attachmentUnsupported: (name: string) => string; authCancel: string; authCard: string; authCopied: string; authCopyDetails: string; authEnterCode: (code: string) => string; authFailed: (message: string) => string; authFixed: string; authHeadline: (auth: AuthFailure, label: string) => string; authOpeningBrowser: string; authOpenPage: string; authPaste: string; authPasteSend: string; authSettings: string; authSettingsHint: string; authSignedIn: string; authSignedInRetrying: string; authSignInAgain: string; authSwitching: (account: string) => string; authTryAgain: string; authUseAccount: (account: string) => string; authWaiting: string; autoDenied: string; back: string; badgeCopied: string; badgeNoComposer: string; badgeOpenIn: (app: string) => string; badgeOpenInBrowserPane: string; badgePathUnavailable: string; blockRunAgain: string; blockRunAttach: string; blockRunAttachmentName: string; blockRunCopy: string; blockRunFailed: (reason: string) => string; blockRunHere: string; blockRunInTerminal: string; blockRunMenu: string; blockRunNeedsTerminal: string; blockRunning: string; blockRunOutput: string; blockRunRemove: string; blockRunStop: string; blockRunStopped: string; blockRunTimedOut: string; blockRunTruncated: string; cancel: string; chats: string; chipBranch: (name: string) => string; chipChat: (name: string) => string; chipCommand: (name: string) => string; chipCommit: (sha: string) => string; chipFactAliases: string; chipFactBranch: string; chipFactChanges: string; chipFactContext: string; chipFactDate: string; chipFactModel: string; chipFactPrompts: string; chipFactSize: string; chipFactTurns: string; chipFactUpdated: string; chipLoading: string; chipNotAmongChats: string; chipNotFound: (title: string) => string; chipRemoteFile: (path: string, host: string) => string; chipSessionError: string; chipSessionRunning: string; chipSkill: (name: string) => string; chipTokens: (count: string) => string; chipUntitledChat: string; chooseModel: string; clickToAnswer: string; close: string; closeTab: (name: string) => string; code: string; collapseGroup: (label: string) => string; commandDetail: string; commandSuggestions: string; completionSuggestions: string; composerBadges: string; composerLabel: string; composerPlaceholder: string; composerPlaceholderQueue: string; composerPlaceholderSteer: string; confirm: string; confirmNo: string; confirmYes: string; contextActiveSkills: string; contextAutoCompact: (pct: number) => string; contextCacheRead: string; contextCacheWrite: string; contextClickToCopy: (hasDescription: boolean) => string; contextCopied: string; contextDeferred: string; contextDetail: string; contextEstimated: string; contextFreshInput: string; contextLastTurn: string; contextNoBreakdown: string; contextOutput: string; contextRunCount: (runs: number) => string; contextSessionCost: string; contextSummary: (used: string, window: string, pct: number) => string; contextSummaryCost: (summary: string, cost: string) => string; contextWindow: string; continue: string; continueHint: string; continueRun: string; copied: string; copy: string; copyCode: string; copyDiagramSource: string; copyImage: string; copyImageBase64: string; copyImageDataUrl: string; current: string; declineSecret: string; declineSecretHint: string; defaultAgent: string; delete: string; diagnosticsCheckedBy: (source: string) => string; diagnosticsChecking: string; diagnosticsNone: string; diagram: (type: string | null) => string; diagramError: (message: string, at: string) => string; diagramErrorAt: (line: number, column: number) => string; dismiss: string; dismissHint: string; dotAttached: string; dotAttention: string; dotCompleted: string; dotError: string; dotIdle: string; dotPending: string; dotRunning: string; earlierHistory: string; earlierLines: (count: number) => string; earlierMessages: (count: number) => string; editorConflict: string; editorConflictDetail: string; editorEmpty: string; editorOverwrite: string; editorReadFailed: (message: string) => string; editorReload: string; effortLevel: (level: string) => string; errorFailed: (region: string) => string; errorStack: string; errorTryAgain: string; estimateDue: string; estimateDueTitle: string; estimateOver: string; estimateOverTitle: string; estimatePausedTitle: (left: string) => string; estimateProblemTitle: (reason: string, message?: string) => string; estimateTitle: (left: string) => string; expandGroup: (label: string) => string; favorites: string; filePath: (path: string) => string; fileReadOnly: (path: string) => string; fileTree: string; fileUnsaved: string; fileUnsavedTitle: (path: string) => string; filterActivities: { '1d': string; '30d': string; '3d': string; '7d': string; all: string }; filterActivity: string; filterAgent: string; filterAllAgents: string; filterAllAgentsOption: string; filterAllProjects: string; filterAllProjectsOption: string; filterAny: string; filterNoAgents: string; filterNoProjects: string; filterOrigin: string; filterOrigins: { all: string; scheduled: string; unscheduled: string }; filterPicked: (count: number) => string; filterProject: string; filterSaveView: string; filterSessions: string; filterSort: string; filterSorts: { alphabetical: string; createdTime: string; recency: string }; filterSpaceDefault: string; filterStatus: string; filterStatuses: { active: string; all: string; archived: string }; filterView: string; filterViews: { agent: string; date: string; host: string; none: string; project: string; state: string }; findClose: string; findCloseHint: string; findInConversation: string; findInConversationClose: string; findInFile: string; findMatchCase: string; findNext: string; findNextHint: string; findNoResults: string; findPrevious: string; findPreviousHint: string; findReferences: string; fitDiagram: string; foldOutcomes: (ok: number, failed: number) => string; foldSteps: (count: number) => string; generatedImage: string; generatingImage: (model: string | null) => string; generatingImages: (count: number, model: string | null) => string; goToDefinition: string; goToStep: (step: string) => string; hostBadgeTitle: (host: string, status: string) => string; hostCollapse: (name: string) => string; hostExpand: (name: string) => string; hostOpenSettings: (host: string) => string; hostPicker: string; hostRunsOn: (name: string) => string; hostRunsOnSection: string; hostStatusError: (status: string, error: string) => string; hostStatuses: { 'auth-refused': string; connected: string; connecting: string; identity: string; local: string; offline: string; reconnecting: string; 'version-mismatch': string }; hostThisMachine: string; imageModelReferences: string; imageModelReferencesHint: string; imageModelsNone: string; imageModelsPill: string; imageModelTransparency: string; imageModelTransparencyHint: string; inboxEmpty: string; inboxInProgress: string; inboxNeedsYou: string; inboxPreviousSession: string; inboxRecent: string; inputCaption: string; interactionAnsweredBy: (who: string) => string; interactionApproved: string; interactionDismissed: string; interactionPlan: string; interactionQuestion: string; interactionRejected: string; interactionRevise: string; interactionsLabel: string; interactionWaitingAnswers: string; interactionWaitingDecision: string; justNow: string; loadEarlierHistory: string; loadFullOutput: string; loading: string; loadingEarlierHistory: string; loadingEarlierMessages: string; loadingFullOutput: string; mentionSuggestions: string; modalBack: string; modalFailed: string; modelAccountBlocked: (provider: string) => string; modelChain: string; modelChainNoModel: string; modelChainOrderHint: string; modelFallback: string; modelFallbackHint: string; modelFallbackPosition: (n: number) => string; modelFeatures: string; modelForNextChat: string; modelInUse: string; modelKinds: string; modelLegacy: string; modelLegacyHint: string; modelNotInCatalog: string; modelNotInCatalogHint: string; modelOptions: string; modelOptionsEmpty: string; modelOptionsHint: string; modelPrimary: string; modelPrimaryHint: string; modelReasoning: string; modelReasoningHint: string; modelRemoveFallback: (n: number) => string; modelRemoveFromChain: string; modelRemovePrimary: string; modelsChatTab: string; modelsCustomId: string; modelServing: (picked: string, serving: string) => string; modelServingFallback: string; modelsImageTab: string; modelsInUse: string; modelsJumpHint: (provider: string, digit: number | null) => string; modelsJumpToProvider: string; modelsLegacy: string; modelsLegacyHidden: (count: number) => string; modelsLoadFailed: (error: string) => string; modelsLoading: string; modelsNoMatch: (query: string) => string; modelsNoProviders: string; modelsSelected: (count: number) => string; modelsShowLegacy: string; modelsShowLegacyHint: string; modelsShownOf: (shown: number, total: number) => string; modelsTypeAnId: string; modelUnavailable: string; modelVerdictTitle: (approved: boolean, model: string, confidence: string | null) => string; modelVia: string; modelViaHint: (modelId: string, provider: string) => string; months: readonly string[]; moreActions: string; moreAttachments: (count: number) => string; newSession: string; newSessionIn: (label: string) => string; next: string; noAnswer: string; noMatches: (query: string) => string; noReferences: string; noSessions: string; noSuggestions: string; of: (index: number, count: number) => string; openFiles: string; openGroup: (label: string) => string; openImageFile: (path: string) => string; openInNewTab: string; openNamedSession: (title: string) => string; openSecrets: string; openSession: string; outputCaption: string; paletteBack: string; paletteBackHint: string; paletteChoose: string; paletteEmpty: string; paletteFilter: string; paletteLabel: string; paletteLoading: string; paletteNoMatch: (query: string) => string; paletteOpen: string; paletteRun: string; paletteScopeHint: string; paletteTurnOff: string; paletteTurnOn: string; pickModel: string; pickOneOrMore: string; planApprove: string; planReject: string; planRejectAndStop: string; planRejectNote: string; planRejectPlaceholder: string; planRevise: string; planReviseNote: string; planRevisePlaceholder: string; planSendRevision: string; previewFailed: (name: string) => string; previewTooLarge: (name: string, size: string) => string; previous: string; questionCount: (count: number) => string; queueHint: string; queueMessage: string; reasoningEffort: string; receiptAgent: string; receiptAgentSwitched: string; receiptCost: string; receiptDuration: string; receiptModel: string; receiptModelOthers: (others: number) => string; receiptSpeed: string; receiptTokens: (sent: string, received: string) => string; receiptTurns: (turns: number) => string; reload: string; removeAttachment: (name: string) => string; removeFavorite: string; rename: string; requiredHint: string; requiredMark: string; resetsAt: (time: string) => string; retry: string; retryHint: string; runningFor: (elapsed: string) => string; runReceipt: string; runRetrying: (attempt: number, max: number, source?: string) => string; runWaiting: string; saveSecurely: string; screenBack: (screen: string) => string; screenBackKey: string; scriptCallsDone: (done: number) => string; scriptCallsFailed: (failed: number) => string; scriptCallsOf: (done: number, total: number) => string; scriptCallsRunning: (running: number) => string; scriptLineCalls: (calls: number) => string; scriptLiveOutput: string; scriptLoop: string; scriptLoopRound: (round: number) => string; scriptLoopRounds: (rounds: number) => string; scriptLoopRuns: (runs: number) => string; scriptOptionOutput: string; scriptOptions: string; scriptOptionTimeout: string; scriptOptionTokens: (tokens: number) => string; scriptPercent: (percent: number) => string; scriptProgress: string; scriptWaitLeft: (seconds: number) => string; searchModels: string; searchModelsPlaceholder: string; searchSessions: string; secretDeclined: (name: string) => string; secretNote: (ttl: SecretTtl) => string; secretReused: (name: string) => string; secretSaved: (name: string, left: SecretTimeLeft) => string; secretSent: (name: string) => string; secretTtlLabel: string; secretTtlName: (ttl: SecretTtl) => string; secretValueLabel: string; secretValuePlaceholder: string; selectTurnCopied: string; selectTurnCopy: string; selectTurnDetails: string; selectTurnExit: string; selectTurnFork: string; selectTurnForkFailed: string; selectTurnMove: string; selectTurnNothingToCopy: string; selectTurnSelecting: string; sendAnswers: (count: number) => string; sendHint: string; sendMessage: string; sessionActions: string; sessionEventLabel: (title: string, verb: string, needsAttention: boolean) => string; sessions: string; setModelOptions: string; shellCancelled: string; shellExit: (code: number) => string; shellKilled: string; showDiagram: string; showDiagramSource: string; showMore: string; showMoreAttachments: (count: number) => string; showOutput: string; showSystemPrompt: string; signInCopyCode: string; signInDone: (account?: string) => string; signInEnterCode: (host: string) => string; signInFailed: string; signInInBrowser: (service: string) => string; signInNotOpened: string; signInOpenPage: string; signInPaste: string; signInStarting: string; signInSubmit: string; skip: string; spawnResumes: (childId: string) => string; spawnTask: string; stateCompleted: string; stateError: string; stateIdle: string; stateRunning: string; steerHint: string; steerMessage: string; stepDone: string; stepFailed: string; stepOf: (index: number, count: number) => string; stepResuming: string; stepRunning: string; steps: string; stepWaiting: string; stopCommand: string; stopHint: string; stopped: string; stoppedByYou: string; stopRun: string; switchAgent: string; switchingAgent: string; switchModel: string; terminal: string; terminalExited: (code: number) => string; terminalLoadFailed: (message: string) => string; thinkingLive: string; thoughtFor: (seconds: number) => string; thoughts: string; thoughtTimes: (count: number) => string; today: string; toolAttachments: string; transcriptLoading: string; turnMenuCopy: string; turnMenuCopySelection: string; turnMenuCopySelectionFailed: string; turnMenuDelete: string; turnMenuEdit: string; turnMenuEditNeedsComposer: string; turnMenuFork: string; turnMenuRewind: string; turnMenuSent: (age: string) => string; turnMenuStopFirst: (label: string) => string; turnsCompacted: string; unarchive: string; unsupportedInteraction: (tool: string) => string; viewAttachment: (name: string) => string; waitingForSlot: (max: number) => string; workerContinues: string; workerModel: string; workerSystemPrompt: string; workerSystemReplaced: string; workerType: string; working: string; wrapLines: string; yesterday: string; zoomFit: string; zoomInDiagram: string; zoomOutDiagram: string; zoomPercent: (percent: number) => string }>

Overrides for the chat components' strings, passed to ChatProvider. Keys you leave out keep the default English label.

childrenReactNode

The app's components.

hostAppHost

Every area's host the app offers.

loadExtensionModule?ExtensionModuleLoader

Loads an extension's ui.tsx module for the extension components (ExtensionsProvider's loadModule). Absent: extension items draw their data.

ui/src/app/AppHostProvider.tsx:46

LayerOptionsInterface#

Options of ModalContextValue.openLayer.

TypeScript
interface LayerOptions
LayerOptions properties
NameTypeDescription
labelledBystring

Id of the layer's own title element.

onDismiss() => void

Called when the layer is dismissed from outside (Esc, scrim, slot closed, replaced).

ui/src/app/ModalProvider.tsx:63

ModalChromeInsetInterface#

The band native window chrome covers, in device-independent pixels.

TypeScript
interface ModalChromeInset
ModalChromeInset properties
NameTypeDescription
leadingnumber

Width kept clear at the start of that band; 0 for none.

topnumber

Height of the top band (the traffic lights' row).

ui/src/app/ModalProvider.tsx:123

ModalContextValueInterface#

What useModal returns.

TypeScript
interface ModalContextValue
ModalContextValue properties
NameTypeDescription
activeIdstring | null

Whose surface fills the slot. Callers that pass id on open can tell "still mine" from "replaced by another modal" without relying on an unmount, which StrictMode simulates in development.

close(id?: string) => void

Close the slot; with id, only while that surface still owns it (a self-close).

closeLayer() => void

Removes the layer without calling its onDismiss.

isOpenboolean

A slot surface or a stacked layer is up.

open(node: ReactNode, options?: ModalOpenOptions) => void

Show node in the slot, replacing what is there.

openLayer(node: ReactNode, options: LayerOptions) => void

Shows node above the current slot without replacing it.

setDismissHandler(handler: (() => void) | null, owner?: () => void) => void

What Esc and a scrim click call instead of close (a shell registers its onClose); null clears it. With owner, null clears only while owner is still the handler: a surface that leaves after the next one registered never clears that one's.

ui/src/app/ModalProvider.tsx:95

ModalOpenOptionsInterface#

Options of ModalContextValue.open.

TypeScript
interface ModalOpenOptions
ModalOpenOptions properties
NameTypeDescription
id?string

Names the surface, so it can tell "still mine" (ModalContextValue.activeId) and close only itself.

scrim?ModalScrimKind

The dialog scrim: blur (default) frosts the window behind a dialog you stay in; dim only darkens it, for a quick surface (the palette) that comes and goes with a key and must never cost a frame.

variant?ModalVariant

dialog (default) or screen.

ui/src/app/ModalProvider.tsx:71

ModalProviderPropsInterface#

Props for ModalProvider.

TypeScript
interface ModalProviderProps
ModalProviderProps properties
NameTypeDescription
childrenReactNode

The app: inert while a modal is open.

chromeInset?ModalChromeInset

Native window chrome over the page; absent: a 44px band with nothing to keep clear.

ui/src/app/ModalProvider.tsx:137

ModalShellPropsInterface#

Props for ModalShell.

TypeScript
interface ModalShellProps
ModalShellProps properties
NameTypeDescription
childrenReactNode

The body.

className?string

Extra classes on the panel.

description?ReactNode

A line under the title.

footer?ReactNode

Optional element rendered in the bottom-right corner (e.g. primary action).

onBack?() => void

Optional back-navigation handler. When set, the header renders a chevron-left button to the left of the title. Used by the surfaces Settings opens (Safelist, the Claude Code import) so the sub-modal can return to Settings instead of dead-ending on close. onClose is still called for the X button and Esc.

onClose() => void

The close button and Esc.

scrollBody?boolean

When false, the shell body clips instead of scrolling and the child owns its scroll containers. For modals with an internal fixed rail + scrolling panel (Settings): a scrolling shell body would drag the rail along whenever the content outgrows the viewport. Default true.

size?'medium' | 'large' | 'xlarge' | 'xxlarge'

Size preset, by panel width: medium 560px for forms / pickers; large 760px for content-rich surfaces (the model picker, the safelist); xlarge 920px for diff-heavy modals (the file-edit review, chat/composer/ApprovalDock.tsx); xxlarge 1040px for workspace-style surfaces with their own internal navigation. It also raises the height cap from 85vh to 88vh. Every preset is clamped by max-w-[92vw] on narrower windows.

style?CSSProperties

Inline styles on the panel.

titleReactNode

Plain string for most modals; a ReactNode lets a modal animate its own heading content (Settings crossfades the active tab's label in place).

ui/src/app/ModalProvider.tsx:485

ScreenShellPropsInterface#

Props for ScreenShell.

TypeScript
interface ScreenShellProps
ScreenShellProps properties
NameTypeDescription
aside{ nav: ReactNode; search?: ReactNode }

Left column: search shares the title row; nav fills the rest.

asideFooter?ReactNode

Pinned to the bottom of the left column.

childrenReactNode

The main column's body.

className?string

Extra classes on the root.

description?ReactNode

A line under the heading.

headerActions?ReactNode

Right-aligned controls on the main header row.

lead?ReactNode

Before the heading and its line (a mark).

onClose() => void

The back button and Esc.

screenLabelstring

Label for the back affordance in the left column, e.g. "Settings".

style?CSSProperties

Inline styles on the root.

titleReactNode

Heading for the main column (stamped with MODAL_TITLE_ID).

ui/src/app/ModalProvider.tsx:620

Types#

ModalScrimKindType#

The dialog scrim: blur frosts the window behind, dim only darkens it.

TypeScript
type ModalScrimKind = 'blur' | 'dim'

ui/src/app/ModalProvider.tsx:85

ModalVariantType#

How the slot presents its surface: a centred dialog over a scrim, or the whole window.

TypeScript
type ModalVariant = 'dialog' | 'screen'

ui/src/app/ModalProvider.tsx:60