@workerdeck/ui 2.13.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/{SessionPanel-CJwp5B3q.d.mts → SessionPanel-BVKqPs_3.d.mts} +9 -3
- package/build/index.d.mts +84 -6
- package/build/index.mjs +83 -37
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +24 -3
- package/build/{use-path-links-CepFsMdW.mjs → use-path-links-BgWXmfAS.mjs} +849 -236
- package/build/use-path-links-BgWXmfAS.mjs.map +1 -0
- package/build/workspace.d.mts +19 -4
- package/build/workspace.mjs +7 -4
- package/build/workspace.mjs.map +1 -1
- package/package.json +16 -6
- package/src/components/agent/Composer.tsx +18 -13
- package/src/components/agent/SessionBrowser.tsx +24 -1
- package/src/components/agent/SessionItem.tsx +13 -3
- package/src/components/agent/SessionPanel.tsx +264 -211
- package/src/components/agent/SessionSteps.tsx +78 -27
- package/src/components/agent/SessionWorkspace.tsx +10 -1
- package/src/components/agent/ShellStrip.tsx +71 -0
- package/src/components/agent/ShellTerminal.tsx +170 -0
- package/src/components/agent/SubagentToggle.tsx +7 -1
- package/src/components/agent/TranscriptItemView.tsx +74 -1
- package/src/components/agent/scrubber-marks.ts +9 -1
- package/src/components/agent/shell-actions.tsx +25 -0
- package/src/components/agent/use-shell-frame.ts +111 -0
- package/src/components/terminal/TerminalTranscript.tsx +4 -0
- package/src/components/terminal/affordances.tsx +37 -0
- package/src/components/terminal/height.ts +14 -0
- package/src/components/terminal/items.tsx +72 -3
- package/src/components/terminal/press.tsx +5 -3
- package/src/components/terminal/scrubber.tsx +9 -1
- package/src/components/terminal/shell-row.ts +106 -0
- package/src/index.ts +12 -1
- package/src/styles/terminal.css +11 -0
- package/src/styles/theme.css +3 -0
- package/src/workspace.ts +1 -0
- package/build/use-path-links-CepFsMdW.mjs.map +0 -1
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type PermissionRequest,
|
|
21
21
|
type RateLimitInfo,
|
|
22
22
|
type SessionTask,
|
|
23
|
+
type ShellInfo,
|
|
23
24
|
type SkillInfo,
|
|
24
25
|
type SubagentInfo,
|
|
25
26
|
} from '@workerdeck/protocol'
|
|
@@ -60,6 +61,9 @@ import { PermissionModeSelect, permissionModeChoices, type PermissionModeChoice
|
|
|
60
61
|
import { PermissionPrompt } from './PermissionPrompt.tsx'
|
|
61
62
|
import { SubagentStrip } from './SubagentStrip.tsx'
|
|
62
63
|
import { useSubagentFrame } from './use-subagent-frame.ts'
|
|
64
|
+
import { ShellStrip } from './ShellStrip.tsx'
|
|
65
|
+
import { ShellTerminal } from './ShellTerminal.tsx'
|
|
66
|
+
import { useShellFrame } from './use-shell-frame.ts'
|
|
63
67
|
import { QuestionPrompt, parseUserQuestions } from './QuestionPrompt.tsx'
|
|
64
68
|
import { TerminalPermissionPrompt } from '../terminal/PermissionPrompt.tsx'
|
|
65
69
|
import { TerminalQuestionPrompt } from '../terminal/QuestionPrompt.tsx'
|
|
@@ -71,6 +75,7 @@ import { SessionInfoDialog } from './SessionInfoDialog.tsx'
|
|
|
71
75
|
import { StatusBar } from './StatusBar.tsx'
|
|
72
76
|
import { Transcript } from './Transcript.tsx'
|
|
73
77
|
import { ToolResultFetchProvider } from './tool-result-fetch.tsx'
|
|
78
|
+
import { ShellActionsProvider } from './shell-actions.tsx'
|
|
74
79
|
import { ToolTitleProvider } from './tool-titles.tsx'
|
|
75
80
|
import { ToolResultImageProvider, useToolResultImages } from './tool-result-image.tsx'
|
|
76
81
|
import {
|
|
@@ -143,8 +148,12 @@ export interface SessionPanelProps {
|
|
|
143
148
|
reveal?: { toolUseId: string; nonce: number }
|
|
144
149
|
openSubagent?: { toolUseId: string; nonce: number }
|
|
145
150
|
onSubagentChange?: (toolUseId: string | undefined) => void
|
|
151
|
+
// Host request to drill in to a shell's terminal; `shellId: undefined` withdraws it (Back/Forward).
|
|
152
|
+
openShell?: { shellId: string; nonce: number }
|
|
153
|
+
onShellChange?: (shellId: string | undefined) => void
|
|
146
154
|
// The attach frame's `state.session` never refreshes, so a host that polls the sessions list passes the live records here.
|
|
147
155
|
subagents?: SubagentInfo[]
|
|
156
|
+
shells?: ShellInfo[]
|
|
148
157
|
stickyPrompt?: boolean
|
|
149
158
|
transcriptDensity?: TranscriptDensity
|
|
150
159
|
transcriptFont?: TranscriptFont
|
|
@@ -234,8 +243,11 @@ export function SessionPanel({
|
|
|
234
243
|
onToggleBookmark,
|
|
235
244
|
reveal,
|
|
236
245
|
subagents,
|
|
246
|
+
shells,
|
|
237
247
|
openSubagent,
|
|
238
248
|
onSubagentChange,
|
|
249
|
+
openShell,
|
|
250
|
+
onShellChange,
|
|
239
251
|
stickyPrompt = false,
|
|
240
252
|
controlsSurface = 'internal',
|
|
241
253
|
onControls,
|
|
@@ -283,7 +295,22 @@ export function SessionPanel({
|
|
|
283
295
|
setPermissionMode,
|
|
284
296
|
reconnectNow,
|
|
285
297
|
loadFullResult,
|
|
298
|
+
loadShellOutput,
|
|
299
|
+
verifyShell,
|
|
300
|
+
killShell,
|
|
286
301
|
} = useClaudeSession(client, sessionId, { onProtocolError: setProtocolError, cacheTranscript })
|
|
302
|
+
const {
|
|
303
|
+
shellId: framedShellId,
|
|
304
|
+
enterShell,
|
|
305
|
+
leaveShell,
|
|
306
|
+
returnReveal: shellReturnReveal,
|
|
307
|
+
shell: framedShell,
|
|
308
|
+
label: framedShellLabel,
|
|
309
|
+
} = useShellFrame({ sessionId, items: state.items, session: state.session, shells, reveal, openShell, onShellChange })
|
|
310
|
+
const shellActions = useMemo(
|
|
311
|
+
() => ({ loadOutput: loadShellOutput, verify: verifyShell, kill: killShell, open: enterShell }),
|
|
312
|
+
[loadShellOutput, verifyShell, killShell, enterShell],
|
|
313
|
+
)
|
|
287
314
|
useEffect(() => setProtocolError(undefined), [sessionId])
|
|
288
315
|
const {
|
|
289
316
|
subagentId,
|
|
@@ -295,6 +322,15 @@ export function SessionPanel({
|
|
|
295
322
|
fallbackLabel: subagentFallbackLabel,
|
|
296
323
|
} = useSubagentFrame({ sessionId, items: state.items, session: state.session, reveal, openSubagent, onSubagentChange })
|
|
297
324
|
|
|
325
|
+
// Two frames, one reveal slot: the more recent exit wins, so leaving a shell never lands on the
|
|
326
|
+
// row a sub-agent frame left behind.
|
|
327
|
+
const frameReturnReveal = useMemo(() => {
|
|
328
|
+
if (returnReveal && shellReturnReveal) {
|
|
329
|
+
return returnReveal.nonce >= shellReturnReveal.nonce ? returnReveal : shellReturnReveal
|
|
330
|
+
}
|
|
331
|
+
return returnReveal ?? shellReturnReveal
|
|
332
|
+
}, [returnReveal, shellReturnReveal])
|
|
333
|
+
|
|
298
334
|
const [caughtUp, setCaughtUp] = useState(false)
|
|
299
335
|
useEffect(() => {
|
|
300
336
|
setCaughtUp(false)
|
|
@@ -667,227 +703,244 @@ export function SessionPanel({
|
|
|
667
703
|
<TranscriptDensityProvider value={transcriptDensity}>
|
|
668
704
|
<FileLinkProvider value={fileLinks}>
|
|
669
705
|
<ToolResultFetchProvider value={loadFullResult}>
|
|
670
|
-
<
|
|
671
|
-
<
|
|
672
|
-
<
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
{
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
{
|
|
741
|
-
{
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
type="button"
|
|
752
|
-
onClick={() => setCaughtUp(true)}
|
|
753
|
-
className="shrink-0 underline-offset-2 hover:text-fg-1 hover:underline"
|
|
706
|
+
<ShellActionsProvider value={shellActions}>
|
|
707
|
+
<ToolTitleProvider value={state.toolTitles}>
|
|
708
|
+
<ToolResultImageProvider value={resultImages}>
|
|
709
|
+
<div
|
|
710
|
+
ref={panelRef}
|
|
711
|
+
data-slot="session-panel"
|
|
712
|
+
data-agent-font={transcriptFont}
|
|
713
|
+
onClick={handleClick}
|
|
714
|
+
className={cn('flex h-full min-h-0 flex-col overflow-hidden bg-bg', className)}
|
|
715
|
+
style={fontSize !== undefined ? ({ '--wd-font-size': `${Math.round(fontSize)}px` } as React.CSSProperties) : undefined}
|
|
716
|
+
>
|
|
717
|
+
{headerTakesActions ? header({ actions: menu }) : header}
|
|
718
|
+
{statusPlacement === 'top' ? statusBar : null}
|
|
719
|
+
{protocolMismatch !== undefined ? (
|
|
720
|
+
<Notice level="warning">
|
|
721
|
+
Server speaks protocol v{protocolMismatch}, this build renders v{PROTOCOL_VERSION}. Some events may not render.
|
|
722
|
+
</Notice>
|
|
723
|
+
) : null}
|
|
724
|
+
{protocolError ? (
|
|
725
|
+
<Notice level="error" onDismiss={() => setProtocolError(undefined)}>
|
|
726
|
+
{protocolError}
|
|
727
|
+
</Notice>
|
|
728
|
+
) : null}
|
|
729
|
+
{framedShellId !== undefined ? (
|
|
730
|
+
<ShellStrip
|
|
731
|
+
shell={framedShell}
|
|
732
|
+
label={framedShellLabel}
|
|
733
|
+
onBack={leaveShell}
|
|
734
|
+
onKill={() => void killShell(framedShellId)}
|
|
735
|
+
terminal={terminal}
|
|
736
|
+
fontSize={effectiveTermFontSize}
|
|
737
|
+
lineHeight={effectiveTermLineHeight}
|
|
738
|
+
/>
|
|
739
|
+
) : null}
|
|
740
|
+
{framedShellId === undefined && subagentId !== undefined ? (
|
|
741
|
+
<SubagentStrip
|
|
742
|
+
task={subagentTask}
|
|
743
|
+
items={subagentFrameItems}
|
|
744
|
+
label={subagentFallbackLabel}
|
|
745
|
+
onBack={leaveSubagent}
|
|
746
|
+
terminal={terminal}
|
|
747
|
+
fontSize={effectiveTermFontSize}
|
|
748
|
+
lineHeight={effectiveTermLineHeight}
|
|
749
|
+
/>
|
|
750
|
+
) : null}
|
|
751
|
+
{framedShellId !== undefined ? (
|
|
752
|
+
<ShellTerminal key={framedShellId} handle={handle} shellId={framedShellId} fontSize={effectiveTermFontSize} />
|
|
753
|
+
) : (
|
|
754
|
+
<BookmarkProvider value={bookmarkHandle}>
|
|
755
|
+
<Transcript
|
|
756
|
+
key={subagentId ?? 'session'}
|
|
757
|
+
state={state}
|
|
758
|
+
fileUrl={sessionId ? (path) => client.sessionFileUrl(sessionId, path) : undefined}
|
|
759
|
+
attachmentUrl={sessionId ? (id) => client.attachmentUrl(sessionId, id) : undefined}
|
|
760
|
+
canBrowseFiles={hostFiles.available}
|
|
761
|
+
sessionNames={peers.names}
|
|
762
|
+
hostImage={hostImage}
|
|
763
|
+
variant={transcriptVariant}
|
|
764
|
+
density={transcriptDensity}
|
|
765
|
+
fontSize={effectiveTermFontSize}
|
|
766
|
+
lineHeight={effectiveTermLineHeight}
|
|
767
|
+
affordances={affordances}
|
|
768
|
+
stickyPrompt={stickyPrompt}
|
|
769
|
+
scrubber={scrubber}
|
|
770
|
+
bookmarks={bookmarks}
|
|
771
|
+
replaying={replaying}
|
|
772
|
+
catchUp={catchUp && newCount > 0 ? { from: catchUp.itemCount, since: catchUp.since } : undefined}
|
|
773
|
+
reveal={taskReveal ?? frameReturnReveal ?? reveal}
|
|
774
|
+
frame={subagentId === undefined ? undefined : { parentToolUseId: subagentId }}
|
|
775
|
+
onOpenSubagent={enterSubagent}
|
|
776
|
+
emptyState={emptyState}
|
|
777
|
+
jumpToRecapRef={jumpToRecap}
|
|
778
|
+
repinRef={repinTranscript}
|
|
779
|
+
/>
|
|
780
|
+
</BookmarkProvider>
|
|
781
|
+
)}
|
|
782
|
+
{catchUp && newCount > 0 && !replaying && subagentId === undefined && framedShellId === undefined ? (
|
|
783
|
+
<div className="px-3 pb-1">
|
|
784
|
+
<div
|
|
785
|
+
data-slot="catch-up"
|
|
786
|
+
className="mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3"
|
|
754
787
|
>
|
|
755
|
-
|
|
756
|
-
|
|
788
|
+
<span aria-hidden className={cn('select-none', terminal ? 'text-fg-3' : 'text-accent')}>
|
|
789
|
+
※
|
|
790
|
+
</span>
|
|
791
|
+
<span className="min-w-0 flex-1 truncate">
|
|
792
|
+
{newCount} new {newCount === 1 ? 'row' : 'rows'}
|
|
793
|
+
{catchUp.since !== undefined ? ` since you were last here` : ''}
|
|
794
|
+
</span>
|
|
795
|
+
<button
|
|
796
|
+
type="button"
|
|
797
|
+
onClick={() => jumpToRecap.current?.()}
|
|
798
|
+
className="shrink-0 underline-offset-2 hover:text-fg-1 hover:underline"
|
|
799
|
+
>
|
|
800
|
+
jump
|
|
801
|
+
</button>
|
|
802
|
+
<button
|
|
803
|
+
type="button"
|
|
804
|
+
onClick={() => setCaughtUp(true)}
|
|
805
|
+
className="shrink-0 underline-offset-2 hover:text-fg-1 hover:underline"
|
|
806
|
+
>
|
|
807
|
+
dismiss
|
|
808
|
+
</button>
|
|
809
|
+
</div>
|
|
757
810
|
</div>
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
811
|
+
) : null}
|
|
812
|
+
{!readOnly && capabilities.interactiveApprovals && state.pendingApprovals.length > 0 ? (
|
|
813
|
+
<div className={cn(terminal ? 'pb-2' : 'px-3 pb-2')}>
|
|
814
|
+
<PromptSurface
|
|
815
|
+
terminal={terminal}
|
|
816
|
+
metrics={{ fontSize: effectiveTermFontSize, lineHeight: effectiveTermLineHeight }}
|
|
817
|
+
affordances={affordances}
|
|
818
|
+
>
|
|
819
|
+
{state.pendingApprovals.map((request) => {
|
|
820
|
+
// Before the variant split: a host's entry is the renderer for its tool in
|
|
821
|
+
// both themes, and it overrides the built-in entries rather than racing them.
|
|
822
|
+
const HostPrompt = approvalPrompts?.[request.toolName]
|
|
823
|
+
if (HostPrompt) {
|
|
824
|
+
return <HostPrompt key={request.id} request={request} onApprove={approve} onDeny={deny} />
|
|
825
|
+
}
|
|
826
|
+
const isQuestion = request.toolName === 'AskUserQuestion' && parseUserQuestions(request.input).length > 0
|
|
827
|
+
if (terminal) {
|
|
828
|
+
return isQuestion ? (
|
|
829
|
+
<TerminalQuestionPrompt
|
|
830
|
+
key={request.id}
|
|
831
|
+
request={request}
|
|
832
|
+
onAnswer={approve}
|
|
833
|
+
onDismiss={(id) => deny(id, 'Question dismissed by user')}
|
|
834
|
+
/>
|
|
835
|
+
) : (
|
|
836
|
+
<TerminalPermissionPrompt key={request.id} request={request} onApprove={approve} onDeny={deny} />
|
|
837
|
+
)
|
|
838
|
+
}
|
|
776
839
|
return isQuestion ? (
|
|
777
|
-
<
|
|
840
|
+
<QuestionPrompt
|
|
778
841
|
key={request.id}
|
|
779
842
|
request={request}
|
|
780
843
|
onAnswer={approve}
|
|
781
844
|
onDismiss={(id) => deny(id, 'Question dismissed by user')}
|
|
782
845
|
/>
|
|
783
846
|
) : (
|
|
784
|
-
<
|
|
847
|
+
<PermissionPrompt key={request.id} request={request} onApprove={approve} onDeny={deny} />
|
|
785
848
|
)
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
client={client}
|
|
882
|
-
cwd={state.cwd}
|
|
883
|
-
open={panel === 'files'}
|
|
884
|
-
onOpenChange={(next) => setPanel(next ? 'files' : undefined)}
|
|
885
|
-
/>
|
|
886
|
-
</>
|
|
887
|
-
) : null}
|
|
888
|
-
</div>
|
|
889
|
-
</ToolResultImageProvider>
|
|
890
|
-
</ToolTitleProvider>
|
|
849
|
+
})}
|
|
850
|
+
</PromptSurface>
|
|
851
|
+
</div>
|
|
852
|
+
) : null}
|
|
853
|
+
{readOnly || subagentId !== undefined || framedShellId !== undefined ? null : (
|
|
854
|
+
<>
|
|
855
|
+
<Composer
|
|
856
|
+
ref={composerRef}
|
|
857
|
+
onSend={handleSend}
|
|
858
|
+
onInterrupt={interrupt}
|
|
859
|
+
busy={busy}
|
|
860
|
+
disabled={ended || !sessionId}
|
|
861
|
+
commands={capabilities.slashCommands ? state.commands : undefined}
|
|
862
|
+
skills={capabilities.skillsList ? state.skills : undefined}
|
|
863
|
+
clientCommands={clientCommands}
|
|
864
|
+
attachments={attachments}
|
|
865
|
+
draft={draft}
|
|
866
|
+
onSearchFiles={hostFiles.available ? searchComposerFiles : undefined}
|
|
867
|
+
peers={peers.peers}
|
|
868
|
+
onShellCommand={shell ? runShell : undefined}
|
|
869
|
+
layout={controlsExternal ? 'inline' : 'stacked'}
|
|
870
|
+
toolbar={controlsExternal ? undefined : sessionControls}
|
|
871
|
+
fontSize={effectiveTermFontSize}
|
|
872
|
+
lineHeight={effectiveTermLineHeight}
|
|
873
|
+
affordances={affordances}
|
|
874
|
+
/>
|
|
875
|
+
</>
|
|
876
|
+
)}
|
|
877
|
+
{statusPlacement === 'bottom' ? statusBar : null}
|
|
878
|
+
|
|
879
|
+
{!external ? (
|
|
880
|
+
<>
|
|
881
|
+
<SessionInfoDialog
|
|
882
|
+
state={state}
|
|
883
|
+
client={client}
|
|
884
|
+
sessionId={sessionId}
|
|
885
|
+
open={panel === 'info'}
|
|
886
|
+
onOpenChange={(next) => setPanel(next ? 'info' : undefined)}
|
|
887
|
+
/>
|
|
888
|
+
<ContextDialog
|
|
889
|
+
usage={state.contextUsage}
|
|
890
|
+
engine={state.engine ?? 'claude'}
|
|
891
|
+
open={panel === 'context'}
|
|
892
|
+
onOpenChange={(next) => setPanel(next ? 'context' : undefined)}
|
|
893
|
+
/>
|
|
894
|
+
<UsageDialog
|
|
895
|
+
rateLimits={windows}
|
|
896
|
+
subscriptionType={state.subscriptionType}
|
|
897
|
+
engine={state.engine ?? 'claude'}
|
|
898
|
+
totalCostUsd={state.totalCostUsd}
|
|
899
|
+
costUsd={state.costUsd}
|
|
900
|
+
usageByModel={state.usageByModel}
|
|
901
|
+
pricing={pricing}
|
|
902
|
+
spend={profileSpend}
|
|
903
|
+
updatedAt={usageUpdatedAt}
|
|
904
|
+
open={panel === 'usage'}
|
|
905
|
+
onOpenChange={(next) => setPanel(next ? 'usage' : undefined)}
|
|
906
|
+
/>
|
|
907
|
+
<McpDialog
|
|
908
|
+
client={client}
|
|
909
|
+
sessionId={sessionId}
|
|
910
|
+
canManageServers={capabilities.mcpServerActions}
|
|
911
|
+
open={panel === 'mcp'}
|
|
912
|
+
onOpenChange={(next) => setPanel(next ? 'mcp' : undefined)}
|
|
913
|
+
/>
|
|
914
|
+
<TasksDialog
|
|
915
|
+
tasks={tasks}
|
|
916
|
+
showCompleted={showCompletedTasks}
|
|
917
|
+
onShowCompletedChange={setShowCompletedTasks}
|
|
918
|
+
onSelectTask={(task) => {
|
|
919
|
+
if (task.toolUseId) {
|
|
920
|
+
setTaskReveal({ toolUseId: task.toolUseId, nonce: Date.now() })
|
|
921
|
+
}
|
|
922
|
+
}}
|
|
923
|
+
open={panel === 'tasks'}
|
|
924
|
+
onOpenChange={(next) => setPanel(next ? 'tasks' : undefined)}
|
|
925
|
+
/>
|
|
926
|
+
<SkillsDialog
|
|
927
|
+
skills={state.skills}
|
|
928
|
+
open={panel === 'skills'}
|
|
929
|
+
onOpenChange={(next) => setPanel(next ? 'skills' : undefined)}
|
|
930
|
+
onUse={(skill) => composerRef.current?.insertText(skillPrompt(skill))}
|
|
931
|
+
/>
|
|
932
|
+
<HostFilesDialog
|
|
933
|
+
client={client}
|
|
934
|
+
cwd={state.cwd}
|
|
935
|
+
open={panel === 'files'}
|
|
936
|
+
onOpenChange={(next) => setPanel(next ? 'files' : undefined)}
|
|
937
|
+
/>
|
|
938
|
+
</>
|
|
939
|
+
) : null}
|
|
940
|
+
</div>
|
|
941
|
+
</ToolResultImageProvider>
|
|
942
|
+
</ToolTitleProvider>
|
|
943
|
+
</ShellActionsProvider>
|
|
891
944
|
</ToolResultFetchProvider>
|
|
892
945
|
</FileLinkProvider>
|
|
893
946
|
</TranscriptDensityProvider>
|