WIP: Large refactor checkpoint

- Refactored daemon client and RPC layer
- Added new client package structure in server
- Removed legacy hooks (use-daemon-request, use-session-rpc, use-websocket)
- Added use-daemon-client hook
- Added e2e test infrastructure with Playwright
- Updated agent providers and session handling
- Removed codex-sdk patches
This commit is contained in:
Mohamed Boudra
2026-01-12 13:30:20 +07:00
parent 7c2e959c19
commit 868f9fb571
64 changed files with 5773 additions and 4741 deletions
+17
View File
@@ -0,0 +1,17 @@
import { test, expect } from './fixtures';
import { createAgent, ensureHostSelected, gotoHome, setWorkingDirectory } from './helpers/app';
import { createTempGitRepo } from './helpers/workspace';
test('create agent in a temp repo', async ({ page }) => {
const repo = await createTempGitRepo();
const message = `E2E create agent ${Date.now()}`;
try {
await gotoHome(page);
await setWorkingDirectory(page, repo.path);
await ensureHostSelected(page);
await createAgent(page, message);
} finally {
await repo.cleanup();
}
});
@@ -0,0 +1,11 @@
import { test, expect } from './fixtures';
import { gotoHome, openSettings } from './helpers/app';
test('daemon is connected in settings', async ({ page }) => {
await gotoHome(page);
await openSettings(page);
await expect(page.getByText('localhost', { exact: true })).toBeVisible();
await expect(page.getByText('ws://localhost:6767/ws')).toBeVisible();
await expect(page.getByText('Online', { exact: true })).toBeVisible();
});
+34
View File
@@ -0,0 +1,34 @@
import { test, expect, type Page } from '@playwright/test';
const consoleEntries = new WeakMap<Page, string[]>();
test.beforeEach(({ page }) => {
const entries: string[] = [];
consoleEntries.set(page, entries);
page.on('console', (message) => {
entries.push(`[console:${message.type()}] ${message.text()}`);
});
page.on('pageerror', (error) => {
entries.push(`[pageerror] ${error.message}`);
});
});
test.afterEach(async ({ page }, testInfo) => {
const entries = consoleEntries.get(page);
if (!entries || entries.length === 0) {
return;
}
if (testInfo.status === testInfo.expectedStatus) {
return;
}
await testInfo.attach('browser-console', {
body: entries.join('\n'),
contentType: 'text/plain',
});
});
export { test, expect };
+65
View File
@@ -0,0 +1,65 @@
import { expect, type Page } from '@playwright/test';
export const gotoHome = async (page: Page) => {
await page.goto('/');
await expect(page.getByText('New Agent', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: 'Message agent...' })).toBeVisible();
};
export const openSettings = async (page: Page) => {
const settingsLink = page.getByText('Settings', { exact: true }).first();
await expect(settingsLink).toBeVisible();
await settingsLink.click();
await expect(page).toHaveURL(/\/settings$/);
};
export const setWorkingDirectory = async (page: Page, directory: string) => {
const workingDirectoryLabel = page.getByText('WORKING DIRECTORY', { exact: true }).first();
await expect(workingDirectoryLabel).toBeVisible();
await workingDirectoryLabel.click();
const input = page.getByRole('textbox', { name: '/path/to/project' });
await expect(input).toBeVisible();
await input.fill(directory);
await input.press('Enter');
const useOption = page.getByText(`Use "${directory}"`);
await expect(useOption).toBeVisible();
await useOption.click();
await expect(page.getByText(directory, { exact: true })).toBeVisible();
};
export const ensureHostSelected = async (page: Page) => {
const input = page.getByRole('textbox', { name: 'Message agent...' });
await expect(input).toBeVisible();
if (await input.isEditable()) {
return;
}
const selectHost = page.getByText('Select host', { exact: true });
if (await selectHost.isVisible()) {
await selectHost.click();
const hostOption = page.getByText('localhost', { exact: true }).first();
if (await hostOption.isVisible()) {
await hostOption.click();
} else {
const fallbackOption = page.getByText('Local Host', { exact: true }).first();
await expect(fallbackOption).toBeVisible();
await fallbackOption.click();
}
}
await expect(input).toBeEditable();
};
export const createAgent = async (page: Page, message: string) => {
const input = page.getByRole('textbox', { name: 'Message agent...' });
await expect(input).toBeEditable();
await input.fill(message);
await input.press('Enter');
await page.waitForURL(/\/agent\//);
await expect(page.getByText(message, { exact: true })).toBeVisible();
};
+23
View File
@@ -0,0 +1,23 @@
import { execSync } from 'node:child_process';
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
type TempRepo = {
path: string;
cleanup: () => Promise<void>;
};
export const createTempGitRepo = async (prefix = 'paseo-e2e-'): Promise<TempRepo> => {
const repoPath = await mkdtemp(path.join(tmpdir(), prefix));
execSync('git init', { cwd: repoPath, stdio: 'ignore' });
await writeFile(path.join(repoPath, 'README.md'), '# Temp Repo\n');
return {
path: repoPath,
cleanup: async () => {
await rm(repoPath, { recursive: true, force: true });
},
};
};