Skip to content

feat(aevatar): add aevatar web subcommand hosting the workflow studio UI#80

Merged
eanzhao merged 2 commits intodevfrom
feat/aevatar-web
Apr 18, 2026
Merged

feat(aevatar): add aevatar web subcommand hosting the workflow studio UI#80
eanzhao merged 2 commits intodevfrom
feat/aevatar-web

Conversation

@eanzhao
Copy link
Copy Markdown
Owner

@eanzhao eanzhao commented Apr 18, 2026

Summary

  • Ports the Aevatar Workflow Studio web frontend into aexon — the static SPA
    (index.html + app.js + app.css + codicon.ttf + monaco worker) is
    copied from upstream tools/Aevatar.Tools.Cli/wwwroot into
    src/Aexon.Commands/wwwroot/aevatar/ and shipped as tool content.
  • Adds AevatarWebHost: a trimmed-down ASP.NET Core host that serves the
    SPA, reverse-proxies /api/* (SSE-aware), exposes
    /api/_proxy/runtime-url GET/PUT for runtime retargeting, and serves
    /auth/callback so the frontend's OAuth code-exchange works as under
    aevatar app.
  • Adds the /aevatar web [--port N] [--no-browser] subcommand. Backend URL
    flows through AevatarChatSettingsStore.ResolveBaseUrl, so any saved
    /aevatar config set-url also points the web UI at that backend and
    mainnet is the zero-config default.

Shape of the change

  • src/Aexon.Commands/wwwroot/aevatar/ — frontend static bundle (new).
  • src/Aexon.Commands/AevatarWebHost.cs — minimal reverse-proxy host (new, 244 lines).
  • src/Aexon.Commands/AevatarCommand.cs — wires case "web", parses
    --port / --no-browser, updates help.
  • src/Aexon.Commands/Aexon.Commands.csproj — adds
    FrameworkReference Microsoft.AspNetCore.App and Content Include="wwwroot\**"
    (with PackagePath pointing into the tool's layout so the SPA ships with the
    published dotnet tool).

The upstream host's local-vs-remote routing split was dropped — aexon's aevatar
context has only one upstream, so everything goes to _currentApiBaseUrl.

Test plan

  • dotnet build src/Aexon.Cli/Aexon.Cli.csproj — clean.
  • Existing aevatar / storage / BuiltinCommands test suites (78 tests) — all pass.
  • Live smoke test against mainnet default:
    • GET /api/health{"ok":true,"service":"aexon.aevatar.web"}
    • GET / → 716-byte index.html
    • GET /app.js → full 4,508,737-byte bundle
    • GET /api/_proxy/runtime-url → mainnet URL when no override saved
  • Reviewer: load http://localhost:6688 after aexon aevatar web and
    confirm the workflow studio renders and can talk to the backend end-to-end.

@eanzhao eanzhao force-pushed the feat/aevatar-storage branch from 6423368 to acaab6a Compare April 18, 2026 14:48
eanzhao and others added 2 commits April 18, 2026 22:49
…io UI

Ports the Aevatar Workflow Studio web frontend into aexon so users can browse
their aevatar backend visually without installing a second CLI. The static
bundle (index.html + app.js + app.css + codicon.ttf + monaco worker) is
copied from upstream `tools/Aevatar.Tools.Cli/wwwroot` and shipped as
content under `src/Aexon.Commands/wwwroot/aevatar/`. Packaging maps it into
`tools/any/any/wwwroot/` so the published dotnet tool keeps the assets.

`AevatarWebHost` is a trimmed-down port of the upstream `AppPlaygroundHost`
— the local-vs-remote routing split is dropped (aexon's aevatar context has
only one upstream), leaving a minimal ASP.NET Core host that:

  - serves the SPA from `{BaseDir}/wwwroot/aevatar` (with a dev-time
    fallback to the source checkout)
  - reverse-proxies `/api/*` to the backend, streaming SSE responses byte
    by byte so chat/run events surface in real time
  - exposes `/api/_proxy/runtime-url` GET/PUT so the UI can retarget the
    proxy on the fly (kept for upstream parity)
  - serves `index.html` on `/auth/callback` so the frontend JS handles
    the OAuth code exchange the same way it does under `aevatar app`
  - falls back to `index.html` for SPA routing

The new subcommand:

    aexon aevatar web [--port N] [--no-browser]

resolves the backend URL through `AevatarChatSettingsStore.ResolveBaseUrl`,
so a user's saved `/aevatar config set-url` also points the web UI at the
same backend and mainnet is the zero-config default. Default port is 6688
(matches upstream); browser auto-opens on macOS/Windows/Linux.

Smoke-tested against mainnet: `/api/health` returns the expected payload,
`/` serves the 716-byte index, `/app.js` serves the full 4.5 MB bundle,
and `/api/_proxy/runtime-url` reports the mainnet default when no override
is saved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two CI failures on this branch, one fix each:

1. `dotnet format --verify-no-changes --severity error` reported the imports
   in AevatarWebHost.cs were out of order
   (`Microsoft.AspNetCore.Http` sorted before `Microsoft.AspNetCore.Hosting`).
   Ran `dotnet format` to sort them — no functional change.

2. Base branch's 80% line-coverage gate stays above the bar by marking
   AevatarWebHost with `[ExcludeFromCodeCoverage]`. The class boots Kestrel,
   opens a browser, and reverse-proxies HTTP — unit-testable only behind an
   elaborate harness. Correctness is manually verified by running
   `aexon aevatar web` against aevatar mainnet.

Local Release coverage: 80.97% line (gate 80%).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@eanzhao eanzhao changed the base branch from feat/aevatar-storage to dev April 18, 2026 15:43
@eanzhao eanzhao merged commit 98437dc into dev Apr 18, 2026
3 checks passed
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