feat(cockpit): Clawd mascot + live agent chat on Meet your agent
Rework the Meet-your-agent rail into a self-contained agent surface: - Clawd, the Claude Code pixel crab, animates the LED matrix on a 26x16 grid, coupled to the chat lifecycle (idle stare / claws pump while working / green flash on reply). Static antennas, permanent black eyes. - A full free-form chat to the default agent (useAgentChat): free text goes to the blocking /webhook path so conversational replies actually render; the 3 canned prompts stay fire-and-forget + SSE (tool turns). - Chat and the working log are separate panes; the 3 prompts became starter buttons; the ZeroClaw runtime + channels moved into an Advanced drawer. The whole agent rail is now theme-aware (light/dark). - Strip the phase eyebrows from the sidebar + page headers; reduce the EnvSetup left column to editorial copy. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5975287d56
commit
a9a5176f7c
+10
-30
@@ -4,10 +4,11 @@ import { MemoryRouter } from 'react-router-dom'
|
||||
import { EnvSetup } from './EnvSetup'
|
||||
import { useSession } from '@/store/session'
|
||||
|
||||
// EnvSetup now renders the agent chat + say-hi; stub the streaming/mode calls.
|
||||
// The chat, starters, runtime and channels all moved to the cockpit rail
|
||||
// (CockpitRail's "agent" variant) — the page itself is now editorial copy + a
|
||||
// proceed gate. Stub the mode call the rail would otherwise make elsewhere.
|
||||
vi.mock('@/lib/api', async (orig) => ({
|
||||
...(await orig<typeof import('@/lib/api')>()),
|
||||
openTeamActivity: () => () => {},
|
||||
getMode: () => Promise.resolve({ localMode: false }),
|
||||
}))
|
||||
|
||||
@@ -29,44 +30,23 @@ describe('EnvSetup — Meet your agent', () => {
|
||||
sessionStorage.clear()
|
||||
})
|
||||
|
||||
it('renders the heading', () => {
|
||||
it('renders the heading and the editorial intro', () => {
|
||||
renderPage()
|
||||
expect(screen.getByRole('heading', { name: /meet your agent/i })).toBeInTheDocument()
|
||||
expect(screen.getByTestId('agent-intro')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('prompts to claim a board first when not connected, and gates Proceed', () => {
|
||||
it('guides to connect the board first when not connected, and gates Proceed', () => {
|
||||
renderPage()
|
||||
expect(screen.getByText(/claim your board first/i)).toBeInTheDocument()
|
||||
expect(screen.getByText(/connect your board on the previous step/i)).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: /proceed/i })).toBeDisabled()
|
||||
})
|
||||
|
||||
it('shows the node as Connected with the board url when claimed', () => {
|
||||
connect('http://192.168.1.7:8080')
|
||||
renderPage()
|
||||
const link = screen.getByRole('link', { name: /open your node/i })
|
||||
expect(link).toHaveAttribute('href', 'http://192.168.1.7:8080')
|
||||
expect(link).toHaveAttribute('target', '_blank')
|
||||
expect(screen.getByText(/^connected$/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('falls back to the claim prompt when connected but there is no nodeUrl', () => {
|
||||
connect(null)
|
||||
renderPage()
|
||||
expect(screen.queryByRole('link', { name: /open your node/i })).not.toBeInTheDocument()
|
||||
expect(screen.getByText(/claim your board first/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('reveals the Your Agent section (say-hi + chat) once connected', () => {
|
||||
connect()
|
||||
renderPage()
|
||||
expect(screen.getByTestId('your-agent')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: /say hi to your agent/i })).toBeInTheDocument()
|
||||
expect(screen.getByTestId('agent-chat')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('enables Proceed once the board is connected (domain moved to Module 1)', () => {
|
||||
it('enables Proceed once the board is connected', () => {
|
||||
connect()
|
||||
renderPage()
|
||||
expect(screen.getByRole('button', { name: /proceed/i })).toBeEnabled()
|
||||
// the connect nudge disappears once online
|
||||
expect(screen.queryByText(/connect your board on the previous step/i)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user