feat(webui): add project workspaces and access controls (#4007)

* feat(webui): add project workspaces and access controls

* feat(webui): add project workspaces and access controls

* refactor(tools): centralize workspace access resolution

* refactor(webui): remove unused workspace host state

* fix(webui): hide estimated file edit label

* fix(webui): clarify file edit deletion feedback

* fix(webui): label deleted file activity

* fix(webui): flatten file edit activity rows

* fix(core): remove path-only patch deletion

* fix(core): keep apply patch non-destructive

* refactor(webui): trim workspace host plumbing

* fix(tools): register exec with tools config
This commit is contained in:
Xubin Ren
2026-05-29 03:42:53 +08:00
committed by GitHub
parent 84428136e6
commit 3a420136bb
111 changed files with 9972 additions and 1822 deletions
+25
View File
@@ -186,6 +186,7 @@ describe("useSessions", () => {
await result.current.createChat();
});
expect(client.newChat).toHaveBeenCalledWith(5000, undefined);
expect(result.current.sessions.map((s) => s.key)).toEqual(["websocket:chat-new"]);
await act(async () => {
@@ -204,6 +205,30 @@ describe("useSessions", () => {
expect(result.current.sessions[0]?.title).toBe("Generated title");
});
it("stores optimistic workspace scope when creating a chat", async () => {
vi.mocked(api.listSessions).mockResolvedValue([]);
const client = fakeClient();
client.newChat.mockResolvedValue("chat-workspace");
const workspaceScope = {
project_path: "/tmp/project",
project_name: "project",
access_mode: "restricted" as const,
restrict_to_workspace: true,
};
const { result } = renderHook(() => useSessions(), {
wrapper: wrap(client),
});
await waitFor(() => expect(result.current.loading).toBe(false));
await act(async () => {
await result.current.createChat(workspaceScope);
});
expect(client.newChat).toHaveBeenCalledWith(5000, workspaceScope);
expect(result.current.sessions[0]?.workspaceScope).toEqual(workspaceScope);
});
it("passes through WebUI transcript user media as images and media", async () => {
vi.mocked(api.fetchWebuiThread).mockResolvedValue({
schemaVersion: 3,