Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ui/src/demo/fixtures/inbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const demoInboxEntry: InboxEntry = {
export const demoWorkspaceFiles: Record<string, string> = {
[DEMO_REPORT_PATH]: `# AAPL Q1 — Hidden Deceleration Signal

**Workspace:** demo · **Generated:** just now
**Workspace:** aapl-q1 · **Generated:** just now

## TL;DR

Expand Down
2 changes: 1 addition & 1 deletion ui/src/demo/fixtures/transcripts/welcome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function typeOut(text: string, perCharMs = 30): void {

add(0, '\x1b[2J\x1b[H')
add(80, '\x1b[1;36m╭───────────────────────────────╮\x1b[0m\r\n')
add(40, '\x1b[1;36m│\x1b[0m \x1b[1mClaude Code\x1b[0m \x1b[2m· workspace demo\x1b[0m \x1b[1;36m│\x1b[0m\r\n')
add(40, '\x1b[1;36m│\x1b[0m \x1b[1mClaude Code\x1b[0m \x1b[2m· workspace aapl-q1\x1b[0m \x1b[1;36m│\x1b[0m\r\n')
add(40, '\x1b[1;36m╰───────────────────────────────╯\x1b[0m\r\n')
add(600, '\r\n')
add(0, "Hi! I'm Claude.\r\n\r\n")
Expand Down
83 changes: 74 additions & 9 deletions ui/src/demo/fixtures/workspaces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import type { Workspace, TemplateInfo, SessionRecord } from '../../components/workspace/api'

// The flagship demo workspace — the one inbox/transcript fixtures tie to.
// Template is `finance-research` because the AAPL Q1 transcript IS a
// finance-research session (read SEC filings, compute services-rev YoY,
// write report, inbox_push). Using a real template name (vs the earlier
// `demo-template` placeholder) makes the Workspaces sidebar group it
// correctly AND keeps the door open for the Chat shortcut sidebar to find
// its own workspace via the `chat` template filter.
export const DEMO_WORKSPACE_ID = 'demo-ws'
export const DEMO_SESSION_ID = 'demo-session'

Expand All @@ -18,10 +25,10 @@ const demoSession: SessionRecord = {

export const demoWorkspace: Workspace = {
id: DEMO_WORKSPACE_ID,
tag: 'demo',
dir: '/demo/workspaces/demo',
tag: 'aapl-q1',
dir: '/demo/workspaces/aapl-q1',
createdAt: new Date().toISOString(),
template: 'demo-template',
template: 'finance-research',
spawnedFromVersion: '0.1.0',
currentVersion: '0.1.0',
upgradeAvailable: null,
Expand All @@ -30,12 +37,70 @@ export const demoWorkspace: Workspace = {
agentOverride: { claude: false, codex: false },
}

export const demoTemplate: TemplateInfo = {
name: 'demo-template',
displayName: 'Demo Template',
description: 'A read-only demo template — workspace creation is disabled in demo mode.',
groupOrder: 0,
defaultAgents: ['claude'],
// Chat workspace — populates the Chat activity sidebar (which filters
// `template === 'chat'`). No transcript registered, so its session pane
// falls back to DemoTerminalStub — that's the right "this is a live PTY
// in real OpenAlice" placeholder for demo mode.
export const DEMO_CHAT_WORKSPACE_ID = 'demo-chat-ws'
export const DEMO_CHAT_SESSION_ID = 'demo-chat-session'

const demoChatSession: SessionRecord = {
id: DEMO_CHAT_SESSION_ID,
wsId: DEMO_CHAT_WORKSPACE_ID,
agent: 'claude',
name: 'c1',
createdAt: new Date().toISOString(),
lastActiveAt: new Date().toISOString(),
state: 'running',
agentSessionId: null,
pid: 0,
startedAt: Date.now(),
}

export const demoChatWorkspace: Workspace = {
id: DEMO_CHAT_WORKSPACE_ID,
tag: 'chat-may26',
dir: '/demo/workspaces/chat-may26',
createdAt: new Date().toISOString(),
template: 'chat',
spawnedFromVersion: '0.1.0',
currentVersion: '0.1.0',
upgradeAvailable: null,
agents: ['claude', 'codex'],
sessions: [demoChatSession],
agentOverride: { claude: false, codex: false },
}

export const demoWorkspaces: Workspace[] = [demoWorkspace, demoChatWorkspace]

// Templates — names + metadata mirror the real templates at
// src/workspaces/templates/{chat,finance-research}/template.json. Aligning
// the names matters: Chat / Workspaces sidebars filter on the literal
// 'chat' / 'finance-research' template name.
export const financeResearchTemplate: TemplateInfo = {
name: 'finance-research',
displayName: 'Finance Research',
description:
'Finance research workspace bundling himself65/finance-skills (yfinance market data, valuation, earnings, social readers, sentiment).',
groupOrder: 30,
defaultAgents: ['claude', 'codex'],
version: '0.1.0',
hasReadme: false,
}

export const chatTemplate: TemplateInfo = {
name: 'chat',
displayName: 'Chat',
description:
"Chat workspace wired to OpenAlice's MCP server — full trading/market tool surface available to the agent.",
groupOrder: 10,
defaultAgents: ['claude', 'codex'],
version: '0.1.0',
hasReadme: false,
}

export const demoTemplates: TemplateInfo[] = [chatTemplate, financeResearchTemplate]

// Back-compat singleton for older callers (other fixture files reference
// `demoTemplate` and we want a stable name). Points at the flagship.
export const demoTemplate: TemplateInfo = financeResearchTemplate
6 changes: 3 additions & 3 deletions ui/src/demo/handlers/workspaces.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { http, HttpResponse } from 'msw'
import { demoWorkspace, demoTemplate } from '../fixtures/workspaces'
import { demoWorkspaces, demoTemplates } from '../fixtures/workspaces'
import { demoWorkspaceFiles } from '../fixtures/inbox'

export const workspacesHandlers = [
http.get('/api/workspaces', () => HttpResponse.json({ workspaces: [demoWorkspace] })),
http.get('/api/workspaces', () => HttpResponse.json({ workspaces: demoWorkspaces })),
http.post('/api/workspaces', () =>
HttpResponse.json(
{ ok: false, status: 400, error: { error: 'bootstrap_failed', message: 'Demo mode — workspace creation is disabled.' } },
Expand All @@ -13,7 +13,7 @@ export const workspacesHandlers = [
http.delete('/api/workspaces/:id', () => HttpResponse.json(true)),
http.post('/api/workspaces/:id/stop', () => HttpResponse.json(true)),

http.get('/api/workspaces/templates', () => HttpResponse.json({ templates: [demoTemplate] })),
http.get('/api/workspaces/templates', () => HttpResponse.json({ templates: demoTemplates })),
http.get('/api/workspaces/templates/:name/readme', () =>
HttpResponse.text('', { status: 404 }),
),
Expand Down
Loading