@workerdeck/ui 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/build/{SessionPanel-J2U8v88q.d.mts → SessionPanel-B9CHoq8x.d.mts} +158 -21
- package/build/{SessionPanel-DI1NO4l8.mjs → SessionPanel-DII9MmQ8.mjs} +4254 -1661
- package/build/SessionPanel-DII9MmQ8.mjs.map +1 -0
- package/build/{format-ljc3lKpA.d.mts → format-DfI_je9S.d.mts} +1 -1
- package/build/format.d.mts +39 -4
- package/build/format.mjs +2 -118
- package/build/index.d.mts +442 -45
- package/build/index.mjs +105 -2
- package/build/index.mjs.map +1 -1
- package/build/status-Ydzi7n6j.mjs +143 -0
- package/build/status-Ydzi7n6j.mjs.map +1 -0
- package/build/workspace.d.mts +9 -1
- package/build/workspace.mjs +108 -5
- package/build/workspace.mjs.map +1 -1
- package/package.json +14 -7
- package/src/components/agent/Composer.tsx +189 -89
- package/src/components/agent/Conversation.tsx +12 -12
- package/src/components/agent/FileCard.tsx +0 -26
- package/src/components/agent/FileTree.tsx +9 -8
- package/src/components/agent/Loader.tsx +22 -72
- package/src/components/agent/Message.tsx +11 -46
- package/src/components/agent/PermissionPrompt.tsx +0 -92
- package/src/components/agent/QuestionPrompt.tsx +0 -122
- package/src/components/agent/Reasoning.tsx +5 -19
- package/src/components/agent/Response.tsx +1 -132
- package/src/components/agent/SessionPanel.tsx +224 -28
- package/src/components/agent/SessionWorkspace.tsx +29 -0
- package/src/components/agent/StatusBar.tsx +20 -4
- package/src/components/agent/ToolCallCard.tsx +17 -111
- package/src/components/agent/Transcript.tsx +710 -203
- package/src/components/agent/UsageDialog.tsx +20 -106
- package/src/components/agent/UsageMeters.tsx +133 -0
- package/src/components/agent/pulse.tsx +3 -2
- package/src/components/agent/transcript-rows.ts +82 -0
- package/src/components/agent/transcript-variant.tsx +29 -51
- package/src/components/agent/use-height-epoch.ts +60 -0
- package/src/components/agent/use-path-links.ts +147 -0
- package/src/components/agent/use-transcript-jumps.ts +190 -0
- package/src/components/prompt-area/cursor-helpers.ts +65 -0
- package/src/components/prompt-area/use-prompt-area.ts +16 -10
- package/src/components/terminal/PermissionPrompt.tsx +119 -0
- package/src/components/terminal/QuestionPrompt.tsx +322 -0
- package/src/components/terminal/StatusLine.tsx +159 -0
- package/src/components/terminal/TerminalTranscript.tsx +147 -0
- package/src/components/terminal/affordances.tsx +118 -0
- package/src/components/terminal/diff.tsx +130 -0
- package/src/components/terminal/height.ts +727 -0
- package/src/components/terminal/items.tsx +449 -0
- package/src/components/terminal/markdown.tsx +191 -0
- package/src/components/terminal/press.tsx +120 -0
- package/src/components/terminal/prompt.tsx +343 -0
- package/src/components/terminal/result-preview.ts +72 -0
- package/src/components/terminal/row.tsx +132 -0
- package/src/components/terminal/scrubber.tsx +663 -0
- package/src/components/terminal/surface.tsx +80 -0
- package/src/components/terminal/tool-run.ts +91 -0
- package/src/index.ts +34 -0
- package/src/lib/status.ts +59 -3
- package/src/lib/tool-icon.ts +14 -0
- package/src/styles/terminal.css +1011 -0
- package/src/styles/theme.css +41 -0
- package/build/SessionPanel-DI1NO4l8.mjs.map +0 -1
- package/build/format.mjs.map +0 -1
- package/src/components/agent/line-prompt.tsx +0 -249
|
@@ -6,10 +6,7 @@ import { CodeBlock } from '../ui/CodeBlock.tsx'
|
|
|
6
6
|
import { Spinner } from '../ui/Spinner.tsx'
|
|
7
7
|
import { cn } from '../../lib/utils.ts'
|
|
8
8
|
import { toolInputPreview } from '../../lib/format.ts'
|
|
9
|
-
import {
|
|
10
|
-
import { LINE_INDENT, LinePayload } from './line-prompt.tsx'
|
|
11
|
-
import { usePulse } from './pulse.tsx'
|
|
12
|
-
import { LineGlyph, useLines } from './transcript-variant.tsx'
|
|
9
|
+
import { toolIcon } from '../../lib/tool-icon.ts'
|
|
13
10
|
|
|
14
11
|
export type ToolCallItem = Extract<TranscriptItem, { kind: 'tool_call' }>
|
|
15
12
|
|
|
@@ -51,15 +48,6 @@ const STATE_BADGE = {
|
|
|
51
48
|
failed: { label: 'Error', variant: 'danger', busy: false },
|
|
52
49
|
} as const
|
|
53
50
|
|
|
54
|
-
/** The gutter dot's colour in `lines`: the state, said without a badge. */
|
|
55
|
-
const STATE_GLYPH = {
|
|
56
|
-
running: 'text-info',
|
|
57
|
-
pending: 'text-info',
|
|
58
|
-
deferred: 'text-accent',
|
|
59
|
-
settled: 'text-fg-4',
|
|
60
|
-
failed: 'text-danger',
|
|
61
|
-
} as const
|
|
62
|
-
|
|
63
51
|
/**
|
|
64
52
|
* The language to highlight a payload as.
|
|
65
53
|
*
|
|
@@ -91,47 +79,35 @@ function resultLanguage(item: ToolCallItem): string | undefined {
|
|
|
91
79
|
type Status = keyof typeof STATE_BADGE
|
|
92
80
|
|
|
93
81
|
export function ToolCallCard({ item, hostImage, className }: ToolCallCardProps) {
|
|
94
|
-
const lines = useLines()
|
|
95
82
|
const [open, setOpen] = useState(false)
|
|
96
83
|
const [fullResult, setFullResult] = useState(false)
|
|
97
84
|
const imagePath = imagePathOf(item)
|
|
98
85
|
const status: Status = item.status ?? (item.result === undefined ? 'running' : 'settled')
|
|
99
86
|
const badge = STATE_BADGE[status]
|
|
100
87
|
const isError = status === 'failed' || item.result?.isError === true
|
|
101
|
-
// Ticks only while this row is actually running, and only in the variant with a
|
|
102
|
-
// gutter to pulse in — an idle transcript of a hundred settled tools starts no
|
|
103
|
-
// timers at all.
|
|
104
|
-
const pulse = usePulse(lines && badge.busy)
|
|
105
88
|
const Icon = toolIcon(item.name)
|
|
106
89
|
|
|
107
90
|
const resultText = item.result?.text ?? ''
|
|
108
91
|
const truncated = !fullResult && resultText.length > RESULT_PREVIEW_CHARS
|
|
109
92
|
const shownResult = truncated ? resultText.slice(0, RESULT_PREVIEW_CHARS) : resultText
|
|
110
93
|
|
|
111
|
-
// In `lines` the payloads are dim label + highlighted band, not framed cards:
|
|
112
|
-
// a tool call is already one row, and boxing what it expands into puts back
|
|
113
|
-
// the chrome the variant exists to remove.
|
|
114
|
-
const blockVariant = lines ? 'plain' : 'panel'
|
|
115
|
-
const Payload = lines ? HighlightedPayload : PlainPayload
|
|
116
94
|
const details = open ? (
|
|
117
|
-
<div className=
|
|
118
|
-
<
|
|
95
|
+
<div className='flex flex-col gap-2 border-t border-border p-2.5'>
|
|
96
|
+
<PlainPayload
|
|
119
97
|
code={JSON.stringify(item.input, null, 2)}
|
|
120
98
|
language='json'
|
|
121
99
|
label='Parameters'
|
|
122
|
-
variant={blockVariant}
|
|
123
100
|
/>
|
|
124
101
|
{item.logs?.length ? (
|
|
125
|
-
<
|
|
102
|
+
<PlainPayload code={item.logs.join('\n')} label='Logs'/>
|
|
126
103
|
) : null}
|
|
127
104
|
{item.result !== undefined ? (
|
|
128
105
|
<div>
|
|
129
|
-
<
|
|
106
|
+
<PlainPayload
|
|
130
107
|
code={shownResult || '(empty result)'}
|
|
131
108
|
language={resultLanguage(item)}
|
|
132
109
|
label={isError ? 'Error' : 'Result'}
|
|
133
|
-
|
|
134
|
-
className={cn(isError && (lines ? '[&_pre]:text-danger' : 'border-danger/40 [&_pre]:text-danger'))}
|
|
110
|
+
className={cn(isError && 'border-danger/40 [&_pre]:text-danger')}
|
|
135
111
|
/>
|
|
136
112
|
{truncated ? (
|
|
137
113
|
<button
|
|
@@ -148,63 +124,7 @@ export function ToolCallCard({ item, hostImage, className }: ToolCallCardProps)
|
|
|
148
124
|
|
|
149
125
|
// The picture is the point of the call — shown without expanding, the way the
|
|
150
126
|
// tool's own output would be if the engine had sent bytes.
|
|
151
|
-
const image = imagePath && hostImage ? <HostImage path={imagePath} load={hostImage}
|
|
152
|
-
|
|
153
|
-
if (lines) {
|
|
154
|
-
return (
|
|
155
|
-
<div data-slot='tool-call' data-state={status} className={cn('w-full', className)}>
|
|
156
|
-
<button
|
|
157
|
-
type='button'
|
|
158
|
-
onClick={() => setOpen((v) => !v)}
|
|
159
|
-
className='flex w-full items-baseline gap-2 text-left outline-none'>
|
|
160
|
-
<LineGlyph
|
|
161
|
-
className={
|
|
162
|
-
// A settled write is green: skimming a run, "what did it change"
|
|
163
|
-
// is the question you come back to, and it is the one you might
|
|
164
|
-
// need to undo. Every other state keeps its own colour — a failed
|
|
165
|
-
// write is a failure first.
|
|
166
|
-
status === 'settled' && !isError && isMutatingTool(item.name)
|
|
167
|
-
? 'text-success'
|
|
168
|
-
: STATE_GLYPH[status]
|
|
169
|
-
}>
|
|
170
|
-
{/* Running: the mark's own pulse, so a working tool row and the
|
|
171
|
-
transcript's working line beat together. Settled: a plain dot,
|
|
172
|
-
which reads as "done" precisely by not moving. */}
|
|
173
|
-
{badge.busy ? pulse : '●'}
|
|
174
|
-
</LineGlyph>
|
|
175
|
-
<span className='min-w-0 flex-1 truncate text-body-sm leading-5 text-fg-3'>
|
|
176
|
-
<span className='font-medium text-fg-1'>{item.name}</span>
|
|
177
|
-
<span className='text-fg-4'>({toolInputPreview(item.input)})</span>
|
|
178
|
-
</span>
|
|
179
|
-
{item.backend && item.backend !== 'server' ? (
|
|
180
|
-
<span className='shrink-0 text-label text-fg-4'>{item.backend}</span>
|
|
181
|
-
) : null}
|
|
182
|
-
{/* No Spinner here: the gutter glyph animates now, and two spinners on
|
|
183
|
-
one row is one too many. `cards` keeps its own — it has no gutter. */}
|
|
184
|
-
{status === 'deferred' ? <Clock className='size-3 shrink-0 self-center text-fg-4' /> : null}
|
|
185
|
-
{isError && !badge.busy ? (
|
|
186
|
-
<span className='shrink-0 text-label text-danger'>error</span>
|
|
187
|
-
) : null}
|
|
188
|
-
</button>
|
|
189
|
-
{/* Collapsed, the first line of the output is the whole story most of
|
|
190
|
-
the time — a summary line costs one row and saves an expand. */}
|
|
191
|
-
{!open && resultText ? (
|
|
192
|
-
<div className='flex items-baseline gap-2'>
|
|
193
|
-
<LineGlyph className='text-fg-4'>⎿</LineGlyph>
|
|
194
|
-
<span
|
|
195
|
-
className={cn(
|
|
196
|
-
'min-w-0 flex-1 truncate text-label leading-5',
|
|
197
|
-
isError ? 'text-danger' : 'text-fg-4',
|
|
198
|
-
)}>
|
|
199
|
-
{resultSummary(resultText)}
|
|
200
|
-
</span>
|
|
201
|
-
</div>
|
|
202
|
-
) : null}
|
|
203
|
-
{image}
|
|
204
|
-
{details ? <div className={LINE_INDENT}>{details}</div> : null}
|
|
205
|
-
</div>
|
|
206
|
-
)
|
|
207
|
-
}
|
|
127
|
+
const image = imagePath && hostImage ? <HostImage path={imagePath} load={hostImage} /> : null
|
|
208
128
|
|
|
209
129
|
return (
|
|
210
130
|
<div
|
|
@@ -243,31 +163,19 @@ export function ToolCallCard({ item, hostImage, className }: ToolCallCardProps)
|
|
|
243
163
|
)
|
|
244
164
|
}
|
|
245
165
|
|
|
246
|
-
/** The
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
type PayloadProps = {
|
|
166
|
+
/** The framed card the `cards` transcript expands into. Unhighlighted by
|
|
167
|
+
* design: it is structured data in a panel, not a file. */
|
|
168
|
+
function PlainPayload({
|
|
169
|
+
code,
|
|
170
|
+
label,
|
|
171
|
+
className,
|
|
172
|
+
}: {
|
|
255
173
|
code: string
|
|
256
174
|
label: string
|
|
257
175
|
language?: string
|
|
258
|
-
variant: 'panel' | 'plain'
|
|
259
176
|
className?: string
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/** The framed card, for the `cards` transcript. Unhighlighted by design: it is
|
|
263
|
-
* structured data in a panel, not a file. */
|
|
264
|
-
function PlainPayload({ code, label, variant, className }: PayloadProps) {
|
|
265
|
-
return <CodeBlock code={code} label={label} variant={variant} className={className} />
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/** The terminal payload — shared with the line-shaped prompts. */
|
|
269
|
-
function HighlightedPayload({ code, label, language, className }: PayloadProps) {
|
|
270
|
-
return <LinePayload code={code} label={label} language={language} className={className} />
|
|
177
|
+
}) {
|
|
178
|
+
return <CodeBlock code={code} label={label} variant='panel' className={className} />
|
|
271
179
|
}
|
|
272
180
|
|
|
273
181
|
/**
|
|
@@ -282,11 +190,9 @@ function HighlightedPayload({ code, label, language, className }: PayloadProps)
|
|
|
282
190
|
function HostImage({
|
|
283
191
|
path,
|
|
284
192
|
load,
|
|
285
|
-
lines,
|
|
286
193
|
}: {
|
|
287
194
|
path: string
|
|
288
195
|
load: (path: string) => Promise<string | undefined>
|
|
289
|
-
lines?: boolean
|
|
290
196
|
}) {
|
|
291
197
|
const [src, setSrc] = useState<string | undefined>()
|
|
292
198
|
useEffect(() => {
|
|
@@ -305,7 +211,7 @@ function HostImage({
|
|
|
305
211
|
}, [path, load])
|
|
306
212
|
if (!src) return null
|
|
307
213
|
return (
|
|
308
|
-
<div className=
|
|
214
|
+
<div className='border-t border-border p-2.5'>
|
|
309
215
|
<img
|
|
310
216
|
src={src}
|
|
311
217
|
alt={path.split('/').pop() ?? 'Generated image'}
|