refactor: rename API and frontend projects to Vocero

Rename the project directories, Python distribution and import package, and npm package. Update launcher, Docker, tooling, tests, lockfiles, and documentation while preserving existing API contracts.

Make AGENTS.md self-contained and remove external skill and workflow references.
This commit is contained in:
2026-10-06 19:26:55 -03:00
parent e0304b2bdb
commit abd03ed07d
105 changed files with 353 additions and 312 deletions
+104
View File
@@ -0,0 +1,104 @@
import { fireEvent, render, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { StrictMode } from "react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import App from "./App";
const bootstrap = { theme: "white", s2sUrl: "ws://localhost:8420/v1/realtime", apipilot: true };
beforeEach(() => {
window.history.replaceState({}, "", "/?debug=true&phoneNumber=1234");
vi.spyOn(HTMLDialogElement.prototype, "showModal").mockImplementation(function (this: HTMLDialogElement) {
this.open = true;
});
vi.spyOn(HTMLDialogElement.prototype, "close").mockImplementation(function (this: HTMLDialogElement) {
this.open = false;
});
vi.stubGlobal(
"fetch",
vi.fn((input: string) => {
const path = new URL(input, window.location.origin).pathname;
const data: Record<string, unknown> = {
"/api/config": bootstrap,
"/api/user/phone": { result: { name: "Ana Vargas", contact: { emailAddress: "ana@example.test" } } },
"/api/user/reports": {
count: 1,
entries: [{ sourceScheduleLabel: null, date: null }],
hints: [],
truncated: true,
note: "Lista abreviada",
},
"/api/apipilot/tools": {
success: true,
data: { tools: [{ name: "get_reports", description: "Consulta tus reportes", parameters: {} }] },
},
};
return Promise.resolve(new Response(JSON.stringify(data[path] ?? {})));
}),
);
});
afterEach(() => {
vi.unstubAllGlobals();
window.history.replaceState({}, "", "/");
});
describe("React application", () => {
it("loads the configured theme and persists voice settings across remounts under StrictMode", async () => {
const user = userEvent.setup();
const view = render(
<StrictMode>
<App />
</StrictMode>,
);
await user.click(await screen.findByRole("button", { name: "Configuración" }));
expect(document.documentElement.dataset.theme).toBe("white");
await user.selectOptions(screen.getByRole("combobox"), "Serena");
expect(localStorage.getItem("s2s.ws.voice")).toBe("Serena");
await user.click(screen.getByRole("button", { name: "Guardar" }));
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
view.unmount();
render(
<StrictMode>
<App />
</StrictMode>,
);
await user.click(await screen.findByRole("button", { name: "Configuración" }));
expect(screen.getByRole("combobox")).toHaveValue("Serena");
});
it("saves and clears session-only RAG context and supports keyboard dialog dismissal", async () => {
const user = userEvent.setup();
render(<App />);
await user.click(await screen.findByRole("button", { name: "Contexto RAG personalizado" }));
await user.type(screen.getByRole("textbox"), "Datos de prueba para esta conversación");
await user.click(screen.getByRole("button", { name: "Enviar a la sesión" }));
expect(within(screen.getByRole("dialog")).getByRole("status")).toHaveTextContent("Contexto actualizado");
fireEvent(screen.getByRole("dialog"), new Event("cancel", { bubbles: true }));
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
await user.click(screen.getByRole("button", { name: "Contexto RAG personalizado" }));
expect(screen.getByRole("textbox")).toHaveValue("Datos de prueba para esta conversación");
await user.click(screen.getByRole("button", { name: "Vaciar" }));
expect(screen.getByRole("textbox")).toHaveValue("");
});
it("shows nested profile fields and discovers remote tools after bootstrap", async () => {
const user = userEvent.setup();
render(<App />);
await user.click(await screen.findByRole("button", { name: "Ver datos de Ana Vargas" }));
expect(within(screen.getByRole("dialog")).getByRole("link", { name: "ana@example.test" })).toHaveAttribute(
"href",
"mailto:ana@example.test",
);
await user.click(screen.getByRole("button", { name: "Cerrar" }));
await user.click(screen.getByRole("button", { name: "Herramientas" }));
await waitFor(() => {
expect(screen.getByText("get_reports")).toBeInTheDocument();
});
expect(screen.getByText("Consulta tus reportes")).toBeInTheDocument();
});
it("keeps debug controls out of the normal user screen", async () => {
window.history.replaceState({}, "", "/");
render(<App />);
expect(await screen.findByRole("button", { name: "Iniciar conversación de voz" })).toBeEnabled();
expect(screen.queryByRole("button", { name: "Configuración" })).not.toBeInTheDocument();
expect(screen.getByText("Aún no hay mensajes")).toBeInTheDocument();
});
});