Skip to content

feat(demo): Stage 2 PR-2/3/4 aggregate — land remaining demo work on master#229

Merged
luokerenx4 merged 3 commits into
masterfrom
feat/ui-demo-stage2-aggregate
May 31, 2026
Merged

feat(demo): Stage 2 PR-2/3/4 aggregate — land remaining demo work on master#229
luokerenx4 merged 3 commits into
masterfrom
feat/ui-demo-stage2-aggregate

Conversation

@luokerenx4
Copy link
Copy Markdown
Contributor

Summary

Lands the three "stuck" stacked PRs from Stage 2 — #222 (PTY replay), #223 (flagship scenario), #224 (fixture richness) — directly on master. These were all merged into their stacked base branches but never bumped to master; this PR is the aggregate.

Methodology: three clean cherry-picks from the original branches onto current master tip. No conflicts, no MiniMax/auth work disturbed (the parallel PR #228 changes touch different file regions than the demo work).

Why this is needed

The Stage 2 stack used `base: feat/ui-demo-stage2-skeleton` for PR-2, `base: feat/ui-demo-stage2-pty-replay` for PR-3, `base: feat/ui-demo-stage2-scenario` for PR-4. When "Merge PR" was clicked on all four, each landed in its declared base — so only PR-1 (#221), which had `base: master`, actually shipped to master. PR-2/3/4 are sitting on intermediate branches that nothing else consumes.

Rather than force-push to rewrite history on those merged branches, this PR cherry-picks the three feat commits onto a fresh branch off master.

Contents

Three cherry-picked commits (preserve original commit messages):

  • `b1b9ee2` feat(demo): Stage 2 PR-2 — PTY transcript replay + recorder tool
  • `5b539e6` feat(demo): Stage 2 PR-3 — flagship scenario (Inbox ↔ workspace ↔ transcript)
  • `f92e748` feat(demo): Stage 2 PR-4 — secondary fixture richness

Diff scope

21 files, +1016 / -77, all under `ui/src/demo/` plus the existing `ui/src/main.tsx` (recorder dev-import) and `ui/src/components/workspace/Terminal.tsx` (lazy-import the demo terminal so prod bundle stays clean).

Verification

Check Result
`npx tsc --noEmit` (Alice strict) clean
`pnpm -F open-alice-ui exec tsc -b` (UI strict) clean
`pnpm test` 99 files / 1811 tests passed
`pnpm -F open-alice-ui build:demo` 286KB demo chunk + 2.83MB main chunk
`pnpm -F open-alice-ui build` (prod) main chunk has zero `Alpaca Paper` / `Binance Spot` / `Morning market prep` / `demoCronJobs` / `demoNewsArticles` / `aaplResearch` / `Hello from demo` / `hey, what jumped` literals; demo content code-split into separate `DemoTerminalReplay-*.js` chunk that prod never fetches

Cleanup

Once this lands, the three stale stacked branches (`feat/ui-demo-stage2-skeleton`, `feat/ui-demo-stage2-pty-replay`, `feat/ui-demo-stage2-scenario`) can be deleted manually if you want — they're dead refs now. `feat/ui-demo-stage2-fixtures` can also go. None of them are GitHub-protected.

Boundary touch

None — no trading / auth / broker / migrations code modified.

🤖 Generated with Claude Code

Ame and others added 3 commits May 31, 2026 13:54
The Terminal in demo mode now plays back a recorded PTY transcript using
xterm.js, replacing the static "terminal disabled" stub for workspaces
that have a registered transcript fixture. Stage 1's stub remains the
fallback for any workspace without one.

Transcript format (`ui/src/demo/types.ts`): `{label, durationMs, frames:
[{atMs, bytesB64}]}`. bytesB64 is base64-encoded raw PTY output bytes;
ANSI escapes, colors, cursor moves all replay faithfully because they
ride along inside the bytes.

DemoTerminalReplay (`ui/src/demo/DemoTerminalReplay.tsx`) — looks up a
transcript by workspace id, instantiates xterm with the same theme +
addons as the real Terminal, polls the container until it has real
dimensions before fitting + writing (avoids xterm's "Cannot read
properties of undefined (reading 'dimensions')" race in
Viewport.syncScrollArea), then schedules `term.write` calls at the
recorded timestamps via rAF. End of transcript → "↻ Replay again"
button.

Recorder (`ui/src/demo/recorder/recorder.ts`) — dev-mode helper that
monkey-patches `window.WebSocket` to tap server→client frames on URLs
matching `/api/workspaces/pty`, captures `{atMs, bytesB64}` per frame,
and on `__demoRecord.stop(label)` packages them as a JSON download.
Main.tsx auto-loads it in dev mode (NOT demo mode, NOT prod) so the
console-driven recorder is available alongside the real backend.

Placeholder transcript (`fixtures/transcripts/welcome.ts`) — hand-
crafted Claude-Code-style intro with banner, typed query, tool calls,
and a multi-paragraph response describing OpenAlice's architecture.
PR-3 will replace this with a real recorded session captured via the
recorder tool.

Verified:
- pnpm -F open-alice-ui exec tsc -b clean
- pnpm -F open-alice-ui build:demo: 277KB demo chunk + 2.83MB main chunk
- pnpm -F open-alice-ui build (prod): zero __demoRecord/
  DemoTerminalReplay/transcriptsByWorkspace/welcomeTranscript/
  startRecording/stopRecording/VITE_DEMO_MODE refs in dist
- pnpm dev:demo + Playwright walk: transcript plays back end-to-end,
  ANSI colors + bold + dim render correctly, line wrapping respects
  container width, "Replay again" button re-runs from start

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nscript)

Wires three demo surfaces into a coherent story for the visitor:

1. Inbox: shows a single agent-written report from a workspace named
   "demo" timestamped 5 minutes ago — "AAPL Q1 — Hidden Deceleration
   Signal" with a fully-rendered markdown document (TL;DR + analysis
   table + recommendations) inline.
2. Workspace file handler: returns the markdown content for
   `research-AAPL-q1.md` from `demoWorkspaceFiles` map. Inbox's
   readWorkspaceFile() call pulls it live (no snapshot), matching real
   product behavior.
3. PTY replay (welcome.ts rewritten as `aaplResearchTranscript`):
   shows the session that produced the report — user asks "what jumped
   out from Apple's Q1 earnings?", agent reads filings, computes
   services-rev YoY across quarters, finds the three-quarter
   deceleration, writes the report, inbox_pushes.

Cross-link is implicit and clean: the Inbox entry has
`workspaceId: DEMO_WORKSPACE_ID`. Clicking opens the workspace, the
session terminal plays the transcript that produced the entry. No
explicit "this entry came from that session" pointer needed — the
narrative reads itself.

Also scripts the SSE event timeline (handlers/events.ts +
fixtures/events.ts): 6 historical events spanning ~5 minutes covering
agent.work.started → tool_calls → write_file → inbox.entry_created →
agent.work.completed. Emitted as one burst on stream connect to
populate the events feed.

Tree-shaking fix (the necessary side-effect of this PR): Terminal.tsx
now lazy-imports DemoTerminalReplay via React.lazy. With the prior
static import, Rollup conservatively kept the transcript file in the
prod main bundle because its top-level frame-building IIFE has module-
scope side effects. Lazy import code-splits the demo terminal into its
own 5.7KB chunk that is never fetched in prod (gated by
import.meta.env.VITE_DEMO_MODE at the call site).

Verified:
- pnpm -F open-alice-ui exec tsc -b clean
- pnpm -F open-alice-ui build (prod): main chunk has zero
  transcript / fixture / handler strings; only "DemoTerminalReplay"
  literal (the lazy-import module specifier) remains. Separate
  DemoTerminalReplay-*.js chunk (5.7KB / 2.5KB gz) exists but is never
  fetched in prod.
- pnpm -F open-alice-ui build:demo: 279KB demo chunk + 2.82MB main,
  builds clean.
- pnpm dev:demo + Playwright: Inbox shows demo entry, markdown report
  renders inline, navigating to workspace plays the AAPL research
  transcript end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fills out the long tail of fixture content so the demo doesn't look
gutted once a visitor scrolls past the Inbox/workspace flagship flow
from PR-3.

**3 trading accounts (instead of 1)** —
- Alpaca Paper: \$52,840 NL, 4 stock positions (AAPL/NVDA/GOOG/AMD)
  with realistic avg-cost vs market-price spreads
- IBKR Demo: \$247,310 NL, mix of ETFs (SPY, QQQ, TLT) + an
  underwater AAPL options position to show non-trivial P&L
- Binance Spot: \$15,032 NL (USDT base), BTC and ETH spot positions

Equity curve generator uses a seeded random walk per UTA (30 daily
points, distinct vol + drift per account) so the Portfolio chart
shows plausible-looking lines without the numbers shifting on each
page reload — visitors who refresh see consistent state.

**6 news articles** — Reuters/Bloomberg/CNBC/WSJ/CoinDesk spread
across the last 22 hours covering AAPL Q1, NVDA capex, Fed minutes,
BTC, SPY, TLT. The AAPL article (timestamped 30m ago) ties to the
Inbox AAPL research from PR-3 (timestamped 5m ago) — "news landed →
agent dug in → wrote up the deceleration signal".

**4 cron jobs** — Morning market prep (weekdays 8:30 AM), EOD
snapshot + journal (weekdays 4:05 PM), Weekly position review
(Fridays 5 PM, disabled), AAPL watch alert (every 15m). Mix of cron-
schedule vs every-N-minutes formats; mix of enabled vs disabled.

Skipped from this PR: topology graph fake (Dev page, low marketing
value), populated agent-status log (the events SSE in PR-3 already
carries the "system is alive" signal).

Verified:
- pnpm -F open-alice-ui exec tsc -b clean
- pnpm -F open-alice-ui build (prod): zero fixture name leaks in main
  bundle (`Alpaca Paper`, `Binance Spot`, `Morning market prep`,
  `demoCronJobs`, `demoNewsArticles` — all absent)
- pnpm dev:demo + Playwright: portfolio page renders chart with the
  random-walk curve + cumulative equity numbers, news page lists all
  6 articles with badges, sidebar shows 3 trading accounts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@luokerenx4 luokerenx4 merged commit a2dd6c0 into master May 31, 2026
1 check passed
@luokerenx4 luokerenx4 deleted the feat/ui-demo-stage2-aggregate branch May 31, 2026 06:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant