Markdown Edit/Preview tabs + read-only .md viewer for skills & profiles
Adds MarkdownEditor (react-markdown + remark-gfm, no raw HTML — authored/retrieved content is data, not markup) with Edit | Preview tabs, wired into the AGENTS.md and SKILL.md editors, the agent persona, and the review artifact. Adds a read-only "View" on every skill and agent-profile card — including builtins, which previously had no way to be inspected at all — rendering the full SKILL.md / AGENTS.md (frontmatter + body + actions/golden tests). Collapses a same-version builtin that an org has forked so its own copy shadows it, keeping the version picker unambiguous and the item clearly editable/versionable. Also lands the agent-face wiring on the seat configurator (a live xl preview with a state cycler) and the review inbox header. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,8 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { KeyRound, Plug, Plus, Bot, Sparkles, Trash2, Wand2 } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { AppShell } from '@/components/AppShell'
|
||||
import { AgentFace, type FaceState } from '@/components/AgentFace'
|
||||
import { MarkdownEditor } from '@/components/MarkdownEditor'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
@@ -101,6 +103,7 @@ export function SeatsPage() {
|
||||
const [mcp, setMcp] = useState({ name: '', endpoint: '', headerName: 'Authorization', headerValue: '' })
|
||||
const [newSeat, setNewSeat] = useState('')
|
||||
const [selectedSeat, setSelectedSeat] = useState<string | null>(null)
|
||||
const [facePreview, setFacePreview] = useState<FaceState>('idle')
|
||||
const [profiles, setProfiles] = useState<AgentProfileLite[]>([])
|
||||
const [agent, setAgent] = useState({
|
||||
name: '',
|
||||
@@ -459,6 +462,36 @@ export function SeatsPage() {
|
||||
</CardHeader>
|
||||
{selected && (
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-4 rounded-lg border bg-muted/30 p-4">
|
||||
<AgentFace
|
||||
size="xl"
|
||||
name={agent.name}
|
||||
monogram={agent.monogram || agent.name}
|
||||
state={facePreview}
|
||||
/>
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
||||
<div>
|
||||
<p className="text-sm font-medium leading-tight">{agent.name || 'Unnamed agent'}</p>
|
||||
<p className="text-xs text-muted-foreground">Live face — preview each run state</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{(['idle', 'thinking', 'working', 'review', 'done', 'failed'] as FaceState[]).map((s) => (
|
||||
<button
|
||||
key={s}
|
||||
type="button"
|
||||
onClick={() => setFacePreview(s)}
|
||||
className={cn(
|
||||
'rounded-md border px-2 py-1 text-xs',
|
||||
facePreview === s ? 'bg-foreground text-background' : 'text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{s}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{profiles.length > 0 && (
|
||||
<Field label="Start from a profile (AGENTS.md)">
|
||||
<Select value="" onValueChange={applyProfile}>
|
||||
@@ -552,12 +585,11 @@ export function SeatsPage() {
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>Operating guide (persona)</Label>
|
||||
<textarea
|
||||
<MarkdownEditor
|
||||
value={agent.persona}
|
||||
onChange={(e) => setAgent({ ...agent, persona: e.target.value })}
|
||||
onChange={(persona) => setAgent({ ...agent, persona })}
|
||||
rows={4}
|
||||
placeholder="The agent's persona / operating guide — set by a profile, editable here. Injected into the run."
|
||||
className="w-full resize-y rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user