From 01f3a3697a51a63d7940bded80c11d2110c55422 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 26 Feb 2026 16:18:47 +0000 Subject: [PATCH] story-211: skip selection screen when CLI path argument provided When a project path is passed on the command line, skip the project selection screen in the frontend and go straight to the main UI. Squash merge of feature/story-211 Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/App.test.tsx | 21 +++++++++++++++++++++ frontend/src/App.tsx | 19 +++++++++++++++++++ frontend/tests/e2e/smoke.spec.ts | 8 ++++++++ 3 files changed, 48 insertions(+) diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 56443bf..1ed7b03 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -57,6 +57,7 @@ describe("App", () => { beforeEach(() => { vi.resetModules(); vi.clearAllMocks(); + mockedApi.getCurrentProject.mockResolvedValue(null); mockedApi.getKnownProjects.mockResolvedValue([]); mockedApi.getHomeDirectory.mockResolvedValue("/home/user"); mockedApi.listDirectoryAbsolute.mockResolvedValue([]); @@ -71,6 +72,26 @@ describe("App", () => { return render(); } + it("calls getCurrentProject() on mount", async () => { + await renderApp(); + + await waitFor(() => { + expect(mockedApi.getCurrentProject).toHaveBeenCalledTimes(1); + }); + }); + + it("skips selection screen and shows workspace when server already has a project open", async () => { + mockedApi.getCurrentProject.mockResolvedValue("/home/user/myproject"); + + await renderApp(); + + await waitFor(() => { + expect( + screen.queryByPlaceholderText(/\/path\/to\/project/i), + ).not.toBeInTheDocument(); + }); + }); + it("renders the selection screen when no project is open", async () => { await renderApp(); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a845471..3a3eab6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -7,12 +7,27 @@ import "./App.css"; function App() { const [projectPath, setProjectPath] = React.useState(null); + const [isCheckingProject, setIsCheckingProject] = React.useState(true); const [errorMsg, setErrorMsg] = React.useState(null); const [pathInput, setPathInput] = React.useState(""); const [isOpening, setIsOpening] = React.useState(false); const [knownProjects, setKnownProjects] = React.useState([]); const [homeDir, setHomeDir] = React.useState(null); + React.useEffect(() => { + api + .getCurrentProject() + .then((path) => { + if (path) { + setProjectPath(path); + } + }) + .catch((error) => console.error(error)) + .finally(() => { + setIsCheckingProject(false); + }); + }, []); + React.useEffect(() => { api .getKnownProjects() @@ -138,6 +153,10 @@ function App() { } } + if (isCheckingProject) { + return null; + } + return (
{ + test.beforeEach(async ({ request }) => { + // Close any project the server may have auto-opened (e.g. via CLI path + // argument) so we always start from the selection screen. + await request.delete("/api/project").catch(() => { + // Ignore errors when no project is open or backend is unavailable. + }); + }); + test("renders the project selection screen", async ({ page }) => { await page.goto("/");