feat(aevatar): add aevatar web subcommand hosting the workflow studio UI#80
Merged
feat(aevatar): add aevatar web subcommand hosting the workflow studio UI#80
aevatar web subcommand hosting the workflow studio UI#80Conversation
6423368 to
acaab6a
Compare
…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>
df5cb44 to
96ee2bd
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
(
index.html+app.js+app.css+codicon.ttf+ monaco worker) iscopied from upstream
tools/Aevatar.Tools.Cli/wwwrootintosrc/Aexon.Commands/wwwroot/aevatar/and shipped as tool content.AevatarWebHost: a trimmed-down ASP.NET Core host that serves theSPA, reverse-proxies
/api/*(SSE-aware), exposes/api/_proxy/runtime-urlGET/PUT for runtime retargeting, and serves/auth/callbackso the frontend's OAuth code-exchange works as underaevatar app./aevatar web [--port N] [--no-browser]subcommand. Backend URLflows through
AevatarChatSettingsStore.ResolveBaseUrl, so any saved/aevatar config set-urlalso points the web UI at that backend andmainnet 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— wirescase "web", parses--port/--no-browser, updates help.src/Aexon.Commands/Aexon.Commands.csproj— addsFrameworkReference Microsoft.AspNetCore.AppandContent Include="wwwroot\**"(with
PackagePathpointing into the tool's layout so the SPA ships with thepublished 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.GET /api/health→{"ok":true,"service":"aexon.aevatar.web"}GET /→ 716-byteindex.htmlGET /app.js→ full 4,508,737-byte bundleGET /api/_proxy/runtime-url→ mainnet URL when no override savedhttp://localhost:6688afteraexon aevatar webandconfirm the workflow studio renders and can talk to the backend end-to-end.