@bytespell/shella 0.2.4 → 0.2.6

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 (53) hide show
  1. package/bundled-plugins/agent/AGENT_SPEC.md +611 -0
  2. package/bundled-plugins/agent/README.md +7 -0
  3. package/bundled-plugins/agent/components.json +24 -0
  4. package/bundled-plugins/agent/eslint.config.js +23 -0
  5. package/bundled-plugins/agent/index.html +13 -0
  6. package/bundled-plugins/agent/package-lock.json +12140 -0
  7. package/bundled-plugins/agent/package.json +62 -0
  8. package/bundled-plugins/agent/public/vite.svg +1 -0
  9. package/bundled-plugins/agent/server.js +631 -0
  10. package/bundled-plugins/agent/src/App.tsx +755 -0
  11. package/bundled-plugins/agent/src/assets/react.svg +1 -0
  12. package/bundled-plugins/agent/src/components/ui/alert-dialog.tsx +182 -0
  13. package/bundled-plugins/agent/src/components/ui/badge.tsx +45 -0
  14. package/bundled-plugins/agent/src/components/ui/button.tsx +60 -0
  15. package/bundled-plugins/agent/src/components/ui/card.tsx +94 -0
  16. package/bundled-plugins/agent/src/components/ui/combobox.tsx +294 -0
  17. package/bundled-plugins/agent/src/components/ui/dropdown-menu.tsx +253 -0
  18. package/bundled-plugins/agent/src/components/ui/field.tsx +225 -0
  19. package/bundled-plugins/agent/src/components/ui/input-group.tsx +147 -0
  20. package/bundled-plugins/agent/src/components/ui/input.tsx +19 -0
  21. package/bundled-plugins/agent/src/components/ui/label.tsx +24 -0
  22. package/bundled-plugins/agent/src/components/ui/select.tsx +185 -0
  23. package/bundled-plugins/agent/src/components/ui/separator.tsx +26 -0
  24. package/bundled-plugins/agent/src/components/ui/switch.tsx +31 -0
  25. package/bundled-plugins/agent/src/components/ui/textarea.tsx +18 -0
  26. package/bundled-plugins/agent/src/index.css +131 -0
  27. package/bundled-plugins/agent/src/lib/utils.ts +6 -0
  28. package/bundled-plugins/agent/src/main.tsx +11 -0
  29. package/bundled-plugins/agent/src/reducer.test.ts +359 -0
  30. package/bundled-plugins/agent/src/reducer.ts +255 -0
  31. package/bundled-plugins/agent/src/store.ts +379 -0
  32. package/bundled-plugins/agent/src/types.ts +98 -0
  33. package/bundled-plugins/agent/src/utils.test.ts +393 -0
  34. package/bundled-plugins/agent/src/utils.ts +158 -0
  35. package/bundled-plugins/agent/tsconfig.app.json +32 -0
  36. package/bundled-plugins/agent/tsconfig.json +13 -0
  37. package/bundled-plugins/agent/tsconfig.node.json +26 -0
  38. package/bundled-plugins/agent/vite.config.ts +14 -0
  39. package/bundled-plugins/agent/vitest.config.ts +17 -0
  40. package/bundled-plugins/terminal/README.md +7 -0
  41. package/bundled-plugins/terminal/index.html +24 -0
  42. package/bundled-plugins/terminal/package-lock.json +3346 -0
  43. package/bundled-plugins/terminal/package.json +38 -0
  44. package/bundled-plugins/terminal/server.ts +265 -0
  45. package/bundled-plugins/terminal/src/App.tsx +153 -0
  46. package/bundled-plugins/terminal/src/TERMINAL_SPEC.md +404 -0
  47. package/bundled-plugins/terminal/src/main.tsx +9 -0
  48. package/bundled-plugins/terminal/src/store.ts +114 -0
  49. package/bundled-plugins/terminal/tsconfig.json +22 -0
  50. package/bundled-plugins/terminal/vite.config.ts +10 -0
  51. package/dist/src/plugin-manager.js +1 -1
  52. package/dist/src/plugin-manager.js.map +1 -1
  53. package/package.json +1 -1
@@ -0,0 +1,611 @@
1
+ # Agent Plugin UI Specification
2
+
3
+ This document specifies how the agent plugin UI should handle all RPC events from the pi-agent and render the conversation.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Architecture Overview](#architecture-overview)
8
+ 2. [State Management](#state-management)
9
+ 3. [Event Handling](#event-handling)
10
+ 4. [Message Rendering](#message-rendering)
11
+ 5. [Streaming Behavior](#streaming-behavior)
12
+ 6. [Tool Execution](#tool-execution)
13
+ 7. [User Interactions](#user-interactions)
14
+ 8. [Edge Cases](#edge-cases)
15
+ 9. [Components](#components)
16
+
17
+ ---
18
+
19
+ ## Architecture Overview
20
+
21
+ ### Data Flow
22
+
23
+ ```
24
+ ┌─────────────────────────────────────────────────────────────────┐
25
+ │ WebSocket │
26
+ │ │
27
+ │ Client (App.tsx) ◄────────────────────► Server (server.js) │
28
+ │ │ │ │
29
+ │ │ │ │
30
+ │ ▼ ▼ │
31
+ │ React State pi --mode rpc │
32
+ │ - messages[] (stdio JSON lines) │
33
+ │ - sessionState │
34
+ │ - activeToolCalls │
35
+ │ - streamingContent │
36
+ └─────────────────────────────────────────────────────────────────┘
37
+ ```
38
+
39
+ ### Key Principle
40
+
41
+ **Messages are the source of truth.** The UI builds its render tree from the `messages[]` array. Streaming updates modify the last message in-place. Tool executions are tracked separately only for showing progress indicators.
42
+
43
+ ---
44
+
45
+ ## State Management
46
+
47
+ ### Primary State
48
+
49
+ ```typescript
50
+ interface AppState {
51
+ // Connection
52
+ status: 'connecting' | 'connected' | 'disconnected' | 'error'
53
+ error: string | null
54
+ currentCwd: string | null
55
+
56
+ // Session
57
+ sessionState: SessionState | null
58
+ sessionStats: SessionStats | null
59
+
60
+ // Messages - THE source of truth for rendering
61
+ messages: AgentMessage[]
62
+
63
+ // Streaming indicators (not for rendering content, just for UI feedback)
64
+ isStreaming: boolean // Is the agent currently processing?
65
+ streamingMessageIndex: number | null // Which message is being streamed?
66
+
67
+ // Active tool calls (for progress indicators during execution)
68
+ activeToolCalls: Map<string, ActiveToolCall>
69
+
70
+ // UI state
71
+ availableModels: AvailableModel[]
72
+ pendingExtensionRequest: ExtensionUIRequest | null
73
+ }
74
+
75
+ interface ActiveToolCall {
76
+ toolCallId: string
77
+ toolName: string
78
+ args: Record<string, unknown>
79
+ status: 'running' | 'done' | 'error'
80
+ partialOutput: string | null // Streaming output for bash/etc
81
+ }
82
+
83
+ interface SessionState {
84
+ model?: Model
85
+ thinkingLevel: ThinkingLevel
86
+ isStreaming: boolean
87
+ isCompacting: boolean
88
+ steeringMode: 'all' | 'one-at-a-time'
89
+ followUpMode: 'all' | 'one-at-a-time'
90
+ sessionFile?: string
91
+ sessionId: string
92
+ autoCompactionEnabled: boolean
93
+ messageCount: number
94
+ pendingMessageCount: number // Queued steering/follow-up messages
95
+ }
96
+ ```
97
+
98
+ ### Message Types
99
+
100
+ ```typescript
101
+ type AgentMessage =
102
+ | UserMessage
103
+ | AssistantMessage
104
+ | ToolResultMessage
105
+ | BashExecutionMessage
106
+ | CompactionSummaryMessage
107
+ | CustomMessage
108
+
109
+ interface UserMessage {
110
+ role: 'user'
111
+ content: string | ContentBlock[]
112
+ timestamp: number
113
+ }
114
+
115
+ interface AssistantMessage {
116
+ role: 'assistant'
117
+ content: ContentBlock[] // text, thinking, toolCall blocks
118
+ model: string
119
+ usage: Usage
120
+ stopReason: 'stop' | 'length' | 'toolUse' | 'error' | 'aborted'
121
+ timestamp: number
122
+ }
123
+
124
+ interface ToolResultMessage {
125
+ role: 'toolResult'
126
+ toolCallId: string
127
+ toolName: string
128
+ content: ContentBlock[]
129
+ details?: unknown // Tool-specific display data
130
+ isError: boolean
131
+ timestamp: number
132
+ }
133
+
134
+ type ContentBlock =
135
+ | { type: 'text'; text: string }
136
+ | { type: 'thinking'; thinking: string }
137
+ | { type: 'toolCall'; id: string; name: string; arguments: Record<string, unknown> }
138
+ | { type: 'image'; data: string; mimeType: string }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Event Handling
144
+
145
+ ### Connection Events
146
+
147
+ | Event | Action |
148
+ |-------|--------|
149
+ | `ready` | Set status='connected', set cwd if provided, request initial state |
150
+ | `cwd_changed` | Update cwd, clear messages (new session in new directory) |
151
+ | `error` | Display error message |
152
+ | `process_exit` | Show reconnection UI or error |
153
+
154
+ ### Agent Lifecycle Events
155
+
156
+ | Event | Action |
157
+ |-------|--------|
158
+ | `agent_start` | Set isStreaming=true, clear activeToolCalls |
159
+ | `agent_end` | Set isStreaming=false, clear activeToolCalls, request stats |
160
+
161
+ ### Message Events
162
+
163
+ | Event | Action |
164
+ |-------|--------|
165
+ | `message_start` | Append message to messages[], set streamingMessageIndex if assistant |
166
+ | `message_update` | Update message at streamingMessageIndex with new content |
167
+ | `message_end` | Clear streamingMessageIndex |
168
+
169
+ **Important:** `message_update` includes `assistantMessageEvent` with granular streaming info:
170
+ - `text_delta` - Append text to current text block
171
+ - `thinking_delta` - Append to thinking block
172
+ - `toolcall_end` - Tool call block complete
173
+ - `done` - Message complete
174
+
175
+ ### Tool Execution Events
176
+
177
+ | Event | Action |
178
+ |-------|--------|
179
+ | `tool_execution_start` | Add to activeToolCalls with status='running' |
180
+ | `tool_execution_update` | Update partialOutput in activeToolCalls |
181
+ | `tool_execution_end` | Update status='done' or 'error', keep until toolResult message arrives |
182
+
183
+ **When `message_start` arrives with role='toolResult':**
184
+ - Remove corresponding entry from activeToolCalls (it's now in messages)
185
+
186
+ ### Response Events
187
+
188
+ | Event | Action |
189
+ |-------|--------|
190
+ | `response` to `get_state` | Update sessionState |
191
+ | `response` to `get_messages` | Set messages (only on initial load, not during streaming) |
192
+ | `response` to `get_session_stats` | Update sessionStats |
193
+ | `response` to `get_available_models` | Update availableModels |
194
+
195
+ ### Extension UI Events
196
+
197
+ | Event | Action |
198
+ |-------|--------|
199
+ | `extension_ui_request` | Show appropriate dialog/input, send response back |
200
+
201
+ ---
202
+
203
+ ## Message Rendering
204
+
205
+ ### Render Order
206
+
207
+ Messages are rendered in array order. Each message type has specific rendering:
208
+
209
+ ```
210
+ ┌─────────────────────────────────────────┐
211
+ │ User message (right-aligned bubble) │
212
+ ├─────────────────────────────────────────┤
213
+ │ Assistant text (left-aligned bubble) │
214
+ │ - Render markdown │
215
+ │ - Show thinking in collapsible │
216
+ ├─────────────────────────────────────────┤
217
+ │ Tool Call Card │
218
+ │ - Show tool name + args │
219
+ │ - While executing: show progress │
220
+ ├─────────────────────────────────────────┤
221
+ │ Tool Result Card │
222
+ │ - For bash: show $ command + output │
223
+ │ - For others: show formatted result │
224
+ │ - Error state: red styling │
225
+ ├─────────────────────────────────────────┤
226
+ │ Assistant text (continuation) │
227
+ │ - Streaming cursor if active │
228
+ └─────────────────────────────────────────┘
229
+ ```
230
+
231
+ ### Splitting Assistant Messages
232
+
233
+ Assistant messages may contain mixed content (text + toolCall + more text). Split for display:
234
+
235
+ ```typescript
236
+ function splitAssistantContent(content: ContentBlock[]): RenderItem[] {
237
+ const items: RenderItem[] = []
238
+ let textBuffer: ContentBlock[] = []
239
+
240
+ for (const block of content) {
241
+ if (block.type === 'toolCall') {
242
+ // Flush text buffer
243
+ if (textBuffer.length > 0) {
244
+ items.push({ type: 'text-chunk', blocks: textBuffer })
245
+ textBuffer = []
246
+ }
247
+ items.push({ type: 'tool-call', block })
248
+ } else {
249
+ textBuffer.push(block)
250
+ }
251
+ }
252
+
253
+ // Flush remaining text
254
+ if (textBuffer.length > 0) {
255
+ items.push({ type: 'text-chunk', blocks: textBuffer })
256
+ }
257
+
258
+ return items
259
+ }
260
+ ```
261
+
262
+ ### Content Block Rendering
263
+
264
+ | Block Type | Rendering |
265
+ |------------|-----------|
266
+ | `text` | Markdown with syntax highlighting. Use streaming-capable renderer. |
267
+ | `thinking` | Collapsible "Thinking..." section, muted styling |
268
+ | `toolCall` | Tool call card showing name + arguments (only during streaming before result) |
269
+ | `image` | Inline image |
270
+
271
+ ### Tool Result Rendering
272
+
273
+ | Tool | Rendering |
274
+ |------|-----------|
275
+ | `bash` / `Bash` | Mini-terminal: `$ command` header + scrollable output |
276
+ | `Read` | File content with path header |
277
+ | `Write` / `Edit` | Diff view component |
278
+ | `Grep` / `Glob` | Formatted list of matches/files |
279
+ | Other | JSON-formatted arguments + result |
280
+
281
+ ---
282
+
283
+ ## Streaming Behavior
284
+
285
+ ### Text Streaming
286
+
287
+ 1. On `message_start` (assistant): Add message to array, set streamingMessageIndex
288
+ 2. On `message_update`: Replace message at streamingMessageIndex
289
+ 3. Show pulsing cursor after last text in streaming message
290
+ 4. On `message_end`: Clear streamingMessageIndex, cursor disappears
291
+
292
+ ### Tool Execution Streaming
293
+
294
+ 1. `tool_execution_start`: Add to activeToolCalls, show card with spinner
295
+ 2. `tool_execution_update`: Update partialOutput, show in card (for bash output)
296
+ 3. `tool_execution_end`: Mark complete, show success/error indicator
297
+ 4. `message_start` (toolResult): Move from activeToolCalls to messages
298
+
299
+ **Visual transition:** The tool card should smoothly transition from "running" state (in activeToolCalls) to "complete" state (in messages) without flashing or jumping.
300
+
301
+ ### Render Priority
302
+
303
+ During streaming, render in this order:
304
+ 1. All messages from `messages[]` (split as needed)
305
+ 2. Active tool calls from `activeToolCalls` (only those not yet in messages)
306
+ 3. (Streaming cursor shown inline in last assistant message)
307
+
308
+ ---
309
+
310
+ ## Tool Execution
311
+
312
+ ### Tool Call Card (During Execution)
313
+
314
+ ```
315
+ ┌────────────────────────────────────────┐
316
+ │ ● bash Running │
317
+ │ $ ls -la │
318
+ ├────────────────────────────────────────┤
319
+ │ total 48 │
320
+ │ drwxr-xr-x 12 user staff 384 ... │
321
+ │ ... │
322
+ │ (streaming output) │
323
+ └────────────────────────────────────────┘
324
+ ```
325
+
326
+ - Yellow pulsing dot while running
327
+ - Green dot when complete
328
+ - Red dot on error
329
+ - Show command for bash tools
330
+ - Stream partial output as it arrives
331
+
332
+ ### Tool Result Card (After Completion)
333
+
334
+ ```
335
+ ┌────────────────────────────────────────┐
336
+ │ ● $ ls -la │
337
+ ├────────────────────────────────────────┤
338
+ │ total 48 │
339
+ │ drwxr-xr-x 12 user staff 384 ... │
340
+ │ ... │
341
+ │ (full output, scrollable) │
342
+ └────────────────────────────────────────┘
343
+ ```
344
+
345
+ - Green dot for success, red for error
346
+ - Command in header for bash
347
+ - Scrollable output area (max-height with overflow)
348
+ - Error output in red text
349
+
350
+ ### Special Tool Rendering
351
+
352
+ **Edit/Write Tools (Diff View):**
353
+ ```
354
+ ┌────────────────────────────────────────┐
355
+ │ Edit: src/App.tsx │
356
+ ├────────────────────────────────────────┤
357
+ │ - old line │
358
+ │ + new line │
359
+ │ unchanged line │
360
+ └────────────────────────────────────────┘
361
+ ```
362
+
363
+ **Read Tool:**
364
+ ```
365
+ ┌────────────────────────────────────────┐
366
+ │ Read: package.json │
367
+ ├────────────────────────────────────────┤
368
+ │ { │
369
+ │ "name": "my-app", │
370
+ │ ... │
371
+ │ } │
372
+ └────────────────────────────────────────┘
373
+ ```
374
+
375
+ ---
376
+
377
+ ## User Interactions
378
+
379
+ ### Sending Messages
380
+
381
+ **Normal prompt:**
382
+ ```typescript
383
+ ws.send({ type: 'prompt', message: text })
384
+ ```
385
+
386
+ **With images:**
387
+ ```typescript
388
+ ws.send({ type: 'prompt', message: text, images: [{ type: 'image', data: base64, mimeType: 'image/png' }] })
389
+ ```
390
+
391
+ ### Steering (Interrupt)
392
+
393
+ When agent is streaming and user sends a message:
394
+ ```typescript
395
+ ws.send({ type: 'steer', message: text })
396
+ ```
397
+
398
+ - Interrupts current tool execution
399
+ - Message is injected before next LLM turn
400
+ - Show indicator that message was queued for steering
401
+
402
+ ### Follow-Up (Queue)
403
+
404
+ Queue a message to run after agent finishes:
405
+ ```typescript
406
+ ws.send({ type: 'follow_up', message: text })
407
+ ```
408
+
409
+ - Does not interrupt
410
+ - Show indicator that message is queued
411
+ - Show pending count from sessionState.pendingMessageCount
412
+
413
+ ### Abort
414
+
415
+ Stop agent execution:
416
+ ```typescript
417
+ ws.send({ type: 'abort' })
418
+ ```
419
+
420
+ - Show "Stop" button when isStreaming
421
+ - Cancel current tool execution
422
+ - Agent will emit `agent_end`
423
+
424
+ ### UI Indicators
425
+
426
+ | State | Indicator |
427
+ |-------|-----------|
428
+ | Agent streaming | Pulsing cursor, "Stop" button |
429
+ | Tool running | Yellow spinner on tool card |
430
+ | Message queued | Badge showing pending count |
431
+ | Compacting | "Compacting..." status |
432
+ | Error | Red error banner |
433
+
434
+ ---
435
+
436
+ ## Edge Cases
437
+
438
+ ### 1. Multiple Tool Calls in One Message
439
+
440
+ Assistant may request multiple tools at once:
441
+ ```typescript
442
+ {
443
+ role: 'assistant',
444
+ content: [
445
+ { type: 'text', text: 'I will read both files...' },
446
+ { type: 'toolCall', id: 'call_1', name: 'Read', arguments: { path: 'a.txt' } },
447
+ { type: 'toolCall', id: 'call_2', name: 'Read', arguments: { path: 'b.txt' } }
448
+ ]
449
+ }
450
+ ```
451
+
452
+ **Handling:**
453
+ - Split into: text chunk, tool card 1, tool card 2
454
+ - Tool results arrive as separate `toolResult` messages
455
+ - Match by `toolCallId`
456
+
457
+ ### 2. Steering Mid-Tool-Execution
458
+
459
+ User steers while tool is running:
460
+ - Tool execution continues until next checkpoint
461
+ - Steering message is queued
462
+ - After tool completes, steering is processed
463
+ - May result in remaining tool calls being skipped
464
+
465
+ ### 3. Auto-Compaction
466
+
467
+ Events: `auto_compaction_start`, `auto_compaction_end`
468
+
469
+ **Handling:**
470
+ - Show "Compacting context..." indicator
471
+ - On completion, a `compactionSummary` message may be added
472
+ - Older messages may be removed from context (but kept in history)
473
+
474
+ ### 4. Auto-Retry
475
+
476
+ Events: `auto_retry_start`, `auto_retry_end`
477
+
478
+ **Handling:**
479
+ - Show "Retrying... (attempt N of M)"
480
+ - Show countdown timer if delay > 1s
481
+ - On success, continue normally
482
+ - On final failure, show error
483
+
484
+ ### 5. Extension UI Requests
485
+
486
+ Agent may request user input via `extension_ui_request`:
487
+
488
+ | Method | UI |
489
+ |--------|-----|
490
+ | `select` | Dropdown/radio buttons |
491
+ | `confirm` | Yes/No dialog |
492
+ | `input` | Text input |
493
+ | `editor` | Multi-line text editor |
494
+ | `notify` | Toast notification |
495
+
496
+ **Response:**
497
+ ```typescript
498
+ ws.send({
499
+ type: 'extension_ui_response',
500
+ id: request.id,
501
+ value: userInput // or { cancelled: true }
502
+ })
503
+ ```
504
+
505
+ ### 6. Connection Loss
506
+
507
+ - Show disconnected state
508
+ - Auto-reconnect with exponential backoff
509
+ - On reconnect, request `get_state` and `get_messages` to sync
510
+
511
+ ### 7. CWD Change
512
+
513
+ - Kills pi process, respawns in new directory
514
+ - Clears messages (new session)
515
+ - Show brief "Switching directory..." indicator
516
+
517
+ ### 8. Session Switch
518
+
519
+ User may switch to different session file:
520
+ - Current conversation is saved
521
+ - New session loaded
522
+ - Messages replaced with new session's history
523
+
524
+ ### 9. Empty Responses
525
+
526
+ Assistant may return empty text (only tool calls, or aborted):
527
+ - Don't render empty text bubbles
528
+ - Still show tool calls if present
529
+
530
+ ### 10. Long-Running Tools
531
+
532
+ Some tools take a long time (build, test):
533
+ - Show elapsed time indicator
534
+ - Stream partial output if available
535
+ - Allow abort via "Stop" button
536
+
537
+ ---
538
+
539
+ ## Components
540
+
541
+ ### Required Components
542
+
543
+ 1. **MessageBubble** - User/assistant text messages with markdown
544
+ 2. **ToolCallCard** - Tool execution progress (running state)
545
+ 3. **ToolResultCard** - Tool result display (completed state)
546
+ 4. **BashResultCard** - Specialized for bash with command header
547
+ 5. **DiffView** - For Edit/Write tool results
548
+ 6. **ThinkingBlock** - Collapsible thinking content
549
+ 7. **StreamingCursor** - Pulsing cursor for active streaming
550
+ 8. **QueueIndicator** - Shows pending message count
551
+ 9. **StatusBar** - Session stats, model, connection status
552
+ 10. **DirectoryPicker** - CWD selection
553
+ 11. **ExtensionDialog** - Generic dialog for extension UI requests
554
+
555
+ ### Component Hierarchy
556
+
557
+ ```
558
+ <App>
559
+ <Header>
560
+ <DirectoryPicker />
561
+ <SessionStats />
562
+ <StatusIndicator />
563
+ <SettingsMenu />
564
+ </Header>
565
+
566
+ <MessageList>
567
+ {messages.map(msg => {
568
+ if (msg.role === 'user') return <UserBubble />
569
+ if (msg.role === 'assistant') return <AssistantMessage />
570
+ if (msg.role === 'toolResult') return <ToolResultCard />
571
+ ...
572
+ })}
573
+
574
+ {activeToolCalls.map(tool => (
575
+ <ToolCallCard status="running" />
576
+ ))}
577
+ </MessageList>
578
+
579
+ <InputArea>
580
+ <Textarea />
581
+ <SendButton /> or <StopButton />
582
+ {pendingCount > 0 && <QueueIndicator count={pendingCount} />}
583
+ </InputArea>
584
+
585
+ {extensionRequest && <ExtensionDialog />}
586
+ </App>
587
+ ```
588
+
589
+ ---
590
+
591
+ ## Implementation Notes
592
+
593
+ ### Performance
594
+
595
+ 1. **Virtualization:** For long conversations, consider virtualizing the message list
596
+ 2. **Memoization:** Memoize message components to avoid re-renders
597
+ 3. **Streaming:** Use streaming-capable markdown renderer (e.g., streamdown)
598
+ 4. **Debounce:** Debounce rapid `message_update` events if needed
599
+
600
+ ### Accessibility
601
+
602
+ 1. Keyboard navigation for message list
603
+ 2. Screen reader announcements for new messages
604
+ 3. Focus management for dialogs
605
+ 4. High contrast support for tool status indicators
606
+
607
+ ### Mobile
608
+
609
+ 1. Responsive layout for smaller screens
610
+ 2. Touch-friendly buttons and controls
611
+ 3. Swipe gestures for common actions
@@ -0,0 +1,7 @@
1
+ # Agent Plugin
2
+
3
+ A web UI for AI coding agents. Point it at any directory and start a conversation—the agent can read files, write code, run commands, and iterate on your codebase. Sessions persist across restarts, so you can pick up where you left off.
4
+
5
+ **Usage:** Split a panel, select "Agent", choose a working directory, and start prompting. Switch between sessions or start new ones from the session picker. Each panel instance maintains its own independent session.
6
+
7
+ **Vision:** Your AI pair programmer, always available in a panel alongside your terminal and editor. No context switching to a separate app—just split, prompt, and ship.
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "radix-vega",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/index.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "aliases": {
15
+ "components": "@/components",
16
+ "utils": "@/lib/utils",
17
+ "ui": "@/components/ui",
18
+ "lib": "@/lib",
19
+ "hooks": "@/hooks"
20
+ },
21
+ "menuColor": "default",
22
+ "menuAccent": "subtle",
23
+ "registries": {}
24
+ }
@@ -0,0 +1,23 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+ import { defineConfig, globalIgnores } from 'eslint/config'
7
+
8
+ export default defineConfig([
9
+ globalIgnores(['dist']),
10
+ {
11
+ files: ['**/*.{ts,tsx}'],
12
+ extends: [
13
+ js.configs.recommended,
14
+ tseslint.configs.recommended,
15
+ reactHooks.configs.flat.recommended,
16
+ reactRefresh.configs.vite,
17
+ ],
18
+ languageOptions: {
19
+ ecmaVersion: 2020,
20
+ globals: globals.browser,
21
+ },
22
+ },
23
+ ])
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Agent</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>