Files
q792602257andClaude Opus 4.6 e00c50e703 feat(api): server-rendered Jinja2 Runtime console at /ui/
Replaces the separate Vue/Vite `console/` SPA with a same-origin,
server-rendered console built on a module-level Jinja2 Environment
with select_autoescape(["html","xml"]).

- Add api/console_web.py with /ui/ routes (dashboard, tasks, task
  detail/timeline, config) and a _status_fragment polled every 10s.
- Refactor api/console.py into a typed ConsoleService shared by the
  JSON and HTML routers so validation/persistence cannot drift.
- Remove RUNTIME_CONSOLE_STATIC_DIR, SpaStaticFiles, and the wildcard
  CORS middleware from api/rest.py; GET / now redirects to /ui/.
- Delete the top-level console/ project; add jinja2 and python-multipart
  as direct dependencies and ship templates/CSS/JS via package-data.
- Add 31 tests (XSS probes, PRG flows, fragment refresh, no-static-dir
  and no-CORS regressions, wheel-packaging smoke test).

/console/* JSON endpoints remain unchanged. The console keeps the
trusted-network-only boundary; auth/CSRF is intentionally deferred.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-15 08:03:13 +08:00

4.8 KiB

1. Runtime package and web-resource setup

  • 1.1 Add direct jinja2>=3.1 and python-multipart Runtime dependencies, configure setuptools package-data for Runtime console templates/CSS/JavaScript, regenerate uv.lock, and verify uv lock --check.
  • 1.2 Create the Runtime-owned template and static-asset layout under api/ for the /ui/ console, with names suitable for wheel packaging and standard static-file serving.
  • 1.3 Add a package-resource smoke test that builds and installs device-agent-runtime outside the source checkout and confirms /ui/ can find its templates and assets.

2. Shared API-layer console operations

  • 2.1 Refactor api/console.py to expose an API-local typed console service for device, task, timeline, and runtime-config reads and mutations, preserving current validation and error semantics.
  • 2.2 Rewire create_console_router() to use the shared service and retain every existing /console/* method, JSON response shape, status code, filtering rule, and persistence behavior.
  • 2.3 Update api/rest.py to construct one shared service from its existing injected Runtime state and pass it to both JSON and HTML console routers without changing lower-layer dependencies.

3. Jinja2 Runtime console routes and pages

  • 3.1 Implement api/console_web.py with one module-level Jinja2 Environment, FileSystemLoader, select_autoescape(["html", "xml"]), and a small HTMLResponse render helper.
  • 3.2 Mount same-origin /ui/ page routes and /ui/assets static resources; make GET / redirect to /ui/ unconditionally.
  • 3.3 Implement the shared base layout, dashboard, and Jinja-rendered live-status fragment, including the small polling enhancement that replaces only the live region.
  • 3.4 Implement server-rendered task list/filter and task-detail/timeline pages, including ordered records, safe structured tool/result output, and available screenshot data URIs.
  • 3.5 Implement the configuration page and POST/Redirect/GET device registration/removal and max_steps update handlers, with readable 400 HTML validation errors that retain submitted safe values and perform no partial mutation.
  • 3.6 Port the existing console visual layout to package-owned CSS and the narrow polling script without adding a JavaScript framework or a frontend build step.

4. Retire SPA deployment wiring and update documentation

  • 4.1 Remove RUNTIME_CONSOLE_STATIC_DIR, SpaStaticFiles, the SPA fallback, and the wildcard CORS middleware used only for Vite development from api/rest.py.
  • 4.2 Delete the top-level console/ Vue/Vite project and remove its obsolete environment, npm, and ignore-file references while leaving cloud-console/ untouched.
  • 4.3 Update README.md, docs/CONSTITUTION.md, and docs/MACOS_IPHONE_SETUP.md to document normal Runtime startup followed by /ui/, the breaking removal of the npm/static-directory workflow, and the trusted-network-only security boundary.
  • 4.4 Remove stale Docker ignore/configuration entries that only described the deleted Runtime SPA, without changing Cloud Console build or deployment behavior.

5. Automated verification

  • 5.1 Keep and extend console JSON API tests to prove /console/* compatibility before and after page-route mutations.
  • 5.2 Add template tests covering every Runtime console template, module-level autoescape configuration, XSS probes in device/task/timeline/configuration values, safe structured JSON output, and absence of unintended |safe bypasses.
  • 5.3 Add FastAPI TestClient coverage for root redirect, page navigation, empty/populated dashboard state, task filters/detail/timeline, dashboard fragment refresh, static assets, form PRG success paths, and invalid-form no-mutation paths.
  • 5.4 Add regression coverage that same-origin /ui/ works without RUNTIME_CONSOLE_STATIC_DIR and does not depend on the removed wildcard CORS middleware.

6. Validation and migration handoff

  • 6.1 Run targeted formatting, lint, compile, and Runtime console tests, then run the repository non-integration test suite; record any pre-existing failures separately from this change.
  • 6.2 Build the Runtime wheel and run the isolated package-resource smoke test after the final dependency lock update.
  • 6.3 Run openspec validate runtime-console-jinja2-templates --strict and resolve all validation failures.
  • 6.4 Perform a browser walkthrough of dashboard live refresh, task filtering/timeline replay, valid and invalid device configuration, device removal, and max_steps update using a real Runtime process.
  • 6.5 After human browser verification, reconcile the remaining manual verification and superseded SPA decision in the pending web-console change before any archive decision; do not mark it complete from automated evidence alone.