Skip to content

feat: web frontend parity — HTTP routes for 58/59 Tauri commands#543

Merged
kwannoel merged 4 commits into
mainfrom
session-1-bf76f5
Apr 23, 2026
Merged

feat: web frontend parity — HTTP routes for 58/59 Tauri commands#543
kwannoel merged 4 commits into
mainfrom
session-1-bf76f5

Conversation

@kwannoel

Copy link
Copy Markdown
Owner

Summary

Brings the web frontend (vite + axum server) to feature parity with the Tauri desktop frontend so the desktop target can be deprecated. Web mode is end-to-end testable with Playwright; Tauri is not.

Ships 4 passes across 4 commits:

  • Pass 1 + 2 (e6331d6) — Unblock the web golden path + wire project/session lifecycle routes. Fixed 2 broken-semantic routes (/api/load_project, /api/close_session), un-stubbed create_session, added 16 new routes, and plugged 7 frontend files that bypassed backend.ts with direct @tauri-apps/* imports. Also deleted 6 dead e2e specs from removed workspaces (chore: remove voice, notes, infrastructure, and architecture workspaces #535) and loosened the title assertion in smoke/ui-consistency since the web mode now sets document.title dynamically.
  • Pass 3 (9be2cec) — GitHub + kanban: 11 new routes. Refactored commands/github.rs to take &AppState instead of State<'_, AppState> so both transports share one body.
  • Pass 4 (4e9f679) — Maintainer + auto-worker: 10 new routes. All events continue to flow through WsBroadcastEmitter to web clients over /ws.
  • Pass 5 (e5d094d) — Secure env, Claude login, scaffold_project, stage/unstage: 7 new routes.

Design: docs/plans/2026-04-23-web-frontend-parity-design.md.

Coverage: 58/59 Tauri commands. The one gap is copy_image_file_to_clipboard + capture_app_screenshot — slated for drop per the web deprecation plan; frontend still calls them in two spots but those paths silently degrade in web mode.

Not in this PR: the deprecation itself (deleting Tauri wrappers, removing @tauri-apps/* deps, dropping tauri.conf.json). That's a larger mechanical diff and should be its own PR.

Test plan

  • cargo test --lib — 290/290 pass
  • pnpm test — 300/300 pass
  • npx playwright test --project=e2e — 20 passed, 1 skipped, 1 failed (merge-codex; pre-existing environmental failure, also fails on main)
  • Live curl on every new route returned real data or impl-produced errors, confirming routing reaches the shared implementations
  • Browser smoke: opened http://localhost:1420 with both services running; app loads

🤖 Generated with Claude Code

kwannoel and others added 4 commits April 23, 2026 12:25
Pass 1 (unblock web): the web frontend (vite + axum server binary) can
now boot the golden path. backend.ts already abstracted invoke/fetch and
Tauri-event/WebSocket dispatch; this commit plugs the direct @tauri-apps
imports that bypassed the abstraction and fills in three P0 HTTP routes
the bootstrap needs:

- server.rs: un-stub /api/create_session (was 501), add
  /api/read_daemon_token (chat mode bootstrap), /api/log_frontend_error.
- commands.rs: extract create_session_impl(&AppState, ...) so Tauri and
  axum share one body; make commands::daemon pub so server can reuse
  the token-read helper.
- backend.ts: add openUrl() with Tauri→window.open fallback, export
  isTauri; components (Terminal/AgentDashboard/IssuesModal/KanbanCard)
  route through backend instead of plugin-opener.
- App.svelte: gate getCurrentWindow() behind isTauri; web falls back to
  document.title.
- clipboard.ts: dynamic-import plugin-clipboard-manager behind isTauri.
- main.ts: invoke → backend.command for log_frontend_error.
- finish-branch.ts: rename InvokeFn → CommandFn (transport-agnostic).
- vitest-setup.ts: add isTauri/openUrl/listenAsync to backend mock.

Pass 2 (feature parity — session & project lifecycle): extract 13
_impl(&AppState, ...) helpers and wire 16 new routes plus fix 2 broken
existing ones.

Fixed semantics:
- /api/load_project: was by projectId; now takes name+repoPath matching
  the Tauri command and the actual frontend caller.
- /api/close_session: was PTY-only; now does full storage + worktree
  cleanup matching the Tauri command.

New routes: create_project, delete_project, get_agents_md,
update_agents_md, set_initial_prompt, save_session_prompt,
list_project_prompts, get_session_commits, get_session_token_usage,
get_repo_head, save_onboarding_config, home_dir, list_directories_at,
list_root_directories, check_claude_cli, generate_project_names.

Coverage: 13/59 → 30/59 Tauri commands have HTTP parity. Remaining:
GitHub (8), kanban order (2), maintainer/auto-worker (12), secure env,
stage/unstage, Claude login, scaffold_project, media (slated for drop).

Also deletes 6 dead e2e specs (voice/notes/architecture/visual-audit)
left over from the workspace removal in #535, and prunes the
removed-mode sections from ui-consistency.spec.ts.

Design: docs/plans/2026-04-23-web-frontend-parity-design.md.

Verification: cargo test --lib 290/290, pnpm test 300/300, playwright
--project=e2e 20 passed / 1 skipped / 1 failed (merge-codex; fails on
main too — environmental).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass 3 of the web frontend parity effort. Moves 11 more Tauri commands
to HTTP parity, bringing the total to 41/59.

commands/github.rs: swap `State<'_, AppState>` → `&AppState` in the six
functions that touched the issue cache (`State` derefs to `&AppState`,
so the `state.issue_cache.lock()` bodies are unchanged). Make the
module `pub` so server.rs can call into it. Tauri wrappers now pass
`&state` to reach the same implementations.

commands/kanban.rs: expose `order_file_in`, `load_order_from`,
`save_order_to` as `pub` free functions. Tauri still resolves the file
via `AppHandle::app_data_dir()`; the server resolves via
`storage.base_dir()`. One-off cost: existing desktop users on their
first web session start with an empty kanban ordering — acceptable
since the feature landed in #539 and the desktop target is slated for
removal.

server.rs: 11 new routes — `/api/list_github_issues`,
`/api/create_github_issue`, `/api/close_github_issue`,
`/api/delete_github_issue`, `/api/post_github_comment`,
`/api/add_github_label`, `/api/remove_github_label`,
`/api/generate_issue_body`, `/api/list_assigned_issues`,
`/api/kanban_load_order`, `/api/kanban_save_order`.

Verification: cargo test --lib 290/290, pnpm test 300/300, playwright
--project=e2e 20 passed / 1 skipped / 1 failed (merge-codex; still the
pre-existing environmental failure, fails on main). Live curl on
/api/list_github_issues returned real issue data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass 4. Moves the remaining 10 maintainer/auto-worker commands to HTTP
parity — brings total to 51/59.

commands.rs: extract `_impl(&AppState, ...)` siblings for each command
(all already used only `state.storage.lock()` and `state.emitter.emit`,
both reachable through `&AppState`). Tauri wrappers become one-line
forwards. Also changes `github::list_github_issues` caller in
`get_auto_worker_queue_impl` from `&state` to `state` (it's now taking
`&AppState` already).

server.rs: 10 new routes — /api/configure_maintainer,
/api/configure_auto_worker, /api/get_worker_reports,
/api/get_auto_worker_queue, /api/get_maintainer_status,
/api/get_maintainer_history, /api/trigger_maintainer_check,
/api/clear_maintainer_reports, /api/get_maintainer_issues,
/api/get_maintainer_issue_detail.

The `maintainer-status:*` and `maintainer-error:*` events are emitted
via `state.emitter` which in server mode is the `WsBroadcastEmitter` —
web clients receive them via the existing `/ws` connection, no extra
wiring needed.

Remaining for full parity (8 commands): secure env (2), stage/unstage
session (2), Claude login (2), scaffold_project (1), log_frontend_error
is done. Plus the two media commands slated for drop.

Verification: cargo test --lib 290/290, pnpm test 300/300, playwright
--project=e2e 20 passed / 1 skipped / 1 failed (merge-codex only, still
the pre-existing environmental failure). Live curl on each new route
returned impl-produced errors for bogus inputs, confirming routing
reaches the shared implementations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass 5. Wires the remaining 7 feature routes, bringing total to 58/59.
Only the two media commands (copy_image_file_to_clipboard,
capture_app_screenshot) are left — slated for drop per the web
deprecation plan.

commands.rs: extract `_impl(&AppState, ...)` siblings for
`start_claude_login`, `stop_claude_login`, `scaffold_project`,
`unstage_session`. Widen `stage_session_core` visibility from
`pub(crate)` to `pub` so server.rs can reach it directly (it already
takes `&AppState`).

secure_env.rs: add `submit_secure_env_value_status(&AppState, ...) ->
Result<String, String>` that wraps the existing crate-private helpers
and produces the `"created"`/`"updated"` status the UI expects. Keeps
`PendingSecureEnvRequest`/`SecureEnvResponse`/`EnvWriteResult` private
so the module's surface stays tight.

server.rs: 7 new routes — /api/submit_secure_env_value,
/api/cancel_secure_env_request, /api/start_claude_login,
/api/stop_claude_login, /api/scaffold_project, /api/stage_session,
/api/unstage_session.

Verification: cargo test --lib 290/290, pnpm test 300/300, playwright
--project=e2e 20 passed / 1 skipped / 1 failed (merge-codex, still
pre-existing). Live curl on the new routes returned impl-produced
errors for bogus inputs, confirming routing hits the shared
implementations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kwannoel kwannoel enabled auto-merge (squash) April 23, 2026 07:05
@kwannoel kwannoel merged commit 4a699ae into main Apr 23, 2026
3 checks passed
@kwannoel kwannoel deleted the session-1-bf76f5 branch April 23, 2026 07:07
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